* [PATCH 0/4] NC-SI PHY Support
@ 2019-06-06 4:49 ` Samuel Mendoza-Jonas
0 siblings, 0 replies; 24+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-06 4:49 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/
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 | 6 +
cmd/net.c | 18 +
drivers/net/ftgmac100.c | 39 +-
drivers/net/phy/Kconfig | 4 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/ncsi.c | 892 +++++++++++++++++++++++++++++++++++++++
drivers/net/phy/phy.c | 8 +
include/net.h | 3 +-
include/net/ncsi-pkt.h | 415 ++++++++++++++++++
include/net/ncsi.h | 14 +
include/phy.h | 12 +
include/phy_interface.h | 2 +
net/net.c | 27 +-
13 files changed, 1429 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] 24+ messages in thread
* [U-Boot] [PATCH 0/4] NC-SI PHY Support
@ 2019-06-06 4:49 ` Samuel Mendoza-Jonas
0 siblings, 0 replies; 24+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-06 4:49 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/
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 | 6 +
cmd/net.c | 18 +
drivers/net/ftgmac100.c | 39 +-
drivers/net/phy/Kconfig | 4 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/ncsi.c | 892 +++++++++++++++++++++++++++++++++++++++
drivers/net/phy/phy.c | 8 +
include/net.h | 3 +-
include/net/ncsi-pkt.h | 415 ++++++++++++++++++
include/net/ncsi.h | 14 +
include/phy.h | 12 +
include/phy_interface.h | 2 +
net/net.c | 27 +-
13 files changed, 1429 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] 24+ messages in thread
* [PATCH 1/4] phy: Add support for the NC-SI protocol
2019-06-06 4:49 ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-06 4:49 ` Samuel Mendoza-Jonas
-1 siblings, 0 replies; 24+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-06 4:49 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>
---
drivers/net/phy/Kconfig | 4 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/ncsi.c | 892 +++++++++++++++++++++++++++++++++++++++
include/net.h | 1 +
include/net/ncsi-pkt.h | 415 ++++++++++++++++++
include/net/ncsi.h | 14 +
include/phy.h | 1 +
7 files changed, 1328 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 3dc0822d9c..f6dde8af1c 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -227,4 +227,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..b1b717ed5c
--- /dev/null
+++ b/drivers/net/phy/ncsi.c
@@ -0,0 +1,892 @@
+// 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;
+ __be32 pchecksum;
+ u32 checksum;
+
+ 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;
+ }
+
+ 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 -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;
+
+ addr = eth_get_ethaddr();
+ if (!addr) {
+ printf("NCSI: no MAC address configured\n");
+ return;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ memcpy(cmd.mac, addr, 6);
+ 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)
+{
+ // TODO Associate per device
+ if (!ncsi_priv) {
+ ncsi_priv = malloc(sizeof(struct ncsi));
+ if (!ncsi_priv)
+ return -ENOMEM;
+ memset(ncsi_priv, 0, sizeof(struct ncsi));
+ }
+
+ phydev->priv = ncsi_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 ftgmac100 sets final bits up */
+ phydev->link = true;
+
+ 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 51c099dae2..4f7ba211b6 100644
--- a/include/net.h
+++ b/include/net.h
@@ -350,6 +350,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..91b4b66438
--- /dev/null
+++ b/include/net/ncsi-pkt.h
@@ -0,0 +1,415 @@
+/*
+ * Copyright Gavin Shan, IBM Corporation 2016.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __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];
+};
+
+/* 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 b86fdfb2ce..f0c9df46c6 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 related [flat|nested] 24+ messages in thread
* [U-Boot] [PATCH 1/4] phy: Add support for the NC-SI protocol
@ 2019-06-06 4:49 ` Samuel Mendoza-Jonas
0 siblings, 0 replies; 24+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-06 4:49 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>
---
drivers/net/phy/Kconfig | 4 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/ncsi.c | 892 +++++++++++++++++++++++++++++++++++++++
include/net.h | 1 +
include/net/ncsi-pkt.h | 415 ++++++++++++++++++
include/net/ncsi.h | 14 +
include/phy.h | 1 +
7 files changed, 1328 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 3dc0822d9c..f6dde8af1c 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -227,4 +227,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..b1b717ed5c
--- /dev/null
+++ b/drivers/net/phy/ncsi.c
@@ -0,0 +1,892 @@
+// 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;
+ __be32 pchecksum;
+ u32 checksum;
+
+ 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;
+ }
+
+ 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 -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;
+
+ addr = eth_get_ethaddr();
+ if (!addr) {
+ printf("NCSI: no MAC address configured\n");
+ return;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ memcpy(cmd.mac, addr, 6);
+ 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)
+{
+ // TODO Associate per device
+ if (!ncsi_priv) {
+ ncsi_priv = malloc(sizeof(struct ncsi));
+ if (!ncsi_priv)
+ return -ENOMEM;
+ memset(ncsi_priv, 0, sizeof(struct ncsi));
+ }
+
+ phydev->priv = ncsi_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 ftgmac100 sets final bits up */
+ phydev->link = true;
+
+ 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 51c099dae2..4f7ba211b6 100644
--- a/include/net.h
+++ b/include/net.h
@@ -350,6 +350,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..91b4b66438
--- /dev/null
+++ b/include/net/ncsi-pkt.h
@@ -0,0 +1,415 @@
+/*
+ * Copyright Gavin Shan, IBM Corporation 2016.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __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];
+};
+
+/* 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 b86fdfb2ce..f0c9df46c6 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 related [flat|nested] 24+ messages in thread
* [PATCH 2/4] phy: Include NC-SI in phy setup
2019-06-06 4:49 ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-06 4:49 ` Samuel Mendoza-Jonas
-1 siblings, 0 replies; 24+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-06 4:49 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 | 8 ++++++++
include/phy.h | 11 +++++++++++
include/phy_interface.h | 2 ++
3 files changed, 21 insertions(+)
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index cda4caa803..c2bc57c45d 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -527,6 +527,9 @@ int phy_init(void)
#endif
#ifdef CONFIG_PHY_FIXED
phy_fixed_init();
+#endif
+#ifdef CONFIG_PHY_NCSI
+ phy_ncsi_init();
#endif
return 0;
}
@@ -902,6 +905,11 @@ struct phy_device *phy_connect(struct mii_dev *bus, int addr,
sn = fdt_next_subnode(gd->fdt_blob, sn);
}
#endif
+
+#ifdef CONFIG_PHY_NCSI
+ phydev = phy_device_create(bus, 0, PHY_NCSI_ID, interface);
+#endif
+
if (!phydev)
phydev = phy_find_by_mask(bus, 1 << addr, interface);
diff --git a/include/phy.h b/include/phy.h
index f0c9df46c6..e1d546a81f 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -154,6 +154,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);
}
@@ -162,6 +167,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);
}
@@ -241,6 +251,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 related [flat|nested] 24+ messages in thread
* [U-Boot] [PATCH 2/4] phy: Include NC-SI in phy setup
@ 2019-06-06 4:49 ` Samuel Mendoza-Jonas
0 siblings, 0 replies; 24+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-06 4:49 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 | 8 ++++++++
include/phy.h | 11 +++++++++++
include/phy_interface.h | 2 ++
3 files changed, 21 insertions(+)
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index cda4caa803..c2bc57c45d 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -527,6 +527,9 @@ int phy_init(void)
#endif
#ifdef CONFIG_PHY_FIXED
phy_fixed_init();
+#endif
+#ifdef CONFIG_PHY_NCSI
+ phy_ncsi_init();
#endif
return 0;
}
@@ -902,6 +905,11 @@ struct phy_device *phy_connect(struct mii_dev *bus, int addr,
sn = fdt_next_subnode(gd->fdt_blob, sn);
}
#endif
+
+#ifdef CONFIG_PHY_NCSI
+ phydev = phy_device_create(bus, 0, PHY_NCSI_ID, interface);
+#endif
+
if (!phydev)
phydev = phy_find_by_mask(bus, 1 << addr, interface);
diff --git a/include/phy.h b/include/phy.h
index f0c9df46c6..e1d546a81f 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -154,6 +154,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);
}
@@ -162,6 +167,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);
}
@@ -241,6 +251,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 related [flat|nested] 24+ messages in thread
* [PATCH 3/4] net/ftgmac100: Add NC-SI mode support
2019-06-06 4:49 ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-06 4:49 ` Samuel Mendoza-Jonas
-1 siblings, 0 replies; 24+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-06 4:49 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 related [flat|nested] 24+ messages in thread
* [U-Boot] [PATCH 3/4] net/ftgmac100: Add NC-SI mode support
@ 2019-06-06 4:49 ` Samuel Mendoza-Jonas
0 siblings, 0 replies; 24+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-06 4:49 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 related [flat|nested] 24+ messages in thread
* [PATCH 4/4] net: NC-SI setup and handling
2019-06-06 4:49 ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-06 4:49 ` Samuel Mendoza-Jonas
-1 siblings, 0 replies; 24+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-06 4:49 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>
---
cmd/Kconfig | 6 ++++++
cmd/net.c | 18 ++++++++++++++++++
include/net.h | 2 +-
net/net.c | 27 ++++++++++++++++++++++++++-
4 files changed, 51 insertions(+), 2 deletions(-)
diff --git a/cmd/Kconfig b/cmd/Kconfig
index ea1a325eb3..0b5df0db90 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1296,6 +1296,12 @@ 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
+ Configure the attached NIC via NC-SI
+
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 4f7ba211b6..82a71c5219 100644
--- a/include/net.h
+++ b/include/net.h
@@ -538,7 +538,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 a5a216c3ee..16ca2b0e18 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>
@@ -411,6 +412,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) {
@@ -424,6 +435,7 @@ int net_loop(enum proto_t protocol)
} else {
eth_init_state_only();
}
+
restart:
#ifdef CONFIG_USB_KEYBOARD
net_busy_flag = 0;
@@ -530,6 +542,11 @@ restart:
case WOL:
wol_start();
break;
+#endif
+#if defined(CONFIG_CMD_NCSI)
+ case NCSI:
+ ncsi_probe_packages();
+ break;
#endif
default:
break;
@@ -641,7 +658,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();
@@ -1324,6 +1341,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
}
}
@@ -1385,6 +1407,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 related [flat|nested] 24+ messages in thread
* [U-Boot] [PATCH 4/4] net: NC-SI setup and handling
@ 2019-06-06 4:49 ` Samuel Mendoza-Jonas
0 siblings, 0 replies; 24+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-06 4:49 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>
---
cmd/Kconfig | 6 ++++++
cmd/net.c | 18 ++++++++++++++++++
include/net.h | 2 +-
net/net.c | 27 ++++++++++++++++++++++++++-
4 files changed, 51 insertions(+), 2 deletions(-)
diff --git a/cmd/Kconfig b/cmd/Kconfig
index ea1a325eb3..0b5df0db90 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1296,6 +1296,12 @@ 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
+ Configure the attached NIC via NC-SI
+
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 4f7ba211b6..82a71c5219 100644
--- a/include/net.h
+++ b/include/net.h
@@ -538,7 +538,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 a5a216c3ee..16ca2b0e18 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>
@@ -411,6 +412,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) {
@@ -424,6 +435,7 @@ int net_loop(enum proto_t protocol)
} else {
eth_init_state_only();
}
+
restart:
#ifdef CONFIG_USB_KEYBOARD
net_busy_flag = 0;
@@ -530,6 +542,11 @@ restart:
case WOL:
wol_start();
break;
+#endif
+#if defined(CONFIG_CMD_NCSI)
+ case NCSI:
+ ncsi_probe_packages();
+ break;
#endif
default:
break;
@@ -641,7 +658,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();
@@ -1324,6 +1341,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
}
}
@@ -1385,6 +1407,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 related [flat|nested] 24+ messages in thread
* Re: [PATCH 4/4] net: NC-SI setup and handling
2019-06-06 4:49 ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-12 2:05 ` Joel Stanley
-1 siblings, 0 replies; 24+ messages in thread
From: Joel Stanley @ 2019-06-12 2:05 UTC (permalink / raw)
To: Samuel Mendoza-Jonas
Cc: U-Boot Mailing List, Cédric Le Goater, OpenBMC Maillist,
joe.hershberger, Simon Glass
On Thu, 6 Jun 2019 at 04:50, 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>
We need the u-boot net specialists to weigh in, but this looks okay to
me. Please clarify the help text for the NCSI command, then add:
Reviewed-by: Joel Stanley <joel@jms.id.au>
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -1296,6 +1296,12 @@ 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
> + Configure the attached NIC via NC-SI
Can we clarify in the text if we need the 'ncsi' command to use any
NC-SI attached NIC, or if it's more for ncsi and network debugging?
^ permalink raw reply [flat|nested] 24+ messages in thread
* [U-Boot] [PATCH 4/4] net: NC-SI setup and handling
@ 2019-06-12 2:05 ` Joel Stanley
0 siblings, 0 replies; 24+ messages in thread
From: Joel Stanley @ 2019-06-12 2:05 UTC (permalink / raw)
To: u-boot
On Thu, 6 Jun 2019 at 04:50, 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>
We need the u-boot net specialists to weigh in, but this looks okay to
me. Please clarify the help text for the NCSI command, then add:
Reviewed-by: Joel Stanley <joel@jms.id.au>
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -1296,6 +1296,12 @@ 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
> + Configure the attached NIC via NC-SI
Can we clarify in the text if we need the 'ncsi' command to use any
NC-SI attached NIC, or if it's more for ncsi and network debugging?
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 1/4] phy: Add support for the NC-SI protocol
2019-06-06 4:49 ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-12 2:40 ` Joel Stanley
-1 siblings, 0 replies; 24+ messages in thread
From: Joel Stanley @ 2019-06-12 2:40 UTC (permalink / raw)
To: Samuel Mendoza-Jonas
Cc: U-Boot Mailing List, Cédric Le Goater, OpenBMC Maillist,
joe.hershberger, Simon Glass
On Thu, 6 Jun 2019 at 04:50, 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>
Looks good. Some comments below.
> +static int ncsi_validate_rsp(struct ncsi_rsp_pkt *pkt, int payload)
> +{
> + struct ncsi_rsp_pkt_hdr *hdr = &pkt->rsp;
> + __be32 pchecksum;
> + u32 checksum;
> + if (ntohs(hdr->common.length) != payload) {
> + printf("NCSI: 0x%02x response has incorrect length %d\n",
> + hdr->common.type, hdr->common.length);
> + return -1;
> + }
> +
> + pchecksum = get_unaligned_be32((void *)(hdr + 1) + payload - 4);
Wheee. So the checksum is the last 4-bytes of the payload. I assume
it's always longer than 4?
A clarifying comment might help, or try to write it in a different way:
endp = (void *)hdr + sizeof(hdr) + payload;
pchecksum = get_unaligned_be32(endp - sizeof(checksum));
or
checksum_offset = sizeof(hdr) + payload - sizeof(checksum);
pchecksum = get_unaligned_be32(payload + checksum_offset);
> + if (pchecksum != 0) {
> + checksum = ncsi_calculate_checksum((unsigned char *)hdr,
> + sizeof(*hdr) + payload - 4);
And then this can be:
checksum = ((unsigned char *)hdr, checksum_offset);
> + if (pchecksum != checksum) {
> + printf("NCSI: 0x%02x response has invalid checksum\n",
> + hdr->common.type);
> + return -1;
> + }
> + }
> +static void ncsi_send_sma(unsigned int np, unsigned int nc)
> +{
> + struct ncsi_cmd_sma_pkt cmd;
> + unsigned char *addr;
> +
> + addr = eth_get_ethaddr();
> + if (!addr) {
> + printf("NCSI: no MAC address configured\n");
> + return;
> + }
> +
> + memset(&cmd, 0, sizeof(cmd));
> + memcpy(cmd.mac, addr, 6);
Are there endianness issues with addr here?
> + 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);
> +}
> +
> +int ncsi_probe(struct phy_device *phydev)
> +{
> + // TODO Associate per device
Is this required before we can support multiple NICs?
> + if (!ncsi_priv) {
> + ncsi_priv = malloc(sizeof(struct ncsi));
> + if (!ncsi_priv)
> + return -ENOMEM;
> + memset(ncsi_priv, 0, sizeof(struct ncsi));
> + }
> +
> + phydev->priv = ncsi_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 ftgmac100 sets final bits up */
s/ftgmac100/mac driver/ ?
> + phydev->link = true;
> +
> + 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;
> +}
> --- /dev/null
> +++ b/include/net/ncsi-pkt.h
> @@ -0,0 +1,415 @@
> +/*
> + * Copyright Gavin Shan, IBM Corporation 2016.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
If you grab the version from 5.2-rc3 it has been SPDXified.
> --- 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
hmmm...
>
> #define PHY_MAX_ADDR 32
>
> --
> 2.21.0
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* [U-Boot] [PATCH 1/4] phy: Add support for the NC-SI protocol
@ 2019-06-12 2:40 ` Joel Stanley
0 siblings, 0 replies; 24+ messages in thread
From: Joel Stanley @ 2019-06-12 2:40 UTC (permalink / raw)
To: u-boot
On Thu, 6 Jun 2019 at 04:50, 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>
Looks good. Some comments below.
> +static int ncsi_validate_rsp(struct ncsi_rsp_pkt *pkt, int payload)
> +{
> + struct ncsi_rsp_pkt_hdr *hdr = &pkt->rsp;
> + __be32 pchecksum;
> + u32 checksum;
> + if (ntohs(hdr->common.length) != payload) {
> + printf("NCSI: 0x%02x response has incorrect length %d\n",
> + hdr->common.type, hdr->common.length);
> + return -1;
> + }
> +
> + pchecksum = get_unaligned_be32((void *)(hdr + 1) + payload - 4);
Wheee. So the checksum is the last 4-bytes of the payload. I assume
it's always longer than 4?
A clarifying comment might help, or try to write it in a different way:
endp = (void *)hdr + sizeof(hdr) + payload;
pchecksum = get_unaligned_be32(endp - sizeof(checksum));
or
checksum_offset = sizeof(hdr) + payload - sizeof(checksum);
pchecksum = get_unaligned_be32(payload + checksum_offset);
> + if (pchecksum != 0) {
> + checksum = ncsi_calculate_checksum((unsigned char *)hdr,
> + sizeof(*hdr) + payload - 4);
And then this can be:
checksum = ((unsigned char *)hdr, checksum_offset);
> + if (pchecksum != checksum) {
> + printf("NCSI: 0x%02x response has invalid checksum\n",
> + hdr->common.type);
> + return -1;
> + }
> + }
> +static void ncsi_send_sma(unsigned int np, unsigned int nc)
> +{
> + struct ncsi_cmd_sma_pkt cmd;
> + unsigned char *addr;
> +
> + addr = eth_get_ethaddr();
> + if (!addr) {
> + printf("NCSI: no MAC address configured\n");
> + return;
> + }
> +
> + memset(&cmd, 0, sizeof(cmd));
> + memcpy(cmd.mac, addr, 6);
Are there endianness issues with addr here?
> + 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);
> +}
> +
> +int ncsi_probe(struct phy_device *phydev)
> +{
> + // TODO Associate per device
Is this required before we can support multiple NICs?
> + if (!ncsi_priv) {
> + ncsi_priv = malloc(sizeof(struct ncsi));
> + if (!ncsi_priv)
> + return -ENOMEM;
> + memset(ncsi_priv, 0, sizeof(struct ncsi));
> + }
> +
> + phydev->priv = ncsi_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 ftgmac100 sets final bits up */
s/ftgmac100/mac driver/ ?
> + phydev->link = true;
> +
> + 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;
> +}
> --- /dev/null
> +++ b/include/net/ncsi-pkt.h
> @@ -0,0 +1,415 @@
> +/*
> + * Copyright Gavin Shan, IBM Corporation 2016.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
If you grab the version from 5.2-rc3 it has been SPDXified.
> --- 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
hmmm...
>
> #define PHY_MAX_ADDR 32
>
> --
> 2.21.0
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 2/4] phy: Include NC-SI in phy setup
2019-06-06 4:49 ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-12 2:42 ` Joel Stanley
-1 siblings, 0 replies; 24+ messages in thread
From: Joel Stanley @ 2019-06-12 2:42 UTC (permalink / raw)
To: Samuel Mendoza-Jonas
Cc: U-Boot Mailing List, Cédric Le Goater, OpenBMC Maillist,
joe.hershberger, Simon Glass
On Thu, 6 Jun 2019 at 04:50, 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] 24+ messages in thread
* [U-Boot] [PATCH 2/4] phy: Include NC-SI in phy setup
@ 2019-06-12 2:42 ` Joel Stanley
0 siblings, 0 replies; 24+ messages in thread
From: Joel Stanley @ 2019-06-12 2:42 UTC (permalink / raw)
To: u-boot
On Thu, 6 Jun 2019 at 04:50, 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] 24+ messages in thread
* Re: [PATCH 3/4] net/ftgmac100: Add NC-SI mode support
2019-06-06 4:49 ` [U-Boot] " Samuel Mendoza-Jonas
@ 2019-06-12 3:04 ` Joel Stanley
-1 siblings, 0 replies; 24+ messages in thread
From: Joel Stanley @ 2019-06-12 3:04 UTC (permalink / raw)
To: Samuel Mendoza-Jonas
Cc: U-Boot Mailing List, Cédric Le Goater, OpenBMC Maillist,
joe.hershberger, Simon Glass
On Thu, 6 Jun 2019 at 04:50, 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 +++++++++++++++++++++++++++++----------
> @@ -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;
Instead of hiding this behind ncsi_mode I was assuming the ncsi "phy"
driver would answer these questions through the phy_read callbacks.
If you don't think that is going to work then this solution isn't too
invasive, and we've been using this in Linux for a while, so we know
it works.
^ permalink raw reply [flat|nested] 24+ messages in thread
* [U-Boot] [PATCH 3/4] net/ftgmac100: Add NC-SI mode support
@ 2019-06-12 3:04 ` Joel Stanley
0 siblings, 0 replies; 24+ messages in thread
From: Joel Stanley @ 2019-06-12 3:04 UTC (permalink / raw)
To: u-boot
On Thu, 6 Jun 2019 at 04:50, 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 +++++++++++++++++++++++++++++----------
> @@ -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;
Instead of hiding this behind ncsi_mode I was assuming the ncsi "phy"
driver would answer these questions through the phy_read callbacks.
If you don't think that is going to work then this solution isn't too
invasive, and we've been using this in Linux for a while, so we know
it works.
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 1/4] phy: Add support for the NC-SI protocol
2019-06-12 2:40 ` [U-Boot] " Joel Stanley
@ 2019-06-12 5:42 ` Samuel Mendoza-Jonas
-1 siblings, 0 replies; 24+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-12 5:42 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-12 at 02:40 +0000, Joel Stanley wrote:
> On Thu, 6 Jun 2019 at 04:50, 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>
>
> Looks good. Some comments below.
>
> > +static int ncsi_validate_rsp(struct ncsi_rsp_pkt *pkt, int payload)
> > +{
> > + struct ncsi_rsp_pkt_hdr *hdr = &pkt->rsp;
> > + __be32 pchecksum;
> > + u32 checksum;
> > + if (ntohs(hdr->common.length) != payload) {
> > + printf("NCSI: 0x%02x response has incorrect length %d\n",
> > + hdr->common.type, hdr->common.length);
> > + return -1;
> > + }
> > +
> > + pchecksum = get_unaligned_be32((void *)(hdr + 1) + payload - 4);
>
> Wheee. So the checksum is the last 4-bytes of the payload. I assume
> it's always longer than 4?
>
> A clarifying comment might help, or try to write it in a different way:
"Wheee" indeed. I kept this roughly as it is in the kernel so I could
more easily verify it was doing the right thing; now that it's more
tested I'll do something like below so it's less traumatic.
>
> endp = (void *)hdr + sizeof(hdr) + payload;
> pchecksum = get_unaligned_be32(endp - sizeof(checksum));
>
> or
>
> checksum_offset = sizeof(hdr) + payload - sizeof(checksum);
> pchecksum = get_unaligned_be32(payload + checksum_offset);
>
> > + if (pchecksum != 0) {
> > + checksum = ncsi_calculate_checksum((unsigned char *)hdr,
> > + sizeof(*hdr) + payload - 4);
>
> And then this can be:
>
> checksum = ((unsigned char *)hdr, checksum_offset);
>
> > + if (pchecksum != checksum) {
> > + printf("NCSI: 0x%02x response has invalid checksum\n",
> > + hdr->common.type);
> > + return -1;
> > + }
> > + }
> > +static void ncsi_send_sma(unsigned int np, unsigned int nc)
> > +{
> > + struct ncsi_cmd_sma_pkt cmd;
> > + unsigned char *addr;
> > +
> > + addr = eth_get_ethaddr();
> > + if (!addr) {
> > + printf("NCSI: no MAC address configured\n");
> > + return;
> > + }
> > +
> > + memset(&cmd, 0, sizeof(cmd));
> > + memcpy(cmd.mac, addr, 6);
>
> Are there endianness issues with addr here?
Aha, will fixup.
>
> > + 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);
> > +}
> > +
> > +int ncsi_probe(struct phy_device *phydev)
> > +{
> > + // TODO Associate per device
>
> Is this required before we can support multiple NICs?
Yes, I'll chase this up.
>
> > + if (!ncsi_priv) {
> > + ncsi_priv = malloc(sizeof(struct ncsi));
> > + if (!ncsi_priv)
> > + return -ENOMEM;
> > + memset(ncsi_priv, 0, sizeof(struct ncsi));
> > + }
> > +
> > + phydev->priv = ncsi_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 ftgmac100 sets final bits up */
>
> s/ftgmac100/mac driver/ ?
Ack
>
> > + phydev->link = true;
> > +
> > + 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;
> > +}
> > --- /dev/null
> > +++ b/include/net/ncsi-pkt.h
> > @@ -0,0 +1,415 @@
> > +/*
> > + * Copyright Gavin Shan, IBM Corporation 2016.
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + */
>
> If you grab the version from 5.2-rc3 it has been SPDXified.
Cheers, will do.
>
> > --- 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
>
> hmmm...
Haha - suggestions welcome?
>
> > #define PHY_MAX_ADDR 32
> >
> > --
> > 2.21.0
> >
^ permalink raw reply [flat|nested] 24+ messages in thread
* [U-Boot] [PATCH 1/4] phy: Add support for the NC-SI protocol
@ 2019-06-12 5:42 ` Samuel Mendoza-Jonas
0 siblings, 0 replies; 24+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-12 5:42 UTC (permalink / raw)
To: u-boot
On Wed, 2019-06-12 at 02:40 +0000, Joel Stanley wrote:
> On Thu, 6 Jun 2019 at 04:50, 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>
>
> Looks good. Some comments below.
>
> > +static int ncsi_validate_rsp(struct ncsi_rsp_pkt *pkt, int payload)
> > +{
> > + struct ncsi_rsp_pkt_hdr *hdr = &pkt->rsp;
> > + __be32 pchecksum;
> > + u32 checksum;
> > + if (ntohs(hdr->common.length) != payload) {
> > + printf("NCSI: 0x%02x response has incorrect length %d\n",
> > + hdr->common.type, hdr->common.length);
> > + return -1;
> > + }
> > +
> > + pchecksum = get_unaligned_be32((void *)(hdr + 1) + payload - 4);
>
> Wheee. So the checksum is the last 4-bytes of the payload. I assume
> it's always longer than 4?
>
> A clarifying comment might help, or try to write it in a different way:
"Wheee" indeed. I kept this roughly as it is in the kernel so I could
more easily verify it was doing the right thing; now that it's more
tested I'll do something like below so it's less traumatic.
>
> endp = (void *)hdr + sizeof(hdr) + payload;
> pchecksum = get_unaligned_be32(endp - sizeof(checksum));
>
> or
>
> checksum_offset = sizeof(hdr) + payload - sizeof(checksum);
> pchecksum = get_unaligned_be32(payload + checksum_offset);
>
> > + if (pchecksum != 0) {
> > + checksum = ncsi_calculate_checksum((unsigned char *)hdr,
> > + sizeof(*hdr) + payload - 4);
>
> And then this can be:
>
> checksum = ((unsigned char *)hdr, checksum_offset);
>
> > + if (pchecksum != checksum) {
> > + printf("NCSI: 0x%02x response has invalid checksum\n",
> > + hdr->common.type);
> > + return -1;
> > + }
> > + }
> > +static void ncsi_send_sma(unsigned int np, unsigned int nc)
> > +{
> > + struct ncsi_cmd_sma_pkt cmd;
> > + unsigned char *addr;
> > +
> > + addr = eth_get_ethaddr();
> > + if (!addr) {
> > + printf("NCSI: no MAC address configured\n");
> > + return;
> > + }
> > +
> > + memset(&cmd, 0, sizeof(cmd));
> > + memcpy(cmd.mac, addr, 6);
>
> Are there endianness issues with addr here?
Aha, will fixup.
>
> > + 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);
> > +}
> > +
> > +int ncsi_probe(struct phy_device *phydev)
> > +{
> > + // TODO Associate per device
>
> Is this required before we can support multiple NICs?
Yes, I'll chase this up.
>
> > + if (!ncsi_priv) {
> > + ncsi_priv = malloc(sizeof(struct ncsi));
> > + if (!ncsi_priv)
> > + return -ENOMEM;
> > + memset(ncsi_priv, 0, sizeof(struct ncsi));
> > + }
> > +
> > + phydev->priv = ncsi_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 ftgmac100 sets final bits up */
>
> s/ftgmac100/mac driver/ ?
Ack
>
> > + phydev->link = true;
> > +
> > + 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;
> > +}
> > --- /dev/null
> > +++ b/include/net/ncsi-pkt.h
> > @@ -0,0 +1,415 @@
> > +/*
> > + * Copyright Gavin Shan, IBM Corporation 2016.
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + */
>
> If you grab the version from 5.2-rc3 it has been SPDXified.
Cheers, will do.
>
> > --- 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
>
> hmmm...
Haha - suggestions welcome?
>
> > #define PHY_MAX_ADDR 32
> >
> > --
> > 2.21.0
> >
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 3/4] net/ftgmac100: Add NC-SI mode support
2019-06-12 3:04 ` [U-Boot] " Joel Stanley
@ 2019-06-12 5:51 ` Samuel Mendoza-Jonas
-1 siblings, 0 replies; 24+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-12 5:51 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-12 at 03:04 +0000, Joel Stanley wrote:
> On Thu, 6 Jun 2019 at 04:50, 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 +++++++++++++++++++++++++++++----------
> > @@ -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;
>
> Instead of hiding this behind ncsi_mode I was assuming the ncsi "phy"
> driver would answer these questions through the phy_read callbacks.
>
> If you don't think that is going to work then this solution isn't too
> invasive, and we've been using this in Linux for a while, so we know
> it works.
Having this purely transparent would indeed be nice, but it's been a
little awkward fitting NCSI into the u-boot model. phy_read, etc don't
really make sense for a NCSI "PHY" like in the Linux model since there
aren't any registers as such to query - thus checking the device-tree and
skipping the normal mdio bus setup.
I'll have a bit more of a think about the driver model, and probably
exactly how Aspeed (for example) hooks this up; maybe there's a way we
can fit in to the more usual model.
^ permalink raw reply [flat|nested] 24+ messages in thread
* [U-Boot] [PATCH 3/4] net/ftgmac100: Add NC-SI mode support
@ 2019-06-12 5:51 ` Samuel Mendoza-Jonas
0 siblings, 0 replies; 24+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-12 5:51 UTC (permalink / raw)
To: u-boot
On Wed, 2019-06-12 at 03:04 +0000, Joel Stanley wrote:
> On Thu, 6 Jun 2019 at 04:50, 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 +++++++++++++++++++++++++++++----------
> > @@ -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;
>
> Instead of hiding this behind ncsi_mode I was assuming the ncsi "phy"
> driver would answer these questions through the phy_read callbacks.
>
> If you don't think that is going to work then this solution isn't too
> invasive, and we've been using this in Linux for a while, so we know
> it works.
Having this purely transparent would indeed be nice, but it's been a
little awkward fitting NCSI into the u-boot model. phy_read, etc don't
really make sense for a NCSI "PHY" like in the Linux model since there
aren't any registers as such to query - thus checking the device-tree and
skipping the normal mdio bus setup.
I'll have a bit more of a think about the driver model, and probably
exactly how Aspeed (for example) hooks this up; maybe there's a way we
can fit in to the more usual model.
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 4/4] net: NC-SI setup and handling
2019-06-12 2:05 ` [U-Boot] " Joel Stanley
@ 2019-06-12 5:53 ` Samuel Mendoza-Jonas
-1 siblings, 0 replies; 24+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-12 5:53 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-12 at 02:05 +0000, Joel Stanley wrote:
> On Thu, 6 Jun 2019 at 04:50, 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>
>
> We need the u-boot net specialists to weigh in, but this looks okay to
> me. Please clarify the help text for the NCSI command, then add:
>
> Reviewed-by: Joel Stanley <joel@jms.id.au>
>
> > --- a/cmd/Kconfig
> > +++ b/cmd/Kconfig
> > @@ -1296,6 +1296,12 @@ 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
> > + Configure the attached NIC via NC-SI
>
> Can we clarify in the text if we need the 'ncsi' command to use any
> NC-SI attached NIC, or if it's more for ncsi and network debugging?
Can do - the command manually kicks off configuration of the NC-SI
topology, but isn't needed in normal use.
^ permalink raw reply [flat|nested] 24+ messages in thread
* [U-Boot] [PATCH 4/4] net: NC-SI setup and handling
@ 2019-06-12 5:53 ` Samuel Mendoza-Jonas
0 siblings, 0 replies; 24+ messages in thread
From: Samuel Mendoza-Jonas @ 2019-06-12 5:53 UTC (permalink / raw)
To: u-boot
On Wed, 2019-06-12 at 02:05 +0000, Joel Stanley wrote:
> On Thu, 6 Jun 2019 at 04:50, 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>
>
> We need the u-boot net specialists to weigh in, but this looks okay to
> me. Please clarify the help text for the NCSI command, then add:
>
> Reviewed-by: Joel Stanley <joel@jms.id.au>
>
> > --- a/cmd/Kconfig
> > +++ b/cmd/Kconfig
> > @@ -1296,6 +1296,12 @@ 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
> > + Configure the attached NIC via NC-SI
>
> Can we clarify in the text if we need the 'ncsi' command to use any
> NC-SI attached NIC, or if it's more for ncsi and network debugging?
Can do - the command manually kicks off configuration of the NC-SI
topology, but isn't needed in normal use.
^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2019-06-12 5:53 UTC | newest]
Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-06 4:49 [PATCH 0/4] NC-SI PHY Support Samuel Mendoza-Jonas
2019-06-06 4:49 ` [U-Boot] " Samuel Mendoza-Jonas
2019-06-06 4:49 ` [PATCH 1/4] phy: Add support for the NC-SI protocol Samuel Mendoza-Jonas
2019-06-06 4:49 ` [U-Boot] " Samuel Mendoza-Jonas
2019-06-12 2:40 ` Joel Stanley
2019-06-12 2:40 ` [U-Boot] " Joel Stanley
2019-06-12 5:42 ` Samuel Mendoza-Jonas
2019-06-12 5:42 ` [U-Boot] " Samuel Mendoza-Jonas
2019-06-06 4:49 ` [PATCH 2/4] phy: Include NC-SI in phy setup Samuel Mendoza-Jonas
2019-06-06 4:49 ` [U-Boot] " Samuel Mendoza-Jonas
2019-06-12 2:42 ` Joel Stanley
2019-06-12 2:42 ` [U-Boot] " Joel Stanley
2019-06-06 4:49 ` [PATCH 3/4] net/ftgmac100: Add NC-SI mode support Samuel Mendoza-Jonas
2019-06-06 4:49 ` [U-Boot] " Samuel Mendoza-Jonas
2019-06-12 3:04 ` Joel Stanley
2019-06-12 3:04 ` [U-Boot] " Joel Stanley
2019-06-12 5:51 ` Samuel Mendoza-Jonas
2019-06-12 5:51 ` [U-Boot] " Samuel Mendoza-Jonas
2019-06-06 4:49 ` [PATCH 4/4] net: NC-SI setup and handling Samuel Mendoza-Jonas
2019-06-06 4:49 ` [U-Boot] " Samuel Mendoza-Jonas
2019-06-12 2:05 ` Joel Stanley
2019-06-12 2:05 ` [U-Boot] " Joel Stanley
2019-06-12 5:53 ` Samuel Mendoza-Jonas
2019-06-12 5:53 ` [U-Boot] " Samuel Mendoza-Jonas
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.