Re: [PATCHv4 3/4] crypto: inside-secure - add support for PCI based FPGA development board

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Pascal,

On Tue, Aug 06, 2019 at 09:46:25AM +0200, Pascal van Leeuwen wrote:
> This patch adds support for a PCIE development board with FPGA from Xilinx,
> to facilitate pre-silicon driver development by both Inside Secure and its
> IP customers. Since Inside Secure neither produces nor has access to actual
> silicon, this is required functionality to allow us to contribute.
> 
> Signed-off-by: Pascal van Leeuwen <pvanleeuwen@xxxxxxxxxxxxxx>

Acked-by: Antoine Tenart <antoine.tenart@xxxxxxxxxxx>

Thanks!
Antoine

> ---
>  drivers/crypto/inside-secure/safexcel.c      | 543 +++++++++++++++++++--------
>  drivers/crypto/inside-secure/safexcel.h      |  30 +-
>  drivers/crypto/inside-secure/safexcel_ring.c |   3 +-
>  3 files changed, 407 insertions(+), 169 deletions(-)
> 
> diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c
> index a066152..aa8c1b3 100644
> --- a/drivers/crypto/inside-secure/safexcel.c
> +++ b/drivers/crypto/inside-secure/safexcel.c
> @@ -14,6 +14,7 @@
>  #include <linux/module.h>
>  #include <linux/of_platform.h>
>  #include <linux/of_irq.h>
> +#include <linux/pci.h>
>  #include <linux/platform_device.h>
>  #include <linux/workqueue.h>
> 
> @@ -32,16 +33,17 @@ static void eip197_trc_cache_init(struct safexcel_crypto_priv *priv)
>  	u32 val, htable_offset;
>  	int i, cs_rc_max, cs_ht_wc, cs_trc_rec_wc, cs_trc_lg_rec_wc;
> 
> -	if (priv->version == EIP197B) {
> -		cs_rc_max = EIP197B_CS_RC_MAX;
> -		cs_ht_wc = EIP197B_CS_HT_WC;
> -		cs_trc_rec_wc = EIP197B_CS_TRC_REC_WC;
> -		cs_trc_lg_rec_wc = EIP197B_CS_TRC_LG_REC_WC;
> -	} else {
> +	if (priv->version == EIP197D_MRVL) {
>  		cs_rc_max = EIP197D_CS_RC_MAX;
>  		cs_ht_wc = EIP197D_CS_HT_WC;
>  		cs_trc_rec_wc = EIP197D_CS_TRC_REC_WC;
>  		cs_trc_lg_rec_wc = EIP197D_CS_TRC_LG_REC_WC;
> +	} else {
> +		/* Default to minimum "safe" settings */
> +		cs_rc_max = EIP197B_CS_RC_MAX;
> +		cs_ht_wc = EIP197B_CS_HT_WC;
> +		cs_trc_rec_wc = EIP197B_CS_TRC_REC_WC;
> +		cs_trc_lg_rec_wc = EIP197B_CS_TRC_LG_REC_WC;
>  	}
> 
>  	/* Enable the record cache memory access */
> @@ -145,23 +147,19 @@ static int eip197_load_firmwares(struct safexcel_crypto_priv *priv)
>  	int i, j, ret = 0, pe;
>  	u32 val;
> 
> -	switch (priv->version) {
> -	case EIP197B:
> -		dir = "eip197b";
> -		break;
> -	case EIP197D:
> +	if (priv->version == EIP197D_MRVL)
>  		dir = "eip197d";
> -		break;
> -	default:
> -		/* No firmware is required */
> -		return 0;
> -	}
> +	else if (priv->version == EIP197D_MRVL ||
> +		 priv->version == EIP197_DEVBRD)
> +		dir = "eip197b";
> +	else
> +		return -ENODEV;
> 
>  	for (i = 0; i < FW_NB; i++) {
>  		snprintf(fw_path, 31, "inside-secure/%s/%s", dir, fw_name[i]);
>  		ret = request_firmware(&fw[i], fw_path, priv->dev);
>  		if (ret) {
> -			if (priv->version != EIP197B)
> +			if (priv->version != EIP197B_MRVL)
>  				goto release_fw;
> 
>  			/* Fallback to the old firmware location for the
> @@ -294,6 +292,9 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv)
>  	u32 version, val;
>  	int i, ret, pe;
> 
> +	dev_dbg(priv->dev, "HW init: using %d pipe(s) and %d ring(s)\n",
> +		priv->config.pes, priv->config.rings);
> +
>  	/* Determine endianess and configure byte swap */
>  	version = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_VERSION);
>  	val = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL);
> @@ -303,8 +304,11 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv)
>  	else if (((version >> 16) & 0xffff) == EIP197_HIA_VERSION_LE)
>  		val |= (EIP197_MST_CTRL_NO_BYTE_SWAP >> 24);
> 
> -	/* For EIP197 set maximum number of TX commands to 2^5 = 32 */
> -	if (priv->version == EIP197B || priv->version == EIP197D)
> +	/*
> +	 * For EIP197's only set maximum number of TX commands to 2^5 = 32
> +	 * Skip for the EIP97 as it does not have this field.
> +	 */
> +	if (priv->version != EIP97IES_MRVL)
>  		val |= EIP197_MST_CTRL_TX_MAX_CMD(5);
> 
>  	writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL);
> @@ -330,11 +334,10 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv)
>  		writel(EIP197_DxE_THR_CTRL_RESET_PE,
>  		       EIP197_HIA_DFE_THR(priv) + EIP197_HIA_DFE_THR_CTRL(pe));
> 
> -		if (priv->version == EIP197B || priv->version == EIP197D) {
> -			/* Reset HIA input interface arbiter */
> +		if (priv->version != EIP97IES_MRVL)
> +			/* Reset HIA input interface arbiter (EIP197 only) */
>  			writel(EIP197_HIA_RA_PE_CTRL_RESET,
>  			       EIP197_HIA_AIC(priv) + EIP197_HIA_RA_PE_CTRL(pe));
> -		}
> 
>  		/* DMA transfer size to use */
>  		val = EIP197_HIA_DFE_CFG_DIS_DEBUG;
> @@ -357,12 +360,11 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv)
>  		       EIP197_PE_IN_xBUF_THRES_MAX(7),
>  		       EIP197_PE(priv) + EIP197_PE_IN_TBUF_THRES(pe));
> 
> -		if (priv->version == EIP197B || priv->version == EIP197D) {
> +		if (priv->version != EIP97IES_MRVL)
>  			/* enable HIA input interface arbiter and rings */
>  			writel(EIP197_HIA_RA_PE_CTRL_EN |
>  			       GENMASK(priv->config.rings - 1, 0),
>  			       EIP197_HIA_AIC(priv) + EIP197_HIA_RA_PE_CTRL(pe));
> -		}
> 
>  		/* Data Store Engine configuration */
> 
> @@ -381,10 +383,10 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv)
>  		       EIP197_HIA_DxE_CFG_MAX_DATA_SIZE(8);
>  		val |= EIP197_HIA_DxE_CFG_DATA_CACHE_CTRL(WR_CACHE_3BITS);
>  		val |= EIP197_HIA_DSE_CFG_ALWAYS_BUFFERABLE;
> -		/* FIXME: instability issues can occur for EIP97 but disabling it impact
> -		 * performances.
> +		/* FIXME: instability issues can occur for EIP97 but disabling
> +		 * it impacts performance.
>  		 */
> -		if (priv->version == EIP197B || priv->version == EIP197D)
> +		if (priv->version != EIP97IES_MRVL)
>  			val |= EIP197_HIA_DSE_CFG_EN_SINGLE_WR;
>  		writel(val, EIP197_HIA_DSE(priv) + EIP197_HIA_DSE_CFG(pe));
> 
> @@ -479,7 +481,7 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv)
>  	/* Clear any HIA interrupt */
>  	writel(GENMASK(30, 20), EIP197_HIA_AIC_G(priv) + EIP197_HIA_AIC_G_ACK);
> 
> -	if (priv->version == EIP197B || priv->version == EIP197D) {
> +	if (priv->version != EIP97IES_MRVL) {
>  		eip197_trc_cache_init(priv);
> 
>  		ret = eip197_load_firmwares(priv);
> @@ -711,7 +713,8 @@ static inline void safexcel_handle_result_descriptor(struct safexcel_crypto_priv
>  		ndesc = ctx->handle_result(priv, ring, req,
>  					   &should_complete, &ret);
>  		if (ndesc < 0) {
> -			dev_err(priv->dev, "failed to handle result (%d)", ndesc);
> +			dev_err(priv->dev, "failed to handle result (%d)\n",
> +				ndesc);
>  			goto acknowledge;
>  		}
> 
> @@ -783,7 +786,7 @@ static irqreturn_t safexcel_irq_ring(int irq, void *data)
>  			 * reinitialized. This should not happen under
>  			 * normal circumstances.
>  			 */
> -			dev_err(priv->dev, "RDR: fatal error.");
> +			dev_err(priv->dev, "RDR: fatal error.\n");
>  		} else if (likely(stat & EIP197_xDR_THRESH)) {
>  			rc = IRQ_WAKE_THREAD;
>  		}
> @@ -813,23 +816,45 @@ static irqreturn_t safexcel_irq_ring_thread(int irq, void *data)
>  	return IRQ_HANDLED;
>  }
> 
> -static int safexcel_request_ring_irq(struct platform_device *pdev, const char *name,
> +static int safexcel_request_ring_irq(void *pdev, int irqid,
> +				     int is_pci_dev,
>  				     irq_handler_t handler,
>  				     irq_handler_t threaded_handler,
>  				     struct safexcel_ring_irq_data *ring_irq_priv)
>  {
> -	int ret, irq = platform_get_irq_byname(pdev, name);
> +	int ret, irq;
> +	struct device *dev;
> +
> +	if (IS_ENABLED(CONFIG_PCI) && is_pci_dev) {
> +		struct pci_dev *pci_pdev = pdev;
> 
> -	if (irq < 0) {
> -		dev_err(&pdev->dev, "unable to get IRQ '%s'\n", name);
> -		return irq;
> +		dev = &pci_pdev->dev;
> +		irq = pci_irq_vector(pci_pdev, irqid);
> +		if (irq < 0) {
> +			dev_err(dev, "unable to get device MSI IRQ %d (err %d)\n",
> +				irqid, irq);
> +			return irq;
> +		}
> +	} else if (IS_ENABLED(CONFIG_OF)) {
> +		struct platform_device *plf_pdev = pdev;
> +		char irq_name[6] = {0}; /* "ringX\0" */
> +
> +		snprintf(irq_name, 6, "ring%d", irqid);
> +		dev = &plf_pdev->dev;
> +		irq = platform_get_irq_byname(plf_pdev, irq_name);
> +
> +		if (irq < 0) {
> +			dev_err(dev, "unable to get IRQ '%s' (err %d)\n",
> +				irq_name, irq);
> +			return irq;
> +		}
>  	}
> 
> -	ret = devm_request_threaded_irq(&pdev->dev, irq, handler,
> +	ret = devm_request_threaded_irq(dev, irq, handler,
>  					threaded_handler, IRQF_ONESHOT,
> -					dev_name(&pdev->dev), ring_irq_priv);
> +					dev_name(dev), ring_irq_priv);
>  	if (ret) {
> -		dev_err(&pdev->dev, "unable to request IRQ %d\n", irq);
> +		dev_err(dev, "unable to request IRQ %d\n", irq);
>  		return ret;
>  	}
> 
> @@ -916,22 +941,20 @@ static void safexcel_configure(struct safexcel_crypto_priv *priv)
>  	val = readl(EIP197_HIA_AIC_G(priv) + EIP197_HIA_OPTIONS);
> 
>  	/* Read number of PEs from the engine */
> -	switch (priv->version) {
> -	case EIP197B:
> -	case EIP197D:
> -		mask = EIP197_N_PES_MASK;
> -		break;
> -	default:
> +	if (priv->version == EIP97IES_MRVL)
> +		/* Narrow field width for EIP97 type engine */
>  		mask = EIP97_N_PES_MASK;
> -	}
> +	else
> +		/* Wider field width for all EIP197 type engines */
> +		mask = EIP197_N_PES_MASK;
> +
>  	priv->config.pes = (val >> EIP197_N_PES_OFFSET) & mask;
> 
> +	priv->config.rings = min_t(u32, val & GENMASK(3, 0), max_rings);
> +
>  	val = (val & GENMASK(27, 25)) >> 25;
>  	mask = BIT(val) - 1;
> 
> -	val = readl(EIP197_HIA_AIC_G(priv) + EIP197_HIA_OPTIONS);
> -	priv->config.rings = min_t(u32, val & GENMASK(3, 0), max_rings);
> -
>  	priv->config.cd_size = (sizeof(struct safexcel_command_desc) / sizeof(u32));
>  	priv->config.cd_offset = (priv->config.cd_size + mask) & ~mask;
> 
> @@ -943,21 +966,7 @@ static void safexcel_init_register_offsets(struct safexcel_crypto_priv *priv)
>  {
>  	struct safexcel_register_offsets *offsets = &priv->offsets;
> 
> -	switch (priv->version) {
> -	case EIP197B:
> -	case EIP197D:
> -		offsets->hia_aic	= EIP197_HIA_AIC_BASE;
> -		offsets->hia_aic_g	= EIP197_HIA_AIC_G_BASE;
> -		offsets->hia_aic_r	= EIP197_HIA_AIC_R_BASE;
> -		offsets->hia_aic_xdr	= EIP197_HIA_AIC_xDR_BASE;
> -		offsets->hia_dfe	= EIP197_HIA_DFE_BASE;
> -		offsets->hia_dfe_thr	= EIP197_HIA_DFE_THR_BASE;
> -		offsets->hia_dse	= EIP197_HIA_DSE_BASE;
> -		offsets->hia_dse_thr	= EIP197_HIA_DSE_THR_BASE;
> -		offsets->hia_gen_cfg	= EIP197_HIA_GEN_CFG_BASE;
> -		offsets->pe		= EIP197_PE_BASE;
> -		break;
> -	case EIP97IES:
> +	if (priv->version == EIP97IES_MRVL) {
>  		offsets->hia_aic	= EIP97_HIA_AIC_BASE;
>  		offsets->hia_aic_g	= EIP97_HIA_AIC_G_BASE;
>  		offsets->hia_aic_r	= EIP97_HIA_AIC_R_BASE;
> @@ -968,135 +977,119 @@ static void safexcel_init_register_offsets(struct safexcel_crypto_priv *priv)
>  		offsets->hia_dse_thr	= EIP97_HIA_DSE_THR_BASE;
>  		offsets->hia_gen_cfg	= EIP97_HIA_GEN_CFG_BASE;
>  		offsets->pe		= EIP97_PE_BASE;
> -		break;
> +	} else {
> +		offsets->hia_aic	= EIP197_HIA_AIC_BASE;
> +		offsets->hia_aic_g	= EIP197_HIA_AIC_G_BASE;
> +		offsets->hia_aic_r	= EIP197_HIA_AIC_R_BASE;
> +		offsets->hia_aic_xdr	= EIP197_HIA_AIC_xDR_BASE;
> +		offsets->hia_dfe	= EIP197_HIA_DFE_BASE;
> +		offsets->hia_dfe_thr	= EIP197_HIA_DFE_THR_BASE;
> +		offsets->hia_dse	= EIP197_HIA_DSE_BASE;
> +		offsets->hia_dse_thr	= EIP197_HIA_DSE_THR_BASE;
> +		offsets->hia_gen_cfg	= EIP197_HIA_GEN_CFG_BASE;
> +		offsets->pe		= EIP197_PE_BASE;
>  	}
>  }
> 
> -static int safexcel_probe(struct platform_device *pdev)
> +/*
> + * Generic part of probe routine, shared by platform and PCI driver
> + *
> + * Assumes IO resources have been mapped, private data mem has been allocated,
> + * clocks have been enabled, device pointer has been assigned etc.
> + *
> + */
> +static int safexcel_probe_generic(void *pdev,
> +				  struct safexcel_crypto_priv *priv,
> +				  int is_pci_dev)
>  {
> -	struct device *dev = &pdev->dev;
> -	struct resource *res;
> -	struct safexcel_crypto_priv *priv;
> +	struct device *dev = priv->dev;
>  	int i, ret;
> 
> -	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> -	if (!priv)
> +	priv->context_pool = dmam_pool_create("safexcel-context", dev,
> +					      sizeof(struct safexcel_context_record),
> +					      1, 0);
> +	if (!priv->context_pool)
>  		return -ENOMEM;
> 
> -	priv->dev = dev;
> -	priv->version = (enum safexcel_eip_version)of_device_get_match_data(dev);
> -
> -	if (priv->version == EIP197B || priv->version == EIP197D)
> -		priv->flags |= EIP197_TRC_CACHE;
> -
>  	safexcel_init_register_offsets(priv);
> 
> -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	priv->base = devm_ioremap_resource(dev, res);
> -	if (IS_ERR(priv->base)) {
> -		dev_err(dev, "failed to get resource\n");
> -		return PTR_ERR(priv->base);
> -	}
> +	if (priv->version != EIP97IES_MRVL)
> +		priv->flags |= EIP197_TRC_CACHE;
> 
> -	priv->clk = devm_clk_get(&pdev->dev, NULL);
> -	ret = PTR_ERR_OR_ZERO(priv->clk);
> -	/* The clock isn't mandatory */
> -	if  (ret != -ENOENT) {
> -		if (ret)
> -			return ret;
> +	safexcel_configure(priv);
> 
> -		ret = clk_prepare_enable(priv->clk);
> -		if (ret) {
> -			dev_err(dev, "unable to enable clk (%d)\n", ret);
> +	if (IS_ENABLED(CONFIG_PCI) && priv->version == EIP197_DEVBRD) {
> +		/*
> +		 * Request MSI vectors for global + 1 per ring -
> +		 * or just 1 for older dev images
> +		 */
> +		struct pci_dev *pci_pdev = pdev;
> +
> +		ret = pci_alloc_irq_vectors(pci_pdev,
> +					    priv->config.rings + 1,
> +					    priv->config.rings + 1,
> +					    PCI_IRQ_MSI | PCI_IRQ_MSIX);
> +		if (ret < 0) {
> +			dev_err(dev, "Failed to allocate PCI MSI interrupts\n");
>  			return ret;
>  		}
>  	}
> 
> -	priv->reg_clk = devm_clk_get(&pdev->dev, "reg");
> -	ret = PTR_ERR_OR_ZERO(priv->reg_clk);
> -	/* The clock isn't mandatory */
> -	if  (ret != -ENOENT) {
> -		if (ret)
> -			goto err_core_clk;
> -
> -		ret = clk_prepare_enable(priv->reg_clk);
> -		if (ret) {
> -			dev_err(dev, "unable to enable reg clk (%d)\n", ret);
> -			goto err_core_clk;
> -		}
> -	}
> -
> -	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
> -	if (ret)
> -		goto err_reg_clk;
> -
> -	priv->context_pool = dmam_pool_create("safexcel-context", dev,
> -					      sizeof(struct safexcel_context_record),
> -					      1, 0);
> -	if (!priv->context_pool) {
> -		ret = -ENOMEM;
> -		goto err_reg_clk;
> -	}
> -
> -	safexcel_configure(priv);
> -
> +	/* Register the ring IRQ handlers and configure the rings */
>  	priv->ring = devm_kcalloc(dev, priv->config.rings,
>  				  sizeof(*priv->ring),
>  				  GFP_KERNEL);
> -	if (!priv->ring) {
> -		ret = -ENOMEM;
> -		goto err_reg_clk;
> -	}
> +	if (!priv->ring)
> +		return -ENOMEM;
> 
>  	for (i = 0; i < priv->config.rings; i++) {
> -		char irq_name[6] = {0}; /* "ringX\0" */
> -		char wq_name[9] = {0}; /* "wq_ringX\0" */
> +		char wq_name[9] = {0};
>  		int irq;
>  		struct safexcel_ring_irq_data *ring_irq;
> 
>  		ret = safexcel_init_ring_descriptors(priv,
>  						     &priv->ring[i].cdr,
>  						     &priv->ring[i].rdr);
> -		if (ret)
> -			goto err_reg_clk;
> +		if (ret) {
> +			dev_err(dev, "Failed to initialize rings\n");
> +			return ret;
> +		}
> 
>  		priv->ring[i].rdr_req = devm_kcalloc(dev,
>  			EIP197_DEFAULT_RING_SIZE,
>  			sizeof(priv->ring[i].rdr_req),
>  			GFP_KERNEL);
> -		if (!priv->ring[i].rdr_req) {
> -			ret = -ENOMEM;
> -			goto err_reg_clk;
> -		}
> +		if (!priv->ring[i].rdr_req)
> +			return -ENOMEM;
> 
>  		ring_irq = devm_kzalloc(dev, sizeof(*ring_irq), GFP_KERNEL);
> -		if (!ring_irq) {
> -			ret = -ENOMEM;
> -			goto err_reg_clk;
> -		}
> +		if (!ring_irq)
> +			return -ENOMEM;
> 
>  		ring_irq->priv = priv;
>  		ring_irq->ring = i;
> 
> -		snprintf(irq_name, 6, "ring%d", i);
> -		irq = safexcel_request_ring_irq(pdev, irq_name, safexcel_irq_ring,
> +		irq = safexcel_request_ring_irq(pdev,
> +						EIP197_IRQ_NUMBER(i, is_pci_dev),
> +						is_pci_dev,
> +						safexcel_irq_ring,
>  						safexcel_irq_ring_thread,
>  						ring_irq);
>  		if (irq < 0) {
> -			ret = irq;
> -			goto err_reg_clk;
> +			dev_err(dev, "Failed to get IRQ ID for ring %d\n", i);
> +			return irq;
>  		}
> 
>  		priv->ring[i].work_data.priv = priv;
>  		priv->ring[i].work_data.ring = i;
> -		INIT_WORK(&priv->ring[i].work_data.work, safexcel_dequeue_work);
> +		INIT_WORK(&priv->ring[i].work_data.work,
> +			  safexcel_dequeue_work);
> 
>  		snprintf(wq_name, 9, "wq_ring%d", i);
> -		priv->ring[i].workqueue = create_singlethread_workqueue(wq_name);
> -		if (!priv->ring[i].workqueue) {
> -			ret = -ENOMEM;
> -			goto err_reg_clk;
> -		}
> +		priv->ring[i].workqueue =
> +			create_singlethread_workqueue(wq_name);
> +		if (!priv->ring[i].workqueue)
> +			return -ENOMEM;
> 
>  		priv->ring[i].requests = 0;
>  		priv->ring[i].busy = false;
> @@ -1108,28 +1101,21 @@ static int safexcel_probe(struct platform_device *pdev)
>  		spin_lock_init(&priv->ring[i].queue_lock);
>  	}
> 
> -	platform_set_drvdata(pdev, priv);
>  	atomic_set(&priv->ring_used, 0);
> 
>  	ret = safexcel_hw_init(priv);
>  	if (ret) {
> -		dev_err(dev, "EIP h/w init failed (%d)\n", ret);
> -		goto err_reg_clk;
> +		dev_err(dev, "HW init failed (%d)\n", ret);
> +		return ret;
>  	}
> 
>  	ret = safexcel_register_algorithms(priv);
>  	if (ret) {
>  		dev_err(dev, "Failed to register algorithms (%d)\n", ret);
> -		goto err_reg_clk;
> +		return ret;
>  	}
> 
>  	return 0;
> -
> -err_reg_clk:
> -	clk_disable_unprepare(priv->reg_clk);
> -err_core_clk:
> -	clk_disable_unprepare(priv->clk);
> -	return ret;
>  }
> 
>  static void safexcel_hw_reset_rings(struct safexcel_crypto_priv *priv)
> @@ -1151,6 +1137,78 @@ static void safexcel_hw_reset_rings(struct safexcel_crypto_priv *priv)
>  	}
>  }
> 
> +#if IS_ENABLED(CONFIG_OF)
> +/* for Device Tree platform driver */
> +
> +static int safexcel_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct resource *res;
> +	struct safexcel_crypto_priv *priv;
> +	int ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = dev;
> +	priv->version = (enum safexcel_eip_version)of_device_get_match_data(dev);
> +
> +	platform_set_drvdata(pdev, priv);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	priv->base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(priv->base)) {
> +		dev_err(dev, "failed to get resource\n");
> +		return PTR_ERR(priv->base);
> +	}
> +
> +	priv->clk = devm_clk_get(&pdev->dev, NULL);
> +	ret = PTR_ERR_OR_ZERO(priv->clk);
> +	/* The clock isn't mandatory */
> +	if  (ret != -ENOENT) {
> +		if (ret)
> +			return ret;
> +
> +		ret = clk_prepare_enable(priv->clk);
> +		if (ret) {
> +			dev_err(dev, "unable to enable clk (%d)\n", ret);
> +			return ret;
> +		}
> +	}
> +
> +	priv->reg_clk = devm_clk_get(&pdev->dev, "reg");
> +	ret = PTR_ERR_OR_ZERO(priv->reg_clk);
> +	/* The clock isn't mandatory */
> +	if  (ret != -ENOENT) {
> +		if (ret)
> +			goto err_core_clk;
> +
> +		ret = clk_prepare_enable(priv->reg_clk);
> +		if (ret) {
> +			dev_err(dev, "unable to enable reg clk (%d)\n", ret);
> +			goto err_core_clk;
> +		}
> +	}
> +
> +	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
> +	if (ret)
> +		goto err_reg_clk;
> +
> +	/* Generic EIP97/EIP197 device probing */
> +	ret = safexcel_probe_generic(pdev, priv, 0);
> +	if (ret)
> +		goto err_reg_clk;
> +
> +	return 0;
> +
> +err_reg_clk:
> +	clk_disable_unprepare(priv->reg_clk);
> +err_core_clk:
> +	clk_disable_unprepare(priv->clk);
> +	return ret;
> +}
> +
>  static int safexcel_remove(struct platform_device *pdev)
>  {
>  	struct safexcel_crypto_priv *priv = platform_get_drvdata(pdev);
> @@ -1170,30 +1228,28 @@ static int safexcel_remove(struct platform_device *pdev)
>  static const struct of_device_id safexcel_of_match_table[] = {
>  	{
>  		.compatible = "inside-secure,safexcel-eip97ies",
> -		.data = (void *)EIP97IES,
> +		.data = (void *)EIP97IES_MRVL,
>  	},
>  	{
>  		.compatible = "inside-secure,safexcel-eip197b",
> -		.data = (void *)EIP197B,
> +		.data = (void *)EIP197B_MRVL,
>  	},
>  	{
>  		.compatible = "inside-secure,safexcel-eip197d",
> -		.data = (void *)EIP197D,
> +		.data = (void *)EIP197D_MRVL,
>  	},
> +	/* For backward compatibility and intended for generic use */
>  	{
> -		/* Deprecated. Kept for backward compatibility. */
>  		.compatible = "inside-secure,safexcel-eip97",
> -		.data = (void *)EIP97IES,
> +		.data = (void *)EIP97IES_MRVL,
>  	},
>  	{
> -		/* Deprecated. Kept for backward compatibility. */
>  		.compatible = "inside-secure,safexcel-eip197",
> -		.data = (void *)EIP197B,
> +		.data = (void *)EIP197B_MRVL,
>  	},
>  	{},
>  };
> 
> -
>  static struct platform_driver  crypto_safexcel = {
>  	.probe		= safexcel_probe,
>  	.remove		= safexcel_remove,
> @@ -1202,10 +1258,167 @@ static int safexcel_remove(struct platform_device *pdev)
>  		.of_match_table = safexcel_of_match_table,
>  	},
>  };
> -module_platform_driver(crypto_safexcel);
> +#endif
> +
> +#if IS_ENABLED(CONFIG_PCI)
> +/* PCIE devices - i.e. Inside Secure development boards */
> +
> +static int safexcel_pci_probe(struct pci_dev *pdev,
> +			       const struct pci_device_id *ent)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct safexcel_crypto_priv *priv;
> +	void __iomem *pciebase;
> +	int rc;
> +	u32 val;
> +
> +	dev_dbg(dev, "Probing PCIE device: vendor %04x, device %04x, subv %04x, subdev %04x, ctxt %lx\n",
> +		ent->vendor, ent->device, ent->subvendor,
> +		ent->subdevice, ent->driver_data);
> +
> +	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = dev;
> +	priv->version = (enum safexcel_eip_version)ent->driver_data;
> +
> +	pci_set_drvdata(pdev, priv);
> +
> +	/* enable the device */
> +	rc = pcim_enable_device(pdev);
> +	if (rc) {
> +		dev_err(dev, "Failed to enable PCI device\n");
> +		return rc;
> +	}
> +
> +	/* take ownership of PCI BAR0 */
> +	rc = pcim_iomap_regions(pdev, 1, "crypto_safexcel");
> +	if (rc) {
> +		dev_err(dev, "Failed to map IO region for BAR0\n");
> +		return rc;
> +	}
> +	priv->base = pcim_iomap_table(pdev)[0];
> +
> +	if (priv->version == EIP197_DEVBRD) {
> +		dev_dbg(dev, "Device identified as FPGA based development board - applying HW reset\n");
> +
> +		rc = pcim_iomap_regions(pdev, 4, "crypto_safexcel");
> +		if (rc) {
> +			dev_err(dev, "Failed to map IO region for BAR4\n");
> +			return rc;
> +		}
> +
> +		pciebase = pcim_iomap_table(pdev)[2];
> +		val = readl(pciebase + EIP197_XLX_IRQ_BLOCK_ID_ADDR);
> +		if ((val >> 16) == EIP197_XLX_IRQ_BLOCK_ID_VALUE) {
> +			dev_dbg(dev, "Detected Xilinx PCIE IRQ block version %d, multiple MSI support enabled\n",
> +				(val & 0xff));
> +
> +			/* Setup MSI identity map mapping */
> +			writel(EIP197_XLX_USER_VECT_LUT0_IDENT,
> +			       pciebase + EIP197_XLX_USER_VECT_LUT0_ADDR);
> +			writel(EIP197_XLX_USER_VECT_LUT1_IDENT,
> +			       pciebase + EIP197_XLX_USER_VECT_LUT1_ADDR);
> +			writel(EIP197_XLX_USER_VECT_LUT2_IDENT,
> +			       pciebase + EIP197_XLX_USER_VECT_LUT2_ADDR);
> +			writel(EIP197_XLX_USER_VECT_LUT3_IDENT,
> +			       pciebase + EIP197_XLX_USER_VECT_LUT3_ADDR);
> +
> +			/* Enable all device interrupts */
> +			writel(GENMASK(31, 0),
> +			       pciebase + EIP197_XLX_USER_INT_ENB_MSK);
> +		} else {
> +			dev_err(dev, "Unrecognised IRQ block identifier %x\n",
> +				val);
> +			return -ENODEV;
> +		}
> +
> +		/* HW reset FPGA dev board */
> +		/* assert reset */
> +		writel(1, priv->base + EIP197_XLX_GPIO_BASE);
> +		wmb(); /* maintain strict ordering for accesses here */
> +		/* deassert reset */
> +		writel(0, priv->base + EIP197_XLX_GPIO_BASE);
> +		wmb(); /* maintain strict ordering for accesses here */
> +	}
> +
> +	/* enable bus mastering */
> +	pci_set_master(pdev);
> +
> +	/* Generic EIP97/EIP197 device probing */
> +	rc = safexcel_probe_generic(pdev, priv, 1);
> +	return rc;
> +}
> +
> +void safexcel_pci_remove(struct pci_dev *pdev)
> +{
> +	struct safexcel_crypto_priv *priv = pci_get_drvdata(pdev);
> +	int i;
> +
> +	safexcel_unregister_algorithms(priv);
> +
> +	for (i = 0; i < priv->config.rings; i++)
> +		destroy_workqueue(priv->ring[i].workqueue);
> +
> +	safexcel_hw_reset_rings(priv);
> +}
> +
> +static const struct pci_device_id safexcel_pci_ids[] = {
> +	{
> +		PCI_DEVICE_SUB(PCI_VENDOR_ID_XILINX, 0x9038,
> +			       0x16ae, 0xc522),
> +		/* assume EIP197B for now */
> +		.driver_data = EIP197_DEVBRD,
> +	},
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(pci, safexcel_pci_ids);
> +
> +static struct pci_driver safexcel_pci_driver = {
> +	.name          = "crypto-safexcel",
> +	.id_table      = safexcel_pci_ids,
> +	.probe         = safexcel_pci_probe,
> +	.remove        = safexcel_pci_remove,
> +};
> +#endif
> +
> +static int __init safexcel_init(void)
> +{
> +	int rc;
> +
> +#if IS_ENABLED(CONFIG_OF)
> +		/* Register platform driver */
> +		platform_driver_register(&crypto_safexcel);
> +#endif
> +
> +#if IS_ENABLED(CONFIG_PCI)
> +		/* Register PCI driver */
> +		rc = pci_register_driver(&safexcel_pci_driver);
> +#endif
> +
> +	return 0;
> +}
> +
> +static void __exit safexcel_exit(void)
> +{
> +#if IS_ENABLED(CONFIG_OF)
> +		/* Unregister platform driver */
> +		platform_driver_unregister(&crypto_safexcel);
> +#endif
> +
> +#if IS_ENABLED(CONFIG_PCI)
> +		/* Unregister PCI driver if successfully registered before */
> +		pci_unregister_driver(&safexcel_pci_driver);
> +#endif
> +}
> +
> +module_init(safexcel_init);
> +module_exit(safexcel_exit);
> 
>  MODULE_AUTHOR("Antoine Tenart <antoine.tenart@xxxxxxxxxxxxxxxxxx>");
>  MODULE_AUTHOR("Ofer Heifetz <oferh@xxxxxxxxxxx>");
>  MODULE_AUTHOR("Igal Liberman <igall@xxxxxxxxxxx>");
> -MODULE_DESCRIPTION("Support for SafeXcel cryptographic engine EIP197");
> +MODULE_DESCRIPTION("Support for SafeXcel cryptographic engines: EIP97 & EIP197");
>  MODULE_LICENSE("GPL v2");
> diff --git a/drivers/crypto/inside-secure/safexcel.h b/drivers/crypto/inside-secure/safexcel.h
> index e53c232..a9a239b 100644
> --- a/drivers/crypto/inside-secure/safexcel.h
> +++ b/drivers/crypto/inside-secure/safexcel.h
> @@ -38,6 +38,27 @@
>  	char __##name##_desc[size] CRYPTO_MINALIGN_ATTR; \
>  	struct type##_request *name = (void *)__##name##_desc
> 
> +/* Xilinx dev board base offsets */
> +#define EIP197_XLX_GPIO_BASE		0x200000
> +#define EIP197_XLX_IRQ_BLOCK_ID_ADDR	0x2000
> +#define EIP197_XLX_IRQ_BLOCK_ID_VALUE	0x1fc2
> +#define EIP197_XLX_USER_INT_ENB_MSK	0x2004
> +#define EIP197_XLX_USER_INT_ENB_SET	0x2008
> +#define EIP197_XLX_USER_INT_ENB_CLEAR	0x200c
> +#define EIP197_XLX_USER_INT_BLOCK	0x2040
> +#define EIP197_XLX_USER_INT_PEND	0x2048
> +#define EIP197_XLX_USER_VECT_LUT0_ADDR	0x2080
> +#define EIP197_XLX_USER_VECT_LUT0_IDENT	0x03020100
> +#define EIP197_XLX_USER_VECT_LUT1_ADDR	0x2084
> +#define EIP197_XLX_USER_VECT_LUT1_IDENT	0x07060504
> +#define EIP197_XLX_USER_VECT_LUT2_ADDR	0x2088
> +#define EIP197_XLX_USER_VECT_LUT2_IDENT	0x0b0a0908
> +#define EIP197_XLX_USER_VECT_LUT3_ADDR	0x208c
> +#define EIP197_XLX_USER_VECT_LUT3_IDENT	0x0f0e0d0c
> +
> +/* Helper defines for probe function */
> +#define EIP197_IRQ_NUMBER(i, is_pci)	(i + is_pci)
> +
>  /* Register base offsets */
>  #define EIP197_HIA_AIC(priv)		((priv)->base + (priv)->offsets.hia_aic)
>  #define EIP197_HIA_AIC_G(priv)		((priv)->base + (priv)->offsets.hia_aic_g)
> @@ -581,10 +602,13 @@ struct safexcel_ring {
>  	struct crypto_async_request *backlog;
>  };
> 
> +/* EIP integration context flags */
>  enum safexcel_eip_version {
> -	EIP97IES = BIT(0),
> -	EIP197B  = BIT(1),
> -	EIP197D  = BIT(2),
> +	/* Platform (EIP integration context) specifier */
> +	EIP97IES_MRVL,
> +	EIP197B_MRVL,
> +	EIP197D_MRVL,
> +	EIP197_DEVBRD
>  };
> 
>  struct safexcel_register_offsets {
> diff --git a/drivers/crypto/inside-secure/safexcel_ring.c b/drivers/crypto/inside-secure/safexcel_ring.c
> index 142bc3f..2402a62 100644
> --- a/drivers/crypto/inside-secure/safexcel_ring.c
> +++ b/drivers/crypto/inside-secure/safexcel_ring.c
> @@ -145,7 +145,8 @@ struct safexcel_command_desc *safexcel_add_cdesc(struct safexcel_crypto_priv *pr
>  			(lower_32_bits(context) & GENMASK(31, 2)) >> 2;
>  		cdesc->control_data.context_hi = upper_32_bits(context);
> 
> -		if (priv->version == EIP197B || priv->version == EIP197D)
> +		if (priv->version == EIP197B_MRVL ||
> +		    priv->version == EIP197D_MRVL)
>  			cdesc->control_data.options |= EIP197_OPTION_RC_AUTO;
> 
>  		/* TODO: large xform HMAC with SHA-384/512 uses refresh = 3 */
> --
> 1.8.3.1

-- 
Antoine Ténart, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com



[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]

  Powered by Linux