From b19111bb23044c9312d13e64dd1df2a9565f6b38 Mon Sep 17 00:00:00 2001 From: Artem Senichev 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 --- 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 #include #include +#include +#include +#include #include #include @@ -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