sfc_ef100: implement MCDI transport
Signed-off-by: Edward Cree <ecree@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									35a36af88f
								
							
						
					
					
						commit
						2200e6d92e
					
				| @ -25,11 +25,23 @@ | ||||
| #include "ef100_netdev.h" | ||||
| 
 | ||||
| #define EF100_MAX_VIS 4096 | ||||
| #define EF100_NUM_MCDI_BUFFERS	1 | ||||
| #define MCDI_BUF_LEN (8 + MCDI_CTL_SDU_LEN_MAX) | ||||
| 
 | ||||
| #define EF100_RESET_PORT ((ETH_RESET_MAC | ETH_RESET_PHY) << ETH_RESET_SHARED_SHIFT) | ||||
| 
 | ||||
| /*	MCDI
 | ||||
|  */ | ||||
| static u8 *ef100_mcdi_buf(struct efx_nic *efx, u8 bufid, dma_addr_t *dma_addr) | ||||
| { | ||||
| 	struct ef100_nic_data *nic_data = efx->nic_data; | ||||
| 
 | ||||
| 	if (dma_addr) | ||||
| 		*dma_addr = nic_data->mcdi_buf.dma_addr + | ||||
| 			    bufid * ALIGN(MCDI_BUF_LEN, 256); | ||||
| 	return nic_data->mcdi_buf.addr + bufid * ALIGN(MCDI_BUF_LEN, 256); | ||||
| } | ||||
| 
 | ||||
| static int ef100_get_warm_boot_count(struct efx_nic *efx) | ||||
| { | ||||
| 	efx_dword_t reg; | ||||
| @ -46,6 +58,72 @@ static int ef100_get_warm_boot_count(struct efx_nic *efx) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void ef100_mcdi_request(struct efx_nic *efx, | ||||
| 			       const efx_dword_t *hdr, size_t hdr_len, | ||||
| 			       const efx_dword_t *sdu, size_t sdu_len) | ||||
| { | ||||
| 	dma_addr_t dma_addr; | ||||
| 	u8 *pdu = ef100_mcdi_buf(efx, 0, &dma_addr); | ||||
| 
 | ||||
| 	memcpy(pdu, hdr, hdr_len); | ||||
| 	memcpy(pdu + hdr_len, sdu, sdu_len); | ||||
| 	wmb(); | ||||
| 
 | ||||
| 	/* The hardware provides 'low' and 'high' (doorbell) registers
 | ||||
| 	 * for passing the 64-bit address of an MCDI request to | ||||
| 	 * firmware.  However the dwords are swapped by firmware.  The | ||||
| 	 * least significant bits of the doorbell are then 0 for all | ||||
| 	 * MCDI requests due to alignment. | ||||
| 	 */ | ||||
| 	_efx_writed(efx, cpu_to_le32((u64)dma_addr >> 32),  efx_reg(efx, ER_GZ_MC_DB_LWRD)); | ||||
| 	_efx_writed(efx, cpu_to_le32((u32)dma_addr),  efx_reg(efx, ER_GZ_MC_DB_HWRD)); | ||||
| } | ||||
| 
 | ||||
| static bool ef100_mcdi_poll_response(struct efx_nic *efx) | ||||
| { | ||||
| 	const efx_dword_t hdr = | ||||
| 		*(const efx_dword_t *)(ef100_mcdi_buf(efx, 0, NULL)); | ||||
| 
 | ||||
| 	rmb(); | ||||
| 	return EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE); | ||||
| } | ||||
| 
 | ||||
| static void ef100_mcdi_read_response(struct efx_nic *efx, | ||||
| 				     efx_dword_t *outbuf, size_t offset, | ||||
| 				     size_t outlen) | ||||
| { | ||||
| 	const u8 *pdu = ef100_mcdi_buf(efx, 0, NULL); | ||||
| 
 | ||||
| 	memcpy(outbuf, pdu + offset, outlen); | ||||
| } | ||||
| 
 | ||||
| static int ef100_mcdi_poll_reboot(struct efx_nic *efx) | ||||
| { | ||||
| 	struct ef100_nic_data *nic_data = efx->nic_data; | ||||
| 	int rc; | ||||
| 
 | ||||
| 	rc = ef100_get_warm_boot_count(efx); | ||||
| 	if (rc < 0) { | ||||
| 		/* The firmware is presumably in the process of
 | ||||
| 		 * rebooting.  However, we are supposed to report each | ||||
| 		 * reboot just once, so we must only do that once we | ||||
| 		 * can read and store the updated warm boot count. | ||||
| 		 */ | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (rc == nic_data->warm_boot_count) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	nic_data->warm_boot_count = rc; | ||||
| 
 | ||||
| 	return -EIO; | ||||
| } | ||||
| 
 | ||||
| static void ef100_mcdi_reboot_detected(struct efx_nic *efx) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| /*	Event handling
 | ||||
|  */ | ||||
| static int ef100_ev_probe(struct efx_channel *channel) | ||||
| @ -139,6 +217,11 @@ const struct efx_nic_type ef100_pf_nic_type = { | ||||
| 	.is_vf = false, | ||||
| 	.probe = ef100_probe_pf, | ||||
| 	.mcdi_max_ver = 2, | ||||
| 	.mcdi_request = ef100_mcdi_request, | ||||
| 	.mcdi_poll_response = ef100_mcdi_poll_response, | ||||
| 	.mcdi_read_response = ef100_mcdi_read_response, | ||||
| 	.mcdi_poll_reboot = ef100_mcdi_poll_reboot, | ||||
| 	.mcdi_reboot_detected = ef100_mcdi_reboot_detected, | ||||
| 	.irq_enable_master = efx_port_dummy_op_void, | ||||
| 	.irq_disable_non_ev = efx_port_dummy_op_void, | ||||
| 	.push_irq_moderation = efx_channel_dummy_op_void, | ||||
| @ -178,6 +261,15 @@ static int ef100_probe_main(struct efx_nic *efx) | ||||
| 	net_dev->features |= efx->type->offload_features; | ||||
| 	net_dev->hw_features |= efx->type->offload_features; | ||||
| 
 | ||||
| 	/* we assume later that we can copy from this buffer in dwords */ | ||||
| 	BUILD_BUG_ON(MCDI_CTL_SDU_LEN_MAX_V2 % 4); | ||||
| 
 | ||||
| 	/* MCDI buffers must be 256 byte aligned. */ | ||||
| 	rc = efx_nic_alloc_buffer(efx, &nic_data->mcdi_buf, MCDI_BUF_LEN, | ||||
| 				  GFP_KERNEL); | ||||
| 	if (rc) | ||||
| 		goto fail; | ||||
| 
 | ||||
| 	/* Get the MC's warm boot count.  In case it's rebooting right
 | ||||
| 	 * now, be prepared to retry. | ||||
| 	 */ | ||||
| @ -201,6 +293,16 @@ static int ef100_probe_main(struct efx_nic *efx) | ||||
| 
 | ||||
| 	/* Post-IO section. */ | ||||
| 
 | ||||
| 	rc = efx_mcdi_init(efx); | ||||
| 	if (!rc && efx->mcdi->fn_flags & | ||||
| 		   (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_NO_ACTIVE_PORT)) { | ||||
| 		netif_info(efx, probe, efx->net_dev, | ||||
| 			   "No network port on this PCI function"); | ||||
| 		rc = -ENODEV; | ||||
| 	} | ||||
| 	if (rc) | ||||
| 		goto fail; | ||||
| 
 | ||||
| 	efx->max_vis = EF100_MAX_VIS; | ||||
| 
 | ||||
| 	rc = ef100_phy_probe(efx); | ||||
| @ -233,6 +335,10 @@ void ef100_remove(struct efx_nic *efx) | ||||
| 	efx_fini_channels(efx); | ||||
| 	kfree(efx->phy_data); | ||||
| 	efx->phy_data = NULL; | ||||
| 	efx_mcdi_detach(efx); | ||||
| 	efx_mcdi_fini(efx); | ||||
| 	if (nic_data) | ||||
| 		efx_nic_free_buffer(efx, &nic_data->mcdi_buf); | ||||
| 	kfree(nic_data); | ||||
| 	efx->nic_data = NULL; | ||||
| } | ||||
|  | ||||
| @ -19,6 +19,7 @@ void ef100_remove(struct efx_nic *efx); | ||||
| 
 | ||||
| struct ef100_nic_data { | ||||
| 	struct efx_nic *efx; | ||||
| 	struct efx_buffer mcdi_buf; | ||||
| 	u16 warm_boot_count; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user