nicole: NCSI channel selector
NCSI channel number is selected depending on GPIO state of a pin
described in the device tree (gpio/nsci_cfg node).
Currently, this pin is controlled via MCU, and its state represents
Nicole's physical position inside a fabric.
Channel selector scheme:
* GPIO pin is LOW: channel 0;
* GPIO pin is HIGH: channel 1;
* invalid configuration or error: channel 0.
After changing pin's state it is necessary to reboot the BMC to apply
new channel number.
(From meta-yadro rev: 2661355417e52d968e9845298c37cae8ff1dfe6b)
Signed-off-by: Artem Senichev <a.senichev@yadro.com>
Change-Id: I8eeac34f71197fc110e41d186dd1fd4d2f1ef064
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
diff --git a/meta-yadro/meta-nicole/recipes-kernel/linux/linux-aspeed/0001-Add-NCSI-channel-selector.patch b/meta-yadro/meta-nicole/recipes-kernel/linux/linux-aspeed/0001-Add-NCSI-channel-selector.patch
new file mode 100644
index 0000000..6028f42
--- /dev/null
+++ b/meta-yadro/meta-nicole/recipes-kernel/linux/linux-aspeed/0001-Add-NCSI-channel-selector.patch
@@ -0,0 +1,131 @@
+From b19111bb23044c9312d13e64dd1df2a9565f6b38 Mon Sep 17 00:00:00 2001
+From: Artem Senichev <a.senichev@yadro.com>
+Date: Wed, 12 Feb 2020 14:05:15 +0300
+Subject: [PATCH] Add NCSI channel selector
+
+NCSI channel number is selected depending on GPIO state of a pin
+described in the device tree (gpio/nsci_cfg node).
+Currently, this pin is controlled via MCU, and its state represents
+Nicole's physical position inside a fabric.
+
+Channel selector scheme:
+* GPIO pin value is 0: channel 0;
+* GPIO pin value is 1: channel 1;
+* invalid configuration or error: channel 0.
+
+After changing pin's state it is necessary to reboot the BMC to apply
+new channel number.
+
+Signed-off-by: Artem Senichev <a.senichev@yadro.com>
+---
+ net/ncsi/ncsi-rsp.c | 80 ++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 79 insertions(+), 1 deletion(-)
+
+diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
+index d876bd55f356..d211a7e64b14 100644
+--- a/net/ncsi/ncsi-rsp.c
++++ b/net/ncsi/ncsi-rsp.c
+@@ -9,6 +9,9 @@
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+ #include <linux/skbuff.h>
++#include <linux/of.h>
++#include <linux/gpio.h>
++#include <linux/gpio/consumer.h>
+
+ #include <net/ncsi.h>
+ #include <net/net_namespace.h>
+@@ -19,6 +22,81 @@
+ #include "ncsi-pkt.h"
+ #include "ncsi-netlink.h"
+
++/* NSCI channel number, used as default in case of errors. */
++#define NCSI_DEFAULT_CHANNEL 0
++
++/* Predicate for gpiochip_find() call. */
++static int device_match(struct gpio_chip* chip, void* data)
++{
++ const struct device_node *node = data;
++ return chip->of_node == node;
++}
++
++/**
++ * ncsi_select_channel() - Get channel number for NCSI.
++ * @dev: Network device.
++ *
++ * NCSI channel number is selected depending on GPIO state of a pin
++ * described in the device tree (gpio/nsci_cfg node).
++ *
++ * Return: channel number.
++ */
++static int ncsi_select_channel(const struct net_device* dev)
++{
++ static int channel_id = -1;
++ struct device_node* node = NULL;
++
++ while (channel_id < 0) {
++ struct gpio_chip* chip;
++ const struct gpio_desc* desc;
++ u32 pin;
++ int rc;
++
++ /* Read NCSI configuration node from device tree */
++ node = of_find_node_by_name(NULL, "ncsi_cfg");
++ if (!node) {
++ netdev_err(dev, "NCSI: Configuration node not found\n");
++ break;
++ }
++
++ /* Read GPIO pin configuration */
++ rc = of_property_read_u32_index(node, "gpios", 0, &pin);
++ if (rc) {
++ netdev_err(dev, "NCSI: GPIO configuration not found\n");
++ break;
++ }
++
++ /* Find GPIO chip */
++ chip = gpiochip_find(node->parent, device_match);
++ if (!chip) {
++ netdev_err(dev, "NCSI: GPIO chip not found\n");
++ break;
++ }
++
++ /* Read GPIO state */
++ desc = gpio_to_desc(chip->base + pin);
++ if (!desc) {
++ netdev_err(dev, "NCSI: Cannot get GPIO descriptor\n");
++ break;
++ }
++ channel_id = gpiod_get_value(desc);
++ if (channel_id < 0) {
++ netdev_err(dev, "NCSI: GPIO read error %d\n", channel_id);
++ }
++ break;
++ }
++
++ if (node) {
++ of_node_put(node);
++ }
++ if (channel_id < 0) {
++ channel_id = NCSI_DEFAULT_CHANNEL;
++ }
++ netdev_info(dev, "NCSI: Set channel %d\n", channel_id);
++
++ return channel_id;
++}
++
+ static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
+ unsigned short payload)
+ {
+@@ -87,7 +165,7 @@ static int ncsi_rsp_handler_cis(struct ncsi_request *nr)
+ if (ndp->flags & NCSI_DEV_PROBED)
+ return -ENXIO;
+
+- id = NCSI_CHANNEL_INDEX(rsp->rsp.common.channel);
++ id = ncsi_select_channel(ndp->ndev.dev);
+ nc = ncsi_add_channel(np, id);
+ }
+
+--
+2.25.0
+
diff --git a/meta-yadro/meta-nicole/recipes-kernel/linux/linux-aspeed/arch/arm/boot/dts/aspeed-bmc-opp-nicole.dts b/meta-yadro/meta-nicole/recipes-kernel/linux/linux-aspeed/arch/arm/boot/dts/aspeed-bmc-opp-nicole.dts
index 51c8de0..07f7d29 100644
--- a/meta-yadro/meta-nicole/recipes-kernel/linux/linux-aspeed/arch/arm/boot/dts/aspeed-bmc-opp-nicole.dts
+++ b/meta-yadro/meta-nicole/recipes-kernel/linux/linux-aspeed/arch/arm/boot/dts/aspeed-bmc-opp-nicole.dts
@@ -217,6 +217,12 @@
output-low;
line-name = "seq_cont";
};
+ ncsi_cfg {
+ gpio-hog;
+ input;
+ gpios = <ASPEED_GPIO(E, 1) GPIO_ACTIVE_HIGH>;
+ line-name = "ncsi_cfg";
+ };
};
&vuart {
diff --git a/meta-yadro/meta-nicole/recipes-kernel/linux/linux-aspeed_%.bbappend b/meta-yadro/meta-nicole/recipes-kernel/linux/linux-aspeed_%.bbappend
index bd3e475..bf06fe2 100644
--- a/meta-yadro/meta-nicole/recipes-kernel/linux/linux-aspeed_%.bbappend
+++ b/meta-yadro/meta-nicole/recipes-kernel/linux/linux-aspeed_%.bbappend
@@ -1,6 +1,7 @@
FILESEXTRAPATHS_prepend_nicole := "${THISDIR}/${PN}:"
SRC_URI += "file://nicole.cfg \
file://arch \
+ file://0001-Add-NCSI-channel-selector.patch \
"
# Merge source tree by original project with our layer of additional files