summaryrefslogtreecommitdiffstats
path: root/drivers/crypto/omap-crypto.c
diff options
context:
space:
mode:
authorDanilo Krummrich <dakr@kernel.org>2026-08-13 18:52:04 +0200
committerDanilo Krummrich <dakr@kernel.org>2026-08-17 01:41:36 +0200
commitf146c7bc85a51f95c05e0f8173d484eb301ece78 (patch)
tree07296ae54ed6551492b0c609dc0f5463f61f89ca /drivers/crypto/omap-crypto.c
downloadlinux-stable-f146c7bc85a51f95c05e0f8173d484eb301ece78.tar.gz
linux-stable-f146c7bc85a51f95c05e0f8173d484eb301ece78.zip
PCI: Add pci_irq_type() to query the allocated interrupt typegrafted
Add a helper that returns PCI_IRQ_MSIX, PCI_IRQ_MSI, or PCI_IRQ_INTX based on the interrupt type the PCI core selected after pci_alloc_irq_vectors(). Several drivers already open-code this check against pdev->msix_enabled and pdev->msi_enabled, or even open code this helper [1]. A common helper avoids the duplication and keeps drivers from accessing the bitfield directly (see also [2]). Acked-by: Bjorn Helgaas <bhelgaas@google.com> Tested-by: John Hubbard <jhubbard@nvidia.com> Link: https://elixir.bootlin.com/linux/v7.1/source/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c#L196 [1] Inspired-by: John Hubbard <jhubbard@nvidia.com> Link: https://lore.kernel.org/all/DKKG2QM3YJYB.Z2H2B2UXJ75N@kernel.org/ [2] Reviewed-by: Gary Guo <gary@garyguo.net> Link: https://patch.msgid.link/20260813165234.620555-5-dakr@kernel.org [ Add missing pci_irq_type() stub for CONFIG_PCI=n. ] Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Diffstat (limited to 'drivers/crypto/omap-crypto.c')
-rw-r--r--drivers/crypto/omap-crypto.c225
1 files changed, 225 insertions, 0 deletions
diff --git a/drivers/crypto/omap-crypto.c b/drivers/crypto/omap-crypto.c
new file mode 100644
index 000000000..7bd6869c2
--- /dev/null
+++ b/drivers/crypto/omap-crypto.c
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * OMAP Crypto driver common support routines.
+ *
+ * Copyright (c) 2017 Texas Instruments Incorporated
+ * Tero Kristo <t-kristo@ti.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/scatterlist.h>
+#include <crypto/scatterwalk.h>
+
+#include "omap-crypto.h"
+
+static int omap_crypto_copy_sg_lists(int total, int bs,
+ struct scatterlist **sg,
+ struct scatterlist *new_sg, u16 flags)
+{
+ int n = sg_nents(*sg);
+ struct scatterlist *tmp;
+
+ if (!(flags & OMAP_CRYPTO_FORCE_SINGLE_ENTRY)) {
+ new_sg = kmalloc_objs(*new_sg, n);
+ if (!new_sg)
+ return -ENOMEM;
+
+ sg_init_table(new_sg, n);
+ }
+
+ tmp = new_sg;
+
+ while (*sg && total) {
+ int len = (*sg)->length;
+
+ if (total < len)
+ len = total;
+
+ if (len > 0) {
+ total -= len;
+ sg_set_page(tmp, sg_page(*sg), len, (*sg)->offset);
+ if (total <= 0)
+ sg_mark_end(tmp);
+ tmp = sg_next(tmp);
+ }
+
+ *sg = sg_next(*sg);
+ }
+
+ *sg = new_sg;
+
+ return 0;
+}
+
+static int omap_crypto_copy_sgs(int total, int bs, struct scatterlist **sg,
+ struct scatterlist *new_sg, u16 flags)
+{
+ void *buf;
+ int pages;
+ int new_len;
+
+ new_len = ALIGN(total, bs);
+ pages = get_order(new_len);
+
+ buf = (void *)__get_free_pages(GFP_ATOMIC, pages);
+ if (!buf) {
+ pr_err("%s: Couldn't allocate pages for unaligned cases.\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ if (flags & OMAP_CRYPTO_COPY_DATA) {
+ scatterwalk_map_and_copy(buf, *sg, 0, total, 0);
+ if (flags & OMAP_CRYPTO_ZERO_BUF)
+ memset(buf + total, 0, new_len - total);
+ }
+
+ if (!(flags & OMAP_CRYPTO_FORCE_SINGLE_ENTRY))
+ sg_init_table(new_sg, 1);
+
+ sg_set_buf(new_sg, buf, new_len);
+
+ *sg = new_sg;
+
+ return 0;
+}
+
+static int omap_crypto_check_sg(struct scatterlist *sg, int total, int bs,
+ u16 flags)
+{
+ int len = 0;
+ int num_sg = 0;
+
+ if (!IS_ALIGNED(total, bs))
+ return OMAP_CRYPTO_NOT_ALIGNED;
+
+ while (sg) {
+ num_sg++;
+
+ if (!IS_ALIGNED(sg->offset, 4))
+ return OMAP_CRYPTO_NOT_ALIGNED;
+ if (!IS_ALIGNED(sg->length, bs))
+ return OMAP_CRYPTO_NOT_ALIGNED;
+#ifdef CONFIG_ZONE_DMA
+ if (page_zonenum(sg_page(sg)) != ZONE_DMA)
+ return OMAP_CRYPTO_NOT_ALIGNED;
+#endif
+
+ len += sg->length;
+ sg = sg_next(sg);
+
+ if (len >= total)
+ break;
+ }
+
+ if ((flags & OMAP_CRYPTO_FORCE_SINGLE_ENTRY) && num_sg > 1)
+ return OMAP_CRYPTO_NOT_ALIGNED;
+
+ if (len != total)
+ return OMAP_CRYPTO_BAD_DATA_LENGTH;
+
+ return 0;
+}
+
+int omap_crypto_align_sg(struct scatterlist **sg, int total, int bs,
+ struct scatterlist *new_sg, u16 flags,
+ u8 flags_shift, unsigned long *dd_flags)
+{
+ int ret;
+
+ *dd_flags &= ~(OMAP_CRYPTO_COPY_MASK << flags_shift);
+
+ if (flags & OMAP_CRYPTO_FORCE_COPY)
+ ret = OMAP_CRYPTO_NOT_ALIGNED;
+ else
+ ret = omap_crypto_check_sg(*sg, total, bs, flags);
+
+ if (ret == OMAP_CRYPTO_NOT_ALIGNED) {
+ ret = omap_crypto_copy_sgs(total, bs, sg, new_sg, flags);
+ if (ret)
+ return ret;
+ *dd_flags |= OMAP_CRYPTO_DATA_COPIED << flags_shift;
+ } else if (ret == OMAP_CRYPTO_BAD_DATA_LENGTH) {
+ ret = omap_crypto_copy_sg_lists(total, bs, sg, new_sg, flags);
+ if (ret)
+ return ret;
+ if (!(flags & OMAP_CRYPTO_FORCE_SINGLE_ENTRY))
+ *dd_flags |= OMAP_CRYPTO_SG_COPIED << flags_shift;
+ } else if (flags & OMAP_CRYPTO_FORCE_SINGLE_ENTRY) {
+ sg_set_buf(new_sg, sg_virt(*sg), (*sg)->length);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(omap_crypto_align_sg);
+
+static void omap_crypto_copy_data(struct scatterlist *src,
+ struct scatterlist *dst,
+ int offset, int len)
+{
+ int amt;
+ void *srcb, *dstb;
+ int srco = 0, dsto = offset;
+
+ while (src && dst && len) {
+ if (srco >= src->length) {
+ srco -= src->length;
+ src = sg_next(src);
+ continue;
+ }
+
+ if (dsto >= dst->length) {
+ dsto -= dst->length;
+ dst = sg_next(dst);
+ continue;
+ }
+
+ amt = min(src->length - srco, dst->length - dsto);
+ amt = min(len, amt);
+
+ srcb = kmap_atomic(sg_page(src)) + srco + src->offset;
+ dstb = kmap_atomic(sg_page(dst)) + dsto + dst->offset;
+
+ memcpy(dstb, srcb, amt);
+
+ flush_dcache_page(sg_page(dst));
+
+ kunmap_atomic(srcb);
+ kunmap_atomic(dstb);
+
+ srco += amt;
+ dsto += amt;
+ len -= amt;
+ }
+}
+
+void omap_crypto_cleanup(struct scatterlist *sg, struct scatterlist *orig,
+ int offset, int len, u8 flags_shift,
+ unsigned long flags)
+{
+ void *buf;
+ int pages;
+
+ flags >>= flags_shift;
+ flags &= OMAP_CRYPTO_COPY_MASK;
+
+ if (!flags)
+ return;
+
+ buf = sg_virt(sg);
+ pages = get_order(len);
+
+ if (orig && (flags & OMAP_CRYPTO_DATA_COPIED))
+ omap_crypto_copy_data(sg, orig, offset, len);
+
+ if (flags & OMAP_CRYPTO_DATA_COPIED)
+ free_pages((unsigned long)buf, pages);
+ else if (flags & OMAP_CRYPTO_SG_COPIED)
+ kfree(sg);
+}
+EXPORT_SYMBOL_GPL(omap_crypto_cleanup);
+
+MODULE_DESCRIPTION("OMAP crypto support library.");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Tero Kristo <t-kristo@ti.com>");