Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b586c77b authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller
Browse files

nfp: core: allow 4-byte aligned accesses to Memory Units



Current code doesn't enforce length requirements on 32bit accesses
with action NFP_CPP_ACTION_RW to memory units, but if the access
is only aligned to 4 bytes as well we will fall into the explicit
access case and error out.  Such accesses are correct, allow them
by lowering the width earlier.

While at it use a switch statement to improve readability.

Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: default avatarDirk van der Merwe <dirk.vandermerwe@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a0d163f4
Loading
Loading
Loading
Loading
+44 −50
Original line number Diff line number Diff line
@@ -933,7 +933,6 @@ static int nfp6000_area_read(struct nfp_cpp_area *area, void *kernel_vaddr,
	u32 *wrptr32 = kernel_vaddr;
	const u32 __iomem *rdptr32;
	int n, width;
	bool is_64;

	priv = nfp_cpp_area_priv(area);
	rdptr64 = priv->iomem + offset;
@@ -943,10 +942,15 @@ static int nfp6000_area_read(struct nfp_cpp_area *area, void *kernel_vaddr,
		return -EFAULT;

	width = priv->width.read;

	if (width <= 0)
		return -EINVAL;

	/* MU reads via a PCIe2CPP BAR support 32bit (and other) lengths */
	if (priv->target == (NFP_CPP_TARGET_MU & NFP_CPP_TARGET_ID_MASK) &&
	    priv->action == NFP_CPP_ACTION_RW &&
	    (offset % sizeof(u64) == 4 || length % sizeof(u64) == 4))
		width = TARGET_WIDTH_32;

	/* Unaligned? Translate to an explicit access */
	if ((priv->offset + offset) & (width - 1))
		return nfp_cpp_explicit_read(nfp_cpp_area_cpp(area),
@@ -956,36 +960,29 @@ static int nfp6000_area_read(struct nfp_cpp_area *area, void *kernel_vaddr,
					     priv->offset + offset,
					     kernel_vaddr, length, width);

	is_64 = width == TARGET_WIDTH_64;

	/* MU reads via a PCIe2CPP BAR supports 32bit (and other) lengths */
	if (priv->target == (NFP_CPP_TARGET_ID_MASK & NFP_CPP_TARGET_MU) &&
	    priv->action == NFP_CPP_ACTION_RW)
		is_64 = false;

	if (is_64) {
		if (offset % sizeof(u64) != 0 || length % sizeof(u64) != 0)
			return -EINVAL;
	} else {
		if (offset % sizeof(u32) != 0 || length % sizeof(u32) != 0)
			return -EINVAL;
	}

	if (WARN_ON(!priv->bar))
		return -EFAULT;

	if (is_64)
#ifndef __raw_readq
	switch (width) {
	case TARGET_WIDTH_32:
		if (offset % sizeof(u32) != 0 || length % sizeof(u32) != 0)
			return -EINVAL;
#else
		for (n = 0; n < length; n += sizeof(u64))
			*wrptr64++ = __raw_readq(rdptr64++);
#endif
	else

		for (n = 0; n < length; n += sizeof(u32))
			*wrptr32++ = __raw_readl(rdptr32++);
		return n;
#ifdef __raw_readq
	case TARGET_WIDTH_64:
		if (offset % sizeof(u64) != 0 || length % sizeof(u64) != 0)
			return -EINVAL;

		for (n = 0; n < length; n += sizeof(u64))
			*wrptr64++ = __raw_readq(rdptr64++);
		return n;
#endif
	default:
		return -EINVAL;
	}
}

static int
@@ -999,7 +996,6 @@ nfp6000_area_write(struct nfp_cpp_area *area,
	struct nfp6000_area_priv *priv;
	u32 __iomem *wrptr32;
	int n, width;
	bool is_64;

	priv = nfp_cpp_area_priv(area);
	wrptr64 = priv->iomem + offset;
@@ -1009,10 +1005,15 @@ nfp6000_area_write(struct nfp_cpp_area *area,
		return -EFAULT;

	width = priv->width.write;

	if (width <= 0)
		return -EINVAL;

	/* MU writes via a PCIe2CPP BAR support 32bit (and other) lengths */
	if (priv->target == (NFP_CPP_TARGET_ID_MASK & NFP_CPP_TARGET_MU) &&
	    priv->action == NFP_CPP_ACTION_RW &&
	    (offset % sizeof(u64) == 4 || length % sizeof(u64) == 4))
		width = TARGET_WIDTH_32;

	/* Unaligned? Translate to an explicit access */
	if ((priv->offset + offset) & (width - 1))
		return nfp_cpp_explicit_write(nfp_cpp_area_cpp(area),
@@ -1022,40 +1023,33 @@ nfp6000_area_write(struct nfp_cpp_area *area,
					      priv->offset + offset,
					      kernel_vaddr, length, width);

	is_64 = width == TARGET_WIDTH_64;

	/* MU writes via a PCIe2CPP BAR supports 32bit (and other) lengths */
	if (priv->target == (NFP_CPP_TARGET_ID_MASK & NFP_CPP_TARGET_MU) &&
	    priv->action == NFP_CPP_ACTION_RW)
		is_64 = false;
	if (WARN_ON(!priv->bar))
		return -EFAULT;

	if (is_64) {
		if (offset % sizeof(u64) != 0 || length % sizeof(u64) != 0)
			return -EINVAL;
	} else {
	switch (width) {
	case TARGET_WIDTH_32:
		if (offset % sizeof(u32) != 0 || length % sizeof(u32) != 0)
			return -EINVAL;
	}

	if (WARN_ON(!priv->bar))
		return -EFAULT;

	if (is_64)
#ifndef __raw_writeq
		for (n = 0; n < length; n += sizeof(u32)) {
			__raw_writel(*rdptr32++, wrptr32++);
			wmb();
		}
		return n;
#ifdef __raw_writeq
	case TARGET_WIDTH_64:
		if (offset % sizeof(u64) != 0 || length % sizeof(u64) != 0)
			return -EINVAL;
#else

		for (n = 0; n < length; n += sizeof(u64)) {
			__raw_writeq(*rdptr64++, wrptr64++);
			wmb();
		}
		return n;
#endif
	else
		for (n = 0; n < length; n += sizeof(u32)) {
			__raw_writel(*rdptr32++, wrptr32++);
			wmb();
	default:
		return -EINVAL;
	}

	return n;
}

struct nfp6000_explicit_priv {