OSDN Git Service

net/ncsi: Add NCSI Broadcom OEM command
authorVijay Khemka <vijaykhemka@fb.com>
Tue, 16 Oct 2018 19:13:19 +0000 (12:13 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 18 Oct 2018 05:14:54 +0000 (22:14 -0700)
This patch adds OEM Broadcom commands and response handling. It also
defines OEM Get MAC Address handler to get and configure the device.

ncsi_oem_gma_handler_bcm: This handler send NCSI broadcom command for
getting mac address.
ncsi_rsp_handler_oem_bcm: This handles response received for all
broadcom OEM commands.
ncsi_rsp_handler_oem_bcm_gma: This handles get mac address response and
set it to device.

Signed-off-by: Vijay Khemka <vijaykhemka@fb.com>
Reviewed-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ncsi/Kconfig
net/ncsi/internal.h
net/ncsi/ncsi-manage.c
net/ncsi/ncsi-pkt.h
net/ncsi/ncsi-rsp.c

index 08a8a60..7f2b461 100644 (file)
@@ -10,3 +10,9 @@ 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
+       ---help---
+         This allows to get MAC address from NCSI firmware and set them back to
+               controller.
index 13c9b5e..1dae77c 100644 (file)
@@ -71,6 +71,13 @@ enum {
 /* OEM Vendor Manufacture ID */
 #define NCSI_OEM_MFR_MLX_ID             0x8119
 #define NCSI_OEM_MFR_BCM_ID             0x113d
+/* Broadcom specific OEM Command */
+#define NCSI_OEM_BCM_CMD_GMA            0x01   /* CMD ID for Get MAC */
+/* OEM Command payload lengths*/
+#define NCSI_OEM_BCM_CMD_GMA_LEN        12
+/* Mac address offset in OEM response */
+#define BCM_MAC_ADDR_OFFSET             28
+
 
 struct ncsi_channel_version {
        u32 version;            /* Supported BCD encoded NCSI version */
@@ -246,6 +253,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,
@@ -279,6 +287,7 @@ struct ncsi_dev_priv {
 #define NCSI_DEV_PROBED                1            /* Finalized NCSI topology    */
 #define NCSI_DEV_HWA           2            /* Enabled HW arbitration     */
 #define NCSI_DEV_RESHUFFLE     4
+       unsigned int        gma_flag;        /* OEM GMA flag               */
        spinlock_t          lock;            /* Protect the NCSI device    */
 #if IS_ENABLED(CONFIG_IPV6)
        unsigned int        inet6_addr_num;  /* Number of IPv6 addresses   */
index 6aa0614..bfc43b2 100644 (file)
@@ -651,6 +651,72 @@ 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 OEM Command APIs */
+static int ncsi_oem_gma_handler_bcm(struct ncsi_cmd_arg *nca)
+{
+       unsigned char data[NCSI_OEM_BCM_CMD_GMA_LEN];
+       int ret = 0;
+
+       nca->payload = NCSI_OEM_BCM_CMD_GMA_LEN;
+
+       memset(data, 0, NCSI_OEM_BCM_CMD_GMA_LEN);
+       *(unsigned int *)data = ntohl(NCSI_OEM_MFR_BCM_ID);
+       data[5] = NCSI_OEM_BCM_CMD_GMA;
+
+       nca->data = data;
+
+       ret = ncsi_xmit_cmd(nca);
+       if (ret)
+               netdev_err(nca->ndp->ndev.dev,
+                          "NCSI: Failed to transmit cmd 0x%x during configure\n",
+                          nca->type);
+       return ret;
+}
+
+/* OEM Command handlers initialization */
+static struct ncsi_oem_gma_handler {
+       unsigned int    mfr_id;
+       int             (*handler)(struct ncsi_cmd_arg *nca);
+} ncsi_oem_gma_handlers[] = {
+       { NCSI_OEM_MFR_BCM_ID, ncsi_oem_gma_handler_bcm }
+};
+
+static int ncsi_gma_handler(struct ncsi_cmd_arg *nca, unsigned int mf_id)
+{
+       struct ncsi_oem_gma_handler *nch = NULL;
+       int i;
+
+       /* This function should only be called once, return if flag set */
+       if (nca->ndp->gma_flag == 1)
+               return -1;
+
+       /* Find gma handler for given manufacturer id */
+       for (i = 0; i < ARRAY_SIZE(ncsi_oem_gma_handlers); i++) {
+               if (ncsi_oem_gma_handlers[i].mfr_id == mf_id) {
+                       if (ncsi_oem_gma_handlers[i].handler)
+                               nch = &ncsi_oem_gma_handlers[i];
+                       break;
+                       }
+       }
+
+       if (!nch) {
+               netdev_err(nca->ndp->ndev.dev,
+                          "NCSI: No GMA handler available for MFR-ID (0x%x)\n",
+                          mf_id);
+               return -1;
+       }
+
+       /* Set the flag for GMA command which should only be called once */
+       nca->ndp->gma_flag = 1;
+
+       /* Get Mac address from NCSI device */
+       return nch->handler(nca);
+}
+
+#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */
+
 static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
 {
        struct ncsi_dev *nd = &ndp->ndev;
@@ -701,7 +767,23 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
                        goto error;
                }
 
+               nd->state = ncsi_dev_state_config_oem_gma;
+               break;
+       case ncsi_dev_state_config_oem_gma:
                nd->state = ncsi_dev_state_config_clear_vids;
+               ret = -1;
+
+#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC)
+               nca.type = NCSI_PKT_CMD_OEM;
+               nca.package = np->id;
+               nca.channel = nc->id;
+               ndp->pending_req_num = 1;
+               ret = ncsi_gma_handler(&nca, nc->version.mf_id);
+#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */
+
+               if (ret < 0)
+                       schedule_work(&ndp->work);
+
                break;
        case ncsi_dev_state_config_clear_vids:
        case ncsi_dev_state_config_svf:
index 0f2087c..4d3f06b 100644 (file)
@@ -165,6 +165,14 @@ struct ncsi_rsp_oem_pkt {
        unsigned char           data[];      /* Payload data      */
 };
 
+/* Broadcom Response Data */
+struct ncsi_rsp_oem_bcm_pkt {
+       unsigned char           ver;         /* Payload Version   */
+       unsigned char           type;        /* OEM Command type  */
+       __be16                  len;         /* Payload Length    */
+       unsigned char           data[];      /* Cmd specific Data */
+};
+
 /* Get Link Status */
 struct ncsi_rsp_gls_pkt {
        struct ncsi_rsp_pkt_hdr rsp;        /* Response header   */
index 85fa59a..77e07ba 100644 (file)
@@ -611,19 +611,59 @@ static int ncsi_rsp_handler_snfc(struct ncsi_request *nr)
        return 0;
 }
 
+/* Response handler for Broadcom command Get Mac Address */
+static int ncsi_rsp_handler_oem_bcm_gma(struct ncsi_request *nr)
+{
+       struct ncsi_dev_priv *ndp = nr->ndp;
+       struct net_device *ndev = ndp->ndev.dev;
+       const struct net_device_ops *ops = ndev->netdev_ops;
+       struct ncsi_rsp_oem_pkt *rsp;
+       struct sockaddr saddr;
+       int ret = 0;
+
+       /* Get the response header */
+       rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
+
+       saddr.sa_family = ndev->type;
+       ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+       memcpy(saddr.sa_data, &rsp->data[BCM_MAC_ADDR_OFFSET], ETH_ALEN);
+       /* Increase mac address by 1 for BMC's address */
+       saddr.sa_data[ETH_ALEN - 1]++;
+       ret = ops->ndo_set_mac_address(ndev, &saddr);
+       if (ret < 0)
+               netdev_warn(ndev, "NCSI: 'Writing mac address to device failed\n");
+
+       return ret;
+}
+
+/* Response handler for Broadcom card */
+static int ncsi_rsp_handler_oem_bcm(struct ncsi_request *nr)
+{
+       struct ncsi_rsp_oem_bcm_pkt *bcm;
+       struct ncsi_rsp_oem_pkt *rsp;
+
+       /* Get the response header */
+       rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
+       bcm = (struct ncsi_rsp_oem_bcm_pkt *)(rsp->data);
+
+       if (bcm->type == NCSI_OEM_BCM_CMD_GMA)
+               return ncsi_rsp_handler_oem_bcm_gma(nr);
+       return 0;
+}
+
 static struct ncsi_rsp_oem_handler {
        unsigned int    mfr_id;
        int             (*handler)(struct ncsi_request *nr);
 } ncsi_rsp_oem_handlers[] = {
        { NCSI_OEM_MFR_MLX_ID, NULL },
-       { NCSI_OEM_MFR_BCM_ID, NULL }
+       { NCSI_OEM_MFR_BCM_ID, ncsi_rsp_handler_oem_bcm }
 };
 
 /* Response handler for OEM command */
 static int ncsi_rsp_handler_oem(struct ncsi_request *nr)
 {
-       struct ncsi_rsp_oem_pkt *rsp;
        struct ncsi_rsp_oem_handler *nrh = NULL;
+       struct ncsi_rsp_oem_pkt *rsp;
        unsigned int mfr_id, i;
 
        /* Get the response header */