Skip to content

Commit

Permalink
net/ncsi: Add NCSI Broadcom OEM command
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Vijay Khemka authored and David S. Miller committed Oct 18, 2018
1 parent 1010c17 commit cb10c7c
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 2 deletions.
6 changes: 6 additions & 0 deletions net/ncsi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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.
9 changes: 9 additions & 0 deletions net/ncsi/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 */
Expand Down
82 changes: 82 additions & 0 deletions net/ncsi/ncsi-manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down
8 changes: 8 additions & 0 deletions net/ncsi/ncsi-pkt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
44 changes: 42 additions & 2 deletions net/ncsi/ncsi-rsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down

0 comments on commit cb10c7c

Please sign in to comment.