static int safexcel_probe_generic()

in inside-secure/safexcel.c [1397:1700]


static int safexcel_probe_generic(void *pdev,
				  struct safexcel_crypto_priv *priv,
				  int is_pci_dev)
{
	struct device *dev = priv->dev;
	u32 peid, version, mask, val, hiaopt, hwopt, peopt;
	int i, ret, hwctg;

	priv->context_pool = dmam_pool_create("safexcel-context", dev,
					      sizeof(struct safexcel_context_record),
					      1, 0);
	if (!priv->context_pool)
		return -ENOMEM;

	/*
	 * First try the EIP97 HIA version regs
	 * For the EIP197, this is guaranteed to NOT return any of the test
	 * values
	 */
	version = readl(priv->base + EIP97_HIA_AIC_BASE + EIP197_HIA_VERSION);

	mask = 0;  /* do not swap */
	if (EIP197_REG_LO16(version) == EIP197_HIA_VERSION_LE) {
		priv->hwconfig.hiaver = EIP197_VERSION_MASK(version);
	} else if (EIP197_REG_HI16(version) == EIP197_HIA_VERSION_BE) {
		/* read back byte-swapped, so complement byte swap bits */
		mask = EIP197_MST_CTRL_BYTE_SWAP_BITS;
		priv->hwconfig.hiaver = EIP197_VERSION_SWAP(version);
	} else {
		/* So it wasn't an EIP97 ... maybe it's an EIP197? */
		version = readl(priv->base + EIP197_HIA_AIC_BASE +
				EIP197_HIA_VERSION);
		if (EIP197_REG_LO16(version) == EIP197_HIA_VERSION_LE) {
			priv->hwconfig.hiaver = EIP197_VERSION_MASK(version);
			priv->flags |= SAFEXCEL_HW_EIP197;
		} else if (EIP197_REG_HI16(version) ==
			   EIP197_HIA_VERSION_BE) {
			/* read back byte-swapped, so complement swap bits */
			mask = EIP197_MST_CTRL_BYTE_SWAP_BITS;
			priv->hwconfig.hiaver = EIP197_VERSION_SWAP(version);
			priv->flags |= SAFEXCEL_HW_EIP197;
		} else {
			return -ENODEV;
		}
	}

	/* Now initialize the reg offsets based on the probing info so far */
	safexcel_init_register_offsets(priv);

	/*
	 * If the version was read byte-swapped, we need to flip the device
	 * swapping Keep in mind here, though, that what we write will also be
	 * byte-swapped ...
	 */
	if (mask) {
		val = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL);
		val = val ^ (mask >> 24); /* toggle byte swap bits */
		writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL);
	}

	/*
	 * We're not done probing yet! We may fall through to here if no HIA
	 * was found at all. So, with the endianness presumably correct now and
	 * the offsets setup, *really* probe for the EIP97/EIP197.
	 */
	version = readl(EIP197_GLOBAL(priv) + EIP197_VERSION);
	if (((priv->flags & SAFEXCEL_HW_EIP197) &&
	     (EIP197_REG_LO16(version) != EIP197_VERSION_LE) &&
	     (EIP197_REG_LO16(version) != EIP196_VERSION_LE)) ||
	    ((!(priv->flags & SAFEXCEL_HW_EIP197) &&
	     (EIP197_REG_LO16(version) != EIP97_VERSION_LE)))) {
		/*
		 * We did not find the device that matched our initial probing
		 * (or our initial probing failed) Report appropriate error.
		 */
		dev_err(priv->dev, "Probing for EIP97/EIP19x failed - no such device (read %08x)\n",
			version);
		return -ENODEV;
	}

	priv->hwconfig.hwver = EIP197_VERSION_MASK(version);
	hwctg = version >> 28;
	peid = version & 255;

	/* Detect EIP206 processing pipe */
	version = readl(EIP197_PE(priv) + + EIP197_PE_VERSION(0));
	if (EIP197_REG_LO16(version) != EIP206_VERSION_LE) {
		dev_err(priv->dev, "EIP%d: EIP206 not detected\n", peid);
		return -ENODEV;
	}
	priv->hwconfig.ppver = EIP197_VERSION_MASK(version);

	/* Detect EIP96 packet engine and version */
	version = readl(EIP197_PE(priv) + EIP197_PE_EIP96_VERSION(0));
	if (EIP197_REG_LO16(version) != EIP96_VERSION_LE) {
		dev_err(dev, "EIP%d: EIP96 not detected.\n", peid);
		return -ENODEV;
	}
	priv->hwconfig.pever = EIP197_VERSION_MASK(version);

	hwopt = readl(EIP197_GLOBAL(priv) + EIP197_OPTIONS);
	hiaopt = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_OPTIONS);

	priv->hwconfig.icever = 0;
	priv->hwconfig.ocever = 0;
	priv->hwconfig.psever = 0;
	if (priv->flags & SAFEXCEL_HW_EIP197) {
		/* EIP197 */
		peopt = readl(EIP197_PE(priv) + EIP197_PE_OPTIONS(0));

		priv->hwconfig.hwdataw  = (hiaopt >> EIP197_HWDATAW_OFFSET) &
					  EIP197_HWDATAW_MASK;
		priv->hwconfig.hwcfsize = ((hiaopt >> EIP197_CFSIZE_OFFSET) &
					   EIP197_CFSIZE_MASK) +
					  EIP197_CFSIZE_ADJUST;
		priv->hwconfig.hwrfsize = ((hiaopt >> EIP197_RFSIZE_OFFSET) &
					   EIP197_RFSIZE_MASK) +
					  EIP197_RFSIZE_ADJUST;
		priv->hwconfig.hwnumpes	= (hiaopt >> EIP197_N_PES_OFFSET) &
					  EIP197_N_PES_MASK;
		priv->hwconfig.hwnumrings = (hiaopt >> EIP197_N_RINGS_OFFSET) &
					    EIP197_N_RINGS_MASK;
		if (hiaopt & EIP197_HIA_OPT_HAS_PE_ARB)
			priv->flags |= EIP197_PE_ARB;
		if (EIP206_OPT_ICE_TYPE(peopt) == 1) {
			priv->flags |= EIP197_ICE;
			/* Detect ICE EIP207 class. engine and version */
			version = readl(EIP197_PE(priv) +
				  EIP197_PE_ICE_VERSION(0));
			if (EIP197_REG_LO16(version) != EIP207_VERSION_LE) {
				dev_err(dev, "EIP%d: ICE EIP207 not detected.\n",
					peid);
				return -ENODEV;
			}
			priv->hwconfig.icever = EIP197_VERSION_MASK(version);
		}
		if (EIP206_OPT_OCE_TYPE(peopt) == 1) {
			priv->flags |= EIP197_OCE;
			/* Detect EIP96PP packet stream editor and version */
			version = readl(EIP197_PE(priv) + EIP197_PE_PSE_VERSION(0));
			if (EIP197_REG_LO16(version) != EIP96_VERSION_LE) {
				dev_err(dev, "EIP%d: EIP96PP not detected.\n", peid);
				return -ENODEV;
			}
			priv->hwconfig.psever = EIP197_VERSION_MASK(version);
			/* Detect OCE EIP207 class. engine and version */
			version = readl(EIP197_PE(priv) +
				  EIP197_PE_ICE_VERSION(0));
			if (EIP197_REG_LO16(version) != EIP207_VERSION_LE) {
				dev_err(dev, "EIP%d: OCE EIP207 not detected.\n",
					peid);
				return -ENODEV;
			}
			priv->hwconfig.ocever = EIP197_VERSION_MASK(version);
		}
		/* If not a full TRC, then assume simple TRC */
		if (!(hwopt & EIP197_OPT_HAS_TRC))
			priv->flags |= EIP197_SIMPLE_TRC;
		/* EIP197 always has SOME form of TRC */
		priv->flags |= EIP197_TRC_CACHE;
	} else {
		/* EIP97 */
		priv->hwconfig.hwdataw  = (hiaopt >> EIP197_HWDATAW_OFFSET) &
					  EIP97_HWDATAW_MASK;
		priv->hwconfig.hwcfsize = (hiaopt >> EIP97_CFSIZE_OFFSET) &
					  EIP97_CFSIZE_MASK;
		priv->hwconfig.hwrfsize = (hiaopt >> EIP97_RFSIZE_OFFSET) &
					  EIP97_RFSIZE_MASK;
		priv->hwconfig.hwnumpes	= 1; /* by definition */
		priv->hwconfig.hwnumrings = (hiaopt >> EIP197_N_RINGS_OFFSET) &
					    EIP197_N_RINGS_MASK;
	}

	/* Scan for ring AIC's */
	for (i = 0; i < EIP197_MAX_RING_AIC; i++) {
		version = readl(EIP197_HIA_AIC_R(priv) +
				EIP197_HIA_AIC_R_VERSION(i));
		if (EIP197_REG_LO16(version) != EIP201_VERSION_LE)
			break;
	}
	priv->hwconfig.hwnumraic = i;
	/* Low-end EIP196 may not have any ring AIC's ... */
	if (!priv->hwconfig.hwnumraic) {
		dev_err(priv->dev, "No ring interrupt controller present!\n");
		return -ENODEV;
	}

	/* Get supported algorithms from EIP96 transform engine */
	priv->hwconfig.algo_flags = readl(EIP197_PE(priv) +
				    EIP197_PE_EIP96_OPTIONS(0));

	/* Print single info line describing what we just detected */
	dev_info(priv->dev, "EIP%d:%x(%d,%d,%d,%d)-HIA:%x(%d,%d,%d),PE:%x/%x(alg:%08x)/%x/%x/%x\n",
		 peid, priv->hwconfig.hwver, hwctg, priv->hwconfig.hwnumpes,
		 priv->hwconfig.hwnumrings, priv->hwconfig.hwnumraic,
		 priv->hwconfig.hiaver, priv->hwconfig.hwdataw,
		 priv->hwconfig.hwcfsize, priv->hwconfig.hwrfsize,
		 priv->hwconfig.ppver, priv->hwconfig.pever,
		 priv->hwconfig.algo_flags, priv->hwconfig.icever,
		 priv->hwconfig.ocever, priv->hwconfig.psever);

	safexcel_configure(priv);

	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;
		}
	}

	/* 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)
		return -ENOMEM;

	for (i = 0; i < priv->config.rings; i++) {
		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) {
			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)
			return -ENOMEM;

		ring_irq = devm_kzalloc(dev, sizeof(*ring_irq), GFP_KERNEL);
		if (!ring_irq)
			return -ENOMEM;

		ring_irq->priv = priv;
		ring_irq->ring = i;

		irq = safexcel_request_ring_irq(pdev,
						EIP197_IRQ_NUMBER(i, is_pci_dev),
						is_pci_dev,
						i,
						safexcel_irq_ring,
						safexcel_irq_ring_thread,
						ring_irq);
		if (irq < 0) {
			dev_err(dev, "Failed to get IRQ ID for ring %d\n", i);
			return irq;
		}

		priv->ring[i].irq = 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);

		snprintf(wq_name, 9, "wq_ring%d", i);
		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;

		crypto_init_queue(&priv->ring[i].queue,
				  EIP197_DEFAULT_RING_SIZE);

		spin_lock_init(&priv->ring[i].lock);
		spin_lock_init(&priv->ring[i].queue_lock);
	}

	atomic_set(&priv->ring_used, 0);

	ret = safexcel_hw_init(priv);
	if (ret) {
		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);
		return ret;
	}

	return 0;
}