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

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
...@@ -933,7 +933,6 @@ static int nfp6000_area_read(struct nfp_cpp_area *area, void *kernel_vaddr, ...@@ -933,7 +933,6 @@ static int nfp6000_area_read(struct nfp_cpp_area *area, void *kernel_vaddr,
u32 *wrptr32 = kernel_vaddr; u32 *wrptr32 = kernel_vaddr;
const u32 __iomem *rdptr32; const u32 __iomem *rdptr32;
int n, width; int n, width;
bool is_64;
priv = nfp_cpp_area_priv(area); priv = nfp_cpp_area_priv(area);
rdptr64 = priv->iomem + offset; rdptr64 = priv->iomem + offset;
...@@ -943,10 +942,15 @@ static int nfp6000_area_read(struct nfp_cpp_area *area, void *kernel_vaddr, ...@@ -943,10 +942,15 @@ static int nfp6000_area_read(struct nfp_cpp_area *area, void *kernel_vaddr,
return -EFAULT; return -EFAULT;
width = priv->width.read; width = priv->width.read;
if (width <= 0) if (width <= 0)
return -EINVAL; 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 */ /* Unaligned? Translate to an explicit access */
if ((priv->offset + offset) & (width - 1)) if ((priv->offset + offset) & (width - 1))
return nfp_cpp_explicit_read(nfp_cpp_area_cpp(area), 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, ...@@ -956,36 +960,29 @@ static int nfp6000_area_read(struct nfp_cpp_area *area, void *kernel_vaddr,
priv->offset + offset, priv->offset + offset,
kernel_vaddr, length, width); 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)) if (WARN_ON(!priv->bar))
return -EFAULT; return -EFAULT;
if (is_64) switch (width) {
#ifndef __raw_readq case TARGET_WIDTH_32:
if (offset % sizeof(u32) != 0 || length % sizeof(u32) != 0)
return -EINVAL; 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)) for (n = 0; n < length; n += sizeof(u32))
*wrptr32++ = __raw_readl(rdptr32++); *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; return n;
#endif
default:
return -EINVAL;
}
} }
static int static int
...@@ -999,7 +996,6 @@ nfp6000_area_write(struct nfp_cpp_area *area, ...@@ -999,7 +996,6 @@ nfp6000_area_write(struct nfp_cpp_area *area,
struct nfp6000_area_priv *priv; struct nfp6000_area_priv *priv;
u32 __iomem *wrptr32; u32 __iomem *wrptr32;
int n, width; int n, width;
bool is_64;
priv = nfp_cpp_area_priv(area); priv = nfp_cpp_area_priv(area);
wrptr64 = priv->iomem + offset; wrptr64 = priv->iomem + offset;
...@@ -1009,10 +1005,15 @@ nfp6000_area_write(struct nfp_cpp_area *area, ...@@ -1009,10 +1005,15 @@ nfp6000_area_write(struct nfp_cpp_area *area,
return -EFAULT; return -EFAULT;
width = priv->width.write; width = priv->width.write;
if (width <= 0) if (width <= 0)
return -EINVAL; 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 */ /* Unaligned? Translate to an explicit access */
if ((priv->offset + offset) & (width - 1)) if ((priv->offset + offset) & (width - 1))
return nfp_cpp_explicit_write(nfp_cpp_area_cpp(area), return nfp_cpp_explicit_write(nfp_cpp_area_cpp(area),
...@@ -1022,40 +1023,33 @@ nfp6000_area_write(struct nfp_cpp_area *area, ...@@ -1022,40 +1023,33 @@ nfp6000_area_write(struct nfp_cpp_area *area,
priv->offset + offset, priv->offset + offset,
kernel_vaddr, length, width); kernel_vaddr, length, width);
is_64 = width == TARGET_WIDTH_64; if (WARN_ON(!priv->bar))
return -EFAULT;
/* 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 (is_64) { switch (width) {
if (offset % sizeof(u64) != 0 || length % sizeof(u64) != 0) case TARGET_WIDTH_32:
return -EINVAL;
} else {
if (offset % sizeof(u32) != 0 || length % sizeof(u32) != 0) if (offset % sizeof(u32) != 0 || length % sizeof(u32) != 0)
return -EINVAL; return -EINVAL;
}
if (WARN_ON(!priv->bar)) for (n = 0; n < length; n += sizeof(u32)) {
return -EFAULT; __raw_writel(*rdptr32++, wrptr32++);
wmb();
if (is_64) }
#ifndef __raw_writeq return n;
#ifdef __raw_writeq
case TARGET_WIDTH_64:
if (offset % sizeof(u64) != 0 || length % sizeof(u64) != 0)
return -EINVAL; return -EINVAL;
#else
for (n = 0; n < length; n += sizeof(u64)) { for (n = 0; n < length; n += sizeof(u64)) {
__raw_writeq(*rdptr64++, wrptr64++); __raw_writeq(*rdptr64++, wrptr64++);
wmb(); wmb();
} }
return n;
#endif #endif
else default:
for (n = 0; n < length; n += sizeof(u32)) { return -EINVAL;
__raw_writel(*rdptr32++, wrptr32++);
wmb();
} }
return n;
} }
struct nfp6000_explicit_priv { struct nfp6000_explicit_priv {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment