nfp: support long reads and writes with the cpp helpers
nfp_cpp_{read,write}() helpers perform device memory mapping (setting the PCIe -> NOC translation BARs) and accessing it. They, however, currently implicitly expect that the length of entire operation will fit in one BAR translation window. There is a number of 16MB windows available, and we don't really need to access such large areas today. If the user, however, manages to trick the driver into making a big mapping (e.g. by providing a huge fake FW file), the driver will print a warning saying "No suitable BAR found for request" and a stack trace - which most users find concerning. To be future-proof and not scare users with warnings, make the nfp_cpp_{read,write}() helpers do accesses chunk by chunk if the area size is large. Set the notion of "large" to 2MB, which is the size of the smallest BAR window. Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
321b5e9afe
commit
8b3d5a47ae
|
@ -42,6 +42,7 @@
|
|||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#ifndef NFP_SUBSYS
|
||||
#define NFP_SUBSYS "nfp"
|
||||
|
@ -59,6 +60,8 @@
|
|||
#define PCI_64BIT_BAR_COUNT 3
|
||||
|
||||
#define NFP_CPP_NUM_TARGETS 16
|
||||
/* Max size of area it should be safe to request */
|
||||
#define NFP_CPP_SAFE_AREA_SIZE SZ_2M
|
||||
|
||||
struct device;
|
||||
|
||||
|
|
|
@ -924,18 +924,9 @@ area_cache_put(struct nfp_cpp *cpp, struct nfp_cpp_area_cache *cache)
|
|||
mutex_unlock(&cpp->area_cache_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* nfp_cpp_read() - read from CPP target
|
||||
* @cpp: CPP handle
|
||||
* @destination: CPP id
|
||||
* @address: offset into CPP target
|
||||
* @kernel_vaddr: kernel buffer for result
|
||||
* @length: number of bytes to read
|
||||
*
|
||||
* Return: length of io, or -ERRNO
|
||||
*/
|
||||
int nfp_cpp_read(struct nfp_cpp *cpp, u32 destination,
|
||||
unsigned long long address, void *kernel_vaddr, size_t length)
|
||||
static int __nfp_cpp_read(struct nfp_cpp *cpp, u32 destination,
|
||||
unsigned long long address, void *kernel_vaddr,
|
||||
size_t length)
|
||||
{
|
||||
struct nfp_cpp_area_cache *cache;
|
||||
struct nfp_cpp_area *area;
|
||||
|
@ -968,18 +959,43 @@ int nfp_cpp_read(struct nfp_cpp *cpp, u32 destination,
|
|||
}
|
||||
|
||||
/**
|
||||
* nfp_cpp_write() - write to CPP target
|
||||
* nfp_cpp_read() - read from CPP target
|
||||
* @cpp: CPP handle
|
||||
* @destination: CPP id
|
||||
* @address: offset into CPP target
|
||||
* @kernel_vaddr: kernel buffer to read from
|
||||
* @length: number of bytes to write
|
||||
* @kernel_vaddr: kernel buffer for result
|
||||
* @length: number of bytes to read
|
||||
*
|
||||
* Return: length of io, or -ERRNO
|
||||
*/
|
||||
int nfp_cpp_write(struct nfp_cpp *cpp, u32 destination,
|
||||
unsigned long long address,
|
||||
const void *kernel_vaddr, size_t length)
|
||||
int nfp_cpp_read(struct nfp_cpp *cpp, u32 destination,
|
||||
unsigned long long address, void *kernel_vaddr,
|
||||
size_t length)
|
||||
{
|
||||
size_t n, offset;
|
||||
int ret;
|
||||
|
||||
for (offset = 0; offset < length; offset += n) {
|
||||
unsigned long long r_addr = address + offset;
|
||||
|
||||
/* make first read smaller to align to safe window */
|
||||
n = min_t(size_t, length - offset,
|
||||
ALIGN(r_addr + 1, NFP_CPP_SAFE_AREA_SIZE) - r_addr);
|
||||
|
||||
ret = __nfp_cpp_read(cpp, destination, address + offset,
|
||||
kernel_vaddr + offset, n);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret != n)
|
||||
return offset + n;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static int __nfp_cpp_write(struct nfp_cpp *cpp, u32 destination,
|
||||
unsigned long long address,
|
||||
const void *kernel_vaddr, size_t length)
|
||||
{
|
||||
struct nfp_cpp_area_cache *cache;
|
||||
struct nfp_cpp_area *area;
|
||||
|
@ -1011,6 +1027,41 @@ int nfp_cpp_write(struct nfp_cpp *cpp, u32 destination,
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfp_cpp_write() - write to CPP target
|
||||
* @cpp: CPP handle
|
||||
* @destination: CPP id
|
||||
* @address: offset into CPP target
|
||||
* @kernel_vaddr: kernel buffer to read from
|
||||
* @length: number of bytes to write
|
||||
*
|
||||
* Return: length of io, or -ERRNO
|
||||
*/
|
||||
int nfp_cpp_write(struct nfp_cpp *cpp, u32 destination,
|
||||
unsigned long long address,
|
||||
const void *kernel_vaddr, size_t length)
|
||||
{
|
||||
size_t n, offset;
|
||||
int ret;
|
||||
|
||||
for (offset = 0; offset < length; offset += n) {
|
||||
unsigned long long w_addr = address + offset;
|
||||
|
||||
/* make first write smaller to align to safe window */
|
||||
n = min_t(size_t, length - offset,
|
||||
ALIGN(w_addr + 1, NFP_CPP_SAFE_AREA_SIZE) - w_addr);
|
||||
|
||||
ret = __nfp_cpp_write(cpp, destination, address + offset,
|
||||
kernel_vaddr + offset, n);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret != n)
|
||||
return offset + n;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/* Return the correct CPP address, and fixup xpb_addr as needed. */
|
||||
static u32 nfp_xpb_to_cpp(struct nfp_cpp *cpp, u32 *xpb_addr)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue