Commit 4dce97b1 authored by David S. Miller's avatar David S. Miller

Merge branch 'ncsi-mac-address-command'

Patrick Williams says:

====================
net/ncsi: Add NC-SI 1.2 Get MC MAC Address command

NC-SI 1.2 has now been published[1] and adds a new command for "Get MC
MAC Address".  This is often used by BMCs to get the assigned MAC
address for the channel used by the BMC.

This change set has been tested on a Broadcomm 200G NIC with updated
firmware for NC-SI 1.2 and at least one other non-public NIC design.

1. https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.2.0.pdf
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f9672265 b8291cf3
...@@ -105,8 +105,11 @@ enum { ...@@ -105,8 +105,11 @@ enum {
struct ncsi_channel_version { struct ncsi_channel_version {
u32 version; /* Supported BCD encoded NCSI version */ u8 major; /* NCSI version major */
u32 alpha2; /* Supported BCD encoded NCSI version */ u8 minor; /* NCSI version minor */
u8 update; /* NCSI version update */
char alpha1; /* NCSI version alpha1 */
char alpha2; /* NCSI version alpha2 */
u8 fw_name[12]; /* Firmware name string */ u8 fw_name[12]; /* Firmware name string */
u32 fw_version; /* Firmware version */ u32 fw_version; /* Firmware version */
u16 pci_ids[4]; /* PCI identification */ u16 pci_ids[4]; /* PCI identification */
......
...@@ -270,7 +270,8 @@ static struct ncsi_cmd_handler { ...@@ -270,7 +270,8 @@ static struct ncsi_cmd_handler {
{ NCSI_PKT_CMD_GPS, 0, ncsi_cmd_handler_default }, { NCSI_PKT_CMD_GPS, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_OEM, -1, ncsi_cmd_handler_oem }, { NCSI_PKT_CMD_OEM, -1, ncsi_cmd_handler_oem },
{ NCSI_PKT_CMD_PLDM, 0, NULL }, { NCSI_PKT_CMD_PLDM, 0, NULL },
{ NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default } { NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_GMCMA, 0, ncsi_cmd_handler_default }
}; };
static struct ncsi_request *ncsi_alloc_command(struct ncsi_cmd_arg *nca) static struct ncsi_request *ncsi_alloc_command(struct ncsi_cmd_arg *nca)
......
...@@ -689,8 +689,6 @@ static int set_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc, ...@@ -689,8 +689,6 @@ static int set_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc,
return 0; return 0;
} }
#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY)
static int ncsi_oem_keep_phy_intel(struct ncsi_cmd_arg *nca) static int ncsi_oem_keep_phy_intel(struct ncsi_cmd_arg *nca)
{ {
unsigned char data[NCSI_OEM_INTEL_CMD_KEEP_PHY_LEN]; unsigned char data[NCSI_OEM_INTEL_CMD_KEEP_PHY_LEN];
...@@ -716,10 +714,6 @@ static int ncsi_oem_keep_phy_intel(struct ncsi_cmd_arg *nca) ...@@ -716,10 +714,6 @@ static int ncsi_oem_keep_phy_intel(struct ncsi_cmd_arg *nca)
return ret; return ret;
} }
#endif
#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC)
/* NCSI OEM Command APIs */ /* NCSI OEM Command APIs */
static int ncsi_oem_gma_handler_bcm(struct ncsi_cmd_arg *nca) static int ncsi_oem_gma_handler_bcm(struct ncsi_cmd_arg *nca)
{ {
...@@ -856,8 +850,6 @@ static int ncsi_gma_handler(struct ncsi_cmd_arg *nca, unsigned int mf_id) ...@@ -856,8 +850,6 @@ static int ncsi_gma_handler(struct ncsi_cmd_arg *nca, unsigned int mf_id)
return nch->handler(nca); return nch->handler(nca);
} }
#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */
/* Determine if a given channel from the channel_queue should be used for Tx */ /* Determine if a given channel from the channel_queue should be used for Tx */
static bool ncsi_channel_is_tx(struct ncsi_dev_priv *ndp, static bool ncsi_channel_is_tx(struct ncsi_dev_priv *ndp,
struct ncsi_channel *nc) struct ncsi_channel *nc)
...@@ -1039,20 +1031,23 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) ...@@ -1039,20 +1031,23 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
goto error; goto error;
} }
nd->state = ncsi_dev_state_config_oem_gma; nd->state = IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC)
? ncsi_dev_state_config_oem_gma
: ncsi_dev_state_config_clear_vids;
break; break;
case ncsi_dev_state_config_oem_gma: case ncsi_dev_state_config_oem_gma:
nd->state = ncsi_dev_state_config_clear_vids; 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.package = np->id;
nca.channel = nc->id; nca.channel = nc->id;
ndp->pending_req_num = 1; ndp->pending_req_num = 1;
ret = ncsi_gma_handler(&nca, nc->version.mf_id); if (nc->version.major >= 1 && nc->version.minor >= 2) {
#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */ nca.type = NCSI_PKT_CMD_GMCMA;
ret = ncsi_xmit_cmd(&nca);
} else {
nca.type = NCSI_PKT_CMD_OEM;
ret = ncsi_gma_handler(&nca, nc->version.mf_id);
}
if (ret < 0) if (ret < 0)
schedule_work(&ndp->work); schedule_work(&ndp->work);
...@@ -1404,7 +1399,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) ...@@ -1404,7 +1399,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
schedule_work(&ndp->work); schedule_work(&ndp->work);
break; break;
#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC)
case ncsi_dev_state_probe_mlx_gma: case ncsi_dev_state_probe_mlx_gma:
ndp->pending_req_num = 1; ndp->pending_req_num = 1;
...@@ -1429,7 +1423,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) ...@@ -1429,7 +1423,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
nd->state = ncsi_dev_state_probe_cis; nd->state = ncsi_dev_state_probe_cis;
break; break;
#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */
case ncsi_dev_state_probe_cis: case ncsi_dev_state_probe_cis:
ndp->pending_req_num = NCSI_RESERVED_CHANNEL; ndp->pending_req_num = NCSI_RESERVED_CHANNEL;
...@@ -1447,7 +1440,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) ...@@ -1447,7 +1440,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
if (IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY)) if (IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY))
nd->state = ncsi_dev_state_probe_keep_phy; nd->state = ncsi_dev_state_probe_keep_phy;
break; break;
#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY)
case ncsi_dev_state_probe_keep_phy: case ncsi_dev_state_probe_keep_phy:
ndp->pending_req_num = 1; ndp->pending_req_num = 1;
...@@ -1460,7 +1452,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) ...@@ -1460,7 +1452,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
nd->state = ncsi_dev_state_probe_gvi; nd->state = ncsi_dev_state_probe_gvi;
break; break;
#endif /* CONFIG_NCSI_OEM_CMD_KEEP_PHY */
case ncsi_dev_state_probe_gvi: case ncsi_dev_state_probe_gvi:
case ncsi_dev_state_probe_gc: case ncsi_dev_state_probe_gc:
case ncsi_dev_state_probe_gls: case ncsi_dev_state_probe_gls:
......
...@@ -71,8 +71,8 @@ static int ncsi_write_channel_info(struct sk_buff *skb, ...@@ -71,8 +71,8 @@ static int ncsi_write_channel_info(struct sk_buff *skb,
if (nc == nc->package->preferred_channel) if (nc == nc->package->preferred_channel)
nla_put_flag(skb, NCSI_CHANNEL_ATTR_FORCED); nla_put_flag(skb, NCSI_CHANNEL_ATTR_FORCED);
nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.version); nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.major);
nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MINOR, nc->version.alpha2); nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MINOR, nc->version.minor);
nla_put_string(skb, NCSI_CHANNEL_ATTR_VERSION_STR, nc->version.fw_name); nla_put_string(skb, NCSI_CHANNEL_ATTR_VERSION_STR, nc->version.fw_name);
vid_nest = nla_nest_start_noflag(skb, NCSI_CHANNEL_ATTR_VLAN_LIST); vid_nest = nla_nest_start_noflag(skb, NCSI_CHANNEL_ATTR_VLAN_LIST);
......
...@@ -197,9 +197,12 @@ struct ncsi_rsp_gls_pkt { ...@@ -197,9 +197,12 @@ struct ncsi_rsp_gls_pkt {
/* Get Version ID */ /* Get Version ID */
struct ncsi_rsp_gvi_pkt { struct ncsi_rsp_gvi_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */ struct ncsi_rsp_pkt_hdr rsp; /* Response header */
__be32 ncsi_version; /* NCSI version */ unsigned char major; /* NCSI version major */
unsigned char minor; /* NCSI version minor */
unsigned char update; /* NCSI version update */
unsigned char alpha1; /* NCSI version alpha1 */
unsigned char reserved[3]; /* Reserved */ unsigned char reserved[3]; /* Reserved */
unsigned char alpha2; /* NCSI version */ unsigned char alpha2; /* NCSI version alpha2 */
unsigned char fw_name[12]; /* f/w name string */ unsigned char fw_name[12]; /* f/w name string */
__be32 fw_version; /* f/w version */ __be32 fw_version; /* f/w version */
__be16 pci_ids[4]; /* PCI IDs */ __be16 pci_ids[4]; /* PCI IDs */
...@@ -335,6 +338,14 @@ struct ncsi_rsp_gpuuid_pkt { ...@@ -335,6 +338,14 @@ struct ncsi_rsp_gpuuid_pkt {
__be32 checksum; __be32 checksum;
}; };
/* Get MC MAC Address */
struct ncsi_rsp_gmcma_pkt {
struct ncsi_rsp_pkt_hdr rsp;
unsigned char address_count;
unsigned char reserved[3];
unsigned char addresses[][ETH_ALEN];
};
/* AEN: Link State Change */ /* AEN: Link State Change */
struct ncsi_aen_lsc_pkt { struct ncsi_aen_lsc_pkt {
struct ncsi_aen_pkt_hdr aen; /* AEN header */ struct ncsi_aen_pkt_hdr aen; /* AEN header */
...@@ -395,6 +406,7 @@ struct ncsi_aen_hncdsc_pkt { ...@@ -395,6 +406,7 @@ struct ncsi_aen_hncdsc_pkt {
#define NCSI_PKT_CMD_GPUUID 0x52 /* Get package UUID */ #define NCSI_PKT_CMD_GPUUID 0x52 /* Get package UUID */
#define NCSI_PKT_CMD_QPNPR 0x56 /* Query Pending NC PLDM request */ #define NCSI_PKT_CMD_QPNPR 0x56 /* Query Pending NC PLDM request */
#define NCSI_PKT_CMD_SNPR 0x57 /* Send NC PLDM Reply */ #define NCSI_PKT_CMD_SNPR 0x57 /* Send NC PLDM Reply */
#define NCSI_PKT_CMD_GMCMA 0x58 /* Get MC MAC Address */
/* NCSI packet responses */ /* NCSI packet responses */
...@@ -430,6 +442,7 @@ struct ncsi_aen_hncdsc_pkt { ...@@ -430,6 +442,7 @@ struct ncsi_aen_hncdsc_pkt {
#define NCSI_PKT_RSP_GPUUID (NCSI_PKT_CMD_GPUUID + 0x80) #define NCSI_PKT_RSP_GPUUID (NCSI_PKT_CMD_GPUUID + 0x80)
#define NCSI_PKT_RSP_QPNPR (NCSI_PKT_CMD_QPNPR + 0x80) #define NCSI_PKT_RSP_QPNPR (NCSI_PKT_CMD_QPNPR + 0x80)
#define NCSI_PKT_RSP_SNPR (NCSI_PKT_CMD_SNPR + 0x80) #define NCSI_PKT_RSP_SNPR (NCSI_PKT_CMD_SNPR + 0x80)
#define NCSI_PKT_RSP_GMCMA (NCSI_PKT_CMD_GMCMA + 0x80)
/* NCSI response code/reason */ /* NCSI response code/reason */
#define NCSI_PKT_RSP_C_COMPLETED 0x0000 /* Command Completed */ #define NCSI_PKT_RSP_C_COMPLETED 0x0000 /* Command Completed */
......
...@@ -19,6 +19,19 @@ ...@@ -19,6 +19,19 @@
#include "ncsi-pkt.h" #include "ncsi-pkt.h"
#include "ncsi-netlink.h" #include "ncsi-netlink.h"
/* Nibbles within [0xA, 0xF] add zero "0" to the returned value.
* Optional fields (encoded as 0xFF) will default to zero.
*/
static u8 decode_bcd_u8(u8 x)
{
int lo = x & 0xF;
int hi = x >> 4;
lo = lo < 0xA ? lo : 0;
hi = hi < 0xA ? hi : 0;
return lo + hi * 10;
}
static int ncsi_validate_rsp_pkt(struct ncsi_request *nr, static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
unsigned short payload) unsigned short payload)
{ {
...@@ -755,9 +768,18 @@ static int ncsi_rsp_handler_gvi(struct ncsi_request *nr) ...@@ -755,9 +768,18 @@ static int ncsi_rsp_handler_gvi(struct ncsi_request *nr)
if (!nc) if (!nc)
return -ENODEV; return -ENODEV;
/* Update to channel's version info */ /* Update channel's version info
*
* Major, minor, and update fields are supposed to be
* unsigned integers encoded as packed BCD.
*
* Alpha1 and alpha2 are ISO/IEC 8859-1 characters.
*/
ncv = &nc->version; ncv = &nc->version;
ncv->version = ntohl(rsp->ncsi_version); ncv->major = decode_bcd_u8(rsp->major);
ncv->minor = decode_bcd_u8(rsp->minor);
ncv->update = decode_bcd_u8(rsp->update);
ncv->alpha1 = rsp->alpha1;
ncv->alpha2 = rsp->alpha2; ncv->alpha2 = rsp->alpha2;
memcpy(ncv->fw_name, rsp->fw_name, 12); memcpy(ncv->fw_name, rsp->fw_name, 12);
ncv->fw_version = ntohl(rsp->fw_version); ncv->fw_version = ntohl(rsp->fw_version);
...@@ -1069,6 +1091,44 @@ static int ncsi_rsp_handler_netlink(struct ncsi_request *nr) ...@@ -1069,6 +1091,44 @@ static int ncsi_rsp_handler_netlink(struct ncsi_request *nr)
return ret; return ret;
} }
static int ncsi_rsp_handler_gmcma(struct ncsi_request *nr)
{
struct ncsi_dev_priv *ndp = nr->ndp;
struct net_device *ndev = ndp->ndev.dev;
struct ncsi_rsp_gmcma_pkt *rsp;
struct sockaddr saddr;
int ret = -1;
int i;
rsp = (struct ncsi_rsp_gmcma_pkt *)skb_network_header(nr->rsp);
saddr.sa_family = ndev->type;
ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
netdev_info(ndev, "NCSI: Received %d provisioned MAC addresses\n",
rsp->address_count);
for (i = 0; i < rsp->address_count; i++) {
netdev_info(ndev, "NCSI: MAC address %d: %02x:%02x:%02x:%02x:%02x:%02x\n",
i, rsp->addresses[i][0], rsp->addresses[i][1],
rsp->addresses[i][2], rsp->addresses[i][3],
rsp->addresses[i][4], rsp->addresses[i][5]);
}
for (i = 0; i < rsp->address_count; i++) {
memcpy(saddr.sa_data, &rsp->addresses[i], ETH_ALEN);
ret = ndev->netdev_ops->ndo_set_mac_address(ndev, &saddr);
if (ret < 0) {
netdev_warn(ndev, "NCSI: Unable to assign %pM to device\n",
saddr.sa_data);
continue;
}
netdev_warn(ndev, "NCSI: Set MAC address to %pM\n", saddr.sa_data);
break;
}
ndp->gma_flag = ret == 0;
return ret;
}
static struct ncsi_rsp_handler { static struct ncsi_rsp_handler {
unsigned char type; unsigned char type;
int payload; int payload;
...@@ -1105,7 +1165,8 @@ static struct ncsi_rsp_handler { ...@@ -1105,7 +1165,8 @@ static struct ncsi_rsp_handler {
{ NCSI_PKT_RSP_PLDM, -1, ncsi_rsp_handler_pldm }, { NCSI_PKT_RSP_PLDM, -1, ncsi_rsp_handler_pldm },
{ NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid }, { NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid },
{ NCSI_PKT_RSP_QPNPR, -1, ncsi_rsp_handler_pldm }, { NCSI_PKT_RSP_QPNPR, -1, ncsi_rsp_handler_pldm },
{ NCSI_PKT_RSP_SNPR, -1, ncsi_rsp_handler_pldm } { NCSI_PKT_RSP_SNPR, -1, ncsi_rsp_handler_pldm },
{ NCSI_PKT_RSP_GMCMA, -1, ncsi_rsp_handler_gmcma },
}; };
int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev, int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment