All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] NC-SI PHY Support
@ 2019-06-18  1:37 ` Samuel Mendoza-Jonas
  0 siblings, 0 replies; 34+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-18  1:37 UTC (permalink / raw)
  To: u-boot; +Cc: Samuel Mendoza-Jonas, joel, clg, openbmc, joe.hershberger, sjg

This series introduces support for the NC-SI protocol to u-boot,
functionality which so far has only been available in vendor trees.

NC-SI (Network Controller Sideband Interface) is a protocol to manage a
sideband connection to a proper network interface, for example a BMC
(Baseboard Management Controller) sharing the NIC of the host system.
Probing and configuration occurs by communicating with the "remote" NIC
via NC-SI control frames (Ethernet header 0x88f8).

Since the RFC[0] the changes have been split out into a few different
patches to make the overall changes more obvious. Additionally a few
small improvements have been added including adding a check to see if
NC-SI is already configured, and marking the PHY bus "reset" as invalid
since it does not define a bus.

An example of NC-SI setup before a normal network command:

=> dhcp
net_loop: configuring NCSI first
ethernet@1e660000: link up, 100 Mbps full-duplex mac:0c:c4:7a:d5:48:43
NCSI: probing channels
NCSI: configuring channel 0
NCSI: configuration done!
BOOTP broadcast 1
BOOTP broadcast 2
DHCP client bound to address 10.61.161.188 (255 ms)

[0]: https://patchwork.ozlabs.org/patch/1107087/

Changes in v2:
- Fix endianess issue when setting MAC address
- Make checksum offsets easier to read
- Instantiate per-phy ncsi_priv structures
- Update ncsi command help text
- Used update ncsi-pkt.h version to include SPDX header


Samuel Mendoza-Jonas (4):
  phy: Add support for the NC-SI protocol
  phy: Include NC-SI in phy setup
  net/ftgmac100: Add NC-SI mode support
  net: NC-SI setup and handling

 cmd/Kconfig              |   8 +
 cmd/net.c                |  18 +
 drivers/net/ftgmac100.c  |  39 +-
 drivers/net/phy/Kconfig  |   4 +
 drivers/net/phy/Makefile |   1 +
 drivers/net/phy/ncsi.c   | 896 +++++++++++++++++++++++++++++++++++++++
 drivers/net/phy/phy.c    |   7 +
 include/net.h            |   3 +-
 include/net/ncsi-pkt.h   | 442 +++++++++++++++++++
 include/net/ncsi.h       |  14 +
 include/phy.h            |  12 +
 include/phy_interface.h  |   2 +
 net/net.c                |  27 +-
 13 files changed, 1461 insertions(+), 12 deletions(-)
 create mode 100644 drivers/net/phy/ncsi.c
 create mode 100644 include/net/ncsi-pkt.h
 create mode 100644 include/net/ncsi.h

-- 
2.21.0

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 0/4] NC-SI PHY Support
@ 2019-06-18  1:37 ` Samuel Mendoza-Jonas
  0 siblings, 0 replies; 34+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-18  1:37 UTC (permalink / raw)
  To: u-boot

This series introduces support for the NC-SI protocol to u-boot,
functionality which so far has only been available in vendor trees.

NC-SI (Network Controller Sideband Interface) is a protocol to manage a
sideband connection to a proper network interface, for example a BMC
(Baseboard Management Controller) sharing the NIC of the host system.
Probing and configuration occurs by communicating with the "remote" NIC
via NC-SI control frames (Ethernet header 0x88f8).

Since the RFC[0] the changes have been split out into a few different
patches to make the overall changes more obvious. Additionally a few
small improvements have been added including adding a check to see if
NC-SI is already configured, and marking the PHY bus "reset" as invalid
since it does not define a bus.

An example of NC-SI setup before a normal network command:

=> dhcp
net_loop: configuring NCSI first
ethernet at 1e660000: link up, 100 Mbps full-duplex mac:0c:c4:7a:d5:48:43
NCSI: probing channels
NCSI: configuring channel 0
NCSI: configuration done!
BOOTP broadcast 1
BOOTP broadcast 2
DHCP client bound to address 10.61.161.188 (255 ms)

[0]: https://patchwork.ozlabs.org/patch/1107087/

Changes in v2:
- Fix endianess issue when setting MAC address
- Make checksum offsets easier to read
- Instantiate per-phy ncsi_priv structures
- Update ncsi command help text
- Used update ncsi-pkt.h version to include SPDX header


Samuel Mendoza-Jonas (4):
  phy: Add support for the NC-SI protocol
  phy: Include NC-SI in phy setup
  net/ftgmac100: Add NC-SI mode support
  net: NC-SI setup and handling

 cmd/Kconfig              |   8 +
 cmd/net.c                |  18 +
 drivers/net/ftgmac100.c  |  39 +-
 drivers/net/phy/Kconfig  |   4 +
 drivers/net/phy/Makefile |   1 +
 drivers/net/phy/ncsi.c   | 896 +++++++++++++++++++++++++++++++++++++++
 drivers/net/phy/phy.c    |   7 +
 include/net.h            |   3 +-
 include/net/ncsi-pkt.h   | 442 +++++++++++++++++++
 include/net/ncsi.h       |  14 +
 include/phy.h            |  12 +
 include/phy_interface.h  |   2 +
 net/net.c                |  27 +-
 13 files changed, 1461 insertions(+), 12 deletions(-)
 create mode 100644 drivers/net/phy/ncsi.c
 create mode 100644 include/net/ncsi-pkt.h
 create mode 100644 include/net/ncsi.h

-- 
2.21.0

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v2 1/4] phy: Add support for the NC-SI protocol
  2019-06-18  1:37 ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-18  1:37   ` Samuel Mendoza-Jonas
  -1 siblings, 0 replies; 34+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-18  1:37 UTC (permalink / raw)
  To: u-boot; +Cc: Samuel Mendoza-Jonas, joel, clg, openbmc, joe.hershberger, sjg

This introduces support for the NC-SI protocol, modelled as a phy driver
for other ethernet drivers to consume.

NC-SI (Network Controller Sideband Interface) is a protocol to manage a
sideband connection to a proper network interface, for example a BMC
(Baseboard Management Controller) sharing the NIC of the host system.
Probing and configuration occurs by communicating with the "remote" NIC
via NC-SI control frames (Ethernet header 0x88f8).

This implementation is roughly based on the upstream Linux
implementation[0], with a reduced feature set and an emphasis on getting
a link up as fast as possible rather than probing the full possible
topology of the bus.
The current phy model relies on the network being "up", sending NC-SI
command frames via net_send_packet() and receiving them from the
net_loop() loop (added in a following patch).

The ncsi-pkt.h header[1] is copied from the Linux kernel for consistent
field definitions.

[0]: https://github.com/torvalds/linux/tree/master/net/ncsi
[1]: https://github.com/torvalds/linux/blob/master/net/ncsi/ncsi-pkt.h

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
v2:
- Fix endianess issue when setting MAC address
- Make checksum offsets easier to read
- Instantiate per-phy ncsi_priv structures
- Used update ncsi-pkt.h version to include SPDX header

 drivers/net/phy/Kconfig  |   4 +
 drivers/net/phy/Makefile |   1 +
 drivers/net/phy/ncsi.c   | 896 +++++++++++++++++++++++++++++++++++++++
 include/net.h            |   1 +
 include/net/ncsi-pkt.h   | 442 +++++++++++++++++++
 include/net/ncsi.h       |  14 +
 include/phy.h            |   1 +
 7 files changed, 1359 insertions(+)
 create mode 100644 drivers/net/phy/ncsi.c
 create mode 100644 include/net/ncsi-pkt.h
 create mode 100644 include/net/ncsi.h

diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 2a3da068c9..35d96ab34b 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -238,4 +238,8 @@ config PHY_FIXED
 	  on, the link is always up with fixed speed and fixed duplex-setting.
 	  More information: doc/device-tree-bindings/net/fixed-link.txt
 
+config PHY_NCSI
+	bool "NC-SI based PHY"
+	depends on DM_ETH
+
 endif #PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 555da83630..32a8409a85 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -30,3 +30,4 @@ obj-$(CONFIG_PHY_XILINX) += xilinx_phy.o
 obj-$(CONFIG_PHY_VITESSE) += vitesse.o
 obj-$(CONFIG_PHY_MSCC) += mscc.o
 obj-$(CONFIG_PHY_FIXED) += fixed.o
+obj-$(CONFIG_PHY_NCSI) += ncsi.o
diff --git a/drivers/net/phy/ncsi.c b/drivers/net/phy/ncsi.c
new file mode 100644
index 0000000000..4d0ea48b04
--- /dev/null
+++ b/drivers/net/phy/ncsi.c
@@ -0,0 +1,896 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * NC-SI protocol configuration
+ *
+ * Copyright (C) 2019, IBM Corporation.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <phy.h>
+#include <net/ncsi.h>
+#include <net/ncsi-pkt.h>
+#include <asm/unaligned.h>
+
+#define NCSI_PACKAGE_MAX 8
+#define NCSI_CHANNEL_MAX 31
+
+#define NCSI_PACKAGE_SHIFT      5
+#define NCSI_PACKAGE_INDEX(c)   (((c) >> NCSI_PACKAGE_SHIFT) & 0x7)
+#define NCSI_RESERVED_CHANNEL   0x1f
+#define NCSI_CHANNEL_INDEX(c)   ((c) & ((1 << NCSI_PACKAGE_SHIFT) - 1))
+#define NCSI_TO_CHANNEL(p, c)   (((p) << NCSI_PACKAGE_SHIFT) | (c))
+
+#define NCSI_PKT_REVISION       0x01
+
+#define NCSI_CAP_GENERIC_MASK	0x7f
+#define NCSI_CAP_BC_MASK	0x0f
+#define NCSI_CAP_MC_MASK	0x3f
+#define NCSI_CAP_AEN_MASK	0x07
+#define NCSI_CAP_VLAN_MASK	0x07
+
+static void ncsi_send_ebf(unsigned int np, unsigned int nc);
+static void ncsi_send_ae(unsigned int np, unsigned int nc);
+static void ncsi_send_gls(unsigned int np, unsigned int nc);
+static int ncsi_send_command(unsigned int np, unsigned int nc, unsigned int cmd,
+			     uchar *payload, int len, bool wait);
+
+struct ncsi_channel {
+	unsigned int	id;
+	bool		has_link;
+
+	/* capabilities */
+	u32 cap_generic;
+	u32 cap_bc;
+	u32 cap_mc;
+	u32 cap_buffer;
+	u32 cap_aen;
+	u32 cap_vlan;
+
+	/* version information */
+	struct {
+		u32 version;            /* Supported BCD encoded NCSI version */
+		u32 alpha2;             /* Supported BCD encoded NCSI version */
+		u8  fw_name[12];        /* Firmware name string               */
+		u32 fw_version;         /* Firmware version                   */
+		u16 pci_ids[4];         /* PCI identification                 */
+		u32 mf_id;              /* Manufacture ID                     */
+	} version;
+
+};
+
+struct ncsi_package {
+	unsigned int		id;
+	unsigned int		n_channels;
+	struct ncsi_channel	*channels;
+};
+
+struct ncsi {
+	enum {
+		NCSI_PROBE_PACKAGE_SP,
+		NCSI_PROBE_PACKAGE_DP,
+		NCSI_PROBE_CHANNEL_SP,
+		NCSI_PROBE_CHANNEL,
+		NCSI_CONFIG,
+	} state;
+
+	unsigned int	pending_requests;
+	unsigned int	requests[256];
+	unsigned int	last_request;
+
+	unsigned int	current_package;
+	unsigned int	current_channel;
+
+	unsigned int		n_packages;
+	struct ncsi_package	*packages;
+};
+
+struct ncsi *ncsi_priv;
+
+bool ncsi_active(void)
+{
+	unsigned int np, nc;
+
+	if (!ncsi_priv)
+		return false;
+
+	np = ncsi_priv->current_package;
+	nc = ncsi_priv->current_channel;
+
+	if (ncsi_priv->state != NCSI_CONFIG)
+		return false;
+
+	return np < NCSI_PACKAGE_MAX && nc < NCSI_CHANNEL_MAX &&
+		ncsi_priv->packages[np].channels[nc].has_link;
+}
+
+static unsigned int cmd_payload(int cmd)
+{
+	switch (cmd) {
+	case NCSI_PKT_CMD_CIS:
+		return 0;
+	case NCSI_PKT_CMD_SP:
+		return 4;
+	case NCSI_PKT_CMD_DP:
+		return 0;
+	case NCSI_PKT_CMD_EC:
+		return 0;
+	case NCSI_PKT_CMD_DC:
+		return 4;
+	case NCSI_PKT_CMD_RC:
+		return 4;
+	case NCSI_PKT_CMD_ECNT:
+		return 0;
+	case NCSI_PKT_CMD_DCNT:
+		return 0;
+	case NCSI_PKT_CMD_AE:
+		return 8;
+	case NCSI_PKT_CMD_SL:
+		return 8;
+	case NCSI_PKT_CMD_GLS:
+		return 0;
+	case NCSI_PKT_CMD_SVF:
+		return 8;
+	case NCSI_PKT_CMD_EV:
+		return 4;
+	case NCSI_PKT_CMD_DV:
+		return 0;
+	case NCSI_PKT_CMD_SMA:
+		return 8;
+	case NCSI_PKT_CMD_EBF:
+		return 4;
+	case NCSI_PKT_CMD_DBF:
+		return 0;
+	case NCSI_PKT_CMD_EGMF:
+		return 4;
+	case NCSI_PKT_CMD_DGMF:
+		return 0;
+	case NCSI_PKT_CMD_SNFC:
+		return 4;
+	case NCSI_PKT_CMD_GVI:
+		return 0;
+	case NCSI_PKT_CMD_GC:
+		return 0;
+	case NCSI_PKT_CMD_GP:
+		return 0;
+	case NCSI_PKT_CMD_GCPS:
+		return 0;
+	case NCSI_PKT_CMD_GNS:
+		return 0;
+	case NCSI_PKT_CMD_GNPTS:
+		return 0;
+	case NCSI_PKT_CMD_GPS:
+		return 0;
+	default:
+		printf("NCSI: Unknown command 0x%02x\n", cmd);
+		return 0;
+	}
+}
+
+static u32 ncsi_calculate_checksum(unsigned char *data, int len)
+{
+	u32 checksum = 0;
+	int i;
+
+	for (i = 0; i < len; i += 2)
+		checksum += (((u32)data[i] << 8) | data[i + 1]);
+
+	checksum = (~checksum + 1);
+	return checksum;
+}
+
+static int ncsi_validate_rsp(struct ncsi_rsp_pkt *pkt, int payload)
+{
+	struct ncsi_rsp_pkt_hdr *hdr = &pkt->rsp;
+	u32 checksum, c_offset;
+	__be32 pchecksum;
+
+	if (hdr->common.revision != 1) {
+		printf("NCSI: 0x%02x response has unsupported revision 0x%x\n",
+		       hdr->common.type, hdr->common.revision);
+		return -1;
+	}
+
+	if (hdr->code != 0) {
+		printf("NCSI: 0x%02x response returns error %d\n",
+		       hdr->common.type, __be16_to_cpu(hdr->code));
+		if (ntohs(hdr->reason) == 0x05)
+			printf("(Invalid command length)\n");
+		return -1;
+	}
+
+	if (ntohs(hdr->common.length) != payload) {
+		printf("NCSI: 0x%02x response has incorrect length %d\n",
+		       hdr->common.type, hdr->common.length);
+		return -1;
+	}
+
+	c_offset = sizeof(struct ncsi_rsp_pkt_hdr) + payload - sizeof(checksum);
+	pchecksum = get_unaligned_be32((void *)hdr + c_offset);
+	if (pchecksum != 0) {
+		checksum = ncsi_calculate_checksum((unsigned char *)hdr,
+						   c_offset);
+		if (pchecksum != checksum) {
+			printf("NCSI: 0x%02x response has invalid checksum\n",
+			       hdr->common.type);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static void ncsi_rsp_ec(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	if (ncsi_priv->packages[np].channels[nc].cap_aen != 0)
+		ncsi_send_ae(np, nc);
+	/* else, done */
+}
+
+static void ncsi_rsp_ecnt(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_EC, NULL, 0, true);
+}
+
+static void ncsi_rsp_ebf(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_ECNT, NULL, 0, true);
+}
+
+static void ncsi_rsp_sma(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	ncsi_send_ebf(np, nc);
+}
+
+static void ncsi_rsp_gc(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_gc_pkt *gc = (struct ncsi_rsp_gc_pkt *)pkt;
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&gc->rsp;
+	struct ncsi_channel *c;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	if (np >= ncsi_priv->n_packages ||
+	    nc >= ncsi_priv->packages[np].n_channels) {
+		printf("NCSI: Invalid package / channel (0x%02x, 0x%02x)\n",
+		       np, nc);
+		return;
+	}
+
+	c = &ncsi_priv->packages[np].channels[nc];
+	c->cap_generic = ntohl(gc->cap) & NCSI_CAP_GENERIC_MASK;
+	c->cap_bc = ntohl(gc->bc_cap) & NCSI_CAP_BC_MASK;
+	c->cap_mc = ntohl(gc->mc_cap) & NCSI_CAP_MC_MASK;
+	c->cap_aen = ntohl(gc->aen_cap) & NCSI_CAP_AEN_MASK;
+	c->cap_vlan = ntohl(gc->vlan_mode) & NCSI_CAP_VLAN_MASK;
+
+	/* End of probe for this channel */
+}
+
+static void ncsi_rsp_gvi(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_gvi_pkt *gvi = (struct ncsi_rsp_gvi_pkt *)pkt;
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&gvi->rsp;
+	struct ncsi_channel *c;
+	unsigned int np, nc, i;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	if (np >= ncsi_priv->n_packages ||
+	    nc >= ncsi_priv->packages[np].n_channels) {
+		printf("NCSI: Invalid package / channel (0x%02x, 0x%02x)\n",
+		       np, nc);
+		return;
+	}
+
+	c = &ncsi_priv->packages[np].channels[nc];
+	c->version.version = get_unaligned_be32(&gvi->ncsi_version);
+	c->version.alpha2 = gvi->alpha2;
+	memcpy(c->version.fw_name, gvi->fw_name, sizeof(c->version.fw_name));
+	c->version.fw_version = get_unaligned_be32(&gvi->fw_version);
+	for (i = 0; i < ARRAY_SIZE(c->version.pci_ids); i++)
+		c->version.pci_ids[i] = get_unaligned_be16(gvi->pci_ids + i);
+	c->version.mf_id = get_unaligned_be32(&gvi->mf_id);
+
+	if (ncsi_priv->state == NCSI_PROBE_CHANNEL)
+		ncsi_send_command(np, nc, NCSI_PKT_CMD_GC, NULL, 0, true);
+}
+
+static void ncsi_rsp_gls(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_gls_pkt *gls = (struct ncsi_rsp_gls_pkt *)pkt;
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&gls->rsp;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	if (np >= ncsi_priv->n_packages ||
+	    nc >= ncsi_priv->packages[np].n_channels) {
+		printf("NCSI: Invalid package / channel (0x%02x, 0x%02x)\n",
+		       np, nc);
+		return;
+	}
+
+	ncsi_priv->packages[np].channels[nc].has_link =
+					!!(get_unaligned_be32(&gls->status));
+
+	if (ncsi_priv->state == NCSI_PROBE_CHANNEL)
+		ncsi_send_command(np, nc, NCSI_PKT_CMD_GVI, NULL, 0, true);
+}
+
+static void ncsi_rsp_cis(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)pkt;
+	struct ncsi_package *package;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	if (np >= ncsi_priv->n_packages) {
+		printf("NCSI: Mystery package 0x%02x from CIS\n", np);
+		return;
+	}
+
+	package = &ncsi_priv->packages[np];
+
+	if (nc < package->n_channels) {
+		/*
+		 * This is fine in general but in the current design we
+		 * don't send CIS commands to known channels.
+		 */
+		debug("NCSI: Duplicate channel 0x%02x\n", nc);
+		return;
+	}
+
+	package->channels = realloc(package->channels,
+				    sizeof(struct ncsi_channel) *
+				    (package->n_channels + 1));
+	if (!package->channels) {
+		printf("NCSI: Could not allocate memory for new channel\n");
+		return;
+	}
+
+	debug("NCSI: New channel 0x%02x\n", nc);
+
+	package->channels[nc].id = nc;
+	package->channels[nc].has_link = false;
+	package->n_channels++;
+
+	ncsi_send_gls(np, nc);
+}
+
+static void ncsi_rsp_dp(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)pkt;
+	unsigned int np;
+
+	/* No action needed */
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	if (np >= ncsi_priv->n_packages)
+		debug("NCSI: DP response from unknown package %d\n", np);
+}
+
+static void ncsi_rsp_sp(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)pkt;
+	unsigned int np;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+
+	if (np < ncsi_priv->n_packages) {
+		/* Already know about this package */
+		debug("NCSI: package 0x%02x selected\n", np);
+		return;
+	}
+
+	debug("NCSI: adding new package %d\n", np);
+
+	ncsi_priv->packages = realloc(ncsi_priv->packages,
+				      sizeof(struct ncsi_package) *
+				      (ncsi_priv->n_packages + 1));
+	if (!ncsi_priv->packages) {
+		printf("NCSI: could not allocate memory for new package\n");
+		return;
+	}
+
+	ncsi_priv->packages[np].id = np;
+	ncsi_priv->packages[np].n_channels = 0;
+	ncsi_priv->packages[np].channels = NULL;
+	ncsi_priv->n_packages++;
+}
+
+static void ncsi_update_state(struct ncsi_rsp_pkt_hdr *nh)
+{
+	bool timeout = !nh;
+	int np, nc;
+
+	switch (ncsi_priv->state) {
+	case NCSI_PROBE_PACKAGE_SP:
+		if (!timeout &&
+		    ncsi_priv->current_package + 1 < NCSI_PACKAGE_MAX) {
+			ncsi_priv->current_package++;
+		} else {
+			ncsi_priv->state = NCSI_PROBE_PACKAGE_DP;
+			ncsi_priv->current_package = 0;
+		}
+		return ncsi_probe_packages();
+	case NCSI_PROBE_PACKAGE_DP:
+		if (ncsi_priv->current_package + 1 < ncsi_priv->n_packages &&
+		    !timeout) {
+			ncsi_priv->current_package++;
+		} else {
+			if (!ncsi_priv->n_packages) {
+				printf("NCSI: no packages found\n");
+				net_set_state(NETLOOP_FAIL);
+				return;
+			}
+			printf("NCSI: probing channels\n");
+			ncsi_priv->state = NCSI_PROBE_CHANNEL_SP;
+			ncsi_priv->current_package = 0;
+			ncsi_priv->current_channel = 0;
+		}
+		return ncsi_probe_packages();
+	case NCSI_PROBE_CHANNEL_SP:
+		if (!timeout && nh->common.type == NCSI_PKT_RSP_SP) {
+			ncsi_priv->state = NCSI_PROBE_CHANNEL;
+			return ncsi_probe_packages();
+		}
+		printf("NCSI: failed to select package 0x%0x2 or timeout\n",
+		       ncsi_priv->current_package);
+		net_set_state(NETLOOP_FAIL);
+		break;
+	case NCSI_PROBE_CHANNEL:
+		// TODO only does package 0 for now
+		if (ncsi_priv->pending_requests == 0) {
+			np = ncsi_priv->current_package;
+			nc = ncsi_priv->current_channel;
+
+			/* Configure first channel that has link */
+			if (ncsi_priv->packages[np].channels[nc].has_link) {
+				ncsi_priv->state = NCSI_CONFIG;
+			} else if (ncsi_priv->current_channel + 1 <
+				   NCSI_CHANNEL_MAX) {
+				ncsi_priv->current_channel++;
+			} else {
+				// XXX As above only package 0
+				printf("NCSI: no channel found with link\n");
+				net_set_state(NETLOOP_FAIL);
+				return;
+			}
+			return ncsi_probe_packages();
+		}
+		break;
+	case NCSI_CONFIG:
+		if (ncsi_priv->pending_requests == 0) {
+			printf("NCSI: configuration done!\n");
+			net_set_state(NETLOOP_SUCCESS);
+		} else if (timeout) {
+			printf("NCSI: timeout during configure\n");
+			net_set_state(NETLOOP_FAIL);
+		}
+		break;
+	default:
+		printf("NCSI: something went very wrong, nevermind\n");
+		net_set_state(NETLOOP_FAIL);
+		break;
+	}
+}
+
+static void ncsi_timeout_handler(void)
+{
+	if (ncsi_priv->pending_requests)
+		ncsi_priv->pending_requests--;
+
+	ncsi_update_state(NULL);
+}
+
+static int ncsi_send_command(unsigned int np, unsigned int nc, unsigned int cmd,
+			     uchar *payload, int len, bool wait)
+{
+	struct ncsi_pkt_hdr *hdr;
+	__be32 *pchecksum;
+	int eth_hdr_size;
+	u32 checksum;
+	uchar *pkt, *start;
+	int final_len;
+
+	pkt = calloc(1, PKTSIZE_ALIGN + PKTALIGN);
+	if (!pkt)
+		return -ENOMEM;
+	start = pkt;
+
+	eth_hdr_size = net_set_ether(pkt, net_bcast_ethaddr, PROT_NCSI);
+	pkt += eth_hdr_size;
+
+	/* Set NCSI command header fields */
+	hdr = (struct ncsi_pkt_hdr *)pkt;
+	hdr->mc_id = 0;
+	hdr->revision = NCSI_PKT_REVISION;
+	hdr->id = ++ncsi_priv->last_request;
+	ncsi_priv->requests[ncsi_priv->last_request] = 1;
+	hdr->type = cmd;
+	hdr->channel = NCSI_TO_CHANNEL(np, nc);
+	hdr->length = htons(len);
+
+	if (payload && len)
+		memcpy(pkt + sizeof(struct ncsi_pkt_hdr), payload, len);
+
+	/* Calculate checksum */
+	checksum = ncsi_calculate_checksum((unsigned char *)hdr,
+					   sizeof(*hdr) + len);
+	pchecksum = (__be32 *)((void *)(hdr + 1) + len);
+	put_unaligned_be32(htonl(checksum), pchecksum);
+
+	if (wait) {
+		net_set_timeout_handler(1000UL, ncsi_timeout_handler);
+		ncsi_priv->pending_requests++;
+	}
+
+	if (len < 26)
+		len = 26;
+	/* frame header, packet header, payload, checksum */
+	final_len = eth_hdr_size + sizeof(struct ncsi_cmd_pkt_hdr) + len + 4;
+
+	net_send_packet(start, final_len);
+	free(start);
+	return 0;
+}
+
+static void ncsi_handle_aen(struct ip_udp_hdr *ip, unsigned int len)
+{
+	struct ncsi_aen_pkt_hdr *hdr = (struct ncsi_aen_pkt_hdr *)ip;
+	int payload, i;
+	__be32 pchecksum;
+	u32 checksum;
+
+	switch (hdr->type) {
+	case NCSI_PKT_AEN_LSC:
+		printf("NCSI: link state changed\n");
+		payload = 12;
+		break;
+	case NCSI_PKT_AEN_CR:
+		printf("NCSI: re-configuration required\n");
+		payload = 4;
+		break;
+	case NCSI_PKT_AEN_HNCDSC:
+		/* Host notifcation - N/A but weird */
+		debug("NCSI: HNCDSC AEN received\n");
+		return;
+	default:
+		printf("%s: Invalid type 0x%02x\n", __func__, hdr->type);
+		return;
+	}
+
+	/* Validate packet */
+	if (hdr->common.revision != 1) {
+		printf("NCSI: 0x%02x response has unsupported revision 0x%x\n",
+		       hdr->common.type, hdr->common.revision);
+		return;
+	}
+
+	if (ntohs(hdr->common.length) != payload) {
+		printf("NCSI: 0x%02x response has incorrect length %d\n",
+		       hdr->common.type, hdr->common.length);
+		return;
+	}
+
+	pchecksum = get_unaligned_be32((void *)(hdr + 1) + payload - 4);
+	if (pchecksum != 0) {
+		checksum = ncsi_calculate_checksum((unsigned char *)hdr,
+						   sizeof(*hdr) + payload - 4);
+		if (pchecksum != checksum) {
+			printf("NCSI: 0x%02x response has invalid checksum\n",
+			       hdr->common.type);
+			return;
+		}
+	}
+
+	/* Link or configuration lost - just redo the discovery process */
+	ncsi_priv->state = NCSI_PROBE_PACKAGE_SP;
+	for (i = 0; i < ncsi_priv->n_packages; i++)
+		free(ncsi_priv->packages[i].channels);
+	free(ncsi_priv->packages);
+	ncsi_priv->n_packages = 0;
+
+	ncsi_priv->current_package = NCSI_PACKAGE_MAX;
+	ncsi_priv->current_channel = NCSI_CHANNEL_MAX;
+
+	ncsi_probe_packages();
+}
+
+void ncsi_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip,
+		  unsigned int len)
+{
+	struct ncsi_rsp_pkt *pkt = (struct ncsi_rsp_pkt *)ip;
+	struct ncsi_rsp_pkt_hdr *nh = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp;
+	void (*handler)(struct ncsi_rsp_pkt *pkt) = NULL;
+	unsigned short payload;
+
+	if (ncsi_priv->pending_requests)
+		ncsi_priv->pending_requests--;
+
+	if (len < sizeof(struct ncsi_rsp_pkt_hdr)) {
+		printf("NCSI: undersized packet: %u bytes\n", len);
+		goto out;
+	}
+
+	if (nh->common.type == NCSI_PKT_AEN)
+		return ncsi_handle_aen(ip, len);
+
+	switch (nh->common.type) {
+	case NCSI_PKT_RSP_SP:
+		payload = 4;
+		handler = ncsi_rsp_sp;
+		break;
+	case NCSI_PKT_RSP_DP:
+		payload = 4;
+		handler = ncsi_rsp_dp;
+		break;
+	case NCSI_PKT_RSP_CIS:
+		payload = 4;
+		handler = ncsi_rsp_cis;
+		break;
+	case NCSI_PKT_RSP_GLS:
+		payload = 16;
+		handler = ncsi_rsp_gls;
+		break;
+	case NCSI_PKT_RSP_GVI:
+		payload = 40;
+		handler = ncsi_rsp_gvi;
+		break;
+	case NCSI_PKT_RSP_GC:
+		payload = 32;
+		handler = ncsi_rsp_gc;
+		break;
+	case NCSI_PKT_RSP_SMA:
+		payload = 4;
+		handler = ncsi_rsp_sma;
+		break;
+	case NCSI_PKT_RSP_EBF:
+		payload = 4;
+		handler = ncsi_rsp_ebf;
+		break;
+	case NCSI_PKT_RSP_ECNT:
+		payload = 4;
+		handler = ncsi_rsp_ecnt;
+		break;
+	case NCSI_PKT_RSP_EC:
+		payload = 4;
+		handler = ncsi_rsp_ec;
+		break;
+	case NCSI_PKT_RSP_AE:
+		payload = 4;
+		handler = NULL;
+		break;
+	default:
+		printf("NCSI: unsupported packet type 0x%02x\n",
+		       nh->common.type);
+		goto out;
+	}
+
+	if (ncsi_validate_rsp(pkt, payload) != 0) {
+		printf("NCSI: discarding invalid packet of type 0x%02x\n",
+		       nh->common.type);
+		goto out;
+	}
+
+	if (handler)
+		handler(pkt);
+out:
+	ncsi_update_state(nh);
+}
+
+static void ncsi_send_sp(unsigned int np)
+{
+	uchar payload[4] = {0};
+
+	ncsi_send_command(np, NCSI_RESERVED_CHANNEL, NCSI_PKT_CMD_SP,
+			  (unsigned char *)&payload,
+			  cmd_payload(NCSI_PKT_CMD_SP), true);
+}
+
+static void ncsi_send_dp(unsigned int np)
+{
+	ncsi_send_command(np, NCSI_RESERVED_CHANNEL, NCSI_PKT_CMD_DP, NULL, 0,
+			  true);
+}
+
+static void ncsi_send_gls(unsigned int np, unsigned int nc)
+{
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_GLS, NULL, 0, true);
+}
+
+static void ncsi_send_cis(unsigned int np, unsigned int nc)
+{
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_CIS, NULL, 0, true);
+}
+
+static void ncsi_send_ae(unsigned int np, unsigned int nc)
+{
+	struct ncsi_cmd_ae_pkt cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.mode = htonl(ncsi_priv->packages[np].channels[nc].cap_aen);
+
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_AE,
+			  ((unsigned char *)&cmd)
+			  + sizeof(struct ncsi_cmd_pkt_hdr),
+			  cmd_payload(NCSI_PKT_CMD_AE), true);
+}
+
+static void ncsi_send_ebf(unsigned int np, unsigned int nc)
+{
+	struct ncsi_cmd_ebf_pkt cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.mode = htonl(ncsi_priv->packages[np].channels[nc].cap_bc);
+
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_EBF,
+			  ((unsigned char *)&cmd)
+			  + sizeof(struct ncsi_cmd_pkt_hdr),
+			  cmd_payload(NCSI_PKT_CMD_EBF), true);
+}
+
+static void ncsi_send_sma(unsigned int np, unsigned int nc)
+{
+	struct ncsi_cmd_sma_pkt cmd;
+	unsigned char *addr, i;
+
+	addr = eth_get_ethaddr();
+	if (!addr) {
+		printf("NCSI: no MAC address configured\n");
+		return;
+	}
+
+	memset(&cmd, 0, sizeof(cmd));
+	for (i = 0; i < ARP_HLEN; i++)
+		cmd.mac[i] = addr[i];
+	cmd.index = 1;
+	cmd.at_e = 1;
+
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_SMA,
+			  ((unsigned char *)&cmd)
+			  + sizeof(struct ncsi_cmd_pkt_hdr),
+			  cmd_payload(NCSI_PKT_CMD_SMA), true);
+}
+
+void ncsi_probe_packages(void)
+{
+	struct ncsi_package *package;
+	unsigned int np, nc;
+
+	switch (ncsi_priv->state) {
+	case NCSI_PROBE_PACKAGE_SP:
+		if (ncsi_priv->current_package == NCSI_PACKAGE_MAX)
+			ncsi_priv->current_package = 0;
+		ncsi_send_sp(ncsi_priv->current_package);
+		break;
+	case NCSI_PROBE_PACKAGE_DP:
+		ncsi_send_dp(ncsi_priv->current_package);
+		break;
+	case NCSI_PROBE_CHANNEL_SP:
+		if (ncsi_priv->n_packages > 0)
+			ncsi_send_sp(ncsi_priv->current_package);
+		else
+			printf("NCSI: no packages discovered, configuration not possible\n");
+		break;
+	case NCSI_PROBE_CHANNEL:
+		/* Kicks off chain of channel discovery */
+		ncsi_send_cis(ncsi_priv->current_package,
+			      ncsi_priv->current_channel);
+		break;
+	case NCSI_CONFIG:
+		for (np = 0; np < ncsi_priv->n_packages; np++) {
+			package = &ncsi_priv->packages[np];
+			for (nc = 0; nc < package->n_channels; nc++)
+				if (package->channels[nc].has_link)
+					break;
+			if (nc < package->n_channels)
+				break;
+		}
+		if (np == ncsi_priv->n_packages) {
+			printf("NCSI: no link available\n");
+			return;
+		}
+
+		printf("NCSI: configuring channel %d\n", nc);
+		ncsi_priv->current_package = np;
+		ncsi_priv->current_channel = nc;
+		/* Kicks off rest of configure chain */
+		ncsi_send_sma(np, nc);
+		break;
+	default:
+		printf("NCSI: unknown state 0x%x\n", ncsi_priv->state);
+	}
+}
+
+int ncsi_probe(struct phy_device *phydev)
+{
+	if (!phydev->priv) {
+		phydev->priv = malloc(sizeof(struct ncsi));
+		if (!phydev->priv)
+			return -ENOMEM;
+		memset(phydev->priv, 0, sizeof(struct ncsi));
+	}
+
+	ncsi_priv = phydev->priv;
+
+	return 0;
+}
+
+int ncsi_startup(struct phy_device *phydev)
+{
+	/* Set phydev parameters */
+	phydev->speed = SPEED_100;
+	phydev->duplex = DUPLEX_FULL;
+	/* Normal phy reset is N/A */
+	phydev->flags |= PHY_FLAG_BROKEN_RESET;
+
+	/* Set initial probe state */
+	ncsi_priv->state = NCSI_PROBE_PACKAGE_SP;
+
+	/* No active package/channel yet */
+	ncsi_priv->current_package = NCSI_PACKAGE_MAX;
+	ncsi_priv->current_channel = NCSI_CHANNEL_MAX;
+
+	/* Pretend link works so the MAC driver sets final bits up */
+	phydev->link = true;
+
+	/* Set ncsi_priv so we can use it when called from net_loop() */
+	ncsi_priv = phydev->priv;
+
+	return 0;
+}
+
+int ncsi_shutdown(struct phy_device *phydev)
+{
+	printf("NCSI: Disabling package %d\n", ncsi_priv->current_package);
+	ncsi_send_dp(ncsi_priv->current_package);
+	return 0;
+}
+
+static struct phy_driver ncsi_driver = {
+	.uid		= PHY_NCSI_ID,
+	.mask		= 0xffffffff,
+	.name		= "NC-SI",
+	.features	= PHY_100BT_FEATURES | PHY_DEFAULT_FEATURES | SUPPORTED_100baseT_Full | SUPPORTED_MII,
+	.probe		= ncsi_probe,
+	.startup	= ncsi_startup,
+	.shutdown	= ncsi_shutdown,
+};
+
+int phy_ncsi_init(void)
+{
+	phy_register(&ncsi_driver);
+	return 0;
+}
diff --git a/include/net.h b/include/net.h
index 44b32385c4..20c448ee60 100644
--- a/include/net.h
+++ b/include/net.h
@@ -343,6 +343,7 @@ struct vlan_ethernet_hdr {
 #define PROT_VLAN	0x8100		/* IEEE 802.1q protocol		*/
 #define PROT_IPV6	0x86dd		/* IPv6 over bluebook		*/
 #define PROT_PPP_SES	0x8864		/* PPPoE session messages	*/
+#define PROT_NCSI	0x88f8		/* NC-SI control packets        */
 
 #define IPPROTO_ICMP	 1	/* Internet Control Message Protocol	*/
 #define IPPROTO_UDP	17	/* User Datagram Protocol		*/
diff --git a/include/net/ncsi-pkt.h b/include/net/ncsi-pkt.h
new file mode 100644
index 0000000000..a8e9def593
--- /dev/null
+++ b/include/net/ncsi-pkt.h
@@ -0,0 +1,442 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright Gavin Shan, IBM Corporation 2016.
+ */
+
+#ifndef __NCSI_PKT_H__
+#define __NCSI_PKT_H__
+
+struct ncsi_pkt_hdr {
+	unsigned char mc_id;        /* Management controller ID */
+	unsigned char revision;     /* NCSI version - 0x01      */
+	unsigned char reserved;     /* Reserved                 */
+	unsigned char id;           /* Packet sequence number   */
+	unsigned char type;         /* Packet type              */
+	unsigned char channel;      /* Network controller ID    */
+	__be16        length;       /* Payload length           */
+	__be32        reserved1[2]; /* Reserved                 */
+};
+
+struct ncsi_cmd_pkt_hdr {
+	struct ncsi_pkt_hdr common; /* Common NCSI packet header */
+};
+
+struct ncsi_rsp_pkt_hdr {
+	struct ncsi_pkt_hdr common; /* Common NCSI packet header */
+	__be16              code;   /* Response code             */
+	__be16              reason; /* Response reason           */
+};
+
+struct ncsi_aen_pkt_hdr {
+	struct ncsi_pkt_hdr common;       /* Common NCSI packet header */
+	unsigned char       reserved2[3]; /* Reserved                  */
+	unsigned char       type;         /* AEN packet type           */
+};
+
+/* NCSI common command packet */
+struct ncsi_cmd_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
+	__be32                  checksum; /* Checksum       */
+	unsigned char           pad[26];
+};
+
+struct ncsi_rsp_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;      /* Response header */
+	__be32                  checksum; /* Checksum        */
+	unsigned char           pad[22];
+};
+
+/* Select Package */
+struct ncsi_cmd_sp_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;            /* Command header */
+	unsigned char           reserved[3];    /* Reserved       */
+	unsigned char           hw_arbitration; /* HW arbitration */
+	__be32                  checksum;       /* Checksum       */
+	unsigned char           pad[22];
+};
+
+/* Disable Channel */
+struct ncsi_cmd_dc_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;         /* Command header  */
+	unsigned char           reserved[3]; /* Reserved        */
+	unsigned char           ald;         /* Allow link down */
+	__be32                  checksum;    /* Checksum        */
+	unsigned char           pad[22];
+};
+
+/* Reset Channel */
+struct ncsi_cmd_rc_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
+	__be32                  reserved; /* Reserved       */
+	__be32                  checksum; /* Checksum       */
+	unsigned char           pad[22];
+};
+
+/* AEN Enable */
+struct ncsi_cmd_ae_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;         /* Command header   */
+	unsigned char           reserved[3]; /* Reserved         */
+	unsigned char           mc_id;       /* MC ID            */
+	__be32                  mode;        /* AEN working mode */
+	__be32                  checksum;    /* Checksum         */
+	unsigned char           pad[18];
+};
+
+/* Set Link */
+struct ncsi_cmd_sl_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header    */
+	__be32                  mode;     /* Link working mode */
+	__be32                  oem_mode; /* OEM link mode     */
+	__be32                  checksum; /* Checksum          */
+	unsigned char           pad[18];
+};
+
+/* Set VLAN Filter */
+struct ncsi_cmd_svf_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;       /* Command header    */
+	__be16                  reserved;  /* Reserved          */
+	__be16                  vlan;      /* VLAN ID           */
+	__be16                  reserved1; /* Reserved          */
+	unsigned char           index;     /* VLAN table index  */
+	unsigned char           enable;    /* Enable or disable */
+	__be32                  checksum;  /* Checksum          */
+	unsigned char           pad[18];
+};
+
+/* Enable VLAN */
+struct ncsi_cmd_ev_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;         /* Command header   */
+	unsigned char           reserved[3]; /* Reserved         */
+	unsigned char           mode;        /* VLAN filter mode */
+	__be32                  checksum;    /* Checksum         */
+	unsigned char           pad[22];
+};
+
+/* Set MAC Address */
+struct ncsi_cmd_sma_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header          */
+	unsigned char           mac[6];   /* MAC address             */
+	unsigned char           index;    /* MAC table index         */
+	unsigned char           at_e;     /* Addr type and operation */
+	__be32                  checksum; /* Checksum                */
+	unsigned char           pad[18];
+};
+
+/* Enable Broadcast Filter */
+struct ncsi_cmd_ebf_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
+	__be32                  mode;     /* Filter mode    */
+	__be32                  checksum; /* Checksum       */
+	unsigned char           pad[22];
+};
+
+/* Enable Global Multicast Filter */
+struct ncsi_cmd_egmf_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
+	__be32                  mode;     /* Global MC mode */
+	__be32                  checksum; /* Checksum       */
+	unsigned char           pad[22];
+};
+
+/* Set NCSI Flow Control */
+struct ncsi_cmd_snfc_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;         /* Command header    */
+	unsigned char           reserved[3]; /* Reserved          */
+	unsigned char           mode;        /* Flow control mode */
+	__be32                  checksum;    /* Checksum          */
+	unsigned char           pad[22];
+};
+
+/* OEM Request Command as per NCSI Specification */
+struct ncsi_cmd_oem_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;         /* Command header    */
+	__be32                  mfr_id;      /* Manufacture ID    */
+	unsigned char           data[];      /* OEM Payload Data  */
+};
+
+/* OEM Response Packet as per NCSI Specification */
+struct ncsi_rsp_oem_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;         /* Command header    */
+	__be32                  mfr_id;      /* Manufacture ID    */
+	unsigned char           data[];      /* Payload data      */
+};
+
+/* Mellanox Response Data */
+struct ncsi_rsp_oem_mlx_pkt {
+	unsigned char           cmd_rev;     /* Command Revision  */
+	unsigned char           cmd;         /* Command ID        */
+	unsigned char           param;       /* Parameter         */
+	unsigned char           optional;    /* Optional data     */
+	unsigned char           data[];      /* Data              */
+};
+
+/* Broadcom Response Data */
+struct ncsi_rsp_oem_bcm_pkt {
+	unsigned char           ver;         /* Payload Version   */
+	unsigned char           type;        /* OEM Command type  */
+	__be16                  len;         /* Payload Length    */
+	unsigned char           data[];      /* Cmd specific Data */
+};
+
+/* Get Link Status */
+struct ncsi_rsp_gls_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;        /* Response header   */
+	__be32                  status;     /* Link status       */
+	__be32                  other;      /* Other indications */
+	__be32                  oem_status; /* OEM link status   */
+	__be32                  checksum;
+	unsigned char           pad[10];
+};
+
+/* Get Version ID */
+struct ncsi_rsp_gvi_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;          /* Response header */
+	__be32                  ncsi_version; /* NCSI version    */
+	unsigned char           reserved[3];  /* Reserved        */
+	unsigned char           alpha2;       /* NCSI version    */
+	unsigned char           fw_name[12];  /* f/w name string */
+	__be32                  fw_version;   /* f/w version     */
+	__be16                  pci_ids[4];   /* PCI IDs         */
+	__be32                  mf_id;        /* Manufacture ID  */
+	__be32                  checksum;
+};
+
+/* Get Capabilities */
+struct ncsi_rsp_gc_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;         /* Response header   */
+	__be32                  cap;         /* Capabilities      */
+	__be32                  bc_cap;      /* Broadcast cap     */
+	__be32                  mc_cap;      /* Multicast cap     */
+	__be32                  buf_cap;     /* Buffering cap     */
+	__be32                  aen_cap;     /* AEN cap           */
+	unsigned char           vlan_cnt;    /* VLAN filter count */
+	unsigned char           mixed_cnt;   /* Mix filter count  */
+	unsigned char           mc_cnt;      /* MC filter count   */
+	unsigned char           uc_cnt;      /* UC filter count   */
+	unsigned char           reserved[2]; /* Reserved          */
+	unsigned char           vlan_mode;   /* VLAN mode         */
+	unsigned char           channel_cnt; /* Channel count     */
+	__be32                  checksum;    /* Checksum          */
+};
+
+/* Get Parameters */
+struct ncsi_rsp_gp_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;          /* Response header       */
+	unsigned char           mac_cnt;      /* Number of MAC addr    */
+	unsigned char           reserved[2];  /* Reserved              */
+	unsigned char           mac_enable;   /* MAC addr enable flags */
+	unsigned char           vlan_cnt;     /* VLAN tag count        */
+	unsigned char           reserved1;    /* Reserved              */
+	__be16                  vlan_enable;  /* VLAN tag enable flags */
+	__be32                  link_mode;    /* Link setting          */
+	__be32                  bc_mode;      /* BC filter mode        */
+	__be32                  valid_modes;  /* Valid mode parameters */
+	unsigned char           vlan_mode;    /* VLAN mode             */
+	unsigned char           fc_mode;      /* Flow control mode     */
+	unsigned char           reserved2[2]; /* Reserved              */
+	__be32                  aen_mode;     /* AEN mode              */
+	unsigned char           mac[6];       /* Supported MAC addr    */
+	__be16                  vlan;         /* Supported VLAN tags   */
+	__be32                  checksum;     /* Checksum              */
+};
+
+/* Get Controller Packet Statistics */
+struct ncsi_rsp_gcps_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;            /* Response header            */
+	__be32                  cnt_hi;         /* Counter cleared            */
+	__be32                  cnt_lo;         /* Counter cleared            */
+	__be32                  rx_bytes;       /* Rx bytes                   */
+	__be32                  tx_bytes;       /* Tx bytes                   */
+	__be32                  rx_uc_pkts;     /* Rx UC packets              */
+	__be32                  rx_mc_pkts;     /* Rx MC packets              */
+	__be32                  rx_bc_pkts;     /* Rx BC packets              */
+	__be32                  tx_uc_pkts;     /* Tx UC packets              */
+	__be32                  tx_mc_pkts;     /* Tx MC packets              */
+	__be32                  tx_bc_pkts;     /* Tx BC packets              */
+	__be32                  fcs_err;        /* FCS errors                 */
+	__be32                  align_err;      /* Alignment errors           */
+	__be32                  false_carrier;  /* False carrier detection    */
+	__be32                  runt_pkts;      /* Rx runt packets            */
+	__be32                  jabber_pkts;    /* Rx jabber packets          */
+	__be32                  rx_pause_xon;   /* Rx pause XON frames        */
+	__be32                  rx_pause_xoff;  /* Rx XOFF frames             */
+	__be32                  tx_pause_xon;   /* Tx XON frames              */
+	__be32                  tx_pause_xoff;  /* Tx XOFF frames             */
+	__be32                  tx_s_collision; /* Single collision frames    */
+	__be32                  tx_m_collision; /* Multiple collision frames  */
+	__be32                  l_collision;    /* Late collision frames      */
+	__be32                  e_collision;    /* Excessive collision frames */
+	__be32                  rx_ctl_frames;  /* Rx control frames          */
+	__be32                  rx_64_frames;   /* Rx 64-bytes frames         */
+	__be32                  rx_127_frames;  /* Rx 65-127 bytes frames     */
+	__be32                  rx_255_frames;  /* Rx 128-255 bytes frames    */
+	__be32                  rx_511_frames;  /* Rx 256-511 bytes frames    */
+	__be32                  rx_1023_frames; /* Rx 512-1023 bytes frames   */
+	__be32                  rx_1522_frames; /* Rx 1024-1522 bytes frames  */
+	__be32                  rx_9022_frames; /* Rx 1523-9022 bytes frames  */
+	__be32                  tx_64_frames;   /* Tx 64-bytes frames         */
+	__be32                  tx_127_frames;  /* Tx 65-127 bytes frames     */
+	__be32                  tx_255_frames;  /* Tx 128-255 bytes frames    */
+	__be32                  tx_511_frames;  /* Tx 256-511 bytes frames    */
+	__be32                  tx_1023_frames; /* Tx 512-1023 bytes frames   */
+	__be32                  tx_1522_frames; /* Tx 1024-1522 bytes frames  */
+	__be32                  tx_9022_frames; /* Tx 1523-9022 bytes frames  */
+	__be32                  rx_valid_bytes; /* Rx valid bytes             */
+	__be32                  rx_runt_pkts;   /* Rx error runt packets      */
+	__be32                  rx_jabber_pkts; /* Rx error jabber packets    */
+	__be32                  checksum;       /* Checksum                   */
+};
+
+/* Get NCSI Statistics */
+struct ncsi_rsp_gns_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;           /* Response header         */
+	__be32                  rx_cmds;       /* Rx NCSI commands        */
+	__be32                  dropped_cmds;  /* Dropped commands        */
+	__be32                  cmd_type_errs; /* Command type errors     */
+	__be32                  cmd_csum_errs; /* Command checksum errors */
+	__be32                  rx_pkts;       /* Rx NCSI packets         */
+	__be32                  tx_pkts;       /* Tx NCSI packets         */
+	__be32                  tx_aen_pkts;   /* Tx AEN packets          */
+	__be32                  checksum;      /* Checksum                */
+};
+
+/* Get NCSI Pass-through Statistics */
+struct ncsi_rsp_gnpts_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;            /* Response header     */
+	__be32                  tx_pkts;        /* Tx packets          */
+	__be32                  tx_dropped;     /* Tx dropped packets  */
+	__be32                  tx_channel_err; /* Tx channel errors   */
+	__be32                  tx_us_err;      /* Tx undersize errors */
+	__be32                  rx_pkts;        /* Rx packets          */
+	__be32                  rx_dropped;     /* Rx dropped packets  */
+	__be32                  rx_channel_err; /* Rx channel errors   */
+	__be32                  rx_us_err;      /* Rx undersize errors */
+	__be32                  rx_os_err;      /* Rx oversize errors  */
+	__be32                  checksum;       /* Checksum            */
+};
+
+/* Get package status */
+struct ncsi_rsp_gps_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;      /* Response header             */
+	__be32                  status;   /* Hardware arbitration status */
+	__be32                  checksum;
+};
+
+/* Get package UUID */
+struct ncsi_rsp_gpuuid_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;      /* Response header */
+	unsigned char           uuid[16]; /* UUID            */
+	__be32                  checksum;
+};
+
+/* AEN: Link State Change */
+struct ncsi_aen_lsc_pkt {
+	struct ncsi_aen_pkt_hdr aen;        /* AEN header      */
+	__be32                  status;     /* Link status     */
+	__be32                  oem_status; /* OEM link status */
+	__be32                  checksum;   /* Checksum        */
+	unsigned char           pad[14];
+};
+
+/* AEN: Configuration Required */
+struct ncsi_aen_cr_pkt {
+	struct ncsi_aen_pkt_hdr aen;      /* AEN header */
+	__be32                  checksum; /* Checksum   */
+	unsigned char           pad[22];
+};
+
+/* AEN: Host Network Controller Driver Status Change */
+struct ncsi_aen_hncdsc_pkt {
+	struct ncsi_aen_pkt_hdr aen;      /* AEN header */
+	__be32                  status;   /* Status     */
+	__be32                  checksum; /* Checksum   */
+	unsigned char           pad[18];
+};
+
+/* NCSI packet revision */
+#define NCSI_PKT_REVISION	0x01
+
+/* NCSI packet commands */
+#define NCSI_PKT_CMD_CIS	0x00 /* Clear Initial State              */
+#define NCSI_PKT_CMD_SP		0x01 /* Select Package                   */
+#define NCSI_PKT_CMD_DP		0x02 /* Deselect Package                 */
+#define NCSI_PKT_CMD_EC		0x03 /* Enable Channel                   */
+#define NCSI_PKT_CMD_DC		0x04 /* Disable Channel                  */
+#define NCSI_PKT_CMD_RC		0x05 /* Reset Channel                    */
+#define NCSI_PKT_CMD_ECNT	0x06 /* Enable Channel Network Tx        */
+#define NCSI_PKT_CMD_DCNT	0x07 /* Disable Channel Network Tx       */
+#define NCSI_PKT_CMD_AE		0x08 /* AEN Enable                       */
+#define NCSI_PKT_CMD_SL		0x09 /* Set Link                         */
+#define NCSI_PKT_CMD_GLS	0x0a /* Get Link                         */
+#define NCSI_PKT_CMD_SVF	0x0b /* Set VLAN Filter                  */
+#define NCSI_PKT_CMD_EV		0x0c /* Enable VLAN                      */
+#define NCSI_PKT_CMD_DV		0x0d /* Disable VLAN                     */
+#define NCSI_PKT_CMD_SMA	0x0e /* Set MAC address                  */
+#define NCSI_PKT_CMD_EBF	0x10 /* Enable Broadcast Filter          */
+#define NCSI_PKT_CMD_DBF	0x11 /* Disable Broadcast Filter         */
+#define NCSI_PKT_CMD_EGMF	0x12 /* Enable Global Multicast Filter   */
+#define NCSI_PKT_CMD_DGMF	0x13 /* Disable Global Multicast Filter  */
+#define NCSI_PKT_CMD_SNFC	0x14 /* Set NCSI Flow Control            */
+#define NCSI_PKT_CMD_GVI	0x15 /* Get Version ID                   */
+#define NCSI_PKT_CMD_GC		0x16 /* Get Capabilities                 */
+#define NCSI_PKT_CMD_GP		0x17 /* Get Parameters                   */
+#define NCSI_PKT_CMD_GCPS	0x18 /* Get Controller Packet Statistics */
+#define NCSI_PKT_CMD_GNS	0x19 /* Get NCSI Statistics              */
+#define NCSI_PKT_CMD_GNPTS	0x1a /* Get NCSI Pass-throu Statistics   */
+#define NCSI_PKT_CMD_GPS	0x1b /* Get package status               */
+#define NCSI_PKT_CMD_OEM	0x50 /* OEM                              */
+#define NCSI_PKT_CMD_PLDM	0x51 /* PLDM request over NCSI over RBT  */
+#define NCSI_PKT_CMD_GPUUID	0x52 /* Get package UUID                 */
+
+/* NCSI packet responses */
+#define NCSI_PKT_RSP_CIS	(NCSI_PKT_CMD_CIS    + 0x80)
+#define NCSI_PKT_RSP_SP		(NCSI_PKT_CMD_SP     + 0x80)
+#define NCSI_PKT_RSP_DP		(NCSI_PKT_CMD_DP     + 0x80)
+#define NCSI_PKT_RSP_EC		(NCSI_PKT_CMD_EC     + 0x80)
+#define NCSI_PKT_RSP_DC		(NCSI_PKT_CMD_DC     + 0x80)
+#define NCSI_PKT_RSP_RC		(NCSI_PKT_CMD_RC     + 0x80)
+#define NCSI_PKT_RSP_ECNT	(NCSI_PKT_CMD_ECNT   + 0x80)
+#define NCSI_PKT_RSP_DCNT	(NCSI_PKT_CMD_DCNT   + 0x80)
+#define NCSI_PKT_RSP_AE		(NCSI_PKT_CMD_AE     + 0x80)
+#define NCSI_PKT_RSP_SL		(NCSI_PKT_CMD_SL     + 0x80)
+#define NCSI_PKT_RSP_GLS	(NCSI_PKT_CMD_GLS    + 0x80)
+#define NCSI_PKT_RSP_SVF	(NCSI_PKT_CMD_SVF    + 0x80)
+#define NCSI_PKT_RSP_EV		(NCSI_PKT_CMD_EV     + 0x80)
+#define NCSI_PKT_RSP_DV		(NCSI_PKT_CMD_DV     + 0x80)
+#define NCSI_PKT_RSP_SMA	(NCSI_PKT_CMD_SMA    + 0x80)
+#define NCSI_PKT_RSP_EBF	(NCSI_PKT_CMD_EBF    + 0x80)
+#define NCSI_PKT_RSP_DBF	(NCSI_PKT_CMD_DBF    + 0x80)
+#define NCSI_PKT_RSP_EGMF	(NCSI_PKT_CMD_EGMF   + 0x80)
+#define NCSI_PKT_RSP_DGMF	(NCSI_PKT_CMD_DGMF   + 0x80)
+#define NCSI_PKT_RSP_SNFC	(NCSI_PKT_CMD_SNFC   + 0x80)
+#define NCSI_PKT_RSP_GVI	(NCSI_PKT_CMD_GVI    + 0x80)
+#define NCSI_PKT_RSP_GC		(NCSI_PKT_CMD_GC     + 0x80)
+#define NCSI_PKT_RSP_GP		(NCSI_PKT_CMD_GP     + 0x80)
+#define NCSI_PKT_RSP_GCPS	(NCSI_PKT_CMD_GCPS   + 0x80)
+#define NCSI_PKT_RSP_GNS	(NCSI_PKT_CMD_GNS    + 0x80)
+#define NCSI_PKT_RSP_GNPTS	(NCSI_PKT_CMD_GNPTS  + 0x80)
+#define NCSI_PKT_RSP_GPS	(NCSI_PKT_CMD_GPS    + 0x80)
+#define NCSI_PKT_RSP_OEM	(NCSI_PKT_CMD_OEM    + 0x80)
+#define NCSI_PKT_RSP_PLDM	(NCSI_PKT_CMD_PLDM   + 0x80)
+#define NCSI_PKT_RSP_GPUUID	(NCSI_PKT_CMD_GPUUID + 0x80)
+
+/* NCSI response code/reason */
+#define NCSI_PKT_RSP_C_COMPLETED	0x0000 /* Command Completed        */
+#define NCSI_PKT_RSP_C_FAILED		0x0001 /* Command Failed           */
+#define NCSI_PKT_RSP_C_UNAVAILABLE	0x0002 /* Command Unavailable      */
+#define NCSI_PKT_RSP_C_UNSUPPORTED	0x0003 /* Command Unsupported      */
+#define NCSI_PKT_RSP_R_NO_ERROR		0x0000 /* No Error                 */
+#define NCSI_PKT_RSP_R_INTERFACE	0x0001 /* Interface not ready      */
+#define NCSI_PKT_RSP_R_PARAM		0x0002 /* Invalid Parameter        */
+#define NCSI_PKT_RSP_R_CHANNEL		0x0003 /* Channel not Ready        */
+#define NCSI_PKT_RSP_R_PACKAGE		0x0004 /* Package not Ready        */
+#define NCSI_PKT_RSP_R_LENGTH		0x0005 /* Invalid payload length   */
+#define NCSI_PKT_RSP_R_UNKNOWN		0x7fff /* Command type unsupported */
+
+/* NCSI AEN packet type */
+#define NCSI_PKT_AEN		0xFF /* AEN Packet               */
+#define NCSI_PKT_AEN_LSC	0x00 /* Link status change       */
+#define NCSI_PKT_AEN_CR		0x01 /* Configuration required   */
+#define NCSI_PKT_AEN_HNCDSC	0x02 /* HNC driver status change */
+
+#endif /* __NCSI_PKT_H__ */
diff --git a/include/net/ncsi.h b/include/net/ncsi.h
new file mode 100644
index 0000000000..9637beab2a
--- /dev/null
+++ b/include/net/ncsi.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * NC-SI PHY
+ *
+ * Copyright (C) 2019, IBM Corporation.
+ */
+
+#include <common.h>
+#include <phy.h>
+
+bool ncsi_active(void);
+void ncsi_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip,
+		  unsigned int len);
+void ncsi_probe_packages(void);
diff --git a/include/phy.h b/include/phy.h
index d01435d1aa..297fc7a78e 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -17,6 +17,7 @@
 #include <phy_interface.h>
 
 #define PHY_FIXED_ID		0xa5a55a5a
+#define PHY_NCSI_ID		0xbeefcafe
 
 #define PHY_MAX_ADDR 32
 
-- 
2.21.0

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 1/4] phy: Add support for the NC-SI protocol
@ 2019-06-18  1:37   ` Samuel Mendoza-Jonas
  0 siblings, 0 replies; 34+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-18  1:37 UTC (permalink / raw)
  To: u-boot

This introduces support for the NC-SI protocol, modelled as a phy driver
for other ethernet drivers to consume.

NC-SI (Network Controller Sideband Interface) is a protocol to manage a
sideband connection to a proper network interface, for example a BMC
(Baseboard Management Controller) sharing the NIC of the host system.
Probing and configuration occurs by communicating with the "remote" NIC
via NC-SI control frames (Ethernet header 0x88f8).

This implementation is roughly based on the upstream Linux
implementation[0], with a reduced feature set and an emphasis on getting
a link up as fast as possible rather than probing the full possible
topology of the bus.
The current phy model relies on the network being "up", sending NC-SI
command frames via net_send_packet() and receiving them from the
net_loop() loop (added in a following patch).

The ncsi-pkt.h header[1] is copied from the Linux kernel for consistent
field definitions.

[0]: https://github.com/torvalds/linux/tree/master/net/ncsi
[1]: https://github.com/torvalds/linux/blob/master/net/ncsi/ncsi-pkt.h

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
v2:
- Fix endianess issue when setting MAC address
- Make checksum offsets easier to read
- Instantiate per-phy ncsi_priv structures
- Used update ncsi-pkt.h version to include SPDX header

 drivers/net/phy/Kconfig  |   4 +
 drivers/net/phy/Makefile |   1 +
 drivers/net/phy/ncsi.c   | 896 +++++++++++++++++++++++++++++++++++++++
 include/net.h            |   1 +
 include/net/ncsi-pkt.h   | 442 +++++++++++++++++++
 include/net/ncsi.h       |  14 +
 include/phy.h            |   1 +
 7 files changed, 1359 insertions(+)
 create mode 100644 drivers/net/phy/ncsi.c
 create mode 100644 include/net/ncsi-pkt.h
 create mode 100644 include/net/ncsi.h

diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 2a3da068c9..35d96ab34b 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -238,4 +238,8 @@ config PHY_FIXED
 	  on, the link is always up with fixed speed and fixed duplex-setting.
 	  More information: doc/device-tree-bindings/net/fixed-link.txt
 
+config PHY_NCSI
+	bool "NC-SI based PHY"
+	depends on DM_ETH
+
 endif #PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 555da83630..32a8409a85 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -30,3 +30,4 @@ obj-$(CONFIG_PHY_XILINX) += xilinx_phy.o
 obj-$(CONFIG_PHY_VITESSE) += vitesse.o
 obj-$(CONFIG_PHY_MSCC) += mscc.o
 obj-$(CONFIG_PHY_FIXED) += fixed.o
+obj-$(CONFIG_PHY_NCSI) += ncsi.o
diff --git a/drivers/net/phy/ncsi.c b/drivers/net/phy/ncsi.c
new file mode 100644
index 0000000000..4d0ea48b04
--- /dev/null
+++ b/drivers/net/phy/ncsi.c
@@ -0,0 +1,896 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * NC-SI protocol configuration
+ *
+ * Copyright (C) 2019, IBM Corporation.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <phy.h>
+#include <net/ncsi.h>
+#include <net/ncsi-pkt.h>
+#include <asm/unaligned.h>
+
+#define NCSI_PACKAGE_MAX 8
+#define NCSI_CHANNEL_MAX 31
+
+#define NCSI_PACKAGE_SHIFT      5
+#define NCSI_PACKAGE_INDEX(c)   (((c) >> NCSI_PACKAGE_SHIFT) & 0x7)
+#define NCSI_RESERVED_CHANNEL   0x1f
+#define NCSI_CHANNEL_INDEX(c)   ((c) & ((1 << NCSI_PACKAGE_SHIFT) - 1))
+#define NCSI_TO_CHANNEL(p, c)   (((p) << NCSI_PACKAGE_SHIFT) | (c))
+
+#define NCSI_PKT_REVISION       0x01
+
+#define NCSI_CAP_GENERIC_MASK	0x7f
+#define NCSI_CAP_BC_MASK	0x0f
+#define NCSI_CAP_MC_MASK	0x3f
+#define NCSI_CAP_AEN_MASK	0x07
+#define NCSI_CAP_VLAN_MASK	0x07
+
+static void ncsi_send_ebf(unsigned int np, unsigned int nc);
+static void ncsi_send_ae(unsigned int np, unsigned int nc);
+static void ncsi_send_gls(unsigned int np, unsigned int nc);
+static int ncsi_send_command(unsigned int np, unsigned int nc, unsigned int cmd,
+			     uchar *payload, int len, bool wait);
+
+struct ncsi_channel {
+	unsigned int	id;
+	bool		has_link;
+
+	/* capabilities */
+	u32 cap_generic;
+	u32 cap_bc;
+	u32 cap_mc;
+	u32 cap_buffer;
+	u32 cap_aen;
+	u32 cap_vlan;
+
+	/* version information */
+	struct {
+		u32 version;            /* Supported BCD encoded NCSI version */
+		u32 alpha2;             /* Supported BCD encoded NCSI version */
+		u8  fw_name[12];        /* Firmware name string               */
+		u32 fw_version;         /* Firmware version                   */
+		u16 pci_ids[4];         /* PCI identification                 */
+		u32 mf_id;              /* Manufacture ID                     */
+	} version;
+
+};
+
+struct ncsi_package {
+	unsigned int		id;
+	unsigned int		n_channels;
+	struct ncsi_channel	*channels;
+};
+
+struct ncsi {
+	enum {
+		NCSI_PROBE_PACKAGE_SP,
+		NCSI_PROBE_PACKAGE_DP,
+		NCSI_PROBE_CHANNEL_SP,
+		NCSI_PROBE_CHANNEL,
+		NCSI_CONFIG,
+	} state;
+
+	unsigned int	pending_requests;
+	unsigned int	requests[256];
+	unsigned int	last_request;
+
+	unsigned int	current_package;
+	unsigned int	current_channel;
+
+	unsigned int		n_packages;
+	struct ncsi_package	*packages;
+};
+
+struct ncsi *ncsi_priv;
+
+bool ncsi_active(void)
+{
+	unsigned int np, nc;
+
+	if (!ncsi_priv)
+		return false;
+
+	np = ncsi_priv->current_package;
+	nc = ncsi_priv->current_channel;
+
+	if (ncsi_priv->state != NCSI_CONFIG)
+		return false;
+
+	return np < NCSI_PACKAGE_MAX && nc < NCSI_CHANNEL_MAX &&
+		ncsi_priv->packages[np].channels[nc].has_link;
+}
+
+static unsigned int cmd_payload(int cmd)
+{
+	switch (cmd) {
+	case NCSI_PKT_CMD_CIS:
+		return 0;
+	case NCSI_PKT_CMD_SP:
+		return 4;
+	case NCSI_PKT_CMD_DP:
+		return 0;
+	case NCSI_PKT_CMD_EC:
+		return 0;
+	case NCSI_PKT_CMD_DC:
+		return 4;
+	case NCSI_PKT_CMD_RC:
+		return 4;
+	case NCSI_PKT_CMD_ECNT:
+		return 0;
+	case NCSI_PKT_CMD_DCNT:
+		return 0;
+	case NCSI_PKT_CMD_AE:
+		return 8;
+	case NCSI_PKT_CMD_SL:
+		return 8;
+	case NCSI_PKT_CMD_GLS:
+		return 0;
+	case NCSI_PKT_CMD_SVF:
+		return 8;
+	case NCSI_PKT_CMD_EV:
+		return 4;
+	case NCSI_PKT_CMD_DV:
+		return 0;
+	case NCSI_PKT_CMD_SMA:
+		return 8;
+	case NCSI_PKT_CMD_EBF:
+		return 4;
+	case NCSI_PKT_CMD_DBF:
+		return 0;
+	case NCSI_PKT_CMD_EGMF:
+		return 4;
+	case NCSI_PKT_CMD_DGMF:
+		return 0;
+	case NCSI_PKT_CMD_SNFC:
+		return 4;
+	case NCSI_PKT_CMD_GVI:
+		return 0;
+	case NCSI_PKT_CMD_GC:
+		return 0;
+	case NCSI_PKT_CMD_GP:
+		return 0;
+	case NCSI_PKT_CMD_GCPS:
+		return 0;
+	case NCSI_PKT_CMD_GNS:
+		return 0;
+	case NCSI_PKT_CMD_GNPTS:
+		return 0;
+	case NCSI_PKT_CMD_GPS:
+		return 0;
+	default:
+		printf("NCSI: Unknown command 0x%02x\n", cmd);
+		return 0;
+	}
+}
+
+static u32 ncsi_calculate_checksum(unsigned char *data, int len)
+{
+	u32 checksum = 0;
+	int i;
+
+	for (i = 0; i < len; i += 2)
+		checksum += (((u32)data[i] << 8) | data[i + 1]);
+
+	checksum = (~checksum + 1);
+	return checksum;
+}
+
+static int ncsi_validate_rsp(struct ncsi_rsp_pkt *pkt, int payload)
+{
+	struct ncsi_rsp_pkt_hdr *hdr = &pkt->rsp;
+	u32 checksum, c_offset;
+	__be32 pchecksum;
+
+	if (hdr->common.revision != 1) {
+		printf("NCSI: 0x%02x response has unsupported revision 0x%x\n",
+		       hdr->common.type, hdr->common.revision);
+		return -1;
+	}
+
+	if (hdr->code != 0) {
+		printf("NCSI: 0x%02x response returns error %d\n",
+		       hdr->common.type, __be16_to_cpu(hdr->code));
+		if (ntohs(hdr->reason) == 0x05)
+			printf("(Invalid command length)\n");
+		return -1;
+	}
+
+	if (ntohs(hdr->common.length) != payload) {
+		printf("NCSI: 0x%02x response has incorrect length %d\n",
+		       hdr->common.type, hdr->common.length);
+		return -1;
+	}
+
+	c_offset = sizeof(struct ncsi_rsp_pkt_hdr) + payload - sizeof(checksum);
+	pchecksum = get_unaligned_be32((void *)hdr + c_offset);
+	if (pchecksum != 0) {
+		checksum = ncsi_calculate_checksum((unsigned char *)hdr,
+						   c_offset);
+		if (pchecksum != checksum) {
+			printf("NCSI: 0x%02x response has invalid checksum\n",
+			       hdr->common.type);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static void ncsi_rsp_ec(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	if (ncsi_priv->packages[np].channels[nc].cap_aen != 0)
+		ncsi_send_ae(np, nc);
+	/* else, done */
+}
+
+static void ncsi_rsp_ecnt(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_EC, NULL, 0, true);
+}
+
+static void ncsi_rsp_ebf(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_ECNT, NULL, 0, true);
+}
+
+static void ncsi_rsp_sma(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	ncsi_send_ebf(np, nc);
+}
+
+static void ncsi_rsp_gc(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_gc_pkt *gc = (struct ncsi_rsp_gc_pkt *)pkt;
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&gc->rsp;
+	struct ncsi_channel *c;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	if (np >= ncsi_priv->n_packages ||
+	    nc >= ncsi_priv->packages[np].n_channels) {
+		printf("NCSI: Invalid package / channel (0x%02x, 0x%02x)\n",
+		       np, nc);
+		return;
+	}
+
+	c = &ncsi_priv->packages[np].channels[nc];
+	c->cap_generic = ntohl(gc->cap) & NCSI_CAP_GENERIC_MASK;
+	c->cap_bc = ntohl(gc->bc_cap) & NCSI_CAP_BC_MASK;
+	c->cap_mc = ntohl(gc->mc_cap) & NCSI_CAP_MC_MASK;
+	c->cap_aen = ntohl(gc->aen_cap) & NCSI_CAP_AEN_MASK;
+	c->cap_vlan = ntohl(gc->vlan_mode) & NCSI_CAP_VLAN_MASK;
+
+	/* End of probe for this channel */
+}
+
+static void ncsi_rsp_gvi(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_gvi_pkt *gvi = (struct ncsi_rsp_gvi_pkt *)pkt;
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&gvi->rsp;
+	struct ncsi_channel *c;
+	unsigned int np, nc, i;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	if (np >= ncsi_priv->n_packages ||
+	    nc >= ncsi_priv->packages[np].n_channels) {
+		printf("NCSI: Invalid package / channel (0x%02x, 0x%02x)\n",
+		       np, nc);
+		return;
+	}
+
+	c = &ncsi_priv->packages[np].channels[nc];
+	c->version.version = get_unaligned_be32(&gvi->ncsi_version);
+	c->version.alpha2 = gvi->alpha2;
+	memcpy(c->version.fw_name, gvi->fw_name, sizeof(c->version.fw_name));
+	c->version.fw_version = get_unaligned_be32(&gvi->fw_version);
+	for (i = 0; i < ARRAY_SIZE(c->version.pci_ids); i++)
+		c->version.pci_ids[i] = get_unaligned_be16(gvi->pci_ids + i);
+	c->version.mf_id = get_unaligned_be32(&gvi->mf_id);
+
+	if (ncsi_priv->state == NCSI_PROBE_CHANNEL)
+		ncsi_send_command(np, nc, NCSI_PKT_CMD_GC, NULL, 0, true);
+}
+
+static void ncsi_rsp_gls(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_gls_pkt *gls = (struct ncsi_rsp_gls_pkt *)pkt;
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&gls->rsp;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	if (np >= ncsi_priv->n_packages ||
+	    nc >= ncsi_priv->packages[np].n_channels) {
+		printf("NCSI: Invalid package / channel (0x%02x, 0x%02x)\n",
+		       np, nc);
+		return;
+	}
+
+	ncsi_priv->packages[np].channels[nc].has_link =
+					!!(get_unaligned_be32(&gls->status));
+
+	if (ncsi_priv->state == NCSI_PROBE_CHANNEL)
+		ncsi_send_command(np, nc, NCSI_PKT_CMD_GVI, NULL, 0, true);
+}
+
+static void ncsi_rsp_cis(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)pkt;
+	struct ncsi_package *package;
+	unsigned int np, nc;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	nc = NCSI_CHANNEL_INDEX(rsp->common.channel);
+
+	if (np >= ncsi_priv->n_packages) {
+		printf("NCSI: Mystery package 0x%02x from CIS\n", np);
+		return;
+	}
+
+	package = &ncsi_priv->packages[np];
+
+	if (nc < package->n_channels) {
+		/*
+		 * This is fine in general but in the current design we
+		 * don't send CIS commands to known channels.
+		 */
+		debug("NCSI: Duplicate channel 0x%02x\n", nc);
+		return;
+	}
+
+	package->channels = realloc(package->channels,
+				    sizeof(struct ncsi_channel) *
+				    (package->n_channels + 1));
+	if (!package->channels) {
+		printf("NCSI: Could not allocate memory for new channel\n");
+		return;
+	}
+
+	debug("NCSI: New channel 0x%02x\n", nc);
+
+	package->channels[nc].id = nc;
+	package->channels[nc].has_link = false;
+	package->n_channels++;
+
+	ncsi_send_gls(np, nc);
+}
+
+static void ncsi_rsp_dp(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)pkt;
+	unsigned int np;
+
+	/* No action needed */
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+	if (np >= ncsi_priv->n_packages)
+		debug("NCSI: DP response from unknown package %d\n", np);
+}
+
+static void ncsi_rsp_sp(struct ncsi_rsp_pkt *pkt)
+{
+	struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)pkt;
+	unsigned int np;
+
+	np = NCSI_PACKAGE_INDEX(rsp->common.channel);
+
+	if (np < ncsi_priv->n_packages) {
+		/* Already know about this package */
+		debug("NCSI: package 0x%02x selected\n", np);
+		return;
+	}
+
+	debug("NCSI: adding new package %d\n", np);
+
+	ncsi_priv->packages = realloc(ncsi_priv->packages,
+				      sizeof(struct ncsi_package) *
+				      (ncsi_priv->n_packages + 1));
+	if (!ncsi_priv->packages) {
+		printf("NCSI: could not allocate memory for new package\n");
+		return;
+	}
+
+	ncsi_priv->packages[np].id = np;
+	ncsi_priv->packages[np].n_channels = 0;
+	ncsi_priv->packages[np].channels = NULL;
+	ncsi_priv->n_packages++;
+}
+
+static void ncsi_update_state(struct ncsi_rsp_pkt_hdr *nh)
+{
+	bool timeout = !nh;
+	int np, nc;
+
+	switch (ncsi_priv->state) {
+	case NCSI_PROBE_PACKAGE_SP:
+		if (!timeout &&
+		    ncsi_priv->current_package + 1 < NCSI_PACKAGE_MAX) {
+			ncsi_priv->current_package++;
+		} else {
+			ncsi_priv->state = NCSI_PROBE_PACKAGE_DP;
+			ncsi_priv->current_package = 0;
+		}
+		return ncsi_probe_packages();
+	case NCSI_PROBE_PACKAGE_DP:
+		if (ncsi_priv->current_package + 1 < ncsi_priv->n_packages &&
+		    !timeout) {
+			ncsi_priv->current_package++;
+		} else {
+			if (!ncsi_priv->n_packages) {
+				printf("NCSI: no packages found\n");
+				net_set_state(NETLOOP_FAIL);
+				return;
+			}
+			printf("NCSI: probing channels\n");
+			ncsi_priv->state = NCSI_PROBE_CHANNEL_SP;
+			ncsi_priv->current_package = 0;
+			ncsi_priv->current_channel = 0;
+		}
+		return ncsi_probe_packages();
+	case NCSI_PROBE_CHANNEL_SP:
+		if (!timeout && nh->common.type == NCSI_PKT_RSP_SP) {
+			ncsi_priv->state = NCSI_PROBE_CHANNEL;
+			return ncsi_probe_packages();
+		}
+		printf("NCSI: failed to select package 0x%0x2 or timeout\n",
+		       ncsi_priv->current_package);
+		net_set_state(NETLOOP_FAIL);
+		break;
+	case NCSI_PROBE_CHANNEL:
+		// TODO only does package 0 for now
+		if (ncsi_priv->pending_requests == 0) {
+			np = ncsi_priv->current_package;
+			nc = ncsi_priv->current_channel;
+
+			/* Configure first channel that has link */
+			if (ncsi_priv->packages[np].channels[nc].has_link) {
+				ncsi_priv->state = NCSI_CONFIG;
+			} else if (ncsi_priv->current_channel + 1 <
+				   NCSI_CHANNEL_MAX) {
+				ncsi_priv->current_channel++;
+			} else {
+				// XXX As above only package 0
+				printf("NCSI: no channel found with link\n");
+				net_set_state(NETLOOP_FAIL);
+				return;
+			}
+			return ncsi_probe_packages();
+		}
+		break;
+	case NCSI_CONFIG:
+		if (ncsi_priv->pending_requests == 0) {
+			printf("NCSI: configuration done!\n");
+			net_set_state(NETLOOP_SUCCESS);
+		} else if (timeout) {
+			printf("NCSI: timeout during configure\n");
+			net_set_state(NETLOOP_FAIL);
+		}
+		break;
+	default:
+		printf("NCSI: something went very wrong, nevermind\n");
+		net_set_state(NETLOOP_FAIL);
+		break;
+	}
+}
+
+static void ncsi_timeout_handler(void)
+{
+	if (ncsi_priv->pending_requests)
+		ncsi_priv->pending_requests--;
+
+	ncsi_update_state(NULL);
+}
+
+static int ncsi_send_command(unsigned int np, unsigned int nc, unsigned int cmd,
+			     uchar *payload, int len, bool wait)
+{
+	struct ncsi_pkt_hdr *hdr;
+	__be32 *pchecksum;
+	int eth_hdr_size;
+	u32 checksum;
+	uchar *pkt, *start;
+	int final_len;
+
+	pkt = calloc(1, PKTSIZE_ALIGN + PKTALIGN);
+	if (!pkt)
+		return -ENOMEM;
+	start = pkt;
+
+	eth_hdr_size = net_set_ether(pkt, net_bcast_ethaddr, PROT_NCSI);
+	pkt += eth_hdr_size;
+
+	/* Set NCSI command header fields */
+	hdr = (struct ncsi_pkt_hdr *)pkt;
+	hdr->mc_id = 0;
+	hdr->revision = NCSI_PKT_REVISION;
+	hdr->id = ++ncsi_priv->last_request;
+	ncsi_priv->requests[ncsi_priv->last_request] = 1;
+	hdr->type = cmd;
+	hdr->channel = NCSI_TO_CHANNEL(np, nc);
+	hdr->length = htons(len);
+
+	if (payload && len)
+		memcpy(pkt + sizeof(struct ncsi_pkt_hdr), payload, len);
+
+	/* Calculate checksum */
+	checksum = ncsi_calculate_checksum((unsigned char *)hdr,
+					   sizeof(*hdr) + len);
+	pchecksum = (__be32 *)((void *)(hdr + 1) + len);
+	put_unaligned_be32(htonl(checksum), pchecksum);
+
+	if (wait) {
+		net_set_timeout_handler(1000UL, ncsi_timeout_handler);
+		ncsi_priv->pending_requests++;
+	}
+
+	if (len < 26)
+		len = 26;
+	/* frame header, packet header, payload, checksum */
+	final_len = eth_hdr_size + sizeof(struct ncsi_cmd_pkt_hdr) + len + 4;
+
+	net_send_packet(start, final_len);
+	free(start);
+	return 0;
+}
+
+static void ncsi_handle_aen(struct ip_udp_hdr *ip, unsigned int len)
+{
+	struct ncsi_aen_pkt_hdr *hdr = (struct ncsi_aen_pkt_hdr *)ip;
+	int payload, i;
+	__be32 pchecksum;
+	u32 checksum;
+
+	switch (hdr->type) {
+	case NCSI_PKT_AEN_LSC:
+		printf("NCSI: link state changed\n");
+		payload = 12;
+		break;
+	case NCSI_PKT_AEN_CR:
+		printf("NCSI: re-configuration required\n");
+		payload = 4;
+		break;
+	case NCSI_PKT_AEN_HNCDSC:
+		/* Host notifcation - N/A but weird */
+		debug("NCSI: HNCDSC AEN received\n");
+		return;
+	default:
+		printf("%s: Invalid type 0x%02x\n", __func__, hdr->type);
+		return;
+	}
+
+	/* Validate packet */
+	if (hdr->common.revision != 1) {
+		printf("NCSI: 0x%02x response has unsupported revision 0x%x\n",
+		       hdr->common.type, hdr->common.revision);
+		return;
+	}
+
+	if (ntohs(hdr->common.length) != payload) {
+		printf("NCSI: 0x%02x response has incorrect length %d\n",
+		       hdr->common.type, hdr->common.length);
+		return;
+	}
+
+	pchecksum = get_unaligned_be32((void *)(hdr + 1) + payload - 4);
+	if (pchecksum != 0) {
+		checksum = ncsi_calculate_checksum((unsigned char *)hdr,
+						   sizeof(*hdr) + payload - 4);
+		if (pchecksum != checksum) {
+			printf("NCSI: 0x%02x response has invalid checksum\n",
+			       hdr->common.type);
+			return;
+		}
+	}
+
+	/* Link or configuration lost - just redo the discovery process */
+	ncsi_priv->state = NCSI_PROBE_PACKAGE_SP;
+	for (i = 0; i < ncsi_priv->n_packages; i++)
+		free(ncsi_priv->packages[i].channels);
+	free(ncsi_priv->packages);
+	ncsi_priv->n_packages = 0;
+
+	ncsi_priv->current_package = NCSI_PACKAGE_MAX;
+	ncsi_priv->current_channel = NCSI_CHANNEL_MAX;
+
+	ncsi_probe_packages();
+}
+
+void ncsi_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip,
+		  unsigned int len)
+{
+	struct ncsi_rsp_pkt *pkt = (struct ncsi_rsp_pkt *)ip;
+	struct ncsi_rsp_pkt_hdr *nh = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp;
+	void (*handler)(struct ncsi_rsp_pkt *pkt) = NULL;
+	unsigned short payload;
+
+	if (ncsi_priv->pending_requests)
+		ncsi_priv->pending_requests--;
+
+	if (len < sizeof(struct ncsi_rsp_pkt_hdr)) {
+		printf("NCSI: undersized packet: %u bytes\n", len);
+		goto out;
+	}
+
+	if (nh->common.type == NCSI_PKT_AEN)
+		return ncsi_handle_aen(ip, len);
+
+	switch (nh->common.type) {
+	case NCSI_PKT_RSP_SP:
+		payload = 4;
+		handler = ncsi_rsp_sp;
+		break;
+	case NCSI_PKT_RSP_DP:
+		payload = 4;
+		handler = ncsi_rsp_dp;
+		break;
+	case NCSI_PKT_RSP_CIS:
+		payload = 4;
+		handler = ncsi_rsp_cis;
+		break;
+	case NCSI_PKT_RSP_GLS:
+		payload = 16;
+		handler = ncsi_rsp_gls;
+		break;
+	case NCSI_PKT_RSP_GVI:
+		payload = 40;
+		handler = ncsi_rsp_gvi;
+		break;
+	case NCSI_PKT_RSP_GC:
+		payload = 32;
+		handler = ncsi_rsp_gc;
+		break;
+	case NCSI_PKT_RSP_SMA:
+		payload = 4;
+		handler = ncsi_rsp_sma;
+		break;
+	case NCSI_PKT_RSP_EBF:
+		payload = 4;
+		handler = ncsi_rsp_ebf;
+		break;
+	case NCSI_PKT_RSP_ECNT:
+		payload = 4;
+		handler = ncsi_rsp_ecnt;
+		break;
+	case NCSI_PKT_RSP_EC:
+		payload = 4;
+		handler = ncsi_rsp_ec;
+		break;
+	case NCSI_PKT_RSP_AE:
+		payload = 4;
+		handler = NULL;
+		break;
+	default:
+		printf("NCSI: unsupported packet type 0x%02x\n",
+		       nh->common.type);
+		goto out;
+	}
+
+	if (ncsi_validate_rsp(pkt, payload) != 0) {
+		printf("NCSI: discarding invalid packet of type 0x%02x\n",
+		       nh->common.type);
+		goto out;
+	}
+
+	if (handler)
+		handler(pkt);
+out:
+	ncsi_update_state(nh);
+}
+
+static void ncsi_send_sp(unsigned int np)
+{
+	uchar payload[4] = {0};
+
+	ncsi_send_command(np, NCSI_RESERVED_CHANNEL, NCSI_PKT_CMD_SP,
+			  (unsigned char *)&payload,
+			  cmd_payload(NCSI_PKT_CMD_SP), true);
+}
+
+static void ncsi_send_dp(unsigned int np)
+{
+	ncsi_send_command(np, NCSI_RESERVED_CHANNEL, NCSI_PKT_CMD_DP, NULL, 0,
+			  true);
+}
+
+static void ncsi_send_gls(unsigned int np, unsigned int nc)
+{
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_GLS, NULL, 0, true);
+}
+
+static void ncsi_send_cis(unsigned int np, unsigned int nc)
+{
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_CIS, NULL, 0, true);
+}
+
+static void ncsi_send_ae(unsigned int np, unsigned int nc)
+{
+	struct ncsi_cmd_ae_pkt cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.mode = htonl(ncsi_priv->packages[np].channels[nc].cap_aen);
+
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_AE,
+			  ((unsigned char *)&cmd)
+			  + sizeof(struct ncsi_cmd_pkt_hdr),
+			  cmd_payload(NCSI_PKT_CMD_AE), true);
+}
+
+static void ncsi_send_ebf(unsigned int np, unsigned int nc)
+{
+	struct ncsi_cmd_ebf_pkt cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.mode = htonl(ncsi_priv->packages[np].channels[nc].cap_bc);
+
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_EBF,
+			  ((unsigned char *)&cmd)
+			  + sizeof(struct ncsi_cmd_pkt_hdr),
+			  cmd_payload(NCSI_PKT_CMD_EBF), true);
+}
+
+static void ncsi_send_sma(unsigned int np, unsigned int nc)
+{
+	struct ncsi_cmd_sma_pkt cmd;
+	unsigned char *addr, i;
+
+	addr = eth_get_ethaddr();
+	if (!addr) {
+		printf("NCSI: no MAC address configured\n");
+		return;
+	}
+
+	memset(&cmd, 0, sizeof(cmd));
+	for (i = 0; i < ARP_HLEN; i++)
+		cmd.mac[i] = addr[i];
+	cmd.index = 1;
+	cmd.at_e = 1;
+
+	ncsi_send_command(np, nc, NCSI_PKT_CMD_SMA,
+			  ((unsigned char *)&cmd)
+			  + sizeof(struct ncsi_cmd_pkt_hdr),
+			  cmd_payload(NCSI_PKT_CMD_SMA), true);
+}
+
+void ncsi_probe_packages(void)
+{
+	struct ncsi_package *package;
+	unsigned int np, nc;
+
+	switch (ncsi_priv->state) {
+	case NCSI_PROBE_PACKAGE_SP:
+		if (ncsi_priv->current_package == NCSI_PACKAGE_MAX)
+			ncsi_priv->current_package = 0;
+		ncsi_send_sp(ncsi_priv->current_package);
+		break;
+	case NCSI_PROBE_PACKAGE_DP:
+		ncsi_send_dp(ncsi_priv->current_package);
+		break;
+	case NCSI_PROBE_CHANNEL_SP:
+		if (ncsi_priv->n_packages > 0)
+			ncsi_send_sp(ncsi_priv->current_package);
+		else
+			printf("NCSI: no packages discovered, configuration not possible\n");
+		break;
+	case NCSI_PROBE_CHANNEL:
+		/* Kicks off chain of channel discovery */
+		ncsi_send_cis(ncsi_priv->current_package,
+			      ncsi_priv->current_channel);
+		break;
+	case NCSI_CONFIG:
+		for (np = 0; np < ncsi_priv->n_packages; np++) {
+			package = &ncsi_priv->packages[np];
+			for (nc = 0; nc < package->n_channels; nc++)
+				if (package->channels[nc].has_link)
+					break;
+			if (nc < package->n_channels)
+				break;
+		}
+		if (np == ncsi_priv->n_packages) {
+			printf("NCSI: no link available\n");
+			return;
+		}
+
+		printf("NCSI: configuring channel %d\n", nc);
+		ncsi_priv->current_package = np;
+		ncsi_priv->current_channel = nc;
+		/* Kicks off rest of configure chain */
+		ncsi_send_sma(np, nc);
+		break;
+	default:
+		printf("NCSI: unknown state 0x%x\n", ncsi_priv->state);
+	}
+}
+
+int ncsi_probe(struct phy_device *phydev)
+{
+	if (!phydev->priv) {
+		phydev->priv = malloc(sizeof(struct ncsi));
+		if (!phydev->priv)
+			return -ENOMEM;
+		memset(phydev->priv, 0, sizeof(struct ncsi));
+	}
+
+	ncsi_priv = phydev->priv;
+
+	return 0;
+}
+
+int ncsi_startup(struct phy_device *phydev)
+{
+	/* Set phydev parameters */
+	phydev->speed = SPEED_100;
+	phydev->duplex = DUPLEX_FULL;
+	/* Normal phy reset is N/A */
+	phydev->flags |= PHY_FLAG_BROKEN_RESET;
+
+	/* Set initial probe state */
+	ncsi_priv->state = NCSI_PROBE_PACKAGE_SP;
+
+	/* No active package/channel yet */
+	ncsi_priv->current_package = NCSI_PACKAGE_MAX;
+	ncsi_priv->current_channel = NCSI_CHANNEL_MAX;
+
+	/* Pretend link works so the MAC driver sets final bits up */
+	phydev->link = true;
+
+	/* Set ncsi_priv so we can use it when called from net_loop() */
+	ncsi_priv = phydev->priv;
+
+	return 0;
+}
+
+int ncsi_shutdown(struct phy_device *phydev)
+{
+	printf("NCSI: Disabling package %d\n", ncsi_priv->current_package);
+	ncsi_send_dp(ncsi_priv->current_package);
+	return 0;
+}
+
+static struct phy_driver ncsi_driver = {
+	.uid		= PHY_NCSI_ID,
+	.mask		= 0xffffffff,
+	.name		= "NC-SI",
+	.features	= PHY_100BT_FEATURES | PHY_DEFAULT_FEATURES | SUPPORTED_100baseT_Full | SUPPORTED_MII,
+	.probe		= ncsi_probe,
+	.startup	= ncsi_startup,
+	.shutdown	= ncsi_shutdown,
+};
+
+int phy_ncsi_init(void)
+{
+	phy_register(&ncsi_driver);
+	return 0;
+}
diff --git a/include/net.h b/include/net.h
index 44b32385c4..20c448ee60 100644
--- a/include/net.h
+++ b/include/net.h
@@ -343,6 +343,7 @@ struct vlan_ethernet_hdr {
 #define PROT_VLAN	0x8100		/* IEEE 802.1q protocol		*/
 #define PROT_IPV6	0x86dd		/* IPv6 over bluebook		*/
 #define PROT_PPP_SES	0x8864		/* PPPoE session messages	*/
+#define PROT_NCSI	0x88f8		/* NC-SI control packets        */
 
 #define IPPROTO_ICMP	 1	/* Internet Control Message Protocol	*/
 #define IPPROTO_UDP	17	/* User Datagram Protocol		*/
diff --git a/include/net/ncsi-pkt.h b/include/net/ncsi-pkt.h
new file mode 100644
index 0000000000..a8e9def593
--- /dev/null
+++ b/include/net/ncsi-pkt.h
@@ -0,0 +1,442 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright Gavin Shan, IBM Corporation 2016.
+ */
+
+#ifndef __NCSI_PKT_H__
+#define __NCSI_PKT_H__
+
+struct ncsi_pkt_hdr {
+	unsigned char mc_id;        /* Management controller ID */
+	unsigned char revision;     /* NCSI version - 0x01      */
+	unsigned char reserved;     /* Reserved                 */
+	unsigned char id;           /* Packet sequence number   */
+	unsigned char type;         /* Packet type              */
+	unsigned char channel;      /* Network controller ID    */
+	__be16        length;       /* Payload length           */
+	__be32        reserved1[2]; /* Reserved                 */
+};
+
+struct ncsi_cmd_pkt_hdr {
+	struct ncsi_pkt_hdr common; /* Common NCSI packet header */
+};
+
+struct ncsi_rsp_pkt_hdr {
+	struct ncsi_pkt_hdr common; /* Common NCSI packet header */
+	__be16              code;   /* Response code             */
+	__be16              reason; /* Response reason           */
+};
+
+struct ncsi_aen_pkt_hdr {
+	struct ncsi_pkt_hdr common;       /* Common NCSI packet header */
+	unsigned char       reserved2[3]; /* Reserved                  */
+	unsigned char       type;         /* AEN packet type           */
+};
+
+/* NCSI common command packet */
+struct ncsi_cmd_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
+	__be32                  checksum; /* Checksum       */
+	unsigned char           pad[26];
+};
+
+struct ncsi_rsp_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;      /* Response header */
+	__be32                  checksum; /* Checksum        */
+	unsigned char           pad[22];
+};
+
+/* Select Package */
+struct ncsi_cmd_sp_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;            /* Command header */
+	unsigned char           reserved[3];    /* Reserved       */
+	unsigned char           hw_arbitration; /* HW arbitration */
+	__be32                  checksum;       /* Checksum       */
+	unsigned char           pad[22];
+};
+
+/* Disable Channel */
+struct ncsi_cmd_dc_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;         /* Command header  */
+	unsigned char           reserved[3]; /* Reserved        */
+	unsigned char           ald;         /* Allow link down */
+	__be32                  checksum;    /* Checksum        */
+	unsigned char           pad[22];
+};
+
+/* Reset Channel */
+struct ncsi_cmd_rc_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
+	__be32                  reserved; /* Reserved       */
+	__be32                  checksum; /* Checksum       */
+	unsigned char           pad[22];
+};
+
+/* AEN Enable */
+struct ncsi_cmd_ae_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;         /* Command header   */
+	unsigned char           reserved[3]; /* Reserved         */
+	unsigned char           mc_id;       /* MC ID            */
+	__be32                  mode;        /* AEN working mode */
+	__be32                  checksum;    /* Checksum         */
+	unsigned char           pad[18];
+};
+
+/* Set Link */
+struct ncsi_cmd_sl_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header    */
+	__be32                  mode;     /* Link working mode */
+	__be32                  oem_mode; /* OEM link mode     */
+	__be32                  checksum; /* Checksum          */
+	unsigned char           pad[18];
+};
+
+/* Set VLAN Filter */
+struct ncsi_cmd_svf_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;       /* Command header    */
+	__be16                  reserved;  /* Reserved          */
+	__be16                  vlan;      /* VLAN ID           */
+	__be16                  reserved1; /* Reserved          */
+	unsigned char           index;     /* VLAN table index  */
+	unsigned char           enable;    /* Enable or disable */
+	__be32                  checksum;  /* Checksum          */
+	unsigned char           pad[18];
+};
+
+/* Enable VLAN */
+struct ncsi_cmd_ev_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;         /* Command header   */
+	unsigned char           reserved[3]; /* Reserved         */
+	unsigned char           mode;        /* VLAN filter mode */
+	__be32                  checksum;    /* Checksum         */
+	unsigned char           pad[22];
+};
+
+/* Set MAC Address */
+struct ncsi_cmd_sma_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header          */
+	unsigned char           mac[6];   /* MAC address             */
+	unsigned char           index;    /* MAC table index         */
+	unsigned char           at_e;     /* Addr type and operation */
+	__be32                  checksum; /* Checksum                */
+	unsigned char           pad[18];
+};
+
+/* Enable Broadcast Filter */
+struct ncsi_cmd_ebf_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
+	__be32                  mode;     /* Filter mode    */
+	__be32                  checksum; /* Checksum       */
+	unsigned char           pad[22];
+};
+
+/* Enable Global Multicast Filter */
+struct ncsi_cmd_egmf_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;      /* Command header */
+	__be32                  mode;     /* Global MC mode */
+	__be32                  checksum; /* Checksum       */
+	unsigned char           pad[22];
+};
+
+/* Set NCSI Flow Control */
+struct ncsi_cmd_snfc_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;         /* Command header    */
+	unsigned char           reserved[3]; /* Reserved          */
+	unsigned char           mode;        /* Flow control mode */
+	__be32                  checksum;    /* Checksum          */
+	unsigned char           pad[22];
+};
+
+/* OEM Request Command as per NCSI Specification */
+struct ncsi_cmd_oem_pkt {
+	struct ncsi_cmd_pkt_hdr cmd;         /* Command header    */
+	__be32                  mfr_id;      /* Manufacture ID    */
+	unsigned char           data[];      /* OEM Payload Data  */
+};
+
+/* OEM Response Packet as per NCSI Specification */
+struct ncsi_rsp_oem_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;         /* Command header    */
+	__be32                  mfr_id;      /* Manufacture ID    */
+	unsigned char           data[];      /* Payload data      */
+};
+
+/* Mellanox Response Data */
+struct ncsi_rsp_oem_mlx_pkt {
+	unsigned char           cmd_rev;     /* Command Revision  */
+	unsigned char           cmd;         /* Command ID        */
+	unsigned char           param;       /* Parameter         */
+	unsigned char           optional;    /* Optional data     */
+	unsigned char           data[];      /* Data              */
+};
+
+/* Broadcom Response Data */
+struct ncsi_rsp_oem_bcm_pkt {
+	unsigned char           ver;         /* Payload Version   */
+	unsigned char           type;        /* OEM Command type  */
+	__be16                  len;         /* Payload Length    */
+	unsigned char           data[];      /* Cmd specific Data */
+};
+
+/* Get Link Status */
+struct ncsi_rsp_gls_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;        /* Response header   */
+	__be32                  status;     /* Link status       */
+	__be32                  other;      /* Other indications */
+	__be32                  oem_status; /* OEM link status   */
+	__be32                  checksum;
+	unsigned char           pad[10];
+};
+
+/* Get Version ID */
+struct ncsi_rsp_gvi_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;          /* Response header */
+	__be32                  ncsi_version; /* NCSI version    */
+	unsigned char           reserved[3];  /* Reserved        */
+	unsigned char           alpha2;       /* NCSI version    */
+	unsigned char           fw_name[12];  /* f/w name string */
+	__be32                  fw_version;   /* f/w version     */
+	__be16                  pci_ids[4];   /* PCI IDs         */
+	__be32                  mf_id;        /* Manufacture ID  */
+	__be32                  checksum;
+};
+
+/* Get Capabilities */
+struct ncsi_rsp_gc_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;         /* Response header   */
+	__be32                  cap;         /* Capabilities      */
+	__be32                  bc_cap;      /* Broadcast cap     */
+	__be32                  mc_cap;      /* Multicast cap     */
+	__be32                  buf_cap;     /* Buffering cap     */
+	__be32                  aen_cap;     /* AEN cap           */
+	unsigned char           vlan_cnt;    /* VLAN filter count */
+	unsigned char           mixed_cnt;   /* Mix filter count  */
+	unsigned char           mc_cnt;      /* MC filter count   */
+	unsigned char           uc_cnt;      /* UC filter count   */
+	unsigned char           reserved[2]; /* Reserved          */
+	unsigned char           vlan_mode;   /* VLAN mode         */
+	unsigned char           channel_cnt; /* Channel count     */
+	__be32                  checksum;    /* Checksum          */
+};
+
+/* Get Parameters */
+struct ncsi_rsp_gp_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;          /* Response header       */
+	unsigned char           mac_cnt;      /* Number of MAC addr    */
+	unsigned char           reserved[2];  /* Reserved              */
+	unsigned char           mac_enable;   /* MAC addr enable flags */
+	unsigned char           vlan_cnt;     /* VLAN tag count        */
+	unsigned char           reserved1;    /* Reserved              */
+	__be16                  vlan_enable;  /* VLAN tag enable flags */
+	__be32                  link_mode;    /* Link setting          */
+	__be32                  bc_mode;      /* BC filter mode        */
+	__be32                  valid_modes;  /* Valid mode parameters */
+	unsigned char           vlan_mode;    /* VLAN mode             */
+	unsigned char           fc_mode;      /* Flow control mode     */
+	unsigned char           reserved2[2]; /* Reserved              */
+	__be32                  aen_mode;     /* AEN mode              */
+	unsigned char           mac[6];       /* Supported MAC addr    */
+	__be16                  vlan;         /* Supported VLAN tags   */
+	__be32                  checksum;     /* Checksum              */
+};
+
+/* Get Controller Packet Statistics */
+struct ncsi_rsp_gcps_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;            /* Response header            */
+	__be32                  cnt_hi;         /* Counter cleared            */
+	__be32                  cnt_lo;         /* Counter cleared            */
+	__be32                  rx_bytes;       /* Rx bytes                   */
+	__be32                  tx_bytes;       /* Tx bytes                   */
+	__be32                  rx_uc_pkts;     /* Rx UC packets              */
+	__be32                  rx_mc_pkts;     /* Rx MC packets              */
+	__be32                  rx_bc_pkts;     /* Rx BC packets              */
+	__be32                  tx_uc_pkts;     /* Tx UC packets              */
+	__be32                  tx_mc_pkts;     /* Tx MC packets              */
+	__be32                  tx_bc_pkts;     /* Tx BC packets              */
+	__be32                  fcs_err;        /* FCS errors                 */
+	__be32                  align_err;      /* Alignment errors           */
+	__be32                  false_carrier;  /* False carrier detection    */
+	__be32                  runt_pkts;      /* Rx runt packets            */
+	__be32                  jabber_pkts;    /* Rx jabber packets          */
+	__be32                  rx_pause_xon;   /* Rx pause XON frames        */
+	__be32                  rx_pause_xoff;  /* Rx XOFF frames             */
+	__be32                  tx_pause_xon;   /* Tx XON frames              */
+	__be32                  tx_pause_xoff;  /* Tx XOFF frames             */
+	__be32                  tx_s_collision; /* Single collision frames    */
+	__be32                  tx_m_collision; /* Multiple collision frames  */
+	__be32                  l_collision;    /* Late collision frames      */
+	__be32                  e_collision;    /* Excessive collision frames */
+	__be32                  rx_ctl_frames;  /* Rx control frames          */
+	__be32                  rx_64_frames;   /* Rx 64-bytes frames         */
+	__be32                  rx_127_frames;  /* Rx 65-127 bytes frames     */
+	__be32                  rx_255_frames;  /* Rx 128-255 bytes frames    */
+	__be32                  rx_511_frames;  /* Rx 256-511 bytes frames    */
+	__be32                  rx_1023_frames; /* Rx 512-1023 bytes frames   */
+	__be32                  rx_1522_frames; /* Rx 1024-1522 bytes frames  */
+	__be32                  rx_9022_frames; /* Rx 1523-9022 bytes frames  */
+	__be32                  tx_64_frames;   /* Tx 64-bytes frames         */
+	__be32                  tx_127_frames;  /* Tx 65-127 bytes frames     */
+	__be32                  tx_255_frames;  /* Tx 128-255 bytes frames    */
+	__be32                  tx_511_frames;  /* Tx 256-511 bytes frames    */
+	__be32                  tx_1023_frames; /* Tx 512-1023 bytes frames   */
+	__be32                  tx_1522_frames; /* Tx 1024-1522 bytes frames  */
+	__be32                  tx_9022_frames; /* Tx 1523-9022 bytes frames  */
+	__be32                  rx_valid_bytes; /* Rx valid bytes             */
+	__be32                  rx_runt_pkts;   /* Rx error runt packets      */
+	__be32                  rx_jabber_pkts; /* Rx error jabber packets    */
+	__be32                  checksum;       /* Checksum                   */
+};
+
+/* Get NCSI Statistics */
+struct ncsi_rsp_gns_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;           /* Response header         */
+	__be32                  rx_cmds;       /* Rx NCSI commands        */
+	__be32                  dropped_cmds;  /* Dropped commands        */
+	__be32                  cmd_type_errs; /* Command type errors     */
+	__be32                  cmd_csum_errs; /* Command checksum errors */
+	__be32                  rx_pkts;       /* Rx NCSI packets         */
+	__be32                  tx_pkts;       /* Tx NCSI packets         */
+	__be32                  tx_aen_pkts;   /* Tx AEN packets          */
+	__be32                  checksum;      /* Checksum                */
+};
+
+/* Get NCSI Pass-through Statistics */
+struct ncsi_rsp_gnpts_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;            /* Response header     */
+	__be32                  tx_pkts;        /* Tx packets          */
+	__be32                  tx_dropped;     /* Tx dropped packets  */
+	__be32                  tx_channel_err; /* Tx channel errors   */
+	__be32                  tx_us_err;      /* Tx undersize errors */
+	__be32                  rx_pkts;        /* Rx packets          */
+	__be32                  rx_dropped;     /* Rx dropped packets  */
+	__be32                  rx_channel_err; /* Rx channel errors   */
+	__be32                  rx_us_err;      /* Rx undersize errors */
+	__be32                  rx_os_err;      /* Rx oversize errors  */
+	__be32                  checksum;       /* Checksum            */
+};
+
+/* Get package status */
+struct ncsi_rsp_gps_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;      /* Response header             */
+	__be32                  status;   /* Hardware arbitration status */
+	__be32                  checksum;
+};
+
+/* Get package UUID */
+struct ncsi_rsp_gpuuid_pkt {
+	struct ncsi_rsp_pkt_hdr rsp;      /* Response header */
+	unsigned char           uuid[16]; /* UUID            */
+	__be32                  checksum;
+};
+
+/* AEN: Link State Change */
+struct ncsi_aen_lsc_pkt {
+	struct ncsi_aen_pkt_hdr aen;        /* AEN header      */
+	__be32                  status;     /* Link status     */
+	__be32                  oem_status; /* OEM link status */
+	__be32                  checksum;   /* Checksum        */
+	unsigned char           pad[14];
+};
+
+/* AEN: Configuration Required */
+struct ncsi_aen_cr_pkt {
+	struct ncsi_aen_pkt_hdr aen;      /* AEN header */
+	__be32                  checksum; /* Checksum   */
+	unsigned char           pad[22];
+};
+
+/* AEN: Host Network Controller Driver Status Change */
+struct ncsi_aen_hncdsc_pkt {
+	struct ncsi_aen_pkt_hdr aen;      /* AEN header */
+	__be32                  status;   /* Status     */
+	__be32                  checksum; /* Checksum   */
+	unsigned char           pad[18];
+};
+
+/* NCSI packet revision */
+#define NCSI_PKT_REVISION	0x01
+
+/* NCSI packet commands */
+#define NCSI_PKT_CMD_CIS	0x00 /* Clear Initial State              */
+#define NCSI_PKT_CMD_SP		0x01 /* Select Package                   */
+#define NCSI_PKT_CMD_DP		0x02 /* Deselect Package                 */
+#define NCSI_PKT_CMD_EC		0x03 /* Enable Channel                   */
+#define NCSI_PKT_CMD_DC		0x04 /* Disable Channel                  */
+#define NCSI_PKT_CMD_RC		0x05 /* Reset Channel                    */
+#define NCSI_PKT_CMD_ECNT	0x06 /* Enable Channel Network Tx        */
+#define NCSI_PKT_CMD_DCNT	0x07 /* Disable Channel Network Tx       */
+#define NCSI_PKT_CMD_AE		0x08 /* AEN Enable                       */
+#define NCSI_PKT_CMD_SL		0x09 /* Set Link                         */
+#define NCSI_PKT_CMD_GLS	0x0a /* Get Link                         */
+#define NCSI_PKT_CMD_SVF	0x0b /* Set VLAN Filter                  */
+#define NCSI_PKT_CMD_EV		0x0c /* Enable VLAN                      */
+#define NCSI_PKT_CMD_DV		0x0d /* Disable VLAN                     */
+#define NCSI_PKT_CMD_SMA	0x0e /* Set MAC address                  */
+#define NCSI_PKT_CMD_EBF	0x10 /* Enable Broadcast Filter          */
+#define NCSI_PKT_CMD_DBF	0x11 /* Disable Broadcast Filter         */
+#define NCSI_PKT_CMD_EGMF	0x12 /* Enable Global Multicast Filter   */
+#define NCSI_PKT_CMD_DGMF	0x13 /* Disable Global Multicast Filter  */
+#define NCSI_PKT_CMD_SNFC	0x14 /* Set NCSI Flow Control            */
+#define NCSI_PKT_CMD_GVI	0x15 /* Get Version ID                   */
+#define NCSI_PKT_CMD_GC		0x16 /* Get Capabilities                 */
+#define NCSI_PKT_CMD_GP		0x17 /* Get Parameters                   */
+#define NCSI_PKT_CMD_GCPS	0x18 /* Get Controller Packet Statistics */
+#define NCSI_PKT_CMD_GNS	0x19 /* Get NCSI Statistics              */
+#define NCSI_PKT_CMD_GNPTS	0x1a /* Get NCSI Pass-throu Statistics   */
+#define NCSI_PKT_CMD_GPS	0x1b /* Get package status               */
+#define NCSI_PKT_CMD_OEM	0x50 /* OEM                              */
+#define NCSI_PKT_CMD_PLDM	0x51 /* PLDM request over NCSI over RBT  */
+#define NCSI_PKT_CMD_GPUUID	0x52 /* Get package UUID                 */
+
+/* NCSI packet responses */
+#define NCSI_PKT_RSP_CIS	(NCSI_PKT_CMD_CIS    + 0x80)
+#define NCSI_PKT_RSP_SP		(NCSI_PKT_CMD_SP     + 0x80)
+#define NCSI_PKT_RSP_DP		(NCSI_PKT_CMD_DP     + 0x80)
+#define NCSI_PKT_RSP_EC		(NCSI_PKT_CMD_EC     + 0x80)
+#define NCSI_PKT_RSP_DC		(NCSI_PKT_CMD_DC     + 0x80)
+#define NCSI_PKT_RSP_RC		(NCSI_PKT_CMD_RC     + 0x80)
+#define NCSI_PKT_RSP_ECNT	(NCSI_PKT_CMD_ECNT   + 0x80)
+#define NCSI_PKT_RSP_DCNT	(NCSI_PKT_CMD_DCNT   + 0x80)
+#define NCSI_PKT_RSP_AE		(NCSI_PKT_CMD_AE     + 0x80)
+#define NCSI_PKT_RSP_SL		(NCSI_PKT_CMD_SL     + 0x80)
+#define NCSI_PKT_RSP_GLS	(NCSI_PKT_CMD_GLS    + 0x80)
+#define NCSI_PKT_RSP_SVF	(NCSI_PKT_CMD_SVF    + 0x80)
+#define NCSI_PKT_RSP_EV		(NCSI_PKT_CMD_EV     + 0x80)
+#define NCSI_PKT_RSP_DV		(NCSI_PKT_CMD_DV     + 0x80)
+#define NCSI_PKT_RSP_SMA	(NCSI_PKT_CMD_SMA    + 0x80)
+#define NCSI_PKT_RSP_EBF	(NCSI_PKT_CMD_EBF    + 0x80)
+#define NCSI_PKT_RSP_DBF	(NCSI_PKT_CMD_DBF    + 0x80)
+#define NCSI_PKT_RSP_EGMF	(NCSI_PKT_CMD_EGMF   + 0x80)
+#define NCSI_PKT_RSP_DGMF	(NCSI_PKT_CMD_DGMF   + 0x80)
+#define NCSI_PKT_RSP_SNFC	(NCSI_PKT_CMD_SNFC   + 0x80)
+#define NCSI_PKT_RSP_GVI	(NCSI_PKT_CMD_GVI    + 0x80)
+#define NCSI_PKT_RSP_GC		(NCSI_PKT_CMD_GC     + 0x80)
+#define NCSI_PKT_RSP_GP		(NCSI_PKT_CMD_GP     + 0x80)
+#define NCSI_PKT_RSP_GCPS	(NCSI_PKT_CMD_GCPS   + 0x80)
+#define NCSI_PKT_RSP_GNS	(NCSI_PKT_CMD_GNS    + 0x80)
+#define NCSI_PKT_RSP_GNPTS	(NCSI_PKT_CMD_GNPTS  + 0x80)
+#define NCSI_PKT_RSP_GPS	(NCSI_PKT_CMD_GPS    + 0x80)
+#define NCSI_PKT_RSP_OEM	(NCSI_PKT_CMD_OEM    + 0x80)
+#define NCSI_PKT_RSP_PLDM	(NCSI_PKT_CMD_PLDM   + 0x80)
+#define NCSI_PKT_RSP_GPUUID	(NCSI_PKT_CMD_GPUUID + 0x80)
+
+/* NCSI response code/reason */
+#define NCSI_PKT_RSP_C_COMPLETED	0x0000 /* Command Completed        */
+#define NCSI_PKT_RSP_C_FAILED		0x0001 /* Command Failed           */
+#define NCSI_PKT_RSP_C_UNAVAILABLE	0x0002 /* Command Unavailable      */
+#define NCSI_PKT_RSP_C_UNSUPPORTED	0x0003 /* Command Unsupported      */
+#define NCSI_PKT_RSP_R_NO_ERROR		0x0000 /* No Error                 */
+#define NCSI_PKT_RSP_R_INTERFACE	0x0001 /* Interface not ready      */
+#define NCSI_PKT_RSP_R_PARAM		0x0002 /* Invalid Parameter        */
+#define NCSI_PKT_RSP_R_CHANNEL		0x0003 /* Channel not Ready        */
+#define NCSI_PKT_RSP_R_PACKAGE		0x0004 /* Package not Ready        */
+#define NCSI_PKT_RSP_R_LENGTH		0x0005 /* Invalid payload length   */
+#define NCSI_PKT_RSP_R_UNKNOWN		0x7fff /* Command type unsupported */
+
+/* NCSI AEN packet type */
+#define NCSI_PKT_AEN		0xFF /* AEN Packet               */
+#define NCSI_PKT_AEN_LSC	0x00 /* Link status change       */
+#define NCSI_PKT_AEN_CR		0x01 /* Configuration required   */
+#define NCSI_PKT_AEN_HNCDSC	0x02 /* HNC driver status change */
+
+#endif /* __NCSI_PKT_H__ */
diff --git a/include/net/ncsi.h b/include/net/ncsi.h
new file mode 100644
index 0000000000..9637beab2a
--- /dev/null
+++ b/include/net/ncsi.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * NC-SI PHY
+ *
+ * Copyright (C) 2019, IBM Corporation.
+ */
+
+#include <common.h>
+#include <phy.h>
+
+bool ncsi_active(void);
+void ncsi_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip,
+		  unsigned int len);
+void ncsi_probe_packages(void);
diff --git a/include/phy.h b/include/phy.h
index d01435d1aa..297fc7a78e 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -17,6 +17,7 @@
 #include <phy_interface.h>
 
 #define PHY_FIXED_ID		0xa5a55a5a
+#define PHY_NCSI_ID		0xbeefcafe
 
 #define PHY_MAX_ADDR 32
 
-- 
2.21.0

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v2 2/4] phy: Include NC-SI in phy setup
  2019-06-18  1:37 ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-18  1:37   ` Samuel Mendoza-Jonas
  -1 siblings, 0 replies; 34+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-18  1:37 UTC (permalink / raw)
  To: u-boot; +Cc: Samuel Mendoza-Jonas, joel, clg, openbmc, joe.hershberger, sjg

Add NC-SI to the usual phy handling. This makes two notable changes:
- Somewhat similar to a fixed phy, phy_connect() will create an NC-SI
phy if CONFIG_PHY_NCSI is defined.
- An early return is added to phy_read() and phy_write() to handle a
case like the NC-SI phy which does not define a bus.

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
 drivers/net/phy/phy.c   |  7 +++++++
 include/phy.h           | 11 +++++++++++
 include/phy_interface.h |  2 ++
 3 files changed, 20 insertions(+)

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index c1c1af9abd..dc68f25ebf 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -539,6 +539,9 @@ int phy_init(void)
 #endif
 #ifdef CONFIG_PHY_FIXED
 	phy_fixed_init();
+#endif
+#ifdef CONFIG_PHY_NCSI
+	phy_ncsi_init();
 #endif
 	return 0;
 }
@@ -947,6 +950,10 @@ struct phy_device *phy_connect(struct mii_dev *bus, int addr,
 	phydev = phy_connect_fixed(bus, dev, interface);
 #endif
 
+#ifdef CONFIG_PHY_NCSI
+	phydev = phy_device_create(bus, 0, PHY_NCSI_ID, false, interface);
+#endif
+
 	if (!phydev)
 		phydev = phy_find_by_mask(bus, mask, interface);
 
diff --git a/include/phy.h b/include/phy.h
index 297fc7a78e..56bd146e2c 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -163,6 +163,11 @@ static inline int phy_read(struct phy_device *phydev, int devad, int regnum)
 {
 	struct mii_dev *bus = phydev->bus;
 
+	if (!bus || !bus->read) {
+		debug("%s: No bus configured\n", __func__);
+		return -1;
+	}
+
 	return bus->read(bus, phydev->addr, devad, regnum);
 }
 
@@ -171,6 +176,11 @@ static inline int phy_write(struct phy_device *phydev, int devad, int regnum,
 {
 	struct mii_dev *bus = phydev->bus;
 
+	if (!bus || !bus->read) {
+		debug("%s: No bus configured\n", __func__);
+		return -1;
+	}
+
 	return bus->write(bus, phydev->addr, devad, regnum, val);
 }
 
@@ -312,6 +322,7 @@ int phy_vitesse_init(void);
 int phy_xilinx_init(void);
 int phy_mscc_init(void);
 int phy_fixed_init(void);
+int phy_ncsi_init(void);
 
 int board_phy_config(struct phy_device *phydev);
 int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id);
diff --git a/include/phy_interface.h b/include/phy_interface.h
index c6823189f8..9e334bb47d 100644
--- a/include/phy_interface.h
+++ b/include/phy_interface.h
@@ -31,6 +31,7 @@ typedef enum {
 	PHY_INTERFACE_MODE_XLAUI,
 	PHY_INTERFACE_MODE_CAUI2,
 	PHY_INTERFACE_MODE_CAUI4,
+	PHY_INTERFACE_MODE_NCSI,
 	PHY_INTERFACE_MODE_NONE,	/* Must be last */
 
 	PHY_INTERFACE_MODE_COUNT,
@@ -58,6 +59,7 @@ static const char * const phy_interface_strings[] = {
 	[PHY_INTERFACE_MODE_XLAUI]		= "xlaui4",
 	[PHY_INTERFACE_MODE_CAUI2]		= "caui2",
 	[PHY_INTERFACE_MODE_CAUI4]		= "caui4",
+	[PHY_INTERFACE_MODE_NCSI]		= "NC-SI",
 	[PHY_INTERFACE_MODE_NONE]		= "",
 };
 
-- 
2.21.0

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 2/4] phy: Include NC-SI in phy setup
@ 2019-06-18  1:37   ` Samuel Mendoza-Jonas
  0 siblings, 0 replies; 34+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-18  1:37 UTC (permalink / raw)
  To: u-boot

Add NC-SI to the usual phy handling. This makes two notable changes:
- Somewhat similar to a fixed phy, phy_connect() will create an NC-SI
phy if CONFIG_PHY_NCSI is defined.
- An early return is added to phy_read() and phy_write() to handle a
case like the NC-SI phy which does not define a bus.

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
 drivers/net/phy/phy.c   |  7 +++++++
 include/phy.h           | 11 +++++++++++
 include/phy_interface.h |  2 ++
 3 files changed, 20 insertions(+)

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index c1c1af9abd..dc68f25ebf 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -539,6 +539,9 @@ int phy_init(void)
 #endif
 #ifdef CONFIG_PHY_FIXED
 	phy_fixed_init();
+#endif
+#ifdef CONFIG_PHY_NCSI
+	phy_ncsi_init();
 #endif
 	return 0;
 }
@@ -947,6 +950,10 @@ struct phy_device *phy_connect(struct mii_dev *bus, int addr,
 	phydev = phy_connect_fixed(bus, dev, interface);
 #endif
 
+#ifdef CONFIG_PHY_NCSI
+	phydev = phy_device_create(bus, 0, PHY_NCSI_ID, false, interface);
+#endif
+
 	if (!phydev)
 		phydev = phy_find_by_mask(bus, mask, interface);
 
diff --git a/include/phy.h b/include/phy.h
index 297fc7a78e..56bd146e2c 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -163,6 +163,11 @@ static inline int phy_read(struct phy_device *phydev, int devad, int regnum)
 {
 	struct mii_dev *bus = phydev->bus;
 
+	if (!bus || !bus->read) {
+		debug("%s: No bus configured\n", __func__);
+		return -1;
+	}
+
 	return bus->read(bus, phydev->addr, devad, regnum);
 }
 
@@ -171,6 +176,11 @@ static inline int phy_write(struct phy_device *phydev, int devad, int regnum,
 {
 	struct mii_dev *bus = phydev->bus;
 
+	if (!bus || !bus->read) {
+		debug("%s: No bus configured\n", __func__);
+		return -1;
+	}
+
 	return bus->write(bus, phydev->addr, devad, regnum, val);
 }
 
@@ -312,6 +322,7 @@ int phy_vitesse_init(void);
 int phy_xilinx_init(void);
 int phy_mscc_init(void);
 int phy_fixed_init(void);
+int phy_ncsi_init(void);
 
 int board_phy_config(struct phy_device *phydev);
 int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id);
diff --git a/include/phy_interface.h b/include/phy_interface.h
index c6823189f8..9e334bb47d 100644
--- a/include/phy_interface.h
+++ b/include/phy_interface.h
@@ -31,6 +31,7 @@ typedef enum {
 	PHY_INTERFACE_MODE_XLAUI,
 	PHY_INTERFACE_MODE_CAUI2,
 	PHY_INTERFACE_MODE_CAUI4,
+	PHY_INTERFACE_MODE_NCSI,
 	PHY_INTERFACE_MODE_NONE,	/* Must be last */
 
 	PHY_INTERFACE_MODE_COUNT,
@@ -58,6 +59,7 @@ static const char * const phy_interface_strings[] = {
 	[PHY_INTERFACE_MODE_XLAUI]		= "xlaui4",
 	[PHY_INTERFACE_MODE_CAUI2]		= "caui2",
 	[PHY_INTERFACE_MODE_CAUI4]		= "caui4",
+	[PHY_INTERFACE_MODE_NCSI]		= "NC-SI",
 	[PHY_INTERFACE_MODE_NONE]		= "",
 };
 
-- 
2.21.0

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v2 3/4] net/ftgmac100: Add NC-SI mode support
  2019-06-18  1:37 ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-18  1:37   ` Samuel Mendoza-Jonas
  -1 siblings, 0 replies; 34+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-18  1:37 UTC (permalink / raw)
  To: u-boot; +Cc: Samuel Mendoza-Jonas, joel, clg, openbmc, joe.hershberger, sjg

Update the ftgmac100 driver to support NC-SI instead of an mdio phy
where available. This is a common setup for Aspeed AST2x00 platforms.

NC-SI mode is determined from the device-tree if either phy-mode sets it
or the use-ncsi property exists. If set then normal mdio setup is
skipped in favour of the NC-SI phy.

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
 drivers/net/ftgmac100.c | 39 +++++++++++++++++++++++++++++----------
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
index 92c38a81bd..c0100e91c7 100644
--- a/drivers/net/ftgmac100.c
+++ b/drivers/net/ftgmac100.c
@@ -18,6 +18,7 @@
 #include <wait_bit.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <net/ncsi.h>
 
 #include "ftgmac100.h"
 
@@ -81,6 +82,7 @@ struct ftgmac100_data {
 	struct mii_dev *bus;
 	u32 phy_mode;
 	u32 max_speed;
+	bool ncsi_mode;
 
 	struct clk_bulk clks;
 
@@ -181,7 +183,7 @@ static int ftgmac100_phy_adjust_link(struct ftgmac100_data *priv)
 	struct phy_device *phydev = priv->phydev;
 	u32 maccr;
 
-	if (!phydev->link) {
+	if (!phydev->link && !priv->ncsi_mode) {
 		dev_err(phydev->dev, "No link\n");
 		return -EREMOTEIO;
 	}
@@ -217,7 +219,8 @@ static int ftgmac100_phy_init(struct udevice *dev)
 	if (!phydev)
 		return -ENODEV;
 
-	phydev->supported &= PHY_GBIT_FEATURES;
+	if (!priv->ncsi_mode)
+		phydev->supported &= PHY_GBIT_FEATURES;
 	if (priv->max_speed) {
 		ret = phy_set_supported(phydev, priv->max_speed);
 		if (ret)
@@ -275,7 +278,8 @@ static void ftgmac100_stop(struct udevice *dev)
 
 	writel(0, &ftgmac100->maccr);
 
-	phy_shutdown(priv->phydev);
+	if (!priv->ncsi_mode)
+		phy_shutdown(priv->phydev);
 }
 
 static int ftgmac100_start(struct udevice *dev)
@@ -513,6 +517,7 @@ static int ftgmac100_ofdata_to_platdata(struct udevice *dev)
 	pdata->iobase = devfdt_get_addr(dev);
 	pdata->phy_interface = -1;
 	phy_mode = dev_read_string(dev, "phy-mode");
+
 	if (phy_mode)
 		pdata->phy_interface = phy_get_interface_by_name(phy_mode);
 	if (pdata->phy_interface == -1) {
@@ -537,8 +542,13 @@ static int ftgmac100_probe(struct udevice *dev)
 {
 	struct eth_pdata *pdata = dev_get_platdata(dev);
 	struct ftgmac100_data *priv = dev_get_priv(dev);
+	const char *phy_mode;
 	int ret;
 
+	phy_mode = dev_read_string(dev, "phy-mode");
+	priv->ncsi_mode = dev_read_bool(dev, "use-ncsi") ||
+		(phy_mode && strcmp(phy_mode, "NC-SI") == 0);
+
 	priv->iobase = (struct ftgmac100 *)pdata->iobase;
 	priv->phy_mode = pdata->phy_interface;
 	priv->max_speed = pdata->max_speed;
@@ -548,10 +558,15 @@ static int ftgmac100_probe(struct udevice *dev)
 	if (ret)
 		goto out;
 
-	ret = ftgmac100_mdio_init(dev);
-	if (ret) {
-		dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
-		goto out;
+	if (priv->ncsi_mode) {
+		printf("%s - NCSI detected\n", __func__);
+	} else {
+		ret = ftgmac100_mdio_init(dev);
+		if (ret) {
+			dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
+			goto out;
+		}
+
 	}
 
 	ret = ftgmac100_phy_init(dev);
@@ -571,9 +586,13 @@ static int ftgmac100_remove(struct udevice *dev)
 {
 	struct ftgmac100_data *priv = dev_get_priv(dev);
 
-	free(priv->phydev);
-	mdio_unregister(priv->bus);
-	mdio_free(priv->bus);
+	if (!priv->ncsi_mode) {
+		free(priv->phydev);
+		mdio_unregister(priv->bus);
+		mdio_free(priv->bus);
+	} else {
+		free(priv->phydev);
+	}
 	clk_release_bulk(&priv->clks);
 
 	return 0;
-- 
2.21.0

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 3/4] net/ftgmac100: Add NC-SI mode support
@ 2019-06-18  1:37   ` Samuel Mendoza-Jonas
  0 siblings, 0 replies; 34+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-18  1:37 UTC (permalink / raw)
  To: u-boot

Update the ftgmac100 driver to support NC-SI instead of an mdio phy
where available. This is a common setup for Aspeed AST2x00 platforms.

NC-SI mode is determined from the device-tree if either phy-mode sets it
or the use-ncsi property exists. If set then normal mdio setup is
skipped in favour of the NC-SI phy.

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
 drivers/net/ftgmac100.c | 39 +++++++++++++++++++++++++++++----------
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
index 92c38a81bd..c0100e91c7 100644
--- a/drivers/net/ftgmac100.c
+++ b/drivers/net/ftgmac100.c
@@ -18,6 +18,7 @@
 #include <wait_bit.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <net/ncsi.h>
 
 #include "ftgmac100.h"
 
@@ -81,6 +82,7 @@ struct ftgmac100_data {
 	struct mii_dev *bus;
 	u32 phy_mode;
 	u32 max_speed;
+	bool ncsi_mode;
 
 	struct clk_bulk clks;
 
@@ -181,7 +183,7 @@ static int ftgmac100_phy_adjust_link(struct ftgmac100_data *priv)
 	struct phy_device *phydev = priv->phydev;
 	u32 maccr;
 
-	if (!phydev->link) {
+	if (!phydev->link && !priv->ncsi_mode) {
 		dev_err(phydev->dev, "No link\n");
 		return -EREMOTEIO;
 	}
@@ -217,7 +219,8 @@ static int ftgmac100_phy_init(struct udevice *dev)
 	if (!phydev)
 		return -ENODEV;
 
-	phydev->supported &= PHY_GBIT_FEATURES;
+	if (!priv->ncsi_mode)
+		phydev->supported &= PHY_GBIT_FEATURES;
 	if (priv->max_speed) {
 		ret = phy_set_supported(phydev, priv->max_speed);
 		if (ret)
@@ -275,7 +278,8 @@ static void ftgmac100_stop(struct udevice *dev)
 
 	writel(0, &ftgmac100->maccr);
 
-	phy_shutdown(priv->phydev);
+	if (!priv->ncsi_mode)
+		phy_shutdown(priv->phydev);
 }
 
 static int ftgmac100_start(struct udevice *dev)
@@ -513,6 +517,7 @@ static int ftgmac100_ofdata_to_platdata(struct udevice *dev)
 	pdata->iobase = devfdt_get_addr(dev);
 	pdata->phy_interface = -1;
 	phy_mode = dev_read_string(dev, "phy-mode");
+
 	if (phy_mode)
 		pdata->phy_interface = phy_get_interface_by_name(phy_mode);
 	if (pdata->phy_interface == -1) {
@@ -537,8 +542,13 @@ static int ftgmac100_probe(struct udevice *dev)
 {
 	struct eth_pdata *pdata = dev_get_platdata(dev);
 	struct ftgmac100_data *priv = dev_get_priv(dev);
+	const char *phy_mode;
 	int ret;
 
+	phy_mode = dev_read_string(dev, "phy-mode");
+	priv->ncsi_mode = dev_read_bool(dev, "use-ncsi") ||
+		(phy_mode && strcmp(phy_mode, "NC-SI") == 0);
+
 	priv->iobase = (struct ftgmac100 *)pdata->iobase;
 	priv->phy_mode = pdata->phy_interface;
 	priv->max_speed = pdata->max_speed;
@@ -548,10 +558,15 @@ static int ftgmac100_probe(struct udevice *dev)
 	if (ret)
 		goto out;
 
-	ret = ftgmac100_mdio_init(dev);
-	if (ret) {
-		dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
-		goto out;
+	if (priv->ncsi_mode) {
+		printf("%s - NCSI detected\n", __func__);
+	} else {
+		ret = ftgmac100_mdio_init(dev);
+		if (ret) {
+			dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
+			goto out;
+		}
+
 	}
 
 	ret = ftgmac100_phy_init(dev);
@@ -571,9 +586,13 @@ static int ftgmac100_remove(struct udevice *dev)
 {
 	struct ftgmac100_data *priv = dev_get_priv(dev);
 
-	free(priv->phydev);
-	mdio_unregister(priv->bus);
-	mdio_free(priv->bus);
+	if (!priv->ncsi_mode) {
+		free(priv->phydev);
+		mdio_unregister(priv->bus);
+		mdio_free(priv->bus);
+	} else {
+		free(priv->phydev);
+	}
 	clk_release_bulk(&priv->clks);
 
 	return 0;
-- 
2.21.0

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v2 4/4] net: NC-SI setup and handling
  2019-06-18  1:37 ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-18  1:37   ` Samuel Mendoza-Jonas
  -1 siblings, 0 replies; 34+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-18  1:37 UTC (permalink / raw)
  To: u-boot; +Cc: Samuel Mendoza-Jonas, joel, clg, openbmc, joe.hershberger, sjg

Add the handling of NC-SI ethernet frames, and add a check at the start
of net_loop() to configure NC-SI before starting other network commands.
This also adds an "ncsi" command to manually start NC-SI configuration.

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
v2: Update ncsi command help text

 cmd/Kconfig   |  8 ++++++++
 cmd/net.c     | 18 ++++++++++++++++++
 include/net.h |  2 +-
 net/net.c     | 27 ++++++++++++++++++++++++++-
 4 files changed, 53 insertions(+), 2 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 0badcb3fe0..9851b04972 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1332,6 +1332,14 @@ config CMD_LINK_LOCAL
 	help
 	  Acquire a network IP address using the link-local protocol
 
+config CMD_NCSI
+	bool "ncsi"
+	depends on PHY_NCSI
+	help
+	  Manually configure the attached NIC via NC-SI.
+	  Normally this happens automatically before other network
+	  operations.
+
 endif
 
 config CMD_ETHSW
diff --git a/cmd/net.c b/cmd/net.c
index 89721b8f8b..7d2c21ba4d 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -457,3 +457,21 @@ U_BOOT_CMD(
 );
 
 #endif  /* CONFIG_CMD_LINK_LOCAL */
+
+#if defined(CONFIG_CMD_NCSI)
+static int do_ncsi(cmd_tbl_t *cmdtp, int flag, int argc,
+		   char * const argv[])
+{
+	if (net_loop(NCSI) < 0)
+		return CMD_RET_FAILURE;
+
+	return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+	ncsi,	1,	1,	do_ncsi,
+	"Configure attached NIC via NC-SI",
+	""
+);
+
+#endif  /* CONFIG_CMD_NCSI */
diff --git a/include/net.h b/include/net.h
index 20c448ee60..9189f0fb53 100644
--- a/include/net.h
+++ b/include/net.h
@@ -531,7 +531,7 @@ extern int		net_restart_wrap;	/* Tried all network devices */
 
 enum proto_t {
 	BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP,
-	TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL
+	TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, NCSI
 };
 
 extern char	net_boot_file_name[1024];/* Boot File name */
diff --git a/net/net.c b/net/net.c
index 58b0417cbe..a59169a032 100644
--- a/net/net.c
+++ b/net/net.c
@@ -95,6 +95,7 @@
 #include <net.h>
 #include <net/fastboot.h>
 #include <net/tftp.h>
+#include <net/ncsi.h>
 #if defined(CONFIG_LED_STATUS)
 #include <miiphy.h>
 #include <status_led.h>
@@ -407,6 +408,16 @@ int net_loop(enum proto_t protocol)
 	net_try_count = 1;
 	debug_cond(DEBUG_INT_STATE, "--- net_loop Entry\n");
 
+#ifdef CONFIG_PHY_NCSI
+	if (protocol != NCSI && !ncsi_active()) {
+		printf("%s: configuring NCSI first\n", __func__);
+		if (net_loop(NCSI) < 0)
+			return ret;
+		eth_init_state_only();
+		goto restart;
+	}
+#endif
+
 	bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
 	net_init();
 	if (eth_is_on_demand_init() || protocol != NETCONS) {
@@ -420,6 +431,7 @@ int net_loop(enum proto_t protocol)
 	} else {
 		eth_init_state_only();
 	}
+
 restart:
 #ifdef CONFIG_USB_KEYBOARD
 	net_busy_flag = 0;
@@ -526,6 +538,11 @@ restart:
 		case WOL:
 			wol_start();
 			break;
+#endif
+#if defined(CONFIG_CMD_NCSI)
+		case NCSI:
+			ncsi_probe_packages();
+			break;
 #endif
 		default:
 			break;
@@ -637,7 +654,7 @@ restart:
 				env_set_hex("filesize", net_boot_file_size);
 				env_set_hex("fileaddr", load_addr);
 			}
-			if (protocol != NETCONS)
+			if (protocol != NETCONS && protocol != NCSI)
 				eth_halt();
 			else
 				eth_halt_state_only();
@@ -1318,6 +1335,11 @@ void net_process_received_packet(uchar *in_packet, int len)
 	case PROT_WOL:
 		wol_receive(ip, len);
 		break;
+#endif
+#ifdef CONFIG_PHY_NCSI
+	case PROT_NCSI:
+		ncsi_receive(et, ip, len);
+		break;
 #endif
 	}
 }
@@ -1379,6 +1401,9 @@ common:
 
 #ifdef CONFIG_CMD_RARP
 	case RARP:
+#endif
+#ifdef CONFIG_CMD_NCSI
+	case NCSI:
 #endif
 	case BOOTP:
 	case CDP:
-- 
2.21.0

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 4/4] net: NC-SI setup and handling
@ 2019-06-18  1:37   ` Samuel Mendoza-Jonas
  0 siblings, 0 replies; 34+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-18  1:37 UTC (permalink / raw)
  To: u-boot

Add the handling of NC-SI ethernet frames, and add a check at the start
of net_loop() to configure NC-SI before starting other network commands.
This also adds an "ncsi" command to manually start NC-SI configuration.

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
v2: Update ncsi command help text

 cmd/Kconfig   |  8 ++++++++
 cmd/net.c     | 18 ++++++++++++++++++
 include/net.h |  2 +-
 net/net.c     | 27 ++++++++++++++++++++++++++-
 4 files changed, 53 insertions(+), 2 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 0badcb3fe0..9851b04972 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1332,6 +1332,14 @@ config CMD_LINK_LOCAL
 	help
 	  Acquire a network IP address using the link-local protocol
 
+config CMD_NCSI
+	bool "ncsi"
+	depends on PHY_NCSI
+	help
+	  Manually configure the attached NIC via NC-SI.
+	  Normally this happens automatically before other network
+	  operations.
+
 endif
 
 config CMD_ETHSW
diff --git a/cmd/net.c b/cmd/net.c
index 89721b8f8b..7d2c21ba4d 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -457,3 +457,21 @@ U_BOOT_CMD(
 );
 
 #endif  /* CONFIG_CMD_LINK_LOCAL */
+
+#if defined(CONFIG_CMD_NCSI)
+static int do_ncsi(cmd_tbl_t *cmdtp, int flag, int argc,
+		   char * const argv[])
+{
+	if (net_loop(NCSI) < 0)
+		return CMD_RET_FAILURE;
+
+	return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+	ncsi,	1,	1,	do_ncsi,
+	"Configure attached NIC via NC-SI",
+	""
+);
+
+#endif  /* CONFIG_CMD_NCSI */
diff --git a/include/net.h b/include/net.h
index 20c448ee60..9189f0fb53 100644
--- a/include/net.h
+++ b/include/net.h
@@ -531,7 +531,7 @@ extern int		net_restart_wrap;	/* Tried all network devices */
 
 enum proto_t {
 	BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP,
-	TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL
+	TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, NCSI
 };
 
 extern char	net_boot_file_name[1024];/* Boot File name */
diff --git a/net/net.c b/net/net.c
index 58b0417cbe..a59169a032 100644
--- a/net/net.c
+++ b/net/net.c
@@ -95,6 +95,7 @@
 #include <net.h>
 #include <net/fastboot.h>
 #include <net/tftp.h>
+#include <net/ncsi.h>
 #if defined(CONFIG_LED_STATUS)
 #include <miiphy.h>
 #include <status_led.h>
@@ -407,6 +408,16 @@ int net_loop(enum proto_t protocol)
 	net_try_count = 1;
 	debug_cond(DEBUG_INT_STATE, "--- net_loop Entry\n");
 
+#ifdef CONFIG_PHY_NCSI
+	if (protocol != NCSI && !ncsi_active()) {
+		printf("%s: configuring NCSI first\n", __func__);
+		if (net_loop(NCSI) < 0)
+			return ret;
+		eth_init_state_only();
+		goto restart;
+	}
+#endif
+
 	bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
 	net_init();
 	if (eth_is_on_demand_init() || protocol != NETCONS) {
@@ -420,6 +431,7 @@ int net_loop(enum proto_t protocol)
 	} else {
 		eth_init_state_only();
 	}
+
 restart:
 #ifdef CONFIG_USB_KEYBOARD
 	net_busy_flag = 0;
@@ -526,6 +538,11 @@ restart:
 		case WOL:
 			wol_start();
 			break;
+#endif
+#if defined(CONFIG_CMD_NCSI)
+		case NCSI:
+			ncsi_probe_packages();
+			break;
 #endif
 		default:
 			break;
@@ -637,7 +654,7 @@ restart:
 				env_set_hex("filesize", net_boot_file_size);
 				env_set_hex("fileaddr", load_addr);
 			}
-			if (protocol != NETCONS)
+			if (protocol != NETCONS && protocol != NCSI)
 				eth_halt();
 			else
 				eth_halt_state_only();
@@ -1318,6 +1335,11 @@ void net_process_received_packet(uchar *in_packet, int len)
 	case PROT_WOL:
 		wol_receive(ip, len);
 		break;
+#endif
+#ifdef CONFIG_PHY_NCSI
+	case PROT_NCSI:
+		ncsi_receive(et, ip, len);
+		break;
 #endif
 	}
 }
@@ -1379,6 +1401,9 @@ common:
 
 #ifdef CONFIG_CMD_RARP
 	case RARP:
+#endif
+#ifdef CONFIG_CMD_NCSI
+	case NCSI:
 #endif
 	case BOOTP:
 	case CDP:
-- 
2.21.0

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 3/4] net/ftgmac100: Add NC-SI mode support
  2019-06-18  1:37   ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-18  8:31     ` Cédric Le Goater
  -1 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2019-06-18  8:31 UTC (permalink / raw)
  To: Samuel Mendoza-Jonas, u-boot; +Cc: joel, openbmc, joe.hershberger, sjg

On 18/06/2019 03:37, Samuel Mendoza-Jonas wrote:
> Update the ftgmac100 driver to support NC-SI instead of an mdio phy
> where available. This is a common setup for Aspeed AST2x00 platforms.
> 
> NC-SI mode is determined from the device-tree if either phy-mode sets it
> or the use-ncsi property exists. If set then normal mdio setup is
> skipped in favour of the NC-SI phy.
> 
> Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>


LGTM. Some very minor remarks below in case you resend.

Reviewed-by: Cédric Le Goater <clg@kaod.org>

Thanks,

C.

> ---
>  drivers/net/ftgmac100.c | 39 +++++++++++++++++++++++++++++----------
>  1 file changed, 29 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
> index 92c38a81bd..c0100e91c7 100644
> --- a/drivers/net/ftgmac100.c
> +++ b/drivers/net/ftgmac100.c
> @@ -18,6 +18,7 @@
>  #include <wait_bit.h>
>  #include <linux/io.h>
>  #include <linux/iopoll.h>
> +#include <net/ncsi.h>
>  
>  #include "ftgmac100.h"
>  
> @@ -81,6 +82,7 @@ struct ftgmac100_data {
>  	struct mii_dev *bus;
>  	u32 phy_mode;
>  	u32 max_speed;
> +	bool ncsi_mode;
>  
>  	struct clk_bulk clks;
>  
> @@ -181,7 +183,7 @@ static int ftgmac100_phy_adjust_link(struct ftgmac100_data *priv)
>  	struct phy_device *phydev = priv->phydev;
>  	u32 maccr;
>  
> -	if (!phydev->link) {
> +	if (!phydev->link && !priv->ncsi_mode) {
>  		dev_err(phydev->dev, "No link\n");
>  		return -EREMOTEIO;
>  	}
> @@ -217,7 +219,8 @@ static int ftgmac100_phy_init(struct udevice *dev)
>  	if (!phydev)
>  		return -ENODEV;
>  
> -	phydev->supported &= PHY_GBIT_FEATURES;
> +	if (!priv->ncsi_mode)
> +		phydev->supported &= PHY_GBIT_FEATURES;
>  	if (priv->max_speed) {
>  		ret = phy_set_supported(phydev, priv->max_speed);
>  		if (ret)
> @@ -275,7 +278,8 @@ static void ftgmac100_stop(struct udevice *dev)
>  
>  	writel(0, &ftgmac100->maccr);
>  
> -	phy_shutdown(priv->phydev);
> +	if (!priv->ncsi_mode)
> +		phy_shutdown(priv->phydev);
>  }
>  
>  static int ftgmac100_start(struct udevice *dev)
> @@ -513,6 +517,7 @@ static int ftgmac100_ofdata_to_platdata(struct udevice *dev)
>  	pdata->iobase = devfdt_get_addr(dev);
>  	pdata->phy_interface = -1;
>  	phy_mode = dev_read_string(dev, "phy-mode");
> +
>  	if (phy_mode)
>  		pdata->phy_interface = phy_get_interface_by_name(phy_mode);
>  	if (pdata->phy_interface == -1) {
> @@ -537,8 +542,13 @@ static int ftgmac100_probe(struct udevice *dev)
>  {
>  	struct eth_pdata *pdata = dev_get_platdata(dev);
>  	struct ftgmac100_data *priv = dev_get_priv(dev);
> +	const char *phy_mode;
>  	int ret;
>  
> +	phy_mode = dev_read_string(dev, "phy-mode");
> +	priv->ncsi_mode = dev_read_bool(dev, "use-ncsi") ||
> +		(phy_mode && strcmp(phy_mode, "NC-SI") == 0);

strncmp() may be ? I think a helper routine would make sense. 

> +
>  	priv->iobase = (struct ftgmac100 *)pdata->iobase;
>  	priv->phy_mode = pdata->phy_interface;
>  	priv->max_speed = pdata->max_speed;
> @@ -548,10 +558,15 @@ static int ftgmac100_probe(struct udevice *dev)
>  	if (ret)
>  		goto out;
>  
> -	ret = ftgmac100_mdio_init(dev);
> -	if (ret) {
> -		dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
> -		goto out;
> +	if (priv->ncsi_mode) {
> +		printf("%s - NCSI detected\n", __func__);

"NC-SI"

> +	} else {
> +		ret = ftgmac100_mdio_init(dev);
> +		if (ret) {
> +			dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
> +			goto out;
> +		}
> +
>  	}
>  
>  	ret = ftgmac100_phy_init(dev);
> @@ -571,9 +586,13 @@ static int ftgmac100_remove(struct udevice *dev)
>  {
>  	struct ftgmac100_data *priv = dev_get_priv(dev);
>  
> -	free(priv->phydev);
> -	mdio_unregister(priv->bus);
> -	mdio_free(priv->bus);
> +	if (!priv->ncsi_mode) {
> +		free(priv->phydev);
> +		mdio_unregister(priv->bus);
> +		mdio_free(priv->bus);
> +	} else {
> +		free(priv->phydev);
> +	}
>  	clk_release_bulk(&priv->clks);
>  
>  	return 0;
> 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 3/4] net/ftgmac100: Add NC-SI mode support
@ 2019-06-18  8:31     ` Cédric Le Goater
  0 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2019-06-18  8:31 UTC (permalink / raw)
  To: u-boot

On 18/06/2019 03:37, Samuel Mendoza-Jonas wrote:
> Update the ftgmac100 driver to support NC-SI instead of an mdio phy
> where available. This is a common setup for Aspeed AST2x00 platforms.
> 
> NC-SI mode is determined from the device-tree if either phy-mode sets it
> or the use-ncsi property exists. If set then normal mdio setup is
> skipped in favour of the NC-SI phy.
> 
> Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>


LGTM. Some very minor remarks below in case you resend.

Reviewed-by: Cédric Le Goater <clg@kaod.org>

Thanks,

C.

> ---
>  drivers/net/ftgmac100.c | 39 +++++++++++++++++++++++++++++----------
>  1 file changed, 29 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
> index 92c38a81bd..c0100e91c7 100644
> --- a/drivers/net/ftgmac100.c
> +++ b/drivers/net/ftgmac100.c
> @@ -18,6 +18,7 @@
>  #include <wait_bit.h>
>  #include <linux/io.h>
>  #include <linux/iopoll.h>
> +#include <net/ncsi.h>
>  
>  #include "ftgmac100.h"
>  
> @@ -81,6 +82,7 @@ struct ftgmac100_data {
>  	struct mii_dev *bus;
>  	u32 phy_mode;
>  	u32 max_speed;
> +	bool ncsi_mode;
>  
>  	struct clk_bulk clks;
>  
> @@ -181,7 +183,7 @@ static int ftgmac100_phy_adjust_link(struct ftgmac100_data *priv)
>  	struct phy_device *phydev = priv->phydev;
>  	u32 maccr;
>  
> -	if (!phydev->link) {
> +	if (!phydev->link && !priv->ncsi_mode) {
>  		dev_err(phydev->dev, "No link\n");
>  		return -EREMOTEIO;
>  	}
> @@ -217,7 +219,8 @@ static int ftgmac100_phy_init(struct udevice *dev)
>  	if (!phydev)
>  		return -ENODEV;
>  
> -	phydev->supported &= PHY_GBIT_FEATURES;
> +	if (!priv->ncsi_mode)
> +		phydev->supported &= PHY_GBIT_FEATURES;
>  	if (priv->max_speed) {
>  		ret = phy_set_supported(phydev, priv->max_speed);
>  		if (ret)
> @@ -275,7 +278,8 @@ static void ftgmac100_stop(struct udevice *dev)
>  
>  	writel(0, &ftgmac100->maccr);
>  
> -	phy_shutdown(priv->phydev);
> +	if (!priv->ncsi_mode)
> +		phy_shutdown(priv->phydev);
>  }
>  
>  static int ftgmac100_start(struct udevice *dev)
> @@ -513,6 +517,7 @@ static int ftgmac100_ofdata_to_platdata(struct udevice *dev)
>  	pdata->iobase = devfdt_get_addr(dev);
>  	pdata->phy_interface = -1;
>  	phy_mode = dev_read_string(dev, "phy-mode");
> +
>  	if (phy_mode)
>  		pdata->phy_interface = phy_get_interface_by_name(phy_mode);
>  	if (pdata->phy_interface == -1) {
> @@ -537,8 +542,13 @@ static int ftgmac100_probe(struct udevice *dev)
>  {
>  	struct eth_pdata *pdata = dev_get_platdata(dev);
>  	struct ftgmac100_data *priv = dev_get_priv(dev);
> +	const char *phy_mode;
>  	int ret;
>  
> +	phy_mode = dev_read_string(dev, "phy-mode");
> +	priv->ncsi_mode = dev_read_bool(dev, "use-ncsi") ||
> +		(phy_mode && strcmp(phy_mode, "NC-SI") == 0);

strncmp() may be ? I think a helper routine would make sense. 

> +
>  	priv->iobase = (struct ftgmac100 *)pdata->iobase;
>  	priv->phy_mode = pdata->phy_interface;
>  	priv->max_speed = pdata->max_speed;
> @@ -548,10 +558,15 @@ static int ftgmac100_probe(struct udevice *dev)
>  	if (ret)
>  		goto out;
>  
> -	ret = ftgmac100_mdio_init(dev);
> -	if (ret) {
> -		dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
> -		goto out;
> +	if (priv->ncsi_mode) {
> +		printf("%s - NCSI detected\n", __func__);

"NC-SI"

> +	} else {
> +		ret = ftgmac100_mdio_init(dev);
> +		if (ret) {
> +			dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
> +			goto out;
> +		}
> +
>  	}
>  
>  	ret = ftgmac100_phy_init(dev);
> @@ -571,9 +586,13 @@ static int ftgmac100_remove(struct udevice *dev)
>  {
>  	struct ftgmac100_data *priv = dev_get_priv(dev);
>  
> -	free(priv->phydev);
> -	mdio_unregister(priv->bus);
> -	mdio_free(priv->bus);
> +	if (!priv->ncsi_mode) {
> +		free(priv->phydev);
> +		mdio_unregister(priv->bus);
> +		mdio_free(priv->bus);
> +	} else {
> +		free(priv->phydev);
> +	}
>  	clk_release_bulk(&priv->clks);
>  
>  	return 0;
> 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 0/4] NC-SI PHY Support
  2019-06-18  1:37 ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-18  8:35   ` Cédric Le Goater
  -1 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2019-06-18  8:35 UTC (permalink / raw)
  To: Samuel Mendoza-Jonas, u-boot; +Cc: joel, openbmc, joe.hershberger, sjg

On 18/06/2019 03:37, Samuel Mendoza-Jonas wrote:
> This series introduces support for the NC-SI protocol to u-boot,
> functionality which so far has only been available in vendor trees.

Would it be complex to add a romulus DT and config file ? 

Thanks,

C. 

> 
> NC-SI (Network Controller Sideband Interface) is a protocol to manage a
> sideband connection to a proper network interface, for example a BMC
> (Baseboard Management Controller) sharing the NIC of the host system.
> Probing and configuration occurs by communicating with the "remote" NIC
> via NC-SI control frames (Ethernet header 0x88f8).
> 
> Since the RFC[0] the changes have been split out into a few different
> patches to make the overall changes more obvious. Additionally a few
> small improvements have been added including adding a check to see if
> NC-SI is already configured, and marking the PHY bus "reset" as invalid
> since it does not define a bus.
> 
> An example of NC-SI setup before a normal network command:
> 
> => dhcp
> net_loop: configuring NCSI first
> ethernet@1e660000: link up, 100 Mbps full-duplex mac:0c:c4:7a:d5:48:43
> NCSI: probing channels
> NCSI: configuring channel 0
> NCSI: configuration done!
> BOOTP broadcast 1
> BOOTP broadcast 2
> DHCP client bound to address 10.61.161.188 (255 ms)
> 
> [0]: https://patchwork.ozlabs.org/patch/1107087/
> 
> Changes in v2:
> - Fix endianess issue when setting MAC address
> - Make checksum offsets easier to read
> - Instantiate per-phy ncsi_priv structures
> - Update ncsi command help text
> - Used update ncsi-pkt.h version to include SPDX header
> 
> 
> Samuel Mendoza-Jonas (4):
>   phy: Add support for the NC-SI protocol
>   phy: Include NC-SI in phy setup
>   net/ftgmac100: Add NC-SI mode support
>   net: NC-SI setup and handling
> 
>  cmd/Kconfig              |   8 +
>  cmd/net.c                |  18 +
>  drivers/net/ftgmac100.c  |  39 +-
>  drivers/net/phy/Kconfig  |   4 +
>  drivers/net/phy/Makefile |   1 +
>  drivers/net/phy/ncsi.c   | 896 +++++++++++++++++++++++++++++++++++++++
>  drivers/net/phy/phy.c    |   7 +
>  include/net.h            |   3 +-
>  include/net/ncsi-pkt.h   | 442 +++++++++++++++++++
>  include/net/ncsi.h       |  14 +
>  include/phy.h            |  12 +
>  include/phy_interface.h  |   2 +
>  net/net.c                |  27 +-
>  13 files changed, 1461 insertions(+), 12 deletions(-)
>  create mode 100644 drivers/net/phy/ncsi.c
>  create mode 100644 include/net/ncsi-pkt.h
>  create mode 100644 include/net/ncsi.h
> 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 0/4] NC-SI PHY Support
@ 2019-06-18  8:35   ` Cédric Le Goater
  0 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2019-06-18  8:35 UTC (permalink / raw)
  To: u-boot

On 18/06/2019 03:37, Samuel Mendoza-Jonas wrote:
> This series introduces support for the NC-SI protocol to u-boot,
> functionality which so far has only been available in vendor trees.

Would it be complex to add a romulus DT and config file ? 

Thanks,

C. 

> 
> NC-SI (Network Controller Sideband Interface) is a protocol to manage a
> sideband connection to a proper network interface, for example a BMC
> (Baseboard Management Controller) sharing the NIC of the host system.
> Probing and configuration occurs by communicating with the "remote" NIC
> via NC-SI control frames (Ethernet header 0x88f8).
> 
> Since the RFC[0] the changes have been split out into a few different
> patches to make the overall changes more obvious. Additionally a few
> small improvements have been added including adding a check to see if
> NC-SI is already configured, and marking the PHY bus "reset" as invalid
> since it does not define a bus.
> 
> An example of NC-SI setup before a normal network command:
> 
> => dhcp
> net_loop: configuring NCSI first
> ethernet at 1e660000: link up, 100 Mbps full-duplex mac:0c:c4:7a:d5:48:43
> NCSI: probing channels
> NCSI: configuring channel 0
> NCSI: configuration done!
> BOOTP broadcast 1
> BOOTP broadcast 2
> DHCP client bound to address 10.61.161.188 (255 ms)
> 
> [0]: https://patchwork.ozlabs.org/patch/1107087/
> 
> Changes in v2:
> - Fix endianess issue when setting MAC address
> - Make checksum offsets easier to read
> - Instantiate per-phy ncsi_priv structures
> - Update ncsi command help text
> - Used update ncsi-pkt.h version to include SPDX header
> 
> 
> Samuel Mendoza-Jonas (4):
>   phy: Add support for the NC-SI protocol
>   phy: Include NC-SI in phy setup
>   net/ftgmac100: Add NC-SI mode support
>   net: NC-SI setup and handling
> 
>  cmd/Kconfig              |   8 +
>  cmd/net.c                |  18 +
>  drivers/net/ftgmac100.c  |  39 +-
>  drivers/net/phy/Kconfig  |   4 +
>  drivers/net/phy/Makefile |   1 +
>  drivers/net/phy/ncsi.c   | 896 +++++++++++++++++++++++++++++++++++++++
>  drivers/net/phy/phy.c    |   7 +
>  include/net.h            |   3 +-
>  include/net/ncsi-pkt.h   | 442 +++++++++++++++++++
>  include/net/ncsi.h       |  14 +
>  include/phy.h            |  12 +
>  include/phy_interface.h  |   2 +
>  net/net.c                |  27 +-
>  13 files changed, 1461 insertions(+), 12 deletions(-)
>  create mode 100644 drivers/net/phy/ncsi.c
>  create mode 100644 include/net/ncsi-pkt.h
>  create mode 100644 include/net/ncsi.h
> 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 0/4] NC-SI PHY Support
  2019-06-18  8:35   ` [U-Boot] " Cédric Le Goater
@ 2019-06-19  2:27     ` Joel Stanley
  -1 siblings, 0 replies; 34+ messages in thread
From: Joel Stanley @ 2019-06-19  2:27 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: Samuel Mendoza-Jonas, U-Boot Mailing List, OpenBMC Maillist,
	joe.hershberger, Simon Glass

On Tue, 18 Jun 2019 at 08:35, Cédric Le Goater <clg@kaod.org> wrote:
>
> On 18/06/2019 03:37, Samuel Mendoza-Jonas wrote:
> > This series introduces support for the NC-SI protocol to u-boot,
> > functionality which so far has only been available in vendor trees.
>
> Would it be complex to add a romulus DT and config file ?

I think it's a great idea to follow up with that. I suggested Sam
focus on the network and ftgmac100 parts of NCSI first.

We will need to add support for the NCSI clocking in addition to the
device tree and config.

Cheers,

Joel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 0/4] NC-SI PHY Support
@ 2019-06-19  2:27     ` Joel Stanley
  0 siblings, 0 replies; 34+ messages in thread
From: Joel Stanley @ 2019-06-19  2:27 UTC (permalink / raw)
  To: u-boot

On Tue, 18 Jun 2019 at 08:35, Cédric Le Goater <clg@kaod.org> wrote:
>
> On 18/06/2019 03:37, Samuel Mendoza-Jonas wrote:
> > This series introduces support for the NC-SI protocol to u-boot,
> > functionality which so far has only been available in vendor trees.
>
> Would it be complex to add a romulus DT and config file ?

I think it's a great idea to follow up with that. I suggested Sam
focus on the network and ftgmac100 parts of NCSI first.

We will need to add support for the NCSI clocking in addition to the
device tree and config.

Cheers,

Joel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 1/4] phy: Add support for the NC-SI protocol
  2019-06-18  1:37   ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-19  2:32     ` Joel Stanley
  -1 siblings, 0 replies; 34+ messages in thread
From: Joel Stanley @ 2019-06-19  2:32 UTC (permalink / raw)
  To: Samuel Mendoza-Jonas
  Cc: U-Boot Mailing List, Cédric Le Goater, OpenBMC Maillist,
	joe.hershberger, Simon Glass

On Tue, 18 Jun 2019 at 01:37, Samuel Mendoza-Jonas <sam@mendozajonas.com> wrote:
>
> This introduces support for the NC-SI protocol, modelled as a phy driver
> for other ethernet drivers to consume.
>
> NC-SI (Network Controller Sideband Interface) is a protocol to manage a
> sideband connection to a proper network interface, for example a BMC
> (Baseboard Management Controller) sharing the NIC of the host system.
> Probing and configuration occurs by communicating with the "remote" NIC
> via NC-SI control frames (Ethernet header 0x88f8).
>
> This implementation is roughly based on the upstream Linux
> implementation[0], with a reduced feature set and an emphasis on getting
> a link up as fast as possible rather than probing the full possible
> topology of the bus.
> The current phy model relies on the network being "up", sending NC-SI
> command frames via net_send_packet() and receiving them from the
> net_loop() loop (added in a following patch).
>
> The ncsi-pkt.h header[1] is copied from the Linux kernel for consistent
> field definitions.
>
> [0]: https://github.com/torvalds/linux/tree/master/net/ncsi
> [1]: https://github.com/torvalds/linux/blob/master/net/ncsi/ncsi-pkt.h
>
> Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
> ---
> v2:
> - Fix endianess issue when setting MAC address
> - Make checksum offsets easier to read
> - Instantiate per-phy ncsi_priv structures
> - Used update ncsi-pkt.h version to include SPDX header

Thanks, the updates look good.

Reviewed-by: Joel Stanley <joel@jms.id.au>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 1/4] phy: Add support for the NC-SI protocol
@ 2019-06-19  2:32     ` Joel Stanley
  0 siblings, 0 replies; 34+ messages in thread
From: Joel Stanley @ 2019-06-19  2:32 UTC (permalink / raw)
  To: u-boot

On Tue, 18 Jun 2019 at 01:37, Samuel Mendoza-Jonas <sam@mendozajonas.com> wrote:
>
> This introduces support for the NC-SI protocol, modelled as a phy driver
> for other ethernet drivers to consume.
>
> NC-SI (Network Controller Sideband Interface) is a protocol to manage a
> sideband connection to a proper network interface, for example a BMC
> (Baseboard Management Controller) sharing the NIC of the host system.
> Probing and configuration occurs by communicating with the "remote" NIC
> via NC-SI control frames (Ethernet header 0x88f8).
>
> This implementation is roughly based on the upstream Linux
> implementation[0], with a reduced feature set and an emphasis on getting
> a link up as fast as possible rather than probing the full possible
> topology of the bus.
> The current phy model relies on the network being "up", sending NC-SI
> command frames via net_send_packet() and receiving them from the
> net_loop() loop (added in a following patch).
>
> The ncsi-pkt.h header[1] is copied from the Linux kernel for consistent
> field definitions.
>
> [0]: https://github.com/torvalds/linux/tree/master/net/ncsi
> [1]: https://github.com/torvalds/linux/blob/master/net/ncsi/ncsi-pkt.h
>
> Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
> ---
> v2:
> - Fix endianess issue when setting MAC address
> - Make checksum offsets easier to read
> - Instantiate per-phy ncsi_priv structures
> - Used update ncsi-pkt.h version to include SPDX header

Thanks, the updates look good.

Reviewed-by: Joel Stanley <joel@jms.id.au>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 2/4] phy: Include NC-SI in phy setup
  2019-06-18  1:37   ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-19  2:32     ` Joel Stanley
  -1 siblings, 0 replies; 34+ messages in thread
From: Joel Stanley @ 2019-06-19  2:32 UTC (permalink / raw)
  To: Samuel Mendoza-Jonas
  Cc: U-Boot Mailing List, Cédric Le Goater, OpenBMC Maillist,
	joe.hershberger, Simon Glass

On Tue, 18 Jun 2019 at 01:37, Samuel Mendoza-Jonas <sam@mendozajonas.com> wrote:
>
> Add NC-SI to the usual phy handling. This makes two notable changes:
> - Somewhat similar to a fixed phy, phy_connect() will create an NC-SI
> phy if CONFIG_PHY_NCSI is defined.
> - An early return is added to phy_read() and phy_write() to handle a
> case like the NC-SI phy which does not define a bus.
>
> Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>

Reviewed-by: Joel Stanley <joel@jms.id.au>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 2/4] phy: Include NC-SI in phy setup
@ 2019-06-19  2:32     ` Joel Stanley
  0 siblings, 0 replies; 34+ messages in thread
From: Joel Stanley @ 2019-06-19  2:32 UTC (permalink / raw)
  To: u-boot

On Tue, 18 Jun 2019 at 01:37, Samuel Mendoza-Jonas <sam@mendozajonas.com> wrote:
>
> Add NC-SI to the usual phy handling. This makes two notable changes:
> - Somewhat similar to a fixed phy, phy_connect() will create an NC-SI
> phy if CONFIG_PHY_NCSI is defined.
> - An early return is added to phy_read() and phy_write() to handle a
> case like the NC-SI phy which does not define a bus.
>
> Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>

Reviewed-by: Joel Stanley <joel@jms.id.au>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 4/4] net: NC-SI setup and handling
  2019-06-18  1:37   ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-19  2:35     ` Joel Stanley
  -1 siblings, 0 replies; 34+ messages in thread
From: Joel Stanley @ 2019-06-19  2:35 UTC (permalink / raw)
  To: Samuel Mendoza-Jonas
  Cc: U-Boot Mailing List, Cédric Le Goater, OpenBMC Maillist,
	joe.hershberger, Simon Glass

On Tue, 18 Jun 2019 at 01:38, Samuel Mendoza-Jonas <sam@mendozajonas.com> wrote:
>
> Add the handling of NC-SI ethernet frames, and add a check at the start
> of net_loop() to configure NC-SI before starting other network commands.
> This also adds an "ncsi" command to manually start NC-SI configuration.
>
> Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
> ---
> v2: Update ncsi command help text
>
>  cmd/Kconfig   |  8 ++++++++
>  cmd/net.c     | 18 ++++++++++++++++++
>  include/net.h |  2 +-
>  net/net.c     | 27 ++++++++++++++++++++++++++-
>  4 files changed, 53 insertions(+), 2 deletions(-)
>
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 0badcb3fe0..9851b04972 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -1332,6 +1332,14 @@ config CMD_LINK_LOCAL
>         help
>           Acquire a network IP address using the link-local protocol
>
> +config CMD_NCSI
> +       bool "ncsi"
> +       depends on PHY_NCSI
> +       help
> +         Manually configure the attached NIC via NC-SI.
> +         Normally this happens automatically before other network
> +         operations.

Do we need to make it even clearer that "this command not required to use NCSI"?

I'm thinking of future me wondering if we should put this in openbmc
builds or not. It would be good to have your advice on this.

Cheers,

Joel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 4/4] net: NC-SI setup and handling
@ 2019-06-19  2:35     ` Joel Stanley
  0 siblings, 0 replies; 34+ messages in thread
From: Joel Stanley @ 2019-06-19  2:35 UTC (permalink / raw)
  To: u-boot

On Tue, 18 Jun 2019 at 01:38, Samuel Mendoza-Jonas <sam@mendozajonas.com> wrote:
>
> Add the handling of NC-SI ethernet frames, and add a check at the start
> of net_loop() to configure NC-SI before starting other network commands.
> This also adds an "ncsi" command to manually start NC-SI configuration.
>
> Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
> ---
> v2: Update ncsi command help text
>
>  cmd/Kconfig   |  8 ++++++++
>  cmd/net.c     | 18 ++++++++++++++++++
>  include/net.h |  2 +-
>  net/net.c     | 27 ++++++++++++++++++++++++++-
>  4 files changed, 53 insertions(+), 2 deletions(-)
>
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 0badcb3fe0..9851b04972 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -1332,6 +1332,14 @@ config CMD_LINK_LOCAL
>         help
>           Acquire a network IP address using the link-local protocol
>
> +config CMD_NCSI
> +       bool "ncsi"
> +       depends on PHY_NCSI
> +       help
> +         Manually configure the attached NIC via NC-SI.
> +         Normally this happens automatically before other network
> +         operations.

Do we need to make it even clearer that "this command not required to use NCSI"?

I'm thinking of future me wondering if we should put this in openbmc
builds or not. It would be good to have your advice on this.

Cheers,

Joel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 4/4] net: NC-SI setup and handling
  2019-06-19  2:35     ` [U-Boot] " Joel Stanley
@ 2019-06-20  3:35       ` Samuel Mendoza-Jonas
  -1 siblings, 0 replies; 34+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-20  3:35 UTC (permalink / raw)
  To: Joel Stanley
  Cc: U-Boot Mailing List, Cédric Le Goater, OpenBMC Maillist,
	joe.hershberger, Simon Glass

On Wed, 2019-06-19 at 02:35 +0000, Joel Stanley wrote:
> On Tue, 18 Jun 2019 at 01:38, Samuel Mendoza-Jonas <sam@mendozajonas.com> wrote:
> > Add the handling of NC-SI ethernet frames, and add a check at the start
> > of net_loop() to configure NC-SI before starting other network commands.
> > This also adds an "ncsi" command to manually start NC-SI configuration.
> > 
> > Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
> > ---
> > v2: Update ncsi command help text
> > 
> >  cmd/Kconfig   |  8 ++++++++
> >  cmd/net.c     | 18 ++++++++++++++++++
> >  include/net.h |  2 +-
> >  net/net.c     | 27 ++++++++++++++++++++++++++-
> >  4 files changed, 53 insertions(+), 2 deletions(-)
> > 
> > diff --git a/cmd/Kconfig b/cmd/Kconfig
> > index 0badcb3fe0..9851b04972 100644
> > --- a/cmd/Kconfig
> > +++ b/cmd/Kconfig
> > @@ -1332,6 +1332,14 @@ config CMD_LINK_LOCAL
> >         help
> >           Acquire a network IP address using the link-local protocol
> > 
> > +config CMD_NCSI
> > +       bool "ncsi"
> > +       depends on PHY_NCSI
> > +       help
> > +         Manually configure the attached NIC via NC-SI.
> > +         Normally this happens automatically before other network
> > +         operations.
> 
> Do we need to make it even clearer that "this command not required to use NCSI"?
> 
> I'm thinking of future me wondering if we should put this in openbmc
> builds or not. It would be good to have your advice on this.
> 
> Cheers,
> 
> Joel

Either way; it's definitely not required but might be useful for sanity
checking things in BMC bringup.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 4/4] net: NC-SI setup and handling
@ 2019-06-20  3:35       ` Samuel Mendoza-Jonas
  0 siblings, 0 replies; 34+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-20  3:35 UTC (permalink / raw)
  To: u-boot

On Wed, 2019-06-19 at 02:35 +0000, Joel Stanley wrote:
> On Tue, 18 Jun 2019 at 01:38, Samuel Mendoza-Jonas <sam@mendozajonas.com> wrote:
> > Add the handling of NC-SI ethernet frames, and add a check at the start
> > of net_loop() to configure NC-SI before starting other network commands.
> > This also adds an "ncsi" command to manually start NC-SI configuration.
> > 
> > Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
> > ---
> > v2: Update ncsi command help text
> > 
> >  cmd/Kconfig   |  8 ++++++++
> >  cmd/net.c     | 18 ++++++++++++++++++
> >  include/net.h |  2 +-
> >  net/net.c     | 27 ++++++++++++++++++++++++++-
> >  4 files changed, 53 insertions(+), 2 deletions(-)
> > 
> > diff --git a/cmd/Kconfig b/cmd/Kconfig
> > index 0badcb3fe0..9851b04972 100644
> > --- a/cmd/Kconfig
> > +++ b/cmd/Kconfig
> > @@ -1332,6 +1332,14 @@ config CMD_LINK_LOCAL
> >         help
> >           Acquire a network IP address using the link-local protocol
> > 
> > +config CMD_NCSI
> > +       bool "ncsi"
> > +       depends on PHY_NCSI
> > +       help
> > +         Manually configure the attached NIC via NC-SI.
> > +         Normally this happens automatically before other network
> > +         operations.
> 
> Do we need to make it even clearer that "this command not required to use NCSI"?
> 
> I'm thinking of future me wondering if we should put this in openbmc
> builds or not. It would be good to have your advice on this.
> 
> Cheers,
> 
> Joel

Either way; it's definitely not required but might be useful for sanity
checking things in BMC bringup.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [U-Boot] [PATCH v2 1/4] phy: Add support for the NC-SI protocol
  2019-06-18  1:37   ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-07-09 23:22     ` Joe Hershberger
  -1 siblings, 0 replies; 34+ messages in thread
From: Joe Hershberger @ 2019-07-09 23:22 UTC (permalink / raw)
  To: Samuel Mendoza-Jonas; +Cc: u-boot, openbmc, Joseph Hershberger

On Mon, Jun 17, 2019 at 8:39 PM Samuel Mendoza-Jonas
<sam@mendozajonas.com> wrote:
>
> This introduces support for the NC-SI protocol, modelled as a phy driver
> for other ethernet drivers to consume.
>
> NC-SI (Network Controller Sideband Interface) is a protocol to manage a
> sideband connection to a proper network interface, for example a BMC
> (Baseboard Management Controller) sharing the NIC of the host system.
> Probing and configuration occurs by communicating with the "remote" NIC
> via NC-SI control frames (Ethernet header 0x88f8).
>
> This implementation is roughly based on the upstream Linux
> implementation[0], with a reduced feature set and an emphasis on getting
> a link up as fast as possible rather than probing the full possible
> topology of the bus.
> The current phy model relies on the network being "up", sending NC-SI
> command frames via net_send_packet() and receiving them from the
> net_loop() loop (added in a following patch).
>
> The ncsi-pkt.h header[1] is copied from the Linux kernel for consistent
> field definitions.
>
> [0]: https://github.com/torvalds/linux/tree/master/net/ncsi
> [1]: https://github.com/torvalds/linux/blob/master/net/ncsi/ncsi-pkt.h
>
> Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>

Acked-by: Joe Hershberger <joe.hershberger@ni.com>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 1/4] phy: Add support for the NC-SI protocol
@ 2019-07-09 23:22     ` Joe Hershberger
  0 siblings, 0 replies; 34+ messages in thread
From: Joe Hershberger @ 2019-07-09 23:22 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 17, 2019 at 8:39 PM Samuel Mendoza-Jonas
<sam@mendozajonas.com> wrote:
>
> This introduces support for the NC-SI protocol, modelled as a phy driver
> for other ethernet drivers to consume.
>
> NC-SI (Network Controller Sideband Interface) is a protocol to manage a
> sideband connection to a proper network interface, for example a BMC
> (Baseboard Management Controller) sharing the NIC of the host system.
> Probing and configuration occurs by communicating with the "remote" NIC
> via NC-SI control frames (Ethernet header 0x88f8).
>
> This implementation is roughly based on the upstream Linux
> implementation[0], with a reduced feature set and an emphasis on getting
> a link up as fast as possible rather than probing the full possible
> topology of the bus.
> The current phy model relies on the network being "up", sending NC-SI
> command frames via net_send_packet() and receiving them from the
> net_loop() loop (added in a following patch).
>
> The ncsi-pkt.h header[1] is copied from the Linux kernel for consistent
> field definitions.
>
> [0]: https://github.com/torvalds/linux/tree/master/net/ncsi
> [1]: https://github.com/torvalds/linux/blob/master/net/ncsi/ncsi-pkt.h
>
> Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>

Acked-by: Joe Hershberger <joe.hershberger@ni.com>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [U-Boot] [PATCH v2 2/4] phy: Include NC-SI in phy setup
  2019-06-18  1:37   ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-07-09 23:24     ` Joe Hershberger
  -1 siblings, 0 replies; 34+ messages in thread
From: Joe Hershberger @ 2019-07-09 23:24 UTC (permalink / raw)
  To: Samuel Mendoza-Jonas; +Cc: u-boot, openbmc, Joseph Hershberger

On Mon, Jun 17, 2019 at 8:42 PM Samuel Mendoza-Jonas
<sam@mendozajonas.com> wrote:
>
> Add NC-SI to the usual phy handling. This makes two notable changes:
> - Somewhat similar to a fixed phy, phy_connect() will create an NC-SI
> phy if CONFIG_PHY_NCSI is defined.
> - An early return is added to phy_read() and phy_write() to handle a
> case like the NC-SI phy which does not define a bus.
>
> Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>

Acked-by: Joe Hershberger <joe.hershberger@ni.com>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 2/4] phy: Include NC-SI in phy setup
@ 2019-07-09 23:24     ` Joe Hershberger
  0 siblings, 0 replies; 34+ messages in thread
From: Joe Hershberger @ 2019-07-09 23:24 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 17, 2019 at 8:42 PM Samuel Mendoza-Jonas
<sam@mendozajonas.com> wrote:
>
> Add NC-SI to the usual phy handling. This makes two notable changes:
> - Somewhat similar to a fixed phy, phy_connect() will create an NC-SI
> phy if CONFIG_PHY_NCSI is defined.
> - An early return is added to phy_read() and phy_write() to handle a
> case like the NC-SI phy which does not define a bus.
>
> Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>

Acked-by: Joe Hershberger <joe.hershberger@ni.com>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [U-Boot] [PATCH v2 3/4] net/ftgmac100: Add NC-SI mode support
  2019-06-18  1:37   ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-07-09 23:28     ` Joe Hershberger
  -1 siblings, 0 replies; 34+ messages in thread
From: Joe Hershberger @ 2019-07-09 23:28 UTC (permalink / raw)
  To: Samuel Mendoza-Jonas; +Cc: u-boot, openbmc, Joseph Hershberger

On Mon, Jun 17, 2019 at 8:43 PM Samuel Mendoza-Jonas
<sam@mendozajonas.com> wrote:
>
> Update the ftgmac100 driver to support NC-SI instead of an mdio phy
> where available. This is a common setup for Aspeed AST2x00 platforms.
>
> NC-SI mode is determined from the device-tree if either phy-mode sets it
> or the use-ncsi property exists. If set then normal mdio setup is
> skipped in favour of the NC-SI phy.
>
> Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
> ---
>  drivers/net/ftgmac100.c | 39 +++++++++++++++++++++++++++++----------
>  1 file changed, 29 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
> index 92c38a81bd..c0100e91c7 100644
> --- a/drivers/net/ftgmac100.c
> +++ b/drivers/net/ftgmac100.c
> @@ -18,6 +18,7 @@
>  #include <wait_bit.h>
>  #include <linux/io.h>
>  #include <linux/iopoll.h>
> +#include <net/ncsi.h>
>
>  #include "ftgmac100.h"
>
> @@ -81,6 +82,7 @@ struct ftgmac100_data {
>         struct mii_dev *bus;
>         u32 phy_mode;
>         u32 max_speed;
> +       bool ncsi_mode;
>
>         struct clk_bulk clks;
>
> @@ -181,7 +183,7 @@ static int ftgmac100_phy_adjust_link(struct ftgmac100_data *priv)
>         struct phy_device *phydev = priv->phydev;
>         u32 maccr;
>
> -       if (!phydev->link) {
> +       if (!phydev->link && !priv->ncsi_mode) {
>                 dev_err(phydev->dev, "No link\n");
>                 return -EREMOTEIO;
>         }
> @@ -217,7 +219,8 @@ static int ftgmac100_phy_init(struct udevice *dev)
>         if (!phydev)
>                 return -ENODEV;
>
> -       phydev->supported &= PHY_GBIT_FEATURES;
> +       if (!priv->ncsi_mode)
> +               phydev->supported &= PHY_GBIT_FEATURES;
>         if (priv->max_speed) {
>                 ret = phy_set_supported(phydev, priv->max_speed);
>                 if (ret)
> @@ -275,7 +278,8 @@ static void ftgmac100_stop(struct udevice *dev)
>
>         writel(0, &ftgmac100->maccr);
>
> -       phy_shutdown(priv->phydev);
> +       if (!priv->ncsi_mode)
> +               phy_shutdown(priv->phydev);
>  }
>
>  static int ftgmac100_start(struct udevice *dev)
> @@ -513,6 +517,7 @@ static int ftgmac100_ofdata_to_platdata(struct udevice *dev)
>         pdata->iobase = devfdt_get_addr(dev);
>         pdata->phy_interface = -1;
>         phy_mode = dev_read_string(dev, "phy-mode");
> +
>         if (phy_mode)
>                 pdata->phy_interface = phy_get_interface_by_name(phy_mode);
>         if (pdata->phy_interface == -1) {
> @@ -537,8 +542,13 @@ static int ftgmac100_probe(struct udevice *dev)
>  {
>         struct eth_pdata *pdata = dev_get_platdata(dev);
>         struct ftgmac100_data *priv = dev_get_priv(dev);
> +       const char *phy_mode;
>         int ret;
>
> +       phy_mode = dev_read_string(dev, "phy-mode");
> +       priv->ncsi_mode = dev_read_bool(dev, "use-ncsi") ||
> +               (phy_mode && strcmp(phy_mode, "NC-SI") == 0);
> +
>         priv->iobase = (struct ftgmac100 *)pdata->iobase;
>         priv->phy_mode = pdata->phy_interface;
>         priv->max_speed = pdata->max_speed;
> @@ -548,10 +558,15 @@ static int ftgmac100_probe(struct udevice *dev)
>         if (ret)
>                 goto out;
>
> -       ret = ftgmac100_mdio_init(dev);
> -       if (ret) {
> -               dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
> -               goto out;
> +       if (priv->ncsi_mode) {
> +               printf("%s - NCSI detected\n", __func__);

NC-SI

> +       } else {
> +               ret = ftgmac100_mdio_init(dev);
> +               if (ret) {
> +                       dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
> +                       goto out;
> +               }
> +
>         }
>
>         ret = ftgmac100_phy_init(dev);
> @@ -571,9 +586,13 @@ static int ftgmac100_remove(struct udevice *dev)
>  {
>         struct ftgmac100_data *priv = dev_get_priv(dev);
>
> -       free(priv->phydev);
> -       mdio_unregister(priv->bus);
> -       mdio_free(priv->bus);

This should be before the test like it was and eliminate the else...
free(priv->phydev);

> +       if (!priv->ncsi_mode) {
> +               free(priv->phydev);
> +               mdio_unregister(priv->bus);
> +               mdio_free(priv->bus);
> +       } else {
> +               free(priv->phydev);
> +       }
>         clk_release_bulk(&priv->clks);
>
>         return 0;
> --
> 2.21.0
>
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> https://lists.denx.de/listinfo/u-boot

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 3/4] net/ftgmac100: Add NC-SI mode support
@ 2019-07-09 23:28     ` Joe Hershberger
  0 siblings, 0 replies; 34+ messages in thread
From: Joe Hershberger @ 2019-07-09 23:28 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 17, 2019 at 8:43 PM Samuel Mendoza-Jonas
<sam@mendozajonas.com> wrote:
>
> Update the ftgmac100 driver to support NC-SI instead of an mdio phy
> where available. This is a common setup for Aspeed AST2x00 platforms.
>
> NC-SI mode is determined from the device-tree if either phy-mode sets it
> or the use-ncsi property exists. If set then normal mdio setup is
> skipped in favour of the NC-SI phy.
>
> Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
> ---
>  drivers/net/ftgmac100.c | 39 +++++++++++++++++++++++++++++----------
>  1 file changed, 29 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
> index 92c38a81bd..c0100e91c7 100644
> --- a/drivers/net/ftgmac100.c
> +++ b/drivers/net/ftgmac100.c
> @@ -18,6 +18,7 @@
>  #include <wait_bit.h>
>  #include <linux/io.h>
>  #include <linux/iopoll.h>
> +#include <net/ncsi.h>
>
>  #include "ftgmac100.h"
>
> @@ -81,6 +82,7 @@ struct ftgmac100_data {
>         struct mii_dev *bus;
>         u32 phy_mode;
>         u32 max_speed;
> +       bool ncsi_mode;
>
>         struct clk_bulk clks;
>
> @@ -181,7 +183,7 @@ static int ftgmac100_phy_adjust_link(struct ftgmac100_data *priv)
>         struct phy_device *phydev = priv->phydev;
>         u32 maccr;
>
> -       if (!phydev->link) {
> +       if (!phydev->link && !priv->ncsi_mode) {
>                 dev_err(phydev->dev, "No link\n");
>                 return -EREMOTEIO;
>         }
> @@ -217,7 +219,8 @@ static int ftgmac100_phy_init(struct udevice *dev)
>         if (!phydev)
>                 return -ENODEV;
>
> -       phydev->supported &= PHY_GBIT_FEATURES;
> +       if (!priv->ncsi_mode)
> +               phydev->supported &= PHY_GBIT_FEATURES;
>         if (priv->max_speed) {
>                 ret = phy_set_supported(phydev, priv->max_speed);
>                 if (ret)
> @@ -275,7 +278,8 @@ static void ftgmac100_stop(struct udevice *dev)
>
>         writel(0, &ftgmac100->maccr);
>
> -       phy_shutdown(priv->phydev);
> +       if (!priv->ncsi_mode)
> +               phy_shutdown(priv->phydev);
>  }
>
>  static int ftgmac100_start(struct udevice *dev)
> @@ -513,6 +517,7 @@ static int ftgmac100_ofdata_to_platdata(struct udevice *dev)
>         pdata->iobase = devfdt_get_addr(dev);
>         pdata->phy_interface = -1;
>         phy_mode = dev_read_string(dev, "phy-mode");
> +
>         if (phy_mode)
>                 pdata->phy_interface = phy_get_interface_by_name(phy_mode);
>         if (pdata->phy_interface == -1) {
> @@ -537,8 +542,13 @@ static int ftgmac100_probe(struct udevice *dev)
>  {
>         struct eth_pdata *pdata = dev_get_platdata(dev);
>         struct ftgmac100_data *priv = dev_get_priv(dev);
> +       const char *phy_mode;
>         int ret;
>
> +       phy_mode = dev_read_string(dev, "phy-mode");
> +       priv->ncsi_mode = dev_read_bool(dev, "use-ncsi") ||
> +               (phy_mode && strcmp(phy_mode, "NC-SI") == 0);
> +
>         priv->iobase = (struct ftgmac100 *)pdata->iobase;
>         priv->phy_mode = pdata->phy_interface;
>         priv->max_speed = pdata->max_speed;
> @@ -548,10 +558,15 @@ static int ftgmac100_probe(struct udevice *dev)
>         if (ret)
>                 goto out;
>
> -       ret = ftgmac100_mdio_init(dev);
> -       if (ret) {
> -               dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
> -               goto out;
> +       if (priv->ncsi_mode) {
> +               printf("%s - NCSI detected\n", __func__);

NC-SI

> +       } else {
> +               ret = ftgmac100_mdio_init(dev);
> +               if (ret) {
> +                       dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
> +                       goto out;
> +               }
> +
>         }
>
>         ret = ftgmac100_phy_init(dev);
> @@ -571,9 +586,13 @@ static int ftgmac100_remove(struct udevice *dev)
>  {
>         struct ftgmac100_data *priv = dev_get_priv(dev);
>
> -       free(priv->phydev);
> -       mdio_unregister(priv->bus);
> -       mdio_free(priv->bus);

This should be before the test like it was and eliminate the else...
free(priv->phydev);

> +       if (!priv->ncsi_mode) {
> +               free(priv->phydev);
> +               mdio_unregister(priv->bus);
> +               mdio_free(priv->bus);
> +       } else {
> +               free(priv->phydev);
> +       }
>         clk_release_bulk(&priv->clks);
>
>         return 0;
> --
> 2.21.0
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [U-Boot] [PATCH v2 4/4] net: NC-SI setup and handling
  2019-06-18  1:37   ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-07-09 23:33     ` Joe Hershberger
  -1 siblings, 0 replies; 34+ messages in thread
From: Joe Hershberger @ 2019-07-09 23:33 UTC (permalink / raw)
  To: Samuel Mendoza-Jonas; +Cc: u-boot, openbmc, Joseph Hershberger

On Mon, Jun 17, 2019 at 8:43 PM Samuel Mendoza-Jonas
<sam@mendozajonas.com> wrote:
>
> Add the handling of NC-SI ethernet frames, and add a check at the start
> of net_loop() to configure NC-SI before starting other network commands.
> This also adds an "ncsi" command to manually start NC-SI configuration.
>
> Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
> ---
> v2: Update ncsi command help text
>
>  cmd/Kconfig   |  8 ++++++++
>  cmd/net.c     | 18 ++++++++++++++++++
>  include/net.h |  2 +-
>  net/net.c     | 27 ++++++++++++++++++++++++++-
>  4 files changed, 53 insertions(+), 2 deletions(-)
>
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 0badcb3fe0..9851b04972 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -1332,6 +1332,14 @@ config CMD_LINK_LOCAL
>         help
>           Acquire a network IP address using the link-local protocol
>
> +config CMD_NCSI
> +       bool "ncsi"
> +       depends on PHY_NCSI
> +       help
> +         Manually configure the attached NIC via NC-SI.
> +         Normally this happens automatically before other network
> +         operations.
> +
>  endif
>
>  config CMD_ETHSW
> diff --git a/cmd/net.c b/cmd/net.c
> index 89721b8f8b..7d2c21ba4d 100644
> --- a/cmd/net.c
> +++ b/cmd/net.c
> @@ -457,3 +457,21 @@ U_BOOT_CMD(
>  );
>
>  #endif  /* CONFIG_CMD_LINK_LOCAL */
> +
> +#if defined(CONFIG_CMD_NCSI)
> +static int do_ncsi(cmd_tbl_t *cmdtp, int flag, int argc,
> +                  char * const argv[])
> +{
> +       if (net_loop(NCSI) < 0)
> +               return CMD_RET_FAILURE;
> +
> +       return CMD_RET_SUCCESS;
> +}
> +
> +U_BOOT_CMD(
> +       ncsi,   1,      1,      do_ncsi,
> +       "Configure attached NIC via NC-SI",
> +       ""
> +);
> +
> +#endif  /* CONFIG_CMD_NCSI */
> diff --git a/include/net.h b/include/net.h
> index 20c448ee60..9189f0fb53 100644
> --- a/include/net.h
> +++ b/include/net.h
> @@ -531,7 +531,7 @@ extern int          net_restart_wrap;       /* Tried all network devices */
>
>  enum proto_t {
>         BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP,
> -       TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL
> +       TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, NCSI
>  };
>
>  extern char    net_boot_file_name[1024];/* Boot File name */
> diff --git a/net/net.c b/net/net.c
> index 58b0417cbe..a59169a032 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -95,6 +95,7 @@
>  #include <net.h>
>  #include <net/fastboot.h>
>  #include <net/tftp.h>
> +#include <net/ncsi.h>
>  #if defined(CONFIG_LED_STATUS)
>  #include <miiphy.h>
>  #include <status_led.h>
> @@ -407,6 +408,16 @@ int net_loop(enum proto_t protocol)
>         net_try_count = 1;
>         debug_cond(DEBUG_INT_STATE, "--- net_loop Entry\n");
>
> +#ifdef CONFIG_PHY_NCSI
> +       if (protocol != NCSI && !ncsi_active()) {
> +               printf("%s: configuring NCSI first\n", __func__);

NC-SI

> +               if (net_loop(NCSI) < 0)
> +                       return ret;
> +               eth_init_state_only();
> +               goto restart;
> +       }
> +#endif
> +
>         bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
>         net_init();
>         if (eth_is_on_demand_init() || protocol != NETCONS) {
> @@ -420,6 +431,7 @@ int net_loop(enum proto_t protocol)
>         } else {
>                 eth_init_state_only();
>         }
> +
>  restart:
>  #ifdef CONFIG_USB_KEYBOARD
>         net_busy_flag = 0;
> @@ -526,6 +538,11 @@ restart:
>                 case WOL:
>                         wol_start();
>                         break;
> +#endif
> +#if defined(CONFIG_CMD_NCSI)
> +               case NCSI:
> +                       ncsi_probe_packages();
> +                       break;
>  #endif
>                 default:
>                         break;
> @@ -637,7 +654,7 @@ restart:
>                                 env_set_hex("filesize", net_boot_file_size);
>                                 env_set_hex("fileaddr", load_addr);
>                         }
> -                       if (protocol != NETCONS)
> +                       if (protocol != NETCONS && protocol != NCSI)

Why is this using eth_halt_state_only()? It is not using the
eth_init_state_only().

>                                 eth_halt();
>                         else
>                                 eth_halt_state_only();
> @@ -1318,6 +1335,11 @@ void net_process_received_packet(uchar *in_packet, int len)
>         case PROT_WOL:
>                 wol_receive(ip, len);
>                 break;
> +#endif
> +#ifdef CONFIG_PHY_NCSI
> +       case PROT_NCSI:
> +               ncsi_receive(et, ip, len);
> +               break;
>  #endif
>         }
>  }
> @@ -1379,6 +1401,9 @@ common:
>
>  #ifdef CONFIG_CMD_RARP
>         case RARP:
> +#endif
> +#ifdef CONFIG_CMD_NCSI
> +       case NCSI:
>  #endif
>         case BOOTP:
>         case CDP:
> --
> 2.21.0
>
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> https://lists.denx.de/listinfo/u-boot

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 4/4] net: NC-SI setup and handling
@ 2019-07-09 23:33     ` Joe Hershberger
  0 siblings, 0 replies; 34+ messages in thread
From: Joe Hershberger @ 2019-07-09 23:33 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 17, 2019 at 8:43 PM Samuel Mendoza-Jonas
<sam@mendozajonas.com> wrote:
>
> Add the handling of NC-SI ethernet frames, and add a check at the start
> of net_loop() to configure NC-SI before starting other network commands.
> This also adds an "ncsi" command to manually start NC-SI configuration.
>
> Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
> ---
> v2: Update ncsi command help text
>
>  cmd/Kconfig   |  8 ++++++++
>  cmd/net.c     | 18 ++++++++++++++++++
>  include/net.h |  2 +-
>  net/net.c     | 27 ++++++++++++++++++++++++++-
>  4 files changed, 53 insertions(+), 2 deletions(-)
>
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 0badcb3fe0..9851b04972 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -1332,6 +1332,14 @@ config CMD_LINK_LOCAL
>         help
>           Acquire a network IP address using the link-local protocol
>
> +config CMD_NCSI
> +       bool "ncsi"
> +       depends on PHY_NCSI
> +       help
> +         Manually configure the attached NIC via NC-SI.
> +         Normally this happens automatically before other network
> +         operations.
> +
>  endif
>
>  config CMD_ETHSW
> diff --git a/cmd/net.c b/cmd/net.c
> index 89721b8f8b..7d2c21ba4d 100644
> --- a/cmd/net.c
> +++ b/cmd/net.c
> @@ -457,3 +457,21 @@ U_BOOT_CMD(
>  );
>
>  #endif  /* CONFIG_CMD_LINK_LOCAL */
> +
> +#if defined(CONFIG_CMD_NCSI)
> +static int do_ncsi(cmd_tbl_t *cmdtp, int flag, int argc,
> +                  char * const argv[])
> +{
> +       if (net_loop(NCSI) < 0)
> +               return CMD_RET_FAILURE;
> +
> +       return CMD_RET_SUCCESS;
> +}
> +
> +U_BOOT_CMD(
> +       ncsi,   1,      1,      do_ncsi,
> +       "Configure attached NIC via NC-SI",
> +       ""
> +);
> +
> +#endif  /* CONFIG_CMD_NCSI */
> diff --git a/include/net.h b/include/net.h
> index 20c448ee60..9189f0fb53 100644
> --- a/include/net.h
> +++ b/include/net.h
> @@ -531,7 +531,7 @@ extern int          net_restart_wrap;       /* Tried all network devices */
>
>  enum proto_t {
>         BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP,
> -       TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL
> +       TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, NCSI
>  };
>
>  extern char    net_boot_file_name[1024];/* Boot File name */
> diff --git a/net/net.c b/net/net.c
> index 58b0417cbe..a59169a032 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -95,6 +95,7 @@
>  #include <net.h>
>  #include <net/fastboot.h>
>  #include <net/tftp.h>
> +#include <net/ncsi.h>
>  #if defined(CONFIG_LED_STATUS)
>  #include <miiphy.h>
>  #include <status_led.h>
> @@ -407,6 +408,16 @@ int net_loop(enum proto_t protocol)
>         net_try_count = 1;
>         debug_cond(DEBUG_INT_STATE, "--- net_loop Entry\n");
>
> +#ifdef CONFIG_PHY_NCSI
> +       if (protocol != NCSI && !ncsi_active()) {
> +               printf("%s: configuring NCSI first\n", __func__);

NC-SI

> +               if (net_loop(NCSI) < 0)
> +                       return ret;
> +               eth_init_state_only();
> +               goto restart;
> +       }
> +#endif
> +
>         bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
>         net_init();
>         if (eth_is_on_demand_init() || protocol != NETCONS) {
> @@ -420,6 +431,7 @@ int net_loop(enum proto_t protocol)
>         } else {
>                 eth_init_state_only();
>         }
> +
>  restart:
>  #ifdef CONFIG_USB_KEYBOARD
>         net_busy_flag = 0;
> @@ -526,6 +538,11 @@ restart:
>                 case WOL:
>                         wol_start();
>                         break;
> +#endif
> +#if defined(CONFIG_CMD_NCSI)
> +               case NCSI:
> +                       ncsi_probe_packages();
> +                       break;
>  #endif
>                 default:
>                         break;
> @@ -637,7 +654,7 @@ restart:
>                                 env_set_hex("filesize", net_boot_file_size);
>                                 env_set_hex("fileaddr", load_addr);
>                         }
> -                       if (protocol != NETCONS)
> +                       if (protocol != NETCONS && protocol != NCSI)

Why is this using eth_halt_state_only()? It is not using the
eth_init_state_only().

>                                 eth_halt();
>                         else
>                                 eth_halt_state_only();
> @@ -1318,6 +1335,11 @@ void net_process_received_packet(uchar *in_packet, int len)
>         case PROT_WOL:
>                 wol_receive(ip, len);
>                 break;
> +#endif
> +#ifdef CONFIG_PHY_NCSI
> +       case PROT_NCSI:
> +               ncsi_receive(et, ip, len);
> +               break;
>  #endif
>         }
>  }
> @@ -1379,6 +1401,9 @@ common:
>
>  #ifdef CONFIG_CMD_RARP
>         case RARP:
> +#endif
> +#ifdef CONFIG_CMD_NCSI
> +       case NCSI:
>  #endif
>         case BOOTP:
>         case CDP:
> --
> 2.21.0
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [U-Boot] [PATCH v2 4/4] net: NC-SI setup and handling
  2019-07-09 23:33     ` Joe Hershberger
@ 2019-09-09  2:34       ` Samuel Mendoza-Jonas
  -1 siblings, 0 replies; 34+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-09-09  2:34 UTC (permalink / raw)
  To: joe.hershberger; +Cc: u-boot, openbmc, Joseph Hershberger

On Tue, 2019-07-09 at 23:33 +0000, Joe Hershberger wrote:
> On Mon, Jun 17, 2019 at 8:43 PM Samuel Mendoza-Jonas
> <sam@mendozajonas.com> wrote:
> > Add the handling of NC-SI ethernet frames, and add a check at the
> > start
> > of net_loop() to configure NC-SI before starting other network
> > commands.
> > This also adds an "ncsi" command to manually start NC-SI
> > configuration.
> > 
> > Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
> > ---
> > v2: Update ncsi command help text
> > 
> >  cmd/Kconfig   |  8 ++++++++
> >  cmd/net.c     | 18 ++++++++++++++++++
> >  include/net.h |  2 +-
> >  net/net.c     | 27 ++++++++++++++++++++++++++-
> >  4 files changed, 53 insertions(+), 2 deletions(-)
> > 
> > diff --git a/cmd/Kconfig b/cmd/Kconfig
> > index 0badcb3fe0..9851b04972 100644
> > --- a/cmd/Kconfig
> > +++ b/cmd/Kconfig
> > @@ -1332,6 +1332,14 @@ config CMD_LINK_LOCAL
> >         help
> >           Acquire a network IP address using the link-local
> > protocol
> > 
> > +config CMD_NCSI
> > +       bool "ncsi"
> > +       depends on PHY_NCSI
> > +       help
> > +         Manually configure the attached NIC via NC-SI.
> > +         Normally this happens automatically before other network
> > +         operations.
> > +
> >  endif
> > 
> >  config CMD_ETHSW
> > diff --git a/cmd/net.c b/cmd/net.c
> > index 89721b8f8b..7d2c21ba4d 100644
> > --- a/cmd/net.c
> > +++ b/cmd/net.c
> > @@ -457,3 +457,21 @@ U_BOOT_CMD(
> >  );
> > 
> >  #endif  /* CONFIG_CMD_LINK_LOCAL */
> > +
> > +#if defined(CONFIG_CMD_NCSI)
> > +static int do_ncsi(cmd_tbl_t *cmdtp, int flag, int argc,
> > +                  char * const argv[])
> > +{
> > +       if (net_loop(NCSI) < 0)
> > +               return CMD_RET_FAILURE;
> > +
> > +       return CMD_RET_SUCCESS;
> > +}
> > +
> > +U_BOOT_CMD(
> > +       ncsi,   1,      1,      do_ncsi,
> > +       "Configure attached NIC via NC-SI",
> > +       ""
> > +);
> > +
> > +#endif  /* CONFIG_CMD_NCSI */
> > diff --git a/include/net.h b/include/net.h
> > index 20c448ee60..9189f0fb53 100644
> > --- a/include/net.h
> > +++ b/include/net.h
> > @@ -531,7 +531,7 @@ extern int          net_restart_wrap;       /*
> > Tried all network devices */
> > 
> >  enum proto_t {
> >         BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP,
> > NETCONS, SNTP,
> > -       TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL
> > +       TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, NCSI
> >  };
> > 
> >  extern char    net_boot_file_name[1024];/* Boot File name */
> > diff --git a/net/net.c b/net/net.c
> > index 58b0417cbe..a59169a032 100644
> > --- a/net/net.c
> > +++ b/net/net.c
> > @@ -95,6 +95,7 @@
> >  #include <net.h>
> >  #include <net/fastboot.h>
> >  #include <net/tftp.h>
> > +#include <net/ncsi.h>
> >  #if defined(CONFIG_LED_STATUS)
> >  #include <miiphy.h>
> >  #include <status_led.h>
> > @@ -407,6 +408,16 @@ int net_loop(enum proto_t protocol)
> >         net_try_count = 1;
> >         debug_cond(DEBUG_INT_STATE, "--- net_loop Entry\n");
> > 
> > +#ifdef CONFIG_PHY_NCSI
> > +       if (protocol != NCSI && !ncsi_active()) {
> > +               printf("%s: configuring NCSI first\n", __func__);
> 
> NC-SI
> 
> > +               if (net_loop(NCSI) < 0)
> > +                       return ret;
> > +               eth_init_state_only();
> > +               goto restart;
> > +       }
> > +#endif
> > +
> >         bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
> >         net_init();
> >         if (eth_is_on_demand_init() || protocol != NETCONS) {
> > @@ -420,6 +431,7 @@ int net_loop(enum proto_t protocol)
> >         } else {
> >                 eth_init_state_only();
> >         }
> > +
> >  restart:
> >  #ifdef CONFIG_USB_KEYBOARD
> >         net_busy_flag = 0;
> > @@ -526,6 +538,11 @@ restart:
> >                 case WOL:
> >                         wol_start();
> >                         break;
> > +#endif
> > +#if defined(CONFIG_CMD_NCSI)
> > +               case NCSI:
> > +                       ncsi_probe_packages();
> > +                       break;
> >  #endif
> >                 default:
> >                         break;
> > @@ -637,7 +654,7 @@ restart:
> >                                 env_set_hex("filesize",
> > net_boot_file_size);
> >                                 env_set_hex("fileaddr", load_addr);
> >                         }
> > -                       if (protocol != NETCONS)
> > +                       if (protocol != NETCONS && protocol !=
> > NCSI)
> 
> Why is this using eth_halt_state_only()? It is not using the
> eth_init_state_only().

The aim here was to avoid completely halting the network state because
we're about to start the net_loop again with whatever protocol caused
NC-SI to need to be configured. I'm new to this part of u-boot however
so it's possible I've misinterpeted the actions here; the NC-SI model
is an odd fit for the network loop.

> 
> >                                 eth_halt();
> >                         else
> >                                 eth_halt_state_only();
> > @@ -1318,6 +1335,11 @@ void net_process_received_packet(uchar
> > *in_packet, int len)
> >         case PROT_WOL:
> >                 wol_receive(ip, len);
> >                 break;
> > +#endif
> > +#ifdef CONFIG_PHY_NCSI
> > +       case PROT_NCSI:
> > +               ncsi_receive(et, ip, len);
> > +               break;
> >  #endif
> >         }
> >  }
> > @@ -1379,6 +1401,9 @@ common:
> > 
> >  #ifdef CONFIG_CMD_RARP
> >         case RARP:
> > +#endif
> > +#ifdef CONFIG_CMD_NCSI
> > +       case NCSI:
> >  #endif
> >         case BOOTP:
> >         case CDP:
> > --
> > 2.21.0
> > 
> > _______________________________________________
> > U-Boot mailing list
> > U-Boot@lists.denx.de
> > https://lists.denx.de/listinfo/u-boot

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [U-Boot] [PATCH v2 4/4] net: NC-SI setup and handling
@ 2019-09-09  2:34       ` Samuel Mendoza-Jonas
  0 siblings, 0 replies; 34+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-09-09  2:34 UTC (permalink / raw)
  To: u-boot

On Tue, 2019-07-09 at 23:33 +0000, Joe Hershberger wrote:
> On Mon, Jun 17, 2019 at 8:43 PM Samuel Mendoza-Jonas
> <sam@mendozajonas.com> wrote:
> > Add the handling of NC-SI ethernet frames, and add a check at the
> > start
> > of net_loop() to configure NC-SI before starting other network
> > commands.
> > This also adds an "ncsi" command to manually start NC-SI
> > configuration.
> > 
> > Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
> > ---
> > v2: Update ncsi command help text
> > 
> >  cmd/Kconfig   |  8 ++++++++
> >  cmd/net.c     | 18 ++++++++++++++++++
> >  include/net.h |  2 +-
> >  net/net.c     | 27 ++++++++++++++++++++++++++-
> >  4 files changed, 53 insertions(+), 2 deletions(-)
> > 
> > diff --git a/cmd/Kconfig b/cmd/Kconfig
> > index 0badcb3fe0..9851b04972 100644
> > --- a/cmd/Kconfig
> > +++ b/cmd/Kconfig
> > @@ -1332,6 +1332,14 @@ config CMD_LINK_LOCAL
> >         help
> >           Acquire a network IP address using the link-local
> > protocol
> > 
> > +config CMD_NCSI
> > +       bool "ncsi"
> > +       depends on PHY_NCSI
> > +       help
> > +         Manually configure the attached NIC via NC-SI.
> > +         Normally this happens automatically before other network
> > +         operations.
> > +
> >  endif
> > 
> >  config CMD_ETHSW
> > diff --git a/cmd/net.c b/cmd/net.c
> > index 89721b8f8b..7d2c21ba4d 100644
> > --- a/cmd/net.c
> > +++ b/cmd/net.c
> > @@ -457,3 +457,21 @@ U_BOOT_CMD(
> >  );
> > 
> >  #endif  /* CONFIG_CMD_LINK_LOCAL */
> > +
> > +#if defined(CONFIG_CMD_NCSI)
> > +static int do_ncsi(cmd_tbl_t *cmdtp, int flag, int argc,
> > +                  char * const argv[])
> > +{
> > +       if (net_loop(NCSI) < 0)
> > +               return CMD_RET_FAILURE;
> > +
> > +       return CMD_RET_SUCCESS;
> > +}
> > +
> > +U_BOOT_CMD(
> > +       ncsi,   1,      1,      do_ncsi,
> > +       "Configure attached NIC via NC-SI",
> > +       ""
> > +);
> > +
> > +#endif  /* CONFIG_CMD_NCSI */
> > diff --git a/include/net.h b/include/net.h
> > index 20c448ee60..9189f0fb53 100644
> > --- a/include/net.h
> > +++ b/include/net.h
> > @@ -531,7 +531,7 @@ extern int          net_restart_wrap;       /*
> > Tried all network devices */
> > 
> >  enum proto_t {
> >         BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP,
> > NETCONS, SNTP,
> > -       TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL
> > +       TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, NCSI
> >  };
> > 
> >  extern char    net_boot_file_name[1024];/* Boot File name */
> > diff --git a/net/net.c b/net/net.c
> > index 58b0417cbe..a59169a032 100644
> > --- a/net/net.c
> > +++ b/net/net.c
> > @@ -95,6 +95,7 @@
> >  #include <net.h>
> >  #include <net/fastboot.h>
> >  #include <net/tftp.h>
> > +#include <net/ncsi.h>
> >  #if defined(CONFIG_LED_STATUS)
> >  #include <miiphy.h>
> >  #include <status_led.h>
> > @@ -407,6 +408,16 @@ int net_loop(enum proto_t protocol)
> >         net_try_count = 1;
> >         debug_cond(DEBUG_INT_STATE, "--- net_loop Entry\n");
> > 
> > +#ifdef CONFIG_PHY_NCSI
> > +       if (protocol != NCSI && !ncsi_active()) {
> > +               printf("%s: configuring NCSI first\n", __func__);
> 
> NC-SI
> 
> > +               if (net_loop(NCSI) < 0)
> > +                       return ret;
> > +               eth_init_state_only();
> > +               goto restart;
> > +       }
> > +#endif
> > +
> >         bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
> >         net_init();
> >         if (eth_is_on_demand_init() || protocol != NETCONS) {
> > @@ -420,6 +431,7 @@ int net_loop(enum proto_t protocol)
> >         } else {
> >                 eth_init_state_only();
> >         }
> > +
> >  restart:
> >  #ifdef CONFIG_USB_KEYBOARD
> >         net_busy_flag = 0;
> > @@ -526,6 +538,11 @@ restart:
> >                 case WOL:
> >                         wol_start();
> >                         break;
> > +#endif
> > +#if defined(CONFIG_CMD_NCSI)
> > +               case NCSI:
> > +                       ncsi_probe_packages();
> > +                       break;
> >  #endif
> >                 default:
> >                         break;
> > @@ -637,7 +654,7 @@ restart:
> >                                 env_set_hex("filesize",
> > net_boot_file_size);
> >                                 env_set_hex("fileaddr", load_addr);
> >                         }
> > -                       if (protocol != NETCONS)
> > +                       if (protocol != NETCONS && protocol !=
> > NCSI)
> 
> Why is this using eth_halt_state_only()? It is not using the
> eth_init_state_only().

The aim here was to avoid completely halting the network state because
we're about to start the net_loop again with whatever protocol caused
NC-SI to need to be configured. I'm new to this part of u-boot however
so it's possible I've misinterpeted the actions here; the NC-SI model
is an odd fit for the network loop.

> 
> >                                 eth_halt();
> >                         else
> >                                 eth_halt_state_only();
> > @@ -1318,6 +1335,11 @@ void net_process_received_packet(uchar
> > *in_packet, int len)
> >         case PROT_WOL:
> >                 wol_receive(ip, len);
> >                 break;
> > +#endif
> > +#ifdef CONFIG_PHY_NCSI
> > +       case PROT_NCSI:
> > +               ncsi_receive(et, ip, len);
> > +               break;
> >  #endif
> >         }
> >  }
> > @@ -1379,6 +1401,9 @@ common:
> > 
> >  #ifdef CONFIG_CMD_RARP
> >         case RARP:
> > +#endif
> > +#ifdef CONFIG_CMD_NCSI
> > +       case NCSI:
> >  #endif
> >         case BOOTP:
> >         case CDP:
> > --
> > 2.21.0
> > 
> > _______________________________________________
> > U-Boot mailing list
> > U-Boot at lists.denx.de
> > https://lists.denx.de/listinfo/u-boot

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2019-09-09  2:40 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-18  1:37 [PATCH v2 0/4] NC-SI PHY Support Samuel Mendoza-Jonas
2019-06-18  1:37 ` [U-Boot] " Samuel Mendoza-Jonas
2019-06-18  1:37 ` [PATCH v2 1/4] phy: Add support for the NC-SI protocol Samuel Mendoza-Jonas
2019-06-18  1:37   ` [U-Boot] " Samuel Mendoza-Jonas
2019-06-19  2:32   ` Joel Stanley
2019-06-19  2:32     ` [U-Boot] " Joel Stanley
2019-07-09 23:22   ` Joe Hershberger
2019-07-09 23:22     ` Joe Hershberger
2019-06-18  1:37 ` [PATCH v2 2/4] phy: Include NC-SI in phy setup Samuel Mendoza-Jonas
2019-06-18  1:37   ` [U-Boot] " Samuel Mendoza-Jonas
2019-06-19  2:32   ` Joel Stanley
2019-06-19  2:32     ` [U-Boot] " Joel Stanley
2019-07-09 23:24   ` Joe Hershberger
2019-07-09 23:24     ` Joe Hershberger
2019-06-18  1:37 ` [PATCH v2 3/4] net/ftgmac100: Add NC-SI mode support Samuel Mendoza-Jonas
2019-06-18  1:37   ` [U-Boot] " Samuel Mendoza-Jonas
2019-06-18  8:31   ` Cédric Le Goater
2019-06-18  8:31     ` [U-Boot] " Cédric Le Goater
2019-07-09 23:28   ` Joe Hershberger
2019-07-09 23:28     ` Joe Hershberger
2019-06-18  1:37 ` [PATCH v2 4/4] net: NC-SI setup and handling Samuel Mendoza-Jonas
2019-06-18  1:37   ` [U-Boot] " Samuel Mendoza-Jonas
2019-06-19  2:35   ` Joel Stanley
2019-06-19  2:35     ` [U-Boot] " Joel Stanley
2019-06-20  3:35     ` Samuel Mendoza-Jonas
2019-06-20  3:35       ` [U-Boot] " Samuel Mendoza-Jonas
2019-07-09 23:33   ` Joe Hershberger
2019-07-09 23:33     ` Joe Hershberger
2019-09-09  2:34     ` Samuel Mendoza-Jonas
2019-09-09  2:34       ` Samuel Mendoza-Jonas
2019-06-18  8:35 ` [PATCH v2 0/4] NC-SI PHY Support Cédric Le Goater
2019-06-18  8:35   ` [U-Boot] " Cédric Le Goater
2019-06-19  2:27   ` Joel Stanley
2019-06-19  2:27     ` [U-Boot] " Joel Stanley

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.