// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) /* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_cppcore.c * Provides low-level access to the NFP's internal CPP bus * Authors: Jakub Kicinski <[email protected]> * Jason McMullan <[email protected]> * Rolf Neugebauer <[email protected]> */ #include <asm/unaligned.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/ioport.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/wait.h> #include "nfp_arm.h" #include "nfp_cpp.h" #include "nfp6000/nfp6000.h" #define NFP_ARM_GCSR_SOFTMODEL2 … #define NFP_ARM_GCSR_SOFTMODEL3 … struct nfp_cpp_resource { … }; /** * struct nfp_cpp - main nfpcore device structure * Following fields are read-only after probe() exits or netdevs are spawned. * @dev: embedded device structure * @op: low-level implementation ops * @priv: private data of the low-level implementation * @model: chip model * @interface: chip interface id we are using to reach it * @serial: chip serial number * @imb_cat_table: CPP Mapping Table * @mu_locality_lsb: MU access type bit offset * * Following fields use explicit locking: * @resource_list: NFP CPP resource list * @resource_lock: protects @resource_list * * @area_cache_list: cached areas for cpp/xpb read/write speed up * @area_cache_mutex: protects @area_cache_list * * @waitq: area wait queue */ struct nfp_cpp { … }; /* Element of the area_cache_list */ struct nfp_cpp_area_cache { … }; struct nfp_cpp_area { … }; struct nfp_cpp_explicit { … }; static void __resource_add(struct list_head *head, struct nfp_cpp_resource *res) { … } static void __resource_del(struct nfp_cpp_resource *res) { … } static void __release_cpp_area(struct kref *kref) { … } static void nfp_cpp_area_put(struct nfp_cpp_area *area) { … } static struct nfp_cpp_area *nfp_cpp_area_get(struct nfp_cpp_area *area) { … } /** * nfp_cpp_free() - free the CPP handle * @cpp: CPP handle */ void nfp_cpp_free(struct nfp_cpp *cpp) { … } /** * nfp_cpp_model() - Retrieve the Model ID of the NFP * @cpp: NFP CPP handle * * Return: NFP CPP Model ID */ u32 nfp_cpp_model(struct nfp_cpp *cpp) { … } /** * nfp_cpp_interface() - Retrieve the Interface ID of the NFP * @cpp: NFP CPP handle * * Return: NFP CPP Interface ID */ u16 nfp_cpp_interface(struct nfp_cpp *cpp) { … } /** * nfp_cpp_serial() - Retrieve the Serial ID of the NFP * @cpp: NFP CPP handle * @serial: Pointer to NFP serial number * * Return: Length of NFP serial number */ int nfp_cpp_serial(struct nfp_cpp *cpp, const u8 **serial) { … } #define NFP_IMB_TGTADDRESSMODECFG_MODE_of(_x) … #define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE … #define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_32_BIT … #define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_40_BIT … static int nfp_cpp_set_mu_locality_lsb(struct nfp_cpp *cpp) { … } unsigned int nfp_cpp_mu_locality_lsb(struct nfp_cpp *cpp) { … } /** * nfp_cpp_area_alloc_with_name() - allocate a new CPP area * @cpp: CPP device handle * @dest: NFP CPP ID * @name: Name of region * @address: Address of region * @size: Size of region * * Allocate and initialize a CPP area structure. The area must later * be locked down with an 'acquire' before it can be safely accessed. * * NOTE: @address and @size must be 32-bit aligned values. * * Return: NFP CPP area handle, or NULL */ struct nfp_cpp_area * nfp_cpp_area_alloc_with_name(struct nfp_cpp *cpp, u32 dest, const char *name, unsigned long long address, unsigned long size) { … } /** * nfp_cpp_area_alloc() - allocate a new CPP area * @cpp: CPP handle * @dest: CPP id * @address: Start address on CPP target * @size: Size of area in bytes * * Allocate and initialize a CPP area structure. The area must later * be locked down with an 'acquire' before it can be safely accessed. * * NOTE: @address and @size must be 32-bit aligned values. * * Return: NFP CPP Area handle, or NULL */ struct nfp_cpp_area * nfp_cpp_area_alloc(struct nfp_cpp *cpp, u32 dest, unsigned long long address, unsigned long size) { … } /** * nfp_cpp_area_alloc_acquire() - allocate a new CPP area and lock it down * @cpp: CPP handle * @name: Name of region * @dest: CPP id * @address: Start address on CPP target * @size: Size of area * * Allocate and initialize a CPP area structure, and lock it down so * that it can be accessed directly. * * NOTE: @address and @size must be 32-bit aligned values. * The area must also be 'released' when the structure is freed. * * Return: NFP CPP Area handle, or NULL */ struct nfp_cpp_area * nfp_cpp_area_alloc_acquire(struct nfp_cpp *cpp, const char *name, u32 dest, unsigned long long address, unsigned long size) { … } /** * nfp_cpp_area_free() - free up the CPP area * @area: CPP area handle * * Frees up memory resources held by the CPP area. */ void nfp_cpp_area_free(struct nfp_cpp_area *area) { … } static bool nfp_cpp_area_acquire_try(struct nfp_cpp_area *area, int *status) { … } static int __nfp_cpp_area_acquire(struct nfp_cpp_area *area) { … } /** * nfp_cpp_area_acquire() - lock down a CPP area for access * @area: CPP area handle * * Locks down the CPP area for a potential long term activity. Area * must always be locked down before being accessed. * * Return: 0, or -ERRNO */ int nfp_cpp_area_acquire(struct nfp_cpp_area *area) { … } /** * nfp_cpp_area_acquire_nonblocking() - lock down a CPP area for access * @area: CPP area handle * * Locks down the CPP area for a potential long term activity. Area * must always be locked down before being accessed. * * NOTE: Returns -EAGAIN is no area is available * * Return: 0, or -ERRNO */ int nfp_cpp_area_acquire_nonblocking(struct nfp_cpp_area *area) { … } /** * nfp_cpp_area_release() - release a locked down CPP area * @area: CPP area handle * * Releases a previously locked down CPP area. */ void nfp_cpp_area_release(struct nfp_cpp_area *area) { … } /** * nfp_cpp_area_release_free() - release CPP area and free it * @area: CPP area handle * * Releases CPP area and frees up memory resources held by the it. */ void nfp_cpp_area_release_free(struct nfp_cpp_area *area) { … } /** * nfp_cpp_area_read() - read data from CPP area * @area: CPP area handle * @offset: offset into CPP area * @kernel_vaddr: kernel address to put data into * @length: number of bytes to read * * Read data from indicated CPP region. * * NOTE: @offset and @length must be 32-bit aligned values. * Area must have been locked down with an 'acquire'. * * Return: length of io, or -ERRNO */ int nfp_cpp_area_read(struct nfp_cpp_area *area, unsigned long offset, void *kernel_vaddr, size_t length) { … } /** * nfp_cpp_area_write() - write data to CPP area * @area: CPP area handle * @offset: offset into CPP area * @kernel_vaddr: kernel address to read data from * @length: number of bytes to write * * Write data to indicated CPP region. * * NOTE: @offset and @length must be 32-bit aligned values. * Area must have been locked down with an 'acquire'. * * Return: length of io, or -ERRNO */ int nfp_cpp_area_write(struct nfp_cpp_area *area, unsigned long offset, const void *kernel_vaddr, size_t length) { … } /** * nfp_cpp_area_size() - return size of a CPP area * @cpp_area: CPP area handle * * Return: Size of the area */ size_t nfp_cpp_area_size(struct nfp_cpp_area *cpp_area) { … } /** * nfp_cpp_area_name() - return name of a CPP area * @cpp_area: CPP area handle * * Return: Name of the area, or NULL */ const char *nfp_cpp_area_name(struct nfp_cpp_area *cpp_area) { … } /** * nfp_cpp_area_priv() - return private struct for CPP area * @cpp_area: CPP area handle * * Return: Private data for the CPP area */ void *nfp_cpp_area_priv(struct nfp_cpp_area *cpp_area) { … } /** * nfp_cpp_area_cpp() - return CPP handle for CPP area * @cpp_area: CPP area handle * * Return: NFP CPP handle */ struct nfp_cpp *nfp_cpp_area_cpp(struct nfp_cpp_area *cpp_area) { … } /** * nfp_cpp_area_resource() - get resource * @area: CPP area handle * * NOTE: Area must have been locked down with an 'acquire'. * * Return: struct resource pointer, or NULL */ struct resource *nfp_cpp_area_resource(struct nfp_cpp_area *area) { … } /** * nfp_cpp_area_phys() - get physical address of CPP area * @area: CPP area handle * * NOTE: Area must have been locked down with an 'acquire'. * * Return: phy_addr_t of the area, or NULL */ phys_addr_t nfp_cpp_area_phys(struct nfp_cpp_area *area) { … } /** * nfp_cpp_area_iomem() - get IOMEM region for CPP area * @area: CPP area handle * * Returns an iomem pointer for use with readl()/writel() style * operations. * * NOTE: Area must have been locked down with an 'acquire'. * * Return: __iomem pointer to the area, or NULL */ void __iomem *nfp_cpp_area_iomem(struct nfp_cpp_area *area) { … } /** * nfp_cpp_area_readl() - Read a u32 word from an area * @area: CPP Area handle * @offset: Offset into area * @value: Pointer to read buffer * * Return: 0 on success, or -ERRNO */ int nfp_cpp_area_readl(struct nfp_cpp_area *area, unsigned long offset, u32 *value) { … } /** * nfp_cpp_area_writel() - Write a u32 word to an area * @area: CPP Area handle * @offset: Offset into area * @value: Value to write * * Return: 0 on success, or -ERRNO */ int nfp_cpp_area_writel(struct nfp_cpp_area *area, unsigned long offset, u32 value) { … } /** * nfp_cpp_area_readq() - Read a u64 word from an area * @area: CPP Area handle * @offset: Offset into area * @value: Pointer to read buffer * * Return: 0 on success, or -ERRNO */ int nfp_cpp_area_readq(struct nfp_cpp_area *area, unsigned long offset, u64 *value) { … } /** * nfp_cpp_area_writeq() - Write a u64 word to an area * @area: CPP Area handle * @offset: Offset into area * @value: Value to write * * Return: 0 on success, or -ERRNO */ int nfp_cpp_area_writeq(struct nfp_cpp_area *area, unsigned long offset, u64 value) { … } /** * nfp_cpp_area_fill() - fill a CPP area with a value * @area: CPP area * @offset: offset into CPP area * @value: value to fill with * @length: length of area to fill * * Fill indicated area with given value. * * Return: length of io, or -ERRNO */ int nfp_cpp_area_fill(struct nfp_cpp_area *area, unsigned long offset, u32 value, size_t length) { … } /** * nfp_cpp_area_cache_add() - Permanently reserve and area for the hot cache * @cpp: NFP CPP handle * @size: Size of the area - MUST BE A POWER OF 2. */ int nfp_cpp_area_cache_add(struct nfp_cpp *cpp, size_t size) { … } static struct nfp_cpp_area_cache * area_cache_get(struct nfp_cpp *cpp, u32 id, u64 addr, unsigned long *offset, size_t length) { … } static void area_cache_put(struct nfp_cpp *cpp, struct nfp_cpp_area_cache *cache) { … } static int __nfp_cpp_read(struct nfp_cpp *cpp, u32 destination, unsigned long long address, void *kernel_vaddr, size_t length) { … } /** * 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_write(struct nfp_cpp *cpp, u32 destination, unsigned long long address, const void *kernel_vaddr, size_t length) { … } /** * 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) { … } /* Return the correct CPP address, and fixup xpb_addr as needed. */ static u32 nfp_xpb_to_cpp(struct nfp_cpp *cpp, u32 *xpb_addr) { … } /** * nfp_xpb_readl() - Read a u32 word from a XPB location * @cpp: CPP device handle * @xpb_addr: Address for operation * @value: Pointer to read buffer * * Return: 0 on success, or -ERRNO */ int nfp_xpb_readl(struct nfp_cpp *cpp, u32 xpb_addr, u32 *value) { … } /** * nfp_xpb_writel() - Write a u32 word to a XPB location * @cpp: CPP device handle * @xpb_addr: Address for operation * @value: Value to write * * Return: 0 on success, or -ERRNO */ int nfp_xpb_writel(struct nfp_cpp *cpp, u32 xpb_addr, u32 value) { … } /** * nfp_xpb_writelm() - Modify bits of a 32-bit value from the XPB bus * @cpp: NFP CPP device handle * @xpb_tgt: XPB target and address * @mask: mask of bits to alter * @value: value to modify * * KERNEL: This operation is safe to call in interrupt or softirq context. * * Return: 0 on success, or -ERRNO */ int nfp_xpb_writelm(struct nfp_cpp *cpp, u32 xpb_tgt, u32 mask, u32 value) { … } /* Lockdep markers */ static struct lock_class_key nfp_cpp_resource_lock_key; static void nfp_cpp_dev_release(struct device *dev) { … } /** * nfp_cpp_from_operations() - Create a NFP CPP handle * from an operations structure * @ops: NFP CPP operations structure * @parent: Parent device * @priv: Private data of low-level implementation * * NOTE: On failure, cpp_ops->free will be called! * * Return: NFP CPP handle on success, ERR_PTR on failure */ struct nfp_cpp * nfp_cpp_from_operations(const struct nfp_cpp_operations *ops, struct device *parent, void *priv) { … } /** * nfp_cpp_priv() - Get the operations private data of a CPP handle * @cpp: CPP handle * * Return: Private data for the NFP CPP handle */ void *nfp_cpp_priv(struct nfp_cpp *cpp) { … } /** * nfp_cpp_device() - Get the Linux device handle of a CPP handle * @cpp: CPP handle * * Return: Device for the NFP CPP bus */ struct device *nfp_cpp_device(struct nfp_cpp *cpp) { … } #define NFP_EXPL_OP(func, expl, args...) … #define NFP_EXPL_OP_NR(func, expl, args...) … /** * nfp_cpp_explicit_acquire() - Acquire explicit access handle * @cpp: NFP CPP handle * * The 'data_ref' and 'signal_ref' values are useful when * constructing the NFP_EXPL_CSR1 and NFP_EXPL_POST values. * * Return: NFP CPP explicit handle */ struct nfp_cpp_explicit *nfp_cpp_explicit_acquire(struct nfp_cpp *cpp) { … } /** * nfp_cpp_explicit_set_target() - Set target fields for explicit * @expl: Explicit handle * @cpp_id: CPP ID field * @len: CPP Length field * @mask: CPP Mask field * * Return: 0, or -ERRNO */ int nfp_cpp_explicit_set_target(struct nfp_cpp_explicit *expl, u32 cpp_id, u8 len, u8 mask) { … } /** * nfp_cpp_explicit_set_data() - Set data fields for explicit * @expl: Explicit handle * @data_master: CPP Data Master field * @data_ref: CPP Data Ref field * * Return: 0, or -ERRNO */ int nfp_cpp_explicit_set_data(struct nfp_cpp_explicit *expl, u8 data_master, u16 data_ref) { … } /** * nfp_cpp_explicit_set_signal() - Set signal fields for explicit * @expl: Explicit handle * @signal_master: CPP Signal Master field * @signal_ref: CPP Signal Ref field * * Return: 0, or -ERRNO */ int nfp_cpp_explicit_set_signal(struct nfp_cpp_explicit *expl, u8 signal_master, u8 signal_ref) { … } /** * nfp_cpp_explicit_set_posted() - Set completion fields for explicit * @expl: Explicit handle * @posted: True for signaled completion, false otherwise * @siga: CPP Signal A field * @siga_mode: CPP Signal A Mode field * @sigb: CPP Signal B field * @sigb_mode: CPP Signal B Mode field * * Return: 0, or -ERRNO */ int nfp_cpp_explicit_set_posted(struct nfp_cpp_explicit *expl, int posted, u8 siga, enum nfp_cpp_explicit_signal_mode siga_mode, u8 sigb, enum nfp_cpp_explicit_signal_mode sigb_mode) { … } /** * nfp_cpp_explicit_put() - Set up the write (pull) data for a explicit access * @expl: NFP CPP Explicit handle * @buff: Data to have the target pull in the transaction * @len: Length of data, in bytes * * The 'len' parameter must be less than or equal to 128 bytes. * * If this function is called before the configuration * registers are set, it will return -EINVAL. * * Return: 0, or -ERRNO */ int nfp_cpp_explicit_put(struct nfp_cpp_explicit *expl, const void *buff, size_t len) { … } /** * nfp_cpp_explicit_do() - Execute a transaction, and wait for it to complete * @expl: NFP CPP Explicit handle * @address: Address to send in the explicit transaction * * If this function is called before the configuration * registers are set, it will return -1, with an errno of EINVAL. * * Return: 0, or -ERRNO */ int nfp_cpp_explicit_do(struct nfp_cpp_explicit *expl, u64 address) { … } /** * nfp_cpp_explicit_get() - Get the 'push' (read) data from a explicit access * @expl: NFP CPP Explicit handle * @buff: Data that the target pushed in the transaction * @len: Length of data, in bytes * * The 'len' parameter must be less than or equal to 128 bytes. * * If this function is called before all three configuration * registers are set, it will return -1, with an errno of EINVAL. * * If this function is called before nfp_cpp_explicit_do() * has completed, it will return -1, with an errno of EBUSY. * * Return: 0, or -ERRNO */ int nfp_cpp_explicit_get(struct nfp_cpp_explicit *expl, void *buff, size_t len) { … } /** * nfp_cpp_explicit_release() - Release explicit access handle * @expl: NFP CPP Explicit handle * */ void nfp_cpp_explicit_release(struct nfp_cpp_explicit *expl) { … } /** * nfp_cpp_explicit_cpp() - return CPP handle for CPP explicit * @cpp_explicit: CPP explicit handle * * Return: NFP CPP handle of the explicit */ struct nfp_cpp *nfp_cpp_explicit_cpp(struct nfp_cpp_explicit *cpp_explicit) { … } /** * nfp_cpp_explicit_priv() - return private struct for CPP explicit * @cpp_explicit: CPP explicit handle * * Return: private data of the explicit, or NULL */ void *nfp_cpp_explicit_priv(struct nfp_cpp_explicit *cpp_explicit) { … }