[PATCH] net/ncsi: Add NCSI OEM command for FB Tiogapass
Samuel Mendoza-Jonas
sam at mendozajonas.com
Thu Sep 27 13:54:32 AEST 2018
On Thu, 2018-09-27 at 13:43 +1000, Samuel Mendoza-Jonas wrote:
> On Mon, 2018-09-24 at 17:08 -0700, Vijay Khemka wrote:
> > This patch adds OEM command to get mac address from NCSI device and and
> > configure the same to the network card.
> >
> > ncsi_cmd_arg - Modified this structure to include bigger payload data.
> > ncsi_cmd_handler_oem: This function handles oem command request
> > ncsi_rsp_handler_oem: This function handles response for OEM command.
> > get_mac_address_oem_mlx: This function will send OEM command to get
> > mac address for Mellanox card
> > set_mac_affinity_mlx: This will send OEM command to set Mac affinity
> > for Mellanox card
> >
> > Signed-off-by: Vijay Khemka <vijaykhemka at fb.com>
>
> Hi Vijay,
>
> Having had a chance to take a closer look, there is probably room for
> both this patchset and Justin's potential changes to coexist; while
> Justin's is a more general solution for sending arbitrary commands, the
> approach of this patch is also useful for handling commands we want
> included in the configure process (such as get-mac-address).
>
> Some comments below:
Whoops, forgot to re-add netdev.
>
> > ---
> > net/ncsi/Kconfig | 3 ++
> > net/ncsi/internal.h | 11 +++++--
> > net/ncsi/ncsi-cmd.c | 24 +++++++++++++--
> > net/ncsi/ncsi-manage.c | 68 ++++++++++++++++++++++++++++++++++++++++++
> > net/ncsi/ncsi-pkt.h | 16 ++++++++++
> > net/ncsi/ncsi-rsp.c | 33 +++++++++++++++++++-
> > 6 files changed, 149 insertions(+), 6 deletions(-)
> >
> > diff --git a/net/ncsi/Kconfig b/net/ncsi/Kconfig
> > index 08a8a6031fd7..b8bf89fea7c8 100644
> > --- a/net/ncsi/Kconfig
> > +++ b/net/ncsi/Kconfig
> > @@ -10,3 +10,6 @@ config NET_NCSI
> > support. Enable this only if your system connects to a network
> > device via NCSI and the ethernet driver you're using supports
> > the protocol explicitly.
> > +config NCSI_OEM_CMD_GET_MAC
> > + bool "Get NCSI OEM MAC Address"
> > + depends on NET_NCSI
>
> For the moment this isn't too bad but I wonder if in the future it would
> be more flexible to have something like NCSI_OEM_CMD_MELLANOX etc, so we
> could selectively enable a class of OEM commands based on vendor rather
> than per-command.
>
> > diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
> > index 8055e3965cef..da17958e6a4b 100644
> > --- a/net/ncsi/internal.h
> > +++ b/net/ncsi/internal.h
> > @@ -68,6 +68,10 @@ enum {
> > NCSI_MODE_MAX
> > };
> >
> > +#define NCSI_OEM_MFR_MLX_ID 0x8119
> > +#define NCSI_OEM_MLX_CMD_GET_MAC 0x1b00
> > +#define NCSI_OEM_MLX_CMD_SET_AFFINITY 0x010700
>
> I gather this is part of the OEM command but it would be good to describe
> what these bits mean. Is this command documented anywhere by Mellanox?
>
> > +
> > struct ncsi_channel_version {
> > u32 version; /* Supported BCD encoded NCSI version */
> > u32 alpha2; /* Supported BCD encoded NCSI version */
> > @@ -236,6 +240,7 @@ enum {
> > ncsi_dev_state_probe_dp,
> > ncsi_dev_state_config_sp = 0x0301,
> > ncsi_dev_state_config_cis,
> > + ncsi_dev_state_config_oem_gma,
> > ncsi_dev_state_config_clear_vids,
> > ncsi_dev_state_config_svf,
> > ncsi_dev_state_config_ev,
> > @@ -301,9 +306,9 @@ struct ncsi_cmd_arg {
> > unsigned short payload; /* Command packet payload length */
> > unsigned int req_flags; /* NCSI request properties */
> > union {
> > - unsigned char bytes[16]; /* Command packet specific data */
> > - unsigned short words[8];
> > - unsigned int dwords[4];
> > + unsigned char bytes[64]; /* Command packet specific data */
> > + unsigned short words[32];
> > + unsigned int dwords[16];
> > };
> > };
> >
> > diff --git a/net/ncsi/ncsi-cmd.c b/net/ncsi/ncsi-cmd.c
> > index 7567ca63aae2..3205e22c1734 100644
> > --- a/net/ncsi/ncsi-cmd.c
> > +++ b/net/ncsi/ncsi-cmd.c
> > @@ -211,6 +211,25 @@ static int ncsi_cmd_handler_snfc(struct sk_buff *skb,
> > return 0;
> > }
> >
> > +static int ncsi_cmd_handler_oem(struct sk_buff *skb,
> > + struct ncsi_cmd_arg *nca)
> > +{
> > + struct ncsi_cmd_oem_pkt *cmd;
> > + unsigned int len;
> > +
> > + len = sizeof(struct ncsi_cmd_pkt_hdr) + 4;
> > + if (nca->payload < 26)
> > + len += 26;
>
> This will have already happened in ncsi_alloc_command(), is this check
> needed?
>
> > + else
> > + len += nca->payload;
> > +
> > + cmd = skb_put_zero(skb, len);
> > + memcpy(cmd->data, nca->bytes, nca->payload);
> > + ncsi_cmd_build_header(&cmd->cmd.common, nca);
> > +
> > + return 0;
> > +}
> > +
> > static struct ncsi_cmd_handler {
> > unsigned char type;
> > int payload;
> > @@ -244,7 +263,7 @@ static struct ncsi_cmd_handler {
> > { NCSI_PKT_CMD_GNS, 0, ncsi_cmd_handler_default },
> > { NCSI_PKT_CMD_GNPTS, 0, ncsi_cmd_handler_default },
> > { NCSI_PKT_CMD_GPS, 0, ncsi_cmd_handler_default },
> > - { NCSI_PKT_CMD_OEM, 0, NULL },
> > + { NCSI_PKT_CMD_OEM, -1, ncsi_cmd_handler_oem },
> > { NCSI_PKT_CMD_PLDM, 0, NULL },
> > { NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default }
> > };
> > @@ -317,7 +336,8 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
> > }
> >
> > /* Get packet payload length and allocate the request */
> > - nca->payload = nch->payload;
> > + if (nch->payload >= 0)
> > + nca->payload = nch->payload;
>
> I think with this there is a chance of nca->payload being uninitialised
> and then used in ncsi_alloc_command(). Can you describe what the aim here
> is?
>
> > nr = ncsi_alloc_command(nca);
> > if (!nr)
> > return -ENOMEM;
> > diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
> > index 091284760d21..3b2b86560cc8 100644
> > --- a/net/ncsi/ncsi-manage.c
> > +++ b/net/ncsi/ncsi-manage.c
> > @@ -635,6 +635,58 @@ static int set_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc,
> > return 0;
> > }
> >
> > +#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC)
> > +/* NCSI Facebook OEM APIs */
>
> Are these Facebook OEM commands or Mellanox OEM commands?
>
> > +static void get_mac_address_oem_mlx(struct ncsi_dev_priv *ndp)
> > +{
> > + struct ncsi_cmd_arg nca;
> > + int ret = 0;
> > +
> > + memset(&nca, 0, sizeof(struct ncsi_cmd_arg));
> > + nca.ndp = ndp;
> > + nca.channel = ndp->active_channel->id;
> > + nca.package = ndp->active_package->id;
> > + nca.req_flags = NCSI_REQ_FLAG_EVENT_DRIVEN;
> > + nca.type = NCSI_PKT_CMD_OEM;
> > + nca.payload = 8;
> > +
> > + nca.dwords[0] = ntohl(NCSI_OEM_MFR_MLX_ID);
> > + nca.dwords[1] = ntohl(NCSI_OEM_MLX_CMD_GET_MAC);
> > +
> > + ret = ncsi_xmit_cmd(&nca);
> > + if (ret)
> > + netdev_err(ndp->ndev.dev,
> > + "NCSI: Failed to transmit cmd 0x%x during probe\n",
> > + nca.type);
> > +}
> > +
> > +static void set_mac_affinity_mlx(struct ncsi_dev_priv *ndp)
> > +{
> > + struct ncsi_cmd_arg nca;
> > + int ret = 0;
> > +
> > + memset(&nca, 0, sizeof(struct ncsi_cmd_arg));
>
> Ah I see we initialise nca, and thus payload here - the path between
> these two points in the driver isn't super obvious (not this patch's
> fault :) ), it might be better to explicitly mention/handle this where we
> use payload later on.
>
> > + nca.ndp = ndp;
> > + nca.channel = ndp->active_channel->id;
> > + nca.package = ndp->active_package->id;
>
> These should probably be set in ncsi_configure_channel (eg. see the CIS
> state before these are called).
>
> > + nca.req_flags = NCSI_REQ_FLAG_EVENT_DRIVEN;
> > + nca.type = NCSI_PKT_CMD_OEM;
> > + nca.payload = 60;
> > +
> > + nca.dwords[0] = ntohl(NCSI_OEM_MFR_MLX_ID);
> > + nca.dwords[1] = ntohl(NCSI_OEM_MLX_CMD_SET_AFFINITY);
> > +
> > + memcpy(&(nca.bytes[8]), ndp->ndev.dev->dev_addr, ETH_ALEN);
> > + nca.bytes[14] = 0x09;
> > +
> > + ret = ncsi_xmit_cmd(&nca);
> > + if (ret)
> > + netdev_err(ndp->ndev.dev,
> > + "NCSI: Failed to transmit cmd 0x%x during probe\n",
> > + nca.type);
> > +}
> > +#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */
> > +
> > static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
> > {
> > struct ncsi_dev *nd = &ndp->ndev;
> > @@ -685,6 +737,22 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
> > goto error;
> > }
> >
> > +#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC)
> > + /* Check Manufacture id if it is Mellanox then
> > + * get and set mac address. To Do: Add code for
> > + * other types of card if required
> > + */
> > + if (nc->version.mf_id == NCSI_OEM_MFR_MLX_ID)
> > + nd->state = ncsi_dev_state_config_oem_gma;
> > + else
> > + nd->state = ncsi_dev_state_config_clear_vids;
> > + break;
> > + case ncsi_dev_state_config_oem_gma:
> > + ndp->pending_req_num = 2;
> > + get_mac_address_oem_mlx(ndp);
> > + msleep(500);
>
> Is this msleep() required?
>
> > + set_mac_affinity_mlx(ndp);
>
> Since this *sets* the MAC address, should we name the state and config
> option more accurately? How does this OEM command interact with the NCSI
> set-mac-address command?
> Does this command depend on the previous get_mac_address_oem_mlx()
> command succeeding?
>
> > +#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */
> > nd->state = ncsi_dev_state_config_clear_vids;
> > break;
> > case ncsi_dev_state_config_clear_vids:
> > diff --git a/net/ncsi/ncsi-pkt.h b/net/ncsi/ncsi-pkt.h
> > index 91b4b66438df..0653a893eb12 100644
> > --- a/net/ncsi/ncsi-pkt.h
> > +++ b/net/ncsi/ncsi-pkt.h
> > @@ -151,6 +151,22 @@ struct ncsi_cmd_snfc_pkt {
> > unsigned char pad[22];
> > };
> >
> > +/* Oem Request Command */
>
> In general, s/Oem/OEM
>
> > +struct ncsi_cmd_oem_pkt {
> > + struct ncsi_cmd_pkt_hdr cmd; /* Command header */
> > + unsigned char data[64]; /* OEM Payload Data */
> > + __be32 checksum; /* Checksum */
> > +};
> > +
> > +/* Oem Response Packet */
> > +struct ncsi_rsp_oem_pkt {
> > + struct ncsi_rsp_pkt_hdr rsp; /* Command header */
> > + __be32 mfr_id; /* Manufacture ID */
> > + __be32 oem_cmd; /* oem command */
> > + unsigned char data[32]; /* Payload data */
> > + __be32 checksum; /* Checksum */
> > +};
> > +
> > /* Get Link Status */
> > struct ncsi_rsp_gls_pkt {
> > struct ncsi_rsp_pkt_hdr rsp; /* Response header */
> > diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
> > index 930c1d3796f0..3b94c96b9c7f 100644
> > --- a/net/ncsi/ncsi-rsp.c
> > +++ b/net/ncsi/ncsi-rsp.c
> > @@ -596,6 +596,37 @@ static int ncsi_rsp_handler_snfc(struct ncsi_request *nr)
> > return 0;
> > }
> >
> > +static int ncsi_rsp_handler_oem(struct ncsi_request *nr)
> > +{
> > + struct ncsi_rsp_oem_pkt *rsp;
> > + struct ncsi_dev_priv *ndp = nr->ndp;
> > + struct net_device *ndev = ndp->ndev.dev;
> > + int ret = 0;
> > + unsigned int oem_cmd, mfr_id;
> > + const struct net_device_ops *ops = ndev->netdev_ops;
> > + struct sockaddr saddr;
> > +
> > + /* Get the response header */
> > + rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
> > +
> > + oem_cmd = ntohl(rsp->oem_cmd);
> > + mfr_id = ntohl(rsp->mfr_id);
> > +
> > + /* Check for Mellanox manufacturer id */
> > + if (mfr_id != NCSI_OEM_MFR_MLX_ID)
> > + return 0;
> > +
> > + if (oem_cmd == NCSI_OEM_MLX_CMD_GET_MAC) {
> > + saddr.sa_family = ndev->type;
> > + ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
> > + memcpy(saddr.sa_data, &(rsp->data[4]), ETH_ALEN);
> > + ret = ops->ndo_set_mac_address(ndev, &saddr);
> > + if (ret < 0)
> > + netdev_warn(ndev, "NCSI: 'Writing mac address to device failed\n");
> > + }
> > + return ret;
> > +}
> > +
> > static int ncsi_rsp_handler_gvi(struct ncsi_request *nr)
> > {
> > struct ncsi_rsp_gvi_pkt *rsp;
> > @@ -932,7 +963,7 @@ static struct ncsi_rsp_handler {
> > { NCSI_PKT_RSP_GNS, 172, ncsi_rsp_handler_gns },
> > { NCSI_PKT_RSP_GNPTS, 172, ncsi_rsp_handler_gnpts },
> > { NCSI_PKT_RSP_GPS, 8, ncsi_rsp_handler_gps },
> > - { NCSI_PKT_RSP_OEM, 0, NULL },
> > + { NCSI_PKT_RSP_OEM, -1, ncsi_rsp_handler_oem },
> > { NCSI_PKT_RSP_PLDM, 0, NULL },
> > { NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid }
> > };
More information about the openbmc
mailing list