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: Jakub Kicinski <jakub.kicinski@netronome.com> Reviewed-by: Dirk van der Merwe <dirk.vandermerwe@netronome.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a0d163f432
commit
b586c77b3c
|
@ -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,
|
||||||
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,
|
||||||
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:
|
||||||
return -EINVAL;
|
if (offset % sizeof(u32) != 0 || length % sizeof(u32) != 0)
|
||||||
#else
|
return -EINVAL;
|
||||||
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;
|
||||||
|
|
||||||
return n;
|
for (n = 0; n < length; n += sizeof(u64))
|
||||||
|
*wrptr64++ = __raw_readq(rdptr64++);
|
||||||
|
return n;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -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,
|
||||||
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,
|
||||||
priv->offset + offset,
|
priv->offset + offset,
|
||||||
kernel_vaddr, length, width);
|
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 (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_writeq
|
case TARGET_WIDTH_32:
|
||||||
return -EINVAL;
|
if (offset % sizeof(u32) != 0 || length % sizeof(u32) != 0)
|
||||||
#else
|
return -EINVAL;
|
||||||
for (n = 0; n < length; n += sizeof(u64)) {
|
|
||||||
__raw_writeq(*rdptr64++, wrptr64++);
|
|
||||||
wmb();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else
|
|
||||||
for (n = 0; n < length; n += sizeof(u32)) {
|
for (n = 0; n < length; n += sizeof(u32)) {
|
||||||
__raw_writel(*rdptr32++, wrptr32++);
|
__raw_writel(*rdptr32++, wrptr32++);
|
||||||
wmb();
|
wmb();
|
||||||
}
|
}
|
||||||
|
return n;
|
||||||
|
#ifdef __raw_writeq
|
||||||
|
case TARGET_WIDTH_64:
|
||||||
|
if (offset % sizeof(u64) != 0 || length % sizeof(u64) != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
return n;
|
for (n = 0; n < length; n += sizeof(u64)) {
|
||||||
|
__raw_writeq(*rdptr64++, wrptr64++);
|
||||||
|
wmb();
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nfp6000_explicit_priv {
|
struct nfp6000_explicit_priv {
|
||||||
|
|
Loading…
Reference in New Issue