forked from mirrors/linux
		
	net/ncsi: Add NCSI Broadcom OEM command
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>
This commit is contained in:
		
							parent
							
								
									1010c17ec5
								
							
						
					
					
						commit
						cb10c7c0df
					
				
					 5 changed files with 147 additions and 2 deletions
				
			
		| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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   */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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   */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue