[U-Boot] [RFC PATCH 0/7] Add Driver Model support to network stack

For now this simply addresses the MAC part of the network hardware. The next part to implement is the PHY children. I wanted to get early feedback on what I have so far to make sure I'm going in the direction that Simon envisioned.
Joe Hershberger (7): net: Provide a function to get the current MAC address net: Rename helper function to be more clear net: Remove unneeded "extern" in net.h net: Refactor in preparation for driver model net: Add basic driver model support to Ethernet stack net: Add network support to sandbox net: Add ARP and PING response to sandbox driver
arch/mips/cpu/mips32/au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- arch/sandbox/dts/sandbox.dts | 4 + common/board_r.c | 4 +- common/cmd_bdinfo.c | 2 + drivers/net/Makefile | 2 + drivers/net/sandbox.c | 166 +++++++++++++ include/configs/sandbox.h | 14 +- include/dm/uclass-id.h | 1 + include/net.h | 158 +++++++----- net/eth.c | 408 +++++++++++++++++++++++++++---- net/net.c | 2 +- 14 files changed, 649 insertions(+), 120 deletions(-) create mode 100644 drivers/net/sandbox.c

The current implementation exposes the eth_device struct to code that needs to access the MAC address. Add a wrapper function for this to abstract away the pointer for this operation.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com ---
arch/mips/cpu/mips32/au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- include/net.h | 8 ++++++++ net/net.c | 2 +- 6 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/arch/mips/cpu/mips32/au1x00/au1x00_eth.c b/arch/mips/cpu/mips32/au1x00/au1x00_eth.c index 4770f56..535d713 100644 --- a/arch/mips/cpu/mips32/au1x00/au1x00_eth.c +++ b/arch/mips/cpu/mips32/au1x00/au1x00_eth.c @@ -238,7 +238,7 @@ static int au1x00_init(struct eth_device* dev, bd_t * bd){ }
/* Put mac addr in little endian */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() *mac_addr_high = (ea[5] << 8) | (ea[4] ) ; *mac_addr_low = (ea[3] << 24) | (ea[2] << 16) | (ea[1] << 8) | (ea[0] ) ; diff --git a/arch/powerpc/cpu/mpc8260/ether_fcc.c b/arch/powerpc/cpu/mpc8260/ether_fcc.c index f9f15b5..f777ba1 100644 --- a/arch/powerpc/cpu/mpc8260/ether_fcc.c +++ b/arch/powerpc/cpu/mpc8260/ether_fcc.c @@ -299,7 +299,7 @@ static int fec_init(struct eth_device* dev, bd_t *bis) * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc85xx/ether_fcc.c b/arch/powerpc/cpu/mpc85xx/ether_fcc.c index 166dc9e..58d4bfb 100644 --- a/arch/powerpc/cpu/mpc85xx/ether_fcc.c +++ b/arch/powerpc/cpu/mpc85xx/ether_fcc.c @@ -338,7 +338,7 @@ static int fec_init(struct eth_device* dev, bd_t *bis) * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc8xx/scc.c b/arch/powerpc/cpu/mpc8xx/scc.c index 251966b..66e4014 100644 --- a/arch/powerpc/cpu/mpc8xx/scc.c +++ b/arch/powerpc/cpu/mpc8xx/scc.c @@ -339,7 +339,7 @@ static int scc_init (struct eth_device *dev, bd_t * bis) pram_ptr->sen_gaddr3 = 0x0; /* Group Address Filter 3 (unused) */ pram_ptr->sen_gaddr4 = 0x0; /* Group Address Filter 4 (unused) */
-#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/include/net.h b/include/net.h index 73ea88b..a9579ee 100644 --- a/include/net.h +++ b/include/net.h @@ -111,6 +111,14 @@ struct eth_device *eth_get_dev(void) { return eth_current; } + +static inline unsigned char *eth_get_ethaddr(void) +{ + if (eth_current) + return eth_current->enetaddr; + return NULL; +} + extern struct eth_device *eth_get_dev_by_name(const char *devname); extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ extern int eth_get_dev_index(void); /* get the device index */ diff --git a/net/net.c b/net/net.c index 2bea07b..ddd630c 100644 --- a/net/net.c +++ b/net/net.c @@ -275,7 +275,7 @@ static void NetInitLoop(void) env_changed_id = env_id; } if (eth_get_dev()) - memcpy(NetOurEther, eth_get_dev()->enetaddr, 6); + memcpy(NetOurEther, eth_get_ethaddr(), 6);
return; }

Hi Joe,
On 27 January 2015 at 16:27, Joe Hershberger joe.hershberger@ni.com wrote:
The current implementation exposes the eth_device struct to code that needs to access the MAC address. Add a wrapper function for this to abstract away the pointer for this operation.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
arch/mips/cpu/mips32/au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- include/net.h | 8 ++++++++ net/net.c | 2 +- 6 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/arch/mips/cpu/mips32/au1x00/au1x00_eth.c b/arch/mips/cpu/mips32/au1x00/au1x00_eth.c index 4770f56..535d713 100644 --- a/arch/mips/cpu/mips32/au1x00/au1x00_eth.c +++ b/arch/mips/cpu/mips32/au1x00/au1x00_eth.c @@ -238,7 +238,7 @@ static int au1x00_init(struct eth_device* dev, bd_t * bd){ }
/* Put mac addr in little endian */
-#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() *mac_addr_high = (ea[5] << 8) | (ea[4] ) ; *mac_addr_low = (ea[3] << 24) | (ea[2] << 16) |
I know this is existing code, but (perhaps separately) it might be nice to remove the #define and assign it it to a local variable, i.e.:
unsigned char *ea = eth_get_ethaddr();
(ea[1] << 8) | (ea[0] ) ;
diff --git a/arch/powerpc/cpu/mpc8260/ether_fcc.c b/arch/powerpc/cpu/mpc8260/ether_fcc.c index f9f15b5..f777ba1 100644 --- a/arch/powerpc/cpu/mpc8260/ether_fcc.c +++ b/arch/powerpc/cpu/mpc8260/ether_fcc.c @@ -299,7 +299,7 @@ static int fec_init(struct eth_device* dev, bd_t *bis) * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc85xx/ether_fcc.c b/arch/powerpc/cpu/mpc85xx/ether_fcc.c index 166dc9e..58d4bfb 100644 --- a/arch/powerpc/cpu/mpc85xx/ether_fcc.c +++ b/arch/powerpc/cpu/mpc85xx/ether_fcc.c @@ -338,7 +338,7 @@ static int fec_init(struct eth_device* dev, bd_t *bis) * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc8xx/scc.c b/arch/powerpc/cpu/mpc8xx/scc.c index 251966b..66e4014 100644 --- a/arch/powerpc/cpu/mpc8xx/scc.c +++ b/arch/powerpc/cpu/mpc8xx/scc.c @@ -339,7 +339,7 @@ static int scc_init (struct eth_device *dev, bd_t * bis) pram_ptr->sen_gaddr3 = 0x0; /* Group Address Filter 3 (unused) */ pram_ptr->sen_gaddr4 = 0x0; /* Group Address Filter 4 (unused) */
-#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/include/net.h b/include/net.h index 73ea88b..a9579ee 100644 --- a/include/net.h +++ b/include/net.h @@ -111,6 +111,14 @@ struct eth_device *eth_get_dev(void) { return eth_current; }
+static inline unsigned char *eth_get_ethaddr(void) +{
if (eth_current)
return eth_current->enetaddr;
return NULL;
+}
extern struct eth_device *eth_get_dev_by_name(const char *devname); extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ extern int eth_get_dev_index(void); /* get the device index */ diff --git a/net/net.c b/net/net.c index 2bea07b..ddd630c 100644 --- a/net/net.c +++ b/net/net.c @@ -275,7 +275,7 @@ static void NetInitLoop(void) env_changed_id = env_id; } if (eth_get_dev())
memcpy(NetOurEther, eth_get_dev()->enetaddr, 6);
memcpy(NetOurEther, eth_get_ethaddr(), 6); return;
}
1.7.11.5
Regards, Simon

On Tue, Jan 27, 2015 at 8:33 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 27 January 2015 at 16:27, Joe Hershberger joe.hershberger@ni.com
wrote:
The current implementation exposes the eth_device struct to code that needs to access the MAC address. Add a wrapper function for this to abstract away the pointer for this operation.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
arch/mips/cpu/mips32/au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- include/net.h | 8 ++++++++ net/net.c | 2 +- 6 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/arch/mips/cpu/mips32/au1x00/au1x00_eth.c
b/arch/mips/cpu/mips32/au1x00/au1x00_eth.c
index 4770f56..535d713 100644 --- a/arch/mips/cpu/mips32/au1x00/au1x00_eth.c +++ b/arch/mips/cpu/mips32/au1x00/au1x00_eth.c @@ -238,7 +238,7 @@ static int au1x00_init(struct eth_device* dev, bd_t
* bd){
} /* Put mac addr in little endian */
-#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() *mac_addr_high = (ea[5] << 8) | (ea[4] ) ; *mac_addr_low = (ea[3] << 24) | (ea[2] << 16) |
I know this is existing code, but (perhaps separately) it might be nice to remove the #define and assign it it to a local variable, i.e.:
unsigned char *ea = eth_get_ethaddr();
I'm sure that if this code is not deleted before it is reworked that this sort of improvement will be made. For this series I just wanted to change as little as possible. I agree that the #define is ugly.
(ea[1] << 8) | (ea[0] ) ;
diff --git a/arch/powerpc/cpu/mpc8260/ether_fcc.c
b/arch/powerpc/cpu/mpc8260/ether_fcc.c
index f9f15b5..f777ba1 100644 --- a/arch/powerpc/cpu/mpc8260/ether_fcc.c +++ b/arch/powerpc/cpu/mpc8260/ether_fcc.c @@ -299,7 +299,7 @@ static int fec_init(struct eth_device* dev, bd_t
*bis)
* it unique by setting a few bits in the upper byte of the * non-static part of the address. */
-#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc85xx/ether_fcc.c
b/arch/powerpc/cpu/mpc85xx/ether_fcc.c
index 166dc9e..58d4bfb 100644 --- a/arch/powerpc/cpu/mpc85xx/ether_fcc.c +++ b/arch/powerpc/cpu/mpc85xx/ether_fcc.c @@ -338,7 +338,7 @@ static int fec_init(struct eth_device* dev, bd_t
*bis)
* it unique by setting a few bits in the upper byte of the * non-static part of the address. */
-#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc8xx/scc.c
b/arch/powerpc/cpu/mpc8xx/scc.c
index 251966b..66e4014 100644 --- a/arch/powerpc/cpu/mpc8xx/scc.c +++ b/arch/powerpc/cpu/mpc8xx/scc.c @@ -339,7 +339,7 @@ static int scc_init (struct eth_device *dev, bd_t *
bis)
pram_ptr->sen_gaddr3 = 0x0; /* Group Address Filter 3
(unused) */
pram_ptr->sen_gaddr4 = 0x0; /* Group Address Filter 4
(unused) */
-#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/include/net.h b/include/net.h index 73ea88b..a9579ee 100644 --- a/include/net.h +++ b/include/net.h @@ -111,6 +111,14 @@ struct eth_device *eth_get_dev(void) { return eth_current; }
+static inline unsigned char *eth_get_ethaddr(void) +{
if (eth_current)
return eth_current->enetaddr;
return NULL;
+}
extern struct eth_device *eth_get_dev_by_name(const char *devname); extern struct eth_device *eth_get_dev_by_index(int index); /* get dev
@ index */
extern int eth_get_dev_index(void); /* get the device index
*/
diff --git a/net/net.c b/net/net.c index 2bea07b..ddd630c 100644 --- a/net/net.c +++ b/net/net.c @@ -275,7 +275,7 @@ static void NetInitLoop(void) env_changed_id = env_id; } if (eth_get_dev())
memcpy(NetOurEther, eth_get_dev()->enetaddr, 6);
memcpy(NetOurEther, eth_get_ethaddr(), 6); return;
}
1.7.11.5
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi Joe,
On 28 January 2015 at 02:45, Joe Hershberger joe.hershberger@gmail.com wrote:
On Tue, Jan 27, 2015 at 8:33 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 27 January 2015 at 16:27, Joe Hershberger joe.hershberger@ni.com wrote:
The current implementation exposes the eth_device struct to code that needs to access the MAC address. Add a wrapper function for this to abstract away the pointer for this operation.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
arch/mips/cpu/mips32/au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- include/net.h | 8 ++++++++ net/net.c | 2 +- 6 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/arch/mips/cpu/mips32/au1x00/au1x00_eth.c b/arch/mips/cpu/mips32/au1x00/au1x00_eth.c index 4770f56..535d713 100644 --- a/arch/mips/cpu/mips32/au1x00/au1x00_eth.c +++ b/arch/mips/cpu/mips32/au1x00/au1x00_eth.c @@ -238,7 +238,7 @@ static int au1x00_init(struct eth_device* dev, bd_t
bd){ }
/* Put mac addr in little endian */
-#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() *mac_addr_high = (ea[5] << 8) | (ea[4] ) ; *mac_addr_low = (ea[3] << 24) | (ea[2] << 16) |
I know this is existing code, but (perhaps separately) it might be nice to remove the #define and assign it it to a local variable, i.e.:
unsigned char *ea = eth_get_ethaddr();
I'm sure that if this code is not deleted before it is reworked that this sort of improvement will be made. For this series I just wanted to change as little as possible. I agree that the #define is ugly.
OK sounds good.
Regards, Simon

Make it clear that the helper is checking the addr, not setting it.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com ---
net/eth.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/net/eth.c b/net/eth.c index eac4f7b..65e8c77 100644 --- a/net/eth.c +++ b/net/eth.c @@ -153,11 +153,6 @@ static void eth_current_changed(void) setenv("ethact", NULL); }
-static int eth_address_set(unsigned char *addr) -{ - return memcmp(addr, "\0\0\0\0\0\0", 6); -} - int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -166,9 +161,9 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
- if (eth_address_set(env_enetaddr)) { - if (eth_address_set(dev->enetaddr) && - memcmp(dev->enetaddr, env_enetaddr, 6)) { + if (!is_zero_ether_addr(env_enetaddr)) { + if (!is_zero_ether_addr(dev->enetaddr) && + memcmp(dev->enetaddr, env_enetaddr, 6)) { printf("\nWarning: %s MAC addresses don't match:\n", dev->name); printf("Address in SROM is %pM\n", @@ -183,7 +178,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, dev->enetaddr); printf("\nWarning: %s using MAC address from net device\n", dev->name); - } else if (!(eth_address_set(dev->enetaddr))) { + } else if (is_zero_ether_addr(dev->enetaddr)) { printf("\nError: %s address not set.\n", dev->name); return -EINVAL;

On 27 January 2015 at 16:27, Joe Hershberger joe.hershberger@ni.com wrote:
Make it clear that the helper is checking the addr, not setting it.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
net/eth.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/net/eth.c b/net/eth.c index eac4f7b..65e8c77 100644 --- a/net/eth.c +++ b/net/eth.c @@ -153,11 +153,6 @@ static void eth_current_changed(void) setenv("ethact", NULL); }
-static int eth_address_set(unsigned char *addr) -{
return memcmp(addr, "\0\0\0\0\0\0", 6);
-}
int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -166,9 +161,9 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
if (eth_address_set(env_enetaddr)) {
if (eth_address_set(dev->enetaddr) &&
memcmp(dev->enetaddr, env_enetaddr, 6)) {
if (!is_zero_ether_addr(env_enetaddr)) {
if (!is_zero_ether_addr(dev->enetaddr) &&
memcmp(dev->enetaddr, env_enetaddr, 6)) { printf("\nWarning: %s MAC addresses don't match:\n", dev->name); printf("Address in SROM is %pM\n",
@@ -183,7 +178,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, dev->enetaddr); printf("\nWarning: %s using MAC address from net device\n", dev->name);
} else if (!(eth_address_set(dev->enetaddr))) {
} else if (is_zero_ether_addr(dev->enetaddr)) { printf("\nError: %s address not set.\n", dev->name); return -EINVAL;
-- 1.7.11.5

Many of the functions in net.h were preceded extern needlessly. Removing them to limit the number of checkpatch.pl complaints.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com ---
include/net.h | 96 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 48 insertions(+), 48 deletions(-)
diff --git a/include/net.h b/include/net.h index a9579ee..ff8b7af 100644 --- a/include/net.h +++ b/include/net.h @@ -97,11 +97,11 @@ struct eth_device { void *priv; };
-extern int eth_initialize(bd_t *bis); /* Initialize network subsystem */ -extern int eth_register(struct eth_device* dev);/* Register network device */ -extern int eth_unregister(struct eth_device *dev);/* Remove network device */ -extern void eth_try_another(int first_restart); /* Change the device */ -extern void eth_set_current(void); /* set nterface to ethcur var */ +int eth_initialize(bd_t *bis); /* Initialize network subsystem */ +int eth_register(struct eth_device *dev);/* Register network device */ +int eth_unregister(struct eth_device *dev);/* Remove network device */ +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */
/* get the current device MAC */ extern struct eth_device *eth_current; @@ -119,12 +119,12 @@ static inline unsigned char *eth_get_ethaddr(void) return NULL; }
-extern struct eth_device *eth_get_dev_by_name(const char *devname); -extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ -extern int eth_get_dev_index(void); /* get the device index */ -extern void eth_parse_enetaddr(const char *addr, uchar *enetaddr); -extern int eth_getenv_enetaddr(char *name, uchar *enetaddr); -extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr); +struct eth_device *eth_get_dev_by_name(const char *devname); +struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ +int eth_get_dev_index(void); /* get the device index */ +void eth_parse_enetaddr(const char *addr, uchar *enetaddr); +int eth_getenv_enetaddr(char *name, uchar *enetaddr); +int eth_setenv_enetaddr(char *name, const uchar *enetaddr);
/* * Get the hardware address for an ethernet interface . @@ -135,20 +135,20 @@ extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr); * Returns: * Return true if the address is valid. */ -extern int eth_getenv_enetaddr_by_index(const char *base_name, int index, - uchar *enetaddr); +int eth_getenv_enetaddr_by_index(const char *base_name, int index, + uchar *enetaddr);
-extern int usb_eth_initialize(bd_t *bi); -extern int eth_init(bd_t *bis); /* Initialize the device */ -extern int eth_send(void *packet, int length); /* Send a packet */ +int usb_eth_initialize(bd_t *bi); +int eth_init(bd_t *bis); /* Initialize the device */ +int eth_send(void *packet, int length); /* Send a packet */
#ifdef CONFIG_API -extern int eth_receive(void *packet, int length); /* Receive a packet*/ -extern void (*push_packet)(void *packet, int length); +int eth_receive(void *packet, int length); /* Receive a packet*/ +void (*push_packet)(void *packet, int length); #endif -extern int eth_rx(void); /* Check for received packets */ -extern void eth_halt(void); /* stop SCC */ -extern char *eth_get_name(void); /* get name of current device */ +int eth_rx(void); /* Check for received packets */ +void eth_halt(void); /* stop SCC */ +char *eth_get_name(void); /* get name of current device */
/* Set active state */ static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) @@ -469,25 +469,25 @@ extern IPaddr_t Mcast_addr; #endif
/* Initialize the network adapter */ -extern void net_init(void); -extern int NetLoop(enum proto_t); +void net_init(void); +int NetLoop(enum proto_t);
/* Shutdown adapters and cleanup */ -extern void NetStop(void); +void NetStop(void);
/* Load failed. Start again. */ -extern void NetStartAgain(void); +void NetStartAgain(void);
/* Get size of the ethernet header when we send */ -extern int NetEthHdrSize(void); +int NetEthHdrSize(void);
/* Set ethernet header; returns the size of the header */ -extern int NetSetEther(uchar *, uchar *, uint); -extern int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot); +int NetSetEther(uchar *, uchar *, uint); +int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot);
/* Set IP header */ -extern void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source); -extern void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, +void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source); +void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, int sport, int len);
/** @@ -521,16 +521,16 @@ unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new_sum); int ip_checksum_ok(const void *addr, unsigned nbytes);
/* Checksum */ -extern int NetCksumOk(uchar *, int); /* Return true if cksum OK */ -extern uint NetCksum(uchar *, int); /* Calculate the checksum */ +int NetCksumOk(uchar *, int); /* Return true if cksum OK */ +uint NetCksum(uchar *, int); /* Calculate the checksum */
/* Callbacks */ -extern rxhand_f *net_get_udp_handler(void); /* Get UDP RX packet handler */ -extern void net_set_udp_handler(rxhand_f *); /* Set UDP RX packet handler */ -extern rxhand_f *net_get_arp_handler(void); /* Get ARP RX packet handler */ -extern void net_set_arp_handler(rxhand_f *); /* Set ARP RX packet handler */ -extern void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */ -extern void NetSetTimeout(ulong, thand_f *);/* Set timeout handler */ +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 */ +void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */ +void NetSetTimeout(ulong, thand_f *);/* Set timeout handler */
/* Network loop state */ enum net_loop_state { @@ -563,11 +563,11 @@ static inline void NetSendPacket(uchar *pkt, int len) * @param sport Source UDP port * @param payload_len Length of data after the UDP header */ -extern int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, +int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int payload_len);
/* Processes a received packet */ -extern void NetReceive(uchar *, int); +void NetReceive(uchar *, int);
#ifdef CONFIG_NETCONSOLE void NcStart(void); @@ -715,28 +715,28 @@ static inline void eth_random_addr(uchar *addr) }
/* Convert an IP address to a string */ -extern void ip_to_string(IPaddr_t x, char *s); +void ip_to_string(IPaddr_t x, char *s);
/* Convert a string to ip address */ -extern IPaddr_t string_to_ip(const char *s); +IPaddr_t string_to_ip(const char *s);
/* Convert a VLAN id to a string */ -extern void VLAN_to_string(ushort x, char *s); +void VLAN_to_string(ushort x, char *s);
/* Convert a string to a vlan id */ -extern ushort string_to_VLAN(const char *s); +ushort string_to_VLAN(const char *s);
/* read a VLAN id from an environment variable */ -extern ushort getenv_VLAN(char *); +ushort getenv_VLAN(char *);
/* copy a filename (allow for "..." notation, limit length) */ -extern void copy_filename(char *dst, const char *src, int size); +void copy_filename(char *dst, const char *src, int size);
/* get a random source port */ -extern unsigned int random_port(void); +unsigned int random_port(void);
/* Update U-Boot over TFTP */ -extern int update_tftp(ulong addr); +int update_tftp(ulong addr);
/**********************************************************************/

On 27 January 2015 at 16:27, Joe Hershberger joe.hershberger@ni.com wrote:
Many of the functions in net.h were preceded extern needlessly. Removing them to limit the number of checkpatch.pl complaints.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
include/net.h | 96 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 48 insertions(+), 48 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

Move some things around and organize things so that the driver model implementation will fit in more easily.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com ---
include/net.h | 63 +++++++++++++++++++++++++------------------------ net/eth.c | 75 +++++++++++++++++++++++++++++++---------------------------- 2 files changed, 73 insertions(+), 65 deletions(-)
diff --git a/include/net.h b/include/net.h index ff8b7af..7eef9cc 100644 --- a/include/net.h +++ b/include/net.h @@ -100,10 +100,7 @@ struct eth_device { int eth_initialize(bd_t *bis); /* Initialize network subsystem */ int eth_register(struct eth_device *dev);/* Register network device */ int eth_unregister(struct eth_device *dev);/* Remove network device */ -void eth_try_another(int first_restart); /* Change the device */ -void eth_set_current(void); /* set nterface to ethcur var */
-/* get the current device MAC */ extern struct eth_device *eth_current;
static inline __attribute__((always_inline)) @@ -112,6 +109,7 @@ struct eth_device *eth_get_dev(void) return eth_current; }
+/* get the current device MAC */ static inline unsigned char *eth_get_ethaddr(void) { if (eth_current) @@ -119,6 +117,37 @@ static inline unsigned char *eth_get_ethaddr(void) return NULL; }
+/* Set active state */ +static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) +{ + eth_get_dev()->state = ETH_STATE_ACTIVE; + + return 0; +} +/* Set passive state */ +static inline __attribute__((always_inline)) void eth_halt_state_only(void) +{ + eth_get_dev()->state = ETH_STATE_PASSIVE; +} + +/* + * Set the hardware address for an ethernet interface based on 'eth%daddr' + * environment variable (or just 'ethaddr' if eth_number is 0). + * Args: + * base_name - base name for device (normally "eth") + * eth_number - value of %d (0 for first device of this type) + * Returns: + * 0 is success, non-zero is error status from driver. + */ +int eth_write_hwaddr(struct eth_device *dev, const char *base_name, + int eth_number); + +int usb_eth_initialize(bd_t *bi); +#endif + +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */ + struct eth_device *eth_get_dev_by_name(const char *devname); struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ int eth_get_dev_index(void); /* get the device index */ @@ -138,7 +167,6 @@ int eth_setenv_enetaddr(char *name, const uchar *enetaddr); int eth_getenv_enetaddr_by_index(const char *base_name, int index, uchar *enetaddr);
-int usb_eth_initialize(bd_t *bi); int eth_init(bd_t *bis); /* Initialize the device */ int eth_send(void *packet, int length); /* Send a packet */
@@ -148,32 +176,7 @@ void (*push_packet)(void *packet, int length); #endif int eth_rx(void); /* Check for received packets */ void eth_halt(void); /* stop SCC */ -char *eth_get_name(void); /* get name of current device */ - -/* Set active state */ -static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) -{ - eth_get_dev()->state = ETH_STATE_ACTIVE; - - return 0; -} -/* Set passive state */ -static inline __attribute__((always_inline)) void eth_halt_state_only(void) -{ - eth_get_dev()->state = ETH_STATE_PASSIVE; -} - -/* - * Set the hardware address for an ethernet interface based on 'eth%daddr' - * environment variable (or just 'ethaddr' if eth_number is 0). - * Args: - * base_name - base name for device (normally "eth") - * eth_number - value of %d (0 for first device of this type) - * Returns: - * 0 is success, non-zero is error status from driver. - */ -int eth_write_hwaddr(struct eth_device *dev, const char *base_name, - int eth_number); +const char *eth_get_name(void); /* get name of current device */
#ifdef CONFIG_MCAST_TFTP int eth_mcast_join(IPaddr_t mcast_addr, u8 join); diff --git a/net/eth.c b/net/eth.c index 65e8c77..c02548c 100644 --- a/net/eth.c +++ b/net/eth.c @@ -55,6 +55,14 @@ static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index, return eth_setenv_enetaddr(enetvar, enetaddr); }
+static void eth_env_init(void) +{ + const char *s; + + s = getenv("bootfile"); + if (s != NULL) + copy_filename(BootFile, s, sizeof(BootFile)); +}
static int eth_mac_skip(int index) { @@ -87,6 +95,11 @@ static unsigned int eth_rcv_current, eth_rcv_last; static struct eth_device *eth_devices; struct eth_device *eth_current;
+static void eth_set_current_to_next(void) +{ + eth_current = eth_current->next; +} + struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -137,22 +150,6 @@ int eth_get_dev_index(void) return eth_current->index; }
-static void eth_current_changed(void) -{ - char *act = getenv("ethact"); - /* update current ethernet name */ - if (eth_current) { - if (act == NULL || strcmp(act, eth_current->name) != 0) - setenv("ethact", eth_current->name); - } - /* - * remove the variable completely if there is no active - * interface - */ - else if (act != NULL) - setenv("ethact", NULL); -} - int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -251,14 +248,6 @@ int eth_unregister(struct eth_device *dev) return 0; }
-static void eth_env_init(bd_t *bis) -{ - const char *s; - - if ((s = getenv("bootfile")) != NULL) - copy_filename(BootFile, s, sizeof(BootFile)); -} - int eth_initialize(bd_t *bis) { int num_devices = 0; @@ -479,6 +468,22 @@ int eth_receive(void *packet, int length) } #endif /* CONFIG_API */
+static void eth_current_changed(void) +{ + char *act = getenv("ethact"); + /* update current ethernet name */ + if (eth_get_dev()) { + if (act == NULL || strcmp(act, eth_get_name()) != 0) + setenv("ethact", eth_get_name()); + } + /* + * remove the variable completely if there is no active + * interface + */ + else if (act != NULL) + setenv("ethact", NULL); +} + void eth_try_another(int first_restart) { static struct eth_device *first_failed; @@ -492,17 +497,17 @@ void eth_try_another(int first_restart) if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) return;
- if (!eth_current) + if (!eth_get_dev()) return;
if (first_restart) - first_failed = eth_current; + first_failed = eth_get_dev();
- eth_current = eth_current->next; + eth_set_current_to_next();
eth_current_changed();
- if (first_failed == eth_current) + if (first_failed == eth_get_dev()) NetRestartWrap = 1; }
@@ -513,7 +518,7 @@ void eth_set_current(void) struct eth_device *old_current; int env_id;
- if (!eth_current) /* XXX no current */ + if (!eth_get_dev()) /* XXX no current */ return;
env_id = get_env_id(); @@ -522,18 +527,18 @@ void eth_set_current(void) env_changed_id = env_id; } if (act != NULL) { - old_current = eth_current; + old_current = eth_get_dev(); do { - if (strcmp(eth_current->name, act) == 0) + if (strcmp(eth_get_name(), act) == 0) return; - eth_current = eth_current->next; - } while (old_current != eth_current); + eth_set_current_to_next(); + } while (old_current != eth_get_dev()); }
eth_current_changed(); }
-char *eth_get_name(void) +const char *eth_get_name(void) { - return eth_current ? eth_current->name : "unknown"; + return eth_get_dev() ? eth_get_dev()->name : "unknown"; }

On 27 January 2015 at 16:27, Joe Hershberger joe.hershberger@ni.com wrote:
Move some things around and organize things so that the driver model implementation will fit in more easily.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
include/net.h | 63 +++++++++++++++++++++++++------------------------ net/eth.c | 75 +++++++++++++++++++++++++++++++---------------------------- 2 files changed, 73 insertions(+), 65 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

First just add support for MAC drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com ---
common/board_r.c | 4 +- common/cmd_bdinfo.c | 2 + include/dm/uclass-id.h | 1 + include/net.h | 23 ++++ net/eth.c | 320 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 346 insertions(+), 4 deletions(-)
diff --git a/common/board_r.c b/common/board_r.c index a301cc2..9a41cae 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -572,7 +572,7 @@ static int initr_bbmii(void) } #endif
-#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) static int initr_net(void) { puts("Net: "); @@ -841,7 +841,7 @@ init_fnc_t init_sequence_r[] = { #ifdef CONFIG_BITBANGMII initr_bbmii, #endif -#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) INIT_FUNC_WATCHDOG_RESET initr_net, #endif diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index e6d8a7a..8688cf9 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index f17c3c2..b04cbc9 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -33,6 +33,7 @@ enum uclass_id { UCLASS_I2C, /* I2C bus */ UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ + UCLASS_ETH, /* Network device */
UCLASS_COUNT, UCLASS_INVALID = -1, diff --git a/include/net.h b/include/net.h index 7eef9cc..25636e2 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,29 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH +struct eth_pdata { + phys_addr_t iobase; +}; + +struct eth_ops { + int (*init)(struct udevice *dev, bd_t *bis); + int (*send)(struct udevice *dev, void *packet, int length); + int (*recv)(struct udevice *dev); + void (*halt)(struct udevice *dev); +#ifdef CONFIG_MCAST_TFTP + int (*mcast)(struct udevice *dev, const u8 *enetaddr, u8 set); +#endif + int (*write_hwaddr)(struct udevice *dev); +}; + +struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +int eth_init_state_only(bd_t *bis); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ +#endif + +#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; diff --git a/net/eth.c b/net/eth.c index c02548c..d245b65 100644 --- a/net/eth.c +++ b/net/eth.c @@ -72,6 +72,321 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void); + +#ifdef CONFIG_DM_ETH +#include <dm.h> + +struct eth_device_priv { + unsigned char enetaddr[6]; + int state; + int index; + void *priv; +}; + +struct eth_uclass_priv { + struct udevice *current; + int max_index; +}; + +static void eth_set_current_to_next(void) +{ + struct uclass *uc; + struct eth_uclass_priv *priv; + + uclass_get(UCLASS_ETH, &uc); + priv = uc->priv; + uclass_next_device(&(priv->current)); + if (!priv->current) + uclass_first_device(UCLASS_ETH, &(priv->current)); +} + +struct udevice *eth_get_dev(void) +{ + struct uclass *uc; + uclass_get(UCLASS_ETH, &uc); + + struct eth_uclass_priv *priv = uc->priv; + return priv->current; +} + +static void eth_set_dev(struct udevice *dev) +{ + struct uclass *uc; + uclass_get(UCLASS_ETH, &uc); + + struct eth_uclass_priv *priv = uc->priv; + priv->current = dev; +} + +unsigned char *eth_get_ethaddr(void) +{ + struct eth_device_priv *priv; + if (eth_get_dev()) { + priv = eth_get_dev()->uclass_priv; + if (priv) + return priv->enetaddr; + } + return NULL; +} + +/* Set active state */ +int eth_init_state_only(bd_t *bis) +{ + struct eth_device_priv *priv; + if (eth_get_dev()) { + priv = eth_get_dev()->uclass_priv; + if (priv) + priv->state = ETH_STATE_ACTIVE; + } + + return 0; +} +/* Set passive state */ +void eth_halt_state_only(void) +{ + struct eth_device_priv *priv; + if (eth_get_dev()) { + priv = eth_get_dev()->uclass_priv; + if (priv) + priv->state = ETH_STATE_PASSIVE; + } +} + +int eth_get_dev_index(void) +{ + struct eth_device_priv *priv; + if (eth_get_dev()) { + priv = eth_get_dev()->uclass_priv; + if (priv) + return priv->index; + } + return -1; +} + +int eth_init(bd_t *bis) +{ + struct udevice *current, *old_current, *dev; + struct uclass *uc; + + current = eth_get_dev(); + if (!current) { + puts("No ethernet found.\n"); + return -1; + } + + /* Sync environment with network devices */ + uclass_get(UCLASS_ETH, &uc); + uclass_foreach_dev(dev, uc) { + uchar env_enetaddr[6]; + + if (eth_getenv_enetaddr_by_index("eth", dev->seq, + env_enetaddr)) { + struct eth_device_priv *priv = dev->uclass_priv; + if (priv) + memcpy(priv->enetaddr, env_enetaddr, 6); + } + }; + + old_current = current; + do { + debug("Trying %s\n", current->name); + + if (current->driver) { + const struct eth_ops *ops = current->driver->ops; + if (ops->init(current, bis) >= 0) { + struct eth_device_priv *priv = + current->uclass_priv; + if (priv) + priv->state = ETH_STATE_ACTIVE; + + return 0; + } + } + debug("FAIL\n"); + + eth_try_another(0); + current = eth_get_dev(); + } while (old_current != current); + + return -1; +} + +void eth_halt(void) +{ + struct udevice *current; + + current = eth_get_dev(); + if (!current) + return; + if (!current->driver) + return; + + const struct eth_ops *ops = current->driver->ops; + ops->halt(current); + + struct eth_device_priv *priv = current->uclass_priv; + if (priv) + priv->state = ETH_STATE_PASSIVE; +} + +int eth_send(void *packet, int length) +{ + struct udevice *current; + + current = eth_get_dev(); + if (!current) + return -1; + if (!current->driver) + return -1; + + const struct eth_ops *ops = current->driver->ops; + return ops->send(current, packet, length); +} + +int eth_rx(void) +{ + struct udevice *current; + + current = eth_get_dev(); + if (!current) + return -1; + if (!current->driver) + return -1; + + const struct eth_ops *ops = current->driver->ops; + return ops->recv(current); +} + +static int eth_write_hwaddr(struct udevice *dev, const char *base_name, + int eth_number) +{ + unsigned char env_enetaddr[6]; + int ret = 0; + + eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr); + + struct eth_device_priv *priv = dev->uclass_priv; + if (!is_zero_ether_addr(env_enetaddr)) { + if (!is_zero_ether_addr(priv->enetaddr) && + memcmp(priv->enetaddr, env_enetaddr, 6)) { + printf("\nWarning: %s MAC addresses don't match:\n", + dev->name); + printf("Address in SROM is %pM\n", + priv->enetaddr); + printf("Address in environment is %pM\n", + env_enetaddr); + } + + memcpy(priv->enetaddr, env_enetaddr, 6); + } else if (is_valid_ether_addr(priv->enetaddr)) { + eth_setenv_enetaddr_by_index(base_name, eth_number, + priv->enetaddr); + printf("\nWarning: %s using MAC address from net device\n", + dev->name); + } else if (is_zero_ether_addr(priv->enetaddr)) { + printf("\nError: %s address not set.\n", + dev->name); + return -EINVAL; + } + + const struct eth_ops *ops = dev->driver->ops; + if (ops->write_hwaddr && !eth_mac_skip(eth_number)) { + if (!is_valid_ether_addr(priv->enetaddr)) { + printf("\nError: %s address %pM illegal value\n", + dev->name, priv->enetaddr); + return -EINVAL; + } + + ret = ops->write_hwaddr(dev); + if (ret) + printf("\nWarning: %s failed to set MAC address\n", + dev->name); + } + + return ret; +} + +static int eth_uclass_init(struct uclass *class) +{ + bootstage_mark(BOOTSTAGE_ID_NET_ETH_START); + + struct eth_uclass_priv *priv = class->priv; + priv->max_index = 0; + + eth_env_init(); + + return 0; +} + +static int eth_post_bind(struct udevice *dev) +{ + struct udevice *first; + + uclass_first_device(UCLASS_ETH, &first); + if (first == dev) { + eth_current_changed(); + eth_set_dev(dev); + } + + struct eth_device_priv *priv = dev->uclass_priv; + struct eth_uclass_priv *uclass_priv = dev->uclass->priv; + if (priv) { + priv->state = ETH_STATE_INIT; + priv->index = uclass_priv->max_index++; + } + + return 0; +} + +static int eth_pre_unbind(struct udevice *dev) +{ + struct udevice *first; + struct udevice *current; + + current = eth_get_dev(); + uclass_first_device(UCLASS_ETH, &first); + if (current == dev) { + if (dev == first) + uclass_next_device(¤t); + else + current = first; + eth_current_changed(); + eth_set_dev(current); + } + + return 0; +} + +static int eth_post_probe(struct udevice *dev) +{ + char *ethprime = getenv("ethprime"); + if (ethprime && strcmp(dev->name, ethprime) == 0) + eth_set_dev(dev); + + if (strchr(dev->name, ' ')) + printf("\nWarning: eth device name "%s" has a space!\n", + dev->name); + + struct eth_device_priv *priv = dev->uclass_priv; + if (priv) + return eth_write_hwaddr(dev, "eth", priv->index); + return 1; +} + +UCLASS_DRIVER(eth) = { + .name = "eth", + .id = UCLASS_ETH, + .post_bind = eth_post_bind, + .pre_unbind = eth_pre_unbind, + .post_probe = eth_post_probe, + .init = eth_uclass_init, + .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), + .per_device_auto_alloc_size = sizeof(struct eth_device_priv), +}; +#endif + +#ifndef CONFIG_DM_ETH /* * CPU and board-specific Ethernet initializations. Aliased function * signals caller to move on @@ -423,6 +738,7 @@ int eth_rx(void)
return eth_current->recv(eth_current); } +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -486,7 +802,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) { - static struct eth_device *first_failed; + static void *first_failed; char *ethrotate;
/* @@ -515,7 +831,7 @@ void eth_set_current(void) { static char *act; static int env_changed_id; - struct eth_device *old_current; + void *old_current; int env_id;
if (!eth_get_dev()) /* XXX no current */

Hi Joe,
On 27 January 2015 at 16:27, Joe Hershberger joe.hershberger@ni.com wrote:
First just add support for MAC drivers.
I don't fully understand this partly because my knowledge of the network stack is limited. So I'll make a few comments and we can go from there.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
common/board_r.c | 4 +- common/cmd_bdinfo.c | 2 + include/dm/uclass-id.h | 1 + include/net.h | 23 ++++ net/eth.c | 320 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 346 insertions(+), 4 deletions(-)
diff --git a/common/board_r.c b/common/board_r.c index a301cc2..9a41cae 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -572,7 +572,7 @@ static int initr_bbmii(void) } #endif
-#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) static int initr_net(void) { puts("Net: "); @@ -841,7 +841,7 @@ init_fnc_t init_sequence_r[] = { #ifdef CONFIG_BITBANGMII initr_bbmii, #endif -#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) INIT_FUNC_WATCHDOG_RESET initr_net, #endif diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index e6d8a7a..8688cf9 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index f17c3c2..b04cbc9 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -33,6 +33,7 @@ enum uclass_id { UCLASS_I2C, /* I2C bus */ UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */
UCLASS_ETH, /* Network device */
Ethernet device?
UCLASS_COUNT, UCLASS_INVALID = -1,
diff --git a/include/net.h b/include/net.h index 7eef9cc..25636e2 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,29 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH +struct eth_pdata {
phys_addr_t iobase;
+};
+struct eth_ops {
int (*init)(struct udevice *dev, bd_t *bis);
int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev);
void (*halt)(struct udevice *dev);
+#ifdef CONFIG_MCAST_TFTP
int (*mcast)(struct udevice *dev, const u8 *enetaddr, u8 set);
+#endif
int (*write_hwaddr)(struct udevice *dev);
+};
+struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +int eth_init_state_only(bd_t *bis); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ +#endif
+#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; diff --git a/net/eth.c b/net/eth.c index c02548c..d245b65 100644 --- a/net/eth.c +++ b/net/eth.c @@ -72,6 +72,321 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH +#include <dm.h>
+struct eth_device_priv {
unsigned char enetaddr[6];
int state;
int index;
void *priv;
Suggestion: you could have per-child platform data as well as per-child private data. See u-boot-dm/master for this. It is used for I2C and SPI to hold the address of the child on the bus.
You could use it to hold the MAC address. I think this *might* be better because the MAC address can then be set and retained even when the device is probed/removed.
+};
+struct eth_uclass_priv {
struct udevice *current;
int max_index;
+};
+static void eth_set_current_to_next(void) +{
struct uclass *uc;
struct eth_uclass_priv *priv;
uclass_get(UCLASS_ETH, &uc);
priv = uc->priv;
uclass_next_device(&(priv->current));
Note that this will probe the device. I think you are storing the current ethernet device in the uclass, but you could just as well have a static variable in this file if that is easier.
(Also remove internal brackets)
If priv->current is NULL, this will die.
Also to avoid confusion I think you should use uc_priv for the uclass priv local variable, to distinguish it from priv.
if (!priv->current)
uclass_first_device(UCLASS_ETH, &(priv->current));
If I understand this correctly, I think you want:
if (priv->current) uclass_next_device(&priv->current) else uclass_first_device(uc, &priv->current)
+}
+struct udevice *eth_get_dev(void) +{
struct uclass *uc;
uclass_get(UCLASS_ETH, &uc);
struct eth_uclass_priv *priv = uc->priv;
This is OK so long as the device has been probed. I think it always is because you use uclass_next_device() to get the device.
return priv->current;
+}
+static void eth_set_dev(struct udevice *dev) +{
struct uclass *uc;
uclass_get(UCLASS_ETH, &uc);
struct eth_uclass_priv *priv = uc->priv;
priv->current = dev;
+}
+unsigned char *eth_get_ethaddr(void) +{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
This check should be unnecessary. Same in other cases below.
return priv->enetaddr;
}
return NULL;
+}
+/* Set active state */ +int eth_init_state_only(bd_t *bis) +{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_ACTIVE;
}
return 0;
+} +/* Set passive state */ +void eth_halt_state_only(void) +{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
}
+}
+int eth_get_dev_index(void) +{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
return priv->index;
}
return -1;
+}
+int eth_init(bd_t *bis) +{
struct udevice *current, *old_current, *dev;
struct uclass *uc;
current = eth_get_dev();
if (!current) {
puts("No ethernet found.\n");
return -1;
}
/* Sync environment with network devices */
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(dev, uc) {
uchar env_enetaddr[6];
if (eth_getenv_enetaddr_by_index("eth", dev->seq,
env_enetaddr)) {
struct eth_device_priv *priv = dev->uclass_priv;
if (priv)
memcpy(priv->enetaddr, env_enetaddr, 6);
}
};
old_current = current;
do {
debug("Trying %s\n", current->name);
if (current->driver) {
const struct eth_ops *ops = current->driver->ops;
if (ops->init(current, bis) >= 0) {
struct eth_device_priv *priv =
current->uclass_priv;
if (priv)
priv->state = ETH_STATE_ACTIVE;
return 0;
}
}
debug("FAIL\n");
eth_try_another(0);
current = eth_get_dev();
} while (old_current != current);
return -1;
-ENODEV?
+}
+void eth_halt(void) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return;
if (!current->driver)
return;
const struct eth_ops *ops = current->driver->ops;
ops->halt(current);
struct eth_device_priv *priv = current->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
+}
+int eth_send(void *packet, int length) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
const struct eth_ops *ops = current->driver->ops;
return ops->send(current, packet, length);
+}
As a general comment, there is an implicit assumption that only one device can be active at a time. I suppose that is a U-Boot limitation, but we don't need to keep it for driver model, or at least we could permit multiple devices to be probed at a time.
But still I wonder if you should have functions that are passed a udevice, like eth_rx(struct udevice *dev).
+int eth_rx(void) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
const struct eth_ops *ops = current->driver->ops;
return ops->recv(current);
+}
+static int eth_write_hwaddr(struct udevice *dev, const char *base_name,
int eth_number)
+{
unsigned char env_enetaddr[6];
int ret = 0;
eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
struct eth_device_priv *priv = dev->uclass_priv;
if (!is_zero_ether_addr(env_enetaddr)) {
if (!is_zero_ether_addr(priv->enetaddr) &&
memcmp(priv->enetaddr, env_enetaddr, 6)) {
printf("\nWarning: %s MAC addresses don't match:\n",
dev->name);
printf("Address in SROM is %pM\n",
priv->enetaddr);
printf("Address in environment is %pM\n",
env_enetaddr);
}
memcpy(priv->enetaddr, env_enetaddr, 6);
} else if (is_valid_ether_addr(priv->enetaddr)) {
eth_setenv_enetaddr_by_index(base_name, eth_number,
priv->enetaddr);
printf("\nWarning: %s using MAC address from net device\n",
dev->name);
} else if (is_zero_ether_addr(priv->enetaddr)) {
printf("\nError: %s address not set.\n",
dev->name);
return -EINVAL;
}
const struct eth_ops *ops = dev->driver->ops;
if (ops->write_hwaddr && !eth_mac_skip(eth_number)) {
if (!is_valid_ether_addr(priv->enetaddr)) {
printf("\nError: %s address %pM illegal value\n",
dev->name, priv->enetaddr);
return -EINVAL;
}
ret = ops->write_hwaddr(dev);
if (ret)
printf("\nWarning: %s failed to set MAC address\n",
dev->name);
}
return ret;
+}
+static int eth_uclass_init(struct uclass *class) +{
bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
struct eth_uclass_priv *priv = class->priv;
priv->max_index = 0;
What is max_index used for?
eth_env_init();
return 0;
+}
+static int eth_post_bind(struct udevice *dev) +{
struct udevice *first;
uclass_first_device(UCLASS_ETH, &first);
if (first == dev) {
eth_current_changed();
eth_set_dev(dev);
}
struct eth_device_priv *priv = dev->uclass_priv;
struct eth_uclass_priv *uclass_priv = dev->uclass->priv;
if (priv) {
priv->state = ETH_STATE_INIT;
priv->index = uclass_priv->max_index++;
OK I see it is the number of devices. Does this ever decrease?
Anyway, struct udevice has a seq member which can give every device a unique sequence number in the uclass automatically (and if you define DM_UC_FLAG_SEQ_ALIAS then the device tree aliases can provide this numbering)
Otherwise I'm not sure what this function is trying to do.
}
return 0;
+}
+static int eth_pre_unbind(struct udevice *dev) +{
struct udevice *first;
struct udevice *current;
current = eth_get_dev();
uclass_first_device(UCLASS_ETH, &first);
if (current == dev) {
if (dev == first)
uclass_next_device(¤t);
else
current = first;
eth_current_changed();
eth_set_dev(current);
}
I'm not sure what this function is trying to do.
return 0;
+}
+static int eth_post_probe(struct udevice *dev) +{
char *ethprime = getenv("ethprime");
if (ethprime && strcmp(dev->name, ethprime) == 0)
eth_set_dev(dev);
What does this do?
if (strchr(dev->name, ' '))
printf("\nWarning: eth device name \"%s\" has a space!\n",
dev->name);
BTW if this is an error you could refuse to bind it - e.g. in the eth_post_bind, return -EINVAL
struct eth_device_priv *priv = dev->uclass_priv;
if (priv)
return eth_write_hwaddr(dev, "eth", priv->index);
return 1;
+}
+UCLASS_DRIVER(eth) = {
.name = "eth",
.id = UCLASS_ETH,
.post_bind = eth_post_bind,
.pre_unbind = eth_pre_unbind,
.post_probe = eth_post_probe,
.init = eth_uclass_init,
.priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
.per_device_auto_alloc_size = sizeof(struct eth_device_priv),
+}; +#endif
+#ifndef CONFIG_DM_ETH /*
- CPU and board-specific Ethernet initializations. Aliased function
- signals caller to move on
@@ -423,6 +738,7 @@ int eth_rx(void)
return eth_current->recv(eth_current);
} +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -486,7 +802,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) {
static struct eth_device *first_failed;
static void *first_failed; char *ethrotate; /*
@@ -515,7 +831,7 @@ void eth_set_current(void) { static char *act; static int env_changed_id;
struct eth_device *old_current;
void *old_current; int env_id; if (!eth_get_dev()) /* XXX no current */
-- 1.7.11.5
Regards, Simon

On Tue, Jan 27, 2015 at 8:34 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 27 January 2015 at 16:27, Joe Hershberger joe.hershberger@ni.com
wrote:
First just add support for MAC drivers.
I don't fully understand this partly because my knowledge of the network stack is limited. So I'll make a few comments and we can go from there.
Sounds good.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
common/board_r.c | 4 +- common/cmd_bdinfo.c | 2 + include/dm/uclass-id.h | 1 + include/net.h | 23 ++++ net/eth.c | 320
++++++++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 346 insertions(+), 4 deletions(-)
diff --git a/common/board_r.c b/common/board_r.c index a301cc2..9a41cae 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -572,7 +572,7 @@ static int initr_bbmii(void) } #endif
-#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) static int initr_net(void) { puts("Net: "); @@ -841,7 +841,7 @@ init_fnc_t init_sequence_r[] = { #ifdef CONFIG_BITBANGMII initr_bbmii, #endif -#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) INIT_FUNC_WATCHDOG_RESET initr_net, #endif diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index e6d8a7a..8688cf9 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index f17c3c2..b04cbc9 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -33,6 +33,7 @@ enum uclass_id { UCLASS_I2C, /* I2C bus */ UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */
UCLASS_ETH, /* Network device */
Ethernet device?
Sure.
UCLASS_COUNT, UCLASS_INVALID = -1,
diff --git a/include/net.h b/include/net.h index 7eef9cc..25636e2 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,29 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH +struct eth_pdata {
phys_addr_t iobase;
+};
+struct eth_ops {
int (*init)(struct udevice *dev, bd_t *bis);
int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev);
void (*halt)(struct udevice *dev);
+#ifdef CONFIG_MCAST_TFTP
int (*mcast)(struct udevice *dev, const u8 *enetaddr, u8 set);
+#endif
int (*write_hwaddr)(struct udevice *dev);
+};
+struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +int eth_init_state_only(bd_t *bis); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ +#endif
+#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; diff --git a/net/eth.c b/net/eth.c index c02548c..d245b65 100644 --- a/net/eth.c +++ b/net/eth.c @@ -72,6 +72,321 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH +#include <dm.h>
+struct eth_device_priv {
unsigned char enetaddr[6];
int state;
int index;
void *priv;
Suggestion: you could have per-child platform data as well as per-child private data. See u-boot-dm/master for this. It is used for I2C and SPI to hold the address of the child on the bus.
You could use it to hold the MAC address. I think this *might* be better because the MAC address can then be set and retained even when the device is probed/removed.
So in net.h you'll see that I have a platdata structure as well... the reason I didn't put the MAC address in there is that the data is not sourced from the device tree or the platform data in general. It either comes from the env (default) or it is read from the network MAC's eeprom. I'll need a little more convincing that the MAC should move.
+};
+struct eth_uclass_priv {
struct udevice *current;
int max_index;
+};
+static void eth_set_current_to_next(void) +{
struct uclass *uc;
struct eth_uclass_priv *priv;
uclass_get(UCLASS_ETH, &uc);
priv = uc->priv;
uclass_next_device(&(priv->current));
Note that this will probe the device. I think you are storing the current ethernet device in the uclass, but you could just as well have a static variable in this file if that is easier.
I started out using a static variable for the current device, but other code in u-boot uses the current device (via the eth_get_dev() function) and I want it to not require and extern to a non-static variable.
(Also remove internal brackets)
Yes... forgot to clean this up.
If priv->current is NULL, this will die.
This function should not get called if priv->current is NULL.
Also to avoid confusion I think you should use uc_priv for the uclass priv local variable, to distinguish it from priv.
OK.
if (!priv->current)
uclass_first_device(UCLASS_ETH, &(priv->current));
If I understand this correctly, I think you want:
if (priv->current) uclass_next_device(&priv->current) else uclass_first_device(uc, &priv->current)
No... I'm not switching on priv->current being NULL... I get the next, and then if THAT is NULL, I start at the beginning. priv->current must never be NULL (outside of this transition).
This is emulating the behavior that used to exist where the linked list instead of terminating linked back to the head. This way we always cycle through all adapters and never stop.
+}
+struct udevice *eth_get_dev(void) +{
struct uclass *uc;
uclass_get(UCLASS_ETH, &uc);
struct eth_uclass_priv *priv = uc->priv;
This is OK so long as the device has been probed. I think it always is because you use uclass_next_device() to get the device.
Why would the device being probed have any relationship with the priv in the uclass itself? I would expect the uclass priv to be there regardless. This is not the per-device uc_priv.
return priv->current;
+}
+static void eth_set_dev(struct udevice *dev) +{
struct uclass *uc;
uclass_get(UCLASS_ETH, &uc);
struct eth_uclass_priv *priv = uc->priv;
priv->current = dev;
+}
+unsigned char *eth_get_ethaddr(void) +{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
This check should be unnecessary. Same in other cases below.
So this is guaranteed? In all cases? I ran into some pre-allocated buffers that don't get created if post_probe returns an error, for instance.
return priv->enetaddr;
}
return NULL;
+}
+/* Set active state */ +int eth_init_state_only(bd_t *bis) +{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_ACTIVE;
}
return 0;
+} +/* Set passive state */ +void eth_halt_state_only(void) +{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
}
+}
+int eth_get_dev_index(void) +{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
return priv->index;
}
return -1;
+}
+int eth_init(bd_t *bis) +{
struct udevice *current, *old_current, *dev;
struct uclass *uc;
current = eth_get_dev();
if (!current) {
puts("No ethernet found.\n");
return -1;
}
/* Sync environment with network devices */
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(dev, uc) {
uchar env_enetaddr[6];
if (eth_getenv_enetaddr_by_index("eth", dev->seq,
env_enetaddr)) {
struct eth_device_priv *priv = dev->uclass_priv;
if (priv)
memcpy(priv->enetaddr, env_enetaddr, 6);
}
};
old_current = current;
do {
debug("Trying %s\n", current->name);
if (current->driver) {
const struct eth_ops *ops =
current->driver->ops;
if (ops->init(current, bis) >= 0) {
struct eth_device_priv *priv =
current->uclass_priv;
if (priv)
priv->state = ETH_STATE_ACTIVE;
return 0;
}
}
debug("FAIL\n");
eth_try_another(0);
current = eth_get_dev();
} while (old_current != current);
return -1;
-ENODEV?
OK.
+}
+void eth_halt(void) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return;
if (!current->driver)
return;
const struct eth_ops *ops = current->driver->ops;
ops->halt(current);
struct eth_device_priv *priv = current->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
+}
+int eth_send(void *packet, int length) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
const struct eth_ops *ops = current->driver->ops;
return ops->send(current, packet, length);
+}
As a general comment, there is an implicit assumption that only one device can be active at a time. I suppose that is a U-Boot limitation, but we don't need to keep it for driver model, or at least we could permit multiple devices to be probed at a time.
I agree that longer term we should look for ways to remove that limitation, but for now everything that uses the network assumes that the "ethact" env var selects the device. There would be a lot of commands to break compatibility with to allow them to specify the device. I say we hold off on that for now.
But still I wonder if you should have functions that are passed a udevice, like eth_rx(struct udevice *dev).
Even if those functions did, the commands would need to change too. Future enhancement, I think.
+int eth_rx(void) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
const struct eth_ops *ops = current->driver->ops;
return ops->recv(current);
+}
+static int eth_write_hwaddr(struct udevice *dev, const char *base_name,
int eth_number)
+{
unsigned char env_enetaddr[6];
int ret = 0;
eth_getenv_enetaddr_by_index(base_name, eth_number,
env_enetaddr);
struct eth_device_priv *priv = dev->uclass_priv;
if (!is_zero_ether_addr(env_enetaddr)) {
if (!is_zero_ether_addr(priv->enetaddr) &&
memcmp(priv->enetaddr, env_enetaddr, 6)) {
printf("\nWarning: %s MAC addresses don't
match:\n",
dev->name);
printf("Address in SROM is %pM\n",
priv->enetaddr);
printf("Address in environment is %pM\n",
env_enetaddr);
}
memcpy(priv->enetaddr, env_enetaddr, 6);
} else if (is_valid_ether_addr(priv->enetaddr)) {
eth_setenv_enetaddr_by_index(base_name, eth_number,
priv->enetaddr);
printf("\nWarning: %s using MAC address from net
device\n",
dev->name);
} else if (is_zero_ether_addr(priv->enetaddr)) {
printf("\nError: %s address not set.\n",
dev->name);
return -EINVAL;
}
const struct eth_ops *ops = dev->driver->ops;
if (ops->write_hwaddr && !eth_mac_skip(eth_number)) {
if (!is_valid_ether_addr(priv->enetaddr)) {
printf("\nError: %s address %pM illegal
value\n",
dev->name, priv->enetaddr);
return -EINVAL;
}
ret = ops->write_hwaddr(dev);
if (ret)
printf("\nWarning: %s failed to set MAC
address\n",
dev->name);
}
return ret;
+}
+static int eth_uclass_init(struct uclass *class) +{
bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
struct eth_uclass_priv *priv = class->priv;
priv->max_index = 0;
What is max_index used for?
For knowing the number of devices that have been bound and allocating the next unused index for the next device.
eth_env_init();
return 0;
+}
+static int eth_post_bind(struct udevice *dev) +{
struct udevice *first;
uclass_first_device(UCLASS_ETH, &first);
if (first == dev) {
eth_current_changed();
eth_set_dev(dev);
}
struct eth_device_priv *priv = dev->uclass_priv;
struct eth_uclass_priv *uclass_priv = dev->uclass->priv;
if (priv) {
priv->state = ETH_STATE_INIT;
priv->index = uclass_priv->max_index++;
OK I see it is the number of devices. Does this ever decrease?
Never decreases.
Anyway, struct udevice has a seq member which can give every device a unique sequence number in the uclass automatically (and if you define DM_UC_FLAG_SEQ_ALIAS then the device tree aliases can provide this numbering)
I actually used the seq number originally and that worked fine with platdata. When I moved to the device tree, that's where it fell apart. In the device tree, it is expected that the eth name will include an eth@baseaddr format. The DM code then takes that value that is the baseaddr and sets it as the requested seq. That means I get eth268443648 instead of eth0. No good. So now I keep track of my own seq (index) to make sure I get consistent device names.
Otherwise I'm not sure what this function is trying to do.
I needs to initialize the priv->current variable so that everything that tries to use the network finds a current eth device. It also initializes the state variable, which is also important.
}
return 0;
+}
+static int eth_pre_unbind(struct udevice *dev) +{
struct udevice *first;
struct udevice *current;
current = eth_get_dev();
uclass_first_device(UCLASS_ETH, &first);
if (current == dev) {
if (dev == first)
uclass_next_device(¤t);
else
current = first;
eth_current_changed();
eth_set_dev(current);
}
I'm not sure what this function is trying to do.
Again, this is just ensuring the "current" variable is always valid.
return 0;
+}
+static int eth_post_probe(struct udevice *dev) +{
char *ethprime = getenv("ethprime");
if (ethprime && strcmp(dev->name, ethprime) == 0)
eth_set_dev(dev);
What does this do?
This allows the initial "current" device to be specified by they "ethprime" env var. This is preserving existing behaviors as controlled by these env vars.
if (strchr(dev->name, ' '))
printf("\nWarning: eth device name \"%s\" has a
space!\n",
dev->name);
BTW if this is an error you could refuse to bind it - e.g. in the eth_post_bind, return -EINVAL
Good idea.
struct eth_device_priv *priv = dev->uclass_priv;
if (priv)
return eth_write_hwaddr(dev, "eth", priv->index);
return 1;
+}
+UCLASS_DRIVER(eth) = {
.name = "eth",
.id = UCLASS_ETH,
.post_bind = eth_post_bind,
.pre_unbind = eth_pre_unbind,
.post_probe = eth_post_probe,
.init = eth_uclass_init,
.priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
.per_device_auto_alloc_size = sizeof(struct eth_device_priv),
+}; +#endif
+#ifndef CONFIG_DM_ETH /*
- CPU and board-specific Ethernet initializations. Aliased function
- signals caller to move on
@@ -423,6 +738,7 @@ int eth_rx(void)
return eth_current->recv(eth_current);
} +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -486,7 +802,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) {
static struct eth_device *first_failed;
static void *first_failed; char *ethrotate; /*
@@ -515,7 +831,7 @@ void eth_set_current(void) { static char *act; static int env_changed_id;
struct eth_device *old_current;
void *old_current; int env_id; if (!eth_get_dev()) /* XXX no current */
-- 1.7.11.5
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi Joe,
On 28 January 2015 at 03:22, Joe Hershberger joe.hershberger@gmail.com wrote:
On Tue, Jan 27, 2015 at 8:34 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 27 January 2015 at 16:27, Joe Hershberger joe.hershberger@ni.com wrote:
First just add support for MAC drivers.
I don't fully understand this partly because my knowledge of the network stack is limited. So I'll make a few comments and we can go from there.
Sounds good.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
common/board_r.c | 4 +- common/cmd_bdinfo.c | 2 + include/dm/uclass-id.h | 1 + include/net.h | 23 ++++ net/eth.c | 320 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 346 insertions(+), 4 deletions(-)
diff --git a/common/board_r.c b/common/board_r.c index a301cc2..9a41cae 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -572,7 +572,7 @@ static int initr_bbmii(void) } #endif
-#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) static int initr_net(void) { puts("Net: "); @@ -841,7 +841,7 @@ init_fnc_t init_sequence_r[] = { #ifdef CONFIG_BITBANGMII initr_bbmii, #endif -#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) INIT_FUNC_WATCHDOG_RESET initr_net, #endif diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index e6d8a7a..8688cf9 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index f17c3c2..b04cbc9 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -33,6 +33,7 @@ enum uclass_id { UCLASS_I2C, /* I2C bus */ UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */
UCLASS_ETH, /* Network device */
Ethernet device?
Sure.
UCLASS_COUNT, UCLASS_INVALID = -1,
diff --git a/include/net.h b/include/net.h index 7eef9cc..25636e2 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,29 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH +struct eth_pdata {
phys_addr_t iobase;
+};
+struct eth_ops {
int (*init)(struct udevice *dev, bd_t *bis);
int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev);
void (*halt)(struct udevice *dev);
+#ifdef CONFIG_MCAST_TFTP
int (*mcast)(struct udevice *dev, const u8 *enetaddr, u8 set);
+#endif
int (*write_hwaddr)(struct udevice *dev);
+};
+struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +int eth_init_state_only(bd_t *bis); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ +#endif
+#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; diff --git a/net/eth.c b/net/eth.c index c02548c..d245b65 100644 --- a/net/eth.c +++ b/net/eth.c @@ -72,6 +72,321 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH +#include <dm.h>
+struct eth_device_priv {
unsigned char enetaddr[6];
int state;
int index;
void *priv;
Suggestion: you could have per-child platform data as well as per-child private data. See u-boot-dm/master for this. It is used for I2C and SPI to hold the address of the child on the bus.
You could use it to hold the MAC address. I think this *might* be better because the MAC address can then be set and retained even when the device is probed/removed.
So in net.h you'll see that I have a platdata structure as well... the reason I didn't put the MAC address in there is that the data is not sourced from the device tree or the platform data in general. It either comes from the env (default) or it is read from the network MAC's eeprom. I'll need a little more convincing that the MAC should move.
OK. If it only exists when the device is active (probed) then that is fine.
+};
+struct eth_uclass_priv {
struct udevice *current;
int max_index;
+};
+static void eth_set_current_to_next(void) +{
struct uclass *uc;
struct eth_uclass_priv *priv;
uclass_get(UCLASS_ETH, &uc);
priv = uc->priv;
uclass_next_device(&(priv->current));
Note that this will probe the device. I think you are storing the current ethernet device in the uclass, but you could just as well have a static variable in this file if that is easier.
I started out using a static variable for the current device, but other code in u-boot uses the current device (via the eth_get_dev() function) and I want it to not require and extern to a non-static variable.
OK.
(Also remove internal brackets)
Yes... forgot to clean this up.
If priv->current is NULL, this will die.
This function should not get called if priv->current is NULL.
Also to avoid confusion I think you should use uc_priv for the uclass priv local variable, to distinguish it from priv.
OK.
if (!priv->current)
uclass_first_device(UCLASS_ETH, &(priv->current));
If I understand this correctly, I think you want:
if (priv->current) uclass_next_device(&priv->current) else uclass_first_device(uc, &priv->current)
No... I'm not switching on priv->current being NULL... I get the next, and then if THAT is NULL, I start at the beginning. priv->current must never be NULL (outside of this transition).
This is emulating the behavior that used to exist where the linked list instead of terminating linked back to the head. This way we always cycle through all adapters and never stop.
OK I see.
+}
+struct udevice *eth_get_dev(void) +{
struct uclass *uc;
uclass_get(UCLASS_ETH, &uc);
struct eth_uclass_priv *priv = uc->priv;
This is OK so long as the device has been probed. I think it always is because you use uclass_next_device() to get the device.
Why would the device being probed have any relationship with the priv in the uclass itself? I would expect the uclass priv to be there regardless. This is not the per-device uc_priv.
Yes you are right, I was confused by the 'priv' name.
return priv->current;
+}
+static void eth_set_dev(struct udevice *dev) +{
struct uclass *uc;
uclass_get(UCLASS_ETH, &uc);
struct eth_uclass_priv *priv = uc->priv;
priv->current = dev;
+}
+unsigned char *eth_get_ethaddr(void) +{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
This check should be unnecessary. Same in other cases below.
So this is guaranteed? In all cases? I ran into some pre-allocated buffers that don't get created if post_probe returns an error, for instance.
If the device is probed then it has uclass_priv. If post_probe() returns an error then the device will be removed (i.e. the probe will fail).
return priv->enetaddr;
}
return NULL;
+}
+/* Set active state */ +int eth_init_state_only(bd_t *bis) +{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_ACTIVE;
}
return 0;
+} +/* Set passive state */ +void eth_halt_state_only(void) +{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
}
+}
+int eth_get_dev_index(void) +{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
return priv->index;
}
return -1;
+}
+int eth_init(bd_t *bis) +{
struct udevice *current, *old_current, *dev;
struct uclass *uc;
current = eth_get_dev();
if (!current) {
puts("No ethernet found.\n");
return -1;
}
/* Sync environment with network devices */
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(dev, uc) {
uchar env_enetaddr[6];
if (eth_getenv_enetaddr_by_index("eth", dev->seq,
env_enetaddr)) {
struct eth_device_priv *priv = dev->uclass_priv;
if (priv)
memcpy(priv->enetaddr, env_enetaddr, 6);
}
};
old_current = current;
do {
debug("Trying %s\n", current->name);
if (current->driver) {
const struct eth_ops *ops =
current->driver->ops;
if (ops->init(current, bis) >= 0) {
struct eth_device_priv *priv =
current->uclass_priv;
if (priv)
priv->state = ETH_STATE_ACTIVE;
return 0;
}
}
debug("FAIL\n");
eth_try_another(0);
current = eth_get_dev();
} while (old_current != current);
return -1;
-ENODEV?
OK.
+}
+void eth_halt(void) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return;
if (!current->driver)
return;
const struct eth_ops *ops = current->driver->ops;
ops->halt(current);
struct eth_device_priv *priv = current->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
+}
+int eth_send(void *packet, int length) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
const struct eth_ops *ops = current->driver->ops;
return ops->send(current, packet, length);
+}
As a general comment, there is an implicit assumption that only one device can be active at a time. I suppose that is a U-Boot limitation, but we don't need to keep it for driver model, or at least we could permit multiple devices to be probed at a time.
I agree that longer term we should look for ways to remove that limitation, but for now everything that uses the network assumes that the "ethact" env var selects the device. There would be a lot of commands to break compatibility with to allow them to specify the device. I say we hold off on that for now.
OK
One thing to be careful of is probing devices before you use them. By using uclass_first_device() you will probe the device. If you want to pick a particular device and probe it, you will need to find the device through another means - e.g. a helper function in the uclass to find the device without probing it.
But still I wonder if you should have functions that are passed a udevice, like eth_rx(struct udevice *dev).
Even if those functions did, the commands would need to change too. Future enhancement, I think.
OK
+int eth_rx(void) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
const struct eth_ops *ops = current->driver->ops;
return ops->recv(current);
+}
+static int eth_write_hwaddr(struct udevice *dev, const char *base_name,
int eth_number)
+{
unsigned char env_enetaddr[6];
int ret = 0;
eth_getenv_enetaddr_by_index(base_name, eth_number,
env_enetaddr);
struct eth_device_priv *priv = dev->uclass_priv;
if (!is_zero_ether_addr(env_enetaddr)) {
if (!is_zero_ether_addr(priv->enetaddr) &&
memcmp(priv->enetaddr, env_enetaddr, 6)) {
printf("\nWarning: %s MAC addresses don't
match:\n",
dev->name);
printf("Address in SROM is %pM\n",
priv->enetaddr);
printf("Address in environment is %pM\n",
env_enetaddr);
}
memcpy(priv->enetaddr, env_enetaddr, 6);
} else if (is_valid_ether_addr(priv->enetaddr)) {
eth_setenv_enetaddr_by_index(base_name, eth_number,
priv->enetaddr);
printf("\nWarning: %s using MAC address from net
device\n",
dev->name);
} else if (is_zero_ether_addr(priv->enetaddr)) {
printf("\nError: %s address not set.\n",
dev->name);
return -EINVAL;
}
const struct eth_ops *ops = dev->driver->ops;
if (ops->write_hwaddr && !eth_mac_skip(eth_number)) {
if (!is_valid_ether_addr(priv->enetaddr)) {
printf("\nError: %s address %pM illegal
value\n",
dev->name, priv->enetaddr);
return -EINVAL;
}
ret = ops->write_hwaddr(dev);
if (ret)
printf("\nWarning: %s failed to set MAC
address\n",
dev->name);
}
return ret;
+}
+static int eth_uclass_init(struct uclass *class) +{
bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
struct eth_uclass_priv *priv = class->priv;
priv->max_index = 0;
What is max_index used for?
For knowing the number of devices that have been bound and allocating the next unused index for the next device.
Is this different from the number of devices in the uclass?
eth_env_init();
return 0;
+}
+static int eth_post_bind(struct udevice *dev) +{
struct udevice *first;
uclass_first_device(UCLASS_ETH, &first);
if (first == dev) {
eth_current_changed();
eth_set_dev(dev);
}
struct eth_device_priv *priv = dev->uclass_priv;
struct eth_uclass_priv *uclass_priv = dev->uclass->priv;
if (priv) {
priv->state = ETH_STATE_INIT;
priv->index = uclass_priv->max_index++;
OK I see it is the number of devices. Does this ever decrease?
Never decreases.
Anyway, struct udevice has a seq member which can give every device a unique sequence number in the uclass automatically (and if you define DM_UC_FLAG_SEQ_ALIAS then the device tree aliases can provide this numbering)
I actually used the seq number originally and that worked fine with platdata. When I moved to the device tree, that's where it fell apart. In the device tree, it is expected that the eth name will include an eth@baseaddr format. The DM code then takes that value that is the baseaddr and sets it as the requested seq. That means I get eth268443648 instead of eth0. No good. So now I keep track of my own seq (index) to make sure I get consistent device names.
That should be fixed now - see u-boot-dm/master. Also the alias approach is useful since it lets you number the devices within the uclass as you wish.
Otherwise I'm not sure what this function is trying to do.
I needs to initialize the priv->current variable so that everything that tries to use the network finds a current eth device. It also initializes the state variable, which is also important.
OK, also you can't really probe a device in the post_bind() handler. Probing should only happen when the device is used.
}
return 0;
+}
+static int eth_pre_unbind(struct udevice *dev) +{
struct udevice *first;
struct udevice *current;
current = eth_get_dev();
uclass_first_device(UCLASS_ETH, &first);
if (current == dev) {
if (dev == first)
uclass_next_device(¤t);
else
current = first;
eth_current_changed();
eth_set_dev(current);
}
I'm not sure what this function is trying to do.
Again, this is just ensuring the "current" variable is always valid.
OK. Shouldn't this happen when the device is removed rather than when it is unbound (well I suppose if it happens when removed it doesn't need to happen when unbound).
return 0;
+}
+static int eth_post_probe(struct udevice *dev) +{
char *ethprime = getenv("ethprime");
if (ethprime && strcmp(dev->name, ethprime) == 0)
eth_set_dev(dev);
What does this do?
This allows the initial "current" device to be specified by they "ethprime" env var. This is preserving existing behaviors as controlled by these env vars.
OK
if (strchr(dev->name, ' '))
printf("\nWarning: eth device name \"%s\" has a
space!\n",
dev->name);
BTW if this is an error you could refuse to bind it - e.g. in the eth_post_bind, return -EINVAL
Good idea.
struct eth_device_priv *priv = dev->uclass_priv;
if (priv)
return eth_write_hwaddr(dev, "eth", priv->index);
return 1;
+}
+UCLASS_DRIVER(eth) = {
.name = "eth",
.id = UCLASS_ETH,
.post_bind = eth_post_bind,
.pre_unbind = eth_pre_unbind,
.post_probe = eth_post_probe,
.init = eth_uclass_init,
.priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
.per_device_auto_alloc_size = sizeof(struct eth_device_priv),
+}; +#endif
+#ifndef CONFIG_DM_ETH /*
- CPU and board-specific Ethernet initializations. Aliased function
- signals caller to move on
@@ -423,6 +738,7 @@ int eth_rx(void)
return eth_current->recv(eth_current);
} +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -486,7 +802,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) {
static struct eth_device *first_failed;
static void *first_failed; char *ethrotate; /*
@@ -515,7 +831,7 @@ void eth_set_current(void) { static char *act; static int env_changed_id;
struct eth_device *old_current;
void *old_current; int env_id; if (!eth_get_dev()) /* XXX no current */
Regards, Simon

Add basic network support to sandbox which includes a network driver.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com ---
arch/sandbox/dts/sandbox.dts | 4 ++ drivers/net/Makefile | 2 + drivers/net/sandbox.c | 91 ++++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 14 ++++--- 4 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 drivers/net/sandbox.c
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 11748ae..a1d3199 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -174,4 +174,8 @@ }; };
+ eth@10002000 { + compatible = "sandbox,eth"; + reg = <0x10002000 0x1000>; + }; }; diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 46c4ac6..2659a8a 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -50,6 +50,8 @@ obj-$(CONFIG_NS8382X) += ns8382x.o obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o +obj-$(CONFIG_ETH_SANDBOX) += sandbox.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c new file mode 100644 index 0000000..e1ee69b --- /dev/null +++ b/drivers/net/sandbox.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct eth_sandbox_priv { + void *device; + int sd; +}; + +int sb_eth_init(struct udevice *dev, bd_t *bis) +{ + printf("eth_sandbox: Init\n"); + + return 0; +} + +int sb_eth_send(struct udevice *dev, void *packet, int length) +{ + printf("eth_sandbox: Send packet %d\n", length); + + return 0; +#endif +} + +int sb_eth_recv(struct udevice *dev) +{ + return 0; +} + +void sb_eth_halt(struct udevice *dev) +{ + printf("eth_sandbox: Halt\n"); +} + +int sb_eth_write_hwaddr(struct udevice *dev) +{ + printf("eth_sandbox: Write HW ADDR\n"); + return 0; +} + +static const struct eth_ops eth_sandbox_ops = { + .init = sb_eth_init, + .send = sb_eth_send, + .recv = sb_eth_recv, + .halt = sb_eth_halt, + .write_hwaddr = sb_eth_write_hwaddr, +}; + +static int eth_sandbox_remove(struct udevice *dev) +{ + return 0; +} + +#ifdef CONFIG_OF_CONTROL +static int sandbox_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev->platdata; + + pdata->iobase = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); + return 0; +} + +static const struct udevice_id sandbox_eth_ids[] = { + { .compatible = "sandbox,eth" }, + { } +}; +#endif + +U_BOOT_DRIVER(eth_sandbox) = { + .name = "eth_sandbox", + .id = UCLASS_ETH, + .of_match = of_match_ptr(sandbox_eth_ids), + .ofdata_to_platdata = of_match_ptr(sandbox_eth_ofdata_to_platdata), + .remove = eth_sandbox_remove, + .ops = ð_sandbox_ops, + .priv_auto_alloc_size = sizeof(struct eth_sandbox_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 657f751..67bfc52 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -143,9 +143,9 @@ /* include default commands */ #include <config_cmd_default.h>
-/* We don't have networking support yet */ -#undef CONFIG_CMD_NET -#undef CONFIG_CMD_NFS +#define CONFIG_DM_ETH +#define CONFIG_ETH_SANDBOX +#define CONFIG_CMD_PING
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY @@ -188,12 +188,16 @@
#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial,cros-ec-keyb\0" \ "stdout=serial,lcd\0" \ - "stderr=serial,lcd\0" + "stderr=serial,lcd\0" \ + "ethaddr=00:00:11:22:33:44\0" \ + "ipaddr=1.2.3.4\0" #else
#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial\0" \ "stdout=serial,lcd\0" \ - "stderr=serial,lcd\0" + "stderr=serial,lcd\0" \ + "ethaddr=00:00:11:22:33:44\0" \ + "ipaddr=1.2.3.4\0" #endif
#define CONFIG_GZIP_COMPRESSED

Hi Joe,
On 27 January 2015 at 16:27, Joe Hershberger joe.hershberger@ni.com wrote:
Add basic network support to sandbox which includes a network driver.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
arch/sandbox/dts/sandbox.dts | 4 ++ drivers/net/Makefile | 2 + drivers/net/sandbox.c | 91 ++++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 14 ++++--- 4 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 drivers/net/sandbox.c
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 11748ae..a1d3199 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -174,4 +174,8 @@ }; };
eth@10002000 {
compatible = "sandbox,eth";
reg = <0x10002000 0x1000>;
};
}; diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 46c4ac6..2659a8a 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -50,6 +50,8 @@ obj-$(CONFIG_NS8382X) += ns8382x.o obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o +obj-$(CONFIG_ETH_SANDBOX) += sandbox.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c new file mode 100644 index 0000000..e1ee69b --- /dev/null +++ b/drivers/net/sandbox.c @@ -0,0 +1,91 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <malloc.h> +#include <net.h>
+DECLARE_GLOBAL_DATA_PTR;
+struct eth_sandbox_priv {
void *device;
int sd;
I'm not sure what these are for.
+};
+int sb_eth_init(struct udevice *dev, bd_t *bis) +{
printf("eth_sandbox: Init\n");
debug()?
return 0;
+}
+int sb_eth_send(struct udevice *dev, void *packet, int length) +{
printf("eth_sandbox: Send packet %d\n", length);
return 0;
+#endif +}
+int sb_eth_recv(struct udevice *dev) +{
return 0;
+}
+void sb_eth_halt(struct udevice *dev) +{
printf("eth_sandbox: Halt\n");
+}
+int sb_eth_write_hwaddr(struct udevice *dev) +{
printf("eth_sandbox: Write HW ADDR\n");
return 0;
+}
+static const struct eth_ops eth_sandbox_ops = {
.init = sb_eth_init,
.send = sb_eth_send,
.recv = sb_eth_recv,
.halt = sb_eth_halt,
.write_hwaddr = sb_eth_write_hwaddr,
+};
+static int eth_sandbox_remove(struct udevice *dev) +{
return 0;
+}
+#ifdef CONFIG_OF_CONTROL +static int sandbox_eth_ofdata_to_platdata(struct udevice *dev) +{
struct eth_pdata *pdata = dev->platdata;
pdata->iobase = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
return 0;
+}
+static const struct udevice_id sandbox_eth_ids[] = {
{ .compatible = "sandbox,eth" },
{ }
+}; +#endif
+U_BOOT_DRIVER(eth_sandbox) = {
.name = "eth_sandbox",
.id = UCLASS_ETH,
.of_match = of_match_ptr(sandbox_eth_ids),
.ofdata_to_platdata = of_match_ptr(sandbox_eth_ofdata_to_platdata),
.remove = eth_sandbox_remove,
.ops = ð_sandbox_ops,
.priv_auto_alloc_size = sizeof(struct eth_sandbox_priv),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+}; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 657f751..67bfc52 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -143,9 +143,9 @@ /* include default commands */ #include <config_cmd_default.h>
-/* We don't have networking support yet */ -#undef CONFIG_CMD_NET -#undef CONFIG_CMD_NFS +#define CONFIG_DM_ETH +#define CONFIG_ETH_SANDBOX +#define CONFIG_CMD_PING
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY @@ -188,12 +188,16 @@
#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial,cros-ec-keyb\0" \ "stdout=serial,lcd\0" \
"stderr=serial,lcd\0"
"stderr=serial,lcd\0" \
"ethaddr=00:00:11:22:33:44\0" \
"ipaddr=1.2.3.4\0"
#else
#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial\0" \ "stdout=serial,lcd\0" \
"stderr=serial,lcd\0"
"stderr=serial,lcd\0" \
"ethaddr=00:00:11:22:33:44\0" \
"ipaddr=1.2.3.4\0"
#endif
#define CONFIG_GZIP_COMPRESSED
1.7.11.5
Regards, Simon

On Tue, Jan 27, 2015 at 8:34 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 27 January 2015 at 16:27, Joe Hershberger joe.hershberger@ni.com
wrote:
Add basic network support to sandbox which includes a network driver.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
arch/sandbox/dts/sandbox.dts | 4 ++ drivers/net/Makefile | 2 + drivers/net/sandbox.c | 91
++++++++++++++++++++++++++++++++++++++++++++
include/configs/sandbox.h | 14 ++++--- 4 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 drivers/net/sandbox.c
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 11748ae..a1d3199 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -174,4 +174,8 @@ }; };
eth@10002000 {
compatible = "sandbox,eth";
reg = <0x10002000 0x1000>;
};
}; diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 46c4ac6..2659a8a 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -50,6 +50,8 @@ obj-$(CONFIG_NS8382X) += ns8382x.o obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o +obj-$(CONFIG_ETH_SANDBOX) += sandbox.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c new file mode 100644 index 0000000..e1ee69b --- /dev/null +++ b/drivers/net/sandbox.c @@ -0,0 +1,91 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <malloc.h> +#include <net.h>
+DECLARE_GLOBAL_DATA_PTR;
+struct eth_sandbox_priv {
void *device;
int sd;
I'm not sure what these are for.
This is accidentally left over from an experiment. I'd like to pursue it, but I'm having trouble with the build env. I'll probably post what I have so for and maybe you have some ideas for how to make it compile without making it into a .lib
+};
+int sb_eth_init(struct udevice *dev, bd_t *bis) +{
printf("eth_sandbox: Init\n");
debug()?
OK
return 0;
+}
+int sb_eth_send(struct udevice *dev, void *packet, int length) +{
printf("eth_sandbox: Send packet %d\n", length);
return 0;
+#endif +}
+int sb_eth_recv(struct udevice *dev) +{
return 0;
+}
+void sb_eth_halt(struct udevice *dev) +{
printf("eth_sandbox: Halt\n");
+}
+int sb_eth_write_hwaddr(struct udevice *dev) +{
printf("eth_sandbox: Write HW ADDR\n");
return 0;
+}
+static const struct eth_ops eth_sandbox_ops = {
.init = sb_eth_init,
.send = sb_eth_send,
.recv = sb_eth_recv,
.halt = sb_eth_halt,
.write_hwaddr = sb_eth_write_hwaddr,
+};
+static int eth_sandbox_remove(struct udevice *dev) +{
return 0;
+}
+#ifdef CONFIG_OF_CONTROL +static int sandbox_eth_ofdata_to_platdata(struct udevice *dev) +{
struct eth_pdata *pdata = dev->platdata;
pdata->iobase = fdtdec_get_addr(gd->fdt_blob, dev->of_offset,
"reg");
return 0;
+}
+static const struct udevice_id sandbox_eth_ids[] = {
{ .compatible = "sandbox,eth" },
{ }
+}; +#endif
+U_BOOT_DRIVER(eth_sandbox) = {
.name = "eth_sandbox",
.id = UCLASS_ETH,
.of_match = of_match_ptr(sandbox_eth_ids),
.ofdata_to_platdata =
of_match_ptr(sandbox_eth_ofdata_to_platdata),
.remove = eth_sandbox_remove,
.ops = ð_sandbox_ops,
.priv_auto_alloc_size = sizeof(struct eth_sandbox_priv),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+}; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 657f751..67bfc52 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -143,9 +143,9 @@ /* include default commands */ #include <config_cmd_default.h>
-/* We don't have networking support yet */ -#undef CONFIG_CMD_NET -#undef CONFIG_CMD_NFS +#define CONFIG_DM_ETH +#define CONFIG_ETH_SANDBOX +#define CONFIG_CMD_PING
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY @@ -188,12 +188,16 @@
#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial,cros-ec-keyb\0" \ "stdout=serial,lcd\0" \
"stderr=serial,lcd\0"
"stderr=serial,lcd\0" \
"ethaddr=00:00:11:22:33:44\0" \
"ipaddr=1.2.3.4\0"
#else
#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial\0" \ "stdout=serial,lcd\0" \
"stderr=serial,lcd\0"
"stderr=serial,lcd\0" \
"ethaddr=00:00:11:22:33:44\0" \
"ipaddr=1.2.3.4\0"
#endif
#define CONFIG_GZIP_COMPRESSED
1.7.11.5
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

The sandbox driver will now generate response traffic to exercise the ping command even when no network exists. This allows the basic data pathways of the DM to be tested.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com ---
drivers/net/sandbox.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+)
diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index e1ee69b..49413f2 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -20,6 +20,11 @@ struct eth_sandbox_priv { int sd; };
+static uchar fake_host_hwaddr[ARP_HLEN] = {0x00, 0x00, 0x66, 0x44, 0x22, 0x00}; +static IPaddr_t fake_host_ipaddr; +static uchar recv_packet_buffer[PKTSIZE]; +static int recv_packet_length; + int sb_eth_init(struct udevice *dev, bd_t *bis) { printf("eth_sandbox: Init\n"); @@ -31,12 +36,82 @@ int sb_eth_send(struct udevice *dev, void *packet, int length) { printf("eth_sandbox: Send packet %d\n", length);
+ struct ethernet_hdr *eth = packet; + if (ntohs(eth->et_protlen) == PROT_ARP) { + struct arp_hdr *arp = packet + ETHER_HDR_SIZE; + if (ntohs(arp->ar_op) == ARPOP_REQUEST) { + /* store this as the assumed IP of the fake host */ + fake_host_ipaddr = NetReadIP(&arp->ar_tpa); + /* Formulate a fake response */ + struct ethernet_hdr *eth_recv = + (void *)recv_packet_buffer; + memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN); + memcpy(eth_recv->et_src, fake_host_hwaddr, ARP_HLEN); + eth_recv->et_protlen = htons(PROT_ARP); + + struct arp_hdr *arp_recv = (void *)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, fake_host_hwaddr, ARP_HLEN); + NetWriteIP(&arp_recv->ar_spa, fake_host_ipaddr); + memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN); + NetCopyIP(&arp_recv->ar_tpa, &arp->ar_spa); + + 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) { + /* reply to the ping */ + memcpy(recv_packet_buffer, packet, length); + struct ethernet_hdr *eth_recv = + (void *)recv_packet_buffer; + struct ip_udp_hdr *ipr = + (void *)recv_packet_buffer + + ETHER_HDR_SIZE; + struct icmp_hdr *icmpr = + (struct icmp_hdr *)&ipr->udp_src; + memcpy(eth_recv->et_dest, eth->et_src, + ARP_HLEN); + memcpy(eth_recv->et_src, fake_host_hwaddr, + ARP_HLEN); + ipr->ip_sum = 0; + ipr->ip_off = 0; + NetCopyIP((void *)&ipr->ip_dst, &ip->ip_src); + NetWriteIP((void *)&ipr->ip_src, + fake_host_ipaddr); + ipr->ip_sum = ~NetCksum((uchar *)ipr, + IP_HDR_SIZE >> 1); + + icmpr->type = ICMP_ECHO_REPLY; + icmpr->checksum = 0; + icmpr->checksum = ~NetCksum((uchar *)icmpr, + (length - ETHER_HDR_SIZE - + IP_HDR_SIZE) >> 1); + + recv_packet_length = length; + } + } + } + return 0; #endif }
int sb_eth_recv(struct udevice *dev) { + if (recv_packet_length) { + int lcl_recv_packet_length = recv_packet_length; + printf("eth_sandbox: received packet %d\n", recv_packet_length); + recv_packet_length = 0; + NetReceive((void *)recv_packet_buffer, lcl_recv_packet_length); + } return 0; }

Hi Joe,
On 27 January 2015 at 16:27, Joe Hershberger joe.hershberger@ni.com wrote:
The sandbox driver will now generate response traffic to exercise the ping command even when no network exists. This allows the basic data pathways of the DM to be tested.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Looks like this can support ping. Very nice.
drivers/net/sandbox.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+)
diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index e1ee69b..49413f2 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -20,6 +20,11 @@ struct eth_sandbox_priv { int sd; };
+static uchar fake_host_hwaddr[ARP_HLEN] = {0x00, 0x00, 0x66, 0x44, 0x22, 0x00}; +static IPaddr_t fake_host_ipaddr; +static uchar recv_packet_buffer[PKTSIZE]; +static int recv_packet_length;
This could go in the driver's priv area (then we could support multiple sandbox devices).
int sb_eth_init(struct udevice *dev, bd_t *bis) { printf("eth_sandbox: Init\n"); @@ -31,12 +36,82 @@ int sb_eth_send(struct udevice *dev, void *packet, int length) { printf("eth_sandbox: Send packet %d\n", length);
struct ethernet_hdr *eth = packet;
if (ntohs(eth->et_protlen) == PROT_ARP) {
struct arp_hdr *arp = packet + ETHER_HDR_SIZE;
if (ntohs(arp->ar_op) == ARPOP_REQUEST) {
/* store this as the assumed IP of the fake host */
fake_host_ipaddr = NetReadIP(&arp->ar_tpa);
/* Formulate a fake response */
struct ethernet_hdr *eth_recv =
(void *)recv_packet_buffer;
memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN);
memcpy(eth_recv->et_src, fake_host_hwaddr, ARP_HLEN);
eth_recv->et_protlen = htons(PROT_ARP);
struct arp_hdr *arp_recv = (void *)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, fake_host_hwaddr, ARP_HLEN);
NetWriteIP(&arp_recv->ar_spa, fake_host_ipaddr);
memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN);
NetCopyIP(&arp_recv->ar_tpa, &arp->ar_spa);
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) {
/* reply to the ping */
memcpy(recv_packet_buffer, packet, length);
struct ethernet_hdr *eth_recv =
(void *)recv_packet_buffer;
struct ip_udp_hdr *ipr =
(void *)recv_packet_buffer +
ETHER_HDR_SIZE;
struct icmp_hdr *icmpr =
(struct icmp_hdr *)&ipr->udp_src;
memcpy(eth_recv->et_dest, eth->et_src,
ARP_HLEN);
memcpy(eth_recv->et_src, fake_host_hwaddr,
ARP_HLEN);
ipr->ip_sum = 0;
ipr->ip_off = 0;
NetCopyIP((void *)&ipr->ip_dst, &ip->ip_src);
NetWriteIP((void *)&ipr->ip_src,
fake_host_ipaddr);
ipr->ip_sum = ~NetCksum((uchar *)ipr,
IP_HDR_SIZE >> 1);
icmpr->type = ICMP_ECHO_REPLY;
icmpr->checksum = 0;
icmpr->checksum = ~NetCksum((uchar *)icmpr,
(length - ETHER_HDR_SIZE -
IP_HDR_SIZE) >> 1);
recv_packet_length = length;
}
}
}
return 0;
#endif }
int sb_eth_recv(struct udevice *dev) {
if (recv_packet_length) {
int lcl_recv_packet_length = recv_packet_length;
printf("eth_sandbox: received packet %d\n", recv_packet_length);
recv_packet_length = 0;
NetReceive((void *)recv_packet_buffer, lcl_recv_packet_length);
} return 0;
}
Looks good.
Regards, Simon

Hi Joe,
On 27 January 2015 at 16:27, Joe Hershberger joe.hershberger@ni.com wrote:
For now this simply addresses the MAC part of the network hardware. The next part to implement is the PHY children. I wanted to get early feedback on what I have so far to make sure I'm going in the direction that Simon envisioned.
It's great to see this! My comments are against each patch.
Regards, Simon

For now this simply addresses the MAC part of the network hardware. The next part to implement is the PHY children. I wanted to get early feedback on what I have so far to make sure I'm going in the direction that Simon envisioned.
Added an additional patch that I've been playing with to allow actual networking from within sandbox, but I haven't come across a good way to make it build in the u-boot build system. Any good ideas are welcome.
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for our needs -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()). -Change printfs to debug in sandbox driver -Remove unused priv struct for sandbox driver -Change printfs to debug in sandbox driver -Move static data to priv -Move fake hwaddr to the device tree -Added the raw packet proof-of-concept patch.
Joe Hershberger (8): net: Provide a function to get the current MAC address net: Rename helper function to be more clear net: Remove unneeded "extern" in net.h net: Refactor in preparation for driver model net: Add basic driver model support to Ethernet stack net: Add network support to sandbox net: Add ARP and PING response to sandbox driver net: Add actual networking support to sandbox's driver
arch/mips/cpu/mips32/au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- arch/sandbox/dts/sandbox.dts | 5 + common/board_r.c | 4 +- common/cmd_bdinfo.c | 2 + drivers/net/Makefile | 2 + drivers/net/sandbox-raw.c | 60 +++++ drivers/net/sandbox.c | 204 ++++++++++++++++ include/configs/sandbox.h | 14 +- include/dm/uclass-id.h | 1 + include/net.h | 159 +++++++----- net/eth.c | 407 +++++++++++++++++++++++++++---- net/net.c | 2 +- 15 files changed, 748 insertions(+), 120 deletions(-) create mode 100644 drivers/net/sandbox-raw.c create mode 100644 drivers/net/sandbox.c

The current implementation exposes the eth_device struct to code that needs to access the MAC address. Add a wrapper function for this to abstract away the pointer for this operation.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com ---
Changes in v2: None
arch/mips/cpu/mips32/au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- include/net.h | 8 ++++++++ net/net.c | 2 +- 6 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/arch/mips/cpu/mips32/au1x00/au1x00_eth.c b/arch/mips/cpu/mips32/au1x00/au1x00_eth.c index 4770f56..535d713 100644 --- a/arch/mips/cpu/mips32/au1x00/au1x00_eth.c +++ b/arch/mips/cpu/mips32/au1x00/au1x00_eth.c @@ -238,7 +238,7 @@ static int au1x00_init(struct eth_device* dev, bd_t * bd){ }
/* Put mac addr in little endian */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() *mac_addr_high = (ea[5] << 8) | (ea[4] ) ; *mac_addr_low = (ea[3] << 24) | (ea[2] << 16) | (ea[1] << 8) | (ea[0] ) ; diff --git a/arch/powerpc/cpu/mpc8260/ether_fcc.c b/arch/powerpc/cpu/mpc8260/ether_fcc.c index f9f15b5..f777ba1 100644 --- a/arch/powerpc/cpu/mpc8260/ether_fcc.c +++ b/arch/powerpc/cpu/mpc8260/ether_fcc.c @@ -299,7 +299,7 @@ static int fec_init(struct eth_device* dev, bd_t *bis) * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc85xx/ether_fcc.c b/arch/powerpc/cpu/mpc85xx/ether_fcc.c index 166dc9e..58d4bfb 100644 --- a/arch/powerpc/cpu/mpc85xx/ether_fcc.c +++ b/arch/powerpc/cpu/mpc85xx/ether_fcc.c @@ -338,7 +338,7 @@ static int fec_init(struct eth_device* dev, bd_t *bis) * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc8xx/scc.c b/arch/powerpc/cpu/mpc8xx/scc.c index 251966b..66e4014 100644 --- a/arch/powerpc/cpu/mpc8xx/scc.c +++ b/arch/powerpc/cpu/mpc8xx/scc.c @@ -339,7 +339,7 @@ static int scc_init (struct eth_device *dev, bd_t * bis) pram_ptr->sen_gaddr3 = 0x0; /* Group Address Filter 3 (unused) */ pram_ptr->sen_gaddr4 = 0x0; /* Group Address Filter 4 (unused) */
-#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/include/net.h b/include/net.h index 73ea88b..a9579ee 100644 --- a/include/net.h +++ b/include/net.h @@ -111,6 +111,14 @@ struct eth_device *eth_get_dev(void) { return eth_current; } + +static inline unsigned char *eth_get_ethaddr(void) +{ + if (eth_current) + return eth_current->enetaddr; + return NULL; +} + extern struct eth_device *eth_get_dev_by_name(const char *devname); extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ extern int eth_get_dev_index(void); /* get the device index */ diff --git a/net/net.c b/net/net.c index 2bea07b..ddd630c 100644 --- a/net/net.c +++ b/net/net.c @@ -275,7 +275,7 @@ static void NetInitLoop(void) env_changed_id = env_id; } if (eth_get_dev()) - memcpy(NetOurEther, eth_get_dev()->enetaddr, 6); + memcpy(NetOurEther, eth_get_ethaddr(), 6);
return; }

Hi Joe,
On 2 February 2015 at 17:38, Joe Hershberger joe.hershberger@ni.com wrote:
The current implementation exposes the eth_device struct to code that needs to access the MAC address. Add a wrapper function for this to abstract away the pointer for this operation.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v2: None
arch/mips/cpu/mips32/au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- include/net.h | 8 ++++++++ net/net.c | 2 +- 6 files changed, 13 insertions(+), 5 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
I think the first file might have been dropped.
Regards, Simon

Make it clear that the helper is checking the addr, not setting it.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com ---
Changes in v2: None
net/eth.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/net/eth.c b/net/eth.c index eac4f7b..65e8c77 100644 --- a/net/eth.c +++ b/net/eth.c @@ -153,11 +153,6 @@ static void eth_current_changed(void) setenv("ethact", NULL); }
-static int eth_address_set(unsigned char *addr) -{ - return memcmp(addr, "\0\0\0\0\0\0", 6); -} - int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -166,9 +161,9 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
- if (eth_address_set(env_enetaddr)) { - if (eth_address_set(dev->enetaddr) && - memcmp(dev->enetaddr, env_enetaddr, 6)) { + if (!is_zero_ether_addr(env_enetaddr)) { + if (!is_zero_ether_addr(dev->enetaddr) && + memcmp(dev->enetaddr, env_enetaddr, 6)) { printf("\nWarning: %s MAC addresses don't match:\n", dev->name); printf("Address in SROM is %pM\n", @@ -183,7 +178,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, dev->enetaddr); printf("\nWarning: %s using MAC address from net device\n", dev->name); - } else if (!(eth_address_set(dev->enetaddr))) { + } else if (is_zero_ether_addr(dev->enetaddr)) { printf("\nError: %s address not set.\n", dev->name); return -EINVAL;

On 2 February 2015 at 17:38, Joe Hershberger joe.hershberger@ni.com wrote:
Make it clear that the helper is checking the addr, not setting it.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org
Changes in v2: None
net/eth.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/net/eth.c b/net/eth.c index eac4f7b..65e8c77 100644 --- a/net/eth.c +++ b/net/eth.c @@ -153,11 +153,6 @@ static void eth_current_changed(void) setenv("ethact", NULL); }
-static int eth_address_set(unsigned char *addr) -{
return memcmp(addr, "\0\0\0\0\0\0", 6);
-}
int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -166,9 +161,9 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
if (eth_address_set(env_enetaddr)) {
if (eth_address_set(dev->enetaddr) &&
memcmp(dev->enetaddr, env_enetaddr, 6)) {
if (!is_zero_ether_addr(env_enetaddr)) {
if (!is_zero_ether_addr(dev->enetaddr) &&
memcmp(dev->enetaddr, env_enetaddr, 6)) { printf("\nWarning: %s MAC addresses don't match:\n", dev->name); printf("Address in SROM is %pM\n",
@@ -183,7 +178,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, dev->enetaddr); printf("\nWarning: %s using MAC address from net device\n", dev->name);
} else if (!(eth_address_set(dev->enetaddr))) {
} else if (is_zero_ether_addr(dev->enetaddr)) { printf("\nError: %s address not set.\n", dev->name); return -EINVAL;
-- 1.7.11.5

Many of the functions in net.h were preceded extern needlessly. Removing them to limit the number of checkpatch.pl complaints.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com ---
Changes in v2: None
include/net.h | 96 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 48 insertions(+), 48 deletions(-)
diff --git a/include/net.h b/include/net.h index a9579ee..ff8b7af 100644 --- a/include/net.h +++ b/include/net.h @@ -97,11 +97,11 @@ struct eth_device { void *priv; };
-extern int eth_initialize(bd_t *bis); /* Initialize network subsystem */ -extern int eth_register(struct eth_device* dev);/* Register network device */ -extern int eth_unregister(struct eth_device *dev);/* Remove network device */ -extern void eth_try_another(int first_restart); /* Change the device */ -extern void eth_set_current(void); /* set nterface to ethcur var */ +int eth_initialize(bd_t *bis); /* Initialize network subsystem */ +int eth_register(struct eth_device *dev);/* Register network device */ +int eth_unregister(struct eth_device *dev);/* Remove network device */ +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */
/* get the current device MAC */ extern struct eth_device *eth_current; @@ -119,12 +119,12 @@ static inline unsigned char *eth_get_ethaddr(void) return NULL; }
-extern struct eth_device *eth_get_dev_by_name(const char *devname); -extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ -extern int eth_get_dev_index(void); /* get the device index */ -extern void eth_parse_enetaddr(const char *addr, uchar *enetaddr); -extern int eth_getenv_enetaddr(char *name, uchar *enetaddr); -extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr); +struct eth_device *eth_get_dev_by_name(const char *devname); +struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ +int eth_get_dev_index(void); /* get the device index */ +void eth_parse_enetaddr(const char *addr, uchar *enetaddr); +int eth_getenv_enetaddr(char *name, uchar *enetaddr); +int eth_setenv_enetaddr(char *name, const uchar *enetaddr);
/* * Get the hardware address for an ethernet interface . @@ -135,20 +135,20 @@ extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr); * Returns: * Return true if the address is valid. */ -extern int eth_getenv_enetaddr_by_index(const char *base_name, int index, - uchar *enetaddr); +int eth_getenv_enetaddr_by_index(const char *base_name, int index, + uchar *enetaddr);
-extern int usb_eth_initialize(bd_t *bi); -extern int eth_init(bd_t *bis); /* Initialize the device */ -extern int eth_send(void *packet, int length); /* Send a packet */ +int usb_eth_initialize(bd_t *bi); +int eth_init(bd_t *bis); /* Initialize the device */ +int eth_send(void *packet, int length); /* Send a packet */
#ifdef CONFIG_API -extern int eth_receive(void *packet, int length); /* Receive a packet*/ -extern void (*push_packet)(void *packet, int length); +int eth_receive(void *packet, int length); /* Receive a packet*/ +void (*push_packet)(void *packet, int length); #endif -extern int eth_rx(void); /* Check for received packets */ -extern void eth_halt(void); /* stop SCC */ -extern char *eth_get_name(void); /* get name of current device */ +int eth_rx(void); /* Check for received packets */ +void eth_halt(void); /* stop SCC */ +char *eth_get_name(void); /* get name of current device */
/* Set active state */ static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) @@ -469,25 +469,25 @@ extern IPaddr_t Mcast_addr; #endif
/* Initialize the network adapter */ -extern void net_init(void); -extern int NetLoop(enum proto_t); +void net_init(void); +int NetLoop(enum proto_t);
/* Shutdown adapters and cleanup */ -extern void NetStop(void); +void NetStop(void);
/* Load failed. Start again. */ -extern void NetStartAgain(void); +void NetStartAgain(void);
/* Get size of the ethernet header when we send */ -extern int NetEthHdrSize(void); +int NetEthHdrSize(void);
/* Set ethernet header; returns the size of the header */ -extern int NetSetEther(uchar *, uchar *, uint); -extern int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot); +int NetSetEther(uchar *, uchar *, uint); +int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot);
/* Set IP header */ -extern void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source); -extern void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, +void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source); +void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, int sport, int len);
/** @@ -521,16 +521,16 @@ unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new_sum); int ip_checksum_ok(const void *addr, unsigned nbytes);
/* Checksum */ -extern int NetCksumOk(uchar *, int); /* Return true if cksum OK */ -extern uint NetCksum(uchar *, int); /* Calculate the checksum */ +int NetCksumOk(uchar *, int); /* Return true if cksum OK */ +uint NetCksum(uchar *, int); /* Calculate the checksum */
/* Callbacks */ -extern rxhand_f *net_get_udp_handler(void); /* Get UDP RX packet handler */ -extern void net_set_udp_handler(rxhand_f *); /* Set UDP RX packet handler */ -extern rxhand_f *net_get_arp_handler(void); /* Get ARP RX packet handler */ -extern void net_set_arp_handler(rxhand_f *); /* Set ARP RX packet handler */ -extern void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */ -extern void NetSetTimeout(ulong, thand_f *);/* Set timeout handler */ +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 */ +void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */ +void NetSetTimeout(ulong, thand_f *);/* Set timeout handler */
/* Network loop state */ enum net_loop_state { @@ -563,11 +563,11 @@ static inline void NetSendPacket(uchar *pkt, int len) * @param sport Source UDP port * @param payload_len Length of data after the UDP header */ -extern int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, +int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int payload_len);
/* Processes a received packet */ -extern void NetReceive(uchar *, int); +void NetReceive(uchar *, int);
#ifdef CONFIG_NETCONSOLE void NcStart(void); @@ -715,28 +715,28 @@ static inline void eth_random_addr(uchar *addr) }
/* Convert an IP address to a string */ -extern void ip_to_string(IPaddr_t x, char *s); +void ip_to_string(IPaddr_t x, char *s);
/* Convert a string to ip address */ -extern IPaddr_t string_to_ip(const char *s); +IPaddr_t string_to_ip(const char *s);
/* Convert a VLAN id to a string */ -extern void VLAN_to_string(ushort x, char *s); +void VLAN_to_string(ushort x, char *s);
/* Convert a string to a vlan id */ -extern ushort string_to_VLAN(const char *s); +ushort string_to_VLAN(const char *s);
/* read a VLAN id from an environment variable */ -extern ushort getenv_VLAN(char *); +ushort getenv_VLAN(char *);
/* copy a filename (allow for "..." notation, limit length) */ -extern void copy_filename(char *dst, const char *src, int size); +void copy_filename(char *dst, const char *src, int size);
/* get a random source port */ -extern unsigned int random_port(void); +unsigned int random_port(void);
/* Update U-Boot over TFTP */ -extern int update_tftp(ulong addr); +int update_tftp(ulong addr);
/**********************************************************************/

On 2 February 2015 at 17:38, Joe Hershberger joe.hershberger@ni.com wrote:
Many of the functions in net.h were preceded extern needlessly. Removing them to limit the number of checkpatch.pl complaints.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
I think you dropped my tag on these?
Reviewed-by: Simon Glass sjg@chromium.org
Changes in v2: None
include/net.h | 96 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 48 insertions(+), 48 deletions(-)

Move some things around and organize things so that the driver model implementation will fit in more easily.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com ---
Changes in v2: None
include/net.h | 63 +++++++++++++++++++++++++------------------------ net/eth.c | 75 +++++++++++++++++++++++++++++++---------------------------- 2 files changed, 73 insertions(+), 65 deletions(-)
diff --git a/include/net.h b/include/net.h index ff8b7af..7eef9cc 100644 --- a/include/net.h +++ b/include/net.h @@ -100,10 +100,7 @@ struct eth_device { int eth_initialize(bd_t *bis); /* Initialize network subsystem */ int eth_register(struct eth_device *dev);/* Register network device */ int eth_unregister(struct eth_device *dev);/* Remove network device */ -void eth_try_another(int first_restart); /* Change the device */ -void eth_set_current(void); /* set nterface to ethcur var */
-/* get the current device MAC */ extern struct eth_device *eth_current;
static inline __attribute__((always_inline)) @@ -112,6 +109,7 @@ struct eth_device *eth_get_dev(void) return eth_current; }
+/* get the current device MAC */ static inline unsigned char *eth_get_ethaddr(void) { if (eth_current) @@ -119,6 +117,37 @@ static inline unsigned char *eth_get_ethaddr(void) return NULL; }
+/* Set active state */ +static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) +{ + eth_get_dev()->state = ETH_STATE_ACTIVE; + + return 0; +} +/* Set passive state */ +static inline __attribute__((always_inline)) void eth_halt_state_only(void) +{ + eth_get_dev()->state = ETH_STATE_PASSIVE; +} + +/* + * Set the hardware address for an ethernet interface based on 'eth%daddr' + * environment variable (or just 'ethaddr' if eth_number is 0). + * Args: + * base_name - base name for device (normally "eth") + * eth_number - value of %d (0 for first device of this type) + * Returns: + * 0 is success, non-zero is error status from driver. + */ +int eth_write_hwaddr(struct eth_device *dev, const char *base_name, + int eth_number); + +int usb_eth_initialize(bd_t *bi); +#endif + +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */ + struct eth_device *eth_get_dev_by_name(const char *devname); struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ int eth_get_dev_index(void); /* get the device index */ @@ -138,7 +167,6 @@ int eth_setenv_enetaddr(char *name, const uchar *enetaddr); int eth_getenv_enetaddr_by_index(const char *base_name, int index, uchar *enetaddr);
-int usb_eth_initialize(bd_t *bi); int eth_init(bd_t *bis); /* Initialize the device */ int eth_send(void *packet, int length); /* Send a packet */
@@ -148,32 +176,7 @@ void (*push_packet)(void *packet, int length); #endif int eth_rx(void); /* Check for received packets */ void eth_halt(void); /* stop SCC */ -char *eth_get_name(void); /* get name of current device */ - -/* Set active state */ -static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) -{ - eth_get_dev()->state = ETH_STATE_ACTIVE; - - return 0; -} -/* Set passive state */ -static inline __attribute__((always_inline)) void eth_halt_state_only(void) -{ - eth_get_dev()->state = ETH_STATE_PASSIVE; -} - -/* - * Set the hardware address for an ethernet interface based on 'eth%daddr' - * environment variable (or just 'ethaddr' if eth_number is 0). - * Args: - * base_name - base name for device (normally "eth") - * eth_number - value of %d (0 for first device of this type) - * Returns: - * 0 is success, non-zero is error status from driver. - */ -int eth_write_hwaddr(struct eth_device *dev, const char *base_name, - int eth_number); +const char *eth_get_name(void); /* get name of current device */
#ifdef CONFIG_MCAST_TFTP int eth_mcast_join(IPaddr_t mcast_addr, u8 join); diff --git a/net/eth.c b/net/eth.c index 65e8c77..c02548c 100644 --- a/net/eth.c +++ b/net/eth.c @@ -55,6 +55,14 @@ static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index, return eth_setenv_enetaddr(enetvar, enetaddr); }
+static void eth_env_init(void) +{ + const char *s; + + s = getenv("bootfile"); + if (s != NULL) + copy_filename(BootFile, s, sizeof(BootFile)); +}
static int eth_mac_skip(int index) { @@ -87,6 +95,11 @@ static unsigned int eth_rcv_current, eth_rcv_last; static struct eth_device *eth_devices; struct eth_device *eth_current;
+static void eth_set_current_to_next(void) +{ + eth_current = eth_current->next; +} + struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -137,22 +150,6 @@ int eth_get_dev_index(void) return eth_current->index; }
-static void eth_current_changed(void) -{ - char *act = getenv("ethact"); - /* update current ethernet name */ - if (eth_current) { - if (act == NULL || strcmp(act, eth_current->name) != 0) - setenv("ethact", eth_current->name); - } - /* - * remove the variable completely if there is no active - * interface - */ - else if (act != NULL) - setenv("ethact", NULL); -} - int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -251,14 +248,6 @@ int eth_unregister(struct eth_device *dev) return 0; }
-static void eth_env_init(bd_t *bis) -{ - const char *s; - - if ((s = getenv("bootfile")) != NULL) - copy_filename(BootFile, s, sizeof(BootFile)); -} - int eth_initialize(bd_t *bis) { int num_devices = 0; @@ -479,6 +468,22 @@ int eth_receive(void *packet, int length) } #endif /* CONFIG_API */
+static void eth_current_changed(void) +{ + char *act = getenv("ethact"); + /* update current ethernet name */ + if (eth_get_dev()) { + if (act == NULL || strcmp(act, eth_get_name()) != 0) + setenv("ethact", eth_get_name()); + } + /* + * remove the variable completely if there is no active + * interface + */ + else if (act != NULL) + setenv("ethact", NULL); +} + void eth_try_another(int first_restart) { static struct eth_device *first_failed; @@ -492,17 +497,17 @@ void eth_try_another(int first_restart) if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) return;
- if (!eth_current) + if (!eth_get_dev()) return;
if (first_restart) - first_failed = eth_current; + first_failed = eth_get_dev();
- eth_current = eth_current->next; + eth_set_current_to_next();
eth_current_changed();
- if (first_failed == eth_current) + if (first_failed == eth_get_dev()) NetRestartWrap = 1; }
@@ -513,7 +518,7 @@ void eth_set_current(void) struct eth_device *old_current; int env_id;
- if (!eth_current) /* XXX no current */ + if (!eth_get_dev()) /* XXX no current */ return;
env_id = get_env_id(); @@ -522,18 +527,18 @@ void eth_set_current(void) env_changed_id = env_id; } if (act != NULL) { - old_current = eth_current; + old_current = eth_get_dev(); do { - if (strcmp(eth_current->name, act) == 0) + if (strcmp(eth_get_name(), act) == 0) return; - eth_current = eth_current->next; - } while (old_current != eth_current); + eth_set_current_to_next(); + } while (old_current != eth_get_dev()); }
eth_current_changed(); }
-char *eth_get_name(void) +const char *eth_get_name(void) { - return eth_current ? eth_current->name : "unknown"; + return eth_get_dev() ? eth_get_dev()->name : "unknown"; }

On 2 February 2015 at 17:38, Joe Hershberger joe.hershberger@ni.com wrote:
Move some things around and organize things so that the driver model implementation will fit in more easily.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v2: None
include/net.h | 63 +++++++++++++++++++++++++------------------------ net/eth.c | 75 +++++++++++++++++++++++++++++++---------------------------- 2 files changed, 73 insertions(+), 65 deletions(-)
No changes so:
Reviewed-by: Simon Glass sjg@chromium.org

First just add support for MAC drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for our needs -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()).
common/board_r.c | 4 +- common/cmd_bdinfo.c | 2 + include/dm/uclass-id.h | 1 + include/net.h | 24 ++++ net/eth.c | 319 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 346 insertions(+), 4 deletions(-)
diff --git a/common/board_r.c b/common/board_r.c index 68a9448..75147b7 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -556,7 +556,7 @@ static int initr_bbmii(void) } #endif
-#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) static int initr_net(void) { puts("Net: "); @@ -825,7 +825,7 @@ init_fnc_t init_sequence_r[] = { #ifdef CONFIG_BITBANGMII initr_bbmii, #endif -#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) INIT_FUNC_WATCHDOG_RESET initr_net, #endif diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index e6d8a7a..8688cf9 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..ad96682 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */ + UCLASS_ETH, /* Ethernet device */
UCLASS_COUNT, UCLASS_INVALID = -1, diff --git a/include/net.h b/include/net.h index 7eef9cc..4d21d91 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,30 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH +struct eth_pdata { + phys_addr_t iobase; + unsigned char enetaddr[6]; +}; + +struct eth_ops { + int (*init)(struct udevice *dev, bd_t *bis); + int (*send)(struct udevice *dev, void *packet, int length); + int (*recv)(struct udevice *dev); + void (*halt)(struct udevice *dev); +#ifdef CONFIG_MCAST_TFTP + int (*mcast)(struct udevice *dev, const u8 *enetaddr, u8 set); +#endif + int (*write_hwaddr)(struct udevice *dev); +}; + +struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +int eth_init_state_only(bd_t *bis); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ +#endif + +#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; diff --git a/net/eth.c b/net/eth.c index c02548c..1b5a169 100644 --- a/net/eth.c +++ b/net/eth.c @@ -72,6 +72,320 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void); + +#ifdef CONFIG_DM_ETH +#include <dm.h> +#include <dm/device-internal.h> + +struct eth_device_priv { + int state; + void *priv; +}; + +struct eth_uclass_priv { + struct udevice *current; +}; + +static void eth_set_current_to_next(void) +{ + struct uclass *uc; + struct eth_uclass_priv *uc_priv; + + uclass_get(UCLASS_ETH, &uc); + uc_priv = uc->priv; + uclass_next_device(&uc_priv->current); + if (!uc_priv->current) + uclass_first_device(UCLASS_ETH, &uc_priv->current); +} + +struct udevice *eth_get_dev(void) +{ + struct uclass *uc; + uclass_get(UCLASS_ETH, &uc); + + struct eth_uclass_priv *uc_priv = uc->priv; + return uc_priv->current; +} + +static void eth_set_dev(struct udevice *dev) +{ + struct uclass *uc; + uclass_get(UCLASS_ETH, &uc); + + struct eth_uclass_priv *uc_priv = uc->priv; + uc_priv->current = dev; +} + +unsigned char *eth_get_ethaddr(void) +{ + struct eth_pdata *pdata; + if (eth_get_dev()) { + pdata = eth_get_dev()->platdata; + if (pdata) + return pdata->enetaddr; + } + return NULL; +} + +/* Set active state */ +int eth_init_state_only(bd_t *bis) +{ + struct eth_device_priv *priv; + if (eth_get_dev()) { + priv = eth_get_dev()->uclass_priv; + if (priv) + priv->state = ETH_STATE_ACTIVE; + } + + return 0; +} +/* Set passive state */ +void eth_halt_state_only(void) +{ + struct eth_device_priv *priv; + if (eth_get_dev()) { + priv = eth_get_dev()->uclass_priv; + if (priv) + priv->state = ETH_STATE_PASSIVE; + } +} + +int eth_get_dev_index(void) +{ + if (eth_get_dev()) + return eth_get_dev()->seq; + return -1; +} + +int eth_init(bd_t *bis) +{ + struct udevice *current, *old_current, *dev; + struct uclass *uc; + + current = eth_get_dev(); + if (!current) { + puts("No ethernet found.\n"); + return -1; + } + device_probe(current); + + /* Sync environment with network devices */ + uclass_get(UCLASS_ETH, &uc); + uclass_foreach_dev(dev, uc) { + uchar env_enetaddr[6]; + + if (eth_getenv_enetaddr_by_index("eth", dev->seq, + env_enetaddr)) { + struct eth_pdata *pdata = dev->platdata; + if (pdata) + memcpy(pdata->enetaddr, env_enetaddr, 6); + } + }; + + old_current = current; + do { + debug("Trying %s\n", current->name); + + if (current->driver) { + const struct eth_ops *ops = current->driver->ops; + if (ops->init(current, bis) >= 0) { + struct eth_device_priv *priv = + current->uclass_priv; + if (priv) + priv->state = ETH_STATE_ACTIVE; + + return 0; + } + } + debug("FAIL\n"); + + eth_try_another(0); + current = eth_get_dev(); + } while (old_current != current); + + return -ENODEV; +} + +void eth_halt(void) +{ + struct udevice *current; + + current = eth_get_dev(); + if (!current) + return; + if (!current->driver) + return; + + const struct eth_ops *ops = current->driver->ops; + ops->halt(current); + + struct eth_device_priv *priv = current->uclass_priv; + if (priv) + priv->state = ETH_STATE_PASSIVE; +} + +int eth_send(void *packet, int length) +{ + struct udevice *current; + + current = eth_get_dev(); + if (!current) + return -1; + if (!current->driver) + return -1; + + const struct eth_ops *ops = current->driver->ops; + return ops->send(current, packet, length); +} + +int eth_rx(void) +{ + struct udevice *current; + + current = eth_get_dev(); + if (!current) + return -1; + if (!current->driver) + return -1; + + const struct eth_ops *ops = current->driver->ops; + return ops->recv(current); +} + +static int eth_write_hwaddr(struct udevice *dev, const char *base_name, + int eth_number) +{ + unsigned char env_enetaddr[6]; + int ret = 0; + + eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr); + + struct eth_pdata *pdata = dev->platdata; + if (!is_zero_ether_addr(env_enetaddr)) { + if (!is_zero_ether_addr(pdata->enetaddr) && + memcmp(pdata->enetaddr, env_enetaddr, 6)) { + printf("\nWarning: %s MAC addresses don't match:\n", + dev->name); + printf("Address in SROM is %pM\n", + pdata->enetaddr); + printf("Address in environment is %pM\n", + env_enetaddr); + } + + memcpy(pdata->enetaddr, env_enetaddr, 6); + } else if (is_valid_ether_addr(pdata->enetaddr)) { + eth_setenv_enetaddr_by_index(base_name, eth_number, + pdata->enetaddr); + printf("\nWarning: %s using MAC address from net device\n", + dev->name); + } else if (is_zero_ether_addr(pdata->enetaddr)) { + printf("\nError: %s address not set.\n", + dev->name); + return -EINVAL; + } + + const struct eth_ops *ops = dev->driver->ops; + if (ops->write_hwaddr && !eth_mac_skip(eth_number)) { + if (!is_valid_ether_addr(pdata->enetaddr)) { + printf("\nError: %s address %pM illegal value\n", + dev->name, pdata->enetaddr); + return -EINVAL; + } + + ret = ops->write_hwaddr(dev); + if (ret) + printf("\nWarning: %s failed to set MAC address\n", + dev->name); + } + + return ret; +} + +static int eth_uclass_init(struct uclass *class) +{ + bootstage_mark(BOOTSTAGE_ID_NET_ETH_START); + + eth_env_init(); + + return 0; +} + +static int eth_post_bind(struct udevice *dev) +{ + if (strchr(dev->name, ' ')) { + printf("\nError: eth device name "%s" has a space!\n", + dev->name); + return -EINVAL; + } + + if (!eth_get_dev()) { + eth_set_dev(dev); + eth_current_changed(); + } + + char *ethprime = getenv("ethprime"); + if (ethprime && strcmp(dev->name, ethprime) == 0) { + eth_set_dev(dev); + eth_current_changed(); + } + + /* + * Devices need to write the hwaddr even if not probed so that Linux + * will have access to the hwaddr that u-boot stored for the device. + */ + eth_write_hwaddr(dev, "eth", uclass_resolve_seq(dev)); + + return 0; +} + +static int eth_pre_unbind(struct udevice *dev) +{ + struct udevice *first = NULL; + struct udevice *current; + struct uclass *uc; + + uclass_get(UCLASS_ETH, &uc); + uclass_foreach_dev(current, uc) { + if (!first) + first = current; + if (current == dev) { + if (dev == first) { + current = list_entry(current->uclass_node.next, + struct udevice, uclass_node); + } else { + current = first; + } + eth_set_dev(current); + eth_current_changed(); + } + } + + return 0; +} + +static int eth_post_probe(struct udevice *dev) +{ + struct eth_device_priv *priv = dev->uclass_priv; + if (priv) + priv->state = ETH_STATE_INIT; + + return 0; +} + +UCLASS_DRIVER(eth) = { + .name = "eth", + .id = UCLASS_ETH, + .post_bind = eth_post_bind, + .pre_unbind = eth_pre_unbind, + .post_probe = eth_post_probe, + .init = eth_uclass_init, + .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), + .per_device_auto_alloc_size = sizeof(struct eth_device_priv), +}; +#endif + +#ifndef CONFIG_DM_ETH /* * CPU and board-specific Ethernet initializations. Aliased function * signals caller to move on @@ -423,6 +737,7 @@ int eth_rx(void)
return eth_current->recv(eth_current); } +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -486,7 +801,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) { - static struct eth_device *first_failed; + static void *first_failed; char *ethrotate;
/* @@ -515,7 +830,7 @@ void eth_set_current(void) { static char *act; static int env_changed_id; - struct eth_device *old_current; + void *old_current; int env_id;
if (!eth_get_dev()) /* XXX no current */

Hi Joe,
On 2 February 2015 at 17:38, Joe Hershberger joe.hershberger@ni.com wrote:
First just add support for MAC drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for our needs -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()).
common/board_r.c | 4 +- common/cmd_bdinfo.c | 2 + include/dm/uclass-id.h | 1 + include/net.h | 24 ++++ net/eth.c | 319 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 346 insertions(+), 4 deletions(-)
diff --git a/common/board_r.c b/common/board_r.c index 68a9448..75147b7 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -556,7 +556,7 @@ static int initr_bbmii(void) } #endif
-#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) static int initr_net(void) { puts("Net: "); @@ -825,7 +825,7 @@ init_fnc_t init_sequence_r[] = { #ifdef CONFIG_BITBANGMII initr_bbmii, #endif -#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) INIT_FUNC_WATCHDOG_RESET initr_net, #endif diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index e6d8a7a..8688cf9 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..ad96682 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */
UCLASS_ETH, /* Ethernet device */ UCLASS_COUNT, UCLASS_INVALID = -1,
diff --git a/include/net.h b/include/net.h index 7eef9cc..4d21d91 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,30 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH
You may not need this?
+struct eth_pdata {
phys_addr_t iobase;
unsigned char enetaddr[6];
+};
+struct eth_ops {
int (*init)(struct udevice *dev, bd_t *bis);
int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev);
void (*halt)(struct udevice *dev);
+#ifdef CONFIG_MCAST_TFTP
int (*mcast)(struct udevice *dev, const u8 *enetaddr, u8 set);
+#endif
int (*write_hwaddr)(struct udevice *dev);
+};
+struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +int eth_init_state_only(bd_t *bis); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ +#endif
+#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; diff --git a/net/eth.c b/net/eth.c index c02548c..1b5a169 100644 --- a/net/eth.c +++ b/net/eth.c @@ -72,6 +72,320 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH +#include <dm.h> +#include <dm/device-internal.h>
These should go at the top of the file - should be OK to always include them (i.e. no #ifdef)
+struct eth_device_priv {
int state;
void *priv;
+};
+struct eth_uclass_priv {
struct udevice *current;
+};
+static void eth_set_current_to_next(void) +{
struct uclass *uc;
struct eth_uclass_priv *uc_priv;
uclass_get(UCLASS_ETH, &uc);
This can actually return an error, although I agree there is little point in handling it. So I suppose this is OK.
uc_priv = uc->priv;
uclass_next_device(&uc_priv->current);
if (!uc_priv->current)
uclass_first_device(UCLASS_ETH, &uc_priv->current);
+}
+struct udevice *eth_get_dev(void) +{
struct uclass *uc;
blank line here
uclass_get(UCLASS_ETH, &uc);
struct eth_uclass_priv *uc_priv = uc->priv;
return uc_priv->current;
+}
+static void eth_set_dev(struct udevice *dev) +{
struct uclass *uc;
blank line here
uclass_get(UCLASS_ETH, &uc);
struct eth_uclass_priv *uc_priv = uc->priv;
uc_priv->current = dev;
+}
+unsigned char *eth_get_ethaddr(void) +{
struct eth_pdata *pdata;
blank line here
if (eth_get_dev()) {
pdata = eth_get_dev()->platdata;
if (pdata)
return pdata->enetaddr;
}
return NULL;
+}
+/* Set active state */ +int eth_init_state_only(bd_t *bis) +{
struct eth_device_priv *priv;
blank line here
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_ACTIVE;
}
return 0;
+} +/* Set passive state */ +void eth_halt_state_only(void) +{
struct eth_device_priv *priv;
blank line here
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
}
+}
+int eth_get_dev_index(void) +{
if (eth_get_dev())
return eth_get_dev()->seq;
return -1;
+}
+int eth_init(bd_t *bis) +{
struct udevice *current, *old_current, *dev;
struct uclass *uc;
current = eth_get_dev();
if (!current) {
puts("No ethernet found.\n");
return -1;
}
device_probe(current);
Check error
/* Sync environment with network devices */
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(dev, uc) {
uchar env_enetaddr[6];
if (eth_getenv_enetaddr_by_index("eth", dev->seq,
env_enetaddr)) {
struct eth_pdata *pdata = dev->platdata;
blank line
Do all devices have the same platdata by design? What if a particular device wants its own?
if (pdata)
What do you need this check?
memcpy(pdata->enetaddr, env_enetaddr, 6);
}
};
old_current = current;
do {
debug("Trying %s\n", current->name);
if (current->driver) {
const struct eth_ops *ops = current->driver->ops;
blank line
if (ops->init(current, bis) >= 0) {
struct eth_device_priv *priv =
current->uclass_priv;
if (priv)
priv->state = ETH_STATE_ACTIVE;
return 0;
}
}
debug("FAIL\n");
eth_try_another(0);
current = eth_get_dev();
} while (old_current != current);
return -ENODEV;
+}
+void eth_halt(void) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return;
if (!current->driver)
return;
const struct eth_ops *ops = current->driver->ops;
ops->halt(current);
struct eth_device_priv *priv = current->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
+}
+int eth_send(void *packet, int length) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
Seems like eth_get_dev() should return an error code if current or current->driver is NULL.
const struct eth_ops *ops = current->driver->ops;
return ops->send(current, packet, length);
+}
+int eth_rx(void) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
const struct eth_ops *ops = current->driver->ops;
return ops->recv(current);
+}
+static int eth_write_hwaddr(struct udevice *dev, const char *base_name,
int eth_number)
+{
unsigned char env_enetaddr[6];
int ret = 0;
eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
struct eth_pdata *pdata = dev->platdata;
if (!is_zero_ether_addr(env_enetaddr)) {
if (!is_zero_ether_addr(pdata->enetaddr) &&
memcmp(pdata->enetaddr, env_enetaddr, 6)) {
printf("\nWarning: %s MAC addresses don't match:\n",
dev->name);
printf("Address in SROM is %pM\n",
pdata->enetaddr);
printf("Address in environment is %pM\n",
env_enetaddr);
}
memcpy(pdata->enetaddr, env_enetaddr, 6);
} else if (is_valid_ether_addr(pdata->enetaddr)) {
eth_setenv_enetaddr_by_index(base_name, eth_number,
pdata->enetaddr);
printf("\nWarning: %s using MAC address from net device\n",
dev->name);
} else if (is_zero_ether_addr(pdata->enetaddr)) {
printf("\nError: %s address not set.\n",
dev->name);
return -EINVAL;
}
const struct eth_ops *ops = dev->driver->ops;
if (ops->write_hwaddr && !eth_mac_skip(eth_number)) {
if (!is_valid_ether_addr(pdata->enetaddr)) {
printf("\nError: %s address %pM illegal value\n",
dev->name, pdata->enetaddr);
return -EINVAL;
}
ret = ops->write_hwaddr(dev);
if (ret)
printf("\nWarning: %s failed to set MAC address\n",
dev->name);
}
The above code seems mostly duplicated but I suppose it is hard to make it common?
return ret;
+}
+static int eth_uclass_init(struct uclass *class) +{
bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
eth_env_init();
return 0;
+}
+static int eth_post_bind(struct udevice *dev) +{
if (strchr(dev->name, ' ')) {
printf("\nError: eth device name \"%s\" has a space!\n",
dev->name);
return -EINVAL;
}
if (!eth_get_dev()) {
eth_set_dev(dev);
eth_current_changed();
}
I still don't really get what you are doing here. Perhaps you could add some comments? There should be no probed devices at this stage since you are binding only.
char *ethprime = getenv("ethprime");
if (ethprime && strcmp(dev->name, ethprime) == 0) {
eth_set_dev(dev);
eth_current_changed();
}
/*
* Devices need to write the hwaddr even if not probed so that Linux
* will have access to the hwaddr that u-boot stored for the device.
*/
eth_write_hwaddr(dev, "eth", uclass_resolve_seq(dev));
return 0;
+}
+static int eth_pre_unbind(struct udevice *dev) +{
struct udevice *first = NULL;
struct udevice *current;
struct uclass *uc;
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(current, uc) {
if (!first)
first = current;
if (current == dev) {
if (dev == first) {
current = list_entry(current->uclass_node.next,
struct udevice, uclass_node);
} else {
current = first;
}
eth_set_dev(current);
eth_current_changed();
}
}
If this is turning down a device it really should happen in a remove() method. Maybe in post_remove()?
return 0;
+}
+static int eth_post_probe(struct udevice *dev) +{
struct eth_device_priv *priv = dev->uclass_priv;
if (priv)
priv->state = ETH_STATE_INIT;
return 0;
+}
+UCLASS_DRIVER(eth) = {
.name = "eth",
.id = UCLASS_ETH,
.post_bind = eth_post_bind,
.pre_unbind = eth_pre_unbind,
.post_probe = eth_post_probe,
.init = eth_uclass_init,
.priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
.per_device_auto_alloc_size = sizeof(struct eth_device_priv),
+}; +#endif
+#ifndef CONFIG_DM_ETH /*
- CPU and board-specific Ethernet initializations. Aliased function
- signals caller to move on
@@ -423,6 +737,7 @@ int eth_rx(void)
return eth_current->recv(eth_current);
} +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -486,7 +801,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) {
static struct eth_device *first_failed;
static void *first_failed; char *ethrotate; /*
@@ -515,7 +830,7 @@ void eth_set_current(void) { static char *act; static int env_changed_id;
struct eth_device *old_current;
void *old_current; int env_id; if (!eth_get_dev()) /* XXX no current */
-- 1.7.11.5
Regards, Simon

On Fri, Feb 6, 2015 at 7:25 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 2 February 2015 at 17:38, Joe Hershberger joe.hershberger@ni.com
wrote:
First just add support for MAC drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for
our needs
-Move the hwaddr to platdata so that its memory is allocated at bind
when we need it
-Prevent device from being probed before used by a command (i.e. before
eth_init()).
common/board_r.c | 4 +- common/cmd_bdinfo.c | 2 + include/dm/uclass-id.h | 1 + include/net.h | 24 ++++ net/eth.c | 319
++++++++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 346 insertions(+), 4 deletions(-)
diff --git a/common/board_r.c b/common/board_r.c index 68a9448..75147b7 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -556,7 +556,7 @@ static int initr_bbmii(void) } #endif
-#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) static int initr_net(void) { puts("Net: "); @@ -825,7 +825,7 @@ init_fnc_t init_sequence_r[] = { #ifdef CONFIG_BITBANGMII initr_bbmii, #endif -#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) INIT_FUNC_WATCHDOG_RESET initr_net, #endif diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index e6d8a7a..8688cf9 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..ad96682 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */
UCLASS_ETH, /* Ethernet device */ UCLASS_COUNT, UCLASS_INVALID = -1,
diff --git a/include/net.h b/include/net.h index 7eef9cc..4d21d91 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,30 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH
You may not need this?
I need it for the function prototypes that have a different device pointer parameter.
+struct eth_pdata {
phys_addr_t iobase;
unsigned char enetaddr[6];
+};
+struct eth_ops {
int (*init)(struct udevice *dev, bd_t *bis);
int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev);
void (*halt)(struct udevice *dev);
+#ifdef CONFIG_MCAST_TFTP
int (*mcast)(struct udevice *dev, const u8 *enetaddr, u8 set);
+#endif
int (*write_hwaddr)(struct udevice *dev);
+};
+struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +int eth_init_state_only(bd_t *bis); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ +#endif
+#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; diff --git a/net/eth.c b/net/eth.c index c02548c..1b5a169 100644 --- a/net/eth.c +++ b/net/eth.c @@ -72,6 +72,320 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH +#include <dm.h> +#include <dm/device-internal.h>
These should go at the top of the file - should be OK to always include them (i.e. no #ifdef)
OK... Moved them.
+struct eth_device_priv {
int state;
void *priv;
+};
+struct eth_uclass_priv {
struct udevice *current;
+};
+static void eth_set_current_to_next(void) +{
struct uclass *uc;
struct eth_uclass_priv *uc_priv;
uclass_get(UCLASS_ETH, &uc);
This can actually return an error, although I agree there is little point in handling it. So I suppose this is OK.
I think this should be a given.
uc_priv = uc->priv;
uclass_next_device(&uc_priv->current);
if (!uc_priv->current)
uclass_first_device(UCLASS_ETH, &uc_priv->current);
+}
+struct udevice *eth_get_dev(void) +{
struct uclass *uc;
blank line here
OK on all of these.
uclass_get(UCLASS_ETH, &uc);
struct eth_uclass_priv *uc_priv = uc->priv;
return uc_priv->current;
+}
+static void eth_set_dev(struct udevice *dev) +{
struct uclass *uc;
blank line here
uclass_get(UCLASS_ETH, &uc);
struct eth_uclass_priv *uc_priv = uc->priv;
uc_priv->current = dev;
+}
+unsigned char *eth_get_ethaddr(void) +{
struct eth_pdata *pdata;
blank line here
if (eth_get_dev()) {
pdata = eth_get_dev()->platdata;
if (pdata)
return pdata->enetaddr;
}
return NULL;
+}
+/* Set active state */ +int eth_init_state_only(bd_t *bis) +{
struct eth_device_priv *priv;
blank line here
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_ACTIVE;
}
return 0;
+} +/* Set passive state */ +void eth_halt_state_only(void) +{
struct eth_device_priv *priv;
blank line here
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
}
+}
+int eth_get_dev_index(void) +{
if (eth_get_dev())
return eth_get_dev()->seq;
return -1;
+}
+int eth_init(bd_t *bis) +{
struct udevice *current, *old_current, *dev;
struct uclass *uc;
current = eth_get_dev();
if (!current) {
puts("No ethernet found.\n");
return -1;
}
device_probe(current);
Check error
OK.
/* Sync environment with network devices */
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(dev, uc) {
uchar env_enetaddr[6];
if (eth_getenv_enetaddr_by_index("eth", dev->seq,
env_enetaddr)) {
struct eth_pdata *pdata = dev->platdata;
blank line
Do all devices have the same platdata by design? What if a particular device wants its own?
That's a good question. I imagine some devices may have something unique, but I would expect they would read that data into the priv data that they define. How do other subsystems handle platform data for unique devices?
if (pdata)
What do you need this check?
No. This was left over from when enetaddr was in priv.
memcpy(pdata->enetaddr, env_enetaddr,
6);
}
};
old_current = current;
do {
debug("Trying %s\n", current->name);
if (current->driver) {
const struct eth_ops *ops =
current->driver->ops;
blank line
if (ops->init(current, bis) >= 0) {
struct eth_device_priv *priv =
current->uclass_priv;
if (priv)
priv->state = ETH_STATE_ACTIVE;
return 0;
}
}
debug("FAIL\n");
eth_try_another(0);
current = eth_get_dev();
} while (old_current != current);
return -ENODEV;
+}
+void eth_halt(void) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return;
if (!current->driver)
return;
const struct eth_ops *ops = current->driver->ops;
ops->halt(current);
struct eth_device_priv *priv = current->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
+}
+int eth_send(void *packet, int length) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
Seems like eth_get_dev() should return an error code if current or current->driver is NULL.
It's returning a pointer, so I prefer it to be NULL or a valid pointer.
Perhaps you meant to say that eth_send() should return an error code?
const struct eth_ops *ops = current->driver->ops;
return ops->send(current, packet, length);
+}
+int eth_rx(void) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
const struct eth_ops *ops = current->driver->ops;
return ops->recv(current);
+}
+static int eth_write_hwaddr(struct udevice *dev, const char *base_name,
int eth_number)
+{
unsigned char env_enetaddr[6];
int ret = 0;
eth_getenv_enetaddr_by_index(base_name, eth_number,
env_enetaddr);
struct eth_pdata *pdata = dev->platdata;
if (!is_zero_ether_addr(env_enetaddr)) {
if (!is_zero_ether_addr(pdata->enetaddr) &&
memcmp(pdata->enetaddr, env_enetaddr, 6)) {
printf("\nWarning: %s MAC addresses don't
match:\n",
dev->name);
printf("Address in SROM is %pM\n",
pdata->enetaddr);
printf("Address in environment is %pM\n",
env_enetaddr);
}
memcpy(pdata->enetaddr, env_enetaddr, 6);
} else if (is_valid_ether_addr(pdata->enetaddr)) {
eth_setenv_enetaddr_by_index(base_name, eth_number,
pdata->enetaddr);
printf("\nWarning: %s using MAC address from net
device\n",
dev->name);
} else if (is_zero_ether_addr(pdata->enetaddr)) {
printf("\nError: %s address not set.\n",
dev->name);
return -EINVAL;
}
const struct eth_ops *ops = dev->driver->ops;
if (ops->write_hwaddr && !eth_mac_skip(eth_number)) {
if (!is_valid_ether_addr(pdata->enetaddr)) {
printf("\nError: %s address %pM illegal
value\n",
dev->name, pdata->enetaddr);
return -EINVAL;
}
ret = ops->write_hwaddr(dev);
if (ret)
printf("\nWarning: %s failed to set MAC
address\n",
dev->name);
}
The above code seems mostly duplicated but I suppose it is hard to make it common?
It is, but I look forward to the day when we delete the other copy. It would be difficult to combine, for sure.
return ret;
+}
+static int eth_uclass_init(struct uclass *class) +{
bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
eth_env_init();
return 0;
+}
+static int eth_post_bind(struct udevice *dev) +{
if (strchr(dev->name, ' ')) {
printf("\nError: eth device name \"%s\" has a space!\n",
dev->name);
return -EINVAL;
}
if (!eth_get_dev()) {
eth_set_dev(dev);
eth_current_changed();
}
I still don't really get what you are doing here. Perhaps you could add some comments? There should be no probed devices at this stage since you are binding only.
This has changed a fair amount in v3. Please comment there if it's more clear now.
char *ethprime = getenv("ethprime");
if (ethprime && strcmp(dev->name, ethprime) == 0) {
eth_set_dev(dev);
eth_current_changed();
}
/*
* Devices need to write the hwaddr even if not probed so that
Linux
* will have access to the hwaddr that u-boot stored for the
device.
*/
eth_write_hwaddr(dev, "eth", uclass_resolve_seq(dev));
return 0;
+}
+static int eth_pre_unbind(struct udevice *dev) +{
struct udevice *first = NULL;
struct udevice *current;
struct uclass *uc;
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(current, uc) {
if (!first)
first = current;
if (current == dev) {
if (dev == first) {
current =
list_entry(current->uclass_node.next,
struct udevice, uclass_node);
} else {
current = first;
}
eth_set_dev(current);
eth_current_changed();
}
}
If this is turning down a device it really should happen in a remove() method. Maybe in post_remove()?
This has changed a fair amount in v3. Please comment there if it's more clear now.
return 0;
+}
+static int eth_post_probe(struct udevice *dev) +{
struct eth_device_priv *priv = dev->uclass_priv;
if (priv)
priv->state = ETH_STATE_INIT;
return 0;
+}
+UCLASS_DRIVER(eth) = {
.name = "eth",
.id = UCLASS_ETH,
.post_bind = eth_post_bind,
.pre_unbind = eth_pre_unbind,
.post_probe = eth_post_probe,
.init = eth_uclass_init,
.priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
.per_device_auto_alloc_size = sizeof(struct eth_device_priv),
+}; +#endif
+#ifndef CONFIG_DM_ETH /*
- CPU and board-specific Ethernet initializations. Aliased function
- signals caller to move on
@@ -423,6 +737,7 @@ int eth_rx(void)
return eth_current->recv(eth_current);
} +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -486,7 +801,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) {
static struct eth_device *first_failed;
static void *first_failed; char *ethrotate; /*
@@ -515,7 +830,7 @@ void eth_set_current(void) { static char *act; static int env_changed_id;
struct eth_device *old_current;
void *old_current; int env_id; if (!eth_get_dev()) /* XXX no current */
-- 1.7.11.5
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi Joe,
On 10 February 2015 at 23:25, Joe Hershberger joe.hershberger@gmail.com wrote:
On Fri, Feb 6, 2015 at 7:25 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 2 February 2015 at 17:38, Joe Hershberger joe.hershberger@ni.com wrote:
First just add support for MAC drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for our needs -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()).
common/board_r.c | 4 +- common/cmd_bdinfo.c | 2 + include/dm/uclass-id.h | 1 + include/net.h | 24 ++++ net/eth.c | 319 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 346 insertions(+), 4 deletions(-)
[snip]
diff --git a/net/eth.c b/net/eth.c index c02548c..1b5a169 100644 --- a/net/eth.c +++ b/net/eth.c @@ -72,6 +72,320 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH +#include <dm.h> +#include <dm/device-internal.h>
These should go at the top of the file - should be OK to always include them (i.e. no #ifdef)
OK... Moved them.
+struct eth_device_priv {
int state;
void *priv;
+};
+struct eth_uclass_priv {
struct udevice *current;
+};
+static void eth_set_current_to_next(void) +{
struct uclass *uc;
struct eth_uclass_priv *uc_priv;
uclass_get(UCLASS_ETH, &uc);
This can actually return an error, although I agree there is little point in handling it. So I suppose this is OK.
I think this should be a given.
uc_priv = uc->priv;
uclass_next_device(&uc_priv->current);
if (!uc_priv->current)
uclass_first_device(UCLASS_ETH, &uc_priv->current);
+}
+struct udevice *eth_get_dev(void) +{
struct uclass *uc;
blank line here
OK on all of these.
uclass_get(UCLASS_ETH, &uc);
struct eth_uclass_priv *uc_priv = uc->priv;
return uc_priv->current;
+}
+static void eth_set_dev(struct udevice *dev) +{
struct uclass *uc;
blank line here
uclass_get(UCLASS_ETH, &uc);
struct eth_uclass_priv *uc_priv = uc->priv;
uc_priv->current = dev;
+}
+unsigned char *eth_get_ethaddr(void) +{
struct eth_pdata *pdata;
blank line here
if (eth_get_dev()) {
pdata = eth_get_dev()->platdata;
if (pdata)
return pdata->enetaddr;
}
return NULL;
+}
+/* Set active state */ +int eth_init_state_only(bd_t *bis) +{
struct eth_device_priv *priv;
blank line here
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_ACTIVE;
}
return 0;
+} +/* Set passive state */ +void eth_halt_state_only(void) +{
struct eth_device_priv *priv;
blank line here
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
}
+}
+int eth_get_dev_index(void) +{
if (eth_get_dev())
return eth_get_dev()->seq;
return -1;
+}
+int eth_init(bd_t *bis) +{
struct udevice *current, *old_current, *dev;
struct uclass *uc;
current = eth_get_dev();
if (!current) {
puts("No ethernet found.\n");
return -1;
}
device_probe(current);
Check error
OK.
/* Sync environment with network devices */
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(dev, uc) {
uchar env_enetaddr[6];
if (eth_getenv_enetaddr_by_index("eth", dev->seq,
env_enetaddr)) {
struct eth_pdata *pdata = dev->platdata;
blank line
Do all devices have the same platdata by design? What if a particular device wants its own?
That's a good question. I imagine some devices may have something unique, but I would expect they would read that data into the priv data that they define. How do other subsystems handle platform data for unique devices?
There isn't great support for it. Typically the device has its own platform data. For buses there is per-child platform data, which the uclass can define, but we don't have uclass-defined platform data for normal devices (which are not children).
if (pdata)
What do you need this check?
No. This was left over from when enetaddr was in priv.
memcpy(pdata->enetaddr, env_enetaddr,
6);
}
};
old_current = current;
do {
debug("Trying %s\n", current->name);
if (current->driver) {
const struct eth_ops *ops =
current->driver->ops;
blank line
if (ops->init(current, bis) >= 0) {
struct eth_device_priv *priv =
current->uclass_priv;
if (priv)
priv->state = ETH_STATE_ACTIVE;
return 0;
}
}
debug("FAIL\n");
eth_try_another(0);
current = eth_get_dev();
} while (old_current != current);
return -ENODEV;
+}
+void eth_halt(void) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return;
if (!current->driver)
return;
const struct eth_ops *ops = current->driver->ops;
ops->halt(current);
struct eth_device_priv *priv = current->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
+}
+int eth_send(void *packet, int length) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
Seems like eth_get_dev() should return an error code if current or current->driver is NULL.
It's returning a pointer, so I prefer it to be NULL or a valid pointer.
Perhaps you meant to say that eth_send() should return an error code?
Well yes that too. But -1 is not a valid error anymore. You need to use -EPERM or something. And whatever went wrong with eth_get_dev() should really be returned. So you could do:
ret = eth_get_dev(¤t); if (ret) return ret;
or if you prefer:
current = eth_get_dev(); if (IS_ERR(current)) return PTR_ERR(current);
const struct eth_ops *ops = current->driver->ops;
return ops->send(current, packet, length);
+}
Regards, Simon

Hi Simon,
On Thu, Feb 12, 2015 at 11:20 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 23:25, Joe Hershberger joe.hershberger@gmail.com
wrote:
On Fri, Feb 6, 2015 at 7:25 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 2 February 2015 at 17:38, Joe Hershberger joe.hershberger@ni.com wrote:
First just add support for MAC drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for
our
needs -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e.
before
eth_init()).
common/board_r.c | 4 +- common/cmd_bdinfo.c | 2 + include/dm/uclass-id.h | 1 + include/net.h | 24 ++++ net/eth.c | 319 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 346 insertions(+), 4 deletions(-)
[snip]
diff --git a/net/eth.c b/net/eth.c index c02548c..1b5a169 100644 --- a/net/eth.c +++ b/net/eth.c @@ -72,6 +72,320 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH +#include <dm.h> +#include <dm/device-internal.h>
These should go at the top of the file - should be OK to always include them (i.e. no #ifdef)
OK... Moved them.
+struct eth_device_priv {
int state;
void *priv;
+};
+struct eth_uclass_priv {
struct udevice *current;
+};
+static void eth_set_current_to_next(void) +{
struct uclass *uc;
struct eth_uclass_priv *uc_priv;
uclass_get(UCLASS_ETH, &uc);
This can actually return an error, although I agree there is little point in handling it. So I suppose this is OK.
I think this should be a given.
uc_priv = uc->priv;
uclass_next_device(&uc_priv->current);
if (!uc_priv->current)
uclass_first_device(UCLASS_ETH, &uc_priv->current);
+}
+struct udevice *eth_get_dev(void) +{
struct uclass *uc;
blank line here
OK on all of these.
uclass_get(UCLASS_ETH, &uc);
struct eth_uclass_priv *uc_priv = uc->priv;
return uc_priv->current;
+}
+static void eth_set_dev(struct udevice *dev) +{
struct uclass *uc;
blank line here
uclass_get(UCLASS_ETH, &uc);
struct eth_uclass_priv *uc_priv = uc->priv;
uc_priv->current = dev;
+}
+unsigned char *eth_get_ethaddr(void) +{
struct eth_pdata *pdata;
blank line here
if (eth_get_dev()) {
pdata = eth_get_dev()->platdata;
if (pdata)
return pdata->enetaddr;
}
return NULL;
+}
+/* Set active state */ +int eth_init_state_only(bd_t *bis) +{
struct eth_device_priv *priv;
blank line here
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_ACTIVE;
}
return 0;
+} +/* Set passive state */ +void eth_halt_state_only(void) +{
struct eth_device_priv *priv;
blank line here
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
}
+}
+int eth_get_dev_index(void) +{
if (eth_get_dev())
return eth_get_dev()->seq;
return -1;
+}
+int eth_init(bd_t *bis) +{
struct udevice *current, *old_current, *dev;
struct uclass *uc;
current = eth_get_dev();
if (!current) {
puts("No ethernet found.\n");
return -1;
}
device_probe(current);
Check error
OK.
/* Sync environment with network devices */
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(dev, uc) {
uchar env_enetaddr[6];
if (eth_getenv_enetaddr_by_index("eth", dev->seq,
env_enetaddr)) {
struct eth_pdata *pdata = dev->platdata;
blank line
Do all devices have the same platdata by design? What if a particular device wants its own?
That's a good question. I imagine some devices may have something
unique,
but I would expect they would read that data into the priv data that
they
define. How do other subsystems handle platform data for unique
devices?
There isn't great support for it. Typically the device has its own platform data. For buses there is per-child platform data, which the uclass can define, but we don't have uclass-defined platform data for normal devices (which are not children).
So I guess that means we should leave it until needed and then extend core to support such things on non-bus-children?
if (pdata)
What do you need this check?
No. This was left over from when enetaddr was in priv.
memcpy(pdata->enetaddr, env_enetaddr,
6);
}
};
old_current = current;
do {
debug("Trying %s\n", current->name);
if (current->driver) {
const struct eth_ops *ops =
current->driver->ops;
blank line
if (ops->init(current, bis) >= 0) {
struct eth_device_priv *priv =
current->uclass_priv;
if (priv)
priv->state =
ETH_STATE_ACTIVE;
return 0;
}
}
debug("FAIL\n");
eth_try_another(0);
current = eth_get_dev();
} while (old_current != current);
return -ENODEV;
+}
+void eth_halt(void) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return;
if (!current->driver)
return;
const struct eth_ops *ops = current->driver->ops;
ops->halt(current);
struct eth_device_priv *priv = current->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
+}
+int eth_send(void *packet, int length) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
Seems like eth_get_dev() should return an error code if current or current->driver is NULL.
It's returning a pointer, so I prefer it to be NULL or a valid pointer.
Perhaps you meant to say that eth_send() should return an error code?
Well yes that too. But -1 is not a valid error anymore. You need to use -EPERM or something. And whatever went wrong with eth_get_dev() should really be returned. So you could do:
ret = eth_get_dev(¤t); if (ret) return ret;
I don't see this as equivalent.
or if you prefer:
current = eth_get_dev(); if (IS_ERR(current)) return PTR_ERR(current);
This makes more sense, but given that eth_get_dev() is not doing anything other than returning a static global variable, it seems that "NULL" is a valid return. That's just the value of that variable. Nothing "went wrong". It seems like it's jumping through hoops to convert NULL into some error code, return that code as a pointer, then convert it back, when the test for NULL is far more straightforward in the caller and easier to read.
I completely agree about not returning -1 from eth_send() and already have that change in for the next version.
Thanks, -Joe

Add basic network support to sandbox which includes a network driver.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v2: -Change printfs to debug in sandbox driver -Remove unused priv struct for sandbox driver
arch/sandbox/dts/sandbox.dts | 4 +++ drivers/net/Makefile | 2 ++ drivers/net/sandbox.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 14 +++++--- 4 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 drivers/net/sandbox.c
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 4c63e4f..502eb3d 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -183,4 +183,8 @@ }; };
+ eth@10002000 { + compatible = "sandbox,eth"; + reg = <0x10002000 0x1000>; + }; }; diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 46c4ac6..2659a8a 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -50,6 +50,8 @@ obj-$(CONFIG_NS8382X) += ns8382x.o obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o +obj-$(CONFIG_ETH_SANDBOX) += sandbox.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c new file mode 100644 index 0000000..3b7c3ac --- /dev/null +++ b/drivers/net/sandbox.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + +int sb_eth_init(struct udevice *dev, bd_t *bis) +{ + debug("eth_sandbox: Init\n"); + + return 0; +} + +int sb_eth_send(struct udevice *dev, void *packet, int length) +{ + debug("eth_sandbox: Send packet %d\n", length); + + return 0; +#endif +} + +int sb_eth_recv(struct udevice *dev) +{ + return 0; +} + +void sb_eth_halt(struct udevice *dev) +{ + debug("eth_sandbox: Halt\n"); +} + +int sb_eth_write_hwaddr(struct udevice *dev) +{ + debug("eth_sandbox: Write HW ADDR\n"); + return 0; +} + +static const struct eth_ops eth_sandbox_ops = { + .init = sb_eth_init, + .send = sb_eth_send, + .recv = sb_eth_recv, + .halt = sb_eth_halt, + .write_hwaddr = sb_eth_write_hwaddr, +}; + +static int eth_sandbox_remove(struct udevice *dev) +{ + return 0; +} + +#ifdef CONFIG_OF_CONTROL +static int sandbox_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev->platdata; + + pdata->iobase = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); + return 0; +} + +static const struct udevice_id sandbox_eth_ids[] = { + { .compatible = "sandbox,eth" }, + { } +}; +#endif + +U_BOOT_DRIVER(eth_sandbox) = { + .name = "eth_sandbox", + .id = UCLASS_ETH, + .of_match = of_match_ptr(sandbox_eth_ids), + .ofdata_to_platdata = of_match_ptr(sandbox_eth_ofdata_to_platdata), + .remove = eth_sandbox_remove, + .ops = ð_sandbox_ops, + .priv_auto_alloc_size = sizeof(struct eth_sandbox_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index e9d3f32..484caa8 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -139,9 +139,9 @@ /* include default commands */ #include <config_cmd_default.h>
-/* We don't have networking support yet */ -#undef CONFIG_CMD_NET -#undef CONFIG_CMD_NFS +#define CONFIG_DM_ETH +#define CONFIG_ETH_SANDBOX +#define CONFIG_CMD_PING
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY @@ -184,12 +184,16 @@
#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial,cros-ec-keyb\0" \ "stdout=serial,lcd\0" \ - "stderr=serial,lcd\0" + "stderr=serial,lcd\0" \ + "ethaddr=00:00:11:22:33:44\0" \ + "ipaddr=1.2.3.4\0" #else
#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial\0" \ "stdout=serial,lcd\0" \ - "stderr=serial,lcd\0" + "stderr=serial,lcd\0" \ + "ethaddr=00:00:11:22:33:44\0" \ + "ipaddr=1.2.3.4\0" #endif
#define CONFIG_GZIP_COMPRESSED

On 2 February 2015 at 17:38, Joe Hershberger joe.hershberger@ni.com wrote:
Add basic network support to sandbox which includes a network driver.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v2: -Change printfs to debug in sandbox driver -Remove unused priv struct for sandbox driver
arch/sandbox/dts/sandbox.dts | 4 +++ drivers/net/Makefile | 2 ++ drivers/net/sandbox.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 14 +++++--- 4 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 drivers/net/sandbox.c
Reviewed-by: Simon Glass sjg@chromium.org

The sandbox driver will now generate response traffic to exercise the ping command even when no network exists. This allows the basic data pathways of the DM to be tested.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com ---
Changes in v2: -Change printfs to debug in sandbox driver -Move static data to priv -Move fake hwaddr to the device tree
arch/sandbox/dts/sandbox.dts | 1 + drivers/net/sandbox.c | 95 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+)
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 502eb3d..ba635e8 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -186,5 +186,6 @@ eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; }; }; diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 3b7c3ac..79a2fd5 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -15,16 +15,102 @@
DECLARE_GLOBAL_DATA_PTR;
+struct eth_sandbox_priv { + uchar fake_host_hwaddr[ARP_HLEN]; + IPaddr_t fake_host_ipaddr; + uchar recv_packet_buffer[PKTSIZE]; + int recv_packet_length; +}; + int sb_eth_init(struct udevice *dev, bd_t *bis) { debug("eth_sandbox: Init\n");
+ struct eth_sandbox_priv *priv = dev->priv; + u32 int_array[ARP_HLEN]; + int i; + + fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "fake-host-hwaddr", + int_array, ARP_HLEN); + for (i = 0; i < ARP_HLEN; i++) + priv->fake_host_hwaddr[i] = (uchar)int_array[i]; + return 0; }
int sb_eth_send(struct udevice *dev, void *packet, int length) { debug("eth_sandbox: Send packet %d\n", length); + struct eth_sandbox_priv *priv = dev->priv; + + struct ethernet_hdr *eth = packet; + if (ntohs(eth->et_protlen) == PROT_ARP) { + struct arp_hdr *arp = packet + ETHER_HDR_SIZE; + if (ntohs(arp->ar_op) == ARPOP_REQUEST) { + /* store this as the assumed IP of the fake host */ + priv->fake_host_ipaddr = NetReadIP(&arp->ar_tpa); + /* Formulate a fake response */ + struct ethernet_hdr *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); + + struct arp_hdr *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); + NetWriteIP(&arp_recv->ar_spa, priv->fake_host_ipaddr); + memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN); + NetCopyIP(&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) { + /* reply to the ping */ + memcpy(priv->recv_packet_buffer, packet, + length); + struct ethernet_hdr *eth_recv = + (void *)priv->recv_packet_buffer; + struct ip_udp_hdr *ipr = + (void *)priv->recv_packet_buffer + + ETHER_HDR_SIZE; + struct icmp_hdr *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; + NetCopyIP((void *)&ipr->ip_dst, &ip->ip_src); + NetWriteIP((void *)&ipr->ip_src, + priv->fake_host_ipaddr); + ipr->ip_sum = ~NetCksum((uchar *)ipr, + IP_HDR_SIZE >> 1); + + icmpr->type = ICMP_ECHO_REPLY; + icmpr->checksum = 0; + icmpr->checksum = ~NetCksum((uchar *)icmpr, + (length - ETHER_HDR_SIZE - + IP_HDR_SIZE) >> 1); + + priv->recv_packet_length = length; + } + } + }
return 0; #endif @@ -32,6 +118,15 @@ int sb_eth_send(struct udevice *dev, void *packet, int length)
int sb_eth_recv(struct udevice *dev) { + struct eth_sandbox_priv *priv = dev->priv; + if (priv->recv_packet_length) { + int lcl_recv_packet_length = priv->recv_packet_length; + debug("eth_sandbox: received packet %d\n", + priv->recv_packet_length); + priv->recv_packet_length = 0; + NetReceive((void *)priv->recv_packet_buffer, + lcl_recv_packet_length); + } return 0; }

On 2 February 2015 at 17:38, Joe Hershberger joe.hershberger@ni.com wrote:
The sandbox driver will now generate response traffic to exercise the ping command even when no network exists. This allows the basic data pathways of the DM to be tested.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v2: -Change printfs to debug in sandbox driver -Move static data to priv -Move fake hwaddr to the device tree
arch/sandbox/dts/sandbox.dts | 1 + drivers/net/sandbox.c | 95 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

This doesn't build right now
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v2: -Added the raw packet proof-of-concept patch.
drivers/net/sandbox-raw.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/sandbox.c | 23 ++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 drivers/net/sandbox-raw.c
diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c new file mode 100644 index 0000000..735783c --- /dev/null +++ b/drivers/net/sandbox-raw.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <linux/if.h> +#include <linux/if_ether.h> +#include <linux/if_packet.h> +#include <sys/socket.h> +#include <netinet/in.h> + +int sandbox_raw_init(int *sd, void **devp) +{ + uint8_t eth0mac[6]; + int tempsd = 0; + struct ifreq ifr; + const char *ifname = "eth0"; + + strcpy(ifr.ifr_name, ifname); + ifr.ifr_addr.sa_family = AF_INET; + memset(eth0mac, 0, 6); + tempsd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + if (tempsd < 0) + return 1; + if (ioctl(tempsd, SIOCGIFHWADDR, &ifr) < 0) { + close(tempsd); + return 1; + } + memcpy(eth0mac, ifr.ifr_hwaddr.sa_data, 6 * sizeof(uint8_t)); + close(tempsd); + + *devp = malloc(sizeof(struct sockaddr_ll)); + struct sockaddr_ll *device = *devp; + memset(device, 0, sizeof(struct sockaddr_ll)); + device->sll_ifindex = if_nametoindex(ifname); + device->sll_family = AF_PACKET; + memcpy(device->sll_addr, eth0mac, 6); + device->sll_halen = htons(6); + + *sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + + return 0; +} + +int sandbox_raw_send(void *packet, int length, int sd, void *device) +{ + if (sendto(sd, packet, length, 0, + (struct sockaddr *)device, sizeof(struct sockaddr)) <= 0) + return 1; + return 0; +} + +int sandbox_raw_halt(int sd) +{ + close(sd); +} diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 79a2fd5..c5113b4 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -20,8 +20,18 @@ struct eth_sandbox_priv { IPaddr_t fake_host_ipaddr; uchar recv_packet_buffer[PKTSIZE]; int recv_packet_length; +#ifdef CONFIG_ETH_SANDBOX_RAW + void *device; + int sd; +#endif };
+#ifdef CONFIG_ETH_SANDBOX_RAW +int sandbox_raw_init(int *sd, void **devp); +int sandbox_raw_send(void *packet, int length, int sd, void *device); +int sandbox_raw_halt(int sd); +#endif + int sb_eth_init(struct udevice *dev, bd_t *bis) { debug("eth_sandbox: Init\n"); @@ -35,6 +45,11 @@ int sb_eth_init(struct udevice *dev, bd_t *bis) for (i = 0; i < ARP_HLEN; i++) priv->fake_host_hwaddr[i] = (uchar)int_array[i];
+#ifdef CONFIG_ETH_SANDBOX_RAW + int ret = sandbox_raw_init(&(priv->sd), &(priv->device)); + if (ret) + return ret; +#endif return 0; }
@@ -43,6 +58,9 @@ int sb_eth_send(struct udevice *dev, void *packet, int length) debug("eth_sandbox: Send packet %d\n", length); struct eth_sandbox_priv *priv = dev->priv;
+#ifdef CONFIG_ETH_SANDBOX_RAW + return sandbox_raw_send(packet, length, priv->sd, priv->device); +#else struct ethernet_hdr *eth = packet; if (ntohs(eth->et_protlen) == PROT_ARP) { struct arp_hdr *arp = packet + ETHER_HDR_SIZE; @@ -133,6 +151,11 @@ int sb_eth_recv(struct udevice *dev) void sb_eth_halt(struct udevice *dev) { debug("eth_sandbox: Halt\n"); + +#ifdef CONFIG_ETH_SANDBOX_RAW + struct eth_sandbox_priv *priv = dev->priv; + sandbox_raw_halt(priv->sd); +#endif }
int sb_eth_write_hwaddr(struct udevice *dev)

Hi Joe,
On 2 February 2015 at 17:38, Joe Hershberger joe.hershberger@ni.com wrote:
This doesn't build right now
Is this intended to connect sandbox to the real network? Very interesting if so.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v2: -Added the raw packet proof-of-concept patch.
drivers/net/sandbox-raw.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/sandbox.c | 23 ++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 drivers/net/sandbox-raw.c
Regards, Simon

For now this simply addresses the MAC part of the network hardware. The next part to implement is the PHY children. I wanted to get early feedback on what I have so far to make sure I'm going in the direction that Simon envisioned.
I've now added unit tests to verify functionality.
Added an additional patch that I've been playing with to allow actual networking from within sandbox, but I haven't come across a good way to make it build in the u-boot build system. Any good ideas are welcome.
Changes in v3: -Add seq patch to dm core -Reorder dm test makefile -Move the get_dev_by_* protos to also be !DM_ETH like the impl -Correct the pre_unbind logic -Correct failure chaining from bind to probe to init --Fail init if not activated --Fail probe if ethaddr not set -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the previous selection -Allow current eth dev to be NULL -Fixed blank line formatting for variable declaration -Added 2 more ethaddr to sandbox -Print which device in the debug write hwaddr -Prevent a crash if memory is not allocated -Added dm eth testing -Added support for aliases -Added support for ethprime -Added testing for netretry -Made the os raw packet support for sandbox eth build and work.
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for our needs -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()). -Change printfs to debug in sandbox driver -Remove unused priv struct for sandbox driver -Change printfs to debug in sandbox driver -Move static data to priv -Move fake hwaddr to the device tree -Added the raw packet proof-of-concept patch.
Joe Hershberger (14): dm: core: Allow seq numbers to be resolved before probe test: dm: Reorder the objects to build net: Provide a function to get the current MAC address net: Rename helper function to be more clear net: Remove unneeded "extern" in net.h net: Refactor in preparation for driver model dm: eth: Add basic driver model support to Ethernet stack dm: eth: Add network support to sandbox dm: eth: Add ARP and PING response to sandbox driver test: dm: eth: Add tests for the eth dm implementation dm: eth: Add support for aliases dm: eth: Add support for ethprime env var dm: eth: Add testing for netretry env var dm: eth: Add a bridge to a real network for sandbox
arch/mips/cpu/mips32/au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- arch/sandbox/dts/sandbox.dts | 11 + arch/sandbox/include/asm/sandbox-raw-os.h | 16 + common/board_r.c | 4 +- common/cmd_bdinfo.c | 2 + drivers/core/uclass.c | 4 +- drivers/net/Makefile | 12 + drivers/net/sandbox-raw-os.c | 105 +++++++ drivers/net/sandbox-raw.c | 128 ++++++++ drivers/net/sandbox.c | 187 ++++++++++++ include/configs/sandbox.h | 19 +- include/dm/uclass-id.h | 1 + include/fdtdec.h | 1 + include/net.h | 164 +++++++---- lib/fdtdec.c | 1 + net/eth.c | 474 ++++++++++++++++++++++++++---- net/net.c | 2 +- test/dm/Makefile | 5 +- test/dm/eth.c | 110 +++++++ test/dm/test.dts | 20 ++ 23 files changed, 1146 insertions(+), 128 deletions(-) create mode 100644 arch/sandbox/include/asm/sandbox-raw-os.h create mode 100644 drivers/net/sandbox-raw-os.c create mode 100644 drivers/net/sandbox-raw.c create mode 100644 drivers/net/sandbox.c create mode 100644 test/dm/eth.c

Before this patch, if the sequence numbers were resolved before probe, this code would insist on defining new non-conflicting-with-itself seq numbers. Now any "non -1" seq number is accepted as already resolved.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v3: -Add seq patch to dm core
Changes in v2: None
drivers/core/uclass.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 289a5d2..2d8b6f8 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -366,7 +366,9 @@ int uclass_resolve_seq(struct udevice *dev) int seq; int ret;
- assert(dev->seq == -1); + if (dev->seq != -1) + return dev->seq; + ret = uclass_find_device_by_seq(dev->uclass->uc_drv->id, dev->req_seq, false, &dup); if (!ret) {

Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
Before this patch, if the sequence numbers were resolved before probe, this code would insist on defining new non-conflicting-with-itself seq numbers. Now any "non -1" seq number is accepted as already resolved.
Can you explain what problem this solves? At present, when probing a device, ->seq must be -1 (sort-of by definition since it doesn't exist as an active device in the uclass).
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v3: -Add seq patch to dm core
Changes in v2: None
drivers/core/uclass.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 289a5d2..2d8b6f8 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -366,7 +366,9 @@ int uclass_resolve_seq(struct udevice *dev) int seq; int ret;
assert(dev->seq == -1);
if (dev->seq != -1)
return dev->seq;
ret = uclass_find_device_by_seq(dev->uclass->uc_drv->id, dev->req_seq, false, &dup); if (!ret) {
-- 1.7.11.5
Regards, Simon

Hi Simon,
On Tue, Feb 10, 2015 at 10:39 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com
wrote:
Before this patch, if the sequence numbers were resolved before probe, this code would insist on defining new non-conflicting-with-itself seq numbers. Now any "non -1" seq number is accepted as already resolved.
Can you explain what problem this solves? At present, when probing a device, ->seq must be -1 (sort-of by definition since it doesn't exist as an active device in the uclass).
Please look at eth_post_bind() in patch 07/14. The Ethernet devices need to write their hardware addresses to the registers in bind (since it needs to happen regardless of the device being used so that Linux will see the MAC address). As such, the sequence number is needed to look up the ethaddr. In order to avoid probing all the devices to get the seq number resolved, I resolve it in post_bind to avoid the rest of the overhead (thus no longer probing in post_bind, which was one of the issues previously). Then when probe comes along, the seq is already resolved. That's why this patch is needed.
Thanks, -Joe

Hi Joe,
On 10 February 2015 at 23:08, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Tue, Feb 10, 2015 at 10:39 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
Before this patch, if the sequence numbers were resolved before probe, this code would insist on defining new non-conflicting-with-itself seq numbers. Now any "non -1" seq number is accepted as already resolved.
Can you explain what problem this solves? At present, when probing a device, ->seq must be -1 (sort-of by definition since it doesn't exist as an active device in the uclass).
Please look at eth_post_bind() in patch 07/14. The Ethernet devices need to write their hardware addresses to the registers in bind (since it needs to happen regardless of the device being used so that Linux will see the MAC address). As such, the sequence number is needed to look up the ethaddr. In order to avoid probing all the devices to get the seq number resolved, I resolve it in post_bind to avoid the rest of the overhead (thus no longer probing in post_bind, which was one of the issues previously). Then when probe comes along, the seq is already resolved. That's why this patch is needed.
OK I see.
This is a bit messy. If the MAC address assignment is part of the bind step then it shouldn't need the seq number.
I can think of some poor ways to do this but a nice way is not obvious!
One option would be probe all the Ethernet devices on startup. If probe() only set up the hardware (including MAC address) then that might work. It would be fairly fast since it wouldn't involve starting up the link, etc. I suspect you are worried about a lot of Ethernet devices sitting around probed by unused. I'm not sure if that matters though.
Regards, Simon

On Thu, Feb 12, 2015 at 11:14 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 23:08, Joe Hershberger joe.hershberger@gmail.com
wrote:
Hi Simon,
On Tue, Feb 10, 2015 at 10:39 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
Before this patch, if the sequence numbers were resolved before
probe,
this code would insist on defining new non-conflicting-with-itself
seq
numbers. Now any "non -1" seq number is accepted as already resolved.
Can you explain what problem this solves? At present, when probing a device, ->seq must be -1 (sort-of by definition since it doesn't exist as an active device in the uclass).
Please look at eth_post_bind() in patch 07/14. The Ethernet devices
need to
write their hardware addresses to the registers in bind (since it needs
to
happen regardless of the device being used so that Linux will see the
MAC
address). As such, the sequence number is needed to look up the
ethaddr. In
order to avoid probing all the devices to get the seq number resolved, I resolve it in post_bind to avoid the rest of the overhead (thus no
longer
probing in post_bind, which was one of the issues previously). Then
when
probe comes along, the seq is already resolved. That's why this patch
is
needed.
OK I see.
This is a bit messy. If the MAC address assignment is part of the bind step then it shouldn't need the seq number.
Not sure why you say that. The reason I need the seq number is because I need to look up the proper env variable for the MAC address. E.g. ethaddr, eth2addr, etc. The seq number select which one to read from the env.
I can think of some poor ways to do this but a nice way is not obvious!
Not sure what you're referring to here. What is "this" in this context?
One option would be probe all the Ethernet devices on startup. If probe() only set up the hardware (including MAC address) then that might work. It would be fairly fast since it wouldn't involve starting up the link, etc. I suspect you are worried about a lot of Ethernet devices sitting around probed by unused. I'm not sure if that matters though.
I had it probing the devices originally (by calling first and next) and you commented that it shouldn't happen until the devices are used. However, I don't think we can guarantee that all drivers that come later will have simple probe (since that's not part of the contract). I think I agree with your original statement that we should not probe. It seems more suitable to write the hwaddr in bind as a known and limited side effect.
The seq number resolution seems fairly well contained as I implemented it in bind. I simply call the core function and write the result to the device member. Then of course this patch to remove the assert.
Thanks, -Joe

Hi Joe,
On 13 February 2015 at 19:33, Joe Hershberger joe.hershberger@gmail.com wrote:
On Thu, Feb 12, 2015 at 11:14 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 23:08, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Tue, Feb 10, 2015 at 10:39 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
Before this patch, if the sequence numbers were resolved before probe, this code would insist on defining new non-conflicting-with-itself seq numbers. Now any "non -1" seq number is accepted as already resolved.
Can you explain what problem this solves? At present, when probing a device, ->seq must be -1 (sort-of by definition since it doesn't exist as an active device in the uclass).
Please look at eth_post_bind() in patch 07/14. The Ethernet devices need to write their hardware addresses to the registers in bind (since it needs to happen regardless of the device being used so that Linux will see the MAC address). As such, the sequence number is needed to look up the ethaddr. In order to avoid probing all the devices to get the seq number resolved, I resolve it in post_bind to avoid the rest of the overhead (thus no longer probing in post_bind, which was one of the issues previously). Then when probe comes along, the seq is already resolved. That's why this patch is needed.
OK I see.
This is a bit messy. If the MAC address assignment is part of the bind step then it shouldn't need the seq number.
Not sure why you say that. The reason I need the seq number is because I need to look up the proper env variable for the MAC address. E.g. ethaddr, eth2addr, etc. The seq number select which one to read from the env.
We should be able to do this after a probe. A device which is bound but not probed does not have a sequence number, as things currently stand.
I can think of some poor ways to do this but a nice way is not obvious!
Not sure what you're referring to here. What is "this" in this context?
Figuring out the sequence number.
One option would be probe all the Ethernet devices on startup. If probe() only set up the hardware (including MAC address) then that might work. It would be fairly fast since it wouldn't involve starting up the link, etc. I suspect you are worried about a lot of Ethernet devices sitting around probed by unused. I'm not sure if that matters though.
I had it probing the devices originally (by calling first and next) and you commented that it shouldn't happen until the devices are used. However, I
That was because your code was probing things in the bind mehod.
don't think we can guarantee that all drivers that come later will have simple probe (since that's not part of the contract). I think I agree with your original statement that we should not probe. It seems more suitable to write the hwaddr in bind as a known and limited side effect.
I don't like the idea of an ethernet device supporting writing its hardware address before it is probed. Until it is probed we don't really know it is there, nor where it is exactly (bus, memory address). So I think writing the hardware address makes more sense after probe. But probe should not happen as part of bind. It seems to me it could happen in your eth_init().
The seq number resolution seems fairly well contained as I implemented it in bind. I simply call the core function and write the result to the device member. Then of course this patch to remove the assert.
Yes it is well contained, but I still don't think it is right. If you want to put '#ifndef CONFIG_DM_NET' around the assert in uclass_resolve_seq() while we work it out, that is OK with me.
Regards, Simon

Hi Simon,
On Sun, Feb 15, 2015 at 9:59 AM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 13 February 2015 at 19:33, Joe Hershberger joe.hershberger@gmail.com
wrote:
On Thu, Feb 12, 2015 at 11:14 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 23:08, Joe Hershberger <
joe.hershberger@gmail.com>
wrote:
Hi Simon,
On Tue, Feb 10, 2015 at 10:39 PM, Simon Glass sjg@chromium.org
wrote:
Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger <
joe.hershberger@ni.com>
wrote:
Before this patch, if the sequence numbers were resolved before probe, this code would insist on defining new non-conflicting-with-itself seq numbers. Now any "non -1" seq number is accepted as already
resolved.
Can you explain what problem this solves? At present, when probing a device, ->seq must be -1 (sort-of by definition since it doesn't
exist
as an active device in the uclass).
Please look at eth_post_bind() in patch 07/14. The Ethernet devices need to write their hardware addresses to the registers in bind (since it
needs
to happen regardless of the device being used so that Linux will see the MAC address). As such, the sequence number is needed to look up the ethaddr. In order to avoid probing all the devices to get the seq number
resolved, I
resolve it in post_bind to avoid the rest of the overhead (thus no longer probing in post_bind, which was one of the issues previously). Then when probe comes along, the seq is already resolved. That's why this
patch
is needed.
OK I see.
This is a bit messy. If the MAC address assignment is part of the bind step then it shouldn't need the seq number.
Not sure why you say that. The reason I need the seq number is because
I
need to look up the proper env variable for the MAC address. E.g.
ethaddr,
eth2addr, etc. The seq number select which one to read from the env.
We should be able to do this after a probe. A device which is bound but not probed does not have a sequence number, as things currently stand.
I can think of some poor ways to do this but a nice way is not obvious!
Not sure what you're referring to here. What is "this" in this context?
Figuring out the sequence number.
One option would be probe all the Ethernet devices on startup. If probe() only set up the hardware (including MAC address) then that might work. It would be fairly fast since it wouldn't involve starting up the link, etc. I suspect you are worried about a lot of Ethernet devices sitting around probed by unused. I'm not sure if that matters though.
I had it probing the devices originally (by calling first and next) and
you
commented that it shouldn't happen until the devices are used.
However, I
That was because your code was probing things in the bind mehod.
don't think we can guarantee that all drivers that come later will have simple probe (since that's not part of the contract). I think I agree
with
your original statement that we should not probe. It seems more
suitable to
write the hwaddr in bind as a known and limited side effect.
I don't like the idea of an ethernet device supporting writing its hardware address before it is probed. Until it is probed we don't really know it is there, nor where it is exactly (bus, memory address). So I think writing the hardware address makes more sense after probe. But probe should not happen as part of bind. It seems to me it could happen in your eth_init().
OK. I can see why you prefer not to have the hardware accessed in bind. In order to probe the devices (but not from bind) I'll have to add back eth_initialize() and have it probe all of the devices. the "eth_init()" that you see here is what gets called when the network is enabled, so it certainly shouldn't go in eth_init(). I could potentially rename it to eth_start() or something. That would be clearer, but would break from the former naming for anyone familiar.
The seq number resolution seems fairly well contained as I implemented
it in
bind. I simply call the core function and write the result to the
device
member. Then of course this patch to remove the assert.
Yes it is well contained, but I still don't think it is right. If you want to put '#ifndef CONFIG_DM_NET' around the assert in uclass_resolve_seq() while we work it out, that is OK with me.
I will work on making it correct instead of adding that.
-Joe

Hi Joe,
On 16 February 2015 at 21:17, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Sun, Feb 15, 2015 at 9:59 AM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 13 February 2015 at 19:33, Joe Hershberger joe.hershberger@gmail.com wrote:
On Thu, Feb 12, 2015 at 11:14 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 23:08, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Tue, Feb 10, 2015 at 10:39 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote: > Before this patch, if the sequence numbers were resolved before > probe, > this code would insist on defining new non-conflicting-with-itself > seq > numbers. Now any "non -1" seq number is accepted as already > resolved.
Can you explain what problem this solves? At present, when probing a device, ->seq must be -1 (sort-of by definition since it doesn't exist as an active device in the uclass).
Please look at eth_post_bind() in patch 07/14. The Ethernet devices need to write their hardware addresses to the registers in bind (since it needs to happen regardless of the device being used so that Linux will see the MAC address). As such, the sequence number is needed to look up the ethaddr. In order to avoid probing all the devices to get the seq number resolved, I resolve it in post_bind to avoid the rest of the overhead (thus no longer probing in post_bind, which was one of the issues previously). Then when probe comes along, the seq is already resolved. That's why this patch is needed.
OK I see.
This is a bit messy. If the MAC address assignment is part of the bind step then it shouldn't need the seq number.
Not sure why you say that. The reason I need the seq number is because I need to look up the proper env variable for the MAC address. E.g. ethaddr, eth2addr, etc. The seq number select which one to read from the env.
We should be able to do this after a probe. A device which is bound but not probed does not have a sequence number, as things currently stand.
I can think of some poor ways to do this but a nice way is not obvious!
Not sure what you're referring to here. What is "this" in this context?
Figuring out the sequence number.
One option would be probe all the Ethernet devices on startup. If probe() only set up the hardware (including MAC address) then that might work. It would be fairly fast since it wouldn't involve starting up the link, etc. I suspect you are worried about a lot of Ethernet devices sitting around probed by unused. I'm not sure if that matters though.
I had it probing the devices originally (by calling first and next) and you commented that it shouldn't happen until the devices are used. However, I
That was because your code was probing things in the bind mehod.
don't think we can guarantee that all drivers that come later will have simple probe (since that's not part of the contract). I think I agree with your original statement that we should not probe. It seems more suitable to write the hwaddr in bind as a known and limited side effect.
I don't like the idea of an ethernet device supporting writing its hardware address before it is probed. Until it is probed we don't really know it is there, nor where it is exactly (bus, memory address). So I think writing the hardware address makes more sense after probe. But probe should not happen as part of bind. It seems to me it could happen in your eth_init().
OK. I can see why you prefer not to have the hardware accessed in bind. In order to probe the devices (but not from bind) I'll have to add back eth_initialize() and have it probe all of the devices. the "eth_init()" that you see here is what gets called when the network is enabled, so it certainly shouldn't go in eth_init(). I could potentially rename it to eth_start() or something. That would be clearer, but would break from the former naming for anyone familiar.
I see. Maybe eth_probe_all_devices()?
The seq number resolution seems fairly well contained as I implemented it in bind. I simply call the core function and write the result to the device member. Then of course this patch to remove the assert.
Yes it is well contained, but I still don't think it is right. If you want to put '#ifndef CONFIG_DM_NET' around the assert in uclass_resolve_seq() while we work it out, that is OK with me.
I will work on making it correct instead of adding that.
OK.
Regards, Simon

Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v3: -Reorder dm test makefile
Changes in v2: None
test/dm/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/dm/Makefile b/test/dm/Makefile index 612aa95..1d9148f 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_DM_TEST) += core.o obj-$(CONFIG_DM_TEST) += ut.o ifneq ($(CONFIG_SANDBOX),) obj-$(CONFIG_DM_GPIO) += gpio.o -obj-$(CONFIG_DM_SPI) += spi.o -obj-$(CONFIG_DM_SPI_FLASH) += sf.o obj-$(CONFIG_DM_I2C) += i2c.o +obj-$(CONFIG_DM_SPI_FLASH) += sf.o +obj-$(CONFIG_DM_SPI) += spi.o endif

On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v3: -Reorder dm test makefile
Changes in v2: None
test/dm/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Acked-by: Simon Glass sjg@chromium.org

The current implementation exposes the eth_device struct to code that needs to access the MAC address. Add a wrapper function for this to abstract away the pointer for this operation.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
arch/mips/cpu/mips32/au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- include/net.h | 8 ++++++++ net/net.c | 2 +- 6 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/arch/mips/cpu/mips32/au1x00/au1x00_eth.c b/arch/mips/cpu/mips32/au1x00/au1x00_eth.c index 4770f56..535d713 100644 --- a/arch/mips/cpu/mips32/au1x00/au1x00_eth.c +++ b/arch/mips/cpu/mips32/au1x00/au1x00_eth.c @@ -238,7 +238,7 @@ static int au1x00_init(struct eth_device* dev, bd_t * bd){ }
/* Put mac addr in little endian */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() *mac_addr_high = (ea[5] << 8) | (ea[4] ) ; *mac_addr_low = (ea[3] << 24) | (ea[2] << 16) | (ea[1] << 8) | (ea[0] ) ; diff --git a/arch/powerpc/cpu/mpc8260/ether_fcc.c b/arch/powerpc/cpu/mpc8260/ether_fcc.c index f9f15b5..f777ba1 100644 --- a/arch/powerpc/cpu/mpc8260/ether_fcc.c +++ b/arch/powerpc/cpu/mpc8260/ether_fcc.c @@ -299,7 +299,7 @@ static int fec_init(struct eth_device* dev, bd_t *bis) * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc85xx/ether_fcc.c b/arch/powerpc/cpu/mpc85xx/ether_fcc.c index 166dc9e..58d4bfb 100644 --- a/arch/powerpc/cpu/mpc85xx/ether_fcc.c +++ b/arch/powerpc/cpu/mpc85xx/ether_fcc.c @@ -338,7 +338,7 @@ static int fec_init(struct eth_device* dev, bd_t *bis) * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc8xx/scc.c b/arch/powerpc/cpu/mpc8xx/scc.c index 251966b..66e4014 100644 --- a/arch/powerpc/cpu/mpc8xx/scc.c +++ b/arch/powerpc/cpu/mpc8xx/scc.c @@ -339,7 +339,7 @@ static int scc_init (struct eth_device *dev, bd_t * bis) pram_ptr->sen_gaddr3 = 0x0; /* Group Address Filter 3 (unused) */ pram_ptr->sen_gaddr4 = 0x0; /* Group Address Filter 4 (unused) */
-#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/include/net.h b/include/net.h index 73ea88b..a9579ee 100644 --- a/include/net.h +++ b/include/net.h @@ -111,6 +111,14 @@ struct eth_device *eth_get_dev(void) { return eth_current; } + +static inline unsigned char *eth_get_ethaddr(void) +{ + if (eth_current) + return eth_current->enetaddr; + return NULL; +} + extern struct eth_device *eth_get_dev_by_name(const char *devname); extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ extern int eth_get_dev_index(void); /* get the device index */ diff --git a/net/net.c b/net/net.c index 2bea07b..ddd630c 100644 --- a/net/net.c +++ b/net/net.c @@ -275,7 +275,7 @@ static void NetInitLoop(void) env_changed_id = env_id; } if (eth_get_dev()) - memcpy(NetOurEther, eth_get_dev()->enetaddr, 6); + memcpy(NetOurEther, eth_get_ethaddr(), 6);
return; }

Make it clear that the helper is checking the addr, not setting it.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
net/eth.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/net/eth.c b/net/eth.c index eac4f7b..65e8c77 100644 --- a/net/eth.c +++ b/net/eth.c @@ -153,11 +153,6 @@ static void eth_current_changed(void) setenv("ethact", NULL); }
-static int eth_address_set(unsigned char *addr) -{ - return memcmp(addr, "\0\0\0\0\0\0", 6); -} - int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -166,9 +161,9 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
- if (eth_address_set(env_enetaddr)) { - if (eth_address_set(dev->enetaddr) && - memcmp(dev->enetaddr, env_enetaddr, 6)) { + if (!is_zero_ether_addr(env_enetaddr)) { + if (!is_zero_ether_addr(dev->enetaddr) && + memcmp(dev->enetaddr, env_enetaddr, 6)) { printf("\nWarning: %s MAC addresses don't match:\n", dev->name); printf("Address in SROM is %pM\n", @@ -183,7 +178,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, dev->enetaddr); printf("\nWarning: %s using MAC address from net device\n", dev->name); - } else if (!(eth_address_set(dev->enetaddr))) { + } else if (is_zero_ether_addr(dev->enetaddr)) { printf("\nError: %s address not set.\n", dev->name); return -EINVAL;

Many of the functions in net.h were preceded extern needlessly. Removing them to limit the number of checkpatch.pl complaints.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v3: None Changes in v2: None
include/net.h | 96 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 48 insertions(+), 48 deletions(-)
diff --git a/include/net.h b/include/net.h index a9579ee..ff8b7af 100644 --- a/include/net.h +++ b/include/net.h @@ -97,11 +97,11 @@ struct eth_device { void *priv; };
-extern int eth_initialize(bd_t *bis); /* Initialize network subsystem */ -extern int eth_register(struct eth_device* dev);/* Register network device */ -extern int eth_unregister(struct eth_device *dev);/* Remove network device */ -extern void eth_try_another(int first_restart); /* Change the device */ -extern void eth_set_current(void); /* set nterface to ethcur var */ +int eth_initialize(bd_t *bis); /* Initialize network subsystem */ +int eth_register(struct eth_device *dev);/* Register network device */ +int eth_unregister(struct eth_device *dev);/* Remove network device */ +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */
/* get the current device MAC */ extern struct eth_device *eth_current; @@ -119,12 +119,12 @@ static inline unsigned char *eth_get_ethaddr(void) return NULL; }
-extern struct eth_device *eth_get_dev_by_name(const char *devname); -extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ -extern int eth_get_dev_index(void); /* get the device index */ -extern void eth_parse_enetaddr(const char *addr, uchar *enetaddr); -extern int eth_getenv_enetaddr(char *name, uchar *enetaddr); -extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr); +struct eth_device *eth_get_dev_by_name(const char *devname); +struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ +int eth_get_dev_index(void); /* get the device index */ +void eth_parse_enetaddr(const char *addr, uchar *enetaddr); +int eth_getenv_enetaddr(char *name, uchar *enetaddr); +int eth_setenv_enetaddr(char *name, const uchar *enetaddr);
/* * Get the hardware address for an ethernet interface . @@ -135,20 +135,20 @@ extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr); * Returns: * Return true if the address is valid. */ -extern int eth_getenv_enetaddr_by_index(const char *base_name, int index, - uchar *enetaddr); +int eth_getenv_enetaddr_by_index(const char *base_name, int index, + uchar *enetaddr);
-extern int usb_eth_initialize(bd_t *bi); -extern int eth_init(bd_t *bis); /* Initialize the device */ -extern int eth_send(void *packet, int length); /* Send a packet */ +int usb_eth_initialize(bd_t *bi); +int eth_init(bd_t *bis); /* Initialize the device */ +int eth_send(void *packet, int length); /* Send a packet */
#ifdef CONFIG_API -extern int eth_receive(void *packet, int length); /* Receive a packet*/ -extern void (*push_packet)(void *packet, int length); +int eth_receive(void *packet, int length); /* Receive a packet*/ +void (*push_packet)(void *packet, int length); #endif -extern int eth_rx(void); /* Check for received packets */ -extern void eth_halt(void); /* stop SCC */ -extern char *eth_get_name(void); /* get name of current device */ +int eth_rx(void); /* Check for received packets */ +void eth_halt(void); /* stop SCC */ +char *eth_get_name(void); /* get name of current device */
/* Set active state */ static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) @@ -469,25 +469,25 @@ extern IPaddr_t Mcast_addr; #endif
/* Initialize the network adapter */ -extern void net_init(void); -extern int NetLoop(enum proto_t); +void net_init(void); +int NetLoop(enum proto_t);
/* Shutdown adapters and cleanup */ -extern void NetStop(void); +void NetStop(void);
/* Load failed. Start again. */ -extern void NetStartAgain(void); +void NetStartAgain(void);
/* Get size of the ethernet header when we send */ -extern int NetEthHdrSize(void); +int NetEthHdrSize(void);
/* Set ethernet header; returns the size of the header */ -extern int NetSetEther(uchar *, uchar *, uint); -extern int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot); +int NetSetEther(uchar *, uchar *, uint); +int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot);
/* Set IP header */ -extern void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source); -extern void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, +void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source); +void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, int sport, int len);
/** @@ -521,16 +521,16 @@ unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new_sum); int ip_checksum_ok(const void *addr, unsigned nbytes);
/* Checksum */ -extern int NetCksumOk(uchar *, int); /* Return true if cksum OK */ -extern uint NetCksum(uchar *, int); /* Calculate the checksum */ +int NetCksumOk(uchar *, int); /* Return true if cksum OK */ +uint NetCksum(uchar *, int); /* Calculate the checksum */
/* Callbacks */ -extern rxhand_f *net_get_udp_handler(void); /* Get UDP RX packet handler */ -extern void net_set_udp_handler(rxhand_f *); /* Set UDP RX packet handler */ -extern rxhand_f *net_get_arp_handler(void); /* Get ARP RX packet handler */ -extern void net_set_arp_handler(rxhand_f *); /* Set ARP RX packet handler */ -extern void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */ -extern void NetSetTimeout(ulong, thand_f *);/* Set timeout handler */ +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 */ +void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */ +void NetSetTimeout(ulong, thand_f *);/* Set timeout handler */
/* Network loop state */ enum net_loop_state { @@ -563,11 +563,11 @@ static inline void NetSendPacket(uchar *pkt, int len) * @param sport Source UDP port * @param payload_len Length of data after the UDP header */ -extern int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, +int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int payload_len);
/* Processes a received packet */ -extern void NetReceive(uchar *, int); +void NetReceive(uchar *, int);
#ifdef CONFIG_NETCONSOLE void NcStart(void); @@ -715,28 +715,28 @@ static inline void eth_random_addr(uchar *addr) }
/* Convert an IP address to a string */ -extern void ip_to_string(IPaddr_t x, char *s); +void ip_to_string(IPaddr_t x, char *s);
/* Convert a string to ip address */ -extern IPaddr_t string_to_ip(const char *s); +IPaddr_t string_to_ip(const char *s);
/* Convert a VLAN id to a string */ -extern void VLAN_to_string(ushort x, char *s); +void VLAN_to_string(ushort x, char *s);
/* Convert a string to a vlan id */ -extern ushort string_to_VLAN(const char *s); +ushort string_to_VLAN(const char *s);
/* read a VLAN id from an environment variable */ -extern ushort getenv_VLAN(char *); +ushort getenv_VLAN(char *);
/* copy a filename (allow for "..." notation, limit length) */ -extern void copy_filename(char *dst, const char *src, int size); +void copy_filename(char *dst, const char *src, int size);
/* get a random source port */ -extern unsigned int random_port(void); +unsigned int random_port(void);
/* Update U-Boot over TFTP */ -extern int update_tftp(ulong addr); +int update_tftp(ulong addr);
/**********************************************************************/

Move some things around and organize things so that the driver model implementation will fit in more easily.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: -Move the get_dev_by_* protos to also be !DM_ETH like the impl
Changes in v2: None
include/net.h | 66 +++++++++++++++++++++++++++------------------------- net/eth.c | 75 +++++++++++++++++++++++++++++++---------------------------- 2 files changed, 74 insertions(+), 67 deletions(-)
diff --git a/include/net.h b/include/net.h index ff8b7af..4d7575e 100644 --- a/include/net.h +++ b/include/net.h @@ -100,10 +100,7 @@ struct eth_device { int eth_initialize(bd_t *bis); /* Initialize network subsystem */ int eth_register(struct eth_device *dev);/* Register network device */ int eth_unregister(struct eth_device *dev);/* Remove network device */ -void eth_try_another(int first_restart); /* Change the device */ -void eth_set_current(void); /* set nterface to ethcur var */
-/* get the current device MAC */ extern struct eth_device *eth_current;
static inline __attribute__((always_inline)) @@ -111,7 +108,10 @@ struct eth_device *eth_get_dev(void) { return eth_current; } +struct eth_device *eth_get_dev_by_name(const char *devname); +struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */
+/* get the current device MAC */ static inline unsigned char *eth_get_ethaddr(void) { if (eth_current) @@ -119,8 +119,36 @@ static inline unsigned char *eth_get_ethaddr(void) return NULL; }
-struct eth_device *eth_get_dev_by_name(const char *devname); -struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ +/* Set active state */ +static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) +{ + eth_get_dev()->state = ETH_STATE_ACTIVE; + + return 0; +} +/* Set passive state */ +static inline __attribute__((always_inline)) void eth_halt_state_only(void) +{ + eth_get_dev()->state = ETH_STATE_PASSIVE; +} + +/* + * Set the hardware address for an ethernet interface based on 'eth%daddr' + * environment variable (or just 'ethaddr' if eth_number is 0). + * Args: + * base_name - base name for device (normally "eth") + * eth_number - value of %d (0 for first device of this type) + * Returns: + * 0 is success, non-zero is error status from driver. + */ +int eth_write_hwaddr(struct eth_device *dev, const char *base_name, + int eth_number); + +int usb_eth_initialize(bd_t *bi); + +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */ + int eth_get_dev_index(void); /* get the device index */ void eth_parse_enetaddr(const char *addr, uchar *enetaddr); int eth_getenv_enetaddr(char *name, uchar *enetaddr); @@ -138,7 +166,6 @@ int eth_setenv_enetaddr(char *name, const uchar *enetaddr); int eth_getenv_enetaddr_by_index(const char *base_name, int index, uchar *enetaddr);
-int usb_eth_initialize(bd_t *bi); int eth_init(bd_t *bis); /* Initialize the device */ int eth_send(void *packet, int length); /* Send a packet */
@@ -148,32 +175,7 @@ void (*push_packet)(void *packet, int length); #endif int eth_rx(void); /* Check for received packets */ void eth_halt(void); /* stop SCC */ -char *eth_get_name(void); /* get name of current device */ - -/* Set active state */ -static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) -{ - eth_get_dev()->state = ETH_STATE_ACTIVE; - - return 0; -} -/* Set passive state */ -static inline __attribute__((always_inline)) void eth_halt_state_only(void) -{ - eth_get_dev()->state = ETH_STATE_PASSIVE; -} - -/* - * Set the hardware address for an ethernet interface based on 'eth%daddr' - * environment variable (or just 'ethaddr' if eth_number is 0). - * Args: - * base_name - base name for device (normally "eth") - * eth_number - value of %d (0 for first device of this type) - * Returns: - * 0 is success, non-zero is error status from driver. - */ -int eth_write_hwaddr(struct eth_device *dev, const char *base_name, - int eth_number); +const char *eth_get_name(void); /* get name of current device */
#ifdef CONFIG_MCAST_TFTP int eth_mcast_join(IPaddr_t mcast_addr, u8 join); diff --git a/net/eth.c b/net/eth.c index 65e8c77..c02548c 100644 --- a/net/eth.c +++ b/net/eth.c @@ -55,6 +55,14 @@ static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index, return eth_setenv_enetaddr(enetvar, enetaddr); }
+static void eth_env_init(void) +{ + const char *s; + + s = getenv("bootfile"); + if (s != NULL) + copy_filename(BootFile, s, sizeof(BootFile)); +}
static int eth_mac_skip(int index) { @@ -87,6 +95,11 @@ static unsigned int eth_rcv_current, eth_rcv_last; static struct eth_device *eth_devices; struct eth_device *eth_current;
+static void eth_set_current_to_next(void) +{ + eth_current = eth_current->next; +} + struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -137,22 +150,6 @@ int eth_get_dev_index(void) return eth_current->index; }
-static void eth_current_changed(void) -{ - char *act = getenv("ethact"); - /* update current ethernet name */ - if (eth_current) { - if (act == NULL || strcmp(act, eth_current->name) != 0) - setenv("ethact", eth_current->name); - } - /* - * remove the variable completely if there is no active - * interface - */ - else if (act != NULL) - setenv("ethact", NULL); -} - int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -251,14 +248,6 @@ int eth_unregister(struct eth_device *dev) return 0; }
-static void eth_env_init(bd_t *bis) -{ - const char *s; - - if ((s = getenv("bootfile")) != NULL) - copy_filename(BootFile, s, sizeof(BootFile)); -} - int eth_initialize(bd_t *bis) { int num_devices = 0; @@ -479,6 +468,22 @@ int eth_receive(void *packet, int length) } #endif /* CONFIG_API */
+static void eth_current_changed(void) +{ + char *act = getenv("ethact"); + /* update current ethernet name */ + if (eth_get_dev()) { + if (act == NULL || strcmp(act, eth_get_name()) != 0) + setenv("ethact", eth_get_name()); + } + /* + * remove the variable completely if there is no active + * interface + */ + else if (act != NULL) + setenv("ethact", NULL); +} + void eth_try_another(int first_restart) { static struct eth_device *first_failed; @@ -492,17 +497,17 @@ void eth_try_another(int first_restart) if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) return;
- if (!eth_current) + if (!eth_get_dev()) return;
if (first_restart) - first_failed = eth_current; + first_failed = eth_get_dev();
- eth_current = eth_current->next; + eth_set_current_to_next();
eth_current_changed();
- if (first_failed == eth_current) + if (first_failed == eth_get_dev()) NetRestartWrap = 1; }
@@ -513,7 +518,7 @@ void eth_set_current(void) struct eth_device *old_current; int env_id;
- if (!eth_current) /* XXX no current */ + if (!eth_get_dev()) /* XXX no current */ return;
env_id = get_env_id(); @@ -522,18 +527,18 @@ void eth_set_current(void) env_changed_id = env_id; } if (act != NULL) { - old_current = eth_current; + old_current = eth_get_dev(); do { - if (strcmp(eth_current->name, act) == 0) + if (strcmp(eth_get_name(), act) == 0) return; - eth_current = eth_current->next; - } while (old_current != eth_current); + eth_set_current_to_next(); + } while (old_current != eth_get_dev()); }
eth_current_changed(); }
-char *eth_get_name(void) +const char *eth_get_name(void) { - return eth_current ? eth_current->name : "unknown"; + return eth_get_dev() ? eth_get_dev()->name : "unknown"; }

First just add support for MAC drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v3: -Correct the pre_unbind logic -Correct failure chaining from bind to probe to init --Fail init if not activated --Fail probe if ethaddr not set -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the previous selection -Allow current eth dev to be NULL -Fixed blank line formatting for variable declaration
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for our needs -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()).
common/board_r.c | 4 +- common/cmd_bdinfo.c | 2 + include/dm/uclass-id.h | 1 + include/net.h | 25 ++++ net/eth.c | 336 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 361 insertions(+), 7 deletions(-)
diff --git a/common/board_r.c b/common/board_r.c index 68a9448..75147b7 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -556,7 +556,7 @@ static int initr_bbmii(void) } #endif
-#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) static int initr_net(void) { puts("Net: "); @@ -825,7 +825,7 @@ init_fnc_t init_sequence_r[] = { #ifdef CONFIG_BITBANGMII initr_bbmii, #endif -#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) INIT_FUNC_WATCHDOG_RESET initr_net, #endif diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index e6d8a7a..8688cf9 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..ad96682 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */ + UCLASS_ETH, /* Ethernet device */
UCLASS_COUNT, UCLASS_INVALID = -1, diff --git a/include/net.h b/include/net.h index 4d7575e..11471bd 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,30 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH +struct eth_pdata { + phys_addr_t iobase; + unsigned char enetaddr[6]; +}; + +struct eth_ops { + int (*init)(struct udevice *dev, bd_t *bis); + int (*send)(struct udevice *dev, void *packet, int length); + int (*recv)(struct udevice *dev); + void (*halt)(struct udevice *dev); +#ifdef CONFIG_MCAST_TFTP + int (*mcast)(struct udevice *dev, const u8 *enetaddr, u8 set); +#endif + int (*write_hwaddr)(struct udevice *dev); +}; + +struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +int eth_init_state_only(bd_t *bis); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ +#endif + +#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; @@ -145,6 +169,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number);
int usb_eth_initialize(bd_t *bi); +#endif
void eth_try_another(int first_restart); /* Change the device */ void eth_set_current(void); /* set nterface to ethcur var */ diff --git a/net/eth.c b/net/eth.c index c02548c..e84b948 100644 --- a/net/eth.c +++ b/net/eth.c @@ -1,12 +1,15 @@ /* * (C) Copyright 2001-2010 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Joe Hershberger, National Instruments * * SPDX-License-Identifier: GPL-2.0+ */
#include <common.h> #include <command.h> +#include <dm.h> +#include <dm/device-internal.h> #include <net.h> #include <miiphy.h> #include <phy.h> @@ -72,6 +75,331 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void); + +#ifdef CONFIG_DM_ETH +struct eth_device_priv { + int state; + void *priv; +}; + +struct eth_uclass_priv { + struct udevice *current; +}; + +static void eth_set_current_to_next(void) +{ + struct uclass *uc; + struct eth_uclass_priv *uc_priv; + + uclass_get(UCLASS_ETH, &uc); + uc_priv = uc->priv; + if (uc_priv->current) + uclass_next_device(&uc_priv->current); + if (!uc_priv->current) + uclass_first_device(UCLASS_ETH, &uc_priv->current); +} + +struct udevice *eth_get_dev(void) +{ + struct uclass *uc; + struct eth_uclass_priv *uc_priv; + + uclass_get(UCLASS_ETH, &uc); + uc_priv = uc->priv; + + return uc_priv->current; +} + +static void eth_set_dev(struct udevice *dev) +{ + struct uclass *uc; + struct eth_uclass_priv *uc_priv; + + uclass_get(UCLASS_ETH, &uc); + uc_priv = uc->priv; + uc_priv->current = dev; +} + +unsigned char *eth_get_ethaddr(void) +{ + struct eth_pdata *pdata; + + if (eth_get_dev()) { + pdata = eth_get_dev()->platdata; + if (pdata) + return pdata->enetaddr; + } + return NULL; +} + +/* Set active state */ +int eth_init_state_only(bd_t *bis) +{ + struct eth_device_priv *priv; + + if (eth_get_dev()) { + priv = eth_get_dev()->uclass_priv; + if (priv) + priv->state = ETH_STATE_ACTIVE; + } + return 0; +} +/* Set passive state */ +void eth_halt_state_only(void) +{ + struct eth_device_priv *priv; + + if (eth_get_dev()) { + priv = eth_get_dev()->uclass_priv; + if (priv) + priv->state = ETH_STATE_PASSIVE; + } +} + +int eth_get_dev_index(void) +{ + if (eth_get_dev()) + return eth_get_dev()->seq; + return -1; +} + +int eth_init(bd_t *bis) +{ + struct udevice *current, *old_current, *dev; + int retval; + struct uclass *uc; + + current = eth_get_dev(); + if (!current) { + puts("No ethernet found.\n"); + return -1; + } + retval = device_probe(current); + if (retval) + return retval; + + /* Sync environment with network devices */ + uclass_get(UCLASS_ETH, &uc); + uclass_foreach_dev(dev, uc) { + uchar env_enetaddr[6]; + struct eth_pdata *pdata = dev->platdata; + + if (eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr)) + memcpy(pdata->enetaddr, env_enetaddr, 6); + else + memset(pdata->enetaddr, 0, 6); + } + + old_current = current; + do { + debug("Trying %s\n", current->name); + + if (current->driver && (current->flags & DM_FLAG_ACTIVATED)) { + const struct eth_ops *ops = current->driver->ops; + + if (ops->init(current, bis) >= 0) { + struct eth_device_priv *priv = + current->uclass_priv; + if (priv) + priv->state = ETH_STATE_ACTIVE; + + return 0; + } + } + debug("FAIL\n"); + + eth_try_another(0); + current = eth_get_dev(); + } while (old_current != current); + + return -ENODEV; +} + +void eth_halt(void) +{ + struct udevice *current; + const struct eth_ops *ops; + struct eth_device_priv *priv; + + current = eth_get_dev(); + if (!current) + return; + if (!current->driver) + return; + + ops = current->driver->ops; + ops->halt(current); + + priv = current->uclass_priv; + if (priv) + priv->state = ETH_STATE_PASSIVE; +} + +int eth_send(void *packet, int length) +{ + struct udevice *current; + const struct eth_ops *ops; + + current = eth_get_dev(); + if (!current) + return -1; + if (!current->driver) + return -1; + ops = current->driver->ops; + + return ops->send(current, packet, length); +} + +int eth_rx(void) +{ + struct udevice *current; + const struct eth_ops *ops; + + current = eth_get_dev(); + if (!current) + return -1; + if (!current->driver) + return -1; + ops = current->driver->ops; + + return ops->recv(current); +} + +static int eth_write_hwaddr(struct udevice *dev, const char *base_name, + int eth_number) +{ + unsigned char env_enetaddr[6]; + int ret = 0; + struct eth_pdata *pdata; + const struct eth_ops *ops; + + eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr); + + pdata = dev->platdata; + if (!is_zero_ether_addr(env_enetaddr)) { + if (!is_zero_ether_addr(pdata->enetaddr) && + memcmp(pdata->enetaddr, env_enetaddr, 6)) { + printf("\nWarning: %s MAC addresses don't match:\n", + dev->name); + printf("Address in SROM is %pM\n", + pdata->enetaddr); + printf("Address in environment is %pM\n", + env_enetaddr); + } + + memcpy(pdata->enetaddr, env_enetaddr, 6); + } else if (is_valid_ether_addr(pdata->enetaddr)) { + eth_setenv_enetaddr_by_index(base_name, eth_number, + pdata->enetaddr); + printf("\nWarning: %s using MAC address from net device\n", + dev->name); + } else if (is_zero_ether_addr(pdata->enetaddr)) { + printf("\nError: %s address not set.\n", + dev->name); + return -EINVAL; + } + + ops = dev->driver->ops; + if (dev->driver && ops && ops->write_hwaddr && + !eth_mac_skip(eth_number)) { + if (!is_valid_ether_addr(pdata->enetaddr)) { + printf("\nError: %s address %pM illegal value\n", + dev->name, pdata->enetaddr); + return -EINVAL; + } + + ret = ops->write_hwaddr(dev); + if (ret) + printf("\nWarning: %s failed to set MAC address\n", + dev->name); + } + + return ret; +} + +static int eth_uclass_init(struct uclass *class) +{ + bootstage_mark(BOOTSTAGE_ID_NET_ETH_START); + + eth_env_init(); + + return 0; +} + +static int eth_post_bind(struct udevice *dev) +{ + if (strchr(dev->name, ' ')) { + printf("\nError: eth device name "%s" has a space!\n", + dev->name); + return -EINVAL; + } + + /* + * Devices need to write the hwaddr even if not probed so that Linux + * will have access to the hwaddr that u-boot stored for the device. + */ + dev->seq = uclass_resolve_seq(dev); + eth_write_hwaddr(dev, "eth", dev->seq); + + return 0; +} + +static int eth_pre_unbind(struct udevice *dev) +{ + struct udevice *first = NULL; + struct udevice *active; + struct udevice *it; + struct uclass *uc; + + uclass_get(UCLASS_ETH, &uc); + uclass_foreach_dev(it, uc) { + if (!first) + first = it; + if (it == dev) { + if (dev == first) { + active = list_entry(it->uclass_node.next, + struct udevice, uclass_node); + if (&active->uclass_node == &uc->dev_head) + active = NULL; + } else { + active = first; + } + eth_set_dev(active); + eth_current_changed(); + } + } + + return 0; +} + +static int eth_post_probe(struct udevice *dev) +{ + struct eth_device_priv *priv = dev->uclass_priv; + struct eth_pdata *pdata = dev->platdata; + + if (priv) + priv->state = ETH_STATE_INIT; + + if (is_zero_ether_addr(pdata->enetaddr)) + return -EINVAL; + + return 0; +} + +UCLASS_DRIVER(eth) = { + .name = "eth", + .id = UCLASS_ETH, + .post_bind = eth_post_bind, + .pre_unbind = eth_pre_unbind, + .post_probe = eth_post_probe, + .init = eth_uclass_init, + .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), + .per_device_auto_alloc_size = sizeof(struct eth_device_priv), +}; +#endif + +#ifndef CONFIG_DM_ETH /* * CPU and board-specific Ethernet initializations. Aliased function * signals caller to move on @@ -423,6 +751,7 @@ int eth_rx(void)
return eth_current->recv(eth_current); } +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -486,7 +815,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) { - static struct eth_device *first_failed; + static void *first_failed; char *ethrotate;
/* @@ -515,12 +844,9 @@ void eth_set_current(void) { static char *act; static int env_changed_id; - struct eth_device *old_current; + void *old_current; int env_id;
- if (!eth_get_dev()) /* XXX no current */ - return; - env_id = get_env_id(); if ((act == NULL) || (env_changed_id != env_id)) { act = getenv("ethact");

Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
First just add support for MAC drivers.
It has taken me a while to get through all this unfortunately.
This seems OK to me but needs a clean-up with more comments, etc. If you like these could go in a separate patch, so if you want to do that please add my Reviewed-by: Simon Glass sjg@chromium.org to this one. I would prefer that we sort out the bind/probe problem before this is merged but I understand you now have quite a bit of work built on top, and the problems can be separated.
So if you like we could do one more version, merge it, and continue with refinements after that.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v3: -Correct the pre_unbind logic -Correct failure chaining from bind to probe to init --Fail init if not activated --Fail probe if ethaddr not set -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the previous selection -Allow current eth dev to be NULL -Fixed blank line formatting for variable declaration
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for our needs -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()).
common/board_r.c | 4 +- common/cmd_bdinfo.c | 2 + include/dm/uclass-id.h | 1 + include/net.h | 25 ++++ net/eth.c | 336 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 361 insertions(+), 7 deletions(-)
diff --git a/common/board_r.c b/common/board_r.c index 68a9448..75147b7 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -556,7 +556,7 @@ static int initr_bbmii(void) } #endif
-#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) static int initr_net(void) { puts("Net: "); @@ -825,7 +825,7 @@ init_fnc_t init_sequence_r[] = { #ifdef CONFIG_BITBANGMII initr_bbmii, #endif -#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) INIT_FUNC_WATCHDOG_RESET initr_net, #endif diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index e6d8a7a..8688cf9 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..ad96682 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */
UCLASS_ETH, /* Ethernet device */ UCLASS_COUNT, UCLASS_INVALID = -1,
diff --git a/include/net.h b/include/net.h index 4d7575e..11471bd 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,30 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH +struct eth_pdata {
phys_addr_t iobase;
unsigned char enetaddr[6];
+};
+struct eth_ops {
int (*init)(struct udevice *dev, bd_t *bis);
Why do we pass in bd_t? Isn't that available through gd->bd?
int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev);
void (*halt)(struct udevice *dev);
+#ifdef CONFIG_MCAST_TFTP
int (*mcast)(struct udevice *dev, const u8 *enetaddr, u8 set);
s/u8/bool/ or maybe int? On ARM at least it is inefficient to keep having to mask the parameters.
+#endif
int (*write_hwaddr)(struct udevice *dev);
+};
Can you please add interface comments on all of these plus the four below? I'm trying to make driver model an opportunity to improve the code as we go. Things like what the function does, what packet contains.
+struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +int eth_init_state_only(bd_t *bis); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */
Can you expand these a bit? The first one can return NULL in some situations. The second returns a pointer to 6 bytes I think (perhaps we should define a struct for this in a future patch?) What are active and passive state? Why does one function get passed bd_t and not the other (better if neither did).
+#endif
+#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; @@ -145,6 +169,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number);
int usb_eth_initialize(bd_t *bi); +#endif
void eth_try_another(int first_restart); /* Change the device */ void eth_set_current(void); /* set nterface to ethcur var */ diff --git a/net/eth.c b/net/eth.c index c02548c..e84b948 100644 --- a/net/eth.c +++ b/net/eth.c @@ -1,12 +1,15 @@ /*
- (C) Copyright 2001-2010
- Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*/
- Joe Hershberger, National Instruments
- SPDX-License-Identifier: GPL-2.0+
#include <common.h> #include <command.h> +#include <dm.h> +#include <dm/device-internal.h> #include <net.h> #include <miiphy.h> #include <phy.h> @@ -72,6 +75,331 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH
/** * struct eth_device_priv - private structure for each Ethernet device * * @state: ... * @priv: ... /
+struct eth_device_priv {
int state;
void *priv;
+};
Structure attached to the uclass itself.
+struct eth_uclass_priv {
struct udevice *current;
+};
+static void eth_set_current_to_next(void) +{
struct uclass *uc;
struct eth_uclass_priv *uc_priv;
uclass_get(UCLASS_ETH, &uc);
uc_priv = uc->priv;
if (uc_priv->current)
uclass_next_device(&uc_priv->current);
if (!uc_priv->current)
uclass_first_device(UCLASS_ETH, &uc_priv->current);
+}
I think you should have something like this to avoid this duplication:
static struct eth_uclass_priv *get_uclass_priv(void) { struct uclass *uc;
uclass_get(UCLASS_ETH, &uc); assert(uc); return uc->priv; }
At some point we should add a uclass_get_priv() function in uclass.h.
+struct udevice *eth_get_dev(void) +{
struct uclass *uc;
struct eth_uclass_priv *uc_priv;
uclass_get(UCLASS_ETH, &uc);
uc_priv = uc->priv;
return uc_priv->current;
+}
+static void eth_set_dev(struct udevice *dev) +{
struct uclass *uc;
struct eth_uclass_priv *uc_priv;
uclass_get(UCLASS_ETH, &uc);
uc_priv = uc->priv;
uc_priv->current = dev;
+}
+unsigned char *eth_get_ethaddr(void) +{
struct eth_pdata *pdata;
if (eth_get_dev()) {
pdata = eth_get_dev()->platdata;
if (pdata)
return pdata->enetaddr;
}
return NULL;
+}
+/* Set active state */ +int eth_init_state_only(bd_t *bis)
This doesn't seem to use bis, so I suspect it is for backwards compatibility.
+{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_ACTIVE;
It looks like state uses an enum, so that should be described in the comment I mentioned earlier.
}
return 0;
+} +/* Set passive state */ +void eth_halt_state_only(void) +{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
}
+}
+int eth_get_dev_index(void) +{
if (eth_get_dev())
return eth_get_dev()->seq;
return -1;
+}
+int eth_init(bd_t *bis) +{
struct udevice *current, *old_current, *dev;
int retval;
struct uclass *uc;
current = eth_get_dev();
if (!current) {
puts("No ethernet found.\n");
printf() as I believe we are trying to avoid puts().
return -1;
}
retval = device_probe(current);
if (retval)
return retval;
/* Sync environment with network devices */
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(dev, uc) {
uchar env_enetaddr[6];
struct eth_pdata *pdata = dev->platdata;
ret = device_probe(dev); if (ret) ...
here since you can't use dev->seq otherwise.
if (eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr))
memcpy(pdata->enetaddr, env_enetaddr, 6);
else
memset(pdata->enetaddr, 0, 6);
}
old_current = current;
do {
debug("Trying %s\n", current->name);
if (current->driver && (current->flags & DM_FLAG_ACTIVATED)) {
There is no need to check current->driver (here and elsewhere)
device_active(current)
const struct eth_ops *ops = current->driver->ops;
if (ops->init(current, bis) >= 0) {
struct eth_device_priv *priv =
current->uclass_priv;
if (priv)
Remove this check too
priv->state = ETH_STATE_ACTIVE;
return 0;
}
}
debug("FAIL\n");
eth_try_another(0);
current = eth_get_dev();
} while (old_current != current);
return -ENODEV;
+}
+void eth_halt(void) +{
struct udevice *current;
const struct eth_ops *ops;
struct eth_device_priv *priv;
current = eth_get_dev();
if (!current)
return;
if (!current->driver)
return;
Remove these checks
ops = current->driver->ops;
Define this in your header file:
#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
then one day we can add checks on dev, etc.
ops->halt(current);
If you like you can drop the local variable and use:
eth_get_ops(dev)->halt(current)
priv = current->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
+}
+int eth_send(void *packet, int length) +{
struct udevice *current;
const struct eth_ops *ops;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
ops = current->driver->ops;
return ops->send(current, packet, length);
+}
+int eth_rx(void) +{
struct udevice *current;
const struct eth_ops *ops;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
ops = current->driver->ops;
return ops->recv(current);
+}
+static int eth_write_hwaddr(struct udevice *dev, const char *base_name,
int eth_number)
+{
unsigned char env_enetaddr[6];
int ret = 0;
struct eth_pdata *pdata;
const struct eth_ops *ops;
eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
pdata = dev->platdata;
if (!is_zero_ether_addr(env_enetaddr)) {
if (!is_zero_ether_addr(pdata->enetaddr) &&
memcmp(pdata->enetaddr, env_enetaddr, 6)) {
printf("\nWarning: %s MAC addresses don't match:\n",
dev->name);
printf("Address in SROM is %pM\n",
pdata->enetaddr);
printf("Address in environment is %pM\n",
env_enetaddr);
}
memcpy(pdata->enetaddr, env_enetaddr, 6);
} else if (is_valid_ether_addr(pdata->enetaddr)) {
eth_setenv_enetaddr_by_index(base_name, eth_number,
pdata->enetaddr);
printf("\nWarning: %s using MAC address from net device\n",
dev->name);
} else if (is_zero_ether_addr(pdata->enetaddr)) {
printf("\nError: %s address not set.\n",
dev->name);
return -EINVAL;
}
ops = dev->driver->ops;
if (dev->driver && ops && ops->write_hwaddr &&
!eth_mac_skip(eth_number)) {
if (!is_valid_ether_addr(pdata->enetaddr)) {
printf("\nError: %s address %pM illegal value\n",
dev->name, pdata->enetaddr);
return -EINVAL;
}
ret = ops->write_hwaddr(dev);
if (ret)
printf("\nWarning: %s failed to set MAC address\n",
dev->name);
}
return ret;
+}
+static int eth_uclass_init(struct uclass *class) +{
bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
eth_env_init();
return 0;
+}
+static int eth_post_bind(struct udevice *dev) +{
if (strchr(dev->name, ' ')) {
printf("\nError: eth device name \"%s\" has a space!\n",
dev->name);
return -EINVAL;
}
/*
* Devices need to write the hwaddr even if not probed so that Linux
* will have access to the hwaddr that u-boot stored for the device.
*/
dev->seq = uclass_resolve_seq(dev);
eth_write_hwaddr(dev, "eth", dev->seq);
I still don't like this sorry. I don't see why you can't do this in eth_init() above?
If you really want to do this, please add #ifndef CONFIG_DM_NET around the check you have taken out and we can sort it out later.
return 0;
+}
+static int eth_pre_unbind(struct udevice *dev)
It still feels like this is using binding as the presence/absence of a device rather than probing. When a device is removed with the remove() method, it is no longer available for use, so things like eth_try_another() should ignore them. By the time we come to unbind a device, it should already be removed.
One way to think of this is that the probe()/remove() corresponds to the same idea as in Linux, and bind()/unbind() is a new thing meaning that we are aware of the device but it may not currently be available.
+{
struct udevice *first = NULL;
struct udevice *active;
struct udevice *it;
struct uclass *uc;
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(it, uc) {
if (!first)
first = it;
if (it == dev) {
if (dev == first) {
active = list_entry(it->uclass_node.next,
struct udevice, uclass_node);
if (&active->uclass_node == &uc->dev_head)
active = NULL;
} else {
active = first;
}
eth_set_dev(active);
eth_current_changed();
}
}
return 0;
+}
+static int eth_post_probe(struct udevice *dev) +{
struct eth_device_priv *priv = dev->uclass_priv;
struct eth_pdata *pdata = dev->platdata;
if (priv)
no need for this check
priv->state = ETH_STATE_INIT;
if (is_zero_ether_addr(pdata->enetaddr))
return -EINVAL;
return 0;
+}
+UCLASS_DRIVER(eth) = {
.name = "eth",
.id = UCLASS_ETH,
.post_bind = eth_post_bind,
.pre_unbind = eth_pre_unbind,
.post_probe = eth_post_probe,
.init = eth_uclass_init,
.priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
.per_device_auto_alloc_size = sizeof(struct eth_device_priv),
+}; +#endif
+#ifndef CONFIG_DM_ETH /*
- CPU and board-specific Ethernet initializations. Aliased function
- signals caller to move on
@@ -423,6 +751,7 @@ int eth_rx(void)
return eth_current->recv(eth_current);
} +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -486,7 +815,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) {
static struct eth_device *first_failed;
static void *first_failed; char *ethrotate; /*
@@ -515,12 +844,9 @@ void eth_set_current(void) { static char *act; static int env_changed_id;
struct eth_device *old_current;
void *old_current; int env_id;
if (!eth_get_dev()) /* XXX no current */
return;
env_id = get_env_id(); if ((act == NULL) || (env_changed_id != env_id)) { act = getenv("ethact");
-- 1.7.11.5
Regards, Simon

Hi Simon,
On Sun, Feb 15, 2015 at 9:49 AM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com
wrote:
First just add support for MAC drivers.
It has taken me a while to get through all this unfortunately.
This seems OK to me but needs a clean-up with more comments, etc. If you like these could go in a separate patch, so if you want to do that please add my Reviewed-by: Simon Glass sjg@chromium.org to this one. I would prefer that we sort out the bind/probe problem before this is merged but I understand you now have quite a bit of work built on top, and the problems can be separated.
So if you like we could do one more version, merge it, and continue with refinements after that.
I'm a bit leery to merge this until I've actually got more of the real-world implementation for a board done. I guess it could always be corrected in the future, but at the same time, I think it should be fairly complete. Do you prefer that it go in as smaller parts? There's still no actual board supported and the MDIO / PHY support is not done yet.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v3: -Correct the pre_unbind logic -Correct failure chaining from bind to probe to init --Fail init if not activated --Fail probe if ethaddr not set -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the
previous selection
-Allow current eth dev to be NULL -Fixed blank line formatting for variable declaration
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for
our needs
-Move the hwaddr to platdata so that its memory is allocated at bind
when we need it
-Prevent device from being probed before used by a command (i.e. before
eth_init()).
common/board_r.c | 4 +- common/cmd_bdinfo.c | 2 + include/dm/uclass-id.h | 1 + include/net.h | 25 ++++ net/eth.c | 336
++++++++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 361 insertions(+), 7 deletions(-)
diff --git a/common/board_r.c b/common/board_r.c index 68a9448..75147b7 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -556,7 +556,7 @@ static int initr_bbmii(void) } #endif
-#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) static int initr_net(void) { puts("Net: "); @@ -825,7 +825,7 @@ init_fnc_t init_sequence_r[] = { #ifdef CONFIG_BITBANGMII initr_bbmii, #endif -#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) INIT_FUNC_WATCHDOG_RESET initr_net, #endif diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index e6d8a7a..8688cf9 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..ad96682 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */
UCLASS_ETH, /* Ethernet device */ UCLASS_COUNT, UCLASS_INVALID = -1,
diff --git a/include/net.h b/include/net.h index 4d7575e..11471bd 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,30 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH +struct eth_pdata {
phys_addr_t iobase;
unsigned char enetaddr[6];
+};
+struct eth_ops {
int (*init)(struct udevice *dev, bd_t *bis);
Why do we pass in bd_t? Isn't that available through gd->bd?
Legacy. I can kill it if you like.
int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev);
void (*halt)(struct udevice *dev);
+#ifdef CONFIG_MCAST_TFTP
int (*mcast)(struct udevice *dev, const u8 *enetaddr, u8 set);
s/u8/bool/ or maybe int? On ARM at least it is inefficient to keep having to mask the parameters.
Again, legacy. I just copied the former function prototypes and changed the first parameter to udevice*.
+#endif
int (*write_hwaddr)(struct udevice *dev);
+};
Can you please add interface comments on all of these plus the four below? I'm trying to make driver model an opportunity to improve the code as we go. Things like what the function does, what packet contains.
OK.
+struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +int eth_init_state_only(bd_t *bis); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */
Can you expand these a bit? The first one can return NULL in some situations. The second returns a pointer to 6 bytes I think (perhaps we should define a struct for this in a future patch?) What are active and passive state? Why does one function get passed bd_t and not the other (better if neither did).
Legacy. Same function prototypes as original. As for active and passive state, that basically is what the Ethernet stack uses to keep track of if the network driver is enabled. These state-only functions were added to improve NetConsole performance on certain hardware without overhauling the network stack state transitions.
+#endif
+#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; @@ -145,6 +169,7 @@ int eth_write_hwaddr(struct eth_device *dev, const
char *base_name,
int eth_number);
int usb_eth_initialize(bd_t *bi); +#endif
void eth_try_another(int first_restart); /* Change the device */ void eth_set_current(void); /* set nterface to ethcur var */ diff --git a/net/eth.c b/net/eth.c index c02548c..e84b948 100644 --- a/net/eth.c +++ b/net/eth.c @@ -1,12 +1,15 @@ /*
- (C) Copyright 2001-2010
- Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*/
- Joe Hershberger, National Instruments
- SPDX-License-Identifier: GPL-2.0+
#include <common.h> #include <command.h> +#include <dm.h> +#include <dm/device-internal.h> #include <net.h> #include <miiphy.h> #include <phy.h> @@ -72,6 +75,331 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH
/**
- struct eth_device_priv - private structure for each Ethernet device
- @state: ...
- @priv: ...
/
+struct eth_device_priv {
int state;
void *priv;
+};
Structure attached to the uclass itself.
+struct eth_uclass_priv {
struct udevice *current;
+};
+static void eth_set_current_to_next(void) +{
struct uclass *uc;
struct eth_uclass_priv *uc_priv;
uclass_get(UCLASS_ETH, &uc);
uc_priv = uc->priv;
if (uc_priv->current)
uclass_next_device(&uc_priv->current);
if (!uc_priv->current)
uclass_first_device(UCLASS_ETH, &uc_priv->current);
+}
I think you should have something like this to avoid this duplication:
static struct eth_uclass_priv *get_uclass_priv(void) { struct uclass *uc;
uclass_get(UCLASS_ETH, &uc); assert(uc); return uc->priv;
}
OK.
At some point we should add a uclass_get_priv() function in uclass.h.
+struct udevice *eth_get_dev(void) +{
struct uclass *uc;
struct eth_uclass_priv *uc_priv;
uclass_get(UCLASS_ETH, &uc);
uc_priv = uc->priv;
return uc_priv->current;
+}
+static void eth_set_dev(struct udevice *dev) +{
struct uclass *uc;
struct eth_uclass_priv *uc_priv;
uclass_get(UCLASS_ETH, &uc);
uc_priv = uc->priv;
uc_priv->current = dev;
+}
+unsigned char *eth_get_ethaddr(void) +{
struct eth_pdata *pdata;
if (eth_get_dev()) {
pdata = eth_get_dev()->platdata;
if (pdata)
return pdata->enetaddr;
}
return NULL;
+}
+/* Set active state */ +int eth_init_state_only(bd_t *bis)
This doesn't seem to use bis, so I suspect it is for backwards
compatibility.
Correct.
+{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_ACTIVE;
It looks like state uses an enum, so that should be described in the comment I mentioned earlier.
OK
}
return 0;
+} +/* Set passive state */ +void eth_halt_state_only(void) +{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
}
+}
+int eth_get_dev_index(void) +{
if (eth_get_dev())
return eth_get_dev()->seq;
return -1;
+}
+int eth_init(bd_t *bis) +{
struct udevice *current, *old_current, *dev;
int retval;
struct uclass *uc;
current = eth_get_dev();
if (!current) {
puts("No ethernet found.\n");
printf() as I believe we are trying to avoid puts().
Sorry... once again a copy of the previous code with eth_device switched to udevice.
return -1;
}
retval = device_probe(current);
if (retval)
return retval;
/* Sync environment with network devices */
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(dev, uc) {
uchar env_enetaddr[6];
struct eth_pdata *pdata = dev->platdata;
ret = device_probe(dev); if (ret) ...
here since you can't use dev->seq otherwise.
It should already be probed before this function can be called.
if (eth_getenv_enetaddr_by_index("eth", dev->seq,
env_enetaddr))
memcpy(pdata->enetaddr, env_enetaddr, 6);
else
memset(pdata->enetaddr, 0, 6);
}
old_current = current;
do {
debug("Trying %s\n", current->name);
if (current->driver && (current->flags &
DM_FLAG_ACTIVATED)) {
There is no need to check current->driver (here and elsewhere)
OK
device_active(current)
const struct eth_ops *ops =
current->driver->ops;
if (ops->init(current, bis) >= 0) {
struct eth_device_priv *priv =
current->uclass_priv;
if (priv)
Remove this check too
OK
priv->state = ETH_STATE_ACTIVE;
return 0;
}
}
debug("FAIL\n");
eth_try_another(0);
current = eth_get_dev();
} while (old_current != current);
return -ENODEV;
+}
+void eth_halt(void) +{
struct udevice *current;
const struct eth_ops *ops;
struct eth_device_priv *priv;
current = eth_get_dev();
if (!current)
return;
if (!current->driver)
return;
Remove these checks
ops = current->driver->ops;
Define this in your header file:
#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
then one day we can add checks on dev, etc.
ops->halt(current);
If you like you can drop the local variable and use:
eth_get_ops(dev)->halt(current)
priv = current->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
+}
+int eth_send(void *packet, int length) +{
struct udevice *current;
const struct eth_ops *ops;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
ops = current->driver->ops;
return ops->send(current, packet, length);
+}
+int eth_rx(void) +{
struct udevice *current;
const struct eth_ops *ops;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
ops = current->driver->ops;
return ops->recv(current);
+}
+static int eth_write_hwaddr(struct udevice *dev, const char *base_name,
int eth_number)
+{
unsigned char env_enetaddr[6];
int ret = 0;
struct eth_pdata *pdata;
const struct eth_ops *ops;
eth_getenv_enetaddr_by_index(base_name, eth_number,
env_enetaddr);
pdata = dev->platdata;
if (!is_zero_ether_addr(env_enetaddr)) {
if (!is_zero_ether_addr(pdata->enetaddr) &&
memcmp(pdata->enetaddr, env_enetaddr, 6)) {
printf("\nWarning: %s MAC addresses don't
match:\n",
dev->name);
printf("Address in SROM is %pM\n",
pdata->enetaddr);
printf("Address in environment is %pM\n",
env_enetaddr);
}
memcpy(pdata->enetaddr, env_enetaddr, 6);
} else if (is_valid_ether_addr(pdata->enetaddr)) {
eth_setenv_enetaddr_by_index(base_name, eth_number,
pdata->enetaddr);
printf("\nWarning: %s using MAC address from net
device\n",
dev->name);
} else if (is_zero_ether_addr(pdata->enetaddr)) {
printf("\nError: %s address not set.\n",
dev->name);
return -EINVAL;
}
ops = dev->driver->ops;
if (dev->driver && ops && ops->write_hwaddr &&
!eth_mac_skip(eth_number)) {
if (!is_valid_ether_addr(pdata->enetaddr)) {
printf("\nError: %s address %pM illegal
value\n",
dev->name, pdata->enetaddr);
return -EINVAL;
}
ret = ops->write_hwaddr(dev);
if (ret)
printf("\nWarning: %s failed to set MAC
address\n",
dev->name);
}
return ret;
+}
+static int eth_uclass_init(struct uclass *class) +{
bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
eth_env_init();
return 0;
+}
+static int eth_post_bind(struct udevice *dev) +{
if (strchr(dev->name, ' ')) {
printf("\nError: eth device name \"%s\" has a space!\n",
dev->name);
return -EINVAL;
}
/*
* Devices need to write the hwaddr even if not probed so that
Linux
* will have access to the hwaddr that u-boot stored for the
device.
*/
dev->seq = uclass_resolve_seq(dev);
eth_write_hwaddr(dev, "eth", dev->seq);
I still don't like this sorry. I don't see why you can't do this in eth_init() above?
I'll have to make a new function for this (explained in the other patch comments).
If you really want to do this, please add #ifndef CONFIG_DM_NET around the check you have taken out and we can sort it out later.
return 0;
+}
+static int eth_pre_unbind(struct udevice *dev)
It still feels like this is using binding as the presence/absence of a device rather than probing. When a device is removed with the remove() method, it is no longer available for use, so things like eth_try_another() should ignore them. By the time we come to unbind a device, it should already be removed.
One way to think of this is that the probe()/remove() corresponds to the same idea as in Linux, and bind()/unbind() is a new thing meaning that we are aware of the device but it may not currently be available.
OK... That makes sense. I'll move it over.
+{
struct udevice *first = NULL;
struct udevice *active;
struct udevice *it;
struct uclass *uc;
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(it, uc) {
if (!first)
first = it;
if (it == dev) {
if (dev == first) {
active =
list_entry(it->uclass_node.next,
struct udevice, uclass_node);
if (&active->uclass_node ==
&uc->dev_head)
active = NULL;
} else {
active = first;
}
eth_set_dev(active);
eth_current_changed();
}
}
return 0;
+}
+static int eth_post_probe(struct udevice *dev) +{
struct eth_device_priv *priv = dev->uclass_priv;
struct eth_pdata *pdata = dev->platdata;
if (priv)
no need for this check
OK
priv->state = ETH_STATE_INIT;
if (is_zero_ether_addr(pdata->enetaddr))
return -EINVAL;
return 0;
+}
+UCLASS_DRIVER(eth) = {
.name = "eth",
.id = UCLASS_ETH,
.post_bind = eth_post_bind,
.pre_unbind = eth_pre_unbind,
.post_probe = eth_post_probe,
.init = eth_uclass_init,
.priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
.per_device_auto_alloc_size = sizeof(struct eth_device_priv),
+}; +#endif
+#ifndef CONFIG_DM_ETH /*
- CPU and board-specific Ethernet initializations. Aliased function
- signals caller to move on
@@ -423,6 +751,7 @@ int eth_rx(void)
return eth_current->recv(eth_current);
} +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -486,7 +815,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) {
static struct eth_device *first_failed;
static void *first_failed; char *ethrotate; /*
@@ -515,12 +844,9 @@ void eth_set_current(void) { static char *act; static int env_changed_id;
struct eth_device *old_current;
void *old_current; int env_id;
if (!eth_get_dev()) /* XXX no current */
return;
env_id = get_env_id(); if ((act == NULL) || (env_changed_id != env_id)) { act = getenv("ethact");
-- 1.7.11.5

Hi Joe,
On 16 February 2015 at 21:37, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Sun, Feb 15, 2015 at 9:49 AM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
First just add support for MAC drivers.
It has taken me a while to get through all this unfortunately.
This seems OK to me but needs a clean-up with more comments, etc. If you like these could go in a separate patch, so if you want to do that please add my Reviewed-by: Simon Glass sjg@chromium.org to this one. I would prefer that we sort out the bind/probe problem before this is merged but I understand you now have quite a bit of work built on top, and the problems can be separated.
So if you like we could do one more version, merge it, and continue with refinements after that.
I'm a bit leery to merge this until I've actually got more of the real-world implementation for a board done. I guess it could always be corrected in the future, but at the same time, I think it should be fairly complete. Do you prefer that it go in as smaller parts? There's still no actual board supported and the MDIO / PHY support is not done yet.
It's up to you, but I know what it is like when you have a lot of patches backed up. A real board certainly helps though.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v3: -Correct the pre_unbind logic -Correct failure chaining from bind to probe to init --Fail init if not activated --Fail probe if ethaddr not set -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the previous selection -Allow current eth dev to be NULL -Fixed blank line formatting for variable declaration
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for our needs -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()).
common/board_r.c | 4 +- common/cmd_bdinfo.c | 2 + include/dm/uclass-id.h | 1 + include/net.h | 25 ++++ net/eth.c | 336 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 361 insertions(+), 7 deletions(-)
diff --git a/common/board_r.c b/common/board_r.c index 68a9448..75147b7 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -556,7 +556,7 @@ static int initr_bbmii(void) } #endif
-#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) static int initr_net(void) { puts("Net: "); @@ -825,7 +825,7 @@ init_fnc_t init_sequence_r[] = { #ifdef CONFIG_BITBANGMII initr_bbmii, #endif -#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_DM_ETH) INIT_FUNC_WATCHDOG_RESET initr_net, #endif diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index e6d8a7a..8688cf9 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..ad96682 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */
UCLASS_ETH, /* Ethernet device */ UCLASS_COUNT, UCLASS_INVALID = -1,
diff --git a/include/net.h b/include/net.h index 4d7575e..11471bd 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,30 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH +struct eth_pdata {
phys_addr_t iobase;
unsigned char enetaddr[6];
+};
+struct eth_ops {
int (*init)(struct udevice *dev, bd_t *bis);
Why do we pass in bd_t? Isn't that available through gd->bd?
Legacy. I can kill it if you like.
OK, that's fine, it can die later.
int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev);
void (*halt)(struct udevice *dev);
+#ifdef CONFIG_MCAST_TFTP
int (*mcast)(struct udevice *dev, const u8 *enetaddr, u8 set);
s/u8/bool/ or maybe int? On ARM at least it is inefficient to keep having to mask the parameters.
Again, legacy. I just copied the former function prototypes and changed the first parameter to udevice*.
+#endif
int (*write_hwaddr)(struct udevice *dev);
+};
Can you please add interface comments on all of these plus the four below? I'm trying to make driver model an opportunity to improve the code as we go. Things like what the function does, what packet contains.
OK.
+struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +int eth_init_state_only(bd_t *bis); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */
Can you expand these a bit? The first one can return NULL in some situations. The second returns a pointer to 6 bytes I think (perhaps we should define a struct for this in a future patch?) What are active and passive state? Why does one function get passed bd_t and not the other (better if neither did).
Legacy. Same function prototypes as original. As for active and passive state, that basically is what the Ethernet stack uses to keep track of if the network driver is enabled. These state-only functions were added to improve NetConsole performance on certain hardware without overhauling the network stack state transitions.
OK
+#endif
+#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; @@ -145,6 +169,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number);
int usb_eth_initialize(bd_t *bi); +#endif
void eth_try_another(int first_restart); /* Change the device */ void eth_set_current(void); /* set nterface to ethcur var */ diff --git a/net/eth.c b/net/eth.c index c02548c..e84b948 100644 --- a/net/eth.c +++ b/net/eth.c @@ -1,12 +1,15 @@ /*
- (C) Copyright 2001-2010
- Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*/
- Joe Hershberger, National Instruments
- SPDX-License-Identifier: GPL-2.0+
#include <common.h> #include <command.h> +#include <dm.h> +#include <dm/device-internal.h> #include <net.h> #include <miiphy.h> #include <phy.h> @@ -72,6 +75,331 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH
/**
- struct eth_device_priv - private structure for each Ethernet device
- @state: ...
- @priv: ...
/
+struct eth_device_priv {
int state;
void *priv;
+};
Structure attached to the uclass itself.
+struct eth_uclass_priv {
struct udevice *current;
+};
+static void eth_set_current_to_next(void) +{
struct uclass *uc;
struct eth_uclass_priv *uc_priv;
uclass_get(UCLASS_ETH, &uc);
uc_priv = uc->priv;
if (uc_priv->current)
uclass_next_device(&uc_priv->current);
if (!uc_priv->current)
uclass_first_device(UCLASS_ETH, &uc_priv->current);
+}
I think you should have something like this to avoid this duplication:
static struct eth_uclass_priv *get_uclass_priv(void) { struct uclass *uc;
uclass_get(UCLASS_ETH, &uc); assert(uc); return uc->priv;
}
OK.
At some point we should add a uclass_get_priv() function in uclass.h.
+struct udevice *eth_get_dev(void) +{
struct uclass *uc;
struct eth_uclass_priv *uc_priv;
uclass_get(UCLASS_ETH, &uc);
uc_priv = uc->priv;
return uc_priv->current;
+}
+static void eth_set_dev(struct udevice *dev) +{
struct uclass *uc;
struct eth_uclass_priv *uc_priv;
uclass_get(UCLASS_ETH, &uc);
uc_priv = uc->priv;
uc_priv->current = dev;
+}
+unsigned char *eth_get_ethaddr(void) +{
struct eth_pdata *pdata;
if (eth_get_dev()) {
pdata = eth_get_dev()->platdata;
if (pdata)
return pdata->enetaddr;
}
return NULL;
+}
+/* Set active state */ +int eth_init_state_only(bd_t *bis)
This doesn't seem to use bis, so I suspect it is for backwards compatibility.
Correct.
+{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_ACTIVE;
It looks like state uses an enum, so that should be described in the comment I mentioned earlier.
OK
}
return 0;
+} +/* Set passive state */ +void eth_halt_state_only(void) +{
struct eth_device_priv *priv;
if (eth_get_dev()) {
priv = eth_get_dev()->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
}
+}
+int eth_get_dev_index(void) +{
if (eth_get_dev())
return eth_get_dev()->seq;
return -1;
+}
+int eth_init(bd_t *bis) +{
struct udevice *current, *old_current, *dev;
int retval;
struct uclass *uc;
current = eth_get_dev();
if (!current) {
puts("No ethernet found.\n");
printf() as I believe we are trying to avoid puts().
Sorry... once again a copy of the previous code with eth_device switched to udevice.
OK, so it could be an oppty to tidy it up, but it's fine to leave it.
return -1;
}
retval = device_probe(current);
if (retval)
return retval;
/* Sync environment with network devices */
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(dev, uc) {
uchar env_enetaddr[6];
struct eth_pdata *pdata = dev->platdata;
ret = device_probe(dev); if (ret) ...
here since you can't use dev->seq otherwise.
It should already be probed before this function can be called.
OK, can you add a comment about that here?
if (eth_getenv_enetaddr_by_index("eth", dev->seq,
env_enetaddr))
memcpy(pdata->enetaddr, env_enetaddr, 6);
else
memset(pdata->enetaddr, 0, 6);
}
old_current = current;
do {
debug("Trying %s\n", current->name);
if (current->driver && (current->flags &
DM_FLAG_ACTIVATED)) {
There is no need to check current->driver (here and elsewhere)
OK
device_active(current)
const struct eth_ops *ops =
current->driver->ops;
if (ops->init(current, bis) >= 0) {
struct eth_device_priv *priv =
current->uclass_priv;
if (priv)
Remove this check too
OK
priv->state = ETH_STATE_ACTIVE;
return 0;
}
}
debug("FAIL\n");
eth_try_another(0);
current = eth_get_dev();
} while (old_current != current);
return -ENODEV;
+}
+void eth_halt(void) +{
struct udevice *current;
const struct eth_ops *ops;
struct eth_device_priv *priv;
current = eth_get_dev();
if (!current)
return;
if (!current->driver)
return;
Remove these checks
ops = current->driver->ops;
Define this in your header file:
#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
then one day we can add checks on dev, etc.
ops->halt(current);
If you like you can drop the local variable and use:
eth_get_ops(dev)->halt(current)
priv = current->uclass_priv;
if (priv)
priv->state = ETH_STATE_PASSIVE;
+}
+int eth_send(void *packet, int length) +{
struct udevice *current;
const struct eth_ops *ops;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
ops = current->driver->ops;
return ops->send(current, packet, length);
+}
+int eth_rx(void) +{
struct udevice *current;
const struct eth_ops *ops;
current = eth_get_dev();
if (!current)
return -1;
if (!current->driver)
return -1;
ops = current->driver->ops;
return ops->recv(current);
+}
+static int eth_write_hwaddr(struct udevice *dev, const char *base_name,
int eth_number)
+{
unsigned char env_enetaddr[6];
int ret = 0;
struct eth_pdata *pdata;
const struct eth_ops *ops;
eth_getenv_enetaddr_by_index(base_name, eth_number,
env_enetaddr);
pdata = dev->platdata;
if (!is_zero_ether_addr(env_enetaddr)) {
if (!is_zero_ether_addr(pdata->enetaddr) &&
memcmp(pdata->enetaddr, env_enetaddr, 6)) {
printf("\nWarning: %s MAC addresses don't
match:\n",
dev->name);
printf("Address in SROM is %pM\n",
pdata->enetaddr);
printf("Address in environment is %pM\n",
env_enetaddr);
}
memcpy(pdata->enetaddr, env_enetaddr, 6);
} else if (is_valid_ether_addr(pdata->enetaddr)) {
eth_setenv_enetaddr_by_index(base_name, eth_number,
pdata->enetaddr);
printf("\nWarning: %s using MAC address from net
device\n",
dev->name);
} else if (is_zero_ether_addr(pdata->enetaddr)) {
printf("\nError: %s address not set.\n",
dev->name);
return -EINVAL;
}
ops = dev->driver->ops;
if (dev->driver && ops && ops->write_hwaddr &&
!eth_mac_skip(eth_number)) {
if (!is_valid_ether_addr(pdata->enetaddr)) {
printf("\nError: %s address %pM illegal
value\n",
dev->name, pdata->enetaddr);
return -EINVAL;
}
ret = ops->write_hwaddr(dev);
if (ret)
printf("\nWarning: %s failed to set MAC
address\n",
dev->name);
}
return ret;
+}
+static int eth_uclass_init(struct uclass *class) +{
bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
eth_env_init();
return 0;
+}
+static int eth_post_bind(struct udevice *dev) +{
if (strchr(dev->name, ' ')) {
printf("\nError: eth device name \"%s\" has a space!\n",
dev->name);
return -EINVAL;
}
/*
* Devices need to write the hwaddr even if not probed so that
Linux
* will have access to the hwaddr that u-boot stored for the
device.
*/
dev->seq = uclass_resolve_seq(dev);
eth_write_hwaddr(dev, "eth", dev->seq);
I still don't like this sorry. I don't see why you can't do this in eth_init() above?
I'll have to make a new function for this (explained in the other patch comments).
If you really want to do this, please add #ifndef CONFIG_DM_NET around the check you have taken out and we can sort it out later.
return 0;
+}
+static int eth_pre_unbind(struct udevice *dev)
It still feels like this is using binding as the presence/absence of a device rather than probing. When a device is removed with the remove() method, it is no longer available for use, so things like eth_try_another() should ignore them. By the time we come to unbind a device, it should already be removed.
One way to think of this is that the probe()/remove() corresponds to the same idea as in Linux, and bind()/unbind() is a new thing meaning that we are aware of the device but it may not currently be available.
OK... That makes sense. I'll move it over.
+{
struct udevice *first = NULL;
struct udevice *active;
struct udevice *it;
struct uclass *uc;
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(it, uc) {
if (!first)
first = it;
if (it == dev) {
if (dev == first) {
active =
list_entry(it->uclass_node.next,
struct udevice, uclass_node);
if (&active->uclass_node ==
&uc->dev_head)
active = NULL;
} else {
active = first;
}
eth_set_dev(active);
eth_current_changed();
}
}
return 0;
+}
+static int eth_post_probe(struct udevice *dev) +{
struct eth_device_priv *priv = dev->uclass_priv;
struct eth_pdata *pdata = dev->platdata;
if (priv)
no need for this check
OK
priv->state = ETH_STATE_INIT;
if (is_zero_ether_addr(pdata->enetaddr))
return -EINVAL;
return 0;
+}
+UCLASS_DRIVER(eth) = {
.name = "eth",
.id = UCLASS_ETH,
.post_bind = eth_post_bind,
.pre_unbind = eth_pre_unbind,
.post_probe = eth_post_probe,
.init = eth_uclass_init,
.priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
.per_device_auto_alloc_size = sizeof(struct eth_device_priv),
+}; +#endif
+#ifndef CONFIG_DM_ETH /*
- CPU and board-specific Ethernet initializations. Aliased function
- signals caller to move on
@@ -423,6 +751,7 @@ int eth_rx(void)
return eth_current->recv(eth_current);
} +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -486,7 +815,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) {
static struct eth_device *first_failed;
static void *first_failed; char *ethrotate; /*
@@ -515,12 +844,9 @@ void eth_set_current(void) { static char *act; static int env_changed_id;
struct eth_device *old_current;
void *old_current; int env_id;
if (!eth_get_dev()) /* XXX no current */
return;
env_id = get_env_id(); if ((act == NULL) || (env_changed_id != env_id)) { act = getenv("ethact");
-- 1.7.11.5
Regards, Simon

Add basic network support to sandbox which includes a network driver.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: -Added 2 more ethaddr to sandbox -Print which device in the debug write hwaddr
Changes in v2: -Change printfs to debug in sandbox driver -Remove unused priv struct for sandbox driver
arch/sandbox/dts/sandbox.dts | 4 +++ drivers/net/Makefile | 1 + drivers/net/sandbox.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 18 +++++++--- 4 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 drivers/net/sandbox.c
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 4c63e4f..502eb3d 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -183,4 +183,8 @@ }; };
+ eth@10002000 { + compatible = "sandbox,eth"; + reg = <0x10002000 0x1000>; + }; }; diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 46c4ac6..15dc431 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_NS8382X) += ns8382x.o obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o +obj-$(CONFIG_ETH_SANDBOX) += sandbox.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c new file mode 100644 index 0000000..2a2ad41 --- /dev/null +++ b/drivers/net/sandbox.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int sb_eth_init(struct udevice *dev, bd_t *bis) +{ + debug("eth_sandbox: Init\n"); + + return 0; +} + +static int sb_eth_send(struct udevice *dev, void *packet, int length) +{ + debug("eth_sandbox: Send packet %d\n", length); + + return 0; +} + +static int sb_eth_recv(struct udevice *dev) +{ + return 0; +} + +static void sb_eth_halt(struct udevice *dev) +{ + debug("eth_sandbox: Halt\n"); +} + +static int sb_eth_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev->platdata; + debug("eth_sandbox %s: Write HW ADDR - %pM\n", dev->name, + pdata->enetaddr); + return 0; +} + +static const struct eth_ops sb_eth_ops = { + .init = sb_eth_init, + .send = sb_eth_send, + .recv = sb_eth_recv, + .halt = sb_eth_halt, + .write_hwaddr = sb_eth_write_hwaddr, +}; + +static int sb_eth_remove(struct udevice *dev) +{ + return 0; +} + +#ifdef CONFIG_OF_CONTROL +static int sb_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev->platdata; + + pdata->iobase = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); + return 0; +} + +static const struct udevice_id sb_eth_ids[] = { + { .compatible = "sandbox,eth" }, + { } +}; +#endif + +U_BOOT_DRIVER(eth_sandbox) = { + .name = "eth_sandbox", + .id = UCLASS_ETH, + .of_match = of_match_ptr(sb_eth_ids), + .ofdata_to_platdata = of_match_ptr(sb_eth_ofdata_to_platdata), + .remove = sb_eth_remove, + .ops = &sb_eth_ops, + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index e9d3f32..fdba1c8 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -139,9 +139,9 @@ /* include default commands */ #include <config_cmd_default.h>
-/* We don't have networking support yet */ -#undef CONFIG_CMD_NET -#undef CONFIG_CMD_NFS +#define CONFIG_DM_ETH +#define CONFIG_ETH_SANDBOX +#define CONFIG_CMD_PING
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY @@ -184,12 +184,20 @@
#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial,cros-ec-keyb\0" \ "stdout=serial,lcd\0" \ - "stderr=serial,lcd\0" + "stderr=serial,lcd\0" \ + "ethaddr=00:00:11:22:33:44\0" \ + "eth1addr=00:00:11:22:33:45\0" \ + "eth2addr=00:00:11:22:33:46\0" \ + "ipaddr=1.2.3.4\0" #else
#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial\0" \ "stdout=serial,lcd\0" \ - "stderr=serial,lcd\0" + "stderr=serial,lcd\0" \ + "ethaddr=00:00:11:22:33:44\0" \ + "eth1addr=00:00:11:22:33:45\0" \ + "eth2addr=00:00:11:22:33:46\0" \ + "ipaddr=1.2.3.4\0" #endif
#define CONFIG_GZIP_COMPRESSED

Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
Add basic network support to sandbox which includes a network driver.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v3: -Added 2 more ethaddr to sandbox -Print which device in the debug write hwaddr
Changes in v2: -Change printfs to debug in sandbox driver -Remove unused priv struct for sandbox driver
arch/sandbox/dts/sandbox.dts | 4 +++ drivers/net/Makefile | 1 + drivers/net/sandbox.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 18 +++++++--- 4 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 drivers/net/sandbox.c
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 4c63e4f..502eb3d 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -183,4 +183,8 @@ }; };
eth@10002000 {
compatible = "sandbox,eth";
reg = <0x10002000 0x1000>;
};
}; diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 46c4ac6..15dc431 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_NS8382X) += ns8382x.o obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o +obj-$(CONFIG_ETH_SANDBOX) += sandbox.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c new file mode 100644 index 0000000..2a2ad41 --- /dev/null +++ b/drivers/net/sandbox.c @@ -0,0 +1,86 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <malloc.h> +#include <net.h>
+DECLARE_GLOBAL_DATA_PTR;
+static int sb_eth_init(struct udevice *dev, bd_t *bis) +{
debug("eth_sandbox: Init\n");
return 0;
+}
+static int sb_eth_send(struct udevice *dev, void *packet, int length) +{
debug("eth_sandbox: Send packet %d\n", length);
return 0;
+}
+static int sb_eth_recv(struct udevice *dev) +{
return 0;
+}
+static void sb_eth_halt(struct udevice *dev) +{
debug("eth_sandbox: Halt\n");
+}
+static int sb_eth_write_hwaddr(struct udevice *dev) +{
struct eth_pdata *pdata = dev->platdata;
debug("eth_sandbox %s: Write HW ADDR - %pM\n", dev->name,
pdata->enetaddr);
return 0;
+}
+static const struct eth_ops sb_eth_ops = {
.init = sb_eth_init,
.send = sb_eth_send,
.recv = sb_eth_recv,
.halt = sb_eth_halt,
.write_hwaddr = sb_eth_write_hwaddr,
+};
+static int sb_eth_remove(struct udevice *dev) +{
return 0;
+}
+#ifdef CONFIG_OF_CONTROL +static int sb_eth_ofdata_to_platdata(struct udevice *dev) +{
struct eth_pdata *pdata = dev->platdata;
pdata->iobase = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
return 0;
+}
+static const struct udevice_id sb_eth_ids[] = {
{ .compatible = "sandbox,eth" },
{ }
+}; +#endif
+U_BOOT_DRIVER(eth_sandbox) = {
.name = "eth_sandbox",
.id = UCLASS_ETH,
.of_match = of_match_ptr(sb_eth_ids),
.ofdata_to_platdata = of_match_ptr(sb_eth_ofdata_to_platdata),
.remove = sb_eth_remove,
.ops = &sb_eth_ops,
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+}; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index e9d3f32..fdba1c8 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -139,9 +139,9 @@ /* include default commands */ #include <config_cmd_default.h>
-/* We don't have networking support yet */ -#undef CONFIG_CMD_NET -#undef CONFIG_CMD_NFS +#define CONFIG_DM_ETH +#define CONFIG_ETH_SANDBOX +#define CONFIG_CMD_PING
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY @@ -184,12 +184,20 @@
#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial,cros-ec-keyb\0" \ "stdout=serial,lcd\0" \
"stderr=serial,lcd\0"
"stderr=serial,lcd\0" \
"ethaddr=00:00:11:22:33:44\0" \
"eth1addr=00:00:11:22:33:45\0" \
"eth2addr=00:00:11:22:33:46\0" \
"ipaddr=1.2.3.4\0"
#else
#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial\0" \ "stdout=serial,lcd\0" \
"stderr=serial,lcd\0"
"stderr=serial,lcd\0" \
"ethaddr=00:00:11:22:33:44\0" \
"eth1addr=00:00:11:22:33:45\0" \
"eth2addr=00:00:11:22:33:46\0" \
"ipaddr=1.2.3.4\0"
#endif
This needs tidying up, something like:
#define SANDBOX_DEVICE_SETTINGS "stdin...stderr" #define SANDBOX_NET_SETTINGS "your ones"
#define CONFIG_EXTRA_ENV_SETTINGS SANDBOX_DEVICE_SETTINGS SANDBOX_NET_SETTINGS
#define CONFIG_GZIP_COMPRESSED
1.7.11.5
Regards, Simon

The sandbox driver will now generate response traffic to exercise the ping command even when no network exists. This allows the basic data pathways of the DM to be tested.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v3: -Prevent a crash if memory is not allocated
Changes in v2: -Change printfs to debug in sandbox driver -Move static data to priv -Move fake hwaddr to the device tree
arch/sandbox/dts/sandbox.dts | 1 + drivers/net/sandbox.c | 101 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+)
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 502eb3d..ba635e8 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -186,5 +186,6 @@ eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; }; }; diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 2a2ad41..f9fa1a1 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -15,22 +15,121 @@
DECLARE_GLOBAL_DATA_PTR;
+struct eth_sandbox_priv { + uchar fake_host_hwaddr[ARP_HLEN]; + IPaddr_t fake_host_ipaddr; + uchar recv_packet_buffer[PKTSIZE]; + int recv_packet_length; +}; + static int sb_eth_init(struct udevice *dev, bd_t *bis) { debug("eth_sandbox: Init\n");
+ struct eth_sandbox_priv *priv = dev->priv; + u32 int_array[ARP_HLEN]; + int i; + + if (!priv) + return -EINVAL; + + fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "fake-host-hwaddr", + int_array, ARP_HLEN); + for (i = 0; i < ARP_HLEN; i++) + priv->fake_host_hwaddr[i] = (uchar)int_array[i]; + return 0; }
static int sb_eth_send(struct udevice *dev, void *packet, int length) { debug("eth_sandbox: Send packet %d\n", length); + struct eth_sandbox_priv *priv = dev->priv; + struct ethernet_hdr *eth = packet; + + if (ntohs(eth->et_protlen) == PROT_ARP) { + struct arp_hdr *arp = packet + ETHER_HDR_SIZE; + if (ntohs(arp->ar_op) == ARPOP_REQUEST) { + /* store this as the assumed IP of the fake host */ + priv->fake_host_ipaddr = NetReadIP(&arp->ar_tpa); + /* Formulate a fake response */ + struct ethernet_hdr *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); + + struct arp_hdr *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); + NetWriteIP(&arp_recv->ar_spa, priv->fake_host_ipaddr); + memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN); + NetCopyIP(&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) { + /* reply to the ping */ + memcpy(priv->recv_packet_buffer, packet, + length); + struct ethernet_hdr *eth_recv = + (void *)priv->recv_packet_buffer; + struct ip_udp_hdr *ipr = + (void *)priv->recv_packet_buffer + + ETHER_HDR_SIZE; + struct icmp_hdr *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; + NetCopyIP((void *)&ipr->ip_dst, &ip->ip_src); + NetWriteIP((void *)&ipr->ip_src, + priv->fake_host_ipaddr); + ipr->ip_sum = ~NetCksum((uchar *)ipr, + IP_HDR_SIZE >> 1); + + icmpr->type = ICMP_ECHO_REPLY; + icmpr->checksum = 0; + icmpr->checksum = ~NetCksum((uchar *)icmpr, + (length - ETHER_HDR_SIZE - + IP_HDR_SIZE) >> 1); + + priv->recv_packet_length = length; + } + } + }
return 0; }
static int sb_eth_recv(struct udevice *dev) { + struct eth_sandbox_priv *priv = dev->priv; + + if (priv && priv->recv_packet_length) { + int lcl_recv_packet_length = priv->recv_packet_length; + debug("eth_sandbox: received packet %d\n", + priv->recv_packet_length); + priv->recv_packet_length = 0; + NetReceive((void *)priv->recv_packet_buffer, + lcl_recv_packet_length); + } return 0; }
@@ -42,6 +141,7 @@ static void sb_eth_halt(struct udevice *dev) static int sb_eth_write_hwaddr(struct udevice *dev) { struct eth_pdata *pdata = dev->platdata; + debug("eth_sandbox %s: Write HW ADDR - %pM\n", dev->name, pdata->enetaddr); return 0; @@ -82,5 +182,6 @@ U_BOOT_DRIVER(eth_sandbox) = { .ofdata_to_platdata = of_match_ptr(sb_eth_ofdata_to_platdata), .remove = sb_eth_remove, .ops = &sb_eth_ops, + .priv_auto_alloc_size = sizeof(struct eth_sandbox_priv), .platdata_auto_alloc_size = sizeof(struct eth_pdata), };

Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
The sandbox driver will now generate response traffic to exercise the ping command even when no network exists. This allows the basic data pathways of the DM to be tested.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v3: -Prevent a crash if memory is not allocated
Changes in v2: -Change printfs to debug in sandbox driver -Move static data to priv -Move fake hwaddr to the device tree
arch/sandbox/dts/sandbox.dts | 1 + drivers/net/sandbox.c | 101 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+)
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 502eb3d..ba635e8 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -186,5 +186,6 @@ eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>;
fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
}; diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 2a2ad41..f9fa1a1 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -15,22 +15,121 @@
DECLARE_GLOBAL_DATA_PTR;
+struct eth_sandbox_priv {
uchar fake_host_hwaddr[ARP_HLEN];
IPaddr_t fake_host_ipaddr;
uchar recv_packet_buffer[PKTSIZE];
int recv_packet_length;
+};
static int sb_eth_init(struct udevice *dev, bd_t *bis) { debug("eth_sandbox: Init\n");
struct eth_sandbox_priv *priv = dev->priv;
u32 int_array[ARP_HLEN];
int i;
if (!priv)
return -EINVAL;
How can this happen?
fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "fake-host-hwaddr",
int_array, ARP_HLEN);
for (i = 0; i < ARP_HLEN; i++)
priv->fake_host_hwaddr[i] = (uchar)int_array[i];
return 0;
}
static int sb_eth_send(struct udevice *dev, void *packet, int length) { debug("eth_sandbox: Send packet %d\n", length);
struct eth_sandbox_priv *priv = dev->priv;
struct ethernet_hdr *eth = packet;
if (ntohs(eth->et_protlen) == PROT_ARP) {
struct arp_hdr *arp = packet + ETHER_HDR_SIZE;
if (ntohs(arp->ar_op) == ARPOP_REQUEST) {
/* store this as the assumed IP of the fake host */
priv->fake_host_ipaddr = NetReadIP(&arp->ar_tpa);
/* Formulate a fake response */
struct ethernet_hdr *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);
struct arp_hdr *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);
NetWriteIP(&arp_recv->ar_spa, priv->fake_host_ipaddr);
memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN);
NetCopyIP(&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) {
/* reply to the ping */
memcpy(priv->recv_packet_buffer, packet,
length);
struct ethernet_hdr *eth_recv =
(void *)priv->recv_packet_buffer;
struct ip_udp_hdr *ipr =
(void *)priv->recv_packet_buffer +
ETHER_HDR_SIZE;
struct icmp_hdr *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;
NetCopyIP((void *)&ipr->ip_dst, &ip->ip_src);
NetWriteIP((void *)&ipr->ip_src,
priv->fake_host_ipaddr);
ipr->ip_sum = ~NetCksum((uchar *)ipr,
IP_HDR_SIZE >> 1);
icmpr->type = ICMP_ECHO_REPLY;
icmpr->checksum = 0;
icmpr->checksum = ~NetCksum((uchar *)icmpr,
(length - ETHER_HDR_SIZE -
IP_HDR_SIZE) >> 1);
priv->recv_packet_length = length;
}
}
} return 0;
}
static int sb_eth_recv(struct udevice *dev) {
struct eth_sandbox_priv *priv = dev->priv;
if (priv && priv->recv_packet_length) {
int lcl_recv_packet_length = priv->recv_packet_length;
debug("eth_sandbox: received packet %d\n",
priv->recv_packet_length);
priv->recv_packet_length = 0;
NetReceive((void *)priv->recv_packet_buffer,
lcl_recv_packet_length);
} return 0;
}
@@ -42,6 +141,7 @@ static void sb_eth_halt(struct udevice *dev) static int sb_eth_write_hwaddr(struct udevice *dev) { struct eth_pdata *pdata = dev->platdata;
debug("eth_sandbox %s: Write HW ADDR - %pM\n", dev->name, pdata->enetaddr); return 0;
@@ -82,5 +182,6 @@ U_BOOT_DRIVER(eth_sandbox) = { .ofdata_to_platdata = of_match_ptr(sb_eth_ofdata_to_platdata), .remove = sb_eth_remove, .ops = &sb_eth_ops,
.priv_auto_alloc_size = sizeof(struct eth_sandbox_priv), .platdata_auto_alloc_size = sizeof(struct eth_pdata),
};
1.7.11.5
Regards, Simon

On Sun, Feb 15, 2015 at 9:49 AM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com
wrote:
The sandbox driver will now generate response traffic to exercise the ping command even when no network exists. This allows the basic data pathways of the DM to be tested.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v3: -Prevent a crash if memory is not allocated
Changes in v2: -Change printfs to debug in sandbox driver -Move static data to priv -Move fake hwaddr to the device tree
arch/sandbox/dts/sandbox.dts | 1 + drivers/net/sandbox.c | 101
+++++++++++++++++++++++++++++++++++++++++++
2 files changed, 102 insertions(+)
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 502eb3d..ba635e8 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -186,5 +186,6 @@ eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>;
fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
}; diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 2a2ad41..f9fa1a1 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -15,22 +15,121 @@
DECLARE_GLOBAL_DATA_PTR;
+struct eth_sandbox_priv {
uchar fake_host_hwaddr[ARP_HLEN];
IPaddr_t fake_host_ipaddr;
uchar recv_packet_buffer[PKTSIZE];
int recv_packet_length;
+};
static int sb_eth_init(struct udevice *dev, bd_t *bis) { debug("eth_sandbox: Init\n");
struct eth_sandbox_priv *priv = dev->priv;
u32 int_array[ARP_HLEN];
int i;
if (!priv)
return -EINVAL;
How can this happen?
If I recall this was happening when the probe failed due to being unable to find a MAC address. This meant that the device was not active when the init was called on it. I believe I later remedied it by checking that the DM_FLAG_ACTIVATED was set, so this check is probably not needed any longer.
Is there a way in DM to iterate through only those devices that have been successfully probed or is it my responsibility to check activated before using any ops?
fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
"fake-host-hwaddr",
int_array, ARP_HLEN);
for (i = 0; i < ARP_HLEN; i++)
priv->fake_host_hwaddr[i] = (uchar)int_array[i];
return 0;
}
static int sb_eth_send(struct udevice *dev, void *packet, int length) { debug("eth_sandbox: Send packet %d\n", length);
struct eth_sandbox_priv *priv = dev->priv;
struct ethernet_hdr *eth = packet;
if (ntohs(eth->et_protlen) == PROT_ARP) {
struct arp_hdr *arp = packet + ETHER_HDR_SIZE;
if (ntohs(arp->ar_op) == ARPOP_REQUEST) {
/* store this as the assumed IP of the fake
host */
priv->fake_host_ipaddr =
NetReadIP(&arp->ar_tpa);
/* Formulate a fake response */
struct ethernet_hdr *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);
struct arp_hdr *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);
NetWriteIP(&arp_recv->ar_spa,
priv->fake_host_ipaddr);
memcpy(&arp_recv->ar_tha, &arp->ar_sha,
ARP_HLEN);
NetCopyIP(&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) {
/* reply to the ping */
memcpy(priv->recv_packet_buffer, packet,
length);
struct ethernet_hdr *eth_recv =
(void
*)priv->recv_packet_buffer;
struct ip_udp_hdr *ipr =
(void
*)priv->recv_packet_buffer +
ETHER_HDR_SIZE;
struct icmp_hdr *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;
NetCopyIP((void *)&ipr->ip_dst,
&ip->ip_src);
NetWriteIP((void *)&ipr->ip_src,
priv->fake_host_ipaddr);
ipr->ip_sum = ~NetCksum((uchar *)ipr,
IP_HDR_SIZE >> 1);
icmpr->type = ICMP_ECHO_REPLY;
icmpr->checksum = 0;
icmpr->checksum = ~NetCksum((uchar
*)icmpr,
(length - ETHER_HDR_SIZE -
IP_HDR_SIZE) >> 1);
priv->recv_packet_length = length;
}
}
} return 0;
}
static int sb_eth_recv(struct udevice *dev) {
struct eth_sandbox_priv *priv = dev->priv;
if (priv && priv->recv_packet_length) {
int lcl_recv_packet_length = priv->recv_packet_length;
debug("eth_sandbox: received packet %d\n",
priv->recv_packet_length);
priv->recv_packet_length = 0;
NetReceive((void *)priv->recv_packet_buffer,
lcl_recv_packet_length);
} return 0;
}
@@ -42,6 +141,7 @@ static void sb_eth_halt(struct udevice *dev) static int sb_eth_write_hwaddr(struct udevice *dev) { struct eth_pdata *pdata = dev->platdata;
debug("eth_sandbox %s: Write HW ADDR - %pM\n", dev->name, pdata->enetaddr); return 0;
@@ -82,5 +182,6 @@ U_BOOT_DRIVER(eth_sandbox) = { .ofdata_to_platdata = of_match_ptr(sb_eth_ofdata_to_platdata), .remove = sb_eth_remove, .ops = &sb_eth_ops,
.priv_auto_alloc_size = sizeof(struct eth_sandbox_priv), .platdata_auto_alloc_size = sizeof(struct eth_pdata),
};
1.7.11.5
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi Joe,
On 16 February 2015 at 21:46, Joe Hershberger joe.hershberger@gmail.com wrote:
On Sun, Feb 15, 2015 at 9:49 AM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
The sandbox driver will now generate response traffic to exercise the ping command even when no network exists. This allows the basic data pathways of the DM to be tested.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v3: -Prevent a crash if memory is not allocated
Changes in v2: -Change printfs to debug in sandbox driver -Move static data to priv -Move fake hwaddr to the device tree
arch/sandbox/dts/sandbox.dts | 1 + drivers/net/sandbox.c | 101 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+)
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 502eb3d..ba635e8 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -186,5 +186,6 @@ eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>;
fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
}; diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 2a2ad41..f9fa1a1 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -15,22 +15,121 @@
DECLARE_GLOBAL_DATA_PTR;
+struct eth_sandbox_priv {
uchar fake_host_hwaddr[ARP_HLEN];
IPaddr_t fake_host_ipaddr;
uchar recv_packet_buffer[PKTSIZE];
int recv_packet_length;
+};
static int sb_eth_init(struct udevice *dev, bd_t *bis) { debug("eth_sandbox: Init\n");
struct eth_sandbox_priv *priv = dev->priv;
u32 int_array[ARP_HLEN];
int i;
if (!priv)
return -EINVAL;
How can this happen?
If I recall this was happening when the probe failed due to being unable to find a MAC address. This meant that the device was not active when the init was called on it. I believe I later remedied it by checking that the DM_FLAG_ACTIVATED was set, so this check is probably not needed any longer.
Is there a way in DM to iterate through only those devices that have been successfully probed or is it my responsibility to check activated before using any ops?
I normally check it in the uclass. The functions which return a device -e.g. uclass_get_device...() normally probe the device before it is returned. The idea is that it should be hard to obtain a 'struct udevice' in non-core code (i.e. outside drivers/core) without it being probed first.
But if you want to iterate across all devices and skip those that are not probed you will need to do it yourself, or add helper functions.
[snip]
Regards, Simon

Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v3: -Added dm eth testing
Changes in v2: None
test/dm/Makefile | 1 + test/dm/eth.c | 39 +++++++++++++++++++++++++++++++++++++++ test/dm/test.dts | 18 ++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 test/dm/eth.c
diff --git a/test/dm/Makefile b/test/dm/Makefile index 1d9148f..b2eb989 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_DM_TEST) += ut.o obj-$(CONFIG_DM_TEST) += core.o obj-$(CONFIG_DM_TEST) += ut.o ifneq ($(CONFIG_SANDBOX),) +obj-$(CONFIG_DM_ETH) += eth.o obj-$(CONFIG_DM_GPIO) += gpio.o obj-$(CONFIG_DM_I2C) += i2c.o obj-$(CONFIG_DM_SPI_FLASH) += sf.o diff --git a/test/dm/eth.c b/test/dm/eth.c new file mode 100644 index 0000000..2b29fa2 --- /dev/null +++ b/test/dm/eth.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <dm/test.h> +#include <dm/ut.h> +#include <fdtdec.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int dm_test_eth(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + + setenv("ethact", "eth@10002000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth@10003000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10003000", getenv("ethact")); + + setenv("ethact", "eth@10004000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + return 0; +} + +DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 84024a4..2f68cdf 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -149,4 +149,22 @@ }; };
+ eth@10002000 { + compatible = "sandbox,eth"; + reg = <0x10002000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; + }; + + eth@10003000 { + compatible = "sandbox,eth"; + reg = <0x10003000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>; + }; + + eth@10004000 { + compatible = "sandbox,eth"; + reg = <0x10004000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x22>; + }; + };

On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
This needs a commit message describing what is added. With that:
Reviewed-by: Simon Glass sjg@chromium.org
Changes in v3: -Added dm eth testing
Changes in v2: None
test/dm/Makefile | 1 + test/dm/eth.c | 39 +++++++++++++++++++++++++++++++++++++++ test/dm/test.dts | 18 ++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 test/dm/eth.c
diff --git a/test/dm/Makefile b/test/dm/Makefile index 1d9148f..b2eb989 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_DM_TEST) += ut.o obj-$(CONFIG_DM_TEST) += core.o obj-$(CONFIG_DM_TEST) += ut.o ifneq ($(CONFIG_SANDBOX),) +obj-$(CONFIG_DM_ETH) += eth.o obj-$(CONFIG_DM_GPIO) += gpio.o obj-$(CONFIG_DM_I2C) += i2c.o obj-$(CONFIG_DM_SPI_FLASH) += sf.o diff --git a/test/dm/eth.c b/test/dm/eth.c new file mode 100644 index 0000000..2b29fa2 --- /dev/null +++ b/test/dm/eth.c @@ -0,0 +1,39 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <dm/test.h> +#include <dm/ut.h> +#include <fdtdec.h> +#include <malloc.h> +#include <net.h>
+DECLARE_GLOBAL_DATA_PTR;
+static int dm_test_eth(struct dm_test_state *dms) +{
NetPingIP = string_to_ip("1.1.2.2");
setenv("ethact", "eth@10002000");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10002000", getenv("ethact"));
setenv("ethact", "eth@10003000");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10003000", getenv("ethact"));
setenv("ethact", "eth@10004000");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10004000", getenv("ethact"));
return 0;
+}
+DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 84024a4..2f68cdf 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -149,4 +149,22 @@ }; };
eth@10002000 {
compatible = "sandbox,eth";
reg = <0x10002000 0x1000>;
fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>;
};
eth@10003000 {
compatible = "sandbox,eth";
reg = <0x10003000 0x1000>;
fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>;
};
eth@10004000 {
compatible = "sandbox,eth";
reg = <0x10004000 0x1000>;
fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x22>;
};
};
1.7.11.5

Allow network devices to be referred to as "eth0" instead of "eth@12345678" when specified in ethact.
Add tests to verify this behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v3: -Added support for aliases
Changes in v2: None
include/configs/sandbox.h | 4 ++-- include/fdtdec.h | 1 + include/net.h | 5 +++++ lib/fdtdec.c | 1 + net/eth.c | 53 +++++++++++++++++++++++++++++++++++++++-------- test/dm/eth.c | 25 ++++++++++++++++++++++ test/dm/test.dts | 10 +++++---- 7 files changed, 84 insertions(+), 15 deletions(-)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index fdba1c8..9df5f74 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -187,7 +187,7 @@ "stderr=serial,lcd\0" \ "ethaddr=00:00:11:22:33:44\0" \ "eth1addr=00:00:11:22:33:45\0" \ - "eth2addr=00:00:11:22:33:46\0" \ + "eth5addr=00:00:11:22:33:46\0" \ "ipaddr=1.2.3.4\0" #else
@@ -196,7 +196,7 @@ "stderr=serial,lcd\0" \ "ethaddr=00:00:11:22:33:44\0" \ "eth1addr=00:00:11:22:33:45\0" \ - "eth2addr=00:00:11:22:33:46\0" \ + "eth5addr=00:00:11:22:33:46\0" \ "ipaddr=1.2.3.4\0" #endif
diff --git a/include/fdtdec.h b/include/fdtdec.h index 231eed7..e945baa 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -167,6 +167,7 @@ enum fdt_compat_id { COMPAT_INTEL_GMA, /* Intel Graphics Media Accelerator */ COMPAT_AMS_AS3722, /* AMS AS3722 PMIC */ COMPAT_INTEL_ICH_SPI, /* Intel ICH7/9 SPI controller */ + COMPAT_ETHERNET, /* Ethernet devices */
COMPAT_COUNT, }; diff --git a/include/net.h b/include/net.h index 11471bd..4e98850 100644 --- a/include/net.h +++ b/include/net.h @@ -38,6 +38,8 @@
#define PKTALIGN ARCH_DMA_MINALIGN
+#define ETH_MAX_DEVS 32 + /* IPv4 addresses are always 32 bits in size */ typedef __be32 IPaddr_t;
@@ -79,6 +81,8 @@ enum eth_state_t { };
#ifdef CONFIG_DM_ETH +#define ETH_ALIAS_ROOT "eth" + struct eth_pdata { phys_addr_t iobase; unsigned char enetaddr[6]; @@ -96,6 +100,7 @@ struct eth_ops { };
struct udevice *eth_get_dev(void); /* get the current device */ +struct udevice *eth_get_dev_by_name(const char *devname); unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ int eth_init_state_only(bd_t *bis); /* Set active state */ void eth_halt_state_only(void); /* Set passive state */ diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 5bf8f29..33b0a53 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -75,6 +75,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(INTEL_GMA, "intel,gma"), COMPAT(AMS_AS3722, "ams,as3722"), COMPAT(INTEL_ICH_SPI, "intel,ich-spi"), + COMPAT(ETHERNET, "eth"), };
const char *fdtdec_get_compatible(enum fdt_compat_id id) diff --git a/net/eth.c b/net/eth.c index e84b948..762effe 100644 --- a/net/eth.c +++ b/net/eth.c @@ -10,11 +10,14 @@ #include <command.h> #include <dm.h> #include <dm/device-internal.h> +#include <fdtdec.h> #include <net.h> #include <miiphy.h> #include <phy.h> #include <asm/errno.h>
+DECLARE_GLOBAL_DATA_PTR; + void eth_parse_enetaddr(const char *addr, uchar *enetaddr) { char *end; @@ -121,6 +124,39 @@ static void eth_set_dev(struct udevice *dev) uc_priv->current = dev; }
+/* + * Find the udevice that either has the name passed in as devname or has an + * alias named devname. + */ +struct udevice *eth_get_dev_by_name(const char *devname) +{ + int node_list[ETH_MAX_DEVS]; + int count; + int seq; + char *endp = NULL; + const char *true_name = devname; + struct udevice *it; + struct uclass *uc; + + count = fdtdec_find_aliases_for_id(gd->fdt_blob, ETH_ALIAS_ROOT, + COMPAT_ETHERNET, node_list, + ETH_MAX_DEVS); + + seq = simple_strtoul(devname + strlen(ETH_ALIAS_ROOT), &endp, 10); + + if (endp > devname + strlen(ETH_ALIAS_ROOT) && count > seq && + node_list[seq]) + true_name = fdt_get_name(gd->fdt_blob, node_list[seq], NULL); + + uclass_get(UCLASS_ETH, &uc); + uclass_foreach_dev(it, uc) { + if (strcmp(it->name, true_name) == 0 || it->seq == seq) + return it; + } + + return NULL; +} + unsigned char *eth_get_ethaddr(void) { struct eth_pdata *pdata; @@ -396,6 +432,7 @@ UCLASS_DRIVER(eth) = { .init = eth_uclass_init, .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), .per_device_auto_alloc_size = sizeof(struct eth_device_priv), + .flags = DM_UC_FLAG_SEQ_ALIAS, }; #endif
@@ -428,6 +465,11 @@ static void eth_set_current_to_next(void) eth_current = eth_current->next; }
+static void eth_set_dev(struct eth_device *dev) +{ + eth_current = dev; +} + struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -844,7 +886,6 @@ void eth_set_current(void) { static char *act; static int env_changed_id; - void *old_current; int env_id;
env_id = get_env_id(); @@ -852,14 +893,8 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; } - if (act != NULL) { - old_current = eth_get_dev(); - do { - if (strcmp(eth_get_name(), act) == 0) - return; - eth_set_current_to_next(); - } while (old_current != eth_get_dev()); - } + if (act != NULL) + eth_set_dev(eth_get_dev_by_name(act));
eth_current_changed(); } diff --git a/test/dm/eth.c b/test/dm/eth.c index 2b29fa2..c0a8ab5 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -37,3 +37,28 @@ static int dm_test_eth(struct dm_test_state *dms) }
DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT); + +static int dm_test_eth_alias(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + setenv("ethact", "eth0"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth1"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Expected to fail since eth2 is not defined in the device tree */ + setenv("ethact", "eth2"); + ut_asserteq(-1, NetLoop(PING)); + ut_asserteq_ptr(NULL, getenv("ethact")); + + setenv("ethact", "eth5"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10003000", getenv("ethact")); + + return 0; +} + +DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 2f68cdf..c5008c3 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -17,6 +17,8 @@ testfdt3 = "/b-test"; testfdt5 = "/some-bus/c-test@5"; testfdt8 = "/a-test"; + eth0 = "/eth@10002000"; + eth5 = ð_5; };
uart0: serial { @@ -150,19 +152,19 @@ };
eth@10002000 { - compatible = "sandbox,eth"; + compatible = "sandbox,eth", "eth"; reg = <0x10002000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
- eth@10003000 { - compatible = "sandbox,eth"; + eth_5: eth@10003000 { + compatible = "sandbox,eth", "eth"; reg = <0x10003000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>; };
eth@10004000 { - compatible = "sandbox,eth"; + compatible = "sandbox,eth", "eth"; reg = <0x10004000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x22>; };

Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
Allow network devices to be referred to as "eth0" instead of "eth@12345678" when specified in ethact.
Add tests to verify this behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v3: -Added support for aliases
Changes in v2: None
include/configs/sandbox.h | 4 ++-- include/fdtdec.h | 1 + include/net.h | 5 +++++ lib/fdtdec.c | 1 + net/eth.c | 53 +++++++++++++++++++++++++++++++++++++++-------- test/dm/eth.c | 25 ++++++++++++++++++++++ test/dm/test.dts | 10 +++++---- 7 files changed, 84 insertions(+), 15 deletions(-)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index fdba1c8..9df5f74 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -187,7 +187,7 @@ "stderr=serial,lcd\0" \ "ethaddr=00:00:11:22:33:44\0" \ "eth1addr=00:00:11:22:33:45\0" \
"eth2addr=00:00:11:22:33:46\0" \
"eth5addr=00:00:11:22:33:46\0" \ "ipaddr=1.2.3.4\0"
#else
@@ -196,7 +196,7 @@ "stderr=serial,lcd\0" \ "ethaddr=00:00:11:22:33:44\0" \ "eth1addr=00:00:11:22:33:45\0" \
"eth2addr=00:00:11:22:33:46\0" \
"eth5addr=00:00:11:22:33:46\0" \ "ipaddr=1.2.3.4\0"
#endif
diff --git a/include/fdtdec.h b/include/fdtdec.h index 231eed7..e945baa 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -167,6 +167,7 @@ enum fdt_compat_id { COMPAT_INTEL_GMA, /* Intel Graphics Media Accelerator */ COMPAT_AMS_AS3722, /* AMS AS3722 PMIC */ COMPAT_INTEL_ICH_SPI, /* Intel ICH7/9 SPI controller */
COMPAT_ETHERNET, /* Ethernet devices */
SANDBOX_ETHERNET
COMPAT_COUNT,
}; diff --git a/include/net.h b/include/net.h index 11471bd..4e98850 100644 --- a/include/net.h +++ b/include/net.h @@ -38,6 +38,8 @@
#define PKTALIGN ARCH_DMA_MINALIGN
+#define ETH_MAX_DEVS 32
/* IPv4 addresses are always 32 bits in size */ typedef __be32 IPaddr_t;
@@ -79,6 +81,8 @@ enum eth_state_t { };
#ifdef CONFIG_DM_ETH +#define ETH_ALIAS_ROOT "eth"
struct eth_pdata { phys_addr_t iobase; unsigned char enetaddr[6]; @@ -96,6 +100,7 @@ struct eth_ops { };
struct udevice *eth_get_dev(void); /* get the current device */ +struct udevice *eth_get_dev_by_name(const char *devname); unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ int eth_init_state_only(bd_t *bis); /* Set active state */ void eth_halt_state_only(void); /* Set passive state */ diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 5bf8f29..33b0a53 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -75,6 +75,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(INTEL_GMA, "intel,gma"), COMPAT(AMS_AS3722, "ams,as3722"), COMPAT(INTEL_ICH_SPI, "intel,ich-spi"),
COMPAT(ETHERNET, "eth"),
sandbox,eth
};
const char *fdtdec_get_compatible(enum fdt_compat_id id) diff --git a/net/eth.c b/net/eth.c index e84b948..762effe 100644 --- a/net/eth.c +++ b/net/eth.c @@ -10,11 +10,14 @@ #include <command.h> #include <dm.h> #include <dm/device-internal.h> +#include <fdtdec.h> #include <net.h> #include <miiphy.h> #include <phy.h> #include <asm/errno.h>
+DECLARE_GLOBAL_DATA_PTR;
void eth_parse_enetaddr(const char *addr, uchar *enetaddr) { char *end; @@ -121,6 +124,39 @@ static void eth_set_dev(struct udevice *dev) uc_priv->current = dev; }
+/*
- Find the udevice that either has the name passed in as devname or has an
- alias named devname.
- */
+struct udevice *eth_get_dev_by_name(const char *devname) +{
int node_list[ETH_MAX_DEVS];
int count;
int seq;
char *endp = NULL;
const char *true_name = devname;
struct udevice *it;
struct uclass *uc;
count = fdtdec_find_aliases_for_id(gd->fdt_blob, ETH_ALIAS_ROOT,
COMPAT_ETHERNET, node_list,
ETH_MAX_DEVS);
seq = simple_strtoul(devname + strlen(ETH_ALIAS_ROOT), &endp, 10);
if (endp > devname + strlen(ETH_ALIAS_ROOT) && count > seq &&
node_list[seq])
true_name = fdt_get_name(gd->fdt_blob, node_list[seq], NULL);
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(it, uc) {
if (strcmp(it->name, true_name) == 0 || it->seq == seq)
return it;
}
Is it possible for eth_get_dev_by_name() to just look up the name provided?
You already have this:
uclass_foreach_dev(it, uc) { if (strcmp(it->name, true_name) == 0 || it->seq == seq) return it; }
It feels like you just need to through through the devices in the uclass and strcmp(dev->name, find_name).
I guess I am suffering because I don't understand what you are trying to do, so am not sure if there is an easier way with driver model. We really should not go looking in the device tree in eth_get_dev_by_name()...driver is responsible for parsing that.
return NULL;
+}
unsigned char *eth_get_ethaddr(void) { struct eth_pdata *pdata; @@ -396,6 +432,7 @@ UCLASS_DRIVER(eth) = { .init = eth_uclass_init, .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), .per_device_auto_alloc_size = sizeof(struct eth_device_priv),
.flags = DM_UC_FLAG_SEQ_ALIAS,
}; #endif
@@ -428,6 +465,11 @@ static void eth_set_current_to_next(void) eth_current = eth_current->next; }
+static void eth_set_dev(struct eth_device *dev) +{
eth_current = dev;
+}
struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -844,7 +886,6 @@ void eth_set_current(void) { static char *act; static int env_changed_id;
void *old_current; int env_id; env_id = get_env_id();
@@ -852,14 +893,8 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; }
if (act != NULL) {
old_current = eth_get_dev();
do {
if (strcmp(eth_get_name(), act) == 0)
return;
eth_set_current_to_next();
} while (old_current != eth_get_dev());
}
if (act != NULL)
eth_set_dev(eth_get_dev_by_name(act)); eth_current_changed();
} diff --git a/test/dm/eth.c b/test/dm/eth.c index 2b29fa2..c0a8ab5 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -37,3 +37,28 @@ static int dm_test_eth(struct dm_test_state *dms) }
DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT);
+static int dm_test_eth_alias(struct dm_test_state *dms) +{
NetPingIP = string_to_ip("1.1.2.2");
setenv("ethact", "eth0");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10002000", getenv("ethact"));
setenv("ethact", "eth1");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10004000", getenv("ethact"));
/* Expected to fail since eth2 is not defined in the device tree */
setenv("ethact", "eth2");
ut_asserteq(-1, NetLoop(PING));
ut_asserteq_ptr(NULL, getenv("ethact"));
setenv("ethact", "eth5");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10003000", getenv("ethact"));
return 0;
+}
+DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 2f68cdf..c5008c3 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -17,6 +17,8 @@ testfdt3 = "/b-test"; testfdt5 = "/some-bus/c-test@5"; testfdt8 = "/a-test";
eth0 = "/eth@10002000";
eth5 = ð_5; }; uart0: serial {
@@ -150,19 +152,19 @@ };
eth@10002000 {
compatible = "sandbox,eth";
compatible = "sandbox,eth", "eth"; reg = <0x10002000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
eth@10003000 {
compatible = "sandbox,eth";
eth_5: eth@10003000 {
compatible = "sandbox,eth", "eth"; reg = <0x10003000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>; }; eth@10004000 {
compatible = "sandbox,eth";
compatible = "sandbox,eth", "eth"; reg = <0x10004000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x22>; };
-- 1.7.11.5
Regards, Simon

On Sun, Feb 15, 2015 at 9:50 AM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com
wrote:
Allow network devices to be referred to as "eth0" instead of "eth@12345678" when specified in ethact.
Add tests to verify this behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v3: -Added support for aliases
Changes in v2: None
include/configs/sandbox.h | 4 ++-- include/fdtdec.h | 1 + include/net.h | 5 +++++ lib/fdtdec.c | 1 + net/eth.c | 53
+++++++++++++++++++++++++++++++++++++++--------
test/dm/eth.c | 25 ++++++++++++++++++++++ test/dm/test.dts | 10 +++++---- 7 files changed, 84 insertions(+), 15 deletions(-)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index fdba1c8..9df5f74 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -187,7 +187,7 @@ "stderr=serial,lcd\0" \ "ethaddr=00:00:11:22:33:44\0" \ "eth1addr=00:00:11:22:33:45\0" \
"eth2addr=00:00:11:22:33:46\0" \
"eth5addr=00:00:11:22:33:46\0" \ "ipaddr=1.2.3.4\0"
#else
@@ -196,7 +196,7 @@ "stderr=serial,lcd\0" \ "ethaddr=00:00:11:22:33:44\0" \ "eth1addr=00:00:11:22:33:45\0" \
"eth2addr=00:00:11:22:33:46\0" \
"eth5addr=00:00:11:22:33:46\0" \ "ipaddr=1.2.3.4\0"
#endif
diff --git a/include/fdtdec.h b/include/fdtdec.h index 231eed7..e945baa 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -167,6 +167,7 @@ enum fdt_compat_id { COMPAT_INTEL_GMA, /* Intel Graphics Media
Accelerator */
COMPAT_AMS_AS3722, /* AMS AS3722 PMIC */ COMPAT_INTEL_ICH_SPI, /* Intel ICH7/9 SPI controller
*/
COMPAT_ETHERNET, /* Ethernet devices */
SANDBOX_ETHERNET
This is not limited to sandbox. This is needed for all Ethernet MACs. Is there some other way that I should be identifying with all devices in the device tree of a certain class?
COMPAT_COUNT,
}; diff --git a/include/net.h b/include/net.h index 11471bd..4e98850 100644 --- a/include/net.h +++ b/include/net.h @@ -38,6 +38,8 @@
#define PKTALIGN ARCH_DMA_MINALIGN
+#define ETH_MAX_DEVS 32
/* IPv4 addresses are always 32 bits in size */ typedef __be32 IPaddr_t;
@@ -79,6 +81,8 @@ enum eth_state_t { };
#ifdef CONFIG_DM_ETH +#define ETH_ALIAS_ROOT "eth"
struct eth_pdata { phys_addr_t iobase; unsigned char enetaddr[6]; @@ -96,6 +100,7 @@ struct eth_ops { };
struct udevice *eth_get_dev(void); /* get the current device */ +struct udevice *eth_get_dev_by_name(const char *devname); unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ int eth_init_state_only(bd_t *bis); /* Set active state */ void eth_halt_state_only(void); /* Set passive state */ diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 5bf8f29..33b0a53 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -75,6 +75,7 @@ static const char * const compat_names[COMPAT_COUNT]
= {
COMPAT(INTEL_GMA, "intel,gma"), COMPAT(AMS_AS3722, "ams,as3722"), COMPAT(INTEL_ICH_SPI, "intel,ich-spi"),
COMPAT(ETHERNET, "eth"),
sandbox,eth
Again, this is used to identify all Ethernet controllers. Perhaps fdtdec_find_aliases_for_id() should not be limiting the alias search to those that have a certain "compatible" string?
};
const char *fdtdec_get_compatible(enum fdt_compat_id id) diff --git a/net/eth.c b/net/eth.c index e84b948..762effe 100644 --- a/net/eth.c +++ b/net/eth.c @@ -10,11 +10,14 @@ #include <command.h> #include <dm.h> #include <dm/device-internal.h> +#include <fdtdec.h> #include <net.h> #include <miiphy.h> #include <phy.h> #include <asm/errno.h>
+DECLARE_GLOBAL_DATA_PTR;
void eth_parse_enetaddr(const char *addr, uchar *enetaddr) { char *end; @@ -121,6 +124,39 @@ static void eth_set_dev(struct udevice *dev) uc_priv->current = dev; }
+/*
- Find the udevice that either has the name passed in as devname or
has an
- alias named devname.
- */
+struct udevice *eth_get_dev_by_name(const char *devname) +{
int node_list[ETH_MAX_DEVS];
int count;
int seq;
char *endp = NULL;
const char *true_name = devname;
struct udevice *it;
struct uclass *uc;
count = fdtdec_find_aliases_for_id(gd->fdt_blob, ETH_ALIAS_ROOT,
COMPAT_ETHERNET, node_list,
ETH_MAX_DEVS);
seq = simple_strtoul(devname + strlen(ETH_ALIAS_ROOT), &endp,
10);
if (endp > devname + strlen(ETH_ALIAS_ROOT) && count > seq &&
node_list[seq])
true_name = fdt_get_name(gd->fdt_blob, node_list[seq],
NULL);
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(it, uc) {
if (strcmp(it->name, true_name) == 0 || it->seq == seq)
return it;
}
Is it possible for eth_get_dev_by_name() to just look up the name
provided?
You already have this:
uclass_foreach_dev(it, uc) { if (strcmp(it->name, true_name) == 0 || it->seq == seq) return it; }
It feels like you just need to through through the devices in the uclass and strcmp(dev->name, find_name).
That works fine for looking up the exact name, but that's not the point of this patch. Such code was already there and you can see it below.
I guess I am suffering because I don't understand what you are trying to do, so am not sure if there is an easier way with driver model. We really should not go looking in the device tree in eth_get_dev_by_name()...driver is responsible for parsing that.
Perhaps this is a limitation of fdtdec_find_aliases_for_id(). I need to be able to look up the device based on its alias. It doesn't seem to me that I'm digging around in the device tree at random places that should be done by the driver. I'm simply wanting to ask the device tree what the alias that the user passed in is pointing at. Potentially is it not an alias, but a full name. Either way, I want to return the udevice.
return NULL;
+}
unsigned char *eth_get_ethaddr(void) { struct eth_pdata *pdata; @@ -396,6 +432,7 @@ UCLASS_DRIVER(eth) = { .init = eth_uclass_init, .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), .per_device_auto_alloc_size = sizeof(struct eth_device_priv),
.flags = DM_UC_FLAG_SEQ_ALIAS,
}; #endif
@@ -428,6 +465,11 @@ static void eth_set_current_to_next(void) eth_current = eth_current->next; }
+static void eth_set_dev(struct eth_device *dev) +{
eth_current = dev;
+}
struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -844,7 +886,6 @@ void eth_set_current(void) { static char *act; static int env_changed_id;
void *old_current; int env_id; env_id = get_env_id();
@@ -852,14 +893,8 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; }
if (act != NULL) {
old_current = eth_get_dev();
do {
if (strcmp(eth_get_name(), act) == 0)
return;
eth_set_current_to_next();
} while (old_current != eth_get_dev());
}
This is the simple compare that is being replaced.
if (act != NULL)
eth_set_dev(eth_get_dev_by_name(act)); eth_current_changed();
} diff --git a/test/dm/eth.c b/test/dm/eth.c index 2b29fa2..c0a8ab5 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -37,3 +37,28 @@ static int dm_test_eth(struct dm_test_state *dms) }
DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT);
+static int dm_test_eth_alias(struct dm_test_state *dms) +{
NetPingIP = string_to_ip("1.1.2.2");
setenv("ethact", "eth0");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10002000", getenv("ethact"));
setenv("ethact", "eth1");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10004000", getenv("ethact"));
/* Expected to fail since eth2 is not defined in the device
tree */
setenv("ethact", "eth2");
ut_asserteq(-1, NetLoop(PING));
ut_asserteq_ptr(NULL, getenv("ethact"));
setenv("ethact", "eth5");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10003000", getenv("ethact"));
return 0;
+}
+DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 2f68cdf..c5008c3 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -17,6 +17,8 @@ testfdt3 = "/b-test"; testfdt5 = "/some-bus/c-test@5"; testfdt8 = "/a-test";
eth0 = "/eth@10002000";
eth5 = ð_5; }; uart0: serial {
@@ -150,19 +152,19 @@ };
eth@10002000 {
compatible = "sandbox,eth";
compatible = "sandbox,eth", "eth"; reg = <0x10002000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
eth@10003000 {
compatible = "sandbox,eth";
eth_5: eth@10003000 {
compatible = "sandbox,eth", "eth"; reg = <0x10003000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>; }; eth@10004000 {
compatible = "sandbox,eth";
compatible = "sandbox,eth", "eth"; reg = <0x10004000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x22>; };
-- 1.7.11.5
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi Joe,
On 16 February 2015 at 22:04, Joe Hershberger joe.hershberger@gmail.com wrote:
On Sun, Feb 15, 2015 at 9:50 AM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
Allow network devices to be referred to as "eth0" instead of "eth@12345678" when specified in ethact.
Add tests to verify this behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v3: -Added support for aliases
Changes in v2: None
include/configs/sandbox.h | 4 ++-- include/fdtdec.h | 1 + include/net.h | 5 +++++ lib/fdtdec.c | 1 + net/eth.c | 53 +++++++++++++++++++++++++++++++++++++++-------- test/dm/eth.c | 25 ++++++++++++++++++++++ test/dm/test.dts | 10 +++++---- 7 files changed, 84 insertions(+), 15 deletions(-)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index fdba1c8..9df5f74 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -187,7 +187,7 @@ "stderr=serial,lcd\0" \ "ethaddr=00:00:11:22:33:44\0" \ "eth1addr=00:00:11:22:33:45\0" \
"eth2addr=00:00:11:22:33:46\0" \
"eth5addr=00:00:11:22:33:46\0" \ "ipaddr=1.2.3.4\0"
#else
@@ -196,7 +196,7 @@ "stderr=serial,lcd\0" \ "ethaddr=00:00:11:22:33:44\0" \ "eth1addr=00:00:11:22:33:45\0" \
"eth2addr=00:00:11:22:33:46\0" \
"eth5addr=00:00:11:22:33:46\0" \ "ipaddr=1.2.3.4\0"
#endif
diff --git a/include/fdtdec.h b/include/fdtdec.h index 231eed7..e945baa 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -167,6 +167,7 @@ enum fdt_compat_id { COMPAT_INTEL_GMA, /* Intel Graphics Media Accelerator */ COMPAT_AMS_AS3722, /* AMS AS3722 PMIC */ COMPAT_INTEL_ICH_SPI, /* Intel ICH7/9 SPI controller */
COMPAT_ETHERNET, /* Ethernet devices */
SANDBOX_ETHERNET
This is not limited to sandbox. This is needed for all Ethernet MACs. Is there some other way that I should be identifying with all devices in the device tree of a certain class?
Not that I know of. But each Ethernet driver would need its own compatible string, since otherwise driver model won't use the right driver.
COMPAT_COUNT,
}; diff --git a/include/net.h b/include/net.h index 11471bd..4e98850 100644 --- a/include/net.h +++ b/include/net.h @@ -38,6 +38,8 @@
#define PKTALIGN ARCH_DMA_MINALIGN
+#define ETH_MAX_DEVS 32
/* IPv4 addresses are always 32 bits in size */ typedef __be32 IPaddr_t;
@@ -79,6 +81,8 @@ enum eth_state_t { };
#ifdef CONFIG_DM_ETH +#define ETH_ALIAS_ROOT "eth"
struct eth_pdata { phys_addr_t iobase; unsigned char enetaddr[6]; @@ -96,6 +100,7 @@ struct eth_ops { };
struct udevice *eth_get_dev(void); /* get the current device */ +struct udevice *eth_get_dev_by_name(const char *devname); unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ int eth_init_state_only(bd_t *bis); /* Set active state */ void eth_halt_state_only(void); /* Set passive state */ diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 5bf8f29..33b0a53 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -75,6 +75,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(INTEL_GMA, "intel,gma"), COMPAT(AMS_AS3722, "ams,as3722"), COMPAT(INTEL_ICH_SPI, "intel,ich-spi"),
COMPAT(ETHERNET, "eth"),
sandbox,eth
Again, this is used to identify all Ethernet controllers. Perhaps fdtdec_find_aliases_for_id() should not be limiting the alias search to those that have a certain "compatible" string?
I think you want 'sandbox,ethernet' here, or similar, but you probably don't want to use that fdtdec function ultimately. Driver model should do it all for you.
};
const char *fdtdec_get_compatible(enum fdt_compat_id id) diff --git a/net/eth.c b/net/eth.c index e84b948..762effe 100644 --- a/net/eth.c +++ b/net/eth.c @@ -10,11 +10,14 @@ #include <command.h> #include <dm.h> #include <dm/device-internal.h> +#include <fdtdec.h> #include <net.h> #include <miiphy.h> #include <phy.h> #include <asm/errno.h>
+DECLARE_GLOBAL_DATA_PTR;
void eth_parse_enetaddr(const char *addr, uchar *enetaddr) { char *end; @@ -121,6 +124,39 @@ static void eth_set_dev(struct udevice *dev) uc_priv->current = dev; }
+/*
- Find the udevice that either has the name passed in as devname or
has an
- alias named devname.
- */
+struct udevice *eth_get_dev_by_name(const char *devname) +{
int node_list[ETH_MAX_DEVS];
int count;
int seq;
char *endp = NULL;
const char *true_name = devname;
struct udevice *it;
struct uclass *uc;
count = fdtdec_find_aliases_for_id(gd->fdt_blob, ETH_ALIAS_ROOT,
COMPAT_ETHERNET, node_list,
ETH_MAX_DEVS);
seq = simple_strtoul(devname + strlen(ETH_ALIAS_ROOT), &endp,
10);
if (endp > devname + strlen(ETH_ALIAS_ROOT) && count > seq &&
node_list[seq])
true_name = fdt_get_name(gd->fdt_blob, node_list[seq],
NULL);
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(it, uc) {
if (strcmp(it->name, true_name) == 0 || it->seq == seq)
return it;
}
Is it possible for eth_get_dev_by_name() to just look up the name provided?
You already have this:
uclass_foreach_dev(it, uc) { if (strcmp(it->name, true_name) == 0 || it->seq == seq) return it; }
It feels like you just need to through through the devices in the uclass and strcmp(dev->name, find_name).
That works fine for looking up the exact name, but that's not the point of this patch. Such code was already there and you can see it below.
OK
I guess I am suffering because I don't understand what you are trying to do, so am not sure if there is an easier way with driver model. We really should not go looking in the device tree in eth_get_dev_by_name()...driver is responsible for parsing that.
Perhaps this is a limitation of fdtdec_find_aliases_for_id(). I need to be able to look up the device based on its alias. It doesn't seem to me that I'm digging around in the device tree at random places that should be done by the driver. I'm simply wanting to ask the device tree what the alias that the user passed in is pointing at. Potentially is it not an alias, but a full name. Either way, I want to return the udevice.
If you want to know the device's number, use dev->req_seq. This will hold the alias number. If it is -1 then the device is not mentioned in /aliases in the device tree.
But please see if you can use the existing driver model features to find devices, their numbers, etc.
return NULL;
+}
unsigned char *eth_get_ethaddr(void) { struct eth_pdata *pdata; @@ -396,6 +432,7 @@ UCLASS_DRIVER(eth) = { .init = eth_uclass_init, .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), .per_device_auto_alloc_size = sizeof(struct eth_device_priv),
.flags = DM_UC_FLAG_SEQ_ALIAS,
}; #endif
@@ -428,6 +465,11 @@ static void eth_set_current_to_next(void) eth_current = eth_current->next; }
+static void eth_set_dev(struct eth_device *dev) +{
eth_current = dev;
+}
struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -844,7 +886,6 @@ void eth_set_current(void) { static char *act; static int env_changed_id;
void *old_current; int env_id; env_id = get_env_id();
@@ -852,14 +893,8 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; }
if (act != NULL) {
old_current = eth_get_dev();
do {
if (strcmp(eth_get_name(), act) == 0)
return;
eth_set_current_to_next();
} while (old_current != eth_get_dev());
}
This is the simple compare that is being replaced.
if (act != NULL)
eth_set_dev(eth_get_dev_by_name(act)); eth_current_changed();
} diff --git a/test/dm/eth.c b/test/dm/eth.c index 2b29fa2..c0a8ab5 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -37,3 +37,28 @@ static int dm_test_eth(struct dm_test_state *dms) }
DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT);
+static int dm_test_eth_alias(struct dm_test_state *dms) +{
NetPingIP = string_to_ip("1.1.2.2");
setenv("ethact", "eth0");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10002000", getenv("ethact"));
setenv("ethact", "eth1");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10004000", getenv("ethact"));
/* Expected to fail since eth2 is not defined in the device tree
*/
setenv("ethact", "eth2");
ut_asserteq(-1, NetLoop(PING));
ut_asserteq_ptr(NULL, getenv("ethact"));
setenv("ethact", "eth5");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10003000", getenv("ethact"));
return 0;
+}
+DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 2f68cdf..c5008c3 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -17,6 +17,8 @@ testfdt3 = "/b-test"; testfdt5 = "/some-bus/c-test@5"; testfdt8 = "/a-test";
eth0 = "/eth@10002000";
eth5 = ð_5; }; uart0: serial {
@@ -150,19 +152,19 @@ };
eth@10002000 {
compatible = "sandbox,eth";
compatible = "sandbox,eth", "eth"; reg = <0x10002000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
eth@10003000 {
compatible = "sandbox,eth";
eth_5: eth@10003000 {
compatible = "sandbox,eth", "eth"; reg = <0x10003000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>; }; eth@10004000 {
compatible = "sandbox,eth";
compatible = "sandbox,eth", "eth"; reg = <0x10004000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x22>; };
-- 1.7.11.5
Regards, Simon

The ethprime env var is used to indicate the starting device if none is specified in ethact. Also support aliases specified in the ethprime var.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v3: -Added support for ethprime
Changes in v2: None
net/eth.c | 13 ++++++++++++- test/dm/eth.c | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/net/eth.c b/net/eth.c index 762effe..1770662 100644 --- a/net/eth.c +++ b/net/eth.c @@ -893,8 +893,19 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; } - if (act != NULL) + + if (act == NULL) { + char *ethprime = getenv("ethprime"); + + if (ethprime && eth_get_dev_by_name(ethprime)) { + eth_set_dev(eth_get_dev_by_name(ethprime)); + } else { + eth_set_dev(NULL); + eth_set_current_to_next(); + } + } else { eth_set_dev(eth_get_dev_by_name(act)); + }
eth_current_changed(); } diff --git a/test/dm/eth.c b/test/dm/eth.c index c0a8ab5..b39a94a 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -62,3 +62,24 @@ static int dm_test_eth_alias(struct dm_test_state *dms) }
DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT); + +static int dm_test_eth_prime(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + + /* Expected to be "eth@10003000" because of ethprime variable */ + setenv("ethact", NULL); + setenv("ethprime", "eth5"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10003000", getenv("ethact")); + + /* Expected to be "eth@10002000" because it is first */ + setenv("ethact", NULL); + setenv("ethprime", NULL); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + return 0; +} + +DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT);

Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
The ethprime env var is used to indicate the starting device if none is specified in ethact. Also support aliases specified in the ethprime var.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org
Two nits below.
Changes in v3: -Added support for ethprime
Changes in v2: None
net/eth.c | 13 ++++++++++++- test/dm/eth.c | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/net/eth.c b/net/eth.c index 762effe..1770662 100644 --- a/net/eth.c +++ b/net/eth.c @@ -893,8 +893,19 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; }
if (act != NULL)
if (act == NULL) {
char *ethprime = getenv("ethprime");
if (ethprime && eth_get_dev_by_name(ethprime)) {
eth_set_dev(eth_get_dev_by_name(ethprime));
Can you store the result of eth_get_dev_by_name() and reuse it? It seems like an expensive function.
} else {
eth_set_dev(NULL);
eth_set_current_to_next();
}
} else { eth_set_dev(eth_get_dev_by_name(act));
} eth_current_changed();
} diff --git a/test/dm/eth.c b/test/dm/eth.c index c0a8ab5..b39a94a 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -62,3 +62,24 @@ static int dm_test_eth_alias(struct dm_test_state *dms) }
DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT);
+static int dm_test_eth_prime(struct dm_test_state *dms) +{
NetPingIP = string_to_ip("1.1.2.2");
/* Expected to be "eth@10003000" because of ethprime variable */
setenv("ethact", NULL);
setenv("ethprime", "eth5");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10003000", getenv("ethact"));
/* Expected to be "eth@10002000" because it is first */
setenv("ethact", NULL);
setenv("ethprime", NULL);
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10002000", getenv("ethact"));
return 0;
+}
Can you remove this blank line so it is consistent with other test files?
+DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT);
1.7.11.5
Regards, Simon

Make sure that the retry behavior occurs as expected.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v3: -Added testing for netretry
Changes in v2: None
test/dm/eth.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/test/dm/eth.c b/test/dm/eth.c index b39a94a..831a994 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -83,3 +83,28 @@ static int dm_test_eth_prime(struct dm_test_state *dms) }
DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT); + +static int dm_test_eth_retry(struct dm_test_state *dms) +{ + char ethaddr[18]; + + NetPingIP = string_to_ip("1.1.2.2"); + strcpy(ethaddr, getenv("eth1addr")); + setenv("ethact", "eth@10004000"); + setenv("eth1addr", NULL); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth@10004000"); + setenv("netretry", "no"); + ut_asserteq(-1, NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Restore the env */ + setenv("eth1addr", ethaddr); + setenv("netretry", NULL); + + return 0; +} + +DM_TEST(dm_test_eth_retry, DM_TESTF_SCAN_FDT);

On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
Make sure that the retry behavior occurs as expected.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org
Nit below.
Changes in v3: -Added testing for netretry
Changes in v2: None
test/dm/eth.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/test/dm/eth.c b/test/dm/eth.c index b39a94a..831a994 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -83,3 +83,28 @@ static int dm_test_eth_prime(struct dm_test_state *dms) }
DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT);
+static int dm_test_eth_retry(struct dm_test_state *dms) +{
char ethaddr[18];
NetPingIP = string_to_ip("1.1.2.2");
strcpy(ethaddr, getenv("eth1addr"));
setenv("ethact", "eth@10004000");
setenv("eth1addr", NULL);
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10002000", getenv("ethact"));
setenv("ethact", "eth@10004000");
setenv("netretry", "no");
ut_asserteq(-1, NetLoop(PING));
ut_asserteq_str("eth@10004000", getenv("ethact"));
/* Restore the env */
setenv("eth1addr", ethaddr);
setenv("netretry", NULL);
return 0;
+}
Remove blank line again
+DM_TEST(dm_test_eth_retry, DM_TESTF_SCAN_FDT);
1.7.11.5

Implement a bridge between u-boot's network stack and Linux's raw packet API allowing the sandbox to send and receive packets using the host machine's network interface.
This raw Ethernet API requires elevated privileges. You can either run as root, or you can add the capability needed like so:
sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v3: -Made the os raw packet support for sandbox eth build and work.
Changes in v2: -Added the raw packet proof-of-concept patch.
arch/sandbox/dts/sandbox.dts | 6 ++ arch/sandbox/include/asm/sandbox-raw-os.h | 16 ++++ drivers/net/Makefile | 11 +++ drivers/net/sandbox-raw-os.c | 105 ++++++++++++++++++++++++ drivers/net/sandbox-raw.c | 128 ++++++++++++++++++++++++++++++ include/configs/sandbox.h | 1 + 6 files changed, 267 insertions(+) create mode 100644 arch/sandbox/include/asm/sandbox-raw-os.h create mode 100644 drivers/net/sandbox-raw-os.c create mode 100644 drivers/net/sandbox-raw.c
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index ba635e8..13bd6c2 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -188,4 +188,10 @@ reg = <0x10002000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; }; + + eth@80000000 { + compatible = "sandbox,eth,raw"; + reg = <0x80000000 0x1000>; + host-raw-interface = "eth0"; + }; }; diff --git a/arch/sandbox/include/asm/sandbox-raw-os.h b/arch/sandbox/include/asm/sandbox-raw-os.h new file mode 100644 index 0000000..4e5d418 --- /dev/null +++ b/arch/sandbox/include/asm/sandbox-raw-os.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#pragma once + +int sandbox_raw_init(int *sd, void **devp, const char *ifname, + unsigned char *ethmac); +int sandbox_raw_send(void *packet, int length, int sd, void *device); +int sandbox_raw_recv(void *packet, int *length, int sd, void *device); +void sandbox_raw_halt(int *sd, void **devp); diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 15dc431..39975b3 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -51,6 +51,8 @@ obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o obj-$(CONFIG_ETH_SANDBOX) += sandbox.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw-os.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o @@ -68,3 +70,12 @@ obj-$(CONFIG_XILINX_LL_TEMAC) += xilinx_ll_temac.o xilinx_ll_temac_mdio.o \ obj-$(CONFIG_ZYNQ_GEM) += zynq_gem.o obj-$(CONFIG_FSL_MC_ENET) += fsl_mc/ obj-$(CONFIG_VSC9953) += vsc9953.o + +# sandbox-raw-os.c is built in the system env, so needs standard includes +# CFLAGS_REMOVE_sandbox-raw-os.o cannot be used to drop header include path +quiet_cmd_cc_sandbox-raw-os.o = CC $(quiet_modtag) $@ +cmd_cc_sandbox-raw-os.o = $(CC) $(filter-out -nostdinc, \ + $(patsubst -I%,-idirafter%,$(c_flags))) -c -o $@ $< + +$(obj)/sandbox-raw-os.o: $(src)/sandbox-raw-os.c FORCE + $(call if_changed_dep,cc_sandbox-raw-os.o) diff --git a/drivers/net/sandbox-raw-os.c b/drivers/net/sandbox-raw-os.c new file mode 100644 index 0000000..43fae60 --- /dev/null +++ b/drivers/net/sandbox-raw-os.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <errno.h> +#include <net/if.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <linux/if_ether.h> +#include <linux/if_packet.h> + +int sandbox_raw_init(int *sd, void **devp, const char *ifname, + unsigned char *ethmac) +{ + int tempsd = 0; + struct ifreq ifr; + + strcpy(ifr.ifr_name, ifname); + ifr.ifr_addr.sa_family = AF_INET; + memset(ethmac, 0, 6); + tempsd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + if (tempsd < 0) { + printf("Failed to open socket: %d %s\n", errno, + strerror(errno)); + return 1; + } + if (ioctl(tempsd, SIOCGIFHWADDR, &ifr) < 0) { + printf("Failed to call ioctl: %s\n", strerror(errno)); + close(tempsd); + return 1; + } + /* + * This only works if the MAC address is overridden with the actual MAC + * address of the interface being used. + */ + memcpy(ethmac, ifr.ifr_hwaddr.sa_data, 6 * sizeof(uint8_t)); + close(tempsd); + + *devp = malloc(sizeof(struct sockaddr_ll)); + struct sockaddr_ll *device = *devp; + memset(device, 0, sizeof(struct sockaddr_ll)); + device->sll_ifindex = if_nametoindex(ifname); + device->sll_family = AF_PACKET; + memcpy(device->sll_addr, ethmac, 6); + device->sll_halen = htons(6); + + *sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + setsockopt(*sd, SOL_SOCKET, SO_BINDTODEVICE, ifname, + strlen(ifname) + 1); + + return 0; +} + +int sandbox_raw_send(void *packet, int length, int sd, void *device) +{ + int retval; + + if (!sd || !device) + return -EINVAL; + retval = sendto(sd, packet, length, 0, + (struct sockaddr *)device, sizeof(struct sockaddr_ll)); + if (retval < 0) + printf("Failed to send packet: %d %s\n", errno, + strerror(errno)); + return retval; +} + +int sandbox_raw_recv(void *packet, int *length, int sd, void *device) +{ + int retval; + int saddr_size; + + if (!sd || !device) + return -EINVAL; + saddr_size = sizeof(struct sockaddr); + retval = recvfrom(sd, packet, 1536, 0, (struct sockaddr *)device, + (socklen_t *)&saddr_size); + *length = 0; + if (retval > 0) { + *length = retval; + return 0; + } + + return retval; +} + +void sandbox_raw_halt(int *sd, void **devp) +{ + free((struct sockaddr_ll *)*devp); + *devp = NULL; + close(*sd); + *sd = -1; +} diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c new file mode 100644 index 0000000..90e462a --- /dev/null +++ b/drivers/net/sandbox-raw.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <asm/sandbox-raw-os.h> +#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct eth_sandbox_raw_priv { + int sd; + void *device; +}; + +static int sb_eth_raw_init(struct udevice *dev, bd_t *bis) +{ + debug("eth_sandbox_raw: Init\n"); + + struct eth_sandbox_raw_priv *priv = dev->priv; + if (!priv) + return -EINVAL; + + struct eth_pdata *pdata = dev->platdata; + int retval; + const char *interface = fdt_getprop(gd->fdt_blob, dev->of_offset, + "host-raw-interface", NULL); + + retval = sandbox_raw_init(&priv->sd, &priv->device, interface, + pdata->enetaddr); + + return retval; +} + +static int sb_eth_raw_send(struct udevice *dev, void *packet, int length) +{ + debug("eth_sandbox_raw: Send packet %d\n", length); + + struct eth_sandbox_raw_priv *priv = dev->priv; + + return sandbox_raw_send(packet, length, priv->sd, priv->device); +} + +static int sb_eth_raw_recv(struct udevice *dev) +{ + struct eth_sandbox_raw_priv *priv = dev->priv; + + int retval; + uchar buffer[PKTSIZE]; + int length; + + if (!priv) + return 0; + retval = sandbox_raw_recv(buffer, &length, priv->sd, priv->device); + if (!retval && length) { + debug("eth_sandbox_raw: received packet %d\n", + length); + NetReceive(buffer, length); + } + return 0; +} + +static void sb_eth_raw_halt(struct udevice *dev) +{ + debug("eth_sandbox_raw: Halt\n"); + + struct eth_sandbox_raw_priv *priv = dev->priv; + + if (!priv) + return; + sandbox_raw_halt(&priv->sd, &priv->device); +} + +static int sb_eth_raw_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev->platdata; + + debug("eth_sandbox_raw %s: Write HW ADDR - %pM\n", dev->name, + pdata->enetaddr); + return 0; +} + +static const struct eth_ops sb_eth_raw_ops = { + .init = sb_eth_raw_init, + .send = sb_eth_raw_send, + .recv = sb_eth_raw_recv, + .halt = sb_eth_raw_halt, + .write_hwaddr = sb_eth_raw_write_hwaddr, +}; + +static int sb_eth_raw_remove(struct udevice *dev) +{ + return 0; +} + +#ifdef CONFIG_OF_CONTROL +static int sb_eth_raw_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev->platdata; + + pdata->iobase = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); + return 0; +} + +static const struct udevice_id sb_eth_raw_ids[] = { + { .compatible = "sandbox,eth,raw" }, + { } +}; +#endif + +U_BOOT_DRIVER(eth_sandbox_raw) = { + .name = "eth_sandbox_raw", + .id = UCLASS_ETH, + .of_match = of_match_ptr(sb_eth_raw_ids), + .ofdata_to_platdata = of_match_ptr(sb_eth_raw_ofdata_to_platdata), + .remove = sb_eth_raw_remove, + .ops = &sb_eth_raw_ops, + .priv_auto_alloc_size = sizeof(struct eth_sandbox_raw_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 9df5f74..7afa3d2 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -141,6 +141,7 @@
#define CONFIG_DM_ETH #define CONFIG_ETH_SANDBOX +#define CONFIG_ETH_SANDBOX_RAW #define CONFIG_CMD_PING
#define CONFIG_CMD_HASH

Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
Implement a bridge between u-boot's network stack and Linux's raw packet API allowing the sandbox to send and receive packets using the host machine's network interface.
This raw Ethernet API requires elevated privileges. You can either run as root, or you can add the capability needed like so:
sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
Can you add a note about thsi in README.sandbox? This seems like a major new feature. It was talked about a few years ago when sandbox was first created.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v3: -Made the os raw packet support for sandbox eth build and work.
Changes in v2: -Added the raw packet proof-of-concept patch.
arch/sandbox/dts/sandbox.dts | 6 ++ arch/sandbox/include/asm/sandbox-raw-os.h | 16 ++++ drivers/net/Makefile | 11 +++ drivers/net/sandbox-raw-os.c | 105 ++++++++++++++++++++++++ drivers/net/sandbox-raw.c | 128 ++++++++++++++++++++++++++++++ include/configs/sandbox.h | 1 + 6 files changed, 267 insertions(+) create mode 100644 arch/sandbox/include/asm/sandbox-raw-os.h create mode 100644 drivers/net/sandbox-raw-os.c create mode 100644 drivers/net/sandbox-raw.c
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index ba635e8..13bd6c2 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -188,4 +188,10 @@ reg = <0x10002000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
eth@80000000 {
compatible = "sandbox,eth,raw";
We normally have "vendor,device", so maybe "sandbox,raw-eth"
reg = <0x80000000 0x1000>;
host-raw-interface = "eth0";
};
}; diff --git a/arch/sandbox/include/asm/sandbox-raw-os.h b/arch/sandbox/include/asm/sandbox-raw-os.h new file mode 100644 index 0000000..4e5d418 --- /dev/null +++ b/arch/sandbox/include/asm/sandbox-raw-os.h @@ -0,0 +1,16 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#pragma once
We use #ifdef for this in U-Boot at present. I'm not sure why - perhaps compatibility?
+int sandbox_raw_init(int *sd, void **devp, const char *ifname,
unsigned char *ethmac);
+int sandbox_raw_send(void *packet, int length, int sd, void *device); +int sandbox_raw_recv(void *packet, int *length, int sd, void *device); +void sandbox_raw_halt(int *sd, void **devp);
Function comments, also what is 'device'?
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 15dc431..39975b3 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -51,6 +51,8 @@ obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o obj-$(CONFIG_ETH_SANDBOX) += sandbox.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw-os.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o @@ -68,3 +70,12 @@ obj-$(CONFIG_XILINX_LL_TEMAC) += xilinx_ll_temac.o xilinx_ll_temac_mdio.o \ obj-$(CONFIG_ZYNQ_GEM) += zynq_gem.o obj-$(CONFIG_FSL_MC_ENET) += fsl_mc/ obj-$(CONFIG_VSC9953) += vsc9953.o
+# sandbox-raw-os.c is built in the system env, so needs standard includes +# CFLAGS_REMOVE_sandbox-raw-os.o cannot be used to drop header include path +quiet_cmd_cc_sandbox-raw-os.o = CC $(quiet_modtag) $@ +cmd_cc_sandbox-raw-os.o = $(CC) $(filter-out -nostdinc, \
$(patsubst -I%,-idirafter%,$(c_flags))) -c -o $@ $<
+$(obj)/sandbox-raw-os.o: $(src)/sandbox-raw-os.c FORCE
$(call if_changed_dep,cc_sandbox-raw-os.o)
Can we please move this to the same directory as os.c, so that all the OS-specific stuff is in one place.
diff --git a/drivers/net/sandbox-raw-os.c b/drivers/net/sandbox-raw-os.c new file mode 100644 index 0000000..43fae60 --- /dev/null +++ b/drivers/net/sandbox-raw-os.c @@ -0,0 +1,105 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <errno.h> +#include <net/if.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <unistd.h>
+#include <linux/if_ether.h> +#include <linux/if_packet.h>
+int sandbox_raw_init(int *sd, void **devp, const char *ifname,
unsigned char *ethmac)
+{
int tempsd = 0;
struct ifreq ifr;
strcpy(ifr.ifr_name, ifname);
ifr.ifr_addr.sa_family = AF_INET;
memset(ethmac, 0, 6);
tempsd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (tempsd < 0) {
printf("Failed to open socket: %d %s\n", errno,
strerror(errno));
return 1;
How about:
return -errno
here? That is what U-Boot tends to use now.
}
if (ioctl(tempsd, SIOCGIFHWADDR, &ifr) < 0) {
printf("Failed to call ioctl: %s\n", strerror(errno));
close(tempsd);
return 1;
}
/*
* This only works if the MAC address is overridden with the actual MAC
* address of the interface being used.
*/
memcpy(ethmac, ifr.ifr_hwaddr.sa_data, 6 * sizeof(uint8_t));
close(tempsd);
*devp = malloc(sizeof(struct sockaddr_ll));
struct sockaddr_ll *device = *devp;
memset(device, 0, sizeof(struct sockaddr_ll));
device->sll_ifindex = if_nametoindex(ifname);
device->sll_family = AF_PACKET;
memcpy(device->sll_addr, ethmac, 6);
device->sll_halen = htons(6);
*sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
setsockopt(*sd, SOL_SOCKET, SO_BINDTODEVICE, ifname,
strlen(ifname) + 1);
return 0;
+}
+int sandbox_raw_send(void *packet, int length, int sd, void *device) +{
int retval;
if (!sd || !device)
return -EINVAL;
retval = sendto(sd, packet, length, 0,
(struct sockaddr *)device, sizeof(struct sockaddr_ll));
if (retval < 0)
printf("Failed to send packet: %d %s\n", errno,
strerror(errno));
return retval;
+}
+int sandbox_raw_recv(void *packet, int *length, int sd, void *device) +{
int retval;
int saddr_size;
if (!sd || !device)
return -EINVAL;
saddr_size = sizeof(struct sockaddr);
retval = recvfrom(sd, packet, 1536, 0, (struct sockaddr *)device,
(socklen_t *)&saddr_size);
*length = 0;
if (retval > 0) {
*length = retval;
return 0;
}
return retval;
+}
+void sandbox_raw_halt(int *sd, void **devp) +{
free((struct sockaddr_ll *)*devp);
*devp = NULL;
close(*sd);
*sd = -1;
+} diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c new file mode 100644 index 0000000..90e462a --- /dev/null +++ b/drivers/net/sandbox-raw.c @@ -0,0 +1,128 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <asm/sandbox-raw-os.h> +#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <malloc.h> +#include <net.h>
+DECLARE_GLOBAL_DATA_PTR;
+struct eth_sandbox_raw_priv {
int sd;
void *device;
comments
+};
+static int sb_eth_raw_init(struct udevice *dev, bd_t *bis) +{
debug("eth_sandbox_raw: Init\n");
Put after declarations (perhaps removing code from decls if you like) in each case.
struct eth_sandbox_raw_priv *priv = dev->priv;
add blank line
if (!priv)
return -EINVAL;
As elsewhere I don't understand why this is needed
struct eth_pdata *pdata = dev->platdata;
int retval;
const char *interface = fdt_getprop(gd->fdt_blob, dev->of_offset,
"host-raw-interface", NULL);
retval = sandbox_raw_init(&priv->sd, &priv->device, interface,
pdata->enetaddr);
return retval;
+}
+static int sb_eth_raw_send(struct udevice *dev, void *packet, int length) +{
debug("eth_sandbox_raw: Send packet %d\n", length);
struct eth_sandbox_raw_priv *priv = dev->priv;
dev_get_priv(dev) in each case
return sandbox_raw_send(packet, length, priv->sd, priv->device);
+}
+static int sb_eth_raw_recv(struct udevice *dev) +{
struct eth_sandbox_raw_priv *priv = dev->priv;
remove blank line
int retval;
uchar buffer[PKTSIZE];
int length;
if (!priv)
return 0;
retval = sandbox_raw_recv(buffer, &length, priv->sd, priv->device);
if (!retval && length) {
debug("eth_sandbox_raw: received packet %d\n",
length);
NetReceive(buffer, length);
}
return 0;
+}
+static void sb_eth_raw_halt(struct udevice *dev) +{
debug("eth_sandbox_raw: Halt\n");
struct eth_sandbox_raw_priv *priv = dev->priv;
if (!priv)
return;
sandbox_raw_halt(&priv->sd, &priv->device);
+}
+static int sb_eth_raw_write_hwaddr(struct udevice *dev) +{
struct eth_pdata *pdata = dev->platdata;
debug("eth_sandbox_raw %s: Write HW ADDR - %pM\n", dev->name,
pdata->enetaddr);
return 0;
+}
+static const struct eth_ops sb_eth_raw_ops = {
.init = sb_eth_raw_init,
.send = sb_eth_raw_send,
.recv = sb_eth_raw_recv,
.halt = sb_eth_raw_halt,
.write_hwaddr = sb_eth_raw_write_hwaddr,
+};
+static int sb_eth_raw_remove(struct udevice *dev) +{
return 0;
+}
+#ifdef CONFIG_OF_CONTROL
This is always defined for sandbox.
+static int sb_eth_raw_ofdata_to_platdata(struct udevice *dev) +{
struct eth_pdata *pdata = dev->platdata;
pdata->iobase = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
dev_get_addr() is now available in dm/master if you prefer to use that.
return 0;
+}
+static const struct udevice_id sb_eth_raw_ids[] = {
{ .compatible = "sandbox,eth,raw" },
{ }
+}; +#endif
+U_BOOT_DRIVER(eth_sandbox_raw) = {
.name = "eth_sandbox_raw",
.id = UCLASS_ETH,
.of_match = of_match_ptr(sb_eth_raw_ids),
.ofdata_to_platdata = of_match_ptr(sb_eth_raw_ofdata_to_platdata),
.remove = sb_eth_raw_remove,
.ops = &sb_eth_raw_ops,
.priv_auto_alloc_size = sizeof(struct eth_sandbox_raw_priv),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+}; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 9df5f74..7afa3d2 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -141,6 +141,7 @@
#define CONFIG_DM_ETH #define CONFIG_ETH_SANDBOX +#define CONFIG_ETH_SANDBOX_RAW
These should go in Kconfig. Could be a follow-on patch if that is easier.
#define CONFIG_CMD_PING
#define CONFIG_CMD_HASH
1.7.11.5
Regards, Simon

Hi Simon,
On Sun, Feb 15, 2015 at 9:50 AM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com
wrote:
Implement a bridge between u-boot's network stack and Linux's raw packet API allowing the sandbox to send and receive packets using the host machine's network interface.
This raw Ethernet API requires elevated privileges. You can either run as root, or you can add the capability needed like so:
sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
Can you add a note about thsi in README.sandbox? This seems like a major new feature. It was talked about a few years ago when sandbox was first created.
OK. Can you maybe point me to that conversation so I can understand what was anticipated potentially covering more of what was expected.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v3: -Made the os raw packet support for sandbox eth build and work.
Changes in v2: -Added the raw packet proof-of-concept patch.
arch/sandbox/dts/sandbox.dts | 6 ++ arch/sandbox/include/asm/sandbox-raw-os.h | 16 ++++ drivers/net/Makefile | 11 +++ drivers/net/sandbox-raw-os.c | 105
++++++++++++++++++++++++
drivers/net/sandbox-raw.c | 128
++++++++++++++++++++++++++++++
include/configs/sandbox.h | 1 + 6 files changed, 267 insertions(+) create mode 100644 arch/sandbox/include/asm/sandbox-raw-os.h create mode 100644 drivers/net/sandbox-raw-os.c create mode 100644 drivers/net/sandbox-raw.c
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index ba635e8..13bd6c2 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -188,4 +188,10 @@ reg = <0x10002000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
eth@80000000 {
compatible = "sandbox,eth,raw";
We normally have "vendor,device", so maybe "sandbox,raw-eth"
OK
reg = <0x80000000 0x1000>;
host-raw-interface = "eth0";
};
}; diff --git a/arch/sandbox/include/asm/sandbox-raw-os.h
b/arch/sandbox/include/asm/sandbox-raw-os.h
new file mode 100644 index 0000000..4e5d418 --- /dev/null +++ b/arch/sandbox/include/asm/sandbox-raw-os.h @@ -0,0 +1,16 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#pragma once
We use #ifdef for this in U-Boot at present. I'm not sure why - perhaps compatibility?
OK
+int sandbox_raw_init(int *sd, void **devp, const char *ifname,
unsigned char *ethmac);
+int sandbox_raw_send(void *packet, int length, int sd, void *device); +int sandbox_raw_recv(void *packet, int *length, int sd, void *device); +void sandbox_raw_halt(int *sd, void **devp);
Function comments, also what is 'device'?
Comments about what? These are just the functions that implement the Ethernet driver ops. Is it not sufficient to document the driver ops themselves (as you requested in the other patch)?
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 15dc431..39975b3 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -51,6 +51,8 @@ obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o obj-$(CONFIG_ETH_SANDBOX) += sandbox.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw-os.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o @@ -68,3 +70,12 @@ obj-$(CONFIG_XILINX_LL_TEMAC) += xilinx_ll_temac.o
xilinx_ll_temac_mdio.o \
obj-$(CONFIG_ZYNQ_GEM) += zynq_gem.o obj-$(CONFIG_FSL_MC_ENET) += fsl_mc/ obj-$(CONFIG_VSC9953) += vsc9953.o
+# sandbox-raw-os.c is built in the system env, so needs standard
includes
+# CFLAGS_REMOVE_sandbox-raw-os.o cannot be used to drop header include
path
+quiet_cmd_cc_sandbox-raw-os.o = CC $(quiet_modtag) $@ +cmd_cc_sandbox-raw-os.o = $(CC) $(filter-out -nostdinc, \
$(patsubst -I%,-idirafter%,$(c_flags))) -c -o $@ lt;
+$(obj)/sandbox-raw-os.o: $(src)/sandbox-raw-os.c FORCE
$(call if_changed_dep,cc_sandbox-raw-os.o)
Can we please move this to the same directory as os.c, so that all the OS-specific stuff is in one place.
OK
diff --git a/drivers/net/sandbox-raw-os.c b/drivers/net/sandbox-raw-os.c new file mode 100644 index 0000000..43fae60 --- /dev/null +++ b/drivers/net/sandbox-raw-os.c @@ -0,0 +1,105 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <errno.h> +#include <net/if.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <unistd.h>
+#include <linux/if_ether.h> +#include <linux/if_packet.h>
+int sandbox_raw_init(int *sd, void **devp, const char *ifname,
unsigned char *ethmac)
+{
int tempsd = 0;
struct ifreq ifr;
strcpy(ifr.ifr_name, ifname);
ifr.ifr_addr.sa_family = AF_INET;
memset(ethmac, 0, 6);
tempsd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (tempsd < 0) {
printf("Failed to open socket: %d %s\n", errno,
strerror(errno));
return 1;
How about:
return -errno
here? That is what U-Boot tends to use now.
OK
}
if (ioctl(tempsd, SIOCGIFHWADDR, &ifr) < 0) {
printf("Failed to call ioctl: %s\n", strerror(errno));
close(tempsd);
return 1;
}
/*
* This only works if the MAC address is overridden with the
actual MAC
* address of the interface being used.
*/
memcpy(ethmac, ifr.ifr_hwaddr.sa_data, 6 * sizeof(uint8_t));
close(tempsd);
*devp = malloc(sizeof(struct sockaddr_ll));
struct sockaddr_ll *device = *devp;
memset(device, 0, sizeof(struct sockaddr_ll));
device->sll_ifindex = if_nametoindex(ifname);
device->sll_family = AF_PACKET;
memcpy(device->sll_addr, ethmac, 6);
device->sll_halen = htons(6);
*sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
setsockopt(*sd, SOL_SOCKET, SO_BINDTODEVICE, ifname,
strlen(ifname) + 1);
return 0;
+}
+int sandbox_raw_send(void *packet, int length, int sd, void *device) +{
int retval;
if (!sd || !device)
return -EINVAL;
retval = sendto(sd, packet, length, 0,
(struct sockaddr *)device, sizeof(struct
sockaddr_ll));
if (retval < 0)
printf("Failed to send packet: %d %s\n", errno,
strerror(errno));
return retval;
+}
+int sandbox_raw_recv(void *packet, int *length, int sd, void *device) +{
int retval;
int saddr_size;
if (!sd || !device)
return -EINVAL;
saddr_size = sizeof(struct sockaddr);
retval = recvfrom(sd, packet, 1536, 0, (struct sockaddr
*)device,
(socklen_t *)&saddr_size);
*length = 0;
if (retval > 0) {
*length = retval;
return 0;
}
return retval;
+}
+void sandbox_raw_halt(int *sd, void **devp) +{
free((struct sockaddr_ll *)*devp);
*devp = NULL;
close(*sd);
*sd = -1;
+} diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c new file mode 100644 index 0000000..90e462a --- /dev/null +++ b/drivers/net/sandbox-raw.c @@ -0,0 +1,128 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <asm/sandbox-raw-os.h> +#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <malloc.h> +#include <net.h>
+DECLARE_GLOBAL_DATA_PTR;
+struct eth_sandbox_raw_priv {
int sd;
void *device;
comments
+};
+static int sb_eth_raw_init(struct udevice *dev, bd_t *bis) +{
debug("eth_sandbox_raw: Init\n");
Put after declarations (perhaps removing code from decls if you like) in each case.
struct eth_sandbox_raw_priv *priv = dev->priv;
add blank line
if (!priv)
return -EINVAL;
As elsewhere I don't understand why this is needed
struct eth_pdata *pdata = dev->platdata;
int retval;
const char *interface = fdt_getprop(gd->fdt_blob,
dev->of_offset,
"host-raw-interface", NULL);
retval = sandbox_raw_init(&priv->sd, &priv->device, interface,
pdata->enetaddr);
return retval;
+}
+static int sb_eth_raw_send(struct udevice *dev, void *packet, int
length)
+{
debug("eth_sandbox_raw: Send packet %d\n", length);
struct eth_sandbox_raw_priv *priv = dev->priv;
dev_get_priv(dev) in each case
return sandbox_raw_send(packet, length, priv->sd, priv->device);
+}
+static int sb_eth_raw_recv(struct udevice *dev) +{
struct eth_sandbox_raw_priv *priv = dev->priv;
remove blank line
int retval;
uchar buffer[PKTSIZE];
int length;
if (!priv)
return 0;
retval = sandbox_raw_recv(buffer, &length, priv->sd,
priv->device);
if (!retval && length) {
debug("eth_sandbox_raw: received packet %d\n",
length);
NetReceive(buffer, length);
}
return 0;
+}
+static void sb_eth_raw_halt(struct udevice *dev) +{
debug("eth_sandbox_raw: Halt\n");
struct eth_sandbox_raw_priv *priv = dev->priv;
if (!priv)
return;
sandbox_raw_halt(&priv->sd, &priv->device);
+}
+static int sb_eth_raw_write_hwaddr(struct udevice *dev) +{
struct eth_pdata *pdata = dev->platdata;
debug("eth_sandbox_raw %s: Write HW ADDR - %pM\n", dev->name,
pdata->enetaddr);
return 0;
+}
+static const struct eth_ops sb_eth_raw_ops = {
.init = sb_eth_raw_init,
.send = sb_eth_raw_send,
.recv = sb_eth_raw_recv,
.halt = sb_eth_raw_halt,
.write_hwaddr = sb_eth_raw_write_hwaddr,
+};
+static int sb_eth_raw_remove(struct udevice *dev) +{
return 0;
+}
+#ifdef CONFIG_OF_CONTROL
This is always defined for sandbox.
I figured it was a good pattern to use in general, but if you want me to prune it out of sandbox-only code I can.
+static int sb_eth_raw_ofdata_to_platdata(struct udevice *dev) +{
struct eth_pdata *pdata = dev->platdata;
pdata->iobase = fdtdec_get_addr(gd->fdt_blob, dev->of_offset,
"reg");
dev_get_addr() is now available in dm/master if you prefer to use that.
OK
return 0;
+}
+static const struct udevice_id sb_eth_raw_ids[] = {
{ .compatible = "sandbox,eth,raw" },
{ }
+}; +#endif
+U_BOOT_DRIVER(eth_sandbox_raw) = {
.name = "eth_sandbox_raw",
.id = UCLASS_ETH,
.of_match = of_match_ptr(sb_eth_raw_ids),
.ofdata_to_platdata =
of_match_ptr(sb_eth_raw_ofdata_to_platdata),
.remove = sb_eth_raw_remove,
.ops = &sb_eth_raw_ops,
.priv_auto_alloc_size = sizeof(struct eth_sandbox_raw_priv),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+}; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 9df5f74..7afa3d2 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -141,6 +141,7 @@
#define CONFIG_DM_ETH #define CONFIG_ETH_SANDBOX +#define CONFIG_ETH_SANDBOX_RAW
These should go in Kconfig. Could be a follow-on patch if that is easier.
OK
#define CONFIG_CMD_PING
#define CONFIG_CMD_HASH
1.7.11.5
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi Joe,
On 16 February 2015 at 22:16, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Sun, Feb 15, 2015 at 9:50 AM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
Implement a bridge between u-boot's network stack and Linux's raw packet API allowing the sandbox to send and receive packets using the host machine's network interface.
This raw Ethernet API requires elevated privileges. You can either run as root, or you can add the capability needed like so:
sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
Can you add a note about thsi in README.sandbox? This seems like a major new feature. It was talked about a few years ago when sandbox was first created.
OK. Can you maybe point me to that conversation so I can understand what was anticipated potentially covering more of what was expected.
All I could find was this:
http://permalink.gmane.org/gmane.comp.boot-loaders.u-boot/108687
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v3: -Made the os raw packet support for sandbox eth build and work.
Changes in v2: -Added the raw packet proof-of-concept patch.
arch/sandbox/dts/sandbox.dts | 6 ++ arch/sandbox/include/asm/sandbox-raw-os.h | 16 ++++ drivers/net/Makefile | 11 +++ drivers/net/sandbox-raw-os.c | 105 ++++++++++++++++++++++++ drivers/net/sandbox-raw.c | 128 ++++++++++++++++++++++++++++++ include/configs/sandbox.h | 1 + 6 files changed, 267 insertions(+) create mode 100644 arch/sandbox/include/asm/sandbox-raw-os.h create mode 100644 drivers/net/sandbox-raw-os.c create mode 100644 drivers/net/sandbox-raw.c
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index ba635e8..13bd6c2 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -188,4 +188,10 @@ reg = <0x10002000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
eth@80000000 {
compatible = "sandbox,eth,raw";
We normally have "vendor,device", so maybe "sandbox,raw-eth"
OK
reg = <0x80000000 0x1000>;
host-raw-interface = "eth0";
};
}; diff --git a/arch/sandbox/include/asm/sandbox-raw-os.h b/arch/sandbox/include/asm/sandbox-raw-os.h new file mode 100644 index 0000000..4e5d418 --- /dev/null +++ b/arch/sandbox/include/asm/sandbox-raw-os.h @@ -0,0 +1,16 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#pragma once
We use #ifdef for this in U-Boot at present. I'm not sure why - perhaps compatibility?
OK
+int sandbox_raw_init(int *sd, void **devp, const char *ifname,
unsigned char *ethmac);
+int sandbox_raw_send(void *packet, int length, int sd, void *device); +int sandbox_raw_recv(void *packet, int *length, int sd, void *device); +void sandbox_raw_halt(int *sd, void **devp);
Function comments, also what is 'device'?
Comments about what? These are just the functions that implement the Ethernet driver ops. Is it not sufficient to document the driver ops themselves (as you requested in the other patch)?
Well they seem to have different parameters:
- what is 'device'? - what is'sd''?
I think these warrant comments.
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 15dc431..39975b3 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -51,6 +51,8 @@ obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o obj-$(CONFIG_ETH_SANDBOX) += sandbox.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw-os.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o @@ -68,3 +70,12 @@ obj-$(CONFIG_XILINX_LL_TEMAC) += xilinx_ll_temac.o xilinx_ll_temac_mdio.o \ obj-$(CONFIG_ZYNQ_GEM) += zynq_gem.o obj-$(CONFIG_FSL_MC_ENET) += fsl_mc/ obj-$(CONFIG_VSC9953) += vsc9953.o
+# sandbox-raw-os.c is built in the system env, so needs standard includes +# CFLAGS_REMOVE_sandbox-raw-os.o cannot be used to drop header include path +quiet_cmd_cc_sandbox-raw-os.o = CC $(quiet_modtag) $@ +cmd_cc_sandbox-raw-os.o = $(CC) $(filter-out -nostdinc, \
$(patsubst -I%,-idirafter%,$(c_flags))) -c -o $@ lt;
+$(obj)/sandbox-raw-os.o: $(src)/sandbox-raw-os.c FORCE
$(call if_changed_dep,cc_sandbox-raw-os.o)
Can we please move this to the same directory as os.c, so that all the OS-specific stuff is in one place.
OK
diff --git a/drivers/net/sandbox-raw-os.c b/drivers/net/sandbox-raw-os.c new file mode 100644 index 0000000..43fae60 --- /dev/null +++ b/drivers/net/sandbox-raw-os.c @@ -0,0 +1,105 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <errno.h> +#include <net/if.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <unistd.h>
+#include <linux/if_ether.h> +#include <linux/if_packet.h>
+int sandbox_raw_init(int *sd, void **devp, const char *ifname,
unsigned char *ethmac)
+{
int tempsd = 0;
struct ifreq ifr;
strcpy(ifr.ifr_name, ifname);
ifr.ifr_addr.sa_family = AF_INET;
memset(ethmac, 0, 6);
tempsd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (tempsd < 0) {
printf("Failed to open socket: %d %s\n", errno,
strerror(errno));
return 1;
How about:
return -errno
here? That is what U-Boot tends to use now.
OK
}
if (ioctl(tempsd, SIOCGIFHWADDR, &ifr) < 0) {
printf("Failed to call ioctl: %s\n", strerror(errno));
close(tempsd);
return 1;
}
/*
* This only works if the MAC address is overridden with the
actual MAC
* address of the interface being used.
*/
memcpy(ethmac, ifr.ifr_hwaddr.sa_data, 6 * sizeof(uint8_t));
close(tempsd);
*devp = malloc(sizeof(struct sockaddr_ll));
struct sockaddr_ll *device = *devp;
memset(device, 0, sizeof(struct sockaddr_ll));
device->sll_ifindex = if_nametoindex(ifname);
device->sll_family = AF_PACKET;
memcpy(device->sll_addr, ethmac, 6);
device->sll_halen = htons(6);
*sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
setsockopt(*sd, SOL_SOCKET, SO_BINDTODEVICE, ifname,
strlen(ifname) + 1);
return 0;
+}
+int sandbox_raw_send(void *packet, int length, int sd, void *device) +{
int retval;
if (!sd || !device)
return -EINVAL;
retval = sendto(sd, packet, length, 0,
(struct sockaddr *)device, sizeof(struct
sockaddr_ll));
if (retval < 0)
printf("Failed to send packet: %d %s\n", errno,
strerror(errno));
return retval;
+}
+int sandbox_raw_recv(void *packet, int *length, int sd, void *device) +{
int retval;
int saddr_size;
if (!sd || !device)
return -EINVAL;
saddr_size = sizeof(struct sockaddr);
retval = recvfrom(sd, packet, 1536, 0, (struct sockaddr
*)device,
(socklen_t *)&saddr_size);
*length = 0;
if (retval > 0) {
*length = retval;
return 0;
}
return retval;
+}
+void sandbox_raw_halt(int *sd, void **devp) +{
free((struct sockaddr_ll *)*devp);
*devp = NULL;
close(*sd);
*sd = -1;
+} diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c new file mode 100644 index 0000000..90e462a --- /dev/null +++ b/drivers/net/sandbox-raw.c @@ -0,0 +1,128 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <asm/sandbox-raw-os.h> +#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <malloc.h> +#include <net.h>
+DECLARE_GLOBAL_DATA_PTR;
+struct eth_sandbox_raw_priv {
int sd;
void *device;
comments
+};
+static int sb_eth_raw_init(struct udevice *dev, bd_t *bis) +{
debug("eth_sandbox_raw: Init\n");
Put after declarations (perhaps removing code from decls if you like) in each case.
struct eth_sandbox_raw_priv *priv = dev->priv;
add blank line
if (!priv)
return -EINVAL;
As elsewhere I don't understand why this is needed
struct eth_pdata *pdata = dev->platdata;
int retval;
const char *interface = fdt_getprop(gd->fdt_blob,
dev->of_offset,
"host-raw-interface", NULL);
retval = sandbox_raw_init(&priv->sd, &priv->device, interface,
pdata->enetaddr);
return retval;
+}
+static int sb_eth_raw_send(struct udevice *dev, void *packet, int length) +{
debug("eth_sandbox_raw: Send packet %d\n", length);
struct eth_sandbox_raw_priv *priv = dev->priv;
dev_get_priv(dev) in each case
return sandbox_raw_send(packet, length, priv->sd, priv->device);
+}
+static int sb_eth_raw_recv(struct udevice *dev) +{
struct eth_sandbox_raw_priv *priv = dev->priv;
remove blank line
int retval;
uchar buffer[PKTSIZE];
int length;
if (!priv)
return 0;
retval = sandbox_raw_recv(buffer, &length, priv->sd,
priv->device);
if (!retval && length) {
debug("eth_sandbox_raw: received packet %d\n",
length);
NetReceive(buffer, length);
}
return 0;
+}
+static void sb_eth_raw_halt(struct udevice *dev) +{
debug("eth_sandbox_raw: Halt\n");
struct eth_sandbox_raw_priv *priv = dev->priv;
if (!priv)
return;
sandbox_raw_halt(&priv->sd, &priv->device);
+}
+static int sb_eth_raw_write_hwaddr(struct udevice *dev) +{
struct eth_pdata *pdata = dev->platdata;
debug("eth_sandbox_raw %s: Write HW ADDR - %pM\n", dev->name,
pdata->enetaddr);
return 0;
+}
+static const struct eth_ops sb_eth_raw_ops = {
.init = sb_eth_raw_init,
.send = sb_eth_raw_send,
.recv = sb_eth_raw_recv,
.halt = sb_eth_raw_halt,
.write_hwaddr = sb_eth_raw_write_hwaddr,
+};
+static int sb_eth_raw_remove(struct udevice *dev) +{
return 0;
+}
+#ifdef CONFIG_OF_CONTROL
This is always defined for sandbox.
I figured it was a good pattern to use in general, but if you want me to prune it out of sandbox-only code I can.
I think so, it is pointless really and just clutters the code. I can't imagine sandbox being built without device tree (famous last words!)
+static int sb_eth_raw_ofdata_to_platdata(struct udevice *dev) +{
struct eth_pdata *pdata = dev->platdata;
pdata->iobase = fdtdec_get_addr(gd->fdt_blob, dev->of_offset,
"reg");
dev_get_addr() is now available in dm/master if you prefer to use that.
OK
return 0;
+}
+static const struct udevice_id sb_eth_raw_ids[] = {
{ .compatible = "sandbox,eth,raw" },
{ }
+}; +#endif
+U_BOOT_DRIVER(eth_sandbox_raw) = {
.name = "eth_sandbox_raw",
.id = UCLASS_ETH,
.of_match = of_match_ptr(sb_eth_raw_ids),
.ofdata_to_platdata =
of_match_ptr(sb_eth_raw_ofdata_to_platdata),
.remove = sb_eth_raw_remove,
.ops = &sb_eth_raw_ops,
.priv_auto_alloc_size = sizeof(struct eth_sandbox_raw_priv),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+}; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 9df5f74..7afa3d2 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -141,6 +141,7 @@
#define CONFIG_DM_ETH #define CONFIG_ETH_SANDBOX +#define CONFIG_ETH_SANDBOX_RAW
These should go in Kconfig. Could be a follow-on patch if that is easier.
OK
#define CONFIG_CMD_PING
#define CONFIG_CMD_HASH
1.7.11.5
Regards, Simon

Hi Simon,
On Tue, Feb 17, 2015 at 11:02 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 16 February 2015 at 22:16, Joe Hershberger joe.hershberger@gmail.com
wrote:
Hi Simon,
On Sun, Feb 15, 2015 at 9:50 AM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
Implement a bridge between u-boot's network stack and Linux's raw
packet
API allowing the sandbox to send and receive packets using the host machine's network interface.
This raw Ethernet API requires elevated privileges. You can either
run
as root, or you can add the capability needed like so:
sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
Can you add a note about thsi in README.sandbox? This seems like a major new feature. It was talked about a few years ago when sandbox was first created.
OK. Can you maybe point me to that conversation so I can understand
what
was anticipated potentially covering more of what was expected.
All I could find was this:
http://permalink.gmane.org/gmane.comp.boot-loaders.u-boot/108687
I dug around and found this too:
http://comments.gmane.org/gmane.comp.boot-loaders.u-boot/118685
It seems it was more complicated to setup, but may have other benefits (such as being more likely to be able to change MAC address settings eventually).
[snip]
Cheers, -Joe

Hi Joe,
On 19 February 2015 at 16:44, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Tue, Feb 17, 2015 at 11:02 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 16 February 2015 at 22:16, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Sun, Feb 15, 2015 at 9:50 AM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 February 2015 at 18:30, Joe Hershberger joe.hershberger@ni.com wrote:
Implement a bridge between u-boot's network stack and Linux's raw packet API allowing the sandbox to send and receive packets using the host machine's network interface.
This raw Ethernet API requires elevated privileges. You can either run as root, or you can add the capability needed like so:
sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
Can you add a note about thsi in README.sandbox? This seems like a major new feature. It was talked about a few years ago when sandbox was first created.
OK. Can you maybe point me to that conversation so I can understand what was anticipated potentially covering more of what was expected.
All I could find was this:
http://permalink.gmane.org/gmane.comp.boot-loaders.u-boot/108687
I dug around and found this too:
http://comments.gmane.org/gmane.comp.boot-loaders.u-boot/118685
It seems it was more complicated to setup, but may have other benefits (such as being more likely to be able to change MAC address settings eventually).
Ah yes that is it.
I think your method is simpler and useful, and therefore generally better as a starting point. The TAP idea if we have it should be a separate feature. I really like that to, but it requires setup as you say.
Regards, Simon

Add support for the Ethernet MAC controllers. Phy support will come later.
I am still leaving this as an RFC because I plan to add real board support before committing to mainline. When it is acceptable / accepted, I will push it as a dev branch on the net repo until a real device is supported. If any required changes are discovered in the process of supporting a real device I will send those as a patch against the dev branch, but then squash before sending the non-RFC version. I plan to rebase when the merge window opens anyway.
If desired, let me know which of the non-DM related prerequisite patches are wanted for this release.
I've added unit tests to verify functionality.
There is an additional driver for sandbox that bridges to the RAW Ethernet API in Linux which lets you test with real traffic. It now supports localhost as well (the 'lo' interface).
Changes in v4: -New to v4 -Fix compile regression in !DM_ETH case -New to v4 -New to v4 -New to v4 -New to v4 -New to v4 -Redo the seq / probe implementation --Don't prevent eth_initialize on driver model --Use eth_initialize to probe all devices and write_hwaddr --Look up MAC address in post-probe --Include ethprime handling in eth_initialize --If current == NULL, always check if there is a device available in eth_get_dev --Move env init call from uclass init to eth_initialize --Print the alias in eth_initialize -Stop handling selecting a new "current" in pre-unbind as it will now work itself out by clearing the pointer -Change -1 returns to error constants -Remove bd_t *bis from dm eth_ops init function -Add documentation to the structures -Add a helper function for eth_uclass_priv -Change puts to printf -Add eth_get_ops helper -Rename init() to start() in ops -Rename halt() to stop() in ops -Remove checks for driver==NULL -Remove priv pointer in per-device priv struct (drivers already get their own directly from DM) -Cleaned up sandbox EXTRA_ENV define -Moved config to Kconfig -Removed checks on priv != NULL and added protection in uclass instead -Use only the seq from DM to find aliases -Load from ethprime on eth_initialize() -Added testing for ethrotate -Add ability to disable ping reply in sandbox eth driver -Updated expected behavior based on changes to the NetLoop -Added comments to README.sandbox -Use accessors for platdata and priv -Add comments to priv struct definition -Move os file to arch -Cleanup var definition order -Moved config to Kconfig -Clean up the interface to sandbox's eth-raw-os by passing priv to raw-os -Fixed the MAC address limitation (now all traffic uses MAC address from env) -New to v4 -Added support for the 'lo' network interface
Changes in v3: -Reorder dm test makefile -Move the get_dev_by_* protos to also be !DM_ETH like the impl -Correct the pre_unbind logic -Correct failure chaining from bind to probe to init --Fail init if not activated --Fail probe if ethaddr not set -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the previous selection -Allow current eth dev to be NULL -Fixed blank line formatting for variable declaration -Added 2 more ethaddr to sandbox -Print which device in the debug write hwaddr -Prevent a crash if memory is not allocated -Added dm eth testing -Added support for aliases -Added support for ethprime -Added testing for netretry -Made the os raw packet support for sandbox eth build and work.
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for our needs -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()). -Change printfs to debug in sandbox driver -Remove unused priv struct for sandbox driver -Change printfs to debug in sandbox driver -Move static data to priv -Move fake hwaddr to the device tree -Added the raw packet proof-of-concept patch.
Joe Hershberger (23): test: dm: Reorder the objects to build common: Make sure arch-specific map_sysmem() is defined net: Provide a function to get the current MAC address net: Rename helper function to be more clear net: Remove unneeded "extern" in net.h net: Refactor in preparation for driver model net: Change return codes from net/eth.c to use errorno constants net: Use int instead of u8 for boolean flag net: Remove the bd* parameter from net stack functions net: Make netretry actually do something net: Access mapped physmem in net functions dm: eth: Add basic driver model support to Ethernet stack sandbox: eth: Add network support to sandbox sandbox: eth: Add ARP and PING response to sandbox driver test: dm: eth: Add tests for the eth dm implementation dm: eth: Add support for aliases dm: eth: Add support for ethprime env var test: dm: eth: Add testing for ethrotate env var sandbox: eth: Add ability to disable ping reply in sandbox eth driver test: dm: net: Add a test of the netretry behavior sandbox: eth: Add a bridge to a real network for sandbox sandbox: Enable DHCP and IP defrag sandbox: eth: Add support for using the 'lo' interface
arch/mips/mach-au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- arch/sandbox/Kconfig | 12 + arch/sandbox/cpu/Makefile | 10 + arch/sandbox/cpu/eth-raw-os.c | 198 +++++++++++++ arch/sandbox/dts/sandbox.dts | 21 ++ arch/sandbox/include/asm/eth-raw-os.h | 40 +++ board/sandbox/README.sandbox | 17 +- common/board_r.c | 2 +- common/cmd_bdinfo.c | 2 + drivers/net/Kconfig | 28 ++ drivers/net/Makefile | 2 + drivers/net/netconsole.c | 4 +- drivers/net/sandbox-raw.c | 163 +++++++++++ drivers/net/sandbox.c | 200 +++++++++++++ include/common.h | 4 +- include/configs/sandbox.h | 25 +- include/dm/uclass-id.h | 1 + include/net.h | 187 ++++++++---- net/eth.c | 521 +++++++++++++++++++++++++++++----- net/net.c | 17 +- net/nfs.c | 2 +- net/tftp.c | 2 +- test/dm/Makefile | 5 +- test/dm/eth.c | 129 +++++++++ test/dm/test.dts | 20 ++ 28 files changed, 1466 insertions(+), 154 deletions(-) create mode 100644 arch/sandbox/cpu/eth-raw-os.c create mode 100644 arch/sandbox/include/asm/eth-raw-os.h create mode 100644 drivers/net/sandbox-raw.c create mode 100644 drivers/net/sandbox.c create mode 100644 test/dm/eth.c

Signed-off-by: Joe Hershberger joe.hershberger@ni.com Acked-by: Simon Glass sjg@chromium.org
---
Changes in v4: None Changes in v3: -Reorder dm test makefile
Changes in v2: None
test/dm/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/dm/Makefile b/test/dm/Makefile index 612aa95..1d9148f 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_DM_TEST) += core.o obj-$(CONFIG_DM_TEST) += ut.o ifneq ($(CONFIG_SANDBOX),) obj-$(CONFIG_DM_GPIO) += gpio.o -obj-$(CONFIG_DM_SPI) += spi.o -obj-$(CONFIG_DM_SPI_FLASH) += sf.o obj-$(CONFIG_DM_I2C) += i2c.o +obj-$(CONFIG_DM_SPI_FLASH) += sf.o +obj-$(CONFIG_DM_SPI) += spi.o endif

In the case where the arch defines a custom map_sysmem(), make sure that including just common.h is sufficient to have these functions as they are when the arch does not override it.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
include/common.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/include/common.h b/include/common.h index 77c55c6..6510efc 100644 --- a/include/common.h +++ b/include/common.h @@ -846,7 +846,9 @@ int cpu_release(int nr, int argc, char * const argv[]); #endif
/* Define a null map_sysmem() if the architecture doesn't use it */ -# ifndef CONFIG_ARCH_MAP_SYSMEM +# ifdef CONFIG_ARCH_MAP_SYSMEM +#include <asm/io.h> +# else static inline void *map_sysmem(phys_addr_t paddr, unsigned long len) { return (void *)(uintptr_t)paddr;

Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
In the case where the arch defines a custom map_sysmem(), make sure that including just common.h is sufficient to have these functions as they are when the arch does not override it.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
include/common.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/include/common.h b/include/common.h index 77c55c6..6510efc 100644 --- a/include/common.h +++ b/include/common.h @@ -846,7 +846,9 @@ int cpu_release(int nr, int argc, char * const argv[]); #endif
/* Define a null map_sysmem() if the architecture doesn't use it */ -# ifndef CONFIG_ARCH_MAP_SYSMEM +# ifdef CONFIG_ARCH_MAP_SYSMEM +#include <asm/io.h> +# else static inline void *map_sysmem(phys_addr_t paddr, unsigned long len) { return (void *)(uintptr_t)paddr;
Do we need this patch? Is it just for sandbox? It would be nice to remove things from common.h rather than adding them!
Anyway if you want to go ahead I'm OK with it.
Reviewed-by: Simon Glass sjg@chromium.org
Regards, Simon

Hi Simon,
On Sun, Mar 1, 2015 at 12:07 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com
wrote:
In the case where the arch defines a custom map_sysmem(), make sure that including just common.h is sufficient to have these functions as they are when the arch does not override it.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
include/common.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/include/common.h b/include/common.h index 77c55c6..6510efc 100644 --- a/include/common.h +++ b/include/common.h @@ -846,7 +846,9 @@ int cpu_release(int nr, int argc, char * const
argv[]);
#endif
/* Define a null map_sysmem() if the architecture doesn't use it */ -# ifndef CONFIG_ARCH_MAP_SYSMEM +# ifdef CONFIG_ARCH_MAP_SYSMEM +#include <asm/io.h> +# else static inline void *map_sysmem(phys_addr_t paddr, unsigned long len) { return (void *)(uintptr_t)paddr;
Do we need this patch? Is it just for sandbox? It would be nice to remove things from common.h rather than adding them!
If you have a recommendation for where these static inline functions should move, then I'm happy to move it all to a new place. My assertion is that whatever it is that you include to get these static inlines should also be what you include when CONFIG_ARCH_MAP_SYSMEM is defined. You should not need to include the arch-specific header separately each place that one of these mapping functions is used.
Anyway if you want to go ahead I'm OK with it.
Reviewed-by: Simon Glass sjg@chromium.org
Regards, Simon

Hi Joe,
On 1 March 2015 at 14:16, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Sun, Mar 1, 2015 at 12:07 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
In the case where the arch defines a custom map_sysmem(), make sure that including just common.h is sufficient to have these functions as they are when the arch does not override it.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
include/common.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/include/common.h b/include/common.h index 77c55c6..6510efc 100644 --- a/include/common.h +++ b/include/common.h @@ -846,7 +846,9 @@ int cpu_release(int nr, int argc, char * const argv[]); #endif
/* Define a null map_sysmem() if the architecture doesn't use it */ -# ifndef CONFIG_ARCH_MAP_SYSMEM +# ifdef CONFIG_ARCH_MAP_SYSMEM +#include <asm/io.h> +# else static inline void *map_sysmem(phys_addr_t paddr, unsigned long len) { return (void *)(uintptr_t)paddr;
Do we need this patch? Is it just for sandbox? It would be nice to remove things from common.h rather than adding them!
If you have a recommendation for where these static inline functions should move, then I'm happy to move it all to a new place. My assertion is that whatever it is that you include to get these static inlines should also be what you include when CONFIG_ARCH_MAP_SYSMEM is defined. You should not need to include the arch-specific header separately each place that one of these mapping functions is used.
Fair enough. I suppose there are two options - requiring all files to include asm/io.h, and putting them in common.h (or some other file).
Overall I think I'd prefer that they go in a separate file (perhaps mapmem.h) and include that file everywhere. What do you think?
Anyway if you want to go ahead I'm OK with it.
Reviewed-by: Simon Glass sjg@chromium.org
Regards, Simon

The current implementation exposes the eth_device struct to code that needs to access the MAC address. Add a wrapper function for this to abstract away the pointer for this operation.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v4: None Changes in v3: None Changes in v2: None
arch/mips/mach-au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- include/net.h | 8 ++++++++ net/net.c | 2 +- 6 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/arch/mips/mach-au1x00/au1x00_eth.c b/arch/mips/mach-au1x00/au1x00_eth.c index 39c5b6b..a47f088 100644 --- a/arch/mips/mach-au1x00/au1x00_eth.c +++ b/arch/mips/mach-au1x00/au1x00_eth.c @@ -238,7 +238,7 @@ static int au1x00_init(struct eth_device* dev, bd_t * bd){ }
/* Put mac addr in little endian */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() *mac_addr_high = (ea[5] << 8) | (ea[4] ) ; *mac_addr_low = (ea[3] << 24) | (ea[2] << 16) | (ea[1] << 8) | (ea[0] ) ; diff --git a/arch/powerpc/cpu/mpc8260/ether_fcc.c b/arch/powerpc/cpu/mpc8260/ether_fcc.c index f9f15b5..f777ba1 100644 --- a/arch/powerpc/cpu/mpc8260/ether_fcc.c +++ b/arch/powerpc/cpu/mpc8260/ether_fcc.c @@ -299,7 +299,7 @@ static int fec_init(struct eth_device* dev, bd_t *bis) * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc85xx/ether_fcc.c b/arch/powerpc/cpu/mpc85xx/ether_fcc.c index 166dc9e..58d4bfb 100644 --- a/arch/powerpc/cpu/mpc85xx/ether_fcc.c +++ b/arch/powerpc/cpu/mpc85xx/ether_fcc.c @@ -338,7 +338,7 @@ static int fec_init(struct eth_device* dev, bd_t *bis) * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc8xx/scc.c b/arch/powerpc/cpu/mpc8xx/scc.c index 251966b..66e4014 100644 --- a/arch/powerpc/cpu/mpc8xx/scc.c +++ b/arch/powerpc/cpu/mpc8xx/scc.c @@ -339,7 +339,7 @@ static int scc_init (struct eth_device *dev, bd_t * bis) pram_ptr->sen_gaddr3 = 0x0; /* Group Address Filter 3 (unused) */ pram_ptr->sen_gaddr4 = 0x0; /* Group Address Filter 4 (unused) */
-#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/include/net.h b/include/net.h index 43e3d28..6c76976 100644 --- a/include/net.h +++ b/include/net.h @@ -111,6 +111,14 @@ struct eth_device *eth_get_dev(void) { return eth_current; } + +static inline unsigned char *eth_get_ethaddr(void) +{ + if (eth_current) + return eth_current->enetaddr; + return NULL; +} + extern struct eth_device *eth_get_dev_by_name(const char *devname); extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ extern int eth_get_dev_index(void); /* get the device index */ diff --git a/net/net.c b/net/net.c index b60ce62..4b3c90e 100644 --- a/net/net.c +++ b/net/net.c @@ -275,7 +275,7 @@ static void NetInitLoop(void) env_changed_id = env_id; } if (eth_get_dev()) - memcpy(NetOurEther, eth_get_dev()->enetaddr, 6); + memcpy(NetOurEther, eth_get_ethaddr(), 6);
return; }

Make it clear that the helper is checking the addr, not setting it.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v4: None Changes in v3: None Changes in v2: None
net/eth.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/net/eth.c b/net/eth.c index eac4f7b..65e8c77 100644 --- a/net/eth.c +++ b/net/eth.c @@ -153,11 +153,6 @@ static void eth_current_changed(void) setenv("ethact", NULL); }
-static int eth_address_set(unsigned char *addr) -{ - return memcmp(addr, "\0\0\0\0\0\0", 6); -} - int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -166,9 +161,9 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
- if (eth_address_set(env_enetaddr)) { - if (eth_address_set(dev->enetaddr) && - memcmp(dev->enetaddr, env_enetaddr, 6)) { + if (!is_zero_ether_addr(env_enetaddr)) { + if (!is_zero_ether_addr(dev->enetaddr) && + memcmp(dev->enetaddr, env_enetaddr, 6)) { printf("\nWarning: %s MAC addresses don't match:\n", dev->name); printf("Address in SROM is %pM\n", @@ -183,7 +178,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, dev->enetaddr); printf("\nWarning: %s using MAC address from net device\n", dev->name); - } else if (!(eth_address_set(dev->enetaddr))) { + } else if (is_zero_ether_addr(dev->enetaddr)) { printf("\nError: %s address not set.\n", dev->name); return -EINVAL;

Many of the functions in net.h were preceded extern needlessly. Removing them to limit the number of checkpatch.pl complaints.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 92 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 46 insertions(+), 46 deletions(-)
diff --git a/include/net.h b/include/net.h index 6c76976..b82a29d 100644 --- a/include/net.h +++ b/include/net.h @@ -97,11 +97,11 @@ struct eth_device { void *priv; };
-extern int eth_initialize(bd_t *bis); /* Initialize network subsystem */ -extern int eth_register(struct eth_device* dev);/* Register network device */ -extern int eth_unregister(struct eth_device *dev);/* Remove network device */ -extern void eth_try_another(int first_restart); /* Change the device */ -extern void eth_set_current(void); /* set nterface to ethcur var */ +int eth_initialize(bd_t *bis); /* Initialize network subsystem */ +int eth_register(struct eth_device *dev);/* Register network device */ +int eth_unregister(struct eth_device *dev);/* Remove network device */ +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */
/* get the current device MAC */ extern struct eth_device *eth_current; @@ -119,12 +119,12 @@ static inline unsigned char *eth_get_ethaddr(void) return NULL; }
-extern struct eth_device *eth_get_dev_by_name(const char *devname); -extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ -extern int eth_get_dev_index(void); /* get the device index */ -extern void eth_parse_enetaddr(const char *addr, uchar *enetaddr); -extern int eth_getenv_enetaddr(char *name, uchar *enetaddr); -extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr); +struct eth_device *eth_get_dev_by_name(const char *devname); +struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ +int eth_get_dev_index(void); /* get the device index */ +void eth_parse_enetaddr(const char *addr, uchar *enetaddr); +int eth_getenv_enetaddr(char *name, uchar *enetaddr); +int eth_setenv_enetaddr(char *name, const uchar *enetaddr);
/* * Get the hardware address for an ethernet interface . @@ -135,20 +135,20 @@ extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr); * Returns: * Return true if the address is valid. */ -extern int eth_getenv_enetaddr_by_index(const char *base_name, int index, - uchar *enetaddr); +int eth_getenv_enetaddr_by_index(const char *base_name, int index, + uchar *enetaddr);
-extern int usb_eth_initialize(bd_t *bi); -extern int eth_init(bd_t *bis); /* Initialize the device */ -extern int eth_send(void *packet, int length); /* Send a packet */ +int usb_eth_initialize(bd_t *bi); +int eth_init(bd_t *bis); /* Initialize the device */ +int eth_send(void *packet, int length); /* Send a packet */
#ifdef CONFIG_API -extern int eth_receive(void *packet, int length); /* Receive a packet*/ -extern void (*push_packet)(void *packet, int length); +int eth_receive(void *packet, int length); /* Receive a packet*/ +void (*push_packet)(void *packet, int length); #endif -extern int eth_rx(void); /* Check for received packets */ -extern void eth_halt(void); /* stop SCC */ -extern char *eth_get_name(void); /* get name of current device */ +int eth_rx(void); /* Check for received packets */ +void eth_halt(void); /* stop SCC */ +char *eth_get_name(void); /* get name of current device */
/* Set active state */ static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) @@ -469,25 +469,25 @@ extern IPaddr_t Mcast_addr; #endif
/* Initialize the network adapter */ -extern void net_init(void); -extern int NetLoop(enum proto_t); +void net_init(void); +int NetLoop(enum proto_t);
/* Shutdown adapters and cleanup */ -extern void NetStop(void); +void NetStop(void);
/* Load failed. Start again. */ -extern void NetStartAgain(void); +void NetStartAgain(void);
/* Get size of the ethernet header when we send */ -extern int NetEthHdrSize(void); +int NetEthHdrSize(void);
/* Set ethernet header; returns the size of the header */ -extern int NetSetEther(uchar *, uchar *, uint); -extern int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot); +int NetSetEther(uchar *, uchar *, uint); +int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot);
/* Set IP header */ -extern void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source); -extern void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, +void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source); +void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, int sport, int len);
/** @@ -521,12 +521,12 @@ unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new_sum); int ip_checksum_ok(const void *addr, unsigned nbytes);
/* Callbacks */ -extern rxhand_f *net_get_udp_handler(void); /* Get UDP RX packet handler */ -extern void net_set_udp_handler(rxhand_f *); /* Set UDP RX packet handler */ -extern rxhand_f *net_get_arp_handler(void); /* Get ARP RX packet handler */ -extern void net_set_arp_handler(rxhand_f *); /* Set ARP RX packet handler */ -extern void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */ -extern void NetSetTimeout(ulong, thand_f *);/* Set timeout handler */ +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 */ +void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */ +void NetSetTimeout(ulong, thand_f *);/* Set timeout handler */
/* Network loop state */ enum net_loop_state { @@ -559,11 +559,11 @@ static inline void NetSendPacket(uchar *pkt, int len) * @param sport Source UDP port * @param payload_len Length of data after the UDP header */ -extern int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, +int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int payload_len);
/* Processes a received packet */ -extern void NetReceive(uchar *, int); +void NetReceive(uchar *, int);
#ifdef CONFIG_NETCONSOLE void NcStart(void); @@ -711,28 +711,28 @@ static inline void eth_random_addr(uchar *addr) }
/* Convert an IP address to a string */ -extern void ip_to_string(IPaddr_t x, char *s); +void ip_to_string(IPaddr_t x, char *s);
/* Convert a string to ip address */ -extern IPaddr_t string_to_ip(const char *s); +IPaddr_t string_to_ip(const char *s);
/* Convert a VLAN id to a string */ -extern void VLAN_to_string(ushort x, char *s); +void VLAN_to_string(ushort x, char *s);
/* Convert a string to a vlan id */ -extern ushort string_to_VLAN(const char *s); +ushort string_to_VLAN(const char *s);
/* read a VLAN id from an environment variable */ -extern ushort getenv_VLAN(char *); +ushort getenv_VLAN(char *);
/* copy a filename (allow for "..." notation, limit length) */ -extern void copy_filename(char *dst, const char *src, int size); +void copy_filename(char *dst, const char *src, int size);
/* get a random source port */ -extern unsigned int random_port(void); +unsigned int random_port(void);
/* Update U-Boot over TFTP */ -extern int update_tftp(ulong addr); +int update_tftp(ulong addr);
/**********************************************************************/

Move some things around and organize things so that the driver model implementation will fit in more easily.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v4: -Fix compile regression in !DM_ETH case
Changes in v3: -Move the get_dev_by_* protos to also be !DM_ETH like the impl
Changes in v2: None
include/net.h | 68 +++++++++++++++++++++++++++------------------------- net/eth.c | 77 +++++++++++++++++++++++++++++++---------------------------- 2 files changed, 76 insertions(+), 69 deletions(-)
diff --git a/include/net.h b/include/net.h index b82a29d..4cef00c 100644 --- a/include/net.h +++ b/include/net.h @@ -97,13 +97,9 @@ struct eth_device { void *priv; };
-int eth_initialize(bd_t *bis); /* Initialize network subsystem */ int eth_register(struct eth_device *dev);/* Register network device */ int eth_unregister(struct eth_device *dev);/* Remove network device */ -void eth_try_another(int first_restart); /* Change the device */ -void eth_set_current(void); /* set nterface to ethcur var */
-/* get the current device MAC */ extern struct eth_device *eth_current;
static inline __attribute__((always_inline)) @@ -111,7 +107,10 @@ struct eth_device *eth_get_dev(void) { return eth_current; } +struct eth_device *eth_get_dev_by_name(const char *devname); +struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */
+/* get the current device MAC */ static inline unsigned char *eth_get_ethaddr(void) { if (eth_current) @@ -119,8 +118,37 @@ static inline unsigned char *eth_get_ethaddr(void) return NULL; }
-struct eth_device *eth_get_dev_by_name(const char *devname); -struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ +/* Set active state */ +static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) +{ + eth_get_dev()->state = ETH_STATE_ACTIVE; + + return 0; +} +/* Set passive state */ +static inline __attribute__((always_inline)) void eth_halt_state_only(void) +{ + eth_get_dev()->state = ETH_STATE_PASSIVE; +} + +/* + * Set the hardware address for an ethernet interface based on 'eth%daddr' + * environment variable (or just 'ethaddr' if eth_number is 0). + * Args: + * base_name - base name for device (normally "eth") + * eth_number - value of %d (0 for first device of this type) + * Returns: + * 0 is success, non-zero is error status from driver. + */ +int eth_write_hwaddr(struct eth_device *dev, const char *base_name, + int eth_number); + +int usb_eth_initialize(bd_t *bi); + +int eth_initialize(bd_t *bis); /* Initialize network subsystem */ +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */ + int eth_get_dev_index(void); /* get the device index */ void eth_parse_enetaddr(const char *addr, uchar *enetaddr); int eth_getenv_enetaddr(char *name, uchar *enetaddr); @@ -138,7 +166,6 @@ int eth_setenv_enetaddr(char *name, const uchar *enetaddr); int eth_getenv_enetaddr_by_index(const char *base_name, int index, uchar *enetaddr);
-int usb_eth_initialize(bd_t *bi); int eth_init(bd_t *bis); /* Initialize the device */ int eth_send(void *packet, int length); /* Send a packet */
@@ -148,32 +175,7 @@ void (*push_packet)(void *packet, int length); #endif int eth_rx(void); /* Check for received packets */ void eth_halt(void); /* stop SCC */ -char *eth_get_name(void); /* get name of current device */ - -/* Set active state */ -static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) -{ - eth_get_dev()->state = ETH_STATE_ACTIVE; - - return 0; -} -/* Set passive state */ -static inline __attribute__((always_inline)) void eth_halt_state_only(void) -{ - eth_get_dev()->state = ETH_STATE_PASSIVE; -} - -/* - * Set the hardware address for an ethernet interface based on 'eth%daddr' - * environment variable (or just 'ethaddr' if eth_number is 0). - * Args: - * base_name - base name for device (normally "eth") - * eth_number - value of %d (0 for first device of this type) - * Returns: - * 0 is success, non-zero is error status from driver. - */ -int eth_write_hwaddr(struct eth_device *dev, const char *base_name, - int eth_number); +const char *eth_get_name(void); /* get name of current device */
#ifdef CONFIG_MCAST_TFTP int eth_mcast_join(IPaddr_t mcast_addr, u8 join); diff --git a/net/eth.c b/net/eth.c index 65e8c77..3df3c11 100644 --- a/net/eth.c +++ b/net/eth.c @@ -55,6 +55,14 @@ static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index, return eth_setenv_enetaddr(enetvar, enetaddr); }
+static void eth_env_init(void) +{ + const char *s; + + s = getenv("bootfile"); + if (s != NULL) + copy_filename(BootFile, s, sizeof(BootFile)); +}
static int eth_mac_skip(int index) { @@ -87,6 +95,11 @@ static unsigned int eth_rcv_current, eth_rcv_last; static struct eth_device *eth_devices; struct eth_device *eth_current;
+static void eth_set_current_to_next(void) +{ + eth_current = eth_current->next; +} + struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -137,22 +150,6 @@ int eth_get_dev_index(void) return eth_current->index; }
-static void eth_current_changed(void) -{ - char *act = getenv("ethact"); - /* update current ethernet name */ - if (eth_current) { - if (act == NULL || strcmp(act, eth_current->name) != 0) - setenv("ethact", eth_current->name); - } - /* - * remove the variable completely if there is no active - * interface - */ - else if (act != NULL) - setenv("ethact", NULL); -} - int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -251,14 +248,6 @@ int eth_unregister(struct eth_device *dev) return 0; }
-static void eth_env_init(bd_t *bis) -{ - const char *s; - - if ((s = getenv("bootfile")) != NULL) - copy_filename(BootFile, s, sizeof(BootFile)); -} - int eth_initialize(bd_t *bis) { int num_devices = 0; @@ -274,7 +263,7 @@ int eth_initialize(bd_t *bis) phy_init(); #endif
- eth_env_init(bis); + eth_env_init();
/* * If board-specific initialization exists, call it. @@ -479,6 +468,22 @@ int eth_receive(void *packet, int length) } #endif /* CONFIG_API */
+static void eth_current_changed(void) +{ + char *act = getenv("ethact"); + /* update current ethernet name */ + if (eth_get_dev()) { + if (act == NULL || strcmp(act, eth_get_name()) != 0) + setenv("ethact", eth_get_name()); + } + /* + * remove the variable completely if there is no active + * interface + */ + else if (act != NULL) + setenv("ethact", NULL); +} + void eth_try_another(int first_restart) { static struct eth_device *first_failed; @@ -492,17 +497,17 @@ void eth_try_another(int first_restart) if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) return;
- if (!eth_current) + if (!eth_get_dev()) return;
if (first_restart) - first_failed = eth_current; + first_failed = eth_get_dev();
- eth_current = eth_current->next; + eth_set_current_to_next();
eth_current_changed();
- if (first_failed == eth_current) + if (first_failed == eth_get_dev()) NetRestartWrap = 1; }
@@ -513,7 +518,7 @@ void eth_set_current(void) struct eth_device *old_current; int env_id;
- if (!eth_current) /* XXX no current */ + if (!eth_get_dev()) /* XXX no current */ return;
env_id = get_env_id(); @@ -522,18 +527,18 @@ void eth_set_current(void) env_changed_id = env_id; } if (act != NULL) { - old_current = eth_current; + old_current = eth_get_dev(); do { - if (strcmp(eth_current->name, act) == 0) + if (strcmp(eth_get_name(), act) == 0) return; - eth_current = eth_current->next; - } while (old_current != eth_current); + eth_set_current_to_next(); + } while (old_current != eth_get_dev()); }
eth_current_changed(); }
-char *eth_get_name(void) +const char *eth_get_name(void) { - return eth_current ? eth_current->name : "unknown"; + return eth_get_dev() ? eth_get_dev()->name : "unknown"; }

Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
Move some things around and organize things so that the driver model implementation will fit in more easily.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v4: -Fix compile regression in !DM_ETH case
Changes in v3: -Move the get_dev_by_* protos to also be !DM_ETH like the impl
Changes in v2: None
include/net.h | 68 +++++++++++++++++++++++++++------------------------- net/eth.c | 77 +++++++++++++++++++++++++++++++---------------------------- 2 files changed, 76 insertions(+), 69 deletions(-)
I think I mention this in a later response. But for this patch I see the errors below:
08: net: Refactor in preparation for driver model arm: + snow seaboard x86: + coreboot-x86 +../net/eth.c: In function ‘eth_register’: +../net/eth.c:208:3: error: implicit declaration of function ‘eth_current_changed’ [-Werror=implicit-function-declaration] + eth_current_changed(); + ^ +../net/eth.c: At top level: +../net/eth.c:471:13: error: conflicting types for ‘eth_current_changed’ [-Werror] + static void eth_current_changed(void) + ^ +../net/eth.c:471:13: error: static declaration of ‘eth_current_changed’ follows non-static declaration +../net/eth.c:208:3: note: previous implicit declaration of ‘eth_current_changed’ was here +cc1: all warnings being treated as errors +make[2]: *** [net/eth.o] Error 1 +make[1]: *** [net] Error 2 +make: *** [sub-make] Error 2
[snip]
Regards, Simon

Many functions returned -1 previously. Change them to return appropriate error codes.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org
---
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
net/eth.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/net/eth.c b/net/eth.c index 3df3c11..214375b 100644 --- a/net/eth.c +++ b/net/eth.c @@ -225,7 +225,7 @@ int eth_unregister(struct eth_device *dev)
/* No device */ if (!eth_devices) - return -1; + return -ENODEV;
for (cur = eth_devices; cur->next != eth_devices && cur->next != dev; cur = cur->next) @@ -233,7 +233,7 @@ int eth_unregister(struct eth_device *dev)
/* Device not found */ if (cur->next != dev) - return -1; + return -ENODEV;
cur->next = dev->next;
@@ -366,7 +366,7 @@ int eth_init(bd_t *bis)
if (!eth_current) { puts("No ethernet found.\n"); - return -1; + return -ENODEV; }
/* Sync environment with network devices */ @@ -395,7 +395,7 @@ int eth_init(bd_t *bis) eth_try_another(0); } while (old_current != eth_current);
- return -1; + return -ETIMEDOUT; }
void eth_halt(void) @@ -411,7 +411,7 @@ void eth_halt(void) int eth_send(void *packet, int length) { if (!eth_current) - return -1; + return -ENODEV;
return eth_current->send(eth_current, packet, length); } @@ -419,7 +419,7 @@ int eth_send(void *packet, int length) int eth_rx(void) { if (!eth_current) - return -1; + return -ENODEV;
return eth_current->recv(eth_current); }

On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
Many functions returned -1 previously. Change them to return appropriate error codes.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
net/eth.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

On some archs masking the parameter is inefficient, so don't use u8.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org
---
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
include/net.h | 2 +- net/eth.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/net.h b/include/net.h index 4cef00c..ad20145 100644 --- a/include/net.h +++ b/include/net.h @@ -178,7 +178,7 @@ void eth_halt(void); /* stop SCC */ const char *eth_get_name(void); /* get name of current device */
#ifdef CONFIG_MCAST_TFTP -int eth_mcast_join(IPaddr_t mcast_addr, u8 join); +int eth_mcast_join(IPaddr_t mcast_addr, int join); u32 ether_crc(size_t len, unsigned char const *p); #endif
diff --git a/net/eth.c b/net/eth.c index 214375b..484b995 100644 --- a/net/eth.c +++ b/net/eth.c @@ -319,7 +319,7 @@ int eth_initialize(bd_t *bis) * mcast_addr: multicast ipaddr from which multicast Mac is made * join: 1=join, 0=leave. */ -int eth_mcast_join(IPaddr_t mcast_ip, u8 join) +int eth_mcast_join(IPaddr_t mcast_ip, int join) { u8 mcast_mac[6]; if (!eth_current || !eth_current->mcast)

On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
On some archs masking the parameter is inefficient, so don't use u8.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
include/net.h | 2 +- net/eth.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

This value is not used by the network stack and is available in the global data, so stop passing it around. For the one legacy function that still expects it (init op on old Ethernet drivers) pass in the global pointer version directly to avoid changing that interface.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org
---
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
common/board_r.c | 2 +- drivers/net/netconsole.c | 4 ++-- include/net.h | 6 +++--- net/eth.c | 12 +++++++----- net/net.c | 7 +++---- 5 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/common/board_r.c b/common/board_r.c index 4fcd4f6..b62f72f 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -584,7 +584,7 @@ static int initr_bbmii(void) static int initr_net(void) { puts("Net: "); - eth_initialize(gd->bd); + eth_initialize(); #if defined(CONFIG_RESET_PHY_R) debug("Reset Ethernet PHY\n"); reset_phy(); diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 677c89f..87cea7a 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -193,11 +193,11 @@ static void nc_send_packet(const char *buf, int len)
if (eth->state != ETH_STATE_ACTIVE) { if (eth_is_on_demand_init()) { - if (eth_init(gd->bd) < 0) + if (eth_init() < 0) return; eth_set_last_protocol(NETCONS); } else - eth_init_state_only(gd->bd); + eth_init_state_only();
inited = 1; } diff --git a/include/net.h b/include/net.h index ad20145..10d38f8 100644 --- a/include/net.h +++ b/include/net.h @@ -119,7 +119,7 @@ static inline unsigned char *eth_get_ethaddr(void) }
/* Set active state */ -static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) +static inline __attribute__((always_inline)) int eth_init_state_only(void) { eth_get_dev()->state = ETH_STATE_ACTIVE;
@@ -145,7 +145,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
int usb_eth_initialize(bd_t *bi);
-int eth_initialize(bd_t *bis); /* Initialize network subsystem */ +int eth_initialize(void); /* Initialize network subsystem */ void eth_try_another(int first_restart); /* Change the device */ void eth_set_current(void); /* set nterface to ethcur var */
@@ -166,7 +166,7 @@ int eth_setenv_enetaddr(char *name, const uchar *enetaddr); int eth_getenv_enetaddr_by_index(const char *base_name, int index, uchar *enetaddr);
-int eth_init(bd_t *bis); /* Initialize the device */ +int eth_init(void); /* Initialize the device */ int eth_send(void *packet, int length); /* Send a packet */
#ifdef CONFIG_API diff --git a/net/eth.c b/net/eth.c index 484b995..7bbaac4 100644 --- a/net/eth.c +++ b/net/eth.c @@ -12,6 +12,8 @@ #include <phy.h> #include <asm/errno.h>
+DECLARE_GLOBAL_DATA_PTR; + void eth_parse_enetaddr(const char *addr, uchar *enetaddr) { char *end; @@ -248,7 +250,7 @@ int eth_unregister(struct eth_device *dev) return 0; }
-int eth_initialize(bd_t *bis) +int eth_initialize(void) { int num_devices = 0; eth_devices = NULL; @@ -270,10 +272,10 @@ int eth_initialize(bd_t *bis) * If not, call a CPU-specific one */ if (board_eth_init != __def_eth_init) { - if (board_eth_init(bis) < 0) + if (board_eth_init(gd->bd) < 0) printf("Board Net Initialization Failed\n"); } else if (cpu_eth_init != __def_eth_init) { - if (cpu_eth_init(bis) < 0) + if (cpu_eth_init(gd->bd) < 0) printf("CPU Net Initialization Failed\n"); } else printf("Net Initialization Skipped\n"); @@ -360,7 +362,7 @@ u32 ether_crc(size_t len, unsigned char const *p) #endif
-int eth_init(bd_t *bis) +int eth_init(void) { struct eth_device *old_current, *dev;
@@ -385,7 +387,7 @@ int eth_init(bd_t *bis) do { debug("Trying %s\n", eth_current->name);
- if (eth_current->init(eth_current, bis) >= 0) { + if (eth_current->init(eth_current, gd->bd) >= 0) { eth_current->state = ETH_STATE_ACTIVE;
return 0; diff --git a/net/net.c b/net/net.c index 4b3c90e..e5ab07c 100644 --- a/net/net.c +++ b/net/net.c @@ -324,7 +324,6 @@ void net_init(void)
int NetLoop(enum proto_t protocol) { - bd_t *bd = gd->bd; int ret = -1;
NetRestarted = 0; @@ -337,12 +336,12 @@ int NetLoop(enum proto_t protocol) if (eth_is_on_demand_init() || protocol != NETCONS) { eth_halt(); eth_set_current(); - if (eth_init(bd) < 0) { + if (eth_init() < 0) { eth_halt(); return -1; } } else - eth_init_state_only(bd); + eth_init_state_only();
restart: #ifdef CONFIG_USB_KEYBOARD @@ -618,7 +617,7 @@ void NetStartAgain(void) #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER) eth_try_another(!NetRestarted); #endif - eth_init(gd->bd); + eth_init(); if (NetRestartWrap) { NetRestartWrap = 0; if (NetDevExists) {

On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
This value is not used by the network stack and is available in the global data, so stop passing it around. For the one legacy function that still expects it (init op on old Ethernet drivers) pass in the global pointer version directly to avoid changing that interface.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org
Reviewed-by: Simon Glass sjg@chromium.org

netretry previously would only retry in one specific case (your MAC address is not set) and no other. This is basically useless. In the DM implementation for eth it turns this into a completely useless case since an un-configured MAC address results in not even entering the NetLoop. The behavior is now changed to retry any failed command (rotating through the eth adapters if ethrotate != no).
It also defaulted to retry forever. It is now changed to default to not retry
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
net/net.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/net/net.c b/net/net.c index e5ab07c..37b4aab 100644 --- a/net/net.c +++ b/net/net.c @@ -527,6 +527,8 @@ restart: (*x)(); }
+ if (net_state == NETLOOP_FAIL) + NetStartAgain();
switch (net_state) {
@@ -602,8 +604,10 @@ void NetStartAgain(void) retrycnt = 1; else retrycnt = simple_strtoul(nretry, NULL, 0); - } else - retry_forever = 1; + } else { + retrycnt = 0; + retry_forever = 0; + }
if ((!retry_forever) && (NetTryCount >= retrycnt)) { eth_halt();

Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
netretry previously would only retry in one specific case (your MAC address is not set) and no other. This is basically useless. In the DM implementation for eth it turns this into a completely useless case since an un-configured MAC address results in not even entering the NetLoop. The behavior is now changed to retry any failed command (rotating through the eth adapters if ethrotate != no).
It also defaulted to retry forever. It is now changed to default to not retry
That last bit seems like a big change. Does it mean that if I forget to plug in the Ethernet it might not recover?
Regards, Simon

Hi Simon,
On Sun, Mar 1, 2015 at 12:07 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com
wrote:
netretry previously would only retry in one specific case (your MAC address is not set) and no other. This is basically useless. In the DM implementation for eth it turns this into a completely useless case since an un-configured MAC address results in not even entering the NetLoop. The behavior is now changed to retry any failed command (rotating through the eth adapters if ethrotate != no).
It also defaulted to retry forever. It is now changed to default to not retry
That last bit seems like a big change. Does it mean that if I forget to plug in the Ethernet it might not recover?
It seems like it at face value, but this actually is far closer to maintaining existing behavior.
As described in the first paragraph, only a missing MAC address would be retried. all other forms of failure (unplugged Ethernet, for instance) would just error out. This provides a way to retry if that is a behavior you want. Most times if you ping an address, for instance, you would expect your script to get a failure code, not for the ping to be attempted on a different interface (which would become the new default behavior without this env var default also changing).

Hi Joe,
On 1 March 2015 at 14:53, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Sun, Mar 1, 2015 at 12:07 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
netretry previously would only retry in one specific case (your MAC address is not set) and no other. This is basically useless. In the DM implementation for eth it turns this into a completely useless case since an un-configured MAC address results in not even entering the NetLoop. The behavior is now changed to retry any failed command (rotating through the eth adapters if ethrotate != no).
It also defaulted to retry forever. It is now changed to default to not retry
That last bit seems like a big change. Does it mean that if I forget to plug in the Ethernet it might not recover?
It seems like it at face value, but this actually is far closer to maintaining existing behavior.
As described in the first paragraph, only a missing MAC address would be retried. all other forms of failure (unplugged Ethernet, for instance) would just error out. This provides a way to retry if that is a behavior you want. Most times if you ping an address, for instance, you would expect your script to get a failure code, not for the ping to be attempted on a different interface (which would become the new default behavior without this env var default also changing).
Thanks for explaining this.
Reviewed-by: Simon Glass sjg@chromium.org
Regards, Simon

Previously the net functions would access memory assuming physmem did not need to be mapped. In sandbox, that's not the case.
Now we map the physmem specified by the user in loadaddr to the buffer that represents that space.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
net/nfs.c | 2 +- net/tftp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/nfs.c b/net/nfs.c index 381b75f..c816acd 100644 --- a/net/nfs.c +++ b/net/nfs.c @@ -93,7 +93,7 @@ store_block(uchar *src, unsigned offset, unsigned len) } else #endif /* CONFIG_SYS_DIRECT_FLASH_NFS */ { - (void)memcpy((void *)(load_addr + offset), src, len); + memcpy((void *)(map_sysmem(load_addr, 0) + offset), src, len); }
if (NetBootFileXferSize < (offset+len)) diff --git a/net/tftp.c b/net/tftp.c index 0a2c533..9290182 100644 --- a/net/tftp.c +++ b/net/tftp.c @@ -184,7 +184,7 @@ store_block(int block, uchar *src, unsigned len) } else #endif /* CONFIG_SYS_DIRECT_FLASH_TFTP */ { - (void)memcpy((void *)(load_addr + offset), src, len); + memcpy((void *)(map_sysmem(load_addr, 0) + offset), src, len); } #ifdef CONFIG_MCAST_TFTP if (Multicast)

Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
Previously the net functions would access memory assuming physmem did not need to be mapped. In sandbox, that's not the case.
Now we map the physmem specified by the user in loadaddr to the buffer that represents that space.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
net/nfs.c | 2 +- net/tftp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/nfs.c b/net/nfs.c index 381b75f..c816acd 100644 --- a/net/nfs.c +++ b/net/nfs.c @@ -93,7 +93,7 @@ store_block(uchar *src, unsigned offset, unsigned len) } else #endif /* CONFIG_SYS_DIRECT_FLASH_NFS */ {
(void)memcpy((void *)(load_addr + offset), src, len);
memcpy((void *)(map_sysmem(load_addr, 0) + offset), src, len);
I think this would be better as:
memcpy(map_sysmem(load_addr + offset, src_len), src, len);
and for consistency we should call unmap_sysmem() too.
void *ptr = map_sysmem(load_addr + offset, src_len);
memcpy(ptr, src, len); unmap_sysmem(ptr);
} if (NetBootFileXferSize < (offset+len))
diff --git a/net/tftp.c b/net/tftp.c index 0a2c533..9290182 100644 --- a/net/tftp.c +++ b/net/tftp.c @@ -184,7 +184,7 @@ store_block(int block, uchar *src, unsigned len) } else #endif /* CONFIG_SYS_DIRECT_FLASH_TFTP */ {
(void)memcpy((void *)(load_addr + offset), src, len);
memcpy((void *)(map_sysmem(load_addr, 0) + offset), src, len);
Similar here.
}
#ifdef CONFIG_MCAST_TFTP if (Multicast) -- 1.7.11.5
Regards, Simon

First just add support for MAC drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v4: -Redo the seq / probe implementation --Don't prevent eth_initialize on driver model --Use eth_initialize to probe all devices and write_hwaddr --Look up MAC address in post-probe --Include ethprime handling in eth_initialize --If current == NULL, always check if there is a device available in eth_get_dev --Move env init call from uclass init to eth_initialize --Print the alias in eth_initialize -Stop handling selecting a new "current" in pre-unbind as it will now work itself out by clearing the pointer -Change -1 returns to error constants -Remove bd_t *bis from dm eth_ops init function -Add documentation to the structures -Add a helper function for eth_uclass_priv -Change puts to printf -Add eth_get_ops helper -Rename init() to start() in ops -Rename halt() to stop() in ops -Remove checks for driver==NULL -Remove priv pointer in per-device priv struct (drivers already get their own directly from DM)
Changes in v3: -Correct the pre_unbind logic -Correct failure chaining from bind to probe to init --Fail init if not activated --Fail probe if ethaddr not set -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the previous selection -Allow current eth dev to be NULL -Fixed blank line formatting for variable declaration
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for our needs -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()).
common/cmd_bdinfo.c | 2 + drivers/net/Kconfig | 5 + include/dm/uclass-id.h | 1 + include/net.h | 52 ++++++++ net/eth.c | 345 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 399 insertions(+), 6 deletions(-)
diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index aa81da2..b4cce25 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e69de29..bdd0f05 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -0,0 +1,5 @@ +config DM_ETH + bool "Enable Driver Model for Ethernet drivers" + depends on DM + help + Enable driver model for Ethernet. diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..ad96682 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */ + UCLASS_ETH, /* Ethernet device */
UCLASS_COUNT, UCLASS_INVALID = -1, diff --git a/include/net.h b/include/net.h index 10d38f8..508c572 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,57 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH +/** + * struct eth_pdata - Platform data for Ethernet MAC controllers + * + * @iobase: The base address of the hardware registers + * @enetaddr: The Ethernet MAC address that is loaded from EEPROM or env + */ +struct eth_pdata { + phys_addr_t iobase; + unsigned char enetaddr[6]; +}; + +/** + * struct eth_ops - functions of Ethernet MAC controllers + * + * start: Prepare the hardware to send and receive packets + * send: Send the bytes passed in "packet" as a packet on the wire + * recv: Check if the hardware received a packet. Call the network stack if so + * stop: Stop the hardware from looking for packets - may be called even if + * state == PASSIVE + * mcast: Join or leave a multicast group (for TFTP) - optional + * write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux + * on some platforms like ARM). This function expects the + * eth_pdata::enetaddr field to be populated - optional + * read_rom_hwaddr: Some devices have a backup of the MAC address stored in a + * ROM on the board. This is how the driver should expose it + * to the network stack. This function should fill in the + * eth_pdata::enetaddr field - optional + */ +struct eth_ops { + int (*start)(struct udevice *dev); + int (*send)(struct udevice *dev, void *packet, int length); + int (*recv)(struct udevice *dev); + void (*stop)(struct udevice *dev); +#ifdef CONFIG_MCAST_TFTP + int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join); +#endif + int (*write_hwaddr)(struct udevice *dev); + int (*read_rom_hwaddr)(struct udevice *dev); +}; + +#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops) + +struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +/* Used only when NetConsole is enabled */ +int eth_init_state_only(void); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ +#endif + +#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; @@ -144,6 +195,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number);
int usb_eth_initialize(bd_t *bi); +#endif
int eth_initialize(void); /* Initialize network subsystem */ void eth_try_another(int first_restart); /* Change the device */ diff --git a/net/eth.c b/net/eth.c index 7bbaac4..9c2dfb9 100644 --- a/net/eth.c +++ b/net/eth.c @@ -1,12 +1,15 @@ /* - * (C) Copyright 2001-2010 + * (C) Copyright 2001-2015 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Joe Hershberger, National Instruments * * SPDX-License-Identifier: GPL-2.0+ */
#include <common.h> #include <command.h> +#include <dm.h> +#include <dm/device-internal.h> #include <net.h> #include <miiphy.h> #include <phy.h> @@ -74,6 +77,338 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void); + +#ifdef CONFIG_DM_ETH +/** + * struct eth_device_priv - private structure for each Ethernet device + * + * @state: The state of the Ethernet MAC driver (defined by enum eth_state_t) + */ +struct eth_device_priv { + enum eth_state_t state; +}; + +/** + * struct eth_uclass_priv - The structure attached to the uclass itself + * + * @current: The Ethernet device that the network functions are using + */ +struct eth_uclass_priv { + struct udevice *current; +}; + +static struct eth_uclass_priv *eth_get_uclass_priv(void) +{ + struct uclass *uc; + + uclass_get(UCLASS_ETH, &uc); + assert(uc); + return uc->priv; +} + +static void eth_set_current_to_next(void) +{ + struct eth_uclass_priv *uc_priv; + + uc_priv = eth_get_uclass_priv(); + if (uc_priv->current) + uclass_next_device(&uc_priv->current); + if (!uc_priv->current) + uclass_first_device(UCLASS_ETH, &uc_priv->current); +} + +struct udevice *eth_get_dev(void) +{ + if (!eth_get_uclass_priv()->current) + uclass_first_device(UCLASS_ETH, + ð_get_uclass_priv()->current); + return eth_get_uclass_priv()->current; +} + +static void eth_set_dev(struct udevice *dev) +{ + device_probe(dev); + eth_get_uclass_priv()->current = dev; +} + +unsigned char *eth_get_ethaddr(void) +{ + struct eth_pdata *pdata; + + if (eth_get_dev()) { + pdata = eth_get_dev()->platdata; + return pdata->enetaddr; + } + + return NULL; +} + +/* Set active state without calling start on the driver */ +int eth_init_state_only(void) +{ + struct udevice *current; + struct eth_device_priv *priv; + + current = eth_get_dev(); + if (!current || !device_active(current)) + return -EINVAL; + + priv = current->uclass_priv; + priv->state = ETH_STATE_ACTIVE; + + return 0; +} + +/* Set passive state without calling stop on the driver */ +void eth_halt_state_only(void) +{ + struct udevice *current; + struct eth_device_priv *priv; + + current = eth_get_dev(); + if (!current || !device_active(current)) + return; + + priv = current->uclass_priv; + priv->state = ETH_STATE_PASSIVE; +} + +int eth_get_dev_index(void) +{ + if (eth_get_dev()) + return eth_get_dev()->seq; + return -1; +} + +int eth_init(void) +{ + struct udevice *current; + struct udevice *old_current; + + current = eth_get_dev(); + if (!current) { + printf("No ethernet found.\n"); + return -ENODEV; + } + + old_current = current; + do { + debug("Trying %s\n", current->name); + + if (device_active(current)) { + uchar env_enetaddr[6]; + struct eth_pdata *pdata = current->platdata; + + /* Sync environment with network device */ + if (eth_getenv_enetaddr_by_index("eth", current->seq, + env_enetaddr)) + memcpy(pdata->enetaddr, env_enetaddr, 6); + else + memset(pdata->enetaddr, 0, 6); + + if (eth_get_ops(current)->start(current) >= 0) { + struct eth_device_priv *priv = + current->uclass_priv; + + priv->state = ETH_STATE_ACTIVE; + return 0; + } + } + debug("FAIL\n"); + + /* This will ensure the new "current" attempted to probe */ + eth_try_another(0); + current = eth_get_dev(); + } while (old_current != current); + + return -ENODEV; +} + +void eth_halt(void) +{ + struct udevice *current; + struct eth_device_priv *priv; + + current = eth_get_dev(); + if (!current || !device_active(current)) + return; + + eth_get_ops(current)->stop(current); + priv = current->uclass_priv; + priv->state = ETH_STATE_PASSIVE; +} + +int eth_send(void *packet, int length) +{ + struct udevice *current; + + current = eth_get_dev(); + if (!current) + return -ENODEV; + + if (!device_active(current)) + return -EINVAL; + + return eth_get_ops(current)->send(current, packet, length); +} + +int eth_rx(void) +{ + struct udevice *current; + + current = eth_get_dev(); + if (!current) + return -ENODEV; + + if (!device_active(current)) + return -EINVAL; + + return eth_get_ops(current)->recv(current); +} + +static int eth_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev->platdata; + int ret = 0; + + if (!dev || !device_active(dev)) + return -EINVAL; + + /* seq is valid since the device is active */ + if (eth_get_ops(dev)->write_hwaddr && !eth_mac_skip(dev->seq)) { + if (!is_valid_ether_addr(pdata->enetaddr)) { + printf("\nError: %s address %pM illegal value\n", + dev->name, pdata->enetaddr); + return -EINVAL; + } + + ret = eth_get_ops(dev)->write_hwaddr(dev); + if (ret) + printf("\nWarning: %s failed to set MAC address\n", + dev->name); + } + + return ret; +} + +int eth_initialize(void) +{ + int num_devices = 0; + struct udevice *dev; + + bootstage_mark(BOOTSTAGE_ID_NET_ETH_START); + eth_env_init(); + + /* + * Devices need to write the hwaddr even if not started so that Linux + * will have access to the hwaddr that u-boot stored for the device. + * This is accomplished by attempting to probe each device and calling + * their write_hwaddr() operation. + */ + uclass_first_device(UCLASS_ETH, &dev); + if (!dev) { + printf("No ethernet found.\n"); + bootstage_error(BOOTSTAGE_ID_NET_ETH_START); + } else { + bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); + do { + if (num_devices) + printf(", "); + + printf("eth%d: %s", dev->seq, dev->name); + + eth_write_hwaddr(dev); + + uclass_next_device(&dev); + num_devices++; + } while (dev); + + putc('\n'); + } + + return num_devices; +} + +static int eth_post_bind(struct udevice *dev) +{ + if (strchr(dev->name, ' ')) { + printf("\nError: eth device name "%s" has a space!\n", + dev->name); + return -EINVAL; + } + + return 0; +} + +static int eth_pre_unbind(struct udevice *dev) +{ + /* Don't hang onto a pointer that is going away */ + if (dev == eth_get_uclass_priv()->current) + eth_set_dev(NULL); + + return 0; +} + +static int eth_post_probe(struct udevice *dev) +{ + struct eth_device_priv *priv = dev->uclass_priv; + struct eth_pdata *pdata = dev->platdata; + unsigned char env_enetaddr[6]; + + priv->state = ETH_STATE_INIT; + + /* Check if the device has a MAC address in ROM */ + if (eth_get_ops(dev)->read_rom_hwaddr) + eth_get_ops(dev)->read_rom_hwaddr(dev); + + eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr); + if (!is_zero_ether_addr(env_enetaddr)) { + if (!is_zero_ether_addr(pdata->enetaddr) && + memcmp(pdata->enetaddr, env_enetaddr, 6)) { + printf("\nWarning: %s MAC addresses don't match:\n", + dev->name); + printf("Address in SROM is %pM\n", + pdata->enetaddr); + printf("Address in environment is %pM\n", + env_enetaddr); + } + + /* Override the ROM MAC address */ + memcpy(pdata->enetaddr, env_enetaddr, 6); + } else if (is_valid_ether_addr(pdata->enetaddr)) { + eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr); + printf("\nWarning: %s using MAC address from ROM\n", + dev->name); + } else if (is_zero_ether_addr(pdata->enetaddr)) { + printf("\nError: %s address not set.\n", + dev->name); + return -EINVAL; + } + + return 0; +} + +static int eth_pre_remove(struct udevice *dev) +{ + eth_get_ops(dev)->stop(dev); + + return 0; +} + +UCLASS_DRIVER(eth) = { + .name = "eth", + .id = UCLASS_ETH, + .post_bind = eth_post_bind, + .pre_unbind = eth_pre_unbind, + .post_probe = eth_post_probe, + .pre_remove = eth_pre_remove, + .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), + .per_device_auto_alloc_size = sizeof(struct eth_device_priv), +}; +#endif + +#ifndef CONFIG_DM_ETH /* * CPU and board-specific Ethernet initializations. Aliased function * signals caller to move on @@ -425,6 +760,7 @@ int eth_rx(void)
return eth_current->recv(eth_current); } +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -488,7 +824,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) { - static struct eth_device *first_failed; + static void *first_failed; char *ethrotate;
/* @@ -517,12 +853,9 @@ void eth_set_current(void) { static char *act; static int env_changed_id; - struct eth_device *old_current; + void *old_current; int env_id;
- if (!eth_get_dev()) /* XXX no current */ - return; - env_id = get_env_id(); if ((act == NULL) || (env_changed_id != env_id)) { act = getenv("ethact");

Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
First just add support for MAC drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org
This looks right to me. I still have some comments on error handling, but I'm OK with you addressing these in a follow-on patch if you like.
Changes in v4: -Redo the seq / probe implementation --Don't prevent eth_initialize on driver model --Use eth_initialize to probe all devices and write_hwaddr --Look up MAC address in post-probe --Include ethprime handling in eth_initialize --If current == NULL, always check if there is a device available in eth_get_dev --Move env init call from uclass init to eth_initialize --Print the alias in eth_initialize -Stop handling selecting a new "current" in pre-unbind as it will now work itself out by clearing the pointer -Change -1 returns to error constants -Remove bd_t *bis from dm eth_ops init function -Add documentation to the structures -Add a helper function for eth_uclass_priv -Change puts to printf -Add eth_get_ops helper -Rename init() to start() in ops -Rename halt() to stop() in ops -Remove checks for driver==NULL -Remove priv pointer in per-device priv struct (drivers already get their own directly from DM)
Changes in v3: -Correct the pre_unbind logic -Correct failure chaining from bind to probe to init --Fail init if not activated --Fail probe if ethaddr not set -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the previous selection -Allow current eth dev to be NULL -Fixed blank line formatting for variable declaration
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for our needs -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()).
common/cmd_bdinfo.c | 2 + drivers/net/Kconfig | 5 + include/dm/uclass-id.h | 1 + include/net.h | 52 ++++++++ net/eth.c | 345 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 399 insertions(+), 6 deletions(-)
diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index aa81da2..b4cce25 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e69de29..bdd0f05 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -0,0 +1,5 @@ +config DM_ETH
bool "Enable Driver Model for Ethernet drivers"
depends on DM
help
Enable driver model for Ethernet.
Here you could mention that the eth_...() interface is then implemented by the Ethernet uclass. Perhaps a few other notes too? See for example drivers/spi/Kconfig or drivers/gpio/Kconfig.
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..ad96682 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */
UCLASS_ETH, /* Ethernet device */ UCLASS_COUNT, UCLASS_INVALID = -1,
diff --git a/include/net.h b/include/net.h index 10d38f8..508c572 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,57 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH +/**
- struct eth_pdata - Platform data for Ethernet MAC controllers
- @iobase: The base address of the hardware registers
- @enetaddr: The Ethernet MAC address that is loaded from EEPROM or env
- */
+struct eth_pdata {
phys_addr_t iobase;
unsigned char enetaddr[6];
+};
+/**
- struct eth_ops - functions of Ethernet MAC controllers
- start: Prepare the hardware to send and receive packets
- send: Send the bytes passed in "packet" as a packet on the wire
- recv: Check if the hardware received a packet. Call the network stack if so
- stop: Stop the hardware from looking for packets - may be called even if
state == PASSIVE
- mcast: Join or leave a multicast group (for TFTP) - optional
- write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux
on some platforms like ARM). This function expects the
eth_pdata::enetaddr field to be populated - optional
- read_rom_hwaddr: Some devices have a backup of the MAC address stored in a
ROM on the board. This is how the driver should expose it
to the network stack. This function should fill in the
eth_pdata::enetaddr field - optional
- */
+struct eth_ops {
int (*start)(struct udevice *dev);
int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev);
void (*stop)(struct udevice *dev);
+#ifdef CONFIG_MCAST_TFTP
int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join);
+#endif
int (*write_hwaddr)(struct udevice *dev);
int (*read_rom_hwaddr)(struct udevice *dev);
+};
+#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
+struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +/* Used only when NetConsole is enabled */ +int eth_init_state_only(void); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ +#endif
+#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; @@ -144,6 +195,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number);
int usb_eth_initialize(bd_t *bi); +#endif
int eth_initialize(void); /* Initialize network subsystem */ void eth_try_another(int first_restart); /* Change the device */ diff --git a/net/eth.c b/net/eth.c index 7bbaac4..9c2dfb9 100644 --- a/net/eth.c +++ b/net/eth.c @@ -1,12 +1,15 @@ /*
- (C) Copyright 2001-2010
- (C) Copyright 2001-2015
- Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*/
- Joe Hershberger, National Instruments
- SPDX-License-Identifier: GPL-2.0+
#include <common.h> #include <command.h> +#include <dm.h> +#include <dm/device-internal.h>
The dm/ headers should go after the asm/ header below.
#include <net.h> #include <miiphy.h> #include <phy.h> @@ -74,6 +77,338 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH +/**
- struct eth_device_priv - private structure for each Ethernet device
- @state: The state of the Ethernet MAC driver (defined by enum eth_state_t)
- */
+struct eth_device_priv {
enum eth_state_t state;
+};
+/**
- struct eth_uclass_priv - The structure attached to the uclass itself
- @current: The Ethernet device that the network functions are using
- */
+struct eth_uclass_priv {
struct udevice *current;
+};
+static struct eth_uclass_priv *eth_get_uclass_priv(void) +{
struct uclass *uc;
uclass_get(UCLASS_ETH, &uc);
assert(uc);
return uc->priv;
+}
+static void eth_set_current_to_next(void) +{
struct eth_uclass_priv *uc_priv;
uc_priv = eth_get_uclass_priv();
if (uc_priv->current)
uclass_next_device(&uc_priv->current);
if (!uc_priv->current)
uclass_first_device(UCLASS_ETH, &uc_priv->current);
+}
+struct udevice *eth_get_dev(void)
This function needs a comment. It isn't clear what is it supposed to return. Does it only return probed devices (in which case the check in eth_halt() etc. for device_active() is redundant? Or can it return devices which cannot be probed?
I suggest that it only returns probed devices, as it simplifies the code.
+{
if (!eth_get_uclass_priv()->current)
uclass_first_device(UCLASS_ETH,
ð_get_uclass_priv()->current);
This can return an error. You will then eat it and return the device anyway, even though uclass_first_device() will not change ->current.
return eth_get_uclass_priv()->current;
Also I think it would be better to have a local variable here for uc_priv, as in the above functino.
+}
+static void eth_set_dev(struct udevice *dev) +{
device_probe(dev);
This needs an error check, since if it fails you cannot use the device. Also in eth_pre_unbind() you call this function with NULL.
So I think this function should return an error.
eth_get_uclass_priv()->current = dev;
+}
+unsigned char *eth_get_ethaddr(void) +{
struct eth_pdata *pdata;
if (eth_get_dev()) {
pdata = eth_get_dev()->platdata;
return pdata->enetaddr;
}
return NULL;
+}
+/* Set active state without calling start on the driver */ +int eth_init_state_only(void) +{
struct udevice *current;
struct eth_device_priv *priv;
current = eth_get_dev();
if (!current || !device_active(current))
return -EINVAL;
priv = current->uclass_priv;
priv->state = ETH_STATE_ACTIVE;
return 0;
+}
+/* Set passive state without calling stop on the driver */ +void eth_halt_state_only(void) +{
struct udevice *current;
struct eth_device_priv *priv;
current = eth_get_dev();
if (!current || !device_active(current))
return;
priv = current->uclass_priv;
priv->state = ETH_STATE_PASSIVE;
+}
+int eth_get_dev_index(void) +{
if (eth_get_dev())
return eth_get_dev()->seq;
return -1;
+}
+int eth_init(void) +{
struct udevice *current;
struct udevice *old_current;
current = eth_get_dev();
if (!current) {
printf("No ethernet found.\n");
return -ENODEV;
}
old_current = current;
do {
debug("Trying %s\n", current->name);
if (device_active(current)) {
uchar env_enetaddr[6];
struct eth_pdata *pdata = current->platdata;
/* Sync environment with network device */
if (eth_getenv_enetaddr_by_index("eth", current->seq,
env_enetaddr))
memcpy(pdata->enetaddr, env_enetaddr, 6);
else
memset(pdata->enetaddr, 0, 6);
if (eth_get_ops(current)->start(current) >= 0) {
struct eth_device_priv *priv =
current->uclass_priv;
priv->state = ETH_STATE_ACTIVE;
return 0;
}
}
debug("FAIL\n");
/* This will ensure the new "current" attempted to probe */
eth_try_another(0);
current = eth_get_dev();
} while (old_current != current);
return -ENODEV;
+}
+void eth_halt(void) +{
struct udevice *current;
struct eth_device_priv *priv;
current = eth_get_dev();
if (!current || !device_active(current))
return;
As above, probably this device_active() check is redundant?
eth_get_ops(current)->stop(current);
How about adding error checking in these functions? Then eventually we can plumb it through. Driver authors are not going to motivated to deal with errors if they know that their caller ignores them.
ret = eth_get_ops... if (ret) { /* We cannot return the error at present */ debug("%s: stop() returned error %d\n", __func__, ret); }
priv = current->uclass_priv;
priv->state = ETH_STATE_PASSIVE;
+}
+int eth_send(void *packet, int length) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return -ENODEV;
if (!device_active(current))
return -EINVAL;
return eth_get_ops(current)->send(current, packet, length);
+}
+int eth_rx(void) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return -ENODEV;
if (!device_active(current))
return -EINVAL;
return eth_get_ops(current)->recv(current);
+}
+static int eth_write_hwaddr(struct udevice *dev) +{
struct eth_pdata *pdata = dev->platdata;
int ret = 0;
if (!dev || !device_active(dev))
return -EINVAL;
/* seq is valid since the device is active */
if (eth_get_ops(dev)->write_hwaddr && !eth_mac_skip(dev->seq)) {
if (!is_valid_ether_addr(pdata->enetaddr)) {
printf("\nError: %s address %pM illegal value\n",
dev->name, pdata->enetaddr);
return -EINVAL;
}
ret = eth_get_ops(dev)->write_hwaddr(dev);
if (ret)
printf("\nWarning: %s failed to set MAC address\n",
dev->name);
}
return ret;
+}
+int eth_initialize(void) +{
int num_devices = 0;
struct udevice *dev;
bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
eth_env_init();
/*
* Devices need to write the hwaddr even if not started so that Linux
* will have access to the hwaddr that u-boot stored for the device.
* This is accomplished by attempting to probe each device and calling
* their write_hwaddr() operation.
*/
uclass_first_device(UCLASS_ETH, &dev);
if (!dev) {
printf("No ethernet found.\n");
bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
} else {
bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
do {
if (num_devices)
printf(", ");
printf("eth%d: %s", dev->seq, dev->name);
eth_write_hwaddr(dev);
uclass_next_device(&dev);
num_devices++;
} while (dev);
putc('\n');
}
return num_devices;
+}
+static int eth_post_bind(struct udevice *dev) +{
if (strchr(dev->name, ' ')) {
printf("\nError: eth device name \"%s\" has a space!\n",
dev->name);
return -EINVAL;
}
return 0;
+}
+static int eth_pre_unbind(struct udevice *dev) +{
/* Don't hang onto a pointer that is going away */
if (dev == eth_get_uclass_priv()->current)
eth_set_dev(NULL);
return 0;
+}
+static int eth_post_probe(struct udevice *dev) +{
struct eth_device_priv *priv = dev->uclass_priv;
struct eth_pdata *pdata = dev->platdata;
unsigned char env_enetaddr[6];
priv->state = ETH_STATE_INIT;
/* Check if the device has a MAC address in ROM */
if (eth_get_ops(dev)->read_rom_hwaddr)
eth_get_ops(dev)->read_rom_hwaddr(dev);
eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr);
if (!is_zero_ether_addr(env_enetaddr)) {
if (!is_zero_ether_addr(pdata->enetaddr) &&
memcmp(pdata->enetaddr, env_enetaddr, 6)) {
printf("\nWarning: %s MAC addresses don't match:\n",
dev->name);
printf("Address in SROM is %pM\n",
pdata->enetaddr);
printf("Address in environment is %pM\n",
env_enetaddr);
}
/* Override the ROM MAC address */
memcpy(pdata->enetaddr, env_enetaddr, 6);
} else if (is_valid_ether_addr(pdata->enetaddr)) {
eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr);
printf("\nWarning: %s using MAC address from ROM\n",
dev->name);
} else if (is_zero_ether_addr(pdata->enetaddr)) {
printf("\nError: %s address not set.\n",
dev->name);
return -EINVAL;
}
return 0;
+}
+static int eth_pre_remove(struct udevice *dev) +{
eth_get_ops(dev)->stop(dev);
return 0;
+}
+UCLASS_DRIVER(eth) = {
.name = "eth",
.id = UCLASS_ETH,
.post_bind = eth_post_bind,
.pre_unbind = eth_pre_unbind,
.post_probe = eth_post_probe,
.pre_remove = eth_pre_remove,
.priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
.per_device_auto_alloc_size = sizeof(struct eth_device_priv),
+}; +#endif
Could we put the uclass in its own eth-uclass.c file at some point?
+#ifndef CONFIG_DM_ETH /*
- CPU and board-specific Ethernet initializations. Aliased function
- signals caller to move on
@@ -425,6 +760,7 @@ int eth_rx(void)
return eth_current->recv(eth_current);
} +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -488,7 +824,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) {
static struct eth_device *first_failed;
static void *first_failed; char *ethrotate; /*
@@ -517,12 +853,9 @@ void eth_set_current(void) { static char *act; static int env_changed_id;
struct eth_device *old_current;
void *old_current; int env_id;
if (!eth_get_dev()) /* XXX no current */
return;
env_id = get_env_id(); if ((act == NULL) || (env_changed_id != env_id)) { act = getenv("ethact");
-- 1.7.11.5
Regards, Simon

Hi Simon,
On Sun, Mar 1, 2015 at 12:07 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com
wrote:
First just add support for MAC drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org
This looks right to me. I still have some comments on error handling, but I'm OK with you addressing these in a follow-on patch if you like.
Thanks for going back and forth on this to make it right.
Changes in v4: -Redo the seq / probe implementation --Don't prevent eth_initialize on driver model --Use eth_initialize to probe all devices and write_hwaddr --Look up MAC address in post-probe --Include ethprime handling in eth_initialize --If current == NULL, always check if there is a device available in
eth_get_dev
--Move env init call from uclass init to eth_initialize --Print the alias in eth_initialize -Stop handling selecting a new "current" in pre-unbind as it will now
work itself out by clearing the pointer
-Change -1 returns to error constants -Remove bd_t *bis from dm eth_ops init function -Add documentation to the structures -Add a helper function for eth_uclass_priv -Change puts to printf -Add eth_get_ops helper -Rename init() to start() in ops -Rename halt() to stop() in ops -Remove checks for driver==NULL -Remove priv pointer in per-device priv struct (drivers already get
their own directly from DM)
Changes in v3: -Correct the pre_unbind logic -Correct failure chaining from bind to probe to init --Fail init if not activated --Fail probe if ethaddr not set -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the
previous selection
-Allow current eth dev to be NULL -Fixed blank line formatting for variable declaration
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for
our needs
-Move the hwaddr to platdata so that its memory is allocated at bind
when we need it
-Prevent device from being probed before used by a command (i.e. before
eth_init()).
common/cmd_bdinfo.c | 2 + drivers/net/Kconfig | 5 + include/dm/uclass-id.h | 1 + include/net.h | 52 ++++++++ net/eth.c | 345
++++++++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 399 insertions(+), 6 deletions(-)
diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index aa81da2..b4cce25 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e69de29..bdd0f05 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -0,0 +1,5 @@ +config DM_ETH
bool "Enable Driver Model for Ethernet drivers"
depends on DM
help
Enable driver model for Ethernet.
Here you could mention that the eth_...() interface is then implemented by the Ethernet uclass. Perhaps a few other notes too? See for example drivers/spi/Kconfig or drivers/gpio/Kconfig.
OK
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..ad96682 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */
UCLASS_ETH, /* Ethernet device */ UCLASS_COUNT, UCLASS_INVALID = -1,
diff --git a/include/net.h b/include/net.h index 10d38f8..508c572 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,57 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH +/**
- struct eth_pdata - Platform data for Ethernet MAC controllers
- @iobase: The base address of the hardware registers
- @enetaddr: The Ethernet MAC address that is loaded from EEPROM or
env
- */
+struct eth_pdata {
phys_addr_t iobase;
unsigned char enetaddr[6];
+};
+/**
- struct eth_ops - functions of Ethernet MAC controllers
- start: Prepare the hardware to send and receive packets
- send: Send the bytes passed in "packet" as a packet on the wire
- recv: Check if the hardware received a packet. Call the network
stack if so
- stop: Stop the hardware from looking for packets - may be called
even if
state == PASSIVE
- mcast: Join or leave a multicast group (for TFTP) - optional
- write_hwaddr: Write a MAC address to the hardware (used to pass it
to Linux
on some platforms like ARM). This function expects the
eth_pdata::enetaddr field to be populated - optional
- read_rom_hwaddr: Some devices have a backup of the MAC address
stored in a
ROM on the board. This is how the driver should
expose it
to the network stack. This function should fill in
the
eth_pdata::enetaddr field - optional
I consider this one of the primary purposes that board-specific init exists for Ethernet. I think this will help to eliminate them. I'm interested in your thoughts about how to generically expose this to a board / SoC / driver. For now I was thinking that it would be up to the driver to fan out if needed, meaning that if the driver doesn't know the MAC, it has a board-hook function call, but if it does, like USB or PCI adapters, it won't have board hooks. [sorry for the run-on sentence] I feel it's non-ideal, but can work for now.
- */
+struct eth_ops {
int (*start)(struct udevice *dev);
int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev);
void (*stop)(struct udevice *dev);
+#ifdef CONFIG_MCAST_TFTP
int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join);
+#endif
int (*write_hwaddr)(struct udevice *dev);
int (*read_rom_hwaddr)(struct udevice *dev);
+};
+#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
+struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +/* Used only when NetConsole is enabled */ +int eth_init_state_only(void); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ +#endif
+#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; @@ -144,6 +195,7 @@ int eth_write_hwaddr(struct eth_device *dev, const
char *base_name,
int eth_number);
int usb_eth_initialize(bd_t *bi); +#endif
int eth_initialize(void); /* Initialize network subsystem
*/
void eth_try_another(int first_restart); /* Change the device */ diff --git a/net/eth.c b/net/eth.c index 7bbaac4..9c2dfb9 100644 --- a/net/eth.c +++ b/net/eth.c @@ -1,12 +1,15 @@ /*
- (C) Copyright 2001-2010
- (C) Copyright 2001-2015
- Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*/
- Joe Hershberger, National Instruments
- SPDX-License-Identifier: GPL-2.0+
#include <common.h> #include <command.h> +#include <dm.h> +#include <dm/device-internal.h>
The dm/ headers should go after the asm/ header below.
What in the asm headers affects the dm headers? Or is it an aesthetics request?
#include <net.h> #include <miiphy.h> #include <phy.h> @@ -74,6 +77,338 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH +/**
- struct eth_device_priv - private structure for each Ethernet device
- @state: The state of the Ethernet MAC driver (defined by enum
eth_state_t)
- */
+struct eth_device_priv {
enum eth_state_t state;
+};
+/**
- struct eth_uclass_priv - The structure attached to the uclass itself
- @current: The Ethernet device that the network functions are using
- */
+struct eth_uclass_priv {
struct udevice *current;
+};
+static struct eth_uclass_priv *eth_get_uclass_priv(void) +{
struct uclass *uc;
uclass_get(UCLASS_ETH, &uc);
assert(uc);
return uc->priv;
+}
+static void eth_set_current_to_next(void) +{
struct eth_uclass_priv *uc_priv;
uc_priv = eth_get_uclass_priv();
if (uc_priv->current)
uclass_next_device(&uc_priv->current);
if (!uc_priv->current)
uclass_first_device(UCLASS_ETH, &uc_priv->current);
+}
+struct udevice *eth_get_dev(void)
This function needs a comment. It isn't clear what is it supposed to return. Does it only return probed devices (in which case the check in eth_halt() etc. for device_active() is redundant? Or can it return devices which cannot be probed?
In the current implementation it will return any device (probe-able or not), as it is the caller that has the logic to decide how to move on or not.
I suggest that it only returns probed devices, as it simplifies the code.
I can evaluate that, but it is not currently expected anywhere.
+{
if (!eth_get_uclass_priv()->current)
uclass_first_device(UCLASS_ETH,
ð_get_uclass_priv()->current);
This can return an error. You will then eat it and return the device anyway, even though uclass_first_device() will not change ->current.
This can return the error from the probe(), but is the probe fails it also return a NULL pointer, which is what I'm using to determine success. I can't return the device in the error case because uclass_first_device() doesn't give it to me.
return eth_get_uclass_priv()->current;
Also I think it would be better to have a local variable here for uc_priv, as in the above functino.
OK
+}
+static void eth_set_dev(struct udevice *dev) +{
device_probe(dev);
This needs an error check, since if it fails you cannot use the device. Also in eth_pre_unbind() you call this function with NULL.
The device_probe() function already has that check, so I didn't bother adding it again here.
So I think this function should return an error.
I'm not sure what other error it would return. If it's just the NULL pointer, the caller knows what it passed in. NULL pointer is valid here. Essentially asking to unset this device as current (as in pre_unbind handler).
eth_get_uclass_priv()->current = dev;
+}
+unsigned char *eth_get_ethaddr(void) +{
struct eth_pdata *pdata;
if (eth_get_dev()) {
pdata = eth_get_dev()->platdata;
return pdata->enetaddr;
}
return NULL;
+}
+/* Set active state without calling start on the driver */ +int eth_init_state_only(void) +{
struct udevice *current;
struct eth_device_priv *priv;
current = eth_get_dev();
if (!current || !device_active(current))
return -EINVAL;
priv = current->uclass_priv;
priv->state = ETH_STATE_ACTIVE;
return 0;
+}
+/* Set passive state without calling stop on the driver */ +void eth_halt_state_only(void) +{
struct udevice *current;
struct eth_device_priv *priv;
current = eth_get_dev();
if (!current || !device_active(current))
return;
priv = current->uclass_priv;
priv->state = ETH_STATE_PASSIVE;
+}
+int eth_get_dev_index(void) +{
if (eth_get_dev())
return eth_get_dev()->seq;
return -1;
+}
+int eth_init(void) +{
struct udevice *current;
struct udevice *old_current;
current = eth_get_dev();
if (!current) {
printf("No ethernet found.\n");
return -ENODEV;
}
old_current = current;
do {
debug("Trying %s\n", current->name);
if (device_active(current)) {
uchar env_enetaddr[6];
struct eth_pdata *pdata = current->platdata;
/* Sync environment with network device */
if (eth_getenv_enetaddr_by_index("eth",
current->seq,
env_enetaddr))
memcpy(pdata->enetaddr, env_enetaddr,
6);
else
memset(pdata->enetaddr, 0, 6);
if (eth_get_ops(current)->start(current) >= 0) {
struct eth_device_priv *priv =
current->uclass_priv;
priv->state = ETH_STATE_ACTIVE;
return 0;
}
}
debug("FAIL\n");
/* This will ensure the new "current" attempted to
probe */
eth_try_another(0);
current = eth_get_dev();
} while (old_current != current);
return -ENODEV;
+}
+void eth_halt(void) +{
struct udevice *current;
struct eth_device_priv *priv;
current = eth_get_dev();
if (!current || !device_active(current))
return;
As above, probably this device_active() check is redundant?
There is a case where it is not redundant. If the eth_set_dev() is called with a device that fails to probe, then it will be called the current device, but not be active. This is needed to be able to skip over a device that won't probe to get to one that will.
eth_get_ops(current)->stop(current);
How about adding error checking in these functions? Then eventually we can plumb it through. Driver authors are not going to motivated to deal with errors if they know that their caller ignores them.
ret = eth_get_ops... if (ret) { /* We cannot return the error at present */ debug("%s: stop() returned error %d\n", __func__, ret); }
OK
priv = current->uclass_priv;
priv->state = ETH_STATE_PASSIVE;
+}
+int eth_send(void *packet, int length) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return -ENODEV;
if (!device_active(current))
return -EINVAL;
return eth_get_ops(current)->send(current, packet, length);
+}
+int eth_rx(void) +{
struct udevice *current;
current = eth_get_dev();
if (!current)
return -ENODEV;
if (!device_active(current))
return -EINVAL;
return eth_get_ops(current)->recv(current);
+}
+static int eth_write_hwaddr(struct udevice *dev) +{
struct eth_pdata *pdata = dev->platdata;
int ret = 0;
if (!dev || !device_active(dev))
return -EINVAL;
/* seq is valid since the device is active */
if (eth_get_ops(dev)->write_hwaddr && !eth_mac_skip(dev->seq)) {
if (!is_valid_ether_addr(pdata->enetaddr)) {
printf("\nError: %s address %pM illegal
value\n",
dev->name, pdata->enetaddr);
return -EINVAL;
}
ret = eth_get_ops(dev)->write_hwaddr(dev);
if (ret)
printf("\nWarning: %s failed to set MAC
address\n",
dev->name);
}
return ret;
+}
+int eth_initialize(void) +{
int num_devices = 0;
struct udevice *dev;
bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
eth_env_init();
/*
* Devices need to write the hwaddr even if not started so that
Linux
* will have access to the hwaddr that u-boot stored for the
device.
* This is accomplished by attempting to probe each device and
calling
* their write_hwaddr() operation.
*/
uclass_first_device(UCLASS_ETH, &dev);
if (!dev) {
printf("No ethernet found.\n");
bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
} else {
bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
do {
if (num_devices)
printf(", ");
printf("eth%d: %s", dev->seq, dev->name);
eth_write_hwaddr(dev);
uclass_next_device(&dev);
num_devices++;
} while (dev);
putc('\n');
}
return num_devices;
+}
+static int eth_post_bind(struct udevice *dev) +{
if (strchr(dev->name, ' ')) {
printf("\nError: eth device name \"%s\" has a space!\n",
dev->name);
return -EINVAL;
}
return 0;
+}
+static int eth_pre_unbind(struct udevice *dev) +{
/* Don't hang onto a pointer that is going away */
if (dev == eth_get_uclass_priv()->current)
eth_set_dev(NULL);
return 0;
+}
+static int eth_post_probe(struct udevice *dev) +{
struct eth_device_priv *priv = dev->uclass_priv;
struct eth_pdata *pdata = dev->platdata;
unsigned char env_enetaddr[6];
priv->state = ETH_STATE_INIT;
/* Check if the device has a MAC address in ROM */
if (eth_get_ops(dev)->read_rom_hwaddr)
eth_get_ops(dev)->read_rom_hwaddr(dev);
eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr);
if (!is_zero_ether_addr(env_enetaddr)) {
if (!is_zero_ether_addr(pdata->enetaddr) &&
memcmp(pdata->enetaddr, env_enetaddr, 6)) {
printf("\nWarning: %s MAC addresses don't
match:\n",
dev->name);
printf("Address in SROM is %pM\n",
pdata->enetaddr);
printf("Address in environment is %pM\n",
env_enetaddr);
}
/* Override the ROM MAC address */
memcpy(pdata->enetaddr, env_enetaddr, 6);
} else if (is_valid_ether_addr(pdata->enetaddr)) {
eth_setenv_enetaddr_by_index("eth", dev->seq,
pdata->enetaddr);
printf("\nWarning: %s using MAC address from ROM\n",
dev->name);
} else if (is_zero_ether_addr(pdata->enetaddr)) {
printf("\nError: %s address not set.\n",
dev->name);
return -EINVAL;
}
return 0;
+}
+static int eth_pre_remove(struct udevice *dev) +{
eth_get_ops(dev)->stop(dev);
return 0;
+}
+UCLASS_DRIVER(eth) = {
.name = "eth",
.id = UCLASS_ETH,
.post_bind = eth_post_bind,
.pre_unbind = eth_pre_unbind,
.post_probe = eth_post_probe,
.pre_remove = eth_pre_remove,
.priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
.per_device_auto_alloc_size = sizeof(struct eth_device_priv),
+}; +#endif
Could we put the uclass in its own eth-uclass.c file at some point?
At some point, yes.
+#ifndef CONFIG_DM_ETH /*
- CPU and board-specific Ethernet initializations. Aliased function
- signals caller to move on
@@ -425,6 +760,7 @@ int eth_rx(void)
return eth_current->recv(eth_current);
} +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -488,7 +824,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) {
static struct eth_device *first_failed;
static void *first_failed; char *ethrotate; /*
@@ -517,12 +853,9 @@ void eth_set_current(void) { static char *act; static int env_changed_id;
struct eth_device *old_current;
void *old_current; int env_id;
if (!eth_get_dev()) /* XXX no current */
return;
env_id = get_env_id(); if ((act == NULL) || (env_changed_id != env_id)) { act = getenv("ethact");
-- 1.7.11.5
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi Joe,
On 1 March 2015 at 14:45, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Sun, Mar 1, 2015 at 12:07 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
First just add support for MAC drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org
This looks right to me. I still have some comments on error handling, but I'm OK with you addressing these in a follow-on patch if you like.
Thanks for going back and forth on this to make it right.
I'm pleased to see it coming together.
Changes in v4: -Redo the seq / probe implementation --Don't prevent eth_initialize on driver model --Use eth_initialize to probe all devices and write_hwaddr --Look up MAC address in post-probe --Include ethprime handling in eth_initialize --If current == NULL, always check if there is a device available in eth_get_dev --Move env init call from uclass init to eth_initialize --Print the alias in eth_initialize -Stop handling selecting a new "current" in pre-unbind as it will now work itself out by clearing the pointer -Change -1 returns to error constants -Remove bd_t *bis from dm eth_ops init function -Add documentation to the structures -Add a helper function for eth_uclass_priv -Change puts to printf -Add eth_get_ops helper -Rename init() to start() in ops -Rename halt() to stop() in ops -Remove checks for driver==NULL -Remove priv pointer in per-device priv struct (drivers already get their own directly from DM)
Changes in v3: -Correct the pre_unbind logic -Correct failure chaining from bind to probe to init --Fail init if not activated --Fail probe if ethaddr not set -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the previous selection -Allow current eth dev to be NULL -Fixed blank line formatting for variable declaration
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for our needs -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()).
common/cmd_bdinfo.c | 2 + drivers/net/Kconfig | 5 + include/dm/uclass-id.h | 1 + include/net.h | 52 ++++++++ net/eth.c | 345 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 399 insertions(+), 6 deletions(-)
diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index aa81da2..b4cce25 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e69de29..bdd0f05 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -0,0 +1,5 @@ +config DM_ETH
bool "Enable Driver Model for Ethernet drivers"
depends on DM
help
Enable driver model for Ethernet.
Here you could mention that the eth_...() interface is then implemented by the Ethernet uclass. Perhaps a few other notes too? See for example drivers/spi/Kconfig or drivers/gpio/Kconfig.
OK
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..ad96682 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */
UCLASS_ETH, /* Ethernet device */ UCLASS_COUNT, UCLASS_INVALID = -1,
diff --git a/include/net.h b/include/net.h index 10d38f8..508c572 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,57 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH +/**
- struct eth_pdata - Platform data for Ethernet MAC controllers
- @iobase: The base address of the hardware registers
- @enetaddr: The Ethernet MAC address that is loaded from EEPROM or
env
- */
+struct eth_pdata {
phys_addr_t iobase;
unsigned char enetaddr[6];
+};
+/**
- struct eth_ops - functions of Ethernet MAC controllers
- start: Prepare the hardware to send and receive packets
- send: Send the bytes passed in "packet" as a packet on the wire
- recv: Check if the hardware received a packet. Call the network
stack if so
- stop: Stop the hardware from looking for packets - may be called
even if
state == PASSIVE
- mcast: Join or leave a multicast group (for TFTP) - optional
- write_hwaddr: Write a MAC address to the hardware (used to pass it
to Linux
on some platforms like ARM). This function expects the
eth_pdata::enetaddr field to be populated - optional
- read_rom_hwaddr: Some devices have a backup of the MAC address
stored in a
ROM on the board. This is how the driver should
expose it
to the network stack. This function should fill in
the
eth_pdata::enetaddr field - optional
I consider this one of the primary purposes that board-specific init exists for Ethernet. I think this will help to eliminate them. I'm interested in your thoughts about how to generically expose this to a board / SoC / driver. For now I was thinking that it would be up to the driver to fan out if needed, meaning that if the driver doesn't know the MAC, it has a board-hook function call, but if it does, like USB or PCI adapters, it won't have board hooks. [sorry for the run-on sentence] I feel it's non-ideal, but can work for now.
As a general principle I think we should avoid all board hooks. The information (if needed) should be in the device tree / platform data provided by the board, or perhaps set up by the board through some sort of call. Of course the MAC address is in some ways a special case. I don't have a good answer for this, but perhaps it will become apparent once we have more Ethernet driver support?
- */
+struct eth_ops {
int (*start)(struct udevice *dev);
int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev);
void (*stop)(struct udevice *dev);
+#ifdef CONFIG_MCAST_TFTP
int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join);
+#endif
int (*write_hwaddr)(struct udevice *dev);
int (*read_rom_hwaddr)(struct udevice *dev);
+};
+#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
+struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +/* Used only when NetConsole is enabled */ +int eth_init_state_only(void); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ +#endif
+#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; @@ -144,6 +195,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number);
int usb_eth_initialize(bd_t *bi); +#endif
int eth_initialize(void); /* Initialize network subsystem */ void eth_try_another(int first_restart); /* Change the device */ diff --git a/net/eth.c b/net/eth.c index 7bbaac4..9c2dfb9 100644 --- a/net/eth.c +++ b/net/eth.c @@ -1,12 +1,15 @@ /*
- (C) Copyright 2001-2010
- (C) Copyright 2001-2015
- Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*/
- Joe Hershberger, National Instruments
- SPDX-License-Identifier: GPL-2.0+
#include <common.h> #include <command.h> +#include <dm.h> +#include <dm/device-internal.h>
The dm/ headers should go after the asm/ header below.
What in the asm headers affects the dm headers? Or is it an aesthetics request?
#include <net.h> #include <miiphy.h> #include <phy.h> @@ -74,6 +77,338 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH +/**
- struct eth_device_priv - private structure for each Ethernet device
- @state: The state of the Ethernet MAC driver (defined by enum
eth_state_t)
- */
+struct eth_device_priv {
enum eth_state_t state;
+};
+/**
- struct eth_uclass_priv - The structure attached to the uclass itself
- @current: The Ethernet device that the network functions are using
- */
+struct eth_uclass_priv {
struct udevice *current;
+};
+static struct eth_uclass_priv *eth_get_uclass_priv(void) +{
struct uclass *uc;
uclass_get(UCLASS_ETH, &uc);
assert(uc);
return uc->priv;
+}
+static void eth_set_current_to_next(void) +{
struct eth_uclass_priv *uc_priv;
uc_priv = eth_get_uclass_priv();
if (uc_priv->current)
uclass_next_device(&uc_priv->current);
if (!uc_priv->current)
uclass_first_device(UCLASS_ETH, &uc_priv->current);
+}
+struct udevice *eth_get_dev(void)
This function needs a comment. It isn't clear what is it supposed to return. Does it only return probed devices (in which case the check in eth_halt() etc. for device_active() is redundant? Or can it return devices which cannot be probed?
In the current implementation it will return any device (probe-able or not), as it is the caller that has the logic to decide how to move on or not.
I suggest that it only returns probed devices, as it simplifies the code.
I can evaluate that, but it is not currently expected anywhere.
Well I'll leave this to you.
+{
if (!eth_get_uclass_priv()->current)
uclass_first_device(UCLASS_ETH,
ð_get_uclass_priv()->current);
This can return an error. You will then eat it and return the device anyway, even though uclass_first_device() will not change ->current.
This can return the error from the probe(), but is the probe fails it also return a NULL pointer, which is what I'm using to determine success. I can't return the device in the error case because uclass_first_device() doesn't give it to me.
Overall (and maybe this is best figured out later) I think the functions that swallow errors should have special names and be commented that way. The innocuous name eth_get_dev() hides quite a few features. Perhaps eth_scan_for_suitable_device() ?
return eth_get_uclass_priv()->current;
Also I think it would be better to have a local variable here for uc_priv, as in the above functino.
OK
+}
+static void eth_set_dev(struct udevice *dev) +{
device_probe(dev);
This needs an error check, since if it fails you cannot use the device. Also in eth_pre_unbind() you call this function with NULL.
The device_probe() function already has that check, so I didn't bother adding it again here.
So I think this function should return an error.
I'm not sure what other error it would return. If it's just the NULL pointer, the caller knows what it passed in. NULL pointer is valid here. Essentially asking to unset this device as current (as in pre_unbind handler).
You are relying on device_probe() returning an error when dev is NULL? OK, I suppose. Could use a comment.
[snip]
Regards Simon

Add basic network support to sandbox which includes a network driver.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v4: -Cleaned up sandbox EXTRA_ENV define -Moved config to Kconfig
Changes in v3: -Added 2 more ethaddr to sandbox -Print which device in the debug write hwaddr
Changes in v2: -Change printfs to debug in sandbox driver -Remove unused priv struct for sandbox driver
arch/sandbox/Kconfig | 9 +++++ arch/sandbox/dts/sandbox.dts | 4 +++ board/sandbox/README.sandbox | 4 +-- drivers/net/Kconfig | 18 ++++++++++ drivers/net/Makefile | 1 + drivers/net/sandbox.c | 84 ++++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 16 +++++---- 7 files changed, 128 insertions(+), 8 deletions(-) create mode 100644 drivers/net/sandbox.c
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index 2098b9c..186b58d 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -34,4 +34,13 @@ config DM_I2C config DM_TEST default y
+config NET + default y + +config NETDEVICES + default y + +config DM_ETH + default y + endmenu diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 9ce31bf..36b3bd8 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -181,4 +181,8 @@ }; };
+ eth@10002000 { + compatible = "sandbox,eth"; + reg = <0x10002000 0x1000>; + }; }; diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox index 3c0df17..c1f5f7e 100644 --- a/board/sandbox/README.sandbox +++ b/board/sandbox/README.sandbox @@ -173,16 +173,16 @@ U-Boot sandbox supports these emulations: - Chrome OS EC - GPIO - Host filesystem (access files on the host from within U-Boot) +- I2C - Keyboard (Chrome OS) - LCD +- Network - Serial (for console only) - Sound (incomplete - see sandbox_sdl_sound_init() for details) - SPI - SPI flash - TPM (Trusted Platform Module)
-Notable omissions are networking and I2C. - A wide range of commands is implemented. Filesystems which use a block device are supported.
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index bdd0f05..b08746a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -3,3 +3,21 @@ config DM_ETH depends on DM help Enable driver model for Ethernet. + +menuconfig NETDEVICES + bool "Network device support" + depends on NET + help + You must select Y to enable any network device support + Generally if you have any networking support this is a given + + If unsure, say Y + +if NETDEVICES + +config ETH_SANDBOX + depends on DM_ETH && SANDBOX + default y + bool "Sandbox: Mocked Ethernet driver" + +endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 46c4ac6..15dc431 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_NS8382X) += ns8382x.o obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o +obj-$(CONFIG_ETH_SANDBOX) += sandbox.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c new file mode 100644 index 0000000..834e02a --- /dev/null +++ b/drivers/net/sandbox.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int sb_eth_start(struct udevice *dev) +{ + debug("eth_sandbox: Start\n"); + + return 0; +} + +static int sb_eth_send(struct udevice *dev, void *packet, int length) +{ + debug("eth_sandbox: Send packet %d\n", length); + + return 0; +} + +static int sb_eth_recv(struct udevice *dev) +{ + return 0; +} + +static void sb_eth_stop(struct udevice *dev) +{ + debug("eth_sandbox: Stop\n"); +} + +static int sb_eth_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + + debug("eth_sandbox %s: Write HW ADDR - %pM\n", dev->name, + pdata->enetaddr); + return 0; +} + +static const struct eth_ops sb_eth_ops = { + .start = sb_eth_start, + .send = sb_eth_send, + .recv = sb_eth_recv, + .stop = sb_eth_stop, + .write_hwaddr = sb_eth_write_hwaddr, +}; + +static int sb_eth_remove(struct udevice *dev) +{ + return 0; +} + +static int sb_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + + pdata->iobase = dev_get_addr(dev); + return 0; +} + +static const struct udevice_id sb_eth_ids[] = { + { .compatible = "sandbox,eth" }, + { } +}; + +U_BOOT_DRIVER(eth_sandbox) = { + .name = "eth_sandbox", + .id = UCLASS_ETH, + .of_match = sb_eth_ids, + .ofdata_to_platdata = sb_eth_ofdata_to_platdata, + .remove = sb_eth_remove, + .ops = &sb_eth_ops, + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index febbfb6..664b984 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -126,9 +126,6 @@ /* include default commands */ #include <config_cmd_default.h>
-/* We don't have networking support yet */ -#undef CONFIG_CMD_NET -#undef CONFIG_CMD_NFS
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY @@ -165,16 +162,23 @@
#define CONFIG_KEYBOARD
-#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial,cros-ec-keyb\0" \ +#define SANDBOX_SERIAL_SETTINGS "stdin=serial,cros-ec-keyb\0" \ "stdout=serial,lcd\0" \ "stderr=serial,lcd\0" #else - -#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial\0" \ +#define SANDBOX_SERIAL_SETTINGS "stdin=serial\0" \ "stdout=serial,lcd\0" \ "stderr=serial,lcd\0" #endif
+#define SANDBOX_ETH_SETTINGS "ethaddr=00:00:11:22:33:44\0" \ + "eth1addr=00:00:11:22:33:45\0" \ + "eth2addr=00:00:11:22:33:46\0" \ + "ipaddr=1.2.3.4\0" + +#define CONFIG_EXTRA_ENV_SETTINGS SANDBOX_SERIAL_SETTINGS \ + SANDBOX_ETH_SETTINGS + #define CONFIG_GZIP_COMPRESSED #define CONFIG_BZIP2 #define CONFIG_LZO

Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
Add basic network support to sandbox which includes a network driver.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v4: -Cleaned up sandbox EXTRA_ENV define -Moved config to Kconfig
Changes in v3: -Added 2 more ethaddr to sandbox -Print which device in the debug write hwaddr
Changes in v2: -Change printfs to debug in sandbox driver -Remove unused priv struct for sandbox driver
arch/sandbox/Kconfig | 9 +++++ arch/sandbox/dts/sandbox.dts | 4 +++ board/sandbox/README.sandbox | 4 +-- drivers/net/Kconfig | 18 ++++++++++ drivers/net/Makefile | 1 + drivers/net/sandbox.c | 84 ++++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 16 +++++---- 7 files changed, 128 insertions(+), 8 deletions(-) create mode 100644 drivers/net/sandbox.c
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index 2098b9c..186b58d 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -34,4 +34,13 @@ config DM_I2C config DM_TEST default y
+config NET
default y
+config NETDEVICES
default y
+config DM_ETH
default y
endmenu diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 9ce31bf..36b3bd8 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -181,4 +181,8 @@ }; };
eth@10002000 {
compatible = "sandbox,eth";
reg = <0x10002000 0x1000>;
};
}; diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox index 3c0df17..c1f5f7e 100644 --- a/board/sandbox/README.sandbox +++ b/board/sandbox/README.sandbox @@ -173,16 +173,16 @@ U-Boot sandbox supports these emulations:
- Chrome OS EC
- GPIO
- Host filesystem (access files on the host from within U-Boot)
+- I2C
- Keyboard (Chrome OS)
- LCD
+- Network
- Serial (for console only)
- Sound (incomplete - see sandbox_sdl_sound_init() for details)
- SPI
- SPI flash
- TPM (Trusted Platform Module)
-Notable omissions are networking and I2C.
A wide range of commands is implemented. Filesystems which use a block device are supported.
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index bdd0f05..b08746a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -3,3 +3,21 @@ config DM_ETH depends on DM help Enable driver model for Ethernet.
+menuconfig NETDEVICES
bool "Network device support"
depends on NET
help
You must select Y to enable any network device support
Generally if you have any networking support this is a given
If unsure, say Y
+if NETDEVICES
+config ETH_SANDBOX
depends on DM_ETH && SANDBOX
default y
bool "Sandbox: Mocked Ethernet driver"
This needs some help.
+endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 46c4ac6..15dc431 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_NS8382X) += ns8382x.o obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o +obj-$(CONFIG_ETH_SANDBOX) += sandbox.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c new file mode 100644 index 0000000..834e02a --- /dev/null +++ b/drivers/net/sandbox.c @@ -0,0 +1,84 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0
- */
+#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <net.h>
+DECLARE_GLOBAL_DATA_PTR;
+static int sb_eth_start(struct udevice *dev) +{
debug("eth_sandbox: Start\n");
return 0;
+}
+static int sb_eth_send(struct udevice *dev, void *packet, int length) +{
debug("eth_sandbox: Send packet %d\n", length);
return 0;
+}
+static int sb_eth_recv(struct udevice *dev) +{
return 0;
+}
+static void sb_eth_stop(struct udevice *dev) +{
debug("eth_sandbox: Stop\n");
+}
+static int sb_eth_write_hwaddr(struct udevice *dev) +{
struct eth_pdata *pdata = dev_get_platdata(dev);
debug("eth_sandbox %s: Write HW ADDR - %pM\n", dev->name,
pdata->enetaddr);
return 0;
+}
+static const struct eth_ops sb_eth_ops = {
.start = sb_eth_start,
.send = sb_eth_send,
.recv = sb_eth_recv,
.stop = sb_eth_stop,
.write_hwaddr = sb_eth_write_hwaddr,
+};
+static int sb_eth_remove(struct udevice *dev) +{
return 0;
+}
+static int sb_eth_ofdata_to_platdata(struct udevice *dev) +{
struct eth_pdata *pdata = dev_get_platdata(dev);
pdata->iobase = dev_get_addr(dev);
return 0;
+}
+static const struct udevice_id sb_eth_ids[] = {
{ .compatible = "sandbox,eth" },
{ }
+};
+U_BOOT_DRIVER(eth_sandbox) = {
.name = "eth_sandbox",
.id = UCLASS_ETH,
.of_match = sb_eth_ids,
.ofdata_to_platdata = sb_eth_ofdata_to_platdata,
.remove = sb_eth_remove,
.ops = &sb_eth_ops,
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+}; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index febbfb6..664b984 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -126,9 +126,6 @@ /* include default commands */ #include <config_cmd_default.h>
-/* We don't have networking support yet */ -#undef CONFIG_CMD_NET -#undef CONFIG_CMD_NFS
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY @@ -165,16 +162,23 @@
#define CONFIG_KEYBOARD
-#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial,cros-ec-keyb\0" \ +#define SANDBOX_SERIAL_SETTINGS "stdin=serial,cros-ec-keyb\0" \ "stdout=serial,lcd\0" \ "stderr=serial,lcd\0" #else
-#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial\0" \ +#define SANDBOX_SERIAL_SETTINGS "stdin=serial\0" \ "stdout=serial,lcd\0" \ "stderr=serial,lcd\0" #endif
+#define SANDBOX_ETH_SETTINGS "ethaddr=00:00:11:22:33:44\0" \
"eth1addr=00:00:11:22:33:45\0" \
"eth2addr=00:00:11:22:33:46\0" \
"ipaddr=1.2.3.4\0"
+#define CONFIG_EXTRA_ENV_SETTINGS SANDBOX_SERIAL_SETTINGS \
SANDBOX_ETH_SETTINGS
#define CONFIG_GZIP_COMPRESSED #define CONFIG_BZIP2
#define CONFIG_LZO
1.7.11.5
Regards, Simon

The sandbox driver will now generate response traffic to exercise the ping command even when no network exists. This allows the basic data pathways of the DM to be tested.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v4: -Removed checks on priv != NULL and added protection in uclass instead
Changes in v3: -Prevent a crash if memory is not allocated
Changes in v2: -Change printfs to debug in sandbox driver -Move static data to priv -Move fake hwaddr to the device tree
arch/sandbox/dts/sandbox.dts | 1 + drivers/net/sandbox.c | 111 +++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 1 + 3 files changed, 113 insertions(+)
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 36b3bd8..235dcc0 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -184,5 +184,6 @@ eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; }; }; diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 834e02a..81362e6 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -14,22 +14,132 @@
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 + * 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]; + IPaddr_t fake_host_ipaddr; + uchar recv_packet_buffer[PKTSIZE]; + int recv_packet_length; +}; + static int sb_eth_start(struct udevice *dev) { + struct eth_sandbox_priv *priv = dev_get_priv(dev); + u32 int_array[ARP_HLEN]; + int i; + debug("eth_sandbox: Start\n");
+ fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "fake-host-hwaddr", + int_array, ARP_HLEN); + for (i = 0; i < ARP_HLEN; i++) + priv->fake_host_hwaddr[i] = (uchar)int_array[i]; + return 0; }
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 (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 = NetReadIP(&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); + NetWriteIP(&arp_recv->ar_spa, priv->fake_host_ipaddr); + memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN); + NetCopyIP(&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; + NetCopyIP((void *)&ipr->ip_dst, &ip->ip_src); + NetWriteIP((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; }
static int sb_eth_recv(struct udevice *dev) { + struct eth_sandbox_priv *priv = dev_get_priv(dev); + + if (priv->recv_packet_length) { + int lcl_recv_packet_length = priv->recv_packet_length; + + debug("eth_sandbox: received packet %d\n", + priv->recv_packet_length); + priv->recv_packet_length = 0; + NetReceive((void *)priv->recv_packet_buffer, + lcl_recv_packet_length); + } return 0; }
@@ -80,5 +190,6 @@ U_BOOT_DRIVER(eth_sandbox) = { .ofdata_to_platdata = sb_eth_ofdata_to_platdata, .remove = sb_eth_remove, .ops = &sb_eth_ops, + .priv_auto_alloc_size = sizeof(struct eth_sandbox_priv), .platdata_auto_alloc_size = sizeof(struct eth_pdata), }; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 664b984..9189f6a 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -126,6 +126,7 @@ /* include default commands */ #include <config_cmd_default.h>
+#define CONFIG_CMD_PING
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY

Add a test for the eth uclass using the sandbox eth driver. Verify basic functionality of the network stack / eth uclass by exercising the ping function.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v4: None Changes in v3: -Added dm eth testing
Changes in v2: None
test/dm/Makefile | 1 + test/dm/eth.c | 38 ++++++++++++++++++++++++++++++++++++++ test/dm/test.dts | 18 ++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 test/dm/eth.c
diff --git a/test/dm/Makefile b/test/dm/Makefile index 1d9148f..b2eb989 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_DM_TEST) += ut.o obj-$(CONFIG_DM_TEST) += core.o obj-$(CONFIG_DM_TEST) += ut.o ifneq ($(CONFIG_SANDBOX),) +obj-$(CONFIG_DM_ETH) += eth.o obj-$(CONFIG_DM_GPIO) += gpio.o obj-$(CONFIG_DM_I2C) += i2c.o obj-$(CONFIG_DM_SPI_FLASH) += sf.o diff --git a/test/dm/eth.c b/test/dm/eth.c new file mode 100644 index 0000000..04ccf49 --- /dev/null +++ b/test/dm/eth.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <dm/test.h> +#include <dm/ut.h> +#include <fdtdec.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int dm_test_eth(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + + setenv("ethact", "eth@10002000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth@10003000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10003000", getenv("ethact")); + + setenv("ethact", "eth@10004000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + return 0; +} +DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 84024a4..2f68cdf 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -149,4 +149,22 @@ }; };
+ eth@10002000 { + compatible = "sandbox,eth"; + reg = <0x10002000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; + }; + + eth@10003000 { + compatible = "sandbox,eth"; + reg = <0x10003000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>; + }; + + eth@10004000 { + compatible = "sandbox,eth"; + reg = <0x10004000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x22>; + }; + };

Allow network devices to be referred to as "eth0" instead of "eth@12345678" when specified in ethact.
Add tests to verify this behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v4: -Use only the seq from DM to find aliases
Changes in v3: -Added support for aliases
Changes in v2: None
include/configs/sandbox.h | 2 +- include/net.h | 1 + net/eth.c | 47 ++++++++++++++++++++++++++++++++++++++--------- test/dm/eth.c | 24 ++++++++++++++++++++++++ test/dm/test.dts | 4 +++- 5 files changed, 67 insertions(+), 11 deletions(-)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 9189f6a..caf9f5a 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -174,7 +174,7 @@
#define SANDBOX_ETH_SETTINGS "ethaddr=00:00:11:22:33:44\0" \ "eth1addr=00:00:11:22:33:45\0" \ - "eth2addr=00:00:11:22:33:46\0" \ + "eth5addr=00:00:11:22:33:46\0" \ "ipaddr=1.2.3.4\0"
#define CONFIG_EXTRA_ENV_SETTINGS SANDBOX_SERIAL_SETTINGS \ diff --git a/include/net.h b/include/net.h index 508c572..e9cb4a3 100644 --- a/include/net.h +++ b/include/net.h @@ -122,6 +122,7 @@ struct eth_ops { #define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
struct udevice *eth_get_dev(void); /* get the current device */ +struct udevice *eth_get_dev_by_name(const char *devname); unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ /* Used only when NetConsole is enabled */ int eth_init_state_only(void); /* Set active state */ diff --git a/net/eth.c b/net/eth.c index 9c2dfb9..8b853e8 100644 --- a/net/eth.c +++ b/net/eth.c @@ -132,6 +132,36 @@ static void eth_set_dev(struct udevice *dev) eth_get_uclass_priv()->current = dev; }
+/* + * Find the udevice that either has the name passed in as devname or has an + * alias named devname. + */ +struct udevice *eth_get_dev_by_name(const char *devname) +{ + int seq; + char *endp = NULL; + const char *startp; + struct udevice *it; + struct uclass *uc; + + startp = devname + strlen("eth"); + seq = simple_strtoul(startp, &endp, 10); + + uclass_get(UCLASS_ETH, &uc); + uclass_foreach_dev(it, uc) { + /* We need the seq to be valid, so make sure it's probed */ + device_probe(it); + /* + * Check for the name or the sequence number to match + */ + if (strcmp(it->name, devname) == 0 || + (endp > startp && it->seq == seq)) + return it; + } + + return NULL; +} + unsigned char *eth_get_ethaddr(void) { struct eth_pdata *pdata; @@ -405,6 +435,7 @@ UCLASS_DRIVER(eth) = { .pre_remove = eth_pre_remove, .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), .per_device_auto_alloc_size = sizeof(struct eth_device_priv), + .flags = DM_UC_FLAG_SEQ_ALIAS, }; #endif
@@ -437,6 +468,11 @@ static void eth_set_current_to_next(void) eth_current = eth_current->next; }
+static void eth_set_dev(struct eth_device *dev) +{ + eth_current = dev; +} + struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -853,7 +889,6 @@ void eth_set_current(void) { static char *act; static int env_changed_id; - void *old_current; int env_id;
env_id = get_env_id(); @@ -861,14 +896,8 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; } - if (act != NULL) { - old_current = eth_get_dev(); - do { - if (strcmp(eth_get_name(), act) == 0) - return; - eth_set_current_to_next(); - } while (old_current != eth_get_dev()); - } + if (act != NULL) + eth_set_dev(eth_get_dev_by_name(act));
eth_current_changed(); } diff --git a/test/dm/eth.c b/test/dm/eth.c index 04ccf49..5688b71 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -36,3 +36,27 @@ static int dm_test_eth(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT); + +static int dm_test_eth_alias(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + setenv("ethact", "eth0"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth1"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Expected to fail since eth2 is not defined in the device tree */ + setenv("ethact", "eth2"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth5"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10003000", getenv("ethact")); + + return 0; +} +DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 2f68cdf..bc2409d 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -17,6 +17,8 @@ testfdt3 = "/b-test"; testfdt5 = "/some-bus/c-test@5"; testfdt8 = "/a-test"; + eth0 = "/eth@10002000"; + eth5 = ð_5; };
uart0: serial { @@ -155,7 +157,7 @@ fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
- eth@10003000 { + eth_5: eth@10003000 { compatible = "sandbox,eth"; reg = <0x10003000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>;

Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
Allow network devices to be referred to as "eth0" instead of "eth@12345678" when specified in ethact.
Add tests to verify this behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org
Again a few comments on error handling for follow-up.
Changes in v4: -Use only the seq from DM to find aliases
Changes in v3: -Added support for aliases
Changes in v2: None
include/configs/sandbox.h | 2 +- include/net.h | 1 + net/eth.c | 47 ++++++++++++++++++++++++++++++++++++++--------- test/dm/eth.c | 24 ++++++++++++++++++++++++ test/dm/test.dts | 4 +++- 5 files changed, 67 insertions(+), 11 deletions(-)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 9189f6a..caf9f5a 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -174,7 +174,7 @@
#define SANDBOX_ETH_SETTINGS "ethaddr=00:00:11:22:33:44\0" \ "eth1addr=00:00:11:22:33:45\0" \
"eth2addr=00:00:11:22:33:46\0" \
"eth5addr=00:00:11:22:33:46\0" \ "ipaddr=1.2.3.4\0"
#define CONFIG_EXTRA_ENV_SETTINGS SANDBOX_SERIAL_SETTINGS \ diff --git a/include/net.h b/include/net.h index 508c572..e9cb4a3 100644 --- a/include/net.h +++ b/include/net.h @@ -122,6 +122,7 @@ struct eth_ops { #define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
struct udevice *eth_get_dev(void); /* get the current device */ +struct udevice *eth_get_dev_by_name(const char *devname);
This needs a comment to describe what devname is exactly. I thought it was a device name. Also it seems to requite a minimum length of 3 characters?
unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ /* Used only when NetConsole is enabled */ int eth_init_state_only(void); /* Set active state */ diff --git a/net/eth.c b/net/eth.c index 9c2dfb9..8b853e8 100644 --- a/net/eth.c +++ b/net/eth.c @@ -132,6 +132,36 @@ static void eth_set_dev(struct udevice *dev) eth_get_uclass_priv()->current = dev; }
+/*
- Find the udevice that either has the name passed in as devname or has an
- alias named devname.
- */
+struct udevice *eth_get_dev_by_name(const char *devname) +{
int seq;
char *endp = NULL;
const char *startp;
struct udevice *it;
struct uclass *uc;
startp = devname + strlen("eth");
seq = simple_strtoul(startp, &endp, 10);
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(it, uc) {
/* We need the seq to be valid, so make sure it's probed */
device_probe(it);
Error check. I think this function is should return an error.
/*
* Check for the name or the sequence number to match
*/
if (strcmp(it->name, devname) == 0 ||
(endp > startp && it->seq == seq))
return it;
}
return NULL;
+}
unsigned char *eth_get_ethaddr(void) { struct eth_pdata *pdata; @@ -405,6 +435,7 @@ UCLASS_DRIVER(eth) = { .pre_remove = eth_pre_remove, .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), .per_device_auto_alloc_size = sizeof(struct eth_device_priv),
.flags = DM_UC_FLAG_SEQ_ALIAS,
}; #endif
@@ -437,6 +468,11 @@ static void eth_set_current_to_next(void) eth_current = eth_current->next; }
+static void eth_set_dev(struct eth_device *dev) +{
eth_current = dev;
+}
struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -853,7 +889,6 @@ void eth_set_current(void) { static char *act; static int env_changed_id;
void *old_current; int env_id; env_id = get_env_id();
@@ -861,14 +896,8 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; }
if (act != NULL) {
old_current = eth_get_dev();
do {
if (strcmp(eth_get_name(), act) == 0)
return;
eth_set_current_to_next();
} while (old_current != eth_get_dev());
}
if (act != NULL)
eth_set_dev(eth_get_dev_by_name(act));
Again I think the error handling here is dodgy. You may have a device which fails to probe but it will not be reported here.
eth_current_changed();
} diff --git a/test/dm/eth.c b/test/dm/eth.c index 04ccf49..5688b71 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -36,3 +36,27 @@ static int dm_test_eth(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT);
+static int dm_test_eth_alias(struct dm_test_state *dms) +{
NetPingIP = string_to_ip("1.1.2.2");
setenv("ethact", "eth0");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10002000", getenv("ethact"));
setenv("ethact", "eth1");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10004000", getenv("ethact"));
/* Expected to fail since eth2 is not defined in the device tree */
setenv("ethact", "eth2");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10002000", getenv("ethact"));
setenv("ethact", "eth5");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10003000", getenv("ethact"));
Looks good to me.
return 0;
+} +DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 2f68cdf..bc2409d 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -17,6 +17,8 @@ testfdt3 = "/b-test"; testfdt5 = "/some-bus/c-test@5"; testfdt8 = "/a-test";
eth0 = "/eth@10002000";
eth5 = ð_5; }; uart0: serial {
@@ -155,7 +157,7 @@ fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
eth@10003000 {
eth_5: eth@10003000 { compatible = "sandbox,eth"; reg = <0x10003000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>;
-- 1.7.11.5
Regards, Simon

On Sun, Mar 1, 2015 at 12:07 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com
wrote:
Allow network devices to be referred to as "eth0" instead of "eth@12345678" when specified in ethact.
Add tests to verify this behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org
Again a few comments on error handling for follow-up.
Changes in v4: -Use only the seq from DM to find aliases
Changes in v3: -Added support for aliases
Changes in v2: None
include/configs/sandbox.h | 2 +- include/net.h | 1 + net/eth.c | 47
++++++++++++++++++++++++++++++++++++++---------
test/dm/eth.c | 24 ++++++++++++++++++++++++ test/dm/test.dts | 4 +++- 5 files changed, 67 insertions(+), 11 deletions(-)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 9189f6a..caf9f5a 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -174,7 +174,7 @@
#define SANDBOX_ETH_SETTINGS "ethaddr=00:00:11:22:33:44\0" \ "eth1addr=00:00:11:22:33:45\0" \
"eth2addr=00:00:11:22:33:46\0" \
"eth5addr=00:00:11:22:33:46\0" \ "ipaddr=1.2.3.4\0"
#define CONFIG_EXTRA_ENV_SETTINGS SANDBOX_SERIAL_SETTINGS \ diff --git a/include/net.h b/include/net.h index 508c572..e9cb4a3 100644 --- a/include/net.h +++ b/include/net.h @@ -122,6 +122,7 @@ struct eth_ops { #define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
struct udevice *eth_get_dev(void); /* get the current device */ +struct udevice *eth_get_dev_by_name(const char *devname);
This needs a comment to describe what devname is exactly. I thought it was a device name.
OK
Also it seems to requite a minimum length of 3 characters?
Good point. This is a bug. I should be checking the size first. It is not an intended requirement.
unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ /* Used only when NetConsole is enabled */ int eth_init_state_only(void); /* Set active state */ diff --git a/net/eth.c b/net/eth.c index 9c2dfb9..8b853e8 100644 --- a/net/eth.c +++ b/net/eth.c @@ -132,6 +132,36 @@ static void eth_set_dev(struct udevice *dev) eth_get_uclass_priv()->current = dev; }
+/*
- Find the udevice that either has the name passed in as devname or
has an
- alias named devname.
- */
+struct udevice *eth_get_dev_by_name(const char *devname) +{
int seq;
char *endp = NULL;
const char *startp;
struct udevice *it;
struct uclass *uc;
startp = devname + strlen("eth");
seq = simple_strtoul(startp, &endp, 10);
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(it, uc) {
/* We need the seq to be valid, so make sure it's
probed */
device_probe(it);
Error check. I think this function is should return an error.
This is simply searching. If a device annot be probed, why error out a search for presumably a different device? I can look into adding a unit test to validate this behavior.
/*
* Check for the name or the sequence number to match
*/
if (strcmp(it->name, devname) == 0 ||
(endp > startp && it->seq == seq))
return it;
}
return NULL;
+}
unsigned char *eth_get_ethaddr(void) { struct eth_pdata *pdata; @@ -405,6 +435,7 @@ UCLASS_DRIVER(eth) = { .pre_remove = eth_pre_remove, .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), .per_device_auto_alloc_size = sizeof(struct eth_device_priv),
.flags = DM_UC_FLAG_SEQ_ALIAS,
}; #endif
@@ -437,6 +468,11 @@ static void eth_set_current_to_next(void) eth_current = eth_current->next; }
+static void eth_set_dev(struct eth_device *dev) +{
eth_current = dev;
+}
struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -853,7 +889,6 @@ void eth_set_current(void) { static char *act; static int env_changed_id;
void *old_current; int env_id; env_id = get_env_id();
@@ -861,14 +896,8 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; }
if (act != NULL) {
old_current = eth_get_dev();
do {
if (strcmp(eth_get_name(), act) == 0)
return;
eth_set_current_to_next();
} while (old_current != eth_get_dev());
}
if (act != NULL)
eth_set_dev(eth_get_dev_by_name(act));
Again I think the error handling here is dodgy. You may have a device which fails to probe but it will not be reported here.
I'll think about how to make errors be reported when you explicitly ask for a device, but not when you are just scanning through them.
eth_current_changed();
} diff --git a/test/dm/eth.c b/test/dm/eth.c index 04ccf49..5688b71 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -36,3 +36,27 @@ static int dm_test_eth(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT);
+static int dm_test_eth_alias(struct dm_test_state *dms) +{
NetPingIP = string_to_ip("1.1.2.2");
setenv("ethact", "eth0");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10002000", getenv("ethact"));
setenv("ethact", "eth1");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10004000", getenv("ethact"));
/* Expected to fail since eth2 is not defined in the device
tree */
setenv("ethact", "eth2");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10002000", getenv("ethact"));
setenv("ethact", "eth5");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10003000", getenv("ethact"));
Looks good to me.
return 0;
+} +DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 2f68cdf..bc2409d 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -17,6 +17,8 @@ testfdt3 = "/b-test"; testfdt5 = "/some-bus/c-test@5"; testfdt8 = "/a-test";
eth0 = "/eth@10002000";
eth5 = ð_5; }; uart0: serial {
@@ -155,7 +157,7 @@ fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
eth@10003000 {
eth_5: eth@10003000 { compatible = "sandbox,eth"; reg = <0x10003000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>;
-- 1.7.11.5
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi Joe,
On 1 March 2015 at 15:04, Joe Hershberger joe.hershberger@gmail.com wrote:
On Sun, Mar 1, 2015 at 12:07 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
Allow network devices to be referred to as "eth0" instead of "eth@12345678" when specified in ethact.
Add tests to verify this behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org
Again a few comments on error handling for follow-up.
Changes in v4: -Use only the seq from DM to find aliases
Changes in v3: -Added support for aliases
Changes in v2: None
include/configs/sandbox.h | 2 +- include/net.h | 1 + net/eth.c | 47 ++++++++++++++++++++++++++++++++++++++--------- test/dm/eth.c | 24 ++++++++++++++++++++++++ test/dm/test.dts | 4 +++- 5 files changed, 67 insertions(+), 11 deletions(-)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 9189f6a..caf9f5a 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -174,7 +174,7 @@
#define SANDBOX_ETH_SETTINGS "ethaddr=00:00:11:22:33:44\0" \ "eth1addr=00:00:11:22:33:45\0" \
"eth2addr=00:00:11:22:33:46\0" \
"eth5addr=00:00:11:22:33:46\0" \ "ipaddr=1.2.3.4\0"
#define CONFIG_EXTRA_ENV_SETTINGS SANDBOX_SERIAL_SETTINGS \ diff --git a/include/net.h b/include/net.h index 508c572..e9cb4a3 100644 --- a/include/net.h +++ b/include/net.h @@ -122,6 +122,7 @@ struct eth_ops { #define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
struct udevice *eth_get_dev(void); /* get the current device */ +struct udevice *eth_get_dev_by_name(const char *devname);
This needs a comment to describe what devname is exactly. I thought it was a device name.
OK
Also it seems to requite a minimum length of 3 characters?
Good point. This is a bug. I should be checking the size first. It is not an intended requirement.
unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ /* Used only when NetConsole is enabled */ int eth_init_state_only(void); /* Set active state */ diff --git a/net/eth.c b/net/eth.c index 9c2dfb9..8b853e8 100644 --- a/net/eth.c +++ b/net/eth.c @@ -132,6 +132,36 @@ static void eth_set_dev(struct udevice *dev) eth_get_uclass_priv()->current = dev; }
+/*
- Find the udevice that either has the name passed in as devname or
has an
- alias named devname.
- */
+struct udevice *eth_get_dev_by_name(const char *devname) +{
int seq;
char *endp = NULL;
const char *startp;
struct udevice *it;
struct uclass *uc;
startp = devname + strlen("eth");
seq = simple_strtoul(startp, &endp, 10);
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(it, uc) {
/* We need the seq to be valid, so make sure it's probed
*/
device_probe(it);
Error check. I think this function is should return an error.
This is simply searching. If a device annot be probed, why error out a search for presumably a different device? I can look into adding a unit test to validate this behavior.
Well normal error behaviour is to report the error to the upper layers which may or may not stop.
But a failure to probe a device which should be there seems bad.
Anyway if you are wanting to not check these errors you should at least add big comments in those places as to why. I'd hate for people not to understand the rationale and just assume that errors don't matter (because they don't understand the special cases here).
/*
* Check for the name or the sequence number to match
*/
if (strcmp(it->name, devname) == 0 ||
(endp > startp && it->seq == seq))
return it;
}
return NULL;
+}
unsigned char *eth_get_ethaddr(void) { struct eth_pdata *pdata; @@ -405,6 +435,7 @@ UCLASS_DRIVER(eth) = { .pre_remove = eth_pre_remove, .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), .per_device_auto_alloc_size = sizeof(struct eth_device_priv),
.flags = DM_UC_FLAG_SEQ_ALIAS,
}; #endif
@@ -437,6 +468,11 @@ static void eth_set_current_to_next(void) eth_current = eth_current->next; }
+static void eth_set_dev(struct eth_device *dev) +{
eth_current = dev;
+}
struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -853,7 +889,6 @@ void eth_set_current(void) { static char *act; static int env_changed_id;
void *old_current; int env_id; env_id = get_env_id();
@@ -861,14 +896,8 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; }
if (act != NULL) {
old_current = eth_get_dev();
do {
if (strcmp(eth_get_name(), act) == 0)
return;
eth_set_current_to_next();
} while (old_current != eth_get_dev());
}
if (act != NULL)
eth_set_dev(eth_get_dev_by_name(act));
Again I think the error handling here is dodgy. You may have a device which fails to probe but it will not be reported here.
I'll think about how to make errors be reported when you explicitly ask for a device, but not when you are just scanning through them.
It's an interesting question, and fair enough - this is a design decision. But please comment it.
[snip]
Regards, Simon

The ethprime env var is used to indicate the starting device if none is specified in ethact. Also support aliases specified in the ethprime var.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v4: -Load from ethprime on eth_initialize()
Changes in v3: -Added support for ethprime
Changes in v2: None
net/eth.c | 29 ++++++++++++++++++++++++++++- test/dm/eth.c | 20 ++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/net/eth.c b/net/eth.c index 8b853e8..3b3cd84 100644 --- a/net/eth.c +++ b/net/eth.c @@ -341,6 +341,18 @@ int eth_initialize(void) printf("No ethernet found.\n"); bootstage_error(BOOTSTAGE_ID_NET_ETH_START); } else { + char *ethprime = getenv("ethprime"); + struct udevice *prime_dev = NULL; + + if (ethprime) + prime_dev = eth_get_dev_by_name(ethprime); + if (prime_dev) { + eth_set_dev(prime_dev); + eth_current_changed(); + } else { + eth_set_dev(NULL); + } + bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); do { if (num_devices) @@ -348,6 +360,9 @@ int eth_initialize(void)
printf("eth%d: %s", dev->seq, dev->name);
+ if (ethprime && dev == prime_dev) + printf(" [PRIME]"); + eth_write_hwaddr(dev);
uclass_next_device(&dev); @@ -896,8 +911,20 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; } - if (act != NULL) + + if (act == NULL) { + char *ethprime = getenv("ethprime"); + struct udevice *dev = NULL; + + if (ethprime) + dev = eth_get_dev_by_name(ethprime); + if (dev) + eth_set_dev(dev); + else + eth_set_dev(NULL); + } else { eth_set_dev(eth_get_dev_by_name(act)); + }
eth_current_changed(); } diff --git a/test/dm/eth.c b/test/dm/eth.c index 5688b71..96e3c46 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -60,3 +60,23 @@ static int dm_test_eth_alias(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT); + +static int dm_test_eth_prime(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + + /* Expected to be "eth@10003000" because of ethprime variable */ + setenv("ethact", NULL); + setenv("ethprime", "eth5"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10003000", getenv("ethact")); + + /* Expected to be "eth@10002000" because it is first */ + setenv("ethact", NULL); + setenv("ethprime", NULL); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + return 0; +} +DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT);

Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
The ethprime env var is used to indicate the starting device if none is specified in ethact. Also support aliases specified in the ethprime var.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v4: -Load from ethprime on eth_initialize()
Changes in v3: -Added support for ethprime
Changes in v2: None
net/eth.c | 29 ++++++++++++++++++++++++++++- test/dm/eth.c | 20 ++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/net/eth.c b/net/eth.c index 8b853e8..3b3cd84 100644 --- a/net/eth.c +++ b/net/eth.c @@ -341,6 +341,18 @@ int eth_initialize(void) printf("No ethernet found.\n"); bootstage_error(BOOTSTAGE_ID_NET_ETH_START); } else {
char *ethprime = getenv("ethprime");
struct udevice *prime_dev = NULL;
if (ethprime)
prime_dev = eth_get_dev_by_name(ethprime);
if (prime_dev) {
eth_set_dev(prime_dev);
eth_current_changed();
} else {
eth_set_dev(NULL);
}
bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); do { if (num_devices)
@@ -348,6 +360,9 @@ int eth_initialize(void)
printf("eth%d: %s", dev->seq, dev->name);
if (ethprime && dev == prime_dev)
printf(" [PRIME]");
eth_write_hwaddr(dev); uclass_next_device(&dev);
@@ -896,8 +911,20 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; }
if (act != NULL)
if (act == NULL) {
char *ethprime = getenv("ethprime");
struct udevice *dev = NULL;
if (ethprime)
dev = eth_get_dev_by_name(ethprime);
This function can return either a net_device or a udevice. So if DM_ETH is not enabled, you will get a warning here.
if (dev)
eth_set_dev(dev);
else
eth_set_dev(NULL);
} else { eth_set_dev(eth_get_dev_by_name(act));
} eth_current_changed();
} diff --git a/test/dm/eth.c b/test/dm/eth.c index 5688b71..96e3c46 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -60,3 +60,23 @@ static int dm_test_eth_alias(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT);
+static int dm_test_eth_prime(struct dm_test_state *dms) +{
NetPingIP = string_to_ip("1.1.2.2");
/* Expected to be "eth@10003000" because of ethprime variable */
setenv("ethact", NULL);
setenv("ethprime", "eth5");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10003000", getenv("ethact"));
/* Expected to be "eth@10002000" because it is first */
setenv("ethact", NULL);
setenv("ethprime", NULL);
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10002000", getenv("ethact"));
return 0;
+}
+DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT);
1.7.11.5
Regards, Simon

On Sun, Mar 1, 2015 at 12:07 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com
wrote:
The ethprime env var is used to indicate the starting device if none is specified in ethact. Also support aliases specified in the ethprime var.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v4: -Load from ethprime on eth_initialize()
Changes in v3: -Added support for ethprime
Changes in v2: None
net/eth.c | 29 ++++++++++++++++++++++++++++- test/dm/eth.c | 20 ++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/net/eth.c b/net/eth.c index 8b853e8..3b3cd84 100644 --- a/net/eth.c +++ b/net/eth.c @@ -341,6 +341,18 @@ int eth_initialize(void) printf("No ethernet found.\n"); bootstage_error(BOOTSTAGE_ID_NET_ETH_START); } else {
char *ethprime = getenv("ethprime");
struct udevice *prime_dev = NULL;
if (ethprime)
prime_dev = eth_get_dev_by_name(ethprime);
if (prime_dev) {
eth_set_dev(prime_dev);
eth_current_changed();
} else {
eth_set_dev(NULL);
}
bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); do { if (num_devices)
@@ -348,6 +360,9 @@ int eth_initialize(void)
printf("eth%d: %s", dev->seq, dev->name);
if (ethprime && dev == prime_dev)
printf(" [PRIME]");
eth_write_hwaddr(dev); uclass_next_device(&dev);
@@ -896,8 +911,20 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; }
if (act != NULL)
if (act == NULL) {
char *ethprime = getenv("ethprime");
struct udevice *dev = NULL;
if (ethprime)
dev = eth_get_dev_by_name(ethprime);
This function can return either a net_device or a udevice. So if DM_ETH is not enabled, you will get a warning here.
Yes, my apologies.I didn't notice this regression until right after I posted the series. It is fixed in my branch.
if (dev)
eth_set_dev(dev);
else
eth_set_dev(NULL);
} else { eth_set_dev(eth_get_dev_by_name(act));
} eth_current_changed();
} diff --git a/test/dm/eth.c b/test/dm/eth.c index 5688b71..96e3c46 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -60,3 +60,23 @@ static int dm_test_eth_alias(struct dm_test_state
*dms)
return 0;
} DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT);
+static int dm_test_eth_prime(struct dm_test_state *dms) +{
NetPingIP = string_to_ip("1.1.2.2");
/* Expected to be "eth@10003000" because of ethprime variable */
setenv("ethact", NULL);
setenv("ethprime", "eth5");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10003000", getenv("ethact"));
/* Expected to be "eth@10002000" because it is first */
setenv("ethact", NULL);
setenv("ethprime", NULL);
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10002000", getenv("ethact"));
return 0;
+}
+DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT);
1.7.11.5
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Make sure that the ethrotate behavior occurs as expected.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v4: -Added testing for ethrotate
Changes in v3: None Changes in v2: None
test/dm/eth.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/test/dm/eth.c b/test/dm/eth.c index 96e3c46..a3cbd3f 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -80,3 +80,27 @@ static int dm_test_eth_prime(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT); + +static int dm_test_eth_rotate(struct dm_test_state *dms) +{ + char ethaddr[18]; + + NetPingIP = string_to_ip("1.1.2.2"); + strcpy(ethaddr, getenv("eth1addr")); + setenv("ethact", "eth@10004000"); + setenv("eth1addr", NULL); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth@10004000"); + setenv("ethrotate", "no"); + ut_asserteq(-1, NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Restore the env */ + setenv("eth1addr", ethaddr); + setenv("ethrotate", NULL); + + return 0; +} +DM_TEST(dm_test_eth_rotate, DM_TESTF_SCAN_FDT);

On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
Make sure that the ethrotate behavior occurs as expected.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org

This is needed to test the netretry functionality (make the command fail on a sandbox eth device).
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v4: -Add ability to disable ping reply in sandbox eth driver
Changes in v3: None Changes in v2: None
drivers/net/sandbox.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 81362e6..28fe09a 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -49,9 +49,14 @@ 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; + char varname[32];
debug("eth_sandbox: Send packet %d\n", length);
+ sprintf(varname, "eth_sandbox_disable_%d", dev->seq); + if (getenv_yesno(varname) > 0) + return 0; + if (ntohs(eth->et_protlen) == PROT_ARP) { struct arp_hdr *arp = packet + ETHER_HDR_SIZE;

Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
This is needed to test the netretry functionality (make the command fail on a sandbox eth device).
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Rather than using environment variables to communicate, you should use a function call into this code. See arch/sandbox/include/asm/test.h.
Or you can create a state function and update the state (see state.h) if you want it to affect more than one driver.
Changes in v4: -Add ability to disable ping reply in sandbox eth driver
Changes in v3: None Changes in v2: None
drivers/net/sandbox.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 81362e6..28fe09a 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -49,9 +49,14 @@ 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;
char varname[32]; debug("eth_sandbox: Send packet %d\n", length);
sprintf(varname, "eth_sandbox_disable_%d", dev->seq);
if (getenv_yesno(varname) > 0)
return 0;
if (ntohs(eth->et_protlen) == PROT_ARP) { struct arp_hdr *arp = packet + ETHER_HDR_SIZE;
-- 1.7.11.5
Regards, Simon

The effect of the "netretry" env var was recently changed. This test checks that behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v4: -Updated expected behavior based on changes to the NetLoop
Changes in v3: -Added testing for netretry
Changes in v2: None
test/dm/eth.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
diff --git a/test/dm/eth.c b/test/dm/eth.c index a3cbd3f..4581c8e 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -104,3 +104,26 @@ static int dm_test_eth_rotate(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth_rotate, DM_TESTF_SCAN_FDT); + +static int dm_test_net_retry(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + + setenv("eth_sandbox_disable_1", "yes"); + setenv("ethact", "eth@10004000"); + setenv("netretry", "yes"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth@10004000"); + setenv("netretry", "no"); + ut_asserteq(-1, NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Restore the env */ + setenv("netretry", NULL); + setenv("eth_sandbox_disable_1", NULL); + + return 0; +} +DM_TEST(dm_test_net_retry, DM_TESTF_SCAN_FDT);

Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
The effect of the "netretry" env var was recently changed. This test checks that behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v4: -Updated expected behavior based on changes to the NetLoop
Changes in v3: -Added testing for netretry
Changes in v2: None
test/dm/eth.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
diff --git a/test/dm/eth.c b/test/dm/eth.c index a3cbd3f..4581c8e 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -104,3 +104,26 @@ static int dm_test_eth_rotate(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth_rotate, DM_TESTF_SCAN_FDT);
+static int dm_test_net_retry(struct dm_test_state *dms) +{
NetPingIP = string_to_ip("1.1.2.2");
setenv("eth_sandbox_disable_1", "yes");
As mentioned in the other patch, something like:
sandbox_eth_set_disable(1, true);
setenv("ethact", "eth@10004000");
setenv("netretry", "yes");
ut_assertok(NetLoop(PING));
ut_asserteq_str("eth@10002000", getenv("ethact"));
A comment against each test case as to why it works or doesn't would help.
setenv("ethact", "eth@10004000");
setenv("netretry", "no");
ut_asserteq(-1, NetLoop(PING));
One day it would be nice if this could return an error code from errno.h.
ut_asserteq_str("eth@10004000", getenv("ethact"));
/* Restore the env */
setenv("netretry", NULL);
setenv("eth_sandbox_disable_1", NULL);
sandbox_eth_set_disable(1, false);
return 0;
+}
+DM_TEST(dm_test_net_retry, DM_TESTF_SCAN_FDT);
1.7.11.5
Regards, Simon

Implement a bridge between u-boot's network stack and Linux's raw packet API allowing the sandbox to send and receive packets using the host machine's network interface.
This raw Ethernet API requires elevated privileges. You can either run as root, or you can add the capability needed like so:
sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v4: -Added comments to README.sandbox -Use accessors for platdata and priv -Add comments to priv struct definition -Move os file to arch -Cleanup var definition order -Moved config to Kconfig -Clean up the interface to sandbox's eth-raw-os by passing priv to raw-os -Fixed the MAC address limitation (now all traffic uses MAC address from env)
Changes in v3: -Made the os raw packet support for sandbox eth build and work.
Changes in v2: -Added the raw packet proof-of-concept patch.
arch/sandbox/Kconfig | 3 + arch/sandbox/cpu/Makefile | 10 ++++ arch/sandbox/cpu/eth-raw-os.c | 102 +++++++++++++++++++++++++++++++++ arch/sandbox/dts/sandbox.dts | 6 ++ arch/sandbox/include/asm/eth-raw-os.h | 32 +++++++++++ board/sandbox/README.sandbox | 13 +++++ drivers/net/Kconfig | 5 ++ drivers/net/Makefile | 1 + drivers/net/sandbox-raw.c | 105 ++++++++++++++++++++++++++++++++++ 9 files changed, 277 insertions(+) create mode 100644 arch/sandbox/cpu/eth-raw-os.c create mode 100644 arch/sandbox/include/asm/eth-raw-os.h create mode 100644 drivers/net/sandbox-raw.c
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index 186b58d..f84b3fc 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -43,4 +43,7 @@ config NETDEVICES config DM_ETH default y
+config ETH_SANDBOX_RAW + default y + endmenu diff --git a/arch/sandbox/cpu/Makefile b/arch/sandbox/cpu/Makefile index 7d4410c..1b42fee 100644 --- a/arch/sandbox/cpu/Makefile +++ b/arch/sandbox/cpu/Makefile @@ -8,6 +8,7 @@ #
obj-y := cpu.o os.o start.o state.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += eth-raw-os.o obj-$(CONFIG_SANDBOX_SDL) += sdl.o
# os.c is build in the system environment, so needs standard includes @@ -20,3 +21,12 @@ $(obj)/os.o: $(src)/os.c FORCE $(call if_changed_dep,cc_os.o) $(obj)/sdl.o: $(src)/sdl.c FORCE $(call if_changed_dep,cc_os.o) + +# eth-raw-os.c is built in the system env, so needs standard includes +# CFLAGS_REMOVE_eth-raw-os.o cannot be used to drop header include path +quiet_cmd_cc_eth-raw-os.o = CC $(quiet_modtag) $@ +cmd_cc_eth-raw-os.o = $(CC) $(filter-out -nostdinc, \ + $(patsubst -I%,-idirafter%,$(c_flags))) -c -o $@ $< + +$(obj)/eth-raw-os.o: $(src)/eth-raw-os.c FORCE + $(call if_changed_dep,cc_eth-raw-os.o) diff --git a/arch/sandbox/cpu/eth-raw-os.c b/arch/sandbox/cpu/eth-raw-os.c new file mode 100644 index 0000000..9218f94 --- /dev/null +++ b/arch/sandbox/cpu/eth-raw-os.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <asm/eth-raw-os.h> +#include <errno.h> +#include <net/if.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <linux/if_ether.h> +#include <linux/if_packet.h> + +int sandbox_eth_raw_os_init(const char *ifname, unsigned char *ethmac, + struct eth_sandbox_raw_priv *priv) +{ + struct sockaddr_ll *device; + struct packet_mreq mr; + + /* Prepare device struct */ + priv->device = malloc(sizeof(struct sockaddr_ll)); + device = priv->device; + memset(device, 0, sizeof(struct sockaddr_ll)); + device->sll_ifindex = if_nametoindex(ifname); + device->sll_family = AF_PACKET; + memcpy(device->sll_addr, ethmac, 6); + device->sll_halen = htons(6); + + /* Open socket */ + priv->sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (priv->sd < 0) { + printf("Failed to open socket: %d %s\n", errno, + strerror(errno)); + return -errno; + } + /* Bind to the specified interface */ + setsockopt(priv->sd, SOL_SOCKET, SO_BINDTODEVICE, ifname, + strlen(ifname) + 1); + + /* Enable promiscuous mode to receive responses meant for us */ + mr.mr_ifindex = device->sll_ifindex; + mr.mr_type = PACKET_MR_PROMISC; + setsockopt(priv->sd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, + &mr, sizeof(mr)); + return 0; +} + +int sandbox_eth_raw_os_send(void *packet, int length, + const struct eth_sandbox_raw_priv *priv) +{ + int retval; + + if (!priv->sd || !priv->device) + return -EINVAL; + + retval = sendto(priv->sd, packet, length, 0, + (struct sockaddr *)priv->device, + sizeof(struct sockaddr_ll)); + if (retval < 0) + printf("Failed to send packet: %d %s\n", errno, + strerror(errno)); + return retval; +} + +int sandbox_eth_raw_os_recv(void *packet, int *length, + const struct eth_sandbox_raw_priv *priv) +{ + int retval; + int saddr_size; + + if (!priv->sd || !priv->device) + return -EINVAL; + saddr_size = sizeof(struct sockaddr); + retval = recvfrom(priv->sd, packet, 1536, 0, + (struct sockaddr *)priv->device, + (socklen_t *)&saddr_size); + *length = 0; + if (retval > 0) { + *length = retval; + return 0; + } + return retval; +} + +void sandbox_eth_raw_os_halt(struct eth_sandbox_raw_priv *priv) +{ + free((struct sockaddr_ll *)priv->device); + priv->device = NULL; + close(priv->sd); + priv->sd = -1; +} diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 235dcc0..b6762f4 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -186,4 +186,10 @@ reg = <0x10002000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; }; + + eth@80000000 { + compatible = "sandbox,eth-raw"; + reg = <0x80000000 0x1000>; + host-raw-interface = "eth0"; + }; }; diff --git a/arch/sandbox/include/asm/eth-raw-os.h b/arch/sandbox/include/asm/eth-raw-os.h new file mode 100644 index 0000000..d92b72c --- /dev/null +++ b/arch/sandbox/include/asm/eth-raw-os.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __ETH_RAW_OS_H +#define __ETH_RAW_OS_H + +/** + * struct eth_sandbox_raw_priv - raw socket session + * + * sd: socket descriptor - the open socket during a session + * device: struct sockaddr_ll - the host interface packets move to/from + */ +struct eth_sandbox_raw_priv { + int sd; + void *device; +}; + +int sandbox_eth_raw_os_init(const char *ifname, unsigned char *ethmac, + struct eth_sandbox_raw_priv *priv); +int sandbox_eth_raw_os_send(void *packet, int length, + const struct eth_sandbox_raw_priv *priv); +int sandbox_eth_raw_os_recv(void *packet, int *length, + const struct eth_sandbox_raw_priv *priv); +void sandbox_eth_raw_os_halt(struct eth_sandbox_raw_priv *priv); + +#endif /* __ETH_RAW_OS_H */ diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox index c1f5f7e..c4c3139 100644 --- a/board/sandbox/README.sandbox +++ b/board/sandbox/README.sandbox @@ -190,6 +190,19 @@ Also sandbox uses generic board (CONFIG_SYS_GENERIC_BOARD) and supports driver model (CONFIG_DM) and associated commands.
+Linux RAW Networking Bridge +--------------------------- + +The sandbox_eth_raw driver bridges traffic between the bottom of the network +stack and the RAW sockets API in Linux. This allows much of the u-boot network +functionality to be tested in sandbox against real network traffic. + +The RAW sockets Ethernet API requires elevated privileges in Linux. You can +either run as root, or you can add the capability needed like so: + +sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot + + SPI Emulation -------------
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index b08746a..dcbfa8a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -20,4 +20,9 @@ config ETH_SANDBOX default y bool "Sandbox: Mocked Ethernet driver"
+config ETH_SANDBOX_RAW + depends on DM_ETH && SANDBOX + default y + bool "Sandbox: Bridge to Linux Raw Sockets" + endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 15dc431..2659a8a 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o obj-$(CONFIG_ETH_SANDBOX) += sandbox.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c new file mode 100644 index 0000000..01b33a9 --- /dev/null +++ b/drivers/net/sandbox-raw.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <asm/eth-raw-os.h> +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + + +static int sb_eth_raw_start(struct udevice *dev) +{ + struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + int retval; + const char *interface; + + debug("eth_sandbox_raw: Start\n"); + + interface = fdt_getprop(gd->fdt_blob, dev->of_offset, + "host-raw-interface", NULL); + + retval = sandbox_eth_raw_os_init(interface, pdata->enetaddr, priv); + + return retval; +} + +static int sb_eth_raw_send(struct udevice *dev, void *packet, int length) +{ + struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); + + debug("eth_sandbox_raw: Send packet %d\n", length); + + return sandbox_eth_raw_os_send(packet, length, priv); +} + +static int sb_eth_raw_recv(struct udevice *dev) +{ + struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); + int retval; + uchar buffer[PKTSIZE]; + int length; + + retval = sandbox_eth_raw_os_recv(buffer, &length, priv); + + if (!retval && length) { + debug("eth_sandbox_raw: received packet %d\n", + length); + NetReceive(buffer, length); + } + return 0; +} + +static void sb_eth_raw_stop(struct udevice *dev) +{ + struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); + + debug("eth_sandbox_raw: Stop\n"); + + sandbox_eth_raw_os_halt(priv); +} + +static const struct eth_ops sb_eth_raw_ops = { + .start = sb_eth_raw_start, + .send = sb_eth_raw_send, + .recv = sb_eth_raw_recv, + .stop = sb_eth_raw_stop, +}; + +static int sb_eth_raw_remove(struct udevice *dev) +{ + return 0; +} + +static int sb_eth_raw_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + + pdata->iobase = dev_get_addr(dev); + return 0; +} + +static const struct udevice_id sb_eth_raw_ids[] = { + { .compatible = "sandbox,eth-raw" }, + { } +}; + +U_BOOT_DRIVER(eth_sandbox_raw) = { + .name = "eth_sandbox_raw", + .id = UCLASS_ETH, + .of_match = sb_eth_raw_ids, + .ofdata_to_platdata = sb_eth_raw_ofdata_to_platdata, + .remove = sb_eth_raw_remove, + .ops = &sb_eth_raw_ops, + .priv_auto_alloc_size = sizeof(struct eth_sandbox_raw_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +};

On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
Implement a bridge between u-boot's network stack and Linux's raw packet API allowing the sandbox to send and receive packets using the host machine's network interface.
This raw Ethernet API requires elevated privileges. You can either run as root, or you can add the capability needed like so:
sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org
A few nits below.
Changes in v4: -Added comments to README.sandbox -Use accessors for platdata and priv -Add comments to priv struct definition -Move os file to arch -Cleanup var definition order -Moved config to Kconfig -Clean up the interface to sandbox's eth-raw-os by passing priv to raw-os -Fixed the MAC address limitation (now all traffic uses MAC address from env)
Changes in v3: -Made the os raw packet support for sandbox eth build and work.
Changes in v2: -Added the raw packet proof-of-concept patch.
arch/sandbox/Kconfig | 3 + arch/sandbox/cpu/Makefile | 10 ++++ arch/sandbox/cpu/eth-raw-os.c | 102 +++++++++++++++++++++++++++++++++ arch/sandbox/dts/sandbox.dts | 6 ++ arch/sandbox/include/asm/eth-raw-os.h | 32 +++++++++++ board/sandbox/README.sandbox | 13 +++++ drivers/net/Kconfig | 5 ++ drivers/net/Makefile | 1 + drivers/net/sandbox-raw.c | 105 ++++++++++++++++++++++++++++++++++ 9 files changed, 277 insertions(+) create mode 100644 arch/sandbox/cpu/eth-raw-os.c create mode 100644 arch/sandbox/include/asm/eth-raw-os.h create mode 100644 drivers/net/sandbox-raw.c
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index 186b58d..f84b3fc 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -43,4 +43,7 @@ config NETDEVICES config DM_ETH default y
+config ETH_SANDBOX_RAW
default y
endmenu diff --git a/arch/sandbox/cpu/Makefile b/arch/sandbox/cpu/Makefile index 7d4410c..1b42fee 100644 --- a/arch/sandbox/cpu/Makefile +++ b/arch/sandbox/cpu/Makefile @@ -8,6 +8,7 @@ #
obj-y := cpu.o os.o start.o state.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += eth-raw-os.o obj-$(CONFIG_SANDBOX_SDL) += sdl.o
# os.c is build in the system environment, so needs standard includes @@ -20,3 +21,12 @@ $(obj)/os.o: $(src)/os.c FORCE $(call if_changed_dep,cc_os.o) $(obj)/sdl.o: $(src)/sdl.c FORCE $(call if_changed_dep,cc_os.o)
+# eth-raw-os.c is built in the system env, so needs standard includes +# CFLAGS_REMOVE_eth-raw-os.o cannot be used to drop header include path +quiet_cmd_cc_eth-raw-os.o = CC $(quiet_modtag) $@ +cmd_cc_eth-raw-os.o = $(CC) $(filter-out -nostdinc, \
$(patsubst -I%,-idirafter%,$(c_flags))) -c -o $@ $<
+$(obj)/eth-raw-os.o: $(src)/eth-raw-os.c FORCE
$(call if_changed_dep,cc_eth-raw-os.o)
diff --git a/arch/sandbox/cpu/eth-raw-os.c b/arch/sandbox/cpu/eth-raw-os.c new file mode 100644 index 0000000..9218f94 --- /dev/null +++ b/arch/sandbox/cpu/eth-raw-os.c @@ -0,0 +1,102 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0
- */
+#include <asm/eth-raw-os.h> +#include <errno.h> +#include <net/if.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <unistd.h>
+#include <linux/if_ether.h> +#include <linux/if_packet.h>
+int sandbox_eth_raw_os_init(const char *ifname, unsigned char *ethmac,
struct eth_sandbox_raw_priv *priv)
+{
struct sockaddr_ll *device;
struct packet_mreq mr;
/* Prepare device struct */
priv->device = malloc(sizeof(struct sockaddr_ll));
This calls U-Boot's malloc() and it can return NULL, so you should return -ENOMEM in that case.
device = priv->device;
memset(device, 0, sizeof(struct sockaddr_ll));
device->sll_ifindex = if_nametoindex(ifname);
device->sll_family = AF_PACKET;
memcpy(device->sll_addr, ethmac, 6);
device->sll_halen = htons(6);
/* Open socket */
priv->sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (priv->sd < 0) {
printf("Failed to open socket: %d %s\n", errno,
strerror(errno));
return -errno;
}
/* Bind to the specified interface */
setsockopt(priv->sd, SOL_SOCKET, SO_BINDTODEVICE, ifname,
strlen(ifname) + 1);
/* Enable promiscuous mode to receive responses meant for us */
mr.mr_ifindex = device->sll_ifindex;
mr.mr_type = PACKET_MR_PROMISC;
setsockopt(priv->sd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
&mr, sizeof(mr));
return 0;
+}
+int sandbox_eth_raw_os_send(void *packet, int length,
const struct eth_sandbox_raw_priv *priv)
+{
int retval;
if (!priv->sd || !priv->device)
return -EINVAL;
retval = sendto(priv->sd, packet, length, 0,
(struct sockaddr *)priv->device,
sizeof(struct sockaddr_ll));
if (retval < 0)
printf("Failed to send packet: %d %s\n", errno,
strerror(errno));
return -errno here?
return retval;
+}
+int sandbox_eth_raw_os_recv(void *packet, int *length,
const struct eth_sandbox_raw_priv *priv)
+{
int retval;
int saddr_size;
if (!priv->sd || !priv->device)
return -EINVAL;
saddr_size = sizeof(struct sockaddr);
retval = recvfrom(priv->sd, packet, 1536, 0,
(struct sockaddr *)priv->device,
(socklen_t *)&saddr_size);
*length = 0;
if (retval > 0) {
*length = retval;
return 0;
}
return retval;
return -errno here? At present you are returning -1 I think, which is -EPERM.
+}
+void sandbox_eth_raw_os_halt(struct eth_sandbox_raw_priv *priv) +{
free((struct sockaddr_ll *)priv->device);
Don't need that cast?
priv->device = NULL;
close(priv->sd);
priv->sd = -1;
+} diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 235dcc0..b6762f4 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -186,4 +186,10 @@ reg = <0x10002000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
eth@80000000 {
compatible = "sandbox,eth-raw";
reg = <0x80000000 0x1000>;
host-raw-interface = "eth0";
};
}; diff --git a/arch/sandbox/include/asm/eth-raw-os.h b/arch/sandbox/include/asm/eth-raw-os.h new file mode 100644 index 0000000..d92b72c --- /dev/null +++ b/arch/sandbox/include/asm/eth-raw-os.h @@ -0,0 +1,32 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0
- */
+#ifndef __ETH_RAW_OS_H +#define __ETH_RAW_OS_H
+/**
- struct eth_sandbox_raw_priv - raw socket session
- sd: socket descriptor - the open socket during a session
- device: struct sockaddr_ll - the host interface packets move to/from
- */
+struct eth_sandbox_raw_priv {
int sd;
void *device;
+};
+int sandbox_eth_raw_os_init(const char *ifname, unsigned char *ethmac,
struct eth_sandbox_raw_priv *priv);
+int sandbox_eth_raw_os_send(void *packet, int length,
const struct eth_sandbox_raw_priv *priv);
+int sandbox_eth_raw_os_recv(void *packet, int *length,
const struct eth_sandbox_raw_priv *priv);
+void sandbox_eth_raw_os_halt(struct eth_sandbox_raw_priv *priv);
+#endif /* __ETH_RAW_OS_H */ diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox index c1f5f7e..c4c3139 100644 --- a/board/sandbox/README.sandbox +++ b/board/sandbox/README.sandbox @@ -190,6 +190,19 @@ Also sandbox uses generic board (CONFIG_SYS_GENERIC_BOARD) and supports driver model (CONFIG_DM) and associated commands.
+Linux RAW Networking Bridge +---------------------------
+The sandbox_eth_raw driver bridges traffic between the bottom of the network +stack and the RAW sockets API in Linux. This allows much of the u-boot network +functionality to be tested in sandbox against real network traffic.
+The RAW sockets Ethernet API requires elevated privileges in Linux. You can +either run as root, or you can add the capability needed like so:
+sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
This is so cool.
Can you give some examples here? For me, ping seems to work, but I can't use bootp. Is that what the raw mode is for? How do I enable it? I tried setting ethact but am not sure what I am doing.
Useful examples would be:
- ping - bootp - tftpboot
and how to use raw/normal device.
SPI Emulation
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index b08746a..dcbfa8a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -20,4 +20,9 @@ config ETH_SANDBOX default y bool "Sandbox: Mocked Ethernet driver"
+config ETH_SANDBOX_RAW
depends on DM_ETH && SANDBOX
default y
bool "Sandbox: Bridge to Linux Raw Sockets"
This needs some help.
endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 15dc431..2659a8a 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o obj-$(CONFIG_ETH_SANDBOX) += sandbox.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c new file mode 100644 index 0000000..01b33a9 --- /dev/null +++ b/drivers/net/sandbox-raw.c @@ -0,0 +1,105 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0
- */
+#include <asm/eth-raw-os.h> +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <net.h>
+DECLARE_GLOBAL_DATA_PTR;
+static int sb_eth_raw_start(struct udevice *dev) +{
struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
struct eth_pdata *pdata = dev_get_platdata(dev);
int retval;
const char *interface;
debug("eth_sandbox_raw: Start\n");
interface = fdt_getprop(gd->fdt_blob, dev->of_offset,
"host-raw-interface", NULL);
This can return NULL, so you should return -EINVAL in that case.
retval = sandbox_eth_raw_os_init(interface, pdata->enetaddr, priv);
return retval;
+}
+static int sb_eth_raw_send(struct udevice *dev, void *packet, int length) +{
struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
debug("eth_sandbox_raw: Send packet %d\n", length);
return sandbox_eth_raw_os_send(packet, length, priv);
+}
+static int sb_eth_raw_recv(struct udevice *dev) +{
struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
int retval;
uchar buffer[PKTSIZE];
int length;
retval = sandbox_eth_raw_os_recv(buffer, &length, priv);
if (!retval && length) {
debug("eth_sandbox_raw: received packet %d\n",
length);
NetReceive(buffer, length);
}
return 0;
+}
+static void sb_eth_raw_stop(struct udevice *dev) +{
struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
debug("eth_sandbox_raw: Stop\n");
sandbox_eth_raw_os_halt(priv);
+}
+static const struct eth_ops sb_eth_raw_ops = {
.start = sb_eth_raw_start,
.send = sb_eth_raw_send,
.recv = sb_eth_raw_recv,
.stop = sb_eth_raw_stop,
+};
+static int sb_eth_raw_remove(struct udevice *dev) +{
return 0;
+}
You can drop this function.
+static int sb_eth_raw_ofdata_to_platdata(struct udevice *dev) +{
struct eth_pdata *pdata = dev_get_platdata(dev);
pdata->iobase = dev_get_addr(dev);
return 0;
+}
+static const struct udevice_id sb_eth_raw_ids[] = {
{ .compatible = "sandbox,eth-raw" },
{ }
+};
+U_BOOT_DRIVER(eth_sandbox_raw) = {
.name = "eth_sandbox_raw",
.id = UCLASS_ETH,
.of_match = sb_eth_raw_ids,
.ofdata_to_platdata = sb_eth_raw_ofdata_to_platdata,
.remove = sb_eth_raw_remove,
.ops = &sb_eth_raw_ops,
.priv_auto_alloc_size = sizeof(struct eth_sandbox_raw_priv),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
1.7.11.5
Regards, Simon

On Sun, Mar 1, 2015 at 12:07 PM, Simon Glass sjg@chromium.org wrote:
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com
wrote:
Implement a bridge between u-boot's network stack and Linux's raw packet API allowing the sandbox to send and receive packets using the host machine's network interface.
This raw Ethernet API requires elevated privileges. You can either run as root, or you can add the capability needed like so:
sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org
A few nits below.
Changes in v4: -Added comments to README.sandbox -Use accessors for platdata and priv -Add comments to priv struct definition -Move os file to arch -Cleanup var definition order -Moved config to Kconfig -Clean up the interface to sandbox's eth-raw-os by passing priv to
raw-os
-Fixed the MAC address limitation (now all traffic uses MAC address
from env)
Changes in v3: -Made the os raw packet support for sandbox eth build and work.
Changes in v2: -Added the raw packet proof-of-concept patch.
arch/sandbox/Kconfig | 3 + arch/sandbox/cpu/Makefile | 10 ++++ arch/sandbox/cpu/eth-raw-os.c | 102
+++++++++++++++++++++++++++++++++
arch/sandbox/dts/sandbox.dts | 6 ++ arch/sandbox/include/asm/eth-raw-os.h | 32 +++++++++++ board/sandbox/README.sandbox | 13 +++++ drivers/net/Kconfig | 5 ++ drivers/net/Makefile | 1 + drivers/net/sandbox-raw.c | 105
++++++++++++++++++++++++++++++++++
9 files changed, 277 insertions(+) create mode 100644 arch/sandbox/cpu/eth-raw-os.c create mode 100644 arch/sandbox/include/asm/eth-raw-os.h create mode 100644 drivers/net/sandbox-raw.c
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index 186b58d..f84b3fc 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -43,4 +43,7 @@ config NETDEVICES config DM_ETH default y
+config ETH_SANDBOX_RAW
default y
endmenu diff --git a/arch/sandbox/cpu/Makefile b/arch/sandbox/cpu/Makefile index 7d4410c..1b42fee 100644 --- a/arch/sandbox/cpu/Makefile +++ b/arch/sandbox/cpu/Makefile @@ -8,6 +8,7 @@ #
obj-y := cpu.o os.o start.o state.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += eth-raw-os.o obj-$(CONFIG_SANDBOX_SDL) += sdl.o
# os.c is build in the system environment, so needs standard includes @@ -20,3 +21,12 @@ $(obj)/os.o: $(src)/os.c FORCE $(call if_changed_dep,cc_os.o) $(obj)/sdl.o: $(src)/sdl.c FORCE $(call if_changed_dep,cc_os.o)
+# eth-raw-os.c is built in the system env, so needs standard includes +# CFLAGS_REMOVE_eth-raw-os.o cannot be used to drop header include path +quiet_cmd_cc_eth-raw-os.o = CC $(quiet_modtag) $@ +cmd_cc_eth-raw-os.o = $(CC) $(filter-out -nostdinc, \
$(patsubst -I%,-idirafter%,$(c_flags))) -c -o $@ lt;
+$(obj)/eth-raw-os.o: $(src)/eth-raw-os.c FORCE
$(call if_changed_dep,cc_eth-raw-os.o)
diff --git a/arch/sandbox/cpu/eth-raw-os.c
b/arch/sandbox/cpu/eth-raw-os.c
new file mode 100644 index 0000000..9218f94 --- /dev/null +++ b/arch/sandbox/cpu/eth-raw-os.c @@ -0,0 +1,102 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0
- */
+#include <asm/eth-raw-os.h> +#include <errno.h> +#include <net/if.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <unistd.h>
+#include <linux/if_ether.h> +#include <linux/if_packet.h>
+int sandbox_eth_raw_os_init(const char *ifname, unsigned char *ethmac,
struct eth_sandbox_raw_priv *priv)
+{
struct sockaddr_ll *device;
struct packet_mreq mr;
/* Prepare device struct */
priv->device = malloc(sizeof(struct sockaddr_ll));
This calls U-Boot's malloc() and it can return NULL, so you should return -ENOMEM in that case.
OK
device = priv->device;
memset(device, 0, sizeof(struct sockaddr_ll));
device->sll_ifindex = if_nametoindex(ifname);
device->sll_family = AF_PACKET;
memcpy(device->sll_addr, ethmac, 6);
device->sll_halen = htons(6);
/* Open socket */
priv->sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (priv->sd < 0) {
printf("Failed to open socket: %d %s\n", errno,
strerror(errno));
return -errno;
}
/* Bind to the specified interface */
setsockopt(priv->sd, SOL_SOCKET, SO_BINDTODEVICE, ifname,
strlen(ifname) + 1);
/* Enable promiscuous mode to receive responses meant for us */
mr.mr_ifindex = device->sll_ifindex;
mr.mr_type = PACKET_MR_PROMISC;
setsockopt(priv->sd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
&mr, sizeof(mr));
return 0;
+}
+int sandbox_eth_raw_os_send(void *packet, int length,
const struct eth_sandbox_raw_priv *priv)
+{
int retval;
if (!priv->sd || !priv->device)
return -EINVAL;
retval = sendto(priv->sd, packet, length, 0,
(struct sockaddr *)priv->device,
sizeof(struct sockaddr_ll));
if (retval < 0)
printf("Failed to send packet: %d %s\n", errno,
strerror(errno));
return -errno here?
OK
return retval;
+}
+int sandbox_eth_raw_os_recv(void *packet, int *length,
const struct eth_sandbox_raw_priv *priv)
+{
int retval;
int saddr_size;
if (!priv->sd || !priv->device)
return -EINVAL;
saddr_size = sizeof(struct sockaddr);
retval = recvfrom(priv->sd, packet, 1536, 0,
(struct sockaddr *)priv->device,
(socklen_t *)&saddr_size);
*length = 0;
if (retval > 0) {
*length = retval;
return 0;
}
return retval;
return -errno here? At present you are returning -1 I think, which is
-EPERM.
OK
+}
+void sandbox_eth_raw_os_halt(struct eth_sandbox_raw_priv *priv) +{
free((struct sockaddr_ll *)priv->device);
Don't need that cast?
Hmm... good point.
priv->device = NULL;
close(priv->sd);
priv->sd = -1;
+} diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 235dcc0..b6762f4 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -186,4 +186,10 @@ reg = <0x10002000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
eth@80000000 {
compatible = "sandbox,eth-raw";
reg = <0x80000000 0x1000>;
host-raw-interface = "eth0";
};
}; diff --git a/arch/sandbox/include/asm/eth-raw-os.h
b/arch/sandbox/include/asm/eth-raw-os.h
new file mode 100644 index 0000000..d92b72c --- /dev/null +++ b/arch/sandbox/include/asm/eth-raw-os.h @@ -0,0 +1,32 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0
- */
+#ifndef __ETH_RAW_OS_H +#define __ETH_RAW_OS_H
+/**
- struct eth_sandbox_raw_priv - raw socket session
- sd: socket descriptor - the open socket during a session
- device: struct sockaddr_ll - the host interface packets move to/from
- */
+struct eth_sandbox_raw_priv {
int sd;
void *device;
+};
+int sandbox_eth_raw_os_init(const char *ifname, unsigned char *ethmac,
struct eth_sandbox_raw_priv *priv);
+int sandbox_eth_raw_os_send(void *packet, int length,
const struct eth_sandbox_raw_priv *priv);
+int sandbox_eth_raw_os_recv(void *packet, int *length,
const struct eth_sandbox_raw_priv *priv);
+void sandbox_eth_raw_os_halt(struct eth_sandbox_raw_priv *priv);
+#endif /* __ETH_RAW_OS_H */ diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox index c1f5f7e..c4c3139 100644 --- a/board/sandbox/README.sandbox +++ b/board/sandbox/README.sandbox @@ -190,6 +190,19 @@ Also sandbox uses generic board
(CONFIG_SYS_GENERIC_BOARD) and supports
driver model (CONFIG_DM) and associated commands.
+Linux RAW Networking Bridge +---------------------------
+The sandbox_eth_raw driver bridges traffic between the bottom of the
network
+stack and the RAW sockets API in Linux. This allows much of the u-boot
network
+functionality to be tested in sandbox against real network traffic.
+The RAW sockets Ethernet API requires elevated privileges in Linux.
You can
+either run as root, or you can add the capability needed like so:
+sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
This is so cool.
:D
Can you give some examples here? For me, ping seems to work, but I can't use bootp. Is that what the raw mode is for? How do I enable it? I tried setting ethact but am not sure what I am doing.
Sorry it's not clear. I'll update it, but if you want to play with it in the mean time, I'll explain here. But first, what were the symptoms where you say you couldn't use bootp?
This patch only supports the RAW AF_PACKET API. This is needed to get access to the lowest level of the network stack in Linux. This means that all of the Ethernet frame is included. This allows the u-boot network stack to be fully used. In other words, nothing about the Linux network stack is involved in forming the packets that end up on the wire. To receive the responses to packets sent from u-boot the network interface has to be set to promiscuous mode so that the network card won't filter out packets not destined for its configured (on Linux) MAC address.
The device tree as added by this patch should be everything you need to use eth0 on the host machine.
To contrast, the patch that adds support for the 'lo' interface cannot use the RAW AF_PACKET API because the lo interface doesn't support Ethernet-level traffic. It is a higher-level interface that is expected only to be used at the AF_INET level of the API. As such, the most raw we can get on that interface is the RAW AF_INET API on UDP. This allows us to set the IP_HDRINCL option to include everything except the Ethernet header in the packets we send and receive.
There is no decision to make. The local code path will only work on the 'lo' interface and the not-local code path will only work on non-'lo' interface. This check is explicit in sb_eth_raw_start().
Useful examples would be:
- ping
- bootp
- tftpboot
I have tested all 3 of these with just the device tree included in this patch. All that you need to do is set the eth1addr to something. Set ethact to "eth1".
You can then use dhcp (typically need to set autoload to no first) or set a static IP. Then you can ping or tftp.
If you set ethact to eth5 (the localhost interface in the device tree in the 'lo' support patch) then don't expect ping to work, but you should be able to tftpboot from the local TFTP server.
and how to use raw/normal device.
I hope this is clear above.
SPI Emulation
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index b08746a..dcbfa8a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -20,4 +20,9 @@ config ETH_SANDBOX default y bool "Sandbox: Mocked Ethernet driver"
+config ETH_SANDBOX_RAW
depends on DM_ETH && SANDBOX
default y
bool "Sandbox: Bridge to Linux Raw Sockets"
This needs some help.
endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 15dc431..2659a8a 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o obj-$(CONFIG_ETH_SANDBOX) += sandbox.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c new file mode 100644 index 0000000..01b33a9 --- /dev/null +++ b/drivers/net/sandbox-raw.c @@ -0,0 +1,105 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0
- */
+#include <asm/eth-raw-os.h> +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <net.h>
+DECLARE_GLOBAL_DATA_PTR;
+static int sb_eth_raw_start(struct udevice *dev) +{
struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
struct eth_pdata *pdata = dev_get_platdata(dev);
int retval;
const char *interface;
debug("eth_sandbox_raw: Start\n");
interface = fdt_getprop(gd->fdt_blob, dev->of_offset,
"host-raw-interface", NULL);
This can return NULL, so you should return -EINVAL in that case.
OK
retval = sandbox_eth_raw_os_init(interface, pdata->enetaddr,
priv);
return retval;
+}
+static int sb_eth_raw_send(struct udevice *dev, void *packet, int
length)
+{
struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
debug("eth_sandbox_raw: Send packet %d\n", length);
return sandbox_eth_raw_os_send(packet, length, priv);
+}
+static int sb_eth_raw_recv(struct udevice *dev) +{
struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
int retval;
uchar buffer[PKTSIZE];
int length;
retval = sandbox_eth_raw_os_recv(buffer, &length, priv);
if (!retval && length) {
debug("eth_sandbox_raw: received packet %d\n",
length);
NetReceive(buffer, length);
}
return 0;
+}
+static void sb_eth_raw_stop(struct udevice *dev) +{
struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
debug("eth_sandbox_raw: Stop\n");
sandbox_eth_raw_os_halt(priv);
+}
+static const struct eth_ops sb_eth_raw_ops = {
.start = sb_eth_raw_start,
.send = sb_eth_raw_send,
.recv = sb_eth_raw_recv,
.stop = sb_eth_raw_stop,
+};
+static int sb_eth_raw_remove(struct udevice *dev) +{
return 0;
+}
You can drop this function.
Good point.
+static int sb_eth_raw_ofdata_to_platdata(struct udevice *dev) +{
struct eth_pdata *pdata = dev_get_platdata(dev);
pdata->iobase = dev_get_addr(dev);
return 0;
+}
+static const struct udevice_id sb_eth_raw_ids[] = {
{ .compatible = "sandbox,eth-raw" },
{ }
+};
+U_BOOT_DRIVER(eth_sandbox_raw) = {
.name = "eth_sandbox_raw",
.id = UCLASS_ETH,
.of_match = sb_eth_raw_ids,
.ofdata_to_platdata = sb_eth_raw_ofdata_to_platdata,
.remove = sb_eth_raw_remove,
.ops = &sb_eth_raw_ops,
.priv_auto_alloc_size = sizeof(struct eth_sandbox_raw_priv),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
1.7.11.5
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi Joe,
On 2 March 2015 at 00:17, Joe Hershberger joe.hershberger@gmail.com wrote:
On Sun, Mar 1, 2015 at 12:07 PM, Simon Glass sjg@chromium.org wrote:
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
Implement a bridge between u-boot's network stack and Linux's raw packet API allowing the sandbox to send and receive packets using the host machine's network interface.
This raw Ethernet API requires elevated privileges. You can either run as root, or you can add the capability needed like so:
sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org
A few nits below.
[snip]
+Linux RAW Networking Bridge +---------------------------
+The sandbox_eth_raw driver bridges traffic between the bottom of the network +stack and the RAW sockets API in Linux. This allows much of the u-boot network +functionality to be tested in sandbox against real network traffic.
+The RAW sockets Ethernet API requires elevated privileges in Linux. You can +either run as root, or you can add the capability needed like so:
+sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
This is so cool.
:D
Can you give some examples here? For me, ping seems to work, but I can't use bootp. Is that what the raw mode is for? How do I enable it? I tried setting ethact but am not sure what I am doing.
Sorry it's not clear. I'll update it, but if you want to play with it in the mean time, I'll explain here. But first, what were the symptoms where you say you couldn't use bootp?
This patch only supports the RAW AF_PACKET API. This is needed to get access to the lowest level of the network stack in Linux. This means that all of the Ethernet frame is included. This allows the u-boot network stack to be fully used. In other words, nothing about the Linux network stack is involved in forming the packets that end up on the wire. To receive the responses to packets sent from u-boot the network interface has to be set to promiscuous mode so that the network card won't filter out packets not destined for its configured (on Linux) MAC address.
The device tree as added by this patch should be everything you need to use eth0 on the host machine.
To contrast, the patch that adds support for the 'lo' interface cannot use the RAW AF_PACKET API because the lo interface doesn't support Ethernet-level traffic. It is a higher-level interface that is expected only to be used at the AF_INET level of the API. As such, the most raw we can get on that interface is the RAW AF_INET API on UDP. This allows us to set the IP_HDRINCL option to include everything except the Ethernet header in the packets we send and receive.
There is no decision to make. The local code path will only work on the 'lo' interface and the not-local code path will only work on non-'lo' interface. This check is explicit in sb_eth_raw_start().
Useful examples would be:
- ping
- bootp
- tftpboot
I have tested all 3 of these with just the device tree included in this patch. All that you need to do is set the eth1addr to something. Set ethact to "eth1".
You can then use dhcp (typically need to set autoload to no first) or set a static IP. Then you can ping or tftp.
If you set ethact to eth5 (the localhost interface in the device tree in the 'lo' support patch) then don't expect ping to work, but you should be able to tftpboot from the local TFTP server.
and how to use raw/normal device.
I hope this is clear above.
OK the ethact might have been what I was missing. Anyway I'll wait until you update the README and try again.
Regards, Simon

This is now testable via the eth-raw interface
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
include/configs/sandbox.h | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index caf9f5a..034050e 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -127,6 +127,14 @@ #include <config_cmd_default.h>
#define CONFIG_CMD_PING +#define CONFIG_CMD_DHCP +#define CONFIG_BOOTP_DNS +#define CONFIG_BOOTP_DNS2 +#define CONFIG_BOOTP_GATEWAY +#define CONFIG_BOOTP_SEND_HOSTNAME +#define CONFIG_BOOTP_SERVERIP +#define CONFIG_BOOTP_SUBNETMASK +#define CONFIG_IP_DEFRAG
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY

On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
This is now testable via the eth-raw interface
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
include/configs/sandbox.h | 8 ++++++++ 1 file changed, 8 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index caf9f5a..034050e 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -127,6 +127,14 @@ #include <config_cmd_default.h>
#define CONFIG_CMD_PING +#define CONFIG_CMD_DHCP +#define CONFIG_BOOTP_DNS +#define CONFIG_BOOTP_DNS2 +#define CONFIG_BOOTP_GATEWAY +#define CONFIG_BOOTP_SEND_HOSTNAME +#define CONFIG_BOOTP_SERVERIP +#define CONFIG_BOOTP_SUBNETMASK +#define CONFIG_IP_DEFRAG
#define CONFIG_CMD_HASH
#define CONFIG_HASH_VERIFY
1.7.11.5

The 'lo' interface on Linux doesn't support thinks like ARP or link-layer access like we use to talk to a normal network interface. A higher-level network API must be used to access localhost.
As written, this interface is limited to not supporting ICMP since the API doesn't allow the socket to be opened for all IP traffic and be able to receive at the same time. UDP is far more useful to test with, so it was selected over ICMP. Ping won't work, but things like TFTP should work.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v4: -Added support for the 'lo' network interface
Changes in v3: None Changes in v2: None
arch/sandbox/cpu/eth-raw-os.c | 152 +++++++++++++++++++++++++++------- arch/sandbox/dts/sandbox.dts | 10 +++ arch/sandbox/include/asm/eth-raw-os.h | 10 ++- drivers/net/sandbox-raw.c | 62 +++++++++++++- 4 files changed, 203 insertions(+), 31 deletions(-)
diff --git a/arch/sandbox/cpu/eth-raw-os.c b/arch/sandbox/cpu/eth-raw-os.c index 9218f94..acb150a 100644 --- a/arch/sandbox/cpu/eth-raw-os.c +++ b/arch/sandbox/cpu/eth-raw-os.c @@ -11,6 +11,8 @@ #include <errno.h> #include <net/if.h> #include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/udp.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -19,51 +21,139 @@ #include <sys/socket.h> #include <unistd.h>
+#include <arpa/inet.h> #include <linux/if_ether.h> #include <linux/if_packet.h>
int sandbox_eth_raw_os_init(const char *ifname, unsigned char *ethmac, struct eth_sandbox_raw_priv *priv) { - struct sockaddr_ll *device; - struct packet_mreq mr; - - /* Prepare device struct */ - priv->device = malloc(sizeof(struct sockaddr_ll)); - device = priv->device; - memset(device, 0, sizeof(struct sockaddr_ll)); - device->sll_ifindex = if_nametoindex(ifname); - device->sll_family = AF_PACKET; - memcpy(device->sll_addr, ethmac, 6); - device->sll_halen = htons(6); - - /* Open socket */ - priv->sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (priv->sd < 0) { - printf("Failed to open socket: %d %s\n", errno, - strerror(errno)); - return -errno; + if (priv->local) { + struct sockaddr_in *device; + int ret; + struct timeval tv; + int one = 1; + + /* Prepare device struct */ + priv->device = malloc(sizeof(struct sockaddr_in)); + device = priv->device; + memset(device, 0, sizeof(struct sockaddr_in)); + device->sin_family = AF_INET; + ret = inet_pton(AF_INET, "127.0.0.1", + (struct in_addr *)&device->sin_addr.s_addr); + if (ret < 0) { + printf("Failed to convert address: %d %s\n", errno, + strerror(errno)); + return -errno; + } + + /** + * Open socket + * Since we specify UDP here, any incoming ICMP packets will + * not be received, so things like ping will not work on this + * localhost interface. + */ + priv->sd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP); + if (priv->sd < 0) { + printf("Failed to open socket: %d %s\n", errno, + strerror(errno)); + return -errno; + } + + /* Allow the receive to timeout after a millisecond */ + tv.tv_sec = 0; + tv.tv_usec = 1000; + ret = setsockopt(priv->sd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, + sizeof(struct timeval)); + if (ret < 0) { + printf("Failed to set opt: %d %s\n", errno, + strerror(errno)); + return -errno; + } + + /* Include the UDP/IP headers on send and receive */ + ret = setsockopt(priv->sd, IPPROTO_IP, IP_HDRINCL, &one, + sizeof(one)); + if (ret < 0) { + printf("Failed to set opt: %d %s\n", errno, + strerror(errno)); + return -errno; + } + priv->local_bind_sd = -1; + priv->local_bind_udp_port = 0; + } else { + struct sockaddr_ll *device; + struct packet_mreq mr; + + /* Prepare device struct */ + priv->device = malloc(sizeof(struct sockaddr_ll)); + device = priv->device; + memset(device, 0, sizeof(struct sockaddr_ll)); + device->sll_ifindex = if_nametoindex(ifname); + device->sll_family = AF_PACKET; + memcpy(device->sll_addr, ethmac, 6); + device->sll_halen = htons(6); + + /* Open socket */ + priv->sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (priv->sd < 0) { + printf("Failed to open socket: %d %s\n", errno, + strerror(errno)); + return -errno; + } + /* Bind to the specified interface */ + setsockopt(priv->sd, SOL_SOCKET, SO_BINDTODEVICE, ifname, + strlen(ifname) + 1); + + /* Enable promiscuous mode to receive responses meant for us */ + mr.mr_ifindex = device->sll_ifindex; + mr.mr_type = PACKET_MR_PROMISC; + setsockopt(priv->sd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, + &mr, sizeof(mr)); } - /* Bind to the specified interface */ - setsockopt(priv->sd, SOL_SOCKET, SO_BINDTODEVICE, ifname, - strlen(ifname) + 1); - - /* Enable promiscuous mode to receive responses meant for us */ - mr.mr_ifindex = device->sll_ifindex; - mr.mr_type = PACKET_MR_PROMISC; - setsockopt(priv->sd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, - &mr, sizeof(mr)); + return 0; }
int sandbox_eth_raw_os_send(void *packet, int length, - const struct eth_sandbox_raw_priv *priv) + struct eth_sandbox_raw_priv *priv) { int retval; + struct udphdr *udph = packet + sizeof(struct iphdr);
if (!priv->sd || !priv->device) return -EINVAL;
+ if (priv->local && (priv->local_bind_sd == -1 || + priv->local_bind_udp_port != udph->source)) { + struct iphdr *iph = packet; + struct sockaddr_in addr; + + if (priv->local_bind_sd != -1) + close(priv->local_bind_sd); + + /* A normal UDP socket is required to bind */ + priv->local_bind_sd = socket(AF_INET, SOCK_DGRAM, 0); + if (priv->local_bind_sd < 0) { + printf("Failed to open bind sd: %d %s\n", errno, + strerror(errno)); + return -errno; + } + priv->local_bind_udp_port = udph->source; + + /** + * Bind the UDP port that we intend to use as our source port + * so that the kernel will not send ICMP port unreachable + */ + addr.sin_family = AF_INET; + addr.sin_port = udph->source; + addr.sin_addr.s_addr = iph->saddr; + retval = bind(priv->local_bind_sd, &addr, sizeof(addr)); + if (retval < 0) + printf("Failed to bind: %d %s\n", errno, + strerror(errno)); + } + retval = sendto(priv->sd, packet, length, 0, (struct sockaddr *)priv->device, sizeof(struct sockaddr_ll)); @@ -99,4 +189,10 @@ void sandbox_eth_raw_os_halt(struct eth_sandbox_raw_priv *priv) priv->device = NULL; close(priv->sd); priv->sd = -1; + if (priv->local) { + if (priv->local_bind_sd != -1) + close(priv->local_bind_sd); + priv->local_bind_sd = -1; + priv->local_bind_udp_port = 0; + } } diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index b6762f4..9851bda 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -4,6 +4,10 @@ #address-cells = <1>; #size-cells = <0>;
+ aliases { + eth5 = "/eth@90000000"; + }; + chosen { stdout-path = "/serial"; }; @@ -192,4 +196,10 @@ reg = <0x80000000 0x1000>; host-raw-interface = "eth0"; }; + + eth@90000000 { + compatible = "sandbox,eth-raw"; + reg = <0x90000000 0x1000>; + host-raw-interface = "lo"; + }; }; diff --git a/arch/sandbox/include/asm/eth-raw-os.h b/arch/sandbox/include/asm/eth-raw-os.h index d92b72c..44e7050 100644 --- a/arch/sandbox/include/asm/eth-raw-os.h +++ b/arch/sandbox/include/asm/eth-raw-os.h @@ -15,16 +15,24 @@ * * sd: socket descriptor - the open socket during a session * device: struct sockaddr_ll - the host interface packets move to/from + * local: 1 or 0 to select a local interface or not + * local_bindsd: socket descriptor to prevent the kernel from sending + * a message to the server claiming the port is + * unreachable + * local_bind_udp_port: The UDP port number that we bound to */ struct eth_sandbox_raw_priv { int sd; void *device; + int local; + int local_bind_sd; + unsigned short local_bind_udp_port; };
int sandbox_eth_raw_os_init(const char *ifname, unsigned char *ethmac, struct eth_sandbox_raw_priv *priv); int sandbox_eth_raw_os_send(void *packet, int length, - const struct eth_sandbox_raw_priv *priv); + struct eth_sandbox_raw_priv *priv); int sandbox_eth_raw_os_recv(void *packet, int *length, const struct eth_sandbox_raw_priv *priv); void sandbox_eth_raw_os_halt(struct eth_sandbox_raw_priv *priv); diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c index 01b33a9..4b0f836 100644 --- a/drivers/net/sandbox-raw.c +++ b/drivers/net/sandbox-raw.c @@ -15,6 +15,8 @@
DECLARE_GLOBAL_DATA_PTR;
+static int reply_arp; +static IPaddr_t arp_ip;
static int sb_eth_raw_start(struct udevice *dev) { @@ -28,6 +30,12 @@ static int sb_eth_raw_start(struct udevice *dev) interface = fdt_getprop(gd->fdt_blob, dev->of_offset, "host-raw-interface", NULL);
+ if (strcmp(interface, "lo") == 0) { + priv->local = 1; + setenv("ipaddr", "127.0.0.1"); + setenv("serverip", "127.0.0.1"); + } + retval = sandbox_eth_raw_os_init(interface, pdata->enetaddr, priv);
return retval; @@ -39,19 +47,69 @@ static int sb_eth_raw_send(struct udevice *dev, void *packet, int length)
debug("eth_sandbox_raw: Send packet %d\n", length);
+ if (priv->local) { + struct ethernet_hdr *eth = packet; + + if (ntohs(eth->et_protlen) == PROT_ARP) { + struct arp_hdr *arp = packet + ETHER_HDR_SIZE; + + /** + * localhost works on a higher level API in Linux than + * ARP packets, so fake it + */ + arp_ip = NetReadIP(&arp->ar_tpa); + reply_arp = 1; + return 0; + } + packet += ETHER_HDR_SIZE; + length -= ETHER_HDR_SIZE; + } return sandbox_eth_raw_os_send(packet, length, priv); }
static int sb_eth_raw_recv(struct udevice *dev) { + struct eth_pdata *pdata = dev_get_platdata(dev); struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); - int retval; + int retval = 0; uchar buffer[PKTSIZE]; int length;
- retval = sandbox_eth_raw_os_recv(buffer, &length, priv); + if (reply_arp) { + struct arp_hdr *arp = (void *)buffer + ETHER_HDR_SIZE; + + /* Formulate a fake ARP */ + arp->ar_hrd = htons(ARP_ETHER); + arp->ar_pro = htons(PROT_IP); + arp->ar_hln = ARP_HLEN; + arp->ar_pln = ARP_PLEN; + arp->ar_op = htons(ARPOP_REPLY); + /* Any non-zero MAC address will work */ + memset(&arp->ar_sha, 0x01, ARP_HLEN); + /* Use whatever IP we were looking for (always 127.0.0.1?) */ + NetWriteIP(&arp->ar_spa, arp_ip); + memcpy(&arp->ar_tha, pdata->enetaddr, ARP_HLEN); + NetWriteIP(&arp->ar_tpa, NetOurIP); + length = ARP_HDR_SIZE; + } else { + /* If local, the Ethernet header won't be included; skip it */ + uchar *pktptr = priv->local ? buffer + ETHER_HDR_SIZE : buffer; + + retval = sandbox_eth_raw_os_recv(pktptr, &length, priv); + }
if (!retval && length) { + if (priv->local) { + struct ethernet_hdr *eth = (void *)buffer; + + /* Fill in enough of the missing Ethernet header */ + memcpy(eth->et_dest, pdata->enetaddr, ARP_HLEN); + memset(eth->et_src, 0x01, ARP_HLEN); + eth->et_protlen = htons(reply_arp ? PROT_ARP : PROT_IP); + reply_arp = 0; + length += ETHER_HDR_SIZE; + } + debug("eth_sandbox_raw: received packet %d\n", length); NetReceive(buffer, length);

Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
The 'lo' interface on Linux doesn't support thinks like ARP or link-layer access like we use to talk to a normal network interface. A higher-level network API must be used to access localhost.
As written, this interface is limited to not supporting ICMP since the API doesn't allow the socket to be opened for all IP traffic and be able to receive at the same time. UDP is far more useful to test with, so it was selected over ICMP. Ping won't work, but things like TFTP should work.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v4: -Added support for the 'lo' network interface
Changes in v3: None Changes in v2: None
arch/sandbox/cpu/eth-raw-os.c | 152 +++++++++++++++++++++++++++------- arch/sandbox/dts/sandbox.dts | 10 +++ arch/sandbox/include/asm/eth-raw-os.h | 10 ++- drivers/net/sandbox-raw.c | 62 +++++++++++++- 4 files changed, 203 insertions(+), 31 deletions(-)
diff --git a/arch/sandbox/cpu/eth-raw-os.c b/arch/sandbox/cpu/eth-raw-os.c index 9218f94..acb150a 100644 --- a/arch/sandbox/cpu/eth-raw-os.c +++ b/arch/sandbox/cpu/eth-raw-os.c @@ -11,6 +11,8 @@ #include <errno.h> #include <net/if.h> #include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/udp.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -19,51 +21,139 @@ #include <sys/socket.h> #include <unistd.h>
+#include <arpa/inet.h> #include <linux/if_ether.h> #include <linux/if_packet.h>
int sandbox_eth_raw_os_init(const char *ifname, unsigned char *ethmac, struct eth_sandbox_raw_priv *priv) {
struct sockaddr_ll *device;
struct packet_mreq mr;
/* Prepare device struct */
priv->device = malloc(sizeof(struct sockaddr_ll));
device = priv->device;
memset(device, 0, sizeof(struct sockaddr_ll));
device->sll_ifindex = if_nametoindex(ifname);
device->sll_family = AF_PACKET;
memcpy(device->sll_addr, ethmac, 6);
device->sll_halen = htons(6);
/* Open socket */
priv->sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (priv->sd < 0) {
printf("Failed to open socket: %d %s\n", errno,
strerror(errno));
return -errno;
if (priv->local) {
Can you put these two blocks of code (if and else) in separate functions and call them from here? This function is too long.
struct sockaddr_in *device;
int ret;
struct timeval tv;
int one = 1;
/* Prepare device struct */
priv->device = malloc(sizeof(struct sockaddr_in));
return -ENOMEM if NULL.
device = priv->device;
memset(device, 0, sizeof(struct sockaddr_in));
device->sin_family = AF_INET;
ret = inet_pton(AF_INET, "127.0.0.1",
Is this INADDR_LOOPBACK? Maybe you can just assign it here?
(struct in_addr *)&device->sin_addr.s_addr);
if (ret < 0) {
printf("Failed to convert address: %d %s\n", errno,
strerror(errno));
return -errno;
}
/**
* Open socket
* Since we specify UDP here, any incoming ICMP packets will
* not be received, so things like ping will not work on this
* localhost interface.
*/
priv->sd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if (priv->sd < 0) {
printf("Failed to open socket: %d %s\n", errno,
strerror(errno));
return -errno;
}
/* Allow the receive to timeout after a millisecond */
tv.tv_sec = 0;
tv.tv_usec = 1000;
ret = setsockopt(priv->sd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,
sizeof(struct timeval));
if (ret < 0) {
printf("Failed to set opt: %d %s\n", errno,
strerror(errno));
return -errno;
}
/* Include the UDP/IP headers on send and receive */
ret = setsockopt(priv->sd, IPPROTO_IP, IP_HDRINCL, &one,
sizeof(one));
if (ret < 0) {
printf("Failed to set opt: %d %s\n", errno,
strerror(errno));
return -errno;
}
priv->local_bind_sd = -1;
priv->local_bind_udp_port = 0;
} else {
struct sockaddr_ll *device;
struct packet_mreq mr;
/* Prepare device struct */
priv->device = malloc(sizeof(struct sockaddr_ll));
device = priv->device;
memset(device, 0, sizeof(struct sockaddr_ll));
device->sll_ifindex = if_nametoindex(ifname);
device->sll_family = AF_PACKET;
memcpy(device->sll_addr, ethmac, 6);
device->sll_halen = htons(6);
/* Open socket */
priv->sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (priv->sd < 0) {
printf("Failed to open socket: %d %s\n", errno,
strerror(errno));
return -errno;
}
/* Bind to the specified interface */
setsockopt(priv->sd, SOL_SOCKET, SO_BINDTODEVICE, ifname,
strlen(ifname) + 1);
/* Enable promiscuous mode to receive responses meant for us */
mr.mr_ifindex = device->sll_ifindex;
mr.mr_type = PACKET_MR_PROMISC;
setsockopt(priv->sd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
&mr, sizeof(mr)); }
/* Bind to the specified interface */
setsockopt(priv->sd, SOL_SOCKET, SO_BINDTODEVICE, ifname,
strlen(ifname) + 1);
/* Enable promiscuous mode to receive responses meant for us */
mr.mr_ifindex = device->sll_ifindex;
mr.mr_type = PACKET_MR_PROMISC;
setsockopt(priv->sd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
&mr, sizeof(mr));
return 0;
}
int sandbox_eth_raw_os_send(void *packet, int length,
const struct eth_sandbox_raw_priv *priv)
struct eth_sandbox_raw_priv *priv)
{ int retval;
struct udphdr *udph = packet + sizeof(struct iphdr); if (!priv->sd || !priv->device) return -EINVAL;
if (priv->local && (priv->local_bind_sd == -1 ||
priv->local_bind_udp_port != udph->source)) {
What does this block of code do? Comment?
struct iphdr *iph = packet;
struct sockaddr_in addr;
if (priv->local_bind_sd != -1)
close(priv->local_bind_sd);
/* A normal UDP socket is required to bind */
priv->local_bind_sd = socket(AF_INET, SOCK_DGRAM, 0);
if (priv->local_bind_sd < 0) {
printf("Failed to open bind sd: %d %s\n", errno,
strerror(errno));
return -errno;
}
priv->local_bind_udp_port = udph->source;
/**
* Bind the UDP port that we intend to use as our source port
* so that the kernel will not send ICMP port unreachable
Do you mean return the 'ICMP port unreachable' error?
*/
addr.sin_family = AF_INET;
addr.sin_port = udph->source;
addr.sin_addr.s_addr = iph->saddr;
retval = bind(priv->local_bind_sd, &addr, sizeof(addr));
if (retval < 0)
printf("Failed to bind: %d %s\n", errno,
strerror(errno));
}
retval = sendto(priv->sd, packet, length, 0, (struct sockaddr *)priv->device, sizeof(struct sockaddr_ll));
@@ -99,4 +189,10 @@ void sandbox_eth_raw_os_halt(struct eth_sandbox_raw_priv *priv) priv->device = NULL; close(priv->sd); priv->sd = -1;
if (priv->local) {
if (priv->local_bind_sd != -1)
close(priv->local_bind_sd);
priv->local_bind_sd = -1;
priv->local_bind_udp_port = 0;
}
} diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index b6762f4..9851bda 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -4,6 +4,10 @@ #address-cells = <1>; #size-cells = <0>;
aliases {
eth5 = "/eth@90000000";
};
chosen { stdout-path = "/serial"; };
@@ -192,4 +196,10 @@ reg = <0x80000000 0x1000>; host-raw-interface = "eth0"; };
eth@90000000 {
compatible = "sandbox,eth-raw";
reg = <0x90000000 0x1000>;
host-raw-interface = "lo";
};
}; diff --git a/arch/sandbox/include/asm/eth-raw-os.h b/arch/sandbox/include/asm/eth-raw-os.h index d92b72c..44e7050 100644 --- a/arch/sandbox/include/asm/eth-raw-os.h +++ b/arch/sandbox/include/asm/eth-raw-os.h @@ -15,16 +15,24 @@
- sd: socket descriptor - the open socket during a session
- device: struct sockaddr_ll - the host interface packets move to/from
- local: 1 or 0 to select a local interface or not
Should expand this a bit. The local interface is the loopback device....why do you want one over the other?
- local_bindsd: socket descriptor to prevent the kernel from sending
a message to the server claiming the port is
unreachable
*/
- local_bind_udp_port: The UDP port number that we bound to
struct eth_sandbox_raw_priv { int sd; void *device;
int local;
int local_bind_sd;
unsigned short local_bind_udp_port;
};
int sandbox_eth_raw_os_init(const char *ifname, unsigned char *ethmac, struct eth_sandbox_raw_priv *priv); int sandbox_eth_raw_os_send(void *packet, int length,
const struct eth_sandbox_raw_priv *priv);
struct eth_sandbox_raw_priv *priv);
int sandbox_eth_raw_os_recv(void *packet, int *length, const struct eth_sandbox_raw_priv *priv); void sandbox_eth_raw_os_halt(struct eth_sandbox_raw_priv *priv); diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c index 01b33a9..4b0f836 100644 --- a/drivers/net/sandbox-raw.c +++ b/drivers/net/sandbox-raw.c @@ -15,6 +15,8 @@
DECLARE_GLOBAL_DATA_PTR;
+static int reply_arp; +static IPaddr_t arp_ip;
static int sb_eth_raw_start(struct udevice *dev) { @@ -28,6 +30,12 @@ static int sb_eth_raw_start(struct udevice *dev) interface = fdt_getprop(gd->fdt_blob, dev->of_offset, "host-raw-interface", NULL);
if (strcmp(interface, "lo") == 0) {
priv->local = 1;
setenv("ipaddr", "127.0.0.1");
setenv("serverip", "127.0.0.1");
}
retval = sandbox_eth_raw_os_init(interface, pdata->enetaddr, priv); return retval;
@@ -39,19 +47,69 @@ static int sb_eth_raw_send(struct udevice *dev, void *packet, int length)
debug("eth_sandbox_raw: Send packet %d\n", length);
if (priv->local) {
struct ethernet_hdr *eth = packet;
if (ntohs(eth->et_protlen) == PROT_ARP) {
struct arp_hdr *arp = packet + ETHER_HDR_SIZE;
/**
* localhost works on a higher level API in Linux than
nit: higher-level
* ARP packets, so fake it
fake what?
*/
arp_ip = NetReadIP(&arp->ar_tpa);
reply_arp = 1;
return 0;
}
packet += ETHER_HDR_SIZE;
length -= ETHER_HDR_SIZE;
} return sandbox_eth_raw_os_send(packet, length, priv);
}
static int sb_eth_raw_recv(struct udevice *dev) {
struct eth_pdata *pdata = dev_get_platdata(dev); struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
int retval;
int retval = 0; uchar buffer[PKTSIZE]; int length;
retval = sandbox_eth_raw_os_recv(buffer, &length, priv);
if (reply_arp) {
struct arp_hdr *arp = (void *)buffer + ETHER_HDR_SIZE;
/* Formulate a fake ARP */
arp->ar_hrd = htons(ARP_ETHER);
arp->ar_pro = htons(PROT_IP);
arp->ar_hln = ARP_HLEN;
arp->ar_pln = ARP_PLEN;
arp->ar_op = htons(ARPOP_REPLY);
/* Any non-zero MAC address will work */
memset(&arp->ar_sha, 0x01, ARP_HLEN);
/* Use whatever IP we were looking for (always 127.0.0.1?) */
NetWriteIP(&arp->ar_spa, arp_ip);
memcpy(&arp->ar_tha, pdata->enetaddr, ARP_HLEN);
NetWriteIP(&arp->ar_tpa, NetOurIP);
length = ARP_HDR_SIZE;
} else {
/* If local, the Ethernet header won't be included; skip it */
uchar *pktptr = priv->local ? buffer + ETHER_HDR_SIZE : buffer;
retval = sandbox_eth_raw_os_recv(pktptr, &length, priv);
} if (!retval && length) {
if (priv->local) {
struct ethernet_hdr *eth = (void *)buffer;
/* Fill in enough of the missing Ethernet header */
memcpy(eth->et_dest, pdata->enetaddr, ARP_HLEN);
memset(eth->et_src, 0x01, ARP_HLEN);
eth->et_protlen = htons(reply_arp ? PROT_ARP : PROT_IP);
reply_arp = 0;
length += ETHER_HDR_SIZE;
}
debug("eth_sandbox_raw: received packet %d\n", length); NetReceive(buffer, length);
-- 1.7.11.5
Regards, Simon

On Sun, Mar 1, 2015 at 12:07 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com
wrote:
The 'lo' interface on Linux doesn't support thinks like ARP or link-layer access like we use to talk to a normal network interface. A higher-level network API must be used to access localhost.
As written, this interface is limited to not supporting ICMP since the API doesn't allow the socket to be opened for all IP traffic and be able to receive at the same time. UDP is far more useful to test with, so it was selected over ICMP. Ping won't work, but things like TFTP should work.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v4: -Added support for the 'lo' network interface
Changes in v3: None Changes in v2: None
arch/sandbox/cpu/eth-raw-os.c | 152
+++++++++++++++++++++++++++-------
arch/sandbox/dts/sandbox.dts | 10 +++ arch/sandbox/include/asm/eth-raw-os.h | 10 ++- drivers/net/sandbox-raw.c | 62 +++++++++++++- 4 files changed, 203 insertions(+), 31 deletions(-)
diff --git a/arch/sandbox/cpu/eth-raw-os.c
b/arch/sandbox/cpu/eth-raw-os.c
index 9218f94..acb150a 100644 --- a/arch/sandbox/cpu/eth-raw-os.c +++ b/arch/sandbox/cpu/eth-raw-os.c @@ -11,6 +11,8 @@ #include <errno.h> #include <net/if.h> #include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/udp.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -19,51 +21,139 @@ #include <sys/socket.h> #include <unistd.h>
+#include <arpa/inet.h> #include <linux/if_ether.h> #include <linux/if_packet.h>
int sandbox_eth_raw_os_init(const char *ifname, unsigned char *ethmac, struct eth_sandbox_raw_priv *priv) {
struct sockaddr_ll *device;
struct packet_mreq mr;
/* Prepare device struct */
priv->device = malloc(sizeof(struct sockaddr_ll));
device = priv->device;
memset(device, 0, sizeof(struct sockaddr_ll));
device->sll_ifindex = if_nametoindex(ifname);
device->sll_family = AF_PACKET;
memcpy(device->sll_addr, ethmac, 6);
device->sll_halen = htons(6);
/* Open socket */
priv->sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (priv->sd < 0) {
printf("Failed to open socket: %d %s\n", errno,
strerror(errno));
return -errno;
if (priv->local) {
Can you put these two blocks of code (if and else) in separate functions and call them from here? This function is too long.
OK
struct sockaddr_in *device;
int ret;
struct timeval tv;
int one = 1;
/* Prepare device struct */
priv->device = malloc(sizeof(struct sockaddr_in));
return -ENOMEM if NULL.
device = priv->device;
memset(device, 0, sizeof(struct sockaddr_in));
device->sin_family = AF_INET;
ret = inet_pton(AF_INET, "127.0.0.1",
Is this INADDR_LOOPBACK? Maybe you can just assign it here?
(struct in_addr *)&device->sin_addr.s_addr);
if (ret < 0) {
printf("Failed to convert address: %d %s\n",
errno,
strerror(errno));
return -errno;
}
/**
* Open socket
* Since we specify UDP here, any incoming ICMP
packets will
* not be received, so things like ping will not work
on this
* localhost interface.
*/
priv->sd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if (priv->sd < 0) {
printf("Failed to open socket: %d %s\n", errno,
strerror(errno));
return -errno;
}
/* Allow the receive to timeout after a millisecond */
tv.tv_sec = 0;
tv.tv_usec = 1000;
ret = setsockopt(priv->sd, SOL_SOCKET, SO_RCVTIMEO,
(char *)&tv,
sizeof(struct timeval));
if (ret < 0) {
printf("Failed to set opt: %d %s\n", errno,
strerror(errno));
return -errno;
}
/* Include the UDP/IP headers on send and receive */
ret = setsockopt(priv->sd, IPPROTO_IP, IP_HDRINCL, &one,
sizeof(one));
if (ret < 0) {
printf("Failed to set opt: %d %s\n", errno,
strerror(errno));
return -errno;
}
priv->local_bind_sd = -1;
priv->local_bind_udp_port = 0;
} else {
struct sockaddr_ll *device;
struct packet_mreq mr;
/* Prepare device struct */
priv->device = malloc(sizeof(struct sockaddr_ll));
device = priv->device;
memset(device, 0, sizeof(struct sockaddr_ll));
device->sll_ifindex = if_nametoindex(ifname);
device->sll_family = AF_PACKET;
memcpy(device->sll_addr, ethmac, 6);
device->sll_halen = htons(6);
/* Open socket */
priv->sd = socket(PF_PACKET, SOCK_RAW,
htons(ETH_P_ALL));
if (priv->sd < 0) {
printf("Failed to open socket: %d %s\n", errno,
strerror(errno));
return -errno;
}
/* Bind to the specified interface */
setsockopt(priv->sd, SOL_SOCKET, SO_BINDTODEVICE,
ifname,
strlen(ifname) + 1);
/* Enable promiscuous mode to receive responses meant
for us */
mr.mr_ifindex = device->sll_ifindex;
mr.mr_type = PACKET_MR_PROMISC;
setsockopt(priv->sd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
&mr, sizeof(mr)); }
/* Bind to the specified interface */
setsockopt(priv->sd, SOL_SOCKET, SO_BINDTODEVICE, ifname,
strlen(ifname) + 1);
/* Enable promiscuous mode to receive responses meant for us */
mr.mr_ifindex = device->sll_ifindex;
mr.mr_type = PACKET_MR_PROMISC;
setsockopt(priv->sd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
&mr, sizeof(mr));
return 0;
}
int sandbox_eth_raw_os_send(void *packet, int length,
const struct eth_sandbox_raw_priv *priv)
struct eth_sandbox_raw_priv *priv)
{ int retval;
struct udphdr *udph = packet + sizeof(struct iphdr); if (!priv->sd || !priv->device) return -EINVAL;
if (priv->local && (priv->local_bind_sd == -1 ||
priv->local_bind_udp_port != udph->source))
{
What does this block of code do? Comment?
OK, I'll add a comment. This block of code came about when testing tftp on the localhost interface. When using the RAW AF_INET API, the network stack is still in play responding to incoming traffic based on open "ports". Since it is raw (at the IP layer, no Ethernet) the network stack tells the TFTP server that the port it responded to is closed. This causes the TFTP transfer to be aborted. This block of code inspects the outgoing packet as formulated by the u-boot network stack to determine the source port (that the TFTP server will send packets back to) and opens a typical UDP socket on that port, thus preventing the network stack from sending that ICMP message claiming that the port has no bound socket.
struct iphdr *iph = packet;
struct sockaddr_in addr;
if (priv->local_bind_sd != -1)
close(priv->local_bind_sd);
/* A normal UDP socket is required to bind */
priv->local_bind_sd = socket(AF_INET, SOCK_DGRAM, 0);
if (priv->local_bind_sd < 0) {
printf("Failed to open bind sd: %d %s\n", errno,
strerror(errno));
return -errno;
}
priv->local_bind_udp_port = udph->source;
/**
* Bind the UDP port that we intend to use as our
source port
* so that the kernel will not send ICMP port
unreachable
Do you mean return the 'ICMP port unreachable' error?
I guess it is an error. I just thought of it as guidance to the sender.
*/
addr.sin_family = AF_INET;
addr.sin_port = udph->source;
addr.sin_addr.s_addr = iph->saddr;
retval = bind(priv->local_bind_sd, &addr, sizeof(addr));
if (retval < 0)
printf("Failed to bind: %d %s\n", errno,
strerror(errno));
}
retval = sendto(priv->sd, packet, length, 0, (struct sockaddr *)priv->device, sizeof(struct sockaddr_ll));
@@ -99,4 +189,10 @@ void sandbox_eth_raw_os_halt(struct
eth_sandbox_raw_priv *priv)
priv->device = NULL; close(priv->sd); priv->sd = -1;
if (priv->local) {
if (priv->local_bind_sd != -1)
close(priv->local_bind_sd);
priv->local_bind_sd = -1;
priv->local_bind_udp_port = 0;
}
} diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index b6762f4..9851bda 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -4,6 +4,10 @@ #address-cells = <1>; #size-cells = <0>;
aliases {
eth5 = "/eth@90000000";
};
chosen { stdout-path = "/serial"; };
@@ -192,4 +196,10 @@ reg = <0x80000000 0x1000>; host-raw-interface = "eth0"; };
eth@90000000 {
compatible = "sandbox,eth-raw";
reg = <0x90000000 0x1000>;
host-raw-interface = "lo";
};
}; diff --git a/arch/sandbox/include/asm/eth-raw-os.h
b/arch/sandbox/include/asm/eth-raw-os.h
index d92b72c..44e7050 100644 --- a/arch/sandbox/include/asm/eth-raw-os.h +++ b/arch/sandbox/include/asm/eth-raw-os.h @@ -15,16 +15,24 @@
- sd: socket descriptor - the open socket during a session
- device: struct sockaddr_ll - the host interface packets move to/from
- local: 1 or 0 to select a local interface or not
Should expand this a bit. The local interface is the loopback device....why do you want one over the other?
Not sure what you're getting at here. You want local if you want to talk to a local server (TFTP is what I tested with). You want non-local if you want to talk over a real Ethernet interface to a different machine than the one running sandbox.
- local_bindsd: socket descriptor to prevent the kernel from sending
a message to the server claiming the port is
unreachable
*/
- local_bind_udp_port: The UDP port number that we bound to
struct eth_sandbox_raw_priv { int sd; void *device;
int local;
int local_bind_sd;
unsigned short local_bind_udp_port;
};
int sandbox_eth_raw_os_init(const char *ifname, unsigned char *ethmac, struct eth_sandbox_raw_priv *priv); int sandbox_eth_raw_os_send(void *packet, int length,
const struct eth_sandbox_raw_priv *priv);
struct eth_sandbox_raw_priv *priv);
int sandbox_eth_raw_os_recv(void *packet, int *length, const struct eth_sandbox_raw_priv *priv); void sandbox_eth_raw_os_halt(struct eth_sandbox_raw_priv *priv); diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c index 01b33a9..4b0f836 100644 --- a/drivers/net/sandbox-raw.c +++ b/drivers/net/sandbox-raw.c @@ -15,6 +15,8 @@
DECLARE_GLOBAL_DATA_PTR;
+static int reply_arp; +static IPaddr_t arp_ip;
static int sb_eth_raw_start(struct udevice *dev) { @@ -28,6 +30,12 @@ static int sb_eth_raw_start(struct udevice *dev) interface = fdt_getprop(gd->fdt_blob, dev->of_offset, "host-raw-interface", NULL);
if (strcmp(interface, "lo") == 0) {
priv->local = 1;
setenv("ipaddr", "127.0.0.1");
setenv("serverip", "127.0.0.1");
}
retval = sandbox_eth_raw_os_init(interface, pdata->enetaddr,
priv);
return retval;
@@ -39,19 +47,69 @@ static int sb_eth_raw_send(struct udevice *dev,
void *packet, int length)
debug("eth_sandbox_raw: Send packet %d\n", length);
if (priv->local) {
struct ethernet_hdr *eth = packet;
if (ntohs(eth->et_protlen) == PROT_ARP) {
struct arp_hdr *arp = packet + ETHER_HDR_SIZE;
/**
* localhost works on a higher level API in
Linux than
nit: higher-level
* ARP packets, so fake it
fake what?
Fake an ARP response. The u-boot network stack is sending an ARP request (to find the MAC address to address the actual packet to) and requires an ARP response to continue. Since this is the localhost interface, there is no Etherent level traffic at all, so there is no way to send an ARP request or to get a response. For this reason we fake the response to make the u-boot network stack happy.
*/
arp_ip = NetReadIP(&arp->ar_tpa);
reply_arp = 1;
return 0;
}
packet += ETHER_HDR_SIZE;
length -= ETHER_HDR_SIZE;
} return sandbox_eth_raw_os_send(packet, length, priv);
}
static int sb_eth_raw_recv(struct udevice *dev) {
struct eth_pdata *pdata = dev_get_platdata(dev); struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
int retval;
int retval = 0; uchar buffer[PKTSIZE]; int length;
retval = sandbox_eth_raw_os_recv(buffer, &length, priv);
if (reply_arp) {
struct arp_hdr *arp = (void *)buffer + ETHER_HDR_SIZE;
/* Formulate a fake ARP */
arp->ar_hrd = htons(ARP_ETHER);
arp->ar_pro = htons(PROT_IP);
arp->ar_hln = ARP_HLEN;
arp->ar_pln = ARP_PLEN;
arp->ar_op = htons(ARPOP_REPLY);
/* Any non-zero MAC address will work */
memset(&arp->ar_sha, 0x01, ARP_HLEN);
/* Use whatever IP we were looking for (always
127.0.0.1?) */
NetWriteIP(&arp->ar_spa, arp_ip);
memcpy(&arp->ar_tha, pdata->enetaddr, ARP_HLEN);
NetWriteIP(&arp->ar_tpa, NetOurIP);
length = ARP_HDR_SIZE;
} else {
/* If local, the Ethernet header won't be included;
skip it */
uchar *pktptr = priv->local ? buffer + ETHER_HDR_SIZE :
buffer;
retval = sandbox_eth_raw_os_recv(pktptr, &length, priv);
} if (!retval && length) {
if (priv->local) {
struct ethernet_hdr *eth = (void *)buffer;
/* Fill in enough of the missing Ethernet
header */
memcpy(eth->et_dest, pdata->enetaddr, ARP_HLEN);
memset(eth->et_src, 0x01, ARP_HLEN);
eth->et_protlen = htons(reply_arp ? PROT_ARP :
PROT_IP);
reply_arp = 0;
length += ETHER_HDR_SIZE;
}
debug("eth_sandbox_raw: received packet %d\n", length); NetReceive(buffer, length);
-- 1.7.11.5
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi Joe,
On 2 March 2015 at 00:18, Joe Hershberger joe.hershberger@gmail.com wrote:
On Sun, Mar 1, 2015 at 12:07 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
The 'lo' interface on Linux doesn't support thinks like ARP or link-layer access like we use to talk to a normal network interface. A higher-level network API must be used to access localhost.
As written, this interface is limited to not supporting ICMP since the API doesn't allow the socket to be opened for all IP traffic and be able to receive at the same time. UDP is far more useful to test with, so it was selected over ICMP. Ping won't work, but things like TFTP should work.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v4: -Added support for the 'lo' network interface
Changes in v3: None Changes in v2: None
arch/sandbox/cpu/eth-raw-os.c | 152 +++++++++++++++++++++++++++------- arch/sandbox/dts/sandbox.dts | 10 +++ arch/sandbox/include/asm/eth-raw-os.h | 10 ++- drivers/net/sandbox-raw.c | 62 +++++++++++++- 4 files changed, 203 insertions(+), 31 deletions(-)
diff --git a/arch/sandbox/cpu/eth-raw-os.c b/arch/sandbox/cpu/eth-raw-os.c index 9218f94..acb150a 100644 --- a/arch/sandbox/cpu/eth-raw-os.c +++ b/arch/sandbox/cpu/eth-raw-os.c @@ -11,6 +11,8 @@ #include <errno.h> #include <net/if.h> #include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/udp.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -19,51 +21,139 @@ #include <sys/socket.h> #include <unistd.h>
+#include <arpa/inet.h> #include <linux/if_ether.h> #include <linux/if_packet.h>
int sandbox_eth_raw_os_init(const char *ifname, unsigned char *ethmac, struct eth_sandbox_raw_priv *priv) {
struct sockaddr_ll *device;
struct packet_mreq mr;
/* Prepare device struct */
priv->device = malloc(sizeof(struct sockaddr_ll));
device = priv->device;
memset(device, 0, sizeof(struct sockaddr_ll));
device->sll_ifindex = if_nametoindex(ifname);
device->sll_family = AF_PACKET;
memcpy(device->sll_addr, ethmac, 6);
device->sll_halen = htons(6);
/* Open socket */
priv->sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (priv->sd < 0) {
printf("Failed to open socket: %d %s\n", errno,
strerror(errno));
return -errno;
if (priv->local) {
Can you put these two blocks of code (if and else) in separate functions and call them from here? This function is too long.
OK
struct sockaddr_in *device;
int ret;
struct timeval tv;
int one = 1;
/* Prepare device struct */
priv->device = malloc(sizeof(struct sockaddr_in));
return -ENOMEM if NULL.
device = priv->device;
memset(device, 0, sizeof(struct sockaddr_in));
device->sin_family = AF_INET;
ret = inet_pton(AF_INET, "127.0.0.1",
Is this INADDR_LOOPBACK? Maybe you can just assign it here?
(struct in_addr *)&device->sin_addr.s_addr);
if (ret < 0) {
printf("Failed to convert address: %d %s\n",
errno,
strerror(errno));
return -errno;
}
/**
* Open socket
* Since we specify UDP here, any incoming ICMP packets
will
* not be received, so things like ping will not work
on this
* localhost interface.
*/
priv->sd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if (priv->sd < 0) {
printf("Failed to open socket: %d %s\n", errno,
strerror(errno));
return -errno;
}
/* Allow the receive to timeout after a millisecond */
tv.tv_sec = 0;
tv.tv_usec = 1000;
ret = setsockopt(priv->sd, SOL_SOCKET, SO_RCVTIMEO,
(char *)&tv,
sizeof(struct timeval));
if (ret < 0) {
printf("Failed to set opt: %d %s\n", errno,
strerror(errno));
return -errno;
}
/* Include the UDP/IP headers on send and receive */
ret = setsockopt(priv->sd, IPPROTO_IP, IP_HDRINCL, &one,
sizeof(one));
if (ret < 0) {
printf("Failed to set opt: %d %s\n", errno,
strerror(errno));
return -errno;
}
priv->local_bind_sd = -1;
priv->local_bind_udp_port = 0;
} else {
struct sockaddr_ll *device;
struct packet_mreq mr;
/* Prepare device struct */
priv->device = malloc(sizeof(struct sockaddr_ll));
device = priv->device;
memset(device, 0, sizeof(struct sockaddr_ll));
device->sll_ifindex = if_nametoindex(ifname);
device->sll_family = AF_PACKET;
memcpy(device->sll_addr, ethmac, 6);
device->sll_halen = htons(6);
/* Open socket */
priv->sd = socket(PF_PACKET, SOCK_RAW,
htons(ETH_P_ALL));
if (priv->sd < 0) {
printf("Failed to open socket: %d %s\n", errno,
strerror(errno));
return -errno;
}
/* Bind to the specified interface */
setsockopt(priv->sd, SOL_SOCKET, SO_BINDTODEVICE,
ifname,
strlen(ifname) + 1);
/* Enable promiscuous mode to receive responses meant
for us */
mr.mr_ifindex = device->sll_ifindex;
mr.mr_type = PACKET_MR_PROMISC;
setsockopt(priv->sd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
&mr, sizeof(mr)); }
/* Bind to the specified interface */
setsockopt(priv->sd, SOL_SOCKET, SO_BINDTODEVICE, ifname,
strlen(ifname) + 1);
/* Enable promiscuous mode to receive responses meant for us */
mr.mr_ifindex = device->sll_ifindex;
mr.mr_type = PACKET_MR_PROMISC;
setsockopt(priv->sd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
&mr, sizeof(mr));
return 0;
}
int sandbox_eth_raw_os_send(void *packet, int length,
const struct eth_sandbox_raw_priv *priv)
struct eth_sandbox_raw_priv *priv)
{ int retval;
struct udphdr *udph = packet + sizeof(struct iphdr); if (!priv->sd || !priv->device) return -EINVAL;
if (priv->local && (priv->local_bind_sd == -1 ||
priv->local_bind_udp_port != udph->source))
{
What does this block of code do? Comment?
OK, I'll add a comment. This block of code came about when testing tftp on the localhost interface. When using the RAW AF_INET API, the network stack is still in play responding to incoming traffic based on open "ports". Since it is raw (at the IP layer, no Ethernet) the network stack tells the TFTP server that the port it responded to is closed. This causes the TFTP transfer to be aborted. This block of code inspects the outgoing packet as formulated by the u-boot network stack to determine the source port (that the TFTP server will send packets back to) and opens a typical UDP socket on that port, thus preventing the network stack from sending that ICMP message claiming that the port has no bound socket.
Sounds like a good comment :-)
struct iphdr *iph = packet;
struct sockaddr_in addr;
if (priv->local_bind_sd != -1)
close(priv->local_bind_sd);
/* A normal UDP socket is required to bind */
priv->local_bind_sd = socket(AF_INET, SOCK_DGRAM, 0);
if (priv->local_bind_sd < 0) {
printf("Failed to open bind sd: %d %s\n", errno,
strerror(errno));
return -errno;
}
priv->local_bind_udp_port = udph->source;
/**
* Bind the UDP port that we intend to use as our source
port
* so that the kernel will not send ICMP port
unreachable
Do you mean return the 'ICMP port unreachable' error?
I guess it is an error. I just thought of it as guidance to the sender.
*/
addr.sin_family = AF_INET;
addr.sin_port = udph->source;
addr.sin_addr.s_addr = iph->saddr;
retval = bind(priv->local_bind_sd, &addr, sizeof(addr));
if (retval < 0)
printf("Failed to bind: %d %s\n", errno,
strerror(errno));
}
retval = sendto(priv->sd, packet, length, 0, (struct sockaddr *)priv->device, sizeof(struct sockaddr_ll));
@@ -99,4 +189,10 @@ void sandbox_eth_raw_os_halt(struct eth_sandbox_raw_priv *priv) priv->device = NULL; close(priv->sd); priv->sd = -1;
if (priv->local) {
if (priv->local_bind_sd != -1)
close(priv->local_bind_sd);
priv->local_bind_sd = -1;
priv->local_bind_udp_port = 0;
}
} diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index b6762f4..9851bda 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -4,6 +4,10 @@ #address-cells = <1>; #size-cells = <0>;
aliases {
eth5 = "/eth@90000000";
};
chosen { stdout-path = "/serial"; };
@@ -192,4 +196,10 @@ reg = <0x80000000 0x1000>; host-raw-interface = "eth0"; };
eth@90000000 {
compatible = "sandbox,eth-raw";
reg = <0x90000000 0x1000>;
host-raw-interface = "lo";
};
}; diff --git a/arch/sandbox/include/asm/eth-raw-os.h b/arch/sandbox/include/asm/eth-raw-os.h index d92b72c..44e7050 100644 --- a/arch/sandbox/include/asm/eth-raw-os.h +++ b/arch/sandbox/include/asm/eth-raw-os.h @@ -15,16 +15,24 @@
- sd: socket descriptor - the open socket during a session
- device: struct sockaddr_ll - the host interface packets move to/from
- local: 1 or 0 to select a local interface or not
Should expand this a bit. The local interface is the loopback device....why do you want one over the other?
Not sure what you're getting at here. You want local if you want to talk to a local server (TFTP is what I tested with). You want non-local if you want to talk over a real Ethernet interface to a different machine than the one running sandbox.
That's what I was wondering. Just a few notes in the comment about how to choose the parameter value.
- local_bindsd: socket descriptor to prevent the kernel from sending
a message to the server claiming the port is
unreachable
*/
- local_bind_udp_port: The UDP port number that we bound to
struct eth_sandbox_raw_priv { int sd; void *device;
int local;
int local_bind_sd;
unsigned short local_bind_udp_port;
};
int sandbox_eth_raw_os_init(const char *ifname, unsigned char *ethmac, struct eth_sandbox_raw_priv *priv); int sandbox_eth_raw_os_send(void *packet, int length,
const struct eth_sandbox_raw_priv *priv);
struct eth_sandbox_raw_priv *priv);
int sandbox_eth_raw_os_recv(void *packet, int *length, const struct eth_sandbox_raw_priv *priv); void sandbox_eth_raw_os_halt(struct eth_sandbox_raw_priv *priv); diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c index 01b33a9..4b0f836 100644 --- a/drivers/net/sandbox-raw.c +++ b/drivers/net/sandbox-raw.c @@ -15,6 +15,8 @@
DECLARE_GLOBAL_DATA_PTR;
+static int reply_arp; +static IPaddr_t arp_ip;
static int sb_eth_raw_start(struct udevice *dev) { @@ -28,6 +30,12 @@ static int sb_eth_raw_start(struct udevice *dev) interface = fdt_getprop(gd->fdt_blob, dev->of_offset, "host-raw-interface", NULL);
if (strcmp(interface, "lo") == 0) {
priv->local = 1;
setenv("ipaddr", "127.0.0.1");
setenv("serverip", "127.0.0.1");
}
retval = sandbox_eth_raw_os_init(interface, pdata->enetaddr,
priv);
return retval;
@@ -39,19 +47,69 @@ static int sb_eth_raw_send(struct udevice *dev, void *packet, int length)
debug("eth_sandbox_raw: Send packet %d\n", length);
if (priv->local) {
struct ethernet_hdr *eth = packet;
if (ntohs(eth->et_protlen) == PROT_ARP) {
struct arp_hdr *arp = packet + ETHER_HDR_SIZE;
/**
* localhost works on a higher level API in
Linux than
nit: higher-level
* ARP packets, so fake it
fake what?
Fake an ARP response. The u-boot network stack is sending an ARP request (to find the MAC address to address the actual packet to) and requires an ARP response to continue. Since this is the localhost interface, there is no Etherent level traffic at all, so there is no way to send an ARP request or to get a response. For this reason we fake the response to make the u-boot network stack happy.
OK, please add this to the comment too.
*/
arp_ip = NetReadIP(&arp->ar_tpa);
reply_arp = 1;
return 0;
}
packet += ETHER_HDR_SIZE;
length -= ETHER_HDR_SIZE;
} return sandbox_eth_raw_os_send(packet, length, priv);
}
static int sb_eth_raw_recv(struct udevice *dev) {
struct eth_pdata *pdata = dev_get_platdata(dev); struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
int retval;
int retval = 0; uchar buffer[PKTSIZE]; int length;
retval = sandbox_eth_raw_os_recv(buffer, &length, priv);
if (reply_arp) {
struct arp_hdr *arp = (void *)buffer + ETHER_HDR_SIZE;
/* Formulate a fake ARP */
arp->ar_hrd = htons(ARP_ETHER);
arp->ar_pro = htons(PROT_IP);
arp->ar_hln = ARP_HLEN;
arp->ar_pln = ARP_PLEN;
arp->ar_op = htons(ARPOP_REPLY);
/* Any non-zero MAC address will work */
memset(&arp->ar_sha, 0x01, ARP_HLEN);
/* Use whatever IP we were looking for (always
127.0.0.1?) */
NetWriteIP(&arp->ar_spa, arp_ip);
memcpy(&arp->ar_tha, pdata->enetaddr, ARP_HLEN);
NetWriteIP(&arp->ar_tpa, NetOurIP);
length = ARP_HDR_SIZE;
} else {
/* If local, the Ethernet header won't be included; skip
it */
uchar *pktptr = priv->local ? buffer + ETHER_HDR_SIZE :
buffer;
retval = sandbox_eth_raw_os_recv(pktptr, &length, priv);
} if (!retval && length) {
if (priv->local) {
struct ethernet_hdr *eth = (void *)buffer;
/* Fill in enough of the missing Ethernet header
*/
memcpy(eth->et_dest, pdata->enetaddr, ARP_HLEN);
memset(eth->et_src, 0x01, ARP_HLEN);
eth->et_protlen = htons(reply_arp ? PROT_ARP :
PROT_IP);
reply_arp = 0;
length += ETHER_HDR_SIZE;
}
debug("eth_sandbox_raw: received packet %d\n", length); NetReceive(buffer, length);
-- 1.7.11.5
Regards, Simon

Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
Add support for the Ethernet MAC controllers. Phy support will come later.
I am still leaving this as an RFC because I plan to add real board support before committing to mainline. When it is acceptable / accepted, I will push it as a dev branch on the net repo until a real device is supported. If any required changes are discovered in the process of supporting a real device I will send those as a patch against the dev branch, but then squash before sending the non-RFC version. I plan to rebase when the merge window opens anyway.
If desired, let me know which of the non-DM related prerequisite patches are wanted for this release.
I've added unit tests to verify functionality.
There is an additional driver for sandbox that bridges to the RAW Ethernet API in Linux which lets you test with real traffic. It now supports localhost as well (the 'lo' interface).
I've got some comments queued up the the series so will send those soon (never got to it this week so am catching up!). I wanted to try it out on a board to see how things look. The short answer is that it works really nicely on sunxi. I'll send some patches that I needed, hopefully that doesn't duplicate any work you have done.
In terms of getting this into mainline, I'd be happy to use u-boot-dm/next if that suits you and Tom. There are series for PCI and USB to sort out, and if the last merge window is any indication it's a real struggle to get multiple large series applied within the merge window when there are dependencies between them.
Some general comments that I will put here for want of a better place:
- it would be good to have the DM code in drivers/net/eth-uclass.c at some point - struct eth_pdata is used by the uclass and is common to all drivers, but I wonder if we will find that drivers want to add their own private platdata? I added phy_interface but that is generic. Let's see. - I think the recv() method should change before long. The NetReceive() call should be made from the uclass since it is common to all drivers. Then the recv() method can return a packet if it finds one, but not submit it for processing
One interesting point for me is that you have taken a slightly more ambitious approach with the conversion by not reusing eth_device. That seems to have have worked out well and makes me think I could revisit SPI flash perhaps and do the same.
Changes in v4: -New to v4 -Fix compile regression in !DM_ETH case -New to v4 -New to v4 -New to v4 -New to v4 -New to v4
If you put this in a patch, patman will remove duplicates in the cover letter.
Series-process-log: uniq
You can also sort with:
Series-process-log: sort, uniq
-Redo the seq / probe implementation --Don't prevent eth_initialize on driver model --Use eth_initialize to probe all devices and write_hwaddr --Look up MAC address in post-probe --Include ethprime handling in eth_initialize --If current == NULL, always check if there is a device available in eth_get_dev --Move env init call from uclass init to eth_initialize --Print the alias in eth_initialize -Stop handling selecting a new "current" in pre-unbind as it will now work itself out by clearing the pointer -Change -1 returns to error constants -Remove bd_t *bis from dm eth_ops init function -Add documentation to the structures -Add a helper function for eth_uclass_priv -Change puts to printf -Add eth_get_ops helper -Rename init() to start() in ops -Rename halt() to stop() in ops -Remove checks for driver==NULL -Remove priv pointer in per-device priv struct (drivers already get their own directly from DM) -Cleaned up sandbox EXTRA_ENV define -Moved config to Kconfig -Removed checks on priv != NULL and added protection in uclass instead -Use only the seq from DM to find aliases -Load from ethprime on eth_initialize() -Added testing for ethrotate -Add ability to disable ping reply in sandbox eth driver -Updated expected behavior based on changes to the NetLoop -Added comments to README.sandbox -Use accessors for platdata and priv -Add comments to priv struct definition -Move os file to arch -Cleanup var definition order -Moved config to Kconfig -Clean up the interface to sandbox's eth-raw-os by passing priv to raw-os -Fixed the MAC address limitation (now all traffic uses MAC address from env) -New to v4 -Added support for the 'lo' network interface
Changes in v3: -Reorder dm test makefile -Move the get_dev_by_* protos to also be !DM_ETH like the impl -Correct the pre_unbind logic -Correct failure chaining from bind to probe to init --Fail init if not activated --Fail probe if ethaddr not set -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the previous selection -Allow current eth dev to be NULL -Fixed blank line formatting for variable declaration -Added 2 more ethaddr to sandbox -Print which device in the debug write hwaddr -Prevent a crash if memory is not allocated -Added dm eth testing -Added support for aliases -Added support for ethprime -Added testing for netretry -Made the os raw packet support for sandbox eth build and work.
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for our needs -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()). -Change printfs to debug in sandbox driver -Remove unused priv struct for sandbox driver -Change printfs to debug in sandbox driver -Move static data to priv -Move fake hwaddr to the device tree -Added the raw packet proof-of-concept patch.
Joe Hershberger (23): test: dm: Reorder the objects to build common: Make sure arch-specific map_sysmem() is defined net: Provide a function to get the current MAC address net: Rename helper function to be more clear net: Remove unneeded "extern" in net.h net: Refactor in preparation for driver model net: Change return codes from net/eth.c to use errorno constants net: Use int instead of u8 for boolean flag net: Remove the bd* parameter from net stack functions net: Make netretry actually do something net: Access mapped physmem in net functions dm: eth: Add basic driver model support to Ethernet stack sandbox: eth: Add network support to sandbox sandbox: eth: Add ARP and PING response to sandbox driver test: dm: eth: Add tests for the eth dm implementation dm: eth: Add support for aliases dm: eth: Add support for ethprime env var test: dm: eth: Add testing for ethrotate env var sandbox: eth: Add ability to disable ping reply in sandbox eth driver test: dm: net: Add a test of the netretry behavior sandbox: eth: Add a bridge to a real network for sandbox sandbox: Enable DHCP and IP defrag sandbox: eth: Add support for using the 'lo' interface
arch/mips/mach-au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- arch/sandbox/Kconfig | 12 + arch/sandbox/cpu/Makefile | 10 + arch/sandbox/cpu/eth-raw-os.c | 198 +++++++++++++ arch/sandbox/dts/sandbox.dts | 21 ++ arch/sandbox/include/asm/eth-raw-os.h | 40 +++ board/sandbox/README.sandbox | 17 +- common/board_r.c | 2 +- common/cmd_bdinfo.c | 2 + drivers/net/Kconfig | 28 ++ drivers/net/Makefile | 2 + drivers/net/netconsole.c | 4 +- drivers/net/sandbox-raw.c | 163 +++++++++++ drivers/net/sandbox.c | 200 +++++++++++++ include/common.h | 4 +- include/configs/sandbox.h | 25 +- include/dm/uclass-id.h | 1 + include/net.h | 187 ++++++++---- net/eth.c | 521 +++++++++++++++++++++++++++++----- net/net.c | 17 +- net/nfs.c | 2 +- net/tftp.c | 2 +- test/dm/Makefile | 5 +- test/dm/eth.c | 129 +++++++++ test/dm/test.dts | 20 ++ 28 files changed, 1466 insertions(+), 154 deletions(-) create mode 100644 arch/sandbox/cpu/eth-raw-os.c create mode 100644 arch/sandbox/include/asm/eth-raw-os.h create mode 100644 drivers/net/sandbox-raw.c create mode 100644 drivers/net/sandbox.c create mode 100644 test/dm/eth.c
-- 1.7.11.5
Regards, Simon

On Sun, Mar 1, 2015 at 10:13 AM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com
wrote:
Add support for the Ethernet MAC controllers. Phy support will come
later.
I am still leaving this as an RFC because I plan to add real board
support
before committing to mainline. When it is acceptable / accepted, I will
push it
as a dev branch on the net repo until a real device is supported. If any required changes are discovered in the process of supporting a real
device I
will send those as a patch against the dev branch, but then squash
before
sending the non-RFC version. I plan to rebase when the merge window
opens
anyway.
If desired, let me know which of the non-DM related prerequisite
patches are
wanted for this release.
I've added unit tests to verify functionality.
There is an additional driver for sandbox that bridges to the RAW Ethernet API in Linux which lets you test with real traffic. It now supports localhost as well (the 'lo' interface).
I've got some comments queued up the the series so will send those soon (never got to it this week so am catching up!). I wanted to try it out on a board to see how things look. The short answer is that it works really nicely on sunxi. I'll send some patches that I needed, hopefully that doesn't duplicate any work you have done.
It's great that works on your board without much effort. Looking at those patches I wouldn't say it duplicates much effort. It's more like your changes are a stop-gap to my efforts, which makes me less inclined to wait for all of the additional phy and mdio driver-model changes to be complete before integrating the dm-eth support to mainline.
In terms of getting this into mainline, I'd be happy to use u-boot-dm/next if that suits you and Tom. There are series for PCI and USB to sort out, and if the last merge window is any indication it's a real struggle to get multiple large series applied within the merge window when there are dependencies between them.
That makes sense to me. Since it is a next branch, we are still agreeing that the branch will be rebased on top of the release, correct?
Some general comments that I will put here for want of a better place:
- it would be good to have the DM code in drivers/net/eth-uclass.c at
some point
I completely agree. I moved it there probably 3 different times locally in slightly different ways and backed it out each time. I think it should be a follow-on clean-up patch. It makes this initial patch series messier than I wanted (hence I backed it out). That is the long-term goal.
- struct eth_pdata is used by the uclass and is common to all drivers,
but I wonder if we will find that drivers want to add their own private platdata? I added phy_interface but that is generic. Let's see.
Yeah, I think that's something that can be revisited pretty easily if the need becomes clear.
- I think the recv() method should change before long. The
NetReceive() call should be made from the uclass since it is common to all drivers. Then the recv() method can return a packet if it finds one, but not submit it for processing
I agree. I never liked how it was laid out and now is a great opportunity to change it since every driver has to be touched anyway.
One interesting point for me is that you have taken a slightly more ambitious approach with the conversion by not reusing eth_device. That seems to have have worked out well and makes me think I could revisit SPI flash perhaps and do the same.
I agree that it's nicer to get rid of the extra wrapping structure. Naturally the refactor could happen any time, but it seemed simple enough to just do now.
Changes in v4: -New to v4 -Fix compile regression in !DM_ETH case -New to v4 -New to v4 -New to v4 -New to v4 -New to v4
If you put this in a patch, patman will remove duplicates in the cover
letter.
Series-process-log: uniq
You can also sort with:
Series-process-log: sort, uniq
Thanks for the tip. Any reason these are not enabled by default?
-Redo the seq / probe implementation --Don't prevent eth_initialize on driver model --Use eth_initialize to probe all devices and write_hwaddr --Look up MAC address in post-probe --Include ethprime handling in eth_initialize --If current == NULL, always check if there is a device available in
eth_get_dev
--Move env init call from uclass init to eth_initialize --Print the alias in eth_initialize -Stop handling selecting a new "current" in pre-unbind as it will now
work itself out by clearing the pointer
-Change -1 returns to error constants -Remove bd_t *bis from dm eth_ops init function -Add documentation to the structures -Add a helper function for eth_uclass_priv -Change puts to printf -Add eth_get_ops helper -Rename init() to start() in ops -Rename halt() to stop() in ops -Remove checks for driver==NULL -Remove priv pointer in per-device priv struct (drivers already get
their own directly from DM)
-Cleaned up sandbox EXTRA_ENV define -Moved config to Kconfig -Removed checks on priv != NULL and added protection in uclass instead -Use only the seq from DM to find aliases -Load from ethprime on eth_initialize() -Added testing for ethrotate -Add ability to disable ping reply in sandbox eth driver -Updated expected behavior based on changes to the NetLoop -Added comments to README.sandbox -Use accessors for platdata and priv -Add comments to priv struct definition -Move os file to arch -Cleanup var definition order -Moved config to Kconfig -Clean up the interface to sandbox's eth-raw-os by passing priv to
raw-os
-Fixed the MAC address limitation (now all traffic uses MAC address
from env)
-New to v4 -Added support for the 'lo' network interface
Changes in v3: -Reorder dm test makefile -Move the get_dev_by_* protos to also be !DM_ETH like the impl -Correct the pre_unbind logic -Correct failure chaining from bind to probe to init --Fail init if not activated --Fail probe if ethaddr not set -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the
previous selection
-Allow current eth dev to be NULL -Fixed blank line formatting for variable declaration -Added 2 more ethaddr to sandbox -Print which device in the debug write hwaddr -Prevent a crash if memory is not allocated -Added dm eth testing -Added support for aliases -Added support for ethprime -Added testing for netretry -Made the os raw packet support for sandbox eth build and work.
Changes in v2: -Updated comments -Removed extra parentheses -Changed eth_uclass_priv local var names to be uc_priv -Update error codes -Cause an invalid name to fail binding -Rebase on top of dm/master -Stop maintaining our own index and use DM seq now that it works for
our needs
-Move the hwaddr to platdata so that its memory is allocated at bind
when we need it
-Prevent device from being probed before used by a command (i.e. before
eth_init()).
-Change printfs to debug in sandbox driver -Remove unused priv struct for sandbox driver -Change printfs to debug in sandbox driver -Move static data to priv -Move fake hwaddr to the device tree -Added the raw packet proof-of-concept patch.
Joe Hershberger (23): test: dm: Reorder the objects to build common: Make sure arch-specific map_sysmem() is defined net: Provide a function to get the current MAC address net: Rename helper function to be more clear net: Remove unneeded "extern" in net.h net: Refactor in preparation for driver model net: Change return codes from net/eth.c to use errorno constants net: Use int instead of u8 for boolean flag net: Remove the bd* parameter from net stack functions net: Make netretry actually do something net: Access mapped physmem in net functions dm: eth: Add basic driver model support to Ethernet stack sandbox: eth: Add network support to sandbox sandbox: eth: Add ARP and PING response to sandbox driver test: dm: eth: Add tests for the eth dm implementation dm: eth: Add support for aliases dm: eth: Add support for ethprime env var test: dm: eth: Add testing for ethrotate env var sandbox: eth: Add ability to disable ping reply in sandbox eth driver test: dm: net: Add a test of the netretry behavior sandbox: eth: Add a bridge to a real network for sandbox sandbox: Enable DHCP and IP defrag sandbox: eth: Add support for using the 'lo' interface
arch/mips/mach-au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- arch/sandbox/Kconfig | 12 + arch/sandbox/cpu/Makefile | 10 + arch/sandbox/cpu/eth-raw-os.c | 198 +++++++++++++ arch/sandbox/dts/sandbox.dts | 21 ++ arch/sandbox/include/asm/eth-raw-os.h | 40 +++ board/sandbox/README.sandbox | 17 +- common/board_r.c | 2 +- common/cmd_bdinfo.c | 2 + drivers/net/Kconfig | 28 ++ drivers/net/Makefile | 2 + drivers/net/netconsole.c | 4 +- drivers/net/sandbox-raw.c | 163 +++++++++++ drivers/net/sandbox.c | 200 +++++++++++++ include/common.h | 4 +- include/configs/sandbox.h | 25 +- include/dm/uclass-id.h | 1 + include/net.h | 187 ++++++++---- net/eth.c | 521
+++++++++++++++++++++++++++++-----
net/net.c | 17 +- net/nfs.c | 2 +- net/tftp.c | 2 +- test/dm/Makefile | 5 +- test/dm/eth.c | 129 +++++++++ test/dm/test.dts | 20 ++ 28 files changed, 1466 insertions(+), 154 deletions(-) create mode 100644 arch/sandbox/cpu/eth-raw-os.c create mode 100644 arch/sandbox/include/asm/eth-raw-os.h create mode 100644 drivers/net/sandbox-raw.c create mode 100644 drivers/net/sandbox.c create mode 100644 test/dm/eth.c
-- 1.7.11.5
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi Joe,
On 1 March 2015 at 15:12, Joe Hershberger joe.hershberger@gmail.com wrote:
On Sun, Mar 1, 2015 at 10:13 AM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 24 February 2015 at 17:02, Joe Hershberger joe.hershberger@ni.com wrote:
Add support for the Ethernet MAC controllers. Phy support will come later.
I am still leaving this as an RFC because I plan to add real board support before committing to mainline. When it is acceptable / accepted, I will push it as a dev branch on the net repo until a real device is supported. If any required changes are discovered in the process of supporting a real device I will send those as a patch against the dev branch, but then squash before sending the non-RFC version. I plan to rebase when the merge window opens anyway.
If desired, let me know which of the non-DM related prerequisite patches are wanted for this release.
I've added unit tests to verify functionality.
There is an additional driver for sandbox that bridges to the RAW Ethernet API in Linux which lets you test with real traffic. It now supports localhost as well (the 'lo' interface).
I've got some comments queued up the the series so will send those soon (never got to it this week so am catching up!). I wanted to try it out on a board to see how things look. The short answer is that it works really nicely on sunxi. I'll send some patches that I needed, hopefully that doesn't duplicate any work you have done.
It's great that works on your board without much effort. Looking at those patches I wouldn't say it duplicates much effort. It's more like your changes are a stop-gap to my efforts, which makes me less inclined to wait for all of the additional phy and mdio driver-model changes to be complete before integrating the dm-eth support to mainline.
In terms of getting this into mainline, I'd be happy to use u-boot-dm/next if that suits you and Tom. There are series for PCI and USB to sort out, and if the last merge window is any indication it's a real struggle to get multiple large series applied within the merge window when there are dependencies between them.
That makes sense to me. Since it is a next branch, we are still agreeing that the branch will be rebased on top of the release, correct?
Yes, once it is in u-boot-dm/next I'll keep it rebased. But since we are at RC2 I don't expect much effort there.
I want to do this because I originally planned to get PCI into the current release, but found there were just too many patches to respin and apply during the merge window, and I didn't get to it. This will make it easier.
Some general comments that I will put here for want of a better place:
- it would be good to have the DM code in drivers/net/eth-uclass.c at some
point
I completely agree. I moved it there probably 3 different times locally in slightly different ways and backed it out each time. I think it should be a follow-on clean-up patch. It makes this initial patch series messier than I wanted (hence I backed it out). That is the long-term goal.
- struct eth_pdata is used by the uclass and is common to all drivers,
but I wonder if we will find that drivers want to add their own private platdata? I added phy_interface but that is generic. Let's see.
Yeah, I think that's something that can be revisited pretty easily if the need becomes clear.
- I think the recv() method should change before long. The
NetReceive() call should be made from the uclass since it is common to all drivers. Then the recv() method can return a packet if it finds one, but not submit it for processing
I agree. I never liked how it was laid out and now is a great opportunity to change it since every driver has to be touched anyway.
One interesting point for me is that you have taken a slightly more ambitious approach with the conversion by not reusing eth_device. That seems to have have worked out well and makes me think I could revisit SPI flash perhaps and do the same.
I agree that it's nicer to get rid of the extra wrapping structure. Naturally the refactor could happen any time, but it seemed simple enough to just do now.
All sounds good.
Changes in v4: -New to v4 -Fix compile regression in !DM_ETH case -New to v4 -New to v4 -New to v4 -New to v4 -New to v4
If you put this in a patch, patman will remove duplicates in the cover letter.
Series-process-log: uniq
You can also sort with:
Series-process-log: sort, uniq
Thanks for the tip. Any reason these are not enabled by default?
From memory I think some people didn't want their change logs to be
reordered (perhaps because they use more than one line per entry, which I never do).
I suppose we could change it and see if anyone sqeals!
[snip]
Regards, Simon

On Sun, Mar 1, 2015 at 10:13 AM, Simon Glass sjg@chromium.org wrote:
[snip]
- I think the recv() method should change before long. The
NetReceive() call should be made from the uclass since it is common to all drivers. Then the recv() method can return a packet if it finds one, but not submit it for processing
I looked into doing this and I think it may be more of a step backward. Currently devices can directly hand their DMA buffers to the network stack. With this change, most drivers would be forced to memcpy each packet into the supplied buffer.
I do plan to rename the function, though.
-Joe

Hi Joe,
On 3 March 2015 at 15:29, Joe Hershberger joe.hershberger@gmail.com wrote:
On Sun, Mar 1, 2015 at 10:13 AM, Simon Glass sjg@chromium.org wrote:
[snip]
- I think the recv() method should change before long. The
NetReceive() call should be made from the uclass since it is common to all drivers. Then the recv() method can return a packet if it finds one, but not submit it for processing
I looked into doing this and I think it may be more of a step backward. Currently devices can directly hand their DMA buffers to the network stack. With this change, most drivers would be forced to memcpy each packet into the supplied buffer.
I don't see why. The uclass can request the address and length of the buffer.
int (*recv)(char **buffp, int **lenp);
I do plan to rename the function, though.
OK.
Regards, Simon

Hi Simon,
On Tue, Mar 3, 2015 at 5:14 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 3 March 2015 at 15:29, Joe Hershberger joe.hershberger@gmail.com
wrote:
On Sun, Mar 1, 2015 at 10:13 AM, Simon Glass sjg@chromium.org wrote:
[snip]
- I think the recv() method should change before long. The
NetReceive() call should be made from the uclass since it is common to all drivers. Then the recv() method can return a packet if it finds one, but not submit it for processing
I looked into doing this and I think it may be more of a step backward. Currently devices can directly hand their DMA buffers to the network
stack.
With this change, most drivers would be forced to memcpy each packet
into
the supplied buffer.
I don't see why. The uclass can request the address and length of the
buffer.
int (*recv)(char **buffp, int **lenp);
That works... I think I'll return the length though. I don't see much value in having a pointer to the length.
int (*recv)(uchar **packetp);
-Joe

Hi Joe,
On 3 March 2015 at 16:32, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Tue, Mar 3, 2015 at 5:14 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 3 March 2015 at 15:29, Joe Hershberger joe.hershberger@gmail.com wrote:
On Sun, Mar 1, 2015 at 10:13 AM, Simon Glass sjg@chromium.org wrote:
[snip]
- I think the recv() method should change before long. The
NetReceive() call should be made from the uclass since it is common to all drivers. Then the recv() method can return a packet if it finds one, but not submit it for processing
I looked into doing this and I think it may be more of a step backward. Currently devices can directly hand their DMA buffers to the network stack. With this change, most drivers would be forced to memcpy each packet into the supplied buffer.
I don't see why. The uclass can request the address and length of the buffer.
int (*recv)(char **buffp, int **lenp);
That works... I think I'll return the length though. I don't see much value in having a pointer to the length.
int (*recv)(uchar **packetp);
LGTM.
Regards, Simon

Add support for the Ethernet MAC controllers. Phy support will come later.
Switching from RFC to a patch series to be applied to dm/master as a staging area for this series to make it happen more quickly when the window opens.
If desired, let me know which of the non-DM related prerequisite patches are wanted for this release.
I've added unit tests to verify functionality.
There is an additional driver for sandbox that bridges to the RAW Ethernet API in Linux which lets you test with real traffic. It now supports localhost as well (the 'lo' interface).
Changes in v5: -Add a note to doc/README.drivers.eth about its obsolescence -Add details about lo support to the README -Added a comment about devname -Added a test for skipping un-probe-able devices -Added comments about test cases -Added fallback for setting promiscuous mode -Added help to Kconfig -Added help to the sandbox eth mock driver Kconfig entry -Added more details and examples in the README -Check for NULL when reading fdt for host interface -Check for malloc failure -Expanded the Kconfig help -Fix compile error on !DM_ETH -Fixed warning from missing declaration -Include new mapmem.h header -Moved dm/ header -Moved to a separate header mapmem.h -New to v5 -Only check for alias if the name is long enough -Remove cast of pointer passed to free -Remove socket timeout -Remove the empty sb_eth_raw_remove function -Return -errno in from send and recv -Return errno from recv -Separate init to 2 helper static functions -Set the socket to non-blocking -Simplify sandbox eth driver by switching from int array to byte array -Switch priv from packet buffer to a pointer to net_rx_packets[0] -Switched to function to control state of mock driver -Unmap memory for consistency -Use INADDR_LOOPBACK -Use a function call to change mock driver behavior -Use local var for priv in eth_get_dev() -Use more verbose comments -Use net_rx_packets instead of a stack buffer
Changes in v4: --Don't prevent eth_initialize on driver model --If current == NULL, always check if there is a device available in eth_get_dev --Include ethprime handling in eth_initialize --Look up MAC address in post-probe --Move env init call from uclass init to eth_initialize --Print the alias in eth_initialize --Use eth_initialize to probe all devices and write_hwaddr -Add a helper function for eth_uclass_priv -Add ability to disable ping reply in sandbox eth driver -Add comments to priv struct definition -Add documentation to the structures -Add eth_get_ops helper -Added comments to README.sandbox -Added support for the 'lo' network interface -Added testing for ethrotate -Change -1 returns to error constants -Change puts to printf -Clean up the interface to sandbox's eth-raw-os by passing priv to raw-os -Cleaned up sandbox EXTRA_ENV define -Cleanup var definition order -Fix compile regression in !DM_ETH case -Fixed the MAC address limitation (now all traffic uses MAC address from env) -Load from ethprime on eth_initialize() -Move os file to arch -Moved config to Kconfig -New to v4 -Redo the seq / probe implementation -Remove bd_t *bis from dm eth_ops init function -Remove checks for driver==NULL -Remove priv pointer in per-device priv struct (drivers already get their own directly from DM) -Removed checks on priv != NULL and added protection in uclass instead -Rename halt() to stop() in ops -Rename init() to start() in ops -Stop handling selecting a new "current" in pre-unbind as it will now work itself out by clearing the pointer -Updated expected behavior based on changes to the NetLoop -Use accessors for platdata and priv -Use only the seq from DM to find aliases
Changes in v3: --Fail init if not activated --Fail probe if ethaddr not set -Added 2 more ethaddr to sandbox -Added dm eth testing -Added support for aliases -Added support for ethprime -Added testing for netretry -Allow current eth dev to be NULL -Correct failure chaining from bind to probe to init -Correct the pre_unbind logic -Fixed blank line formatting for variable declaration -Made the os raw packet support for sandbox eth build and work. -Move the get_dev_by_* protos to also be !DM_ETH like the impl -Prevent a crash if memory is not allocated -Print which device in the debug write hwaddr -Reorder dm test makefile -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the previous selection
Changes in v2: -Added the raw packet proof-of-concept patch. -Cause an invalid name to fail binding -Change printfs to debug in sandbox driver -Changed eth_uclass_priv local var names to be uc_priv -Move fake hwaddr to the device tree -Move static data to priv -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()). -Rebase on top of dm/master -Remove unused priv struct for sandbox driver -Removed extra parentheses -Stop maintaining our own index and use DM seq now that it works for our needs -Update error codes -Updated comments
Joe Hershberger (27): test: dm: Reorder the objects to build common: Make sure arch-specific map_sysmem() is defined net: Provide a function to get the current MAC address net: Rename helper function to be more clear net: Remove unneeded "extern" in net.h net: Refactor in preparation for driver model net: Change return codes from net/eth.c to use errorno constants net: Use int instead of u8 for boolean flag net: Remove the bd* parameter from net stack functions net: Make netretry actually do something net: Access mapped physmem in net functions cmd: net: Clean up return codes dm: eth: Add basic driver model support to Ethernet stack net: Clean up network stack names used in DM drivers dm: eth: Pass the packet pointer as a parameter to recv sandbox: eth: Add network support to sandbox sandbox: eth: Add ARP and PING response to sandbox driver test: dm: eth: Add tests for the eth dm implementation dm: eth: Add support for aliases dm: eth: Add support for ethprime env var test: dm: eth: Add testing for ethrotate env var sandbox: eth: Add ability to disable ping reply in sandbox eth driver test: dm: net: Add a test of the netretry behavior sandbox: eth: Add a bridge to a real network for sandbox sandbox: Enable DHCP and IP defrag sandbox: eth: Add support for using the 'lo' interface net: Improve error handling
arch/arm/lib/bootm.c | 1 + arch/mips/mach-au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- arch/sandbox/Kconfig | 12 + arch/sandbox/cpu/Makefile | 10 + arch/sandbox/cpu/eth-raw-os.c | 249 +++++++++++++++ arch/sandbox/dts/sandbox.dts | 21 ++ arch/sandbox/include/asm/eth-raw-os.h | 40 +++ arch/sandbox/include/asm/eth.h | 15 + board/sandbox/README.sandbox | 78 ++++- common/board_f.c | 1 + common/board_r.c | 3 +- common/bootm.c | 1 + common/cmd_bdinfo.c | 2 + common/cmd_bootm.c | 1 + common/cmd_demo.c | 1 + common/cmd_fat.c | 1 + common/cmd_fdt.c | 1 + common/cmd_lzmadec.c | 1 + common/cmd_md5sum.c | 1 + common/cmd_mem.c | 1 + common/cmd_net.c | 45 ++- common/cmd_nvedit.c | 1 + common/cmd_pxe.c | 1 + common/cmd_sf.c | 1 + common/cmd_source.c | 1 + common/cmd_trace.c | 1 + common/cmd_ximg.c | 1 + common/hash.c | 1 + common/image-fdt.c | 1 + common/image-fit.c | 1 + common/image.c | 1 + common/iotrace.c | 1 + common/lcd.c | 1 + common/malloc_simple.c | 1 + doc/README.drivers.eth | 6 + drivers/demo/demo-simple.c | 1 + drivers/i2c/i2c-uniphier-f.c | 1 + drivers/i2c/i2c-uniphier.c | 1 + drivers/mtd/spi/sf_probe.c | 1 + drivers/net/Kconfig | 42 +++ drivers/net/Makefile | 2 + drivers/net/netconsole.c | 4 +- drivers/net/sandbox-raw.c | 165 ++++++++++ drivers/net/sandbox.c | 201 ++++++++++++ drivers/serial/ns16550.c | 1 + drivers/serial/serial_uniphier.c | 1 + fs/fs.c | 1 + include/common.h | 17 - include/configs/sandbox.h | 25 +- include/dm/uclass-id.h | 1 + include/mapmem.h | 32 ++ include/net.h | 199 ++++++++---- lib/trace.c | 1 + net/eth.c | 578 ++++++++++++++++++++++++++++++---- net/net.c | 67 ++-- net/nfs.c | 6 +- net/tftp.c | 6 +- test/compression.c | 1 + test/dm/Makefile | 5 +- test/dm/cmd_dm.c | 1 + test/dm/eth.c | 156 +++++++++ test/dm/test.dts | 20 ++ 65 files changed, 1838 insertions(+), 210 deletions(-) create mode 100644 arch/sandbox/cpu/eth-raw-os.c create mode 100644 arch/sandbox/include/asm/eth-raw-os.h create mode 100644 arch/sandbox/include/asm/eth.h create mode 100644 drivers/net/sandbox-raw.c create mode 100644 drivers/net/sandbox.c create mode 100644 include/mapmem.h create mode 100644 test/dm/eth.c

Signed-off-by: Joe Hershberger joe.hershberger@ni.com Acked-by: Simon Glass sjg@chromium.org
---
Changes in v5: None Changes in v4: None Changes in v3: -Reorder dm test makefile
Changes in v2: None
test/dm/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/dm/Makefile b/test/dm/Makefile index 612aa95..1d9148f 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_DM_TEST) += core.o obj-$(CONFIG_DM_TEST) += ut.o ifneq ($(CONFIG_SANDBOX),) obj-$(CONFIG_DM_GPIO) += gpio.o -obj-$(CONFIG_DM_SPI) += spi.o -obj-$(CONFIG_DM_SPI_FLASH) += sf.o obj-$(CONFIG_DM_I2C) += i2c.o +obj-$(CONFIG_DM_SPI_FLASH) += sf.o +obj-$(CONFIG_DM_SPI) += spi.o endif

In the case where the arch defines a custom map_sysmem(), make sure that including just common.h is sufficient to have these functions as they are when the arch does not override it.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v5: -Moved to a separate header mapmem.h
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
arch/arm/lib/bootm.c | 1 + common/board_f.c | 1 + common/board_r.c | 1 + common/bootm.c | 1 + common/cmd_bootm.c | 1 + common/cmd_demo.c | 1 + common/cmd_fat.c | 1 + common/cmd_fdt.c | 1 + common/cmd_lzmadec.c | 1 + common/cmd_md5sum.c | 1 + common/cmd_mem.c | 1 + common/cmd_nvedit.c | 1 + common/cmd_pxe.c | 1 + common/cmd_sf.c | 1 + common/cmd_source.c | 1 + common/cmd_trace.c | 1 + common/cmd_ximg.c | 1 + common/hash.c | 1 + common/image-fdt.c | 1 + common/image-fit.c | 1 + common/image.c | 1 + common/iotrace.c | 1 + common/lcd.c | 1 + common/malloc_simple.c | 1 + drivers/demo/demo-simple.c | 1 + drivers/i2c/i2c-uniphier-f.c | 1 + drivers/i2c/i2c-uniphier.c | 1 + drivers/mtd/spi/sf_probe.c | 1 + drivers/serial/ns16550.c | 1 + drivers/serial/serial_uniphier.c | 1 + fs/fs.c | 1 + include/common.h | 17 ----------------- include/mapmem.h | 32 ++++++++++++++++++++++++++++++++ lib/trace.c | 1 + test/compression.c | 1 + test/dm/cmd_dm.c | 1 + 36 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 include/mapmem.h
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index 0c1298a..42b052c 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -18,6 +18,7 @@ #include <u-boot/zlib.h> #include <asm/byteorder.h> #include <libfdt.h> +#include <mapmem.h> #include <fdt_support.h> #include <asm/bootm.h> #include <asm/secure.h> diff --git a/common/board_f.c b/common/board_f.c index 4d8b8a6..1b7e7d9 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -23,6 +23,7 @@ #include <i2c.h> #include <initcall.h> #include <logbuff.h> +#include <mapmem.h>
/* TODO: Can we move these into arch/ headers? */ #ifdef CONFIG_8xx diff --git a/common/board_r.c b/common/board_r.c index 4fcd4f6..af0f274 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -33,6 +33,7 @@ #endif #include <logbuff.h> #include <malloc.h> +#include <mapmem.h> #ifdef CONFIG_BITBANGMII #include <miiphy.h> #endif diff --git a/common/bootm.c b/common/bootm.c index 34f60bb..6842029 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -13,6 +13,7 @@ #include <fdt_support.h> #include <lmb.h> #include <malloc.h> +#include <mapmem.h> #include <asm/io.h> #include <linux/lzo.h> #include <lzma/LzmaTypes.h> diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 48199bf..b3d3968 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -16,6 +16,7 @@ #include <image.h> #include <lmb.h> #include <malloc.h> +#include <mapmem.h> #include <nand.h> #include <asm/byteorder.h> #include <linux/compiler.h> diff --git a/common/cmd_demo.c b/common/cmd_demo.c index 8a10bdf..209dc4a 100644 --- a/common/cmd_demo.c +++ b/common/cmd_demo.c @@ -9,6 +9,7 @@
#include <common.h> #include <dm-demo.h> +#include <mapmem.h> #include <asm/io.h>
struct udevice *demo_dev; diff --git a/common/cmd_fat.c b/common/cmd_fat.c index c00fb28..aae993d 100644 --- a/common/cmd_fat.c +++ b/common/cmd_fat.c @@ -14,6 +14,7 @@ #include <net.h> #include <ata.h> #include <asm/io.h> +#include <mapmem.h> #include <part.h> #include <fat.h> #include <fs.h> diff --git a/common/cmd_fdt.c b/common/cmd_fdt.c index 48b3e70..682b655 100644 --- a/common/cmd_fdt.c +++ b/common/cmd_fdt.c @@ -15,6 +15,7 @@ #include <asm/global_data.h> #include <libfdt.h> #include <fdt_support.h> +#include <mapmem.h> #include <asm/io.h>
#define MAX_LEVEL 32 /* how deeply nested we will go */ diff --git a/common/cmd_lzmadec.c b/common/cmd_lzmadec.c index 7b0b3fd..1ad9ed6 100644 --- a/common/cmd_lzmadec.c +++ b/common/cmd_lzmadec.c @@ -12,6 +12,7 @@
#include <common.h> #include <command.h> +#include <mapmem.h> #include <asm/io.h>
#include <lzma/LzmaTools.h> diff --git a/common/cmd_md5sum.c b/common/cmd_md5sum.c index d22ace5..23bb81e 100644 --- a/common/cmd_md5sum.c +++ b/common/cmd_md5sum.c @@ -10,6 +10,7 @@
#include <common.h> #include <command.h> +#include <mapmem.h> #include <u-boot/md5.h> #include <asm/io.h>
diff --git a/common/cmd_mem.c b/common/cmd_mem.c index bcb3ee3..66a41da 100644 --- a/common/cmd_mem.c +++ b/common/cmd_mem.c @@ -20,6 +20,7 @@ #endif #include <hash.h> #include <inttypes.h> +#include <mapmem.h> #include <watchdog.h> #include <asm/io.h> #include <linux/compiler.h> diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 855808c..be792ae 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -31,6 +31,7 @@ #include <search.h> #include <errno.h> #include <malloc.h> +#include <mapmem.h> #include <watchdog.h> #include <linux/stddef.h> #include <asm/byteorder.h> diff --git a/common/cmd_pxe.c b/common/cmd_pxe.c index 7e32c95..96f963d 100644 --- a/common/cmd_pxe.c +++ b/common/cmd_pxe.c @@ -8,6 +8,7 @@ #include <common.h> #include <command.h> #include <malloc.h> +#include <mapmem.h> #include <linux/string.h> #include <linux/ctype.h> #include <errno.h> diff --git a/common/cmd_sf.c b/common/cmd_sf.c index 5c788e9..01c37de 100644 --- a/common/cmd_sf.c +++ b/common/cmd_sf.c @@ -10,6 +10,7 @@ #include <div64.h> #include <dm.h> #include <malloc.h> +#include <mapmem.h> #include <spi.h> #include <spi_flash.h>
diff --git a/common/cmd_source.c b/common/cmd_source.c index 6881bc9..d2a881d 100644 --- a/common/cmd_source.c +++ b/common/cmd_source.c @@ -19,6 +19,7 @@ #include <command.h> #include <image.h> #include <malloc.h> +#include <mapmem.h> #include <asm/byteorder.h> #include <asm/io.h> #if defined(CONFIG_8xx) diff --git a/common/cmd_trace.c b/common/cmd_trace.c index 8c630e6..1e62a1a 100644 --- a/common/cmd_trace.c +++ b/common/cmd_trace.c @@ -6,6 +6,7 @@
#include <common.h> #include <command.h> +#include <mapmem.h> #include <trace.h> #include <asm/io.h>
diff --git a/common/cmd_ximg.c b/common/cmd_ximg.c index 64b9186..8b8645c 100644 --- a/common/cmd_ximg.c +++ b/common/cmd_ximg.c @@ -15,6 +15,7 @@ #include <common.h> #include <command.h> #include <image.h> +#include <mapmem.h> #include <watchdog.h> #if defined(CONFIG_BZIP2) #include <bzlib.h> diff --git a/common/hash.c b/common/hash.c index d154d02..b4e3e80 100644 --- a/common/hash.c +++ b/common/hash.c @@ -14,6 +14,7 @@ #include <common.h> #include <command.h> #include <malloc.h> +#include <mapmem.h> #include <hw_sha.h> #include <asm/io.h> #include <asm/errno.h> diff --git a/common/image-fdt.c b/common/image-fdt.c index d9e4728..7e2da7b 100644 --- a/common/image-fdt.c +++ b/common/image-fdt.c @@ -14,6 +14,7 @@ #include <errno.h> #include <image.h> #include <libfdt.h> +#include <mapmem.h> #include <asm/io.h>
#ifndef CONFIG_SYS_FDT_PAD diff --git a/common/image-fit.c b/common/image-fit.c index 778d2a1..4eb4d42 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -16,6 +16,7 @@ #else #include <common.h> #include <errno.h> +#include <mapmem.h> #include <asm/io.h> DECLARE_GLOBAL_DATA_PTR; #endif /* !USE_HOSTCC*/ diff --git a/common/image.c b/common/image.c index a911aa9..f3277c9 100644 --- a/common/image.c +++ b/common/image.c @@ -27,6 +27,7 @@
#include <environment.h> #include <image.h> +#include <mapmem.h>
#if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT) #include <libfdt.h> diff --git a/common/iotrace.c b/common/iotrace.c index ced426e..2725563 100644 --- a/common/iotrace.c +++ b/common/iotrace.c @@ -7,6 +7,7 @@ #define IOTRACE_IMPL
#include <common.h> +#include <mapmem.h> #include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR; diff --git a/common/lcd.c b/common/lcd.c index f33942c..6982759 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -15,6 +15,7 @@ #include <linux/types.h> #include <stdio_dev.h> #include <lcd.h> +#include <mapmem.h> #include <watchdog.h> #include <asm/unaligned.h> #include <splash.h> diff --git a/common/malloc_simple.c b/common/malloc_simple.c index 64ae036..d445199 100644 --- a/common/malloc_simple.c +++ b/common/malloc_simple.c @@ -8,6 +8,7 @@
#include <common.h> #include <malloc.h> +#include <mapmem.h> #include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR; diff --git a/drivers/demo/demo-simple.c b/drivers/demo/demo-simple.c index 2bcb7df..f069748 100644 --- a/drivers/demo/demo-simple.c +++ b/drivers/demo/demo-simple.c @@ -10,6 +10,7 @@ #include <common.h> #include <dm.h> #include <dm-demo.h> +#include <mapmem.h> #include <asm/io.h>
static int simple_hello(struct udevice *dev, int ch) diff --git a/drivers/i2c/i2c-uniphier-f.c b/drivers/i2c/i2c-uniphier-f.c index 6707edd..ffa6ce5 100644 --- a/drivers/i2c/i2c-uniphier-f.c +++ b/drivers/i2c/i2c-uniphier-f.c @@ -13,6 +13,7 @@ #include <dm/root.h> #include <i2c.h> #include <fdtdec.h> +#include <mapmem.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/i2c/i2c-uniphier.c b/drivers/i2c/i2c-uniphier.c index 64a9ed8..760457f 100644 --- a/drivers/i2c/i2c-uniphier.c +++ b/drivers/i2c/i2c-uniphier.c @@ -13,6 +13,7 @@ #include <dm/root.h> #include <i2c.h> #include <fdtdec.h> +#include <mapmem.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 4103723..ffc4caa 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -13,6 +13,7 @@ #include <errno.h> #include <fdtdec.h> #include <malloc.h> +#include <mapmem.h> #include <spi.h> #include <spi_flash.h> #include <asm/io.h> diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index eb00f1c..61b36b6 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -8,6 +8,7 @@ #include <dm.h> #include <errno.h> #include <fdtdec.h> +#include <mapmem.h> #include <ns16550.h> #include <serial.h> #include <watchdog.h> diff --git a/drivers/serial/serial_uniphier.c b/drivers/serial/serial_uniphier.c index e8a1608..d36d20d 100644 --- a/drivers/serial/serial_uniphier.c +++ b/drivers/serial/serial_uniphier.c @@ -10,6 +10,7 @@ #include <asm/errno.h> #include <dm/device.h> #include <dm/platform_data/serial-uniphier.h> +#include <mapmem.h> #include <serial.h> #include <fdtdec.h>
diff --git a/fs/fs.c b/fs/fs.c index 483273f..ac0897d 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -17,6 +17,7 @@ #include <config.h> #include <errno.h> #include <common.h> +#include <mapmem.h> #include <part.h> #include <ext4fs.h> #include <fat.h> diff --git a/include/common.h b/include/common.h index 77c55c6..3ccc6f3 100644 --- a/include/common.h +++ b/include/common.h @@ -845,23 +845,6 @@ int cpu_disable(int nr); int cpu_release(int nr, int argc, char * const argv[]); #endif
-/* Define a null map_sysmem() if the architecture doesn't use it */ -# ifndef CONFIG_ARCH_MAP_SYSMEM -static inline void *map_sysmem(phys_addr_t paddr, unsigned long len) -{ - return (void *)(uintptr_t)paddr; -} - -static inline void unmap_sysmem(const void *vaddr) -{ -} - -static inline phys_addr_t map_to_sysmem(const void *ptr) -{ - return (phys_addr_t)(uintptr_t)ptr; -} -# endif - #endif /* __ASSEMBLY__ */
#ifdef CONFIG_PPC diff --git a/include/mapmem.h b/include/mapmem.h new file mode 100644 index 0000000..42ef3e8 --- /dev/null +++ b/include/mapmem.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __MAPMEM_H +#define __MAPMEM_H + +/* Define a null map_sysmem() if the architecture doesn't use it */ +# ifdef CONFIG_ARCH_MAP_SYSMEM +#include <asm/io.h> +# else +static inline void *map_sysmem(phys_addr_t paddr, unsigned long len) +{ + return (void *)(uintptr_t)paddr; +} + +static inline void unmap_sysmem(const void *vaddr) +{ +} + +static inline phys_addr_t map_to_sysmem(const void *ptr) +{ + return (phys_addr_t)(uintptr_t)ptr; +} +# endif + +#endif /* __MAPMEM_H */ diff --git a/lib/trace.c b/lib/trace.c index 711e5b5..ad5e07b 100644 --- a/lib/trace.c +++ b/lib/trace.c @@ -5,6 +5,7 @@ */
#include <common.h> +#include <mapmem.h> #include <trace.h> #include <asm/io.h> #include <asm/sections.h> diff --git a/test/compression.c b/test/compression.c index ea2e4ad..7ef3a8c 100644 --- a/test/compression.c +++ b/test/compression.c @@ -10,6 +10,7 @@ #include <bootm.h> #include <command.h> #include <malloc.h> +#include <mapmem.h> #include <asm/io.h>
#include <u-boot/zlib.h> diff --git a/test/dm/cmd_dm.c b/test/dm/cmd_dm.c index 79a674e..195815e 100644 --- a/test/dm/cmd_dm.c +++ b/test/dm/cmd_dm.c @@ -10,6 +10,7 @@ #include <common.h> #include <dm.h> #include <malloc.h> +#include <mapmem.h> #include <errno.h> #include <asm/io.h> #include <dm/root.h>

On 3 March 2015 at 19:40, Joe Hershberger joe.hershberger@ni.com wrote:
In the case where the arch defines a custom map_sysmem(), make sure that including just common.h is sufficient to have these functions as they are when the arch does not override it.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v5: -Moved to a separate header mapmem.h
Reviewed-by: Simon Glass sjg@chromium.org

The current implementation exposes the eth_device struct to code that needs to access the MAC address. Add a wrapper function for this to abstract away the pointer for this operation.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None
arch/mips/mach-au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- include/net.h | 8 ++++++++ net/net.c | 2 +- 6 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/arch/mips/mach-au1x00/au1x00_eth.c b/arch/mips/mach-au1x00/au1x00_eth.c index 39c5b6b..a47f088 100644 --- a/arch/mips/mach-au1x00/au1x00_eth.c +++ b/arch/mips/mach-au1x00/au1x00_eth.c @@ -238,7 +238,7 @@ static int au1x00_init(struct eth_device* dev, bd_t * bd){ }
/* Put mac addr in little endian */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() *mac_addr_high = (ea[5] << 8) | (ea[4] ) ; *mac_addr_low = (ea[3] << 24) | (ea[2] << 16) | (ea[1] << 8) | (ea[0] ) ; diff --git a/arch/powerpc/cpu/mpc8260/ether_fcc.c b/arch/powerpc/cpu/mpc8260/ether_fcc.c index f9f15b5..f777ba1 100644 --- a/arch/powerpc/cpu/mpc8260/ether_fcc.c +++ b/arch/powerpc/cpu/mpc8260/ether_fcc.c @@ -299,7 +299,7 @@ static int fec_init(struct eth_device* dev, bd_t *bis) * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc85xx/ether_fcc.c b/arch/powerpc/cpu/mpc85xx/ether_fcc.c index 166dc9e..58d4bfb 100644 --- a/arch/powerpc/cpu/mpc85xx/ether_fcc.c +++ b/arch/powerpc/cpu/mpc85xx/ether_fcc.c @@ -338,7 +338,7 @@ static int fec_init(struct eth_device* dev, bd_t *bis) * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc8xx/scc.c b/arch/powerpc/cpu/mpc8xx/scc.c index 251966b..66e4014 100644 --- a/arch/powerpc/cpu/mpc8xx/scc.c +++ b/arch/powerpc/cpu/mpc8xx/scc.c @@ -339,7 +339,7 @@ static int scc_init (struct eth_device *dev, bd_t * bis) pram_ptr->sen_gaddr3 = 0x0; /* Group Address Filter 3 (unused) */ pram_ptr->sen_gaddr4 = 0x0; /* Group Address Filter 4 (unused) */
-#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/include/net.h b/include/net.h index 43e3d28..6c76976 100644 --- a/include/net.h +++ b/include/net.h @@ -111,6 +111,14 @@ struct eth_device *eth_get_dev(void) { return eth_current; } + +static inline unsigned char *eth_get_ethaddr(void) +{ + if (eth_current) + return eth_current->enetaddr; + return NULL; +} + extern struct eth_device *eth_get_dev_by_name(const char *devname); extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ extern int eth_get_dev_index(void); /* get the device index */ diff --git a/net/net.c b/net/net.c index b60ce62..4b3c90e 100644 --- a/net/net.c +++ b/net/net.c @@ -275,7 +275,7 @@ static void NetInitLoop(void) env_changed_id = env_id; } if (eth_get_dev()) - memcpy(NetOurEther, eth_get_dev()->enetaddr, 6); + memcpy(NetOurEther, eth_get_ethaddr(), 6);
return; }

Make it clear that the helper is checking the addr, not setting it.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None
net/eth.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/net/eth.c b/net/eth.c index eac4f7b..65e8c77 100644 --- a/net/eth.c +++ b/net/eth.c @@ -153,11 +153,6 @@ static void eth_current_changed(void) setenv("ethact", NULL); }
-static int eth_address_set(unsigned char *addr) -{ - return memcmp(addr, "\0\0\0\0\0\0", 6); -} - int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -166,9 +161,9 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
- if (eth_address_set(env_enetaddr)) { - if (eth_address_set(dev->enetaddr) && - memcmp(dev->enetaddr, env_enetaddr, 6)) { + if (!is_zero_ether_addr(env_enetaddr)) { + if (!is_zero_ether_addr(dev->enetaddr) && + memcmp(dev->enetaddr, env_enetaddr, 6)) { printf("\nWarning: %s MAC addresses don't match:\n", dev->name); printf("Address in SROM is %pM\n", @@ -183,7 +178,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, dev->enetaddr); printf("\nWarning: %s using MAC address from net device\n", dev->name); - } else if (!(eth_address_set(dev->enetaddr))) { + } else if (is_zero_ether_addr(dev->enetaddr)) { printf("\nError: %s address not set.\n", dev->name); return -EINVAL;

Many of the functions in net.h were preceded extern needlessly. Removing them to limit the number of checkpatch.pl complaints.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 92 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 46 insertions(+), 46 deletions(-)
diff --git a/include/net.h b/include/net.h index 6c76976..b82a29d 100644 --- a/include/net.h +++ b/include/net.h @@ -97,11 +97,11 @@ struct eth_device { void *priv; };
-extern int eth_initialize(bd_t *bis); /* Initialize network subsystem */ -extern int eth_register(struct eth_device* dev);/* Register network device */ -extern int eth_unregister(struct eth_device *dev);/* Remove network device */ -extern void eth_try_another(int first_restart); /* Change the device */ -extern void eth_set_current(void); /* set nterface to ethcur var */ +int eth_initialize(bd_t *bis); /* Initialize network subsystem */ +int eth_register(struct eth_device *dev);/* Register network device */ +int eth_unregister(struct eth_device *dev);/* Remove network device */ +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */
/* get the current device MAC */ extern struct eth_device *eth_current; @@ -119,12 +119,12 @@ static inline unsigned char *eth_get_ethaddr(void) return NULL; }
-extern struct eth_device *eth_get_dev_by_name(const char *devname); -extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ -extern int eth_get_dev_index(void); /* get the device index */ -extern void eth_parse_enetaddr(const char *addr, uchar *enetaddr); -extern int eth_getenv_enetaddr(char *name, uchar *enetaddr); -extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr); +struct eth_device *eth_get_dev_by_name(const char *devname); +struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ +int eth_get_dev_index(void); /* get the device index */ +void eth_parse_enetaddr(const char *addr, uchar *enetaddr); +int eth_getenv_enetaddr(char *name, uchar *enetaddr); +int eth_setenv_enetaddr(char *name, const uchar *enetaddr);
/* * Get the hardware address for an ethernet interface . @@ -135,20 +135,20 @@ extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr); * Returns: * Return true if the address is valid. */ -extern int eth_getenv_enetaddr_by_index(const char *base_name, int index, - uchar *enetaddr); +int eth_getenv_enetaddr_by_index(const char *base_name, int index, + uchar *enetaddr);
-extern int usb_eth_initialize(bd_t *bi); -extern int eth_init(bd_t *bis); /* Initialize the device */ -extern int eth_send(void *packet, int length); /* Send a packet */ +int usb_eth_initialize(bd_t *bi); +int eth_init(bd_t *bis); /* Initialize the device */ +int eth_send(void *packet, int length); /* Send a packet */
#ifdef CONFIG_API -extern int eth_receive(void *packet, int length); /* Receive a packet*/ -extern void (*push_packet)(void *packet, int length); +int eth_receive(void *packet, int length); /* Receive a packet*/ +void (*push_packet)(void *packet, int length); #endif -extern int eth_rx(void); /* Check for received packets */ -extern void eth_halt(void); /* stop SCC */ -extern char *eth_get_name(void); /* get name of current device */ +int eth_rx(void); /* Check for received packets */ +void eth_halt(void); /* stop SCC */ +char *eth_get_name(void); /* get name of current device */
/* Set active state */ static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) @@ -469,25 +469,25 @@ extern IPaddr_t Mcast_addr; #endif
/* Initialize the network adapter */ -extern void net_init(void); -extern int NetLoop(enum proto_t); +void net_init(void); +int NetLoop(enum proto_t);
/* Shutdown adapters and cleanup */ -extern void NetStop(void); +void NetStop(void);
/* Load failed. Start again. */ -extern void NetStartAgain(void); +void NetStartAgain(void);
/* Get size of the ethernet header when we send */ -extern int NetEthHdrSize(void); +int NetEthHdrSize(void);
/* Set ethernet header; returns the size of the header */ -extern int NetSetEther(uchar *, uchar *, uint); -extern int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot); +int NetSetEther(uchar *, uchar *, uint); +int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot);
/* Set IP header */ -extern void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source); -extern void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, +void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source); +void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, int sport, int len);
/** @@ -521,12 +521,12 @@ unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new_sum); int ip_checksum_ok(const void *addr, unsigned nbytes);
/* Callbacks */ -extern rxhand_f *net_get_udp_handler(void); /* Get UDP RX packet handler */ -extern void net_set_udp_handler(rxhand_f *); /* Set UDP RX packet handler */ -extern rxhand_f *net_get_arp_handler(void); /* Get ARP RX packet handler */ -extern void net_set_arp_handler(rxhand_f *); /* Set ARP RX packet handler */ -extern void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */ -extern void NetSetTimeout(ulong, thand_f *);/* Set timeout handler */ +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 */ +void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */ +void NetSetTimeout(ulong, thand_f *);/* Set timeout handler */
/* Network loop state */ enum net_loop_state { @@ -559,11 +559,11 @@ static inline void NetSendPacket(uchar *pkt, int len) * @param sport Source UDP port * @param payload_len Length of data after the UDP header */ -extern int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, +int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int payload_len);
/* Processes a received packet */ -extern void NetReceive(uchar *, int); +void NetReceive(uchar *, int);
#ifdef CONFIG_NETCONSOLE void NcStart(void); @@ -711,28 +711,28 @@ static inline void eth_random_addr(uchar *addr) }
/* Convert an IP address to a string */ -extern void ip_to_string(IPaddr_t x, char *s); +void ip_to_string(IPaddr_t x, char *s);
/* Convert a string to ip address */ -extern IPaddr_t string_to_ip(const char *s); +IPaddr_t string_to_ip(const char *s);
/* Convert a VLAN id to a string */ -extern void VLAN_to_string(ushort x, char *s); +void VLAN_to_string(ushort x, char *s);
/* Convert a string to a vlan id */ -extern ushort string_to_VLAN(const char *s); +ushort string_to_VLAN(const char *s);
/* read a VLAN id from an environment variable */ -extern ushort getenv_VLAN(char *); +ushort getenv_VLAN(char *);
/* copy a filename (allow for "..." notation, limit length) */ -extern void copy_filename(char *dst, const char *src, int size); +void copy_filename(char *dst, const char *src, int size);
/* get a random source port */ -extern unsigned int random_port(void); +unsigned int random_port(void);
/* Update U-Boot over TFTP */ -extern int update_tftp(ulong addr); +int update_tftp(ulong addr);
/**********************************************************************/

Move some things around and organize things so that the driver model implementation will fit in more easily.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v5: -Fixed warning from missing declaration
Changes in v4: -Fix compile regression in !DM_ETH case
Changes in v3: -Move the get_dev_by_* protos to also be !DM_ETH like the impl
Changes in v2: None
include/net.h | 68 +++++++++++++++++++++++++------------------------- net/eth.c | 79 ++++++++++++++++++++++++++++++++--------------------------- 2 files changed, 78 insertions(+), 69 deletions(-)
diff --git a/include/net.h b/include/net.h index b82a29d..4cef00c 100644 --- a/include/net.h +++ b/include/net.h @@ -97,13 +97,9 @@ struct eth_device { void *priv; };
-int eth_initialize(bd_t *bis); /* Initialize network subsystem */ int eth_register(struct eth_device *dev);/* Register network device */ int eth_unregister(struct eth_device *dev);/* Remove network device */ -void eth_try_another(int first_restart); /* Change the device */ -void eth_set_current(void); /* set nterface to ethcur var */
-/* get the current device MAC */ extern struct eth_device *eth_current;
static inline __attribute__((always_inline)) @@ -111,7 +107,10 @@ struct eth_device *eth_get_dev(void) { return eth_current; } +struct eth_device *eth_get_dev_by_name(const char *devname); +struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */
+/* get the current device MAC */ static inline unsigned char *eth_get_ethaddr(void) { if (eth_current) @@ -119,8 +118,37 @@ static inline unsigned char *eth_get_ethaddr(void) return NULL; }
-struct eth_device *eth_get_dev_by_name(const char *devname); -struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ +/* Set active state */ +static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) +{ + eth_get_dev()->state = ETH_STATE_ACTIVE; + + return 0; +} +/* Set passive state */ +static inline __attribute__((always_inline)) void eth_halt_state_only(void) +{ + eth_get_dev()->state = ETH_STATE_PASSIVE; +} + +/* + * Set the hardware address for an ethernet interface based on 'eth%daddr' + * environment variable (or just 'ethaddr' if eth_number is 0). + * Args: + * base_name - base name for device (normally "eth") + * eth_number - value of %d (0 for first device of this type) + * Returns: + * 0 is success, non-zero is error status from driver. + */ +int eth_write_hwaddr(struct eth_device *dev, const char *base_name, + int eth_number); + +int usb_eth_initialize(bd_t *bi); + +int eth_initialize(bd_t *bis); /* Initialize network subsystem */ +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */ + int eth_get_dev_index(void); /* get the device index */ void eth_parse_enetaddr(const char *addr, uchar *enetaddr); int eth_getenv_enetaddr(char *name, uchar *enetaddr); @@ -138,7 +166,6 @@ int eth_setenv_enetaddr(char *name, const uchar *enetaddr); int eth_getenv_enetaddr_by_index(const char *base_name, int index, uchar *enetaddr);
-int usb_eth_initialize(bd_t *bi); int eth_init(bd_t *bis); /* Initialize the device */ int eth_send(void *packet, int length); /* Send a packet */
@@ -148,32 +175,7 @@ void (*push_packet)(void *packet, int length); #endif int eth_rx(void); /* Check for received packets */ void eth_halt(void); /* stop SCC */ -char *eth_get_name(void); /* get name of current device */ - -/* Set active state */ -static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) -{ - eth_get_dev()->state = ETH_STATE_ACTIVE; - - return 0; -} -/* Set passive state */ -static inline __attribute__((always_inline)) void eth_halt_state_only(void) -{ - eth_get_dev()->state = ETH_STATE_PASSIVE; -} - -/* - * Set the hardware address for an ethernet interface based on 'eth%daddr' - * environment variable (or just 'ethaddr' if eth_number is 0). - * Args: - * base_name - base name for device (normally "eth") - * eth_number - value of %d (0 for first device of this type) - * Returns: - * 0 is success, non-zero is error status from driver. - */ -int eth_write_hwaddr(struct eth_device *dev, const char *base_name, - int eth_number); +const char *eth_get_name(void); /* get name of current device */
#ifdef CONFIG_MCAST_TFTP int eth_mcast_join(IPaddr_t mcast_addr, u8 join); diff --git a/net/eth.c b/net/eth.c index 65e8c77..84919e0 100644 --- a/net/eth.c +++ b/net/eth.c @@ -55,6 +55,14 @@ static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index, return eth_setenv_enetaddr(enetvar, enetaddr); }
+static void eth_env_init(void) +{ + const char *s; + + s = getenv("bootfile"); + if (s != NULL) + copy_filename(BootFile, s, sizeof(BootFile)); +}
static int eth_mac_skip(int index) { @@ -64,6 +72,8 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void); + /* * CPU and board-specific Ethernet initializations. Aliased function * signals caller to move on @@ -87,6 +97,11 @@ static unsigned int eth_rcv_current, eth_rcv_last; static struct eth_device *eth_devices; struct eth_device *eth_current;
+static void eth_set_current_to_next(void) +{ + eth_current = eth_current->next; +} + struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -137,22 +152,6 @@ int eth_get_dev_index(void) return eth_current->index; }
-static void eth_current_changed(void) -{ - char *act = getenv("ethact"); - /* update current ethernet name */ - if (eth_current) { - if (act == NULL || strcmp(act, eth_current->name) != 0) - setenv("ethact", eth_current->name); - } - /* - * remove the variable completely if there is no active - * interface - */ - else if (act != NULL) - setenv("ethact", NULL); -} - int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -251,14 +250,6 @@ int eth_unregister(struct eth_device *dev) return 0; }
-static void eth_env_init(bd_t *bis) -{ - const char *s; - - if ((s = getenv("bootfile")) != NULL) - copy_filename(BootFile, s, sizeof(BootFile)); -} - int eth_initialize(bd_t *bis) { int num_devices = 0; @@ -274,7 +265,7 @@ int eth_initialize(bd_t *bis) phy_init(); #endif
- eth_env_init(bis); + eth_env_init();
/* * If board-specific initialization exists, call it. @@ -479,6 +470,22 @@ int eth_receive(void *packet, int length) } #endif /* CONFIG_API */
+static void eth_current_changed(void) +{ + char *act = getenv("ethact"); + /* update current ethernet name */ + if (eth_get_dev()) { + if (act == NULL || strcmp(act, eth_get_name()) != 0) + setenv("ethact", eth_get_name()); + } + /* + * remove the variable completely if there is no active + * interface + */ + else if (act != NULL) + setenv("ethact", NULL); +} + void eth_try_another(int first_restart) { static struct eth_device *first_failed; @@ -492,17 +499,17 @@ void eth_try_another(int first_restart) if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) return;
- if (!eth_current) + if (!eth_get_dev()) return;
if (first_restart) - first_failed = eth_current; + first_failed = eth_get_dev();
- eth_current = eth_current->next; + eth_set_current_to_next();
eth_current_changed();
- if (first_failed == eth_current) + if (first_failed == eth_get_dev()) NetRestartWrap = 1; }
@@ -513,7 +520,7 @@ void eth_set_current(void) struct eth_device *old_current; int env_id;
- if (!eth_current) /* XXX no current */ + if (!eth_get_dev()) /* XXX no current */ return;
env_id = get_env_id(); @@ -522,18 +529,18 @@ void eth_set_current(void) env_changed_id = env_id; } if (act != NULL) { - old_current = eth_current; + old_current = eth_get_dev(); do { - if (strcmp(eth_current->name, act) == 0) + if (strcmp(eth_get_name(), act) == 0) return; - eth_current = eth_current->next; - } while (old_current != eth_current); + eth_set_current_to_next(); + } while (old_current != eth_get_dev()); }
eth_current_changed(); }
-char *eth_get_name(void) +const char *eth_get_name(void) { - return eth_current ? eth_current->name : "unknown"; + return eth_get_dev() ? eth_get_dev()->name : "unknown"; }

Many functions returned -1 previously. Change them to return appropriate error codes.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v5: None Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
net/eth.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/net/eth.c b/net/eth.c index 84919e0..9ad15cd 100644 --- a/net/eth.c +++ b/net/eth.c @@ -227,7 +227,7 @@ int eth_unregister(struct eth_device *dev)
/* No device */ if (!eth_devices) - return -1; + return -ENODEV;
for (cur = eth_devices; cur->next != eth_devices && cur->next != dev; cur = cur->next) @@ -235,7 +235,7 @@ int eth_unregister(struct eth_device *dev)
/* Device not found */ if (cur->next != dev) - return -1; + return -ENODEV;
cur->next = dev->next;
@@ -368,7 +368,7 @@ int eth_init(bd_t *bis)
if (!eth_current) { puts("No ethernet found.\n"); - return -1; + return -ENODEV; }
/* Sync environment with network devices */ @@ -397,7 +397,7 @@ int eth_init(bd_t *bis) eth_try_another(0); } while (old_current != eth_current);
- return -1; + return -ETIMEDOUT; }
void eth_halt(void) @@ -413,7 +413,7 @@ void eth_halt(void) int eth_send(void *packet, int length) { if (!eth_current) - return -1; + return -ENODEV;
return eth_current->send(eth_current, packet, length); } @@ -421,7 +421,7 @@ int eth_send(void *packet, int length) int eth_rx(void) { if (!eth_current) - return -1; + return -ENODEV;
return eth_current->recv(eth_current); }

On some archs masking the parameter is inefficient, so don't use u8.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v5: None Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
include/net.h | 2 +- net/eth.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/net.h b/include/net.h index 4cef00c..ad20145 100644 --- a/include/net.h +++ b/include/net.h @@ -178,7 +178,7 @@ void eth_halt(void); /* stop SCC */ const char *eth_get_name(void); /* get name of current device */
#ifdef CONFIG_MCAST_TFTP -int eth_mcast_join(IPaddr_t mcast_addr, u8 join); +int eth_mcast_join(IPaddr_t mcast_addr, int join); u32 ether_crc(size_t len, unsigned char const *p); #endif
diff --git a/net/eth.c b/net/eth.c index 9ad15cd..b86994e 100644 --- a/net/eth.c +++ b/net/eth.c @@ -321,7 +321,7 @@ int eth_initialize(bd_t *bis) * mcast_addr: multicast ipaddr from which multicast Mac is made * join: 1=join, 0=leave. */ -int eth_mcast_join(IPaddr_t mcast_ip, u8 join) +int eth_mcast_join(IPaddr_t mcast_ip, int join) { u8 mcast_mac[6]; if (!eth_current || !eth_current->mcast)

This value is not used by the network stack and is available in the global data, so stop passing it around. For the one legacy function that still expects it (init op on old Ethernet drivers) pass in the global pointer version directly to avoid changing that interface.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v5: None Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
common/board_r.c | 2 +- drivers/net/netconsole.c | 4 ++-- include/net.h | 6 +++--- net/eth.c | 12 +++++++----- net/net.c | 7 +++---- 5 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/common/board_r.c b/common/board_r.c index af0f274..b882d9b 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -585,7 +585,7 @@ static int initr_bbmii(void) static int initr_net(void) { puts("Net: "); - eth_initialize(gd->bd); + eth_initialize(); #if defined(CONFIG_RESET_PHY_R) debug("Reset Ethernet PHY\n"); reset_phy(); diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 677c89f..87cea7a 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -193,11 +193,11 @@ static void nc_send_packet(const char *buf, int len)
if (eth->state != ETH_STATE_ACTIVE) { if (eth_is_on_demand_init()) { - if (eth_init(gd->bd) < 0) + if (eth_init() < 0) return; eth_set_last_protocol(NETCONS); } else - eth_init_state_only(gd->bd); + eth_init_state_only();
inited = 1; } diff --git a/include/net.h b/include/net.h index ad20145..10d38f8 100644 --- a/include/net.h +++ b/include/net.h @@ -119,7 +119,7 @@ static inline unsigned char *eth_get_ethaddr(void) }
/* Set active state */ -static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) +static inline __attribute__((always_inline)) int eth_init_state_only(void) { eth_get_dev()->state = ETH_STATE_ACTIVE;
@@ -145,7 +145,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
int usb_eth_initialize(bd_t *bi);
-int eth_initialize(bd_t *bis); /* Initialize network subsystem */ +int eth_initialize(void); /* Initialize network subsystem */ void eth_try_another(int first_restart); /* Change the device */ void eth_set_current(void); /* set nterface to ethcur var */
@@ -166,7 +166,7 @@ int eth_setenv_enetaddr(char *name, const uchar *enetaddr); int eth_getenv_enetaddr_by_index(const char *base_name, int index, uchar *enetaddr);
-int eth_init(bd_t *bis); /* Initialize the device */ +int eth_init(void); /* Initialize the device */ int eth_send(void *packet, int length); /* Send a packet */
#ifdef CONFIG_API diff --git a/net/eth.c b/net/eth.c index b86994e..66ecb79 100644 --- a/net/eth.c +++ b/net/eth.c @@ -12,6 +12,8 @@ #include <phy.h> #include <asm/errno.h>
+DECLARE_GLOBAL_DATA_PTR; + void eth_parse_enetaddr(const char *addr, uchar *enetaddr) { char *end; @@ -250,7 +252,7 @@ int eth_unregister(struct eth_device *dev) return 0; }
-int eth_initialize(bd_t *bis) +int eth_initialize(void) { int num_devices = 0; eth_devices = NULL; @@ -272,10 +274,10 @@ int eth_initialize(bd_t *bis) * If not, call a CPU-specific one */ if (board_eth_init != __def_eth_init) { - if (board_eth_init(bis) < 0) + if (board_eth_init(gd->bd) < 0) printf("Board Net Initialization Failed\n"); } else if (cpu_eth_init != __def_eth_init) { - if (cpu_eth_init(bis) < 0) + if (cpu_eth_init(gd->bd) < 0) printf("CPU Net Initialization Failed\n"); } else printf("Net Initialization Skipped\n"); @@ -362,7 +364,7 @@ u32 ether_crc(size_t len, unsigned char const *p) #endif
-int eth_init(bd_t *bis) +int eth_init(void) { struct eth_device *old_current, *dev;
@@ -387,7 +389,7 @@ int eth_init(bd_t *bis) do { debug("Trying %s\n", eth_current->name);
- if (eth_current->init(eth_current, bis) >= 0) { + if (eth_current->init(eth_current, gd->bd) >= 0) { eth_current->state = ETH_STATE_ACTIVE;
return 0; diff --git a/net/net.c b/net/net.c index 4b3c90e..e5ab07c 100644 --- a/net/net.c +++ b/net/net.c @@ -324,7 +324,6 @@ void net_init(void)
int NetLoop(enum proto_t protocol) { - bd_t *bd = gd->bd; int ret = -1;
NetRestarted = 0; @@ -337,12 +336,12 @@ int NetLoop(enum proto_t protocol) if (eth_is_on_demand_init() || protocol != NETCONS) { eth_halt(); eth_set_current(); - if (eth_init(bd) < 0) { + if (eth_init() < 0) { eth_halt(); return -1; } } else - eth_init_state_only(bd); + eth_init_state_only();
restart: #ifdef CONFIG_USB_KEYBOARD @@ -618,7 +617,7 @@ void NetStartAgain(void) #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER) eth_try_another(!NetRestarted); #endif - eth_init(gd->bd); + eth_init(); if (NetRestartWrap) { NetRestartWrap = 0; if (NetDevExists) {

netretry previously would only retry in one specific case (your MAC address is not set) and no other. This is basically useless. In the DM implementation for eth it turns this into a completely useless case since an un-configured MAC address results in not even entering the NetLoop. The behavior is now changed to retry any failed command (rotating through the eth adapters if ethrotate != no).
It also defaulted to retry forever. It is now changed to default to not retry
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v5: None Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
net/net.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/net/net.c b/net/net.c index e5ab07c..37b4aab 100644 --- a/net/net.c +++ b/net/net.c @@ -527,6 +527,8 @@ restart: (*x)(); }
+ if (net_state == NETLOOP_FAIL) + NetStartAgain();
switch (net_state) {
@@ -602,8 +604,10 @@ void NetStartAgain(void) retrycnt = 1; else retrycnt = simple_strtoul(nretry, NULL, 0); - } else - retry_forever = 1; + } else { + retrycnt = 0; + retry_forever = 0; + }
if ((!retry_forever) && (NetTryCount >= retrycnt)) { eth_halt();

Previously the net functions would access memory assuming physmem did not need to be mapped. In sandbox, that's not the case.
Now we map the physmem specified by the user in loadaddr to the buffer that represents that space.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v5: -Include new mapmem.h header -Unmap memory for consistency
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
net/nfs.c | 6 +++++- net/tftp.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/net/nfs.c b/net/nfs.c index 381b75f..8e05ae5 100644 --- a/net/nfs.c +++ b/net/nfs.c @@ -26,6 +26,7 @@ #include <command.h> #include <net.h> #include <malloc.h> +#include <mapmem.h> #include "nfs.h" #include "bootp.h"
@@ -93,7 +94,10 @@ store_block(uchar *src, unsigned offset, unsigned len) } else #endif /* CONFIG_SYS_DIRECT_FLASH_NFS */ { - (void)memcpy((void *)(load_addr + offset), src, len); + void *ptr = map_sysmem(load_addr + offset, len); + + memcpy(ptr, src, len); + unmap_sysmem(ptr); }
if (NetBootFileXferSize < (offset+len)) diff --git a/net/tftp.c b/net/tftp.c index 0a2c533..51c67be 100644 --- a/net/tftp.c +++ b/net/tftp.c @@ -8,6 +8,7 @@
#include <common.h> #include <command.h> +#include <mapmem.h> #include <net.h> #include "tftp.h" #include "bootp.h" @@ -184,7 +185,10 @@ store_block(int block, uchar *src, unsigned len) } else #endif /* CONFIG_SYS_DIRECT_FLASH_TFTP */ { - (void)memcpy((void *)(load_addr + offset), src, len); + void *ptr = map_sysmem(load_addr + offset, len); + + memcpy(ptr, src, len); + unmap_sysmem(ptr); } #ifdef CONFIG_MCAST_TFTP if (Multicast)

On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com wrote:
Previously the net functions would access memory assuming physmem did not need to be mapped. In sandbox, that's not the case.
Now we map the physmem specified by the user in loadaddr to the buffer that represents that space.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v5: -Include new mapmem.h header -Unmap memory for consistency
Reviewed-by: Simon Glass sjg@chromium.org
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
net/nfs.c | 6 +++++- net/tftp.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/net/nfs.c b/net/nfs.c index 381b75f..8e05ae5 100644 --- a/net/nfs.c +++ b/net/nfs.c @@ -26,6 +26,7 @@ #include <command.h> #include <net.h> #include <malloc.h> +#include <mapmem.h> #include "nfs.h" #include "bootp.h"
@@ -93,7 +94,10 @@ store_block(uchar *src, unsigned offset, unsigned len) } else #endif /* CONFIG_SYS_DIRECT_FLASH_NFS */ {
(void)memcpy((void *)(load_addr + offset), src, len);
void *ptr = map_sysmem(load_addr + offset, len);
memcpy(ptr, src, len);
unmap_sysmem(ptr); } if (NetBootFileXferSize < (offset+len))
diff --git a/net/tftp.c b/net/tftp.c index 0a2c533..51c67be 100644 --- a/net/tftp.c +++ b/net/tftp.c @@ -8,6 +8,7 @@
#include <common.h> #include <command.h> +#include <mapmem.h> #include <net.h> #include "tftp.h" #include "bootp.h" @@ -184,7 +185,10 @@ store_block(int block, uchar *src, unsigned len) } else #endif /* CONFIG_SYS_DIRECT_FLASH_TFTP */ {
(void)memcpy((void *)(load_addr + offset), src, len);
void *ptr = map_sysmem(load_addr + offset, len);
memcpy(ptr, src, len);
unmap_sysmem(ptr); }
#ifdef CONFIG_MCAST_TFTP if (Multicast) -- 1.7.11.5

The return codes in common/cmd_net.c had a number of inconsistencies. Update them to all use the enum from command.h
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
common/cmd_net.c | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-)
diff --git a/common/cmd_net.c b/common/cmd_net.c index 09489d4..3f52edc 100644 --- a/common/cmd_net.c +++ b/common/cmd_net.c @@ -44,10 +44,7 @@ U_BOOT_CMD( #ifdef CONFIG_CMD_TFTPPUT int do_tftpput(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - int ret; - - ret = netboot_common(TFTPPUT, cmdtp, argc, argv); - return ret; + return netboot_common(TFTPPUT, cmdtp, argc, argv); }
U_BOOT_CMD( @@ -217,7 +214,7 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc, if (strict_strtoul(argv[1], 16, &save_addr) < 0 || strict_strtoul(argv[2], 16, &save_size) < 0) { printf("Invalid address/size\n"); - return cmd_usage(cmdtp); + return CMD_RET_USAGE; } copy_filename(BootFile, argv[3], sizeof(BootFile)); break; @@ -230,7 +227,7 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,
if ((size = NetLoop(proto)) < 0) { bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); - return 1; + return CMD_RET_FAILURE; } bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);
@@ -240,7 +237,7 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc, /* done if no file was loaded (no errors though) */ if (size == 0) { bootstage_error(BOOTSTAGE_ID_NET_LOADED); - return 0; + return CMD_RET_SUCCESS; }
/* flush cache */ @@ -250,10 +247,10 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,
rcode = bootm_maybe_autostart(cmdtp, argv[0]);
- if (rcode < 0) - bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR); - else + if (rcode == CMD_RET_SUCCESS) bootstage_mark(BOOTSTAGE_ID_NET_DONE); + else + bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR); return rcode; }
@@ -261,7 +258,7 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc, static int do_ping(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { if (argc < 2) - return -1; + return CMD_RET_USAGE;
NetPingIP = string_to_ip(argv[1]); if (NetPingIP == 0) @@ -269,12 +266,12 @@ static int do_ping(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
if (NetLoop(PING) < 0) { printf("ping failed; host %s is not alive\n", argv[1]); - return 1; + return CMD_RET_FAILURE; }
printf("host %s is alive\n", argv[1]);
- return 0; + return CMD_RET_SUCCESS; }
U_BOOT_CMD( @@ -313,12 +310,12 @@ int do_cdp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) r = NetLoop(CDP); if (r < 0) { printf("cdp failed; perhaps not a CISCO switch?\n"); - return 1; + return CMD_RET_FAILURE; }
cdp_update_env();
- return 0; + return CMD_RET_SUCCESS; }
U_BOOT_CMD( @@ -337,13 +334,13 @@ int do_sntp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) NetNtpServerIP = getenv_IPaddr("ntpserverip"); if (NetNtpServerIP == 0) { printf("ntpserverip not set\n"); - return (1); + return CMD_RET_FAILURE; } } else { NetNtpServerIP = string_to_ip(argv[1]); if (NetNtpServerIP == 0) { printf("Bad NTP server IP address\n"); - return (1); + return CMD_RET_FAILURE; } }
@@ -356,10 +353,10 @@ int do_sntp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (NetLoop(SNTP) < 0) { printf("SNTP failed: host %pI4 not responding\n", &NetNtpServerIP); - return 1; + return CMD_RET_FAILURE; }
- return 0; + return CMD_RET_SUCCESS; }
U_BOOT_CMD( @@ -389,7 +386,7 @@ int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) */ if (strlen(argv[1]) >= 255) { printf("dns error: hostname too long\n"); - return 1; + return CMD_RET_FAILURE; }
NetDNSResolve = argv[1]; @@ -401,10 +398,10 @@ int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
if (NetLoop(DNS) < 0) { printf("dns lookup of %s failed, check setup\n", argv[1]); - return 1; + return CMD_RET_FAILURE; }
- return 0; + return CMD_RET_SUCCESS; }
U_BOOT_CMD( @@ -422,7 +419,7 @@ static int do_link_local(cmd_tbl_t *cmdtp, int flag, int argc, char tmp[22];
if (NetLoop(LINKLOCAL) < 0) - return 1; + return CMD_RET_FAILURE;
NetOurGatewayIP = 0; ip_to_string(NetOurGatewayIP, tmp); @@ -435,7 +432,7 @@ static int do_link_local(cmd_tbl_t *cmdtp, int flag, int argc, setenv("ipaddr", tmp); setenv("llipaddr", tmp); /* store this for next time */
- return 0; + return CMD_RET_SUCCESS; }
U_BOOT_CMD(

On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com wrote:
The return codes in common/cmd_net.c had a number of inconsistencies. Update them to all use the enum from command.h
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
common/cmd_net.c | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

First just add support for MAC drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v5: -Add a note to doc/README.drivers.eth about its obsolescence -Expanded the Kconfig help -Moved dm/ header -Use local var for priv in eth_get_dev()
Changes in v4: --Don't prevent eth_initialize on driver model --If current == NULL, always check if there is a device available in eth_get_dev --Include ethprime handling in eth_initialize --Look up MAC address in post-probe --Move env init call from uclass init to eth_initialize --Print the alias in eth_initialize --Use eth_initialize to probe all devices and write_hwaddr -Add a helper function for eth_uclass_priv -Add documentation to the structures -Add eth_get_ops helper -Change -1 returns to error constants -Change puts to printf -Redo the seq / probe implementation -Remove bd_t *bis from dm eth_ops init function -Remove checks for driver==NULL -Remove priv pointer in per-device priv struct (drivers already get their own directly from DM) -Rename halt() to stop() in ops -Rename init() to start() in ops -Stop handling selecting a new "current" in pre-unbind as it will now work itself out by clearing the pointer
Changes in v3: --Fail init if not activated --Fail probe if ethaddr not set -Allow current eth dev to be NULL -Correct failure chaining from bind to probe to init -Correct the pre_unbind logic -Fixed blank line formatting for variable declaration -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the previous selection
Changes in v2: -Cause an invalid name to fail binding -Changed eth_uclass_priv local var names to be uc_priv -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()). -Rebase on top of dm/master -Removed extra parentheses -Stop maintaining our own index and use DM seq now that it works for our needs -Update error codes -Updated comments
common/cmd_bdinfo.c | 2 + doc/README.drivers.eth | 6 + drivers/net/Kconfig | 9 ++ include/dm/uclass-id.h | 1 + include/net.h | 52 ++++++++ net/eth.c | 346 ++++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 410 insertions(+), 6 deletions(-)
diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index aa81da2..b4cce25 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/doc/README.drivers.eth b/doc/README.drivers.eth index eb83038..98728bc 100644 --- a/doc/README.drivers.eth +++ b/doc/README.drivers.eth @@ -1,3 +1,9 @@ +!!! WARNING !!! + +This guide describes to the old way of doing things. No new Ethernet drivers +should be implemented this way. All new drivers should be written against the +U-Boot core driver model. See doc/driver-model/README.txt + ----------------------- Ethernet Driver Guide ----------------------- diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e69de29..94cf099 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -0,0 +1,9 @@ +config DM_ETH + bool "Enable Driver Model for Ethernet drivers" + depends on DM + help + Enable driver model for Ethernet. + + The eth_*() interface will be implemented by the UC_ETH class + This is currently implemented in net/eth.c + Look in include/net.h for details. diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..ad96682 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */ + UCLASS_ETH, /* Ethernet device */
UCLASS_COUNT, UCLASS_INVALID = -1, diff --git a/include/net.h b/include/net.h index 10d38f8..508c572 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,57 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH +/** + * struct eth_pdata - Platform data for Ethernet MAC controllers + * + * @iobase: The base address of the hardware registers + * @enetaddr: The Ethernet MAC address that is loaded from EEPROM or env + */ +struct eth_pdata { + phys_addr_t iobase; + unsigned char enetaddr[6]; +}; + +/** + * struct eth_ops - functions of Ethernet MAC controllers + * + * start: Prepare the hardware to send and receive packets + * send: Send the bytes passed in "packet" as a packet on the wire + * recv: Check if the hardware received a packet. Call the network stack if so + * stop: Stop the hardware from looking for packets - may be called even if + * state == PASSIVE + * mcast: Join or leave a multicast group (for TFTP) - optional + * write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux + * on some platforms like ARM). This function expects the + * eth_pdata::enetaddr field to be populated - optional + * read_rom_hwaddr: Some devices have a backup of the MAC address stored in a + * ROM on the board. This is how the driver should expose it + * to the network stack. This function should fill in the + * eth_pdata::enetaddr field - optional + */ +struct eth_ops { + int (*start)(struct udevice *dev); + int (*send)(struct udevice *dev, void *packet, int length); + int (*recv)(struct udevice *dev); + void (*stop)(struct udevice *dev); +#ifdef CONFIG_MCAST_TFTP + int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join); +#endif + int (*write_hwaddr)(struct udevice *dev); + int (*read_rom_hwaddr)(struct udevice *dev); +}; + +#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops) + +struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +/* Used only when NetConsole is enabled */ +int eth_init_state_only(void); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ +#endif + +#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; @@ -144,6 +195,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number);
int usb_eth_initialize(bd_t *bi); +#endif
int eth_initialize(void); /* Initialize network subsystem */ void eth_try_another(int first_restart); /* Change the device */ diff --git a/net/eth.c b/net/eth.c index 66ecb79..1abf027 100644 --- a/net/eth.c +++ b/net/eth.c @@ -1,16 +1,19 @@ /* - * (C) Copyright 2001-2010 + * (C) Copyright 2001-2015 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Joe Hershberger, National Instruments * * SPDX-License-Identifier: GPL-2.0+ */
#include <common.h> #include <command.h> +#include <dm.h> #include <net.h> #include <miiphy.h> #include <phy.h> #include <asm/errno.h> +#include <dm/device-internal.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -76,6 +79,339 @@ static int eth_mac_skip(int index)
static void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH +/** + * struct eth_device_priv - private structure for each Ethernet device + * + * @state: The state of the Ethernet MAC driver (defined by enum eth_state_t) + */ +struct eth_device_priv { + enum eth_state_t state; +}; + +/** + * struct eth_uclass_priv - The structure attached to the uclass itself + * + * @current: The Ethernet device that the network functions are using + */ +struct eth_uclass_priv { + struct udevice *current; +}; + +static struct eth_uclass_priv *eth_get_uclass_priv(void) +{ + struct uclass *uc; + + uclass_get(UCLASS_ETH, &uc); + assert(uc); + return uc->priv; +} + +static void eth_set_current_to_next(void) +{ + struct eth_uclass_priv *uc_priv; + + uc_priv = eth_get_uclass_priv(); + if (uc_priv->current) + uclass_next_device(&uc_priv->current); + if (!uc_priv->current) + uclass_first_device(UCLASS_ETH, &uc_priv->current); +} + +struct udevice *eth_get_dev(void) +{ + struct eth_uclass_priv *uc_priv; + + uc_priv = eth_get_uclass_priv(); + if (!uc_priv->current) + uclass_first_device(UCLASS_ETH, + &uc_priv->current); + return uc_priv->current; +} + +static void eth_set_dev(struct udevice *dev) +{ + device_probe(dev); + eth_get_uclass_priv()->current = dev; +} + +unsigned char *eth_get_ethaddr(void) +{ + struct eth_pdata *pdata; + + if (eth_get_dev()) { + pdata = eth_get_dev()->platdata; + return pdata->enetaddr; + } + + return NULL; +} + +/* Set active state without calling start on the driver */ +int eth_init_state_only(void) +{ + struct udevice *current; + struct eth_device_priv *priv; + + current = eth_get_dev(); + if (!current || !device_active(current)) + return -EINVAL; + + priv = current->uclass_priv; + priv->state = ETH_STATE_ACTIVE; + + return 0; +} + +/* Set passive state without calling stop on the driver */ +void eth_halt_state_only(void) +{ + struct udevice *current; + struct eth_device_priv *priv; + + current = eth_get_dev(); + if (!current || !device_active(current)) + return; + + priv = current->uclass_priv; + priv->state = ETH_STATE_PASSIVE; +} + +int eth_get_dev_index(void) +{ + if (eth_get_dev()) + return eth_get_dev()->seq; + return -1; +} + +int eth_init(void) +{ + struct udevice *current; + struct udevice *old_current; + + current = eth_get_dev(); + if (!current) { + printf("No ethernet found.\n"); + return -ENODEV; + } + + old_current = current; + do { + debug("Trying %s\n", current->name); + + if (device_active(current)) { + uchar env_enetaddr[6]; + struct eth_pdata *pdata = current->platdata; + + /* Sync environment with network device */ + if (eth_getenv_enetaddr_by_index("eth", current->seq, + env_enetaddr)) + memcpy(pdata->enetaddr, env_enetaddr, 6); + else + memset(pdata->enetaddr, 0, 6); + + if (eth_get_ops(current)->start(current) >= 0) { + struct eth_device_priv *priv = + current->uclass_priv; + + priv->state = ETH_STATE_ACTIVE; + return 0; + } + } + debug("FAIL\n"); + + /* This will ensure the new "current" attempted to probe */ + eth_try_another(0); + current = eth_get_dev(); + } while (old_current != current); + + return -ENODEV; +} + +void eth_halt(void) +{ + struct udevice *current; + struct eth_device_priv *priv; + + current = eth_get_dev(); + if (!current || !device_active(current)) + return; + + eth_get_ops(current)->stop(current); + priv = current->uclass_priv; + priv->state = ETH_STATE_PASSIVE; +} + +int eth_send(void *packet, int length) +{ + struct udevice *current; + + current = eth_get_dev(); + if (!current) + return -ENODEV; + + if (!device_active(current)) + return -EINVAL; + + return eth_get_ops(current)->send(current, packet, length); +} + +int eth_rx(void) +{ + struct udevice *current; + + current = eth_get_dev(); + if (!current) + return -ENODEV; + + if (!device_active(current)) + return -EINVAL; + + return eth_get_ops(current)->recv(current); +} + +static int eth_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev->platdata; + int ret = 0; + + if (!dev || !device_active(dev)) + return -EINVAL; + + /* seq is valid since the device is active */ + if (eth_get_ops(dev)->write_hwaddr && !eth_mac_skip(dev->seq)) { + if (!is_valid_ether_addr(pdata->enetaddr)) { + printf("\nError: %s address %pM illegal value\n", + dev->name, pdata->enetaddr); + return -EINVAL; + } + + ret = eth_get_ops(dev)->write_hwaddr(dev); + if (ret) + printf("\nWarning: %s failed to set MAC address\n", + dev->name); + } + + return ret; +} + +int eth_initialize(void) +{ + int num_devices = 0; + struct udevice *dev; + + bootstage_mark(BOOTSTAGE_ID_NET_ETH_START); + eth_env_init(); + + /* + * Devices need to write the hwaddr even if not started so that Linux + * will have access to the hwaddr that u-boot stored for the device. + * This is accomplished by attempting to probe each device and calling + * their write_hwaddr() operation. + */ + uclass_first_device(UCLASS_ETH, &dev); + if (!dev) { + printf("No ethernet found.\n"); + bootstage_error(BOOTSTAGE_ID_NET_ETH_START); + } else { + bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); + do { + if (num_devices) + printf(", "); + + printf("eth%d: %s", dev->seq, dev->name); + + eth_write_hwaddr(dev); + + uclass_next_device(&dev); + num_devices++; + } while (dev); + + putc('\n'); + } + + return num_devices; +} + +static int eth_post_bind(struct udevice *dev) +{ + if (strchr(dev->name, ' ')) { + printf("\nError: eth device name "%s" has a space!\n", + dev->name); + return -EINVAL; + } + + return 0; +} + +static int eth_pre_unbind(struct udevice *dev) +{ + /* Don't hang onto a pointer that is going away */ + if (dev == eth_get_uclass_priv()->current) + eth_set_dev(NULL); + + return 0; +} + +static int eth_post_probe(struct udevice *dev) +{ + struct eth_device_priv *priv = dev->uclass_priv; + struct eth_pdata *pdata = dev->platdata; + unsigned char env_enetaddr[6]; + + priv->state = ETH_STATE_INIT; + + /* Check if the device has a MAC address in ROM */ + if (eth_get_ops(dev)->read_rom_hwaddr) + eth_get_ops(dev)->read_rom_hwaddr(dev); + + eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr); + if (!is_zero_ether_addr(env_enetaddr)) { + if (!is_zero_ether_addr(pdata->enetaddr) && + memcmp(pdata->enetaddr, env_enetaddr, 6)) { + printf("\nWarning: %s MAC addresses don't match:\n", + dev->name); + printf("Address in SROM is %pM\n", + pdata->enetaddr); + printf("Address in environment is %pM\n", + env_enetaddr); + } + + /* Override the ROM MAC address */ + memcpy(pdata->enetaddr, env_enetaddr, 6); + } else if (is_valid_ether_addr(pdata->enetaddr)) { + eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr); + printf("\nWarning: %s using MAC address from ROM\n", + dev->name); + } else if (is_zero_ether_addr(pdata->enetaddr)) { + printf("\nError: %s address not set.\n", + dev->name); + return -EINVAL; + } + + return 0; +} + +static int eth_pre_remove(struct udevice *dev) +{ + eth_get_ops(dev)->stop(dev); + + return 0; +} + +UCLASS_DRIVER(eth) = { + .name = "eth", + .id = UCLASS_ETH, + .post_bind = eth_post_bind, + .pre_unbind = eth_pre_unbind, + .post_probe = eth_post_probe, + .pre_remove = eth_pre_remove, + .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), + .per_device_auto_alloc_size = sizeof(struct eth_device_priv), +}; +#endif + +#ifndef CONFIG_DM_ETH /* * CPU and board-specific Ethernet initializations. Aliased function * signals caller to move on @@ -427,6 +763,7 @@ int eth_rx(void)
return eth_current->recv(eth_current); } +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -490,7 +827,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) { - static struct eth_device *first_failed; + static void *first_failed; char *ethrotate;
/* @@ -519,12 +856,9 @@ void eth_set_current(void) { static char *act; static int env_changed_id; - struct eth_device *old_current; + void *old_current; int env_id;
- if (!eth_get_dev()) /* XXX no current */ - return; - env_id = get_env_id(); if ((act == NULL) || (env_changed_id != env_id)) { act = getenv("ethact");

On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com wrote:
First just add support for MAC drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v5: -Add a note to doc/README.drivers.eth about its obsolescence -Expanded the Kconfig help -Moved dm/ header -Use local var for priv in eth_get_dev()
Reviewed-by: Simon Glass sjg@chromium.org

Take the opportunity to enforce better names on newly written or retrofitted Ethernet drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 9 ++++++++- net/net.c | 30 +++++++++++++++++++----------- 2 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/include/net.h b/include/net.h index 508c572..4e44832 100644 --- a/include/net.h +++ b/include/net.h @@ -466,7 +466,11 @@ extern uchar NetServerEther[6]; /* Boot server enet address */ extern IPaddr_t NetOurIP; /* Our IP addr (0 = unknown) */ extern IPaddr_t NetServerIP; /* Server IP addr (0 = unknown) */ extern uchar *NetTxPacket; /* THE transmit packet */ +#ifdef CONFIG_DM_ETH +extern uchar *net_rx_packets[PKTBUFSRX]; /* Receive packets */ +#else extern uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets */ +#endif extern uchar *NetRxPacket; /* Current receive packet */ extern int NetRxPacketLen; /* Current rx packet length */ extern unsigned NetIPID; /* IP ID (counting) */ @@ -616,8 +620,11 @@ static inline void NetSendPacket(uchar *pkt, int len) int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int payload_len);
+#ifndef CONFIG_DM_ETH +#define NetReceive(in_packet, len) net_process_received_packet(in_packet, len) +#endif /* Processes a received packet */ -void NetReceive(uchar *, int); +void net_process_received_packet(uchar *in_packet, int len);
#ifdef CONFIG_NETCONSOLE void NcStart(void); diff --git a/net/net.c b/net/net.c index 37b4aab..afec443 100644 --- a/net/net.c +++ b/net/net.c @@ -183,10 +183,13 @@ int NetTimeOffset; #endif
static uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN]; - +#ifdef CONFIG_DM_ETH +/* Receive packets */ +uchar *net_rx_packets[PKTBUFSRX]; +#else /* Receive packet */ uchar *NetRxPackets[PKTBUFSRX]; - +#endif /* Current UDP RX packet handler */ static rxhand_f *udp_packet_handler; /* Current ARP RX packet handler */ @@ -304,9 +307,15 @@ void net_init(void)
NetTxPacket = &PktBuf[0] + (PKTALIGN - 1); NetTxPacket -= (ulong)NetTxPacket % PKTALIGN; +#ifdef CONFIG_DM_ETH + for (i = 0; i < PKTBUFSRX; i++) { + net_rx_packets[i] = NetTxPacket + (i + 1) * + PKTSIZE_ALIGN; + } +#else for (i = 0; i < PKTBUFSRX; i++) NetRxPackets[i] = NetTxPacket + (i + 1) * PKTSIZE_ALIGN; - +#endif ArpInit(); net_clear_handlers();
@@ -952,8 +961,7 @@ static void receive_icmp(struct ip_udp_hdr *ip, int len, } }
-void -NetReceive(uchar *inpkt, int len) +void net_process_received_packet(uchar *in_packet, int len) { struct ethernet_hdr *et; struct ip_udp_hdr *ip; @@ -967,9 +975,9 @@ NetReceive(uchar *inpkt, int len)
debug_cond(DEBUG_NET_PKT, "packet received\n");
- NetRxPacket = inpkt; + NetRxPacket = in_packet; NetRxPacketLen = len; - et = (struct ethernet_hdr *)inpkt; + et = (struct ethernet_hdr *)in_packet;
/* too small packet? */ if (len < ETHER_HDR_SIZE) @@ -977,7 +985,7 @@ NetReceive(uchar *inpkt, int len)
#ifdef CONFIG_API if (push_packet) { - (*push_packet)(inpkt, len); + (*push_packet)(in_packet, len); return; } #endif @@ -1004,11 +1012,11 @@ NetReceive(uchar *inpkt, int len) */ eth_proto = ntohs(et802->et_prot);
- ip = (struct ip_udp_hdr *)(inpkt + E802_HDR_SIZE); + ip = (struct ip_udp_hdr *)(in_packet + E802_HDR_SIZE); len -= E802_HDR_SIZE;
} else if (eth_proto != PROT_VLAN) { /* normal packet */ - ip = (struct ip_udp_hdr *)(inpkt + ETHER_HDR_SIZE); + ip = (struct ip_udp_hdr *)(in_packet + ETHER_HDR_SIZE); len -= ETHER_HDR_SIZE;
} else { /* VLAN packet */ @@ -1033,7 +1041,7 @@ NetReceive(uchar *inpkt, int len) vlanid = cti & VLAN_IDMASK; eth_proto = ntohs(vet->vet_type);
- ip = (struct ip_udp_hdr *)(inpkt + VLAN_ETHER_HDR_SIZE); + ip = (struct ip_udp_hdr *)(in_packet + VLAN_ETHER_HDR_SIZE); len -= VLAN_ETHER_HDR_SIZE; }

Hi Joe,
On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com wrote:
Take the opportunity to enforce better names on newly written or retrofitted Ethernet drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 9 ++++++++- net/net.c | 30 +++++++++++++++++++----------- 2 files changed, 27 insertions(+), 12 deletions(-)
Not entirely pleasant with the #ifdef, but I assume it would be an easy follow-on patch to change this globally.
Reviewed-by: Simon Glass sjg@chromium.org
Regards, Simon

Stop forcing drivers to call net_process_received_packet() - formerly called NetReceive(). Now the uclass will handle calling the driver for each packet until the driver errors or has nothing to return. The uclass will then pass the good packets off to the network stack by calling net_process_received_packet().
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 2 +- net/eth.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/include/net.h b/include/net.h index 4e44832..37d1f36 100644 --- a/include/net.h +++ b/include/net.h @@ -110,7 +110,7 @@ struct eth_pdata { struct eth_ops { int (*start)(struct udevice *dev); int (*send)(struct udevice *dev, void *packet, int length); - int (*recv)(struct udevice *dev); + int (*recv)(struct udevice *dev, uchar **packetp); void (*stop)(struct udevice *dev); #ifdef CONFIG_MCAST_TFTP int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join); diff --git a/net/eth.c b/net/eth.c index 1abf027..b66d253 100644 --- a/net/eth.c +++ b/net/eth.c @@ -259,6 +259,9 @@ int eth_send(void *packet, int length) int eth_rx(void) { struct udevice *current; + uchar *packet; + int ret; + int i;
current = eth_get_dev(); if (!current) @@ -267,7 +270,15 @@ int eth_rx(void) if (!device_active(current)) return -EINVAL;
- return eth_get_ops(current)->recv(current); + /* Process up to 32 packets at one time */ + for (i = 0; i < 32; i++) { + ret = eth_get_ops(current)->recv(current, &packet); + if (ret > 0) + net_process_received_packet(packet, ret); + else + break; + } + return ret; }
static int eth_write_hwaddr(struct udevice *dev)

Hi Joe,
On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com wrote:
Stop forcing drivers to call net_process_received_packet() - formerly called NetReceive(). Now the uclass will handle calling the driver for each packet until the driver errors or has nothing to return. The uclass will then pass the good packets off to the network stack by calling net_process_received_packet().
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 2 +- net/eth.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/include/net.h b/include/net.h index 4e44832..37d1f36 100644 --- a/include/net.h +++ b/include/net.h @@ -110,7 +110,7 @@ struct eth_pdata { struct eth_ops { int (*start)(struct udevice *dev); int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev);
int (*recv)(struct udevice *dev, uchar **packetp);
Need to update docs above. With serial we return -EAGAIN when there is nothing more to receive. So you might want to swallow that error instead of returning it from eth_rx().
void (*stop)(struct udevice *dev);
#ifdef CONFIG_MCAST_TFTP int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join); diff --git a/net/eth.c b/net/eth.c index 1abf027..b66d253 100644 --- a/net/eth.c +++ b/net/eth.c @@ -259,6 +259,9 @@ int eth_send(void *packet, int length) int eth_rx(void) { struct udevice *current;
uchar *packet;
int ret;
int i; current = eth_get_dev(); if (!current)
@@ -267,7 +270,15 @@ int eth_rx(void) if (!device_active(current)) return -EINVAL;
return eth_get_ops(current)->recv(current);
/* Process up to 32 packets at one time */
for (i = 0; i < 32; i++) {
ret = eth_get_ops(current)->recv(current, &packet);
if (ret > 0)
net_process_received_packet(packet, ret);
else
break;
}
return ret;
}
static int eth_write_hwaddr(struct udevice *dev)
1.7.11.5
Regards, Simon

On Wed, Mar 4, 2015 at 12:35 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com wrote:
Stop forcing drivers to call net_process_received_packet() - formerly called NetReceive(). Now the uclass will handle calling the driver for each packet until the driver errors or has nothing to return. The uclass will then pass the good packets off to the network stack by calling net_process_received_packet().
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 2 +- net/eth.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/include/net.h b/include/net.h index 4e44832..37d1f36 100644 --- a/include/net.h +++ b/include/net.h @@ -110,7 +110,7 @@ struct eth_pdata { struct eth_ops { int (*start)(struct udevice *dev); int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev);
int (*recv)(struct udevice *dev, uchar **packetp);
Need to update docs above. With serial we return -EAGAIN when there is nothing more to receive. So you might want to swallow that error instead of returning it from eth_rx().
I was doing this filtering in the sandbox-raw driver, but I can easily to it here instead (or too) so that it doesn't leak through from other drivers that do not do this check in the future.
void (*stop)(struct udevice *dev);
#ifdef CONFIG_MCAST_TFTP int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join); diff --git a/net/eth.c b/net/eth.c index 1abf027..b66d253 100644 --- a/net/eth.c +++ b/net/eth.c @@ -259,6 +259,9 @@ int eth_send(void *packet, int length) int eth_rx(void) { struct udevice *current;
uchar *packet;
int ret;
int i; current = eth_get_dev(); if (!current)
@@ -267,7 +270,15 @@ int eth_rx(void) if (!device_active(current)) return -EINVAL;
return eth_get_ops(current)->recv(current);
/* Process up to 32 packets at one time */
for (i = 0; i < 32; i++) {
ret = eth_get_ops(current)->recv(current, &packet);
if (ret > 0)
net_process_received_packet(packet, ret);
else
break;
}
return ret;
}
static int eth_write_hwaddr(struct udevice *dev)
1.7.11.5
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi Joe,
On 10 March 2015 at 16:28, Joe Hershberger joe.hershberger@gmail.com wrote:
On Wed, Mar 4, 2015 at 12:35 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com wrote:
Stop forcing drivers to call net_process_received_packet() - formerly called NetReceive(). Now the uclass will handle calling the driver for each packet until the driver errors or has nothing to return. The uclass will then pass the good packets off to the network stack by calling net_process_received_packet().
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 2 +- net/eth.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/include/net.h b/include/net.h index 4e44832..37d1f36 100644 --- a/include/net.h +++ b/include/net.h @@ -110,7 +110,7 @@ struct eth_pdata { struct eth_ops { int (*start)(struct udevice *dev); int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev);
int (*recv)(struct udevice *dev, uchar **packetp);
Need to update docs above. With serial we return -EAGAIN when there is nothing more to receive. So you might want to swallow that error instead of returning it from eth_rx().
I was doing this filtering in the sandbox-raw driver, but I can easily to it here instead (or too) so that it doesn't leak through from other drivers that do not do this check in the future.
OK. My main concerns are:
1. Avoid wait loops in drivers (if needed they should be in the uclass triggered by -EAGAIN) 2. Ensure that uclass ops methods are clearly documented as to purpose, parameters, return value, etc, so people don't have to resort to archaeology to do the right thing :-)
void (*stop)(struct udevice *dev);
#ifdef CONFIG_MCAST_TFTP int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join); diff --git a/net/eth.c b/net/eth.c index 1abf027..b66d253 100644 --- a/net/eth.c +++ b/net/eth.c @@ -259,6 +259,9 @@ int eth_send(void *packet, int length) int eth_rx(void) { struct udevice *current;
uchar *packet;
int ret;
int i; current = eth_get_dev(); if (!current)
@@ -267,7 +270,15 @@ int eth_rx(void) if (!device_active(current)) return -EINVAL;
return eth_get_ops(current)->recv(current);
/* Process up to 32 packets at one time */
for (i = 0; i < 32; i++) {
ret = eth_get_ops(current)->recv(current, &packet);
if (ret > 0)
net_process_received_packet(packet, ret);
else
break;
}
return ret;
}
static int eth_write_hwaddr(struct udevice *dev)
Regards, Simon

On Tue, Mar 10, 2015 at 6:31 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 10 March 2015 at 16:28, Joe Hershberger joe.hershberger@gmail.com
wrote:
On Wed, Mar 4, 2015 at 12:35 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com
wrote:
Stop forcing drivers to call net_process_received_packet() - formerly called NetReceive(). Now the uclass will handle calling the driver
for
each packet until the driver errors or has nothing to return. The
uclass
will then pass the good packets off to the network stack by calling net_process_received_packet().
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 2 +- net/eth.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/include/net.h b/include/net.h index 4e44832..37d1f36 100644 --- a/include/net.h +++ b/include/net.h @@ -110,7 +110,7 @@ struct eth_pdata { struct eth_ops { int (*start)(struct udevice *dev); int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev);
int (*recv)(struct udevice *dev, uchar **packetp);
Need to update docs above. With serial we return -EAGAIN when there is nothing more to receive. So you might want to swallow that error instead of returning it from eth_rx().
I was doing this filtering in the sandbox-raw driver, but I can easily
to it
here instead (or too) so that it doesn't leak through from other drivers that do not do this check in the future.
OK. My main concerns are:
- Avoid wait loops in drivers (if needed they should be in the uclass
triggered by -EAGAIN)
Drivers are expected to return and not wait. I've made this more clear in the function comment.
- Ensure that uclass ops methods are clearly documented as to
purpose, parameters, return value, etc, so people don't have to resort to archaeology to do the right thing :-)
The new function comment looks like this:
+ * recv: Check if the hardware received a packet. If so, set the pointer to the + * packet buffer in the packetp parameter. If not, return an error or 0 to + * indicate that the hardware receive FIFO is empty
void (*stop)(struct udevice *dev);
#ifdef CONFIG_MCAST_TFTP int (*mcast)(struct udevice *dev, const u8 *enetaddr, int
join);
diff --git a/net/eth.c b/net/eth.c index 1abf027..b66d253 100644 --- a/net/eth.c +++ b/net/eth.c @@ -259,6 +259,9 @@ int eth_send(void *packet, int length) int eth_rx(void) { struct udevice *current;
uchar *packet;
int ret;
int i; current = eth_get_dev(); if (!current)
@@ -267,7 +270,15 @@ int eth_rx(void) if (!device_active(current)) return -EINVAL;
return eth_get_ops(current)->recv(current);
/* Process up to 32 packets at one time */
for (i = 0; i < 32; i++) {
ret = eth_get_ops(current)->recv(current, &packet);
if (ret > 0)
net_process_received_packet(packet, ret);
else
break;
}
return ret;
}
static int eth_write_hwaddr(struct udevice *dev)
Regards, Simon

Add basic network support to sandbox which includes a network driver.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v5: -Added help to the sandbox eth mock driver Kconfig entry
Changes in v4: -Cleaned up sandbox EXTRA_ENV define -Moved config to Kconfig
Changes in v3: -Added 2 more ethaddr to sandbox -Print which device in the debug write hwaddr
Changes in v2: -Change printfs to debug in sandbox driver -Remove unused priv struct for sandbox driver
arch/sandbox/Kconfig | 9 +++++ arch/sandbox/dts/sandbox.dts | 4 +++ board/sandbox/README.sandbox | 4 +-- drivers/net/Kconfig | 23 ++++++++++++ drivers/net/Makefile | 1 + drivers/net/sandbox.c | 84 ++++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 16 +++++---- 7 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 drivers/net/sandbox.c
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index 2098b9c..186b58d 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -34,4 +34,13 @@ config DM_I2C config DM_TEST default y
+config NET + default y + +config NETDEVICES + default y + +config DM_ETH + default y + endmenu diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 9ce31bf..36b3bd8 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -181,4 +181,8 @@ }; };
+ eth@10002000 { + compatible = "sandbox,eth"; + reg = <0x10002000 0x1000>; + }; }; diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox index 3c0df17..c1f5f7e 100644 --- a/board/sandbox/README.sandbox +++ b/board/sandbox/README.sandbox @@ -173,16 +173,16 @@ U-Boot sandbox supports these emulations: - Chrome OS EC - GPIO - Host filesystem (access files on the host from within U-Boot) +- I2C - Keyboard (Chrome OS) - LCD +- Network - Serial (for console only) - Sound (incomplete - see sandbox_sdl_sound_init() for details) - SPI - SPI flash - TPM (Trusted Platform Module)
-Notable omissions are networking and I2C. - A wide range of commands is implemented. Filesystems which use a block device are supported.
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 94cf099..e46e57b 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -7,3 +7,26 @@ config DM_ETH The eth_*() interface will be implemented by the UC_ETH class This is currently implemented in net/eth.c Look in include/net.h for details. + +menuconfig NETDEVICES + bool "Network device support" + depends on NET + help + You must select Y to enable any network device support + Generally if you have any networking support this is a given + + If unsure, say Y + +if NETDEVICES + +config ETH_SANDBOX + depends on DM_ETH && SANDBOX + default y + bool "Sandbox: Mocked Ethernet driver" + help + This driver simply responds with fake ARP replies and ping + replies that are used to verify network stack functionality + + This driver is particularly useful in the test/dm/eth.c tests + +endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 46c4ac6..15dc431 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_NS8382X) += ns8382x.o obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o +obj-$(CONFIG_ETH_SANDBOX) += sandbox.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c new file mode 100644 index 0000000..522990d --- /dev/null +++ b/drivers/net/sandbox.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int sb_eth_start(struct udevice *dev) +{ + debug("eth_sandbox: Start\n"); + + return 0; +} + +static int sb_eth_send(struct udevice *dev, void *packet, int length) +{ + debug("eth_sandbox: Send packet %d\n", length); + + return 0; +} + +static int sb_eth_recv(struct udevice *dev, uchar **packetp) +{ + return 0; +} + +static void sb_eth_stop(struct udevice *dev) +{ + debug("eth_sandbox: Stop\n"); +} + +static int sb_eth_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + + debug("eth_sandbox %s: Write HW ADDR - %pM\n", dev->name, + pdata->enetaddr); + return 0; +} + +static const struct eth_ops sb_eth_ops = { + .start = sb_eth_start, + .send = sb_eth_send, + .recv = sb_eth_recv, + .stop = sb_eth_stop, + .write_hwaddr = sb_eth_write_hwaddr, +}; + +static int sb_eth_remove(struct udevice *dev) +{ + return 0; +} + +static int sb_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + + pdata->iobase = dev_get_addr(dev); + return 0; +} + +static const struct udevice_id sb_eth_ids[] = { + { .compatible = "sandbox,eth" }, + { } +}; + +U_BOOT_DRIVER(eth_sandbox) = { + .name = "eth_sandbox", + .id = UCLASS_ETH, + .of_match = sb_eth_ids, + .ofdata_to_platdata = sb_eth_ofdata_to_platdata, + .remove = sb_eth_remove, + .ops = &sb_eth_ops, + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index febbfb6..664b984 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -126,9 +126,6 @@ /* include default commands */ #include <config_cmd_default.h>
-/* We don't have networking support yet */ -#undef CONFIG_CMD_NET -#undef CONFIG_CMD_NFS
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY @@ -165,16 +162,23 @@
#define CONFIG_KEYBOARD
-#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial,cros-ec-keyb\0" \ +#define SANDBOX_SERIAL_SETTINGS "stdin=serial,cros-ec-keyb\0" \ "stdout=serial,lcd\0" \ "stderr=serial,lcd\0" #else - -#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial\0" \ +#define SANDBOX_SERIAL_SETTINGS "stdin=serial\0" \ "stdout=serial,lcd\0" \ "stderr=serial,lcd\0" #endif
+#define SANDBOX_ETH_SETTINGS "ethaddr=00:00:11:22:33:44\0" \ + "eth1addr=00:00:11:22:33:45\0" \ + "eth2addr=00:00:11:22:33:46\0" \ + "ipaddr=1.2.3.4\0" + +#define CONFIG_EXTRA_ENV_SETTINGS SANDBOX_SERIAL_SETTINGS \ + SANDBOX_ETH_SETTINGS + #define CONFIG_GZIP_COMPRESSED #define CONFIG_BZIP2 #define CONFIG_LZO

On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com wrote:
Add basic network support to sandbox which includes a network driver.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v5: -Added help to the sandbox eth mock driver Kconfig entry
Looks good.
Reviewed-by: Simon Glass sjg@chromium.org
Changes in v4: -Cleaned up sandbox EXTRA_ENV define -Moved config to Kconfig
Changes in v3: -Added 2 more ethaddr to sandbox -Print which device in the debug write hwaddr
Changes in v2: -Change printfs to debug in sandbox driver -Remove unused priv struct for sandbox driver
arch/sandbox/Kconfig | 9 +++++ arch/sandbox/dts/sandbox.dts | 4 +++ board/sandbox/README.sandbox | 4 +-- drivers/net/Kconfig | 23 ++++++++++++ drivers/net/Makefile | 1 + drivers/net/sandbox.c | 84 ++++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 16 +++++---- 7 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 drivers/net/sandbox.c

The sandbox driver will now generate response traffic to exercise the ping command even when no network exists. This allows the basic data pathways of the DM to be tested.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v5: -Simplify sandbox eth driver by switching from int array to byte array -Switch priv from packet buffer to a pointer to net_rx_packets[0]
Changes in v4: -Removed checks on priv != NULL and added protection in uclass instead
Changes in v3: -Prevent a crash if memory is not allocated
Changes in v2: -Change printfs to debug in sandbox driver -Move fake hwaddr to the device tree -Move static data to priv
arch/sandbox/dts/sandbox.dts | 1 + drivers/net/sandbox.c | 107 +++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 1 + 3 files changed, 109 insertions(+)
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 36b3bd8..c2a3304 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -184,5 +184,6 @@ eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>; + fake-host-hwaddr = [00 00 66 44 22 00]; }; }; diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 522990d..cb69a95 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -14,22 +14,128 @@
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 + * 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]; + IPaddr_t fake_host_ipaddr; + uchar *recv_packet_buffer; + int recv_packet_length; +}; + static int sb_eth_start(struct udevice *dev) { + struct eth_sandbox_priv *priv = dev_get_priv(dev); + debug("eth_sandbox: Start\n");
+ fdtdec_get_byte_array(gd->fdt_blob, dev->of_offset, "fake-host-hwaddr", + priv->fake_host_hwaddr, ARP_HLEN); + priv->recv_packet_buffer = net_rx_packets[0]; return 0; }
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 (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 = NetReadIP(&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); + NetWriteIP(&arp_recv->ar_spa, priv->fake_host_ipaddr); + memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN); + NetCopyIP(&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; + NetCopyIP((void *)&ipr->ip_dst, &ip->ip_src); + NetWriteIP((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; }
static int sb_eth_recv(struct udevice *dev, uchar **packetp) { + struct eth_sandbox_priv *priv = dev_get_priv(dev); + + if (priv->recv_packet_length) { + int lcl_recv_packet_length = priv->recv_packet_length; + + debug("eth_sandbox: received packet %d\n", + priv->recv_packet_length); + priv->recv_packet_length = 0; + *packetp = priv->recv_packet_buffer; + return lcl_recv_packet_length; + } return 0; }
@@ -80,5 +186,6 @@ U_BOOT_DRIVER(eth_sandbox) = { .ofdata_to_platdata = sb_eth_ofdata_to_platdata, .remove = sb_eth_remove, .ops = &sb_eth_ops, + .priv_auto_alloc_size = sizeof(struct eth_sandbox_priv), .platdata_auto_alloc_size = sizeof(struct eth_pdata), }; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 664b984..9189f6a 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -126,6 +126,7 @@ /* include default commands */ #include <config_cmd_default.h>
+#define CONFIG_CMD_PING
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY

Add a test for the eth uclass using the sandbox eth driver. Verify basic functionality of the network stack / eth uclass by exercising the ping function.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v5: None Changes in v4: None Changes in v3: -Added dm eth testing
Changes in v2: None
test/dm/Makefile | 1 + test/dm/eth.c | 38 ++++++++++++++++++++++++++++++++++++++ test/dm/test.dts | 18 ++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 test/dm/eth.c
diff --git a/test/dm/Makefile b/test/dm/Makefile index 1d9148f..b2eb989 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_DM_TEST) += ut.o obj-$(CONFIG_DM_TEST) += core.o obj-$(CONFIG_DM_TEST) += ut.o ifneq ($(CONFIG_SANDBOX),) +obj-$(CONFIG_DM_ETH) += eth.o obj-$(CONFIG_DM_GPIO) += gpio.o obj-$(CONFIG_DM_I2C) += i2c.o obj-$(CONFIG_DM_SPI_FLASH) += sf.o diff --git a/test/dm/eth.c b/test/dm/eth.c new file mode 100644 index 0000000..04ccf49 --- /dev/null +++ b/test/dm/eth.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <dm/test.h> +#include <dm/ut.h> +#include <fdtdec.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int dm_test_eth(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + + setenv("ethact", "eth@10002000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth@10003000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10003000", getenv("ethact")); + + setenv("ethact", "eth@10004000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + return 0; +} +DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 84024a4..2f68cdf 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -149,4 +149,22 @@ }; };
+ eth@10002000 { + compatible = "sandbox,eth"; + reg = <0x10002000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; + }; + + eth@10003000 { + compatible = "sandbox,eth"; + reg = <0x10003000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>; + }; + + eth@10004000 { + compatible = "sandbox,eth"; + reg = <0x10004000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x22>; + }; + };

Allow network devices to be referred to as "eth0" instead of "eth@12345678" when specified in ethact.
Add tests to verify this behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v5: -Added a comment about devname -Only check for alias if the name is long enough
Changes in v4: -Use only the seq from DM to find aliases
Changes in v3: -Added support for aliases
Changes in v2: None
include/configs/sandbox.h | 2 +- include/net.h | 5 +++++ net/eth.c | 50 ++++++++++++++++++++++++++++++++++++++--------- test/dm/eth.c | 24 +++++++++++++++++++++++ test/dm/test.dts | 4 +++- 5 files changed, 74 insertions(+), 11 deletions(-)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 9189f6a..caf9f5a 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -174,7 +174,7 @@
#define SANDBOX_ETH_SETTINGS "ethaddr=00:00:11:22:33:44\0" \ "eth1addr=00:00:11:22:33:45\0" \ - "eth2addr=00:00:11:22:33:46\0" \ + "eth5addr=00:00:11:22:33:46\0" \ "ipaddr=1.2.3.4\0"
#define CONFIG_EXTRA_ENV_SETTINGS SANDBOX_SERIAL_SETTINGS \ diff --git a/include/net.h b/include/net.h index 37d1f36..5846dfb 100644 --- a/include/net.h +++ b/include/net.h @@ -122,6 +122,11 @@ struct eth_ops { #define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
struct udevice *eth_get_dev(void); /* get the current device */ +/* + * The devname can be either an exact name given by the driver or device tree + * or it can be an alias of the form "eth%d" + */ +struct udevice *eth_get_dev_by_name(const char *devname); unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ /* Used only when NetConsole is enabled */ int eth_init_state_only(void); /* Set active state */ diff --git a/net/eth.c b/net/eth.c index b66d253..14a072b 100644 --- a/net/eth.c +++ b/net/eth.c @@ -135,6 +135,39 @@ static void eth_set_dev(struct udevice *dev) eth_get_uclass_priv()->current = dev; }
+/* + * Find the udevice that either has the name passed in as devname or has an + * alias named devname. + */ +struct udevice *eth_get_dev_by_name(const char *devname) +{ + int seq = -1; + char *endp = NULL; + const char *startp = NULL; + struct udevice *it; + struct uclass *uc; + + /* Must be longer than 3 to be an alias */ + if (strlen(devname) > strlen("eth")) { + startp = devname + strlen("eth"); + seq = simple_strtoul(startp, &endp, 10); + } + + uclass_get(UCLASS_ETH, &uc); + uclass_foreach_dev(it, uc) { + /* We need the seq to be valid, so make sure it's probed */ + device_probe(it); + /* + * Check for the name or the sequence number to match + */ + if (strcmp(it->name, devname) == 0 || + (endp > startp && it->seq == seq)) + return it; + } + + return NULL; +} + unsigned char *eth_get_ethaddr(void) { struct eth_pdata *pdata; @@ -419,6 +452,7 @@ UCLASS_DRIVER(eth) = { .pre_remove = eth_pre_remove, .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), .per_device_auto_alloc_size = sizeof(struct eth_device_priv), + .flags = DM_UC_FLAG_SEQ_ALIAS, }; #endif
@@ -451,6 +485,11 @@ static void eth_set_current_to_next(void) eth_current = eth_current->next; }
+static void eth_set_dev(struct eth_device *dev) +{ + eth_current = dev; +} + struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -867,7 +906,6 @@ void eth_set_current(void) { static char *act; static int env_changed_id; - void *old_current; int env_id;
env_id = get_env_id(); @@ -875,14 +913,8 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; } - if (act != NULL) { - old_current = eth_get_dev(); - do { - if (strcmp(eth_get_name(), act) == 0) - return; - eth_set_current_to_next(); - } while (old_current != eth_get_dev()); - } + if (act != NULL) + eth_set_dev(eth_get_dev_by_name(act));
eth_current_changed(); } diff --git a/test/dm/eth.c b/test/dm/eth.c index 04ccf49..5688b71 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -36,3 +36,27 @@ static int dm_test_eth(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT); + +static int dm_test_eth_alias(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + setenv("ethact", "eth0"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth1"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Expected to fail since eth2 is not defined in the device tree */ + setenv("ethact", "eth2"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth5"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10003000", getenv("ethact")); + + return 0; +} +DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 2f68cdf..bc2409d 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -17,6 +17,8 @@ testfdt3 = "/b-test"; testfdt5 = "/some-bus/c-test@5"; testfdt8 = "/a-test"; + eth0 = "/eth@10002000"; + eth5 = ð_5; };
uart0: serial { @@ -155,7 +157,7 @@ fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
- eth@10003000 { + eth_5: eth@10003000 { compatible = "sandbox,eth"; reg = <0x10003000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>;

On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com wrote:
Allow network devices to be referred to as "eth0" instead of "eth@12345678" when specified in ethact.
Add tests to verify this behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v5: -Added a comment about devname -Only check for alias if the name is long enough
Reviewed-by: Simon Glass sjg@chromium.org
Changes in v4: -Use only the seq from DM to find aliases
Changes in v3: -Added support for aliases
Changes in v2: None
include/configs/sandbox.h | 2 +- include/net.h | 5 +++++ net/eth.c | 50 ++++++++++++++++++++++++++++++++++++++--------- test/dm/eth.c | 24 +++++++++++++++++++++++ test/dm/test.dts | 4 +++- 5 files changed, 74 insertions(+), 11 deletions(-)

The ethprime env var is used to indicate the starting device if none is specified in ethact. Also support aliases specified in the ethprime var.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v5: -Fix compile error on !DM_ETH
Changes in v4: -Load from ethprime on eth_initialize()
Changes in v3: -Added support for ethprime
Changes in v2: None
net/eth.c | 29 ++++++++++++++++++++++++++++- test/dm/eth.c | 20 ++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/net/eth.c b/net/eth.c index 14a072b..9966cf0 100644 --- a/net/eth.c +++ b/net/eth.c @@ -358,6 +358,18 @@ int eth_initialize(void) printf("No ethernet found.\n"); bootstage_error(BOOTSTAGE_ID_NET_ETH_START); } else { + char *ethprime = getenv("ethprime"); + struct udevice *prime_dev = NULL; + + if (ethprime) + prime_dev = eth_get_dev_by_name(ethprime); + if (prime_dev) { + eth_set_dev(prime_dev); + eth_current_changed(); + } else { + eth_set_dev(NULL); + } + bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); do { if (num_devices) @@ -365,6 +377,9 @@ int eth_initialize(void)
printf("eth%d: %s", dev->seq, dev->name);
+ if (ethprime && dev == prime_dev) + printf(" [PRIME]"); + eth_write_hwaddr(dev);
uclass_next_device(&dev); @@ -913,8 +928,20 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; } - if (act != NULL) + + if (act == NULL) { + char *ethprime = getenv("ethprime"); + void *dev = NULL; + + if (ethprime) + dev = eth_get_dev_by_name(ethprime); + if (dev) + eth_set_dev(dev); + else + eth_set_dev(NULL); + } else { eth_set_dev(eth_get_dev_by_name(act)); + }
eth_current_changed(); } diff --git a/test/dm/eth.c b/test/dm/eth.c index 5688b71..96e3c46 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -60,3 +60,23 @@ static int dm_test_eth_alias(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT); + +static int dm_test_eth_prime(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + + /* Expected to be "eth@10003000" because of ethprime variable */ + setenv("ethact", NULL); + setenv("ethprime", "eth5"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10003000", getenv("ethact")); + + /* Expected to be "eth@10002000" because it is first */ + setenv("ethact", NULL); + setenv("ethprime", NULL); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + return 0; +} +DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT);

Make sure that the ethrotate behavior occurs as expected.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v5: -Added a test for skipping un-probe-able devices
Changes in v4: -Added testing for ethrotate
Changes in v3: None Changes in v2: None
test/dm/eth.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
diff --git a/test/dm/eth.c b/test/dm/eth.c index 96e3c46..9b55013 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -80,3 +80,45 @@ static int dm_test_eth_prime(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT); + +static int dm_test_eth_rotate(struct dm_test_state *dms) +{ + char ethaddr[18]; + + /* Invalidate eth1's MAC address */ + NetPingIP = string_to_ip("1.1.2.2"); + strcpy(ethaddr, getenv("eth1addr")); + setenv("eth1addr", NULL); + + /* Make sure that the default is to rotate to the next interface */ + setenv("ethact", "eth@10004000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + /* If ethrotate is no, then we should fail on a bad MAC */ + setenv("ethact", "eth@10004000"); + setenv("ethrotate", "no"); + ut_asserteq(-1, NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Restore the env */ + setenv("eth1addr", ethaddr); + setenv("ethrotate", NULL); + + /* Invalidate eth0's MAC address */ + strcpy(ethaddr, getenv("ethaddr")); + setenv(".flags", "ethaddr"); + setenv("ethaddr", NULL); + + /* Make sure we can skip invalid devices */ + setenv("ethact", "eth@10004000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Restore the env */ + setenv("ethaddr", ethaddr); + setenv(".flags", NULL); + + return 0; +} +DM_TEST(dm_test_eth_rotate, DM_TESTF_SCAN_FDT);

On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com wrote:
Make sure that the ethrotate behavior occurs as expected.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v5: -Added a test for skipping un-probe-able devices
Changes in v4: -Added testing for ethrotate
Changes in v3: None Changes in v2: None
test/dm/eth.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

This is needed to test the netretry functionality (make the command fail on a sandbox eth device).
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v5: -Use a function call to change mock driver behavior
Changes in v4: -Add ability to disable ping reply in sandbox eth driver
Changes in v3: None Changes in v2: None
arch/sandbox/include/asm/eth.h | 15 +++++++++++++++ drivers/net/sandbox.c | 10 ++++++++++ 2 files changed, 25 insertions(+) create mode 100644 arch/sandbox/include/asm/eth.h
diff --git a/arch/sandbox/include/asm/eth.h b/arch/sandbox/include/asm/eth.h new file mode 100644 index 0000000..4b79ede --- /dev/null +++ b/arch/sandbox/include/asm/eth.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __ETH_H +#define __ETH_H + +void sandbox_eth_disable_response(int index, bool disable); + +#endif /* __ETH_H */ diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index cb69a95..0dfd144 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -29,6 +29,13 @@ struct eth_sandbox_priv { int recv_packet_length; };
+static bool disabled[8] = {false}; + +void sandbox_eth_disable_response(int index, bool disable) +{ + disabled[index] = disable; +} + static int sb_eth_start(struct udevice *dev) { struct eth_sandbox_priv *priv = dev_get_priv(dev); @@ -48,6 +55,9 @@ static int sb_eth_send(struct udevice *dev, void *packet, int length)
debug("eth_sandbox: Send packet %d\n", length);
+ if (disabled[dev->seq]) + return 0; + if (ntohs(eth->et_protlen) == PROT_ARP) { struct arp_hdr *arp = packet + ETHER_HDR_SIZE;

Hi Joe,
On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com wrote:
This is needed to test the netretry functionality (make the command fail on a sandbox eth device).
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org
Please see nits below.
Changes in v5: -Use a function call to change mock driver behavior
Changes in v4: -Add ability to disable ping reply in sandbox eth driver
Changes in v3: None Changes in v2: None
arch/sandbox/include/asm/eth.h | 15 +++++++++++++++ drivers/net/sandbox.c | 10 ++++++++++ 2 files changed, 25 insertions(+) create mode 100644 arch/sandbox/include/asm/eth.h
diff --git a/arch/sandbox/include/asm/eth.h b/arch/sandbox/include/asm/eth.h new file mode 100644 index 0000000..4b79ede --- /dev/null +++ b/arch/sandbox/include/asm/eth.h @@ -0,0 +1,15 @@ +/*
- Copyright (c) 2015 National Instruments
- (C) Copyright 2015
- Joe Hershberger joe.hershberger@ni.com
- SPDX-License-Identifier: GPL-2.0
- */
+#ifndef __ETH_H +#define __ETH_H
+void sandbox_eth_disable_response(int index, bool disable);
Function comment - what is index? What does it disable?
+#endif /* __ETH_H */ diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index cb69a95..0dfd144 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -29,6 +29,13 @@ struct eth_sandbox_priv { int recv_packet_length; };
+static bool disabled[8] = {false};
+void sandbox_eth_disable_response(int index, bool disable) +{
disabled[index] = disable;
+}
static int sb_eth_start(struct udevice *dev) { struct eth_sandbox_priv *priv = dev_get_priv(dev); @@ -48,6 +55,9 @@ static int sb_eth_send(struct udevice *dev, void *packet, int length)
debug("eth_sandbox: Send packet %d\n", length);
if (disabled[dev->seq])
if (dev->seq >= 0 && dev->seq <ARRAY_SIZE(disabled) && disabled[dev->seq])
return 0;
if (ntohs(eth->et_protlen) == PROT_ARP) { struct arp_hdr *arp = packet + ETHER_HDR_SIZE;
-- 1.7.11.5
Regards, Simon

The effect of the "netretry" env var was recently changed. This test checks that behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v5: -Added comments about test cases -Switched to function to control state of mock driver
Changes in v4: -Updated expected behavior based on changes to the NetLoop
Changes in v3: -Added testing for netretry
Changes in v2: None
test/dm/eth.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
diff --git a/test/dm/eth.c b/test/dm/eth.c index 9b55013..a0e9359 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -14,6 +14,7 @@ #include <fdtdec.h> #include <malloc.h> #include <net.h> +#include <asm/eth.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -122,3 +123,34 @@ static int dm_test_eth_rotate(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth_rotate, DM_TESTF_SCAN_FDT); + +static int dm_test_net_retry(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + + /* + * eth1 is disabled and netretry is yes, so the ping should succeed and + * the active device should be eth0 + */ + sandbox_eth_disable_response(1, true); + setenv("ethact", "eth@10004000"); + setenv("netretry", "yes"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + /* + * eth1 is disabled and netretry is no, so the ping should fail and the + * active device should be eth1 + */ + setenv("ethact", "eth@10004000"); + setenv("netretry", "no"); + ut_asserteq(-1, NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Restore the env */ + setenv("netretry", NULL); + sandbox_eth_disable_response(1, false); + + return 0; +} +DM_TEST(dm_test_net_retry, DM_TESTF_SCAN_FDT);

On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com wrote:
The effect of the "netretry" env var was recently changed. This test checks that behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org

Implement a bridge between u-boot's network stack and Linux's raw packet API allowing the sandbox to send and receive packets using the host machine's network interface.
This raw Ethernet API requires elevated privileges. You can either run as root, or you can add the capability needed like so:
sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v5: -Added fallback for setting promiscuous mode -Added help to Kconfig -Added more details and examples in the README -Check for NULL when reading fdt for host interface -Check for malloc failure -Remove cast of pointer passed to free -Remove the empty sb_eth_raw_remove function -Return -errno in from send and recv -Return errno from recv -Set the socket to non-blocking -Use net_rx_packets instead of a stack buffer
Changes in v4: -Add comments to priv struct definition -Added comments to README.sandbox -Clean up the interface to sandbox's eth-raw-os by passing priv to raw-os -Cleanup var definition order -Fixed the MAC address limitation (now all traffic uses MAC address from env) -Move os file to arch -Moved config to Kconfig -Use accessors for platdata and priv
Changes in v3: -Made the os raw packet support for sandbox eth build and work.
Changes in v2: -Added the raw packet proof-of-concept patch.
arch/sandbox/Kconfig | 3 + arch/sandbox/cpu/Makefile | 10 +++ arch/sandbox/cpu/eth-raw-os.c | 140 ++++++++++++++++++++++++++++++++++ arch/sandbox/dts/sandbox.dts | 6 ++ arch/sandbox/include/asm/eth-raw-os.h | 32 ++++++++ board/sandbox/README.sandbox | 52 +++++++++++++ drivers/net/Kconfig | 10 +++ drivers/net/Makefile | 1 + drivers/net/sandbox-raw.c | 98 ++++++++++++++++++++++++ 9 files changed, 352 insertions(+) create mode 100644 arch/sandbox/cpu/eth-raw-os.c create mode 100644 arch/sandbox/include/asm/eth-raw-os.h create mode 100644 drivers/net/sandbox-raw.c
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index 186b58d..f84b3fc 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -43,4 +43,7 @@ config NETDEVICES config DM_ETH default y
+config ETH_SANDBOX_RAW + default y + endmenu diff --git a/arch/sandbox/cpu/Makefile b/arch/sandbox/cpu/Makefile index 7d4410c..1b42fee 100644 --- a/arch/sandbox/cpu/Makefile +++ b/arch/sandbox/cpu/Makefile @@ -8,6 +8,7 @@ #
obj-y := cpu.o os.o start.o state.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += eth-raw-os.o obj-$(CONFIG_SANDBOX_SDL) += sdl.o
# os.c is build in the system environment, so needs standard includes @@ -20,3 +21,12 @@ $(obj)/os.o: $(src)/os.c FORCE $(call if_changed_dep,cc_os.o) $(obj)/sdl.o: $(src)/sdl.c FORCE $(call if_changed_dep,cc_os.o) + +# eth-raw-os.c is built in the system env, so needs standard includes +# CFLAGS_REMOVE_eth-raw-os.o cannot be used to drop header include path +quiet_cmd_cc_eth-raw-os.o = CC $(quiet_modtag) $@ +cmd_cc_eth-raw-os.o = $(CC) $(filter-out -nostdinc, \ + $(patsubst -I%,-idirafter%,$(c_flags))) -c -o $@ $< + +$(obj)/eth-raw-os.o: $(src)/eth-raw-os.c FORCE + $(call if_changed_dep,cc_eth-raw-os.o) diff --git a/arch/sandbox/cpu/eth-raw-os.c b/arch/sandbox/cpu/eth-raw-os.c new file mode 100644 index 0000000..601205a --- /dev/null +++ b/arch/sandbox/cpu/eth-raw-os.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <asm/eth-raw-os.h> +#include <errno.h> +#include <fcntl.h> +#include <net/if.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <linux/if_ether.h> +#include <linux/if_packet.h> + +int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, + struct eth_sandbox_raw_priv *priv) +{ + struct sockaddr_ll *device; + struct packet_mreq mr; + int ret; + int flags; + + /* Prepare device struct */ + priv->device = malloc(sizeof(struct sockaddr_ll)); + if (priv->device == NULL) + return -ENOMEM; + device = priv->device; + memset(device, 0, sizeof(struct sockaddr_ll)); + device->sll_ifindex = if_nametoindex(ifname); + device->sll_family = AF_PACKET; + memcpy(device->sll_addr, ethmac, 6); + device->sll_halen = htons(6); + + /* Open socket */ + priv->sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (priv->sd < 0) { + printf("Failed to open socket: %d %s\n", errno, + strerror(errno)); + return -errno; + } + /* Bind to the specified interface */ + ret = setsockopt(priv->sd, SOL_SOCKET, SO_BINDTODEVICE, ifname, + strlen(ifname) + 1); + if (ret < 0) { + printf("Failed to bind to '%s': %d %s\n", ifname, errno, + strerror(errno)); + return -errno; + } + + /* Make the socket non-blocking */ + flags = fcntl(priv->sd, F_GETFL, 0); + fcntl(priv->sd, F_SETFL, flags | O_NONBLOCK); + + /* Enable promiscuous mode to receive responses meant for us */ + mr.mr_ifindex = device->sll_ifindex; + mr.mr_type = PACKET_MR_PROMISC; + ret = setsockopt(priv->sd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, + &mr, sizeof(mr)); + if (ret < 0) { + struct ifreq ifr; + + printf("Failed to set promiscuous mode: %d %s\n" + "Falling back to the old "flags" way...\n", + errno, strerror(errno)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + if (ioctl(priv->sd, SIOCGIFFLAGS, &ifr) < 0) { + printf("Failed to read flags: %d %s\n", errno, + strerror(errno)); + return -errno; + } + ifr.ifr_flags |= IFF_PROMISC; + if (ioctl(priv->sd, SIOCSIFFLAGS, &ifr) < 0) { + printf("Failed to write flags: %d %s\n", errno, + strerror(errno)); + return -errno; + } + } + return 0; +} + +int sandbox_eth_raw_os_send(void *packet, int length, + const struct eth_sandbox_raw_priv *priv) +{ + int retval; + + if (!priv->sd || !priv->device) + return -EINVAL; + + retval = sendto(priv->sd, packet, length, 0, + (struct sockaddr *)priv->device, + sizeof(struct sockaddr_ll)); + if (retval < 0) { + printf("Failed to send packet: %d %s\n", errno, + strerror(errno)); + return -errno; + } + return retval; +} + +int sandbox_eth_raw_os_recv(void *packet, int *length, + const struct eth_sandbox_raw_priv *priv) +{ + int retval; + int saddr_size; + + if (!priv->sd || !priv->device) + return -EINVAL; + saddr_size = sizeof(struct sockaddr); + retval = recvfrom(priv->sd, packet, 1536, 0, + (struct sockaddr *)priv->device, + (socklen_t *)&saddr_size); + *length = 0; + if (retval >= 0) { + *length = retval; + return 0; + } + /* The socket is non-blocking, so expect EAGAIN when there is no data */ + if (errno == EAGAIN) + return 0; + return -errno; +} + +void sandbox_eth_raw_os_stop(struct eth_sandbox_raw_priv *priv) +{ + free(priv->device); + priv->device = NULL; + close(priv->sd); + priv->sd = -1; +} diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index c2a3304..8002196 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -186,4 +186,10 @@ reg = <0x10002000 0x1000>; fake-host-hwaddr = [00 00 66 44 22 00]; }; + + eth@80000000 { + compatible = "sandbox,eth-raw"; + reg = <0x80000000 0x1000>; + host-raw-interface = "eth0"; + }; }; diff --git a/arch/sandbox/include/asm/eth-raw-os.h b/arch/sandbox/include/asm/eth-raw-os.h new file mode 100644 index 0000000..df60c4f --- /dev/null +++ b/arch/sandbox/include/asm/eth-raw-os.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __ETH_RAW_OS_H +#define __ETH_RAW_OS_H + +/** + * struct eth_sandbox_raw_priv - raw socket session + * + * sd: socket descriptor - the open socket during a session + * device: struct sockaddr_ll - the host interface packets move to/from + */ +struct eth_sandbox_raw_priv { + int sd; + void *device; +}; + +int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, + struct eth_sandbox_raw_priv *priv); +int sandbox_eth_raw_os_send(void *packet, int length, + const struct eth_sandbox_raw_priv *priv); +int sandbox_eth_raw_os_recv(void *packet, int *length, + const struct eth_sandbox_raw_priv *priv); +void sandbox_eth_raw_os_stop(struct eth_sandbox_raw_priv *priv); + +#endif /* __ETH_RAW_OS_H */ diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox index c1f5f7e..aedf05a 100644 --- a/board/sandbox/README.sandbox +++ b/board/sandbox/README.sandbox @@ -190,6 +190,58 @@ Also sandbox uses generic board (CONFIG_SYS_GENERIC_BOARD) and supports driver model (CONFIG_DM) and associated commands.
+Linux RAW Networking Bridge +--------------------------- + +The sandbox_eth_raw driver bridges traffic between the bottom of the network +stack and the RAW sockets API in Linux. This allows much of the u-boot network +functionality to be tested in sandbox against real network traffic. + +For Ethernet network adapters, the bridge utilizes the RAW AF_PACKET API. This +is needed to get access to the lowest level of the network stack in Linux. This +means that all of the Ethernet frame is included. This allows the u-boot network +stack to be fully used. In other words, nothing about the Linux network stack is +involved in forming the packets that end up on the wire. To receive the +responses to packets sent from U-Boot the network interface has to be set to +promiscuous mode so that the network card won't filter out packets not destined +for its configured (on Linux) MAC address. + +The RAW sockets Ethernet API requires elevated privileges in Linux. You can +either run as root, or you can add the capability needed like so: + +sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot + +The default device tree for sandbox includes an entry for eth0 on the sandbox +host machine whose alias is "eth1". The following are a few examples of network +operations being tested on the eth0 interface. + +sudo u-boot -d u-boot.dtb + +DHCP +.... + +set autoload no +set ethact eth1 +dhcp + +PING +.... + +set autoload no +set ethact eth1 +dhcp +ping $gatewayip + +TFTP +.... + +set autoload no +set ethact eth1 +dhcp +set serverip WWW.XXX.YYY.ZZZ +tftpboot u-boot.bin + + SPI Emulation -------------
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e46e57b..601366f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -29,4 +29,14 @@ config ETH_SANDBOX
This driver is particularly useful in the test/dm/eth.c tests
+config ETH_SANDBOX_RAW + depends on DM_ETH && SANDBOX + default y + bool "Sandbox: Bridge to Linux Raw Sockets" + help + This driver is a bridge from the bottom of the network stack + in u-boot to the RAW AF_PACKET API in Linux. This allows real + network traffic to be tested from within sandbox. See + board/sandbox/README.sandbox for more details. + endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 15dc431..2659a8a 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o obj-$(CONFIG_ETH_SANDBOX) += sandbox.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c new file mode 100644 index 0000000..435b874 --- /dev/null +++ b/drivers/net/sandbox-raw.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <asm/eth-raw-os.h> +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + + +static int sb_eth_raw_start(struct udevice *dev) +{ + struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + const char *interface; + + debug("eth_sandbox_raw: Start\n"); + + interface = fdt_getprop(gd->fdt_blob, dev->of_offset, + "host-raw-interface", NULL); + if (interface == NULL) + return -EINVAL; + + return sandbox_eth_raw_os_start(interface, pdata->enetaddr, priv); +} + +static int sb_eth_raw_send(struct udevice *dev, void *packet, int length) +{ + struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); + + debug("eth_sandbox_raw: Send packet %d\n", length); + + return sandbox_eth_raw_os_send(packet, length, priv); +} + +static int sb_eth_raw_recv(struct udevice *dev, uchar **packetp) +{ + struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); + int retval; + int length; + + retval = sandbox_eth_raw_os_recv(net_rx_packets[0], &length, priv); + + if (!retval && length) { + debug("eth_sandbox_raw: received packet %d\n", + length); + *packetp = net_rx_packets[0]; + return length; + } + return retval; +} + +static void sb_eth_raw_stop(struct udevice *dev) +{ + struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); + + debug("eth_sandbox_raw: Stop\n"); + + sandbox_eth_raw_os_stop(priv); +} + +static const struct eth_ops sb_eth_raw_ops = { + .start = sb_eth_raw_start, + .send = sb_eth_raw_send, + .recv = sb_eth_raw_recv, + .stop = sb_eth_raw_stop, +}; + +static int sb_eth_raw_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + + pdata->iobase = dev_get_addr(dev); + return 0; +} + +static const struct udevice_id sb_eth_raw_ids[] = { + { .compatible = "sandbox,eth-raw" }, + { } +}; + +U_BOOT_DRIVER(eth_sandbox_raw) = { + .name = "eth_sandbox_raw", + .id = UCLASS_ETH, + .of_match = sb_eth_raw_ids, + .ofdata_to_platdata = sb_eth_raw_ofdata_to_platdata, + .ops = &sb_eth_raw_ops, + .priv_auto_alloc_size = sizeof(struct eth_sandbox_raw_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +};

Hi Joe,
On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com wrote:
Implement a bridge between u-boot's network stack and Linux's raw packet API allowing the sandbox to send and receive packets using the host machine's network interface.
This raw Ethernet API requires elevated privileges. You can either run as root, or you can add the capability needed like so:
sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org
Nits below.
Changes in v5: -Added fallback for setting promiscuous mode -Added help to Kconfig -Added more details and examples in the README -Check for NULL when reading fdt for host interface -Check for malloc failure -Remove cast of pointer passed to free -Remove the empty sb_eth_raw_remove function -Return -errno in from send and recv -Return errno from recv -Set the socket to non-blocking -Use net_rx_packets instead of a stack buffer
Changes in v4: -Add comments to priv struct definition -Added comments to README.sandbox -Clean up the interface to sandbox's eth-raw-os by passing priv to raw-os -Cleanup var definition order -Fixed the MAC address limitation (now all traffic uses MAC address from env) -Move os file to arch -Moved config to Kconfig -Use accessors for platdata and priv
Changes in v3: -Made the os raw packet support for sandbox eth build and work.
Changes in v2: -Added the raw packet proof-of-concept patch.
arch/sandbox/Kconfig | 3 + arch/sandbox/cpu/Makefile | 10 +++ arch/sandbox/cpu/eth-raw-os.c | 140 ++++++++++++++++++++++++++++++++++ arch/sandbox/dts/sandbox.dts | 6 ++ arch/sandbox/include/asm/eth-raw-os.h | 32 ++++++++ board/sandbox/README.sandbox | 52 +++++++++++++ drivers/net/Kconfig | 10 +++ drivers/net/Makefile | 1 + drivers/net/sandbox-raw.c | 98 ++++++++++++++++++++++++ 9 files changed, 352 insertions(+) create mode 100644 arch/sandbox/cpu/eth-raw-os.c create mode 100644 arch/sandbox/include/asm/eth-raw-os.h create mode 100644 drivers/net/sandbox-raw.c
diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox index c1f5f7e..aedf05a 100644 --- a/board/sandbox/README.sandbox +++ b/board/sandbox/README.sandbox @@ -190,6 +190,58 @@ Also sandbox uses generic board (CONFIG_SYS_GENERIC_BOARD) and supports driver model (CONFIG_DM) and associated commands.
+Linux RAW Networking Bridge +---------------------------
+The sandbox_eth_raw driver bridges traffic between the bottom of the network +stack and the RAW sockets API in Linux. This allows much of the u-boot network
s/u-boot/U-Boot/g
(there's one in the Kconfig also)
+functionality to be tested in sandbox against real network traffic.
+For Ethernet network adapters, the bridge utilizes the RAW AF_PACKET API. This +is needed to get access to the lowest level of the network stack in Linux. This +means that all of the Ethernet frame is included. This allows the u-boot network +stack to be fully used. In other words, nothing about the Linux network stack is +involved in forming the packets that end up on the wire. To receive the +responses to packets sent from U-Boot the network interface has to be set to +promiscuous mode so that the network card won't filter out packets not destined +for its configured (on Linux) MAC address.
+The RAW sockets Ethernet API requires elevated privileges in Linux. You can +either run as root, or you can add the capability needed like so:
+sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
I think the last param is the filename, is that right? Would be good to clarify if this is a full path, etc.
+The default device tree for sandbox includes an entry for eth0 on the sandbox +host machine whose alias is "eth1". The following are a few examples of network +operations being tested on the eth0 interface.
+sudo u-boot -d u-boot.dtb
or sudo u-boot -D
+DHCP +....
+set autoload no +set ethact eth1 +dhcp
+PING +....
+set autoload no +set ethact eth1 +dhcp +ping $gatewayip
+TFTP +....
+set autoload no +set ethact eth1 +dhcp +set serverip WWW.XXX.YYY.ZZZ +tftpboot u-boot.bin
SPI Emulation
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e46e57b..601366f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -29,4 +29,14 @@ config ETH_SANDBOX
This driver is particularly useful in the test/dm/eth.c tests
+config ETH_SANDBOX_RAW
depends on DM_ETH && SANDBOX
default y
bool "Sandbox: Bridge to Linux Raw Sockets"
help
This driver is a bridge from the bottom of the network stack
in u-boot to the RAW AF_PACKET API in Linux. This allows real
network traffic to be tested from within sandbox. See
board/sandbox/README.sandbox for more details.
endif # NETDEVICES
Regards, Simon

This is now testable via the eth-raw interface
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v5: None Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
include/configs/sandbox.h | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index caf9f5a..034050e 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -127,6 +127,14 @@ #include <config_cmd_default.h>
#define CONFIG_CMD_PING +#define CONFIG_CMD_DHCP +#define CONFIG_BOOTP_DNS +#define CONFIG_BOOTP_DNS2 +#define CONFIG_BOOTP_GATEWAY +#define CONFIG_BOOTP_SEND_HOSTNAME +#define CONFIG_BOOTP_SERVERIP +#define CONFIG_BOOTP_SUBNETMASK +#define CONFIG_IP_DEFRAG
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY

The 'lo' interface on Linux doesn't support thinks like ARP or link-layer access like we use to talk to a normal network interface. A higher-level network API must be used to access localhost.
As written, this interface is limited to not supporting ICMP since the API doesn't allow the socket to be opened for all IP traffic and be able to receive at the same time. UDP is far more useful to test with, so it was selected over ICMP. Ping won't work, but things like TFTP should work.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v5: -Add details about lo support to the README -Remove socket timeout -Separate init to 2 helper static functions -Set the socket to non-blocking -Use INADDR_LOOPBACK -Use more verbose comments
Changes in v4: -Added support for the 'lo' network interface
Changes in v3: None Changes in v2: None
arch/sandbox/cpu/eth-raw-os.c | 113 +++++++++++++++++++++++++++++++++- arch/sandbox/dts/sandbox.dts | 10 +++ arch/sandbox/include/asm/eth-raw-os.h | 10 ++- board/sandbox/README.sandbox | 22 +++++++ drivers/net/sandbox-raw.c | 71 ++++++++++++++++++++- 5 files changed, 221 insertions(+), 5 deletions(-)
diff --git a/arch/sandbox/cpu/eth-raw-os.c b/arch/sandbox/cpu/eth-raw-os.c index 601205a..b76a731 100644 --- a/arch/sandbox/cpu/eth-raw-os.c +++ b/arch/sandbox/cpu/eth-raw-os.c @@ -12,6 +12,8 @@ #include <fcntl.h> #include <net/if.h> #include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/udp.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -20,10 +22,11 @@ #include <sys/socket.h> #include <unistd.h>
+#include <arpa/inet.h> #include <linux/if_ether.h> #include <linux/if_packet.h>
-int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, +static int _raw_packet_start(const char *ifname, unsigned char *ethmac, struct eth_sandbox_raw_priv *priv) { struct sockaddr_ll *device; @@ -89,14 +92,114 @@ int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, return 0; }
+static int _local_inet_start(struct eth_sandbox_raw_priv *priv) +{ + struct sockaddr_in *device; + int ret; + int flags; + int one = 1; + + /* Prepare device struct */ + priv->device = malloc(sizeof(struct sockaddr_in)); + if (priv->device == NULL) + return -ENOMEM; + device = priv->device; + memset(device, 0, sizeof(struct sockaddr_in)); + device->sin_family = AF_INET; + device->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + /** + * Open socket + * Since we specify UDP here, any incoming ICMP packets will + * not be received, so things like ping will not work on this + * localhost interface. + */ + priv->sd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP); + if (priv->sd < 0) { + printf("Failed to open socket: %d %s\n", errno, + strerror(errno)); + return -errno; + } + + /* Make the socket non-blocking */ + flags = fcntl(priv->sd, F_GETFL, 0); + fcntl(priv->sd, F_SETFL, flags | O_NONBLOCK); + + /* Include the UDP/IP headers on send and receive */ + ret = setsockopt(priv->sd, IPPROTO_IP, IP_HDRINCL, &one, + sizeof(one)); + if (ret < 0) { + printf("Failed to set header include option: %d %s\n", errno, + strerror(errno)); + return -errno; + } + priv->local_bind_sd = -1; + priv->local_bind_udp_port = 0; + return 0; +} + +int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, + struct eth_sandbox_raw_priv *priv) +{ + if (priv->local) + return _local_inet_start(priv); + else + return _raw_packet_start(ifname, ethmac, priv); +} + int sandbox_eth_raw_os_send(void *packet, int length, - const struct eth_sandbox_raw_priv *priv) + struct eth_sandbox_raw_priv *priv) { int retval; + struct udphdr *udph = packet + sizeof(struct iphdr);
if (!priv->sd || !priv->device) return -EINVAL;
+ /* + * This block of code came about when testing tftp on the localhost + * interface. When using the RAW AF_INET API, the network stack is still + * in play responding to incoming traffic based on open "ports". Since + * it is raw (at the IP layer, no Ethernet) the network stack tells the + * TFTP server that the port it responded to is closed. This causes the + * TFTP transfer to be aborted. This block of code inspects the outgoing + * packet as formulated by the u-boot network stack to determine the + * source port (that the TFTP server will send packets back to) and + * opens a typical UDP socket on that port, thus preventing the network + * stack from sending that ICMP message claiming that the port has no + * bound socket. + */ + if (priv->local && (priv->local_bind_sd == -1 || + priv->local_bind_udp_port != udph->source)) { + struct iphdr *iph = packet; + struct sockaddr_in addr; + + if (priv->local_bind_sd != -1) + close(priv->local_bind_sd); + + /* A normal UDP socket is required to bind */ + priv->local_bind_sd = socket(AF_INET, SOCK_DGRAM, 0); + if (priv->local_bind_sd < 0) { + printf("Failed to open bind sd: %d %s\n", errno, + strerror(errno)); + return -errno; + } + priv->local_bind_udp_port = udph->source; + + /** + * Bind the UDP port that we intend to use as our source port + * so that the kernel will not send an ICMP port unreachable + * message to the server + */ + addr.sin_family = AF_INET; + addr.sin_port = udph->source; + addr.sin_addr.s_addr = iph->saddr; + retval = bind(priv->local_bind_sd, &addr, sizeof(addr)); + if (retval < 0) + printf("Failed to bind: %d %s\n", errno, + strerror(errno)); + } + retval = sendto(priv->sd, packet, length, 0, (struct sockaddr *)priv->device, sizeof(struct sockaddr_ll)); @@ -137,4 +240,10 @@ void sandbox_eth_raw_os_stop(struct eth_sandbox_raw_priv *priv) priv->device = NULL; close(priv->sd); priv->sd = -1; + if (priv->local) { + if (priv->local_bind_sd != -1) + close(priv->local_bind_sd); + priv->local_bind_sd = -1; + priv->local_bind_udp_port = 0; + } } diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 8002196..0eaa5a5 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -4,6 +4,10 @@ #address-cells = <1>; #size-cells = <0>;
+ aliases { + eth5 = "/eth@90000000"; + }; + chosen { stdout-path = "/serial"; }; @@ -192,4 +196,10 @@ reg = <0x80000000 0x1000>; host-raw-interface = "eth0"; }; + + eth@90000000 { + compatible = "sandbox,eth-raw"; + reg = <0x90000000 0x1000>; + host-raw-interface = "lo"; + }; }; diff --git a/arch/sandbox/include/asm/eth-raw-os.h b/arch/sandbox/include/asm/eth-raw-os.h index df60c4f..ed4b2e2 100644 --- a/arch/sandbox/include/asm/eth-raw-os.h +++ b/arch/sandbox/include/asm/eth-raw-os.h @@ -15,16 +15,24 @@ * * sd: socket descriptor - the open socket during a session * device: struct sockaddr_ll - the host interface packets move to/from + * local: 1 or 0 to select the local interface ('lo') or not + * local_bindsd: socket descriptor to prevent the kernel from sending + * a message to the server claiming the port is + * unreachable + * local_bind_udp_port: The UDP port number that we bound to */ struct eth_sandbox_raw_priv { int sd; void *device; + int local; + int local_bind_sd; + unsigned short local_bind_udp_port; };
int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, struct eth_sandbox_raw_priv *priv); int sandbox_eth_raw_os_send(void *packet, int length, - const struct eth_sandbox_raw_priv *priv); + struct eth_sandbox_raw_priv *priv); int sandbox_eth_raw_os_recv(void *packet, int *length, const struct eth_sandbox_raw_priv *priv); void sandbox_eth_raw_os_stop(struct eth_sandbox_raw_priv *priv); diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox index aedf05a..73743e0 100644 --- a/board/sandbox/README.sandbox +++ b/board/sandbox/README.sandbox @@ -241,6 +241,28 @@ dhcp set serverip WWW.XXX.YYY.ZZZ tftpboot u-boot.bin
+The bridge also support (to a lesser extent) the localhost inderface, 'lo'. + +The 'lo' interface cannot use the RAW AF_PACKET API because the lo interface +doesn't support Ethernet-level traffic. It is a higher-level interface that is +expected only to be used at the AF_INET level of the API. As such, the most raw +we can get on that interface is the RAW AF_INET API on UDP. This allows us to +set the IP_HDRINCL option to include everything except the Ethernet header in +the packets we send and receive. + +Because only UDP is supported, ICMP traffic will not work, so expect that ping +commands will time out. + +The default device tree for sandbox includes an entry for lo on the sandbox +host machine whose alias is "eth5". The following is an example of a network +operation being tested on the lo interface. + +TFTP +.... + +set ethact eth5 +tftpboot u-boot.bin +
SPI Emulation ------------- diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c index 435b874..91da5f5 100644 --- a/drivers/net/sandbox-raw.c +++ b/drivers/net/sandbox-raw.c @@ -15,6 +15,8 @@
DECLARE_GLOBAL_DATA_PTR;
+static int reply_arp; +static IPaddr_t arp_ip;
static int sb_eth_raw_start(struct udevice *dev) { @@ -29,6 +31,11 @@ static int sb_eth_raw_start(struct udevice *dev) if (interface == NULL) return -EINVAL;
+ if (strcmp(interface, "lo") == 0) { + priv->local = 1; + setenv("ipaddr", "127.0.0.1"); + setenv("serverip", "127.0.0.1"); + } return sandbox_eth_raw_os_start(interface, pdata->enetaddr, priv); }
@@ -38,18 +45,78 @@ static int sb_eth_raw_send(struct udevice *dev, void *packet, int length)
debug("eth_sandbox_raw: Send packet %d\n", length);
+ if (priv->local) { + struct ethernet_hdr *eth = packet; + + if (ntohs(eth->et_protlen) == PROT_ARP) { + struct arp_hdr *arp = packet + ETHER_HDR_SIZE; + + /** + * localhost works on a higher-level API in Linux than + * ARP packets, so fake it + */ + arp_ip = NetReadIP(&arp->ar_tpa); + reply_arp = 1; + return 0; + } + packet += ETHER_HDR_SIZE; + length -= ETHER_HDR_SIZE; + } return sandbox_eth_raw_os_send(packet, length, priv); }
static int sb_eth_raw_recv(struct udevice *dev, uchar **packetp) { + struct eth_pdata *pdata = dev_get_platdata(dev); struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); - int retval; + int retval = 0; int length;
- retval = sandbox_eth_raw_os_recv(net_rx_packets[0], &length, priv); + if (reply_arp) { + struct arp_hdr *arp = (void *)net_rx_packets[0] + + ETHER_HDR_SIZE; + + /* + * Fake an ARP response. The u-boot network stack is sending an + * ARP request (to find the MAC address to address the actual + * packet to) and requires an ARP response to continue. Since + * this is the localhost interface, there is no Etherent level + * traffic at all, so there is no way to send an ARP request or + * to get a response. For this reason we fake the response to + * make the u-boot network stack happy. + */ + arp->ar_hrd = htons(ARP_ETHER); + arp->ar_pro = htons(PROT_IP); + arp->ar_hln = ARP_HLEN; + arp->ar_pln = ARP_PLEN; + arp->ar_op = htons(ARPOP_REPLY); + /* Any non-zero MAC address will work */ + memset(&arp->ar_sha, 0x01, ARP_HLEN); + /* Use whatever IP we were looking for (always 127.0.0.1?) */ + NetWriteIP(&arp->ar_spa, arp_ip); + memcpy(&arp->ar_tha, pdata->enetaddr, ARP_HLEN); + NetWriteIP(&arp->ar_tpa, NetOurIP); + length = ARP_HDR_SIZE; + } else { + /* If local, the Ethernet header won't be included; skip it */ + uchar *pktptr = priv->local ? + net_rx_packets[0] + ETHER_HDR_SIZE : net_rx_packets[0]; + + retval = sandbox_eth_raw_os_recv(pktptr, &length, priv); + }
if (!retval && length) { + if (priv->local) { + struct ethernet_hdr *eth = (void *)net_rx_packets[0]; + + /* Fill in enough of the missing Ethernet header */ + memcpy(eth->et_dest, pdata->enetaddr, ARP_HLEN); + memset(eth->et_src, 0x01, ARP_HLEN); + eth->et_protlen = htons(reply_arp ? PROT_ARP : PROT_IP); + reply_arp = 0; + length += ETHER_HDR_SIZE; + } + debug("eth_sandbox_raw: received packet %d\n", length); *packetp = net_rx_packets[0];

On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com wrote:
The 'lo' interface on Linux doesn't support thinks like ARP or link-layer access like we use to talk to a normal network interface. A higher-level network API must be used to access localhost.
As written, this interface is limited to not supporting ICMP since the API doesn't allow the socket to be opened for all IP traffic and be able to receive at the same time. UDP is far more useful to test with, so it was selected over ICMP. Ping won't work, but things like TFTP should work.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v5: -Add details about lo support to the README -Remove socket timeout -Separate init to 2 helper static functions -Set the socket to non-blocking -Use INADDR_LOOPBACK -Use more verbose comments
Reviewed-by: Simon Glass sjg@chromium.org

Take a pass at plumbing errors through to the users of the network stack
Currently only the start() function errors will be returned from NetLoop(). recv() tends not to have errors, so that is likely not worth adding. send() certainly can return errors, but this patch does not attempt to plumb them yet. halt() is not expected to error.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 3 ++- net/eth.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-------- net/net.c | 26 ++++++++++++++++++-------- test/dm/eth.c | 4 ++-- 4 files changed, 70 insertions(+), 19 deletions(-)
diff --git a/include/net.h b/include/net.h index 5846dfb..c702f2f 100644 --- a/include/net.h +++ b/include/net.h @@ -539,7 +539,7 @@ int NetLoop(enum proto_t); void NetStop(void);
/* Load failed. Start again. */ -void NetStartAgain(void); +int NetStartAgain(void);
/* Get size of the ethernet header when we send */ int NetEthHdrSize(void); @@ -609,6 +609,7 @@ static inline void net_set_state(enum net_loop_state state) /* Transmit a packet */ static inline void NetSendPacket(uchar *pkt, int len) { + /* Currently no way to return errors from eth_send() */ (void) eth_send(pkt, len); }
diff --git a/net/eth.c b/net/eth.c index 9966cf0..81ca436 100644 --- a/net/eth.c +++ b/net/eth.c @@ -98,6 +98,9 @@ struct eth_uclass_priv { struct udevice *current; };
+/* eth_errno - This stores the most recent failure code from DM functions */ +static int eth_errno; + static struct eth_uclass_priv *eth_get_uclass_priv(void) { struct uclass *uc; @@ -118,20 +121,32 @@ static void eth_set_current_to_next(void) uclass_first_device(UCLASS_ETH, &uc_priv->current); }
+/* + * Typically this will simply return the active device. + * In the case where the most recent active device was unset, this will attempt + * to return the first device. If that device doesn't exist or fails to probe, + * this function will return NULL. + */ struct udevice *eth_get_dev(void) { struct eth_uclass_priv *uc_priv;
uc_priv = eth_get_uclass_priv(); if (!uc_priv->current) - uclass_first_device(UCLASS_ETH, + eth_errno = uclass_first_device(UCLASS_ETH, &uc_priv->current); return uc_priv->current; }
+/* + * Typically this will just store a device pointer. + * In case it was not probed, we will attempt to do so. + * dev may be NULL to unset the active device. + */ static void eth_set_dev(struct udevice *dev) { - device_probe(dev); + if (dev && !device_active(dev)) + eth_errno = device_probe(dev); eth_get_uclass_priv()->current = dev; }
@@ -155,7 +170,14 @@ struct udevice *eth_get_dev_by_name(const char *devname)
uclass_get(UCLASS_ETH, &uc); uclass_foreach_dev(it, uc) { - /* We need the seq to be valid, so make sure it's probed */ + /* + * We need the seq to be valid, so try to probe it. + * If the probe fails, the seq will not match since it will be + * -1 instead of what we are looking for. + * We don't care about errors from probe here. Either they won't + * match an alias or it will match a literal name and we'll pick + * up the error when we try to probe again in eth_set_dev(). + */ device_probe(it); /* * Check for the name or the sequence number to match @@ -221,6 +243,7 @@ int eth_init(void) { struct udevice *current; struct udevice *old_current; + int ret = -ENODEV;
current = eth_get_dev(); if (!current) { @@ -243,22 +266,29 @@ int eth_init(void) else memset(pdata->enetaddr, 0, 6);
- if (eth_get_ops(current)->start(current) >= 0) { + ret = eth_get_ops(current)->start(current); + if (ret >= 0) { struct eth_device_priv *priv = current->uclass_priv;
priv->state = ETH_STATE_ACTIVE; return 0; } - } + } else + ret = eth_errno; + debug("FAIL\n");
- /* This will ensure the new "current" attempted to probe */ + /* + * If ethrotate is enabled, this will change "current", + * otherwise we will drop out of this while loop immediately + */ eth_try_another(0); + /* This will ensure the new "current" attempted to probe */ current = eth_get_dev(); } while (old_current != current);
- return -ENODEV; + return ret; }
void eth_halt(void) @@ -278,6 +308,7 @@ void eth_halt(void) int eth_send(void *packet, int length) { struct udevice *current; + int ret;
current = eth_get_dev(); if (!current) @@ -286,7 +317,12 @@ int eth_send(void *packet, int length) if (!device_active(current)) return -EINVAL;
- return eth_get_ops(current)->send(current, packet, length); + ret = eth_get_ops(current)->send(current, packet, length); + if (ret < 0) { + /* We cannot completely return the error at present */ + debug("%s: send() returned error %d\n", __func__, ret); + } + return ret; }
int eth_rx(void) @@ -311,6 +347,10 @@ int eth_rx(void) else break; } + if (ret < 0) { + /* We cannot completely return the error at present */ + debug("%s: recv() returned error %d\n", __func__, ret); + } return ret; }
diff --git a/net/net.c b/net/net.c index afec443..69f38f7 100644 --- a/net/net.c +++ b/net/net.c @@ -84,6 +84,7 @@ #include <common.h> #include <command.h> #include <environment.h> +#include <errno.h> #include <net.h> #if defined(CONFIG_STATUS_LED) #include <miiphy.h> @@ -333,7 +334,7 @@ void net_init(void)
int NetLoop(enum proto_t protocol) { - int ret = -1; + int ret = -EINVAL;
NetRestarted = 0; NetDevExists = 0; @@ -345,9 +346,10 @@ int NetLoop(enum proto_t protocol) if (eth_is_on_demand_init() || protocol != NETCONS) { eth_halt(); eth_set_current(); - if (eth_init() < 0) { + ret = eth_init(); + if (ret < 0) { eth_halt(); - return -1; + return ret; } } else eth_init_state_only(); @@ -370,7 +372,7 @@ restart: case 1: /* network not configured */ eth_halt(); - return -1; + return -ENODEV;
case 2: /* network device not configured */ @@ -484,6 +486,8 @@ restart: /* * Check the ethernet for a new packet. The ethernet * receive routine will process it. + * Most drivers return the most recent packet size, but not + * errors that may have happened. */ eth_rx();
@@ -537,7 +541,7 @@ restart: }
if (net_state == NETLOOP_FAIL) - NetStartAgain(); + ret = NetStartAgain();
switch (net_state) {
@@ -597,11 +601,12 @@ startAgainTimeout(void) net_set_state(NETLOOP_RESTART); }
-void NetStartAgain(void) +int NetStartAgain(void) { char *nretry; int retry_forever = 0; unsigned long retrycnt = 0; + int ret;
nretry = getenv("netretry"); if (nretry) { @@ -621,7 +626,11 @@ void NetStartAgain(void) if ((!retry_forever) && (NetTryCount >= retrycnt)) { eth_halt(); net_set_state(NETLOOP_FAIL); - return; + /* + * We don't provide a way for the protocol to return an error, + * but this is almost always the reason. + */ + return -ETIMEDOUT; }
NetTryCount++; @@ -630,7 +639,7 @@ void NetStartAgain(void) #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER) eth_try_another(!NetRestarted); #endif - eth_init(); + ret = eth_init(); if (NetRestartWrap) { NetRestartWrap = 0; if (NetDevExists) { @@ -642,6 +651,7 @@ void NetStartAgain(void) } else { net_set_state(NETLOOP_RESTART); } + return ret; }
/**********************************************************************/ diff --git a/test/dm/eth.c b/test/dm/eth.c index a0e9359..1923670 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -99,7 +99,7 @@ static int dm_test_eth_rotate(struct dm_test_state *dms) /* If ethrotate is no, then we should fail on a bad MAC */ setenv("ethact", "eth@10004000"); setenv("ethrotate", "no"); - ut_asserteq(-1, NetLoop(PING)); + ut_asserteq(-EINVAL, NetLoop(PING)); ut_asserteq_str("eth@10004000", getenv("ethact"));
/* Restore the env */ @@ -144,7 +144,7 @@ static int dm_test_net_retry(struct dm_test_state *dms) */ setenv("ethact", "eth@10004000"); setenv("netretry", "no"); - ut_asserteq(-1, NetLoop(PING)); + ut_asserteq(-ETIMEDOUT, NetLoop(PING)); ut_asserteq_str("eth@10004000", getenv("ethact"));
/* Restore the env */

Hi Joe,
On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com wrote:
Take a pass at plumbing errors through to the users of the network stack
Currently only the start() function errors will be returned from NetLoop(). recv() tends not to have errors, so that is likely not worth adding. send() certainly can return errors, but this patch does not attempt to plumb them yet. halt() is not expected to error.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Nice patch!
Reviewed-by: Simon Glass sjg@chromium.org
Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 3 ++- net/eth.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-------- net/net.c | 26 ++++++++++++++++++-------- test/dm/eth.c | 4 ++-- 4 files changed, 70 insertions(+), 19 deletions(-)
diff --git a/include/net.h b/include/net.h index 5846dfb..c702f2f 100644 --- a/include/net.h +++ b/include/net.h @@ -539,7 +539,7 @@ int NetLoop(enum proto_t); void NetStop(void);
/* Load failed. Start again. */ -void NetStartAgain(void); +int NetStartAgain(void);
/* Get size of the ethernet header when we send */ int NetEthHdrSize(void); @@ -609,6 +609,7 @@ static inline void net_set_state(enum net_loop_state state) /* Transmit a packet */ static inline void NetSendPacket(uchar *pkt, int len) {
/* Currently no way to return errors from eth_send() */ (void) eth_send(pkt, len);
}
diff --git a/net/eth.c b/net/eth.c index 9966cf0..81ca436 100644 --- a/net/eth.c +++ b/net/eth.c @@ -98,6 +98,9 @@ struct eth_uclass_priv { struct udevice *current; };
+/* eth_errno - This stores the most recent failure code from DM functions */ +static int eth_errno;
static struct eth_uclass_priv *eth_get_uclass_priv(void) { struct uclass *uc; @@ -118,20 +121,32 @@ static void eth_set_current_to_next(void) uclass_first_device(UCLASS_ETH, &uc_priv->current); }
+/*
- Typically this will simply return the active device.
- In the case where the most recent active device was unset, this will attempt
- to return the first device. If that device doesn't exist or fails to probe,
- this function will return NULL.
- */
struct udevice *eth_get_dev(void) { struct eth_uclass_priv *uc_priv;
uc_priv = eth_get_uclass_priv(); if (!uc_priv->current)
uclass_first_device(UCLASS_ETH,
eth_errno = uclass_first_device(UCLASS_ETH, &uc_priv->current); return uc_priv->current;
}
+/*
- Typically this will just store a device pointer.
- In case it was not probed, we will attempt to do so.
- dev may be NULL to unset the active device.
- */
static void eth_set_dev(struct udevice *dev) {
device_probe(dev);
if (dev && !device_active(dev))
eth_errno = device_probe(dev); eth_get_uclass_priv()->current = dev;
}
@@ -155,7 +170,14 @@ struct udevice *eth_get_dev_by_name(const char *devname)
uclass_get(UCLASS_ETH, &uc); uclass_foreach_dev(it, uc) {
/* We need the seq to be valid, so make sure it's probed */
/*
* We need the seq to be valid, so try to probe it.
* If the probe fails, the seq will not match since it will be
* -1 instead of what we are looking for.
* We don't care about errors from probe here. Either they won't
* match an alias or it will match a literal name and we'll pick
* up the error when we try to probe again in eth_set_dev().
*/ device_probe(it); /* * Check for the name or the sequence number to match
@@ -221,6 +243,7 @@ int eth_init(void) { struct udevice *current; struct udevice *old_current;
int ret = -ENODEV; current = eth_get_dev(); if (!current) {
@@ -243,22 +266,29 @@ int eth_init(void) else memset(pdata->enetaddr, 0, 6);
if (eth_get_ops(current)->start(current) >= 0) {
ret = eth_get_ops(current)->start(current);
if (ret >= 0) { struct eth_device_priv *priv = current->uclass_priv; priv->state = ETH_STATE_ACTIVE; return 0; }
}
} else
ret = eth_errno;
debug("FAIL\n");
/* This will ensure the new "current" attempted to probe */
/*
* If ethrotate is enabled, this will change "current",
* otherwise we will drop out of this while loop immediately
*/ eth_try_another(0);
/* This will ensure the new "current" attempted to probe */ current = eth_get_dev(); } while (old_current != current);
return -ENODEV;
return ret;
}
void eth_halt(void) @@ -278,6 +308,7 @@ void eth_halt(void) int eth_send(void *packet, int length) { struct udevice *current;
int ret; current = eth_get_dev(); if (!current)
@@ -286,7 +317,12 @@ int eth_send(void *packet, int length) if (!device_active(current)) return -EINVAL;
return eth_get_ops(current)->send(current, packet, length);
ret = eth_get_ops(current)->send(current, packet, length);
if (ret < 0) {
/* We cannot completely return the error at present */
debug("%s: send() returned error %d\n", __func__, ret);
}
return ret;
}
int eth_rx(void) @@ -311,6 +347,10 @@ int eth_rx(void) else break; }
if (ret < 0) {
/* We cannot completely return the error at present */
debug("%s: recv() returned error %d\n", __func__, ret);
} return ret;
}
diff --git a/net/net.c b/net/net.c index afec443..69f38f7 100644 --- a/net/net.c +++ b/net/net.c @@ -84,6 +84,7 @@ #include <common.h> #include <command.h> #include <environment.h> +#include <errno.h> #include <net.h> #if defined(CONFIG_STATUS_LED) #include <miiphy.h> @@ -333,7 +334,7 @@ void net_init(void)
int NetLoop(enum proto_t protocol) {
int ret = -1;
int ret = -EINVAL; NetRestarted = 0; NetDevExists = 0;
@@ -345,9 +346,10 @@ int NetLoop(enum proto_t protocol) if (eth_is_on_demand_init() || protocol != NETCONS) { eth_halt(); eth_set_current();
if (eth_init() < 0) {
ret = eth_init();
if (ret < 0) { eth_halt();
return -1;
return ret; } } else eth_init_state_only();
@@ -370,7 +372,7 @@ restart: case 1: /* network not configured */ eth_halt();
return -1;
return -ENODEV; case 2: /* network device not configured */
@@ -484,6 +486,8 @@ restart: /* * Check the ethernet for a new packet. The ethernet * receive routine will process it.
* Most drivers return the most recent packet size, but not
* errors that may have happened. */ eth_rx();
@@ -537,7 +541,7 @@ restart: }
if (net_state == NETLOOP_FAIL)
NetStartAgain();
ret = NetStartAgain();
Where does this 'ret' get used?
switch (net_state) {
@@ -597,11 +601,12 @@ startAgainTimeout(void) net_set_state(NETLOOP_RESTART); }
-void NetStartAgain(void) +int NetStartAgain(void) { char *nretry; int retry_forever = 0; unsigned long retrycnt = 0;
int ret; nretry = getenv("netretry"); if (nretry) {
@@ -621,7 +626,11 @@ void NetStartAgain(void) if ((!retry_forever) && (NetTryCount >= retrycnt)) { eth_halt(); net_set_state(NETLOOP_FAIL);
return;
/*
* We don't provide a way for the protocol to return an error,
* but this is almost always the reason.
*/
return -ETIMEDOUT; } NetTryCount++;
@@ -630,7 +639,7 @@ void NetStartAgain(void) #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER) eth_try_another(!NetRestarted); #endif
eth_init();
ret = eth_init(); if (NetRestartWrap) { NetRestartWrap = 0; if (NetDevExists) {
@@ -642,6 +651,7 @@ void NetStartAgain(void) } else { net_set_state(NETLOOP_RESTART); }
return ret;
}
/**********************************************************************/ diff --git a/test/dm/eth.c b/test/dm/eth.c index a0e9359..1923670 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -99,7 +99,7 @@ static int dm_test_eth_rotate(struct dm_test_state *dms) /* If ethrotate is no, then we should fail on a bad MAC */ setenv("ethact", "eth@10004000"); setenv("ethrotate", "no");
ut_asserteq(-1, NetLoop(PING));
ut_asserteq(-EINVAL, NetLoop(PING)); ut_asserteq_str("eth@10004000", getenv("ethact")); /* Restore the env */
@@ -144,7 +144,7 @@ static int dm_test_net_retry(struct dm_test_state *dms) */ setenv("ethact", "eth@10004000"); setenv("netretry", "no");
ut_asserteq(-1, NetLoop(PING));
ut_asserteq(-ETIMEDOUT, NetLoop(PING)); ut_asserteq_str("eth@10004000", getenv("ethact")); /* Restore the env */
-- 1.7.11.5
Regards, Simon

On Wed, Mar 4, 2015 at 12:35 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 3 March 2015 at 19:41, Joe Hershberger joe.hershberger@ni.com wrote:
Take a pass at plumbing errors through to the users of the network stack
Currently only the start() function errors will be returned from NetLoop(). recv() tends not to have errors, so that is likely not worth adding. send() certainly can return errors, but this patch does not attempt to plumb them yet. halt() is not expected to error.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Nice patch!
Reviewed-by: Simon Glass sjg@chromium.org
Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 3 ++- net/eth.c | 56
++++++++++++++++++++++++++++++++++++++++++++++++--------
net/net.c | 26 ++++++++++++++++++-------- test/dm/eth.c | 4 ++-- 4 files changed, 70 insertions(+), 19 deletions(-)
[snip]
diff --git a/net/net.c b/net/net.c index afec443..69f38f7 100644 --- a/net/net.c +++ b/net/net.c @@ -84,6 +84,7 @@ #include <common.h> #include <command.h> #include <environment.h> +#include <errno.h> #include <net.h> #if defined(CONFIG_STATUS_LED) #include <miiphy.h> @@ -333,7 +334,7 @@ void net_init(void)
int NetLoop(enum proto_t protocol) {
int ret = -1;
int ret = -EINVAL; NetRestarted = 0; NetDevExists = 0;
@@ -345,9 +346,10 @@ int NetLoop(enum proto_t protocol) if (eth_is_on_demand_init() || protocol != NETCONS) { eth_halt(); eth_set_current();
if (eth_init() < 0) {
ret = eth_init();
if (ret < 0) { eth_halt();
return -1;
return ret; } } else eth_init_state_only();
@@ -370,7 +372,7 @@ restart: case 1: /* network not configured */ eth_halt();
return -1;
return -ENODEV; case 2: /* network device not configured */
@@ -484,6 +486,8 @@ restart: /* * Check the ethernet for a new packet. The
ethernet
* receive routine will process it.
* Most drivers return the most recent packet
size, but not
* errors that may have happened. */ eth_rx();
@@ -537,7 +541,7 @@ restart: }
if (net_state == NETLOOP_FAIL)
NetStartAgain();
ret = NetStartAgain();
Where does this 'ret' get used?
This is part of the NetLoop() function, the top-most interface to the network stack in net.c.
If the net_state remains "NETLOOP_FAIL" after calling NetStartAgain, then the case structure following this if will "goto done".
At the end of done: is:
return ret;
We need to pass the return value out of NetStartAgain, since it can possibly call eth_ops->start() on a new device.
switch (net_state) {
@@ -597,11 +601,12 @@ startAgainTimeout(void) net_set_state(NETLOOP_RESTART); }
-void NetStartAgain(void) +int NetStartAgain(void) { char *nretry; int retry_forever = 0; unsigned long retrycnt = 0;
int ret; nretry = getenv("netretry"); if (nretry) {
@@ -621,7 +626,11 @@ void NetStartAgain(void) if ((!retry_forever) && (NetTryCount >= retrycnt)) { eth_halt(); net_set_state(NETLOOP_FAIL);
return;
/*
* We don't provide a way for the protocol to return an
error,
* but this is almost always the reason.
*/
return -ETIMEDOUT; } NetTryCount++;
@@ -630,7 +639,7 @@ void NetStartAgain(void) #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER) eth_try_another(!NetRestarted); #endif
eth_init();
ret = eth_init(); if (NetRestartWrap) { NetRestartWrap = 0; if (NetDevExists) {
@@ -642,6 +651,7 @@ void NetStartAgain(void) } else { net_set_state(NETLOOP_RESTART); }
return ret;
}
/**********************************************************************/
[snip]

Add support for the Ethernet MAC controllers. Phy support will come later.
Switching from RFC to a patch series to be applied to dm/master as a staging area for this series to make it happen more quickly when the window opens.
If desired, let me know which of the non-DM related prerequisite patches are wanted for this release.
I've added unit tests to verify functionality.
There is an additional driver for sandbox that bridges to the RAW Ethernet API in Linux which lets you test with real traffic. It now supports localhost as well (the 'lo' interface).
Changes in v6: -Add function comments -Addressed nits -Check array index bounds -Fix compile error on boards with CONFIG_API enabled -Fix compile errors for other boards due to removed parameters -Swallow -EAGAIN error in eth_rx() -Updated function documentation
Changes in v5: -Add a note to doc/README.drivers.eth about its obsolescence -Add details about lo support to the README -Added a comment about devname -Added a test for skipping un-probe-able devices -Added comments about test cases -Added fallback for setting promiscuous mode -Added help to Kconfig -Added help to the sandbox eth mock driver Kconfig entry -Added more details and examples in the README -Check for NULL when reading fdt for host interface -Check for malloc failure -Expanded the Kconfig help -Fix compile error on !DM_ETH -Fixed warning from missing declaration -Include new mapmem.h header -Moved dm/ header -Moved to a separate header mapmem.h -New to v5 -Only check for alias if the name is long enough -Remove cast of pointer passed to free -Remove socket timeout -Remove the empty sb_eth_raw_remove function -Return -errno in from send and recv -Return errno from recv -Separate init to 2 helper static functions -Set the socket to non-blocking -Simplify sandbox eth driver by switching from int array to byte array -Switch priv from packet buffer to a pointer to net_rx_packets[0] -Switched to function to control state of mock driver -Unmap memory for consistency -Use INADDR_LOOPBACK -Use a function call to change mock driver behavior -Use local var for priv in eth_get_dev() -Use more verbose comments -Use net_rx_packets instead of a stack buffer
Changes in v4: --Don't prevent eth_initialize on driver model --If current == NULL, always check if there is a device available in eth_get_dev --Include ethprime handling in eth_initialize --Look up MAC address in post-probe --Move env init call from uclass init to eth_initialize --Print the alias in eth_initialize --Use eth_initialize to probe all devices and write_hwaddr -Add a helper function for eth_uclass_priv -Add ability to disable ping reply in sandbox eth driver -Add comments to priv struct definition -Add documentation to the structures -Add eth_get_ops helper -Added comments to README.sandbox -Added support for the 'lo' network interface -Added testing for ethrotate -Change -1 returns to error constants -Change puts to printf -Clean up the interface to sandbox's eth-raw-os by passing priv to raw-os -Cleaned up sandbox EXTRA_ENV define -Cleanup var definition order -Fix compile regression in !DM_ETH case -Fixed the MAC address limitation (now all traffic uses MAC address from env) -Load from ethprime on eth_initialize() -Move os file to arch -Moved config to Kconfig -New to v4 -Redo the seq / probe implementation -Remove bd_t *bis from dm eth_ops init function -Remove checks for driver==NULL -Remove priv pointer in per-device priv struct (drivers already get their own directly from DM) -Removed checks on priv != NULL and added protection in uclass instead -Rename halt() to stop() in ops -Rename init() to start() in ops -Stop handling selecting a new "current" in pre-unbind as it will now work itself out by clearing the pointer -Updated expected behavior based on changes to the NetLoop -Use accessors for platdata and priv -Use only the seq from DM to find aliases
Changes in v3: --Fail init if not activated --Fail probe if ethaddr not set -Added 2 more ethaddr to sandbox -Added dm eth testing -Added support for aliases -Added support for ethprime -Added testing for netretry -Allow current eth dev to be NULL -Correct failure chaining from bind to probe to init -Correct the pre_unbind logic -Fixed blank line formatting for variable declaration -Made the os raw packet support for sandbox eth build and work. -Move the get_dev_by_* protos to also be !DM_ETH like the impl -Prevent a crash if memory is not allocated -Print which device in the debug write hwaddr -Reorder dm test makefile -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the previous selection
Changes in v2: -Added the raw packet proof-of-concept patch. -Cause an invalid name to fail binding -Change printfs to debug in sandbox driver -Changed eth_uclass_priv local var names to be uc_priv -Move fake hwaddr to the device tree -Move static data to priv -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()). -Rebase on top of dm/master -Remove unused priv struct for sandbox driver -Removed extra parentheses -Stop maintaining our own index and use DM seq now that it works for our needs -Update error codes -Updated comments
Joe Hershberger (27): test: dm: Reorder the objects to build common: Make sure arch-specific map_sysmem() is defined net: Provide a function to get the current MAC address net: Rename helper function to be more clear net: Remove unneeded "extern" in net.h net: Refactor in preparation for driver model net: Change return codes from net/eth.c to use errorno constants net: Use int instead of u8 for boolean flag net: Remove the bd* parameter from net stack functions net: Make netretry actually do something net: Access mapped physmem in net functions cmd: net: Clean up return codes dm: eth: Add basic driver model support to Ethernet stack net: Clean up network stack names used in DM drivers dm: eth: Pass the packet pointer as a parameter to recv sandbox: eth: Add network support to sandbox sandbox: eth: Add ARP and PING response to sandbox driver test: dm: eth: Add tests for the eth dm implementation dm: eth: Add support for aliases dm: eth: Add support for ethprime env var test: dm: eth: Add testing for ethrotate env var sandbox: eth: Add ability to disable ping reply in sandbox eth driver test: dm: net: Add a test of the netretry behavior sandbox: eth: Add a bridge to a real network for sandbox sandbox: Enable DHCP and IP defrag sandbox: eth: Add support for using the 'lo' interface net: Improve error handling
api/api_net.c | 2 +- arch/arm/lib/board.c | 2 +- arch/arm/lib/bootm.c | 1 + arch/avr32/lib/board.c | 2 +- arch/m68k/lib/board.c | 4 +- arch/mips/mach-au1x00/au1x00_eth.c | 2 +- arch/nds32/lib/board.c | 2 +- arch/openrisc/lib/board.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- arch/powerpc/lib/board.c | 2 +- arch/sandbox/Kconfig | 12 + arch/sandbox/cpu/Makefile | 10 + arch/sandbox/cpu/eth-raw-os.c | 249 +++++++++++++ arch/sandbox/dts/sandbox.dts | 21 ++ arch/sandbox/include/asm/eth-raw-os.h | 40 +++ arch/sandbox/include/asm/eth.h | 15 + arch/sh/lib/board.c | 2 +- arch/sparc/lib/board.c | 2 +- board/BuS/eb_cpux9k2/cpux9k2.c | 2 +- board/BuS/vl_ma2sc/vl_ma2sc.c | 2 +- board/atmel/at91sam9261ek/at91sam9261ek.c | 2 +- board/egnite/ethernut5/ethernut5.c | 2 +- board/ronetix/pm9261/pm9261.c | 2 +- board/ronetix/pm9g45/pm9g45.c | 2 +- board/sandbox/README.sandbox | 78 +++- common/board_f.c | 1 + common/board_r.c | 3 +- common/bootm.c | 1 + common/cmd_bdinfo.c | 2 + common/cmd_bootm.c | 1 + common/cmd_demo.c | 1 + common/cmd_fat.c | 1 + common/cmd_fdt.c | 1 + common/cmd_lzmadec.c | 1 + common/cmd_md5sum.c | 1 + common/cmd_mem.c | 1 + common/cmd_net.c | 45 ++- common/cmd_nvedit.c | 1 + common/cmd_pxe.c | 1 + common/cmd_sf.c | 1 + common/cmd_source.c | 1 + common/cmd_trace.c | 1 + common/cmd_ximg.c | 1 + common/hash.c | 1 + common/image-fdt.c | 1 + common/image-fit.c | 1 + common/image.c | 1 + common/iotrace.c | 1 + common/lcd.c | 1 + common/malloc_simple.c | 1 + common/spl/spl_net.c | 2 +- doc/README.drivers.eth | 6 + drivers/demo/demo-simple.c | 1 + drivers/i2c/i2c-uniphier-f.c | 1 + drivers/i2c/i2c-uniphier.c | 1 + drivers/mtd/spi/sf_probe.c | 1 + drivers/net/Kconfig | 42 +++ drivers/net/Makefile | 2 + drivers/net/netconsole.c | 4 +- drivers/net/sandbox-raw.c | 165 +++++++++ drivers/net/sandbox.c | 208 +++++++++++ drivers/serial/ns16550.c | 1 + drivers/serial/serial_uniphier.c | 1 + fs/fs.c | 1 + include/common.h | 17 - include/configs/sandbox.h | 25 +- include/dm/uclass-id.h | 1 + include/mapmem.h | 32 ++ include/net.h | 201 +++++++---- lib/trace.c | 1 + net/eth.c | 580 ++++++++++++++++++++++++++---- net/net.c | 67 ++-- net/nfs.c | 6 +- net/tftp.c | 6 +- test/compression.c | 1 + test/dm/Makefile | 5 +- test/dm/cmd_dm.c | 1 + test/dm/eth.c | 156 ++++++++ test/dm/test.dts | 20 ++ 81 files changed, 1866 insertions(+), 227 deletions(-) create mode 100644 arch/sandbox/cpu/eth-raw-os.c create mode 100644 arch/sandbox/include/asm/eth-raw-os.h create mode 100644 arch/sandbox/include/asm/eth.h create mode 100644 drivers/net/sandbox-raw.c create mode 100644 drivers/net/sandbox.c create mode 100644 include/mapmem.h create mode 100644 test/dm/eth.c

Signed-off-by: Joe Hershberger joe.hershberger@ni.com Acked-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: -Reorder dm test makefile
Changes in v2: None
test/dm/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/dm/Makefile b/test/dm/Makefile index 612aa95..1d9148f 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_DM_TEST) += core.o obj-$(CONFIG_DM_TEST) += ut.o ifneq ($(CONFIG_SANDBOX),) obj-$(CONFIG_DM_GPIO) += gpio.o -obj-$(CONFIG_DM_SPI) += spi.o -obj-$(CONFIG_DM_SPI_FLASH) += sf.o obj-$(CONFIG_DM_I2C) += i2c.o +obj-$(CONFIG_DM_SPI_FLASH) += sf.o +obj-$(CONFIG_DM_SPI) += spi.o endif

In the case where the arch defines a custom map_sysmem(), make sure that including just mapmem.h is sufficient to have these functions as they are when the arch does not override it.
Also split the non-arch specific functions out of common.h
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: -Moved to a separate header mapmem.h
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
arch/arm/lib/bootm.c | 1 + common/board_f.c | 1 + common/board_r.c | 1 + common/bootm.c | 1 + common/cmd_bootm.c | 1 + common/cmd_demo.c | 1 + common/cmd_fat.c | 1 + common/cmd_fdt.c | 1 + common/cmd_lzmadec.c | 1 + common/cmd_md5sum.c | 1 + common/cmd_mem.c | 1 + common/cmd_nvedit.c | 1 + common/cmd_pxe.c | 1 + common/cmd_sf.c | 1 + common/cmd_source.c | 1 + common/cmd_trace.c | 1 + common/cmd_ximg.c | 1 + common/hash.c | 1 + common/image-fdt.c | 1 + common/image-fit.c | 1 + common/image.c | 1 + common/iotrace.c | 1 + common/lcd.c | 1 + common/malloc_simple.c | 1 + drivers/demo/demo-simple.c | 1 + drivers/i2c/i2c-uniphier-f.c | 1 + drivers/i2c/i2c-uniphier.c | 1 + drivers/mtd/spi/sf_probe.c | 1 + drivers/serial/ns16550.c | 1 + drivers/serial/serial_uniphier.c | 1 + fs/fs.c | 1 + include/common.h | 17 ----------------- include/mapmem.h | 32 ++++++++++++++++++++++++++++++++ lib/trace.c | 1 + test/compression.c | 1 + test/dm/cmd_dm.c | 1 + 36 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 include/mapmem.h
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index 2d6b676..b1bff8c 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -18,6 +18,7 @@ #include <u-boot/zlib.h> #include <asm/byteorder.h> #include <libfdt.h> +#include <mapmem.h> #include <fdt_support.h> #include <asm/bootm.h> #include <asm/secure.h> diff --git a/common/board_f.c b/common/board_f.c index 4d8b8a6..1b7e7d9 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -23,6 +23,7 @@ #include <i2c.h> #include <initcall.h> #include <logbuff.h> +#include <mapmem.h>
/* TODO: Can we move these into arch/ headers? */ #ifdef CONFIG_8xx diff --git a/common/board_r.c b/common/board_r.c index 4fcd4f6..af0f274 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -33,6 +33,7 @@ #endif #include <logbuff.h> #include <malloc.h> +#include <mapmem.h> #ifdef CONFIG_BITBANGMII #include <miiphy.h> #endif diff --git a/common/bootm.c b/common/bootm.c index 34f60bb..6842029 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -13,6 +13,7 @@ #include <fdt_support.h> #include <lmb.h> #include <malloc.h> +#include <mapmem.h> #include <asm/io.h> #include <linux/lzo.h> #include <lzma/LzmaTypes.h> diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 48199bf..b3d3968 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -16,6 +16,7 @@ #include <image.h> #include <lmb.h> #include <malloc.h> +#include <mapmem.h> #include <nand.h> #include <asm/byteorder.h> #include <linux/compiler.h> diff --git a/common/cmd_demo.c b/common/cmd_demo.c index 8a10bdf..209dc4a 100644 --- a/common/cmd_demo.c +++ b/common/cmd_demo.c @@ -9,6 +9,7 @@
#include <common.h> #include <dm-demo.h> +#include <mapmem.h> #include <asm/io.h>
struct udevice *demo_dev; diff --git a/common/cmd_fat.c b/common/cmd_fat.c index c00fb28..aae993d 100644 --- a/common/cmd_fat.c +++ b/common/cmd_fat.c @@ -14,6 +14,7 @@ #include <net.h> #include <ata.h> #include <asm/io.h> +#include <mapmem.h> #include <part.h> #include <fat.h> #include <fs.h> diff --git a/common/cmd_fdt.c b/common/cmd_fdt.c index 48b3e70..682b655 100644 --- a/common/cmd_fdt.c +++ b/common/cmd_fdt.c @@ -15,6 +15,7 @@ #include <asm/global_data.h> #include <libfdt.h> #include <fdt_support.h> +#include <mapmem.h> #include <asm/io.h>
#define MAX_LEVEL 32 /* how deeply nested we will go */ diff --git a/common/cmd_lzmadec.c b/common/cmd_lzmadec.c index 7b0b3fd..1ad9ed6 100644 --- a/common/cmd_lzmadec.c +++ b/common/cmd_lzmadec.c @@ -12,6 +12,7 @@
#include <common.h> #include <command.h> +#include <mapmem.h> #include <asm/io.h>
#include <lzma/LzmaTools.h> diff --git a/common/cmd_md5sum.c b/common/cmd_md5sum.c index d22ace5..23bb81e 100644 --- a/common/cmd_md5sum.c +++ b/common/cmd_md5sum.c @@ -10,6 +10,7 @@
#include <common.h> #include <command.h> +#include <mapmem.h> #include <u-boot/md5.h> #include <asm/io.h>
diff --git a/common/cmd_mem.c b/common/cmd_mem.c index bcb3ee3..66a41da 100644 --- a/common/cmd_mem.c +++ b/common/cmd_mem.c @@ -20,6 +20,7 @@ #endif #include <hash.h> #include <inttypes.h> +#include <mapmem.h> #include <watchdog.h> #include <asm/io.h> #include <linux/compiler.h> diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 855808c..be792ae 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -31,6 +31,7 @@ #include <search.h> #include <errno.h> #include <malloc.h> +#include <mapmem.h> #include <watchdog.h> #include <linux/stddef.h> #include <asm/byteorder.h> diff --git a/common/cmd_pxe.c b/common/cmd_pxe.c index 7e32c95..96f963d 100644 --- a/common/cmd_pxe.c +++ b/common/cmd_pxe.c @@ -8,6 +8,7 @@ #include <common.h> #include <command.h> #include <malloc.h> +#include <mapmem.h> #include <linux/string.h> #include <linux/ctype.h> #include <errno.h> diff --git a/common/cmd_sf.c b/common/cmd_sf.c index 5c788e9..01c37de 100644 --- a/common/cmd_sf.c +++ b/common/cmd_sf.c @@ -10,6 +10,7 @@ #include <div64.h> #include <dm.h> #include <malloc.h> +#include <mapmem.h> #include <spi.h> #include <spi_flash.h>
diff --git a/common/cmd_source.c b/common/cmd_source.c index 6881bc9..d2a881d 100644 --- a/common/cmd_source.c +++ b/common/cmd_source.c @@ -19,6 +19,7 @@ #include <command.h> #include <image.h> #include <malloc.h> +#include <mapmem.h> #include <asm/byteorder.h> #include <asm/io.h> #if defined(CONFIG_8xx) diff --git a/common/cmd_trace.c b/common/cmd_trace.c index 8c630e6..1e62a1a 100644 --- a/common/cmd_trace.c +++ b/common/cmd_trace.c @@ -6,6 +6,7 @@
#include <common.h> #include <command.h> +#include <mapmem.h> #include <trace.h> #include <asm/io.h>
diff --git a/common/cmd_ximg.c b/common/cmd_ximg.c index 64b9186..8b8645c 100644 --- a/common/cmd_ximg.c +++ b/common/cmd_ximg.c @@ -15,6 +15,7 @@ #include <common.h> #include <command.h> #include <image.h> +#include <mapmem.h> #include <watchdog.h> #if defined(CONFIG_BZIP2) #include <bzlib.h> diff --git a/common/hash.c b/common/hash.c index 9e9f84b..c94c98b 100644 --- a/common/hash.c +++ b/common/hash.c @@ -14,6 +14,7 @@ #include <common.h> #include <command.h> #include <malloc.h> +#include <mapmem.h> #include <hw_sha.h> #include <asm/io.h> #include <asm/errno.h> diff --git a/common/image-fdt.c b/common/image-fdt.c index d9e4728..7e2da7b 100644 --- a/common/image-fdt.c +++ b/common/image-fdt.c @@ -14,6 +14,7 @@ #include <errno.h> #include <image.h> #include <libfdt.h> +#include <mapmem.h> #include <asm/io.h>
#ifndef CONFIG_SYS_FDT_PAD diff --git a/common/image-fit.c b/common/image-fit.c index 778d2a1..4eb4d42 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -16,6 +16,7 @@ #else #include <common.h> #include <errno.h> +#include <mapmem.h> #include <asm/io.h> DECLARE_GLOBAL_DATA_PTR; #endif /* !USE_HOSTCC*/ diff --git a/common/image.c b/common/image.c index a911aa9..f3277c9 100644 --- a/common/image.c +++ b/common/image.c @@ -27,6 +27,7 @@
#include <environment.h> #include <image.h> +#include <mapmem.h>
#if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT) #include <libfdt.h> diff --git a/common/iotrace.c b/common/iotrace.c index ced426e..2725563 100644 --- a/common/iotrace.c +++ b/common/iotrace.c @@ -7,6 +7,7 @@ #define IOTRACE_IMPL
#include <common.h> +#include <mapmem.h> #include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR; diff --git a/common/lcd.c b/common/lcd.c index f33942c..6982759 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -15,6 +15,7 @@ #include <linux/types.h> #include <stdio_dev.h> #include <lcd.h> +#include <mapmem.h> #include <watchdog.h> #include <asm/unaligned.h> #include <splash.h> diff --git a/common/malloc_simple.c b/common/malloc_simple.c index 64ae036..d445199 100644 --- a/common/malloc_simple.c +++ b/common/malloc_simple.c @@ -8,6 +8,7 @@
#include <common.h> #include <malloc.h> +#include <mapmem.h> #include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR; diff --git a/drivers/demo/demo-simple.c b/drivers/demo/demo-simple.c index 2bcb7df..f069748 100644 --- a/drivers/demo/demo-simple.c +++ b/drivers/demo/demo-simple.c @@ -10,6 +10,7 @@ #include <common.h> #include <dm.h> #include <dm-demo.h> +#include <mapmem.h> #include <asm/io.h>
static int simple_hello(struct udevice *dev, int ch) diff --git a/drivers/i2c/i2c-uniphier-f.c b/drivers/i2c/i2c-uniphier-f.c index 6707edd..ffa6ce5 100644 --- a/drivers/i2c/i2c-uniphier-f.c +++ b/drivers/i2c/i2c-uniphier-f.c @@ -13,6 +13,7 @@ #include <dm/root.h> #include <i2c.h> #include <fdtdec.h> +#include <mapmem.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/i2c/i2c-uniphier.c b/drivers/i2c/i2c-uniphier.c index 64a9ed8..760457f 100644 --- a/drivers/i2c/i2c-uniphier.c +++ b/drivers/i2c/i2c-uniphier.c @@ -13,6 +13,7 @@ #include <dm/root.h> #include <i2c.h> #include <fdtdec.h> +#include <mapmem.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 4103723..ffc4caa 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -13,6 +13,7 @@ #include <errno.h> #include <fdtdec.h> #include <malloc.h> +#include <mapmem.h> #include <spi.h> #include <spi_flash.h> #include <asm/io.h> diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 03beab5..67b1d60 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -8,6 +8,7 @@ #include <dm.h> #include <errno.h> #include <fdtdec.h> +#include <mapmem.h> #include <ns16550.h> #include <serial.h> #include <watchdog.h> diff --git a/drivers/serial/serial_uniphier.c b/drivers/serial/serial_uniphier.c index a6bd27f..2a12250 100644 --- a/drivers/serial/serial_uniphier.c +++ b/drivers/serial/serial_uniphier.c @@ -10,6 +10,7 @@ #include <asm/errno.h> #include <dm/device.h> #include <dm/platform_data/serial-uniphier.h> +#include <mapmem.h> #include <serial.h> #include <fdtdec.h>
diff --git a/fs/fs.c b/fs/fs.c index 483273f..ac0897d 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -17,6 +17,7 @@ #include <config.h> #include <errno.h> #include <common.h> +#include <mapmem.h> #include <part.h> #include <ext4fs.h> #include <fat.h> diff --git a/include/common.h b/include/common.h index 77c55c6..3ccc6f3 100644 --- a/include/common.h +++ b/include/common.h @@ -845,23 +845,6 @@ int cpu_disable(int nr); int cpu_release(int nr, int argc, char * const argv[]); #endif
-/* Define a null map_sysmem() if the architecture doesn't use it */ -# ifndef CONFIG_ARCH_MAP_SYSMEM -static inline void *map_sysmem(phys_addr_t paddr, unsigned long len) -{ - return (void *)(uintptr_t)paddr; -} - -static inline void unmap_sysmem(const void *vaddr) -{ -} - -static inline phys_addr_t map_to_sysmem(const void *ptr) -{ - return (phys_addr_t)(uintptr_t)ptr; -} -# endif - #endif /* __ASSEMBLY__ */
#ifdef CONFIG_PPC diff --git a/include/mapmem.h b/include/mapmem.h new file mode 100644 index 0000000..42ef3e8 --- /dev/null +++ b/include/mapmem.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __MAPMEM_H +#define __MAPMEM_H + +/* Define a null map_sysmem() if the architecture doesn't use it */ +# ifdef CONFIG_ARCH_MAP_SYSMEM +#include <asm/io.h> +# else +static inline void *map_sysmem(phys_addr_t paddr, unsigned long len) +{ + return (void *)(uintptr_t)paddr; +} + +static inline void unmap_sysmem(const void *vaddr) +{ +} + +static inline phys_addr_t map_to_sysmem(const void *ptr) +{ + return (phys_addr_t)(uintptr_t)ptr; +} +# endif + +#endif /* __MAPMEM_H */ diff --git a/lib/trace.c b/lib/trace.c index 711e5b5..ad5e07b 100644 --- a/lib/trace.c +++ b/lib/trace.c @@ -5,6 +5,7 @@ */
#include <common.h> +#include <mapmem.h> #include <trace.h> #include <asm/io.h> #include <asm/sections.h> diff --git a/test/compression.c b/test/compression.c index ea2e4ad..7ef3a8c 100644 --- a/test/compression.c +++ b/test/compression.c @@ -10,6 +10,7 @@ #include <bootm.h> #include <command.h> #include <malloc.h> +#include <mapmem.h> #include <asm/io.h>
#include <u-boot/zlib.h> diff --git a/test/dm/cmd_dm.c b/test/dm/cmd_dm.c index 79a674e..195815e 100644 --- a/test/dm/cmd_dm.c +++ b/test/dm/cmd_dm.c @@ -10,6 +10,7 @@ #include <common.h> #include <dm.h> #include <malloc.h> +#include <mapmem.h> #include <errno.h> #include <asm/io.h> #include <dm/root.h>

The current implementation exposes the eth_device struct to code that needs to access the MAC address. Add a wrapper function for this to abstract away the pointer for this operation.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None
arch/mips/mach-au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- include/net.h | 8 ++++++++ net/net.c | 2 +- 6 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/arch/mips/mach-au1x00/au1x00_eth.c b/arch/mips/mach-au1x00/au1x00_eth.c index 39c5b6b..a47f088 100644 --- a/arch/mips/mach-au1x00/au1x00_eth.c +++ b/arch/mips/mach-au1x00/au1x00_eth.c @@ -238,7 +238,7 @@ static int au1x00_init(struct eth_device* dev, bd_t * bd){ }
/* Put mac addr in little endian */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() *mac_addr_high = (ea[5] << 8) | (ea[4] ) ; *mac_addr_low = (ea[3] << 24) | (ea[2] << 16) | (ea[1] << 8) | (ea[0] ) ; diff --git a/arch/powerpc/cpu/mpc8260/ether_fcc.c b/arch/powerpc/cpu/mpc8260/ether_fcc.c index f9f15b5..f777ba1 100644 --- a/arch/powerpc/cpu/mpc8260/ether_fcc.c +++ b/arch/powerpc/cpu/mpc8260/ether_fcc.c @@ -299,7 +299,7 @@ static int fec_init(struct eth_device* dev, bd_t *bis) * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc85xx/ether_fcc.c b/arch/powerpc/cpu/mpc85xx/ether_fcc.c index 166dc9e..58d4bfb 100644 --- a/arch/powerpc/cpu/mpc85xx/ether_fcc.c +++ b/arch/powerpc/cpu/mpc85xx/ether_fcc.c @@ -338,7 +338,7 @@ static int fec_init(struct eth_device* dev, bd_t *bis) * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc8xx/scc.c b/arch/powerpc/cpu/mpc8xx/scc.c index 251966b..66e4014 100644 --- a/arch/powerpc/cpu/mpc8xx/scc.c +++ b/arch/powerpc/cpu/mpc8xx/scc.c @@ -339,7 +339,7 @@ static int scc_init (struct eth_device *dev, bd_t * bis) pram_ptr->sen_gaddr3 = 0x0; /* Group Address Filter 3 (unused) */ pram_ptr->sen_gaddr4 = 0x0; /* Group Address Filter 4 (unused) */
-#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/include/net.h b/include/net.h index 43e3d28..6c76976 100644 --- a/include/net.h +++ b/include/net.h @@ -111,6 +111,14 @@ struct eth_device *eth_get_dev(void) { return eth_current; } + +static inline unsigned char *eth_get_ethaddr(void) +{ + if (eth_current) + return eth_current->enetaddr; + return NULL; +} + extern struct eth_device *eth_get_dev_by_name(const char *devname); extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ extern int eth_get_dev_index(void); /* get the device index */ diff --git a/net/net.c b/net/net.c index b60ce62..4b3c90e 100644 --- a/net/net.c +++ b/net/net.c @@ -275,7 +275,7 @@ static void NetInitLoop(void) env_changed_id = env_id; } if (eth_get_dev()) - memcpy(NetOurEther, eth_get_dev()->enetaddr, 6); + memcpy(NetOurEther, eth_get_ethaddr(), 6);
return; }

Make it clear that the helper is checking the addr, not setting it.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None
net/eth.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/net/eth.c b/net/eth.c index eac4f7b..65e8c77 100644 --- a/net/eth.c +++ b/net/eth.c @@ -153,11 +153,6 @@ static void eth_current_changed(void) setenv("ethact", NULL); }
-static int eth_address_set(unsigned char *addr) -{ - return memcmp(addr, "\0\0\0\0\0\0", 6); -} - int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -166,9 +161,9 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
- if (eth_address_set(env_enetaddr)) { - if (eth_address_set(dev->enetaddr) && - memcmp(dev->enetaddr, env_enetaddr, 6)) { + if (!is_zero_ether_addr(env_enetaddr)) { + if (!is_zero_ether_addr(dev->enetaddr) && + memcmp(dev->enetaddr, env_enetaddr, 6)) { printf("\nWarning: %s MAC addresses don't match:\n", dev->name); printf("Address in SROM is %pM\n", @@ -183,7 +178,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, dev->enetaddr); printf("\nWarning: %s using MAC address from net device\n", dev->name); - } else if (!(eth_address_set(dev->enetaddr))) { + } else if (is_zero_ether_addr(dev->enetaddr)) { printf("\nError: %s address not set.\n", dev->name); return -EINVAL;

Many of the functions in net.h were preceded extern needlessly. Removing them to limit the number of checkpatch.pl complaints.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: -Fix compile error on boards with CONFIG_API enabled
Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 90 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 45 insertions(+), 45 deletions(-)
diff --git a/include/net.h b/include/net.h index 6c76976..51ed5b0 100644 --- a/include/net.h +++ b/include/net.h @@ -97,11 +97,11 @@ struct eth_device { void *priv; };
-extern int eth_initialize(bd_t *bis); /* Initialize network subsystem */ -extern int eth_register(struct eth_device* dev);/* Register network device */ -extern int eth_unregister(struct eth_device *dev);/* Remove network device */ -extern void eth_try_another(int first_restart); /* Change the device */ -extern void eth_set_current(void); /* set nterface to ethcur var */ +int eth_initialize(bd_t *bis); /* Initialize network subsystem */ +int eth_register(struct eth_device *dev);/* Register network device */ +int eth_unregister(struct eth_device *dev);/* Remove network device */ +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */
/* get the current device MAC */ extern struct eth_device *eth_current; @@ -119,12 +119,12 @@ static inline unsigned char *eth_get_ethaddr(void) return NULL; }
-extern struct eth_device *eth_get_dev_by_name(const char *devname); -extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ -extern int eth_get_dev_index(void); /* get the device index */ -extern void eth_parse_enetaddr(const char *addr, uchar *enetaddr); -extern int eth_getenv_enetaddr(char *name, uchar *enetaddr); -extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr); +struct eth_device *eth_get_dev_by_name(const char *devname); +struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ +int eth_get_dev_index(void); /* get the device index */ +void eth_parse_enetaddr(const char *addr, uchar *enetaddr); +int eth_getenv_enetaddr(char *name, uchar *enetaddr); +int eth_setenv_enetaddr(char *name, const uchar *enetaddr);
/* * Get the hardware address for an ethernet interface . @@ -135,20 +135,20 @@ extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr); * Returns: * Return true if the address is valid. */ -extern int eth_getenv_enetaddr_by_index(const char *base_name, int index, - uchar *enetaddr); +int eth_getenv_enetaddr_by_index(const char *base_name, int index, + uchar *enetaddr);
-extern int usb_eth_initialize(bd_t *bi); -extern int eth_init(bd_t *bis); /* Initialize the device */ -extern int eth_send(void *packet, int length); /* Send a packet */ +int usb_eth_initialize(bd_t *bi); +int eth_init(bd_t *bis); /* Initialize the device */ +int eth_send(void *packet, int length); /* Send a packet */
#ifdef CONFIG_API -extern int eth_receive(void *packet, int length); /* Receive a packet*/ +int eth_receive(void *packet, int length); /* Receive a packet*/ extern void (*push_packet)(void *packet, int length); #endif -extern int eth_rx(void); /* Check for received packets */ -extern void eth_halt(void); /* stop SCC */ -extern char *eth_get_name(void); /* get name of current device */ +int eth_rx(void); /* Check for received packets */ +void eth_halt(void); /* stop SCC */ +char *eth_get_name(void); /* get name of current device */
/* Set active state */ static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) @@ -469,25 +469,25 @@ extern IPaddr_t Mcast_addr; #endif
/* Initialize the network adapter */ -extern void net_init(void); -extern int NetLoop(enum proto_t); +void net_init(void); +int NetLoop(enum proto_t);
/* Shutdown adapters and cleanup */ -extern void NetStop(void); +void NetStop(void);
/* Load failed. Start again. */ -extern void NetStartAgain(void); +void NetStartAgain(void);
/* Get size of the ethernet header when we send */ -extern int NetEthHdrSize(void); +int NetEthHdrSize(void);
/* Set ethernet header; returns the size of the header */ -extern int NetSetEther(uchar *, uchar *, uint); -extern int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot); +int NetSetEther(uchar *, uchar *, uint); +int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot);
/* Set IP header */ -extern void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source); -extern void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, +void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source); +void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, int sport, int len);
/** @@ -521,12 +521,12 @@ unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new_sum); int ip_checksum_ok(const void *addr, unsigned nbytes);
/* Callbacks */ -extern rxhand_f *net_get_udp_handler(void); /* Get UDP RX packet handler */ -extern void net_set_udp_handler(rxhand_f *); /* Set UDP RX packet handler */ -extern rxhand_f *net_get_arp_handler(void); /* Get ARP RX packet handler */ -extern void net_set_arp_handler(rxhand_f *); /* Set ARP RX packet handler */ -extern void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */ -extern void NetSetTimeout(ulong, thand_f *);/* Set timeout handler */ +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 */ +void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */ +void NetSetTimeout(ulong, thand_f *);/* Set timeout handler */
/* Network loop state */ enum net_loop_state { @@ -559,11 +559,11 @@ static inline void NetSendPacket(uchar *pkt, int len) * @param sport Source UDP port * @param payload_len Length of data after the UDP header */ -extern int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, +int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int payload_len);
/* Processes a received packet */ -extern void NetReceive(uchar *, int); +void NetReceive(uchar *, int);
#ifdef CONFIG_NETCONSOLE void NcStart(void); @@ -711,28 +711,28 @@ static inline void eth_random_addr(uchar *addr) }
/* Convert an IP address to a string */ -extern void ip_to_string(IPaddr_t x, char *s); +void ip_to_string(IPaddr_t x, char *s);
/* Convert a string to ip address */ -extern IPaddr_t string_to_ip(const char *s); +IPaddr_t string_to_ip(const char *s);
/* Convert a VLAN id to a string */ -extern void VLAN_to_string(ushort x, char *s); +void VLAN_to_string(ushort x, char *s);
/* Convert a string to a vlan id */ -extern ushort string_to_VLAN(const char *s); +ushort string_to_VLAN(const char *s);
/* read a VLAN id from an environment variable */ -extern ushort getenv_VLAN(char *); +ushort getenv_VLAN(char *);
/* copy a filename (allow for "..." notation, limit length) */ -extern void copy_filename(char *dst, const char *src, int size); +void copy_filename(char *dst, const char *src, int size);
/* get a random source port */ -extern unsigned int random_port(void); +unsigned int random_port(void);
/* Update U-Boot over TFTP */ -extern int update_tftp(ulong addr); +int update_tftp(ulong addr);
/**********************************************************************/

Move some things around and organize things so that the driver model implementation will fit in more easily.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: -Fixed warning from missing declaration
Changes in v4: -Fix compile regression in !DM_ETH case
Changes in v3: -Move the get_dev_by_* protos to also be !DM_ETH like the impl
Changes in v2: None
include/net.h | 68 +++++++++++++++++++++++++------------------------- net/eth.c | 79 ++++++++++++++++++++++++++++++++--------------------------- 2 files changed, 78 insertions(+), 69 deletions(-)
diff --git a/include/net.h b/include/net.h index 51ed5b0..fdf6860 100644 --- a/include/net.h +++ b/include/net.h @@ -97,13 +97,9 @@ struct eth_device { void *priv; };
-int eth_initialize(bd_t *bis); /* Initialize network subsystem */ int eth_register(struct eth_device *dev);/* Register network device */ int eth_unregister(struct eth_device *dev);/* Remove network device */ -void eth_try_another(int first_restart); /* Change the device */ -void eth_set_current(void); /* set nterface to ethcur var */
-/* get the current device MAC */ extern struct eth_device *eth_current;
static inline __attribute__((always_inline)) @@ -111,7 +107,10 @@ struct eth_device *eth_get_dev(void) { return eth_current; } +struct eth_device *eth_get_dev_by_name(const char *devname); +struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */
+/* get the current device MAC */ static inline unsigned char *eth_get_ethaddr(void) { if (eth_current) @@ -119,8 +118,37 @@ static inline unsigned char *eth_get_ethaddr(void) return NULL; }
-struct eth_device *eth_get_dev_by_name(const char *devname); -struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ +/* Set active state */ +static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) +{ + eth_get_dev()->state = ETH_STATE_ACTIVE; + + return 0; +} +/* Set passive state */ +static inline __attribute__((always_inline)) void eth_halt_state_only(void) +{ + eth_get_dev()->state = ETH_STATE_PASSIVE; +} + +/* + * Set the hardware address for an ethernet interface based on 'eth%daddr' + * environment variable (or just 'ethaddr' if eth_number is 0). + * Args: + * base_name - base name for device (normally "eth") + * eth_number - value of %d (0 for first device of this type) + * Returns: + * 0 is success, non-zero is error status from driver. + */ +int eth_write_hwaddr(struct eth_device *dev, const char *base_name, + int eth_number); + +int usb_eth_initialize(bd_t *bi); + +int eth_initialize(bd_t *bis); /* Initialize network subsystem */ +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */ + int eth_get_dev_index(void); /* get the device index */ void eth_parse_enetaddr(const char *addr, uchar *enetaddr); int eth_getenv_enetaddr(char *name, uchar *enetaddr); @@ -138,7 +166,6 @@ int eth_setenv_enetaddr(char *name, const uchar *enetaddr); int eth_getenv_enetaddr_by_index(const char *base_name, int index, uchar *enetaddr);
-int usb_eth_initialize(bd_t *bi); int eth_init(bd_t *bis); /* Initialize the device */ int eth_send(void *packet, int length); /* Send a packet */
@@ -148,32 +175,7 @@ extern void (*push_packet)(void *packet, int length); #endif int eth_rx(void); /* Check for received packets */ void eth_halt(void); /* stop SCC */ -char *eth_get_name(void); /* get name of current device */ - -/* Set active state */ -static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) -{ - eth_get_dev()->state = ETH_STATE_ACTIVE; - - return 0; -} -/* Set passive state */ -static inline __attribute__((always_inline)) void eth_halt_state_only(void) -{ - eth_get_dev()->state = ETH_STATE_PASSIVE; -} - -/* - * Set the hardware address for an ethernet interface based on 'eth%daddr' - * environment variable (or just 'ethaddr' if eth_number is 0). - * Args: - * base_name - base name for device (normally "eth") - * eth_number - value of %d (0 for first device of this type) - * Returns: - * 0 is success, non-zero is error status from driver. - */ -int eth_write_hwaddr(struct eth_device *dev, const char *base_name, - int eth_number); +const char *eth_get_name(void); /* get name of current device */
#ifdef CONFIG_MCAST_TFTP int eth_mcast_join(IPaddr_t mcast_addr, u8 join); diff --git a/net/eth.c b/net/eth.c index 65e8c77..84919e0 100644 --- a/net/eth.c +++ b/net/eth.c @@ -55,6 +55,14 @@ static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index, return eth_setenv_enetaddr(enetvar, enetaddr); }
+static void eth_env_init(void) +{ + const char *s; + + s = getenv("bootfile"); + if (s != NULL) + copy_filename(BootFile, s, sizeof(BootFile)); +}
static int eth_mac_skip(int index) { @@ -64,6 +72,8 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void); + /* * CPU and board-specific Ethernet initializations. Aliased function * signals caller to move on @@ -87,6 +97,11 @@ static unsigned int eth_rcv_current, eth_rcv_last; static struct eth_device *eth_devices; struct eth_device *eth_current;
+static void eth_set_current_to_next(void) +{ + eth_current = eth_current->next; +} + struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -137,22 +152,6 @@ int eth_get_dev_index(void) return eth_current->index; }
-static void eth_current_changed(void) -{ - char *act = getenv("ethact"); - /* update current ethernet name */ - if (eth_current) { - if (act == NULL || strcmp(act, eth_current->name) != 0) - setenv("ethact", eth_current->name); - } - /* - * remove the variable completely if there is no active - * interface - */ - else if (act != NULL) - setenv("ethact", NULL); -} - int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -251,14 +250,6 @@ int eth_unregister(struct eth_device *dev) return 0; }
-static void eth_env_init(bd_t *bis) -{ - const char *s; - - if ((s = getenv("bootfile")) != NULL) - copy_filename(BootFile, s, sizeof(BootFile)); -} - int eth_initialize(bd_t *bis) { int num_devices = 0; @@ -274,7 +265,7 @@ int eth_initialize(bd_t *bis) phy_init(); #endif
- eth_env_init(bis); + eth_env_init();
/* * If board-specific initialization exists, call it. @@ -479,6 +470,22 @@ int eth_receive(void *packet, int length) } #endif /* CONFIG_API */
+static void eth_current_changed(void) +{ + char *act = getenv("ethact"); + /* update current ethernet name */ + if (eth_get_dev()) { + if (act == NULL || strcmp(act, eth_get_name()) != 0) + setenv("ethact", eth_get_name()); + } + /* + * remove the variable completely if there is no active + * interface + */ + else if (act != NULL) + setenv("ethact", NULL); +} + void eth_try_another(int first_restart) { static struct eth_device *first_failed; @@ -492,17 +499,17 @@ void eth_try_another(int first_restart) if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) return;
- if (!eth_current) + if (!eth_get_dev()) return;
if (first_restart) - first_failed = eth_current; + first_failed = eth_get_dev();
- eth_current = eth_current->next; + eth_set_current_to_next();
eth_current_changed();
- if (first_failed == eth_current) + if (first_failed == eth_get_dev()) NetRestartWrap = 1; }
@@ -513,7 +520,7 @@ void eth_set_current(void) struct eth_device *old_current; int env_id;
- if (!eth_current) /* XXX no current */ + if (!eth_get_dev()) /* XXX no current */ return;
env_id = get_env_id(); @@ -522,18 +529,18 @@ void eth_set_current(void) env_changed_id = env_id; } if (act != NULL) { - old_current = eth_current; + old_current = eth_get_dev(); do { - if (strcmp(eth_current->name, act) == 0) + if (strcmp(eth_get_name(), act) == 0) return; - eth_current = eth_current->next; - } while (old_current != eth_current); + eth_set_current_to_next(); + } while (old_current != eth_get_dev()); }
eth_current_changed(); }
-char *eth_get_name(void) +const char *eth_get_name(void) { - return eth_current ? eth_current->name : "unknown"; + return eth_get_dev() ? eth_get_dev()->name : "unknown"; }

Many functions returned -1 previously. Change them to return appropriate error codes.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: None Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
net/eth.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/net/eth.c b/net/eth.c index 84919e0..9ad15cd 100644 --- a/net/eth.c +++ b/net/eth.c @@ -227,7 +227,7 @@ int eth_unregister(struct eth_device *dev)
/* No device */ if (!eth_devices) - return -1; + return -ENODEV;
for (cur = eth_devices; cur->next != eth_devices && cur->next != dev; cur = cur->next) @@ -235,7 +235,7 @@ int eth_unregister(struct eth_device *dev)
/* Device not found */ if (cur->next != dev) - return -1; + return -ENODEV;
cur->next = dev->next;
@@ -368,7 +368,7 @@ int eth_init(bd_t *bis)
if (!eth_current) { puts("No ethernet found.\n"); - return -1; + return -ENODEV; }
/* Sync environment with network devices */ @@ -397,7 +397,7 @@ int eth_init(bd_t *bis) eth_try_another(0); } while (old_current != eth_current);
- return -1; + return -ETIMEDOUT; }
void eth_halt(void) @@ -413,7 +413,7 @@ void eth_halt(void) int eth_send(void *packet, int length) { if (!eth_current) - return -1; + return -ENODEV;
return eth_current->send(eth_current, packet, length); } @@ -421,7 +421,7 @@ int eth_send(void *packet, int length) int eth_rx(void) { if (!eth_current) - return -1; + return -ENODEV;
return eth_current->recv(eth_current); }

On some archs masking the parameter is inefficient, so don't use u8.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: None Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
include/net.h | 2 +- net/eth.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/net.h b/include/net.h index fdf6860..cec5612 100644 --- a/include/net.h +++ b/include/net.h @@ -178,7 +178,7 @@ void eth_halt(void); /* stop SCC */ const char *eth_get_name(void); /* get name of current device */
#ifdef CONFIG_MCAST_TFTP -int eth_mcast_join(IPaddr_t mcast_addr, u8 join); +int eth_mcast_join(IPaddr_t mcast_addr, int join); u32 ether_crc(size_t len, unsigned char const *p); #endif
diff --git a/net/eth.c b/net/eth.c index 9ad15cd..b86994e 100644 --- a/net/eth.c +++ b/net/eth.c @@ -321,7 +321,7 @@ int eth_initialize(bd_t *bis) * mcast_addr: multicast ipaddr from which multicast Mac is made * join: 1=join, 0=leave. */ -int eth_mcast_join(IPaddr_t mcast_ip, u8 join) +int eth_mcast_join(IPaddr_t mcast_ip, int join) { u8 mcast_mac[6]; if (!eth_current || !eth_current->mcast)

This value is not used by the network stack and is available in the global data, so stop passing it around. For the one legacy function that still expects it (init op on old Ethernet drivers) pass in the global pointer version directly to avoid changing that interface.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: -Fix compile errors for other boards due to removed parameters
Changes in v5: None Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
api/api_net.c | 2 +- arch/arm/lib/board.c | 2 +- arch/avr32/lib/board.c | 2 +- arch/m68k/lib/board.c | 4 ++-- arch/nds32/lib/board.c | 2 +- arch/openrisc/lib/board.c | 2 +- arch/powerpc/lib/board.c | 2 +- arch/sh/lib/board.c | 2 +- arch/sparc/lib/board.c | 2 +- board/BuS/eb_cpux9k2/cpux9k2.c | 2 +- board/BuS/vl_ma2sc/vl_ma2sc.c | 2 +- board/atmel/at91sam9261ek/at91sam9261ek.c | 2 +- board/egnite/ethernut5/ethernut5.c | 2 +- board/ronetix/pm9261/pm9261.c | 2 +- board/ronetix/pm9g45/pm9g45.c | 2 +- common/board_r.c | 2 +- common/spl/spl_net.c | 2 +- drivers/net/netconsole.c | 4 ++-- include/net.h | 6 +++--- net/eth.c | 12 +++++++----- net/net.c | 7 +++---- 21 files changed, 33 insertions(+), 32 deletions(-)
diff --git a/api/api_net.c b/api/api_net.c index 7b3805e..04e4f4a 100644 --- a/api/api_net.c +++ b/api/api_net.c @@ -37,7 +37,7 @@ int dev_open_net(void *cookie) if (!dev_valid_net(cookie)) return API_ENODEV;
- if (eth_init(gd->bd) < 0) + if (eth_init() < 0) return API_EIO;
return 0; diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index f606255..37ea6e9 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -644,7 +644,7 @@ void board_init_r(gd_t *id, ulong dest_addr) #endif #if defined(CONFIG_CMD_NET) puts("Net: "); - eth_initialize(gd->bd); + eth_initialize(); #if defined(CONFIG_RESET_PHY_R) debug("Reset Ethernet PHY\n"); reset_phy(); diff --git a/arch/avr32/lib/board.c b/arch/avr32/lib/board.c index 99aa96e..aacfcbf 100644 --- a/arch/avr32/lib/board.c +++ b/arch/avr32/lib/board.c @@ -244,7 +244,7 @@ void board_init_r(gd_t *new_gd, ulong dest_addr) #endif #if defined(CONFIG_CMD_NET) puts("Net: "); - eth_initialize(gd->bd); + eth_initialize(); #endif
#ifdef CONFIG_GENERIC_ATMEL_MCI diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c index 9caff73..c54a3f7 100644 --- a/arch/m68k/lib/board.c +++ b/arch/m68k/lib/board.c @@ -566,10 +566,10 @@ void board_init_r (gd_t *id, ulong dest_addr) #if defined(CONFIG_CMD_NET) WATCHDOG_RESET(); #if defined(FEC_ENET) - eth_init(bd); + eth_init(); #endif puts ("Net: "); - eth_initialize (bd); + eth_initialize(); #endif
#ifdef CONFIG_POST diff --git a/arch/nds32/lib/board.c b/arch/nds32/lib/board.c index 4c06a48..24a09bc 100644 --- a/arch/nds32/lib/board.c +++ b/arch/nds32/lib/board.c @@ -383,7 +383,7 @@ void board_init_r(gd_t *id, ulong dest_addr) #if defined(CONFIG_CMD_NET) puts("Net: ");
- eth_initialize(gd->bd); + eth_initialize(); #if defined(CONFIG_RESET_PHY_R) debug("Reset Ethernet PHY\n"); reset_phy(); diff --git a/arch/openrisc/lib/board.c b/arch/openrisc/lib/board.c index 2346685..c26cc8f 100644 --- a/arch/openrisc/lib/board.c +++ b/arch/openrisc/lib/board.c @@ -128,7 +128,7 @@ void board_init(void)
#if defined(CONFIG_CMD_NET) puts("NET: "); - eth_initialize(bd); + eth_initialize(); #endif
/* main_loop */ diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c index 91645d3..5ea29cc 100644 --- a/arch/powerpc/lib/board.c +++ b/arch/powerpc/lib/board.c @@ -890,7 +890,7 @@ void board_init_r(gd_t *id, ulong dest_addr) #if defined(CONFIG_CMD_NET) WATCHDOG_RESET(); puts("Net: "); - eth_initialize(bd); + eth_initialize(); #endif
#if defined(CONFIG_CMD_NET) && defined(CONFIG_RESET_PHY_R) diff --git a/arch/sh/lib/board.c b/arch/sh/lib/board.c index 1eb7afb..6dad3c7 100644 --- a/arch/sh/lib/board.c +++ b/arch/sh/lib/board.c @@ -178,7 +178,7 @@ void sh_generic_init(void) #endif #if defined(CONFIG_CMD_NET) puts("Net: "); - eth_initialize(gd->bd); + eth_initialize(); #endif /* CONFIG_CMD_NET */
while (1) { diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c index b311a94..d2ac6bc 100644 --- a/arch/sparc/lib/board.c +++ b/arch/sparc/lib/board.c @@ -351,7 +351,7 @@ void board_init_f(ulong bootflag) #if defined(CONFIG_CMD_NET) WATCHDOG_RESET(); puts("Net: "); - eth_initialize(bd); + eth_initialize(); #endif
#if defined(CONFIG_CMD_NET) && defined(CONFIG_RESET_PHY_R) diff --git a/board/BuS/eb_cpux9k2/cpux9k2.c b/board/BuS/eb_cpux9k2/cpux9k2.c index 76ad7c4..3880a06 100644 --- a/board/BuS/eb_cpux9k2/cpux9k2.c +++ b/board/BuS/eb_cpux9k2/cpux9k2.c @@ -111,7 +111,7 @@ int misc_init_r(void) void reset_phy(void) { udelay(10000); - eth_init(gd->bd); + eth_init(); } #endif
diff --git a/board/BuS/vl_ma2sc/vl_ma2sc.c b/board/BuS/vl_ma2sc/vl_ma2sc.c index da39c86..e4e1a85 100644 --- a/board/BuS/vl_ma2sc/vl_ma2sc.c +++ b/board/BuS/vl_ma2sc/vl_ma2sc.c @@ -280,7 +280,7 @@ void reset_phy(void) * Initialize ethernet HW addr prior to starting Linux, * needed for nfsroot */ - eth_init(gd->bd); + eth_init(); #endif } #endif diff --git a/board/atmel/at91sam9261ek/at91sam9261ek.c b/board/atmel/at91sam9261ek/at91sam9261ek.c index a301d72..5250474 100644 --- a/board/atmel/at91sam9261ek/at91sam9261ek.c +++ b/board/atmel/at91sam9261ek/at91sam9261ek.c @@ -275,7 +275,7 @@ void reset_phy(void) * Initialize ethernet HW addr prior to starting Linux, * needed for nfsroot */ - eth_init(gd->bd); + eth_init(); #endif } #endif diff --git a/board/egnite/ethernut5/ethernut5.c b/board/egnite/ethernut5/ethernut5.c index b45213c..67d3984 100644 --- a/board/egnite/ethernut5/ethernut5.c +++ b/board/egnite/ethernut5/ethernut5.c @@ -204,7 +204,7 @@ int board_eth_init(bd_t *bis) miiphy_write(devname, 0, MII_BMCR, BMCR_RESET); } /* Sync environment with network devices, needed for nfsroot. */ - return eth_init(gd->bd); + return eth_init(); } #endif
diff --git a/board/ronetix/pm9261/pm9261.c b/board/ronetix/pm9261/pm9261.c index 1f7679a..b96f745 100644 --- a/board/ronetix/pm9261/pm9261.c +++ b/board/ronetix/pm9261/pm9261.c @@ -288,7 +288,7 @@ void reset_phy(void) * Initialize ethernet HW addr prior to starting Linux, * needed for nfsroot */ - eth_init(gd->bd); + eth_init(); #endif } #endif diff --git a/board/ronetix/pm9g45/pm9g45.c b/board/ronetix/pm9g45/pm9g45.c index 15aa4ac..efc4133 100644 --- a/board/ronetix/pm9g45/pm9g45.c +++ b/board/ronetix/pm9g45/pm9g45.c @@ -166,7 +166,7 @@ void reset_phy(void) * Initialize ethernet HW addr prior to starting Linux, * needed for nfsroot */ - eth_init(gd->bd); + eth_init(); #endif } #endif diff --git a/common/board_r.c b/common/board_r.c index af0f274..b882d9b 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -585,7 +585,7 @@ static int initr_bbmii(void) static int initr_net(void) { puts("Net: "); - eth_initialize(gd->bd); + eth_initialize(); #if defined(CONFIG_RESET_PHY_R) debug("Reset Ethernet PHY\n"); reset_phy(); diff --git a/common/spl/spl_net.c b/common/spl/spl_net.c index ff53705..af4952f 100644 --- a/common/spl/spl_net.c +++ b/common/spl/spl_net.c @@ -21,7 +21,7 @@ void spl_net_load_image(const char *device) env_relocate(); setenv("autoload", "yes"); load_addr = CONFIG_SYS_TEXT_BASE - sizeof(struct image_header); - rv = eth_initialize(gd->bd); + rv = eth_initialize(); if (rv == 0) { printf("No Ethernet devices found\n"); hang(); diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 677c89f..87cea7a 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -193,11 +193,11 @@ static void nc_send_packet(const char *buf, int len)
if (eth->state != ETH_STATE_ACTIVE) { if (eth_is_on_demand_init()) { - if (eth_init(gd->bd) < 0) + if (eth_init() < 0) return; eth_set_last_protocol(NETCONS); } else - eth_init_state_only(gd->bd); + eth_init_state_only();
inited = 1; } diff --git a/include/net.h b/include/net.h index cec5612..ae0f31a 100644 --- a/include/net.h +++ b/include/net.h @@ -119,7 +119,7 @@ static inline unsigned char *eth_get_ethaddr(void) }
/* Set active state */ -static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) +static inline __attribute__((always_inline)) int eth_init_state_only(void) { eth_get_dev()->state = ETH_STATE_ACTIVE;
@@ -145,7 +145,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
int usb_eth_initialize(bd_t *bi);
-int eth_initialize(bd_t *bis); /* Initialize network subsystem */ +int eth_initialize(void); /* Initialize network subsystem */ void eth_try_another(int first_restart); /* Change the device */ void eth_set_current(void); /* set nterface to ethcur var */
@@ -166,7 +166,7 @@ int eth_setenv_enetaddr(char *name, const uchar *enetaddr); int eth_getenv_enetaddr_by_index(const char *base_name, int index, uchar *enetaddr);
-int eth_init(bd_t *bis); /* Initialize the device */ +int eth_init(void); /* Initialize the device */ int eth_send(void *packet, int length); /* Send a packet */
#ifdef CONFIG_API diff --git a/net/eth.c b/net/eth.c index b86994e..66ecb79 100644 --- a/net/eth.c +++ b/net/eth.c @@ -12,6 +12,8 @@ #include <phy.h> #include <asm/errno.h>
+DECLARE_GLOBAL_DATA_PTR; + void eth_parse_enetaddr(const char *addr, uchar *enetaddr) { char *end; @@ -250,7 +252,7 @@ int eth_unregister(struct eth_device *dev) return 0; }
-int eth_initialize(bd_t *bis) +int eth_initialize(void) { int num_devices = 0; eth_devices = NULL; @@ -272,10 +274,10 @@ int eth_initialize(bd_t *bis) * If not, call a CPU-specific one */ if (board_eth_init != __def_eth_init) { - if (board_eth_init(bis) < 0) + if (board_eth_init(gd->bd) < 0) printf("Board Net Initialization Failed\n"); } else if (cpu_eth_init != __def_eth_init) { - if (cpu_eth_init(bis) < 0) + if (cpu_eth_init(gd->bd) < 0) printf("CPU Net Initialization Failed\n"); } else printf("Net Initialization Skipped\n"); @@ -362,7 +364,7 @@ u32 ether_crc(size_t len, unsigned char const *p) #endif
-int eth_init(bd_t *bis) +int eth_init(void) { struct eth_device *old_current, *dev;
@@ -387,7 +389,7 @@ int eth_init(bd_t *bis) do { debug("Trying %s\n", eth_current->name);
- if (eth_current->init(eth_current, bis) >= 0) { + if (eth_current->init(eth_current, gd->bd) >= 0) { eth_current->state = ETH_STATE_ACTIVE;
return 0; diff --git a/net/net.c b/net/net.c index 4b3c90e..e5ab07c 100644 --- a/net/net.c +++ b/net/net.c @@ -324,7 +324,6 @@ void net_init(void)
int NetLoop(enum proto_t protocol) { - bd_t *bd = gd->bd; int ret = -1;
NetRestarted = 0; @@ -337,12 +336,12 @@ int NetLoop(enum proto_t protocol) if (eth_is_on_demand_init() || protocol != NETCONS) { eth_halt(); eth_set_current(); - if (eth_init(bd) < 0) { + if (eth_init() < 0) { eth_halt(); return -1; } } else - eth_init_state_only(bd); + eth_init_state_only();
restart: #ifdef CONFIG_USB_KEYBOARD @@ -618,7 +617,7 @@ void NetStartAgain(void) #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER) eth_try_another(!NetRestarted); #endif - eth_init(gd->bd); + eth_init(); if (NetRestartWrap) { NetRestartWrap = 0; if (NetDevExists) {

Hi Joe,
On 11 March 2015 at 17:44, Joe Hershberger joe.hershberger@ni.com wrote:
This value is not used by the network stack and is available in the global data, so stop passing it around. For the one legacy function that still expects it (init op on old Ethernet drivers) pass in the global pointer version directly to avoid changing that interface.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
Changes in v6: -Fix compile errors for other boards due to removed parameters
Unfortunately this causes several build failures:
38: net: Remove the bd* parameter from net stack functions powerpc: + PLU405 PMC440 sc3 neo acadia csb472 devconcenter sequoia arches lwmon5 t3corp walnut PMC405DE redwood katmai gdppc440etx p3p440 sycamore MIP405 zeus rainier_ramboot canyonlands MIP405T haleakala dlvision csb272 xpedite1000 io yosemite yucca makalu sequoia_ramboot dlvision-10g pcs440ep CPCI4052 sbc405 iocon ebony glacier_ramboot VOM405 bamboo luan io64 PIP405 intip glacier lcd4_lwmon5 bubinga yellowstone icon kilauea rainier
e.g:
$ buildman -b dm-push -s PLU405 -e ... 38: net: Remove the bd* parameter from net stack functions powerpc: + PLU405 +../drivers/net/4xx_enet.c: In function 'mal_err': +../drivers/net/4xx_enet.c:1734:2: error: too many arguments to function 'eth_init' +../include/net.h:169:5: note: declared here +make[2]: *** [drivers/net/4xx_enet.o] Error 1 +make[1]: *** [drivers/net] Error 2 +make: *** [sub-make] Error 2 ...
Can you please check this and respin?
Regards, Simon

Hi Simon,
On Fri, Mar 20, 2015 at 6:01 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 11 March 2015 at 17:44, Joe Hershberger joe.hershberger@ni.com wrote:
This value is not used by the network stack and is available in the global data, so stop passing it around. For the one legacy function that still expects it (init op on old Ethernet drivers) pass in the global pointer version directly to avoid changing that interface.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
Changes in v6: -Fix compile errors for other boards due to removed parameters
Unfortunately this causes several build failures:
38: net: Remove the bd* parameter from net stack functions powerpc: + PLU405 PMC440 sc3 neo acadia csb472 devconcenter sequoia arches lwmon5 t3corp walnut PMC405DE redwood katmai gdppc440etx p3p440 sycamore MIP405 zeus rainier_ramboot canyonlands MIP405T haleakala dlvision csb272 xpedite1000 io yosemite yucca makalu sequoia_ramboot dlvision-10g pcs440ep CPCI4052 sbc405 iocon ebony glacier_ramboot VOM405 bamboo luan io64 PIP405 intip glacier lcd4_lwmon5 bubinga yellowstone icon kilauea rainier
e.g:
$ buildman -b dm-push -s PLU405 -e ... 38: net: Remove the bd* parameter from net stack functions powerpc: + PLU405 +../drivers/net/4xx_enet.c: In function 'mal_err': +../drivers/net/4xx_enet.c:1734:2: error: too many arguments to function 'eth_init' +../include/net.h:169:5: note: declared here +make[2]: *** [drivers/net/4xx_enet.o] Error 1 +make[1]: *** [drivers/net] Error 2 +make: *** [sub-make] Error 2 ...
Can you please check this and respin?
Sorry about that. Are you aware of anything other than the 4xx_enet.c error? I grepped around and didn't find anything else, but I also missed this one previously using the same method.
Thanks, -Joe

Hi Joe,
On 21 March 2015 at 21:42, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Fri, Mar 20, 2015 at 6:01 PM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 11 March 2015 at 17:44, Joe Hershberger joe.hershberger@ni.com wrote:
This value is not used by the network stack and is available in the global data, so stop passing it around. For the one legacy function that still expects it (init op on old Ethernet drivers) pass in the global pointer version directly to avoid changing that interface.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
Changes in v6: -Fix compile errors for other boards due to removed parameters
Unfortunately this causes several build failures:
38: net: Remove the bd* parameter from net stack functions powerpc: + PLU405 PMC440 sc3 neo acadia csb472 devconcenter sequoia arches lwmon5 t3corp walnut PMC405DE redwood katmai gdppc440etx p3p440 sycamore MIP405 zeus rainier_ramboot canyonlands MIP405T haleakala dlvision csb272 xpedite1000 io yosemite yucca makalu sequoia_ramboot dlvision-10g pcs440ep CPCI4052 sbc405 iocon ebony glacier_ramboot VOM405 bamboo luan io64 PIP405 intip glacier lcd4_lwmon5 bubinga yellowstone icon kilauea rainier
e.g:
$ buildman -b dm-push -s PLU405 -e ... 38: net: Remove the bd* parameter from net stack functions powerpc: + PLU405 +../drivers/net/4xx_enet.c: In function 'mal_err': +../drivers/net/4xx_enet.c:1734:2: error: too many arguments to function 'eth_init' +../include/net.h:169:5: note: declared here +make[2]: *** [drivers/net/4xx_enet.o] Error 1 +make[1]: *** [drivers/net] Error 2 +make: *** [sub-make] Error 2 ...
Can you please check this and respin?
Sorry about that. Are you aware of anything other than the 4xx_enet.c error? I grepped around and didn't find anything else, but I also missed this one previously using the same method.
Unfortunately I don't have that build anymore. Given the board names it seems likely.
Regards, Simon

netretry previously would only retry in one specific case (your MAC address is not set) and no other. This is basically useless. In the DM implementation for eth it turns this into a completely useless case since an un-configured MAC address results in not even entering the NetLoop. The behavior is now changed to retry any failed command (rotating through the eth adapters if ethrotate != no).
It also defaulted to retry forever. It is now changed to default to not retry
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: None Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
net/net.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/net/net.c b/net/net.c index e5ab07c..37b4aab 100644 --- a/net/net.c +++ b/net/net.c @@ -527,6 +527,8 @@ restart: (*x)(); }
+ if (net_state == NETLOOP_FAIL) + NetStartAgain();
switch (net_state) {
@@ -602,8 +604,10 @@ void NetStartAgain(void) retrycnt = 1; else retrycnt = simple_strtoul(nretry, NULL, 0); - } else - retry_forever = 1; + } else { + retrycnt = 0; + retry_forever = 0; + }
if ((!retry_forever) && (NetTryCount >= retrycnt)) { eth_halt();

Previously the net functions would access memory assuming physmem did not need to be mapped. In sandbox, that's not the case.
Now we map the physmem specified by the user in loadaddr to the buffer that represents that space.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: -Include new mapmem.h header -Unmap memory for consistency
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
net/nfs.c | 6 +++++- net/tftp.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/net/nfs.c b/net/nfs.c index 381b75f..8e05ae5 100644 --- a/net/nfs.c +++ b/net/nfs.c @@ -26,6 +26,7 @@ #include <command.h> #include <net.h> #include <malloc.h> +#include <mapmem.h> #include "nfs.h" #include "bootp.h"
@@ -93,7 +94,10 @@ store_block(uchar *src, unsigned offset, unsigned len) } else #endif /* CONFIG_SYS_DIRECT_FLASH_NFS */ { - (void)memcpy((void *)(load_addr + offset), src, len); + void *ptr = map_sysmem(load_addr + offset, len); + + memcpy(ptr, src, len); + unmap_sysmem(ptr); }
if (NetBootFileXferSize < (offset+len)) diff --git a/net/tftp.c b/net/tftp.c index 0a2c533..51c67be 100644 --- a/net/tftp.c +++ b/net/tftp.c @@ -8,6 +8,7 @@
#include <common.h> #include <command.h> +#include <mapmem.h> #include <net.h> #include "tftp.h" #include "bootp.h" @@ -184,7 +185,10 @@ store_block(int block, uchar *src, unsigned len) } else #endif /* CONFIG_SYS_DIRECT_FLASH_TFTP */ { - (void)memcpy((void *)(load_addr + offset), src, len); + void *ptr = map_sysmem(load_addr + offset, len); + + memcpy(ptr, src, len); + unmap_sysmem(ptr); } #ifdef CONFIG_MCAST_TFTP if (Multicast)

The return codes in common/cmd_net.c had a number of inconsistencies. Update them to all use the enum from command.h
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
common/cmd_net.c | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-)
diff --git a/common/cmd_net.c b/common/cmd_net.c index 09489d4..3f52edc 100644 --- a/common/cmd_net.c +++ b/common/cmd_net.c @@ -44,10 +44,7 @@ U_BOOT_CMD( #ifdef CONFIG_CMD_TFTPPUT int do_tftpput(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - int ret; - - ret = netboot_common(TFTPPUT, cmdtp, argc, argv); - return ret; + return netboot_common(TFTPPUT, cmdtp, argc, argv); }
U_BOOT_CMD( @@ -217,7 +214,7 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc, if (strict_strtoul(argv[1], 16, &save_addr) < 0 || strict_strtoul(argv[2], 16, &save_size) < 0) { printf("Invalid address/size\n"); - return cmd_usage(cmdtp); + return CMD_RET_USAGE; } copy_filename(BootFile, argv[3], sizeof(BootFile)); break; @@ -230,7 +227,7 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,
if ((size = NetLoop(proto)) < 0) { bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); - return 1; + return CMD_RET_FAILURE; } bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);
@@ -240,7 +237,7 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc, /* done if no file was loaded (no errors though) */ if (size == 0) { bootstage_error(BOOTSTAGE_ID_NET_LOADED); - return 0; + return CMD_RET_SUCCESS; }
/* flush cache */ @@ -250,10 +247,10 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,
rcode = bootm_maybe_autostart(cmdtp, argv[0]);
- if (rcode < 0) - bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR); - else + if (rcode == CMD_RET_SUCCESS) bootstage_mark(BOOTSTAGE_ID_NET_DONE); + else + bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR); return rcode; }
@@ -261,7 +258,7 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc, static int do_ping(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { if (argc < 2) - return -1; + return CMD_RET_USAGE;
NetPingIP = string_to_ip(argv[1]); if (NetPingIP == 0) @@ -269,12 +266,12 @@ static int do_ping(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
if (NetLoop(PING) < 0) { printf("ping failed; host %s is not alive\n", argv[1]); - return 1; + return CMD_RET_FAILURE; }
printf("host %s is alive\n", argv[1]);
- return 0; + return CMD_RET_SUCCESS; }
U_BOOT_CMD( @@ -313,12 +310,12 @@ int do_cdp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) r = NetLoop(CDP); if (r < 0) { printf("cdp failed; perhaps not a CISCO switch?\n"); - return 1; + return CMD_RET_FAILURE; }
cdp_update_env();
- return 0; + return CMD_RET_SUCCESS; }
U_BOOT_CMD( @@ -337,13 +334,13 @@ int do_sntp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) NetNtpServerIP = getenv_IPaddr("ntpserverip"); if (NetNtpServerIP == 0) { printf("ntpserverip not set\n"); - return (1); + return CMD_RET_FAILURE; } } else { NetNtpServerIP = string_to_ip(argv[1]); if (NetNtpServerIP == 0) { printf("Bad NTP server IP address\n"); - return (1); + return CMD_RET_FAILURE; } }
@@ -356,10 +353,10 @@ int do_sntp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (NetLoop(SNTP) < 0) { printf("SNTP failed: host %pI4 not responding\n", &NetNtpServerIP); - return 1; + return CMD_RET_FAILURE; }
- return 0; + return CMD_RET_SUCCESS; }
U_BOOT_CMD( @@ -389,7 +386,7 @@ int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) */ if (strlen(argv[1]) >= 255) { printf("dns error: hostname too long\n"); - return 1; + return CMD_RET_FAILURE; }
NetDNSResolve = argv[1]; @@ -401,10 +398,10 @@ int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
if (NetLoop(DNS) < 0) { printf("dns lookup of %s failed, check setup\n", argv[1]); - return 1; + return CMD_RET_FAILURE; }
- return 0; + return CMD_RET_SUCCESS; }
U_BOOT_CMD( @@ -422,7 +419,7 @@ static int do_link_local(cmd_tbl_t *cmdtp, int flag, int argc, char tmp[22];
if (NetLoop(LINKLOCAL) < 0) - return 1; + return CMD_RET_FAILURE;
NetOurGatewayIP = 0; ip_to_string(NetOurGatewayIP, tmp); @@ -435,7 +432,7 @@ static int do_link_local(cmd_tbl_t *cmdtp, int flag, int argc, setenv("ipaddr", tmp); setenv("llipaddr", tmp); /* store this for next time */
- return 0; + return CMD_RET_SUCCESS; }
U_BOOT_CMD(

First just add support for MAC drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: -Add a note to doc/README.drivers.eth about its obsolescence -Expanded the Kconfig help -Moved dm/ header -Use local var for priv in eth_get_dev()
Changes in v4: --Don't prevent eth_initialize on driver model --If current == NULL, always check if there is a device available in eth_get_dev --Include ethprime handling in eth_initialize --Look up MAC address in post-probe --Move env init call from uclass init to eth_initialize --Print the alias in eth_initialize --Use eth_initialize to probe all devices and write_hwaddr -Add a helper function for eth_uclass_priv -Add documentation to the structures -Add eth_get_ops helper -Change -1 returns to error constants -Change puts to printf -Redo the seq / probe implementation -Remove bd_t *bis from dm eth_ops init function -Remove checks for driver==NULL -Remove priv pointer in per-device priv struct (drivers already get their own directly from DM) -Rename halt() to stop() in ops -Rename init() to start() in ops -Stop handling selecting a new "current" in pre-unbind as it will now work itself out by clearing the pointer
Changes in v3: --Fail init if not activated --Fail probe if ethaddr not set -Allow current eth dev to be NULL -Correct failure chaining from bind to probe to init -Correct the pre_unbind logic -Fixed blank line formatting for variable declaration -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the previous selection
Changes in v2: -Cause an invalid name to fail binding -Changed eth_uclass_priv local var names to be uc_priv -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()). -Rebase on top of dm/master -Removed extra parentheses -Stop maintaining our own index and use DM seq now that it works for our needs -Update error codes -Updated comments
common/cmd_bdinfo.c | 2 + doc/README.drivers.eth | 6 + drivers/net/Kconfig | 9 ++ include/dm/uclass-id.h | 1 + include/net.h | 52 ++++++++ net/eth.c | 346 ++++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 410 insertions(+), 6 deletions(-)
diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index aa81da2..b4cce25 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/doc/README.drivers.eth b/doc/README.drivers.eth index eb83038..98728bc 100644 --- a/doc/README.drivers.eth +++ b/doc/README.drivers.eth @@ -1,3 +1,9 @@ +!!! WARNING !!! + +This guide describes to the old way of doing things. No new Ethernet drivers +should be implemented this way. All new drivers should be written against the +U-Boot core driver model. See doc/driver-model/README.txt + ----------------------- Ethernet Driver Guide ----------------------- diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e69de29..94cf099 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -0,0 +1,9 @@ +config DM_ETH + bool "Enable Driver Model for Ethernet drivers" + depends on DM + help + Enable driver model for Ethernet. + + The eth_*() interface will be implemented by the UC_ETH class + This is currently implemented in net/eth.c + Look in include/net.h for details. diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..ad96682 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */ + UCLASS_ETH, /* Ethernet device */
UCLASS_COUNT, UCLASS_INVALID = -1, diff --git a/include/net.h b/include/net.h index ae0f31a..fff82cb 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,57 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH +/** + * struct eth_pdata - Platform data for Ethernet MAC controllers + * + * @iobase: The base address of the hardware registers + * @enetaddr: The Ethernet MAC address that is loaded from EEPROM or env + */ +struct eth_pdata { + phys_addr_t iobase; + unsigned char enetaddr[6]; +}; + +/** + * struct eth_ops - functions of Ethernet MAC controllers + * + * start: Prepare the hardware to send and receive packets + * send: Send the bytes passed in "packet" as a packet on the wire + * recv: Check if the hardware received a packet. Call the network stack if so + * stop: Stop the hardware from looking for packets - may be called even if + * state == PASSIVE + * mcast: Join or leave a multicast group (for TFTP) - optional + * write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux + * on some platforms like ARM). This function expects the + * eth_pdata::enetaddr field to be populated - optional + * read_rom_hwaddr: Some devices have a backup of the MAC address stored in a + * ROM on the board. This is how the driver should expose it + * to the network stack. This function should fill in the + * eth_pdata::enetaddr field - optional + */ +struct eth_ops { + int (*start)(struct udevice *dev); + int (*send)(struct udevice *dev, void *packet, int length); + int (*recv)(struct udevice *dev); + void (*stop)(struct udevice *dev); +#ifdef CONFIG_MCAST_TFTP + int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join); +#endif + int (*write_hwaddr)(struct udevice *dev); + int (*read_rom_hwaddr)(struct udevice *dev); +}; + +#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops) + +struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +/* Used only when NetConsole is enabled */ +int eth_init_state_only(void); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ +#endif + +#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; @@ -144,6 +195,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number);
int usb_eth_initialize(bd_t *bi); +#endif
int eth_initialize(void); /* Initialize network subsystem */ void eth_try_another(int first_restart); /* Change the device */ diff --git a/net/eth.c b/net/eth.c index 66ecb79..1abf027 100644 --- a/net/eth.c +++ b/net/eth.c @@ -1,16 +1,19 @@ /* - * (C) Copyright 2001-2010 + * (C) Copyright 2001-2015 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Joe Hershberger, National Instruments * * SPDX-License-Identifier: GPL-2.0+ */
#include <common.h> #include <command.h> +#include <dm.h> #include <net.h> #include <miiphy.h> #include <phy.h> #include <asm/errno.h> +#include <dm/device-internal.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -76,6 +79,339 @@ static int eth_mac_skip(int index)
static void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH +/** + * struct eth_device_priv - private structure for each Ethernet device + * + * @state: The state of the Ethernet MAC driver (defined by enum eth_state_t) + */ +struct eth_device_priv { + enum eth_state_t state; +}; + +/** + * struct eth_uclass_priv - The structure attached to the uclass itself + * + * @current: The Ethernet device that the network functions are using + */ +struct eth_uclass_priv { + struct udevice *current; +}; + +static struct eth_uclass_priv *eth_get_uclass_priv(void) +{ + struct uclass *uc; + + uclass_get(UCLASS_ETH, &uc); + assert(uc); + return uc->priv; +} + +static void eth_set_current_to_next(void) +{ + struct eth_uclass_priv *uc_priv; + + uc_priv = eth_get_uclass_priv(); + if (uc_priv->current) + uclass_next_device(&uc_priv->current); + if (!uc_priv->current) + uclass_first_device(UCLASS_ETH, &uc_priv->current); +} + +struct udevice *eth_get_dev(void) +{ + struct eth_uclass_priv *uc_priv; + + uc_priv = eth_get_uclass_priv(); + if (!uc_priv->current) + uclass_first_device(UCLASS_ETH, + &uc_priv->current); + return uc_priv->current; +} + +static void eth_set_dev(struct udevice *dev) +{ + device_probe(dev); + eth_get_uclass_priv()->current = dev; +} + +unsigned char *eth_get_ethaddr(void) +{ + struct eth_pdata *pdata; + + if (eth_get_dev()) { + pdata = eth_get_dev()->platdata; + return pdata->enetaddr; + } + + return NULL; +} + +/* Set active state without calling start on the driver */ +int eth_init_state_only(void) +{ + struct udevice *current; + struct eth_device_priv *priv; + + current = eth_get_dev(); + if (!current || !device_active(current)) + return -EINVAL; + + priv = current->uclass_priv; + priv->state = ETH_STATE_ACTIVE; + + return 0; +} + +/* Set passive state without calling stop on the driver */ +void eth_halt_state_only(void) +{ + struct udevice *current; + struct eth_device_priv *priv; + + current = eth_get_dev(); + if (!current || !device_active(current)) + return; + + priv = current->uclass_priv; + priv->state = ETH_STATE_PASSIVE; +} + +int eth_get_dev_index(void) +{ + if (eth_get_dev()) + return eth_get_dev()->seq; + return -1; +} + +int eth_init(void) +{ + struct udevice *current; + struct udevice *old_current; + + current = eth_get_dev(); + if (!current) { + printf("No ethernet found.\n"); + return -ENODEV; + } + + old_current = current; + do { + debug("Trying %s\n", current->name); + + if (device_active(current)) { + uchar env_enetaddr[6]; + struct eth_pdata *pdata = current->platdata; + + /* Sync environment with network device */ + if (eth_getenv_enetaddr_by_index("eth", current->seq, + env_enetaddr)) + memcpy(pdata->enetaddr, env_enetaddr, 6); + else + memset(pdata->enetaddr, 0, 6); + + if (eth_get_ops(current)->start(current) >= 0) { + struct eth_device_priv *priv = + current->uclass_priv; + + priv->state = ETH_STATE_ACTIVE; + return 0; + } + } + debug("FAIL\n"); + + /* This will ensure the new "current" attempted to probe */ + eth_try_another(0); + current = eth_get_dev(); + } while (old_current != current); + + return -ENODEV; +} + +void eth_halt(void) +{ + struct udevice *current; + struct eth_device_priv *priv; + + current = eth_get_dev(); + if (!current || !device_active(current)) + return; + + eth_get_ops(current)->stop(current); + priv = current->uclass_priv; + priv->state = ETH_STATE_PASSIVE; +} + +int eth_send(void *packet, int length) +{ + struct udevice *current; + + current = eth_get_dev(); + if (!current) + return -ENODEV; + + if (!device_active(current)) + return -EINVAL; + + return eth_get_ops(current)->send(current, packet, length); +} + +int eth_rx(void) +{ + struct udevice *current; + + current = eth_get_dev(); + if (!current) + return -ENODEV; + + if (!device_active(current)) + return -EINVAL; + + return eth_get_ops(current)->recv(current); +} + +static int eth_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev->platdata; + int ret = 0; + + if (!dev || !device_active(dev)) + return -EINVAL; + + /* seq is valid since the device is active */ + if (eth_get_ops(dev)->write_hwaddr && !eth_mac_skip(dev->seq)) { + if (!is_valid_ether_addr(pdata->enetaddr)) { + printf("\nError: %s address %pM illegal value\n", + dev->name, pdata->enetaddr); + return -EINVAL; + } + + ret = eth_get_ops(dev)->write_hwaddr(dev); + if (ret) + printf("\nWarning: %s failed to set MAC address\n", + dev->name); + } + + return ret; +} + +int eth_initialize(void) +{ + int num_devices = 0; + struct udevice *dev; + + bootstage_mark(BOOTSTAGE_ID_NET_ETH_START); + eth_env_init(); + + /* + * Devices need to write the hwaddr even if not started so that Linux + * will have access to the hwaddr that u-boot stored for the device. + * This is accomplished by attempting to probe each device and calling + * their write_hwaddr() operation. + */ + uclass_first_device(UCLASS_ETH, &dev); + if (!dev) { + printf("No ethernet found.\n"); + bootstage_error(BOOTSTAGE_ID_NET_ETH_START); + } else { + bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); + do { + if (num_devices) + printf(", "); + + printf("eth%d: %s", dev->seq, dev->name); + + eth_write_hwaddr(dev); + + uclass_next_device(&dev); + num_devices++; + } while (dev); + + putc('\n'); + } + + return num_devices; +} + +static int eth_post_bind(struct udevice *dev) +{ + if (strchr(dev->name, ' ')) { + printf("\nError: eth device name "%s" has a space!\n", + dev->name); + return -EINVAL; + } + + return 0; +} + +static int eth_pre_unbind(struct udevice *dev) +{ + /* Don't hang onto a pointer that is going away */ + if (dev == eth_get_uclass_priv()->current) + eth_set_dev(NULL); + + return 0; +} + +static int eth_post_probe(struct udevice *dev) +{ + struct eth_device_priv *priv = dev->uclass_priv; + struct eth_pdata *pdata = dev->platdata; + unsigned char env_enetaddr[6]; + + priv->state = ETH_STATE_INIT; + + /* Check if the device has a MAC address in ROM */ + if (eth_get_ops(dev)->read_rom_hwaddr) + eth_get_ops(dev)->read_rom_hwaddr(dev); + + eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr); + if (!is_zero_ether_addr(env_enetaddr)) { + if (!is_zero_ether_addr(pdata->enetaddr) && + memcmp(pdata->enetaddr, env_enetaddr, 6)) { + printf("\nWarning: %s MAC addresses don't match:\n", + dev->name); + printf("Address in SROM is %pM\n", + pdata->enetaddr); + printf("Address in environment is %pM\n", + env_enetaddr); + } + + /* Override the ROM MAC address */ + memcpy(pdata->enetaddr, env_enetaddr, 6); + } else if (is_valid_ether_addr(pdata->enetaddr)) { + eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr); + printf("\nWarning: %s using MAC address from ROM\n", + dev->name); + } else if (is_zero_ether_addr(pdata->enetaddr)) { + printf("\nError: %s address not set.\n", + dev->name); + return -EINVAL; + } + + return 0; +} + +static int eth_pre_remove(struct udevice *dev) +{ + eth_get_ops(dev)->stop(dev); + + return 0; +} + +UCLASS_DRIVER(eth) = { + .name = "eth", + .id = UCLASS_ETH, + .post_bind = eth_post_bind, + .pre_unbind = eth_pre_unbind, + .post_probe = eth_post_probe, + .pre_remove = eth_pre_remove, + .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), + .per_device_auto_alloc_size = sizeof(struct eth_device_priv), +}; +#endif + +#ifndef CONFIG_DM_ETH /* * CPU and board-specific Ethernet initializations. Aliased function * signals caller to move on @@ -427,6 +763,7 @@ int eth_rx(void)
return eth_current->recv(eth_current); } +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -490,7 +827,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) { - static struct eth_device *first_failed; + static void *first_failed; char *ethrotate;
/* @@ -519,12 +856,9 @@ void eth_set_current(void) { static char *act; static int env_changed_id; - struct eth_device *old_current; + void *old_current; int env_id;
- if (!eth_get_dev()) /* XXX no current */ - return; - env_id = get_env_id(); if ((act == NULL) || (env_changed_id != env_id)) { act = getenv("ethact");

Take the opportunity to enforce better names on newly written or retrofitted Ethernet drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 9 ++++++++- net/net.c | 30 +++++++++++++++++++----------- 2 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/include/net.h b/include/net.h index fff82cb..31ef1ff 100644 --- a/include/net.h +++ b/include/net.h @@ -466,7 +466,11 @@ extern uchar NetServerEther[6]; /* Boot server enet address */ extern IPaddr_t NetOurIP; /* Our IP addr (0 = unknown) */ extern IPaddr_t NetServerIP; /* Server IP addr (0 = unknown) */ extern uchar *NetTxPacket; /* THE transmit packet */ +#ifdef CONFIG_DM_ETH +extern uchar *net_rx_packets[PKTBUFSRX]; /* Receive packets */ +#else extern uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets */ +#endif extern uchar *NetRxPacket; /* Current receive packet */ extern int NetRxPacketLen; /* Current rx packet length */ extern unsigned NetIPID; /* IP ID (counting) */ @@ -616,8 +620,11 @@ static inline void NetSendPacket(uchar *pkt, int len) int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int payload_len);
+#ifndef CONFIG_DM_ETH +#define NetReceive(in_packet, len) net_process_received_packet(in_packet, len) +#endif /* Processes a received packet */ -void NetReceive(uchar *, int); +void net_process_received_packet(uchar *in_packet, int len);
#ifdef CONFIG_NETCONSOLE void NcStart(void); diff --git a/net/net.c b/net/net.c index 37b4aab..afec443 100644 --- a/net/net.c +++ b/net/net.c @@ -183,10 +183,13 @@ int NetTimeOffset; #endif
static uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN]; - +#ifdef CONFIG_DM_ETH +/* Receive packets */ +uchar *net_rx_packets[PKTBUFSRX]; +#else /* Receive packet */ uchar *NetRxPackets[PKTBUFSRX]; - +#endif /* Current UDP RX packet handler */ static rxhand_f *udp_packet_handler; /* Current ARP RX packet handler */ @@ -304,9 +307,15 @@ void net_init(void)
NetTxPacket = &PktBuf[0] + (PKTALIGN - 1); NetTxPacket -= (ulong)NetTxPacket % PKTALIGN; +#ifdef CONFIG_DM_ETH + for (i = 0; i < PKTBUFSRX; i++) { + net_rx_packets[i] = NetTxPacket + (i + 1) * + PKTSIZE_ALIGN; + } +#else for (i = 0; i < PKTBUFSRX; i++) NetRxPackets[i] = NetTxPacket + (i + 1) * PKTSIZE_ALIGN; - +#endif ArpInit(); net_clear_handlers();
@@ -952,8 +961,7 @@ static void receive_icmp(struct ip_udp_hdr *ip, int len, } }
-void -NetReceive(uchar *inpkt, int len) +void net_process_received_packet(uchar *in_packet, int len) { struct ethernet_hdr *et; struct ip_udp_hdr *ip; @@ -967,9 +975,9 @@ NetReceive(uchar *inpkt, int len)
debug_cond(DEBUG_NET_PKT, "packet received\n");
- NetRxPacket = inpkt; + NetRxPacket = in_packet; NetRxPacketLen = len; - et = (struct ethernet_hdr *)inpkt; + et = (struct ethernet_hdr *)in_packet;
/* too small packet? */ if (len < ETHER_HDR_SIZE) @@ -977,7 +985,7 @@ NetReceive(uchar *inpkt, int len)
#ifdef CONFIG_API if (push_packet) { - (*push_packet)(inpkt, len); + (*push_packet)(in_packet, len); return; } #endif @@ -1004,11 +1012,11 @@ NetReceive(uchar *inpkt, int len) */ eth_proto = ntohs(et802->et_prot);
- ip = (struct ip_udp_hdr *)(inpkt + E802_HDR_SIZE); + ip = (struct ip_udp_hdr *)(in_packet + E802_HDR_SIZE); len -= E802_HDR_SIZE;
} else if (eth_proto != PROT_VLAN) { /* normal packet */ - ip = (struct ip_udp_hdr *)(inpkt + ETHER_HDR_SIZE); + ip = (struct ip_udp_hdr *)(in_packet + ETHER_HDR_SIZE); len -= ETHER_HDR_SIZE;
} else { /* VLAN packet */ @@ -1033,7 +1041,7 @@ NetReceive(uchar *inpkt, int len) vlanid = cti & VLAN_IDMASK; eth_proto = ntohs(vet->vet_type);
- ip = (struct ip_udp_hdr *)(inpkt + VLAN_ETHER_HDR_SIZE); + ip = (struct ip_udp_hdr *)(in_packet + VLAN_ETHER_HDR_SIZE); len -= VLAN_ETHER_HDR_SIZE; }

Stop forcing drivers to call net_process_received_packet() - formerly called NetReceive(). Now the uclass will handle calling the driver for each packet until the driver errors or has nothing to return. The uclass will then pass the good packets off to the network stack by calling net_process_received_packet().
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v6: -Swallow -EAGAIN error in eth_rx() -Updated function documentation
Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 6 ++++-- net/eth.c | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/include/net.h b/include/net.h index 31ef1ff..241a096 100644 --- a/include/net.h +++ b/include/net.h @@ -95,7 +95,9 @@ struct eth_pdata { * * start: Prepare the hardware to send and receive packets * send: Send the bytes passed in "packet" as a packet on the wire - * recv: Check if the hardware received a packet. Call the network stack if so + * recv: Check if the hardware received a packet. If so, set the pointer to the + * packet buffer in the packetp parameter. If not, return an error or 0 to + * indicate that the hardware receive FIFO is empty * stop: Stop the hardware from looking for packets - may be called even if * state == PASSIVE * mcast: Join or leave a multicast group (for TFTP) - optional @@ -110,7 +112,7 @@ struct eth_pdata { struct eth_ops { int (*start)(struct udevice *dev); int (*send)(struct udevice *dev, void *packet, int length); - int (*recv)(struct udevice *dev); + int (*recv)(struct udevice *dev, uchar **packetp); void (*stop)(struct udevice *dev); #ifdef CONFIG_MCAST_TFTP int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join); diff --git a/net/eth.c b/net/eth.c index 1abf027..058c55a 100644 --- a/net/eth.c +++ b/net/eth.c @@ -259,6 +259,9 @@ int eth_send(void *packet, int length) int eth_rx(void) { struct udevice *current; + uchar *packet; + int ret; + int i;
current = eth_get_dev(); if (!current) @@ -267,7 +270,17 @@ int eth_rx(void) if (!device_active(current)) return -EINVAL;
- return eth_get_ops(current)->recv(current); + /* Process up to 32 packets at one time */ + for (i = 0; i < 32; i++) { + ret = eth_get_ops(current)->recv(current, &packet); + if (ret > 0) + net_process_received_packet(packet, ret); + else + break; + } + if (ret == -EAGAIN) + ret = 0; + return ret; }
static int eth_write_hwaddr(struct udevice *dev)

On 11 March 2015 at 17:44, Joe Hershberger joe.hershberger@ni.com wrote:
Stop forcing drivers to call net_process_received_packet() - formerly called NetReceive(). Now the uclass will handle calling the driver for each packet until the driver errors or has nothing to return. The uclass will then pass the good packets off to the network stack by calling net_process_received_packet().
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Reviewed-by: Simon Glass sjg@chromium.org

Add basic network support to sandbox which includes a network driver.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: -Added help to the sandbox eth mock driver Kconfig entry
Changes in v4: -Cleaned up sandbox EXTRA_ENV define -Moved config to Kconfig
Changes in v3: -Added 2 more ethaddr to sandbox -Print which device in the debug write hwaddr
Changes in v2: -Change printfs to debug in sandbox driver -Remove unused priv struct for sandbox driver
arch/sandbox/Kconfig | 9 +++++ arch/sandbox/dts/sandbox.dts | 4 +++ board/sandbox/README.sandbox | 4 +-- drivers/net/Kconfig | 23 ++++++++++++ drivers/net/Makefile | 1 + drivers/net/sandbox.c | 84 ++++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 16 +++++---- 7 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 drivers/net/sandbox.c
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index 2098b9c..186b58d 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -34,4 +34,13 @@ config DM_I2C config DM_TEST default y
+config NET + default y + +config NETDEVICES + default y + +config DM_ETH + default y + endmenu diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 9ce31bf..36b3bd8 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -181,4 +181,8 @@ }; };
+ eth@10002000 { + compatible = "sandbox,eth"; + reg = <0x10002000 0x1000>; + }; }; diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox index 3c0df17..c1f5f7e 100644 --- a/board/sandbox/README.sandbox +++ b/board/sandbox/README.sandbox @@ -173,16 +173,16 @@ U-Boot sandbox supports these emulations: - Chrome OS EC - GPIO - Host filesystem (access files on the host from within U-Boot) +- I2C - Keyboard (Chrome OS) - LCD +- Network - Serial (for console only) - Sound (incomplete - see sandbox_sdl_sound_init() for details) - SPI - SPI flash - TPM (Trusted Platform Module)
-Notable omissions are networking and I2C. - A wide range of commands is implemented. Filesystems which use a block device are supported.
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 94cf099..e46e57b 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -7,3 +7,26 @@ config DM_ETH The eth_*() interface will be implemented by the UC_ETH class This is currently implemented in net/eth.c Look in include/net.h for details. + +menuconfig NETDEVICES + bool "Network device support" + depends on NET + help + You must select Y to enable any network device support + Generally if you have any networking support this is a given + + If unsure, say Y + +if NETDEVICES + +config ETH_SANDBOX + depends on DM_ETH && SANDBOX + default y + bool "Sandbox: Mocked Ethernet driver" + help + This driver simply responds with fake ARP replies and ping + replies that are used to verify network stack functionality + + This driver is particularly useful in the test/dm/eth.c tests + +endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index b8b0803..a17198c 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_NS8382X) += ns8382x.o obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o +obj-$(CONFIG_ETH_SANDBOX) += sandbox.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c new file mode 100644 index 0000000..522990d --- /dev/null +++ b/drivers/net/sandbox.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int sb_eth_start(struct udevice *dev) +{ + debug("eth_sandbox: Start\n"); + + return 0; +} + +static int sb_eth_send(struct udevice *dev, void *packet, int length) +{ + debug("eth_sandbox: Send packet %d\n", length); + + return 0; +} + +static int sb_eth_recv(struct udevice *dev, uchar **packetp) +{ + return 0; +} + +static void sb_eth_stop(struct udevice *dev) +{ + debug("eth_sandbox: Stop\n"); +} + +static int sb_eth_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + + debug("eth_sandbox %s: Write HW ADDR - %pM\n", dev->name, + pdata->enetaddr); + return 0; +} + +static const struct eth_ops sb_eth_ops = { + .start = sb_eth_start, + .send = sb_eth_send, + .recv = sb_eth_recv, + .stop = sb_eth_stop, + .write_hwaddr = sb_eth_write_hwaddr, +}; + +static int sb_eth_remove(struct udevice *dev) +{ + return 0; +} + +static int sb_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + + pdata->iobase = dev_get_addr(dev); + return 0; +} + +static const struct udevice_id sb_eth_ids[] = { + { .compatible = "sandbox,eth" }, + { } +}; + +U_BOOT_DRIVER(eth_sandbox) = { + .name = "eth_sandbox", + .id = UCLASS_ETH, + .of_match = sb_eth_ids, + .ofdata_to_platdata = sb_eth_ofdata_to_platdata, + .remove = sb_eth_remove, + .ops = &sb_eth_ops, + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index febbfb6..664b984 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -126,9 +126,6 @@ /* include default commands */ #include <config_cmd_default.h>
-/* We don't have networking support yet */ -#undef CONFIG_CMD_NET -#undef CONFIG_CMD_NFS
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY @@ -165,16 +162,23 @@
#define CONFIG_KEYBOARD
-#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial,cros-ec-keyb\0" \ +#define SANDBOX_SERIAL_SETTINGS "stdin=serial,cros-ec-keyb\0" \ "stdout=serial,lcd\0" \ "stderr=serial,lcd\0" #else - -#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial\0" \ +#define SANDBOX_SERIAL_SETTINGS "stdin=serial\0" \ "stdout=serial,lcd\0" \ "stderr=serial,lcd\0" #endif
+#define SANDBOX_ETH_SETTINGS "ethaddr=00:00:11:22:33:44\0" \ + "eth1addr=00:00:11:22:33:45\0" \ + "eth2addr=00:00:11:22:33:46\0" \ + "ipaddr=1.2.3.4\0" + +#define CONFIG_EXTRA_ENV_SETTINGS SANDBOX_SERIAL_SETTINGS \ + SANDBOX_ETH_SETTINGS + #define CONFIG_GZIP_COMPRESSED #define CONFIG_BZIP2 #define CONFIG_LZO

The sandbox driver will now generate response traffic to exercise the ping command even when no network exists. This allows the basic data pathways of the DM to be tested.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v6: None Changes in v5: -Simplify sandbox eth driver by switching from int array to byte array -Switch priv from packet buffer to a pointer to net_rx_packets[0]
Changes in v4: -Removed checks on priv != NULL and added protection in uclass instead
Changes in v3: -Prevent a crash if memory is not allocated
Changes in v2: -Change printfs to debug in sandbox driver -Move fake hwaddr to the device tree -Move static data to priv
arch/sandbox/dts/sandbox.dts | 1 + drivers/net/sandbox.c | 107 +++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 1 + 3 files changed, 109 insertions(+)
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 36b3bd8..c2a3304 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -184,5 +184,6 @@ eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>; + fake-host-hwaddr = [00 00 66 44 22 00]; }; }; diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 522990d..cb69a95 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -14,22 +14,128 @@
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 + * 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]; + IPaddr_t fake_host_ipaddr; + uchar *recv_packet_buffer; + int recv_packet_length; +}; + static int sb_eth_start(struct udevice *dev) { + struct eth_sandbox_priv *priv = dev_get_priv(dev); + debug("eth_sandbox: Start\n");
+ fdtdec_get_byte_array(gd->fdt_blob, dev->of_offset, "fake-host-hwaddr", + priv->fake_host_hwaddr, ARP_HLEN); + priv->recv_packet_buffer = net_rx_packets[0]; return 0; }
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 (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 = NetReadIP(&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); + NetWriteIP(&arp_recv->ar_spa, priv->fake_host_ipaddr); + memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN); + NetCopyIP(&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; + NetCopyIP((void *)&ipr->ip_dst, &ip->ip_src); + NetWriteIP((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; }
static int sb_eth_recv(struct udevice *dev, uchar **packetp) { + struct eth_sandbox_priv *priv = dev_get_priv(dev); + + if (priv->recv_packet_length) { + int lcl_recv_packet_length = priv->recv_packet_length; + + debug("eth_sandbox: received packet %d\n", + priv->recv_packet_length); + priv->recv_packet_length = 0; + *packetp = priv->recv_packet_buffer; + return lcl_recv_packet_length; + } return 0; }
@@ -80,5 +186,6 @@ U_BOOT_DRIVER(eth_sandbox) = { .ofdata_to_platdata = sb_eth_ofdata_to_platdata, .remove = sb_eth_remove, .ops = &sb_eth_ops, + .priv_auto_alloc_size = sizeof(struct eth_sandbox_priv), .platdata_auto_alloc_size = sizeof(struct eth_pdata), }; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 664b984..9189f6a 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -126,6 +126,7 @@ /* include default commands */ #include <config_cmd_default.h>
+#define CONFIG_CMD_PING
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY

Add a test for the eth uclass using the sandbox eth driver. Verify basic functionality of the network stack / eth uclass by exercising the ping function.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: -Added dm eth testing
Changes in v2: None
test/dm/Makefile | 1 + test/dm/eth.c | 38 ++++++++++++++++++++++++++++++++++++++ test/dm/test.dts | 18 ++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 test/dm/eth.c
diff --git a/test/dm/Makefile b/test/dm/Makefile index 1d9148f..b2eb989 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_DM_TEST) += ut.o obj-$(CONFIG_DM_TEST) += core.o obj-$(CONFIG_DM_TEST) += ut.o ifneq ($(CONFIG_SANDBOX),) +obj-$(CONFIG_DM_ETH) += eth.o obj-$(CONFIG_DM_GPIO) += gpio.o obj-$(CONFIG_DM_I2C) += i2c.o obj-$(CONFIG_DM_SPI_FLASH) += sf.o diff --git a/test/dm/eth.c b/test/dm/eth.c new file mode 100644 index 0000000..04ccf49 --- /dev/null +++ b/test/dm/eth.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <dm/test.h> +#include <dm/ut.h> +#include <fdtdec.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int dm_test_eth(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + + setenv("ethact", "eth@10002000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth@10003000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10003000", getenv("ethact")); + + setenv("ethact", "eth@10004000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + return 0; +} +DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 84024a4..2f68cdf 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -149,4 +149,22 @@ }; };
+ eth@10002000 { + compatible = "sandbox,eth"; + reg = <0x10002000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; + }; + + eth@10003000 { + compatible = "sandbox,eth"; + reg = <0x10003000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>; + }; + + eth@10004000 { + compatible = "sandbox,eth"; + reg = <0x10004000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x22>; + }; + };

Allow network devices to be referred to as "eth0" instead of "eth@12345678" when specified in ethact.
Add tests to verify this behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: -Added a comment about devname -Only check for alias if the name is long enough
Changes in v4: -Use only the seq from DM to find aliases
Changes in v3: -Added support for aliases
Changes in v2: None
include/configs/sandbox.h | 2 +- include/net.h | 5 +++++ net/eth.c | 50 ++++++++++++++++++++++++++++++++++++++--------- test/dm/eth.c | 24 +++++++++++++++++++++++ test/dm/test.dts | 4 +++- 5 files changed, 74 insertions(+), 11 deletions(-)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 9189f6a..caf9f5a 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -174,7 +174,7 @@
#define SANDBOX_ETH_SETTINGS "ethaddr=00:00:11:22:33:44\0" \ "eth1addr=00:00:11:22:33:45\0" \ - "eth2addr=00:00:11:22:33:46\0" \ + "eth5addr=00:00:11:22:33:46\0" \ "ipaddr=1.2.3.4\0"
#define CONFIG_EXTRA_ENV_SETTINGS SANDBOX_SERIAL_SETTINGS \ diff --git a/include/net.h b/include/net.h index 241a096..baccd47 100644 --- a/include/net.h +++ b/include/net.h @@ -124,6 +124,11 @@ struct eth_ops { #define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
struct udevice *eth_get_dev(void); /* get the current device */ +/* + * The devname can be either an exact name given by the driver or device tree + * or it can be an alias of the form "eth%d" + */ +struct udevice *eth_get_dev_by_name(const char *devname); unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ /* Used only when NetConsole is enabled */ int eth_init_state_only(void); /* Set active state */ diff --git a/net/eth.c b/net/eth.c index 058c55a..a2e6f34 100644 --- a/net/eth.c +++ b/net/eth.c @@ -135,6 +135,39 @@ static void eth_set_dev(struct udevice *dev) eth_get_uclass_priv()->current = dev; }
+/* + * Find the udevice that either has the name passed in as devname or has an + * alias named devname. + */ +struct udevice *eth_get_dev_by_name(const char *devname) +{ + int seq = -1; + char *endp = NULL; + const char *startp = NULL; + struct udevice *it; + struct uclass *uc; + + /* Must be longer than 3 to be an alias */ + if (strlen(devname) > strlen("eth")) { + startp = devname + strlen("eth"); + seq = simple_strtoul(startp, &endp, 10); + } + + uclass_get(UCLASS_ETH, &uc); + uclass_foreach_dev(it, uc) { + /* We need the seq to be valid, so make sure it's probed */ + device_probe(it); + /* + * Check for the name or the sequence number to match + */ + if (strcmp(it->name, devname) == 0 || + (endp > startp && it->seq == seq)) + return it; + } + + return NULL; +} + unsigned char *eth_get_ethaddr(void) { struct eth_pdata *pdata; @@ -421,6 +454,7 @@ UCLASS_DRIVER(eth) = { .pre_remove = eth_pre_remove, .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), .per_device_auto_alloc_size = sizeof(struct eth_device_priv), + .flags = DM_UC_FLAG_SEQ_ALIAS, }; #endif
@@ -453,6 +487,11 @@ static void eth_set_current_to_next(void) eth_current = eth_current->next; }
+static void eth_set_dev(struct eth_device *dev) +{ + eth_current = dev; +} + struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -869,7 +908,6 @@ void eth_set_current(void) { static char *act; static int env_changed_id; - void *old_current; int env_id;
env_id = get_env_id(); @@ -877,14 +915,8 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; } - if (act != NULL) { - old_current = eth_get_dev(); - do { - if (strcmp(eth_get_name(), act) == 0) - return; - eth_set_current_to_next(); - } while (old_current != eth_get_dev()); - } + if (act != NULL) + eth_set_dev(eth_get_dev_by_name(act));
eth_current_changed(); } diff --git a/test/dm/eth.c b/test/dm/eth.c index 04ccf49..5688b71 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -36,3 +36,27 @@ static int dm_test_eth(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT); + +static int dm_test_eth_alias(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + setenv("ethact", "eth0"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth1"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Expected to fail since eth2 is not defined in the device tree */ + setenv("ethact", "eth2"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth5"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10003000", getenv("ethact")); + + return 0; +} +DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 2f68cdf..bc2409d 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -17,6 +17,8 @@ testfdt3 = "/b-test"; testfdt5 = "/some-bus/c-test@5"; testfdt8 = "/a-test"; + eth0 = "/eth@10002000"; + eth5 = ð_5; };
uart0: serial { @@ -155,7 +157,7 @@ fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
- eth@10003000 { + eth_5: eth@10003000 { compatible = "sandbox,eth"; reg = <0x10003000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>;

The ethprime env var is used to indicate the starting device if none is specified in ethact. Also support aliases specified in the ethprime var.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: -Fix compile error on !DM_ETH
Changes in v4: -Load from ethprime on eth_initialize()
Changes in v3: -Added support for ethprime
Changes in v2: None
net/eth.c | 29 ++++++++++++++++++++++++++++- test/dm/eth.c | 20 ++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/net/eth.c b/net/eth.c index a2e6f34..b6c2af3 100644 --- a/net/eth.c +++ b/net/eth.c @@ -360,6 +360,18 @@ int eth_initialize(void) printf("No ethernet found.\n"); bootstage_error(BOOTSTAGE_ID_NET_ETH_START); } else { + char *ethprime = getenv("ethprime"); + struct udevice *prime_dev = NULL; + + if (ethprime) + prime_dev = eth_get_dev_by_name(ethprime); + if (prime_dev) { + eth_set_dev(prime_dev); + eth_current_changed(); + } else { + eth_set_dev(NULL); + } + bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); do { if (num_devices) @@ -367,6 +379,9 @@ int eth_initialize(void)
printf("eth%d: %s", dev->seq, dev->name);
+ if (ethprime && dev == prime_dev) + printf(" [PRIME]"); + eth_write_hwaddr(dev);
uclass_next_device(&dev); @@ -915,8 +930,20 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; } - if (act != NULL) + + if (act == NULL) { + char *ethprime = getenv("ethprime"); + void *dev = NULL; + + if (ethprime) + dev = eth_get_dev_by_name(ethprime); + if (dev) + eth_set_dev(dev); + else + eth_set_dev(NULL); + } else { eth_set_dev(eth_get_dev_by_name(act)); + }
eth_current_changed(); } diff --git a/test/dm/eth.c b/test/dm/eth.c index 5688b71..96e3c46 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -60,3 +60,23 @@ static int dm_test_eth_alias(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT); + +static int dm_test_eth_prime(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + + /* Expected to be "eth@10003000" because of ethprime variable */ + setenv("ethact", NULL); + setenv("ethprime", "eth5"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10003000", getenv("ethact")); + + /* Expected to be "eth@10002000" because it is first */ + setenv("ethact", NULL); + setenv("ethprime", NULL); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + return 0; +} +DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT);

Make sure that the ethrotate behavior occurs as expected.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: -Added a test for skipping un-probe-able devices
Changes in v4: -Added testing for ethrotate
Changes in v3: None Changes in v2: None
test/dm/eth.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
diff --git a/test/dm/eth.c b/test/dm/eth.c index 96e3c46..9b55013 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -80,3 +80,45 @@ static int dm_test_eth_prime(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT); + +static int dm_test_eth_rotate(struct dm_test_state *dms) +{ + char ethaddr[18]; + + /* Invalidate eth1's MAC address */ + NetPingIP = string_to_ip("1.1.2.2"); + strcpy(ethaddr, getenv("eth1addr")); + setenv("eth1addr", NULL); + + /* Make sure that the default is to rotate to the next interface */ + setenv("ethact", "eth@10004000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + /* If ethrotate is no, then we should fail on a bad MAC */ + setenv("ethact", "eth@10004000"); + setenv("ethrotate", "no"); + ut_asserteq(-1, NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Restore the env */ + setenv("eth1addr", ethaddr); + setenv("ethrotate", NULL); + + /* Invalidate eth0's MAC address */ + strcpy(ethaddr, getenv("ethaddr")); + setenv(".flags", "ethaddr"); + setenv("ethaddr", NULL); + + /* Make sure we can skip invalid devices */ + setenv("ethact", "eth@10004000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Restore the env */ + setenv("ethaddr", ethaddr); + setenv(".flags", NULL); + + return 0; +} +DM_TEST(dm_test_eth_rotate, DM_TESTF_SCAN_FDT);

This is needed to test the netretry functionality (make the command fail on a sandbox eth device).
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: -Add function comments -Check array index bounds
Changes in v5: -Use a function call to change mock driver behavior
Changes in v4: -Add ability to disable ping reply in sandbox eth driver
Changes in v3: None Changes in v2: None
arch/sandbox/include/asm/eth.h | 15 +++++++++++++++ drivers/net/sandbox.c | 17 +++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 arch/sandbox/include/asm/eth.h
diff --git a/arch/sandbox/include/asm/eth.h b/arch/sandbox/include/asm/eth.h new file mode 100644 index 0000000..4b79ede --- /dev/null +++ b/arch/sandbox/include/asm/eth.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __ETH_H +#define __ETH_H + +void sandbox_eth_disable_response(int index, bool disable); + +#endif /* __ETH_H */ diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index cb69a95..db115d0 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -29,6 +29,19 @@ struct eth_sandbox_priv { int recv_packet_length; };
+static bool disabled[8] = {false}; + +/* + * sandbox_eth_disable_response() + * + * index - The alias index (also DM seq number) + * disable - If non-zero, ignore sent packets and don't send mock response + */ +void sandbox_eth_disable_response(int index, bool disable) +{ + disabled[index] = disable; +} + static int sb_eth_start(struct udevice *dev) { struct eth_sandbox_priv *priv = dev_get_priv(dev); @@ -48,6 +61,10 @@ 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]) + return 0; + if (ntohs(eth->et_protlen) == PROT_ARP) { struct arp_hdr *arp = packet + ETHER_HDR_SIZE;

The effect of the "netretry" env var was recently changed. This test checks that behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: -Added comments about test cases -Switched to function to control state of mock driver
Changes in v4: -Updated expected behavior based on changes to the NetLoop
Changes in v3: -Added testing for netretry
Changes in v2: None
test/dm/eth.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
diff --git a/test/dm/eth.c b/test/dm/eth.c index 9b55013..a0e9359 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -14,6 +14,7 @@ #include <fdtdec.h> #include <malloc.h> #include <net.h> +#include <asm/eth.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -122,3 +123,34 @@ static int dm_test_eth_rotate(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth_rotate, DM_TESTF_SCAN_FDT); + +static int dm_test_net_retry(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + + /* + * eth1 is disabled and netretry is yes, so the ping should succeed and + * the active device should be eth0 + */ + sandbox_eth_disable_response(1, true); + setenv("ethact", "eth@10004000"); + setenv("netretry", "yes"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + /* + * eth1 is disabled and netretry is no, so the ping should fail and the + * active device should be eth1 + */ + setenv("ethact", "eth@10004000"); + setenv("netretry", "no"); + ut_asserteq(-1, NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Restore the env */ + setenv("netretry", NULL); + sandbox_eth_disable_response(1, false); + + return 0; +} +DM_TEST(dm_test_net_retry, DM_TESTF_SCAN_FDT);

Implement a bridge between U-Boot's network stack and Linux's raw packet API allowing the sandbox to send and receive packets using the host machine's network interface.
This raw Ethernet API requires elevated privileges. You can either run as root, or you can add the capability needed like so:
sudo /sbin/setcap "CAP_NET_RAW+ep" /path/to/u-boot
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: -Addressed nits
Changes in v5: -Added fallback for setting promiscuous mode -Added help to Kconfig -Added more details and examples in the README -Check for NULL when reading fdt for host interface -Check for malloc failure -Remove cast of pointer passed to free -Remove the empty sb_eth_raw_remove function -Return -errno in from send and recv -Return errno from recv -Set the socket to non-blocking -Use net_rx_packets instead of a stack buffer
Changes in v4: -Add comments to priv struct definition -Added comments to README.sandbox -Clean up the interface to sandbox's eth-raw-os by passing priv to raw-os -Cleanup var definition order -Fixed the MAC address limitation (now all traffic uses MAC address from env) -Move os file to arch -Moved config to Kconfig -Use accessors for platdata and priv
Changes in v3: -Made the os raw packet support for sandbox eth build and work.
Changes in v2: -Added the raw packet proof-of-concept patch.
arch/sandbox/Kconfig | 3 + arch/sandbox/cpu/Makefile | 10 +++ arch/sandbox/cpu/eth-raw-os.c | 140 ++++++++++++++++++++++++++++++++++ arch/sandbox/dts/sandbox.dts | 6 ++ arch/sandbox/include/asm/eth-raw-os.h | 32 ++++++++ board/sandbox/README.sandbox | 52 +++++++++++++ drivers/net/Kconfig | 10 +++ drivers/net/Makefile | 1 + drivers/net/sandbox-raw.c | 98 ++++++++++++++++++++++++ 9 files changed, 352 insertions(+) create mode 100644 arch/sandbox/cpu/eth-raw-os.c create mode 100644 arch/sandbox/include/asm/eth-raw-os.h create mode 100644 drivers/net/sandbox-raw.c
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index 186b58d..f84b3fc 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -43,4 +43,7 @@ config NETDEVICES config DM_ETH default y
+config ETH_SANDBOX_RAW + default y + endmenu diff --git a/arch/sandbox/cpu/Makefile b/arch/sandbox/cpu/Makefile index 7d4410c..1b42fee 100644 --- a/arch/sandbox/cpu/Makefile +++ b/arch/sandbox/cpu/Makefile @@ -8,6 +8,7 @@ #
obj-y := cpu.o os.o start.o state.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += eth-raw-os.o obj-$(CONFIG_SANDBOX_SDL) += sdl.o
# os.c is build in the system environment, so needs standard includes @@ -20,3 +21,12 @@ $(obj)/os.o: $(src)/os.c FORCE $(call if_changed_dep,cc_os.o) $(obj)/sdl.o: $(src)/sdl.c FORCE $(call if_changed_dep,cc_os.o) + +# eth-raw-os.c is built in the system env, so needs standard includes +# CFLAGS_REMOVE_eth-raw-os.o cannot be used to drop header include path +quiet_cmd_cc_eth-raw-os.o = CC $(quiet_modtag) $@ +cmd_cc_eth-raw-os.o = $(CC) $(filter-out -nostdinc, \ + $(patsubst -I%,-idirafter%,$(c_flags))) -c -o $@ $< + +$(obj)/eth-raw-os.o: $(src)/eth-raw-os.c FORCE + $(call if_changed_dep,cc_eth-raw-os.o) diff --git a/arch/sandbox/cpu/eth-raw-os.c b/arch/sandbox/cpu/eth-raw-os.c new file mode 100644 index 0000000..601205a --- /dev/null +++ b/arch/sandbox/cpu/eth-raw-os.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <asm/eth-raw-os.h> +#include <errno.h> +#include <fcntl.h> +#include <net/if.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <linux/if_ether.h> +#include <linux/if_packet.h> + +int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, + struct eth_sandbox_raw_priv *priv) +{ + struct sockaddr_ll *device; + struct packet_mreq mr; + int ret; + int flags; + + /* Prepare device struct */ + priv->device = malloc(sizeof(struct sockaddr_ll)); + if (priv->device == NULL) + return -ENOMEM; + device = priv->device; + memset(device, 0, sizeof(struct sockaddr_ll)); + device->sll_ifindex = if_nametoindex(ifname); + device->sll_family = AF_PACKET; + memcpy(device->sll_addr, ethmac, 6); + device->sll_halen = htons(6); + + /* Open socket */ + priv->sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (priv->sd < 0) { + printf("Failed to open socket: %d %s\n", errno, + strerror(errno)); + return -errno; + } + /* Bind to the specified interface */ + ret = setsockopt(priv->sd, SOL_SOCKET, SO_BINDTODEVICE, ifname, + strlen(ifname) + 1); + if (ret < 0) { + printf("Failed to bind to '%s': %d %s\n", ifname, errno, + strerror(errno)); + return -errno; + } + + /* Make the socket non-blocking */ + flags = fcntl(priv->sd, F_GETFL, 0); + fcntl(priv->sd, F_SETFL, flags | O_NONBLOCK); + + /* Enable promiscuous mode to receive responses meant for us */ + mr.mr_ifindex = device->sll_ifindex; + mr.mr_type = PACKET_MR_PROMISC; + ret = setsockopt(priv->sd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, + &mr, sizeof(mr)); + if (ret < 0) { + struct ifreq ifr; + + printf("Failed to set promiscuous mode: %d %s\n" + "Falling back to the old "flags" way...\n", + errno, strerror(errno)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + if (ioctl(priv->sd, SIOCGIFFLAGS, &ifr) < 0) { + printf("Failed to read flags: %d %s\n", errno, + strerror(errno)); + return -errno; + } + ifr.ifr_flags |= IFF_PROMISC; + if (ioctl(priv->sd, SIOCSIFFLAGS, &ifr) < 0) { + printf("Failed to write flags: %d %s\n", errno, + strerror(errno)); + return -errno; + } + } + return 0; +} + +int sandbox_eth_raw_os_send(void *packet, int length, + const struct eth_sandbox_raw_priv *priv) +{ + int retval; + + if (!priv->sd || !priv->device) + return -EINVAL; + + retval = sendto(priv->sd, packet, length, 0, + (struct sockaddr *)priv->device, + sizeof(struct sockaddr_ll)); + if (retval < 0) { + printf("Failed to send packet: %d %s\n", errno, + strerror(errno)); + return -errno; + } + return retval; +} + +int sandbox_eth_raw_os_recv(void *packet, int *length, + const struct eth_sandbox_raw_priv *priv) +{ + int retval; + int saddr_size; + + if (!priv->sd || !priv->device) + return -EINVAL; + saddr_size = sizeof(struct sockaddr); + retval = recvfrom(priv->sd, packet, 1536, 0, + (struct sockaddr *)priv->device, + (socklen_t *)&saddr_size); + *length = 0; + if (retval >= 0) { + *length = retval; + return 0; + } + /* The socket is non-blocking, so expect EAGAIN when there is no data */ + if (errno == EAGAIN) + return 0; + return -errno; +} + +void sandbox_eth_raw_os_stop(struct eth_sandbox_raw_priv *priv) +{ + free(priv->device); + priv->device = NULL; + close(priv->sd); + priv->sd = -1; +} diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index c2a3304..8002196 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -186,4 +186,10 @@ reg = <0x10002000 0x1000>; fake-host-hwaddr = [00 00 66 44 22 00]; }; + + eth@80000000 { + compatible = "sandbox,eth-raw"; + reg = <0x80000000 0x1000>; + host-raw-interface = "eth0"; + }; }; diff --git a/arch/sandbox/include/asm/eth-raw-os.h b/arch/sandbox/include/asm/eth-raw-os.h new file mode 100644 index 0000000..df60c4f --- /dev/null +++ b/arch/sandbox/include/asm/eth-raw-os.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __ETH_RAW_OS_H +#define __ETH_RAW_OS_H + +/** + * struct eth_sandbox_raw_priv - raw socket session + * + * sd: socket descriptor - the open socket during a session + * device: struct sockaddr_ll - the host interface packets move to/from + */ +struct eth_sandbox_raw_priv { + int sd; + void *device; +}; + +int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, + struct eth_sandbox_raw_priv *priv); +int sandbox_eth_raw_os_send(void *packet, int length, + const struct eth_sandbox_raw_priv *priv); +int sandbox_eth_raw_os_recv(void *packet, int *length, + const struct eth_sandbox_raw_priv *priv); +void sandbox_eth_raw_os_stop(struct eth_sandbox_raw_priv *priv); + +#endif /* __ETH_RAW_OS_H */ diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox index c1f5f7e..9f5d3f7 100644 --- a/board/sandbox/README.sandbox +++ b/board/sandbox/README.sandbox @@ -190,6 +190,58 @@ Also sandbox uses generic board (CONFIG_SYS_GENERIC_BOARD) and supports driver model (CONFIG_DM) and associated commands.
+Linux RAW Networking Bridge +--------------------------- + +The sandbox_eth_raw driver bridges traffic between the bottom of the network +stack and the RAW sockets API in Linux. This allows much of the U-Boot network +functionality to be tested in sandbox against real network traffic. + +For Ethernet network adapters, the bridge utilizes the RAW AF_PACKET API. This +is needed to get access to the lowest level of the network stack in Linux. This +means that all of the Ethernet frame is included. This allows the U-Boot network +stack to be fully used. In other words, nothing about the Linux network stack is +involved in forming the packets that end up on the wire. To receive the +responses to packets sent from U-Boot the network interface has to be set to +promiscuous mode so that the network card won't filter out packets not destined +for its configured (on Linux) MAC address. + +The RAW sockets Ethernet API requires elevated privileges in Linux. You can +either run as root, or you can add the capability needed like so: + +sudo /sbin/setcap "CAP_NET_RAW+ep" /path/to/u-boot + +The default device tree for sandbox includes an entry for eth0 on the sandbox +host machine whose alias is "eth1". The following are a few examples of network +operations being tested on the eth0 interface. + +sudo /path/to/u-boot -D + +DHCP +.... + +set autoload no +set ethact eth1 +dhcp + +PING +.... + +set autoload no +set ethact eth1 +dhcp +ping $gatewayip + +TFTP +.... + +set autoload no +set ethact eth1 +dhcp +set serverip WWW.XXX.YYY.ZZZ +tftpboot u-boot.bin + + SPI Emulation -------------
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e46e57b..5bd66ea 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -29,4 +29,14 @@ config ETH_SANDBOX
This driver is particularly useful in the test/dm/eth.c tests
+config ETH_SANDBOX_RAW + depends on DM_ETH && SANDBOX + default y + bool "Sandbox: Bridge to Linux Raw Sockets" + help + This driver is a bridge from the bottom of the network stack + in U-Boot to the RAW AF_PACKET API in Linux. This allows real + network traffic to be tested from within sandbox. See + board/sandbox/README.sandbox for more details. + endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index a17198c..7d32519 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o obj-$(CONFIG_ETH_SANDBOX) += sandbox.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c new file mode 100644 index 0000000..435b874 --- /dev/null +++ b/drivers/net/sandbox-raw.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <asm/eth-raw-os.h> +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + + +static int sb_eth_raw_start(struct udevice *dev) +{ + struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + const char *interface; + + debug("eth_sandbox_raw: Start\n"); + + interface = fdt_getprop(gd->fdt_blob, dev->of_offset, + "host-raw-interface", NULL); + if (interface == NULL) + return -EINVAL; + + return sandbox_eth_raw_os_start(interface, pdata->enetaddr, priv); +} + +static int sb_eth_raw_send(struct udevice *dev, void *packet, int length) +{ + struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); + + debug("eth_sandbox_raw: Send packet %d\n", length); + + return sandbox_eth_raw_os_send(packet, length, priv); +} + +static int sb_eth_raw_recv(struct udevice *dev, uchar **packetp) +{ + struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); + int retval; + int length; + + retval = sandbox_eth_raw_os_recv(net_rx_packets[0], &length, priv); + + if (!retval && length) { + debug("eth_sandbox_raw: received packet %d\n", + length); + *packetp = net_rx_packets[0]; + return length; + } + return retval; +} + +static void sb_eth_raw_stop(struct udevice *dev) +{ + struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); + + debug("eth_sandbox_raw: Stop\n"); + + sandbox_eth_raw_os_stop(priv); +} + +static const struct eth_ops sb_eth_raw_ops = { + .start = sb_eth_raw_start, + .send = sb_eth_raw_send, + .recv = sb_eth_raw_recv, + .stop = sb_eth_raw_stop, +}; + +static int sb_eth_raw_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + + pdata->iobase = dev_get_addr(dev); + return 0; +} + +static const struct udevice_id sb_eth_raw_ids[] = { + { .compatible = "sandbox,eth-raw" }, + { } +}; + +U_BOOT_DRIVER(eth_sandbox_raw) = { + .name = "eth_sandbox_raw", + .id = UCLASS_ETH, + .of_match = sb_eth_raw_ids, + .ofdata_to_platdata = sb_eth_raw_ofdata_to_platdata, + .ops = &sb_eth_raw_ops, + .priv_auto_alloc_size = sizeof(struct eth_sandbox_raw_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +};

This is now testable via the eth-raw interface
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: None Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
include/configs/sandbox.h | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index caf9f5a..034050e 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -127,6 +127,14 @@ #include <config_cmd_default.h>
#define CONFIG_CMD_PING +#define CONFIG_CMD_DHCP +#define CONFIG_BOOTP_DNS +#define CONFIG_BOOTP_DNS2 +#define CONFIG_BOOTP_GATEWAY +#define CONFIG_BOOTP_SEND_HOSTNAME +#define CONFIG_BOOTP_SERVERIP +#define CONFIG_BOOTP_SUBNETMASK +#define CONFIG_IP_DEFRAG
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY

The 'lo' interface on Linux doesn't support thinks like ARP or link-layer access like we use to talk to a normal network interface. A higher-level network API must be used to access localhost.
As written, this interface is limited to not supporting ICMP since the API doesn't allow the socket to be opened for all IP traffic and be able to receive at the same time. UDP is far more useful to test with, so it was selected over ICMP. Ping won't work, but things like TFTP should work.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: -Add details about lo support to the README -Remove socket timeout -Separate init to 2 helper static functions -Set the socket to non-blocking -Use INADDR_LOOPBACK -Use more verbose comments
Changes in v4: -Added support for the 'lo' network interface
Changes in v3: None Changes in v2: None
arch/sandbox/cpu/eth-raw-os.c | 113 +++++++++++++++++++++++++++++++++- arch/sandbox/dts/sandbox.dts | 10 +++ arch/sandbox/include/asm/eth-raw-os.h | 10 ++- board/sandbox/README.sandbox | 22 +++++++ drivers/net/sandbox-raw.c | 71 ++++++++++++++++++++- 5 files changed, 221 insertions(+), 5 deletions(-)
diff --git a/arch/sandbox/cpu/eth-raw-os.c b/arch/sandbox/cpu/eth-raw-os.c index 601205a..b76a731 100644 --- a/arch/sandbox/cpu/eth-raw-os.c +++ b/arch/sandbox/cpu/eth-raw-os.c @@ -12,6 +12,8 @@ #include <fcntl.h> #include <net/if.h> #include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/udp.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -20,10 +22,11 @@ #include <sys/socket.h> #include <unistd.h>
+#include <arpa/inet.h> #include <linux/if_ether.h> #include <linux/if_packet.h>
-int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, +static int _raw_packet_start(const char *ifname, unsigned char *ethmac, struct eth_sandbox_raw_priv *priv) { struct sockaddr_ll *device; @@ -89,14 +92,114 @@ int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, return 0; }
+static int _local_inet_start(struct eth_sandbox_raw_priv *priv) +{ + struct sockaddr_in *device; + int ret; + int flags; + int one = 1; + + /* Prepare device struct */ + priv->device = malloc(sizeof(struct sockaddr_in)); + if (priv->device == NULL) + return -ENOMEM; + device = priv->device; + memset(device, 0, sizeof(struct sockaddr_in)); + device->sin_family = AF_INET; + device->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + /** + * Open socket + * Since we specify UDP here, any incoming ICMP packets will + * not be received, so things like ping will not work on this + * localhost interface. + */ + priv->sd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP); + if (priv->sd < 0) { + printf("Failed to open socket: %d %s\n", errno, + strerror(errno)); + return -errno; + } + + /* Make the socket non-blocking */ + flags = fcntl(priv->sd, F_GETFL, 0); + fcntl(priv->sd, F_SETFL, flags | O_NONBLOCK); + + /* Include the UDP/IP headers on send and receive */ + ret = setsockopt(priv->sd, IPPROTO_IP, IP_HDRINCL, &one, + sizeof(one)); + if (ret < 0) { + printf("Failed to set header include option: %d %s\n", errno, + strerror(errno)); + return -errno; + } + priv->local_bind_sd = -1; + priv->local_bind_udp_port = 0; + return 0; +} + +int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, + struct eth_sandbox_raw_priv *priv) +{ + if (priv->local) + return _local_inet_start(priv); + else + return _raw_packet_start(ifname, ethmac, priv); +} + int sandbox_eth_raw_os_send(void *packet, int length, - const struct eth_sandbox_raw_priv *priv) + struct eth_sandbox_raw_priv *priv) { int retval; + struct udphdr *udph = packet + sizeof(struct iphdr);
if (!priv->sd || !priv->device) return -EINVAL;
+ /* + * This block of code came about when testing tftp on the localhost + * interface. When using the RAW AF_INET API, the network stack is still + * in play responding to incoming traffic based on open "ports". Since + * it is raw (at the IP layer, no Ethernet) the network stack tells the + * TFTP server that the port it responded to is closed. This causes the + * TFTP transfer to be aborted. This block of code inspects the outgoing + * packet as formulated by the u-boot network stack to determine the + * source port (that the TFTP server will send packets back to) and + * opens a typical UDP socket on that port, thus preventing the network + * stack from sending that ICMP message claiming that the port has no + * bound socket. + */ + if (priv->local && (priv->local_bind_sd == -1 || + priv->local_bind_udp_port != udph->source)) { + struct iphdr *iph = packet; + struct sockaddr_in addr; + + if (priv->local_bind_sd != -1) + close(priv->local_bind_sd); + + /* A normal UDP socket is required to bind */ + priv->local_bind_sd = socket(AF_INET, SOCK_DGRAM, 0); + if (priv->local_bind_sd < 0) { + printf("Failed to open bind sd: %d %s\n", errno, + strerror(errno)); + return -errno; + } + priv->local_bind_udp_port = udph->source; + + /** + * Bind the UDP port that we intend to use as our source port + * so that the kernel will not send an ICMP port unreachable + * message to the server + */ + addr.sin_family = AF_INET; + addr.sin_port = udph->source; + addr.sin_addr.s_addr = iph->saddr; + retval = bind(priv->local_bind_sd, &addr, sizeof(addr)); + if (retval < 0) + printf("Failed to bind: %d %s\n", errno, + strerror(errno)); + } + retval = sendto(priv->sd, packet, length, 0, (struct sockaddr *)priv->device, sizeof(struct sockaddr_ll)); @@ -137,4 +240,10 @@ void sandbox_eth_raw_os_stop(struct eth_sandbox_raw_priv *priv) priv->device = NULL; close(priv->sd); priv->sd = -1; + if (priv->local) { + if (priv->local_bind_sd != -1) + close(priv->local_bind_sd); + priv->local_bind_sd = -1; + priv->local_bind_udp_port = 0; + } } diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 8002196..0eaa5a5 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -4,6 +4,10 @@ #address-cells = <1>; #size-cells = <0>;
+ aliases { + eth5 = "/eth@90000000"; + }; + chosen { stdout-path = "/serial"; }; @@ -192,4 +196,10 @@ reg = <0x80000000 0x1000>; host-raw-interface = "eth0"; }; + + eth@90000000 { + compatible = "sandbox,eth-raw"; + reg = <0x90000000 0x1000>; + host-raw-interface = "lo"; + }; }; diff --git a/arch/sandbox/include/asm/eth-raw-os.h b/arch/sandbox/include/asm/eth-raw-os.h index df60c4f..ed4b2e2 100644 --- a/arch/sandbox/include/asm/eth-raw-os.h +++ b/arch/sandbox/include/asm/eth-raw-os.h @@ -15,16 +15,24 @@ * * sd: socket descriptor - the open socket during a session * device: struct sockaddr_ll - the host interface packets move to/from + * local: 1 or 0 to select the local interface ('lo') or not + * local_bindsd: socket descriptor to prevent the kernel from sending + * a message to the server claiming the port is + * unreachable + * local_bind_udp_port: The UDP port number that we bound to */ struct eth_sandbox_raw_priv { int sd; void *device; + int local; + int local_bind_sd; + unsigned short local_bind_udp_port; };
int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, struct eth_sandbox_raw_priv *priv); int sandbox_eth_raw_os_send(void *packet, int length, - const struct eth_sandbox_raw_priv *priv); + struct eth_sandbox_raw_priv *priv); int sandbox_eth_raw_os_recv(void *packet, int *length, const struct eth_sandbox_raw_priv *priv); void sandbox_eth_raw_os_stop(struct eth_sandbox_raw_priv *priv); diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox index 9f5d3f7..08489e3 100644 --- a/board/sandbox/README.sandbox +++ b/board/sandbox/README.sandbox @@ -241,6 +241,28 @@ dhcp set serverip WWW.XXX.YYY.ZZZ tftpboot u-boot.bin
+The bridge also support (to a lesser extent) the localhost inderface, 'lo'. + +The 'lo' interface cannot use the RAW AF_PACKET API because the lo interface +doesn't support Ethernet-level traffic. It is a higher-level interface that is +expected only to be used at the AF_INET level of the API. As such, the most raw +we can get on that interface is the RAW AF_INET API on UDP. This allows us to +set the IP_HDRINCL option to include everything except the Ethernet header in +the packets we send and receive. + +Because only UDP is supported, ICMP traffic will not work, so expect that ping +commands will time out. + +The default device tree for sandbox includes an entry for lo on the sandbox +host machine whose alias is "eth5". The following is an example of a network +operation being tested on the lo interface. + +TFTP +.... + +set ethact eth5 +tftpboot u-boot.bin +
SPI Emulation ------------- diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c index 435b874..91da5f5 100644 --- a/drivers/net/sandbox-raw.c +++ b/drivers/net/sandbox-raw.c @@ -15,6 +15,8 @@
DECLARE_GLOBAL_DATA_PTR;
+static int reply_arp; +static IPaddr_t arp_ip;
static int sb_eth_raw_start(struct udevice *dev) { @@ -29,6 +31,11 @@ static int sb_eth_raw_start(struct udevice *dev) if (interface == NULL) return -EINVAL;
+ if (strcmp(interface, "lo") == 0) { + priv->local = 1; + setenv("ipaddr", "127.0.0.1"); + setenv("serverip", "127.0.0.1"); + } return sandbox_eth_raw_os_start(interface, pdata->enetaddr, priv); }
@@ -38,18 +45,78 @@ static int sb_eth_raw_send(struct udevice *dev, void *packet, int length)
debug("eth_sandbox_raw: Send packet %d\n", length);
+ if (priv->local) { + struct ethernet_hdr *eth = packet; + + if (ntohs(eth->et_protlen) == PROT_ARP) { + struct arp_hdr *arp = packet + ETHER_HDR_SIZE; + + /** + * localhost works on a higher-level API in Linux than + * ARP packets, so fake it + */ + arp_ip = NetReadIP(&arp->ar_tpa); + reply_arp = 1; + return 0; + } + packet += ETHER_HDR_SIZE; + length -= ETHER_HDR_SIZE; + } return sandbox_eth_raw_os_send(packet, length, priv); }
static int sb_eth_raw_recv(struct udevice *dev, uchar **packetp) { + struct eth_pdata *pdata = dev_get_platdata(dev); struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); - int retval; + int retval = 0; int length;
- retval = sandbox_eth_raw_os_recv(net_rx_packets[0], &length, priv); + if (reply_arp) { + struct arp_hdr *arp = (void *)net_rx_packets[0] + + ETHER_HDR_SIZE; + + /* + * Fake an ARP response. The u-boot network stack is sending an + * ARP request (to find the MAC address to address the actual + * packet to) and requires an ARP response to continue. Since + * this is the localhost interface, there is no Etherent level + * traffic at all, so there is no way to send an ARP request or + * to get a response. For this reason we fake the response to + * make the u-boot network stack happy. + */ + arp->ar_hrd = htons(ARP_ETHER); + arp->ar_pro = htons(PROT_IP); + arp->ar_hln = ARP_HLEN; + arp->ar_pln = ARP_PLEN; + arp->ar_op = htons(ARPOP_REPLY); + /* Any non-zero MAC address will work */ + memset(&arp->ar_sha, 0x01, ARP_HLEN); + /* Use whatever IP we were looking for (always 127.0.0.1?) */ + NetWriteIP(&arp->ar_spa, arp_ip); + memcpy(&arp->ar_tha, pdata->enetaddr, ARP_HLEN); + NetWriteIP(&arp->ar_tpa, NetOurIP); + length = ARP_HDR_SIZE; + } else { + /* If local, the Ethernet header won't be included; skip it */ + uchar *pktptr = priv->local ? + net_rx_packets[0] + ETHER_HDR_SIZE : net_rx_packets[0]; + + retval = sandbox_eth_raw_os_recv(pktptr, &length, priv); + }
if (!retval && length) { + if (priv->local) { + struct ethernet_hdr *eth = (void *)net_rx_packets[0]; + + /* Fill in enough of the missing Ethernet header */ + memcpy(eth->et_dest, pdata->enetaddr, ARP_HLEN); + memset(eth->et_src, 0x01, ARP_HLEN); + eth->et_protlen = htons(reply_arp ? PROT_ARP : PROT_IP); + reply_arp = 0; + length += ETHER_HDR_SIZE; + } + debug("eth_sandbox_raw: received packet %d\n", length); *packetp = net_rx_packets[0];

Take a pass at plumbing errors through to the users of the network stack
Currently only the start() function errors will be returned from NetLoop(). recv() tends not to have errors, so that is likely not worth adding. send() certainly can return errors, but this patch does not attempt to plumb them yet. halt() is not expected to error.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v6: None Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 3 ++- net/eth.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-------- net/net.c | 26 ++++++++++++++++++-------- test/dm/eth.c | 4 ++-- 4 files changed, 70 insertions(+), 19 deletions(-)
diff --git a/include/net.h b/include/net.h index baccd47..a60ff03 100644 --- a/include/net.h +++ b/include/net.h @@ -541,7 +541,7 @@ int NetLoop(enum proto_t); void NetStop(void);
/* Load failed. Start again. */ -void NetStartAgain(void); +int NetStartAgain(void);
/* Get size of the ethernet header when we send */ int NetEthHdrSize(void); @@ -611,6 +611,7 @@ static inline void net_set_state(enum net_loop_state state) /* Transmit a packet */ static inline void NetSendPacket(uchar *pkt, int len) { + /* Currently no way to return errors from eth_send() */ (void) eth_send(pkt, len); }
diff --git a/net/eth.c b/net/eth.c index b6c2af3..13b7723 100644 --- a/net/eth.c +++ b/net/eth.c @@ -98,6 +98,9 @@ struct eth_uclass_priv { struct udevice *current; };
+/* eth_errno - This stores the most recent failure code from DM functions */ +static int eth_errno; + static struct eth_uclass_priv *eth_get_uclass_priv(void) { struct uclass *uc; @@ -118,20 +121,32 @@ static void eth_set_current_to_next(void) uclass_first_device(UCLASS_ETH, &uc_priv->current); }
+/* + * Typically this will simply return the active device. + * In the case where the most recent active device was unset, this will attempt + * to return the first device. If that device doesn't exist or fails to probe, + * this function will return NULL. + */ struct udevice *eth_get_dev(void) { struct eth_uclass_priv *uc_priv;
uc_priv = eth_get_uclass_priv(); if (!uc_priv->current) - uclass_first_device(UCLASS_ETH, + eth_errno = uclass_first_device(UCLASS_ETH, &uc_priv->current); return uc_priv->current; }
+/* + * Typically this will just store a device pointer. + * In case it was not probed, we will attempt to do so. + * dev may be NULL to unset the active device. + */ static void eth_set_dev(struct udevice *dev) { - device_probe(dev); + if (dev && !device_active(dev)) + eth_errno = device_probe(dev); eth_get_uclass_priv()->current = dev; }
@@ -155,7 +170,14 @@ struct udevice *eth_get_dev_by_name(const char *devname)
uclass_get(UCLASS_ETH, &uc); uclass_foreach_dev(it, uc) { - /* We need the seq to be valid, so make sure it's probed */ + /* + * We need the seq to be valid, so try to probe it. + * If the probe fails, the seq will not match since it will be + * -1 instead of what we are looking for. + * We don't care about errors from probe here. Either they won't + * match an alias or it will match a literal name and we'll pick + * up the error when we try to probe again in eth_set_dev(). + */ device_probe(it); /* * Check for the name or the sequence number to match @@ -221,6 +243,7 @@ int eth_init(void) { struct udevice *current; struct udevice *old_current; + int ret = -ENODEV;
current = eth_get_dev(); if (!current) { @@ -243,22 +266,29 @@ int eth_init(void) else memset(pdata->enetaddr, 0, 6);
- if (eth_get_ops(current)->start(current) >= 0) { + ret = eth_get_ops(current)->start(current); + if (ret >= 0) { struct eth_device_priv *priv = current->uclass_priv;
priv->state = ETH_STATE_ACTIVE; return 0; } - } + } else + ret = eth_errno; + debug("FAIL\n");
- /* This will ensure the new "current" attempted to probe */ + /* + * If ethrotate is enabled, this will change "current", + * otherwise we will drop out of this while loop immediately + */ eth_try_another(0); + /* This will ensure the new "current" attempted to probe */ current = eth_get_dev(); } while (old_current != current);
- return -ENODEV; + return ret; }
void eth_halt(void) @@ -278,6 +308,7 @@ void eth_halt(void) int eth_send(void *packet, int length) { struct udevice *current; + int ret;
current = eth_get_dev(); if (!current) @@ -286,7 +317,12 @@ int eth_send(void *packet, int length) if (!device_active(current)) return -EINVAL;
- return eth_get_ops(current)->send(current, packet, length); + ret = eth_get_ops(current)->send(current, packet, length); + if (ret < 0) { + /* We cannot completely return the error at present */ + debug("%s: send() returned error %d\n", __func__, ret); + } + return ret; }
int eth_rx(void) @@ -313,6 +349,10 @@ int eth_rx(void) } if (ret == -EAGAIN) ret = 0; + if (ret < 0) { + /* We cannot completely return the error at present */ + debug("%s: recv() returned error %d\n", __func__, ret); + } return ret; }
diff --git a/net/net.c b/net/net.c index afec443..69f38f7 100644 --- a/net/net.c +++ b/net/net.c @@ -84,6 +84,7 @@ #include <common.h> #include <command.h> #include <environment.h> +#include <errno.h> #include <net.h> #if defined(CONFIG_STATUS_LED) #include <miiphy.h> @@ -333,7 +334,7 @@ void net_init(void)
int NetLoop(enum proto_t protocol) { - int ret = -1; + int ret = -EINVAL;
NetRestarted = 0; NetDevExists = 0; @@ -345,9 +346,10 @@ int NetLoop(enum proto_t protocol) if (eth_is_on_demand_init() || protocol != NETCONS) { eth_halt(); eth_set_current(); - if (eth_init() < 0) { + ret = eth_init(); + if (ret < 0) { eth_halt(); - return -1; + return ret; } } else eth_init_state_only(); @@ -370,7 +372,7 @@ restart: case 1: /* network not configured */ eth_halt(); - return -1; + return -ENODEV;
case 2: /* network device not configured */ @@ -484,6 +486,8 @@ restart: /* * Check the ethernet for a new packet. The ethernet * receive routine will process it. + * Most drivers return the most recent packet size, but not + * errors that may have happened. */ eth_rx();
@@ -537,7 +541,7 @@ restart: }
if (net_state == NETLOOP_FAIL) - NetStartAgain(); + ret = NetStartAgain();
switch (net_state) {
@@ -597,11 +601,12 @@ startAgainTimeout(void) net_set_state(NETLOOP_RESTART); }
-void NetStartAgain(void) +int NetStartAgain(void) { char *nretry; int retry_forever = 0; unsigned long retrycnt = 0; + int ret;
nretry = getenv("netretry"); if (nretry) { @@ -621,7 +626,11 @@ void NetStartAgain(void) if ((!retry_forever) && (NetTryCount >= retrycnt)) { eth_halt(); net_set_state(NETLOOP_FAIL); - return; + /* + * We don't provide a way for the protocol to return an error, + * but this is almost always the reason. + */ + return -ETIMEDOUT; }
NetTryCount++; @@ -630,7 +639,7 @@ void NetStartAgain(void) #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER) eth_try_another(!NetRestarted); #endif - eth_init(); + ret = eth_init(); if (NetRestartWrap) { NetRestartWrap = 0; if (NetDevExists) { @@ -642,6 +651,7 @@ void NetStartAgain(void) } else { net_set_state(NETLOOP_RESTART); } + return ret; }
/**********************************************************************/ diff --git a/test/dm/eth.c b/test/dm/eth.c index a0e9359..1923670 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -99,7 +99,7 @@ static int dm_test_eth_rotate(struct dm_test_state *dms) /* If ethrotate is no, then we should fail on a bad MAC */ setenv("ethact", "eth@10004000"); setenv("ethrotate", "no"); - ut_asserteq(-1, NetLoop(PING)); + ut_asserteq(-EINVAL, NetLoop(PING)); ut_asserteq_str("eth@10004000", getenv("ethact"));
/* Restore the env */ @@ -144,7 +144,7 @@ static int dm_test_net_retry(struct dm_test_state *dms) */ setenv("ethact", "eth@10004000"); setenv("netretry", "no"); - ut_asserteq(-1, NetLoop(PING)); + ut_asserteq(-ETIMEDOUT, NetLoop(PING)); ut_asserteq_str("eth@10004000", getenv("ethact"));
/* Restore the env */

+Tom, Vivek, Marek
Hi Joe,
On 11 March 2015 at 17:43, Joe Hershberger joe.hershberger@ni.com wrote:
Add support for the Ethernet MAC controllers. Phy support will come later.
Switching from RFC to a patch series to be applied to dm/master as a staging area for this series to make it happen more quickly when the window opens.
If desired, let me know which of the non-DM related prerequisite patches are wanted for this release.
I've added unit tests to verify functionality.
There is an additional driver for sandbox that bridges to the RAW Ethernet API in Linux which lets you test with real traffic. It now supports localhost as well (the 'lo' interface).
Changes in v6: -Add function comments -Addressed nits -Check array index bounds -Fix compile error on boards with CONFIG_API enabled -Fix compile errors for other boards due to removed parameters -Swallow -EAGAIN error in eth_rx() -Updated function documentation
Looks great! I'm going to pick this up for u-boot-dm/next soon, putting it on top of the PCI series.
Small USB update:
I've been fiddling with USB. I became inspired by your more ambitious conversion of Ethernet and decided to take USB a bit further (using driver model for all devices, not just controllers).
I have something I am becoming happy with but it does not support USB networking. Once I apply your series I will see if I can use driver model for that also either before or after I send the next version.
Regards, Simon

Hi Simon,
On Fri, Mar 20, 2015 at 7:17 AM, Simon Glass sjg@chromium.org wrote:
+Tom, Vivek, Marek
Hi Joe,
On 11 March 2015 at 17:43, Joe Hershberger joe.hershberger@ni.com wrote:
Add support for the Ethernet MAC controllers. Phy support will come
later.
Switching from RFC to a patch series to be applied to dm/master as a
staging
area for this series to make it happen more quickly when the window
opens.
If desired, let me know which of the non-DM related prerequisite
patches are
wanted for this release.
I've added unit tests to verify functionality.
There is an additional driver for sandbox that bridges to the RAW Ethernet API in Linux which lets you test with real traffic. It now supports localhost as well (the 'lo' interface).
Changes in v6: -Add function comments -Addressed nits -Check array index bounds -Fix compile error on boards with CONFIG_API enabled -Fix compile errors for other boards due to removed parameters -Swallow -EAGAIN error in eth_rx() -Updated function documentation
Looks great! I'm going to pick this up for u-boot-dm/next soon, putting it on top of the PCI series.
Excellent! I'm glad we were able to get this wrapped up before the merge window opened. :D
Small USB update:
I've been fiddling with USB. I became inspired by your more ambitious conversion of Ethernet and decided to take USB a bit further (using driver model for all devices, not just controllers).
Cool!
I have something I am becoming happy with but it does not support USB networking. Once I apply your series I will see if I can use driver model for that also either before or after I send the next version.
Awesome. I can't wait to get rid of usb_eth_initialize() and the usbethaddr in the env. It should fit very cleanly into the DM.
Thanks, -Joe

On Fri, Mar 20, 2015 at 06:17:50AM -0600, Simon Glass wrote:
+Tom, Vivek, Marek
Hi Joe,
On 11 March 2015 at 17:43, Joe Hershberger joe.hershberger@ni.com wrote:
Add support for the Ethernet MAC controllers. Phy support will come later.
Switching from RFC to a patch series to be applied to dm/master as a staging area for this series to make it happen more quickly when the window opens.
If desired, let me know which of the non-DM related prerequisite patches are wanted for this release.
I've added unit tests to verify functionality.
There is an additional driver for sandbox that bridges to the RAW Ethernet API in Linux which lets you test with real traffic. It now supports localhost as well (the 'lo' interface).
Changes in v6: -Add function comments -Addressed nits -Check array index bounds -Fix compile error on boards with CONFIG_API enabled -Fix compile errors for other boards due to removed parameters -Swallow -EAGAIN error in eth_rx() -Updated function documentation
Looks great! I'm going to pick this up for u-boot-dm/next soon, putting it on top of the PCI series.
Small USB update:
I've been fiddling with USB. I became inspired by your more ambitious conversion of Ethernet and decided to take USB a bit further (using driver model for all devices, not just controllers).
I have something I am becoming happy with but it does not support USB networking. Once I apply your series I will see if I can use driver model for that also either before or after I send the next version.
Nice! And please feel free to hassle me at ELC next week :)

Hi Tom,
On Fri, Mar 20, 2015 at 8:21 AM, Tom Rini trini@konsulko.com wrote:
On Fri, Mar 20, 2015 at 06:17:50AM -0600, Simon Glass wrote:
+Tom, Vivek, Marek
Hi Joe,
On 11 March 2015 at 17:43, Joe Hershberger joe.hershberger@ni.com
wrote:
Add support for the Ethernet MAC controllers. Phy support will come
later.
Switching from RFC to a patch series to be applied to dm/master as a
staging
area for this series to make it happen more quickly when the window
opens.
If desired, let me know which of the non-DM related prerequisite
patches are
wanted for this release.
I've added unit tests to verify functionality.
There is an additional driver for sandbox that bridges to the RAW Ethernet API in Linux which lets you test with real traffic. It now supports localhost as well (the 'lo' interface).
Changes in v6: -Add function comments -Addressed nits -Check array index bounds -Fix compile error on boards with CONFIG_API enabled -Fix compile errors for other boards due to removed parameters -Swallow -EAGAIN error in eth_rx() -Updated function documentation
Looks great! I'm going to pick this up for u-boot-dm/next soon, putting it on top of the PCI series.
Small USB update:
I've been fiddling with USB. I became inspired by your more ambitious conversion of Ethernet and decided to take USB a bit further (using driver model for all devices, not just controllers).
I have something I am becoming happy with but it does not support USB networking. Once I apply your series I will see if I can use driver model for that also either before or after I send the next version.
Nice! And please feel free to hassle me at ELC next week :)
Cool. I'll be there next week. Do you know who else will be there?
-Joe

On 20 March 2015 at 08:33, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Tom,
On Fri, Mar 20, 2015 at 8:21 AM, Tom Rini trini@konsulko.com wrote:
On Fri, Mar 20, 2015 at 06:17:50AM -0600, Simon Glass wrote:
+Tom, Vivek, Marek
Hi Joe,
On 11 March 2015 at 17:43, Joe Hershberger joe.hershberger@ni.com wrote:
Add support for the Ethernet MAC controllers. Phy support will come later.
Switching from RFC to a patch series to be applied to dm/master as a staging area for this series to make it happen more quickly when the window opens.
If desired, let me know which of the non-DM related prerequisite patches are wanted for this release.
I've added unit tests to verify functionality.
There is an additional driver for sandbox that bridges to the RAW Ethernet API in Linux which lets you test with real traffic. It now supports localhost as well (the 'lo' interface).
Changes in v6: -Add function comments -Addressed nits -Check array index bounds -Fix compile error on boards with CONFIG_API enabled -Fix compile errors for other boards due to removed parameters -Swallow -EAGAIN error in eth_rx() -Updated function documentation
Looks great! I'm going to pick this up for u-boot-dm/next soon, putting it on top of the PCI series.
Small USB update:
I've been fiddling with USB. I became inspired by your more ambitious conversion of Ethernet and decided to take USB a bit further (using driver model for all devices, not just controllers).
I have something I am becoming happy with but it does not support USB networking. Once I apply your series I will see if I can use driver model for that also either before or after I send the next version.
Nice! And please feel free to hassle me at ELC next week :)
Cool. I'll be there next week. Do you know who else will be there?
Not me this time.
Regards, Simon

Add support for the Ethernet MAC controllers. Phy support will come later.
Switching from RFC to a patch series to be applied to dm/master as a staging area for this series to make it happen more quickly when the window opens.
If desired, let me know which of the non-DM related prerequisite patches are wanted for this release.
I've added unit tests to verify functionality.
There is an additional driver for sandbox that bridges to the RAW Ethernet API in Linux which lets you test with real traffic. It now supports localhost as well (the 'lo' interface).
Changes in v7: -Fixed compile error in 4xx_enet.c
Changes in v6: -Add function comments -Addressed nits -Check array index bounds -Fix compile error on boards with CONFIG_API enabled -Fix compile errors for other boards due to removed parameters -Swallow -EAGAIN error in eth_rx() -Updated function documentation
Changes in v5: -Add a note to doc/README.drivers.eth about its obsolescence -Add details about lo support to the README -Added a comment about devname -Added a test for skipping un-probe-able devices -Added comments about test cases -Added fallback for setting promiscuous mode -Added help to Kconfig -Added help to the sandbox eth mock driver Kconfig entry -Added more details and examples in the README -Check for NULL when reading fdt for host interface -Check for malloc failure -Expanded the Kconfig help -Fix compile error on !DM_ETH -Fixed warning from missing declaration -Include new mapmem.h header -Moved dm/ header -Moved to a separate header mapmem.h -New to v5 -Only check for alias if the name is long enough -Remove cast of pointer passed to free -Remove socket timeout -Remove the empty sb_eth_raw_remove function -Return -errno in from send and recv -Return errno from recv -Separate init to 2 helper static functions -Set the socket to non-blocking -Simplify sandbox eth driver by switching from int array to byte array -Switch priv from packet buffer to a pointer to net_rx_packets[0] -Switched to function to control state of mock driver -Unmap memory for consistency -Use INADDR_LOOPBACK -Use a function call to change mock driver behavior -Use local var for priv in eth_get_dev() -Use more verbose comments -Use net_rx_packets instead of a stack buffer
Changes in v4: --Don't prevent eth_initialize on driver model --If current == NULL, always check if there is a device available in eth_get_dev --Include ethprime handling in eth_initialize --Look up MAC address in post-probe --Move env init call from uclass init to eth_initialize --Print the alias in eth_initialize --Use eth_initialize to probe all devices and write_hwaddr -Add a helper function for eth_uclass_priv -Add ability to disable ping reply in sandbox eth driver -Add comments to priv struct definition -Add documentation to the structures -Add eth_get_ops helper -Added comments to README.sandbox -Added support for the 'lo' network interface -Added testing for ethrotate -Change -1 returns to error constants -Change puts to printf -Clean up the interface to sandbox's eth-raw-os by passing priv to raw-os -Cleaned up sandbox EXTRA_ENV define -Cleanup var definition order -Fix compile regression in !DM_ETH case -Fixed the MAC address limitation (now all traffic uses MAC address from env) -Load from ethprime on eth_initialize() -Move os file to arch -Moved config to Kconfig -New to v4 -Redo the seq / probe implementation -Remove bd_t *bis from dm eth_ops init function -Remove checks for driver==NULL -Remove priv pointer in per-device priv struct (drivers already get their own directly from DM) -Removed checks on priv != NULL and added protection in uclass instead -Rename halt() to stop() in ops -Rename init() to start() in ops -Stop handling selecting a new "current" in pre-unbind as it will now work itself out by clearing the pointer -Updated expected behavior based on changes to the NetLoop -Use accessors for platdata and priv -Use only the seq from DM to find aliases
Changes in v3: --Fail init if not activated --Fail probe if ethaddr not set -Added 2 more ethaddr to sandbox -Added dm eth testing -Added support for aliases -Added support for ethprime -Added testing for netretry -Allow current eth dev to be NULL -Correct failure chaining from bind to probe to init -Correct the pre_unbind logic -Fixed blank line formatting for variable declaration -Made the os raw packet support for sandbox eth build and work. -Move the get_dev_by_* protos to also be !DM_ETH like the impl -Prevent a crash if memory is not allocated -Print which device in the debug write hwaddr -Reorder dm test makefile -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the previous selection
Changes in v2: -Added the raw packet proof-of-concept patch. -Cause an invalid name to fail binding -Change printfs to debug in sandbox driver -Changed eth_uclass_priv local var names to be uc_priv -Move fake hwaddr to the device tree -Move static data to priv -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()). -Rebase on top of dm/master -Remove unused priv struct for sandbox driver -Removed extra parentheses -Stop maintaining our own index and use DM seq now that it works for our needs -Update error codes -Updated comments
Joe Hershberger (27): test: dm: Reorder the objects to build common: Make sure arch-specific map_sysmem() is defined net: Provide a function to get the current MAC address net: Rename helper function to be more clear net: Remove unneeded "extern" in net.h net: Refactor in preparation for driver model net: Change return codes from net/eth.c to use errorno constants net: Use int instead of u8 for boolean flag net: Remove the bd* parameter from net stack functions net: Make netretry actually do something net: Access mapped physmem in net functions cmd: net: Clean up return codes dm: eth: Add basic driver model support to Ethernet stack net: Clean up network stack names used in DM drivers dm: eth: Pass the packet pointer as a parameter to recv sandbox: eth: Add network support to sandbox sandbox: eth: Add ARP and PING response to sandbox driver test: dm: eth: Add tests for the eth dm implementation dm: eth: Add support for aliases dm: eth: Add support for ethprime env var test: dm: eth: Add testing for ethrotate env var sandbox: eth: Add ability to disable ping reply in sandbox eth driver test: dm: net: Add a test of the netretry behavior sandbox: eth: Add a bridge to a real network for sandbox sandbox: Enable DHCP and IP defrag sandbox: eth: Add support for using the 'lo' interface net: Improve error handling
api/api_net.c | 2 +- arch/arm/lib/board.c | 2 +- arch/arm/lib/bootm.c | 1 + arch/avr32/lib/board.c | 2 +- arch/m68k/lib/board.c | 4 +- arch/mips/mach-au1x00/au1x00_eth.c | 2 +- arch/nds32/lib/board.c | 2 +- arch/openrisc/lib/board.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- arch/powerpc/lib/board.c | 2 +- arch/sandbox/Kconfig | 12 + arch/sandbox/cpu/Makefile | 10 + arch/sandbox/cpu/eth-raw-os.c | 249 +++++++++++++ arch/sandbox/dts/sandbox.dts | 21 ++ arch/sandbox/include/asm/eth-raw-os.h | 40 +++ arch/sandbox/include/asm/eth.h | 15 + arch/sh/lib/board.c | 2 +- arch/sparc/lib/board.c | 2 +- board/BuS/eb_cpux9k2/cpux9k2.c | 2 +- board/BuS/vl_ma2sc/vl_ma2sc.c | 2 +- board/atmel/at91sam9261ek/at91sam9261ek.c | 2 +- board/egnite/ethernut5/ethernut5.c | 2 +- board/ronetix/pm9261/pm9261.c | 2 +- board/ronetix/pm9g45/pm9g45.c | 2 +- board/sandbox/README.sandbox | 78 +++- common/board_f.c | 1 + common/board_r.c | 3 +- common/bootm.c | 1 + common/cmd_bdinfo.c | 2 + common/cmd_bootm.c | 1 + common/cmd_demo.c | 1 + common/cmd_fat.c | 1 + common/cmd_fdt.c | 1 + common/cmd_lzmadec.c | 1 + common/cmd_md5sum.c | 1 + common/cmd_mem.c | 1 + common/cmd_net.c | 45 ++- common/cmd_nvedit.c | 1 + common/cmd_pxe.c | 1 + common/cmd_sf.c | 1 + common/cmd_source.c | 1 + common/cmd_trace.c | 1 + common/cmd_ximg.c | 1 + common/hash.c | 1 + common/image-fdt.c | 1 + common/image-fit.c | 1 + common/image.c | 1 + common/iotrace.c | 1 + common/lcd.c | 1 + common/malloc_simple.c | 1 + common/spl/spl_net.c | 2 +- doc/README.drivers.eth | 6 + drivers/demo/demo-simple.c | 1 + drivers/i2c/i2c-uniphier-f.c | 1 + drivers/i2c/i2c-uniphier.c | 1 + drivers/mtd/spi/sf_probe.c | 1 + drivers/net/4xx_enet.c | 5 +- drivers/net/Kconfig | 42 +++ drivers/net/Makefile | 2 + drivers/net/netconsole.c | 4 +- drivers/net/sandbox-raw.c | 165 +++++++++ drivers/net/sandbox.c | 208 +++++++++++ drivers/serial/ns16550.c | 1 + drivers/serial/serial_uniphier.c | 1 + fs/fs.c | 1 + include/common.h | 17 - include/configs/sandbox.h | 25 +- include/dm/uclass-id.h | 1 + include/mapmem.h | 32 ++ include/net.h | 201 +++++++---- lib/trace.c | 1 + net/eth.c | 580 ++++++++++++++++++++++++++---- net/net.c | 67 ++-- net/nfs.c | 6 +- net/tftp.c | 6 +- test/compression.c | 1 + test/dm/Makefile | 5 +- test/dm/cmd_dm.c | 1 + test/dm/eth.c | 156 ++++++++ test/dm/test.dts | 20 ++ 82 files changed, 1869 insertions(+), 229 deletions(-) create mode 100644 arch/sandbox/cpu/eth-raw-os.c create mode 100644 arch/sandbox/include/asm/eth-raw-os.h create mode 100644 arch/sandbox/include/asm/eth.h create mode 100644 drivers/net/sandbox-raw.c create mode 100644 drivers/net/sandbox.c create mode 100644 include/mapmem.h create mode 100644 test/dm/eth.c

Signed-off-by: Joe Hershberger joe.hershberger@ni.com Acked-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: -Reorder dm test makefile
Changes in v2: None
test/dm/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/dm/Makefile b/test/dm/Makefile index 612aa95..1d9148f 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_DM_TEST) += core.o obj-$(CONFIG_DM_TEST) += ut.o ifneq ($(CONFIG_SANDBOX),) obj-$(CONFIG_DM_GPIO) += gpio.o -obj-$(CONFIG_DM_SPI) += spi.o -obj-$(CONFIG_DM_SPI_FLASH) += sf.o obj-$(CONFIG_DM_I2C) += i2c.o +obj-$(CONFIG_DM_SPI_FLASH) += sf.o +obj-$(CONFIG_DM_SPI) += spi.o endif

On 22 March 2015 at 16:08, Joe Hershberger joe.hershberger@ni.com wrote:
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Acked-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

In the case where the arch defines a custom map_sysmem(), make sure that including just mapmem.h is sufficient to have these functions as they are when the arch does not override it.
Also split the non-arch specific functions out of common.h
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: -Moved to a separate header mapmem.h
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
arch/arm/lib/bootm.c | 1 + common/board_f.c | 1 + common/board_r.c | 1 + common/bootm.c | 1 + common/cmd_bootm.c | 1 + common/cmd_demo.c | 1 + common/cmd_fat.c | 1 + common/cmd_fdt.c | 1 + common/cmd_lzmadec.c | 1 + common/cmd_md5sum.c | 1 + common/cmd_mem.c | 1 + common/cmd_nvedit.c | 1 + common/cmd_pxe.c | 1 + common/cmd_sf.c | 1 + common/cmd_source.c | 1 + common/cmd_trace.c | 1 + common/cmd_ximg.c | 1 + common/hash.c | 1 + common/image-fdt.c | 1 + common/image-fit.c | 1 + common/image.c | 1 + common/iotrace.c | 1 + common/lcd.c | 1 + common/malloc_simple.c | 1 + drivers/demo/demo-simple.c | 1 + drivers/i2c/i2c-uniphier-f.c | 1 + drivers/i2c/i2c-uniphier.c | 1 + drivers/mtd/spi/sf_probe.c | 1 + drivers/serial/ns16550.c | 1 + drivers/serial/serial_uniphier.c | 1 + fs/fs.c | 1 + include/common.h | 17 ----------------- include/mapmem.h | 32 ++++++++++++++++++++++++++++++++ lib/trace.c | 1 + test/compression.c | 1 + test/dm/cmd_dm.c | 1 + 36 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 include/mapmem.h
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index 2d6b676..b1bff8c 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -18,6 +18,7 @@ #include <u-boot/zlib.h> #include <asm/byteorder.h> #include <libfdt.h> +#include <mapmem.h> #include <fdt_support.h> #include <asm/bootm.h> #include <asm/secure.h> diff --git a/common/board_f.c b/common/board_f.c index 4d8b8a6..1b7e7d9 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -23,6 +23,7 @@ #include <i2c.h> #include <initcall.h> #include <logbuff.h> +#include <mapmem.h>
/* TODO: Can we move these into arch/ headers? */ #ifdef CONFIG_8xx diff --git a/common/board_r.c b/common/board_r.c index 4fcd4f6..af0f274 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -33,6 +33,7 @@ #endif #include <logbuff.h> #include <malloc.h> +#include <mapmem.h> #ifdef CONFIG_BITBANGMII #include <miiphy.h> #endif diff --git a/common/bootm.c b/common/bootm.c index 34f60bb..6842029 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -13,6 +13,7 @@ #include <fdt_support.h> #include <lmb.h> #include <malloc.h> +#include <mapmem.h> #include <asm/io.h> #include <linux/lzo.h> #include <lzma/LzmaTypes.h> diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 48199bf..b3d3968 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -16,6 +16,7 @@ #include <image.h> #include <lmb.h> #include <malloc.h> +#include <mapmem.h> #include <nand.h> #include <asm/byteorder.h> #include <linux/compiler.h> diff --git a/common/cmd_demo.c b/common/cmd_demo.c index 8a10bdf..209dc4a 100644 --- a/common/cmd_demo.c +++ b/common/cmd_demo.c @@ -9,6 +9,7 @@
#include <common.h> #include <dm-demo.h> +#include <mapmem.h> #include <asm/io.h>
struct udevice *demo_dev; diff --git a/common/cmd_fat.c b/common/cmd_fat.c index c00fb28..aae993d 100644 --- a/common/cmd_fat.c +++ b/common/cmd_fat.c @@ -14,6 +14,7 @@ #include <net.h> #include <ata.h> #include <asm/io.h> +#include <mapmem.h> #include <part.h> #include <fat.h> #include <fs.h> diff --git a/common/cmd_fdt.c b/common/cmd_fdt.c index 48b3e70..682b655 100644 --- a/common/cmd_fdt.c +++ b/common/cmd_fdt.c @@ -15,6 +15,7 @@ #include <asm/global_data.h> #include <libfdt.h> #include <fdt_support.h> +#include <mapmem.h> #include <asm/io.h>
#define MAX_LEVEL 32 /* how deeply nested we will go */ diff --git a/common/cmd_lzmadec.c b/common/cmd_lzmadec.c index 7b0b3fd..1ad9ed6 100644 --- a/common/cmd_lzmadec.c +++ b/common/cmd_lzmadec.c @@ -12,6 +12,7 @@
#include <common.h> #include <command.h> +#include <mapmem.h> #include <asm/io.h>
#include <lzma/LzmaTools.h> diff --git a/common/cmd_md5sum.c b/common/cmd_md5sum.c index d22ace5..23bb81e 100644 --- a/common/cmd_md5sum.c +++ b/common/cmd_md5sum.c @@ -10,6 +10,7 @@
#include <common.h> #include <command.h> +#include <mapmem.h> #include <u-boot/md5.h> #include <asm/io.h>
diff --git a/common/cmd_mem.c b/common/cmd_mem.c index bcb3ee3..66a41da 100644 --- a/common/cmd_mem.c +++ b/common/cmd_mem.c @@ -20,6 +20,7 @@ #endif #include <hash.h> #include <inttypes.h> +#include <mapmem.h> #include <watchdog.h> #include <asm/io.h> #include <linux/compiler.h> diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 855808c..be792ae 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -31,6 +31,7 @@ #include <search.h> #include <errno.h> #include <malloc.h> +#include <mapmem.h> #include <watchdog.h> #include <linux/stddef.h> #include <asm/byteorder.h> diff --git a/common/cmd_pxe.c b/common/cmd_pxe.c index 7e32c95..96f963d 100644 --- a/common/cmd_pxe.c +++ b/common/cmd_pxe.c @@ -8,6 +8,7 @@ #include <common.h> #include <command.h> #include <malloc.h> +#include <mapmem.h> #include <linux/string.h> #include <linux/ctype.h> #include <errno.h> diff --git a/common/cmd_sf.c b/common/cmd_sf.c index 5c788e9..01c37de 100644 --- a/common/cmd_sf.c +++ b/common/cmd_sf.c @@ -10,6 +10,7 @@ #include <div64.h> #include <dm.h> #include <malloc.h> +#include <mapmem.h> #include <spi.h> #include <spi_flash.h>
diff --git a/common/cmd_source.c b/common/cmd_source.c index 6881bc9..d2a881d 100644 --- a/common/cmd_source.c +++ b/common/cmd_source.c @@ -19,6 +19,7 @@ #include <command.h> #include <image.h> #include <malloc.h> +#include <mapmem.h> #include <asm/byteorder.h> #include <asm/io.h> #if defined(CONFIG_8xx) diff --git a/common/cmd_trace.c b/common/cmd_trace.c index 8c630e6..1e62a1a 100644 --- a/common/cmd_trace.c +++ b/common/cmd_trace.c @@ -6,6 +6,7 @@
#include <common.h> #include <command.h> +#include <mapmem.h> #include <trace.h> #include <asm/io.h>
diff --git a/common/cmd_ximg.c b/common/cmd_ximg.c index 64b9186..8b8645c 100644 --- a/common/cmd_ximg.c +++ b/common/cmd_ximg.c @@ -15,6 +15,7 @@ #include <common.h> #include <command.h> #include <image.h> +#include <mapmem.h> #include <watchdog.h> #if defined(CONFIG_BZIP2) #include <bzlib.h> diff --git a/common/hash.c b/common/hash.c index 9e9f84b..c94c98b 100644 --- a/common/hash.c +++ b/common/hash.c @@ -14,6 +14,7 @@ #include <common.h> #include <command.h> #include <malloc.h> +#include <mapmem.h> #include <hw_sha.h> #include <asm/io.h> #include <asm/errno.h> diff --git a/common/image-fdt.c b/common/image-fdt.c index d9e4728..7e2da7b 100644 --- a/common/image-fdt.c +++ b/common/image-fdt.c @@ -14,6 +14,7 @@ #include <errno.h> #include <image.h> #include <libfdt.h> +#include <mapmem.h> #include <asm/io.h>
#ifndef CONFIG_SYS_FDT_PAD diff --git a/common/image-fit.c b/common/image-fit.c index 778d2a1..4eb4d42 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -16,6 +16,7 @@ #else #include <common.h> #include <errno.h> +#include <mapmem.h> #include <asm/io.h> DECLARE_GLOBAL_DATA_PTR; #endif /* !USE_HOSTCC*/ diff --git a/common/image.c b/common/image.c index a911aa9..f3277c9 100644 --- a/common/image.c +++ b/common/image.c @@ -27,6 +27,7 @@
#include <environment.h> #include <image.h> +#include <mapmem.h>
#if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT) #include <libfdt.h> diff --git a/common/iotrace.c b/common/iotrace.c index ced426e..2725563 100644 --- a/common/iotrace.c +++ b/common/iotrace.c @@ -7,6 +7,7 @@ #define IOTRACE_IMPL
#include <common.h> +#include <mapmem.h> #include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR; diff --git a/common/lcd.c b/common/lcd.c index f33942c..6982759 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -15,6 +15,7 @@ #include <linux/types.h> #include <stdio_dev.h> #include <lcd.h> +#include <mapmem.h> #include <watchdog.h> #include <asm/unaligned.h> #include <splash.h> diff --git a/common/malloc_simple.c b/common/malloc_simple.c index 64ae036..d445199 100644 --- a/common/malloc_simple.c +++ b/common/malloc_simple.c @@ -8,6 +8,7 @@
#include <common.h> #include <malloc.h> +#include <mapmem.h> #include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR; diff --git a/drivers/demo/demo-simple.c b/drivers/demo/demo-simple.c index 2bcb7df..f069748 100644 --- a/drivers/demo/demo-simple.c +++ b/drivers/demo/demo-simple.c @@ -10,6 +10,7 @@ #include <common.h> #include <dm.h> #include <dm-demo.h> +#include <mapmem.h> #include <asm/io.h>
static int simple_hello(struct udevice *dev, int ch) diff --git a/drivers/i2c/i2c-uniphier-f.c b/drivers/i2c/i2c-uniphier-f.c index 6707edd..ffa6ce5 100644 --- a/drivers/i2c/i2c-uniphier-f.c +++ b/drivers/i2c/i2c-uniphier-f.c @@ -13,6 +13,7 @@ #include <dm/root.h> #include <i2c.h> #include <fdtdec.h> +#include <mapmem.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/i2c/i2c-uniphier.c b/drivers/i2c/i2c-uniphier.c index 64a9ed8..760457f 100644 --- a/drivers/i2c/i2c-uniphier.c +++ b/drivers/i2c/i2c-uniphier.c @@ -13,6 +13,7 @@ #include <dm/root.h> #include <i2c.h> #include <fdtdec.h> +#include <mapmem.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 4103723..ffc4caa 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -13,6 +13,7 @@ #include <errno.h> #include <fdtdec.h> #include <malloc.h> +#include <mapmem.h> #include <spi.h> #include <spi_flash.h> #include <asm/io.h> diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 03beab5..67b1d60 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -8,6 +8,7 @@ #include <dm.h> #include <errno.h> #include <fdtdec.h> +#include <mapmem.h> #include <ns16550.h> #include <serial.h> #include <watchdog.h> diff --git a/drivers/serial/serial_uniphier.c b/drivers/serial/serial_uniphier.c index a6bd27f..2a12250 100644 --- a/drivers/serial/serial_uniphier.c +++ b/drivers/serial/serial_uniphier.c @@ -10,6 +10,7 @@ #include <asm/errno.h> #include <dm/device.h> #include <dm/platform_data/serial-uniphier.h> +#include <mapmem.h> #include <serial.h> #include <fdtdec.h>
diff --git a/fs/fs.c b/fs/fs.c index 483273f..ac0897d 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -17,6 +17,7 @@ #include <config.h> #include <errno.h> #include <common.h> +#include <mapmem.h> #include <part.h> #include <ext4fs.h> #include <fat.h> diff --git a/include/common.h b/include/common.h index 77c55c6..3ccc6f3 100644 --- a/include/common.h +++ b/include/common.h @@ -845,23 +845,6 @@ int cpu_disable(int nr); int cpu_release(int nr, int argc, char * const argv[]); #endif
-/* Define a null map_sysmem() if the architecture doesn't use it */ -# ifndef CONFIG_ARCH_MAP_SYSMEM -static inline void *map_sysmem(phys_addr_t paddr, unsigned long len) -{ - return (void *)(uintptr_t)paddr; -} - -static inline void unmap_sysmem(const void *vaddr) -{ -} - -static inline phys_addr_t map_to_sysmem(const void *ptr) -{ - return (phys_addr_t)(uintptr_t)ptr; -} -# endif - #endif /* __ASSEMBLY__ */
#ifdef CONFIG_PPC diff --git a/include/mapmem.h b/include/mapmem.h new file mode 100644 index 0000000..42ef3e8 --- /dev/null +++ b/include/mapmem.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __MAPMEM_H +#define __MAPMEM_H + +/* Define a null map_sysmem() if the architecture doesn't use it */ +# ifdef CONFIG_ARCH_MAP_SYSMEM +#include <asm/io.h> +# else +static inline void *map_sysmem(phys_addr_t paddr, unsigned long len) +{ + return (void *)(uintptr_t)paddr; +} + +static inline void unmap_sysmem(const void *vaddr) +{ +} + +static inline phys_addr_t map_to_sysmem(const void *ptr) +{ + return (phys_addr_t)(uintptr_t)ptr; +} +# endif + +#endif /* __MAPMEM_H */ diff --git a/lib/trace.c b/lib/trace.c index 711e5b5..ad5e07b 100644 --- a/lib/trace.c +++ b/lib/trace.c @@ -5,6 +5,7 @@ */
#include <common.h> +#include <mapmem.h> #include <trace.h> #include <asm/io.h> #include <asm/sections.h> diff --git a/test/compression.c b/test/compression.c index ea2e4ad..7ef3a8c 100644 --- a/test/compression.c +++ b/test/compression.c @@ -10,6 +10,7 @@ #include <bootm.h> #include <command.h> #include <malloc.h> +#include <mapmem.h> #include <asm/io.h>
#include <u-boot/zlib.h> diff --git a/test/dm/cmd_dm.c b/test/dm/cmd_dm.c index 79a674e..195815e 100644 --- a/test/dm/cmd_dm.c +++ b/test/dm/cmd_dm.c @@ -10,6 +10,7 @@ #include <common.h> #include <dm.h> #include <malloc.h> +#include <mapmem.h> #include <errno.h> #include <asm/io.h> #include <dm/root.h>

On 22 March 2015 at 16:08, Joe Hershberger joe.hershberger@ni.com wrote:
In the case where the arch defines a custom map_sysmem(), make sure that including just mapmem.h is sufficient to have these functions as they are when the arch does not override it.
Also split the non-arch specific functions out of common.h
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

The current implementation exposes the eth_device struct to code that needs to access the MAC address. Add a wrapper function for this to abstract away the pointer for this operation.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v7: None Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None
arch/mips/mach-au1x00/au1x00_eth.c | 2 +- arch/powerpc/cpu/mpc8260/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc85xx/ether_fcc.c | 2 +- arch/powerpc/cpu/mpc8xx/scc.c | 2 +- include/net.h | 8 ++++++++ net/net.c | 2 +- 6 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/arch/mips/mach-au1x00/au1x00_eth.c b/arch/mips/mach-au1x00/au1x00_eth.c index 39c5b6b..a47f088 100644 --- a/arch/mips/mach-au1x00/au1x00_eth.c +++ b/arch/mips/mach-au1x00/au1x00_eth.c @@ -238,7 +238,7 @@ static int au1x00_init(struct eth_device* dev, bd_t * bd){ }
/* Put mac addr in little endian */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() *mac_addr_high = (ea[5] << 8) | (ea[4] ) ; *mac_addr_low = (ea[3] << 24) | (ea[2] << 16) | (ea[1] << 8) | (ea[0] ) ; diff --git a/arch/powerpc/cpu/mpc8260/ether_fcc.c b/arch/powerpc/cpu/mpc8260/ether_fcc.c index f9f15b5..f777ba1 100644 --- a/arch/powerpc/cpu/mpc8260/ether_fcc.c +++ b/arch/powerpc/cpu/mpc8260/ether_fcc.c @@ -299,7 +299,7 @@ static int fec_init(struct eth_device* dev, bd_t *bis) * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc85xx/ether_fcc.c b/arch/powerpc/cpu/mpc85xx/ether_fcc.c index 166dc9e..58d4bfb 100644 --- a/arch/powerpc/cpu/mpc85xx/ether_fcc.c +++ b/arch/powerpc/cpu/mpc85xx/ether_fcc.c @@ -338,7 +338,7 @@ static int fec_init(struct eth_device* dev, bd_t *bis) * it unique by setting a few bits in the upper byte of the * non-static part of the address. */ -#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/arch/powerpc/cpu/mpc8xx/scc.c b/arch/powerpc/cpu/mpc8xx/scc.c index 251966b..66e4014 100644 --- a/arch/powerpc/cpu/mpc8xx/scc.c +++ b/arch/powerpc/cpu/mpc8xx/scc.c @@ -339,7 +339,7 @@ static int scc_init (struct eth_device *dev, bd_t * bis) pram_ptr->sen_gaddr3 = 0x0; /* Group Address Filter 3 (unused) */ pram_ptr->sen_gaddr4 = 0x0; /* Group Address Filter 4 (unused) */
-#define ea eth_get_dev()->enetaddr +#define ea eth_get_ethaddr() pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4]; pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2]; pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0]; diff --git a/include/net.h b/include/net.h index 43e3d28..6c76976 100644 --- a/include/net.h +++ b/include/net.h @@ -111,6 +111,14 @@ struct eth_device *eth_get_dev(void) { return eth_current; } + +static inline unsigned char *eth_get_ethaddr(void) +{ + if (eth_current) + return eth_current->enetaddr; + return NULL; +} + extern struct eth_device *eth_get_dev_by_name(const char *devname); extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ extern int eth_get_dev_index(void); /* get the device index */ diff --git a/net/net.c b/net/net.c index b60ce62..4b3c90e 100644 --- a/net/net.c +++ b/net/net.c @@ -275,7 +275,7 @@ static void NetInitLoop(void) env_changed_id = env_id; } if (eth_get_dev()) - memcpy(NetOurEther, eth_get_dev()->enetaddr, 6); + memcpy(NetOurEther, eth_get_ethaddr(), 6);
return; }

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
The current implementation exposes the eth_device struct to code that needs to access the MAC address. Add a wrapper function for this to abstract away the pointer for this operation.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

Make it clear that the helper is checking the addr, not setting it.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v7: None Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None
net/eth.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/net/eth.c b/net/eth.c index eac4f7b..65e8c77 100644 --- a/net/eth.c +++ b/net/eth.c @@ -153,11 +153,6 @@ static void eth_current_changed(void) setenv("ethact", NULL); }
-static int eth_address_set(unsigned char *addr) -{ - return memcmp(addr, "\0\0\0\0\0\0", 6); -} - int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -166,9 +161,9 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
- if (eth_address_set(env_enetaddr)) { - if (eth_address_set(dev->enetaddr) && - memcmp(dev->enetaddr, env_enetaddr, 6)) { + if (!is_zero_ether_addr(env_enetaddr)) { + if (!is_zero_ether_addr(dev->enetaddr) && + memcmp(dev->enetaddr, env_enetaddr, 6)) { printf("\nWarning: %s MAC addresses don't match:\n", dev->name); printf("Address in SROM is %pM\n", @@ -183,7 +178,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, dev->enetaddr); printf("\nWarning: %s using MAC address from net device\n", dev->name); - } else if (!(eth_address_set(dev->enetaddr))) { + } else if (is_zero_ether_addr(dev->enetaddr)) { printf("\nError: %s address not set.\n", dev->name); return -EINVAL;

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
Make it clear that the helper is checking the addr, not setting it.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

Many of the functions in net.h were preceded extern needlessly. Removing them to limit the number of checkpatch.pl complaints.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: -Fix compile error on boards with CONFIG_API enabled
Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 90 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 45 insertions(+), 45 deletions(-)
diff --git a/include/net.h b/include/net.h index 6c76976..51ed5b0 100644 --- a/include/net.h +++ b/include/net.h @@ -97,11 +97,11 @@ struct eth_device { void *priv; };
-extern int eth_initialize(bd_t *bis); /* Initialize network subsystem */ -extern int eth_register(struct eth_device* dev);/* Register network device */ -extern int eth_unregister(struct eth_device *dev);/* Remove network device */ -extern void eth_try_another(int first_restart); /* Change the device */ -extern void eth_set_current(void); /* set nterface to ethcur var */ +int eth_initialize(bd_t *bis); /* Initialize network subsystem */ +int eth_register(struct eth_device *dev);/* Register network device */ +int eth_unregister(struct eth_device *dev);/* Remove network device */ +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */
/* get the current device MAC */ extern struct eth_device *eth_current; @@ -119,12 +119,12 @@ static inline unsigned char *eth_get_ethaddr(void) return NULL; }
-extern struct eth_device *eth_get_dev_by_name(const char *devname); -extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ -extern int eth_get_dev_index(void); /* get the device index */ -extern void eth_parse_enetaddr(const char *addr, uchar *enetaddr); -extern int eth_getenv_enetaddr(char *name, uchar *enetaddr); -extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr); +struct eth_device *eth_get_dev_by_name(const char *devname); +struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ +int eth_get_dev_index(void); /* get the device index */ +void eth_parse_enetaddr(const char *addr, uchar *enetaddr); +int eth_getenv_enetaddr(char *name, uchar *enetaddr); +int eth_setenv_enetaddr(char *name, const uchar *enetaddr);
/* * Get the hardware address for an ethernet interface . @@ -135,20 +135,20 @@ extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr); * Returns: * Return true if the address is valid. */ -extern int eth_getenv_enetaddr_by_index(const char *base_name, int index, - uchar *enetaddr); +int eth_getenv_enetaddr_by_index(const char *base_name, int index, + uchar *enetaddr);
-extern int usb_eth_initialize(bd_t *bi); -extern int eth_init(bd_t *bis); /* Initialize the device */ -extern int eth_send(void *packet, int length); /* Send a packet */ +int usb_eth_initialize(bd_t *bi); +int eth_init(bd_t *bis); /* Initialize the device */ +int eth_send(void *packet, int length); /* Send a packet */
#ifdef CONFIG_API -extern int eth_receive(void *packet, int length); /* Receive a packet*/ +int eth_receive(void *packet, int length); /* Receive a packet*/ extern void (*push_packet)(void *packet, int length); #endif -extern int eth_rx(void); /* Check for received packets */ -extern void eth_halt(void); /* stop SCC */ -extern char *eth_get_name(void); /* get name of current device */ +int eth_rx(void); /* Check for received packets */ +void eth_halt(void); /* stop SCC */ +char *eth_get_name(void); /* get name of current device */
/* Set active state */ static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) @@ -469,25 +469,25 @@ extern IPaddr_t Mcast_addr; #endif
/* Initialize the network adapter */ -extern void net_init(void); -extern int NetLoop(enum proto_t); +void net_init(void); +int NetLoop(enum proto_t);
/* Shutdown adapters and cleanup */ -extern void NetStop(void); +void NetStop(void);
/* Load failed. Start again. */ -extern void NetStartAgain(void); +void NetStartAgain(void);
/* Get size of the ethernet header when we send */ -extern int NetEthHdrSize(void); +int NetEthHdrSize(void);
/* Set ethernet header; returns the size of the header */ -extern int NetSetEther(uchar *, uchar *, uint); -extern int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot); +int NetSetEther(uchar *, uchar *, uint); +int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot);
/* Set IP header */ -extern void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source); -extern void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, +void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source); +void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, int sport, int len);
/** @@ -521,12 +521,12 @@ unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new_sum); int ip_checksum_ok(const void *addr, unsigned nbytes);
/* Callbacks */ -extern rxhand_f *net_get_udp_handler(void); /* Get UDP RX packet handler */ -extern void net_set_udp_handler(rxhand_f *); /* Set UDP RX packet handler */ -extern rxhand_f *net_get_arp_handler(void); /* Get ARP RX packet handler */ -extern void net_set_arp_handler(rxhand_f *); /* Set ARP RX packet handler */ -extern void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */ -extern void NetSetTimeout(ulong, thand_f *);/* Set timeout handler */ +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 */ +void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */ +void NetSetTimeout(ulong, thand_f *);/* Set timeout handler */
/* Network loop state */ enum net_loop_state { @@ -559,11 +559,11 @@ static inline void NetSendPacket(uchar *pkt, int len) * @param sport Source UDP port * @param payload_len Length of data after the UDP header */ -extern int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, +int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int payload_len);
/* Processes a received packet */ -extern void NetReceive(uchar *, int); +void NetReceive(uchar *, int);
#ifdef CONFIG_NETCONSOLE void NcStart(void); @@ -711,28 +711,28 @@ static inline void eth_random_addr(uchar *addr) }
/* Convert an IP address to a string */ -extern void ip_to_string(IPaddr_t x, char *s); +void ip_to_string(IPaddr_t x, char *s);
/* Convert a string to ip address */ -extern IPaddr_t string_to_ip(const char *s); +IPaddr_t string_to_ip(const char *s);
/* Convert a VLAN id to a string */ -extern void VLAN_to_string(ushort x, char *s); +void VLAN_to_string(ushort x, char *s);
/* Convert a string to a vlan id */ -extern ushort string_to_VLAN(const char *s); +ushort string_to_VLAN(const char *s);
/* read a VLAN id from an environment variable */ -extern ushort getenv_VLAN(char *); +ushort getenv_VLAN(char *);
/* copy a filename (allow for "..." notation, limit length) */ -extern void copy_filename(char *dst, const char *src, int size); +void copy_filename(char *dst, const char *src, int size);
/* get a random source port */ -extern unsigned int random_port(void); +unsigned int random_port(void);
/* Update U-Boot over TFTP */ -extern int update_tftp(ulong addr); +int update_tftp(ulong addr);
/**********************************************************************/

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
Many of the functions in net.h were preceded extern needlessly. Removing them to limit the number of checkpatch.pl complaints.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

Move some things around and organize things so that the driver model implementation will fit in more easily.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: -Fixed warning from missing declaration
Changes in v4: -Fix compile regression in !DM_ETH case
Changes in v3: -Move the get_dev_by_* protos to also be !DM_ETH like the impl
Changes in v2: None
include/net.h | 68 +++++++++++++++++++++++++------------------------- net/eth.c | 79 ++++++++++++++++++++++++++++++++--------------------------- 2 files changed, 78 insertions(+), 69 deletions(-)
diff --git a/include/net.h b/include/net.h index 51ed5b0..fdf6860 100644 --- a/include/net.h +++ b/include/net.h @@ -97,13 +97,9 @@ struct eth_device { void *priv; };
-int eth_initialize(bd_t *bis); /* Initialize network subsystem */ int eth_register(struct eth_device *dev);/* Register network device */ int eth_unregister(struct eth_device *dev);/* Remove network device */ -void eth_try_another(int first_restart); /* Change the device */ -void eth_set_current(void); /* set nterface to ethcur var */
-/* get the current device MAC */ extern struct eth_device *eth_current;
static inline __attribute__((always_inline)) @@ -111,7 +107,10 @@ struct eth_device *eth_get_dev(void) { return eth_current; } +struct eth_device *eth_get_dev_by_name(const char *devname); +struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */
+/* get the current device MAC */ static inline unsigned char *eth_get_ethaddr(void) { if (eth_current) @@ -119,8 +118,37 @@ static inline unsigned char *eth_get_ethaddr(void) return NULL; }
-struct eth_device *eth_get_dev_by_name(const char *devname); -struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ +/* Set active state */ +static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) +{ + eth_get_dev()->state = ETH_STATE_ACTIVE; + + return 0; +} +/* Set passive state */ +static inline __attribute__((always_inline)) void eth_halt_state_only(void) +{ + eth_get_dev()->state = ETH_STATE_PASSIVE; +} + +/* + * Set the hardware address for an ethernet interface based on 'eth%daddr' + * environment variable (or just 'ethaddr' if eth_number is 0). + * Args: + * base_name - base name for device (normally "eth") + * eth_number - value of %d (0 for first device of this type) + * Returns: + * 0 is success, non-zero is error status from driver. + */ +int eth_write_hwaddr(struct eth_device *dev, const char *base_name, + int eth_number); + +int usb_eth_initialize(bd_t *bi); + +int eth_initialize(bd_t *bis); /* Initialize network subsystem */ +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */ + int eth_get_dev_index(void); /* get the device index */ void eth_parse_enetaddr(const char *addr, uchar *enetaddr); int eth_getenv_enetaddr(char *name, uchar *enetaddr); @@ -138,7 +166,6 @@ int eth_setenv_enetaddr(char *name, const uchar *enetaddr); int eth_getenv_enetaddr_by_index(const char *base_name, int index, uchar *enetaddr);
-int usb_eth_initialize(bd_t *bi); int eth_init(bd_t *bis); /* Initialize the device */ int eth_send(void *packet, int length); /* Send a packet */
@@ -148,32 +175,7 @@ extern void (*push_packet)(void *packet, int length); #endif int eth_rx(void); /* Check for received packets */ void eth_halt(void); /* stop SCC */ -char *eth_get_name(void); /* get name of current device */ - -/* Set active state */ -static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) -{ - eth_get_dev()->state = ETH_STATE_ACTIVE; - - return 0; -} -/* Set passive state */ -static inline __attribute__((always_inline)) void eth_halt_state_only(void) -{ - eth_get_dev()->state = ETH_STATE_PASSIVE; -} - -/* - * Set the hardware address for an ethernet interface based on 'eth%daddr' - * environment variable (or just 'ethaddr' if eth_number is 0). - * Args: - * base_name - base name for device (normally "eth") - * eth_number - value of %d (0 for first device of this type) - * Returns: - * 0 is success, non-zero is error status from driver. - */ -int eth_write_hwaddr(struct eth_device *dev, const char *base_name, - int eth_number); +const char *eth_get_name(void); /* get name of current device */
#ifdef CONFIG_MCAST_TFTP int eth_mcast_join(IPaddr_t mcast_addr, u8 join); diff --git a/net/eth.c b/net/eth.c index 65e8c77..84919e0 100644 --- a/net/eth.c +++ b/net/eth.c @@ -55,6 +55,14 @@ static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index, return eth_setenv_enetaddr(enetvar, enetaddr); }
+static void eth_env_init(void) +{ + const char *s; + + s = getenv("bootfile"); + if (s != NULL) + copy_filename(BootFile, s, sizeof(BootFile)); +}
static int eth_mac_skip(int index) { @@ -64,6 +72,8 @@ static int eth_mac_skip(int index) return ((skip_state = getenv(enetvar)) != NULL); }
+static void eth_current_changed(void); + /* * CPU and board-specific Ethernet initializations. Aliased function * signals caller to move on @@ -87,6 +97,11 @@ static unsigned int eth_rcv_current, eth_rcv_last; static struct eth_device *eth_devices; struct eth_device *eth_current;
+static void eth_set_current_to_next(void) +{ + eth_current = eth_current->next; +} + struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -137,22 +152,6 @@ int eth_get_dev_index(void) return eth_current->index; }
-static void eth_current_changed(void) -{ - char *act = getenv("ethact"); - /* update current ethernet name */ - if (eth_current) { - if (act == NULL || strcmp(act, eth_current->name) != 0) - setenv("ethact", eth_current->name); - } - /* - * remove the variable completely if there is no active - * interface - */ - else if (act != NULL) - setenv("ethact", NULL); -} - int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -251,14 +250,6 @@ int eth_unregister(struct eth_device *dev) return 0; }
-static void eth_env_init(bd_t *bis) -{ - const char *s; - - if ((s = getenv("bootfile")) != NULL) - copy_filename(BootFile, s, sizeof(BootFile)); -} - int eth_initialize(bd_t *bis) { int num_devices = 0; @@ -274,7 +265,7 @@ int eth_initialize(bd_t *bis) phy_init(); #endif
- eth_env_init(bis); + eth_env_init();
/* * If board-specific initialization exists, call it. @@ -479,6 +470,22 @@ int eth_receive(void *packet, int length) } #endif /* CONFIG_API */
+static void eth_current_changed(void) +{ + char *act = getenv("ethact"); + /* update current ethernet name */ + if (eth_get_dev()) { + if (act == NULL || strcmp(act, eth_get_name()) != 0) + setenv("ethact", eth_get_name()); + } + /* + * remove the variable completely if there is no active + * interface + */ + else if (act != NULL) + setenv("ethact", NULL); +} + void eth_try_another(int first_restart) { static struct eth_device *first_failed; @@ -492,17 +499,17 @@ void eth_try_another(int first_restart) if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) return;
- if (!eth_current) + if (!eth_get_dev()) return;
if (first_restart) - first_failed = eth_current; + first_failed = eth_get_dev();
- eth_current = eth_current->next; + eth_set_current_to_next();
eth_current_changed();
- if (first_failed == eth_current) + if (first_failed == eth_get_dev()) NetRestartWrap = 1; }
@@ -513,7 +520,7 @@ void eth_set_current(void) struct eth_device *old_current; int env_id;
- if (!eth_current) /* XXX no current */ + if (!eth_get_dev()) /* XXX no current */ return;
env_id = get_env_id(); @@ -522,18 +529,18 @@ void eth_set_current(void) env_changed_id = env_id; } if (act != NULL) { - old_current = eth_current; + old_current = eth_get_dev(); do { - if (strcmp(eth_current->name, act) == 0) + if (strcmp(eth_get_name(), act) == 0) return; - eth_current = eth_current->next; - } while (old_current != eth_current); + eth_set_current_to_next(); + } while (old_current != eth_get_dev()); }
eth_current_changed(); }
-char *eth_get_name(void) +const char *eth_get_name(void) { - return eth_current ? eth_current->name : "unknown"; + return eth_get_dev() ? eth_get_dev()->name : "unknown"; }

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
Move some things around and organize things so that the driver model implementation will fit in more easily.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

Many functions returned -1 previously. Change them to return appropriate error codes.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: None Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
net/eth.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/net/eth.c b/net/eth.c index 84919e0..9ad15cd 100644 --- a/net/eth.c +++ b/net/eth.c @@ -227,7 +227,7 @@ int eth_unregister(struct eth_device *dev)
/* No device */ if (!eth_devices) - return -1; + return -ENODEV;
for (cur = eth_devices; cur->next != eth_devices && cur->next != dev; cur = cur->next) @@ -235,7 +235,7 @@ int eth_unregister(struct eth_device *dev)
/* Device not found */ if (cur->next != dev) - return -1; + return -ENODEV;
cur->next = dev->next;
@@ -368,7 +368,7 @@ int eth_init(bd_t *bis)
if (!eth_current) { puts("No ethernet found.\n"); - return -1; + return -ENODEV; }
/* Sync environment with network devices */ @@ -397,7 +397,7 @@ int eth_init(bd_t *bis) eth_try_another(0); } while (old_current != eth_current);
- return -1; + return -ETIMEDOUT; }
void eth_halt(void) @@ -413,7 +413,7 @@ void eth_halt(void) int eth_send(void *packet, int length) { if (!eth_current) - return -1; + return -ENODEV;
return eth_current->send(eth_current, packet, length); } @@ -421,7 +421,7 @@ int eth_send(void *packet, int length) int eth_rx(void) { if (!eth_current) - return -1; + return -ENODEV;
return eth_current->recv(eth_current); }

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
Many functions returned -1 previously. Change them to return appropriate error codes.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

On some archs masking the parameter is inefficient, so don't use u8.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: None Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
include/net.h | 2 +- net/eth.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/net.h b/include/net.h index fdf6860..cec5612 100644 --- a/include/net.h +++ b/include/net.h @@ -178,7 +178,7 @@ void eth_halt(void); /* stop SCC */ const char *eth_get_name(void); /* get name of current device */
#ifdef CONFIG_MCAST_TFTP -int eth_mcast_join(IPaddr_t mcast_addr, u8 join); +int eth_mcast_join(IPaddr_t mcast_addr, int join); u32 ether_crc(size_t len, unsigned char const *p); #endif
diff --git a/net/eth.c b/net/eth.c index 9ad15cd..b86994e 100644 --- a/net/eth.c +++ b/net/eth.c @@ -321,7 +321,7 @@ int eth_initialize(bd_t *bis) * mcast_addr: multicast ipaddr from which multicast Mac is made * join: 1=join, 0=leave. */ -int eth_mcast_join(IPaddr_t mcast_ip, u8 join) +int eth_mcast_join(IPaddr_t mcast_ip, int join) { u8 mcast_mac[6]; if (!eth_current || !eth_current->mcast)

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
On some archs masking the parameter is inefficient, so don't use u8.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

This value is not used by the network stack and is available in the global data, so stop passing it around. For the one legacy function that still expects it (init op on old Ethernet drivers) pass in the global pointer version directly to avoid changing that interface.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: -Fixed compile error in 4xx_enet.c
Changes in v6: -Fix compile errors for other boards due to removed parameters
Changes in v5: None Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
api/api_net.c | 2 +- arch/arm/lib/board.c | 2 +- arch/avr32/lib/board.c | 2 +- arch/m68k/lib/board.c | 4 ++-- arch/nds32/lib/board.c | 2 +- arch/openrisc/lib/board.c | 2 +- arch/powerpc/lib/board.c | 2 +- arch/sh/lib/board.c | 2 +- arch/sparc/lib/board.c | 2 +- board/BuS/eb_cpux9k2/cpux9k2.c | 2 +- board/BuS/vl_ma2sc/vl_ma2sc.c | 2 +- board/atmel/at91sam9261ek/at91sam9261ek.c | 2 +- board/egnite/ethernut5/ethernut5.c | 2 +- board/ronetix/pm9261/pm9261.c | 2 +- board/ronetix/pm9g45/pm9g45.c | 2 +- common/board_r.c | 2 +- common/spl/spl_net.c | 2 +- drivers/net/4xx_enet.c | 5 +++-- drivers/net/netconsole.c | 4 ++-- include/net.h | 6 +++--- net/eth.c | 12 +++++++----- net/net.c | 7 +++---- 22 files changed, 36 insertions(+), 34 deletions(-)
diff --git a/api/api_net.c b/api/api_net.c index 7b3805e..04e4f4a 100644 --- a/api/api_net.c +++ b/api/api_net.c @@ -37,7 +37,7 @@ int dev_open_net(void *cookie) if (!dev_valid_net(cookie)) return API_ENODEV;
- if (eth_init(gd->bd) < 0) + if (eth_init() < 0) return API_EIO;
return 0; diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index f606255..37ea6e9 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -644,7 +644,7 @@ void board_init_r(gd_t *id, ulong dest_addr) #endif #if defined(CONFIG_CMD_NET) puts("Net: "); - eth_initialize(gd->bd); + eth_initialize(); #if defined(CONFIG_RESET_PHY_R) debug("Reset Ethernet PHY\n"); reset_phy(); diff --git a/arch/avr32/lib/board.c b/arch/avr32/lib/board.c index 99aa96e..aacfcbf 100644 --- a/arch/avr32/lib/board.c +++ b/arch/avr32/lib/board.c @@ -244,7 +244,7 @@ void board_init_r(gd_t *new_gd, ulong dest_addr) #endif #if defined(CONFIG_CMD_NET) puts("Net: "); - eth_initialize(gd->bd); + eth_initialize(); #endif
#ifdef CONFIG_GENERIC_ATMEL_MCI diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c index 9caff73..c54a3f7 100644 --- a/arch/m68k/lib/board.c +++ b/arch/m68k/lib/board.c @@ -566,10 +566,10 @@ void board_init_r (gd_t *id, ulong dest_addr) #if defined(CONFIG_CMD_NET) WATCHDOG_RESET(); #if defined(FEC_ENET) - eth_init(bd); + eth_init(); #endif puts ("Net: "); - eth_initialize (bd); + eth_initialize(); #endif
#ifdef CONFIG_POST diff --git a/arch/nds32/lib/board.c b/arch/nds32/lib/board.c index 4c06a48..24a09bc 100644 --- a/arch/nds32/lib/board.c +++ b/arch/nds32/lib/board.c @@ -383,7 +383,7 @@ void board_init_r(gd_t *id, ulong dest_addr) #if defined(CONFIG_CMD_NET) puts("Net: ");
- eth_initialize(gd->bd); + eth_initialize(); #if defined(CONFIG_RESET_PHY_R) debug("Reset Ethernet PHY\n"); reset_phy(); diff --git a/arch/openrisc/lib/board.c b/arch/openrisc/lib/board.c index 2346685..c26cc8f 100644 --- a/arch/openrisc/lib/board.c +++ b/arch/openrisc/lib/board.c @@ -128,7 +128,7 @@ void board_init(void)
#if defined(CONFIG_CMD_NET) puts("NET: "); - eth_initialize(bd); + eth_initialize(); #endif
/* main_loop */ diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c index 91645d3..5ea29cc 100644 --- a/arch/powerpc/lib/board.c +++ b/arch/powerpc/lib/board.c @@ -890,7 +890,7 @@ void board_init_r(gd_t *id, ulong dest_addr) #if defined(CONFIG_CMD_NET) WATCHDOG_RESET(); puts("Net: "); - eth_initialize(bd); + eth_initialize(); #endif
#if defined(CONFIG_CMD_NET) && defined(CONFIG_RESET_PHY_R) diff --git a/arch/sh/lib/board.c b/arch/sh/lib/board.c index 1eb7afb..6dad3c7 100644 --- a/arch/sh/lib/board.c +++ b/arch/sh/lib/board.c @@ -178,7 +178,7 @@ void sh_generic_init(void) #endif #if defined(CONFIG_CMD_NET) puts("Net: "); - eth_initialize(gd->bd); + eth_initialize(); #endif /* CONFIG_CMD_NET */
while (1) { diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c index b311a94..d2ac6bc 100644 --- a/arch/sparc/lib/board.c +++ b/arch/sparc/lib/board.c @@ -351,7 +351,7 @@ void board_init_f(ulong bootflag) #if defined(CONFIG_CMD_NET) WATCHDOG_RESET(); puts("Net: "); - eth_initialize(bd); + eth_initialize(); #endif
#if defined(CONFIG_CMD_NET) && defined(CONFIG_RESET_PHY_R) diff --git a/board/BuS/eb_cpux9k2/cpux9k2.c b/board/BuS/eb_cpux9k2/cpux9k2.c index 76ad7c4..3880a06 100644 --- a/board/BuS/eb_cpux9k2/cpux9k2.c +++ b/board/BuS/eb_cpux9k2/cpux9k2.c @@ -111,7 +111,7 @@ int misc_init_r(void) void reset_phy(void) { udelay(10000); - eth_init(gd->bd); + eth_init(); } #endif
diff --git a/board/BuS/vl_ma2sc/vl_ma2sc.c b/board/BuS/vl_ma2sc/vl_ma2sc.c index da39c86..e4e1a85 100644 --- a/board/BuS/vl_ma2sc/vl_ma2sc.c +++ b/board/BuS/vl_ma2sc/vl_ma2sc.c @@ -280,7 +280,7 @@ void reset_phy(void) * Initialize ethernet HW addr prior to starting Linux, * needed for nfsroot */ - eth_init(gd->bd); + eth_init(); #endif } #endif diff --git a/board/atmel/at91sam9261ek/at91sam9261ek.c b/board/atmel/at91sam9261ek/at91sam9261ek.c index a301d72..5250474 100644 --- a/board/atmel/at91sam9261ek/at91sam9261ek.c +++ b/board/atmel/at91sam9261ek/at91sam9261ek.c @@ -275,7 +275,7 @@ void reset_phy(void) * Initialize ethernet HW addr prior to starting Linux, * needed for nfsroot */ - eth_init(gd->bd); + eth_init(); #endif } #endif diff --git a/board/egnite/ethernut5/ethernut5.c b/board/egnite/ethernut5/ethernut5.c index b45213c..67d3984 100644 --- a/board/egnite/ethernut5/ethernut5.c +++ b/board/egnite/ethernut5/ethernut5.c @@ -204,7 +204,7 @@ int board_eth_init(bd_t *bis) miiphy_write(devname, 0, MII_BMCR, BMCR_RESET); } /* Sync environment with network devices, needed for nfsroot. */ - return eth_init(gd->bd); + return eth_init(); } #endif
diff --git a/board/ronetix/pm9261/pm9261.c b/board/ronetix/pm9261/pm9261.c index 1f7679a..b96f745 100644 --- a/board/ronetix/pm9261/pm9261.c +++ b/board/ronetix/pm9261/pm9261.c @@ -288,7 +288,7 @@ void reset_phy(void) * Initialize ethernet HW addr prior to starting Linux, * needed for nfsroot */ - eth_init(gd->bd); + eth_init(); #endif } #endif diff --git a/board/ronetix/pm9g45/pm9g45.c b/board/ronetix/pm9g45/pm9g45.c index 15aa4ac..efc4133 100644 --- a/board/ronetix/pm9g45/pm9g45.c +++ b/board/ronetix/pm9g45/pm9g45.c @@ -166,7 +166,7 @@ void reset_phy(void) * Initialize ethernet HW addr prior to starting Linux, * needed for nfsroot */ - eth_init(gd->bd); + eth_init(); #endif } #endif diff --git a/common/board_r.c b/common/board_r.c index af0f274..b882d9b 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -585,7 +585,7 @@ static int initr_bbmii(void) static int initr_net(void) { puts("Net: "); - eth_initialize(gd->bd); + eth_initialize(); #if defined(CONFIG_RESET_PHY_R) debug("Reset Ethernet PHY\n"); reset_phy(); diff --git a/common/spl/spl_net.c b/common/spl/spl_net.c index ff53705..af4952f 100644 --- a/common/spl/spl_net.c +++ b/common/spl/spl_net.c @@ -21,7 +21,7 @@ void spl_net_load_image(const char *device) env_relocate(); setenv("autoload", "yes"); load_addr = CONFIG_SYS_TEXT_BASE - sizeof(struct image_header); - rv = eth_initialize(gd->bd); + rv = eth_initialize(); if (rv == 0) { printf("No Ethernet devices found\n"); hang(); diff --git a/drivers/net/4xx_enet.c b/drivers/net/4xx_enet.c index 381ec42..8023f3d 100644 --- a/drivers/net/4xx_enet.c +++ b/drivers/net/4xx_enet.c @@ -1728,10 +1728,11 @@ static void mal_err (struct eth_device *dev, unsigned long isr, mtdcr (MAL0_RXDEIR, 0x80000000);
#ifdef INFO_4XX_ENET - printf ("\nMAL error occured.... ISR = %lx UIC = = %lx MAL_DEF = %lx MAL_ERR= %lx \n", isr, uic, maldef, mal_errr); + printf("\nMAL error occured.... ISR = %lx UIC = = %lx MAL_DEF = %lx MAL_ERR= %lx\n", + isr, uic, maldef, mal_errr); #endif
- eth_init (hw_p->bis); /* start again... */ + eth_init(); /* start again... */ }
/*-----------------------------------------------------------------------------+ diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 677c89f..87cea7a 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -193,11 +193,11 @@ static void nc_send_packet(const char *buf, int len)
if (eth->state != ETH_STATE_ACTIVE) { if (eth_is_on_demand_init()) { - if (eth_init(gd->bd) < 0) + if (eth_init() < 0) return; eth_set_last_protocol(NETCONS); } else - eth_init_state_only(gd->bd); + eth_init_state_only();
inited = 1; } diff --git a/include/net.h b/include/net.h index cec5612..ae0f31a 100644 --- a/include/net.h +++ b/include/net.h @@ -119,7 +119,7 @@ static inline unsigned char *eth_get_ethaddr(void) }
/* Set active state */ -static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) +static inline __attribute__((always_inline)) int eth_init_state_only(void) { eth_get_dev()->state = ETH_STATE_ACTIVE;
@@ -145,7 +145,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
int usb_eth_initialize(bd_t *bi);
-int eth_initialize(bd_t *bis); /* Initialize network subsystem */ +int eth_initialize(void); /* Initialize network subsystem */ void eth_try_another(int first_restart); /* Change the device */ void eth_set_current(void); /* set nterface to ethcur var */
@@ -166,7 +166,7 @@ int eth_setenv_enetaddr(char *name, const uchar *enetaddr); int eth_getenv_enetaddr_by_index(const char *base_name, int index, uchar *enetaddr);
-int eth_init(bd_t *bis); /* Initialize the device */ +int eth_init(void); /* Initialize the device */ int eth_send(void *packet, int length); /* Send a packet */
#ifdef CONFIG_API diff --git a/net/eth.c b/net/eth.c index b86994e..66ecb79 100644 --- a/net/eth.c +++ b/net/eth.c @@ -12,6 +12,8 @@ #include <phy.h> #include <asm/errno.h>
+DECLARE_GLOBAL_DATA_PTR; + void eth_parse_enetaddr(const char *addr, uchar *enetaddr) { char *end; @@ -250,7 +252,7 @@ int eth_unregister(struct eth_device *dev) return 0; }
-int eth_initialize(bd_t *bis) +int eth_initialize(void) { int num_devices = 0; eth_devices = NULL; @@ -272,10 +274,10 @@ int eth_initialize(bd_t *bis) * If not, call a CPU-specific one */ if (board_eth_init != __def_eth_init) { - if (board_eth_init(bis) < 0) + if (board_eth_init(gd->bd) < 0) printf("Board Net Initialization Failed\n"); } else if (cpu_eth_init != __def_eth_init) { - if (cpu_eth_init(bis) < 0) + if (cpu_eth_init(gd->bd) < 0) printf("CPU Net Initialization Failed\n"); } else printf("Net Initialization Skipped\n"); @@ -362,7 +364,7 @@ u32 ether_crc(size_t len, unsigned char const *p) #endif
-int eth_init(bd_t *bis) +int eth_init(void) { struct eth_device *old_current, *dev;
@@ -387,7 +389,7 @@ int eth_init(bd_t *bis) do { debug("Trying %s\n", eth_current->name);
- if (eth_current->init(eth_current, bis) >= 0) { + if (eth_current->init(eth_current, gd->bd) >= 0) { eth_current->state = ETH_STATE_ACTIVE;
return 0; diff --git a/net/net.c b/net/net.c index 4b3c90e..e5ab07c 100644 --- a/net/net.c +++ b/net/net.c @@ -324,7 +324,6 @@ void net_init(void)
int NetLoop(enum proto_t protocol) { - bd_t *bd = gd->bd; int ret = -1;
NetRestarted = 0; @@ -337,12 +336,12 @@ int NetLoop(enum proto_t protocol) if (eth_is_on_demand_init() || protocol != NETCONS) { eth_halt(); eth_set_current(); - if (eth_init(bd) < 0) { + if (eth_init() < 0) { eth_halt(); return -1; } } else - eth_init_state_only(bd); + eth_init_state_only();
restart: #ifdef CONFIG_USB_KEYBOARD @@ -618,7 +617,7 @@ void NetStartAgain(void) #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER) eth_try_another(!NetRestarted); #endif - eth_init(gd->bd); + eth_init(); if (NetRestartWrap) { NetRestartWrap = 0; if (NetDevExists) {

Hi Joe,
On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
This value is not used by the network stack and is available in the global data, so stop passing it around. For the one legacy function that still expects it (init op on old Ethernet drivers) pass in the global pointer version directly to avoid changing that interface.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reported-by: Simon Glass sjg@chromium.org Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: -Fixed compile error in 4xx_enet.c
This fixes the compile error but introduced a warning. However the fix was trivial (just removing a variable declaration). So I applied that fix to your patch.
Applied to u-boot-dm/next, thanks!

netretry previously would only retry in one specific case (your MAC address is not set) and no other. This is basically useless. In the DM implementation for eth it turns this into a completely useless case since an un-configured MAC address results in not even entering the NetLoop. The behavior is now changed to retry any failed command (rotating through the eth adapters if ethrotate != no).
It also defaulted to retry forever. It is now changed to default to not retry
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: None Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
net/net.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/net/net.c b/net/net.c index e5ab07c..37b4aab 100644 --- a/net/net.c +++ b/net/net.c @@ -527,6 +527,8 @@ restart: (*x)(); }
+ if (net_state == NETLOOP_FAIL) + NetStartAgain();
switch (net_state) {
@@ -602,8 +604,10 @@ void NetStartAgain(void) retrycnt = 1; else retrycnt = simple_strtoul(nretry, NULL, 0); - } else - retry_forever = 1; + } else { + retrycnt = 0; + retry_forever = 0; + }
if ((!retry_forever) && (NetTryCount >= retrycnt)) { eth_halt();

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
netretry previously would only retry in one specific case (your MAC address is not set) and no other. This is basically useless. In the DM implementation for eth it turns this into a completely useless case since an un-configured MAC address results in not even entering the NetLoop. The behavior is now changed to retry any failed command (rotating through the eth adapters if ethrotate != no).
It also defaulted to retry forever. It is now changed to default to not retry
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

Previously the net functions would access memory assuming physmem did not need to be mapped. In sandbox, that's not the case.
Now we map the physmem specified by the user in loadaddr to the buffer that represents that space.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: -Include new mapmem.h header -Unmap memory for consistency
Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
net/nfs.c | 6 +++++- net/tftp.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/net/nfs.c b/net/nfs.c index 381b75f..8e05ae5 100644 --- a/net/nfs.c +++ b/net/nfs.c @@ -26,6 +26,7 @@ #include <command.h> #include <net.h> #include <malloc.h> +#include <mapmem.h> #include "nfs.h" #include "bootp.h"
@@ -93,7 +94,10 @@ store_block(uchar *src, unsigned offset, unsigned len) } else #endif /* CONFIG_SYS_DIRECT_FLASH_NFS */ { - (void)memcpy((void *)(load_addr + offset), src, len); + void *ptr = map_sysmem(load_addr + offset, len); + + memcpy(ptr, src, len); + unmap_sysmem(ptr); }
if (NetBootFileXferSize < (offset+len)) diff --git a/net/tftp.c b/net/tftp.c index 0a2c533..51c67be 100644 --- a/net/tftp.c +++ b/net/tftp.c @@ -8,6 +8,7 @@
#include <common.h> #include <command.h> +#include <mapmem.h> #include <net.h> #include "tftp.h" #include "bootp.h" @@ -184,7 +185,10 @@ store_block(int block, uchar *src, unsigned len) } else #endif /* CONFIG_SYS_DIRECT_FLASH_TFTP */ { - (void)memcpy((void *)(load_addr + offset), src, len); + void *ptr = map_sysmem(load_addr + offset, len); + + memcpy(ptr, src, len); + unmap_sysmem(ptr); } #ifdef CONFIG_MCAST_TFTP if (Multicast)

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
Previously the net functions would access memory assuming physmem did not need to be mapped. In sandbox, that's not the case.
Now we map the physmem specified by the user in loadaddr to the buffer that represents that space.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

The return codes in common/cmd_net.c had a number of inconsistencies. Update them to all use the enum from command.h
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
common/cmd_net.c | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-)
diff --git a/common/cmd_net.c b/common/cmd_net.c index 09489d4..3f52edc 100644 --- a/common/cmd_net.c +++ b/common/cmd_net.c @@ -44,10 +44,7 @@ U_BOOT_CMD( #ifdef CONFIG_CMD_TFTPPUT int do_tftpput(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - int ret; - - ret = netboot_common(TFTPPUT, cmdtp, argc, argv); - return ret; + return netboot_common(TFTPPUT, cmdtp, argc, argv); }
U_BOOT_CMD( @@ -217,7 +214,7 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc, if (strict_strtoul(argv[1], 16, &save_addr) < 0 || strict_strtoul(argv[2], 16, &save_size) < 0) { printf("Invalid address/size\n"); - return cmd_usage(cmdtp); + return CMD_RET_USAGE; } copy_filename(BootFile, argv[3], sizeof(BootFile)); break; @@ -230,7 +227,7 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,
if ((size = NetLoop(proto)) < 0) { bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); - return 1; + return CMD_RET_FAILURE; } bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);
@@ -240,7 +237,7 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc, /* done if no file was loaded (no errors though) */ if (size == 0) { bootstage_error(BOOTSTAGE_ID_NET_LOADED); - return 0; + return CMD_RET_SUCCESS; }
/* flush cache */ @@ -250,10 +247,10 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,
rcode = bootm_maybe_autostart(cmdtp, argv[0]);
- if (rcode < 0) - bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR); - else + if (rcode == CMD_RET_SUCCESS) bootstage_mark(BOOTSTAGE_ID_NET_DONE); + else + bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR); return rcode; }
@@ -261,7 +258,7 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc, static int do_ping(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { if (argc < 2) - return -1; + return CMD_RET_USAGE;
NetPingIP = string_to_ip(argv[1]); if (NetPingIP == 0) @@ -269,12 +266,12 @@ static int do_ping(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
if (NetLoop(PING) < 0) { printf("ping failed; host %s is not alive\n", argv[1]); - return 1; + return CMD_RET_FAILURE; }
printf("host %s is alive\n", argv[1]);
- return 0; + return CMD_RET_SUCCESS; }
U_BOOT_CMD( @@ -313,12 +310,12 @@ int do_cdp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) r = NetLoop(CDP); if (r < 0) { printf("cdp failed; perhaps not a CISCO switch?\n"); - return 1; + return CMD_RET_FAILURE; }
cdp_update_env();
- return 0; + return CMD_RET_SUCCESS; }
U_BOOT_CMD( @@ -337,13 +334,13 @@ int do_sntp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) NetNtpServerIP = getenv_IPaddr("ntpserverip"); if (NetNtpServerIP == 0) { printf("ntpserverip not set\n"); - return (1); + return CMD_RET_FAILURE; } } else { NetNtpServerIP = string_to_ip(argv[1]); if (NetNtpServerIP == 0) { printf("Bad NTP server IP address\n"); - return (1); + return CMD_RET_FAILURE; } }
@@ -356,10 +353,10 @@ int do_sntp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (NetLoop(SNTP) < 0) { printf("SNTP failed: host %pI4 not responding\n", &NetNtpServerIP); - return 1; + return CMD_RET_FAILURE; }
- return 0; + return CMD_RET_SUCCESS; }
U_BOOT_CMD( @@ -389,7 +386,7 @@ int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) */ if (strlen(argv[1]) >= 255) { printf("dns error: hostname too long\n"); - return 1; + return CMD_RET_FAILURE; }
NetDNSResolve = argv[1]; @@ -401,10 +398,10 @@ int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
if (NetLoop(DNS) < 0) { printf("dns lookup of %s failed, check setup\n", argv[1]); - return 1; + return CMD_RET_FAILURE; }
- return 0; + return CMD_RET_SUCCESS; }
U_BOOT_CMD( @@ -422,7 +419,7 @@ static int do_link_local(cmd_tbl_t *cmdtp, int flag, int argc, char tmp[22];
if (NetLoop(LINKLOCAL) < 0) - return 1; + return CMD_RET_FAILURE;
NetOurGatewayIP = 0; ip_to_string(NetOurGatewayIP, tmp); @@ -435,7 +432,7 @@ static int do_link_local(cmd_tbl_t *cmdtp, int flag, int argc, setenv("ipaddr", tmp); setenv("llipaddr", tmp); /* store this for next time */
- return 0; + return CMD_RET_SUCCESS; }
U_BOOT_CMD(

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
The return codes in common/cmd_net.c had a number of inconsistencies. Update them to all use the enum from command.h
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

First just add support for MAC drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: -Add a note to doc/README.drivers.eth about its obsolescence -Expanded the Kconfig help -Moved dm/ header -Use local var for priv in eth_get_dev()
Changes in v4: --Don't prevent eth_initialize on driver model --If current == NULL, always check if there is a device available in eth_get_dev --Include ethprime handling in eth_initialize --Look up MAC address in post-probe --Move env init call from uclass init to eth_initialize --Print the alias in eth_initialize --Use eth_initialize to probe all devices and write_hwaddr -Add a helper function for eth_uclass_priv -Add documentation to the structures -Add eth_get_ops helper -Change -1 returns to error constants -Change puts to printf -Redo the seq / probe implementation -Remove bd_t *bis from dm eth_ops init function -Remove checks for driver==NULL -Remove priv pointer in per-device priv struct (drivers already get their own directly from DM) -Rename halt() to stop() in ops -Rename init() to start() in ops -Stop handling selecting a new "current" in pre-unbind as it will now work itself out by clearing the pointer
Changes in v3: --Fail init if not activated --Fail probe if ethaddr not set -Allow current eth dev to be NULL -Correct failure chaining from bind to probe to init -Correct the pre_unbind logic -Fixed blank line formatting for variable declaration -Update ethaddr from env unconditionally on init -Use set current to select the current device regardless of the previous selection
Changes in v2: -Cause an invalid name to fail binding -Changed eth_uclass_priv local var names to be uc_priv -Move the hwaddr to platdata so that its memory is allocated at bind when we need it -Prevent device from being probed before used by a command (i.e. before eth_init()). -Rebase on top of dm/master -Removed extra parentheses -Stop maintaining our own index and use DM seq now that it works for our needs -Update error codes -Updated comments
common/cmd_bdinfo.c | 2 + doc/README.drivers.eth | 6 + drivers/net/Kconfig | 9 ++ include/dm/uclass-id.h | 1 + include/net.h | 52 ++++++++ net/eth.c | 346 ++++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 410 insertions(+), 6 deletions(-)
diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index aa81da2..b4cce25 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -34,6 +34,7 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); }
+#ifndef CONFIG_DM_ETH __maybe_unused static void print_eths(void) { @@ -52,6 +53,7 @@ static void print_eths(void) printf("current eth = %s\n", eth_get_name()); printf("ip_addr = %s\n", getenv("ipaddr")); } +#endif
__maybe_unused static void print_lnum(const char *name, unsigned long long value) diff --git a/doc/README.drivers.eth b/doc/README.drivers.eth index eb83038..98728bc 100644 --- a/doc/README.drivers.eth +++ b/doc/README.drivers.eth @@ -1,3 +1,9 @@ +!!! WARNING !!! + +This guide describes to the old way of doing things. No new Ethernet drivers +should be implemented this way. All new drivers should be written against the +U-Boot core driver model. See doc/driver-model/README.txt + ----------------------- Ethernet Driver Guide ----------------------- diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e69de29..94cf099 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -0,0 +1,9 @@ +config DM_ETH + bool "Enable Driver Model for Ethernet drivers" + depends on DM + help + Enable driver model for Ethernet. + + The eth_*() interface will be implemented by the UC_ETH class + This is currently implemented in net/eth.c + Look in include/net.h for details. diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 91bb90d..ad96682 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -34,6 +34,7 @@ enum uclass_id { UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */ + UCLASS_ETH, /* Ethernet device */
UCLASS_COUNT, UCLASS_INVALID = -1, diff --git a/include/net.h b/include/net.h index ae0f31a..fff82cb 100644 --- a/include/net.h +++ b/include/net.h @@ -78,6 +78,57 @@ enum eth_state_t { ETH_STATE_ACTIVE };
+#ifdef CONFIG_DM_ETH +/** + * struct eth_pdata - Platform data for Ethernet MAC controllers + * + * @iobase: The base address of the hardware registers + * @enetaddr: The Ethernet MAC address that is loaded from EEPROM or env + */ +struct eth_pdata { + phys_addr_t iobase; + unsigned char enetaddr[6]; +}; + +/** + * struct eth_ops - functions of Ethernet MAC controllers + * + * start: Prepare the hardware to send and receive packets + * send: Send the bytes passed in "packet" as a packet on the wire + * recv: Check if the hardware received a packet. Call the network stack if so + * stop: Stop the hardware from looking for packets - may be called even if + * state == PASSIVE + * mcast: Join or leave a multicast group (for TFTP) - optional + * write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux + * on some platforms like ARM). This function expects the + * eth_pdata::enetaddr field to be populated - optional + * read_rom_hwaddr: Some devices have a backup of the MAC address stored in a + * ROM on the board. This is how the driver should expose it + * to the network stack. This function should fill in the + * eth_pdata::enetaddr field - optional + */ +struct eth_ops { + int (*start)(struct udevice *dev); + int (*send)(struct udevice *dev, void *packet, int length); + int (*recv)(struct udevice *dev); + void (*stop)(struct udevice *dev); +#ifdef CONFIG_MCAST_TFTP + int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join); +#endif + int (*write_hwaddr)(struct udevice *dev); + int (*read_rom_hwaddr)(struct udevice *dev); +}; + +#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops) + +struct udevice *eth_get_dev(void); /* get the current device */ +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ +/* Used only when NetConsole is enabled */ +int eth_init_state_only(void); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ +#endif + +#ifndef CONFIG_DM_ETH struct eth_device { char name[16]; unsigned char enetaddr[6]; @@ -144,6 +195,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number);
int usb_eth_initialize(bd_t *bi); +#endif
int eth_initialize(void); /* Initialize network subsystem */ void eth_try_another(int first_restart); /* Change the device */ diff --git a/net/eth.c b/net/eth.c index 66ecb79..1abf027 100644 --- a/net/eth.c +++ b/net/eth.c @@ -1,16 +1,19 @@ /* - * (C) Copyright 2001-2010 + * (C) Copyright 2001-2015 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Joe Hershberger, National Instruments * * SPDX-License-Identifier: GPL-2.0+ */
#include <common.h> #include <command.h> +#include <dm.h> #include <net.h> #include <miiphy.h> #include <phy.h> #include <asm/errno.h> +#include <dm/device-internal.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -76,6 +79,339 @@ static int eth_mac_skip(int index)
static void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH +/** + * struct eth_device_priv - private structure for each Ethernet device + * + * @state: The state of the Ethernet MAC driver (defined by enum eth_state_t) + */ +struct eth_device_priv { + enum eth_state_t state; +}; + +/** + * struct eth_uclass_priv - The structure attached to the uclass itself + * + * @current: The Ethernet device that the network functions are using + */ +struct eth_uclass_priv { + struct udevice *current; +}; + +static struct eth_uclass_priv *eth_get_uclass_priv(void) +{ + struct uclass *uc; + + uclass_get(UCLASS_ETH, &uc); + assert(uc); + return uc->priv; +} + +static void eth_set_current_to_next(void) +{ + struct eth_uclass_priv *uc_priv; + + uc_priv = eth_get_uclass_priv(); + if (uc_priv->current) + uclass_next_device(&uc_priv->current); + if (!uc_priv->current) + uclass_first_device(UCLASS_ETH, &uc_priv->current); +} + +struct udevice *eth_get_dev(void) +{ + struct eth_uclass_priv *uc_priv; + + uc_priv = eth_get_uclass_priv(); + if (!uc_priv->current) + uclass_first_device(UCLASS_ETH, + &uc_priv->current); + return uc_priv->current; +} + +static void eth_set_dev(struct udevice *dev) +{ + device_probe(dev); + eth_get_uclass_priv()->current = dev; +} + +unsigned char *eth_get_ethaddr(void) +{ + struct eth_pdata *pdata; + + if (eth_get_dev()) { + pdata = eth_get_dev()->platdata; + return pdata->enetaddr; + } + + return NULL; +} + +/* Set active state without calling start on the driver */ +int eth_init_state_only(void) +{ + struct udevice *current; + struct eth_device_priv *priv; + + current = eth_get_dev(); + if (!current || !device_active(current)) + return -EINVAL; + + priv = current->uclass_priv; + priv->state = ETH_STATE_ACTIVE; + + return 0; +} + +/* Set passive state without calling stop on the driver */ +void eth_halt_state_only(void) +{ + struct udevice *current; + struct eth_device_priv *priv; + + current = eth_get_dev(); + if (!current || !device_active(current)) + return; + + priv = current->uclass_priv; + priv->state = ETH_STATE_PASSIVE; +} + +int eth_get_dev_index(void) +{ + if (eth_get_dev()) + return eth_get_dev()->seq; + return -1; +} + +int eth_init(void) +{ + struct udevice *current; + struct udevice *old_current; + + current = eth_get_dev(); + if (!current) { + printf("No ethernet found.\n"); + return -ENODEV; + } + + old_current = current; + do { + debug("Trying %s\n", current->name); + + if (device_active(current)) { + uchar env_enetaddr[6]; + struct eth_pdata *pdata = current->platdata; + + /* Sync environment with network device */ + if (eth_getenv_enetaddr_by_index("eth", current->seq, + env_enetaddr)) + memcpy(pdata->enetaddr, env_enetaddr, 6); + else + memset(pdata->enetaddr, 0, 6); + + if (eth_get_ops(current)->start(current) >= 0) { + struct eth_device_priv *priv = + current->uclass_priv; + + priv->state = ETH_STATE_ACTIVE; + return 0; + } + } + debug("FAIL\n"); + + /* This will ensure the new "current" attempted to probe */ + eth_try_another(0); + current = eth_get_dev(); + } while (old_current != current); + + return -ENODEV; +} + +void eth_halt(void) +{ + struct udevice *current; + struct eth_device_priv *priv; + + current = eth_get_dev(); + if (!current || !device_active(current)) + return; + + eth_get_ops(current)->stop(current); + priv = current->uclass_priv; + priv->state = ETH_STATE_PASSIVE; +} + +int eth_send(void *packet, int length) +{ + struct udevice *current; + + current = eth_get_dev(); + if (!current) + return -ENODEV; + + if (!device_active(current)) + return -EINVAL; + + return eth_get_ops(current)->send(current, packet, length); +} + +int eth_rx(void) +{ + struct udevice *current; + + current = eth_get_dev(); + if (!current) + return -ENODEV; + + if (!device_active(current)) + return -EINVAL; + + return eth_get_ops(current)->recv(current); +} + +static int eth_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev->platdata; + int ret = 0; + + if (!dev || !device_active(dev)) + return -EINVAL; + + /* seq is valid since the device is active */ + if (eth_get_ops(dev)->write_hwaddr && !eth_mac_skip(dev->seq)) { + if (!is_valid_ether_addr(pdata->enetaddr)) { + printf("\nError: %s address %pM illegal value\n", + dev->name, pdata->enetaddr); + return -EINVAL; + } + + ret = eth_get_ops(dev)->write_hwaddr(dev); + if (ret) + printf("\nWarning: %s failed to set MAC address\n", + dev->name); + } + + return ret; +} + +int eth_initialize(void) +{ + int num_devices = 0; + struct udevice *dev; + + bootstage_mark(BOOTSTAGE_ID_NET_ETH_START); + eth_env_init(); + + /* + * Devices need to write the hwaddr even if not started so that Linux + * will have access to the hwaddr that u-boot stored for the device. + * This is accomplished by attempting to probe each device and calling + * their write_hwaddr() operation. + */ + uclass_first_device(UCLASS_ETH, &dev); + if (!dev) { + printf("No ethernet found.\n"); + bootstage_error(BOOTSTAGE_ID_NET_ETH_START); + } else { + bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); + do { + if (num_devices) + printf(", "); + + printf("eth%d: %s", dev->seq, dev->name); + + eth_write_hwaddr(dev); + + uclass_next_device(&dev); + num_devices++; + } while (dev); + + putc('\n'); + } + + return num_devices; +} + +static int eth_post_bind(struct udevice *dev) +{ + if (strchr(dev->name, ' ')) { + printf("\nError: eth device name "%s" has a space!\n", + dev->name); + return -EINVAL; + } + + return 0; +} + +static int eth_pre_unbind(struct udevice *dev) +{ + /* Don't hang onto a pointer that is going away */ + if (dev == eth_get_uclass_priv()->current) + eth_set_dev(NULL); + + return 0; +} + +static int eth_post_probe(struct udevice *dev) +{ + struct eth_device_priv *priv = dev->uclass_priv; + struct eth_pdata *pdata = dev->platdata; + unsigned char env_enetaddr[6]; + + priv->state = ETH_STATE_INIT; + + /* Check if the device has a MAC address in ROM */ + if (eth_get_ops(dev)->read_rom_hwaddr) + eth_get_ops(dev)->read_rom_hwaddr(dev); + + eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr); + if (!is_zero_ether_addr(env_enetaddr)) { + if (!is_zero_ether_addr(pdata->enetaddr) && + memcmp(pdata->enetaddr, env_enetaddr, 6)) { + printf("\nWarning: %s MAC addresses don't match:\n", + dev->name); + printf("Address in SROM is %pM\n", + pdata->enetaddr); + printf("Address in environment is %pM\n", + env_enetaddr); + } + + /* Override the ROM MAC address */ + memcpy(pdata->enetaddr, env_enetaddr, 6); + } else if (is_valid_ether_addr(pdata->enetaddr)) { + eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr); + printf("\nWarning: %s using MAC address from ROM\n", + dev->name); + } else if (is_zero_ether_addr(pdata->enetaddr)) { + printf("\nError: %s address not set.\n", + dev->name); + return -EINVAL; + } + + return 0; +} + +static int eth_pre_remove(struct udevice *dev) +{ + eth_get_ops(dev)->stop(dev); + + return 0; +} + +UCLASS_DRIVER(eth) = { + .name = "eth", + .id = UCLASS_ETH, + .post_bind = eth_post_bind, + .pre_unbind = eth_pre_unbind, + .post_probe = eth_post_probe, + .pre_remove = eth_pre_remove, + .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), + .per_device_auto_alloc_size = sizeof(struct eth_device_priv), +}; +#endif + +#ifndef CONFIG_DM_ETH /* * CPU and board-specific Ethernet initializations. Aliased function * signals caller to move on @@ -427,6 +763,7 @@ int eth_rx(void)
return eth_current->recv(eth_current); } +#endif /* ifndef CONFIG_DM_ETH */
#ifdef CONFIG_API static void eth_save_packet(void *packet, int length) @@ -490,7 +827,7 @@ static void eth_current_changed(void)
void eth_try_another(int first_restart) { - static struct eth_device *first_failed; + static void *first_failed; char *ethrotate;
/* @@ -519,12 +856,9 @@ void eth_set_current(void) { static char *act; static int env_changed_id; - struct eth_device *old_current; + void *old_current; int env_id;
- if (!eth_get_dev()) /* XXX no current */ - return; - env_id = get_env_id(); if ((act == NULL) || (env_changed_id != env_id)) { act = getenv("ethact");

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
First just add support for MAC drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

Take the opportunity to enforce better names on newly written or retrofitted Ethernet drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 9 ++++++++- net/net.c | 30 +++++++++++++++++++----------- 2 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/include/net.h b/include/net.h index fff82cb..31ef1ff 100644 --- a/include/net.h +++ b/include/net.h @@ -466,7 +466,11 @@ extern uchar NetServerEther[6]; /* Boot server enet address */ extern IPaddr_t NetOurIP; /* Our IP addr (0 = unknown) */ extern IPaddr_t NetServerIP; /* Server IP addr (0 = unknown) */ extern uchar *NetTxPacket; /* THE transmit packet */ +#ifdef CONFIG_DM_ETH +extern uchar *net_rx_packets[PKTBUFSRX]; /* Receive packets */ +#else extern uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets */ +#endif extern uchar *NetRxPacket; /* Current receive packet */ extern int NetRxPacketLen; /* Current rx packet length */ extern unsigned NetIPID; /* IP ID (counting) */ @@ -616,8 +620,11 @@ static inline void NetSendPacket(uchar *pkt, int len) int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int payload_len);
+#ifndef CONFIG_DM_ETH +#define NetReceive(in_packet, len) net_process_received_packet(in_packet, len) +#endif /* Processes a received packet */ -void NetReceive(uchar *, int); +void net_process_received_packet(uchar *in_packet, int len);
#ifdef CONFIG_NETCONSOLE void NcStart(void); diff --git a/net/net.c b/net/net.c index 37b4aab..afec443 100644 --- a/net/net.c +++ b/net/net.c @@ -183,10 +183,13 @@ int NetTimeOffset; #endif
static uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN]; - +#ifdef CONFIG_DM_ETH +/* Receive packets */ +uchar *net_rx_packets[PKTBUFSRX]; +#else /* Receive packet */ uchar *NetRxPackets[PKTBUFSRX]; - +#endif /* Current UDP RX packet handler */ static rxhand_f *udp_packet_handler; /* Current ARP RX packet handler */ @@ -304,9 +307,15 @@ void net_init(void)
NetTxPacket = &PktBuf[0] + (PKTALIGN - 1); NetTxPacket -= (ulong)NetTxPacket % PKTALIGN; +#ifdef CONFIG_DM_ETH + for (i = 0; i < PKTBUFSRX; i++) { + net_rx_packets[i] = NetTxPacket + (i + 1) * + PKTSIZE_ALIGN; + } +#else for (i = 0; i < PKTBUFSRX; i++) NetRxPackets[i] = NetTxPacket + (i + 1) * PKTSIZE_ALIGN; - +#endif ArpInit(); net_clear_handlers();
@@ -952,8 +961,7 @@ static void receive_icmp(struct ip_udp_hdr *ip, int len, } }
-void -NetReceive(uchar *inpkt, int len) +void net_process_received_packet(uchar *in_packet, int len) { struct ethernet_hdr *et; struct ip_udp_hdr *ip; @@ -967,9 +975,9 @@ NetReceive(uchar *inpkt, int len)
debug_cond(DEBUG_NET_PKT, "packet received\n");
- NetRxPacket = inpkt; + NetRxPacket = in_packet; NetRxPacketLen = len; - et = (struct ethernet_hdr *)inpkt; + et = (struct ethernet_hdr *)in_packet;
/* too small packet? */ if (len < ETHER_HDR_SIZE) @@ -977,7 +985,7 @@ NetReceive(uchar *inpkt, int len)
#ifdef CONFIG_API if (push_packet) { - (*push_packet)(inpkt, len); + (*push_packet)(in_packet, len); return; } #endif @@ -1004,11 +1012,11 @@ NetReceive(uchar *inpkt, int len) */ eth_proto = ntohs(et802->et_prot);
- ip = (struct ip_udp_hdr *)(inpkt + E802_HDR_SIZE); + ip = (struct ip_udp_hdr *)(in_packet + E802_HDR_SIZE); len -= E802_HDR_SIZE;
} else if (eth_proto != PROT_VLAN) { /* normal packet */ - ip = (struct ip_udp_hdr *)(inpkt + ETHER_HDR_SIZE); + ip = (struct ip_udp_hdr *)(in_packet + ETHER_HDR_SIZE); len -= ETHER_HDR_SIZE;
} else { /* VLAN packet */ @@ -1033,7 +1041,7 @@ NetReceive(uchar *inpkt, int len) vlanid = cti & VLAN_IDMASK; eth_proto = ntohs(vet->vet_type);
- ip = (struct ip_udp_hdr *)(inpkt + VLAN_ETHER_HDR_SIZE); + ip = (struct ip_udp_hdr *)(in_packet + VLAN_ETHER_HDR_SIZE); len -= VLAN_ETHER_HDR_SIZE; }

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
Take the opportunity to enforce better names on newly written or retrofitted Ethernet drivers.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

Stop forcing drivers to call net_process_received_packet() - formerly called NetReceive(). Now the uclass will handle calling the driver for each packet until the driver errors or has nothing to return. The uclass will then pass the good packets off to the network stack by calling net_process_received_packet().
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
---
Changes in v7: None Changes in v6: -Swallow -EAGAIN error in eth_rx() -Updated function documentation
Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 6 ++++-- net/eth.c | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/include/net.h b/include/net.h index 31ef1ff..241a096 100644 --- a/include/net.h +++ b/include/net.h @@ -95,7 +95,9 @@ struct eth_pdata { * * start: Prepare the hardware to send and receive packets * send: Send the bytes passed in "packet" as a packet on the wire - * recv: Check if the hardware received a packet. Call the network stack if so + * recv: Check if the hardware received a packet. If so, set the pointer to the + * packet buffer in the packetp parameter. If not, return an error or 0 to + * indicate that the hardware receive FIFO is empty * stop: Stop the hardware from looking for packets - may be called even if * state == PASSIVE * mcast: Join or leave a multicast group (for TFTP) - optional @@ -110,7 +112,7 @@ struct eth_pdata { struct eth_ops { int (*start)(struct udevice *dev); int (*send)(struct udevice *dev, void *packet, int length); - int (*recv)(struct udevice *dev); + int (*recv)(struct udevice *dev, uchar **packetp); void (*stop)(struct udevice *dev); #ifdef CONFIG_MCAST_TFTP int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join); diff --git a/net/eth.c b/net/eth.c index 1abf027..058c55a 100644 --- a/net/eth.c +++ b/net/eth.c @@ -259,6 +259,9 @@ int eth_send(void *packet, int length) int eth_rx(void) { struct udevice *current; + uchar *packet; + int ret; + int i;
current = eth_get_dev(); if (!current) @@ -267,7 +270,17 @@ int eth_rx(void) if (!device_active(current)) return -EINVAL;
- return eth_get_ops(current)->recv(current); + /* Process up to 32 packets at one time */ + for (i = 0; i < 32; i++) { + ret = eth_get_ops(current)->recv(current, &packet); + if (ret > 0) + net_process_received_packet(packet, ret); + else + break; + } + if (ret == -EAGAIN) + ret = 0; + return ret; }
static int eth_write_hwaddr(struct udevice *dev)

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
Stop forcing drivers to call net_process_received_packet() - formerly called NetReceive(). Now the uclass will handle calling the driver for each packet until the driver errors or has nothing to return. The uclass will then pass the good packets off to the network stack by calling net_process_received_packet().
Signed-off-by: Joe Hershberger joe.hershberger@ni.com
Changes in v7: None
Applied to u-boot-dm/next, thanks!

Add basic network support to sandbox which includes a network driver.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: -Added help to the sandbox eth mock driver Kconfig entry
Changes in v4: -Cleaned up sandbox EXTRA_ENV define -Moved config to Kconfig
Changes in v3: -Added 2 more ethaddr to sandbox -Print which device in the debug write hwaddr
Changes in v2: -Change printfs to debug in sandbox driver -Remove unused priv struct for sandbox driver
arch/sandbox/Kconfig | 9 +++++ arch/sandbox/dts/sandbox.dts | 4 +++ board/sandbox/README.sandbox | 4 +-- drivers/net/Kconfig | 23 ++++++++++++ drivers/net/Makefile | 1 + drivers/net/sandbox.c | 84 ++++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 16 +++++---- 7 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 drivers/net/sandbox.c
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index 2098b9c..186b58d 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -34,4 +34,13 @@ config DM_I2C config DM_TEST default y
+config NET + default y + +config NETDEVICES + default y + +config DM_ETH + default y + endmenu diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 9ce31bf..36b3bd8 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -181,4 +181,8 @@ }; };
+ eth@10002000 { + compatible = "sandbox,eth"; + reg = <0x10002000 0x1000>; + }; }; diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox index 3c0df17..c1f5f7e 100644 --- a/board/sandbox/README.sandbox +++ b/board/sandbox/README.sandbox @@ -173,16 +173,16 @@ U-Boot sandbox supports these emulations: - Chrome OS EC - GPIO - Host filesystem (access files on the host from within U-Boot) +- I2C - Keyboard (Chrome OS) - LCD +- Network - Serial (for console only) - Sound (incomplete - see sandbox_sdl_sound_init() for details) - SPI - SPI flash - TPM (Trusted Platform Module)
-Notable omissions are networking and I2C. - A wide range of commands is implemented. Filesystems which use a block device are supported.
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 94cf099..e46e57b 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -7,3 +7,26 @@ config DM_ETH The eth_*() interface will be implemented by the UC_ETH class This is currently implemented in net/eth.c Look in include/net.h for details. + +menuconfig NETDEVICES + bool "Network device support" + depends on NET + help + You must select Y to enable any network device support + Generally if you have any networking support this is a given + + If unsure, say Y + +if NETDEVICES + +config ETH_SANDBOX + depends on DM_ETH && SANDBOX + default y + bool "Sandbox: Mocked Ethernet driver" + help + This driver simply responds with fake ARP replies and ping + replies that are used to verify network stack functionality + + This driver is particularly useful in the test/dm/eth.c tests + +endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index b8b0803..a17198c 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_NS8382X) += ns8382x.o obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o +obj-$(CONFIG_ETH_SANDBOX) += sandbox.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c new file mode 100644 index 0000000..522990d --- /dev/null +++ b/drivers/net/sandbox.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int sb_eth_start(struct udevice *dev) +{ + debug("eth_sandbox: Start\n"); + + return 0; +} + +static int sb_eth_send(struct udevice *dev, void *packet, int length) +{ + debug("eth_sandbox: Send packet %d\n", length); + + return 0; +} + +static int sb_eth_recv(struct udevice *dev, uchar **packetp) +{ + return 0; +} + +static void sb_eth_stop(struct udevice *dev) +{ + debug("eth_sandbox: Stop\n"); +} + +static int sb_eth_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + + debug("eth_sandbox %s: Write HW ADDR - %pM\n", dev->name, + pdata->enetaddr); + return 0; +} + +static const struct eth_ops sb_eth_ops = { + .start = sb_eth_start, + .send = sb_eth_send, + .recv = sb_eth_recv, + .stop = sb_eth_stop, + .write_hwaddr = sb_eth_write_hwaddr, +}; + +static int sb_eth_remove(struct udevice *dev) +{ + return 0; +} + +static int sb_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + + pdata->iobase = dev_get_addr(dev); + return 0; +} + +static const struct udevice_id sb_eth_ids[] = { + { .compatible = "sandbox,eth" }, + { } +}; + +U_BOOT_DRIVER(eth_sandbox) = { + .name = "eth_sandbox", + .id = UCLASS_ETH, + .of_match = sb_eth_ids, + .ofdata_to_platdata = sb_eth_ofdata_to_platdata, + .remove = sb_eth_remove, + .ops = &sb_eth_ops, + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index febbfb6..664b984 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -126,9 +126,6 @@ /* include default commands */ #include <config_cmd_default.h>
-/* We don't have networking support yet */ -#undef CONFIG_CMD_NET -#undef CONFIG_CMD_NFS
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY @@ -165,16 +162,23 @@
#define CONFIG_KEYBOARD
-#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial,cros-ec-keyb\0" \ +#define SANDBOX_SERIAL_SETTINGS "stdin=serial,cros-ec-keyb\0" \ "stdout=serial,lcd\0" \ "stderr=serial,lcd\0" #else - -#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial\0" \ +#define SANDBOX_SERIAL_SETTINGS "stdin=serial\0" \ "stdout=serial,lcd\0" \ "stderr=serial,lcd\0" #endif
+#define SANDBOX_ETH_SETTINGS "ethaddr=00:00:11:22:33:44\0" \ + "eth1addr=00:00:11:22:33:45\0" \ + "eth2addr=00:00:11:22:33:46\0" \ + "ipaddr=1.2.3.4\0" + +#define CONFIG_EXTRA_ENV_SETTINGS SANDBOX_SERIAL_SETTINGS \ + SANDBOX_ETH_SETTINGS + #define CONFIG_GZIP_COMPRESSED #define CONFIG_BZIP2 #define CONFIG_LZO

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
Add basic network support to sandbox which includes a network driver.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

The sandbox driver will now generate response traffic to exercise the ping command even when no network exists. This allows the basic data pathways of the DM to be tested.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org ---
Changes in v7: None Changes in v6: None Changes in v5: -Simplify sandbox eth driver by switching from int array to byte array -Switch priv from packet buffer to a pointer to net_rx_packets[0]
Changes in v4: -Removed checks on priv != NULL and added protection in uclass instead
Changes in v3: -Prevent a crash if memory is not allocated
Changes in v2: -Change printfs to debug in sandbox driver -Move fake hwaddr to the device tree -Move static data to priv
arch/sandbox/dts/sandbox.dts | 1 + drivers/net/sandbox.c | 107 +++++++++++++++++++++++++++++++++++++++++++ include/configs/sandbox.h | 1 + 3 files changed, 109 insertions(+)
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 36b3bd8..c2a3304 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -184,5 +184,6 @@ eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>; + fake-host-hwaddr = [00 00 66 44 22 00]; }; }; diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 522990d..cb69a95 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -14,22 +14,128 @@
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 + * 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]; + IPaddr_t fake_host_ipaddr; + uchar *recv_packet_buffer; + int recv_packet_length; +}; + static int sb_eth_start(struct udevice *dev) { + struct eth_sandbox_priv *priv = dev_get_priv(dev); + debug("eth_sandbox: Start\n");
+ fdtdec_get_byte_array(gd->fdt_blob, dev->of_offset, "fake-host-hwaddr", + priv->fake_host_hwaddr, ARP_HLEN); + priv->recv_packet_buffer = net_rx_packets[0]; return 0; }
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 (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 = NetReadIP(&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); + NetWriteIP(&arp_recv->ar_spa, priv->fake_host_ipaddr); + memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN); + NetCopyIP(&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; + NetCopyIP((void *)&ipr->ip_dst, &ip->ip_src); + NetWriteIP((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; }
static int sb_eth_recv(struct udevice *dev, uchar **packetp) { + struct eth_sandbox_priv *priv = dev_get_priv(dev); + + if (priv->recv_packet_length) { + int lcl_recv_packet_length = priv->recv_packet_length; + + debug("eth_sandbox: received packet %d\n", + priv->recv_packet_length); + priv->recv_packet_length = 0; + *packetp = priv->recv_packet_buffer; + return lcl_recv_packet_length; + } return 0; }
@@ -80,5 +186,6 @@ U_BOOT_DRIVER(eth_sandbox) = { .ofdata_to_platdata = sb_eth_ofdata_to_platdata, .remove = sb_eth_remove, .ops = &sb_eth_ops, + .priv_auto_alloc_size = sizeof(struct eth_sandbox_priv), .platdata_auto_alloc_size = sizeof(struct eth_pdata), }; diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 664b984..9189f6a 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -126,6 +126,7 @@ /* include default commands */ #include <config_cmd_default.h>
+#define CONFIG_CMD_PING
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
The sandbox driver will now generate response traffic to exercise the ping command even when no network exists. This allows the basic data pathways of the DM to be tested.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

Add a test for the eth uclass using the sandbox eth driver. Verify basic functionality of the network stack / eth uclass by exercising the ping function.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: -Added dm eth testing
Changes in v2: None
test/dm/Makefile | 1 + test/dm/eth.c | 38 ++++++++++++++++++++++++++++++++++++++ test/dm/test.dts | 18 ++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 test/dm/eth.c
diff --git a/test/dm/Makefile b/test/dm/Makefile index 1d9148f..b2eb989 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_DM_TEST) += ut.o obj-$(CONFIG_DM_TEST) += core.o obj-$(CONFIG_DM_TEST) += ut.o ifneq ($(CONFIG_SANDBOX),) +obj-$(CONFIG_DM_ETH) += eth.o obj-$(CONFIG_DM_GPIO) += gpio.o obj-$(CONFIG_DM_I2C) += i2c.o obj-$(CONFIG_DM_SPI_FLASH) += sf.o diff --git a/test/dm/eth.c b/test/dm/eth.c new file mode 100644 index 0000000..04ccf49 --- /dev/null +++ b/test/dm/eth.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <dm/test.h> +#include <dm/ut.h> +#include <fdtdec.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int dm_test_eth(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + + setenv("ethact", "eth@10002000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth@10003000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10003000", getenv("ethact")); + + setenv("ethact", "eth@10004000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + return 0; +} +DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 84024a4..2f68cdf 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -149,4 +149,22 @@ }; };
+ eth@10002000 { + compatible = "sandbox,eth"; + reg = <0x10002000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; + }; + + eth@10003000 { + compatible = "sandbox,eth"; + reg = <0x10003000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>; + }; + + eth@10004000 { + compatible = "sandbox,eth"; + reg = <0x10004000 0x1000>; + fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x22>; + }; + };

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
Add a test for the eth uclass using the sandbox eth driver. Verify basic functionality of the network stack / eth uclass by exercising the ping function.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

Allow network devices to be referred to as "eth0" instead of "eth@12345678" when specified in ethact.
Add tests to verify this behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: -Added a comment about devname -Only check for alias if the name is long enough
Changes in v4: -Use only the seq from DM to find aliases
Changes in v3: -Added support for aliases
Changes in v2: None
include/configs/sandbox.h | 2 +- include/net.h | 5 +++++ net/eth.c | 50 ++++++++++++++++++++++++++++++++++++++--------- test/dm/eth.c | 24 +++++++++++++++++++++++ test/dm/test.dts | 4 +++- 5 files changed, 74 insertions(+), 11 deletions(-)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 9189f6a..caf9f5a 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -174,7 +174,7 @@
#define SANDBOX_ETH_SETTINGS "ethaddr=00:00:11:22:33:44\0" \ "eth1addr=00:00:11:22:33:45\0" \ - "eth2addr=00:00:11:22:33:46\0" \ + "eth5addr=00:00:11:22:33:46\0" \ "ipaddr=1.2.3.4\0"
#define CONFIG_EXTRA_ENV_SETTINGS SANDBOX_SERIAL_SETTINGS \ diff --git a/include/net.h b/include/net.h index 241a096..baccd47 100644 --- a/include/net.h +++ b/include/net.h @@ -124,6 +124,11 @@ struct eth_ops { #define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
struct udevice *eth_get_dev(void); /* get the current device */ +/* + * The devname can be either an exact name given by the driver or device tree + * or it can be an alias of the form "eth%d" + */ +struct udevice *eth_get_dev_by_name(const char *devname); unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ /* Used only when NetConsole is enabled */ int eth_init_state_only(void); /* Set active state */ diff --git a/net/eth.c b/net/eth.c index 058c55a..a2e6f34 100644 --- a/net/eth.c +++ b/net/eth.c @@ -135,6 +135,39 @@ static void eth_set_dev(struct udevice *dev) eth_get_uclass_priv()->current = dev; }
+/* + * Find the udevice that either has the name passed in as devname or has an + * alias named devname. + */ +struct udevice *eth_get_dev_by_name(const char *devname) +{ + int seq = -1; + char *endp = NULL; + const char *startp = NULL; + struct udevice *it; + struct uclass *uc; + + /* Must be longer than 3 to be an alias */ + if (strlen(devname) > strlen("eth")) { + startp = devname + strlen("eth"); + seq = simple_strtoul(startp, &endp, 10); + } + + uclass_get(UCLASS_ETH, &uc); + uclass_foreach_dev(it, uc) { + /* We need the seq to be valid, so make sure it's probed */ + device_probe(it); + /* + * Check for the name or the sequence number to match + */ + if (strcmp(it->name, devname) == 0 || + (endp > startp && it->seq == seq)) + return it; + } + + return NULL; +} + unsigned char *eth_get_ethaddr(void) { struct eth_pdata *pdata; @@ -421,6 +454,7 @@ UCLASS_DRIVER(eth) = { .pre_remove = eth_pre_remove, .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), .per_device_auto_alloc_size = sizeof(struct eth_device_priv), + .flags = DM_UC_FLAG_SEQ_ALIAS, }; #endif
@@ -453,6 +487,11 @@ static void eth_set_current_to_next(void) eth_current = eth_current->next; }
+static void eth_set_dev(struct eth_device *dev) +{ + eth_current = dev; +} + struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -869,7 +908,6 @@ void eth_set_current(void) { static char *act; static int env_changed_id; - void *old_current; int env_id;
env_id = get_env_id(); @@ -877,14 +915,8 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; } - if (act != NULL) { - old_current = eth_get_dev(); - do { - if (strcmp(eth_get_name(), act) == 0) - return; - eth_set_current_to_next(); - } while (old_current != eth_get_dev()); - } + if (act != NULL) + eth_set_dev(eth_get_dev_by_name(act));
eth_current_changed(); } diff --git a/test/dm/eth.c b/test/dm/eth.c index 04ccf49..5688b71 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -36,3 +36,27 @@ static int dm_test_eth(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT); + +static int dm_test_eth_alias(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + setenv("ethact", "eth0"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth1"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Expected to fail since eth2 is not defined in the device tree */ + setenv("ethact", "eth2"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + setenv("ethact", "eth5"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10003000", getenv("ethact")); + + return 0; +} +DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 2f68cdf..bc2409d 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -17,6 +17,8 @@ testfdt3 = "/b-test"; testfdt5 = "/some-bus/c-test@5"; testfdt8 = "/a-test"; + eth0 = "/eth@10002000"; + eth5 = ð_5; };
uart0: serial { @@ -155,7 +157,7 @@ fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>; };
- eth@10003000 { + eth_5: eth@10003000 { compatible = "sandbox,eth"; reg = <0x10003000 0x1000>; fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>;

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
Allow network devices to be referred to as "eth0" instead of "eth@12345678" when specified in ethact.
Add tests to verify this behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

The ethprime env var is used to indicate the starting device if none is specified in ethact. Also support aliases specified in the ethprime var.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: -Fix compile error on !DM_ETH
Changes in v4: -Load from ethprime on eth_initialize()
Changes in v3: -Added support for ethprime
Changes in v2: None
net/eth.c | 29 ++++++++++++++++++++++++++++- test/dm/eth.c | 20 ++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/net/eth.c b/net/eth.c index a2e6f34..b6c2af3 100644 --- a/net/eth.c +++ b/net/eth.c @@ -360,6 +360,18 @@ int eth_initialize(void) printf("No ethernet found.\n"); bootstage_error(BOOTSTAGE_ID_NET_ETH_START); } else { + char *ethprime = getenv("ethprime"); + struct udevice *prime_dev = NULL; + + if (ethprime) + prime_dev = eth_get_dev_by_name(ethprime); + if (prime_dev) { + eth_set_dev(prime_dev); + eth_current_changed(); + } else { + eth_set_dev(NULL); + } + bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); do { if (num_devices) @@ -367,6 +379,9 @@ int eth_initialize(void)
printf("eth%d: %s", dev->seq, dev->name);
+ if (ethprime && dev == prime_dev) + printf(" [PRIME]"); + eth_write_hwaddr(dev);
uclass_next_device(&dev); @@ -915,8 +930,20 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; } - if (act != NULL) + + if (act == NULL) { + char *ethprime = getenv("ethprime"); + void *dev = NULL; + + if (ethprime) + dev = eth_get_dev_by_name(ethprime); + if (dev) + eth_set_dev(dev); + else + eth_set_dev(NULL); + } else { eth_set_dev(eth_get_dev_by_name(act)); + }
eth_current_changed(); } diff --git a/test/dm/eth.c b/test/dm/eth.c index 5688b71..96e3c46 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -60,3 +60,23 @@ static int dm_test_eth_alias(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT); + +static int dm_test_eth_prime(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + + /* Expected to be "eth@10003000" because of ethprime variable */ + setenv("ethact", NULL); + setenv("ethprime", "eth5"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10003000", getenv("ethact")); + + /* Expected to be "eth@10002000" because it is first */ + setenv("ethact", NULL); + setenv("ethprime", NULL); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + return 0; +} +DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT);

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
The ethprime env var is used to indicate the starting device if none is specified in ethact. Also support aliases specified in the ethprime var.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

Make sure that the ethrotate behavior occurs as expected.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: -Added a test for skipping un-probe-able devices
Changes in v4: -Added testing for ethrotate
Changes in v3: None Changes in v2: None
test/dm/eth.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
diff --git a/test/dm/eth.c b/test/dm/eth.c index 96e3c46..9b55013 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -80,3 +80,45 @@ static int dm_test_eth_prime(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT); + +static int dm_test_eth_rotate(struct dm_test_state *dms) +{ + char ethaddr[18]; + + /* Invalidate eth1's MAC address */ + NetPingIP = string_to_ip("1.1.2.2"); + strcpy(ethaddr, getenv("eth1addr")); + setenv("eth1addr", NULL); + + /* Make sure that the default is to rotate to the next interface */ + setenv("ethact", "eth@10004000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + /* If ethrotate is no, then we should fail on a bad MAC */ + setenv("ethact", "eth@10004000"); + setenv("ethrotate", "no"); + ut_asserteq(-1, NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Restore the env */ + setenv("eth1addr", ethaddr); + setenv("ethrotate", NULL); + + /* Invalidate eth0's MAC address */ + strcpy(ethaddr, getenv("ethaddr")); + setenv(".flags", "ethaddr"); + setenv("ethaddr", NULL); + + /* Make sure we can skip invalid devices */ + setenv("ethact", "eth@10004000"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Restore the env */ + setenv("ethaddr", ethaddr); + setenv(".flags", NULL); + + return 0; +} +DM_TEST(dm_test_eth_rotate, DM_TESTF_SCAN_FDT);

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
Make sure that the ethrotate behavior occurs as expected.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

This is needed to test the netretry functionality (make the command fail on a sandbox eth device).
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: -Add function comments -Check array index bounds
Changes in v5: -Use a function call to change mock driver behavior
Changes in v4: -Add ability to disable ping reply in sandbox eth driver
Changes in v3: None Changes in v2: None
arch/sandbox/include/asm/eth.h | 15 +++++++++++++++ drivers/net/sandbox.c | 17 +++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 arch/sandbox/include/asm/eth.h
diff --git a/arch/sandbox/include/asm/eth.h b/arch/sandbox/include/asm/eth.h new file mode 100644 index 0000000..4b79ede --- /dev/null +++ b/arch/sandbox/include/asm/eth.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __ETH_H +#define __ETH_H + +void sandbox_eth_disable_response(int index, bool disable); + +#endif /* __ETH_H */ diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index cb69a95..db115d0 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -29,6 +29,19 @@ struct eth_sandbox_priv { int recv_packet_length; };
+static bool disabled[8] = {false}; + +/* + * sandbox_eth_disable_response() + * + * index - The alias index (also DM seq number) + * disable - If non-zero, ignore sent packets and don't send mock response + */ +void sandbox_eth_disable_response(int index, bool disable) +{ + disabled[index] = disable; +} + static int sb_eth_start(struct udevice *dev) { struct eth_sandbox_priv *priv = dev_get_priv(dev); @@ -48,6 +61,10 @@ 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]) + return 0; + if (ntohs(eth->et_protlen) == PROT_ARP) { struct arp_hdr *arp = packet + ETHER_HDR_SIZE;

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
This is needed to test the netretry functionality (make the command fail on a sandbox eth device).
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

The effect of the "netretry" env var was recently changed. This test checks that behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: -Added comments about test cases -Switched to function to control state of mock driver
Changes in v4: -Updated expected behavior based on changes to the NetLoop
Changes in v3: -Added testing for netretry
Changes in v2: None
test/dm/eth.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
diff --git a/test/dm/eth.c b/test/dm/eth.c index 9b55013..a0e9359 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -14,6 +14,7 @@ #include <fdtdec.h> #include <malloc.h> #include <net.h> +#include <asm/eth.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -122,3 +123,34 @@ static int dm_test_eth_rotate(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_eth_rotate, DM_TESTF_SCAN_FDT); + +static int dm_test_net_retry(struct dm_test_state *dms) +{ + NetPingIP = string_to_ip("1.1.2.2"); + + /* + * eth1 is disabled and netretry is yes, so the ping should succeed and + * the active device should be eth0 + */ + sandbox_eth_disable_response(1, true); + setenv("ethact", "eth@10004000"); + setenv("netretry", "yes"); + ut_assertok(NetLoop(PING)); + ut_asserteq_str("eth@10002000", getenv("ethact")); + + /* + * eth1 is disabled and netretry is no, so the ping should fail and the + * active device should be eth1 + */ + setenv("ethact", "eth@10004000"); + setenv("netretry", "no"); + ut_asserteq(-1, NetLoop(PING)); + ut_asserteq_str("eth@10004000", getenv("ethact")); + + /* Restore the env */ + setenv("netretry", NULL); + sandbox_eth_disable_response(1, false); + + return 0; +} +DM_TEST(dm_test_net_retry, DM_TESTF_SCAN_FDT);

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
The effect of the "netretry" env var was recently changed. This test checks that behavior.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

Implement a bridge between U-Boot's network stack and Linux's raw packet API allowing the sandbox to send and receive packets using the host machine's network interface.
This raw Ethernet API requires elevated privileges. You can either run as root, or you can add the capability needed like so:
sudo /sbin/setcap "CAP_NET_RAW+ep" /path/to/u-boot
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: -Addressed nits
Changes in v5: -Added fallback for setting promiscuous mode -Added help to Kconfig -Added more details and examples in the README -Check for NULL when reading fdt for host interface -Check for malloc failure -Remove cast of pointer passed to free -Remove the empty sb_eth_raw_remove function -Return -errno in from send and recv -Return errno from recv -Set the socket to non-blocking -Use net_rx_packets instead of a stack buffer
Changes in v4: -Add comments to priv struct definition -Added comments to README.sandbox -Clean up the interface to sandbox's eth-raw-os by passing priv to raw-os -Cleanup var definition order -Fixed the MAC address limitation (now all traffic uses MAC address from env) -Move os file to arch -Moved config to Kconfig -Use accessors for platdata and priv
Changes in v3: -Made the os raw packet support for sandbox eth build and work.
Changes in v2: -Added the raw packet proof-of-concept patch.
arch/sandbox/Kconfig | 3 + arch/sandbox/cpu/Makefile | 10 +++ arch/sandbox/cpu/eth-raw-os.c | 140 ++++++++++++++++++++++++++++++++++ arch/sandbox/dts/sandbox.dts | 6 ++ arch/sandbox/include/asm/eth-raw-os.h | 32 ++++++++ board/sandbox/README.sandbox | 52 +++++++++++++ drivers/net/Kconfig | 10 +++ drivers/net/Makefile | 1 + drivers/net/sandbox-raw.c | 98 ++++++++++++++++++++++++ 9 files changed, 352 insertions(+) create mode 100644 arch/sandbox/cpu/eth-raw-os.c create mode 100644 arch/sandbox/include/asm/eth-raw-os.h create mode 100644 drivers/net/sandbox-raw.c
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index 186b58d..f84b3fc 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -43,4 +43,7 @@ config NETDEVICES config DM_ETH default y
+config ETH_SANDBOX_RAW + default y + endmenu diff --git a/arch/sandbox/cpu/Makefile b/arch/sandbox/cpu/Makefile index 7d4410c..1b42fee 100644 --- a/arch/sandbox/cpu/Makefile +++ b/arch/sandbox/cpu/Makefile @@ -8,6 +8,7 @@ #
obj-y := cpu.o os.o start.o state.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += eth-raw-os.o obj-$(CONFIG_SANDBOX_SDL) += sdl.o
# os.c is build in the system environment, so needs standard includes @@ -20,3 +21,12 @@ $(obj)/os.o: $(src)/os.c FORCE $(call if_changed_dep,cc_os.o) $(obj)/sdl.o: $(src)/sdl.c FORCE $(call if_changed_dep,cc_os.o) + +# eth-raw-os.c is built in the system env, so needs standard includes +# CFLAGS_REMOVE_eth-raw-os.o cannot be used to drop header include path +quiet_cmd_cc_eth-raw-os.o = CC $(quiet_modtag) $@ +cmd_cc_eth-raw-os.o = $(CC) $(filter-out -nostdinc, \ + $(patsubst -I%,-idirafter%,$(c_flags))) -c -o $@ $< + +$(obj)/eth-raw-os.o: $(src)/eth-raw-os.c FORCE + $(call if_changed_dep,cc_eth-raw-os.o) diff --git a/arch/sandbox/cpu/eth-raw-os.c b/arch/sandbox/cpu/eth-raw-os.c new file mode 100644 index 0000000..601205a --- /dev/null +++ b/arch/sandbox/cpu/eth-raw-os.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <asm/eth-raw-os.h> +#include <errno.h> +#include <fcntl.h> +#include <net/if.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <linux/if_ether.h> +#include <linux/if_packet.h> + +int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, + struct eth_sandbox_raw_priv *priv) +{ + struct sockaddr_ll *device; + struct packet_mreq mr; + int ret; + int flags; + + /* Prepare device struct */ + priv->device = malloc(sizeof(struct sockaddr_ll)); + if (priv->device == NULL) + return -ENOMEM; + device = priv->device; + memset(device, 0, sizeof(struct sockaddr_ll)); + device->sll_ifindex = if_nametoindex(ifname); + device->sll_family = AF_PACKET; + memcpy(device->sll_addr, ethmac, 6); + device->sll_halen = htons(6); + + /* Open socket */ + priv->sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (priv->sd < 0) { + printf("Failed to open socket: %d %s\n", errno, + strerror(errno)); + return -errno; + } + /* Bind to the specified interface */ + ret = setsockopt(priv->sd, SOL_SOCKET, SO_BINDTODEVICE, ifname, + strlen(ifname) + 1); + if (ret < 0) { + printf("Failed to bind to '%s': %d %s\n", ifname, errno, + strerror(errno)); + return -errno; + } + + /* Make the socket non-blocking */ + flags = fcntl(priv->sd, F_GETFL, 0); + fcntl(priv->sd, F_SETFL, flags | O_NONBLOCK); + + /* Enable promiscuous mode to receive responses meant for us */ + mr.mr_ifindex = device->sll_ifindex; + mr.mr_type = PACKET_MR_PROMISC; + ret = setsockopt(priv->sd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, + &mr, sizeof(mr)); + if (ret < 0) { + struct ifreq ifr; + + printf("Failed to set promiscuous mode: %d %s\n" + "Falling back to the old "flags" way...\n", + errno, strerror(errno)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + if (ioctl(priv->sd, SIOCGIFFLAGS, &ifr) < 0) { + printf("Failed to read flags: %d %s\n", errno, + strerror(errno)); + return -errno; + } + ifr.ifr_flags |= IFF_PROMISC; + if (ioctl(priv->sd, SIOCSIFFLAGS, &ifr) < 0) { + printf("Failed to write flags: %d %s\n", errno, + strerror(errno)); + return -errno; + } + } + return 0; +} + +int sandbox_eth_raw_os_send(void *packet, int length, + const struct eth_sandbox_raw_priv *priv) +{ + int retval; + + if (!priv->sd || !priv->device) + return -EINVAL; + + retval = sendto(priv->sd, packet, length, 0, + (struct sockaddr *)priv->device, + sizeof(struct sockaddr_ll)); + if (retval < 0) { + printf("Failed to send packet: %d %s\n", errno, + strerror(errno)); + return -errno; + } + return retval; +} + +int sandbox_eth_raw_os_recv(void *packet, int *length, + const struct eth_sandbox_raw_priv *priv) +{ + int retval; + int saddr_size; + + if (!priv->sd || !priv->device) + return -EINVAL; + saddr_size = sizeof(struct sockaddr); + retval = recvfrom(priv->sd, packet, 1536, 0, + (struct sockaddr *)priv->device, + (socklen_t *)&saddr_size); + *length = 0; + if (retval >= 0) { + *length = retval; + return 0; + } + /* The socket is non-blocking, so expect EAGAIN when there is no data */ + if (errno == EAGAIN) + return 0; + return -errno; +} + +void sandbox_eth_raw_os_stop(struct eth_sandbox_raw_priv *priv) +{ + free(priv->device); + priv->device = NULL; + close(priv->sd); + priv->sd = -1; +} diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index c2a3304..8002196 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -186,4 +186,10 @@ reg = <0x10002000 0x1000>; fake-host-hwaddr = [00 00 66 44 22 00]; }; + + eth@80000000 { + compatible = "sandbox,eth-raw"; + reg = <0x80000000 0x1000>; + host-raw-interface = "eth0"; + }; }; diff --git a/arch/sandbox/include/asm/eth-raw-os.h b/arch/sandbox/include/asm/eth-raw-os.h new file mode 100644 index 0000000..df60c4f --- /dev/null +++ b/arch/sandbox/include/asm/eth-raw-os.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __ETH_RAW_OS_H +#define __ETH_RAW_OS_H + +/** + * struct eth_sandbox_raw_priv - raw socket session + * + * sd: socket descriptor - the open socket during a session + * device: struct sockaddr_ll - the host interface packets move to/from + */ +struct eth_sandbox_raw_priv { + int sd; + void *device; +}; + +int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, + struct eth_sandbox_raw_priv *priv); +int sandbox_eth_raw_os_send(void *packet, int length, + const struct eth_sandbox_raw_priv *priv); +int sandbox_eth_raw_os_recv(void *packet, int *length, + const struct eth_sandbox_raw_priv *priv); +void sandbox_eth_raw_os_stop(struct eth_sandbox_raw_priv *priv); + +#endif /* __ETH_RAW_OS_H */ diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox index c1f5f7e..9f5d3f7 100644 --- a/board/sandbox/README.sandbox +++ b/board/sandbox/README.sandbox @@ -190,6 +190,58 @@ Also sandbox uses generic board (CONFIG_SYS_GENERIC_BOARD) and supports driver model (CONFIG_DM) and associated commands.
+Linux RAW Networking Bridge +--------------------------- + +The sandbox_eth_raw driver bridges traffic between the bottom of the network +stack and the RAW sockets API in Linux. This allows much of the U-Boot network +functionality to be tested in sandbox against real network traffic. + +For Ethernet network adapters, the bridge utilizes the RAW AF_PACKET API. This +is needed to get access to the lowest level of the network stack in Linux. This +means that all of the Ethernet frame is included. This allows the U-Boot network +stack to be fully used. In other words, nothing about the Linux network stack is +involved in forming the packets that end up on the wire. To receive the +responses to packets sent from U-Boot the network interface has to be set to +promiscuous mode so that the network card won't filter out packets not destined +for its configured (on Linux) MAC address. + +The RAW sockets Ethernet API requires elevated privileges in Linux. You can +either run as root, or you can add the capability needed like so: + +sudo /sbin/setcap "CAP_NET_RAW+ep" /path/to/u-boot + +The default device tree for sandbox includes an entry for eth0 on the sandbox +host machine whose alias is "eth1". The following are a few examples of network +operations being tested on the eth0 interface. + +sudo /path/to/u-boot -D + +DHCP +.... + +set autoload no +set ethact eth1 +dhcp + +PING +.... + +set autoload no +set ethact eth1 +dhcp +ping $gatewayip + +TFTP +.... + +set autoload no +set ethact eth1 +dhcp +set serverip WWW.XXX.YYY.ZZZ +tftpboot u-boot.bin + + SPI Emulation -------------
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e46e57b..5bd66ea 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -29,4 +29,14 @@ config ETH_SANDBOX
This driver is particularly useful in the test/dm/eth.c tests
+config ETH_SANDBOX_RAW + depends on DM_ETH && SANDBOX + default y + bool "Sandbox: Bridge to Linux Raw Sockets" + help + This driver is a bridge from the bottom of the network stack + in U-Boot to the RAW AF_PACKET API in Linux. This allows real + network traffic to be tested from within sandbox. See + board/sandbox/README.sandbox for more details. + endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index a17198c..7d32519 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_PCNET) += pcnet.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o obj-$(CONFIG_ETH_SANDBOX) += sandbox.o +obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c new file mode 100644 index 0000000..435b874 --- /dev/null +++ b/drivers/net/sandbox-raw.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger joe.hershberger@ni.com + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <asm/eth-raw-os.h> +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <net.h> + +DECLARE_GLOBAL_DATA_PTR; + + +static int sb_eth_raw_start(struct udevice *dev) +{ + struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + const char *interface; + + debug("eth_sandbox_raw: Start\n"); + + interface = fdt_getprop(gd->fdt_blob, dev->of_offset, + "host-raw-interface", NULL); + if (interface == NULL) + return -EINVAL; + + return sandbox_eth_raw_os_start(interface, pdata->enetaddr, priv); +} + +static int sb_eth_raw_send(struct udevice *dev, void *packet, int length) +{ + struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); + + debug("eth_sandbox_raw: Send packet %d\n", length); + + return sandbox_eth_raw_os_send(packet, length, priv); +} + +static int sb_eth_raw_recv(struct udevice *dev, uchar **packetp) +{ + struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); + int retval; + int length; + + retval = sandbox_eth_raw_os_recv(net_rx_packets[0], &length, priv); + + if (!retval && length) { + debug("eth_sandbox_raw: received packet %d\n", + length); + *packetp = net_rx_packets[0]; + return length; + } + return retval; +} + +static void sb_eth_raw_stop(struct udevice *dev) +{ + struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); + + debug("eth_sandbox_raw: Stop\n"); + + sandbox_eth_raw_os_stop(priv); +} + +static const struct eth_ops sb_eth_raw_ops = { + .start = sb_eth_raw_start, + .send = sb_eth_raw_send, + .recv = sb_eth_raw_recv, + .stop = sb_eth_raw_stop, +}; + +static int sb_eth_raw_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + + pdata->iobase = dev_get_addr(dev); + return 0; +} + +static const struct udevice_id sb_eth_raw_ids[] = { + { .compatible = "sandbox,eth-raw" }, + { } +}; + +U_BOOT_DRIVER(eth_sandbox_raw) = { + .name = "eth_sandbox_raw", + .id = UCLASS_ETH, + .of_match = sb_eth_raw_ids, + .ofdata_to_platdata = sb_eth_raw_ofdata_to_platdata, + .ops = &sb_eth_raw_ops, + .priv_auto_alloc_size = sizeof(struct eth_sandbox_raw_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +};

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
Implement a bridge between U-Boot's network stack and Linux's raw packet API allowing the sandbox to send and receive packets using the host machine's network interface.
This raw Ethernet API requires elevated privileges. You can either run as root, or you can add the capability needed like so:
sudo /sbin/setcap "CAP_NET_RAW+ep" /path/to/u-boot
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

This is now testable via the eth-raw interface
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: None Changes in v4: -New to v4
Changes in v3: None Changes in v2: None
include/configs/sandbox.h | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index caf9f5a..034050e 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -127,6 +127,14 @@ #include <config_cmd_default.h>
#define CONFIG_CMD_PING +#define CONFIG_CMD_DHCP +#define CONFIG_BOOTP_DNS +#define CONFIG_BOOTP_DNS2 +#define CONFIG_BOOTP_GATEWAY +#define CONFIG_BOOTP_SEND_HOSTNAME +#define CONFIG_BOOTP_SERVERIP +#define CONFIG_BOOTP_SUBNETMASK +#define CONFIG_IP_DEFRAG
#define CONFIG_CMD_HASH #define CONFIG_HASH_VERIFY

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
This is now testable via the eth-raw interface
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

The 'lo' interface on Linux doesn't support thinks like ARP or link-layer access like we use to talk to a normal network interface. A higher-level network API must be used to access localhost.
As written, this interface is limited to not supporting ICMP since the API doesn't allow the socket to be opened for all IP traffic and be able to receive at the same time. UDP is far more useful to test with, so it was selected over ICMP. Ping won't work, but things like TFTP should work.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: -Add details about lo support to the README -Remove socket timeout -Separate init to 2 helper static functions -Set the socket to non-blocking -Use INADDR_LOOPBACK -Use more verbose comments
Changes in v4: -Added support for the 'lo' network interface
Changes in v3: None Changes in v2: None
arch/sandbox/cpu/eth-raw-os.c | 113 +++++++++++++++++++++++++++++++++- arch/sandbox/dts/sandbox.dts | 10 +++ arch/sandbox/include/asm/eth-raw-os.h | 10 ++- board/sandbox/README.sandbox | 22 +++++++ drivers/net/sandbox-raw.c | 71 ++++++++++++++++++++- 5 files changed, 221 insertions(+), 5 deletions(-)
diff --git a/arch/sandbox/cpu/eth-raw-os.c b/arch/sandbox/cpu/eth-raw-os.c index 601205a..b76a731 100644 --- a/arch/sandbox/cpu/eth-raw-os.c +++ b/arch/sandbox/cpu/eth-raw-os.c @@ -12,6 +12,8 @@ #include <fcntl.h> #include <net/if.h> #include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/udp.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -20,10 +22,11 @@ #include <sys/socket.h> #include <unistd.h>
+#include <arpa/inet.h> #include <linux/if_ether.h> #include <linux/if_packet.h>
-int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, +static int _raw_packet_start(const char *ifname, unsigned char *ethmac, struct eth_sandbox_raw_priv *priv) { struct sockaddr_ll *device; @@ -89,14 +92,114 @@ int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, return 0; }
+static int _local_inet_start(struct eth_sandbox_raw_priv *priv) +{ + struct sockaddr_in *device; + int ret; + int flags; + int one = 1; + + /* Prepare device struct */ + priv->device = malloc(sizeof(struct sockaddr_in)); + if (priv->device == NULL) + return -ENOMEM; + device = priv->device; + memset(device, 0, sizeof(struct sockaddr_in)); + device->sin_family = AF_INET; + device->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + /** + * Open socket + * Since we specify UDP here, any incoming ICMP packets will + * not be received, so things like ping will not work on this + * localhost interface. + */ + priv->sd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP); + if (priv->sd < 0) { + printf("Failed to open socket: %d %s\n", errno, + strerror(errno)); + return -errno; + } + + /* Make the socket non-blocking */ + flags = fcntl(priv->sd, F_GETFL, 0); + fcntl(priv->sd, F_SETFL, flags | O_NONBLOCK); + + /* Include the UDP/IP headers on send and receive */ + ret = setsockopt(priv->sd, IPPROTO_IP, IP_HDRINCL, &one, + sizeof(one)); + if (ret < 0) { + printf("Failed to set header include option: %d %s\n", errno, + strerror(errno)); + return -errno; + } + priv->local_bind_sd = -1; + priv->local_bind_udp_port = 0; + return 0; +} + +int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, + struct eth_sandbox_raw_priv *priv) +{ + if (priv->local) + return _local_inet_start(priv); + else + return _raw_packet_start(ifname, ethmac, priv); +} + int sandbox_eth_raw_os_send(void *packet, int length, - const struct eth_sandbox_raw_priv *priv) + struct eth_sandbox_raw_priv *priv) { int retval; + struct udphdr *udph = packet + sizeof(struct iphdr);
if (!priv->sd || !priv->device) return -EINVAL;
+ /* + * This block of code came about when testing tftp on the localhost + * interface. When using the RAW AF_INET API, the network stack is still + * in play responding to incoming traffic based on open "ports". Since + * it is raw (at the IP layer, no Ethernet) the network stack tells the + * TFTP server that the port it responded to is closed. This causes the + * TFTP transfer to be aborted. This block of code inspects the outgoing + * packet as formulated by the u-boot network stack to determine the + * source port (that the TFTP server will send packets back to) and + * opens a typical UDP socket on that port, thus preventing the network + * stack from sending that ICMP message claiming that the port has no + * bound socket. + */ + if (priv->local && (priv->local_bind_sd == -1 || + priv->local_bind_udp_port != udph->source)) { + struct iphdr *iph = packet; + struct sockaddr_in addr; + + if (priv->local_bind_sd != -1) + close(priv->local_bind_sd); + + /* A normal UDP socket is required to bind */ + priv->local_bind_sd = socket(AF_INET, SOCK_DGRAM, 0); + if (priv->local_bind_sd < 0) { + printf("Failed to open bind sd: %d %s\n", errno, + strerror(errno)); + return -errno; + } + priv->local_bind_udp_port = udph->source; + + /** + * Bind the UDP port that we intend to use as our source port + * so that the kernel will not send an ICMP port unreachable + * message to the server + */ + addr.sin_family = AF_INET; + addr.sin_port = udph->source; + addr.sin_addr.s_addr = iph->saddr; + retval = bind(priv->local_bind_sd, &addr, sizeof(addr)); + if (retval < 0) + printf("Failed to bind: %d %s\n", errno, + strerror(errno)); + } + retval = sendto(priv->sd, packet, length, 0, (struct sockaddr *)priv->device, sizeof(struct sockaddr_ll)); @@ -137,4 +240,10 @@ void sandbox_eth_raw_os_stop(struct eth_sandbox_raw_priv *priv) priv->device = NULL; close(priv->sd); priv->sd = -1; + if (priv->local) { + if (priv->local_bind_sd != -1) + close(priv->local_bind_sd); + priv->local_bind_sd = -1; + priv->local_bind_udp_port = 0; + } } diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 8002196..0eaa5a5 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -4,6 +4,10 @@ #address-cells = <1>; #size-cells = <0>;
+ aliases { + eth5 = "/eth@90000000"; + }; + chosen { stdout-path = "/serial"; }; @@ -192,4 +196,10 @@ reg = <0x80000000 0x1000>; host-raw-interface = "eth0"; }; + + eth@90000000 { + compatible = "sandbox,eth-raw"; + reg = <0x90000000 0x1000>; + host-raw-interface = "lo"; + }; }; diff --git a/arch/sandbox/include/asm/eth-raw-os.h b/arch/sandbox/include/asm/eth-raw-os.h index df60c4f..ed4b2e2 100644 --- a/arch/sandbox/include/asm/eth-raw-os.h +++ b/arch/sandbox/include/asm/eth-raw-os.h @@ -15,16 +15,24 @@ * * sd: socket descriptor - the open socket during a session * device: struct sockaddr_ll - the host interface packets move to/from + * local: 1 or 0 to select the local interface ('lo') or not + * local_bindsd: socket descriptor to prevent the kernel from sending + * a message to the server claiming the port is + * unreachable + * local_bind_udp_port: The UDP port number that we bound to */ struct eth_sandbox_raw_priv { int sd; void *device; + int local; + int local_bind_sd; + unsigned short local_bind_udp_port; };
int sandbox_eth_raw_os_start(const char *ifname, unsigned char *ethmac, struct eth_sandbox_raw_priv *priv); int sandbox_eth_raw_os_send(void *packet, int length, - const struct eth_sandbox_raw_priv *priv); + struct eth_sandbox_raw_priv *priv); int sandbox_eth_raw_os_recv(void *packet, int *length, const struct eth_sandbox_raw_priv *priv); void sandbox_eth_raw_os_stop(struct eth_sandbox_raw_priv *priv); diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox index 9f5d3f7..08489e3 100644 --- a/board/sandbox/README.sandbox +++ b/board/sandbox/README.sandbox @@ -241,6 +241,28 @@ dhcp set serverip WWW.XXX.YYY.ZZZ tftpboot u-boot.bin
+The bridge also support (to a lesser extent) the localhost inderface, 'lo'. + +The 'lo' interface cannot use the RAW AF_PACKET API because the lo interface +doesn't support Ethernet-level traffic. It is a higher-level interface that is +expected only to be used at the AF_INET level of the API. As such, the most raw +we can get on that interface is the RAW AF_INET API on UDP. This allows us to +set the IP_HDRINCL option to include everything except the Ethernet header in +the packets we send and receive. + +Because only UDP is supported, ICMP traffic will not work, so expect that ping +commands will time out. + +The default device tree for sandbox includes an entry for lo on the sandbox +host machine whose alias is "eth5". The following is an example of a network +operation being tested on the lo interface. + +TFTP +.... + +set ethact eth5 +tftpboot u-boot.bin +
SPI Emulation ------------- diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c index 435b874..91da5f5 100644 --- a/drivers/net/sandbox-raw.c +++ b/drivers/net/sandbox-raw.c @@ -15,6 +15,8 @@
DECLARE_GLOBAL_DATA_PTR;
+static int reply_arp; +static IPaddr_t arp_ip;
static int sb_eth_raw_start(struct udevice *dev) { @@ -29,6 +31,11 @@ static int sb_eth_raw_start(struct udevice *dev) if (interface == NULL) return -EINVAL;
+ if (strcmp(interface, "lo") == 0) { + priv->local = 1; + setenv("ipaddr", "127.0.0.1"); + setenv("serverip", "127.0.0.1"); + } return sandbox_eth_raw_os_start(interface, pdata->enetaddr, priv); }
@@ -38,18 +45,78 @@ static int sb_eth_raw_send(struct udevice *dev, void *packet, int length)
debug("eth_sandbox_raw: Send packet %d\n", length);
+ if (priv->local) { + struct ethernet_hdr *eth = packet; + + if (ntohs(eth->et_protlen) == PROT_ARP) { + struct arp_hdr *arp = packet + ETHER_HDR_SIZE; + + /** + * localhost works on a higher-level API in Linux than + * ARP packets, so fake it + */ + arp_ip = NetReadIP(&arp->ar_tpa); + reply_arp = 1; + return 0; + } + packet += ETHER_HDR_SIZE; + length -= ETHER_HDR_SIZE; + } return sandbox_eth_raw_os_send(packet, length, priv); }
static int sb_eth_raw_recv(struct udevice *dev, uchar **packetp) { + struct eth_pdata *pdata = dev_get_platdata(dev); struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); - int retval; + int retval = 0; int length;
- retval = sandbox_eth_raw_os_recv(net_rx_packets[0], &length, priv); + if (reply_arp) { + struct arp_hdr *arp = (void *)net_rx_packets[0] + + ETHER_HDR_SIZE; + + /* + * Fake an ARP response. The u-boot network stack is sending an + * ARP request (to find the MAC address to address the actual + * packet to) and requires an ARP response to continue. Since + * this is the localhost interface, there is no Etherent level + * traffic at all, so there is no way to send an ARP request or + * to get a response. For this reason we fake the response to + * make the u-boot network stack happy. + */ + arp->ar_hrd = htons(ARP_ETHER); + arp->ar_pro = htons(PROT_IP); + arp->ar_hln = ARP_HLEN; + arp->ar_pln = ARP_PLEN; + arp->ar_op = htons(ARPOP_REPLY); + /* Any non-zero MAC address will work */ + memset(&arp->ar_sha, 0x01, ARP_HLEN); + /* Use whatever IP we were looking for (always 127.0.0.1?) */ + NetWriteIP(&arp->ar_spa, arp_ip); + memcpy(&arp->ar_tha, pdata->enetaddr, ARP_HLEN); + NetWriteIP(&arp->ar_tpa, NetOurIP); + length = ARP_HDR_SIZE; + } else { + /* If local, the Ethernet header won't be included; skip it */ + uchar *pktptr = priv->local ? + net_rx_packets[0] + ETHER_HDR_SIZE : net_rx_packets[0]; + + retval = sandbox_eth_raw_os_recv(pktptr, &length, priv); + }
if (!retval && length) { + if (priv->local) { + struct ethernet_hdr *eth = (void *)net_rx_packets[0]; + + /* Fill in enough of the missing Ethernet header */ + memcpy(eth->et_dest, pdata->enetaddr, ARP_HLEN); + memset(eth->et_src, 0x01, ARP_HLEN); + eth->et_protlen = htons(reply_arp ? PROT_ARP : PROT_IP); + reply_arp = 0; + length += ETHER_HDR_SIZE; + } + debug("eth_sandbox_raw: received packet %d\n", length); *packetp = net_rx_packets[0];

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
The 'lo' interface on Linux doesn't support thinks like ARP or link-layer access like we use to talk to a normal network interface. A higher-level network API must be used to access localhost.
As written, this interface is limited to not supporting ICMP since the API doesn't allow the socket to be opened for all IP traffic and be able to receive at the same time. UDP is far more useful to test with, so it was selected over ICMP. Ping won't work, but things like TFTP should work.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!

Take a pass at plumbing errors through to the users of the network stack
Currently only the start() function errors will be returned from NetLoop(). recv() tends not to have errors, so that is likely not worth adding. send() certainly can return errors, but this patch does not attempt to plumb them yet. halt() is not expected to error.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v7: None Changes in v6: None Changes in v5: -New to v5
Changes in v4: None Changes in v3: None Changes in v2: None
include/net.h | 3 ++- net/eth.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-------- net/net.c | 26 ++++++++++++++++++-------- test/dm/eth.c | 4 ++-- 4 files changed, 70 insertions(+), 19 deletions(-)
diff --git a/include/net.h b/include/net.h index baccd47..a60ff03 100644 --- a/include/net.h +++ b/include/net.h @@ -541,7 +541,7 @@ int NetLoop(enum proto_t); void NetStop(void);
/* Load failed. Start again. */ -void NetStartAgain(void); +int NetStartAgain(void);
/* Get size of the ethernet header when we send */ int NetEthHdrSize(void); @@ -611,6 +611,7 @@ static inline void net_set_state(enum net_loop_state state) /* Transmit a packet */ static inline void NetSendPacket(uchar *pkt, int len) { + /* Currently no way to return errors from eth_send() */ (void) eth_send(pkt, len); }
diff --git a/net/eth.c b/net/eth.c index b6c2af3..13b7723 100644 --- a/net/eth.c +++ b/net/eth.c @@ -98,6 +98,9 @@ struct eth_uclass_priv { struct udevice *current; };
+/* eth_errno - This stores the most recent failure code from DM functions */ +static int eth_errno; + static struct eth_uclass_priv *eth_get_uclass_priv(void) { struct uclass *uc; @@ -118,20 +121,32 @@ static void eth_set_current_to_next(void) uclass_first_device(UCLASS_ETH, &uc_priv->current); }
+/* + * Typically this will simply return the active device. + * In the case where the most recent active device was unset, this will attempt + * to return the first device. If that device doesn't exist or fails to probe, + * this function will return NULL. + */ struct udevice *eth_get_dev(void) { struct eth_uclass_priv *uc_priv;
uc_priv = eth_get_uclass_priv(); if (!uc_priv->current) - uclass_first_device(UCLASS_ETH, + eth_errno = uclass_first_device(UCLASS_ETH, &uc_priv->current); return uc_priv->current; }
+/* + * Typically this will just store a device pointer. + * In case it was not probed, we will attempt to do so. + * dev may be NULL to unset the active device. + */ static void eth_set_dev(struct udevice *dev) { - device_probe(dev); + if (dev && !device_active(dev)) + eth_errno = device_probe(dev); eth_get_uclass_priv()->current = dev; }
@@ -155,7 +170,14 @@ struct udevice *eth_get_dev_by_name(const char *devname)
uclass_get(UCLASS_ETH, &uc); uclass_foreach_dev(it, uc) { - /* We need the seq to be valid, so make sure it's probed */ + /* + * We need the seq to be valid, so try to probe it. + * If the probe fails, the seq will not match since it will be + * -1 instead of what we are looking for. + * We don't care about errors from probe here. Either they won't + * match an alias or it will match a literal name and we'll pick + * up the error when we try to probe again in eth_set_dev(). + */ device_probe(it); /* * Check for the name or the sequence number to match @@ -221,6 +243,7 @@ int eth_init(void) { struct udevice *current; struct udevice *old_current; + int ret = -ENODEV;
current = eth_get_dev(); if (!current) { @@ -243,22 +266,29 @@ int eth_init(void) else memset(pdata->enetaddr, 0, 6);
- if (eth_get_ops(current)->start(current) >= 0) { + ret = eth_get_ops(current)->start(current); + if (ret >= 0) { struct eth_device_priv *priv = current->uclass_priv;
priv->state = ETH_STATE_ACTIVE; return 0; } - } + } else + ret = eth_errno; + debug("FAIL\n");
- /* This will ensure the new "current" attempted to probe */ + /* + * If ethrotate is enabled, this will change "current", + * otherwise we will drop out of this while loop immediately + */ eth_try_another(0); + /* This will ensure the new "current" attempted to probe */ current = eth_get_dev(); } while (old_current != current);
- return -ENODEV; + return ret; }
void eth_halt(void) @@ -278,6 +308,7 @@ void eth_halt(void) int eth_send(void *packet, int length) { struct udevice *current; + int ret;
current = eth_get_dev(); if (!current) @@ -286,7 +317,12 @@ int eth_send(void *packet, int length) if (!device_active(current)) return -EINVAL;
- return eth_get_ops(current)->send(current, packet, length); + ret = eth_get_ops(current)->send(current, packet, length); + if (ret < 0) { + /* We cannot completely return the error at present */ + debug("%s: send() returned error %d\n", __func__, ret); + } + return ret; }
int eth_rx(void) @@ -313,6 +349,10 @@ int eth_rx(void) } if (ret == -EAGAIN) ret = 0; + if (ret < 0) { + /* We cannot completely return the error at present */ + debug("%s: recv() returned error %d\n", __func__, ret); + } return ret; }
diff --git a/net/net.c b/net/net.c index afec443..69f38f7 100644 --- a/net/net.c +++ b/net/net.c @@ -84,6 +84,7 @@ #include <common.h> #include <command.h> #include <environment.h> +#include <errno.h> #include <net.h> #if defined(CONFIG_STATUS_LED) #include <miiphy.h> @@ -333,7 +334,7 @@ void net_init(void)
int NetLoop(enum proto_t protocol) { - int ret = -1; + int ret = -EINVAL;
NetRestarted = 0; NetDevExists = 0; @@ -345,9 +346,10 @@ int NetLoop(enum proto_t protocol) if (eth_is_on_demand_init() || protocol != NETCONS) { eth_halt(); eth_set_current(); - if (eth_init() < 0) { + ret = eth_init(); + if (ret < 0) { eth_halt(); - return -1; + return ret; } } else eth_init_state_only(); @@ -370,7 +372,7 @@ restart: case 1: /* network not configured */ eth_halt(); - return -1; + return -ENODEV;
case 2: /* network device not configured */ @@ -484,6 +486,8 @@ restart: /* * Check the ethernet for a new packet. The ethernet * receive routine will process it. + * Most drivers return the most recent packet size, but not + * errors that may have happened. */ eth_rx();
@@ -537,7 +541,7 @@ restart: }
if (net_state == NETLOOP_FAIL) - NetStartAgain(); + ret = NetStartAgain();
switch (net_state) {
@@ -597,11 +601,12 @@ startAgainTimeout(void) net_set_state(NETLOOP_RESTART); }
-void NetStartAgain(void) +int NetStartAgain(void) { char *nretry; int retry_forever = 0; unsigned long retrycnt = 0; + int ret;
nretry = getenv("netretry"); if (nretry) { @@ -621,7 +626,11 @@ void NetStartAgain(void) if ((!retry_forever) && (NetTryCount >= retrycnt)) { eth_halt(); net_set_state(NETLOOP_FAIL); - return; + /* + * We don't provide a way for the protocol to return an error, + * but this is almost always the reason. + */ + return -ETIMEDOUT; }
NetTryCount++; @@ -630,7 +639,7 @@ void NetStartAgain(void) #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER) eth_try_another(!NetRestarted); #endif - eth_init(); + ret = eth_init(); if (NetRestartWrap) { NetRestartWrap = 0; if (NetDevExists) { @@ -642,6 +651,7 @@ void NetStartAgain(void) } else { net_set_state(NETLOOP_RESTART); } + return ret; }
/**********************************************************************/ diff --git a/test/dm/eth.c b/test/dm/eth.c index a0e9359..1923670 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -99,7 +99,7 @@ static int dm_test_eth_rotate(struct dm_test_state *dms) /* If ethrotate is no, then we should fail on a bad MAC */ setenv("ethact", "eth@10004000"); setenv("ethrotate", "no"); - ut_asserteq(-1, NetLoop(PING)); + ut_asserteq(-EINVAL, NetLoop(PING)); ut_asserteq_str("eth@10004000", getenv("ethact"));
/* Restore the env */ @@ -144,7 +144,7 @@ static int dm_test_net_retry(struct dm_test_state *dms) */ setenv("ethact", "eth@10004000"); setenv("netretry", "no"); - ut_asserteq(-1, NetLoop(PING)); + ut_asserteq(-ETIMEDOUT, NetLoop(PING)); ut_asserteq_str("eth@10004000", getenv("ethact"));
/* Restore the env */

On 22 March 2015 at 16:09, Joe Hershberger joe.hershberger@ni.com wrote:
Take a pass at plumbing errors through to the users of the network stack
Currently only the start() function errors will be returned from NetLoop(). recv() tends not to have errors, so that is likely not worth adding. send() certainly can return errors, but this patch does not attempt to plumb them yet. halt() is not expected to error.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v7: None
Applied to u-boot-dm/next, thanks!
participants (4)
-
Joe Hershberger
-
Joe Hershberger
-
Simon Glass
-
Tom Rini