Add support for "net list" and "net stats" to net-lwip/ by copying the
code from cmd/net.c.

Signed-off-by: Jerome Forissier <[email protected]>
---
 cmd/net-lwip.c     | 98 ++++++++++++++++++++++++++++++++++++++++++++++
 include/net-lwip.h | 50 +++++++++++++++++++++++
 2 files changed, 148 insertions(+)

diff --git a/cmd/net-lwip.c b/cmd/net-lwip.c
index 2926399bd0..20d0d61176 100644
--- a/cmd/net-lwip.c
+++ b/cmd/net-lwip.c
@@ -2,6 +2,10 @@
 /* Copyright (C) 2024 Linaro Ltd. */
 
 #include <command.h>
+#include <dm/device.h>
+#include <dm/uclass.h>
+#include <linux/compat.h>
+#include <linux/ethtool.h>
 #include <net-lwip.h>
 
 #if defined(CONFIG_CMD_DHCP_LWIP)
@@ -43,3 +47,97 @@ U_BOOT_CMD(
        "[loadAddress] URL"
 );
 #endif
+
+static int do_net_list(struct cmd_tbl *cmdtp, int flag, int argc, char *const 
argv[])
+{
+       const struct udevice *current = eth_get_dev();
+       unsigned char env_enetaddr[ARP_HLEN];
+       const struct udevice *dev;
+       struct uclass *uc;
+
+       uclass_id_foreach_dev(UCLASS_ETH, dev, uc) {
+               eth_env_get_enetaddr_by_index("eth", dev_seq(dev), 
env_enetaddr);
+               printf("eth%d : %s %pM %s\n", dev_seq(dev), dev->name, 
env_enetaddr,
+                      current == dev ? "active" : "");
+       }
+       return CMD_RET_SUCCESS;
+}
+
+static int do_net_stats(struct cmd_tbl *cmdtp, int flag, int argc, char *const 
argv[])
+{
+       int nstats, err, i, off;
+       struct udevice *dev;
+       u64 *values;
+       u8 *strings;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       err = uclass_get_device_by_name(UCLASS_ETH, argv[1], &dev);
+       if (err) {
+               printf("Could not find device %s\n", argv[1]);
+               return CMD_RET_FAILURE;
+       }
+
+       if (!eth_get_ops(dev)->get_sset_count ||
+           !eth_get_ops(dev)->get_strings ||
+           !eth_get_ops(dev)->get_stats) {
+               printf("Driver does not implement stats dump!\n");
+               return CMD_RET_FAILURE;
+       }
+
+       nstats = eth_get_ops(dev)->get_sset_count(dev);
+       strings = kcalloc(nstats, ETH_GSTRING_LEN, GFP_KERNEL);
+       if (!strings)
+               return CMD_RET_FAILURE;
+
+       values = kcalloc(nstats, sizeof(u64), GFP_KERNEL);
+       if (!values)
+               goto err_free_strings;
+
+       eth_get_ops(dev)->get_strings(dev, strings);
+       eth_get_ops(dev)->get_stats(dev, values);
+
+       off = 0;
+       for (i = 0; i < nstats; i++) {
+               printf("  %s: %llu\n", &strings[off], values[i]);
+               off += ETH_GSTRING_LEN;
+       };
+
+       return CMD_RET_SUCCESS;
+
+err_free_strings:
+       kfree(strings);
+
+       return CMD_RET_FAILURE;
+}
+
+static struct cmd_tbl cmd_net[] = {
+       U_BOOT_CMD_MKENT(list, 1, 0, do_net_list, "", ""),
+       U_BOOT_CMD_MKENT(stats, 2, 0, do_net_stats, "", ""),
+};
+
+static int do_net(struct cmd_tbl *cmdtp, int flag, int argc, char *const 
argv[])
+{
+       struct cmd_tbl *cp;
+
+       cp = find_cmd_tbl(argv[1], cmd_net, ARRAY_SIZE(cmd_net));
+
+       /* Drop the net command */
+       argc--;
+       argv++;
+
+       if (!cp || argc > cp->maxargs)
+               return CMD_RET_USAGE;
+       if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
+               return CMD_RET_SUCCESS;
+
+       return cp->cmd(cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(
+       net, 3, 1, do_net,
+       "NET sub-system",
+       "list - list available devices\n"
+       "stats <device> - dump statistics for specified device\n"
+);
diff --git a/include/net-lwip.h b/include/net-lwip.h
index 23ad70fc09..6fda940fec 100644
--- a/include/net-lwip.h
+++ b/include/net-lwip.h
@@ -51,6 +51,56 @@ int eth_env_get_enetaddr_by_index(const char *base_name, int 
index,
 int eth_init(void);                    /* Initialize the device */
 int eth_send(void *packet, int length);           /* Send a packet */
 int eth_rx(void);
+
+/**
+ * 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. 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. If 0 is returned, the
+ *      network stack will not process the empty packet, but free_pkt() will be
+ *      called if supplied
+ * free_pkt: Give the driver an opportunity to manage its packet buffer memory
+ *          when the network stack is finished processing it. This will only be
+ *          called when no error was returned from recv - optional
+ * 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. The method can
+ *              return -ENOSYS to indicate that this is not implemented for
+                this hardware - 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
+ * set_promisc: Enable or Disable promiscuous mode
+ * get_sset_count: Number of statistics counters
+ * get_string: Names of the statistic counters
+ * get_stats: The values of the statistic counters
+ */
+struct eth_ops {
+       int (*start)(struct udevice *dev);
+       int (*send)(struct udevice *dev, void *packet, int length);
+       int (*recv)(struct udevice *dev, int flags, uchar **packetp);
+       int (*free_pkt)(struct udevice *dev, uchar *packet, int length);
+       void (*stop)(struct udevice *dev);
+       int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join);
+       int (*write_hwaddr)(struct udevice *dev);
+       int (*read_rom_hwaddr)(struct udevice *dev);
+       int (*set_promisc)(struct udevice *dev, bool enable);
+       int (*get_sset_count)(struct udevice *dev);
+       void (*get_strings)(struct udevice *dev, u8 *data);
+       void (*get_stats)(struct udevice *dev, u64 *data);
+};
+
+#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
+
+struct udevice *eth_get_dev(void); /* get the current device */
+int eth_get_dev_index(void);
 const char *eth_get_name(void);
 int eth_get_dev_index(void);
 int eth_init_state_only(void); /* Set active state */
-- 
2.40.1

Reply via email to