@@ -109,6 +109,55 @@ static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
return rc;
}
+static int efx_devlink_port_addr_set(struct devlink_port *port,
+ const u8 *hw_addr, int hw_addr_len,
+ struct netlink_ext_ack *extack)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_CLIENT_MAC_ADDRESSES_IN_LEN(1));
+ struct efx_devlink *devlink = devlink_priv(port->devlink);
+ struct mae_mport_desc *mport_desc;
+ efx_qword_t pciefn;
+ u32 client_id;
+ int rc;
+
+ mport_desc = container_of(port, struct mae_mport_desc, dl_port);
+
+ if (!ef100_mport_is_vf(mport_desc)) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "port mac change not allowed (mport: %u)",
+ mport_desc->mport_id);
+ return -EPERM;
+ }
+
+ EFX_POPULATE_QWORD_3(pciefn,
+ PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
+ PCIE_FUNCTION_VF, mport_desc->vf_idx,
+ PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
+
+ rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
+ if (rc) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "No internal client_ID for port (mport: %u)",
+ mport_desc->mport_id);
+ return rc;
+ }
+
+ MCDI_SET_DWORD(inbuf, SET_CLIENT_MAC_ADDRESSES_IN_CLIENT_HANDLE,
+ client_id);
+
+ ether_addr_copy(MCDI_PTR(inbuf, SET_CLIENT_MAC_ADDRESSES_IN_MAC_ADDRS),
+ hw_addr);
+
+ rc = efx_mcdi_rpc(devlink->efx, MC_CMD_SET_CLIENT_MAC_ADDRESSES, inbuf,
+ sizeof(inbuf), NULL, 0, NULL);
+ if (rc)
+ NL_SET_ERR_MSG_FMT(extack,
+ "sfc MC_CMD_SET_CLIENT_MAC_ADDRESSES mcdi error (mport: %u)",
+ mport_desc->mport_id);
+
+ return rc;
+}
+
#endif
static int efx_devlink_info_nvram_partition(struct efx_nic *efx,
@@ -569,6 +618,7 @@ static const struct devlink_ops sfc_devlink_ops = {
.info_get = efx_devlink_info_get,
#ifdef CONFIG_SFC_SRIOV
.port_function_hw_addr_get = efx_devlink_port_addr_get,
+ .port_function_hw_addr_set = efx_devlink_port_addr_set,
#endif
};