Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: David S. Miller <davem@davemloft.net>

+98 -29
+5 -2
net/ncsi/internal.h
··· 105 105 106 106 107 107 struct ncsi_channel_version { 108 - u32 version; /* Supported BCD encoded NCSI version */ 109 - u32 alpha2; /* Supported BCD encoded NCSI version */ 108 + u8 major; /* NCSI version major */ 109 + u8 minor; /* NCSI version minor */ 110 + u8 update; /* NCSI version update */ 111 + char alpha1; /* NCSI version alpha1 */ 112 + char alpha2; /* NCSI version alpha2 */ 110 113 u8 fw_name[12]; /* Firmware name string */ 111 114 u32 fw_version; /* Firmware version */ 112 115 u16 pci_ids[4]; /* PCI identification */
+2 -1
net/ncsi/ncsi-cmd.c
··· 270 270 { NCSI_PKT_CMD_GPS, 0, ncsi_cmd_handler_default }, 271 271 { NCSI_PKT_CMD_OEM, -1, ncsi_cmd_handler_oem }, 272 272 { NCSI_PKT_CMD_PLDM, 0, NULL }, 273 - { NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default } 273 + { NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default }, 274 + { NCSI_PKT_CMD_GMCMA, 0, ncsi_cmd_handler_default } 274 275 }; 275 276 276 277 static struct ncsi_request *ncsi_alloc_command(struct ncsi_cmd_arg *nca)
+10 -19
net/ncsi/ncsi-manage.c
··· 689 689 return 0; 690 690 } 691 691 692 - #if IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY) 693 - 694 692 static int ncsi_oem_keep_phy_intel(struct ncsi_cmd_arg *nca) 695 693 { 696 694 unsigned char data[NCSI_OEM_INTEL_CMD_KEEP_PHY_LEN]; ··· 713 715 nca->type); 714 716 return ret; 715 717 } 716 - 717 - #endif 718 - 719 - #if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) 720 718 721 719 /* NCSI OEM Command APIs */ 722 720 static int ncsi_oem_gma_handler_bcm(struct ncsi_cmd_arg *nca) ··· 849 855 /* Get Mac address from NCSI device */ 850 856 return nch->handler(nca); 851 857 } 852 - 853 - #endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */ 854 858 855 859 /* Determine if a given channel from the channel_queue should be used for Tx */ 856 860 static bool ncsi_channel_is_tx(struct ncsi_dev_priv *ndp, ··· 1031 1039 goto error; 1032 1040 } 1033 1041 1034 - nd->state = ncsi_dev_state_config_oem_gma; 1042 + nd->state = IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) 1043 + ? ncsi_dev_state_config_oem_gma 1044 + : ncsi_dev_state_config_clear_vids; 1035 1045 break; 1036 1046 case ncsi_dev_state_config_oem_gma: 1037 1047 nd->state = ncsi_dev_state_config_clear_vids; 1038 - ret = -1; 1039 1048 1040 - #if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) 1041 - nca.type = NCSI_PKT_CMD_OEM; 1042 1049 nca.package = np->id; 1043 1050 nca.channel = nc->id; 1044 1051 ndp->pending_req_num = 1; 1045 - ret = ncsi_gma_handler(&nca, nc->version.mf_id); 1046 - #endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */ 1047 - 1052 + if (nc->version.major >= 1 && nc->version.minor >= 2) { 1053 + nca.type = NCSI_PKT_CMD_GMCMA; 1054 + ret = ncsi_xmit_cmd(&nca); 1055 + } else { 1056 + nca.type = NCSI_PKT_CMD_OEM; 1057 + ret = ncsi_gma_handler(&nca, nc->version.mf_id); 1058 + } 1048 1059 if (ret < 0) 1049 1060 schedule_work(&ndp->work); 1050 1061 ··· 1399 1404 1400 1405 schedule_work(&ndp->work); 1401 1406 break; 1402 - #if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) 1403 1407 case ncsi_dev_state_probe_mlx_gma: 1404 1408 ndp->pending_req_num = 1; 1405 1409 ··· 1423 1429 1424 1430 nd->state = ncsi_dev_state_probe_cis; 1425 1431 break; 1426 - #endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */ 1427 1432 case ncsi_dev_state_probe_cis: 1428 1433 ndp->pending_req_num = NCSI_RESERVED_CHANNEL; 1429 1434 ··· 1440 1447 if (IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY)) 1441 1448 nd->state = ncsi_dev_state_probe_keep_phy; 1442 1449 break; 1443 - #if IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY) 1444 1450 case ncsi_dev_state_probe_keep_phy: 1445 1451 ndp->pending_req_num = 1; 1446 1452 ··· 1452 1460 1453 1461 nd->state = ncsi_dev_state_probe_gvi; 1454 1462 break; 1455 - #endif /* CONFIG_NCSI_OEM_CMD_KEEP_PHY */ 1456 1463 case ncsi_dev_state_probe_gvi: 1457 1464 case ncsi_dev_state_probe_gc: 1458 1465 case ncsi_dev_state_probe_gls:
+2 -2
net/ncsi/ncsi-netlink.c
··· 71 71 if (nc == nc->package->preferred_channel) 72 72 nla_put_flag(skb, NCSI_CHANNEL_ATTR_FORCED); 73 73 74 - nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.version); 75 - nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MINOR, nc->version.alpha2); 74 + nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.major); 75 + nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MINOR, nc->version.minor); 76 76 nla_put_string(skb, NCSI_CHANNEL_ATTR_VERSION_STR, nc->version.fw_name); 77 77 78 78 vid_nest = nla_nest_start_noflag(skb, NCSI_CHANNEL_ATTR_VLAN_LIST);
+15 -2
net/ncsi/ncsi-pkt.h
··· 197 197 /* Get Version ID */ 198 198 struct ncsi_rsp_gvi_pkt { 199 199 struct ncsi_rsp_pkt_hdr rsp; /* Response header */ 200 - __be32 ncsi_version; /* NCSI version */ 200 + unsigned char major; /* NCSI version major */ 201 + unsigned char minor; /* NCSI version minor */ 202 + unsigned char update; /* NCSI version update */ 203 + unsigned char alpha1; /* NCSI version alpha1 */ 201 204 unsigned char reserved[3]; /* Reserved */ 202 - unsigned char alpha2; /* NCSI version */ 205 + unsigned char alpha2; /* NCSI version alpha2 */ 203 206 unsigned char fw_name[12]; /* f/w name string */ 204 207 __be32 fw_version; /* f/w version */ 205 208 __be16 pci_ids[4]; /* PCI IDs */ ··· 338 335 __be32 checksum; 339 336 }; 340 337 338 + /* Get MC MAC Address */ 339 + struct ncsi_rsp_gmcma_pkt { 340 + struct ncsi_rsp_pkt_hdr rsp; 341 + unsigned char address_count; 342 + unsigned char reserved[3]; 343 + unsigned char addresses[][ETH_ALEN]; 344 + }; 345 + 341 346 /* AEN: Link State Change */ 342 347 struct ncsi_aen_lsc_pkt { 343 348 struct ncsi_aen_pkt_hdr aen; /* AEN header */ ··· 406 395 #define NCSI_PKT_CMD_GPUUID 0x52 /* Get package UUID */ 407 396 #define NCSI_PKT_CMD_QPNPR 0x56 /* Query Pending NC PLDM request */ 408 397 #define NCSI_PKT_CMD_SNPR 0x57 /* Send NC PLDM Reply */ 398 + #define NCSI_PKT_CMD_GMCMA 0x58 /* Get MC MAC Address */ 409 399 410 400 411 401 /* NCSI packet responses */ ··· 442 430 #define NCSI_PKT_RSP_GPUUID (NCSI_PKT_CMD_GPUUID + 0x80) 443 431 #define NCSI_PKT_RSP_QPNPR (NCSI_PKT_CMD_QPNPR + 0x80) 444 432 #define NCSI_PKT_RSP_SNPR (NCSI_PKT_CMD_SNPR + 0x80) 433 + #define NCSI_PKT_RSP_GMCMA (NCSI_PKT_CMD_GMCMA + 0x80) 445 434 446 435 /* NCSI response code/reason */ 447 436 #define NCSI_PKT_RSP_C_COMPLETED 0x0000 /* Command Completed */
+64 -3
net/ncsi/ncsi-rsp.c
··· 19 19 #include "ncsi-pkt.h" 20 20 #include "ncsi-netlink.h" 21 21 22 + /* Nibbles within [0xA, 0xF] add zero "0" to the returned value. 23 + * Optional fields (encoded as 0xFF) will default to zero. 24 + */ 25 + static u8 decode_bcd_u8(u8 x) 26 + { 27 + int lo = x & 0xF; 28 + int hi = x >> 4; 29 + 30 + lo = lo < 0xA ? lo : 0; 31 + hi = hi < 0xA ? hi : 0; 32 + return lo + hi * 10; 33 + } 34 + 22 35 static int ncsi_validate_rsp_pkt(struct ncsi_request *nr, 23 36 unsigned short payload) 24 37 { ··· 768 755 if (!nc) 769 756 return -ENODEV; 770 757 771 - /* Update to channel's version info */ 758 + /* Update channel's version info 759 + * 760 + * Major, minor, and update fields are supposed to be 761 + * unsigned integers encoded as packed BCD. 762 + * 763 + * Alpha1 and alpha2 are ISO/IEC 8859-1 characters. 764 + */ 772 765 ncv = &nc->version; 773 - ncv->version = ntohl(rsp->ncsi_version); 766 + ncv->major = decode_bcd_u8(rsp->major); 767 + ncv->minor = decode_bcd_u8(rsp->minor); 768 + ncv->update = decode_bcd_u8(rsp->update); 769 + ncv->alpha1 = rsp->alpha1; 774 770 ncv->alpha2 = rsp->alpha2; 775 771 memcpy(ncv->fw_name, rsp->fw_name, 12); 776 772 ncv->fw_version = ntohl(rsp->fw_version); ··· 1091 1069 return ret; 1092 1070 } 1093 1071 1072 + static int ncsi_rsp_handler_gmcma(struct ncsi_request *nr) 1073 + { 1074 + struct ncsi_dev_priv *ndp = nr->ndp; 1075 + struct net_device *ndev = ndp->ndev.dev; 1076 + struct ncsi_rsp_gmcma_pkt *rsp; 1077 + struct sockaddr saddr; 1078 + int ret = -1; 1079 + int i; 1080 + 1081 + rsp = (struct ncsi_rsp_gmcma_pkt *)skb_network_header(nr->rsp); 1082 + saddr.sa_family = ndev->type; 1083 + ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; 1084 + 1085 + netdev_info(ndev, "NCSI: Received %d provisioned MAC addresses\n", 1086 + rsp->address_count); 1087 + for (i = 0; i < rsp->address_count; i++) { 1088 + netdev_info(ndev, "NCSI: MAC address %d: %02x:%02x:%02x:%02x:%02x:%02x\n", 1089 + i, rsp->addresses[i][0], rsp->addresses[i][1], 1090 + rsp->addresses[i][2], rsp->addresses[i][3], 1091 + rsp->addresses[i][4], rsp->addresses[i][5]); 1092 + } 1093 + 1094 + for (i = 0; i < rsp->address_count; i++) { 1095 + memcpy(saddr.sa_data, &rsp->addresses[i], ETH_ALEN); 1096 + ret = ndev->netdev_ops->ndo_set_mac_address(ndev, &saddr); 1097 + if (ret < 0) { 1098 + netdev_warn(ndev, "NCSI: Unable to assign %pM to device\n", 1099 + saddr.sa_data); 1100 + continue; 1101 + } 1102 + netdev_warn(ndev, "NCSI: Set MAC address to %pM\n", saddr.sa_data); 1103 + break; 1104 + } 1105 + 1106 + ndp->gma_flag = ret == 0; 1107 + return ret; 1108 + } 1109 + 1094 1110 static struct ncsi_rsp_handler { 1095 1111 unsigned char type; 1096 1112 int payload; ··· 1165 1105 { NCSI_PKT_RSP_PLDM, -1, ncsi_rsp_handler_pldm }, 1166 1106 { NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid }, 1167 1107 { NCSI_PKT_RSP_QPNPR, -1, ncsi_rsp_handler_pldm }, 1168 - { NCSI_PKT_RSP_SNPR, -1, ncsi_rsp_handler_pldm } 1108 + { NCSI_PKT_RSP_SNPR, -1, ncsi_rsp_handler_pldm }, 1109 + { NCSI_PKT_RSP_GMCMA, -1, ncsi_rsp_handler_gmcma }, 1169 1110 }; 1170 1111 1171 1112 int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,