Message ID | 20210423035612.1048761-1-sr@denx.de |
---|---|
State | Superseded |
Delegated to: | Daniel Schwierzeck |
Headers | show |
Series | None | expand |
Hi Stefan, Am Freitag, den 23.04.2021, 05:56 +0200 schrieb Stefan Roese: > From: Aaron Williams <awilliams@marvell.com> > > Import misc remaining header files from 2013 U-Boot. These will be > used > by the later added drivers to support PCIe and networking on the MIPS > Octeon II / III platforms. > > Signed-off-by: Aaron Williams <awilliams@marvell.com> > Signed-off-by: Stefan Roese <sr@denx.de> > Cc: Aaron Williams <awilliams@marvell.com> > Cc: Chandrakala Chavva <cchavva@marvell.com> > Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com> > --- > v2: > - Add missing mach/octeon_qlm.h file (forgot to commit it in v1) > the patch didn't show up in patchwork. But when manually applying, there is still a build error due to missing mach/octeon_fdt.h > .../mach-octeon/include/mach/cvmx-address.h | 209 ++ > .../mach-octeon/include/mach/cvmx-cmd-queue.h | 441 +++ > .../mach-octeon/include/mach/cvmx-csr-enums.h | 87 + > arch/mips/mach-octeon/include/mach/cvmx-csr.h | 78 + > .../mach-octeon/include/mach/cvmx-error.h | 456 +++ > arch/mips/mach-octeon/include/mach/cvmx-fpa.h | 217 ++ > .../mips/mach-octeon/include/mach/cvmx-fpa1.h | 196 ++ > .../mips/mach-octeon/include/mach/cvmx-fpa3.h | 566 ++++ > .../include/mach/cvmx-global-resources.h | 213 ++ > arch/mips/mach-octeon/include/mach/cvmx-gmx.h | 16 + > .../mach-octeon/include/mach/cvmx-hwfau.h | 606 ++++ > .../mach-octeon/include/mach/cvmx-hwpko.h | 570 ++++ > arch/mips/mach-octeon/include/mach/cvmx-ilk.h | 154 + > arch/mips/mach-octeon/include/mach/cvmx-ipd.h | 233 ++ > .../mach-octeon/include/mach/cvmx-packet.h | 40 + > .../mips/mach-octeon/include/mach/cvmx-pcie.h | 279 ++ > arch/mips/mach-octeon/include/mach/cvmx-pip.h | 1080 ++++++ > .../include/mach/cvmx-pki-resources.h | 157 + > arch/mips/mach-octeon/include/mach/cvmx-pki.h | 970 ++++++ > .../mach/cvmx-pko-internal-ports-range.h | 43 + > .../include/mach/cvmx-pko3-queue.h | 175 + > arch/mips/mach-octeon/include/mach/cvmx-pow.h | 2991 > +++++++++++++++++ > arch/mips/mach-octeon/include/mach/cvmx-qlm.h | 304 ++ > .../mach-octeon/include/mach/cvmx-scratch.h | 113 + > arch/mips/mach-octeon/include/mach/cvmx-wqe.h | 1462 ++++++++ > .../mach-octeon/include/mach/octeon_qlm.h | 109 + > 26 files changed, 11765 insertions(+) > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-address.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-cmd- > queue.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-csr- > enums.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-csr.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-error.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-fpa.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-fpa1.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-fpa3.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-global- > resources.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-gmx.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-hwfau.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-hwpko.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-ilk.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-ipd.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-packet.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-pcie.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-pip.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-pki- > resources.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-pki.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-pko- > internal-ports-range.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-pko3- > queue.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-pow.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-qlm.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-scratch.h > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-wqe.h > create mode 100644 arch/mips/mach-octeon/include/mach/octeon_qlm.h > > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-address.h > b/arch/mips/mach-octeon/include/mach/cvmx-address.h > new file mode 100644 > index 000000000000..984f574a75bb > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-address.h > @@ -0,0 +1,209 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Typedefs and defines for working with Octeon physical addresses. > + */ > + > +#ifndef __CVMX_ADDRESS_H__ > +#define __CVMX_ADDRESS_H__ > + > +typedef enum { > + CVMX_MIPS_SPACE_XKSEG = 3LL, > + CVMX_MIPS_SPACE_XKPHYS = 2LL, > + CVMX_MIPS_SPACE_XSSEG = 1LL, > + CVMX_MIPS_SPACE_XUSEG = 0LL > +} cvmx_mips_space_t; > + > +typedef enum { > + CVMX_MIPS_XKSEG_SPACE_KSEG0 = 0LL, > + CVMX_MIPS_XKSEG_SPACE_KSEG1 = 1LL, > + CVMX_MIPS_XKSEG_SPACE_SSEG = 2LL, > + CVMX_MIPS_XKSEG_SPACE_KSEG3 = 3LL > +} cvmx_mips_xkseg_space_t; > + > +/* decodes <14:13> of a kseg3 window address */ > +typedef enum { > + CVMX_ADD_WIN_SCR = 0L, > + CVMX_ADD_WIN_DMA = 1L, > + CVMX_ADD_WIN_UNUSED = 2L, > + CVMX_ADD_WIN_UNUSED2 = 3L > +} cvmx_add_win_dec_t; > + > +/* decode within DMA space */ > +typedef enum { > + CVMX_ADD_WIN_DMA_ADD = 0L, > + CVMX_ADD_WIN_DMA_SENDMEM = 1L, > + /* store data must be normal DRAM memory space address in this > case */ > + CVMX_ADD_WIN_DMA_SENDDMA = 2L, > + /* see CVMX_ADD_WIN_DMA_SEND_DEC for data contents */ > + CVMX_ADD_WIN_DMA_SENDIO = 3L, > + /* store data must be normal IO space address in this case */ > + CVMX_ADD_WIN_DMA_SENDSINGLE = 4L, > + /* no write buffer data needed/used */ > +} cvmx_add_win_dma_dec_t; > + > +/** > + * Physical Address Decode > + * > + * Octeon-I HW never interprets this X (<39:36> reserved > + * for future expansion), software should set to 0. > + * > + * - 0x0 XXX0 0000 0000 to DRAM Cached > + * - 0x0 XXX0 0FFF FFFF > + * > + * - 0x0 XXX0 1000 0000 to Boot Bus Uncached (Converted > to 0x1 00X0 1000 0000 > + * - 0x0 XXX0 1FFF FFFF + > EJTAG to 0x1 00X0 1FFF FFFF) > + * > + * - 0x0 XXX0 2000 0000 to DRAM Cached > + * - 0x0 XXXF FFFF FFFF > + * > + * - 0x1 00X0 0000 0000 to Boot Bus Uncached > + * - 0x1 00XF FFFF FFFF > + * > + * - 0x1 01X0 0000 0000 to Other NCB Uncached > + * - 0x1 FFXF FFFF FFFF devices > + * > + * Decode of all Octeon addresses > + */ > +typedef union { > + u64 u64; > + struct { > + cvmx_mips_space_t R : 2; > + u64 offset : 62; > + } sva; > + > + struct { > + u64 zeroes : 33; > + u64 offset : 31; > + } suseg; > + > + struct { > + u64 ones : 33; > + cvmx_mips_xkseg_space_t sp : 2; > + u64 offset : 29; > + } sxkseg; > + > + struct { > + cvmx_mips_space_t R : 2; > + u64 cca : 3; > + u64 mbz : 10; > + u64 pa : 49; > + } sxkphys; > + > + struct { > + u64 mbz : 15; > + u64 is_io : 1; > + u64 did : 8; > + u64 unaddr : 4; > + u64 offset : 36; > + } sphys; > + > + struct { > + u64 zeroes : 24; > + u64 unaddr : 4; > + u64 offset : 36; > + } smem; > + > + struct { > + u64 mem_region : 2; > + u64 mbz : 13; > + u64 is_io : 1; > + u64 did : 8; > + u64 unaddr : 4; > + u64 offset : 36; > + } sio; > + > + struct { > + u64 ones : 49; > + cvmx_add_win_dec_t csrdec : 2; > + u64 addr : 13; > + } sscr; > + > + /* there should only be stores to IOBDMA space, no loads */ > + struct { > + u64 ones : 49; > + cvmx_add_win_dec_t csrdec : 2; > + u64 unused2 : 3; > + cvmx_add_win_dma_dec_t type : 3; > + u64 addr : 7; > + } sdma; > + > + struct { > + u64 didspace : 24; > + u64 unused : 40; > + } sfilldidspace; > +} cvmx_addr_t; > + > +/* These macros for used by 32 bit applications */ > + > +#define CVMX_MIPS32_SPACE_KSEG0 1l > +#define CVMX_ADD_SEG32(segment, add) (((s32)segment << 31) | > (s32)(add)) > + > +/* > + * Currently all IOs are performed using XKPHYS addressing. Linux > uses the > + * CvmMemCtl register to enable XKPHYS addressing to IO space from > user mode. > + * Future OSes may need to change the upper bits of IO addresses. > The > + * following define controls the upper two bits for all IO addresses > generated > + * by the simple executive library > + */ > +#define CVMX_IO_SEG CVMX_MIPS_SPACE_XKPHYS > + > +/* These macros simplify the process of creating common IO addresses > */ > +#define CVMX_ADD_SEG(segment, add) ((((u64)segment) << 62) | (add)) > + > +#define CVMX_ADD_IO_SEG(add) (add) > + > +#define CVMX_ADDR_DIDSPACE(did) (((CVMX_IO_SEG) << 22) | > ((1ULL) << 8) | (did)) > +#define CVMX_ADDR_DID(did) (CVMX_ADDR_DIDSPACE(did) << 40) > +#define CVMX_FULL_DID(did, subdid) (((did) << 3) | (subdid)) > + > +/* from include/ncb_rsl_id.v */ > +#define CVMX_OCT_DID_MIS 0ULL /* misc stuff */ > +#define CVMX_OCT_DID_GMX0 1ULL > +#define CVMX_OCT_DID_GMX1 2ULL > +#define CVMX_OCT_DID_PCI 3ULL > +#define CVMX_OCT_DID_KEY 4ULL > +#define CVMX_OCT_DID_FPA 5ULL > +#define CVMX_OCT_DID_DFA 6ULL > +#define CVMX_OCT_DID_ZIP 7ULL > +#define CVMX_OCT_DID_RNG 8ULL > +#define CVMX_OCT_DID_IPD 9ULL > +#define CVMX_OCT_DID_PKT 10ULL > +#define CVMX_OCT_DID_TIM 11ULL > +#define CVMX_OCT_DID_TAG 12ULL > +/* the rest are not on the IO bus */ > +#define CVMX_OCT_DID_L2C 16ULL > +#define CVMX_OCT_DID_LMC 17ULL > +#define CVMX_OCT_DID_SPX0 18ULL > +#define CVMX_OCT_DID_SPX1 19ULL > +#define CVMX_OCT_DID_PIP 20ULL > +#define CVMX_OCT_DID_ASX0 22ULL > +#define CVMX_OCT_DID_ASX1 23ULL > +#define CVMX_OCT_DID_IOB 30ULL > + > +#define CVMX_OCT_DID_PKT_SEND CVMX_FULL_DID(CVMX_OCT_DID_PKT > , 2ULL) > +#define CVMX_OCT_DID_TAG_SWTAG CVMX_FULL_DID(CVMX_OCT_DID_TAG > , 0ULL) > +#define CVMX_OCT_DID_TAG_TAG1 CVMX_FULL_DID(CVMX_OCT_DID_TAG > , 1ULL) > +#define CVMX_OCT_DID_TAG_TAG2 CVMX_FULL_DID(CVMX_OCT_DID_TAG > , 2ULL) > +#define CVMX_OCT_DID_TAG_TAG3 CVMX_FULL_DID(CVMX_OCT_DID_TAG > , 3ULL) > +#define CVMX_OCT_DID_TAG_NULL_RD CVMX_FULL_DID(CVMX_OCT_DID_TAG, > 4ULL) > +#define CVMX_OCT_DID_TAG_TAG5 CVMX_FULL_DID(CVMX_OCT_DID_TAG > , 5ULL) > +#define CVMX_OCT_DID_TAG_CSR CVMX_FULL_DID(CVMX_OCT_DID_TAG, 7ULL) > +#define CVMX_OCT_DID_FAU_FAI CVMX_FULL_DID(CVMX_OCT_DID_IOB, 0ULL) > +#define CVMX_OCT_DID_TIM_CSR CVMX_FULL_DID(CVMX_OCT_DID_TIM, 0ULL) > +#define CVMX_OCT_DID_KEY_RW CVMX_FULL_DID(CVMX_OCT_DID_KEY, 0ULL) > +#define CVMX_OCT_DID_PCI_6 CVMX_FULL_DID(CVMX_OCT_DID_PCI, 6ULL) > +#define CVMX_OCT_DID_MIS_BOO CVMX_FULL_DID(CVMX_OCT_DID_MIS, 0ULL) > +#define CVMX_OCT_DID_PCI_RML CVMX_FULL_DID(CVMX_OCT_DID_PCI, 0ULL) > +#define CVMX_OCT_DID_IPD_CSR CVMX_FULL_DID(CVMX_OCT_DID_IPD, 7ULL) > +#define CVMX_OCT_DID_DFA_CSR CVMX_FULL_DID(CVMX_OCT_DID_DFA, 7ULL) > +#define CVMX_OCT_DID_MIS_CSR CVMX_FULL_DID(CVMX_OCT_DID_MIS, 7ULL) > +#define CVMX_OCT_DID_ZIP_CSR CVMX_FULL_DID(CVMX_OCT_DID_ZIP, 0ULL) > + > +/* Cast to unsigned long long, mainly for use in printfs. */ > +#define CAST_ULL(v) ((unsigned long long)(v)) > + > +#define UNMAPPED_PTR(x) ((1ULL << 63) | (x)) > + > +#endif /* __CVMX_ADDRESS_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-cmd-queue.h > b/arch/mips/mach-octeon/include/mach/cvmx-cmd-queue.h > new file mode 100644 > index 000000000000..ddc294348cb4 > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-cmd-queue.h > @@ -0,0 +1,441 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Support functions for managing command queues used for > + * various hardware blocks. > + * > + * The common command queue infrastructure abstracts out the > + * software necessary for adding to Octeon's chained queue > + * structures. These structures are used for commands to the > + * PKO, ZIP, DFA, RAID, HNA, and DMA engine blocks. Although each > + * hardware unit takes commands and CSRs of different types, > + * they all use basic linked command buffers to store the > + * pending request. In general, users of the CVMX API don't > + * call cvmx-cmd-queue functions directly. Instead the hardware > + * unit specific wrapper should be used. The wrappers perform > + * unit specific validation and CSR writes to submit the > + * commands. > + * > + * Even though most software will never directly interact with > + * cvmx-cmd-queue, knowledge of its internal workings can help > + * in diagnosing performance problems and help with debugging. > + * > + * Command queue pointers are stored in a global named block > + * called "cvmx_cmd_queues". Except for the PKO queues, each > + * hardware queue is stored in its own cache line to reduce SMP > + * contention on spin locks. The PKO queues are stored such that > + * every 16th queue is next to each other in memory. This scheme > + * allows for queues being in separate cache lines when there > + * are low number of queues per port. With 16 queues per port, > + * the first queue for each port is in the same cache area. The > + * second queues for each port are in another area, etc. This > + * allows software to implement very efficient lockless PKO with > + * 16 queues per port using a minimum of cache lines per core. > + * All queues for a given core will be isolated in the same > + * cache area. > + * > + * In addition to the memory pointer layout, cvmx-cmd-queue > + * provides an optimized fair ll/sc locking mechanism for the > + * queues. The lock uses a "ticket / now serving" model to > + * maintain fair order on contended locks. In addition, it uses > + * predicted locking time to limit cache contention. When a core > + * know it must wait in line for a lock, it spins on the > + * internal cycle counter to completely eliminate any causes of > + * bus traffic. > + */ > + > +#ifndef __CVMX_CMD_QUEUE_H__ > +#define __CVMX_CMD_QUEUE_H__ > + > +/** > + * By default we disable the max depth support. Most programs > + * don't use it and it slows down the command queue processing > + * significantly. > + */ > +#ifndef CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH > +#define CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH 0 > +#endif > + > +/** > + * Enumeration representing all hardware blocks that use command > + * queues. Each hardware block has up to 65536 sub identifiers for > + * multiple command queues. Not all chips support all hardware > + * units. > + */ > +typedef enum { > + CVMX_CMD_QUEUE_PKO_BASE = 0x00000, > +#define > CVMX_CMD_QUEUE_PKO(queue) > \ > + ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_PKO_BASE + (0xffff & > (queue)))) > + CVMX_CMD_QUEUE_ZIP = 0x10000, > +#define > CVMX_CMD_QUEUE_ZIP_QUE(queue) > \ > + ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_ZIP + (0xffff & > (queue)))) > + CVMX_CMD_QUEUE_DFA = 0x20000, > + CVMX_CMD_QUEUE_RAID = 0x30000, > + CVMX_CMD_QUEUE_DMA_BASE = 0x40000, > +#define > CVMX_CMD_QUEUE_DMA(queue) > \ > + ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_DMA_BASE + (0xffff & > (queue)))) > + CVMX_CMD_QUEUE_BCH = 0x50000, > +#define CVMX_CMD_QUEUE_BCH(queue) > ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_BCH + (0xffff & (queue)))) > + CVMX_CMD_QUEUE_HNA = 0x60000, > + CVMX_CMD_QUEUE_END = 0x70000, > +} cvmx_cmd_queue_id_t; > + > +#define CVMX_CMD_QUEUE_ZIP3_QUE(node, > queue) \ > + ((cvmx_cmd_queue_id_t)((node) << 24 | CVMX_CMD_QUEUE_ZIP | > (0xffff & (queue)))) > + > +/** > + * Command write operations can fail if the command queue needs > + * a new buffer and the associated FPA pool is empty. It can also > + * fail if the number of queued command words reaches the maximum > + * set at initialization. > + */ > +typedef enum { > + CVMX_CMD_QUEUE_SUCCESS = 0, > + CVMX_CMD_QUEUE_NO_MEMORY = -1, > + CVMX_CMD_QUEUE_FULL = -2, > + CVMX_CMD_QUEUE_INVALID_PARAM = -3, > + CVMX_CMD_QUEUE_ALREADY_SETUP = -4, > +} cvmx_cmd_queue_result_t; > + > +typedef struct { > + /* First 64-bit word: */ > + u64 fpa_pool : 16; > + u64 base_paddr : 48; > + s32 index; > + u16 max_depth; > + u16 pool_size_m1; > +} __cvmx_cmd_queue_state_t; > + > +/** > + * command-queue locking uses a fair ticket spinlock algo, > + * with 64-bit tickets for endianness-neutrality and > + * counter overflow protection. > + * Lock is free when both counters are of equal value. > + */ > +typedef struct { > + u64 ticket; > + u64 now_serving; > +} __cvmx_cmd_queue_lock_t; > + > +/** > + * @INTERNAL > + * This structure contains the global state of all command queues. > + * It is stored in a bootmem named block and shared by all > + * applications running on Octeon. Tickets are stored in a different > + * cache line that queue information to reduce the contention on the > + * ll/sc used to get a ticket. If this is not the case, the update > + * of queue state causes the ll/sc to fail quite often. > + */ > +typedef struct { > + __cvmx_cmd_queue_lock_t lock[(CVMX_CMD_QUEUE_END >> 16) * 256]; > + __cvmx_cmd_queue_state_t state[(CVMX_CMD_QUEUE_END >> 16) * > 256]; > +} __cvmx_cmd_queue_all_state_t; > + > +extern __cvmx_cmd_queue_all_state_t > *__cvmx_cmd_queue_state_ptrs[CVMX_MAX_NODES]; > + > +/** > + * @INTERNAL > + * Internal function to handle the corner cases > + * of adding command words to a queue when the current > + * block is getting full. > + */ > +cvmx_cmd_queue_result_t > __cvmx_cmd_queue_write_raw(cvmx_cmd_queue_id_t queue_id, > + __cvmx_cmd_queue_sta > te_t *qptr, int cmd_count, > + const u64 *cmds); > + > +/** > + * Initialize a command queue for use. The initial FPA buffer is > + * allocated and the hardware unit is configured to point to the > + * new command queue. > + * > + * @param queue_id Hardware command queue to initialize. > + * @param max_depth Maximum outstanding commands that can be queued. > + * @param fpa_pool FPA pool the command queues should come from. > + * @param pool_size Size of each buffer in the FPA pool (bytes) > + * > + * @return CVMX_CMD_QUEUE_SUCCESS or a failure code > + */ > +cvmx_cmd_queue_result_t > cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id, int > max_depth, > + int fpa_pool, int > pool_size); > + > +/** > + * Shutdown a queue a free it's command buffers to the FPA. The > + * hardware connected to the queue must be stopped before this > + * function is called. > + * > + * @param queue_id Queue to shutdown > + * > + * @return CVMX_CMD_QUEUE_SUCCESS or a failure code > + */ > +cvmx_cmd_queue_result_t cvmx_cmd_queue_shutdown(cvmx_cmd_queue_id_t > queue_id); > + > +/** > + * Return the number of command words pending in the queue. This > + * function may be relatively slow for some hardware units. > + * > + * @param queue_id Hardware command queue to query > + * > + * @return Number of outstanding commands > + */ > +int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id); > + > +/** > + * Return the command buffer to be written to. The purpose of this > + * function is to allow CVMX routine access to the low level buffer > + * for initial hardware setup. User applications should not call > this > + * function directly. > + * > + * @param queue_id Command queue to query > + * > + * @return Command buffer or NULL on failure > + */ > +void *cvmx_cmd_queue_buffer(cvmx_cmd_queue_id_t queue_id); > + > +/** > + * @INTERNAL > + * Retrieve or allocate command queue state named block > + */ > +cvmx_cmd_queue_result_t __cvmx_cmd_queue_init_state_ptr(unsigned int > node); > + > +/** > + * @INTERNAL > + * Get the index into the state arrays for the supplied queue id. > + * > + * @param queue_id Queue ID to get an index for > + * > + * @return Index into the state arrays > + */ > +static inline unsigned int > __cvmx_cmd_queue_get_index(cvmx_cmd_queue_id_t queue_id) > +{ > + /* Warning: This code currently only works with devices that > have 256 > + * queues or less. Devices with more than 16 queues are laid > out in > + * memory to allow cores quick access to every 16th queue. This > reduces > + * cache thrashing when you are running 16 queues per port to > support > + * lockless operation > + */ > + unsigned int unit = (queue_id >> 16) & 0xff; > + unsigned int q = (queue_id >> 4) & 0xf; > + unsigned int core = queue_id & 0xf; > + > + return (unit << 8) | (core << 4) | q; > +} > + > +static inline int __cvmx_cmd_queue_get_node(cvmx_cmd_queue_id_t > queue_id) > +{ > + unsigned int node = queue_id >> 24; > + return node; > +} > + > +/** > + * @INTERNAL > + * Lock the supplied queue so nobody else is updating it at the same > + * time as us. > + * > + * @param queue_id Queue ID to lock > + * > + */ > +static inline void __cvmx_cmd_queue_lock(cvmx_cmd_queue_id_t > queue_id) > +{ > +} > + > +/** > + * @INTERNAL > + * Unlock the queue, flushing all writes. > + * > + * @param queue_id Queue ID to lock > + * > + */ > +static inline void __cvmx_cmd_queue_unlock(cvmx_cmd_queue_id_t > queue_id) > +{ > + CVMX_SYNCWS; /* nudge out the unlock. */ > +} > + > +/** > + * @INTERNAL > + * Initialize a command-queue lock to "unlocked" state. > + */ > +static inline void __cvmx_cmd_queue_lock_init(cvmx_cmd_queue_id_t > queue_id) > +{ > + unsigned int index = __cvmx_cmd_queue_get_index(queue_id); > + unsigned int node = __cvmx_cmd_queue_get_node(queue_id); > + > + __cvmx_cmd_queue_state_ptrs[node]->lock[index] = > (__cvmx_cmd_queue_lock_t){ 0, 0 }; > + CVMX_SYNCWS; > +} > + > +/** > + * @INTERNAL > + * Get the queue state structure for the given queue id > + * > + * @param queue_id Queue id to get > + * > + * @return Queue structure or NULL on failure > + */ > +static inline __cvmx_cmd_queue_state_t > *__cvmx_cmd_queue_get_state(cvmx_cmd_queue_id_t queue_id) > +{ > + unsigned int index; > + unsigned int node; > + __cvmx_cmd_queue_state_t *qptr; > + > + node = __cvmx_cmd_queue_get_node(queue_id); > + index = __cvmx_cmd_queue_get_index(queue_id); > + > + if (cvmx_unlikely(!__cvmx_cmd_queue_state_ptrs[node])) > + __cvmx_cmd_queue_init_state_ptr(node); > + > + qptr = &__cvmx_cmd_queue_state_ptrs[node]->state[index]; > + return qptr; > +} > + > +/** > + * Write an arbitrary number of command words to a command queue. > + * This is a generic function; the fixed number of command word > + * functions yield higher performance. > + * > + * @param queue_id Hardware command queue to write to > + * @param use_locking > + * Use internal locking to ensure exclusive access > for queue > + * updates. If you don't use this locking you must > ensure > + * exclusivity some other way. Locking is strongly > recommended. > + * @param cmd_count Number of command words to write > + * @param cmds Array of commands to write > + * > + * @return CVMX_CMD_QUEUE_SUCCESS or a failure code > + */ > +static inline cvmx_cmd_queue_result_t > +cvmx_cmd_queue_write(cvmx_cmd_queue_id_t queue_id, bool use_locking, > int cmd_count, const u64 *cmds) > +{ > + cvmx_cmd_queue_result_t ret = CVMX_CMD_QUEUE_SUCCESS; > + u64 *cmd_ptr; > + > + __cvmx_cmd_queue_state_t *qptr = > __cvmx_cmd_queue_get_state(queue_id); > + > + /* Make sure nobody else is updating the same queue */ > + if (cvmx_likely(use_locking)) > + __cvmx_cmd_queue_lock(queue_id); > + > + /* Most of the time there is lots of free words in current > block */ > + if (cvmx_unlikely((qptr->index + cmd_count) >= qptr- > >pool_size_m1)) { > + /* The rare case when nearing end of block */ > + ret = __cvmx_cmd_queue_write_raw(queue_id, qptr, > cmd_count, cmds); > + } else { > + cmd_ptr = (u64 *)cvmx_phys_to_ptr((u64)qptr- > >base_paddr); > + /* Loop easy for compiler to unroll for the likely case > */ > + while (cmd_count > 0) { > + cmd_ptr[qptr->index++] = *cmds++; > + cmd_count--; > + } > + } > + > + /* All updates are complete. Release the lock and return */ > + if (cvmx_likely(use_locking)) > + __cvmx_cmd_queue_unlock(queue_id); > + else > + CVMX_SYNCWS; > + > + return ret; > +} > + > +/** > + * Simple function to write two command words to a command queue. > + * > + * @param queue_id Hardware command queue to write to > + * @param use_locking > + * Use internal locking to ensure exclusive access > for queue > + * updates. If you don't use this locking you must > ensure > + * exclusivity some other way. Locking is strongly > recommended. > + * @param cmd1 Command > + * @param cmd2 Command > + * > + * @return CVMX_CMD_QUEUE_SUCCESS or a failure code > + */ > +static inline cvmx_cmd_queue_result_t > cvmx_cmd_queue_write2(cvmx_cmd_queue_id_t queue_id, > + bool > use_locking, u64 cmd1, u64 cmd2) > +{ > + cvmx_cmd_queue_result_t ret = CVMX_CMD_QUEUE_SUCCESS; > + u64 *cmd_ptr; > + > + __cvmx_cmd_queue_state_t *qptr = > __cvmx_cmd_queue_get_state(queue_id); > + > + /* Make sure nobody else is updating the same queue */ > + if (cvmx_likely(use_locking)) > + __cvmx_cmd_queue_lock(queue_id); > + > + if (cvmx_unlikely((qptr->index + 2) >= qptr->pool_size_m1)) { > + /* The rare case when nearing end of block */ > + u64 cmds[2]; > + > + cmds[0] = cmd1; > + cmds[1] = cmd2; > + ret = __cvmx_cmd_queue_write_raw(queue_id, qptr, 2, > cmds); > + } else { > + /* Likely case to work fast */ > + cmd_ptr = (u64 *)cvmx_phys_to_ptr((u64)qptr- > >base_paddr); > + cmd_ptr += qptr->index; > + qptr->index += 2; > + cmd_ptr[0] = cmd1; > + cmd_ptr[1] = cmd2; > + } > + > + /* All updates are complete. Release the lock and return */ > + if (cvmx_likely(use_locking)) > + __cvmx_cmd_queue_unlock(queue_id); > + else > + CVMX_SYNCWS; > + > + return ret; > +} > + > +/** > + * Simple function to write three command words to a command queue. > + * > + * @param queue_id Hardware command queue to write to > + * @param use_locking > + * Use internal locking to ensure exclusive access > for queue > + * updates. If you don't use this locking you must > ensure > + * exclusivity some other way. Locking is strongly > recommended. > + * @param cmd1 Command > + * @param cmd2 Command > + * @param cmd3 Command > + * > + * @return CVMX_CMD_QUEUE_SUCCESS or a failure code > + */ > +static inline cvmx_cmd_queue_result_t > +cvmx_cmd_queue_write3(cvmx_cmd_queue_id_t queue_id, bool > use_locking, u64 cmd1, u64 cmd2, u64 cmd3) > +{ > + cvmx_cmd_queue_result_t ret = CVMX_CMD_QUEUE_SUCCESS; > + __cvmx_cmd_queue_state_t *qptr = > __cvmx_cmd_queue_get_state(queue_id); > + u64 *cmd_ptr; > + > + /* Make sure nobody else is updating the same queue */ > + if (cvmx_likely(use_locking)) > + __cvmx_cmd_queue_lock(queue_id); > + > + if (cvmx_unlikely((qptr->index + 3) >= qptr->pool_size_m1)) { > + /* Most of the time there is lots of free words in > current block */ > + u64 cmds[3]; > + > + cmds[0] = cmd1; > + cmds[1] = cmd2; > + cmds[2] = cmd3; > + ret = __cvmx_cmd_queue_write_raw(queue_id, qptr, 3, > cmds); > + } else { > + cmd_ptr = (u64 *)cvmx_phys_to_ptr((u64)qptr- > >base_paddr); > + cmd_ptr += qptr->index; > + qptr->index += 3; > + cmd_ptr[0] = cmd1; > + cmd_ptr[1] = cmd2; > + cmd_ptr[2] = cmd3; > + } > + > + /* All updates are complete. Release the lock and return */ > + if (cvmx_likely(use_locking)) > + __cvmx_cmd_queue_unlock(queue_id); > + else > + CVMX_SYNCWS; > + > + return ret; > +} > + > +#endif /* __CVMX_CMD_QUEUE_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-csr-enums.h > b/arch/mips/mach-octeon/include/mach/cvmx-csr-enums.h > new file mode 100644 > index 000000000000..a8625b4228ac > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-csr-enums.h > @@ -0,0 +1,87 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Definitions for enumerations used with Octeon CSRs. > + */ > + > +#ifndef __CVMX_CSR_ENUMS_H__ > +#define __CVMX_CSR_ENUMS_H__ > + > +typedef enum { > + CVMX_IPD_OPC_MODE_STT = 0LL, > + CVMX_IPD_OPC_MODE_STF = 1LL, > + CVMX_IPD_OPC_MODE_STF1_STT = 2LL, > + CVMX_IPD_OPC_MODE_STF2_STT = 3LL > +} cvmx_ipd_mode_t; > + > +/** > + * Enumeration representing the amount of packet processing > + * and validation performed by the input hardware. > + */ > +typedef enum { > + CVMX_PIP_PORT_CFG_MODE_NONE = 0ull, > + CVMX_PIP_PORT_CFG_MODE_SKIPL2 = 1ull, > + CVMX_PIP_PORT_CFG_MODE_SKIPIP = 2ull > +} cvmx_pip_port_parse_mode_t; > + > +/** > + * This enumeration controls how a QoS watcher matches a packet. > + * > + * @deprecated This enumeration was used with > cvmx_pip_config_watcher which has > + * been deprecated. > + */ > +typedef enum { > + CVMX_PIP_QOS_WATCH_DISABLE = 0ull, > + CVMX_PIP_QOS_WATCH_PROTNH = 1ull, > + CVMX_PIP_QOS_WATCH_TCP = 2ull, > + CVMX_PIP_QOS_WATCH_UDP = 3ull > +} cvmx_pip_qos_watch_types; > + > +/** > + * This enumeration is used in PIP tag config to control how > + * POW tags are generated by the hardware. > + */ > +typedef enum { > + CVMX_PIP_TAG_MODE_TUPLE = 0ull, > + CVMX_PIP_TAG_MODE_MASK = 1ull, > + CVMX_PIP_TAG_MODE_IP_OR_MASK = 2ull, > + CVMX_PIP_TAG_MODE_TUPLE_XOR_MASK = 3ull > +} cvmx_pip_tag_mode_t; > + > +/** > + * Tag type definitions > + */ > +typedef enum { > + CVMX_POW_TAG_TYPE_ORDERED = 0L, > + CVMX_POW_TAG_TYPE_ATOMIC = 1L, > + CVMX_POW_TAG_TYPE_NULL = 2L, > + CVMX_POW_TAG_TYPE_NULL_NULL = 3L > +} cvmx_pow_tag_type_t; > + > +/** > + * LCR bits 0 and 1 control the number of bits per character. See > the following table for encodings: > + * > + * - 00 = 5 bits (bits 0-4 sent) > + * - 01 = 6 bits (bits 0-5 sent) > + * - 10 = 7 bits (bits 0-6 sent) > + * - 11 = 8 bits (all bits sent) > + */ > +typedef enum { > + CVMX_UART_BITS5 = 0, > + CVMX_UART_BITS6 = 1, > + CVMX_UART_BITS7 = 2, > + CVMX_UART_BITS8 = 3 > +} cvmx_uart_bits_t; > + > +typedef enum { > + CVMX_UART_IID_NONE = 1, > + CVMX_UART_IID_RX_ERROR = 6, > + CVMX_UART_IID_RX_DATA = 4, > + CVMX_UART_IID_RX_TIMEOUT = 12, > + CVMX_UART_IID_TX_EMPTY = 2, > + CVMX_UART_IID_MODEM = 0, > + CVMX_UART_IID_BUSY = 7 > +} cvmx_uart_iid_t; > + > +#endif /* __CVMX_CSR_ENUMS_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-csr.h > b/arch/mips/mach-octeon/include/mach/cvmx-csr.h > new file mode 100644 > index 000000000000..730d54bb9278 > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-csr.h > @@ -0,0 +1,78 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Configuration and status register (CSR) address and type > definitions for > + * Octoen. > + */ > + > +#ifndef __CVMX_CSR_H__ > +#define __CVMX_CSR_H__ > + > +#include "cvmx-csr-enums.h" > +#include "cvmx-pip-defs.h" > + > +typedef cvmx_pip_prt_cfgx_t cvmx_pip_port_cfg_t; > + > +/* The CSRs for bootbus region zero used to be independent of the > + other 1-7. As of SDK 1.7.0 these were combined. These macros > + are for backwards compactability */ > +#define CVMX_MIO_BOOT_REG_CFG0 CVMX_MIO_BOOT_REG_CFGX(0) > +#define CVMX_MIO_BOOT_REG_TIM0 CVMX_MIO_BOOT_REG_TIMX(0) > + > +/* The CN3XXX and CN58XX chips used to not have a LMC number > + passed to the address macros. These are here to supply backwards > + compatibility with old code. Code should really use the new > addresses > + with bus arguments for support on other chips */ > +#define CVMX_LMC_BIST_CTL CVMX_LMCX_BIST_CTL(0) > +#define CVMX_LMC_BIST_RESULT CVMX_LMCX_BIST_RESULT(0) > +#define CVMX_LMC_COMP_CTL CVMX_LMCX_COMP_CTL(0) > +#define CVMX_LMC_CTL CVMX_LMCX_CTL(0) > +#define CVMX_LMC_CTL1 CVMX_LMCX_CTL1(0) > +#define CVMX_LMC_DCLK_CNT_HI CVMX_LMCX_DCLK_CNT_HI(0) > +#define CVMX_LMC_DCLK_CNT_LO CVMX_LMCX_DCLK_CNT_LO(0) > +#define CVMX_LMC_DCLK_CTL CVMX_LMCX_DCLK_CTL(0) > +#define CVMX_LMC_DDR2_CTL CVMX_LMCX_DDR2_CTL(0) > +#define CVMX_LMC_DELAY_CFG CVMX_LMCX_DELAY_CFG(0) > +#define CVMX_LMC_DLL_CTL CVMX_LMCX_DLL_CTL(0) > +#define CVMX_LMC_DUAL_MEMCFG CVMX_LMCX_DUAL_MEMCFG(0) > +#define CVMX_LMC_ECC_SYND CVMX_LMCX_ECC_SYND(0) > +#define CVMX_LMC_FADR CVMX_LMCX_FADR(0) > +#define CVMX_LMC_IFB_CNT_HI CVMX_LMCX_IFB_CNT_HI(0) > +#define CVMX_LMC_IFB_CNT_LO CVMX_LMCX_IFB_CNT_LO(0) > +#define CVMX_LMC_MEM_CFG0 CVMX_LMCX_MEM_CFG0(0) > +#define CVMX_LMC_MEM_CFG1 CVMX_LMCX_MEM_CFG1(0) > +#define CVMX_LMC_OPS_CNT_HI CVMX_LMCX_OPS_CNT_HI(0) > +#define CVMX_LMC_OPS_CNT_LO CVMX_LMCX_OPS_CNT_LO(0) > +#define CVMX_LMC_PLL_BWCTL CVMX_LMCX_PLL_BWCTL(0) > +#define CVMX_LMC_PLL_CTL CVMX_LMCX_PLL_CTL(0) > +#define CVMX_LMC_PLL_STATUS CVMX_LMCX_PLL_STATUS(0) > +#define CVMX_LMC_READ_LEVEL_CTL CVMX_LMCX_READ_LEVEL_CTL(0) > +#define CVMX_LMC_READ_LEVEL_DBG CVMX_LMCX_READ_LEVEL_DBG(0) > +#define CVMX_LMC_READ_LEVEL_RANKX CVMX_LMCX_READ_LEVEL_RANKX(0) > +#define CVMX_LMC_RODT_COMP_CTL CVMX_LMCX_RODT_COMP_CTL(0) > +#define CVMX_LMC_RODT_CTL CVMX_LMCX_RODT_CTL(0) > +#define CVMX_LMC_WODT_CTL CVMX_LMCX_WODT_CTL0(0) > +#define CVMX_LMC_WODT_CTL0 CVMX_LMCX_WODT_CTL0(0) > +#define CVMX_LMC_WODT_CTL1 CVMX_LMCX_WODT_CTL1(0) > + > +/* The CN3XXX and CN58XX chips used to not have a TWSI bus number > + passed to the address macros. These are here to supply backwards > + compatibility with old code. Code should really use the new > addresses > + with bus arguments for support on other chips */ > +#define CVMX_MIO_TWS_INT CVMX_MIO_TWSX_INT(0) > +#define CVMX_MIO_TWS_SW_TWSI CVMX_MIO_TWSX_SW_TWSI(0) > +#define CVMX_MIO_TWS_SW_TWSI_EXT CVMX_MIO_TWSX_SW_TWSI_EXT(0) > +#define CVMX_MIO_TWS_TWSI_SW CVMX_MIO_TWSX_TWSI_SW(0) > + > +/* The CN3XXX and CN58XX chips used to not have a SMI/MDIO bus > number > + passed to the address macros. These are here to supply backwards > + compatibility with old code. Code should really use the new > addresses > + with bus arguments for support on other chips */ > +#define CVMX_SMI_CLK CVMX_SMIX_CLK(0) > +#define CVMX_SMI_CMD CVMX_SMIX_CMD(0) > +#define CVMX_SMI_EN CVMX_SMIX_EN(0) > +#define CVMX_SMI_RD_DAT CVMX_SMIX_RD_DAT(0) > +#define CVMX_SMI_WR_DAT CVMX_SMIX_WR_DAT(0) > + > +#endif /* __CVMX_CSR_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-error.h > b/arch/mips/mach-octeon/include/mach/cvmx-error.h > new file mode 100644 > index 000000000000..9a13ed422484 > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-error.h > @@ -0,0 +1,456 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Interface to the Octeon extended error status. > + */ > + > +#ifndef __CVMX_ERROR_H__ > +#define __CVMX_ERROR_H__ > + > +/** > + * There are generally many error status bits associated with a > + * single logical group. The enumeration below is used to > + * communicate high level groups to the error infastructure so > + * error status bits can be enable or disabled in large groups. > + */ > +typedef enum { > + CVMX_ERROR_GROUP_INTERNAL, > + CVMX_ERROR_GROUP_L2C, > + CVMX_ERROR_GROUP_ETHERNET, > + CVMX_ERROR_GROUP_MGMT_PORT, > + CVMX_ERROR_GROUP_PCI, > + CVMX_ERROR_GROUP_SRIO, > + CVMX_ERROR_GROUP_USB, > + CVMX_ERROR_GROUP_LMC, > + CVMX_ERROR_GROUP_ILK, > + CVMX_ERROR_GROUP_DFM, > + CVMX_ERROR_GROUP_ILA, > +} cvmx_error_group_t; > + > +/** > + * Flags representing special handling for some error registers. > + * These flags are passed to cvmx_error_initialize() to control > + * the handling of bits where the same flags were passed to the > + * added cvmx_error_info_t. > + */ > +typedef enum { > + CVMX_ERROR_TYPE_NONE = 0, > + CVMX_ERROR_TYPE_SBE = 1 << 0, > + CVMX_ERROR_TYPE_DBE = 1 << 1, > +} cvmx_error_type_t; > + > +/** > + * When registering for interest in an error status register, the > + * type of the register needs to be known by cvmx-error. Most > + * registers are either IO64 or IO32, but some blocks contain > + * registers that can't be directly accessed. A good example of > + * would be PCIe extended error state stored in config space. > + */ > +typedef enum { > + __CVMX_ERROR_REGISTER_NONE, > + CVMX_ERROR_REGISTER_IO64, > + CVMX_ERROR_REGISTER_IO32, > + CVMX_ERROR_REGISTER_PCICONFIG, > + CVMX_ERROR_REGISTER_SRIOMAINT, > +} cvmx_error_register_t; > + > +struct cvmx_error_info; > +/** > + * Error handling functions must have the following prototype. > + */ > +typedef int (*cvmx_error_func_t)(const struct cvmx_error_info > *info); > + > +/** > + * This structure is passed to all error handling functions. > + */ > +typedef struct cvmx_error_info { > + cvmx_error_register_t reg_type; > + u64 status_addr; > + u64 status_mask; > + u64 enable_addr; > + u64 enable_mask; > + cvmx_error_type_t flags; > + cvmx_error_group_t group; > + int group_index; > + cvmx_error_func_t func; > + u64 user_info; > + struct { > + cvmx_error_register_t reg_type; > + u64 status_addr; > + u64 status_mask; > + } parent; > +} cvmx_error_info_t; > + > +/** > + * Initialize the error status system. This should be called once > + * before any other functions are called. This function adds default > + * handlers for most all error events but does not enable them. > Later > + * calls to cvmx_error_enable() are needed. > + * > + * @param flags Optional flags. > + * > + * @return Zero on success, negative on failure. > + */ > +int cvmx_error_initialize(void); > + > +/** > + * Poll the error status registers and call the appropriate error > + * handlers. This should be called in the RSL interrupt handler > + * for your application or operating system. > + * > + * @return Number of error handlers called. Zero means this call > + * found no errors and was spurious. > + */ > +int cvmx_error_poll(void); > + > +/** > + * Register to be called when an error status bit is set. Most users > + * will not need to call this function as cvmx_error_initialize() > + * registers default handlers for most error conditions. This > function > + * is normally used to add more handlers without changing the > existing > + * handlers. > + * > + * @param new_info Information about the handler for a error > register. The > + * structure passed is copied and can be destroyed > after the > + * call. All members of the structure must be > populated, even the > + * parent information. > + * > + * @return Zero on success, negative on failure. > + */ > +int cvmx_error_add(const cvmx_error_info_t *new_info); > + > +/** > + * Remove all handlers for a status register and mask. Normally > + * this function should not be called. Instead a new handler should > be > + * installed to replace the existing handler. In the even that all > + * reporting of a error bit should be removed, then use this > + * function. > + * > + * @param reg_type Type of the status register to remove > + * @param status_addr > + * Status register to remove. > + * @param status_mask > + * All handlers for this status register with this > mask will be > + * removed. > + * @param old_info If not NULL, this is filled with information > about the handler > + * that was removed. > + * > + * @return Zero on success, negative on failure (not found). > + */ > +int cvmx_error_remove(cvmx_error_register_t reg_type, u64 > status_addr, u64 status_mask, > + cvmx_error_info_t *old_info); > + > +/** > + * Change the function and user_info for an existing error status > + * register. This function should be used to replace the default > + * handler with an application specific version as needed. > + * > + * @param reg_type Type of the status register to change > + * @param status_addr > + * Status register to change. > + * @param status_mask > + * All handlers for this status register with this > mask will be > + * changed. > + * @param new_func New function to use to handle the error status > + * @param new_user_info > + * New user info parameter for the function > + * @param old_func If not NULL, the old function is returned. Useful > for restoring > + * the old handler. > + * @param old_user_info > + * If not NULL, the old user info parameter. > + * > + * @return Zero on success, negative on failure > + */ > +int cvmx_error_change_handler(cvmx_error_register_t reg_type, u64 > status_addr, u64 status_mask, > + cvmx_error_func_t new_func, u64 > new_user_info, > + cvmx_error_func_t *old_func, u64 > *old_user_info); > + > +/** > + * Enable all error registers for a logical group. This should be > + * called whenever a logical group is brought online. > + * > + * @param group Logical group to enable > + * @param group_index > + * Index for the group as defined in the > cvmx_error_group_t > + * comments. > + * > + * @return Zero on success, negative on failure. > + */ > +/* > + * Rather than conditionalize the calls throughout the executive to > not enable > + * interrupts in Uboot, simply make the enable function do nothing > + */ > +static inline int cvmx_error_enable_group(cvmx_error_group_t group, > int group_index) > +{ > + return 0; > +} > + > +/** > + * Disable all error registers for a logical group. This should be > + * called whenever a logical group is brought offline. Many blocks > + * will report spurious errors when offline unless this function > + * is called. > + * > + * @param group Logical group to disable > + * @param group_index > + * Index for the group as defined in the > cvmx_error_group_t > + * comments. > + * > + * @return Zero on success, negative on failure. > + */ > +/* > + * Rather than conditionalize the calls throughout the executive to > not disable > + * interrupts in Uboot, simply make the enable function do nothing > + */ > +static inline int cvmx_error_disable_group(cvmx_error_group_t group, > int group_index) > +{ > + return 0; > +} > + > +/** > + * Enable all handlers for a specific status register mask. > + * > + * @param reg_type Type of the status register > + * @param status_addr > + * Status register address > + * @param status_mask > + * All handlers for this status register with this > mask will be > + * enabled. > + * > + * @return Zero on success, negative on failure. > + */ > +int cvmx_error_enable(cvmx_error_register_t reg_type, u64 > status_addr, u64 status_mask); > + > +/** > + * Disable all handlers for a specific status register and mask. > + * > + * @param reg_type Type of the status register > + * @param status_addr > + * Status register address > + * @param status_mask > + * All handlers for this status register with this > mask will be > + * disabled. > + * > + * @return Zero on success, negative on failure. > + */ > +int cvmx_error_disable(cvmx_error_register_t reg_type, u64 > status_addr, u64 status_mask); > + > +/** > + * @INTERNAL > + * Function for processing non leaf error status registers. This > function > + * calls all handlers for this passed register and all children > linked > + * to it. > + * > + * @param info Error register to check > + * > + * @return Number of error status bits found or zero if no bits were > set. > + */ > +int __cvmx_error_decode(const cvmx_error_info_t *info); > + > +/** > + * @INTERNAL > + * This error bit handler simply prints a message and clears the > status bit > + * > + * @param info Error register to check > + * > + * @return > + */ > +int __cvmx_error_display(const cvmx_error_info_t *info); > + > +/** > + * Find the handler for a specific status register and mask > + * > + * @param status_addr > + * Status register address > + * > + * @return Return the handler on success or null on failure. > + */ > +cvmx_error_info_t *cvmx_error_get_index(u64 status_addr); > + > +void __cvmx_install_gmx_error_handler_for_xaui(void); > + > +/** > + * 78xx related > + */ > +/** > + * Compare two INTSN values. > + * > + * @param key INTSN value to search for > + * @param data current entry from the searched array > + * > + * @return Negative, 0 or positive when respectively key is less > than, > + * equal or greater than data. > + */ > +int cvmx_error_intsn_cmp(const void *key, const void *data); > + > +/** > + * @INTERNAL > + * > + * @param intsn Interrupt source number to display > + * > + * @param node Node number > + * > + * @return Zero on success, -1 on error > + */ > +int cvmx_error_intsn_display_v3(int node, u32 intsn); > + > +/** > + * Initialize the error status system for cn78xx. This should be > called once > + * before any other functions are called. This function enables the > interrupts > + * described in the array. > + * > + * @param node Node number > + * > + * @return Zero on success, negative on failure. > + */ > +int cvmx_error_initialize_cn78xx(int node); > + > +/** > + * Enable interrupt for a specific INTSN. > + * > + * @param node Node number > + * @param intsn Interrupt source number > + * > + * @return Zero on success, negative on failure. > + */ > +int cvmx_error_intsn_enable_v3(int node, u32 intsn); > + > +/** > + * Disable interrupt for a specific INTSN. > + * > + * @param node Node number > + * @param intsn Interrupt source number > + * > + * @return Zero on success, negative on failure. > + */ > +int cvmx_error_intsn_disable_v3(int node, u32 intsn); > + > +/** > + * Clear interrupt for a specific INTSN. > + * > + * @param intsn Interrupt source number > + * > + * @return Zero on success, negative on failure. > + */ > +int cvmx_error_intsn_clear_v3(int node, u32 intsn); > + > +/** > + * Enable interrupts for a specific CSR(all the bits/intsn in the > csr). > + * > + * @param node Node number > + * @param csr_address CSR address > + * > + * @return Zero on success, negative on failure. > + */ > +int cvmx_error_csr_enable_v3(int node, u64 csr_address); > + > +/** > + * Disable interrupts for a specific CSR (all the bits/intsn in the > csr). > + * > + * @param node Node number > + * @param csr_address CSR address > + * > + * @return Zero > + */ > +int cvmx_error_csr_disable_v3(int node, u64 csr_address); > + > +/** > + * Enable all error registers for a logical group. This should be > + * called whenever a logical group is brought online. > + * > + * @param group Logical group to enable > + * @param xipd_port The IPD port value > + * > + * @return Zero. > + */ > +int cvmx_error_enable_group_v3(cvmx_error_group_t group, int > xipd_port); > + > +/** > + * Disable all error registers for a logical group. > + * > + * @param group Logical group to enable > + * @param xipd_port The IPD port value > + * > + * @return Zero. > + */ > +int cvmx_error_disable_group_v3(cvmx_error_group_t group, int > xipd_port); > + > +/** > + * Enable all error registers for a specific category in a logical > group. > + * This should be called whenever a logical group is brought online. > + * > + * @param group Logical group to enable > + * @param type Category in a logical group to enable > + * @param xipd_port The IPD port value > + * > + * @return Zero. > + */ > +int cvmx_error_enable_group_type_v3(cvmx_error_group_t group, > cvmx_error_type_t type, > + int xipd_port); > + > +/** > + * Disable all error registers for a specific category in a logical > group. > + * This should be called whenever a logical group is brought online. > + * > + * @param group Logical group to disable > + * @param type Category in a logical group to disable > + * @param xipd_port The IPD port value > + * > + * @return Zero. > + */ > +int cvmx_error_disable_group_type_v3(cvmx_error_group_t group, > cvmx_error_type_t type, > + int xipd_port); > + > +/** > + * Clear all error registers for a logical group. > + * > + * @param group Logical group to disable > + * @param xipd_port The IPD port value > + * > + * @return Zero. > + */ > +int cvmx_error_clear_group_v3(cvmx_error_group_t group, int > xipd_port); > + > +/** > + * Enable all error registers for a particular category. > + * > + * @param node CCPI node > + * @param type category to enable > + * > + *@return Zero. > + */ > +int cvmx_error_enable_type_v3(int node, cvmx_error_type_t type); > + > +/** > + * Disable all error registers for a particular category. > + * > + * @param node CCPI node > + * @param type category to disable > + * > + *@return Zero. > + */ > +int cvmx_error_disable_type_v3(int node, cvmx_error_type_t type); > + > +void cvmx_octeon_hang(void) __attribute__((__noreturn__)); > + > +/** > + * @INTERNAL > + * > + * Process L2C single and multi-bit ECC errors > + * > + */ > +int __cvmx_cn7xxx_l2c_l2d_ecc_error_display(int node, int intsn); > + > +/** > + * Handle L2 cache TAG ECC errors and noway errors > + * > + * @param CCPI node > + * @param intsn intsn from error array. > + * @param remote true for remote node (cn78xx only) > + * > + * @return 1 if handled, 0 if not handled > + */ > +int __cvmx_cn7xxx_l2c_tag_error_display(int node, int intsn, bool > remote); > + > +#endif > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-fpa.h > b/arch/mips/mach-octeon/include/mach/cvmx-fpa.h > new file mode 100644 > index 000000000000..297fb3f4a28c > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-fpa.h > @@ -0,0 +1,217 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Interface to the hardware Free Pool Allocator. > + */ > + > +#ifndef __CVMX_FPA_H__ > +#define __CVMX_FPA_H__ > + > +#include "cvmx-scratch.h" > +#include "cvmx-fpa-defs.h" > +#include "cvmx-fpa1.h" > +#include "cvmx-fpa3.h" > + > +#define CVMX_FPA_MIN_BLOCK_SIZE 128 > +#define CVMX_FPA_ALIGNMENT 128 > +#define CVMX_FPA_POOL_NAME_LEN 16 > + > +/* On CN78XX in backward-compatible mode, pool is mapped to AURA */ > +#define > CVMX_FPA_NUM_POOLS > \ > + (octeon_has_feature(OCTEON_FEATURE_FPA3) ? > cvmx_fpa3_num_auras() : CVMX_FPA1_NUM_POOLS) > + > +/** > + * Structure to store FPA pool configuration parameters. > + */ > +struct cvmx_fpa_pool_config { > + s64 pool_num; > + u64 buffer_size; > + u64 buffer_count; > +}; > + > +typedef struct cvmx_fpa_pool_config cvmx_fpa_pool_config_t; > + > +/** > + * Return the name of the pool > + * > + * @param pool_num Pool to get the name of > + * @return The name > + */ > +const char *cvmx_fpa_get_name(int pool_num); > + > +/** > + * Initialize FPA per node > + */ > +int cvmx_fpa_global_init_node(int node); > + > +/** > + * Enable the FPA > + */ > +static inline void cvmx_fpa_enable(void) > +{ > + if (!octeon_has_feature(OCTEON_FEATURE_FPA3)) > + cvmx_fpa1_enable(); > + else > + cvmx_fpa_global_init_node(cvmx_get_node_num()); > +} > + > +/** > + * Disable the FPA > + */ > +static inline void cvmx_fpa_disable(void) > +{ > + if (!octeon_has_feature(OCTEON_FEATURE_FPA3)) > + cvmx_fpa1_disable(); > + /* FPA3 does not have a disable function */ > +} > + > +/** > + * @INTERNAL > + * @deprecated OBSOLETE > + * > + * Kept for transition assistance only > + */ > +static inline void cvmx_fpa_global_initialize(void) > +{ > + cvmx_fpa_global_init_node(cvmx_get_node_num()); > +} > + > +/** > + * @INTERNAL > + * > + * Convert FPA1 style POOL into FPA3 AURA in > + * backward compatibility mode. > + */ > +static inline cvmx_fpa3_gaura_t > cvmx_fpa1_pool_to_fpa3_aura(cvmx_fpa1_pool_t pool) > +{ > + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) { > + unsigned int node = cvmx_get_node_num(); > + cvmx_fpa3_gaura_t aura = __cvmx_fpa3_gaura(node, pool); > + return aura; > + } > + return CVMX_FPA3_INVALID_GAURA; > +} > + > +/** > + * Get a new block from the FPA > + * > + * @param pool Pool to get the block from > + * @return Pointer to the block or NULL on failure > + */ > +static inline void *cvmx_fpa_alloc(u64 pool) > +{ > + /* FPA3 is handled differently */ > + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) { > + return > cvmx_fpa3_alloc(cvmx_fpa1_pool_to_fpa3_aura(pool)); > + } else > + return cvmx_fpa1_alloc(pool); > +} > + > +/** > + * Asynchronously get a new block from the FPA > + * > + * The result of cvmx_fpa_async_alloc() may be retrieved using > + * cvmx_fpa_async_alloc_finish(). > + * > + * @param scr_addr Local scratch address to put response in. This > is a byte > + * address but must be 8 byte aligned. > + * @param pool Pool to get the block from > + */ > +static inline void cvmx_fpa_async_alloc(u64 scr_addr, u64 pool) > +{ > + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) { > + return cvmx_fpa3_async_alloc(scr_addr, > cvmx_fpa1_pool_to_fpa3_aura(pool)); > + } else > + return cvmx_fpa1_async_alloc(scr_addr, pool); > +} > + > +/** > + * Retrieve the result of cvmx_fpa_async_alloc > + * > + * @param scr_addr The Local scratch address. Must be the same > value > + * passed to cvmx_fpa_async_alloc(). > + * > + * @param pool Pool the block came from. Must be the same value > + * passed to cvmx_fpa_async_alloc. > + * > + * @return Pointer to the block or NULL on failure > + */ > +static inline void *cvmx_fpa_async_alloc_finish(u64 scr_addr, u64 > pool) > +{ > + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) > + return cvmx_fpa3_async_alloc_finish(scr_addr, > cvmx_fpa1_pool_to_fpa3_aura(pool)); > + else > + return cvmx_fpa1_async_alloc_finish(scr_addr, pool); > +} > + > +/** > + * Free a block allocated with a FPA pool. > + * Does NOT provide memory ordering in cases where the memory block > was > + * modified by the core. > + * > + * @param ptr Block to free > + * @param pool Pool to put it in > + * @param num_cache_lines > + * Cache lines to invalidate > + */ > +static inline void cvmx_fpa_free_nosync(void *ptr, u64 pool, u64 > num_cache_lines) > +{ > + /* FPA3 is handled differently */ > + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) > + cvmx_fpa3_free_nosync(ptr, > cvmx_fpa1_pool_to_fpa3_aura(pool), num_cache_lines); > + else > + cvmx_fpa1_free_nosync(ptr, pool, num_cache_lines); > +} > + > +/** > + * Free a block allocated with a FPA pool. Provides required memory > + * ordering in cases where memory block was modified by core. > + * > + * @param ptr Block to free > + * @param pool Pool to put it in > + * @param num_cache_lines > + * Cache lines to invalidate > + */ > +static inline void cvmx_fpa_free(void *ptr, u64 pool, u64 > num_cache_lines) > +{ > + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) > + cvmx_fpa3_free(ptr, cvmx_fpa1_pool_to_fpa3_aura(pool), > num_cache_lines); > + else > + cvmx_fpa1_free(ptr, pool, num_cache_lines); > +} > + > +/** > + * Setup a FPA pool to control a new block of memory. > + * This can only be called once per pool. Make sure proper > + * locking enforces this. > + * > + * @param pool Pool to initialize > + * @param name Constant character string to name this pool. > + * String is not copied. > + * @param buffer Pointer to the block of memory to use. This > must be > + * accessible by all processors and external > hardware. > + * @param block_size Size for each block controlled by the FPA > + * @param num_blocks Number of blocks > + * > + * @return the pool number on Success, > + * -1 on failure > + */ > +int cvmx_fpa_setup_pool(int pool, const char *name, void *buffer, > u64 block_size, u64 num_blocks); > + > +int cvmx_fpa_shutdown_pool(int pool); > + > +/** > + * Gets the block size of buffer in specified pool > + * @param pool Pool to get the block size from > + * @return Size of buffer in specified pool > + */ > +unsigned int cvmx_fpa_get_block_size(int pool); > + > +int cvmx_fpa_is_pool_available(int pool_num); > +u64 cvmx_fpa_get_pool_owner(int pool_num); > +int cvmx_fpa_get_max_pools(void); > +int cvmx_fpa_get_current_count(int pool_num); > +int cvmx_fpa_validate_pool(int pool); > + > +#endif /* __CVM_FPA_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-fpa1.h > b/arch/mips/mach-octeon/include/mach/cvmx-fpa1.h > new file mode 100644 > index 000000000000..6985083a5d66 > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-fpa1.h > @@ -0,0 +1,196 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Interface to the hardware Free Pool Allocator on Octeon chips. > + * These are the legacy models, i.e. prior to CN78XX/CN76XX. > + */ > + > +#ifndef __CVMX_FPA1_HW_H__ > +#define __CVMX_FPA1_HW_H__ > + > +#include "cvmx-scratch.h" > +#include "cvmx-fpa-defs.h" > +#include "cvmx-fpa3.h" > + > +/* Legacy pool range is 0..7 and 8 on CN68XX */ > +typedef int cvmx_fpa1_pool_t; > + > +#define CVMX_FPA1_NUM_POOLS 8 > +#define CVMX_FPA1_INVALID_POOL ((cvmx_fpa1_pool_t)-1) > +#define CVMX_FPA1_NAME_SIZE 16 > + > +/** > + * Structure describing the data format used for stores to the FPA. > + */ > +typedef union { > + u64 u64; > + struct { > + u64 scraddr : 8; > + u64 len : 8; > + u64 did : 8; > + u64 addr : 40; > + } s; > +} cvmx_fpa1_iobdma_data_t; > + > +/* > + * Allocate or reserve the specified fpa pool. > + * > + * @param pool FPA pool to allocate/reserve. If -1 it > + * finds an empty pool to allocate. > + * @return Alloctaed pool number or CVMX_FPA1_POOL_INVALID > + * if fails to allocate the pool > + */ > +cvmx_fpa1_pool_t cvmx_fpa1_reserve_pool(cvmx_fpa1_pool_t pool); > + > +/** > + * Free the specified fpa pool. > + * @param pool Pool to free > + * @return 0 for success -1 failure > + */ > +int cvmx_fpa1_release_pool(cvmx_fpa1_pool_t pool); > + > +static inline void cvmx_fpa1_free(void *ptr, cvmx_fpa1_pool_t pool, > u64 num_cache_lines) > +{ > + cvmx_addr_t newptr; > + > + newptr.u64 = cvmx_ptr_to_phys(ptr); > + newptr.sfilldidspace.didspace = > CVMX_ADDR_DIDSPACE(CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool)); > + /* Make sure that any previous writes to memory go out before > we free > + * this buffer. This also serves as a barrier to prevent GCC > from > + * reordering operations to after the free. > + */ > + CVMX_SYNCWS; > + /* value written is number of cache lines not written back */ > + cvmx_write_io(newptr.u64, num_cache_lines); > +} > + > +static inline void cvmx_fpa1_free_nosync(void *ptr, cvmx_fpa1_pool_t > pool, > + unsigned int num_cache_lines) > +{ > + cvmx_addr_t newptr; > + > + newptr.u64 = cvmx_ptr_to_phys(ptr); > + newptr.sfilldidspace.didspace = > CVMX_ADDR_DIDSPACE(CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool)); > + /* Prevent GCC from reordering around free */ > + asm volatile("" : : : "memory"); > + /* value written is number of cache lines not written back */ > + cvmx_write_io(newptr.u64, num_cache_lines); > +} > + > +/** > + * Enable the FPA for use. Must be performed after any CSR > + * configuration but before any other FPA functions. > + */ > +static inline void cvmx_fpa1_enable(void) > +{ > + cvmx_fpa_ctl_status_t status; > + > + status.u64 = csr_rd(CVMX_FPA_CTL_STATUS); > + if (status.s.enb) { > + /* > + * CN68XXP1 should not reset the FPA (doing so may > break > + * the SSO, so we may end up enabling it more than > once. > + * Just return and don't spew messages. > + */ > + return; > + } > + > + status.u64 = 0; > + status.s.enb = 1; > + csr_wr(CVMX_FPA_CTL_STATUS, status.u64); > +} > + > +/** > + * Reset FPA to disable. Make sure buffers from all FPA pools are > freed > + * before disabling FPA. > + */ > +static inline void cvmx_fpa1_disable(void) > +{ > + cvmx_fpa_ctl_status_t status; > + > + if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1)) > + return; > + > + status.u64 = csr_rd(CVMX_FPA_CTL_STATUS); > + status.s.reset = 1; > + csr_wr(CVMX_FPA_CTL_STATUS, status.u64); > +} > + > +static inline void *cvmx_fpa1_alloc(cvmx_fpa1_pool_t pool) > +{ > + u64 address; > + > + for (;;) { > + address = > csr_rd(CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool))); > + if (cvmx_likely(address)) { > + return cvmx_phys_to_ptr(address); > + } else { > + if (csr_rd(CVMX_FPA_QUEX_AVAILABLE(pool)) > 0) > + udelay(50); > + else > + return NULL; > + } > + } > +} > + > +/** > + * Asynchronously get a new block from the FPA > + * @INTERNAL > + * > + * The result of cvmx_fpa_async_alloc() may be retrieved using > + * cvmx_fpa_async_alloc_finish(). > + * > + * @param scr_addr Local scratch address to put response in. This > is a byte > + * address but must be 8 byte aligned. > + * @param pool Pool to get the block from > + */ > +static inline void cvmx_fpa1_async_alloc(u64 scr_addr, > cvmx_fpa1_pool_t pool) > +{ > + cvmx_fpa1_iobdma_data_t data; > + > + /* Hardware only uses 64 bit aligned locations, so convert from > byte > + * address to 64-bit index > + */ > + data.u64 = 0ull; > + data.s.scraddr = scr_addr >> 3; > + data.s.len = 1; > + data.s.did = CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool); > + data.s.addr = 0; > + > + cvmx_scratch_write64(scr_addr, 0ull); > + CVMX_SYNCW; > + cvmx_send_single(data.u64); > +} > + > +/** > + * Retrieve the result of cvmx_fpa_async_alloc > + * @INTERNAL > + * > + * @param scr_addr The Local scratch address. Must be the same > value > + * passed to cvmx_fpa_async_alloc(). > + * > + * @param pool Pool the block came from. Must be the same value > + * passed to cvmx_fpa_async_alloc. > + * > + * @return Pointer to the block or NULL on failure > + */ > +static inline void *cvmx_fpa1_async_alloc_finish(u64 scr_addr, > cvmx_fpa1_pool_t pool) > +{ > + u64 address; > + > + CVMX_SYNCIOBDMA; > + > + address = cvmx_scratch_read64(scr_addr); > + if (cvmx_likely(address)) > + return cvmx_phys_to_ptr(address); > + else > + return cvmx_fpa1_alloc(pool); > +} > + > +static inline u64 cvmx_fpa1_get_available(cvmx_fpa1_pool_t pool) > +{ > + return csr_rd(CVMX_FPA_QUEX_AVAILABLE(pool)); > +} > + > +#endif /* __CVMX_FPA1_HW_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-fpa3.h > b/arch/mips/mach-octeon/include/mach/cvmx-fpa3.h > new file mode 100644 > index 000000000000..229982b83163 > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-fpa3.h > @@ -0,0 +1,566 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Interface to the CN78XX Free Pool Allocator, a.k.a. FPA3 > + */ > + > +#include "cvmx-address.h" > +#include "cvmx-fpa-defs.h" > +#include "cvmx-scratch.h" > + > +#ifndef __CVMX_FPA3_H__ > +#define __CVMX_FPA3_H__ > + > +typedef struct { > + unsigned res0 : 6; > + unsigned node : 2; > + unsigned res1 : 2; > + unsigned lpool : 6; > + unsigned valid_magic : 16; > +} cvmx_fpa3_pool_t; > + > +typedef struct { > + unsigned res0 : 6; > + unsigned node : 2; > + unsigned res1 : 6; > + unsigned laura : 10; > + unsigned valid_magic : 16; > +} cvmx_fpa3_gaura_t; > + > +#define CVMX_FPA3_VALID_MAGIC 0xf9a3 > +#define CVMX_FPA3_INVALID_GAURA ((cvmx_fpa3_gaura_t){ 0, 0, 0, 0, 0 > }) > +#define CVMX_FPA3_INVALID_POOL ((cvmx_fpa3_pool_t){ 0, 0, 0, > 0, 0 }) > + > +static inline bool __cvmx_fpa3_aura_valid(cvmx_fpa3_gaura_t aura) > +{ > + if (aura.valid_magic != CVMX_FPA3_VALID_MAGIC) > + return false; > + return true; > +} > + > +static inline bool __cvmx_fpa3_pool_valid(cvmx_fpa3_pool_t pool) > +{ > + if (pool.valid_magic != CVMX_FPA3_VALID_MAGIC) > + return false; > + return true; > +} > + > +static inline cvmx_fpa3_gaura_t __cvmx_fpa3_gaura(int node, int > laura) > +{ > + cvmx_fpa3_gaura_t aura; > + > + if (node < 0) > + node = cvmx_get_node_num(); > + if (laura < 0) > + return CVMX_FPA3_INVALID_GAURA; > + > + aura.node = node; > + aura.laura = laura; > + aura.valid_magic = CVMX_FPA3_VALID_MAGIC; > + return aura; > +} > + > +static inline cvmx_fpa3_pool_t __cvmx_fpa3_pool(int node, int lpool) > +{ > + cvmx_fpa3_pool_t pool; > + > + if (node < 0) > + node = cvmx_get_node_num(); > + if (lpool < 0) > + return CVMX_FPA3_INVALID_POOL; > + > + pool.node = node; > + pool.lpool = lpool; > + pool.valid_magic = CVMX_FPA3_VALID_MAGIC; > + return pool; > +} > + > +#undef CVMX_FPA3_VALID_MAGIC > + > +/** > + * Structure describing the data format used for stores to the FPA. > + */ > +typedef union { > + u64 u64; > + struct { > + u64 scraddr : 8; > + u64 len : 8; > + u64 did : 8; > + u64 addr : 40; > + } s; > + struct { > + u64 scraddr : 8; > + u64 len : 8; > + u64 did : 8; > + u64 node : 4; > + u64 red : 1; > + u64 reserved2 : 9; > + u64 aura : 10; > + u64 reserved3 : 16; > + } cn78xx; > +} cvmx_fpa3_iobdma_data_t; > + > +/** > + * Struct describing load allocate operation addresses for FPA pool. > + */ > +union cvmx_fpa3_load_data { > + u64 u64; > + struct { > + u64 seg : 2; > + u64 reserved1 : 13; > + u64 io : 1; > + u64 did : 8; > + u64 node : 4; > + u64 red : 1; > + u64 reserved2 : 9; > + u64 aura : 10; > + u64 reserved3 : 16; > + }; > +}; > + > +typedef union cvmx_fpa3_load_data cvmx_fpa3_load_data_t; > + > +/** > + * Struct describing store free operation addresses from FPA pool. > + */ > +union cvmx_fpa3_store_addr { > + u64 u64; > + struct { > + u64 seg : 2; > + u64 reserved1 : 13; > + u64 io : 1; > + u64 did : 8; > + u64 node : 4; > + u64 reserved2 : 10; > + u64 aura : 10; > + u64 fabs : 1; > + u64 reserved3 : 3; > + u64 dwb_count : 9; > + u64 reserved4 : 3; > + }; > +}; > + > +typedef union cvmx_fpa3_store_addr cvmx_fpa3_store_addr_t; > + > +enum cvmx_fpa3_pool_alignment_e { > + FPA_NATURAL_ALIGNMENT, > + FPA_OFFSET_ALIGNMENT, > + FPA_OPAQUE_ALIGNMENT > +}; > + > +#define CVMX_FPA3_AURAX_LIMIT_MAX ((1ull << 40) - 1) > + > +/** > + * @INTERNAL > + * Accessor functions to return number of POOLS in an FPA3 > + * depending on SoC model. > + * The number is per-node for models supporting multi-node > configurations. > + */ > +static inline int cvmx_fpa3_num_pools(void) > +{ > + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) > + return 64; > + if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) > + return 32; > + if (OCTEON_IS_MODEL(OCTEON_CN73XX)) > + return 32; > + printf("ERROR: %s: Unknowm model\n", __func__); > + return -1; > +} > + > +/** > + * @INTERNAL > + * Accessor functions to return number of AURAS in an FPA3 > + * depending on SoC model. > + * The number is per-node for models supporting multi-node > configurations. > + */ > +static inline int cvmx_fpa3_num_auras(void) > +{ > + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) > + return 1024; > + if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) > + return 512; > + if (OCTEON_IS_MODEL(OCTEON_CN73XX)) > + return 512; > + printf("ERROR: %s: Unknowm model\n", __func__); > + return -1; > +} > + > +/** > + * Get the FPA3 POOL underneath FPA3 AURA, containing all its > buffers > + * > + */ > +static inline cvmx_fpa3_pool_t > cvmx_fpa3_aura_to_pool(cvmx_fpa3_gaura_t aura) > +{ > + cvmx_fpa3_pool_t pool; > + cvmx_fpa_aurax_pool_t aurax_pool; > + > + aurax_pool.u64 = cvmx_read_csr_node(aura.node, > CVMX_FPA_AURAX_POOL(aura.laura)); > + > + pool = __cvmx_fpa3_pool(aura.node, aurax_pool.s.pool); > + return pool; > +} > + > +/** > + * Get a new block from the FPA pool > + * > + * @param aura - aura number > + * @return pointer to the block or NULL on failure > + */ > +static inline void *cvmx_fpa3_alloc(cvmx_fpa3_gaura_t aura) > +{ > + u64 address; > + cvmx_fpa3_load_data_t load_addr; > + > + load_addr.u64 = 0; > + load_addr.seg = CVMX_MIPS_SPACE_XKPHYS; > + load_addr.io = 1; > + load_addr.did = 0x29; /* Device ID. Indicates FPA. */ > + load_addr.node = aura.node; > + load_addr.red = 0; /* Perform RED on allocation. > + * FIXME to use config option > + */ > + load_addr.aura = aura.laura; > + > + address = cvmx_read64_uint64(load_addr.u64); > + if (!address) > + return NULL; > + return cvmx_phys_to_ptr(address); > +} > + > +/** > + * Asynchronously get a new block from the FPA > + * > + * The result of cvmx_fpa_async_alloc() may be retrieved using > + * cvmx_fpa_async_alloc_finish(). > + * > + * @param scr_addr Local scratch address to put response in. This > is a byte > + * address but must be 8 byte aligned. > + * @param aura Global aura to get the block from > + */ > +static inline void cvmx_fpa3_async_alloc(u64 scr_addr, > cvmx_fpa3_gaura_t aura) > +{ > + cvmx_fpa3_iobdma_data_t data; > + > + /* Hardware only uses 64 bit aligned locations, so convert from > byte > + * address to 64-bit index > + */ > + data.u64 = 0ull; > + data.cn78xx.scraddr = scr_addr >> 3; > + data.cn78xx.len = 1; > + data.cn78xx.did = 0x29; > + data.cn78xx.node = aura.node; > + data.cn78xx.aura = aura.laura; > + cvmx_scratch_write64(scr_addr, 0ull); > + > + CVMX_SYNCW; > + cvmx_send_single(data.u64); > +} > + > +/** > + * Retrieve the result of cvmx_fpa3_async_alloc > + * > + * @param scr_addr The Local scratch address. Must be the same > value > + * passed to cvmx_fpa_async_alloc(). > + * > + * @param aura Global aura the block came from. Must be the same > value > + * passed to cvmx_fpa_async_alloc. > + * > + * @return Pointer to the block or NULL on failure > + */ > +static inline void *cvmx_fpa3_async_alloc_finish(u64 scr_addr, > cvmx_fpa3_gaura_t aura) > +{ > + u64 address; > + > + CVMX_SYNCIOBDMA; > + > + address = cvmx_scratch_read64(scr_addr); > + if (cvmx_likely(address)) > + return cvmx_phys_to_ptr(address); > + else > + /* Try regular alloc if async failed */ > + return cvmx_fpa3_alloc(aura); > +} > + > +/** > + * Free a pointer back to the pool. > + * > + * @param aura global aura number > + * @param ptr physical address of block to free. > + * @param num_cache_lines Cache lines to invalidate > + */ > +static inline void cvmx_fpa3_free(void *ptr, cvmx_fpa3_gaura_t aura, > unsigned int num_cache_lines) > +{ > + cvmx_fpa3_store_addr_t newptr; > + cvmx_addr_t newdata; > + > + newdata.u64 = cvmx_ptr_to_phys(ptr); > + > + /* Make sure that any previous writes to memory go out before > we free > + this buffer. This also serves as a barrier to prevent GCC > from > + reordering operations to after the free. */ > + CVMX_SYNCWS; > + > + newptr.u64 = 0; > + newptr.seg = CVMX_MIPS_SPACE_XKPHYS; > + newptr.io = 1; > + newptr.did = 0x29; /* Device id, indicates FPA */ > + newptr.node = aura.node; > + newptr.aura = aura.laura; > + newptr.fabs = 0; /* Free absolute. FIXME to use config option > */ > + newptr.dwb_count = num_cache_lines; > + > + cvmx_write_io(newptr.u64, newdata.u64); > +} > + > +/** > + * Free a pointer back to the pool without flushing the write > buffer. > + * > + * @param aura global aura number > + * @param ptr physical address of block to free. > + * @param num_cache_lines Cache lines to invalidate > + */ > +static inline void cvmx_fpa3_free_nosync(void *ptr, > cvmx_fpa3_gaura_t aura, > + unsigned int num_cache_lines) > +{ > + cvmx_fpa3_store_addr_t newptr; > + cvmx_addr_t newdata; > + > + newdata.u64 = cvmx_ptr_to_phys(ptr); > + > + /* Prevent GCC from reordering writes to (*ptr) */ > + asm volatile("" : : : "memory"); > + > + newptr.u64 = 0; > + newptr.seg = CVMX_MIPS_SPACE_XKPHYS; > + newptr.io = 1; > + newptr.did = 0x29; /* Device id, indicates FPA */ > + newptr.node = aura.node; > + newptr.aura = aura.laura; > + newptr.fabs = 0; /* Free absolute. FIXME to use config option > */ > + newptr.dwb_count = num_cache_lines; > + > + cvmx_write_io(newptr.u64, newdata.u64); > +} > + > +static inline int cvmx_fpa3_pool_is_enabled(cvmx_fpa3_pool_t pool) > +{ > + cvmx_fpa_poolx_cfg_t pool_cfg; > + > + if (!__cvmx_fpa3_pool_valid(pool)) > + return -1; > + > + pool_cfg.u64 = cvmx_read_csr_node(pool.node, > CVMX_FPA_POOLX_CFG(pool.lpool)); > + return pool_cfg.cn78xx.ena; > +} > + > +static inline int cvmx_fpa3_config_red_params(unsigned int node, int > qos_avg_en, int red_lvl_dly, > + int avg_dly) > +{ > + cvmx_fpa_gen_cfg_t fpa_cfg; > + cvmx_fpa_red_delay_t red_delay; > + > + fpa_cfg.u64 = cvmx_read_csr_node(node, CVMX_FPA_GEN_CFG); > + fpa_cfg.s.avg_en = qos_avg_en; > + fpa_cfg.s.lvl_dly = red_lvl_dly; > + cvmx_write_csr_node(node, CVMX_FPA_GEN_CFG, fpa_cfg.u64); > + > + red_delay.u64 = cvmx_read_csr_node(node, CVMX_FPA_RED_DELAY); > + red_delay.s.avg_dly = avg_dly; > + cvmx_write_csr_node(node, CVMX_FPA_RED_DELAY, red_delay.u64); > + return 0; > +} > + > +/** > + * Gets the buffer size of the specified pool, > + * > + * @param aura Global aura number > + * @return Returns size of the buffers in the specified pool. > + */ > +static inline int cvmx_fpa3_get_aura_buf_size(cvmx_fpa3_gaura_t > aura) > +{ > + cvmx_fpa3_pool_t pool; > + cvmx_fpa_poolx_cfg_t pool_cfg; > + int block_size; > + > + pool = cvmx_fpa3_aura_to_pool(aura); > + > + pool_cfg.u64 = cvmx_read_csr_node(pool.node, > CVMX_FPA_POOLX_CFG(pool.lpool)); > + block_size = pool_cfg.cn78xx.buf_size << 7; > + return block_size; > +} > + > +/** > + * Return the number of available buffers in an AURA > + * > + * @param aura to receive count for > + * @return available buffer count > + */ > +static inline long long cvmx_fpa3_get_available(cvmx_fpa3_gaura_t > aura) > +{ > + cvmx_fpa3_pool_t pool; > + cvmx_fpa_poolx_available_t avail_reg; > + cvmx_fpa_aurax_cnt_t cnt_reg; > + cvmx_fpa_aurax_cnt_limit_t limit_reg; > + long long ret; > + > + pool = cvmx_fpa3_aura_to_pool(aura); > + > + /* Get POOL available buffer count */ > + avail_reg.u64 = cvmx_read_csr_node(pool.node, > CVMX_FPA_POOLX_AVAILABLE(pool.lpool)); > + > + /* Get AURA current available count */ > + cnt_reg.u64 = cvmx_read_csr_node(aura.node, > CVMX_FPA_AURAX_CNT(aura.laura)); > + limit_reg.u64 = cvmx_read_csr_node(aura.node, > CVMX_FPA_AURAX_CNT_LIMIT(aura.laura)); > + > + if (limit_reg.cn78xx.limit < cnt_reg.cn78xx.cnt) > + return 0; > + > + /* Calculate AURA-based buffer allowance */ > + ret = limit_reg.cn78xx.limit - cnt_reg.cn78xx.cnt; > + > + /* Use POOL real buffer availability when less then allowance > */ > + if (ret > (long long)avail_reg.cn78xx.count) > + ret = avail_reg.cn78xx.count; > + > + return ret; > +} > + > +/** > + * Configure the QoS parameters of an FPA3 AURA > + * > + * @param aura is the FPA3 AURA handle > + * @param ena_bp enables backpressure when outstanding count exceeds > 'bp_thresh' > + * @param ena_red enables random early discard when outstanding > count exceeds 'pass_thresh' > + * @param pass_thresh is the maximum count to invoke flow control > + * @param drop_thresh is the count threshold to begin dropping > packets > + * @param bp_thresh is the back-pressure threshold > + * > + */ > +static inline void cvmx_fpa3_setup_aura_qos(cvmx_fpa3_gaura_t aura, > bool ena_red, u64 pass_thresh, > + u64 drop_thresh, bool > ena_bp, u64 bp_thresh) > +{ > + unsigned int shift = 0; > + u64 shift_thresh; > + cvmx_fpa_aurax_cnt_limit_t limit_reg; > + cvmx_fpa_aurax_cnt_levels_t aura_level; > + > + if (!__cvmx_fpa3_aura_valid(aura)) > + return; > + > + /* Get AURAX count limit for validation */ > + limit_reg.u64 = cvmx_read_csr_node(aura.node, > CVMX_FPA_AURAX_CNT_LIMIT(aura.laura)); > + > + if (pass_thresh < 256) > + pass_thresh = 255; > + > + if (drop_thresh <= pass_thresh || drop_thresh > > limit_reg.cn78xx.limit) > + drop_thresh = limit_reg.cn78xx.limit; > + > + if (bp_thresh < 256 || bp_thresh > limit_reg.cn78xx.limit) > + bp_thresh = limit_reg.cn78xx.limit >> 1; > + > + shift_thresh = (bp_thresh > drop_thresh) ? bp_thresh : > drop_thresh; > + > + /* Calculate shift so that the largest threshold fits in 8 bits > */ > + for (shift = 0; shift < (1 << 6); shift++) { > + if (0 == ((shift_thresh >> shift) & ~0xffull)) > + break; > + }; > + > + aura_level.u64 = cvmx_read_csr_node(aura.node, > CVMX_FPA_AURAX_CNT_LEVELS(aura.laura)); > + aura_level.s.pass = pass_thresh >> shift; > + aura_level.s.drop = drop_thresh >> shift; > + aura_level.s.bp = bp_thresh >> shift; > + aura_level.s.shift = shift; > + aura_level.s.red_ena = ena_red; > + aura_level.s.bp_ena = ena_bp; > + cvmx_write_csr_node(aura.node, > CVMX_FPA_AURAX_CNT_LEVELS(aura.laura), aura_level.u64); > +} > + > +cvmx_fpa3_gaura_t cvmx_fpa3_reserve_aura(int node, int > desired_aura_num); > +int cvmx_fpa3_release_aura(cvmx_fpa3_gaura_t aura); > +cvmx_fpa3_pool_t cvmx_fpa3_reserve_pool(int node, int > desired_pool_num); > +int cvmx_fpa3_release_pool(cvmx_fpa3_pool_t pool); > +int cvmx_fpa3_is_aura_available(int node, int aura_num); > +int cvmx_fpa3_is_pool_available(int node, int pool_num); > + > +cvmx_fpa3_pool_t cvmx_fpa3_setup_fill_pool(int node, int > desired_pool, const char *name, > + unsigned int block_size, > unsigned int num_blocks, > + void *buffer); > + > +/** > + * Function to attach an aura to an existing pool > + * > + * @param node - configure fpa on this node > + * @param pool - configured pool to attach aura to > + * @param desired_aura - pointer to aura to use, set to -1 to > allocate > + * @param name - name to register > + * @param block_size - size of buffers to use > + * @param num_blocks - number of blocks to allocate > + * > + * @return configured gaura on success, CVMX_FPA3_INVALID_GAURA on > failure > + */ > +cvmx_fpa3_gaura_t cvmx_fpa3_set_aura_for_pool(cvmx_fpa3_pool_t pool, > int desired_aura, > + const char *name, > unsigned int block_size, > + unsigned int num_blocks); > + > +/** > + * Function to setup and initialize a pool. > + * > + * @param node - configure fpa on this node > + * @param desired_aura - aura to use, -1 for dynamic allocation > + * @param name - name to register > + * @param block_size - size of buffers in pool > + * @param num_blocks - max number of buffers allowed > + */ > +cvmx_fpa3_gaura_t cvmx_fpa3_setup_aura_and_pool(int node, int > desired_aura, const char *name, > + void *buffer, unsigned > int block_size, > + unsigned int > num_blocks); > + > +int cvmx_fpa3_shutdown_aura_and_pool(cvmx_fpa3_gaura_t aura); > +int cvmx_fpa3_shutdown_aura(cvmx_fpa3_gaura_t aura); > +int cvmx_fpa3_shutdown_pool(cvmx_fpa3_pool_t pool); > +const char *cvmx_fpa3_get_pool_name(cvmx_fpa3_pool_t pool); > +int cvmx_fpa3_get_pool_buf_size(cvmx_fpa3_pool_t pool); > +const char *cvmx_fpa3_get_aura_name(cvmx_fpa3_gaura_t aura); > + > +/* FIXME: Need a different macro for stage2 of u-boot */ > + > +static inline void cvmx_fpa3_stage2_init(int aura, int pool, u64 > stack_paddr, int stacklen, > + int buffer_sz, int buf_cnt) > +{ > + cvmx_fpa_poolx_cfg_t pool_cfg; > + > + /* Configure pool stack */ > + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_BASE(pool), > stack_paddr); > + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_ADDR(pool), > stack_paddr); > + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_END(pool), > stack_paddr + stacklen); > + > + /* Configure pool with buffer size */ > + pool_cfg.u64 = 0; > + pool_cfg.cn78xx.nat_align = 1; > + pool_cfg.cn78xx.buf_size = buffer_sz >> 7; > + pool_cfg.cn78xx.l_type = 0x2; > + pool_cfg.cn78xx.ena = 0; > + cvmx_write_csr_node(0, CVMX_FPA_POOLX_CFG(pool), pool_cfg.u64); > + /* Reset pool before starting */ > + pool_cfg.cn78xx.ena = 1; > + cvmx_write_csr_node(0, CVMX_FPA_POOLX_CFG(pool), pool_cfg.u64); > + > + cvmx_write_csr_node(0, CVMX_FPA_AURAX_CFG(aura), 0); > + cvmx_write_csr_node(0, CVMX_FPA_AURAX_CNT_ADD(aura), buf_cnt); > + cvmx_write_csr_node(0, CVMX_FPA_AURAX_POOL(aura), (u64)pool); > +} > + > +static inline void cvmx_fpa3_stage2_disable(int aura, int pool) > +{ > + cvmx_write_csr_node(0, CVMX_FPA_AURAX_POOL(aura), 0); > + cvmx_write_csr_node(0, CVMX_FPA_POOLX_CFG(pool), 0); > + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_BASE(pool), 0); > + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_ADDR(pool), 0); > + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_END(pool), 0); > +} > + > +#endif /* __CVMX_FPA3_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-global- > resources.h b/arch/mips/mach-octeon/include/mach/cvmx-global- > resources.h > new file mode 100644 > index 000000000000..28c32ddbe17a > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-global-resources.h > @@ -0,0 +1,213 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + */ > + > +#ifndef _CVMX_GLOBAL_RESOURCES_T_ > +#define _CVMX_GLOBAL_RESOURCES_T_ > + > +#define CVMX_GLOBAL_RESOURCES_DATA_NAME "cvmx-global-resources" > + > +/*In macros below abbreviation GR stands for global resources. */ > +#define > CVMX_GR_TAG_INVALID > \ > + cvmx_get_gr_tag('i', 'n', 'v', 'a', 'l', 'i', 'd', '.', '.', > '.', '.', '.', '.', '.', '.', \ > + '.') > +/*Tag for pko que table range. */ > +#define > CVMX_GR_TAG_PKO_QUEUES > \ > + cvmx_get_gr_tag('c', 'v', 'm', '_', 'p', 'k', 'o', '_', 'q', > 'u', 'e', 'u', 's', '.', '.', \ > + '.') > +/*Tag for a pko internal ports range */ > +#define > CVMX_GR_TAG_PKO_IPORTS > \ > + cvmx_get_gr_tag('c', 'v', 'm', '_', 'p', 'k', 'o', '_', 'i', > 'p', 'o', 'r', 't', '.', '.', \ > + '.') > +#define > CVMX_GR_TAG_FPA > \ > + cvmx_get_gr_tag('c', 'v', 'm', '_', 'f', 'p', 'a', '.', '.', > '.', '.', '.', '.', '.', '.', \ > + '.') > +#define > CVMX_GR_TAG_FAU > \ > + cvmx_get_gr_tag('c', 'v', 'm', '_', 'f', 'a', 'u', '.', '.', > '.', '.', '.', '.', '.', '.', \ > + '.') > +#define > CVMX_GR_TAG_SSO_GRP(n) > \ > + cvmx_get_gr_tag('c', 'v', 'm', '_', 's', 's', 'o', '_', '0', > (n) + '0', '.', '.', '.', \ > + '.', '.', '.'); > +#define > CVMX_GR_TAG_TIM(n) > \ > + cvmx_get_gr_tag('c', 'v', 'm', '_', 't', 'i', 'm', '_', (n) + > '0', '.', '.', '.', '.', \ > + '.', '.', '.') > +#define > CVMX_GR_TAG_CLUSTERS(x) > \ > + cvmx_get_gr_tag('c', 'v', 'm', '_', 'c', 'l', 'u', 's', 't', > 'e', 'r', '_', (x + '0'), \ > + '.', '.', '.') > +#define > CVMX_GR_TAG_CLUSTER_GRP(x) > \ > + cvmx_get_gr_tag('c', 'v', 'm', '_', 'c', 'l', 'g', 'r', 'p', > '_', (x + '0'), '.', '.', \ > + '.', '.', '.') > +#define > CVMX_GR_TAG_STYLE(x) > \ > + cvmx_get_gr_tag('c', 'v', 'm', '_', 's', 't', 'y', 'l', 'e', > '_', (x + '0'), '.', '.', \ > + '.', '.', '.') > +#define > CVMX_GR_TAG_QPG_ENTRY(x) > \ > + cvmx_get_gr_tag('c', 'v', 'm', '_', 'q', 'p', 'g', 'e', 't', > '_', (x + '0'), '.', '.', \ > + '.', '.', '.') > +#define > CVMX_GR_TAG_BPID(x) > \ > + cvmx_get_gr_tag('c', 'v', 'm', '_', 'b', 'p', 'i', 'd', 's', > '_', (x + '0'), '.', '.', \ > + '.', '.', '.') > +#define > CVMX_GR_TAG_MTAG_IDX(x) > \ > + cvmx_get_gr_tag('c', 'v', 'm', '_', 'm', 't', 'a', 'g', 'x', > '_', (x + '0'), '.', '.', \ > + '.', '.', '.') > +#define CVMX_GR_TAG_PCAM(x, y, > z) \ > + cvmx_get_gr_tag('c', 'v', 'm', '_', 'p', 'c', 'a', 'm', '_', (x > + '0'), (y + '0'), \ > + (z + '0'), '.', '.', '.', '.') > + > +#define > CVMX_GR_TAG_CIU3_IDT(_n) > \ > + cvmx_get_gr_tag('c', 'v', 'm', '_', 'c', 'i', 'u', '3', '_', > ((_n) + '0'), '_', 'i', 'd', \ > + 't', '.', '.') > + > +/* Allocation of the 512 SW INTSTs (in the 12 bit SW INTSN space) > */ > +#define > CVMX_GR_TAG_CIU3_SWINTSN(_n) > \ > + cvmx_get_gr_tag('c', 'v', 'm', '_', 'c', 'i', 'u', '3', '_', > ((_n) + '0'), '_', 's', 'w', \ > + 'i', 's', 'n') > + > +#define TAG_INIT_PART(A, B, C, D, E, F, G, > H) \ > + ((((u64)(A) & 0xff) << 56) | (((u64)(B) & 0xff) << 48) | > (((u64)(C) & 0xff) << 40) | \ > + (((u64)(D) & 0xff) << 32) | (((u64)(E) & 0xff) << 24) | > (((u64)(F) & 0xff) << 16) | \ > + (((u64)(G) & 0xff) << 8) | (((u64)(H) & 0xff))) > + > +struct global_resource_tag { > + u64 lo; > + u64 hi; > +}; > + > +enum cvmx_resource_err { CVMX_RESOURCE_ALLOC_FAILED = -1, > CVMX_RESOURCE_ALREADY_RESERVED = -2 }; > + > +/* > + * @INTERNAL > + * Creates a tag from the specified characters. > + */ > +static inline struct global_resource_tag cvmx_get_gr_tag(char a, > char b, char c, char d, char e, > + char f, char > g, char h, char i, char j, > + char k, char > l, char m, char n, char o, > + char p) > +{ > + struct global_resource_tag tag; > + > + tag.lo = TAG_INIT_PART(a, b, c, d, e, f, g, h); > + tag.hi = TAG_INIT_PART(i, j, k, l, m, n, o, p); > + return tag; > +} > + > +static inline int cvmx_gr_same_tag(struct global_resource_tag gr1, > struct global_resource_tag gr2) > +{ > + return (gr1.hi == gr2.hi) && (gr1.lo == gr2.lo); > +} > + > +/* > + * @INTERNAL > + * Creates a global resource range that can hold the specified > number of > + * elements > + * @param tag is the tag of the range. The taga is created using the > method > + * cvmx_get_gr_tag() > + * @param nelements is the number of elements to be held in the > resource range. > + */ > +int cvmx_create_global_resource_range(struct global_resource_tag > tag, int nelements); > + > +/* > + * @INTERNAL > + * Allocate nelements in the global resource range with the > specified tag. It > + * is assumed that prior > + * to calling this the global resource range has already been > created using > + * cvmx_create_global_resource_range(). > + * @param tag is the tag of the global resource range. > + * @param nelements is the number of elements to be allocated. > + * @param owner is a 64 bit number that identifes the owner of this > range. > + * @aligment specifes the required alignment of the returned base > number. > + * @return returns the base of the allocated range. -1 return value > indicates > + * failure. > + */ > +int cvmx_allocate_global_resource_range(struct global_resource_tag > tag, u64 owner, int nelements, > + int alignment); > + > +/* > + * @INTERNAL > + * Allocate nelements in the global resource range with the > specified tag. > + * The elements allocated need not be contiguous. It is assumed that > prior to > + * calling this the global resource range has already > + * been created using cvmx_create_global_resource_range(). > + * @param tag is the tag of the global resource range. > + * @param nelements is the number of elements to be allocated. > + * @param owner is a 64 bit number that identifes the owner of the > allocated > + * elements. > + * @param allocated_elements returns indexs of the allocated > entries. > + * @return returns 0 on success and -1 on failure. > + */ > +int cvmx_resource_alloc_many(struct global_resource_tag tag, u64 > owner, int nelements, > + int allocated_elements[]); > +int cvmx_resource_alloc_reverse(struct global_resource_tag, u64 > owner); > +/* > + * @INTERNAL > + * Reserve nelements starting from base in the global resource range > with the > + * specified tag. > + * It is assumed that prior to calling this the global resource > range has > + * already been created using cvmx_create_global_resource_range(). > + * @param tag is the tag of the global resource range. > + * @param nelements is the number of elements to be allocated. > + * @param owner is a 64 bit number that identifes the owner of this > range. > + * @base specifies the base start of nelements. > + * @return returns the base of the allocated range. -1 return value > indicates > + * failure. > + */ > +int cvmx_reserve_global_resource_range(struct global_resource_tag > tag, u64 owner, int base, > + int nelements); > +/* > + * @INTERNAL > + * Free nelements starting at base in the global resource range with > the > + * specified tag. > + * @param tag is the tag of the global resource range. > + * @param base is the base number > + * @param nelements is the number of elements that are to be freed. > + * @return returns 0 if successful and -1 on failure. > + */ > +int cvmx_free_global_resource_range_with_base(struct > global_resource_tag tag, int base, > + int nelements); > + > +/* > + * @INTERNAL > + * Free nelements with the bases specified in bases[] with the > + * specified tag. > + * @param tag is the tag of the global resource range. > + * @param bases is an array containing the bases to be freed. > + * @param nelements is the number of elements that are to be freed. > + * @return returns 0 if successful and -1 on failure. > + */ > +int cvmx_free_global_resource_range_multiple(struct > global_resource_tag tag, int bases[], > + int nelements); > +/* > + * @INTERNAL > + * Free elements from the specified owner in the global resource > range with the > + * specified tag. > + * @param tag is the tag of the global resource range. > + * @param owner is the owner of resources that are to be freed. > + * @return returns 0 if successful and -1 on failure. > + */ > +int cvmx_free_global_resource_range_with_owner(struct > global_resource_tag tag, int owner); > + > +/* > + * @INTERNAL > + * Frees all the global resources that have been created. > + * For use only from the bootloader, when it shutdown and boots up > the > + * application or kernel. > + */ > +int free_global_resources(void); > + > +u64 cvmx_get_global_resource_owner(struct global_resource_tag tag, > int base); > +/* > + * @INTERNAL > + * Shows the global resource range with the specified tag. Use > mainly for debug. > + */ > +void cvmx_show_global_resource_range(struct global_resource_tag > tag); > + > +/* > + * @INTERNAL > + * Shows all the global resources. Used mainly for debug. > + */ > +void cvmx_global_resources_show(void); > + > +u64 cvmx_allocate_app_id(void); > +u64 cvmx_get_app_id(void); > + > +#endif > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-gmx.h > b/arch/mips/mach-octeon/include/mach/cvmx-gmx.h > new file mode 100644 > index 000000000000..2df7da102a0f > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-gmx.h > @@ -0,0 +1,16 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Interface to the GMX hardware. > + */ > + > +#ifndef __CVMX_GMX_H__ > +#define __CVMX_GMX_H__ > + > +/* CSR typedefs have been moved to cvmx-gmx-defs.h */ > + > +int cvmx_gmx_set_backpressure_override(u32 interface, u32 > port_mask); > +int cvmx_agl_set_backpressure_override(u32 interface, u32 > port_mask); > + > +#endif > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-hwfau.h > b/arch/mips/mach-octeon/include/mach/cvmx-hwfau.h > new file mode 100644 > index 000000000000..59772190aa3b > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-hwfau.h > @@ -0,0 +1,606 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Interface to the hardware Fetch and Add Unit. > + */ > + > +/** > + * @file > + * > + * Interface to the hardware Fetch and Add Unit. > + * > + */ > + > +#ifndef __CVMX_HWFAU_H__ > +#define __CVMX_HWFAU_H__ > + > +typedef int cvmx_fau_reg64_t; > +typedef int cvmx_fau_reg32_t; > +typedef int cvmx_fau_reg16_t; > +typedef int cvmx_fau_reg8_t; > + > +#define CVMX_FAU_REG_ANY -1 > + > +/* > + * Octeon Fetch and Add Unit (FAU) > + */ > + > +#define CVMX_FAU_LOAD_IO_ADDRESS cvmx_build_io_address(0x1e, 0) > +#define CVMX_FAU_BITS_SCRADDR 63, 56 > +#define CVMX_FAU_BITS_LEN 55, 48 > +#define CVMX_FAU_BITS_INEVAL 35, 14 > +#define CVMX_FAU_BITS_TAGWAIT 13, 13 > +#define CVMX_FAU_BITS_NOADD 13, 13 > +#define CVMX_FAU_BITS_SIZE 12, 11 > +#define CVMX_FAU_BITS_REGISTER 10, 0 > + > +#define CVMX_FAU_MAX_REGISTERS_8 (2048) > + > +typedef enum { > + CVMX_FAU_OP_SIZE_8 = 0, > + CVMX_FAU_OP_SIZE_16 = 1, > + CVMX_FAU_OP_SIZE_32 = 2, > + CVMX_FAU_OP_SIZE_64 = 3 > +} cvmx_fau_op_size_t; > + > +/** > + * Tagwait return definition. If a timeout occurs, the error > + * bit will be set. Otherwise the value of the register before > + * the update will be returned. > + */ > +typedef struct { > + u64 error : 1; > + s64 value : 63; > +} cvmx_fau_tagwait64_t; > + > +/** > + * Tagwait return definition. If a timeout occurs, the error > + * bit will be set. Otherwise the value of the register before > + * the update will be returned. > + */ > +typedef struct { > + u64 error : 1; > + s32 value : 31; > +} cvmx_fau_tagwait32_t; > + > +/** > + * Tagwait return definition. If a timeout occurs, the error > + * bit will be set. Otherwise the value of the register before > + * the update will be returned. > + */ > +typedef struct { > + u64 error : 1; > + s16 value : 15; > +} cvmx_fau_tagwait16_t; > + > +/** > + * Tagwait return definition. If a timeout occurs, the error > + * bit will be set. Otherwise the value of the register before > + * the update will be returned. > + */ > +typedef struct { > + u64 error : 1; > + int8_t value : 7; > +} cvmx_fau_tagwait8_t; > + > +/** > + * Asynchronous tagwait return definition. If a timeout occurs, > + * the error bit will be set. Otherwise the value of the > + * register before the update will be returned. > + */ > +typedef union { > + u64 u64; > + struct { > + u64 invalid : 1; > + u64 data : 63; /* unpredictable if invalid is set */ > + } s; > +} cvmx_fau_async_tagwait_result_t; > + > +#define SWIZZLE_8 0 > +#define SWIZZLE_16 0 > +#define SWIZZLE_32 0 > + > +/** > + * @INTERNAL > + * Builds a store I/O address for writing to the FAU > + * > + * @param noadd 0 = Store value is atomically added to the current > value > + * 1 = Store value is atomically written over the > current value > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 2 for 16 bit access. > + * - Step by 4 for 32 bit access. > + * - Step by 8 for 64 bit access. > + * @return Address to store for atomic update > + */ > +static inline u64 __cvmx_hwfau_store_address(u64 noadd, u64 reg) > +{ > + return (CVMX_ADD_IO_SEG(CVMX_FAU_LOAD_IO_ADDRESS) | > + cvmx_build_bits(CVMX_FAU_BITS_NOADD, noadd) | > + cvmx_build_bits(CVMX_FAU_BITS_REGISTER, reg)); > +} > + > +/** > + * @INTERNAL > + * Builds a I/O address for accessing the FAU > + * > + * @param tagwait Should the atomic add wait for the current tag > switch > + * operation to complete. > + * - 0 = Don't wait > + * - 1 = Wait for tag switch to complete > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 2 for 16 bit access. > + * - Step by 4 for 32 bit access. > + * - Step by 8 for 64 bit access. > + * @param value Signed value to add. > + * Note: When performing 32 and 64 bit access, only > the low > + * 22 bits are available. > + * @return Address to read from for atomic update > + */ > +static inline u64 __cvmx_hwfau_atomic_address(u64 tagwait, u64 reg, > s64 value) > +{ > + return (CVMX_ADD_IO_SEG(CVMX_FAU_LOAD_IO_ADDRESS) | > + cvmx_build_bits(CVMX_FAU_BITS_INEVAL, value) | > + cvmx_build_bits(CVMX_FAU_BITS_TAGWAIT, tagwait) | > + cvmx_build_bits(CVMX_FAU_BITS_REGISTER, reg)); > +} > + > +/** > + * Perform an atomic 64 bit add > + * > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 8 for 64 bit access. > + * @param value Signed value to add. > + * Note: Only the low 22 bits are available. > + * @return Value of the register before the update > + */ > +static inline s64 cvmx_hwfau_fetch_and_add64(cvmx_fau_reg64_t reg, > s64 value) > +{ > + return cvmx_read64_int64(__cvmx_hwfau_atomic_address(0, reg, > value)); > +} > + > +/** > + * Perform an atomic 32 bit add > + * > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 4 for 32 bit access. > + * @param value Signed value to add. > + * Note: Only the low 22 bits are available. > + * @return Value of the register before the update > + */ > +static inline s32 cvmx_hwfau_fetch_and_add32(cvmx_fau_reg32_t reg, > s32 value) > +{ > + reg ^= SWIZZLE_32; > + return cvmx_read64_int32(__cvmx_hwfau_atomic_address(0, reg, > value)); > +} > + > +/** > + * Perform an atomic 16 bit add > + * > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 2 for 16 bit access. > + * @param value Signed value to add. > + * @return Value of the register before the update > + */ > +static inline s16 cvmx_hwfau_fetch_and_add16(cvmx_fau_reg16_t reg, > s16 value) > +{ > + reg ^= SWIZZLE_16; > + return cvmx_read64_int16(__cvmx_hwfau_atomic_address(0, reg, > value)); > +} > + > +/** > + * Perform an atomic 8 bit add > + * > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * @param value Signed value to add. > + * @return Value of the register before the update > + */ > +static inline int8_t cvmx_hwfau_fetch_and_add8(cvmx_fau_reg8_t reg, > int8_t value) > +{ > + reg ^= SWIZZLE_8; > + return cvmx_read64_int8(__cvmx_hwfau_atomic_address(0, reg, > value)); > +} > + > +/** > + * Perform an atomic 64 bit add after the current tag switch > + * completes > + * > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 8 for 64 bit access. > + * @param value Signed value to add. > + * Note: Only the low 22 bits are available. > + * @return If a timeout occurs, the error bit will be set. Otherwise > + * the value of the register before the update will be > + * returned > + */ > +static inline cvmx_fau_tagwait64_t > cvmx_hwfau_tagwait_fetch_and_add64(cvmx_fau_reg64_t reg, > + s > 64 value) > +{ > + union { > + u64 i64; > + cvmx_fau_tagwait64_t t; > + } result; > + result.i64 = cvmx_read64_int64(__cvmx_hwfau_atomic_address(1, > reg, value)); > + return result.t; > +} > + > +/** > + * Perform an atomic 32 bit add after the current tag switch > + * completes > + * > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 4 for 32 bit access. > + * @param value Signed value to add. > + * Note: Only the low 22 bits are available. > + * @return If a timeout occurs, the error bit will be set. Otherwise > + * the value of the register before the update will be > + * returned > + */ > +static inline cvmx_fau_tagwait32_t > cvmx_hwfau_tagwait_fetch_and_add32(cvmx_fau_reg32_t reg, > + s > 32 value) > +{ > + union { > + u64 i32; > + cvmx_fau_tagwait32_t t; > + } result; > + reg ^= SWIZZLE_32; > + result.i32 = cvmx_read64_int32(__cvmx_hwfau_atomic_address(1, > reg, value)); > + return result.t; > +} > + > +/** > + * Perform an atomic 16 bit add after the current tag switch > + * completes > + * > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 2 for 16 bit access. > + * @param value Signed value to add. > + * @return If a timeout occurs, the error bit will be set. Otherwise > + * the value of the register before the update will be > + * returned > + */ > +static inline cvmx_fau_tagwait16_t > cvmx_hwfau_tagwait_fetch_and_add16(cvmx_fau_reg16_t reg, > + s > 16 value) > +{ > + union { > + u64 i16; > + cvmx_fau_tagwait16_t t; > + } result; > + reg ^= SWIZZLE_16; > + result.i16 = cvmx_read64_int16(__cvmx_hwfau_atomic_address(1, > reg, value)); > + return result.t; > +} > + > +/** > + * Perform an atomic 8 bit add after the current tag switch > + * completes > + * > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * @param value Signed value to add. > + * @return If a timeout occurs, the error bit will be set. Otherwise > + * the value of the register before the update will be > + * returned > + */ > +static inline cvmx_fau_tagwait8_t > cvmx_hwfau_tagwait_fetch_and_add8(cvmx_fau_reg8_t reg, > + int > 8_t value) > +{ > + union { > + u64 i8; > + cvmx_fau_tagwait8_t t; > + } result; > + reg ^= SWIZZLE_8; > + result.i8 = cvmx_read64_int8(__cvmx_hwfau_atomic_address(1, > reg, value)); > + return result.t; > +} > + > +/** > + * @INTERNAL > + * Builds I/O data for async operations > + * > + * @param scraddr Scratch pad byte address to write to. Must be 8 > byte aligned > + * @param value Signed value to add. > + * Note: When performing 32 and 64 bit access, only > the low > + * 22 bits are available. > + * @param tagwait Should the atomic add wait for the current tag > switch > + * operation to complete. > + * - 0 = Don't wait > + * - 1 = Wait for tag switch to complete > + * @param size The size of the operation: > + * - CVMX_FAU_OP_SIZE_8 (0) = 8 bits > + * - CVMX_FAU_OP_SIZE_16 (1) = 16 bits > + * - CVMX_FAU_OP_SIZE_32 (2) = 32 bits > + * - CVMX_FAU_OP_SIZE_64 (3) = 64 bits > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 2 for 16 bit access. > + * - Step by 4 for 32 bit access. > + * - Step by 8 for 64 bit access. > + * @return Data to write using cvmx_send_single > + */ > +static inline u64 __cvmx_fau_iobdma_data(u64 scraddr, s64 value, u64 > tagwait, > + cvmx_fau_op_size_t size, u64 > reg) > +{ > + return (CVMX_FAU_LOAD_IO_ADDRESS | > cvmx_build_bits(CVMX_FAU_BITS_SCRADDR, scraddr >> 3) | > + cvmx_build_bits(CVMX_FAU_BITS_LEN, 1) | > + cvmx_build_bits(CVMX_FAU_BITS_INEVAL, value) | > + cvmx_build_bits(CVMX_FAU_BITS_TAGWAIT, tagwait) | > + cvmx_build_bits(CVMX_FAU_BITS_SIZE, size) | > + cvmx_build_bits(CVMX_FAU_BITS_REGISTER, reg)); > +} > + > +/** > + * Perform an async atomic 64 bit add. The old value is > + * placed in the scratch memory at byte address scraddr. > + * > + * @param scraddr Scratch memory byte address to put response in. > + * Must be 8 byte aligned. > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 8 for 64 bit access. > + * @param value Signed value to add. > + * Note: Only the low 22 bits are available. > + * @return Placed in the scratch pad register > + */ > +static inline void cvmx_hwfau_async_fetch_and_add64(u64 scraddr, > cvmx_fau_reg64_t reg, s64 value) > +{ > + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 0, > CVMX_FAU_OP_SIZE_64, reg)); > +} > + > +/** > + * Perform an async atomic 32 bit add. The old value is > + * placed in the scratch memory at byte address scraddr. > + * > + * @param scraddr Scratch memory byte address to put response in. > + * Must be 8 byte aligned. > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 4 for 32 bit access. > + * @param value Signed value to add. > + * Note: Only the low 22 bits are available. > + * @return Placed in the scratch pad register > + */ > +static inline void cvmx_hwfau_async_fetch_and_add32(u64 scraddr, > cvmx_fau_reg32_t reg, s32 value) > +{ > + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 0, > CVMX_FAU_OP_SIZE_32, reg)); > +} > + > +/** > + * Perform an async atomic 16 bit add. The old value is > + * placed in the scratch memory at byte address scraddr. > + * > + * @param scraddr Scratch memory byte address to put response in. > + * Must be 8 byte aligned. > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 2 for 16 bit access. > + * @param value Signed value to add. > + * @return Placed in the scratch pad register > + */ > +static inline void cvmx_hwfau_async_fetch_and_add16(u64 scraddr, > cvmx_fau_reg16_t reg, s16 value) > +{ > + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 0, > CVMX_FAU_OP_SIZE_16, reg)); > +} > + > +/** > + * Perform an async atomic 8 bit add. The old value is > + * placed in the scratch memory at byte address scraddr. > + * > + * @param scraddr Scratch memory byte address to put response in. > + * Must be 8 byte aligned. > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * @param value Signed value to add. > + * @return Placed in the scratch pad register > + */ > +static inline void cvmx_hwfau_async_fetch_and_add8(u64 scraddr, > cvmx_fau_reg8_t reg, int8_t value) > +{ > + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 0, > CVMX_FAU_OP_SIZE_8, reg)); > +} > + > +/** > + * Perform an async atomic 64 bit add after the current tag > + * switch completes. > + * > + * @param scraddr Scratch memory byte address to put response in. > + * Must be 8 byte aligned. > + * If a timeout occurs, the error bit (63) will be > set. Otherwise > + * the value of the register before the update will > be > + * returned > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 8 for 64 bit access. > + * @param value Signed value to add. > + * Note: Only the low 22 bits are available. > + * @return Placed in the scratch pad register > + */ > +static inline void cvmx_hwfau_async_tagwait_fetch_and_add64(u64 > scraddr, cvmx_fau_reg64_t reg, > + s64 value) > +{ > + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 1, > CVMX_FAU_OP_SIZE_64, reg)); > +} > + > +/** > + * Perform an async atomic 32 bit add after the current tag > + * switch completes. > + * > + * @param scraddr Scratch memory byte address to put response in. > + * Must be 8 byte aligned. > + * If a timeout occurs, the error bit (63) will be > set. Otherwise > + * the value of the register before the update will > be > + * returned > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 4 for 32 bit access. > + * @param value Signed value to add. > + * Note: Only the low 22 bits are available. > + * @return Placed in the scratch pad register > + */ > +static inline void cvmx_hwfau_async_tagwait_fetch_and_add32(u64 > scraddr, cvmx_fau_reg32_t reg, > + s32 value) > +{ > + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 1, > CVMX_FAU_OP_SIZE_32, reg)); > +} > + > +/** > + * Perform an async atomic 16 bit add after the current tag > + * switch completes. > + * > + * @param scraddr Scratch memory byte address to put response in. > + * Must be 8 byte aligned. > + * If a timeout occurs, the error bit (63) will be > set. Otherwise > + * the value of the register before the update will > be > + * returned > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 2 for 16 bit access. > + * @param value Signed value to add. > + * @return Placed in the scratch pad register > + */ > +static inline void cvmx_hwfau_async_tagwait_fetch_and_add16(u64 > scraddr, cvmx_fau_reg16_t reg, > + s16 value) > +{ > + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 1, > CVMX_FAU_OP_SIZE_16, reg)); > +} > + > +/** > + * Perform an async atomic 8 bit add after the current tag > + * switch completes. > + * > + * @param scraddr Scratch memory byte address to put response in. > + * Must be 8 byte aligned. > + * If a timeout occurs, the error bit (63) will be > set. Otherwise > + * the value of the register before the update will > be > + * returned > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * @param value Signed value to add. > + * @return Placed in the scratch pad register > + */ > +static inline void cvmx_hwfau_async_tagwait_fetch_and_add8(u64 > scraddr, cvmx_fau_reg8_t reg, > + int8_t > value) > +{ > + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 1, > CVMX_FAU_OP_SIZE_8, reg)); > +} > + > +/** > + * Perform an atomic 64 bit add > + * > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 8 for 64 bit access. > + * @param value Signed value to add. > + */ > +static inline void cvmx_hwfau_atomic_add64(cvmx_fau_reg64_t reg, s64 > value) > +{ > + cvmx_write64_int64(__cvmx_hwfau_store_address(0, reg), value); > +} > + > +/** > + * Perform an atomic 32 bit add > + * > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 4 for 32 bit access. > + * @param value Signed value to add. > + */ > +static inline void cvmx_hwfau_atomic_add32(cvmx_fau_reg32_t reg, s32 > value) > +{ > + reg ^= SWIZZLE_32; > + cvmx_write64_int32(__cvmx_hwfau_store_address(0, reg), value); > +} > + > +/** > + * Perform an atomic 16 bit add > + * > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 2 for 16 bit access. > + * @param value Signed value to add. > + */ > +static inline void cvmx_hwfau_atomic_add16(cvmx_fau_reg16_t reg, s16 > value) > +{ > + reg ^= SWIZZLE_16; > + cvmx_write64_int16(__cvmx_hwfau_store_address(0, reg), value); > +} > + > +/** > + * Perform an atomic 8 bit add > + * > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * @param value Signed value to add. > + */ > +static inline void cvmx_hwfau_atomic_add8(cvmx_fau_reg8_t reg, > int8_t value) > +{ > + reg ^= SWIZZLE_8; > + cvmx_write64_int8(__cvmx_hwfau_store_address(0, reg), value); > +} > + > +/** > + * Perform an atomic 64 bit write > + * > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 8 for 64 bit access. > + * @param value Signed value to write. > + */ > +static inline void cvmx_hwfau_atomic_write64(cvmx_fau_reg64_t reg, > s64 value) > +{ > + cvmx_write64_int64(__cvmx_hwfau_store_address(1, reg), value); > +} > + > +/** > + * Perform an atomic 32 bit write > + * > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 4 for 32 bit access. > + * @param value Signed value to write. > + */ > +static inline void cvmx_hwfau_atomic_write32(cvmx_fau_reg32_t reg, > s32 value) > +{ > + reg ^= SWIZZLE_32; > + cvmx_write64_int32(__cvmx_hwfau_store_address(1, reg), value); > +} > + > +/** > + * Perform an atomic 16 bit write > + * > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * - Step by 2 for 16 bit access. > + * @param value Signed value to write. > + */ > +static inline void cvmx_hwfau_atomic_write16(cvmx_fau_reg16_t reg, > s16 value) > +{ > + reg ^= SWIZZLE_16; > + cvmx_write64_int16(__cvmx_hwfau_store_address(1, reg), value); > +} > + > +/** > + * Perform an atomic 8 bit write > + * > + * @param reg FAU atomic register to access. 0 <= reg < 2048. > + * @param value Signed value to write. > + */ > +static inline void cvmx_hwfau_atomic_write8(cvmx_fau_reg8_t reg, > int8_t value) > +{ > + reg ^= SWIZZLE_8; > + cvmx_write64_int8(__cvmx_hwfau_store_address(1, reg), value); > +} > + > +/** Allocates 64bit FAU register. > + * @return value is the base address of allocated FAU register > + */ > +int cvmx_fau64_alloc(int reserve); > + > +/** Allocates 32bit FAU register. > + * @return value is the base address of allocated FAU register > + */ > +int cvmx_fau32_alloc(int reserve); > + > +/** Allocates 16bit FAU register. > + * @return value is the base address of allocated FAU register > + */ > +int cvmx_fau16_alloc(int reserve); > + > +/** Allocates 8bit FAU register. > + * @return value is the base address of allocated FAU register > + */ > +int cvmx_fau8_alloc(int reserve); > + > +/** Frees the specified FAU register. > + * @param address Base address of register to release. > + * @return 0 on success; -1 on failure > + */ > +int cvmx_fau_free(int address); > + > +/** Display the fau registers array > + */ > +void cvmx_fau_show(void); > + > +#endif /* __CVMX_HWFAU_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-hwpko.h > b/arch/mips/mach-octeon/include/mach/cvmx-hwpko.h > new file mode 100644 > index 000000000000..459c19bbc0f1 > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-hwpko.h > @@ -0,0 +1,570 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Interface to the hardware Packet Output unit. > + * > + * Starting with SDK 1.7.0, the PKO output functions now support > + * two types of locking. CVMX_PKO_LOCK_ATOMIC_TAG continues to > + * function similarly to previous SDKs by using POW atomic tags > + * to preserve ordering and exclusivity. As a new option, you > + * can now pass CVMX_PKO_LOCK_CMD_QUEUE which uses a ll/sc > + * memory based locking instead. This locking has the advantage > + * of not affecting the tag state but doesn't preserve packet > + * ordering. CVMX_PKO_LOCK_CMD_QUEUE is appropriate in most > + * generic code while CVMX_PKO_LOCK_CMD_QUEUE should be used > + * with hand tuned fast path code. > + * > + * Some of other SDK differences visible to the command command > + * queuing: > + * - PKO indexes are no longer stored in the FAU. A large > + * percentage of the FAU register block used to be tied up > + * maintaining PKO queue pointers. These are now stored in a > + * global named block. > + * - The PKO <b>use_locking</b> parameter can now have a global > + * effect. Since all application use the same named block, > + * queue locking correctly applies across all operating > + * systems when using CVMX_PKO_LOCK_CMD_QUEUE. > + * - PKO 3 word commands are now supported. Use > + * cvmx_pko_send_packet_finish3(). > + */ > + > +#ifndef __CVMX_HWPKO_H__ > +#define __CVMX_HWPKO_H__ > + > +#include "cvmx-hwfau.h" > +#include "cvmx-fpa.h" > +#include "cvmx-pow.h" > +#include "cvmx-cmd-queue.h" > +#include "cvmx-helper.h" > +#include "cvmx-helper-util.h" > +#include "cvmx-helper-cfg.h" > + > +/* Adjust the command buffer size by 1 word so that in the case of > using only > +** two word PKO commands no command words stradle buffers. The > useful values > +** for this are 0 and 1. */ > +#define CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST (1) > + > +#define CVMX_PKO_MAX_OUTPUT_QUEUES_STATIC 256 > +#define > CVMX_PKO_MAX_OUTPUT_QUEUES > \ > + ((OCTEON_IS_OCTEON2() || OCTEON_IS_MODEL(OCTEON_CN70XX)) ? 256 > : 128) > +#define > CVMX_PKO_NUM_OUTPUT_PORTS > \ > + ((OCTEON_IS_MODEL(OCTEON_CN63XX)) ? 44 : > (OCTEON_IS_MODEL(OCTEON_CN66XX) ? 48 : 40)) > +#define CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID 63 > +#define CVMX_PKO_QUEUE_STATIC_PRIORITY 9 > +#define CVMX_PKO_ILLEGAL_QUEUE 0xFFFF > +#define CVMX_PKO_MAX_QUEUE_DEPTH 0 > + > +typedef enum { > + CVMX_PKO_SUCCESS, > + CVMX_PKO_INVALID_PORT, > + CVMX_PKO_INVALID_QUEUE, > + CVMX_PKO_INVALID_PRIORITY, > + CVMX_PKO_NO_MEMORY, > + CVMX_PKO_PORT_ALREADY_SETUP, > + CVMX_PKO_CMD_QUEUE_INIT_ERROR > +} cvmx_pko_return_value_t; > + > +/** > + * This enumeration represents the differnet locking modes supported > by PKO. > + */ > +typedef enum { > + CVMX_PKO_LOCK_NONE = 0, > + CVMX_PKO_LOCK_ATOMIC_TAG = 1, > + CVMX_PKO_LOCK_CMD_QUEUE = 2, > +} cvmx_pko_lock_t; > + > +typedef struct cvmx_pko_port_status { > + u32 packets; > + u64 octets; > + u64 doorbell; > +} cvmx_pko_port_status_t; > + > +/** > + * This structure defines the address to use on a packet enqueue > + */ > +typedef union { > + u64 u64; > + struct { > + cvmx_mips_space_t mem_space : 2; > + u64 reserved : 13; > + u64 is_io : 1; > + u64 did : 8; > + u64 reserved2 : 4; > + u64 reserved3 : 15; > + u64 port : 9; > + u64 queue : 9; > + u64 reserved4 : 3; > + } s; > +} cvmx_pko_doorbell_address_t; > + > +/** > + * Structure of the first packet output command word. > + */ > +typedef union { > + u64 u64; > + struct { > + cvmx_fau_op_size_t size1 : 2; > + cvmx_fau_op_size_t size0 : 2; > + u64 subone1 : 1; > + u64 reg1 : 11; > + u64 subone0 : 1; > + u64 reg0 : 11; > + u64 le : 1; > + u64 n2 : 1; > + u64 wqp : 1; > + u64 rsp : 1; > + u64 gather : 1; > + u64 ipoffp1 : 7; > + u64 ignore_i : 1; > + u64 dontfree : 1; > + u64 segs : 6; > + u64 total_bytes : 16; > + } s; > +} cvmx_pko_command_word0_t; > + > +/** > + * Call before any other calls to initialize the packet > + * output system. > + */ > + > +void cvmx_pko_hw_init(u8 pool, unsigned int bufsize); > + > +/** > + * Enables the packet output hardware. It must already be > + * configured. > + */ > +void cvmx_pko_enable(void); > + > +/** > + * Disables the packet output. Does not affect any configuration. > + */ > +void cvmx_pko_disable(void); > + > +/** > + * Shutdown and free resources required by packet output. > + */ > + > +void cvmx_pko_shutdown(void); > + > +/** > + * Configure a output port and the associated queues for use. > + * > + * @param port Port to configure. > + * @param base_queue First queue number to associate with this port. > + * @param num_queues Number of queues t oassociate with this port > + * @param priority Array of priority levels for each queue. Values > are > + * allowed to be 1-8. A value of 8 get 8 times the > traffic > + * of a value of 1. There must be num_queues > elements in the > + * array. > + */ > +cvmx_pko_return_value_t cvmx_pko_config_port(int port, int > base_queue, int num_queues, > + const u8 priority[]); > + > +/** > + * Ring the packet output doorbell. This tells the packet > + * output hardware that "len" command words have been added > + * to its pending list. This command includes the required > + * CVMX_SYNCWS before the doorbell ring. > + * > + * WARNING: This function may have to look up the proper PKO port in > + * the IPD port to PKO port map, and is thus slower than calling > + * cvmx_pko_doorbell_pkoid() directly if the PKO port identifier is > + * known. > + * > + * @param ipd_port The IPD port corresponding the to pko port the > packet is for > + * @param queue Queue the packet is for > + * @param len Length of the command in 64 bit words > + */ > +static inline void cvmx_pko_doorbell(u64 ipd_port, u64 queue, u64 > len) > +{ > + cvmx_pko_doorbell_address_t ptr; > + u64 pko_port; > + > + pko_port = ipd_port; > + if (octeon_has_feature(OCTEON_FEATURE_PKND)) > + pko_port = cvmx_helper_cfg_ipd2pko_port_base(ipd_port); > + > + ptr.u64 = 0; > + ptr.s.mem_space = CVMX_IO_SEG; > + ptr.s.did = CVMX_OCT_DID_PKT_SEND; > + ptr.s.is_io = 1; > + ptr.s.port = pko_port; > + ptr.s.queue = queue; > + /* Need to make sure output queue data is in DRAM before > doorbell write */ > + CVMX_SYNCWS; > + cvmx_write_io(ptr.u64, len); > +} > + > +/** > + * Prepare to send a packet. This may initiate a tag switch to > + * get exclusive access to the output queue structure, and > + * performs other prep work for the packet send operation. > + * > + * cvmx_pko_send_packet_finish() MUST be called after this function > is called, > + * and must be called with the same port/queue/use_locking > arguments. > + * > + * The use_locking parameter allows the caller to use three > + * possible locking modes. > + * - CVMX_PKO_LOCK_NONE > + * - PKO doesn't do any locking. It is the responsibility > + * of the application to make sure that no other core > + * is accessing the same queue at the same time. > + * - CVMX_PKO_LOCK_ATOMIC_TAG > + * - PKO performs an atomic tagswitch to insure exclusive > + * access to the output queue. This will maintain > + * packet ordering on output. > + * - CVMX_PKO_LOCK_CMD_QUEUE > + * - PKO uses the common command queue locks to insure > + * exclusive access to the output queue. This is a > + * memory based ll/sc. This is the most portable > + * locking mechanism. > + * > + * NOTE: If atomic locking is used, the POW entry CANNOT be > + * descheduled, as it does not contain a valid WQE pointer. > + * > + * @param port Port to send it on, this can be either IPD port or > PKO > + * port. > + * @param queue Queue to use > + * @param use_locking > + * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or > CVMX_PKO_LOCK_CMD_QUEUE > + */ > +static inline void cvmx_pko_send_packet_prepare(u64 port > __attribute__((unused)), u64 queue, > + cvmx_pko_lock_t > use_locking) > +{ > + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) { > + /* > + * Must do a full switch here to handle all cases. We > use a > + * fake WQE pointer, as the POW does not access this > memory. > + * The WQE pointer and group are only used if this work > is > + * descheduled, which is not supported by the > + * > cvmx_pko_send_packet_prepare/cvmx_pko_send_packet_finish > + * combination. Note that this is a special case in > which these > + * fake values can be used - this is not a general > technique. > + */ > + u32 tag = CVMX_TAG_SW_BITS_INTERNAL << > CVMX_TAG_SW_SHIFT | > + CVMX_TAG_SUBGROUP_PKO << > CVMX_TAG_SUBGROUP_SHIFT | > + (CVMX_TAG_SUBGROUP_MASK & queue); > + cvmx_pow_tag_sw_full((cvmx_wqe_t > *)cvmx_phys_to_ptr(0x80), tag, > + CVMX_POW_TAG_TYPE_ATOMIC, 0); > + } > +} > + > +#define cvmx_pko_send_packet_prepare_pkoid > cvmx_pko_send_packet_prepare > + > +/** > + * Complete packet output. cvmx_pko_send_packet_prepare() must be > called exactly once before this, > + * and the same parameters must be passed to both > cvmx_pko_send_packet_prepare() and > + * cvmx_pko_send_packet_finish(). > + * > + * WARNING: This function may have to look up the proper PKO port in > + * the IPD port to PKO port map, and is thus slower than calling > + * cvmx_pko_send_packet_finish_pkoid() directly if the PKO port > + * identifier is known. > + * > + * @param ipd_port The IPD port corresponding the to pko port the > packet is for > + * @param queue Queue to use > + * @param pko_command > + * PKO HW command word > + * @param packet Packet to send > + * @param use_locking > + * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or > CVMX_PKO_LOCK_CMD_QUEUE > + * > + * @return returns CVMX_PKO_SUCCESS on success, or error code on > failure of output > + */ > +static inline cvmx_pko_return_value_t > +cvmx_hwpko_send_packet_finish(u64 ipd_port, u64 queue, > cvmx_pko_command_word0_t pko_command, > + cvmx_buf_ptr_t packet, cvmx_pko_lock_t > use_locking) > +{ > + cvmx_cmd_queue_result_t result; > + > + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) > + cvmx_pow_tag_sw_wait(); > + > + result = cvmx_cmd_queue_write2(CVMX_CMD_QUEUE_PKO(queue), > + (use_locking == > CVMX_PKO_LOCK_CMD_QUEUE), pko_command.u64, > + packet.u64); > + if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS)) { > + cvmx_pko_doorbell(ipd_port, queue, 2); > + return CVMX_PKO_SUCCESS; > + } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == > CVMX_CMD_QUEUE_FULL)) { > + return CVMX_PKO_NO_MEMORY; > + } else { > + return CVMX_PKO_INVALID_QUEUE; > + } > +} > + > +/** > + * Complete packet output. cvmx_pko_send_packet_prepare() must be > called exactly once before this, > + * and the same parameters must be passed to both > cvmx_pko_send_packet_prepare() and > + * cvmx_pko_send_packet_finish(). > + * > + * WARNING: This function may have to look up the proper PKO port in > + * the IPD port to PKO port map, and is thus slower than calling > + * cvmx_pko_send_packet_finish3_pkoid() directly if the PKO port > + * identifier is known. > + * > + * @param ipd_port The IPD port corresponding the to pko port the > packet is for > + * @param queue Queue to use > + * @param pko_command > + * PKO HW command word > + * @param packet Packet to send > + * @param addr Plysical address of a work queue entry or physical > address to zero on complete. > + * @param use_locking > + * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or > CVMX_PKO_LOCK_CMD_QUEUE > + * > + * @return returns CVMX_PKO_SUCCESS on success, or error code on > failure of output > + */ > +static inline cvmx_pko_return_value_t > +cvmx_hwpko_send_packet_finish3(u64 ipd_port, u64 queue, > cvmx_pko_command_word0_t pko_command, > + cvmx_buf_ptr_t packet, u64 addr, > cvmx_pko_lock_t use_locking) > +{ > + cvmx_cmd_queue_result_t result; > + > + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) > + cvmx_pow_tag_sw_wait(); > + > + result = cvmx_cmd_queue_write3(CVMX_CMD_QUEUE_PKO(queue), > + (use_locking == > CVMX_PKO_LOCK_CMD_QUEUE), pko_command.u64, > + packet.u64, addr); > + if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS)) { > + cvmx_pko_doorbell(ipd_port, queue, 3); > + return CVMX_PKO_SUCCESS; > + } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == > CVMX_CMD_QUEUE_FULL)) { > + return CVMX_PKO_NO_MEMORY; > + } else { > + return CVMX_PKO_INVALID_QUEUE; > + } > +} > + > +/** > + * Get the first pko_port for the (interface, index) > + * > + * @param interface > + * @param index > + */ > +int cvmx_pko_get_base_pko_port(int interface, int index); > + > +/** > + * Get the number of pko_ports for the (interface, index) > + * > + * @param interface > + * @param index > + */ > +int cvmx_pko_get_num_pko_ports(int interface, int index); > + > +/** > + * For a given port number, return the base pko output queue > + * for the port. > + * > + * @param port IPD port number > + * @return Base output queue > + */ > +int cvmx_pko_get_base_queue(int port); > + > +/** > + * For a given port number, return the number of pko output queues. > + * > + * @param port IPD port number > + * @return Number of output queues > + */ > +int cvmx_pko_get_num_queues(int port); > + > +/** > + * Sets the internal FPA pool data structure for PKO comamnd queue. > + * @param pool fpa pool number yo use > + * @param buffer_size buffer size of pool > + * @param buffer_count number of buufers to allocate to pool > + * > + * @note the caller is responsable for setting up the pool with > + * an appropriate buffer size and sufficient buffer count. > + */ > +void cvmx_pko_set_cmd_que_pool_config(s64 pool, u64 buffer_size, u64 > buffer_count); > + > +/** > + * Get the status counters for a port. > + * > + * @param ipd_port Port number (ipd_port) to get statistics for. > + * @param clear Set to 1 to clear the counters after they are > read > + * @param status Where to put the results. > + * > + * Note: > + * - Only the doorbell for the base queue of the ipd_port is > + * collected. > + * - Retrieving the stats involves writing the index through > + * CVMX_PKO_REG_READ_IDX and reading the stat CSRs, in that > + * order. It is not MP-safe and caller should guarantee > + * atomicity. > + */ > +void cvmx_pko_get_port_status(u64 ipd_port, u64 clear, > cvmx_pko_port_status_t *status); > + > +/** > + * Rate limit a PKO port to a max packets/sec. This function is only > + * supported on CN57XX, CN56XX, CN55XX, and CN54XX. > + * > + * @param port Port to rate limit > + * @param packets_s Maximum packet/sec > + * @param burst Maximum number of packets to burst in a row > before rate > + * limiting cuts in. > + * > + * @return Zero on success, negative on failure > + */ > +int cvmx_pko_rate_limit_packets(int port, int packets_s, int burst); > + > +/** > + * Rate limit a PKO port to a max bits/sec. This function is only > + * supported on CN57XX, CN56XX, CN55XX, and CN54XX. > + * > + * @param port Port to rate limit > + * @param bits_s PKO rate limit in bits/sec > + * @param burst Maximum number of bits to burst before rate > + * limiting cuts in. > + * > + * @return Zero on success, negative on failure > + */ > +int cvmx_pko_rate_limit_bits(int port, u64 bits_s, int burst); > + > +/** > + * @INTERNAL > + * > + * Retrieve the PKO pipe number for a port > + * > + * @param interface > + * @param index > + * > + * @return negative on error. > + * > + * This applies only to the non-loopback interfaces. > + * > + */ > +int __cvmx_pko_get_pipe(int interface, int index); > + > +/** > + * For a given PKO port number, return the base output queue > + * for the port. > + * > + * @param pko_port PKO port number > + * @return Base output queue > + */ > +int cvmx_pko_get_base_queue_pkoid(int pko_port); > + > +/** > + * For a given PKO port number, return the number of output queues > + * for the port. > + * > + * @param pko_port PKO port number > + * @return the number of output queues > + */ > +int cvmx_pko_get_num_queues_pkoid(int pko_port); > + > +/** > + * Ring the packet output doorbell. This tells the packet > + * output hardware that "len" command words have been added > + * to its pending list. This command includes the required > + * CVMX_SYNCWS before the doorbell ring. > + * > + * @param pko_port Port the packet is for > + * @param queue Queue the packet is for > + * @param len Length of the command in 64 bit words > + */ > +static inline void cvmx_pko_doorbell_pkoid(u64 pko_port, u64 queue, > u64 len) > +{ > + cvmx_pko_doorbell_address_t ptr; > + > + ptr.u64 = 0; > + ptr.s.mem_space = CVMX_IO_SEG; > + ptr.s.did = CVMX_OCT_DID_PKT_SEND; > + ptr.s.is_io = 1; > + ptr.s.port = pko_port; > + ptr.s.queue = queue; > + /* Need to make sure output queue data is in DRAM before > doorbell write */ > + CVMX_SYNCWS; > + cvmx_write_io(ptr.u64, len); > +} > + > +/** > + * Complete packet output. cvmx_pko_send_packet_prepare() must be > called exactly once before this, > + * and the same parameters must be passed to both > cvmx_pko_send_packet_prepare() and > + * cvmx_pko_send_packet_finish_pkoid(). > + * > + * @param pko_port Port to send it on > + * @param queue Queue to use > + * @param pko_command > + * PKO HW command word > + * @param packet Packet to send > + * @param use_locking > + * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or > CVMX_PKO_LOCK_CMD_QUEUE > + * > + * @return returns CVMX_PKO_SUCCESS on success, or error code on > failure of output > + */ > +static inline cvmx_pko_return_value_t > +cvmx_hwpko_send_packet_finish_pkoid(int pko_port, u64 queue, > cvmx_pko_command_word0_t pko_command, > + cvmx_buf_ptr_t packet, > cvmx_pko_lock_t use_locking) > +{ > + cvmx_cmd_queue_result_t result; > + > + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) > + cvmx_pow_tag_sw_wait(); > + > + result = cvmx_cmd_queue_write2(CVMX_CMD_QUEUE_PKO(queue), > + (use_locking == > CVMX_PKO_LOCK_CMD_QUEUE), pko_command.u64, > + packet.u64); > + if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS)) { > + cvmx_pko_doorbell_pkoid(pko_port, queue, 2); > + return CVMX_PKO_SUCCESS; > + } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == > CVMX_CMD_QUEUE_FULL)) { > + return CVMX_PKO_NO_MEMORY; > + } else { > + return CVMX_PKO_INVALID_QUEUE; > + } > +} > + > +/** > + * Complete packet output. cvmx_pko_send_packet_prepare() must be > called exactly once before this, > + * and the same parameters must be passed to both > cvmx_pko_send_packet_prepare() and > + * cvmx_pko_send_packet_finish_pkoid(). > + * > + * @param pko_port The PKO port the packet is for > + * @param queue Queue to use > + * @param pko_command > + * PKO HW command word > + * @param packet Packet to send > + * @param addr Plysical address of a work queue entry or physical > address to zero on complete. > + * @param use_locking > + * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or > CVMX_PKO_LOCK_CMD_QUEUE > + * > + * @return returns CVMX_PKO_SUCCESS on success, or error code on > failure of output > + */ > +static inline cvmx_pko_return_value_t > +cvmx_hwpko_send_packet_finish3_pkoid(u64 pko_port, u64 queue, > cvmx_pko_command_word0_t pko_command, > + cvmx_buf_ptr_t packet, u64 addr, > cvmx_pko_lock_t use_locking) > +{ > + cvmx_cmd_queue_result_t result; > + > + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) > + cvmx_pow_tag_sw_wait(); > + > + result = cvmx_cmd_queue_write3(CVMX_CMD_QUEUE_PKO(queue), > + (use_locking == > CVMX_PKO_LOCK_CMD_QUEUE), pko_command.u64, > + packet.u64, addr); > + if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS)) { > + cvmx_pko_doorbell_pkoid(pko_port, queue, 3); > + return CVMX_PKO_SUCCESS; > + } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == > CVMX_CMD_QUEUE_FULL)) { > + return CVMX_PKO_NO_MEMORY; > + } else { > + return CVMX_PKO_INVALID_QUEUE; > + } > +} > + > +/* > + * Obtain the number of PKO commands pending in a queue > + * > + * @param queue is the queue identifier to be queried > + * @return the number of commands pending transmission or -1 on > error > + */ > +int cvmx_pko_queue_pend_count(cvmx_cmd_queue_id_t queue); > + > +void cvmx_pko_set_cmd_queue_pool_buffer_count(u64 buffer_count); > + > +#endif /* __CVMX_HWPKO_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-ilk.h > b/arch/mips/mach-octeon/include/mach/cvmx-ilk.h > new file mode 100644 > index 000000000000..727298352c28 > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-ilk.h > @@ -0,0 +1,154 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * This file contains defines for the ILK interface > + */ > + > +#ifndef __CVMX_ILK_H__ > +#define __CVMX_ILK_H__ > + > +/* CSR typedefs have been moved to cvmx-ilk-defs.h */ > + > +/* > + * Note: this macro must match the first ilk port in the > ipd_port_map_68xx[] > + * and ipd_port_map_78xx[] arrays. > + */ > +static inline int CVMX_ILK_GBL_BASE(void) > +{ > + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) > + return 5; > + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) > + return 6; > + return -1; > +} > + > +static inline int CVMX_ILK_QLM_BASE(void) > +{ > + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) > + return 1; > + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) > + return 4; > + return -1; > +} > + > +typedef struct { > + int intf_en : 1; > + int la_mode : 1; > + int reserved : 14; /* unused */ > + int lane_speed : 16; > + /* add more here */ > +} cvmx_ilk_intf_t; > + > +#define CVMX_NUM_ILK_INTF 2 > +static inline int CVMX_ILK_MAX_LANES(void) > +{ > + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) > + return 8; > + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) > + return 16; > + return -1; > +} > + > +extern unsigned short > cvmx_ilk_lane_mask[CVMX_MAX_NODES][CVMX_NUM_ILK_INTF]; > + > +typedef struct { > + unsigned int pipe; > + unsigned int chan; > +} cvmx_ilk_pipe_chan_t; > + > +#define CVMX_ILK_MAX_PIPES 45 > +/* Max number of channels allowed */ > +#define CVMX_ILK_MAX_CHANS 256 > + > +extern int cvmx_ilk_chans[CVMX_MAX_NODES][CVMX_NUM_ILK_INTF]; > + > +typedef struct { > + unsigned int chan; > + unsigned int pknd; > +} cvmx_ilk_chan_pknd_t; > + > +#define CVMX_ILK_MAX_PKNDS 16 /* must be <45 */ > + > +typedef struct { > + int *chan_list; /* for discrete channels. or, must be null */ > + unsigned int num_chans; > + > + unsigned int chan_start; /* for continuous channels */ > + unsigned int chan_end; > + unsigned int chan_step; > + > + unsigned int clr_on_rd; > +} cvmx_ilk_stats_ctrl_t; > + > +#define CVMX_ILK_MAX_CAL 288 > +#define CVMX_ILK_MAX_CAL_IDX (CVMX_ILK_MAX_CAL / 8) > +#define CVMX_ILK_TX_MIN_CAL 1 > +#define CVMX_ILK_RX_MIN_CAL 1 > +#define CVMX_ILK_CAL_GRP_SZ 8 > +#define CVMX_ILK_PIPE_BPID_SZ 7 > +#define CVMX_ILK_ENT_CTRL_SZ 2 > +#define CVMX_ILK_RX_FIFO_WM 0x200 > + > +typedef enum { PIPE_BPID = 0, LINK, XOFF, XON } > cvmx_ilk_cal_ent_ctrl_t; > + > +typedef struct { > + unsigned char pipe_bpid; > + cvmx_ilk_cal_ent_ctrl_t ent_ctrl; > +} cvmx_ilk_cal_entry_t; > + > +typedef enum { CVMX_ILK_LPBK_DISA = 0, CVMX_ILK_LPBK_ENA } > cvmx_ilk_lpbk_ena_t; > + > +typedef enum { CVMX_ILK_LPBK_INT = 0, CVMX_ILK_LPBK_EXT } > cvmx_ilk_lpbk_mode_t; > + > +/** > + * This header is placed in front of all received ILK look-aside > mode packets > + */ > +typedef union { > + u64 u64; > + > + struct { > + u32 reserved_63_57 : 7; /* bits 63...57 */ > + u32 nsp_cmd : 5; /* bits 56...52 */ > + u32 nsp_flags : 4; /* bits 51...48 */ > + u32 nsp_grp_id_upper : 6; /* bits 47...42 */ > + u32 reserved_41_40 : 2; /* bits 41...40 */ > + /* Protocol type, 1 for LA mode packet */ > + u32 la_mode : 1; /* bit 39 */ > + u32 nsp_grp_id_lower : 2; /* bits 38...37 */ > + u32 nsp_xid_upper : 4; /* bits 36...33 */ > + /* ILK channel number, 0 or 1 */ > + u32 ilk_channel : 1; /* bit 32 */ > + u32 nsp_xid_lower : 8; /* bits 31...24 */ > + /* Unpredictable, may be any value */ > + u32 reserved_23_0 : 24; /* bits 23...0 */ > + } s; > +} cvmx_ilk_la_nsp_compact_hdr_t; > + > +typedef struct cvmx_ilk_LA_mode_struct { > + int ilk_LA_mode; > + int ilk_LA_mode_cal_ena; > +} cvmx_ilk_LA_mode_t; > + > +extern cvmx_ilk_LA_mode_t cvmx_ilk_LA_mode[CVMX_NUM_ILK_INTF]; > + > +int cvmx_ilk_use_la_mode(int interface, int channel); > +int cvmx_ilk_start_interface(int interface, unsigned short > num_lanes); > +int cvmx_ilk_start_interface_la(int interface, unsigned char > num_lanes); > +int cvmx_ilk_set_pipe(int interface, int pipe_base, unsigned int > pipe_len); > +int cvmx_ilk_tx_set_channel(int interface, cvmx_ilk_pipe_chan_t > *pch, unsigned int num_chs); > +int cvmx_ilk_rx_set_pknd(int interface, cvmx_ilk_chan_pknd_t > *chpknd, unsigned int num_pknd); > +int cvmx_ilk_enable(int interface); > +int cvmx_ilk_disable(int interface); > +int cvmx_ilk_get_intf_ena(int interface); > +int cvmx_ilk_get_chan_info(int interface, unsigned char **chans, > unsigned char *num_chan); > +cvmx_ilk_la_nsp_compact_hdr_t cvmx_ilk_enable_la_header(int > ipd_port, int mode); > +void cvmx_ilk_show_stats(int interface, cvmx_ilk_stats_ctrl_t > *pstats); > +int cvmx_ilk_cal_setup_rx(int interface, int cal_depth, > cvmx_ilk_cal_entry_t *pent, int hi_wm, > + unsigned char cal_ena); > +int cvmx_ilk_cal_setup_tx(int interface, int cal_depth, > cvmx_ilk_cal_entry_t *pent, > + unsigned char cal_ena); > +int cvmx_ilk_lpbk(int interface, cvmx_ilk_lpbk_ena_t enable, > cvmx_ilk_lpbk_mode_t mode); > +int cvmx_ilk_la_mode_enable_rx_calendar(int interface); > + > +#endif /* __CVMX_ILK_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-ipd.h > b/arch/mips/mach-octeon/include/mach/cvmx-ipd.h > new file mode 100644 > index 000000000000..cdff36fffb56 > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-ipd.h > @@ -0,0 +1,233 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Interface to the hardware Input Packet Data unit. > + */ > + > +#ifndef __CVMX_IPD_H__ > +#define __CVMX_IPD_H__ > + > +#include "cvmx-pki.h" > + > +/* CSR typedefs have been moved to cvmx-ipd-defs.h */ > + > +typedef cvmx_ipd_1st_mbuff_skip_t cvmx_ipd_mbuff_not_first_skip_t; > +typedef cvmx_ipd_1st_next_ptr_back_t > cvmx_ipd_second_next_ptr_back_t; > + > +typedef struct cvmx_ipd_tag_fields { > + u64 ipv6_src_ip : 1; > + u64 ipv6_dst_ip : 1; > + u64 ipv6_src_port : 1; > + u64 ipv6_dst_port : 1; > + u64 ipv6_next_header : 1; > + u64 ipv4_src_ip : 1; > + u64 ipv4_dst_ip : 1; > + u64 ipv4_src_port : 1; > + u64 ipv4_dst_port : 1; > + u64 ipv4_protocol : 1; > + u64 input_port : 1; > +} cvmx_ipd_tag_fields_t; > + > +typedef struct cvmx_pip_port_config { > + u64 parse_mode; > + u64 tag_type; > + u64 tag_mode; > + cvmx_ipd_tag_fields_t tag_fields; > +} cvmx_pip_port_config_t; > + > +typedef struct cvmx_ipd_config_struct { > + u64 first_mbuf_skip; > + u64 not_first_mbuf_skip; > + u64 ipd_enable; > + u64 enable_len_M8_fix; > + u64 cache_mode; > + cvmx_fpa_pool_config_t packet_pool; > + cvmx_fpa_pool_config_t wqe_pool; > + cvmx_pip_port_config_t port_config; > +} cvmx_ipd_config_t; > + > +extern cvmx_ipd_config_t cvmx_ipd_cfg; > + > +/** > + * Gets the fpa pool number of packet pool > + */ > +static inline s64 cvmx_fpa_get_packet_pool(void) > +{ > + return (cvmx_ipd_cfg.packet_pool.pool_num); > +} > + > +/** > + * Gets the buffer size of packet pool buffer > + */ > +static inline u64 cvmx_fpa_get_packet_pool_block_size(void) > +{ > + return (cvmx_ipd_cfg.packet_pool.buffer_size); > +} > + > +/** > + * Gets the buffer count of packet pool > + */ > +static inline u64 cvmx_fpa_get_packet_pool_buffer_count(void) > +{ > + return (cvmx_ipd_cfg.packet_pool.buffer_count); > +} > + > +/** > + * Gets the fpa pool number of wqe pool > + */ > +static inline s64 cvmx_fpa_get_wqe_pool(void) > +{ > + return (cvmx_ipd_cfg.wqe_pool.pool_num); > +} > + > +/** > + * Gets the buffer size of wqe pool buffer > + */ > +static inline u64 cvmx_fpa_get_wqe_pool_block_size(void) > +{ > + return (cvmx_ipd_cfg.wqe_pool.buffer_size); > +} > + > +/** > + * Gets the buffer count of wqe pool > + */ > +static inline u64 cvmx_fpa_get_wqe_pool_buffer_count(void) > +{ > + return (cvmx_ipd_cfg.wqe_pool.buffer_count); > +} > + > +/** > + * Sets the ipd related configuration in internal structure which is > then used > + * for seting IPD hardware block > + */ > +int cvmx_ipd_set_config(cvmx_ipd_config_t ipd_config); > + > +/** > + * Gets the ipd related configuration from internal structure. > + */ > +void cvmx_ipd_get_config(cvmx_ipd_config_t *ipd_config); > + > +/** > + * Sets the internal FPA pool data structure for packet buffer pool. > + * @param pool fpa pool number yo use > + * @param buffer_size buffer size of pool > + * @param buffer_count number of buufers to allocate to pool > + */ > +void cvmx_ipd_set_packet_pool_config(s64 pool, u64 buffer_size, u64 > buffer_count); > + > +/** > + * Sets the internal FPA pool data structure for wqe pool. > + * @param pool fpa pool number yo use > + * @param buffer_size buffer size of pool > + * @param buffer_count number of buufers to allocate to pool > + */ > +void cvmx_ipd_set_wqe_pool_config(s64 pool, u64 buffer_size, u64 > buffer_count); > + > +/** > + * Gets the FPA packet buffer pool parameters. > + */ > +static inline void cvmx_fpa_get_packet_pool_config(s64 *pool, u64 > *buffer_size, u64 *buffer_count) > +{ > + if (pool) > + *pool = cvmx_ipd_cfg.packet_pool.pool_num; > + if (buffer_size) > + *buffer_size = cvmx_ipd_cfg.packet_pool.buffer_size; > + if (buffer_count) > + *buffer_count = cvmx_ipd_cfg.packet_pool.buffer_count; > +} > + > +/** > + * Sets the FPA packet buffer pool parameters. > + */ > +static inline void cvmx_fpa_set_packet_pool_config(s64 pool, u64 > buffer_size, u64 buffer_count) > +{ > + cvmx_ipd_set_packet_pool_config(pool, buffer_size, > buffer_count); > +} > + > +/** > + * Gets the FPA WQE pool parameters. > + */ > +static inline void cvmx_fpa_get_wqe_pool_config(s64 *pool, u64 > *buffer_size, u64 *buffer_count) > +{ > + if (pool) > + *pool = cvmx_ipd_cfg.wqe_pool.pool_num; > + if (buffer_size) > + *buffer_size = cvmx_ipd_cfg.wqe_pool.buffer_size; > + if (buffer_count) > + *buffer_count = cvmx_ipd_cfg.wqe_pool.buffer_count; > +} > + > +/** > + * Sets the FPA WQE pool parameters. > + */ > +static inline void cvmx_fpa_set_wqe_pool_config(s64 pool, u64 > buffer_size, u64 buffer_count) > +{ > + cvmx_ipd_set_wqe_pool_config(pool, buffer_size, buffer_count); > +} > + > +/** > + * Configure IPD > + * > + * @param mbuff_size Packets buffer size in 8 byte words > + * @param first_mbuff_skip > + * Number of 8 byte words to skip in the first > buffer > + * @param not_first_mbuff_skip > + * Number of 8 byte words to skip in each > following buffer > + * @param first_back Must be same as first_mbuff_skip / 128 > + * @param second_back > + * Must be same as not_first_mbuff_skip / 128 > + * @param wqe_fpa_pool > + * FPA pool to get work entries from > + * @param cache_mode > + * @param back_pres_enable_flag > + * Enable or disable port back pressure at a > global level. > + * This should always be 1 as more accurate > control can be > + * found in IPD_PORTX_BP_PAGE_CNT[BP_ENB]. > + */ > +void cvmx_ipd_config(u64 mbuff_size, u64 first_mbuff_skip, u64 > not_first_mbuff_skip, u64 first_back, > + u64 second_back, u64 wqe_fpa_pool, cvmx_ipd_mode_t > cache_mode, > + u64 back_pres_enable_flag); > +/** > + * Enable IPD > + */ > +void cvmx_ipd_enable(void); > + > +/** > + * Disable IPD > + */ > +void cvmx_ipd_disable(void); > + > +void __cvmx_ipd_free_ptr(void); > + > +void cvmx_ipd_set_packet_pool_buffer_count(u64 buffer_count); > +void cvmx_ipd_set_wqe_pool_buffer_count(u64 buffer_count); > + > +/** > + * Setup Random Early Drop on a specific input queue > + * > + * @param queue Input queue to setup RED on (0-7) > + * @param pass_thresh > + * Packets will begin slowly dropping when there are > less than > + * this many packet buffers free in FPA 0. > + * @param drop_thresh > + * All incoming packets will be dropped when there are > less > + * than this many free packet buffers in FPA 0. > + * @return Zero on success. Negative on failure > + */ > +int cvmx_ipd_setup_red_queue(int queue, int pass_thresh, int > drop_thresh); > + > +/** > + * Setup Random Early Drop to automatically begin dropping packets. > + * > + * @param pass_thresh > + * Packets will begin slowly dropping when there are > less than > + * this many packet buffers free in FPA 0. > + * @param drop_thresh > + * All incoming packets will be dropped when there are > less > + * than this many free packet buffers in FPA 0. > + * @return Zero on success. Negative on failure > + */ > +int cvmx_ipd_setup_red(int pass_thresh, int drop_thresh); > + > +#endif /* __CVMX_IPD_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-packet.h > b/arch/mips/mach-octeon/include/mach/cvmx-packet.h > new file mode 100644 > index 000000000000..f3cfe9c64f43 > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-packet.h > @@ -0,0 +1,40 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Packet buffer defines. > + */ > + > +#ifndef __CVMX_PACKET_H__ > +#define __CVMX_PACKET_H__ > + > +union cvmx_buf_ptr_pki { > + u64 u64; > + struct { > + u64 size : 16; > + u64 packet_outside_wqe : 1; > + u64 rsvd0 : 5; > + u64 addr : 42; > + }; > +}; > + > +typedef union cvmx_buf_ptr_pki cvmx_buf_ptr_pki_t; > + > +/** > + * This structure defines a buffer pointer on Octeon > + */ > +union cvmx_buf_ptr { > + void *ptr; > + u64 u64; > + struct { > + u64 i : 1; > + u64 back : 4; > + u64 pool : 3; > + u64 size : 16; > + u64 addr : 40; > + } s; > +}; > + > +typedef union cvmx_buf_ptr cvmx_buf_ptr_t; > + > +#endif /* __CVMX_PACKET_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pcie.h > b/arch/mips/mach-octeon/include/mach/cvmx-pcie.h > new file mode 100644 > index 000000000000..a819196c021c > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-pcie.h > @@ -0,0 +1,279 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + */ > + > +#ifndef __CVMX_PCIE_H__ > +#define __CVMX_PCIE_H__ > + > +#define CVMX_PCIE_MAX_PORTS 4 > +#define > CVMX_PCIE_PORTS > \ > + ((OCTEON_IS_MODEL(OCTEON_CN78XX) || > OCTEON_IS_MODEL(OCTEON_CN73XX)) ? \ > + CVMX_PCIE_MAX_PORTS > : \ > + (OCTEON_IS_MODEL(OCTEON_CN70XX) ? 3 : 2)) > + > +/* > + * The physical memory base mapped by BAR1. 256MB at the end of the > + * first 4GB. > + */ > +#define CVMX_PCIE_BAR1_PHYS_BASE ((1ull << 32) - (1ull << 28)) > +#define CVMX_PCIE_BAR1_PHYS_SIZE BIT_ULL(28) > + > +/* > + * The RC base of BAR1. gen1 has a 39-bit BAR2, gen2 has 41-bit > BAR2, > + * place BAR1 so it is the same for both. > + */ > +#define CVMX_PCIE_BAR1_RC_BASE BIT_ULL(41) > + > +typedef union { > + u64 u64; > + struct { > + u64 upper : 2; /* Normally 2 for XKPHYS */ > + u64 reserved_49_61 : 13; /* Must be zero */ > + u64 io : 1; /* 1 for IO space access */ > + u64 did : 5; /* PCIe DID = 3 */ > + u64 subdid : 3; /* PCIe SubDID = 1 */ > + u64 reserved_38_39 : 2; /* Must be zero */ > + u64 node : 2; /* Numa node number */ > + u64 es : 2; /* Endian swap = 1 */ > + u64 port : 2; /* PCIe port 0,1 */ > + u64 reserved_29_31 : 3; /* Must be zero */ > + u64 ty : 1; > + u64 bus : 8; > + u64 dev : 5; > + u64 func : 3; > + u64 reg : 12; > + } config; > + struct { > + u64 upper : 2; /* Normally 2 for XKPHYS */ > + u64 reserved_49_61 : 13; /* Must be zero */ > + u64 io : 1; /* 1 for IO space access */ > + u64 did : 5; /* PCIe DID = 3 */ > + u64 subdid : 3; /* PCIe SubDID = 2 */ > + u64 reserved_38_39 : 2; /* Must be zero */ > + u64 node : 2; /* Numa node number */ > + u64 es : 2; /* Endian swap = 1 */ > + u64 port : 2; /* PCIe port 0,1 */ > + u64 address : 32; /* PCIe IO address */ > + } io; > + struct { > + u64 upper : 2; /* Normally 2 for XKPHYS */ > + u64 reserved_49_61 : 13; /* Must be zero */ > + u64 io : 1; /* 1 for IO space access */ > + u64 did : 5; /* PCIe DID = 3 */ > + u64 subdid : 3; /* PCIe SubDID = 3-6 */ > + u64 reserved_38_39 : 2; /* Must be zero */ > + u64 node : 2; /* Numa node number */ > + u64 address : 36; /* PCIe Mem address */ > + } mem; > +} cvmx_pcie_address_t; > + > +/** > + * Return the Core virtual base address for PCIe IO access. IOs are > + * read/written as an offset from this address. > + * > + * @param pcie_port PCIe port the IO is for > + * > + * @return 64bit Octeon IO base address for read/write > + */ > +u64 cvmx_pcie_get_io_base_address(int pcie_port); > + > +/** > + * Size of the IO address region returned at address > + * cvmx_pcie_get_io_base_address() > + * > + * @param pcie_port PCIe port the IO is for > + * > + * @return Size of the IO window > + */ > +u64 cvmx_pcie_get_io_size(int pcie_port); > + > +/** > + * Return the Core virtual base address for PCIe MEM access. Memory > is > + * read/written as an offset from this address. > + * > + * @param pcie_port PCIe port the IO is for > + * > + * @return 64bit Octeon IO base address for read/write > + */ > +u64 cvmx_pcie_get_mem_base_address(int pcie_port); > + > +/** > + * Size of the Mem address region returned at address > + * cvmx_pcie_get_mem_base_address() > + * > + * @param pcie_port PCIe port the IO is for > + * > + * @return Size of the Mem window > + */ > +u64 cvmx_pcie_get_mem_size(int pcie_port); > + > +/** > + * Initialize a PCIe port for use in host(RC) mode. It doesn't > enumerate the bus. > + * > + * @param pcie_port PCIe port to initialize > + * > + * @return Zero on success > + */ > +int cvmx_pcie_rc_initialize(int pcie_port); > + > +/** > + * Shutdown a PCIe port and put it in reset > + * > + * @param pcie_port PCIe port to shutdown > + * > + * @return Zero on success > + */ > +int cvmx_pcie_rc_shutdown(int pcie_port); > + > +/** > + * Read 8bits from a Device's config space > + * > + * @param pcie_port PCIe port the device is on > + * @param bus Sub bus > + * @param dev Device ID > + * @param fn Device sub function > + * @param reg Register to access > + * > + * @return Result of the read > + */ > +u8 cvmx_pcie_config_read8(int pcie_port, int bus, int dev, int fn, > int reg); > + > +/** > + * Read 16bits from a Device's config space > + * > + * @param pcie_port PCIe port the device is on > + * @param bus Sub bus > + * @param dev Device ID > + * @param fn Device sub function > + * @param reg Register to access > + * > + * @return Result of the read > + */ > +u16 cvmx_pcie_config_read16(int pcie_port, int bus, int dev, int fn, > int reg); > + > +/** > + * Read 32bits from a Device's config space > + * > + * @param pcie_port PCIe port the device is on > + * @param bus Sub bus > + * @param dev Device ID > + * @param fn Device sub function > + * @param reg Register to access > + * > + * @return Result of the read > + */ > +u32 cvmx_pcie_config_read32(int pcie_port, int bus, int dev, int fn, > int reg); > + > +/** > + * Write 8bits to a Device's config space > + * > + * @param pcie_port PCIe port the device is on > + * @param bus Sub bus > + * @param dev Device ID > + * @param fn Device sub function > + * @param reg Register to access > + * @param val Value to write > + */ > +void cvmx_pcie_config_write8(int pcie_port, int bus, int dev, int > fn, int reg, u8 val); > + > +/** > + * Write 16bits to a Device's config space > + * > + * @param pcie_port PCIe port the device is on > + * @param bus Sub bus > + * @param dev Device ID > + * @param fn Device sub function > + * @param reg Register to access > + * @param val Value to write > + */ > +void cvmx_pcie_config_write16(int pcie_port, int bus, int dev, int > fn, int reg, u16 val); > + > +/** > + * Write 32bits to a Device's config space > + * > + * @param pcie_port PCIe port the device is on > + * @param bus Sub bus > + * @param dev Device ID > + * @param fn Device sub function > + * @param reg Register to access > + * @param val Value to write > + */ > +void cvmx_pcie_config_write32(int pcie_port, int bus, int dev, int > fn, int reg, u32 val); > + > +/** > + * Read a PCIe config space register indirectly. This is used for > + * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???. > + * > + * @param pcie_port PCIe port to read from > + * @param cfg_offset Address to read > + * > + * @return Value read > + */ > +u32 cvmx_pcie_cfgx_read(int pcie_port, u32 cfg_offset); > +u32 cvmx_pcie_cfgx_read_node(int node, int pcie_port, u32 > cfg_offset); > + > +/** > + * Write a PCIe config space register indirectly. This is used for > + * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???. > + * > + * @param pcie_port PCIe port to write to > + * @param cfg_offset Address to write > + * @param val Value to write > + */ > +void cvmx_pcie_cfgx_write(int pcie_port, u32 cfg_offset, u32 val); > +void cvmx_pcie_cfgx_write_node(int node, int pcie_port, u32 > cfg_offset, u32 val); > + > +/** > + * Write a 32bit value to the Octeon NPEI register space > + * > + * @param address Address to write to > + * @param val Value to write > + */ > +static inline void cvmx_pcie_npei_write32(u64 address, u32 val) > +{ > + cvmx_write64_uint32(address ^ 4, val); > + cvmx_read64_uint32(address ^ 4); > +} > + > +/** > + * Read a 32bit value from the Octeon NPEI register space > + * > + * @param address Address to read > + * @return The result > + */ > +static inline u32 cvmx_pcie_npei_read32(u64 address) > +{ > + return cvmx_read64_uint32(address ^ 4); > +} > + > +/** > + * Initialize a PCIe port for use in target(EP) mode. > + * > + * @param pcie_port PCIe port to initialize > + * > + * @return Zero on success > + */ > +int cvmx_pcie_ep_initialize(int pcie_port); > + > +/** > + * Wait for posted PCIe read/writes to reach the other side of > + * the internal PCIe switch. This will insure that core > + * read/writes are posted before anything after this function > + * is called. This may be necessary when writing to memory that > + * will later be read using the DMA/PKT engines. > + * > + * @param pcie_port PCIe port to wait for > + */ > +void cvmx_pcie_wait_for_pending(int pcie_port); > + > +/** > + * Returns if a PCIe port is in host or target mode. > + * > + * @param pcie_port PCIe port number (PEM number) > + * > + * @return 0 if PCIe port is in target mode, !0 if in host mode. > + */ > +int cvmx_pcie_is_host_mode(int pcie_port); > + > +#endif > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pip.h > b/arch/mips/mach-octeon/include/mach/cvmx-pip.h > new file mode 100644 > index 000000000000..013f533fb7bb > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-pip.h > @@ -0,0 +1,1080 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Interface to the hardware Packet Input Processing unit. > + */ > + > +#ifndef __CVMX_PIP_H__ > +#define __CVMX_PIP_H__ > + > +#include "cvmx-wqe.h" > +#include "cvmx-pki.h" > +#include "cvmx-helper-pki.h" > + > +#include "cvmx-helper.h" > +#include "cvmx-helper-util.h" > +#include "cvmx-pki-resources.h" > + > +#define CVMX_PIP_NUM_INPUT_PORTS 46 > +#define CVMX_PIP_NUM_WATCHERS 8 > + > +/* > + * Encodes the different error and exception codes > + */ > +typedef enum { > + CVMX_PIP_L4_NO_ERR = 0ull, > + /* 1 = TCP (UDP) packet not long enough to cover TCP > (UDP) header */ > + CVMX_PIP_L4_MAL_ERR = 1ull, > + /* 2 = TCP/UDP checksum failure */ > + CVMX_PIP_CHK_ERR = 2ull, > + /* 3 = TCP/UDP length check (TCP/UDP length does not > match IP length) */ > + CVMX_PIP_L4_LENGTH_ERR = 3ull, > + /* 4 = illegal TCP/UDP port (either source or dest port > is zero) */ > + CVMX_PIP_BAD_PRT_ERR = 4ull, > + /* 8 = TCP flags = FIN only */ > + CVMX_PIP_TCP_FLG8_ERR = 8ull, > + /* 9 = TCP flags = 0 */ > + CVMX_PIP_TCP_FLG9_ERR = 9ull, > + /* 10 = TCP flags = FIN+RST+* */ > + CVMX_PIP_TCP_FLG10_ERR = 10ull, > + /* 11 = TCP flags = SYN+URG+* */ > + CVMX_PIP_TCP_FLG11_ERR = 11ull, > + /* 12 = TCP flags = SYN+RST+* */ > + CVMX_PIP_TCP_FLG12_ERR = 12ull, > + /* 13 = TCP flags = SYN+FIN+* */ > + CVMX_PIP_TCP_FLG13_ERR = 13ull > +} cvmx_pip_l4_err_t; > + > +typedef enum { > + CVMX_PIP_IP_NO_ERR = 0ull, > + /* 1 = not IPv4 or IPv6 */ > + CVMX_PIP_NOT_IP = 1ull, > + /* 2 = IPv4 header checksum violation */ > + CVMX_PIP_IPV4_HDR_CHK = 2ull, > + /* 3 = malformed (packet not long enough to cover IP > hdr) */ > + CVMX_PIP_IP_MAL_HDR = 3ull, > + /* 4 = malformed (packet not long enough to cover len in > IP hdr) */ > + CVMX_PIP_IP_MAL_PKT = 4ull, > + /* 5 = TTL / hop count equal zero */ > + CVMX_PIP_TTL_HOP = 5ull, > + /* 6 = IPv4 options / IPv6 early extension headers */ > + CVMX_PIP_OPTS = 6ull > +} cvmx_pip_ip_exc_t; > + > +/** > + * NOTES > + * late collision (data received before collision) > + * late collisions cannot be detected by the receiver > + * they would appear as JAM bits which would appear as > bad FCS > + * or carrier extend error which is CVMX_PIP_EXTEND_ERR > + */ > +typedef enum { > + /** > + * No error > + */ > + CVMX_PIP_RX_NO_ERR = 0ull, > + > + CVMX_PIP_PARTIAL_ERR = > + 1ull, /* RGM+SPI 1 = partially received > packet (buffering/bandwidth not adequate) */ > + CVMX_PIP_JABBER_ERR = > + 2ull, /* RGM+SPI 2 = receive packet too > large and truncated */ > + CVMX_PIP_OVER_FCS_ERR = > + 3ull, /* RGM 3 = max frame error (pkt > len > max frame len) (with FCS error) */ > + CVMX_PIP_OVER_ERR = > + 4ull, /* RGM+SPI 4 = max frame error (pkt > len > max frame len) */ > + CVMX_PIP_ALIGN_ERR = > + 5ull, /* RGM 5 = nibble error (data not > byte multiple - 100M and 10M only) */ > + CVMX_PIP_UNDER_FCS_ERR = > + 6ull, /* RGM 6 = min frame error (pkt > len < min frame len) (with FCS error) */ > + CVMX_PIP_GMX_FCS_ERR = 7ull, /* RGM 7 = FCS > error */ > + CVMX_PIP_UNDER_ERR = > + 8ull, /* RGM+SPI 8 = min frame error (pkt > len < min frame len) */ > + CVMX_PIP_EXTEND_ERR = 9ull, /* RGM 9 = Frame > carrier extend error */ > + CVMX_PIP_TERMINATE_ERR = > + 9ull, /* XAUI 9 = Packet was terminated > with an idle cycle */ > + CVMX_PIP_LENGTH_ERR = > + 10ull, /* RGM 10 = length mismatch (len > did not match len in L2 length/type) */ > + CVMX_PIP_DAT_ERR = > + 11ull, /* RGM 11 = Frame error (some or > all data bits marked err) */ > + CVMX_PIP_DIP_ERR = 11ull, /* SPI 11 = DIP4 error > */ > + CVMX_PIP_SKIP_ERR = > + 12ull, /* RGM 12 = packet was not large > enough to pass the skipper - no inspection could occur */ > + CVMX_PIP_NIBBLE_ERR = > + 13ull, /* RGM 13 = studder error (data > not repeated - 100M and 10M only) */ > + CVMX_PIP_PIP_FCS = 16L, /* RGM+SPI 16 = FCS error */ > + CVMX_PIP_PIP_SKIP_ERR = > + 17L, /* RGM+SPI+PCI 17 = packet was not large > enough to pass the skipper - no inspection could occur */ > + CVMX_PIP_PIP_L2_MAL_HDR = > + 18L, /* RGM+SPI+PCI 18 = malformed l2 (packet not > long enough to cover L2 hdr) */ > + CVMX_PIP_PUNY_ERR = > + 47L /* SGMII 47 = PUNY error (packet was 4B > or less when FCS stripping is enabled) */ > + /* NOTES > + * xx = late collision (data received before collision) > + * late collisions cannot be detected by the > receiver > + * they would appear as JAM bits which would appear > as bad FCS > + * or carrier extend error which is > CVMX_PIP_EXTEND_ERR > + */ > +} cvmx_pip_rcv_err_t; > + > +/** > + * This defines the err_code field errors in the work Q entry > + */ > +typedef union { > + cvmx_pip_l4_err_t l4_err; > + cvmx_pip_ip_exc_t ip_exc; > + cvmx_pip_rcv_err_t rcv_err; > +} cvmx_pip_err_t; > + > +/** > + * Status statistics for a port > + */ > +typedef struct { > + u64 dropped_octets; > + u64 dropped_packets; > + u64 pci_raw_packets; > + u64 octets; > + u64 packets; > + u64 multicast_packets; > + u64 broadcast_packets; > + u64 len_64_packets; > + u64 len_65_127_packets; > + u64 len_128_255_packets; > + u64 len_256_511_packets; > + u64 len_512_1023_packets; > + u64 len_1024_1518_packets; > + u64 len_1519_max_packets; > + u64 fcs_align_err_packets; > + u64 runt_packets; > + u64 runt_crc_packets; > + u64 oversize_packets; > + u64 oversize_crc_packets; > + u64 inb_packets; > + u64 inb_octets; > + u64 inb_errors; > + u64 mcast_l2_red_packets; > + u64 bcast_l2_red_packets; > + u64 mcast_l3_red_packets; > + u64 bcast_l3_red_packets; > +} cvmx_pip_port_status_t; > + > +/** > + * Definition of the PIP custom header that can be prepended > + * to a packet by external hardware. > + */ > +typedef union { > + u64 u64; > + struct { > + u64 rawfull : 1; > + u64 reserved0 : 5; > + cvmx_pip_port_parse_mode_t parse_mode : 2; > + u64 reserved1 : 1; > + u64 skip_len : 7; > + u64 grpext : 2; > + u64 nqos : 1; > + u64 ngrp : 1; > + u64 ntt : 1; > + u64 ntag : 1; > + u64 qos : 3; > + u64 grp : 4; > + u64 rs : 1; > + cvmx_pow_tag_type_t tag_type : 2; > + u64 tag : 32; > + } s; > +} cvmx_pip_pkt_inst_hdr_t; > + > +enum cvmx_pki_pcam_match { > + CVMX_PKI_PCAM_MATCH_IP, > + CVMX_PKI_PCAM_MATCH_IPV4, > + CVMX_PKI_PCAM_MATCH_IPV6, > + CVMX_PKI_PCAM_MATCH_TCP > +}; > + > +/* CSR typedefs have been moved to cvmx-pip-defs.h */ > +static inline int cvmx_pip_config_watcher(int index, int type, u16 > match, u16 mask, int grp, > + int qos) > +{ > + if (index >= CVMX_PIP_NUM_WATCHERS) { > + debug("ERROR: pip watcher %d is > than supported\n", > index); > + return -1; > + } > + if (octeon_has_feature(OCTEON_FEATURE_PKI)) { > + /* store in software for now, only when the watcher is > enabled program the entry*/ > + if (type == CVMX_PIP_QOS_WATCH_PROTNH) { > + qos_watcher[index].field = > CVMX_PKI_PCAM_TERM_L3_FLAGS; > + qos_watcher[index].data = (u32)(match << 16); > + qos_watcher[index].data_mask = (u32)(mask << > 16); > + qos_watcher[index].advance = 0; > + } else if (type == CVMX_PIP_QOS_WATCH_TCP) { > + qos_watcher[index].field = > CVMX_PKI_PCAM_TERM_L4_PORT; > + qos_watcher[index].data = 0x060000; > + qos_watcher[index].data |= (u32)match; > + qos_watcher[index].data_mask = (u32)(mask); > + qos_watcher[index].advance = 0; > + } else if (type == CVMX_PIP_QOS_WATCH_UDP) { > + qos_watcher[index].field = > CVMX_PKI_PCAM_TERM_L4_PORT; > + qos_watcher[index].data = 0x110000; > + qos_watcher[index].data |= (u32)match; > + qos_watcher[index].data_mask = (u32)(mask); > + qos_watcher[index].advance = 0; > + } else if (type == 0x4 > /*CVMX_PIP_QOS_WATCH_ETHERTYPE*/) { > + qos_watcher[index].field = > CVMX_PKI_PCAM_TERM_ETHTYPE0; > + if (match == 0x8100) { > + debug("ERROR: default vlan entry > already exist, cant set watcher\n"); > + return -1; > + } > + qos_watcher[index].data = (u32)(match << 16); > + qos_watcher[index].data_mask = (u32)(mask << > 16); > + qos_watcher[index].advance = 4; > + } else { > + debug("ERROR: Unsupported watcher type %d\n", > type); > + return -1; > + } > + if (grp >= 32) { > + debug("ERROR: grp %d out of range for backward > compat 78xx\n", grp); > + return -1; > + } > + qos_watcher[index].sso_grp = (u8)(grp << 3 | qos); > + qos_watcher[index].configured = 1; > + } else { > + /* Implement it later */ > + } > + return 0; > +} > + > +static inline int __cvmx_pip_set_tag_type(int node, int style, int > tag_type, int field) > +{ > + struct cvmx_pki_style_config style_cfg; > + int style_num; > + int pcam_offset; > + int bank; > + struct cvmx_pki_pcam_input pcam_input; > + struct cvmx_pki_pcam_action pcam_action; > + > + /* All other style parameters remain same except tag type */ > + cvmx_pki_read_style_config(node, style, CVMX_PKI_CLUSTER_ALL, > &style_cfg); > + style_cfg.parm_cfg.tag_type = (enum cvmx_sso_tag_type)tag_type; > + style_num = cvmx_pki_style_alloc(node, -1); > + if (style_num < 0) { > + debug("ERROR: style not available to set tag type\n"); > + return -1; > + } > + cvmx_pki_write_style_config(node, style_num, > CVMX_PKI_CLUSTER_ALL, &style_cfg); > + memset(&pcam_input, 0, sizeof(pcam_input)); > + memset(&pcam_action, 0, sizeof(pcam_action)); > + pcam_input.style = style; > + pcam_input.style_mask = 0xff; > + if (field == CVMX_PKI_PCAM_MATCH_IP) { > + pcam_input.field = CVMX_PKI_PCAM_TERM_ETHTYPE0; > + pcam_input.field_mask = 0xff; > + pcam_input.data = 0x08000000; > + pcam_input.data_mask = 0xffff0000; > + pcam_action.pointer_advance = 4; > + /* legacy will write to all clusters*/ > + bank = 0; > + pcam_offset = cvmx_pki_pcam_entry_alloc(node, > CVMX_PKI_FIND_AVAL_ENTRY, bank, > + CVMX_PKI_CLUSTE > R_ALL); > + if (pcam_offset < 0) { > + debug("ERROR: pcam entry not available to > enable qos watcher\n"); > + cvmx_pki_style_free(node, style_num); > + return -1; > + } > + pcam_action.parse_mode_chg = CVMX_PKI_PARSE_NO_CHG; > + pcam_action.layer_type_set = CVMX_PKI_LTYPE_E_NONE; > + pcam_action.style_add = (u8)(style_num - style); > + cvmx_pki_pcam_write_entry(node, pcam_offset, > CVMX_PKI_CLUSTER_ALL, pcam_input, > + pcam_action); > + field = CVMX_PKI_PCAM_MATCH_IPV6; > + } > + if (field == CVMX_PKI_PCAM_MATCH_IPV4) { > + pcam_input.field = CVMX_PKI_PCAM_TERM_ETHTYPE0; > + pcam_input.field_mask = 0xff; > + pcam_input.data = 0x08000000; > + pcam_input.data_mask = 0xffff0000; > + pcam_action.pointer_advance = 4; > + } else if (field == CVMX_PKI_PCAM_MATCH_IPV6) { > + pcam_input.field = CVMX_PKI_PCAM_TERM_ETHTYPE0; > + pcam_input.field_mask = 0xff; > + pcam_input.data = 0x86dd00000; > + pcam_input.data_mask = 0xffff0000; > + pcam_action.pointer_advance = 4; > + } else if (field == CVMX_PKI_PCAM_MATCH_TCP) { > + pcam_input.field = CVMX_PKI_PCAM_TERM_L4_PORT; > + pcam_input.field_mask = 0xff; > + pcam_input.data = 0x60000; > + pcam_input.data_mask = 0xff0000; > + pcam_action.pointer_advance = 0; > + } > + pcam_action.parse_mode_chg = CVMX_PKI_PARSE_NO_CHG; > + pcam_action.layer_type_set = CVMX_PKI_LTYPE_E_NONE; > + pcam_action.style_add = (u8)(style_num - style); > + bank = pcam_input.field & 0x01; > + pcam_offset = cvmx_pki_pcam_entry_alloc(node, > CVMX_PKI_FIND_AVAL_ENTRY, bank, > + CVMX_PKI_CLUSTER_ALL); > + if (pcam_offset < 0) { > + debug("ERROR: pcam entry not available to enable qos > watcher\n"); > + cvmx_pki_style_free(node, style_num); > + return -1; > + } > + cvmx_pki_pcam_write_entry(node, pcam_offset, > CVMX_PKI_CLUSTER_ALL, pcam_input, pcam_action); > + return style_num; > +} > + > +/* Only for legacy internal use */ > +static inline int __cvmx_pip_enable_watcher_78xx(int node, int > index, int style) > +{ > + struct cvmx_pki_style_config style_cfg; > + struct cvmx_pki_qpg_config qpg_cfg; > + struct cvmx_pki_pcam_input pcam_input; > + struct cvmx_pki_pcam_action pcam_action; > + int style_num; > + int qpg_offset; > + int pcam_offset; > + int bank; > + > + if (!qos_watcher[index].configured) { > + debug("ERROR: qos watcher %d should be configured > before enable\n", index); > + return -1; > + } > + /* All other style parameters remain same except grp and qos > and qps base */ > + cvmx_pki_read_style_config(node, style, CVMX_PKI_CLUSTER_ALL, > &style_cfg); > + cvmx_pki_read_qpg_entry(node, style_cfg.parm_cfg.qpg_base, > &qpg_cfg); > + qpg_cfg.qpg_base = CVMX_PKI_FIND_AVAL_ENTRY; > + qpg_cfg.grp_ok = qos_watcher[index].sso_grp; > + qpg_cfg.grp_bad = qos_watcher[index].sso_grp; > + qpg_offset = cvmx_helper_pki_set_qpg_entry(node, &qpg_cfg); > + if (qpg_offset == -1) { > + debug("Warning: no new qpg entry available to enable > watcher\n"); > + return -1; > + } > + /* try to reserve the style, if it is not configured already, > reserve > + and configure it */ > + style_cfg.parm_cfg.qpg_base = qpg_offset; > + style_num = cvmx_pki_style_alloc(node, -1); > + if (style_num < 0) { > + debug("ERROR: style not available to enable qos > watcher\n"); > + cvmx_pki_qpg_entry_free(node, qpg_offset, 1); > + return -1; > + } > + cvmx_pki_write_style_config(node, style_num, > CVMX_PKI_CLUSTER_ALL, &style_cfg); > + /* legacy will write to all clusters*/ > + bank = qos_watcher[index].field & 0x01; > + pcam_offset = cvmx_pki_pcam_entry_alloc(node, > CVMX_PKI_FIND_AVAL_ENTRY, bank, > + CVMX_PKI_CLUSTER_ALL); > + if (pcam_offset < 0) { > + debug("ERROR: pcam entry not available to enable qos > watcher\n"); > + cvmx_pki_style_free(node, style_num); > + cvmx_pki_qpg_entry_free(node, qpg_offset, 1); > + return -1; > + } > + memset(&pcam_input, 0, sizeof(pcam_input)); > + memset(&pcam_action, 0, sizeof(pcam_action)); > + pcam_input.style = style; > + pcam_input.style_mask = 0xff; > + pcam_input.field = qos_watcher[index].field; > + pcam_input.field_mask = 0xff; > + pcam_input.data = qos_watcher[index].data; > + pcam_input.data_mask = qos_watcher[index].data_mask; > + pcam_action.parse_mode_chg = CVMX_PKI_PARSE_NO_CHG; > + pcam_action.layer_type_set = CVMX_PKI_LTYPE_E_NONE; > + pcam_action.style_add = (u8)(style_num - style); > + pcam_action.pointer_advance = qos_watcher[index].advance; > + cvmx_pki_pcam_write_entry(node, pcam_offset, > CVMX_PKI_CLUSTER_ALL, pcam_input, pcam_action); > + return 0; > +} > + > +/** > + * Configure an ethernet input port > + * > + * @param ipd_port Port number to configure > + * @param port_cfg Port hardware configuration > + * @param port_tag_cfg Port POW tagging configuration > + */ > +static inline void cvmx_pip_config_port(u64 ipd_port, > cvmx_pip_prt_cfgx_t port_cfg, > + cvmx_pip_prt_tagx_t > port_tag_cfg) > +{ > + struct cvmx_pki_qpg_config qpg_cfg; > + int qpg_offset; > + u8 tcp_tag = 0xff; > + u8 ip_tag = 0xaa; > + int style, nstyle, n4style, n6style; > + > + if (octeon_has_feature(OCTEON_FEATURE_PKI)) { > + struct cvmx_pki_port_config pki_prt_cfg; > + struct cvmx_xport xp = > cvmx_helper_ipd_port_to_xport(ipd_port); > + > + cvmx_pki_get_port_config(ipd_port, &pki_prt_cfg); > + style = pki_prt_cfg.pkind_cfg.initial_style; > + if (port_cfg.s.ih_pri || port_cfg.s.vlan_len || > port_cfg.s.pad_len) > + debug("Warning: 78xx: use different config for > this option\n"); > + pki_prt_cfg.style_cfg.parm_cfg.minmax_sel = > port_cfg.s.len_chk_sel; > + pki_prt_cfg.style_cfg.parm_cfg.lenerr_en = > port_cfg.s.lenerr_en; > + pki_prt_cfg.style_cfg.parm_cfg.maxerr_en = > port_cfg.s.maxerr_en; > + pki_prt_cfg.style_cfg.parm_cfg.minerr_en = > port_cfg.s.minerr_en; > + pki_prt_cfg.style_cfg.parm_cfg.fcs_chk = > port_cfg.s.crc_en; > + if (port_cfg.s.grp_wat || port_cfg.s.qos_wat || > port_cfg.s.grp_wat_47 || > + port_cfg.s.qos_wat_47) { > + u8 group_mask = (u8)(port_cfg.s.grp_wat | > (u8)(port_cfg.s.grp_wat_47 << 4)); > + u8 qos_mask = (u8)(port_cfg.s.qos_wat | > (u8)(port_cfg.s.qos_wat_47 << 4)); > + int i; > + > + for (i = 0; i < CVMX_PIP_NUM_WATCHERS; i++) { > + if ((group_mask & (1 << i)) || > (qos_mask & (1 << i))) > + __cvmx_pip_enable_watcher_78xx( > xp.node, i, style); > + } > + } > + if (port_tag_cfg.s.tag_mode) { > + if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X)) > + cvmx_printf("Warning: mask tag is not > supported in 78xx pass1\n"); > + else { > + } > + /* need to implement for 78xx*/ > + } > + if (port_cfg.s.tag_inc) > + debug("Warning: 78xx uses differnet method for > tag generation\n"); > + pki_prt_cfg.style_cfg.parm_cfg.rawdrp = > port_cfg.s.rawdrp; > + pki_prt_cfg.pkind_cfg.parse_en.inst_hdr = > port_cfg.s.inst_hdr; > + if (port_cfg.s.hg_qos) > + pki_prt_cfg.style_cfg.parm_cfg.qpg_qos = > CVMX_PKI_QPG_QOS_HIGIG; > + else if (port_cfg.s.qos_vlan) > + pki_prt_cfg.style_cfg.parm_cfg.qpg_qos = > CVMX_PKI_QPG_QOS_VLAN; > + else if (port_cfg.s.qos_diff) > + pki_prt_cfg.style_cfg.parm_cfg.qpg_qos = > CVMX_PKI_QPG_QOS_DIFFSERV; > + if (port_cfg.s.qos_vod) > + debug("Warning: 78xx needs pcam entries > installed to achieve qos_vod\n"); > + if (port_cfg.s.qos) { > + cvmx_pki_read_qpg_entry(xp.node, > pki_prt_cfg.style_cfg.parm_cfg.qpg_base, > + &qpg_cfg); > + qpg_cfg.qpg_base = CVMX_PKI_FIND_AVAL_ENTRY; > + qpg_cfg.grp_ok |= port_cfg.s.qos; > + qpg_cfg.grp_bad |= port_cfg.s.qos; > + qpg_offset = > cvmx_helper_pki_set_qpg_entry(xp.node, &qpg_cfg); > + if (qpg_offset == -1) > + debug("Warning: no new qpg entry > available, will not modify qos\n"); > + else > + pki_prt_cfg.style_cfg.parm_cfg.qpg_base > = qpg_offset; > + } > + if (port_tag_cfg.s.grp != > pki_dflt_sso_grp[xp.node].group) { > + cvmx_pki_read_qpg_entry(xp.node, > pki_prt_cfg.style_cfg.parm_cfg.qpg_base, > + &qpg_cfg); > + qpg_cfg.qpg_base = CVMX_PKI_FIND_AVAL_ENTRY; > + qpg_cfg.grp_ok |= (u8)(port_tag_cfg.s.grp << > 3); > + qpg_cfg.grp_bad |= (u8)(port_tag_cfg.s.grp << > 3); > + qpg_offset = > cvmx_helper_pki_set_qpg_entry(xp.node, &qpg_cfg); > + if (qpg_offset == -1) > + debug("Warning: no new qpg entry > available, will not modify group\n"); > + else > + pki_prt_cfg.style_cfg.parm_cfg.qpg_base > = qpg_offset; > + } > + pki_prt_cfg.pkind_cfg.parse_en.dsa_en = > port_cfg.s.dsa_en; > + pki_prt_cfg.pkind_cfg.parse_en.hg_en = > port_cfg.s.higig_en; > + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.layer_c_src = > + port_tag_cfg.s.ip6_src_flag | > port_tag_cfg.s.ip4_src_flag; > + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.layer_c_dst = > + port_tag_cfg.s.ip6_dst_flag | > port_tag_cfg.s.ip4_dst_flag; > + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.ip_prot_nexthd > r = > + port_tag_cfg.s.ip6_nxth_flag | > port_tag_cfg.s.ip4_pctl_flag; > + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.layer_d_src = > + port_tag_cfg.s.ip6_sprt_flag | > port_tag_cfg.s.ip4_sprt_flag; > + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.layer_d_dst = > + port_tag_cfg.s.ip6_dprt_flag | > port_tag_cfg.s.ip4_dprt_flag; > + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.input_port = > port_tag_cfg.s.inc_prt_flag; > + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.first_vlan = > port_tag_cfg.s.inc_vlan; > + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.second_vlan = > port_tag_cfg.s.inc_vs; > + > + if (port_tag_cfg.s.tcp6_tag_type == > port_tag_cfg.s.tcp4_tag_type) > + tcp_tag = port_tag_cfg.s.tcp6_tag_type; > + if (port_tag_cfg.s.ip6_tag_type == > port_tag_cfg.s.ip4_tag_type) > + ip_tag = port_tag_cfg.s.ip6_tag_type; > + pki_prt_cfg.style_cfg.parm_cfg.tag_type = > + (enum > cvmx_sso_tag_type)port_tag_cfg.s.non_tag_type; > + if (tcp_tag == ip_tag && tcp_tag == > port_tag_cfg.s.non_tag_type) > + pki_prt_cfg.style_cfg.parm_cfg.tag_type = (enum > cvmx_sso_tag_type)tcp_tag; > + else if (tcp_tag == ip_tag) { > + /* allocate and copy style */ > + /* modify tag type */ > + /*pcam entry for ip6 && ip4 match*/ > + /* default is non tag type */ > + __cvmx_pip_set_tag_type(xp.node, style, ip_tag, > CVMX_PKI_PCAM_MATCH_IP); > + } else if (ip_tag == port_tag_cfg.s.non_tag_type) { > + /* allocate and copy style */ > + /* modify tag type */ > + /*pcam entry for tcp6 & tcp4 match*/ > + /* default is non tag type */ > + __cvmx_pip_set_tag_type(xp.node, style, > tcp_tag, CVMX_PKI_PCAM_MATCH_TCP); > + } else { > + if (ip_tag != 0xaa) { > + nstyle = > __cvmx_pip_set_tag_type(xp.node, style, ip_tag, > + CVMX_P > KI_PCAM_MATCH_IP); > + if (tcp_tag != 0xff) > + __cvmx_pip_set_tag_type(xp.node > , nstyle, tcp_tag, > + CVMX_PK > I_PCAM_MATCH_TCP); > + else { > + n4style = > __cvmx_pip_set_tag_type(xp.node, nstyle, ip_tag, > + > CVMX_PKI_PCAM_MATCH_IPV4); > + __cvmx_pip_set_tag_type(xp.node > , n4style, > + port_ta > g_cfg.s.tcp4_tag_type, > + CVMX_PK > I_PCAM_MATCH_TCP); > + n6style = > __cvmx_pip_set_tag_type(xp.node, nstyle, ip_tag, > + > CVMX_PKI_PCAM_MATCH_IPV6); > + __cvmx_pip_set_tag_type(xp.node > , n6style, > + port_ta > g_cfg.s.tcp6_tag_type, > + CVMX_PK > I_PCAM_MATCH_TCP); > + } > + } else { > + n4style = > __cvmx_pip_set_tag_type(xp.node, style, > + port_ > tag_cfg.s.ip4_tag_type, > + CVMX_ > PKI_PCAM_MATCH_IPV4); > + n6style = > __cvmx_pip_set_tag_type(xp.node, style, > + port_ > tag_cfg.s.ip6_tag_type, > + CVMX_ > PKI_PCAM_MATCH_IPV6); > + if (tcp_tag != 0xff) { > + __cvmx_pip_set_tag_type(xp.node > , n4style, tcp_tag, > + CVMX_PK > I_PCAM_MATCH_TCP); > + __cvmx_pip_set_tag_type(xp.node > , n6style, tcp_tag, > + CVMX_PK > I_PCAM_MATCH_TCP); > + } else { > + __cvmx_pip_set_tag_type(xp.node > , n4style, > + port_ta > g_cfg.s.tcp4_tag_type, > + CVMX_PK > I_PCAM_MATCH_TCP); > + __cvmx_pip_set_tag_type(xp.node > , n6style, > + port_ta > g_cfg.s.tcp6_tag_type, > + CVMX_PK > I_PCAM_MATCH_TCP); > + } > + } > + } > + pki_prt_cfg.style_cfg.parm_cfg.qpg_dis_padd = > !port_tag_cfg.s.portadd_en; > + > + if (port_cfg.s.mode == 0x1) > + pki_prt_cfg.pkind_cfg.initial_parse_mode = > CVMX_PKI_PARSE_LA_TO_LG; > + else if (port_cfg.s.mode == 0x2) > + pki_prt_cfg.pkind_cfg.initial_parse_mode = > CVMX_PKI_PARSE_LC_TO_LG; > + else > + pki_prt_cfg.pkind_cfg.initial_parse_mode = > CVMX_PKI_PARSE_NOTHING; > + /* This is only for backward compatibility, not all the > parameters are supported in 78xx */ > + cvmx_pki_set_port_config(ipd_port, &pki_prt_cfg); > + } else { > + if (octeon_has_feature(OCTEON_FEATURE_PKND)) { > + int interface, index, pknd; > + > + interface = > cvmx_helper_get_interface_num(ipd_port); > + index = > cvmx_helper_get_interface_index_num(ipd_port); > + pknd = cvmx_helper_get_pknd(interface, index); > + > + ipd_port = pknd; /* overload port_num with pknd > */ > + } > + csr_wr(CVMX_PIP_PRT_CFGX(ipd_port), port_cfg.u64); > + csr_wr(CVMX_PIP_PRT_TAGX(ipd_port), port_tag_cfg.u64); > + } > +} > + > +/** > + * Configure the VLAN priority to QoS queue mapping. > + * > + * @param vlan_priority > + * VLAN priority (0-7) > + * @param qos QoS queue for packets matching this watcher > + */ > +static inline void cvmx_pip_config_vlan_qos(u64 vlan_priority, u64 > qos) > +{ > + if (!octeon_has_feature(OCTEON_FEATURE_PKND)) { > + cvmx_pip_qos_vlanx_t pip_qos_vlanx; > + > + pip_qos_vlanx.u64 = 0; > + pip_qos_vlanx.s.qos = qos; > + csr_wr(CVMX_PIP_QOS_VLANX(vlan_priority), > pip_qos_vlanx.u64); > + } > +} > + > +/** > + * Configure the Diffserv to QoS queue mapping. > + * > + * @param diffserv Diffserv field value (0-63) > + * @param qos QoS queue for packets matching this watcher > + */ > +static inline void cvmx_pip_config_diffserv_qos(u64 diffserv, u64 > qos) > +{ > + if (!octeon_has_feature(OCTEON_FEATURE_PKND)) { > + cvmx_pip_qos_diffx_t pip_qos_diffx; > + > + pip_qos_diffx.u64 = 0; > + pip_qos_diffx.s.qos = qos; > + csr_wr(CVMX_PIP_QOS_DIFFX(diffserv), > pip_qos_diffx.u64); > + } > +} > + > +/** > + * Get the status counters for a port for older non PKI chips. > + * > + * @param port_num Port number (ipd_port) to get statistics for. > + * @param clear Set to 1 to clear the counters after they are > read > + * @param status Where to put the results. > + */ > +static inline void cvmx_pip_get_port_stats(u64 port_num, u64 clear, > cvmx_pip_port_status_t *status) > +{ > + cvmx_pip_stat_ctl_t pip_stat_ctl; > + cvmx_pip_stat0_prtx_t stat0; > + cvmx_pip_stat1_prtx_t stat1; > + cvmx_pip_stat2_prtx_t stat2; > + cvmx_pip_stat3_prtx_t stat3; > + cvmx_pip_stat4_prtx_t stat4; > + cvmx_pip_stat5_prtx_t stat5; > + cvmx_pip_stat6_prtx_t stat6; > + cvmx_pip_stat7_prtx_t stat7; > + cvmx_pip_stat8_prtx_t stat8; > + cvmx_pip_stat9_prtx_t stat9; > + cvmx_pip_stat10_x_t stat10; > + cvmx_pip_stat11_x_t stat11; > + cvmx_pip_stat_inb_pktsx_t pip_stat_inb_pktsx; > + cvmx_pip_stat_inb_octsx_t pip_stat_inb_octsx; > + cvmx_pip_stat_inb_errsx_t pip_stat_inb_errsx; > + int interface = cvmx_helper_get_interface_num(port_num); > + int index = cvmx_helper_get_interface_index_num(port_num); > + > + pip_stat_ctl.u64 = 0; > + pip_stat_ctl.s.rdclr = clear; > + csr_wr(CVMX_PIP_STAT_CTL, pip_stat_ctl.u64); > + > + if (octeon_has_feature(OCTEON_FEATURE_PKND)) { > + int pknd = cvmx_helper_get_pknd(interface, index); > + /* > + * PIP_STAT_CTL[MODE] 0 means pkind. > + */ > + stat0.u64 = csr_rd(CVMX_PIP_STAT0_X(pknd)); > + stat1.u64 = csr_rd(CVMX_PIP_STAT1_X(pknd)); > + stat2.u64 = csr_rd(CVMX_PIP_STAT2_X(pknd)); > + stat3.u64 = csr_rd(CVMX_PIP_STAT3_X(pknd)); > + stat4.u64 = csr_rd(CVMX_PIP_STAT4_X(pknd)); > + stat5.u64 = csr_rd(CVMX_PIP_STAT5_X(pknd)); > + stat6.u64 = csr_rd(CVMX_PIP_STAT6_X(pknd)); > + stat7.u64 = csr_rd(CVMX_PIP_STAT7_X(pknd)); > + stat8.u64 = csr_rd(CVMX_PIP_STAT8_X(pknd)); > + stat9.u64 = csr_rd(CVMX_PIP_STAT9_X(pknd)); > + stat10.u64 = csr_rd(CVMX_PIP_STAT10_X(pknd)); > + stat11.u64 = csr_rd(CVMX_PIP_STAT11_X(pknd)); > + } else { > + if (port_num >= 40) { > + stat0.u64 = > csr_rd(CVMX_PIP_XSTAT0_PRTX(port_num)); > + stat1.u64 = > csr_rd(CVMX_PIP_XSTAT1_PRTX(port_num)); > + stat2.u64 = > csr_rd(CVMX_PIP_XSTAT2_PRTX(port_num)); > + stat3.u64 = > csr_rd(CVMX_PIP_XSTAT3_PRTX(port_num)); > + stat4.u64 = > csr_rd(CVMX_PIP_XSTAT4_PRTX(port_num)); > + stat5.u64 = > csr_rd(CVMX_PIP_XSTAT5_PRTX(port_num)); > + stat6.u64 = > csr_rd(CVMX_PIP_XSTAT6_PRTX(port_num)); > + stat7.u64 = > csr_rd(CVMX_PIP_XSTAT7_PRTX(port_num)); > + stat8.u64 = > csr_rd(CVMX_PIP_XSTAT8_PRTX(port_num)); > + stat9.u64 = > csr_rd(CVMX_PIP_XSTAT9_PRTX(port_num)); > + if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { > + stat10.u64 = > csr_rd(CVMX_PIP_XSTAT10_PRTX(port_num)); > + stat11.u64 = > csr_rd(CVMX_PIP_XSTAT11_PRTX(port_num)); > + } > + } else { > + stat0.u64 = > csr_rd(CVMX_PIP_STAT0_PRTX(port_num)); > + stat1.u64 = > csr_rd(CVMX_PIP_STAT1_PRTX(port_num)); > + stat2.u64 = > csr_rd(CVMX_PIP_STAT2_PRTX(port_num)); > + stat3.u64 = > csr_rd(CVMX_PIP_STAT3_PRTX(port_num)); > + stat4.u64 = > csr_rd(CVMX_PIP_STAT4_PRTX(port_num)); > + stat5.u64 = > csr_rd(CVMX_PIP_STAT5_PRTX(port_num)); > + stat6.u64 = > csr_rd(CVMX_PIP_STAT6_PRTX(port_num)); > + stat7.u64 = > csr_rd(CVMX_PIP_STAT7_PRTX(port_num)); > + stat8.u64 = > csr_rd(CVMX_PIP_STAT8_PRTX(port_num)); > + stat9.u64 = > csr_rd(CVMX_PIP_STAT9_PRTX(port_num)); > + if (OCTEON_IS_OCTEON2() || > OCTEON_IS_MODEL(OCTEON_CN70XX)) { > + stat10.u64 = > csr_rd(CVMX_PIP_STAT10_PRTX(port_num)); > + stat11.u64 = > csr_rd(CVMX_PIP_STAT11_PRTX(port_num)); > + } > + } > + } > + if (octeon_has_feature(OCTEON_FEATURE_PKND)) { > + int pknd = cvmx_helper_get_pknd(interface, index); > + > + pip_stat_inb_pktsx.u64 = > csr_rd(CVMX_PIP_STAT_INB_PKTS_PKNDX(pknd)); > + pip_stat_inb_octsx.u64 = > csr_rd(CVMX_PIP_STAT_INB_OCTS_PKNDX(pknd)); > + pip_stat_inb_errsx.u64 = > csr_rd(CVMX_PIP_STAT_INB_ERRS_PKNDX(pknd)); > + } else { > + pip_stat_inb_pktsx.u64 = > csr_rd(CVMX_PIP_STAT_INB_PKTSX(port_num)); > + pip_stat_inb_octsx.u64 = > csr_rd(CVMX_PIP_STAT_INB_OCTSX(port_num)); > + pip_stat_inb_errsx.u64 = > csr_rd(CVMX_PIP_STAT_INB_ERRSX(port_num)); > + } > + > + status->dropped_octets = stat0.s.drp_octs; > + status->dropped_packets = stat0.s.drp_pkts; > + status->octets = stat1.s.octs; > + status->pci_raw_packets = stat2.s.raw; > + status->packets = stat2.s.pkts; > + status->multicast_packets = stat3.s.mcst; > + status->broadcast_packets = stat3.s.bcst; > + status->len_64_packets = stat4.s.h64; > + status->len_65_127_packets = stat4.s.h65to127; > + status->len_128_255_packets = stat5.s.h128to255; > + status->len_256_511_packets = stat5.s.h256to511; > + status->len_512_1023_packets = stat6.s.h512to1023; > + status->len_1024_1518_packets = stat6.s.h1024to1518; > + status->len_1519_max_packets = stat7.s.h1519; > + status->fcs_align_err_packets = stat7.s.fcs; > + status->runt_packets = stat8.s.undersz; > + status->runt_crc_packets = stat8.s.frag; > + status->oversize_packets = stat9.s.oversz; > + status->oversize_crc_packets = stat9.s.jabber; > + if (OCTEON_IS_OCTEON2() || OCTEON_IS_MODEL(OCTEON_CN70XX)) { > + status->mcast_l2_red_packets = stat10.s.mcast; > + status->bcast_l2_red_packets = stat10.s.bcast; > + status->mcast_l3_red_packets = stat11.s.mcast; > + status->bcast_l3_red_packets = stat11.s.bcast; > + } > + status->inb_packets = pip_stat_inb_pktsx.s.pkts; > + status->inb_octets = pip_stat_inb_octsx.s.octs; > + status->inb_errors = pip_stat_inb_errsx.s.errs; > +} > + > +/** > + * Get the status counters for a port. > + * > + * @param port_num Port number (ipd_port) to get statistics for. > + * @param clear Set to 1 to clear the counters after they are > read > + * @param status Where to put the results. > + */ > +static inline void cvmx_pip_get_port_status(u64 port_num, u64 clear, > cvmx_pip_port_status_t *status) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_PKI)) { > + unsigned int node = cvmx_get_node_num(); > + > + cvmx_pki_get_port_stats(node, port_num, (struct > cvmx_pki_port_stats *)status); > + } else { > + cvmx_pip_get_port_stats(port_num, clear, status); > + } > +} > + > +/** > + * Configure the hardware CRC engine > + * > + * @param interface Interface to configure (0 or 1) > + * @param invert_result > + * Invert the result of the CRC > + * @param reflect Reflect > + * @param initialization_vector > + * CRC initialization vector > + */ > +static inline void cvmx_pip_config_crc(u64 interface, u64 > invert_result, u64 reflect, > + u32 initialization_vector) > +{ > + /* Only CN38XX & CN58XX */ > +} > + > +/** > + * Clear all bits in a tag mask. This should be called on > + * startup before any calls to cvmx_pip_tag_mask_set. Each bit > + * set in the final mask represent a byte used in the packet for > + * tag generation. > + * > + * @param mask_index Which tag mask to clear (0..3) > + */ > +static inline void cvmx_pip_tag_mask_clear(u64 mask_index) > +{ > + u64 index; > + cvmx_pip_tag_incx_t pip_tag_incx; > + > + pip_tag_incx.u64 = 0; > + pip_tag_incx.s.en = 0; > + for (index = mask_index * 16; index < (mask_index + 1) * 16; > index++) > + csr_wr(CVMX_PIP_TAG_INCX(index), pip_tag_incx.u64); > +} > + > +/** > + * Sets a range of bits in the tag mask. The tag mask is used > + * when the cvmx_pip_port_tag_cfg_t tag_mode is non zero. > + * There are four separate masks that can be configured. > + * > + * @param mask_index Which tag mask to modify (0..3) > + * @param offset Offset into the bitmask to set bits at. Use the > GCC macro > + * offsetof() to determine the offsets into packet > headers. > + * For example, offsetof(ethhdr, protocol) returns > the offset > + * of the ethernet protocol field. The bitmask > selects which bytes > + * to include the the tag, with bit offset X > selecting byte at offset X > + * from the beginning of the packet data. > + * @param len Number of bytes to include. Usually this is the > sizeof() > + * the field. > + */ > +static inline void cvmx_pip_tag_mask_set(u64 mask_index, u64 offset, > u64 len) > +{ > + while (len--) { > + cvmx_pip_tag_incx_t pip_tag_incx; > + u64 index = mask_index * 16 + offset / 8; > + > + pip_tag_incx.u64 = csr_rd(CVMX_PIP_TAG_INCX(index)); > + pip_tag_incx.s.en |= 0x80 >> (offset & 0x7); > + csr_wr(CVMX_PIP_TAG_INCX(index), pip_tag_incx.u64); > + offset++; > + } > +} > + > +/** > + * Set byte count for Max-Sized and Min Sized frame check. > + * > + * @param interface Which interface to set the limit > + * @param max_size Byte count for Max-Size frame check > + */ > +static inline void cvmx_pip_set_frame_check(int interface, u32 > max_size) > +{ > + cvmx_pip_frm_len_chkx_t frm_len; > + > + /* max_size and min_size are passed as 0, reset to default > values. */ > + if (max_size < 1536) > + max_size = 1536; > + > + /* On CN68XX frame check is enabled for a pkind n and > + PIP_PRT_CFG[len_chk_sel] selects which set of > + MAXLEN/MINLEN to use. */ > + if (octeon_has_feature(OCTEON_FEATURE_PKND)) { > + int port; > + int num_ports = > cvmx_helper_ports_on_interface(interface); > + > + for (port = 0; port < num_ports; port++) { > + if (octeon_has_feature(OCTEON_FEATURE_PKI)) { > + int ipd_port; > + > + ipd_port = > cvmx_helper_get_ipd_port(interface, port); > + cvmx_pki_set_max_frm_len(ipd_port, > max_size); > + } else { > + int pknd; > + int sel; > + cvmx_pip_prt_cfgx_t config; > + > + pknd = cvmx_helper_get_pknd(interface, > port); > + config.u64 = > csr_rd(CVMX_PIP_PRT_CFGX(pknd)); > + sel = config.s.len_chk_sel; > + frm_len.u64 = > csr_rd(CVMX_PIP_FRM_LEN_CHKX(sel)); > + frm_len.s.maxlen = max_size; > + csr_wr(CVMX_PIP_FRM_LEN_CHKX(sel), > frm_len.u64); > + } > + } > + } > + /* on cn6xxx and cn7xxx models, PIP_FRM_LEN_CHK0 applies to > + * all incoming traffic */ > + else if (OCTEON_IS_OCTEON2() || OCTEON_IS_MODEL(OCTEON_CN70XX)) > { > + frm_len.u64 = csr_rd(CVMX_PIP_FRM_LEN_CHKX(0)); > + frm_len.s.maxlen = max_size; > + csr_wr(CVMX_PIP_FRM_LEN_CHKX(0), frm_len.u64); > + } > +} > + > +/** > + * Initialize Bit Select Extractor config. Their are 8 bit positions > and valids > + * to be used when using the corresponding extractor. > + * > + * @param bit Bit Select Extractor to use > + * @param pos Which position to update > + * @param val The value to update the position with > + */ > +static inline void cvmx_pip_set_bsel_pos(int bit, int pos, int val) > +{ > + cvmx_pip_bsel_ext_posx_t bsel_pos; > + > + /* The bit select extractor is available in CN61XX and CN68XX > pass2.0 onwards. */ > + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) > + return; > + > + if (bit < 0 || bit > 3) { > + debug("ERROR: cvmx_pip_set_bsel_pos: Invalid Bit-Select > Extractor (%d) passed\n", > + bit); > + return; > + } > + > + bsel_pos.u64 = csr_rd(CVMX_PIP_BSEL_EXT_POSX(bit)); > + switch (pos) { > + case 0: > + bsel_pos.s.pos0_val = 1; > + bsel_pos.s.pos0 = val & 0x7f; > + break; > + case 1: > + bsel_pos.s.pos1_val = 1; > + bsel_pos.s.pos1 = val & 0x7f; > + break; > + case 2: > + bsel_pos.s.pos2_val = 1; > + bsel_pos.s.pos2 = val & 0x7f; > + break; > + case 3: > + bsel_pos.s.pos3_val = 1; > + bsel_pos.s.pos3 = val & 0x7f; > + break; > + case 4: > + bsel_pos.s.pos4_val = 1; > + bsel_pos.s.pos4 = val & 0x7f; > + break; > + case 5: > + bsel_pos.s.pos5_val = 1; > + bsel_pos.s.pos5 = val & 0x7f; > + break; > + case 6: > + bsel_pos.s.pos6_val = 1; > + bsel_pos.s.pos6 = val & 0x7f; > + break; > + case 7: > + bsel_pos.s.pos7_val = 1; > + bsel_pos.s.pos7 = val & 0x7f; > + break; > + default: > + debug("Warning: cvmx_pip_set_bsel_pos: Invalid > pos(%d)\n", pos); > + break; > + } > + csr_wr(CVMX_PIP_BSEL_EXT_POSX(bit), bsel_pos.u64); > +} > + > +/** > + * Initialize offset and skip values to use by bit select extractor. > + > + * @param bit Bit Select Extractor to use > + * @param offset Offset to add to extractor mem addr to get > final address > + * to lookup table. > + * @param skip Number of bytes to skip from start of > packet 0-64 > + */ > +static inline void cvmx_pip_bsel_config(int bit, int offset, int > skip) > +{ > + cvmx_pip_bsel_ext_cfgx_t bsel_cfg; > + > + /* The bit select extractor is available in CN61XX and CN68XX > pass2.0 onwards. */ > + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) > + return; > + > + bsel_cfg.u64 = csr_rd(CVMX_PIP_BSEL_EXT_CFGX(bit)); > + bsel_cfg.s.offset = offset; > + bsel_cfg.s.skip = skip; > + csr_wr(CVMX_PIP_BSEL_EXT_CFGX(bit), bsel_cfg.u64); > +} > + > +/** > + * Get the entry for the Bit Select Extractor Table. > + * @param work pointer to work queue entry > + * @return Index of the Bit Select Extractor Table > + */ > +static inline int cvmx_pip_get_bsel_table_index(cvmx_wqe_t *work) > +{ > + int bit = cvmx_wqe_get_port(work) & 0x3; > + /* Get the Bit select table index. */ > + int index; > + int y; > + cvmx_pip_bsel_ext_cfgx_t bsel_cfg; > + cvmx_pip_bsel_ext_posx_t bsel_pos; > + > + /* The bit select extractor is available in CN61XX and CN68XX > pass2.0 onwards. */ > + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) > + return -1; > + > + bsel_cfg.u64 = csr_rd(CVMX_PIP_BSEL_EXT_CFGX(bit)); > + bsel_pos.u64 = csr_rd(CVMX_PIP_BSEL_EXT_POSX(bit)); > + > + for (y = 0; y < 8; y++) { > + char *ptr = (char *)cvmx_phys_to_ptr(work- > >packet_ptr.s.addr); > + int bit_loc = 0; > + int bit; > + > + ptr += bsel_cfg.s.skip; > + switch (y) { > + case 0: > + ptr += (bsel_pos.s.pos0 >> 3); > + bit_loc = 7 - (bsel_pos.s.pos0 & 0x3); > + break; > + case 1: > + ptr += (bsel_pos.s.pos1 >> 3); > + bit_loc = 7 - (bsel_pos.s.pos1 & 0x3); > + break; > + case 2: > + ptr += (bsel_pos.s.pos2 >> 3); > + bit_loc = 7 - (bsel_pos.s.pos2 & 0x3); > + break; > + case 3: > + ptr += (bsel_pos.s.pos3 >> 3); > + bit_loc = 7 - (bsel_pos.s.pos3 & 0x3); > + break; > + case 4: > + ptr += (bsel_pos.s.pos4 >> 3); > + bit_loc = 7 - (bsel_pos.s.pos4 & 0x3); > + break; > + case 5: > + ptr += (bsel_pos.s.pos5 >> 3); > + bit_loc = 7 - (bsel_pos.s.pos5 & 0x3); > + break; > + case 6: > + ptr += (bsel_pos.s.pos6 >> 3); > + bit_loc = 7 - (bsel_pos.s.pos6 & 0x3); > + break; > + case 7: > + ptr += (bsel_pos.s.pos7 >> 3); > + bit_loc = 7 - (bsel_pos.s.pos7 & 0x3); > + break; > + } > + bit = (*ptr >> bit_loc) & 1; > + index |= bit << y; > + } > + index += bsel_cfg.s.offset; > + index &= 0x1ff; > + return index; > +} > + > +static inline int cvmx_pip_get_bsel_qos(cvmx_wqe_t *work) > +{ > + int index = cvmx_pip_get_bsel_table_index(work); > + cvmx_pip_bsel_tbl_entx_t bsel_tbl; > + > + /* The bit select extractor is available in CN61XX and CN68XX > pass2.0 onwards. */ > + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) > + return -1; > + > + bsel_tbl.u64 = csr_rd(CVMX_PIP_BSEL_TBL_ENTX(index)); > + > + return bsel_tbl.s.qos; > +} > + > +static inline int cvmx_pip_get_bsel_grp(cvmx_wqe_t *work) > +{ > + int index = cvmx_pip_get_bsel_table_index(work); > + cvmx_pip_bsel_tbl_entx_t bsel_tbl; > + > + /* The bit select extractor is available in CN61XX and CN68XX > pass2.0 onwards. */ > + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) > + return -1; > + > + bsel_tbl.u64 = csr_rd(CVMX_PIP_BSEL_TBL_ENTX(index)); > + > + return bsel_tbl.s.grp; > +} > + > +static inline int cvmx_pip_get_bsel_tt(cvmx_wqe_t *work) > +{ > + int index = cvmx_pip_get_bsel_table_index(work); > + cvmx_pip_bsel_tbl_entx_t bsel_tbl; > + > + /* The bit select extractor is available in CN61XX and CN68XX > pass2.0 onwards. */ > + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) > + return -1; > + > + bsel_tbl.u64 = csr_rd(CVMX_PIP_BSEL_TBL_ENTX(index)); > + > + return bsel_tbl.s.tt; > +} > + > +static inline int cvmx_pip_get_bsel_tag(cvmx_wqe_t *work) > +{ > + int index = cvmx_pip_get_bsel_table_index(work); > + int port = cvmx_wqe_get_port(work); > + int bit = port & 0x3; > + int upper_tag = 0; > + cvmx_pip_bsel_tbl_entx_t bsel_tbl; > + cvmx_pip_bsel_ext_cfgx_t bsel_cfg; > + cvmx_pip_prt_tagx_t prt_tag; > + > + /* The bit select extractor is available in CN61XX and CN68XX > pass2.0 onwards. */ > + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) > + return -1; > + > + bsel_tbl.u64 = csr_rd(CVMX_PIP_BSEL_TBL_ENTX(index)); > + bsel_cfg.u64 = csr_rd(CVMX_PIP_BSEL_EXT_CFGX(bit)); > + > + prt_tag.u64 = csr_rd(CVMX_PIP_PRT_TAGX(port)); > + if (prt_tag.s.inc_prt_flag == 0) > + upper_tag = bsel_cfg.s.upper_tag; > + return bsel_tbl.s.tag | ((bsel_cfg.s.tag << 8) & 0xff00) | > ((upper_tag << 16) & 0xffff0000); > +} > + > +#endif /* __CVMX_PIP_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pki-resources.h > b/arch/mips/mach-octeon/include/mach/cvmx-pki-resources.h > new file mode 100644 > index 000000000000..79b99b0bd7c2 > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-pki-resources.h > @@ -0,0 +1,157 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Resource management for PKI resources. > + */ > + > +#ifndef __CVMX_PKI_RESOURCES_H__ > +#define __CVMX_PKI_RESOURCES_H__ > + > +/** > + * This function allocates/reserves a style from pool of global > styles per node. > + * @param node node to allocate style from. > + * @param style style to allocate, if -1 it will be allocated > + first available style from style resource. If index is > positive > + number and in range, it will try to allocate specified > style. > + * @return style number on success, -1 on failure. > + */ > +int cvmx_pki_style_alloc(int node, int style); > + > +/** > + * This function allocates/reserves a cluster group from per node > + cluster group resources. > + * @param node node to allocate cluster group from. > + @param cl_grp cluster group to allocate/reserve, if -1 , > + allocate any available cluster group. > + * @return cluster group number or -1 on failure > + */ > +int cvmx_pki_cluster_grp_alloc(int node, int cl_grp); > + > +/** > + * This function allocates/reserves a cluster from per node > + cluster resources. > + * @param node node to allocate cluster group from. > + @param cluster_mask mask of clusters to allocate/reserve, > if -1 , > + allocate any available clusters. > + * @param num_clusters number of clusters that will be > allocated > + */ > +int cvmx_pki_cluster_alloc(int node, int num_clusters, u64 > *cluster_mask); > + > +/** > + * This function allocates/reserves a pcam entry from node > + * @param node node to allocate pcam entry from. > + @param index index of pacm entry (0-191), if -1 , > + allocate any available pcam entry. > + * @param bank pcam bank where to allocate/reserve > pcan entry from > + * @param cluster_mask mask of clusters from which pcam entry is > needed. > + * @return pcam entry of -1 on failure > + */ > +int cvmx_pki_pcam_entry_alloc(int node, int index, int bank, u64 > cluster_mask); > + > +/** > + * This function allocates/reserves QPG table entries per node. > + * @param node node number. > + * @param base_offset base_offset in qpg table. If -1, first > available > + qpg base_offset will be allocated. If > base_offset is positive > + number and in range, it will try to allocate > specified base_offset. > + @param count number of consecutive qpg entries to > allocate. They will be consecutive > + from base offset. > + * @return qpg table base offset number on success, -1 on > failure. > + */ > +int cvmx_pki_qpg_entry_alloc(int node, int base_offset, int count); > + > +/** > + * This function frees a style from pool of global styles per node. > + * @param node node to free style from. > + * @param style style to free > + * @return 0 on success, -1 on failure. > + */ > +int cvmx_pki_style_free(int node, int style); > + > +/** > + * This function frees a cluster group from per node > + cluster group resources. > + * @param node node to free cluster group from. > + @param cl_grp cluster group to free > + * @return 0 on success or -1 on failure > + */ > +int cvmx_pki_cluster_grp_free(int node, int cl_grp); > + > +/** > + * This function frees QPG table entries per node. > + * @param node node number. > + * @param base_offset base_offset in qpg table. If -1, first > available > + * qpg base_offset will be allocated. If > base_offset is positive > + * number and in range, it will try to allocate > specified base_offset. > + * @param count number of consecutive qpg entries to > allocate. They will be consecutive > + * from base offset. > + * @return qpg table base offset number on success, -1 on > failure. > + */ > +int cvmx_pki_qpg_entry_free(int node, int base_offset, int count); > + > +/** > + * This function frees clusters from per node > + clusters resources. > + * @param node node to free clusters from. > + * @param cluster_mask mask of clusters need freeing > + * @return 0 on success or -1 on failure > + */ > +int cvmx_pki_cluster_free(int node, u64 cluster_mask); > + > +/** > + * This function frees a pcam entry from node > + * @param node node to allocate pcam entry from. > + @param index index of pacm entry (0-191) needs to be freed. > + * @param bank pcam bank where to free pcam entry from > + * @param cluster_mask mask of clusters from which pcam entry is > freed. > + * @return 0 on success OR -1 on failure > + */ > +int cvmx_pki_pcam_entry_free(int node, int index, int bank, u64 > cluster_mask); > + > +/** > + * This function allocates/reserves a bpid from pool of global bpid > per node. > + * @param node node to allocate bpid from. > + * @param bpid bpid to allocate, if -1 it will be allocated > + * first available boid from bpid resource. If index is > positive > + * number and in range, it will try to allocate specified > bpid. > + * @return bpid number on success, > + * -1 on alloc failure. > + * -2 on resource already reserved. > + */ > +int cvmx_pki_bpid_alloc(int node, int bpid); > + > +/** > + * This function frees a bpid from pool of global bpid per node. > + * @param node node to free bpid from. > + * @param bpid bpid to free > + * @return 0 on success, -1 on failure or > + */ > +int cvmx_pki_bpid_free(int node, int bpid); > + > +/** > + * This function frees all the PKI software resources > + * (clusters, styles, qpg_entry, pcam_entry etc) for the specified > node > + */ > + > +/** > + * This function allocates/reserves an index from pool of global > MTAG-IDX per node. > + * @param node node to allocate index from. > + * @param idx index to allocate, if -1 it will be allocated > + * @return MTAG index number on success, > + * -1 on alloc failure. > + * -2 on resource already reserved. > + */ > +int cvmx_pki_mtag_idx_alloc(int node, int idx); > + > +/** > + * This function frees an index from pool of global MTAG-IDX per > node. > + * @param node node to free bpid from. > + * @param bpid bpid to free > + * @return 0 on success, -1 on failure or > + */ > +int cvmx_pki_mtag_idx_free(int node, int idx); > + > +void __cvmx_pki_global_rsrc_free(int node); > + > +#endif /* __CVM_PKI_RESOURCES_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pki.h > b/arch/mips/mach-octeon/include/mach/cvmx-pki.h > new file mode 100644 > index 000000000000..c1feb55a1f01 > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-pki.h > @@ -0,0 +1,970 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Interface to the hardware Packet Input Data unit. > + */ > + > +#ifndef __CVMX_PKI_H__ > +#define __CVMX_PKI_H__ > + > +#include "cvmx-fpa3.h" > +#include "cvmx-helper-util.h" > +#include "cvmx-helper-cfg.h" > +#include "cvmx-error.h" > + > +/* PKI AURA and BPID count are equal to FPA AURA count */ > +#define CVMX_PKI_NUM_AURA (cvmx_fpa3_num_auras()) > +#define CVMX_PKI_NUM_BPID (cvmx_fpa3_num_auras()) > +#define CVMX_PKI_NUM_SSO_GROUP (cvmx_sso_num_xgrp()) > +#define CVMX_PKI_NUM_CLUSTER_GROUP_MAX 1 > +#define CVMX_PKI_NUM_CLUSTER_GROUP (cvmx_pki_num_cl_grp()) > +#define CVMX_PKI_NUM_CLUSTER (cvmx_pki_num_clusters()) > + > +/* FIXME: Reduce some of these values, convert to routines XXX */ > +#define CVMX_PKI_NUM_CHANNEL 4096 > +#define CVMX_PKI_NUM_PKIND 64 > +#define CVMX_PKI_NUM_INTERNAL_STYLE 256 > +#define CVMX_PKI_NUM_FINAL_STYLE 64 > +#define CVMX_PKI_NUM_QPG_ENTRY 2048 > +#define CVMX_PKI_NUM_MTAG_IDX (32 / 4) /* 32 registers > grouped by 4*/ > +#define CVMX_PKI_NUM_LTYPE 32 > +#define CVMX_PKI_NUM_PCAM_BANK 2 > +#define CVMX_PKI_NUM_PCAM_ENTRY 192 > +#define CVMX_PKI_NUM_FRAME_CHECK 2 > +#define CVMX_PKI_NUM_BELTYPE 32 > +#define CVMX_PKI_MAX_FRAME_SIZE 65535 > +#define CVMX_PKI_FIND_AVAL_ENTRY (-1) > +#define CVMX_PKI_CLUSTER_ALL 0xf > + > +#ifdef CVMX_SUPPORT_SEPARATE_CLUSTER_CONFIG > +#define > CVMX_PKI_TOTAL_PCAM_ENTRY > \ > + ((CVMX_PKI_NUM_CLUSTER) * (CVMX_PKI_NUM_PCAM_BANK) * > (CVMX_PKI_NUM_PCAM_ENTRY)) > +#else > +#define CVMX_PKI_TOTAL_PCAM_ENTRY (CVMX_PKI_NUM_PCAM_BANK * > CVMX_PKI_NUM_PCAM_ENTRY) > +#endif > + > +static inline unsigned int cvmx_pki_num_clusters(void) > +{ > + if (OCTEON_IS_MODEL(OCTEON_CN73XX) || > OCTEON_IS_MODEL(OCTEON_CNF75XX)) > + return 2; > + return 4; > +} > + > +static inline unsigned int cvmx_pki_num_cl_grp(void) > +{ > + if (OCTEON_IS_MODEL(OCTEON_CN73XX) || > OCTEON_IS_MODEL(OCTEON_CNF75XX) || > + OCTEON_IS_MODEL(OCTEON_CN78XX)) > + return 1; > + return 0; > +} > + > +enum cvmx_pki_pkind_parse_mode { > + CVMX_PKI_PARSE_LA_TO_LG = 0, /* Parse LA(L2) to LG */ > + CVMX_PKI_PARSE_LB_TO_LG = 1, /* Parse LB(custom) to LG */ > + CVMX_PKI_PARSE_LC_TO_LG = 3, /* Parse LC(L3) to LG */ > + CVMX_PKI_PARSE_LG = 0x3f, /* Parse LG */ > + CVMX_PKI_PARSE_NOTHING = 0x7f /* Parse nothing */ > +}; > + > +enum cvmx_pki_parse_mode_chg { > + CVMX_PKI_PARSE_NO_CHG = 0x0, > + CVMX_PKI_PARSE_SKIP_TO_LB = 0x1, > + CVMX_PKI_PARSE_SKIP_TO_LC = 0x3, > + CVMX_PKI_PARSE_SKIP_TO_LD = 0x7, > + CVMX_PKI_PARSE_SKIP_TO_LG = 0x3f, > + CVMX_PKI_PARSE_SKIP_ALL = 0x7f, > +}; > + > +enum cvmx_pki_l2_len_mode { PKI_L2_LENCHK_EQUAL_GREATER = 0, > PKI_L2_LENCHK_EQUAL_ONLY }; > + > +enum cvmx_pki_cache_mode { > + CVMX_PKI_OPC_MODE_STT = 0LL, /* All blocks write through > DRAM,*/ > + CVMX_PKI_OPC_MODE_STF = 1LL, /* All blocks into L2 */ > + CVMX_PKI_OPC_MODE_STF1_STT = 2LL, /* 1st block L2, rest DRAM */ > + CVMX_PKI_OPC_MODE_STF2_STT = 3LL /* 1st, 2nd blocks L2, rest > DRAM */ > +}; > + > +/** > + * Tag type definitions > + */ > +enum cvmx_sso_tag_type { > + CVMX_SSO_TAG_TYPE_ORDERED = 0L, > + CVMX_SSO_TAG_TYPE_ATOMIC = 1L, > + CVMX_SSO_TAG_TYPE_UNTAGGED = 2L, > + CVMX_SSO_TAG_TYPE_EMPTY = 3L > +}; > + > +enum cvmx_pki_qpg_qos { > + CVMX_PKI_QPG_QOS_NONE = 0, > + CVMX_PKI_QPG_QOS_VLAN, > + CVMX_PKI_QPG_QOS_MPLS, > + CVMX_PKI_QPG_QOS_DSA_SRC, > + CVMX_PKI_QPG_QOS_DIFFSERV, > + CVMX_PKI_QPG_QOS_HIGIG, > +}; > + > +enum cvmx_pki_wqe_vlan { CVMX_PKI_USE_FIRST_VLAN = 0, > CVMX_PKI_USE_SECOND_VLAN }; > + > +/** > + * Controls how the PKI statistics counters are handled > + * The PKI_STAT*_X registers can be indexed either by port kind > (pkind), or > + * final style. (Does not apply to the PKI_STAT_INB* registers.) > + * 0 = X represents the packet’s pkind > + * 1 = X represents the low 6-bits of packet’s final style > + */ > +enum cvmx_pki_stats_mode { CVMX_PKI_STAT_MODE_PKIND, > CVMX_PKI_STAT_MODE_STYLE }; > + > +enum cvmx_pki_fpa_wait { CVMX_PKI_DROP_PKT, CVMX_PKI_WAIT_PKT }; > + > +#define PKI_BELTYPE_E__NONE_M 0x0 > +#define PKI_BELTYPE_E__MISC_M 0x1 > +#define PKI_BELTYPE_E__IP4_M 0x2 > +#define PKI_BELTYPE_E__IP6_M 0x3 > +#define PKI_BELTYPE_E__TCP_M 0x4 > +#define PKI_BELTYPE_E__UDP_M 0x5 > +#define PKI_BELTYPE_E__SCTP_M 0x6 > +#define PKI_BELTYPE_E__SNAP_M 0x7 > + > +/* PKI_BELTYPE_E_t */ > +enum cvmx_pki_beltype { > + CVMX_PKI_BELTYPE_NONE = PKI_BELTYPE_E__NONE_M, > + CVMX_PKI_BELTYPE_MISC = PKI_BELTYPE_E__MISC_M, > + CVMX_PKI_BELTYPE_IP4 = PKI_BELTYPE_E__IP4_M, > + CVMX_PKI_BELTYPE_IP6 = PKI_BELTYPE_E__IP6_M, > + CVMX_PKI_BELTYPE_TCP = PKI_BELTYPE_E__TCP_M, > + CVMX_PKI_BELTYPE_UDP = PKI_BELTYPE_E__UDP_M, > + CVMX_PKI_BELTYPE_SCTP = PKI_BELTYPE_E__SCTP_M, > + CVMX_PKI_BELTYPE_SNAP = PKI_BELTYPE_E__SNAP_M, > + CVMX_PKI_BELTYPE_MAX = CVMX_PKI_BELTYPE_SNAP > +}; > + > +struct cvmx_pki_frame_len { > + u16 maxlen; > + u16 minlen; > +}; > + > +struct cvmx_pki_tag_fields { > + u64 layer_g_src : 1; > + u64 layer_f_src : 1; > + u64 layer_e_src : 1; > + u64 layer_d_src : 1; > + u64 layer_c_src : 1; > + u64 layer_b_src : 1; > + u64 layer_g_dst : 1; > + u64 layer_f_dst : 1; > + u64 layer_e_dst : 1; > + u64 layer_d_dst : 1; > + u64 layer_c_dst : 1; > + u64 layer_b_dst : 1; > + u64 input_port : 1; > + u64 mpls_label : 1; > + u64 first_vlan : 1; > + u64 second_vlan : 1; > + u64 ip_prot_nexthdr : 1; > + u64 tag_sync : 1; > + u64 tag_spi : 1; > + u64 tag_gtp : 1; > + u64 tag_vni : 1; > +}; > + > +struct cvmx_pki_pkind_parse { > + u64 mpls_en : 1; > + u64 inst_hdr : 1; > + u64 lg_custom : 1; > + u64 fulc_en : 1; > + u64 dsa_en : 1; > + u64 hg2_en : 1; > + u64 hg_en : 1; > +}; > + > +struct cvmx_pki_pool_config { > + int pool_num; > + cvmx_fpa3_pool_t pool; > + u64 buffer_size; > + u64 buffer_count; > +}; > + > +struct cvmx_pki_qpg_config { > + int qpg_base; > + int port_add; > + int aura_num; > + int grp_ok; > + int grp_bad; > + int grptag_ok; > + int grptag_bad; > +}; > + > +struct cvmx_pki_aura_config { > + int aura_num; > + int pool_num; > + cvmx_fpa3_pool_t pool; > + cvmx_fpa3_gaura_t aura; > + int buffer_count; > +}; > + > +struct cvmx_pki_cluster_grp_config { > + int grp_num; > + u64 cluster_mask; /* Bit mask of cluster assigned to this > cluster group */ > +}; > + > +struct cvmx_pki_sso_grp_config { > + int group; > + int priority; > + int weight; > + int affinity; > + u64 core_mask; > + u8 core_mask_set; > +}; > + > +/* This is per style structure for configuring port parameters, > + * it is kind of of profile which can be assigned to any port. > + * If multiple ports are assigned same style be aware that modifying > + * that style will modify the respective parameters for all the > ports > + * which are using this style > + */ > +struct cvmx_pki_style_parm { > + bool ip6_udp_opt; > + bool lenerr_en; > + bool maxerr_en; > + bool minerr_en; > + u8 lenerr_eqpad; > + u8 minmax_sel; > + bool qpg_dis_grptag; > + bool fcs_strip; > + bool fcs_chk; > + bool rawdrp; > + bool force_drop; > + bool nodrop; > + bool qpg_dis_padd; > + bool qpg_dis_grp; > + bool qpg_dis_aura; > + u16 qpg_base; > + enum cvmx_pki_qpg_qos qpg_qos; > + u8 qpg_port_sh; > + u8 qpg_port_msb; > + u8 apad_nip; > + u8 wqe_vs; > + enum cvmx_sso_tag_type tag_type; > + bool pkt_lend; > + u8 wqe_hsz; > + u16 wqe_skip; > + u16 first_skip; > + u16 later_skip; > + enum cvmx_pki_cache_mode cache_mode; > + u8 dis_wq_dat; > + u64 mbuff_size; > + bool len_lg; > + bool len_lf; > + bool len_le; > + bool len_ld; > + bool len_lc; > + bool len_lb; > + bool csum_lg; > + bool csum_lf; > + bool csum_le; > + bool csum_ld; > + bool csum_lc; > + bool csum_lb; > +}; > + > +/* This is per style structure for configuring port's tag > configuration, > + * it is kind of of profile which can be assigned to any port. > + * If multiple ports are assigned same style be aware that modiying > that style > + * will modify the respective parameters for all the ports which are > + * using this style */ > +enum cvmx_pki_mtag_ptrsel { > + CVMX_PKI_MTAG_PTRSEL_SOP = 0, > + CVMX_PKI_MTAG_PTRSEL_LA = 8, > + CVMX_PKI_MTAG_PTRSEL_LB = 9, > + CVMX_PKI_MTAG_PTRSEL_LC = 10, > + CVMX_PKI_MTAG_PTRSEL_LD = 11, > + CVMX_PKI_MTAG_PTRSEL_LE = 12, > + CVMX_PKI_MTAG_PTRSEL_LF = 13, > + CVMX_PKI_MTAG_PTRSEL_LG = 14, > + CVMX_PKI_MTAG_PTRSEL_VL = 15, > +}; > + > +struct cvmx_pki_mask_tag { > + bool enable; > + int base; /* CVMX_PKI_MTAG_PTRSEL_XXX */ > + int offset; /* Offset from base. */ > + u64 val; /* Bitmask: > + 1 = enable, 0 = disabled for each byte in the 64-byte > array.*/ > +}; > + > +struct cvmx_pki_style_tag_cfg { > + struct cvmx_pki_tag_fields tag_fields; > + struct cvmx_pki_mask_tag mask_tag[4]; > +}; > + > +struct cvmx_pki_style_config { > + struct cvmx_pki_style_parm parm_cfg; > + struct cvmx_pki_style_tag_cfg tag_cfg; > +}; > + > +struct cvmx_pki_pkind_config { > + u8 cluster_grp; > + bool fcs_pres; > + struct cvmx_pki_pkind_parse parse_en; > + enum cvmx_pki_pkind_parse_mode initial_parse_mode; > + u8 fcs_skip; > + u8 inst_skip; > + int initial_style; > + bool custom_l2_hdr; > + u8 l2_scan_offset; > + u64 lg_scan_offset; > +}; > + > +struct cvmx_pki_port_config { > + struct cvmx_pki_pkind_config pkind_cfg; > + struct cvmx_pki_style_config style_cfg; > +}; > + > +struct cvmx_pki_global_parse { > + u64 virt_pen : 1; > + u64 clg_pen : 1; > + u64 cl2_pen : 1; > + u64 l4_pen : 1; > + u64 il3_pen : 1; > + u64 l3_pen : 1; > + u64 mpls_pen : 1; > + u64 fulc_pen : 1; > + u64 dsa_pen : 1; > + u64 hg_pen : 1; > +}; > + > +struct cvmx_pki_tag_sec { > + u16 dst6; > + u16 src6; > + u16 dst; > + u16 src; > +}; > + > +struct cvmx_pki_global_config { > + u64 cluster_mask[CVMX_PKI_NUM_CLUSTER_GROUP_MAX]; > + enum cvmx_pki_stats_mode stat_mode; > + enum cvmx_pki_fpa_wait fpa_wait; > + struct cvmx_pki_global_parse gbl_pen; > + struct cvmx_pki_tag_sec tag_secret; > + struct cvmx_pki_frame_len frm_len[CVMX_PKI_NUM_FRAME_CHECK]; > + enum cvmx_pki_beltype ltype_map[CVMX_PKI_NUM_BELTYPE]; > + int pki_enable; > +}; > + > +#define CVMX_PKI_PCAM_TERM_E_NONE_M 0x0 > +#define CVMX_PKI_PCAM_TERM_E_L2_CUSTOM_M 0x2 > +#define CVMX_PKI_PCAM_TERM_E_HIGIGD_M 0x4 > +#define CVMX_PKI_PCAM_TERM_E_HIGIG_M 0x5 > +#define CVMX_PKI_PCAM_TERM_E_SMACH_M 0x8 > +#define CVMX_PKI_PCAM_TERM_E_SMACL_M 0x9 > +#define CVMX_PKI_PCAM_TERM_E_DMACH_M 0xA > +#define CVMX_PKI_PCAM_TERM_E_DMACL_M 0xB > +#define CVMX_PKI_PCAM_TERM_E_GLORT_M 0x12 > +#define CVMX_PKI_PCAM_TERM_E_DSA_M 0x13 > +#define CVMX_PKI_PCAM_TERM_E_ETHTYPE0_M 0x18 > +#define CVMX_PKI_PCAM_TERM_E_ETHTYPE1_M 0x19 > +#define CVMX_PKI_PCAM_TERM_E_ETHTYPE2_M 0x1A > +#define CVMX_PKI_PCAM_TERM_E_ETHTYPE3_M 0x1B > +#define CVMX_PKI_PCAM_TERM_E_MPLS0_M 0x1E > +#define CVMX_PKI_PCAM_TERM_E_L3_SIPHH_M 0x1F > +#define CVMX_PKI_PCAM_TERM_E_L3_SIPMH_M 0x20 > +#define CVMX_PKI_PCAM_TERM_E_L3_SIPML_M 0x21 > +#define CVMX_PKI_PCAM_TERM_E_L3_SIPLL_M 0x22 > +#define CVMX_PKI_PCAM_TERM_E_L3_FLAGS_M 0x23 > +#define CVMX_PKI_PCAM_TERM_E_L3_DIPHH_M 0x24 > +#define CVMX_PKI_PCAM_TERM_E_L3_DIPMH_M 0x25 > +#define CVMX_PKI_PCAM_TERM_E_L3_DIPML_M 0x26 > +#define CVMX_PKI_PCAM_TERM_E_L3_DIPLL_M 0x27 > +#define CVMX_PKI_PCAM_TERM_E_LD_VNI_M 0x28 > +#define CVMX_PKI_PCAM_TERM_E_IL3_FLAGS_M 0x2B > +#define CVMX_PKI_PCAM_TERM_E_LF_SPI_M 0x2E > +#define CVMX_PKI_PCAM_TERM_E_L4_SPORT_M 0x2f > +#define CVMX_PKI_PCAM_TERM_E_L4_PORT_M 0x30 > +#define CVMX_PKI_PCAM_TERM_E_LG_CUSTOM_M 0x39 > + > +enum cvmx_pki_term { > + CVMX_PKI_PCAM_TERM_NONE = CVMX_PKI_PCAM_TERM_E_NONE_M, > + CVMX_PKI_PCAM_TERM_L2_CUSTOM = > CVMX_PKI_PCAM_TERM_E_L2_CUSTOM_M, > + CVMX_PKI_PCAM_TERM_HIGIGD = CVMX_PKI_PCAM_TERM_E_HIGIGD_M, > + CVMX_PKI_PCAM_TERM_HIGIG = CVMX_PKI_PCAM_TERM_E_HIGIG_M, > + CVMX_PKI_PCAM_TERM_SMACH = CVMX_PKI_PCAM_TERM_E_SMACH_M, > + CVMX_PKI_PCAM_TERM_SMACL = CVMX_PKI_PCAM_TERM_E_SMACL_M, > + CVMX_PKI_PCAM_TERM_DMACH = CVMX_PKI_PCAM_TERM_E_DMACH_M, > + CVMX_PKI_PCAM_TERM_DMACL = CVMX_PKI_PCAM_TERM_E_DMACL_M, > + CVMX_PKI_PCAM_TERM_GLORT = CVMX_PKI_PCAM_TERM_E_GLORT_M, > + CVMX_PKI_PCAM_TERM_DSA = CVMX_PKI_PCAM_TERM_E_DSA_M, > + CVMX_PKI_PCAM_TERM_ETHTYPE0 = CVMX_PKI_PCAM_TERM_E_ETHTYPE0_M, > + CVMX_PKI_PCAM_TERM_ETHTYPE1 = CVMX_PKI_PCAM_TERM_E_ETHTYPE1_M, > + CVMX_PKI_PCAM_TERM_ETHTYPE2 = CVMX_PKI_PCAM_TERM_E_ETHTYPE2_M, > + CVMX_PKI_PCAM_TERM_ETHTYPE3 = CVMX_PKI_PCAM_TERM_E_ETHTYPE3_M, > + CVMX_PKI_PCAM_TERM_MPLS0 = CVMX_PKI_PCAM_TERM_E_MPLS0_M, > + CVMX_PKI_PCAM_TERM_L3_SIPHH = CVMX_PKI_PCAM_TERM_E_L3_SIPHH_M, > + CVMX_PKI_PCAM_TERM_L3_SIPMH = CVMX_PKI_PCAM_TERM_E_L3_SIPMH_M, > + CVMX_PKI_PCAM_TERM_L3_SIPML = CVMX_PKI_PCAM_TERM_E_L3_SIPML_M, > + CVMX_PKI_PCAM_TERM_L3_SIPLL = CVMX_PKI_PCAM_TERM_E_L3_SIPLL_M, > + CVMX_PKI_PCAM_TERM_L3_FLAGS = CVMX_PKI_PCAM_TERM_E_L3_FLAGS_M, > + CVMX_PKI_PCAM_TERM_L3_DIPHH = CVMX_PKI_PCAM_TERM_E_L3_DIPHH_M, > + CVMX_PKI_PCAM_TERM_L3_DIPMH = CVMX_PKI_PCAM_TERM_E_L3_DIPMH_M, > + CVMX_PKI_PCAM_TERM_L3_DIPML = CVMX_PKI_PCAM_TERM_E_L3_DIPML_M, > + CVMX_PKI_PCAM_TERM_L3_DIPLL = CVMX_PKI_PCAM_TERM_E_L3_DIPLL_M, > + CVMX_PKI_PCAM_TERM_LD_VNI = CVMX_PKI_PCAM_TERM_E_LD_VNI_M, > + CVMX_PKI_PCAM_TERM_IL3_FLAGS = > CVMX_PKI_PCAM_TERM_E_IL3_FLAGS_M, > + CVMX_PKI_PCAM_TERM_LF_SPI = CVMX_PKI_PCAM_TERM_E_LF_SPI_M, > + CVMX_PKI_PCAM_TERM_L4_PORT = CVMX_PKI_PCAM_TERM_E_L4_PORT_M, > + CVMX_PKI_PCAM_TERM_L4_SPORT = CVMX_PKI_PCAM_TERM_E_L4_SPORT_M, > + CVMX_PKI_PCAM_TERM_LG_CUSTOM = CVMX_PKI_PCAM_TERM_E_LG_CUSTOM_M > +}; > + > +#define CVMX_PKI_DMACH_SHIFT 32 > +#define CVMX_PKI_DMACH_MASK cvmx_build_mask(16) > +#define CVMX_PKI_DMACL_MASK CVMX_PKI_DATA_MASK_32 > +#define CVMX_PKI_DATA_MASK_32 cvmx_build_mask(32) > +#define CVMX_PKI_DATA_MASK_16 cvmx_build_mask(16) > +#define CVMX_PKI_DMAC_MATCH_EXACT cvmx_build_mask(48) > + > +struct cvmx_pki_pcam_input { > + u64 style; > + u64 style_mask; /* bits: 1-match, 0-dont care */ > + enum cvmx_pki_term field; > + u32 field_mask; /* bits: 1-match, 0-dont care */ > + u64 data; > + u64 data_mask; /* bits: 1-match, 0-dont care */ > +}; > + > +struct cvmx_pki_pcam_action { > + enum cvmx_pki_parse_mode_chg parse_mode_chg; > + enum cvmx_pki_layer_type layer_type_set; > + int style_add; > + int parse_flag_set; > + int pointer_advance; > +}; > + > +struct cvmx_pki_pcam_config { > + int in_use; > + int entry_num; > + u64 cluster_mask; > + struct cvmx_pki_pcam_input pcam_input; > + struct cvmx_pki_pcam_action pcam_action; > +}; > + > +/** > + * Status statistics for a port > + */ > +struct cvmx_pki_port_stats { > + u64 dropped_octets; > + u64 dropped_packets; > + u64 pci_raw_packets; > + u64 octets; > + u64 packets; > + u64 multicast_packets; > + u64 broadcast_packets; > + u64 len_64_packets; > + u64 len_65_127_packets; > + u64 len_128_255_packets; > + u64 len_256_511_packets; > + u64 len_512_1023_packets; > + u64 len_1024_1518_packets; > + u64 len_1519_max_packets; > + u64 fcs_align_err_packets; > + u64 runt_packets; > + u64 runt_crc_packets; > + u64 oversize_packets; > + u64 oversize_crc_packets; > + u64 inb_packets; > + u64 inb_octets; > + u64 inb_errors; > + u64 mcast_l2_red_packets; > + u64 bcast_l2_red_packets; > + u64 mcast_l3_red_packets; > + u64 bcast_l3_red_packets; > +}; > + > +/** > + * PKI Packet Instruction Header Structure (PKI_INST_HDR_S) > + */ > +typedef union { > + u64 u64; > + struct { > + u64 w : 1; /* INST_HDR size: 0 = 2 bytes, 1 = 4 or 8 > bytes */ > + u64 raw : 1; /* RAW packet indicator in WQE[RAW]: 1 = > enable */ > + u64 utag : 1; /* Use INST_HDR[TAG] to compute WQE[TAG]: > 1 = enable */ > + u64 uqpg : 1; /* Use INST_HDR[QPG] to compute QPG: 1 = > enable */ > + u64 rsvd1 : 1; > + u64 pm : 3; /* Packet parsing mode. Legal values = > 0x0..0x7 */ > + u64 sl : 8; /* Number of bytes in INST_HDR. */ > + /* The following fields are not present, if INST_HDR[W] > = 0: */ > + u64 utt : 1; /* Use INST_HDR[TT] to compute WQE[TT]: 1 > = enable */ > + u64 tt : 2; /* INST_HDR[TT] => WQE[TT], if > INST_HDR[UTT] = 1 */ > + u64 rsvd2 : 2; > + u64 qpg : 11; /* INST_HDR[QPG] => QPG, if > INST_HDR[UQPG] = 1 */ > + u64 tag : 32; /* INST_HDR[TAG] => WQE[TAG], if > INST_HDR[UTAG] = 1 */ > + } s; > +} cvmx_pki_inst_hdr_t; > + > +/** > + * This function assignes the clusters to a group, later pkind can > be > + * configured to use that group depending on number of clusters > pkind > + * would use. A given cluster can only be enabled in a single > cluster group. > + * Number of clusters assign to that group determines how many > engine can work > + * in parallel to process the packet. Eack cluster can process x > MPPS. > + * > + * @param node Node > + * @param cluster_group Group to attach clusters to. > + * @param cluster_mask The mask of clusters which needs to be > assigned to the group. > + */ > +static inline int cvmx_pki_attach_cluster_to_group(int node, u64 > cluster_group, u64 cluster_mask) > +{ > + cvmx_pki_icgx_cfg_t pki_cl_grp; > + > + if (cluster_group >= CVMX_PKI_NUM_CLUSTER_GROUP) { > + debug("ERROR: config cluster group %d", > (int)cluster_group); > + return -1; > + } > + pki_cl_grp.u64 = cvmx_read_csr_node(node, > CVMX_PKI_ICGX_CFG(cluster_group)); > + pki_cl_grp.s.clusters = cluster_mask; > + cvmx_write_csr_node(node, CVMX_PKI_ICGX_CFG(cluster_group), > pki_cl_grp.u64); > + return 0; > +} > + > +static inline void cvmx_pki_write_global_parse(int node, struct > cvmx_pki_global_parse gbl_pen) > +{ > + cvmx_pki_gbl_pen_t gbl_pen_reg; > + > + gbl_pen_reg.u64 = cvmx_read_csr_node(node, CVMX_PKI_GBL_PEN); > + gbl_pen_reg.s.virt_pen = gbl_pen.virt_pen; > + gbl_pen_reg.s.clg_pen = gbl_pen.clg_pen; > + gbl_pen_reg.s.cl2_pen = gbl_pen.cl2_pen; > + gbl_pen_reg.s.l4_pen = gbl_pen.l4_pen; > + gbl_pen_reg.s.il3_pen = gbl_pen.il3_pen; > + gbl_pen_reg.s.l3_pen = gbl_pen.l3_pen; > + gbl_pen_reg.s.mpls_pen = gbl_pen.mpls_pen; > + gbl_pen_reg.s.fulc_pen = gbl_pen.fulc_pen; > + gbl_pen_reg.s.dsa_pen = gbl_pen.dsa_pen; > + gbl_pen_reg.s.hg_pen = gbl_pen.hg_pen; > + cvmx_write_csr_node(node, CVMX_PKI_GBL_PEN, gbl_pen_reg.u64); > +} > + > +static inline void cvmx_pki_write_tag_secret(int node, struct > cvmx_pki_tag_sec tag_secret) > +{ > + cvmx_pki_tag_secret_t tag_secret_reg; > + > + tag_secret_reg.u64 = cvmx_read_csr_node(node, > CVMX_PKI_TAG_SECRET); > + tag_secret_reg.s.dst6 = tag_secret.dst6; > + tag_secret_reg.s.src6 = tag_secret.src6; > + tag_secret_reg.s.dst = tag_secret.dst; > + tag_secret_reg.s.src = tag_secret.src; > + cvmx_write_csr_node(node, CVMX_PKI_TAG_SECRET, > tag_secret_reg.u64); > +} > + > +static inline void cvmx_pki_write_ltype_map(int node, enum > cvmx_pki_layer_type layer, > + enum cvmx_pki_beltype > backend) > +{ > + cvmx_pki_ltypex_map_t ltype_map; > + > + if (layer > CVMX_PKI_LTYPE_E_MAX || backend > > CVMX_PKI_BELTYPE_MAX) { > + debug("ERROR: invalid ltype beltype mapping\n"); > + return; > + } > + ltype_map.u64 = cvmx_read_csr_node(node, > CVMX_PKI_LTYPEX_MAP(layer)); > + ltype_map.s.beltype = backend; > + cvmx_write_csr_node(node, CVMX_PKI_LTYPEX_MAP(layer), > ltype_map.u64); > +} > + > +/** > + * This function enables the cluster group to start parsing. > + * > + * @param node Node number. > + * @param cl_grp Cluster group to enable parsing. > + */ > +static inline int cvmx_pki_parse_enable(int node, unsigned int > cl_grp) > +{ > + cvmx_pki_icgx_cfg_t pki_cl_grp; > + > + if (cl_grp >= CVMX_PKI_NUM_CLUSTER_GROUP) { > + debug("ERROR: pki parse en group %d", (int)cl_grp); > + return -1; > + } > + pki_cl_grp.u64 = cvmx_read_csr_node(node, > CVMX_PKI_ICGX_CFG(cl_grp)); > + pki_cl_grp.s.pena = 1; > + cvmx_write_csr_node(node, CVMX_PKI_ICGX_CFG(cl_grp), > pki_cl_grp.u64); > + return 0; > +} > + > +/** > + * This function enables the PKI to send bpid level backpressure to > CN78XX inputs. > + * > + * @param node Node number. > + */ > +static inline void cvmx_pki_enable_backpressure(int node) > +{ > + cvmx_pki_buf_ctl_t pki_buf_ctl; > + > + pki_buf_ctl.u64 = cvmx_read_csr_node(node, CVMX_PKI_BUF_CTL); > + pki_buf_ctl.s.pbp_en = 1; > + cvmx_write_csr_node(node, CVMX_PKI_BUF_CTL, pki_buf_ctl.u64); > +} > + > +/** > + * Clear the statistics counters for a port. > + * > + * @param node Node number. > + * @param port Port number (ipd_port) to get statistics for. > + * Make sure PKI_STATS_CTL:mode is set to 0 for collecting per > port/pkind stats. > + */ > +void cvmx_pki_clear_port_stats(int node, u64 port); > + > +/** > + * Get the status counters for index from PKI. > + * > + * @param node Node number. > + * @param index PKIND number, if PKI_STATS_CTL:mode = 0 or > + * style(flow) number, if PKI_STATS_CTL:mode = 1 > + * @param status Where to put the results. > + */ > +void cvmx_pki_get_stats(int node, int index, struct > cvmx_pki_port_stats *status); > + > +/** > + * Get the statistics counters for a port. > + * > + * @param node Node number > + * @param port Port number (ipd_port) to get statistics for. > + * Make sure PKI_STATS_CTL:mode is set to 0 for collecting per > port/pkind stats. > + * @param status Where to put the results. > + */ > +static inline void cvmx_pki_get_port_stats(int node, u64 port, > struct cvmx_pki_port_stats *status) > +{ > + int xipd = cvmx_helper_node_to_ipd_port(node, port); > + int xiface = cvmx_helper_get_interface_num(xipd); > + int index = cvmx_helper_get_interface_index_num(port); > + int pknd = cvmx_helper_get_pknd(xiface, index); > + > + cvmx_pki_get_stats(node, pknd, status); > +} > + > +/** > + * Get the statistics counters for a flow represented by style in > PKI. > + * > + * @param node Node number. > + * @param style_num Style number to get statistics for. > + * Make sure PKI_STATS_CTL:mode is set to 1 for collecting per > style/flow stats. > + * @param status Where to put the results. > + */ > +static inline void cvmx_pki_get_flow_stats(int node, u64 style_num, > + struct cvmx_pki_port_stats > *status) > +{ > + cvmx_pki_get_stats(node, style_num, status); > +} > + > +/** > + * Show integrated PKI configuration. > + * > + * @param node node number > + */ > +int cvmx_pki_config_dump(unsigned int node); > + > +/** > + * Show integrated PKI statistics. > + * > + * @param node node number > + */ > +int cvmx_pki_stats_dump(unsigned int node); > + > +/** > + * Clear PKI statistics. > + * > + * @param node node number > + */ > +void cvmx_pki_stats_clear(unsigned int node); > + > +/** > + * This function enables PKI. > + * > + * @param node node to enable pki in. > + */ > +void cvmx_pki_enable(int node); > + > +/** > + * This function disables PKI. > + * > + * @param node node to disable pki in. > + */ > +void cvmx_pki_disable(int node); > + > +/** > + * This function soft resets PKI. > + * > + * @param node node to enable pki in. > + */ > +void cvmx_pki_reset(int node); > + > +/** > + * This function sets the clusters in PKI. > + * > + * @param node node to set clusters in. > + */ > +int cvmx_pki_setup_clusters(int node); > + > +/** > + * This function reads global configuration of PKI block. > + * > + * @param node Node number. > + * @param gbl_cfg Pointer to struct to read global configuration > + */ > +void cvmx_pki_read_global_config(int node, struct > cvmx_pki_global_config *gbl_cfg); > + > +/** > + * This function writes global configuration of PKI into hw. > + * > + * @param node Node number. > + * @param gbl_cfg Pointer to struct to global configuration > + */ > +void cvmx_pki_write_global_config(int node, struct > cvmx_pki_global_config *gbl_cfg); > + > +/** > + * This function reads per pkind parameters in hardware which > defines how > + * the incoming packet is processed. > + * > + * @param node Node number. > + * @param pkind PKI supports a large number of incoming interfaces > and packets > + * arriving on different interfaces or channels may want to be > processed > + * differently. PKI uses the pkind to determine how the incoming > packet > + * is processed. > + * @param pkind_cfg Pointer to struct conatining pkind > configuration read > + * from hardware. > + */ > +int cvmx_pki_read_pkind_config(int node, int pkind, struct > cvmx_pki_pkind_config *pkind_cfg); > + > +/** > + * This function writes per pkind parameters in hardware which > defines how > + * the incoming packet is processed. > + * > + * @param node Node number. > + * @param pkind PKI supports a large number of incoming interfaces > and packets > + * arriving on different interfaces or channels may want to be > processed > + * differently. PKI uses the pkind to determine how the incoming > packet > + * is processed. > + * @param pkind_cfg Pointer to struct conatining pkind > configuration need > + * to be written in hardware. > + */ > +int cvmx_pki_write_pkind_config(int node, int pkind, struct > cvmx_pki_pkind_config *pkind_cfg); > + > +/** > + * This function reads parameters associated with tag configuration > in hardware. > + * > + * @param node Node number. > + * @param style Style to configure tag for. > + * @param cluster_mask Mask of clusters to configure the style for. > + * @param tag_cfg Pointer to tag configuration struct. > + */ > +void cvmx_pki_read_tag_config(int node, int style, u64 cluster_mask, > + struct cvmx_pki_style_tag_cfg *tag_cfg); > + > +/** > + * This function writes/configures parameters associated with tag > + * configuration in hardware. > + * > + * @param node Node number. > + * @param style Style to configure tag for. > + * @param cluster_mask Mask of clusters to configure the style for. > + * @param tag_cfg Pointer to taf configuration struct. > + */ > +void cvmx_pki_write_tag_config(int node, int style, u64 > cluster_mask, > + struct cvmx_pki_style_tag_cfg *tag_cfg); > + > +/** > + * This function reads parameters associated with style in hardware. > + * > + * @param node Node number. > + * @param style Style to read from. > + * @param cluster_mask Mask of clusters style belongs to. > + * @param style_cfg Pointer to style config struct. > + */ > +void cvmx_pki_read_style_config(int node, int style, u64 > cluster_mask, > + struct cvmx_pki_style_config > *style_cfg); > + > +/** > + * This function writes/configures parameters associated with style > in hardware. > + * > + * @param node Node number. > + * @param style Style to configure. > + * @param cluster_mask Mask of clusters to configure the style for. > + * @param style_cfg Pointer to style config struct. > + */ > +void cvmx_pki_write_style_config(int node, u64 style, u64 > cluster_mask, > + struct cvmx_pki_style_config > *style_cfg); > +/** > + * This function reads qpg entry at specified offset from qpg table > + * > + * @param node Node number. > + * @param offset Offset in qpg table to read from. > + * @param qpg_cfg Pointer to structure containing qpg values > + */ > +int cvmx_pki_read_qpg_entry(int node, int offset, struct > cvmx_pki_qpg_config *qpg_cfg); > + > +/** > + * This function writes qpg entry at specified offset in qpg table > + * > + * @param node Node number. > + * @param offset Offset in qpg table to write to. > + * @param qpg_cfg Pointer to stricture containing qpg values. > + */ > +void cvmx_pki_write_qpg_entry(int node, int offset, struct > cvmx_pki_qpg_config *qpg_cfg); > + > +/** > + * This function writes pcam entry at given offset in pcam table in > hardware > + * > + * @param node Node number. > + * @param index Offset in pcam table. > + * @param cluster_mask Mask of clusters in which to write pcam > entry. > + * @param input Input keys to pcam match passed as struct. > + * @param action PCAM match action passed as struct > + */ > +int cvmx_pki_pcam_write_entry(int node, int index, u64 cluster_mask, > + struct cvmx_pki_pcam_input input, struct > cvmx_pki_pcam_action action); > +/** > + * Configures the channel which will receive backpressure from the > specified bpid. > + * Each channel listens for backpressure on a specific bpid. > + * Each bpid can backpressure multiple channels. > + * @param node Node number. > + * @param bpid BPID from which channel will receive backpressure. > + * @param channel Channel number to receive backpressue. > + */ > +int cvmx_pki_write_channel_bpid(int node, int channel, int bpid); > + > +/** > + * Configures the bpid on which, specified channel will > + * assert backpressure. > + * Each bpid receives backpressure from auras. > + * Multiple auras can backpressure single bpid. > + * @param node Node number. > + * @param aura Number which will assert backpressure on that bpid. > + * @param bpid To assert backpressure on. > + */ > +int cvmx_pki_write_aura_bpid(int node, int aura, int bpid); > + > +/** > + * Enables/Disabled QoS (RED Drop, Tail Drop & backpressure) for > the* PKI aura. > + * > + * @param node Node number > + * @param aura To enable/disable QoS on. > + * @param ena_red Enable/Disable RED drop between pass and drop > level > + * 1-enable 0-disable > + * @param ena_drop Enable/disable tail drop when max drop level > exceeds > + * 1-enable 0-disable > + * @param ena_bp Enable/Disable asserting backpressure on bpid when > + * max DROP level exceeds. > + * 1-enable 0-disable > + */ > +int cvmx_pki_enable_aura_qos(int node, int aura, bool ena_red, bool > ena_drop, bool ena_bp); > + > +/** > + * This function gives the initial style used by that pkind. > + * > + * @param node Node number. > + * @param pkind PKIND number. > + */ > +int cvmx_pki_get_pkind_style(int node, int pkind); > + > +/** > + * This function sets the wqe buffer mode. First packet data buffer > can reside > + * either in same buffer as wqe OR it can go in separate buffer. If > used the later mode, > + * make sure software allocate enough buffers to now have wqe > separate from packet data. > + * > + * @param node Node number. > + * @param style Style to configure. > + * @param pkt_outside_wqe > + * 0 = The packet link pointer will be at word [FIRST_SKIP] > immediately > + * followed by packet data, in the same buffer as the work queue > entry. > + * 1 = The packet link pointer will be at word [FIRST_SKIP] in a > new > + * buffer separate from the work queue entry. Words following the > + * WQE in the same cache line will be zeroed, other lines in the > + * buffer will not be modified and will retain stale data (from > the > + * buffer’s previous use). This setting may decrease the peak PKI > + * performance by up to half on small packets. > + */ > +void cvmx_pki_set_wqe_mode(int node, u64 style, bool > pkt_outside_wqe); > + > +/** > + * This function sets the Packet mode of all ports and styles to > little-endian. > + * It Changes write operations of packet data to L2C to > + * be in little-endian. Does not change the WQE header format, which > is > + * properly endian neutral. > + * > + * @param node Node number. > + * @param style Style to configure. > + */ > +void cvmx_pki_set_little_endian(int node, u64 style); > + > +/** > + * Enables/Disables L2 length error check and max & min frame length > checks. > + * > + * @param node Node number. > + * @param pknd PKIND to disable error for. > + * @param l2len_err L2 length error check enable. > + * @param maxframe_err Max frame error check enable. > + * @param minframe_err Min frame error check enable. > + * 1 -- Enabel err checks > + * 0 -- Disable error checks > + */ > +void cvmx_pki_endis_l2_errs(int node, int pknd, bool l2len_err, bool > maxframe_err, > + bool minframe_err); > + > +/** > + * Enables/Disables fcs check and fcs stripping on the pkind. > + * > + * @param node Node number. > + * @param pknd PKIND to apply settings on. > + * @param fcs_chk Enable/disable fcs check. > + * 1 -- enable fcs error check. > + * 0 -- disable fcs error check. > + * @param fcs_strip Strip L2 FCS bytes from packet, decrease > WQE[LEN] by 4 bytes > + * 1 -- strip L2 FCS. > + * 0 -- Do not strip L2 FCS. > + */ > +void cvmx_pki_endis_fcs_check(int node, int pknd, bool fcs_chk, bool > fcs_strip); > + > +/** > + * This function shows the qpg table entries, read directly from > hardware. > + * > + * @param node Node number. > + * @param num_entry Number of entries to print. > + */ > +void cvmx_pki_show_qpg_entries(int node, u16 num_entry); > + > +/** > + * This function shows the pcam table in raw format read directly > from hardware. > + * > + * @param node Node number. > + */ > +void cvmx_pki_show_pcam_entries(int node); > + > +/** > + * This function shows the valid entries in readable format, > + * read directly from hardware. > + * > + * @param node Node number. > + */ > +void cvmx_pki_show_valid_pcam_entries(int node); > + > +/** > + * This function shows the pkind attributes in readable format, > + * read directly from hardware. > + * @param node Node number. > + * @param pkind PKIND number to print. > + */ > +void cvmx_pki_show_pkind_attributes(int node, int pkind); > + > +/** > + * @INTERNAL > + * This function is called by cvmx_helper_shutdown() to extract all > FPA buffers > + * out of the PKI. After this function completes, all FPA buffers > that were > + * prefetched by PKI will be in the appropriate FPA pool. > + * This functions does not reset the PKI. > + * WARNING: It is very important that PKI be reset soon after a call > to this function. > + * > + * @param node Node number. > + */ > +void __cvmx_pki_free_ptr(int node); > + > +#endif > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pko-internal- > ports-range.h b/arch/mips/mach-octeon/include/mach/cvmx-pko-internal- > ports-range.h > new file mode 100644 > index 000000000000..1fb49b3fb6de > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-pko-internal-ports- > range.h > @@ -0,0 +1,43 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + */ > + > +#ifndef __CVMX_INTERNAL_PORTS_RANGE__ > +#define __CVMX_INTERNAL_PORTS_RANGE__ > + > +/* > + * Allocated a block of internal ports for the specified > interface/port > + * > + * @param interface the interface for which the internal ports are > requested > + * @param port the index of the port within in the interface > for which the internal ports > + * are requested. > + * @param count the number of internal ports requested > + * > + * @return 0 on success > + * -1 on failure > + */ > +int cvmx_pko_internal_ports_alloc(int interface, int port, u64 > count); > + > +/* > + * Free the internal ports associated with the specified > interface/port > + * > + * @param interface the interface for which the internal ports are > requested > + * @param port the index of the port within in the interface > for which the internal ports > + * are requested. > + * > + * @return 0 on success > + * -1 on failure > + */ > +int cvmx_pko_internal_ports_free(int interface, int port); > + > +/* > + * Frees up all the allocated internal ports. > + */ > +void cvmx_pko_internal_ports_range_free_all(void); > + > +void cvmx_pko_internal_ports_range_show(void); > + > +int __cvmx_pko_internal_ports_range_init(void); > + > +#endif > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pko3-queue.h > b/arch/mips/mach-octeon/include/mach/cvmx-pko3-queue.h > new file mode 100644 > index 000000000000..5f8398904953 > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-pko3-queue.h > @@ -0,0 +1,175 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + */ > + > +#ifndef __CVMX_PKO3_QUEUE_H__ > +#define __CVMX_PKO3_QUEUE_H__ > + > +/** > + * @INTERNAL > + * > + * Find or allocate global port/dq map table > + * which is a named table, contains entries for > + * all possible OCI nodes. > + * > + * The table global pointer is stored in core-local variable > + * so that every core will call this function once, on first use. > + */ > +int __cvmx_pko3_dq_table_setup(void); > + > +/* > + * Get the base Descriptor Queue number for an IPD port on the local > node > + */ > +int cvmx_pko3_get_queue_base(int ipd_port); > + > +/* > + * Get the number of Descriptor Queues assigned for an IPD port > + */ > +int cvmx_pko3_get_queue_num(int ipd_port); > + > +/** > + * Get L1/Port Queue number assigned to interface port. > + * > + * @param xiface is interface number. > + * @param index is port index. > + */ > +int cvmx_pko3_get_port_queue(int xiface, int index); > + > +/* > + * Configure L3 through L5 Scheduler Queues and Descriptor Queues > + * > + * The Scheduler Queues in Levels 3 to 5 and Descriptor Queues are > + * configured one-to-one or many-to-one to a single parent Scheduler > + * Queues. The level of the parent SQ is specified in an argument, > + * as well as the number of children to attach to the specific > parent. > + * The children can have fair round-robin or priority-based > scheduling > + * when multiple children are assigned a single parent. > + * > + * @param node is the OCI node location for the queues to be > configured > + * @param parent_level is the level of the parent queue, 2 to 5. > + * @param parent_queue is the number of the parent Scheduler Queue > + * @param child_base is the number of the first child SQ or DQ to > assign to > + * @param parent > + * @param child_count is the number of consecutive children to > assign > + * @param stat_prio_count is the priority setting for the children > L2 SQs > + * > + * If <stat_prio_count> is -1, the Ln children will have equal > Round-Robin > + * relationship with eachother. If <stat_prio_count> is 0, all Ln > children > + * will be arranged in Weighted-Round-Robin, with the first having > the most > + * precedence. If <stat_prio_count> is between 1 and 8, it indicates > how > + * many children will have static priority settings (with the first > having > + * the most precedence), with the remaining Ln children having WRR > scheduling. > + * > + * @returns 0 on success, -1 on failure. > + * > + * Note: this function supports the configuration of node-local > unit. > + */ > +int cvmx_pko3_sq_config_children(unsigned int node, unsigned int > parent_level, > + unsigned int parent_queue, unsigned > int child_base, > + unsigned int child_count, int > stat_prio_count); > + > +/* > + * @INTERNAL > + * Register a range of Descriptor Queues wth an interface port > + * > + * This function poulates the DQ-to-IPD translation table > + * used by the application to retrieve the DQ range (typically > ordered > + * by priority) for a given IPD-port, which is either a physical > port, > + * or a channel on a channelized interface (i.e. ILK). > + * > + * @param xiface is the physical interface number > + * @param index is either a physical port on an interface > + * @param or a channel of an ILK interface > + * @param dq_base is the first Descriptor Queue number in a > consecutive range > + * @param dq_count is the number of consecutive Descriptor Queues > leading > + * @param the same channel or port. > + * > + * Only a consecurive range of Descriptor Queues can be associated > with any > + * given channel/port, and usually they are ordered from most to > least > + * in terms of scheduling priority. > + * > + * Note: thus function only populates the node-local translation > table. > + * > + * @returns 0 on success, -1 on failure. > + */ > +int __cvmx_pko3_ipd_dq_register(int xiface, int index, unsigned int > dq_base, unsigned int dq_count); > + > +/** > + * @INTERNAL > + * > + * Unregister DQs associated with CHAN_E (IPD port) > + */ > +int __cvmx_pko3_ipd_dq_unregister(int xiface, int index); > + > +/* > + * Map channel number in PKO > + * > + * @param node is to specify the node to which this configuration is > applied. > + * @param pq_num specifies the Port Queue (i.e. L1) queue number. > + * @param l2_l3_q_num specifies L2/L3 queue number. > + * @param channel specifies the channel number to map to the queue. > + * > + * The channel assignment applies to L2 or L3 Shaper Queues > depending > + * on the setting of channel credit level. > + * > + * @return returns none. > + */ > +void cvmx_pko3_map_channel(unsigned int node, unsigned int pq_num, > unsigned int l2_l3_q_num, > + u16 channel); > + > +int cvmx_pko3_pq_config(unsigned int node, unsigned int mac_num, > unsigned int pq_num); > + > +int cvmx_pko3_port_cir_set(unsigned int node, unsigned int pq_num, > unsigned long rate_kbips, > + unsigned int burst_bytes, int adj_bytes); > +int cvmx_pko3_dq_cir_set(unsigned int node, unsigned int pq_num, > unsigned long rate_kbips, > + unsigned int burst_bytes); > +int cvmx_pko3_dq_pir_set(unsigned int node, unsigned int pq_num, > unsigned long rate_kbips, > + unsigned int burst_bytes); > +typedef enum { > + CVMX_PKO3_SHAPE_RED_STALL, > + CVMX_PKO3_SHAPE_RED_DISCARD, > + CVMX_PKO3_SHAPE_RED_PASS > +} red_action_t; > + > +void cvmx_pko3_dq_red(unsigned int node, unsigned int dq_num, > red_action_t red_act, > + int8_t len_adjust); > + > +/** > + * Macros to deal with short floating point numbers, > + * where unsigned exponent, and an unsigned normalized > + * mantissa are represented each with a defined field width. > + * > + */ > +#define CVMX_SHOFT_MANT_BITS 8 > +#define CVMX_SHOFT_EXP_BITS 4 > + > +/** > + * Convert short-float to an unsigned integer > + * Note that it will lose precision. > + */ > +#define CVMX_SHOFT_TO_U64(m, > e) > \ > + ((((1ull << CVMX_SHOFT_MANT_BITS) | (m)) << (e)) >> > CVMX_SHOFT_MANT_BITS) > + > +/** > + * Convert to short-float from an unsigned integer > + */ > +#define CVMX_SHOFT_FROM_U64(ui, m, > e) \ > + do > { > \ > + unsigned long long > u; \ > + unsigned int > k; > \ > + k = (1ull << (CVMX_SHOFT_MANT_BITS + 1)) - > 1; \ > + (e) = > 0; > \ > + u = (ui) << > CVMX_SHOFT_MANT_BITS; > \ > + while ((u) > k) > { \ > + u >>= > 1; > \ > + (e)++; > \ > + } > \ > + (m) = u & (k >> > 1); \ > + } while (0); > + > +#define > CVMX_SHOFT_MAX() > \ > + CVMX_SHOFT_TO_U64((1 << CVMX_SHOFT_MANT_BITS) - 1, (1 << > CVMX_SHOFT_EXP_BITS) - 1) > +#define CVMX_SHOFT_MIN() CVMX_SHOFT_TO_U64(0, 0) > + > +#endif /* __CVMX_PKO3_QUEUE_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pow.h > b/arch/mips/mach-octeon/include/mach/cvmx-pow.h > new file mode 100644 > index 000000000000..0680ca258f12 > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-pow.h > @@ -0,0 +1,2991 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * Interface to the hardware Scheduling unit. > + * > + * New, starting with SDK 1.7.0, cvmx-pow supports a number of > + * extended consistency checks. The define > + * CVMX_ENABLE_POW_CHECKS controls the runtime insertion of POW > + * internal state checks to find common programming errors. If > + * CVMX_ENABLE_POW_CHECKS is not defined, checks are by default > + * enabled. For example, cvmx-pow will check for the following > + * program errors or POW state inconsistency. > + * - Requesting a POW operation with an active tag switch in > + * progress. > + * - Waiting for a tag switch to complete for an excessively > + * long period. This is normally a sign of an error in locking > + * causing deadlock. > + * - Illegal tag switches from NULL_NULL. > + * - Illegal tag switches from NULL. > + * - Illegal deschedule request. > + * - WQE pointer not matching the one attached to the core by > + * the POW. > + */ > + > +#ifndef __CVMX_POW_H__ > +#define __CVMX_POW_H__ > + > +#include "cvmx-wqe.h" > +#include "cvmx-pow-defs.h" > +#include "cvmx-sso-defs.h" > +#include "cvmx-address.h" > +#include "cvmx-coremask.h" > + > +/* Default to having all POW constancy checks turned on */ > +#ifndef CVMX_ENABLE_POW_CHECKS > +#define CVMX_ENABLE_POW_CHECKS 1 > +#endif > + > +/* > + * Special type for CN78XX style SSO groups (0..255), > + * for distinction from legacy-style groups (0..15) > + */ > +typedef union { > + u8 xgrp; > + /* Fields that map XGRP for backwards compatibility */ > + struct __attribute__((__packed__)) { > + u8 group : 5; > + u8 qus : 3; > + }; > +} cvmx_xgrp_t; > + > +/* > + * Softwsare-only structure to convey a return value > + * containing multiple information fields about an work queue entry > + */ > +typedef struct { > + u32 tag; > + u16 index; > + u8 grp; /* Legacy group # (0..15) */ > + u8 tag_type; > +} cvmx_pow_tag_info_t; > + > +/** > + * Wait flag values for pow functions. > + */ > +typedef enum { > + CVMX_POW_WAIT = 1, > + CVMX_POW_NO_WAIT = 0, > +} cvmx_pow_wait_t; > + > +/** > + * POW tag operations. These are used in the data stored to the > POW. > + */ > +typedef enum { > + CVMX_POW_TAG_OP_SWTAG = 0L, > + CVMX_POW_TAG_OP_SWTAG_FULL = 1L, > + CVMX_POW_TAG_OP_SWTAG_DESCH = 2L, > + CVMX_POW_TAG_OP_DESCH = 3L, > + CVMX_POW_TAG_OP_ADDWQ = 4L, > + CVMX_POW_TAG_OP_UPDATE_WQP_GRP = 5L, > + CVMX_POW_TAG_OP_SET_NSCHED = 6L, > + CVMX_POW_TAG_OP_CLR_NSCHED = 7L, > + CVMX_POW_TAG_OP_NOP = 15L > +} cvmx_pow_tag_op_t; > + > +/** > + * This structure defines the store data on a store to POW > + */ > +typedef union { > + u64 u64; > + struct { > + u64 no_sched : 1; > + u64 unused : 2; > + u64 index : 13; > + cvmx_pow_tag_op_t op : 4; > + u64 unused2 : 2; > + u64 qos : 3; > + u64 grp : 4; > + cvmx_pow_tag_type_t type : 3; > + u64 tag : 32; > + } s_cn38xx; > + struct { > + u64 no_sched : 1; > + cvmx_pow_tag_op_t op : 4; > + u64 unused1 : 4; > + u64 index : 11; > + u64 unused2 : 1; > + u64 grp : 6; > + u64 unused3 : 3; > + cvmx_pow_tag_type_t type : 2; > + u64 tag : 32; > + } s_cn68xx_clr; > + struct { > + u64 no_sched : 1; > + cvmx_pow_tag_op_t op : 4; > + u64 unused1 : 12; > + u64 qos : 3; > + u64 unused2 : 1; > + u64 grp : 6; > + u64 unused3 : 3; > + cvmx_pow_tag_type_t type : 2; > + u64 tag : 32; > + } s_cn68xx_add; > + struct { > + u64 no_sched : 1; > + cvmx_pow_tag_op_t op : 4; > + u64 unused1 : 16; > + u64 grp : 6; > + u64 unused3 : 3; > + cvmx_pow_tag_type_t type : 2; > + u64 tag : 32; > + } s_cn68xx_other; > + struct { > + u64 rsvd_62_63 : 2; > + u64 grp : 10; > + cvmx_pow_tag_type_t type : 2; > + u64 no_sched : 1; > + u64 rsvd_48 : 1; > + cvmx_pow_tag_op_t op : 4; > + u64 rsvd_42_43 : 2; > + u64 wqp : 42; > + } s_cn78xx_other; > + > +} cvmx_pow_tag_req_t; > + > +union cvmx_pow_tag_req_addr { > + u64 u64; > + struct { > + u64 mem_region : 2; > + u64 reserved_49_61 : 13; > + u64 is_io : 1; > + u64 did : 8; > + u64 addr : 40; > + } s; > + struct { > + u64 mem_region : 2; > + u64 reserved_49_61 : 13; > + u64 is_io : 1; > + u64 did : 8; > + u64 node : 4; > + u64 tag : 32; > + u64 reserved_0_3 : 4; > + } s_cn78xx; > +}; > + > +/** > + * This structure describes the address to load stuff from POW > + */ > +typedef union { > + u64 u64; > + /** > + * Address for new work request loads (did<2:0> == 0) > + */ > + struct { > + u64 mem_region : 2; > + u64 reserved_49_61 : 13; > + u64 is_io : 1; > + u64 did : 8; > + u64 reserved_4_39 : 36; > + u64 wait : 1; > + u64 reserved_0_2 : 3; > + } swork; > + struct { > + u64 mem_region : 2; > + u64 reserved_49_61 : 13; > + u64 is_io : 1; > + u64 did : 8; > + u64 node : 4; > + u64 reserved_32_35 : 4; > + u64 indexed : 1; > + u64 grouped : 1; > + u64 rtngrp : 1; > + u64 reserved_16_28 : 13; > + u64 index : 12; > + u64 wait : 1; > + u64 reserved_0_2 : 3; > + } swork_78xx; > + /** > + * Address for loads to get POW internal status > + */ > + struct { > + u64 mem_region : 2; > + u64 reserved_49_61 : 13; > + u64 is_io : 1; > + u64 did : 8; > + u64 reserved_10_39 : 30; > + u64 coreid : 4; > + u64 get_rev : 1; > + u64 get_cur : 1; > + u64 get_wqp : 1; > + u64 reserved_0_2 : 3; > + } sstatus; > + /** > + * Address for loads to get 68XX SS0 internal status > + */ > + struct { > + u64 mem_region : 2; > + u64 reserved_49_61 : 13; > + u64 is_io : 1; > + u64 did : 8; > + u64 reserved_14_39 : 26; > + u64 coreid : 5; > + u64 reserved_6_8 : 3; > + u64 opcode : 3; > + u64 reserved_0_2 : 3; > + } sstatus_cn68xx; > + /** > + * Address for memory loads to get POW internal state > + */ > + struct { > + u64 mem_region : 2; > + u64 reserved_49_61 : 13; > + u64 is_io : 1; > + u64 did : 8; > + u64 reserved_16_39 : 24; > + u64 index : 11; > + u64 get_des : 1; > + u64 get_wqp : 1; > + u64 reserved_0_2 : 3; > + } smemload; > + /** > + * Address for memory loads to get SSO internal state > + */ > + struct { > + u64 mem_region : 2; > + u64 reserved_49_61 : 13; > + u64 is_io : 1; > + u64 did : 8; > + u64 reserved_20_39 : 20; > + u64 index : 11; > + u64 reserved_6_8 : 3; > + u64 opcode : 3; > + u64 reserved_0_2 : 3; > + } smemload_cn68xx; > + /** > + * Address for index/pointer loads > + */ > + struct { > + u64 mem_region : 2; > + u64 reserved_49_61 : 13; > + u64 is_io : 1; > + u64 did : 8; > + u64 reserved_9_39 : 31; > + u64 qosgrp : 4; > + u64 get_des_get_tail : 1; > + u64 get_rmt : 1; > + u64 reserved_0_2 : 3; > + } sindexload; > + /** > + * Address for a Index/Pointer loads to get SSO internal state > + */ > + struct { > + u64 mem_region : 2; > + u64 reserved_49_61 : 13; > + u64 is_io : 1; > + u64 did : 8; > + u64 reserved_15_39 : 25; > + u64 qos_grp : 6; > + u64 reserved_6_8 : 3; > + u64 opcode : 3; > + u64 reserved_0_2 : 3; > + } sindexload_cn68xx; > + /** > + * Address for NULL_RD request (did<2:0> == 4) > + * when this is read, HW attempts to change the state to NULL > if it is NULL_NULL > + * (the hardware cannot switch from NULL_NULL to NULL if a POW > entry is not available - > + * software may need to recover by finishing another piece of > work before a POW > + * entry can ever become available.) > + */ > + struct { > + u64 mem_region : 2; > + u64 reserved_49_61 : 13; > + u64 is_io : 1; > + u64 did : 8; > + u64 reserved_0_39 : 40; > + } snull_rd; > +} cvmx_pow_load_addr_t; > + > +/** > + * This structure defines the response to a load/SENDSINGLE to POW > (except CSR reads) > + */ > +typedef union { > + u64 u64; > + /** > + * Response to new work request loads > + */ > + struct { > + u64 no_work : 1; > + u64 pend_switch : 1; > + u64 tt : 2; > + u64 reserved_58_59 : 2; > + u64 grp : 10; > + u64 reserved_42_47 : 6; > + u64 addr : 42; > + } s_work; > + > + /** > + * Result for a POW Status Load (when get_cur==0 and > get_wqp==0) > + */ > + struct { > + u64 reserved_62_63 : 2; > + u64 pend_switch : 1; > + u64 pend_switch_full : 1; > + u64 pend_switch_null : 1; > + u64 pend_desched : 1; > + u64 pend_desched_switch : 1; > + u64 pend_nosched : 1; > + u64 pend_new_work : 1; > + u64 pend_new_work_wait : 1; > + u64 pend_null_rd : 1; > + u64 pend_nosched_clr : 1; > + u64 reserved_51 : 1; > + u64 pend_index : 11; > + u64 pend_grp : 4; > + u64 reserved_34_35 : 2; > + u64 pend_type : 2; > + u64 pend_tag : 32; > + } s_sstatus0; > + /** > + * Result for a SSO Status Load (when opcode is SL_PENDTAG) > + */ > + struct { > + u64 pend_switch : 1; > + u64 pend_get_work : 1; > + u64 pend_get_work_wait : 1; > + u64 pend_nosched : 1; > + u64 pend_nosched_clr : 1; > + u64 pend_desched : 1; > + u64 pend_alloc_we : 1; > + u64 reserved_48_56 : 9; > + u64 pend_index : 11; > + u64 reserved_34_36 : 3; > + u64 pend_type : 2; > + u64 pend_tag : 32; > + } s_sstatus0_cn68xx; > + /** > + * Result for a POW Status Load (when get_cur==0 and > get_wqp==1) > + */ > + struct { > + u64 reserved_62_63 : 2; > + u64 pend_switch : 1; > + u64 pend_switch_full : 1; > + u64 pend_switch_null : 1; > + u64 pend_desched : 1; > + u64 pend_desched_switch : 1; > + u64 pend_nosched : 1; > + u64 pend_new_work : 1; > + u64 pend_new_work_wait : 1; > + u64 pend_null_rd : 1; > + u64 pend_nosched_clr : 1; > + u64 reserved_51 : 1; > + u64 pend_index : 11; > + u64 pend_grp : 4; > + u64 pend_wqp : 36; > + } s_sstatus1; > + /** > + * Result for a SSO Status Load (when opcode is SL_PENDWQP) > + */ > + struct { > + u64 pend_switch : 1; > + u64 pend_get_work : 1; > + u64 pend_get_work_wait : 1; > + u64 pend_nosched : 1; > + u64 pend_nosched_clr : 1; > + u64 pend_desched : 1; > + u64 pend_alloc_we : 1; > + u64 reserved_51_56 : 6; > + u64 pend_index : 11; > + u64 reserved_38_39 : 2; > + u64 pend_wqp : 38; > + } s_sstatus1_cn68xx; > + > + struct { > + u64 pend_switch : 1; > + u64 pend_get_work : 1; > + u64 pend_get_work_wait : 1; > + u64 pend_nosched : 1; > + u64 pend_nosched_clr : 1; > + u64 pend_desched : 1; > + u64 pend_alloc_we : 1; > + u64 reserved_56 : 1; > + u64 prep_index : 12; > + u64 reserved_42_43 : 2; > + u64 pend_tag : 42; > + } s_sso_ppx_pendwqp_cn78xx; > + /** > + * Result for a POW Status Load (when get_cur==1, get_wqp==0, > and get_rev==0) > + */ > + struct { > + u64 reserved_62_63 : 2; > + u64 link_index : 11; > + u64 index : 11; > + u64 grp : 4; > + u64 head : 1; > + u64 tail : 1; > + u64 tag_type : 2; > + u64 tag : 32; > + } s_sstatus2; > + /** > + * Result for a SSO Status Load (when opcode is SL_TAG) > + */ > + struct { > + u64 reserved_57_63 : 7; > + u64 index : 11; > + u64 reserved_45 : 1; > + u64 grp : 6; > + u64 head : 1; > + u64 tail : 1; > + u64 reserved_34_36 : 3; > + u64 tag_type : 2; > + u64 tag : 32; > + } s_sstatus2_cn68xx; > + > + struct { > + u64 tailc : 1; > + u64 reserved_60_62 : 3; > + u64 index : 12; > + u64 reserved_46_47 : 2; > + u64 grp : 10; > + u64 head : 1; > + u64 tail : 1; > + u64 tt : 2; > + u64 tag : 32; > + } s_sso_ppx_tag_cn78xx; > + /** > + * Result for a POW Status Load (when get_cur==1, get_wqp==0, > and get_rev==1) > + */ > + struct { > + u64 reserved_62_63 : 2; > + u64 revlink_index : 11; > + u64 index : 11; > + u64 grp : 4; > + u64 head : 1; > + u64 tail : 1; > + u64 tag_type : 2; > + u64 tag : 32; > + } s_sstatus3; > + /** > + * Result for a SSO Status Load (when opcode is SL_WQP) > + */ > + struct { > + u64 reserved_58_63 : 6; > + u64 index : 11; > + u64 reserved_46 : 1; > + u64 grp : 6; > + u64 reserved_38_39 : 2; > + u64 wqp : 38; > + } s_sstatus3_cn68xx; > + > + struct { > + u64 reserved_58_63 : 6; > + u64 grp : 10; > + u64 reserved_42_47 : 6; > + u64 tag : 42; > + } s_sso_ppx_wqp_cn78xx; > + /** > + * Result for a POW Status Load (when get_cur==1, get_wqp==1, > and get_rev==0) > + */ > + struct { > + u64 reserved_62_63 : 2; > + u64 link_index : 11; > + u64 index : 11; > + u64 grp : 4; > + u64 wqp : 36; > + } s_sstatus4; > + /** > + * Result for a SSO Status Load (when opcode is SL_LINKS) > + */ > + struct { > + u64 reserved_46_63 : 18; > + u64 index : 11; > + u64 reserved_34 : 1; > + u64 grp : 6; > + u64 head : 1; > + u64 tail : 1; > + u64 reserved_24_25 : 2; > + u64 revlink_index : 11; > + u64 reserved_11_12 : 2; > + u64 link_index : 11; > + } s_sstatus4_cn68xx; > + > + struct { > + u64 tailc : 1; > + u64 reserved_60_62 : 3; > + u64 index : 12; > + u64 reserved_38_47 : 10; > + u64 grp : 10; > + u64 head : 1; > + u64 tail : 1; > + u64 reserved_25 : 1; > + u64 revlink_index : 12; > + u64 link_index_vld : 1; > + u64 link_index : 12; > + } s_sso_ppx_links_cn78xx; > + /** > + * Result for a POW Status Load (when get_cur==1, get_wqp==1, > and get_rev==1) > + */ > + struct { > + u64 reserved_62_63 : 2; > + u64 revlink_index : 11; > + u64 index : 11; > + u64 grp : 4; > + u64 wqp : 36; > + } s_sstatus5; > + /** > + * Result For POW Memory Load (get_des == 0 and get_wqp == 0) > + */ > + struct { > + u64 reserved_51_63 : 13; > + u64 next_index : 11; > + u64 grp : 4; > + u64 reserved_35 : 1; > + u64 tail : 1; > + u64 tag_type : 2; > + u64 tag : 32; > + } s_smemload0; > + /** > + * Result For SSO Memory Load (opcode is ML_TAG) > + */ > + struct { > + u64 reserved_38_63 : 26; > + u64 tail : 1; > + u64 reserved_34_36 : 3; > + u64 tag_type : 2; > + u64 tag : 32; > + } s_smemload0_cn68xx; > + > + struct { > + u64 reserved_39_63 : 25; > + u64 tail : 1; > + u64 reserved_34_36 : 3; > + u64 tag_type : 2; > + u64 tag : 32; > + } s_sso_iaq_ppx_tag_cn78xx; > + /** > + * Result For POW Memory Load (get_des == 0 and get_wqp == 1) > + */ > + struct { > + u64 reserved_51_63 : 13; > + u64 next_index : 11; > + u64 grp : 4; > + u64 wqp : 36; > + } s_smemload1; > + /** > + * Result For SSO Memory Load (opcode is ML_WQPGRP) > + */ > + struct { > + u64 reserved_48_63 : 16; > + u64 nosched : 1; > + u64 reserved_46 : 1; > + u64 grp : 6; > + u64 reserved_38_39 : 2; > + u64 wqp : 38; > + } s_smemload1_cn68xx; > + > + /** > + * Entry structures for the CN7XXX chips. > + */ > + struct { > + u64 reserved_39_63 : 25; > + u64 tailc : 1; > + u64 tail : 1; > + u64 reserved_34_36 : 3; > + u64 tt : 2; > + u64 tag : 32; > + } s_sso_ientx_tag_cn78xx; > + > + struct { > + u64 reserved_62_63 : 2; > + u64 head : 1; > + u64 nosched : 1; > + u64 reserved_56_59 : 4; > + u64 grp : 8; > + u64 reserved_42_47 : 6; > + u64 wqp : 42; > + } s_sso_ientx_wqpgrp_cn73xx; > + > + struct { > + u64 reserved_62_63 : 2; > + u64 head : 1; > + u64 nosched : 1; > + u64 reserved_58_59 : 2; > + u64 grp : 10; > + u64 reserved_42_47 : 6; > + u64 wqp : 42; > + } s_sso_ientx_wqpgrp_cn78xx; > + > + struct { > + u64 reserved_38_63 : 26; > + u64 pend_switch : 1; > + u64 reserved_34_36 : 3; > + u64 pend_tt : 2; > + u64 pend_tag : 32; > + } s_sso_ientx_pendtag_cn78xx; > + > + struct { > + u64 reserved_26_63 : 38; > + u64 prev_index : 10; > + u64 reserved_11_15 : 5; > + u64 next_index_vld : 1; > + u64 next_index : 10; > + } s_sso_ientx_links_cn73xx; > + > + struct { > + u64 reserved_28_63 : 36; > + u64 prev_index : 12; > + u64 reserved_13_15 : 3; > + u64 next_index_vld : 1; > + u64 next_index : 12; > + } s_sso_ientx_links_cn78xx; > + > + /** > + * Result For POW Memory Load (get_des == 1) > + */ > + struct { > + u64 reserved_51_63 : 13; > + u64 fwd_index : 11; > + u64 grp : 4; > + u64 nosched : 1; > + u64 pend_switch : 1; > + u64 pend_type : 2; > + u64 pend_tag : 32; > + } s_smemload2; > + /** > + * Result For SSO Memory Load (opcode is ML_PENTAG) > + */ > + struct { > + u64 reserved_38_63 : 26; > + u64 pend_switch : 1; > + u64 reserved_34_36 : 3; > + u64 pend_type : 2; > + u64 pend_tag : 32; > + } s_smemload2_cn68xx; > + > + struct { > + u64 pend_switch : 1; > + u64 pend_get_work : 1; > + u64 pend_get_work_wait : 1; > + u64 pend_nosched : 1; > + u64 pend_nosched_clr : 1; > + u64 pend_desched : 1; > + u64 pend_alloc_we : 1; > + u64 reserved_34_56 : 23; > + u64 pend_tt : 2; > + u64 pend_tag : 32; > + } s_sso_ppx_pendtag_cn78xx; > + /** > + * Result For SSO Memory Load (opcode is ML_LINKS) > + */ > + struct { > + u64 reserved_24_63 : 40; > + u64 fwd_index : 11; > + u64 reserved_11_12 : 2; > + u64 next_index : 11; > + } s_smemload3_cn68xx; > + > + /** > + * Result For POW Index/Pointer Load (get_rmt == > 0/get_des_get_tail == 0) > + */ > + struct { > + u64 reserved_52_63 : 12; > + u64 free_val : 1; > + u64 free_one : 1; > + u64 reserved_49 : 1; > + u64 free_head : 11; > + u64 reserved_37 : 1; > + u64 free_tail : 11; > + u64 loc_val : 1; > + u64 loc_one : 1; > + u64 reserved_23 : 1; > + u64 loc_head : 11; > + u64 reserved_11 : 1; > + u64 loc_tail : 11; > + } sindexload0; > + /** > + * Result for SSO Index/Pointer Load(opcode == > + * IPL_IQ/IPL_DESCHED/IPL_NOSCHED) > + */ > + struct { > + u64 reserved_28_63 : 36; > + u64 queue_val : 1; > + u64 queue_one : 1; > + u64 reserved_24_25 : 2; > + u64 queue_head : 11; > + u64 reserved_11_12 : 2; > + u64 queue_tail : 11; > + } sindexload0_cn68xx; > + /** > + * Result For POW Index/Pointer Load (get_rmt == > 0/get_des_get_tail == 1) > + */ > + struct { > + u64 reserved_52_63 : 12; > + u64 nosched_val : 1; > + u64 nosched_one : 1; > + u64 reserved_49 : 1; > + u64 nosched_head : 11; > + u64 reserved_37 : 1; > + u64 nosched_tail : 11; > + u64 des_val : 1; > + u64 des_one : 1; > + u64 reserved_23 : 1; > + u64 des_head : 11; > + u64 reserved_11 : 1; > + u64 des_tail : 11; > + } sindexload1; > + /** > + * Result for SSO Index/Pointer Load(opcode == > IPL_FREE0/IPL_FREE1/IPL_FREE2) > + */ > + struct { > + u64 reserved_60_63 : 4; > + u64 qnum_head : 2; > + u64 qnum_tail : 2; > + u64 reserved_28_55 : 28; > + u64 queue_val : 1; > + u64 queue_one : 1; > + u64 reserved_24_25 : 2; > + u64 queue_head : 11; > + u64 reserved_11_12 : 2; > + u64 queue_tail : 11; > + } sindexload1_cn68xx; > + /** > + * Result For POW Index/Pointer Load (get_rmt == > 1/get_des_get_tail == 0) > + */ > + struct { > + u64 reserved_39_63 : 25; > + u64 rmt_is_head : 1; > + u64 rmt_val : 1; > + u64 rmt_one : 1; > + u64 rmt_head : 36; > + } sindexload2; > + /** > + * Result For POW Index/Pointer Load (get_rmt == > 1/get_des_get_tail == 1) > + */ > + struct { > + u64 reserved_39_63 : 25; > + u64 rmt_is_head : 1; > + u64 rmt_val : 1; > + u64 rmt_one : 1; > + u64 rmt_tail : 36; > + } sindexload3; > + /** > + * Response to NULL_RD request loads > + */ > + struct { > + u64 unused : 62; > + u64 state : 2; > + } s_null_rd; > + > +} cvmx_pow_tag_load_resp_t; > + > +typedef union { > + u64 u64; > + struct { > + u64 reserved_57_63 : 7; > + u64 index : 11; > + u64 reserved_45 : 1; > + u64 grp : 6; > + u64 head : 1; > + u64 tail : 1; > + u64 reserved_34_36 : 3; > + u64 tag_type : 2; > + u64 tag : 32; > + } s; > +} cvmx_pow_sl_tag_resp_t; > + > +/** > + * This structure describes the address used for stores to the POW. > + * The store address is meaningful on stores to the POW. The > hardware assumes that an aligned > + * 64-bit store was used for all these stores. > + * Note the assumption that the work queue entry is aligned on an > 8-byte > + * boundary (since the low-order 3 address bits must be zero). > + * Note that not all fields are used by all operations. > + * > + * NOTE: The following is the behavior of the pending switch bit at > the PP > + * for POW stores (i.e. when did<7:3> == 0xc) > + * - did<2:0> == 0 => pending switch bit is set > + * - did<2:0> == 1 => no affect on the pending switch bit > + * - did<2:0> == 3 => pending switch bit is cleared > + * - did<2:0> == 7 => no affect on the pending switch bit > + * - did<2:0> == others => must not be used > + * - No other loads/stores have an affect on the pending switch > bit > + * - The switch bus from POW can clear the pending switch bit > + * > + * NOTE: did<2:0> == 2 is used by the HW for a special single-cycle > ADDWQ command > + * that only contains the pointer). SW must never use did<2:0> == > 2. > + */ > +typedef union { > + u64 u64; > + struct { > + u64 mem_reg : 2; > + u64 reserved_49_61 : 13; > + u64 is_io : 1; > + u64 did : 8; > + u64 addr : 40; > + } stag; > +} cvmx_pow_tag_store_addr_t; /* FIXME- this type is unused */ > + > +/** > + * Decode of the store data when an IOBDMA SENDSINGLE is sent to POW > + */ > +typedef union { > + u64 u64; > + struct { > + u64 scraddr : 8; > + u64 len : 8; > + u64 did : 8; > + u64 unused : 36; > + u64 wait : 1; > + u64 unused2 : 3; > + } s; > + struct { > + u64 scraddr : 8; > + u64 len : 8; > + u64 did : 8; > + u64 node : 4; > + u64 unused1 : 4; > + u64 indexed : 1; > + u64 grouped : 1; > + u64 rtngrp : 1; > + u64 unused2 : 13; > + u64 index_grp_mask : 12; > + u64 wait : 1; > + u64 unused3 : 3; > + } s_cn78xx; > +} cvmx_pow_iobdma_store_t; > + > +/* CSR typedefs have been moved to cvmx-pow-defs.h */ > + > +/*enum for group priority parameters which needs modification*/ > +enum cvmx_sso_group_modify_mask { > + CVMX_SSO_MODIFY_GROUP_PRIORITY = 0x01, > + CVMX_SSO_MODIFY_GROUP_WEIGHT = 0x02, > + CVMX_SSO_MODIFY_GROUP_AFFINITY = 0x04 > +}; > + > +/** > + * @INTERNAL > + * Return the number of SSO groups for a given SoC model > + */ > +static inline unsigned int cvmx_sso_num_xgrp(void) > +{ > + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) > + return 256; > + if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) > + return 64; > + if (OCTEON_IS_MODEL(OCTEON_CN73XX)) > + return 64; > + printf("ERROR: %s: Unknown model\n", __func__); > + return 0; > +} > + > +/** > + * @INTERNAL > + * Return the number of POW groups on current model. > + * In case of CN78XX/CN73XX this is the number of equivalent > + * "legacy groups" on the chip when it is used in backward > + * compatible mode. > + */ > +static inline unsigned int cvmx_pow_num_groups(void) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) > + return cvmx_sso_num_xgrp() >> 3; > + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) > + return 64; > + else > + return 16; > +} > + > +/** > + * @INTERNAL > + * Return the number of mask-set registers. > + */ > +static inline unsigned int cvmx_sso_num_maskset(void) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) > + return 2; > + else > + return 1; > +} > + > +/** > + * Get the POW tag for this core. This returns the current > + * tag type, tag, group, and POW entry index associated with > + * this core. Index is only valid if the tag type isn't NULL_NULL. > + * If a tag switch is pending this routine returns the tag before > + * the tag switch, not after. > + * > + * @return Current tag > + */ > +static inline cvmx_pow_tag_info_t cvmx_pow_get_current_tag(void) > +{ > + cvmx_pow_load_addr_t load_addr; > + cvmx_pow_tag_info_t result; > + > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_sso_sl_ppx_tag_t sl_ppx_tag; > + cvmx_xgrp_t xgrp; > + int node, core; > + > + CVMX_SYNCS; > + node = cvmx_get_node_num(); > + core = cvmx_get_local_core_num(); > + sl_ppx_tag.u64 = csr_rd_node(node, > CVMX_SSO_SL_PPX_TAG(core)); > + result.index = sl_ppx_tag.s.index; > + result.tag_type = sl_ppx_tag.s.tt; > + result.tag = sl_ppx_tag.s.tag; > + > + /* Get native XGRP value */ > + xgrp.xgrp = sl_ppx_tag.s.grp; > + > + /* Return legacy style group 0..15 */ > + result.grp = xgrp.group; > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + cvmx_pow_sl_tag_resp_t load_resp; > + > + load_addr.u64 = 0; > + load_addr.sstatus_cn68xx.mem_region = CVMX_IO_SEG; > + load_addr.sstatus_cn68xx.is_io = 1; > + load_addr.sstatus_cn68xx.did = CVMX_OCT_DID_TAG_TAG5; > + load_addr.sstatus_cn68xx.coreid = cvmx_get_core_num(); > + load_addr.sstatus_cn68xx.opcode = 3; > + load_resp.u64 = csr_rd(load_addr.u64); > + result.grp = load_resp.s.grp; > + result.index = load_resp.s.index; > + result.tag_type = load_resp.s.tag_type; > + result.tag = load_resp.s.tag; > + } else { > + cvmx_pow_tag_load_resp_t load_resp; > + > + load_addr.u64 = 0; > + load_addr.sstatus.mem_region = CVMX_IO_SEG; > + load_addr.sstatus.is_io = 1; > + load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1; > + load_addr.sstatus.coreid = cvmx_get_core_num(); > + load_addr.sstatus.get_cur = 1; > + load_resp.u64 = csr_rd(load_addr.u64); > + result.grp = load_resp.s_sstatus2.grp; > + result.index = load_resp.s_sstatus2.index; > + result.tag_type = load_resp.s_sstatus2.tag_type; > + result.tag = load_resp.s_sstatus2.tag; > + } > + return result; > +} > + > +/** > + * Get the POW WQE for this core. This returns the work queue > + * entry currently associated with this core. > + * > + * @return WQE pointer > + */ > +static inline cvmx_wqe_t *cvmx_pow_get_current_wqp(void) > +{ > + cvmx_pow_load_addr_t load_addr; > + cvmx_pow_tag_load_resp_t load_resp; > + > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_sso_sl_ppx_wqp_t sso_wqp; > + int node = cvmx_get_node_num(); > + int core = cvmx_get_local_core_num(); > + > + sso_wqp.u64 = csr_rd_node(node, > CVMX_SSO_SL_PPX_WQP(core)); > + if (sso_wqp.s.wqp) > + return (cvmx_wqe_t > *)cvmx_phys_to_ptr(sso_wqp.s.wqp); > + return (cvmx_wqe_t *)0; > + } > + if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + load_addr.u64 = 0; > + load_addr.sstatus_cn68xx.mem_region = CVMX_IO_SEG; > + load_addr.sstatus_cn68xx.is_io = 1; > + load_addr.sstatus_cn68xx.did = CVMX_OCT_DID_TAG_TAG5; > + load_addr.sstatus_cn68xx.coreid = cvmx_get_core_num(); > + load_addr.sstatus_cn68xx.opcode = 4; > + load_resp.u64 = csr_rd(load_addr.u64); > + if (load_resp.s_sstatus3_cn68xx.wqp) > + return (cvmx_wqe_t > *)cvmx_phys_to_ptr(load_resp.s_sstatus3_cn68xx.wqp); > + else > + return (cvmx_wqe_t *)0; > + } else { > + load_addr.u64 = 0; > + load_addr.sstatus.mem_region = CVMX_IO_SEG; > + load_addr.sstatus.is_io = 1; > + load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1; > + load_addr.sstatus.coreid = cvmx_get_core_num(); > + load_addr.sstatus.get_cur = 1; > + load_addr.sstatus.get_wqp = 1; > + load_resp.u64 = csr_rd(load_addr.u64); > + return (cvmx_wqe_t > *)cvmx_phys_to_ptr(load_resp.s_sstatus4.wqp); > + } > +} > + > +/** > + * @INTERNAL > + * Print a warning if a tag switch is pending for this core > + * > + * @param function Function name checking for a pending tag switch > + */ > +static inline void __cvmx_pow_warn_if_pending_switch(const char > *function) > +{ > + u64 switch_complete; > + > + CVMX_MF_CHORD(switch_complete); > + cvmx_warn_if(!switch_complete, "%s called with tag switch in > progress\n", function); > +} > + > +/** > + * Waits for a tag switch to complete by polling the completion bit. > + * Note that switches to NULL complete immediately and do not need > + * to be waited for. > + */ > +static inline void cvmx_pow_tag_sw_wait(void) > +{ > + const u64 TIMEOUT_MS = 10; /* 10ms timeout */ > + u64 switch_complete; > + u64 start_cycle; > + > + if (CVMX_ENABLE_POW_CHECKS) > + start_cycle = get_timer(0); > + > + while (1) { > + CVMX_MF_CHORD(switch_complete); > + if (cvmx_likely(switch_complete)) > + break; > + > + if (CVMX_ENABLE_POW_CHECKS) { > + if (cvmx_unlikely(get_timer(start_cycle) > > TIMEOUT_MS)) { > + debug("WARNING: %s: Tag switch is > taking a long time, possible deadlock\n", > + __func__); > + } > + } > + } > +} > + > +/** > + * Synchronous work request. Requests work from the POW. > + * This function does NOT wait for previous tag switches to > complete, > + * so the caller must ensure that there is not a pending tag switch. > + * > + * @param wait When set, call stalls until work becomes available, > or > + * times out. If not set, returns immediately. > + * > + * @return Returns the WQE pointer from POW. Returns NULL if no work > was > + * available. > + */ > +static inline cvmx_wqe_t > *cvmx_pow_work_request_sync_nocheck(cvmx_pow_wait_t wait) > +{ > + cvmx_pow_load_addr_t ptr; > + cvmx_pow_tag_load_resp_t result; > + > + if (CVMX_ENABLE_POW_CHECKS) > + __cvmx_pow_warn_if_pending_switch(__func__); > + > + ptr.u64 = 0; > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + ptr.swork_78xx.node = cvmx_get_node_num(); > + ptr.swork_78xx.mem_region = CVMX_IO_SEG; > + ptr.swork_78xx.is_io = 1; > + ptr.swork_78xx.did = CVMX_OCT_DID_TAG_SWTAG; > + ptr.swork_78xx.wait = wait; > + } else { > + ptr.swork.mem_region = CVMX_IO_SEG; > + ptr.swork.is_io = 1; > + ptr.swork.did = CVMX_OCT_DID_TAG_SWTAG; > + ptr.swork.wait = wait; > + } > + > + result.u64 = csr_rd(ptr.u64); > + if (result.s_work.no_work) > + return NULL; > + else > + return (cvmx_wqe_t > *)cvmx_phys_to_ptr(result.s_work.addr); > +} > + > +/** > + * Synchronous work request. Requests work from the POW. > + * This function waits for any previous tag switch to complete > before > + * requesting the new work. > + * > + * @param wait When set, call stalls until work becomes available, > or > + * times out. If not set, returns immediately. > + * > + * @return Returns the WQE pointer from POW. Returns NULL if no work > was > + * available. > + */ > +static inline cvmx_wqe_t *cvmx_pow_work_request_sync(cvmx_pow_wait_t > wait) > +{ > + /* Must not have a switch pending when requesting work */ > + cvmx_pow_tag_sw_wait(); > + return (cvmx_pow_work_request_sync_nocheck(wait)); > +} > + > +/** > + * Synchronous null_rd request. Requests a switch out of NULL_NULL > POW state. > + * This function waits for any previous tag switch to complete > before > + * requesting the null_rd. > + * > + * @return Returns the POW state of type cvmx_pow_tag_type_t. > + */ > +static inline cvmx_pow_tag_type_t > cvmx_pow_work_request_null_rd(void) > +{ > + cvmx_pow_load_addr_t ptr; > + cvmx_pow_tag_load_resp_t result; > + > + /* Must not have a switch pending when requesting work */ > + cvmx_pow_tag_sw_wait(); > + > + ptr.u64 = 0; > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + ptr.swork_78xx.mem_region = CVMX_IO_SEG; > + ptr.swork_78xx.is_io = 1; > + ptr.swork_78xx.did = CVMX_OCT_DID_TAG_NULL_RD; > + ptr.swork_78xx.node = cvmx_get_node_num(); > + } else { > + ptr.snull_rd.mem_region = CVMX_IO_SEG; > + ptr.snull_rd.is_io = 1; > + ptr.snull_rd.did = CVMX_OCT_DID_TAG_NULL_RD; > + } > + result.u64 = csr_rd(ptr.u64); > + return (cvmx_pow_tag_type_t)result.s_null_rd.state; > +} > + > +/** > + * Asynchronous work request. > + * Work is requested from the POW unit, and should later be checked > with > + * function cvmx_pow_work_response_async. > + * This function does NOT wait for previous tag switches to > complete, > + * so the caller must ensure that there is not a pending tag switch. > + * > + * @param scr_addr Scratch memory address that response will be > returned to, > + * which is either a valid WQE, or a response with the invalid > bit set. > + * Byte address, must be 8 byte aligned. > + * @param wait 1 to cause response to wait for work to become > available > + * (or timeout) > + * 0 to cause response to return immediately > + */ > +static inline void cvmx_pow_work_request_async_nocheck(int scr_addr, > cvmx_pow_wait_t wait) > +{ > + cvmx_pow_iobdma_store_t data; > + > + if (CVMX_ENABLE_POW_CHECKS) > + __cvmx_pow_warn_if_pending_switch(__func__); > + > + /* scr_addr must be 8 byte aligned */ > + data.u64 = 0; > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + data.s_cn78xx.node = cvmx_get_node_num(); > + data.s_cn78xx.scraddr = scr_addr >> 3; > + data.s_cn78xx.len = 1; > + data.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; > + data.s_cn78xx.wait = wait; > + } else { > + data.s.scraddr = scr_addr >> 3; > + data.s.len = 1; > + data.s.did = CVMX_OCT_DID_TAG_SWTAG; > + data.s.wait = wait; > + } > + cvmx_send_single(data.u64); > +} > + > +/** > + * Asynchronous work request. > + * Work is requested from the POW unit, and should later be checked > with > + * function cvmx_pow_work_response_async. > + * This function waits for any previous tag switch to complete > before > + * requesting the new work. > + * > + * @param scr_addr Scratch memory address that response will be > returned to, > + * which is either a valid WQE, or a response with the invalid > bit set. > + * Byte address, must be 8 byte aligned. > + * @param wait 1 to cause response to wait for work to become > available > + * (or timeout) > + * 0 to cause response to return immediately > + */ > +static inline void cvmx_pow_work_request_async(int scr_addr, > cvmx_pow_wait_t wait) > +{ > + /* Must not have a switch pending when requesting work */ > + cvmx_pow_tag_sw_wait(); > + cvmx_pow_work_request_async_nocheck(scr_addr, wait); > +} > + > +/** > + * Gets result of asynchronous work request. Performs a IOBDMA sync > + * to wait for the response. > + * > + * @param scr_addr Scratch memory address to get result from > + * Byte address, must be 8 byte aligned. > + * @return Returns the WQE from the scratch register, or NULL if no > work was > + * available. > + */ > +static inline cvmx_wqe_t *cvmx_pow_work_response_async(int scr_addr) > +{ > + cvmx_pow_tag_load_resp_t result; > + > + CVMX_SYNCIOBDMA; > + result.u64 = cvmx_scratch_read64(scr_addr); > + if (result.s_work.no_work) > + return NULL; > + else > + return (cvmx_wqe_t > *)cvmx_phys_to_ptr(result.s_work.addr); > +} > + > +/** > + * Checks if a work queue entry pointer returned by a work > + * request is valid. It may be invalid due to no work > + * being available or due to a timeout. > + * > + * @param wqe_ptr pointer to a work queue entry returned by the POW > + * > + * @return 0 if pointer is valid > + * 1 if invalid (no work was returned) > + */ > +static inline u64 cvmx_pow_work_invalid(cvmx_wqe_t *wqe_ptr) > +{ > + return (!wqe_ptr); /* FIXME: improve */ > +} > + > +/** > + * Starts a tag switch to the provided tag value and tag > type. Completion for > + * the tag switch must be checked for separately. > + * This function does NOT update the > + * work queue entry in dram to match tag value and type, so the > application must > + * keep track of these if they are important to the application. > + * This tag switch command must not be used for switches to NULL, as > the tag > + * switch pending bit will be set by the switch request, but never > cleared by > + * the hardware. > + * > + * NOTE: This should not be used when switching from a NULL > tag. Use > + * cvmx_pow_tag_sw_full() instead. > + * > + * This function does no checks, so the caller must ensure that any > previous tag > + * switch has completed. > + * > + * @param tag new tag value > + * @param tag_type new tag type (ordered or atomic) > + */ > +static inline void cvmx_pow_tag_sw_nocheck(u32 tag, > cvmx_pow_tag_type_t tag_type) > +{ > + union cvmx_pow_tag_req_addr ptr; > + cvmx_pow_tag_req_t tag_req; > + > + if (CVMX_ENABLE_POW_CHECKS) { > + cvmx_pow_tag_info_t current_tag; > + > + __cvmx_pow_warn_if_pending_switch(__func__); > + current_tag = cvmx_pow_get_current_tag(); > + cvmx_warn_if(current_tag.tag_type == > CVMX_POW_TAG_TYPE_NULL_NULL, > + "%s called with NULL_NULL tag\n", > __func__); > + cvmx_warn_if(current_tag.tag_type == > CVMX_POW_TAG_TYPE_NULL, > + "%s called with NULL tag\n", __func__); > + cvmx_warn_if((current_tag.tag_type == tag_type) && > (current_tag.tag == tag), > + "%s called to perform a tag switch to the > same tag\n", __func__); > + cvmx_warn_if( > + tag_type == CVMX_POW_TAG_TYPE_NULL, > + "%s called to perform a tag switch to NULL. Use > cvmx_pow_tag_sw_null() instead\n", > + __func__); > + } > + > + /* > + * Note that WQE in DRAM is not updated here, as the POW does > not read > + * from DRAM once the WQE is in flight. See hardware manual > for > + * complete details. > + * It is the application's responsibility to keep track of the > + * current tag value if that is important. > + */ > + tag_req.u64 = 0; > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG; > + tag_req.s_cn78xx_other.type = tag_type; > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + tag_req.s_cn68xx_other.op = CVMX_POW_TAG_OP_SWTAG; > + tag_req.s_cn68xx_other.tag = tag; > + tag_req.s_cn68xx_other.type = tag_type; > + } else { > + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_SWTAG; > + tag_req.s_cn38xx.tag = tag; > + tag_req.s_cn38xx.type = tag_type; > + } > + ptr.u64 = 0; > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; > + ptr.s_cn78xx.is_io = 1; > + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; > + ptr.s_cn78xx.node = cvmx_get_node_num(); > + ptr.s_cn78xx.tag = tag; > + } else { > + ptr.s.mem_region = CVMX_IO_SEG; > + ptr.s.is_io = 1; > + ptr.s.did = CVMX_OCT_DID_TAG_SWTAG; > + } > + /* Once this store arrives at POW, it will attempt the switch > + software must wait for the switch to complete separately */ > + cvmx_write_io(ptr.u64, tag_req.u64); > +} > + > +/** > + * Starts a tag switch to the provided tag value and tag > type. Completion for > + * the tag switch must be checked for separately. > + * This function does NOT update the > + * work queue entry in dram to match tag value and type, so the > application must > + * keep track of these if they are important to the application. > + * This tag switch command must not be used for switches to NULL, as > the tag > + * switch pending bit will be set by the switch request, but never > cleared by > + * the hardware. > + * > + * NOTE: This should not be used when switching from a NULL > tag. Use > + * cvmx_pow_tag_sw_full() instead. > + * > + * This function waits for any previous tag switch to complete, and > also > + * displays an error on tag switches to NULL. > + * > + * @param tag new tag value > + * @param tag_type new tag type (ordered or atomic) > + */ > +static inline void cvmx_pow_tag_sw(u32 tag, cvmx_pow_tag_type_t > tag_type) > +{ > + /* > + * Note that WQE in DRAM is not updated here, as the POW does > not read > + * from DRAM once the WQE is in flight. See hardware manual > for > + * complete details. It is the application's responsibility to > keep > + * track of the current tag value if that is important. > + */ > + > + /* > + * Ensure that there is not a pending tag switch, as a tag > switch > + * cannot be started if a previous switch is still pending. > + */ > + cvmx_pow_tag_sw_wait(); > + cvmx_pow_tag_sw_nocheck(tag, tag_type); > +} > + > +/** > + * Starts a tag switch to the provided tag value and tag > type. Completion for > + * the tag switch must be checked for separately. > + * This function does NOT update the > + * work queue entry in dram to match tag value and type, so the > application must > + * keep track of these if they are important to the application. > + * This tag switch command must not be used for switches to NULL, as > the tag > + * switch pending bit will be set by the switch request, but never > cleared by > + * the hardware. > + * > + * This function must be used for tag switches from NULL. > + * > + * This function does no checks, so the caller must ensure that any > previous tag > + * switch has completed. > + * > + * @param wqp pointer to work queue entry to submit. This > entry is > + * updated to match the other parameters > + * @param tag tag value to be assigned to work queue entry > + * @param tag_type type of tag > + * @param group group value for the work queue entry. > + */ > +static inline void cvmx_pow_tag_sw_full_nocheck(cvmx_wqe_t *wqp, u32 > tag, > + cvmx_pow_tag_type_t > tag_type, u64 group) > +{ > + union cvmx_pow_tag_req_addr ptr; > + cvmx_pow_tag_req_t tag_req; > + unsigned int node = cvmx_get_node_num(); > + u64 wqp_phys = cvmx_ptr_to_phys(wqp); > + > + if (CVMX_ENABLE_POW_CHECKS) { > + cvmx_pow_tag_info_t current_tag; > + > + __cvmx_pow_warn_if_pending_switch(__func__); > + current_tag = cvmx_pow_get_current_tag(); > + cvmx_warn_if(current_tag.tag_type == > CVMX_POW_TAG_TYPE_NULL_NULL, > + "%s called with NULL_NULL tag\n", > __func__); > + cvmx_warn_if((current_tag.tag_type == tag_type) && > (current_tag.tag == tag), > + "%s called to perform a tag switch to the > same tag\n", __func__); > + cvmx_warn_if( > + tag_type == CVMX_POW_TAG_TYPE_NULL, > + "%s called to perform a tag switch to NULL. Use > cvmx_pow_tag_sw_null() instead\n", > + __func__); > + if ((wqp != cvmx_phys_to_ptr(0x80)) && > cvmx_pow_get_current_wqp()) > + cvmx_warn_if(wqp != cvmx_pow_get_current_wqp(), > + "%s passed WQE(%p) doesn't match > the address in the POW(%p)\n", > + __func__, wqp, > cvmx_pow_get_current_wqp()); > + } > + > + /* > + * Note that WQE in DRAM is not updated here, as the POW does > not > + * read from DRAM once the WQE is in flight. See hardware > manual > + * for complete details. It is the application's responsibility > to > + * keep track of the current tag value if that is important. > + */ > + tag_req.u64 = 0; > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + unsigned int xgrp; > + > + if (wqp_phys != 0x80) { > + /* If WQE is valid, use its XGRP: > + * WQE GRP is 10 bits, and is mapped > + * to legacy GRP + QoS, includes node number. > + */ > + xgrp = wqp->word1.cn78xx.grp; > + /* Use XGRP[node] too */ > + node = xgrp >> 8; > + /* Modify XGRP with legacy group # from arg */ > + xgrp &= ~0xf8; > + xgrp |= 0xf8 & (group << 3); > + > + } else { > + /* If no WQE, build XGRP with QoS=0 and current > node */ > + xgrp = group << 3; > + xgrp |= node << 8; > + } > + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG_FULL; > + tag_req.s_cn78xx_other.type = tag_type; > + tag_req.s_cn78xx_other.grp = xgrp; > + tag_req.s_cn78xx_other.wqp = wqp_phys; > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + tag_req.s_cn68xx_other.op = CVMX_POW_TAG_OP_SWTAG_FULL; > + tag_req.s_cn68xx_other.tag = tag; > + tag_req.s_cn68xx_other.type = tag_type; > + tag_req.s_cn68xx_other.grp = group; > + } else { > + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_SWTAG_FULL; > + tag_req.s_cn38xx.tag = tag; > + tag_req.s_cn38xx.type = tag_type; > + tag_req.s_cn38xx.grp = group; > + } > + ptr.u64 = 0; > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; > + ptr.s_cn78xx.is_io = 1; > + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; > + ptr.s_cn78xx.node = node; > + ptr.s_cn78xx.tag = tag; > + } else { > + ptr.s.mem_region = CVMX_IO_SEG; > + ptr.s.is_io = 1; > + ptr.s.did = CVMX_OCT_DID_TAG_SWTAG; > + ptr.s.addr = wqp_phys; > + } > + /* Once this store arrives at POW, it will attempt the switch > + software must wait for the switch to complete separately */ > + cvmx_write_io(ptr.u64, tag_req.u64); > +} > + > +/** > + * Starts a tag switch to the provided tag value and tag type. > + * Completion for the tag switch must be checked for separately. > + * This function does NOT update the work queue entry in dram to > match tag value > + * and type, so the application must keep track of these if they are > important > + * to the application. This tag switch command must not be used for > switches > + * to NULL, as the tag switch pending bit will be set by the switch > request, > + * but never cleared by the hardware. > + * > + * This function must be used for tag switches from NULL. > + * > + * This function waits for any pending tag switches to complete > + * before requesting the tag switch. > + * > + * @param wqp Pointer to work queue entry to submit. > + * This entry is updated to match the other parameters > + * @param tag Tag value to be assigned to work queue entry > + * @param tag_type Type of tag > + * @param group Group value for the work queue entry. > + */ > +static inline void cvmx_pow_tag_sw_full(cvmx_wqe_t *wqp, u32 tag, > cvmx_pow_tag_type_t tag_type, > + u64 group) > +{ > + /* > + * Ensure that there is not a pending tag switch, as a tag > switch cannot > + * be started if a previous switch is still pending. > + */ > + cvmx_pow_tag_sw_wait(); > + cvmx_pow_tag_sw_full_nocheck(wqp, tag, tag_type, group); > +} > + > +/** > + * Switch to a NULL tag, which ends any ordering or > + * synchronization provided by the POW for the current > + * work queue entry. This operation completes immediately, > + * so completion should not be waited for. > + * This function does NOT wait for previous tag switches to > complete, > + * so the caller must ensure that any previous tag switches have > completed. > + */ > +static inline void cvmx_pow_tag_sw_null_nocheck(void) > +{ > + union cvmx_pow_tag_req_addr ptr; > + cvmx_pow_tag_req_t tag_req; > + > + if (CVMX_ENABLE_POW_CHECKS) { > + cvmx_pow_tag_info_t current_tag; > + > + __cvmx_pow_warn_if_pending_switch(__func__); > + current_tag = cvmx_pow_get_current_tag(); > + cvmx_warn_if(current_tag.tag_type == > CVMX_POW_TAG_TYPE_NULL_NULL, > + "%s called with NULL_NULL tag\n", > __func__); > + cvmx_warn_if(current_tag.tag_type == > CVMX_POW_TAG_TYPE_NULL, > + "%s called when we already have a NULL > tag\n", __func__); > + } > + tag_req.u64 = 0; > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG; > + tag_req.s_cn78xx_other.type = CVMX_POW_TAG_TYPE_NULL; > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + tag_req.s_cn68xx_other.op = CVMX_POW_TAG_OP_SWTAG; > + tag_req.s_cn68xx_other.type = CVMX_POW_TAG_TYPE_NULL; > + } else { > + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_SWTAG; > + tag_req.s_cn38xx.type = CVMX_POW_TAG_TYPE_NULL; > + } > + ptr.u64 = 0; > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; > + ptr.s_cn78xx.is_io = 1; > + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_TAG1; > + ptr.s_cn78xx.node = cvmx_get_node_num(); > + } else { > + ptr.s.mem_region = CVMX_IO_SEG; > + ptr.s.is_io = 1; > + ptr.s.did = CVMX_OCT_DID_TAG_TAG1; > + } > + cvmx_write_io(ptr.u64, tag_req.u64); > +} > + > +/** > + * Switch to a NULL tag, which ends any ordering or > + * synchronization provided by the POW for the current > + * work queue entry. This operation completes immediately, > + * so completion should not be waited for. > + * This function waits for any pending tag switches to complete > + * before requesting the switch to NULL. > + */ > +static inline void cvmx_pow_tag_sw_null(void) > +{ > + /* > + * Ensure that there is not a pending tag switch, as a tag > switch cannot > + * be started if a previous switch is still pending. > + */ > + cvmx_pow_tag_sw_wait(); > + cvmx_pow_tag_sw_null_nocheck(); > +} > + > +/** > + * Submits work to an input queue. > + * This function updates the work queue entry in DRAM to match the > arguments given. > + * Note that the tag provided is for the work queue entry submitted, > and > + * is unrelated to the tag that the core currently holds. > + * > + * @param wqp pointer to work queue entry to submit. > + * This entry is updated to match the other > parameters > + * @param tag tag value to be assigned to work queue entry > + * @param tag_type type of tag > + * @param qos Input queue to add to. > + * @param grp group value for the work queue entry. > + */ > +static inline void cvmx_pow_work_submit(cvmx_wqe_t *wqp, u32 tag, > cvmx_pow_tag_type_t tag_type, > + u64 qos, u64 grp) > +{ > + union cvmx_pow_tag_req_addr ptr; > + cvmx_pow_tag_req_t tag_req; > + > + tag_req.u64 = 0; > + ptr.u64 = 0; > + > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + unsigned int node = cvmx_get_node_num(); > + unsigned int xgrp; > + > + xgrp = (grp & 0x1f) << 3; > + xgrp |= (qos & 7); > + xgrp |= 0x300 & (node << 8); > + > + wqp->word1.cn78xx.rsvd_0 = 0; > + wqp->word1.cn78xx.rsvd_1 = 0; > + wqp->word1.cn78xx.tag = tag; > + wqp->word1.cn78xx.tag_type = tag_type; > + wqp->word1.cn78xx.grp = xgrp; > + CVMX_SYNCWS; > + > + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_ADDWQ; > + tag_req.s_cn78xx_other.type = tag_type; > + tag_req.s_cn78xx_other.wqp = cvmx_ptr_to_phys(wqp); > + tag_req.s_cn78xx_other.grp = xgrp; > + > + ptr.s_cn78xx.did = 0x66; // CVMX_OCT_DID_TAG_TAG6; > + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; > + ptr.s_cn78xx.is_io = 1; > + ptr.s_cn78xx.node = node; > + ptr.s_cn78xx.tag = tag; > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + /* Reset all reserved bits */ > + wqp->word1.cn68xx.zero_0 = 0; > + wqp->word1.cn68xx.zero_1 = 0; > + wqp->word1.cn68xx.zero_2 = 0; > + wqp->word1.cn68xx.qos = qos; > + wqp->word1.cn68xx.grp = grp; > + > + wqp->word1.tag = tag; > + wqp->word1.tag_type = tag_type; > + > + tag_req.s_cn68xx_add.op = CVMX_POW_TAG_OP_ADDWQ; > + tag_req.s_cn68xx_add.type = tag_type; > + tag_req.s_cn68xx_add.tag = tag; > + tag_req.s_cn68xx_add.qos = qos; > + tag_req.s_cn68xx_add.grp = grp; > + > + ptr.s.mem_region = CVMX_IO_SEG; > + ptr.s.is_io = 1; > + ptr.s.did = CVMX_OCT_DID_TAG_TAG1; > + ptr.s.addr = cvmx_ptr_to_phys(wqp); > + } else { > + /* Reset all reserved bits */ > + wqp->word1.cn38xx.zero_2 = 0; > + wqp->word1.cn38xx.qos = qos; > + wqp->word1.cn38xx.grp = grp; > + > + wqp->word1.tag = tag; > + wqp->word1.tag_type = tag_type; > + > + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_ADDWQ; > + tag_req.s_cn38xx.type = tag_type; > + tag_req.s_cn38xx.tag = tag; > + tag_req.s_cn38xx.qos = qos; > + tag_req.s_cn38xx.grp = grp; > + > + ptr.s.mem_region = CVMX_IO_SEG; > + ptr.s.is_io = 1; > + ptr.s.did = CVMX_OCT_DID_TAG_TAG1; > + ptr.s.addr = cvmx_ptr_to_phys(wqp); > + } > + /* SYNC write to memory before the work submit. > + * This is necessary as POW may read values from DRAM at this > time */ > + CVMX_SYNCWS; > + cvmx_write_io(ptr.u64, tag_req.u64); > +} > + > +/** > + * This function sets the group mask for a core. The group mask > + * indicates which groups each core will accept work from. There are > + * 16 groups. > + * > + * @param core_num core to apply mask to > + * @param mask Group mask, one bit for up to 64 groups. > + * Each 1 bit in the mask enables the core to accept > work from > + * the corresponding group. > + * The CN68XX supports 64 groups, earlier models only > support > + * 16 groups. > + * > + * The CN78XX in backwards compatibility mode allows up to 32 > groups, > + * so the 'mask' argument has one bit for every of the legacy > + * groups, and a '1' in the mask causes a total of 8 groups > + * which share the legacy group numbher and 8 qos levels, > + * to be enabled for the calling processor core. > + * A '0' in the mask will disable the current core > + * from receiving work from the associated group. > + */ > +static inline void cvmx_pow_set_group_mask(u64 core_num, u64 mask) > +{ > + u64 valid_mask; > + int num_groups = cvmx_pow_num_groups(); > + > + if (num_groups >= 64) > + valid_mask = ~0ull; > + else > + valid_mask = (1ull << num_groups) - 1; > + > + if ((mask & valid_mask) == 0) { > + printf("ERROR: %s empty group mask disables work on > core# %llu, ignored.\n", > + __func__, (unsigned long long)core_num); > + return; > + } > + cvmx_warn_if(mask & (~valid_mask), "%s group number range > exceeded: %#llx\n", __func__, > + (unsigned long long)mask); > + > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + unsigned int mask_set; > + cvmx_sso_ppx_sx_grpmskx_t grp_msk; > + unsigned int core, node; > + unsigned int rix; /* Register index */ > + unsigned int grp; /* Legacy group # */ > + unsigned int bit; /* bit index */ > + unsigned int xgrp; /* native group # */ > + > + node = cvmx_coremask_core_to_node(core_num); > + core = cvmx_coremask_core_on_node(core_num); > + > + /* 78xx: 256 groups divided into 4 X 64 bit registers > */ > + /* 73xx: 64 groups are in one register */ > + for (rix = 0; rix < (cvmx_sso_num_xgrp() >> 6); rix++) > { > + grp_msk.u64 = 0; > + for (bit = 0; bit < 64; bit++) { > + /* 8-bit native XGRP number */ > + xgrp = (rix << 6) | bit; > + /* Legacy 5-bit group number */ > + grp = (xgrp >> 3) & 0x1f; > + /* Inspect legacy mask by legacy group > */ > + if (mask & (1ull << grp)) > + grp_msk.s.grp_msk |= 1ull << > bit; > + /* Pre-set to all 0's */ > + } > + for (mask_set = 0; mask_set < > cvmx_sso_num_maskset(); mask_set++) { > + csr_wr_node(node, > CVMX_SSO_PPX_SX_GRPMSKX(core, mask_set, rix), > + grp_msk.u64); > + } > + } > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + cvmx_sso_ppx_grp_msk_t grp_msk; > + > + grp_msk.s.grp_msk = mask; > + csr_wr(CVMX_SSO_PPX_GRP_MSK(core_num), grp_msk.u64); > + } else { > + cvmx_pow_pp_grp_mskx_t grp_msk; > + > + grp_msk.u64 = csr_rd(CVMX_POW_PP_GRP_MSKX(core_num)); > + grp_msk.s.grp_msk = mask & 0xffff; > + csr_wr(CVMX_POW_PP_GRP_MSKX(core_num), grp_msk.u64); > + } > +} > + > +/** > + * This function gets the group mask for a core. The group mask > + * indicates which groups each core will accept work from. > + * > + * @param core_num core to apply mask to > + * @return Group mask, one bit for up to 64 groups. > + * Each 1 bit in the mask enables the core to accept > work from > + * the corresponding group. > + * The CN68XX supports 64 groups, earlier models only > support > + * 16 groups. > + * > + * The CN78XX in backwards compatibility mode allows up to 32 > groups, > + * so the 'mask' argument has one bit for every of the legacy > + * groups, and a '1' in the mask causes a total of 8 groups > + * which share the legacy group numbher and 8 qos levels, > + * to be enabled for the calling processor core. > + * A '0' in the mask will disable the current core > + * from receiving work from the associated group. > + */ > +static inline u64 cvmx_pow_get_group_mask(u64 core_num) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_sso_ppx_sx_grpmskx_t grp_msk; > + unsigned int core, node, i; > + int rix; /* Register index */ > + u64 mask = 0; > + > + node = cvmx_coremask_core_to_node(core_num); > + core = cvmx_coremask_core_on_node(core_num); > + > + /* 78xx: 256 groups divided into 4 X 64 bit registers > */ > + /* 73xx: 64 groups are in one register */ > + for (rix = (cvmx_sso_num_xgrp() >> 6) - 1; rix >= 0; > rix--) { > + /* read only mask_set=0 (both 'set' was written > same) */ > + grp_msk.u64 = csr_rd_node(node, > CVMX_SSO_PPX_SX_GRPMSKX(core, 0, rix)); > + /* ASSUME: (this is how mask bits got written) > */ > + /* grp_mask[7:0]: all bits 0..7 are same */ > + /* grp_mask[15:8]: all bits 8..15 are same, etc > */ > + /* DO: mask[7:0] = > grp_mask.u64[56,48,40,32,24,16,8,0] */ > + for (i = 0; i < 8; i++) > + mask |= (grp_msk.u64 & ((u64)1 << (i * > 8))) >> (7 * i); > + /* we collected 8 MSBs in mask[7:0], <<=8 and > continue */ > + if (cvmx_likely(rix != 0)) > + mask <<= 8; > + } > + return mask & 0xFFFFFFFF; > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + cvmx_sso_ppx_grp_msk_t grp_msk; > + > + grp_msk.u64 = csr_rd(CVMX_SSO_PPX_GRP_MSK(core_num)); > + return grp_msk.u64; > + } else { > + cvmx_pow_pp_grp_mskx_t grp_msk; > + > + grp_msk.u64 = csr_rd(CVMX_POW_PP_GRP_MSKX(core_num)); > + return grp_msk.u64 & 0xffff; > + } > +} > + > +/* > + * Returns 0 if 78xx(73xx,75xx) is not programmed in legacy > compatible mode > + * Returns 1 if 78xx(73xx,75xx) is programmed in legacy compatible > mode > + * Returns 1 if octeon model is not 78xx(73xx,75xx) > + */ > +static inline u64 cvmx_pow_is_legacy78mode(u64 core_num) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_sso_ppx_sx_grpmskx_t grp_msk0, grp_msk1; > + unsigned int core, node, i; > + int rix; /* Register index */ > + u64 mask = 0; > + > + node = cvmx_coremask_core_to_node(core_num); > + core = cvmx_coremask_core_on_node(core_num); > + > + /* 78xx: 256 groups divided into 4 X 64 bit registers > */ > + /* 73xx: 64 groups are in one register */ > + /* 1) in order for the 78_SSO to be in legacy > compatible mode > + * the both mask_sets should be programmed the same */ > + for (rix = (cvmx_sso_num_xgrp() >> 6) - 1; rix >= 0; > rix--) { > + /* read mask_set=0 (both 'set' was written > same) */ > + grp_msk0.u64 = csr_rd_node(node, > CVMX_SSO_PPX_SX_GRPMSKX(core, 0, rix)); > + grp_msk1.u64 = csr_rd_node(node, > CVMX_SSO_PPX_SX_GRPMSKX(core, 1, rix)); > + if (grp_msk0.u64 != grp_msk1.u64) { > + return 0; > + } > + /* (this is how mask bits should be written) */ > + /* grp_mask[7:0]: all bits 0..7 are same */ > + /* grp_mask[15:8]: all bits 8..15 are same, etc > */ > + /* 2) in order for the 78_SSO to be in legacy > compatible > + * mode above should be true (test only > mask_set=0 */ > + for (i = 0; i < 8; i++) { > + mask = (grp_msk0.u64 >> (i << 3)) & > 0xFF; > + if (!(mask == 0 || mask == 0xFF)) { > + return 0; > + } > + } > + } > + /* if we come here, the 78_SSO is in legacy compatible > mode */ > + } > + return 1; /* the SSO/POW is in legacy (or compatible) mode */ > +} > + > +/** > + * This function sets POW static priorities for a core. Each input > queue has > + * an associated priority value. > + * > + * @param core_num core to apply priorities to > + * @param priority Vector of 8 priorities, one per POW Input Queue > (0-7). > + * Highest priority is 0 and lowest is 7. A > priority value > + * of 0xF instructs POW to skip the Input Queue > when > + * scheduling to this specific core. > + * NOTE: priorities should not have gaps in > values, meaning > + * {0,1,1,1,1,1,1,1} is a valid > configuration while > + * {0,2,2,2,2,2,2,2} is not. > + */ > +static inline void cvmx_pow_set_priority(u64 core_num, const u8 > priority[]) > +{ > + /* Detect gaps between priorities and flag error */ > + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + int i; > + u32 prio_mask = 0; > + > + for (i = 0; i < 8; i++) > + if (priority[i] != 0xF) > + prio_mask |= 1 << priority[i]; > + > + if (prio_mask ^ ((1 << cvmx_pop(prio_mask)) - 1)) { > + debug("ERROR: POW static priorities should be > contiguous (0x%llx)\n", > + (unsigned long long)prio_mask); > + return; > + } > + } > + > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + unsigned int group; > + unsigned int node = cvmx_get_node_num(); > + cvmx_sso_grpx_pri_t grp_pri; > + > + /*grp_pri.s.weight = 0x3f; these will be anyway > overwritten */ > + /*grp_pri.s.affinity = 0xf; by the next > csr_rd_node(..), */ > + > + for (group = 0; group < cvmx_sso_num_xgrp(); group++) { > + grp_pri.u64 = csr_rd_node(node, > CVMX_SSO_GRPX_PRI(group)); > + grp_pri.s.pri = priority[group & 0x7]; > + csr_wr_node(node, CVMX_SSO_GRPX_PRI(group), > grp_pri.u64); > + } > + > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + cvmx_sso_ppx_qos_pri_t qos_pri; > + > + qos_pri.u64 = csr_rd(CVMX_SSO_PPX_QOS_PRI(core_num)); > + qos_pri.s.qos0_pri = priority[0]; > + qos_pri.s.qos1_pri = priority[1]; > + qos_pri.s.qos2_pri = priority[2]; > + qos_pri.s.qos3_pri = priority[3]; > + qos_pri.s.qos4_pri = priority[4]; > + qos_pri.s.qos5_pri = priority[5]; > + qos_pri.s.qos6_pri = priority[6]; > + qos_pri.s.qos7_pri = priority[7]; > + csr_wr(CVMX_SSO_PPX_QOS_PRI(core_num), qos_pri.u64); > + } else { > + /* POW priorities on CN5xxx .. CN66XX */ > + cvmx_pow_pp_grp_mskx_t grp_msk; > + > + grp_msk.u64 = csr_rd(CVMX_POW_PP_GRP_MSKX(core_num)); > + grp_msk.s.qos0_pri = priority[0]; > + grp_msk.s.qos1_pri = priority[1]; > + grp_msk.s.qos2_pri = priority[2]; > + grp_msk.s.qos3_pri = priority[3]; > + grp_msk.s.qos4_pri = priority[4]; > + grp_msk.s.qos5_pri = priority[5]; > + grp_msk.s.qos6_pri = priority[6]; > + grp_msk.s.qos7_pri = priority[7]; > + > + csr_wr(CVMX_POW_PP_GRP_MSKX(core_num), grp_msk.u64); > + } > +} > + > +/** > + * This function gets POW static priorities for a core. Each input > queue has > + * an associated priority value. > + * > + * @param[in] core_num core to get priorities for > + * @param[out] priority Pointer to u8[] where to return priorities > + * Vector of 8 priorities, one per POW Input Queue > (0-7). > + * Highest priority is 0 and lowest is 7. A > priority value > + * of 0xF instructs POW to skip the Input Queue > when > + * scheduling to this specific core. > + * NOTE: priorities should not have gaps in > values, meaning > + * {0,1,1,1,1,1,1,1} is a valid > configuration while > + * {0,2,2,2,2,2,2,2} is not. > + */ > +static inline void cvmx_pow_get_priority(u64 core_num, u8 > priority[]) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + unsigned int group; > + unsigned int node = cvmx_get_node_num(); > + cvmx_sso_grpx_pri_t grp_pri; > + > + /* read priority only from the first 8 groups */ > + /* the next groups are programmed the same > (periodicaly) */ > + for (group = 0; group < 8 /*cvmx_sso_num_xgrp() */; > group++) { > + grp_pri.u64 = csr_rd_node(node, > CVMX_SSO_GRPX_PRI(group)); > + priority[group /* & 0x7 */] = grp_pri.s.pri; > + } > + > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + cvmx_sso_ppx_qos_pri_t qos_pri; > + > + qos_pri.u64 = csr_rd(CVMX_SSO_PPX_QOS_PRI(core_num)); > + priority[0] = qos_pri.s.qos0_pri; > + priority[1] = qos_pri.s.qos1_pri; > + priority[2] = qos_pri.s.qos2_pri; > + priority[3] = qos_pri.s.qos3_pri; > + priority[4] = qos_pri.s.qos4_pri; > + priority[5] = qos_pri.s.qos5_pri; > + priority[6] = qos_pri.s.qos6_pri; > + priority[7] = qos_pri.s.qos7_pri; > + } else { > + /* POW priorities on CN5xxx .. CN66XX */ > + cvmx_pow_pp_grp_mskx_t grp_msk; > + > + grp_msk.u64 = csr_rd(CVMX_POW_PP_GRP_MSKX(core_num)); > + priority[0] = grp_msk.s.qos0_pri; > + priority[1] = grp_msk.s.qos1_pri; > + priority[2] = grp_msk.s.qos2_pri; > + priority[3] = grp_msk.s.qos3_pri; > + priority[4] = grp_msk.s.qos4_pri; > + priority[5] = grp_msk.s.qos5_pri; > + priority[6] = grp_msk.s.qos6_pri; > + priority[7] = grp_msk.s.qos7_pri; > + } > + > + /* Detect gaps between priorities and flag error - (optional) > */ > + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + int i; > + u32 prio_mask = 0; > + > + for (i = 0; i < 8; i++) > + if (priority[i] != 0xF) > + prio_mask |= 1 << priority[i]; > + > + if (prio_mask ^ ((1 << cvmx_pop(prio_mask)) - 1)) { > + debug("ERROR:%s: POW static priorities should > be contiguous (0x%llx)\n", > + __func__, (unsigned long long)prio_mask); > + return; > + } > + } > +} > + > +static inline void cvmx_sso_get_group_priority(int node, cvmx_xgrp_t > xgrp, int *priority, > + int *weight, int > *affinity) > +{ > + cvmx_sso_grpx_pri_t grp_pri; > + > + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + debug("ERROR: %s is not supported on this chip)\n", > __func__); > + return; > + } > + > + grp_pri.u64 = csr_rd_node(node, CVMX_SSO_GRPX_PRI(xgrp.xgrp)); > + *affinity = grp_pri.s.affinity; > + *priority = grp_pri.s.pri; > + *weight = grp_pri.s.weight; > +} > + > +/** > + * Performs a tag switch and then an immediate deschedule. This > completes > + * immediately, so completion must not be waited for. This function > does NOT > + * update the wqe in DRAM to match arguments. > + * > + * This function does NOT wait for any prior tag switches to > complete, so the > + * calling code must do this. > + * > + * Note the following CAVEAT of the Octeon HW behavior when > + * re-scheduling DE-SCHEDULEd items whose (next) state is > + * ORDERED: > + * - If there are no switches pending at the time that the > + * HW executes the de-schedule, the HW will only re-schedule > + * the head of the FIFO associated with the given tag. This > + * means that in many respects, the HW treats this ORDERED > + * tag as an ATOMIC tag. Note that in the SWTAG_DESCH > + * case (to an ORDERED tag), the HW will do the switch > + * before the deschedule whenever it is possible to do > + * the switch immediately, so it may often look like > + * this case. > + * - If there is a pending switch to ORDERED at the time > + * the HW executes the de-schedule, the HW will perform > + * the switch at the time it re-schedules, and will be > + * able to reschedule any/all of the entries with the > + * same tag. > + * Due to this behavior, the RECOMMENDATION to software is > + * that they have a (next) state of ATOMIC when they > + * DE-SCHEDULE. If an ORDERED tag is what was really desired, > + * SW can choose to immediately switch to an ORDERED tag > + * after the work (that has an ATOMIC tag) is re-scheduled. > + * Note that since there are never any tag switches pending > + * when the HW re-schedules, this switch can be IMMEDIATE upon > + * the reception of the pointer during the re-schedule. > + * > + * @param tag New tag value > + * @param tag_type New tag type > + * @param group New group value > + * @param no_sched Control whether this work queue entry will be > rescheduled. > + * - 1 : don't schedule this work > + * - 0 : allow this work to be scheduled. > + */ > +static inline void cvmx_pow_tag_sw_desched_nocheck(u32 tag, > cvmx_pow_tag_type_t tag_type, u64 group, > + u64 no_sched) > +{ > + union cvmx_pow_tag_req_addr ptr; > + cvmx_pow_tag_req_t tag_req; > + > + if (CVMX_ENABLE_POW_CHECKS) { > + cvmx_pow_tag_info_t current_tag; > + > + __cvmx_pow_warn_if_pending_switch(__func__); > + current_tag = cvmx_pow_get_current_tag(); > + cvmx_warn_if(current_tag.tag_type == > CVMX_POW_TAG_TYPE_NULL_NULL, > + "%s called with NULL_NULL tag\n", > __func__); > + cvmx_warn_if(current_tag.tag_type == > CVMX_POW_TAG_TYPE_NULL, > + "%s called with NULL tag. Deschedule not > allowed from NULL state\n", > + __func__); > + cvmx_warn_if((current_tag.tag_type != > CVMX_POW_TAG_TYPE_ATOMIC) && > + (tag_type != CVMX_POW_TAG_TYPE_ATOMIC), > + "%s called where neither the before or > after tag is ATOMIC\n", > + __func__); > + } > + tag_req.u64 = 0; > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_t *wqp = cvmx_pow_get_current_wqp(); > + > + if (!wqp) { > + debug("ERROR: Failed to get WQE, %s\n", > __func__); > + return; > + } > + group &= 0x1f; > + wqp->word1.cn78xx.tag = tag; > + wqp->word1.cn78xx.tag_type = tag_type; > + wqp->word1.cn78xx.grp = group << 3; > + CVMX_SYNCWS; > + tag_req.s_cn78xx_other.op = > CVMX_POW_TAG_OP_SWTAG_DESCH; > + tag_req.s_cn78xx_other.type = tag_type; > + tag_req.s_cn78xx_other.grp = group << 3; > + tag_req.s_cn78xx_other.no_sched = no_sched; > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + group &= 0x3f; > + tag_req.s_cn68xx_other.op = > CVMX_POW_TAG_OP_SWTAG_DESCH; > + tag_req.s_cn68xx_other.tag = tag; > + tag_req.s_cn68xx_other.type = tag_type; > + tag_req.s_cn68xx_other.grp = group; > + tag_req.s_cn68xx_other.no_sched = no_sched; > + } else { > + group &= 0x0f; > + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_SWTAG_DESCH; > + tag_req.s_cn38xx.tag = tag; > + tag_req.s_cn38xx.type = tag_type; > + tag_req.s_cn38xx.grp = group; > + tag_req.s_cn38xx.no_sched = no_sched; > + } > + ptr.u64 = 0; > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + ptr.s.mem_region = CVMX_IO_SEG; > + ptr.s.is_io = 1; > + ptr.s.did = CVMX_OCT_DID_TAG_TAG3; > + ptr.s_cn78xx.node = cvmx_get_node_num(); > + ptr.s_cn78xx.tag = tag; > + } else { > + ptr.s.mem_region = CVMX_IO_SEG; > + ptr.s.is_io = 1; > + ptr.s.did = CVMX_OCT_DID_TAG_TAG3; > + } > + cvmx_write_io(ptr.u64, tag_req.u64); > +} > + > +/** > + * Performs a tag switch and then an immediate deschedule. This > completes > + * immediately, so completion must not be waited for. This function > does NOT > + * update the wqe in DRAM to match arguments. > + * > + * This function waits for any prior tag switches to complete, so > the > + * calling code may call this function with a pending tag switch. > + * > + * Note the following CAVEAT of the Octeon HW behavior when > + * re-scheduling DE-SCHEDULEd items whose (next) state is > + * ORDERED: > + * - If there are no switches pending at the time that the > + * HW executes the de-schedule, the HW will only re-schedule > + * the head of the FIFO associated with the given tag. This > + * means that in many respects, the HW treats this ORDERED > + * tag as an ATOMIC tag. Note that in the SWTAG_DESCH > + * case (to an ORDERED tag), the HW will do the switch > + * before the deschedule whenever it is possible to do > + * the switch immediately, so it may often look like > + * this case. > + * - If there is a pending switch to ORDERED at the time > + * the HW executes the de-schedule, the HW will perform > + * the switch at the time it re-schedules, and will be > + * able to reschedule any/all of the entries with the > + * same tag. > + * Due to this behavior, the RECOMMENDATION to software is > + * that they have a (next) state of ATOMIC when they > + * DE-SCHEDULE. If an ORDERED tag is what was really desired, > + * SW can choose to immediately switch to an ORDERED tag > + * after the work (that has an ATOMIC tag) is re-scheduled. > + * Note that since there are never any tag switches pending > + * when the HW re-schedules, this switch can be IMMEDIATE upon > + * the reception of the pointer during the re-schedule. > + * > + * @param tag New tag value > + * @param tag_type New tag type > + * @param group New group value > + * @param no_sched Control whether this work queue entry will be > rescheduled. > + * - 1 : don't schedule this work > + * - 0 : allow this work to be scheduled. > + */ > +static inline void cvmx_pow_tag_sw_desched(u32 tag, > cvmx_pow_tag_type_t tag_type, u64 group, > + u64 no_sched) > +{ > + /* Need to make sure any writes to the work queue entry are > complete */ > + CVMX_SYNCWS; > + /* Ensure that there is not a pending tag switch, as a tag > switch cannot be started > + * if a previous switch is still pending. */ > + cvmx_pow_tag_sw_wait(); > + cvmx_pow_tag_sw_desched_nocheck(tag, tag_type, group, > no_sched); > +} > + > +/** > + * Descchedules the current work queue entry. > + * > + * @param no_sched no schedule flag value to be set on the work > queue entry. > + * If this is set the entry will not be rescheduled. > + */ > +static inline void cvmx_pow_desched(u64 no_sched) > +{ > + union cvmx_pow_tag_req_addr ptr; > + cvmx_pow_tag_req_t tag_req; > + > + if (CVMX_ENABLE_POW_CHECKS) { > + cvmx_pow_tag_info_t current_tag; > + > + __cvmx_pow_warn_if_pending_switch(__func__); > + current_tag = cvmx_pow_get_current_tag(); > + cvmx_warn_if(current_tag.tag_type == > CVMX_POW_TAG_TYPE_NULL_NULL, > + "%s called with NULL_NULL tag\n", > __func__); > + cvmx_warn_if(current_tag.tag_type == > CVMX_POW_TAG_TYPE_NULL, > + "%s called with NULL tag. Deschedule not > expected from NULL state\n", > + __func__); > + } > + /* Need to make sure any writes to the work queue entry are > complete */ > + CVMX_SYNCWS; > + > + tag_req.u64 = 0; > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_DESCH; > + tag_req.s_cn78xx_other.no_sched = no_sched; > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + tag_req.s_cn68xx_other.op = CVMX_POW_TAG_OP_DESCH; > + tag_req.s_cn68xx_other.no_sched = no_sched; > + } else { > + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_DESCH; > + tag_req.s_cn38xx.no_sched = no_sched; > + } > + ptr.u64 = 0; > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; > + ptr.s_cn78xx.is_io = 1; > + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_TAG3; > + ptr.s_cn78xx.node = cvmx_get_node_num(); > + } else { > + ptr.s.mem_region = CVMX_IO_SEG; > + ptr.s.is_io = 1; > + ptr.s.did = CVMX_OCT_DID_TAG_TAG3; > + } > + cvmx_write_io(ptr.u64, tag_req.u64); > +} > + > +/******************************************************************* > ***********/ > +/* OCTEON3-specific > functions. */ > +/******************************************************************* > ***********/ > +/** > + * This function sets the the affinity of group to the cores in > 78xx. > + * It sets up all the cores in core_mask to accept work from the > specified group. > + * > + * @param xgrp Group to accept work from, 0 - 255. > + * @param core_mask Mask of all the cores which will accept work > from this group > + * @param mask_set Every core has set of 2 masks which can be set > to accept work > + * from 256 groups. At the time of get_work, cores can choose > which mask_set > + * to get work from. 'mask_set' values range from 0 to 3, where > each of the > + * two bits represents a mask set. Cores will be added to the > mask set with > + * corresponding bit set, and removed from the mask set with > corresponding > + * bit clear. > + * Note: cores can only accept work from SSO groups on the same > node, > + * so the node number for the group is derived from the core number. > + */ > +static inline void cvmx_sso_set_group_core_affinity(cvmx_xgrp_t > xgrp, > + const struct > cvmx_coremask *core_mask, > + u8 mask_set) > +{ > + cvmx_sso_ppx_sx_grpmskx_t grp_msk; > + int core; > + int grp_index = xgrp.xgrp >> 6; > + int bit_pos = xgrp.xgrp % 64; > + > + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + debug("ERROR: %s is not supported on this chip)\n", > __func__); > + return; > + } > + cvmx_coremask_for_each_core(core, core_mask) > + { > + unsigned int node, ncore; > + u64 reg_addr; > + > + node = cvmx_coremask_core_to_node(core); > + ncore = cvmx_coremask_core_on_node(core); > + > + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(ncore, 0, > grp_index); > + grp_msk.u64 = csr_rd_node(node, reg_addr); > + > + if (mask_set & 1) > + grp_msk.s.grp_msk |= (1ull << bit_pos); > + else > + grp_msk.s.grp_msk &= ~(1ull << bit_pos); > + > + csr_wr_node(node, reg_addr, grp_msk.u64); > + > + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(ncore, 1, > grp_index); > + grp_msk.u64 = csr_rd_node(node, reg_addr); > + > + if (mask_set & 2) > + grp_msk.s.grp_msk |= (1ull << bit_pos); > + else > + grp_msk.s.grp_msk &= ~(1ull << bit_pos); > + > + csr_wr_node(node, reg_addr, grp_msk.u64); > + } > +} > + > +/** > + * This function sets the priority and group affinity arbitration > for each group. > + * > + * @param node Node number > + * @param xgrp Group 0 - 255 to apply mask parameters to > + * @param priority Priority of the group relative to other groups > + * 0x0 - highest priority > + * 0x7 - lowest priority > + * @param weight Cross-group arbitration weight to apply to this > group. > + * valid values are 1-63 > + * h/w default is 0x3f > + * @param affinity Processor affinity arbitration weight to apply > to this group. > + * If zero, affinity is disabled. > + * valid values are 0-15 > + * h/w default which is 0xf. > + * @param modify_mask mask of the parameters which needs to be > modified. > + * enum cvmx_sso_group_modify_mask > + * to modify only priority -- set bit0 > + * to modify only weight -- set bit1 > + * to modify only affinity -- set bit2 > + */ > +static inline void cvmx_sso_set_group_priority(int node, cvmx_xgrp_t > xgrp, int priority, int weight, > + int affinity, > + enum > cvmx_sso_group_modify_mask modify_mask) > +{ > + cvmx_sso_grpx_pri_t grp_pri; > + > + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + debug("ERROR: %s is not supported on this chip)\n", > __func__); > + return; > + } > + if (weight <= 0) > + weight = 0x3f; /* Force HW default when out of range */ > + > + grp_pri.u64 = csr_rd_node(node, CVMX_SSO_GRPX_PRI(xgrp.xgrp)); > + if (grp_pri.s.weight == 0) > + grp_pri.s.weight = 0x3f; > + if (modify_mask & CVMX_SSO_MODIFY_GROUP_PRIORITY) > + grp_pri.s.pri = priority; > + if (modify_mask & CVMX_SSO_MODIFY_GROUP_WEIGHT) > + grp_pri.s.weight = weight; > + if (modify_mask & CVMX_SSO_MODIFY_GROUP_AFFINITY) > + grp_pri.s.affinity = affinity; > + csr_wr_node(node, CVMX_SSO_GRPX_PRI(xgrp.xgrp), grp_pri.u64); > +} > + > +/** > + * Asynchronous work request. > + * Only works on CN78XX style SSO. > + * > + * Work is requested from the SSO unit, and should later be checked > with > + * function cvmx_pow_work_response_async. > + * This function does NOT wait for previous tag switches to > complete, > + * so the caller must ensure that there is not a pending tag switch. > + * > + * @param scr_addr Scratch memory address that response will be > returned to, > + * which is either a valid WQE, or a response with the invalid > bit set. > + * Byte address, must be 8 byte aligned. > + * @param xgrp Group to receive work for (0-255). > + * @param wait > + * 1 to cause response to wait for work to become available (or > timeout) > + * 0 to cause response to return immediately > + */ > +static inline void cvmx_sso_work_request_grp_async_nocheck(int > scr_addr, cvmx_xgrp_t xgrp, > + cvmx_pow_wai > t_t wait) > +{ > + cvmx_pow_iobdma_store_t data; > + unsigned int node = cvmx_get_node_num(); > + > + if (CVMX_ENABLE_POW_CHECKS) { > + __cvmx_pow_warn_if_pending_switch(__func__); > + cvmx_warn_if(!octeon_has_feature(OCTEON_FEATURE_CN78XX_ > WQE), "Not CN78XX"); > + } > + /* scr_addr must be 8 byte aligned */ > + data.u64 = 0; > + data.s_cn78xx.scraddr = scr_addr >> 3; > + data.s_cn78xx.len = 1; > + data.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; > + data.s_cn78xx.grouped = 1; > + data.s_cn78xx.index_grp_mask = (node << 8) | xgrp.xgrp; > + data.s_cn78xx.wait = wait; > + data.s_cn78xx.node = node; > + > + cvmx_send_single(data.u64); > +} > + > +/** > + * Synchronous work request from the node-local SSO without > verifying > + * pending tag switch. It requests work from a specific SSO group. > + * > + * @param lgrp The local group number (within the SSO of the node of > the caller) > + * from which to get the work. > + * @param wait When set, call stalls until work becomes available, > or times out. > + * If not set, returns immediately. > + * > + * @return Returns the WQE pointer from SSO. > + * Returns NULL if no work was available. > + */ > +static inline void *cvmx_sso_work_request_grp_sync_nocheck(unsigned > int lgrp, cvmx_pow_wait_t wait) > +{ > + cvmx_pow_load_addr_t ptr; > + cvmx_pow_tag_load_resp_t result; > + unsigned int node = cvmx_get_node_num() & 3; > + > + if (CVMX_ENABLE_POW_CHECKS) { > + __cvmx_pow_warn_if_pending_switch(__func__); > + cvmx_warn_if(!octeon_has_feature(OCTEON_FEATURE_CN78XX_ > WQE), "Not CN78XX"); > + } > + ptr.u64 = 0; > + ptr.swork_78xx.mem_region = CVMX_IO_SEG; > + ptr.swork_78xx.is_io = 1; > + ptr.swork_78xx.did = CVMX_OCT_DID_TAG_SWTAG; > + ptr.swork_78xx.node = node; > + ptr.swork_78xx.grouped = 1; > + ptr.swork_78xx.index = (lgrp & 0xff) | node << 8; > + ptr.swork_78xx.wait = wait; > + > + result.u64 = csr_rd(ptr.u64); > + if (result.s_work.no_work) > + return NULL; > + else > + return cvmx_phys_to_ptr(result.s_work.addr); > +} > + > +/** > + * Synchronous work request from the node-local SSO. > + * It requests work from a specific SSO group. > + * This function waits for any previous tag switch to complete > before > + * requesting the new work. > + * > + * @param lgrp The node-local group number from which to get the > work. > + * @param wait When set, call stalls until work becomes available, > or times out. > + * If not set, returns immediately. > + * > + * @return The WQE pointer or NULL, if work is not available. > + */ > +static inline void *cvmx_sso_work_request_grp_sync(unsigned int > lgrp, cvmx_pow_wait_t wait) > +{ > + cvmx_pow_tag_sw_wait(); > + return cvmx_sso_work_request_grp_sync_nocheck(lgrp, wait); > +} > + > +/** > + * This function sets the group mask for a core. The group mask > bits > + * indicate which groups each core will accept work from. > + * > + * @param core_num Processor core to apply mask to. > + * @param mask_set 7XXX has 2 sets of masks per core. > + * Bit 0 represents the first mask set, bit 1 -- the second. > + * @param xgrp_mask Group mask array. > + * Total number of groups is divided into a number of > + * 64-bits mask sets. Each bit in the mask, if set, enables > + * the core to accept work from the corresponding group. > + * > + * NOTE: Each core can be configured to accept work in accordance to > both > + * mask sets, with the first having higher precedence over the > second, > + * or to accept work in accordance to just one of the two mask sets. > + * The 'core_num' argument represents a processor core on any node > + * in a coherent multi-chip system. > + * > + * If the 'mask_set' argument is 3, both mask sets are configured > + * with the same value (which is not typically the intention), > + * so keep in mind the function needs to be called twice > + * to set a different value into each of the mask sets, > + * once with 'mask_set=1' and second time with 'mask_set=2'. > + */ > +static inline void cvmx_pow_set_xgrp_mask(u64 core_num, u8 mask_set, > const u64 xgrp_mask[]) > +{ > + unsigned int grp, node, core; > + u64 reg_addr; > + > + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + debug("ERROR: %s is not supported on this chip)\n", > __func__); > + return; > + } > + > + if (CVMX_ENABLE_POW_CHECKS) { > + cvmx_warn_if(((mask_set < 1) || (mask_set > 3)), > "Invalid mask set"); > + } > + > + if ((mask_set < 1) || (mask_set > 3)) > + mask_set = 3; > + > + node = cvmx_coremask_core_to_node(core_num); > + core = cvmx_coremask_core_on_node(core_num); > + > + for (grp = 0; grp < (cvmx_sso_num_xgrp() >> 6); grp++) { > + if (mask_set & 1) { > + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(core, 0, > grp), > + csr_wr_node(node, reg_addr, xgrp_mask[grp]); > + } > + if (mask_set & 2) { > + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(core, 1, > grp), > + csr_wr_node(node, reg_addr, xgrp_mask[grp]); > + } > + } > +} > + > +/** > + * This function gets the group mask for a core. The group mask > bits > + * indicate which groups each core will accept work from. > + * > + * @param core_num Processor core to apply mask to. > + * @param mask_set 7XXX has 2 sets of masks per core. > + * Bit 0 represents the first mask set, bit 1 -- the second. > + * @param xgrp_mask Provide pointer to u64 mask[8] output array. > + * Total number of groups is divided into a number of > + * 64-bits mask sets. Each bit in the mask represents > + * the core accepts work from the corresponding group. > + * > + * NOTE: Each core can be configured to accept work in accordance to > both > + * mask sets, with the first having higher precedence over the > second, > + * or to accept work in accordance to just one of the two mask sets. > + * The 'core_num' argument represents a processor core on any node > + * in a coherent multi-chip system. > + */ > +static inline void cvmx_pow_get_xgrp_mask(u64 core_num, u8 mask_set, > u64 *xgrp_mask) > +{ > + cvmx_sso_ppx_sx_grpmskx_t grp_msk; > + unsigned int grp, node, core; > + u64 reg_addr; > + > + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + debug("ERROR: %s is not supported on this chip)\n", > __func__); > + return; > + } > + > + if (CVMX_ENABLE_POW_CHECKS) { > + cvmx_warn_if(mask_set != 1 && mask_set != 2, "Invalid > mask set"); > + } > + > + node = cvmx_coremask_core_to_node(core_num); > + core = cvmx_coremask_core_on_node(core_num); > + > + for (grp = 0; grp < cvmx_sso_num_xgrp() >> 6; grp++) { > + if (mask_set & 1) { > + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(core, 0, > grp), > + grp_msk.u64 = csr_rd_node(node, reg_addr); > + xgrp_mask[grp] = grp_msk.s.grp_msk; > + } > + if (mask_set & 2) { > + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(core, 1, > grp), > + grp_msk.u64 = csr_rd_node(node, reg_addr); > + xgrp_mask[grp] = grp_msk.s.grp_msk; > + } > + } > +} > + > +/** > + * Executes SSO SWTAG command. > + * This is similar to cvmx_pow_tag_sw() function, but uses linear > + * (vs. integrated group-qos) group index. > + */ > +static inline void cvmx_pow_tag_sw_node(cvmx_wqe_t *wqp, u32 tag, > cvmx_pow_tag_type_t tag_type, > + int node) > +{ > + union cvmx_pow_tag_req_addr ptr; > + cvmx_pow_tag_req_t tag_req; > + > + if > (cvmx_unlikely(!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE))) { > + debug("ERROR: %s is supported on OCTEON3 only\n", > __func__); > + return; > + } > + CVMX_SYNCWS; > + cvmx_pow_tag_sw_wait(); > + > + if (CVMX_ENABLE_POW_CHECKS) { > + cvmx_pow_tag_info_t current_tag; > + > + __cvmx_pow_warn_if_pending_switch(__func__); > + current_tag = cvmx_pow_get_current_tag(); > + cvmx_warn_if(current_tag.tag_type == > CVMX_POW_TAG_TYPE_NULL_NULL, > + "%s called with NULL_NULL tag\n", > __func__); > + cvmx_warn_if(current_tag.tag_type == > CVMX_POW_TAG_TYPE_NULL, > + "%s called with NULL tag\n", __func__); > + cvmx_warn_if((current_tag.tag_type == tag_type) && > (current_tag.tag == tag), > + "%s called to perform a tag switch to the > same tag\n", __func__); > + cvmx_warn_if( > + tag_type == CVMX_POW_TAG_TYPE_NULL, > + "%s called to perform a tag switch to NULL. Use > cvmx_pow_tag_sw_null() instead\n", > + __func__); > + } > + wqp->word1.cn78xx.tag = tag; > + wqp->word1.cn78xx.tag_type = tag_type; > + CVMX_SYNCWS; > + > + tag_req.u64 = 0; > + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG; > + tag_req.s_cn78xx_other.type = tag_type; > + > + ptr.u64 = 0; > + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; > + ptr.s_cn78xx.is_io = 1; > + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; > + ptr.s_cn78xx.node = node; > + ptr.s_cn78xx.tag = tag; > + cvmx_write_io(ptr.u64, tag_req.u64); > +} > + > +/** > + * Executes SSO SWTAG_FULL command. > + * This is similar to cvmx_pow_tag_sw_full() function, but > + * uses linear (vs. integrated group-qos) group index. > + */ > +static inline void cvmx_pow_tag_sw_full_node(cvmx_wqe_t *wqp, u32 > tag, cvmx_pow_tag_type_t tag_type, > + u8 xgrp, int node) > +{ > + union cvmx_pow_tag_req_addr ptr; > + cvmx_pow_tag_req_t tag_req; > + u16 gxgrp; > + > + if > (cvmx_unlikely(!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE))) { > + debug("ERROR: %s is supported on OCTEON3 only\n", > __func__); > + return; > + } > + /* Ensure that there is not a pending tag switch, as a tag > switch cannot be > + * started, if a previous switch is still pending. */ > + CVMX_SYNCWS; > + cvmx_pow_tag_sw_wait(); > + > + if (CVMX_ENABLE_POW_CHECKS) { > + cvmx_pow_tag_info_t current_tag; > + > + __cvmx_pow_warn_if_pending_switch(__func__); > + current_tag = cvmx_pow_get_current_tag(); > + cvmx_warn_if(current_tag.tag_type == > CVMX_POW_TAG_TYPE_NULL_NULL, > + "%s called with NULL_NULL tag\n", > __func__); > + cvmx_warn_if((current_tag.tag_type == tag_type) && > (current_tag.tag == tag), > + "%s called to perform a tag switch to the > same tag\n", __func__); > + cvmx_warn_if( > + tag_type == CVMX_POW_TAG_TYPE_NULL, > + "%s called to perform a tag switch to NULL. Use > cvmx_pow_tag_sw_null() instead\n", > + __func__); > + if ((wqp != cvmx_phys_to_ptr(0x80)) && > cvmx_pow_get_current_wqp()) > + cvmx_warn_if(wqp != cvmx_pow_get_current_wqp(), > + "%s passed WQE(%p) doesn't match > the address in the POW(%p)\n", > + __func__, wqp, > cvmx_pow_get_current_wqp()); > + } > + gxgrp = node; > + gxgrp = gxgrp << 8 | xgrp; > + wqp->word1.cn78xx.grp = gxgrp; > + wqp->word1.cn78xx.tag = tag; > + wqp->word1.cn78xx.tag_type = tag_type; > + CVMX_SYNCWS; > + > + tag_req.u64 = 0; > + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG_FULL; > + tag_req.s_cn78xx_other.type = tag_type; > + tag_req.s_cn78xx_other.grp = gxgrp; > + tag_req.s_cn78xx_other.wqp = cvmx_ptr_to_phys(wqp); > + > + ptr.u64 = 0; > + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; > + ptr.s_cn78xx.is_io = 1; > + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; > + ptr.s_cn78xx.node = node; > + ptr.s_cn78xx.tag = tag; > + cvmx_write_io(ptr.u64, tag_req.u64); > +} > + > +/** > + * Submits work to an SSO group on any OCI node. > + * This function updates the work queue entry in DRAM to match > + * the arguments given. > + * Note that the tag provided is for the work queue entry submitted, > + * and is unrelated to the tag that the core currently holds. > + * > + * @param wqp pointer to work queue entry to submit. > + * This entry is updated to match the other parameters > + * @param tag tag value to be assigned to work queue entry > + * @param tag_type type of tag > + * @param xgrp native CN78XX group in the range 0..255 > + * @param node The OCI node number for the target group > + * > + * When this function is called on a model prior to CN78XX, which > does > + * not support OCI nodes, the 'node' argument is ignored, and the > 'xgrp' > + * parameter is converted into 'qos' (the lower 3 bits) and 'grp' > (the higher > + * 5 bits), following the backward-compatibility scheme of > translating > + * between new and old style group numbers. > + */ > +static inline void cvmx_pow_work_submit_node(cvmx_wqe_t *wqp, u32 > tag, cvmx_pow_tag_type_t tag_type, > + u8 xgrp, u8 node) > +{ > + union cvmx_pow_tag_req_addr ptr; > + cvmx_pow_tag_req_t tag_req; > + u16 group; > + > + if > (cvmx_unlikely(!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE))) { > + debug("ERROR: %s is supported on OCTEON3 only\n", > __func__); > + return; > + } > + group = node; > + group = group << 8 | xgrp; > + wqp->word1.cn78xx.tag = tag; > + wqp->word1.cn78xx.tag_type = tag_type; > + wqp->word1.cn78xx.grp = group; > + CVMX_SYNCWS; > + > + tag_req.u64 = 0; > + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_ADDWQ; > + tag_req.s_cn78xx_other.type = tag_type; > + tag_req.s_cn78xx_other.wqp = cvmx_ptr_to_phys(wqp); > + tag_req.s_cn78xx_other.grp = group; > + > + ptr.u64 = 0; > + ptr.s_cn78xx.did = 0x66; // CVMX_OCT_DID_TAG_TAG6; > + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; > + ptr.s_cn78xx.is_io = 1; > + ptr.s_cn78xx.node = node; > + ptr.s_cn78xx.tag = tag; > + > + /* SYNC write to memory before the work submit. This is > necessary > + ** as POW may read values from DRAM at this time */ > + CVMX_SYNCWS; > + cvmx_write_io(ptr.u64, tag_req.u64); > +} > + > +/** > + * Executes the SSO SWTAG_DESCHED operation. > + * This is similar to the cvmx_pow_tag_sw_desched() function, but > + * uses linear (vs. unified group-qos) group index. > + */ > +static inline void cvmx_pow_tag_sw_desched_node(cvmx_wqe_t *wqe, u32 > tag, > + cvmx_pow_tag_type_t > tag_type, u8 xgrp, u64 no_sched, > + u8 node) > +{ > + union cvmx_pow_tag_req_addr ptr; > + cvmx_pow_tag_req_t tag_req; > + u16 group; > + > + if > (cvmx_unlikely(!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE))) { > + debug("ERROR: %s is supported on OCTEON3 only\n", > __func__); > + return; > + } > + /* Need to make sure any writes to the work queue entry are > complete */ > + CVMX_SYNCWS; > + /* > + * Ensure that there is not a pending tag switch, as a tag > switch cannot > + * be started if a previous switch is still pending. > + */ > + cvmx_pow_tag_sw_wait(); > + > + if (CVMX_ENABLE_POW_CHECKS) { > + cvmx_pow_tag_info_t current_tag; > + > + __cvmx_pow_warn_if_pending_switch(__func__); > + current_tag = cvmx_pow_get_current_tag(); > + cvmx_warn_if(current_tag.tag_type == > CVMX_POW_TAG_TYPE_NULL_NULL, > + "%s called with NULL_NULL tag\n", > __func__); > + cvmx_warn_if(current_tag.tag_type == > CVMX_POW_TAG_TYPE_NULL, > + "%s called with NULL tag. Deschedule not > allowed from NULL state\n", > + __func__); > + cvmx_warn_if((current_tag.tag_type != > CVMX_POW_TAG_TYPE_ATOMIC) && > + (tag_type != CVMX_POW_TAG_TYPE_ATOMIC), > + "%s called where neither the before or > after tag is ATOMIC\n", > + __func__); > + } > + group = node; > + group = group << 8 | xgrp; > + wqe->word1.cn78xx.tag = tag; > + wqe->word1.cn78xx.tag_type = tag_type; > + wqe->word1.cn78xx.grp = group; > + CVMX_SYNCWS; > + > + tag_req.u64 = 0; > + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG_DESCH; > + tag_req.s_cn78xx_other.type = tag_type; > + tag_req.s_cn78xx_other.grp = group; > + tag_req.s_cn78xx_other.no_sched = no_sched; > + > + ptr.u64 = 0; > + ptr.s.mem_region = CVMX_IO_SEG; > + ptr.s.is_io = 1; > + ptr.s.did = CVMX_OCT_DID_TAG_TAG3; > + ptr.s_cn78xx.node = node; > + ptr.s_cn78xx.tag = tag; > + cvmx_write_io(ptr.u64, tag_req.u64); > +} > + > +/* Executes the UPD_WQP_GRP SSO operation. > + * > + * @param wqp Pointer to the new work queue entry to switch to. > + * @param xgrp SSO group in the range 0..255 > + * > + * NOTE: The operation can be performed only on the local node. > + */ > +static inline void cvmx_sso_update_wqp_group(cvmx_wqe_t *wqp, u8 > xgrp) > +{ > + union cvmx_pow_tag_req_addr addr; > + cvmx_pow_tag_req_t data; > + int node = cvmx_get_node_num(); > + int group = node << 8 | xgrp; > + > + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + debug("ERROR: %s is not supported on this chip)\n", > __func__); > + return; > + } > + wqp->word1.cn78xx.grp = group; > + CVMX_SYNCWS; > + > + data.u64 = 0; > + data.s_cn78xx_other.op = CVMX_POW_TAG_OP_UPDATE_WQP_GRP; > + data.s_cn78xx_other.grp = group; > + data.s_cn78xx_other.wqp = cvmx_ptr_to_phys(wqp); > + > + addr.u64 = 0; > + addr.s_cn78xx.mem_region = CVMX_IO_SEG; > + addr.s_cn78xx.is_io = 1; > + addr.s_cn78xx.did = CVMX_OCT_DID_TAG_TAG1; > + addr.s_cn78xx.node = node; > + cvmx_write_io(addr.u64, data.u64); > +} > + > +/******************************************************************* > ***********/ > +/* Define usage of bits within the 32 bit tag > values. */ > +/******************************************************************* > ***********/ > +/* > + * Number of bits of the tag used by software. The SW bits > + * are always a contiguous block of the high starting at bit 31. > + * The hardware bits are always the low bits. By default, the top 8 > bits > + * of the tag are reserved for software, and the low 24 are set by > the IPD unit. > + */ > +#define CVMX_TAG_SW_BITS (8) > +#define CVMX_TAG_SW_SHIFT (32 - CVMX_TAG_SW_BITS) > + > +/* Below is the list of values for the top 8 bits of the tag. */ > +/* > + * Tag values with top byte of this value are reserved for internal > executive > + * uses > + */ > +#define CVMX_TAG_SW_BITS_INTERNAL 0x1 > + > +/* > + * The executive divides the remaining 24 bits as follows: > + * the upper 8 bits (bits 23 - 16 of the tag) define a subgroup > + * the lower 16 bits (bits 15 - 0 of the tag) define are the value > with > + * the subgroup. Note that this section describes the format of tags > generated > + * by software - refer to the hardware documentation for a > description of the > + * tags values generated by the packet input hardware. > + * Subgroups are defined here > + */ > + > +/* Mask for the value portion of the tag */ > +#define CVMX_TAG_SUBGROUP_MASK 0xFFFF > +#define CVMX_TAG_SUBGROUP_SHIFT 16 > +#define CVMX_TAG_SUBGROUP_PKO 0x1 > + > +/* End of executive tag subgroup definitions */ > + > +/* The remaining values software bit values 0x2 - 0xff are available > + * for application use */ > + > +/** > + * This function creates a 32 bit tag value from the two values > provided. > + * > + * @param sw_bits The upper bits (number depends on configuration) > are set > + * to this value. The remainder of bits are set by the hw_bits > parameter. > + * @param hw_bits The lower bits (number depends on configuration) > are set > + * to this value. The remainder of bits are set by the sw_bits > parameter. > + * > + * @return 32 bit value of the combined hw and sw bits. > + */ > +static inline u32 cvmx_pow_tag_compose(u64 sw_bits, u64 hw_bits) > +{ > + return (((sw_bits & cvmx_build_mask(CVMX_TAG_SW_BITS)) << > CVMX_TAG_SW_SHIFT) | > + (hw_bits & cvmx_build_mask(32 - CVMX_TAG_SW_BITS))); > +} > + > +/** > + * Extracts the bits allocated for software use from the tag > + * > + * @param tag 32 bit tag value > + * > + * @return N bit software tag value, where N is configurable with > + * the CVMX_TAG_SW_BITS define > + */ > +static inline u32 cvmx_pow_tag_get_sw_bits(u64 tag) > +{ > + return ((tag >> (32 - CVMX_TAG_SW_BITS)) & > cvmx_build_mask(CVMX_TAG_SW_BITS)); > +} > + > +/** > + * > + * Extracts the bits allocated for hardware use from the tag > + * > + * @param tag 32 bit tag value > + * > + * @return (32 - N) bit software tag value, where N is configurable > with > + * the CVMX_TAG_SW_BITS define > + */ > +static inline u32 cvmx_pow_tag_get_hw_bits(u64 tag) > +{ > + return (tag & cvmx_build_mask(32 - CVMX_TAG_SW_BITS)); > +} > + > +static inline u64 cvmx_sso3_get_wqe_count(int node) > +{ > + cvmx_sso_grpx_aq_cnt_t aq_cnt; > + unsigned int grp = 0; > + u64 cnt = 0; > + > + for (grp = 0; grp < cvmx_sso_num_xgrp(); grp++) { > + aq_cnt.u64 = csr_rd_node(node, > CVMX_SSO_GRPX_AQ_CNT(grp)); > + cnt += aq_cnt.s.aq_cnt; > + } > + return cnt; > +} > + > +static inline u64 cvmx_sso_get_total_wqe_count(void) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + int node = cvmx_get_node_num(); > + > + return cvmx_sso3_get_wqe_count(node); > + } else if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { > + cvmx_sso_iq_com_cnt_t sso_iq_com_cnt; > + > + sso_iq_com_cnt.u64 = csr_rd(CVMX_SSO_IQ_COM_CNT); > + return (sso_iq_com_cnt.s.iq_cnt); > + } else { > + cvmx_pow_iq_com_cnt_t pow_iq_com_cnt; > + > + pow_iq_com_cnt.u64 = csr_rd(CVMX_POW_IQ_COM_CNT); > + return (pow_iq_com_cnt.s.iq_cnt); > + } > +} > + > +/** > + * Store the current POW internal state into the supplied > + * buffer. It is recommended that you pass a buffer of at least > + * 128KB. The format of the capture may change based on SDK > + * version and Octeon chip. > + * > + * @param buffer Buffer to store capture into > + * @param buffer_size The size of the supplied buffer > + * > + * @return Zero on success, negative on failure > + */ > +int cvmx_pow_capture(void *buffer, int buffer_size); > + > +/** > + * Dump a POW capture to the console in a human readable format. > + * > + * @param buffer POW capture from cvmx_pow_capture() > + * @param buffer_size Size of the buffer > + */ > +void cvmx_pow_display(void *buffer, int buffer_size); > + > +/** > + * Return the number of POW entries supported by this chip > + * > + * @return Number of POW entries > + */ > +int cvmx_pow_get_num_entries(void); > +int cvmx_pow_get_dump_size(void); > + > +/** > + * This will allocate count number of SSO groups on the specified > node to the > + * calling application. These groups will be for exclusive use of > the > + * application until they are freed. > + * @param node The numa node for the allocation. > + * @param base_group Pointer to the initial group, -1 to allocate > anywhere. > + * @param count The number of consecutive groups to allocate. > + * @return 0 on success and -1 on failure. > + */ > +int cvmx_sso_reserve_group_range(int node, int *base_group, int > count); > +#define cvmx_sso_allocate_group_range cvmx_sso_reserve_group_range > +int cvmx_sso_reserve_group(int node); > +#define cvmx_sso_allocate_group cvmx_sso_reserve_group > +int cvmx_sso_release_group_range(int node, int base_group, int > count); > +int cvmx_sso_release_group(int node, int group); > + > +/** > + * Show integrated SSO configuration. > + * > + * @param node node number > + */ > +int cvmx_sso_config_dump(unsigned int node); > + > +/** > + * Show integrated SSO statistics. > + * > + * @param node node number > + */ > +int cvmx_sso_stats_dump(unsigned int node); > + > +/** > + * Clear integrated SSO statistics. > + * > + * @param node node number > + */ > +int cvmx_sso_stats_clear(unsigned int node); > + > +/** > + * Show SSO core-group affinity and priority per node (multi-node > systems) > + */ > +void cvmx_pow_mask_priority_dump_node(unsigned int node, struct > cvmx_coremask *avail_coremask); > + > +/** > + * Show POW/SSO core-group affinity and priority (legacy, single- > node systems) > + */ > +static inline void cvmx_pow_mask_priority_dump(struct cvmx_coremask > *avail_coremask) > +{ > + cvmx_pow_mask_priority_dump_node(0 /*node */, avail_coremask); > +} > + > +/** > + * Show SSO performance counters (multi-node systems) > + */ > +void cvmx_pow_show_perf_counters_node(unsigned int node); > + > +/** > + * Show POW/SSO performance counters (legacy, single-node systems) > + */ > +static inline void cvmx_pow_show_perf_counters(void) > +{ > + cvmx_pow_show_perf_counters_node(0 /*node */); > +} > + > +#endif /* __CVMX_POW_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-qlm.h > b/arch/mips/mach-octeon/include/mach/cvmx-qlm.h > new file mode 100644 > index 000000000000..19915eb82c51 > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-qlm.h > @@ -0,0 +1,304 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + */ > + > +#ifndef __CVMX_QLM_H__ > +#define __CVMX_QLM_H__ > + > +/* > + * Interface 0 on the 78xx can be connected to qlm 0 or qlm 2. When > interface > + * 0 is connected to qlm 0, this macro must be set to 0. When > interface 0 is > + * connected to qlm 2, this macro must be set to 1. > + */ > +#define MUX_78XX_IFACE0 0 > + > +/* > + * Interface 1 on the 78xx can be connected to qlm 1 or qlm 3. When > interface > + * 1 is connected to qlm 1, this macro must be set to 0. When > interface 1 is > + * connected to qlm 3, this macro must be set to 1. > + */ > +#define MUX_78XX_IFACE1 0 > + > +/* Uncomment this line to print QLM JTAG state */ > +/* #define CVMX_QLM_DUMP_STATE 1 */ > + > +typedef struct { > + const char *name; > + int stop_bit; > + int start_bit; > +} __cvmx_qlm_jtag_field_t; > + > +/** > + * Return the number of QLMs supported by the chip > + * > + * @return Number of QLMs > + */ > +int cvmx_qlm_get_num(void); > + > +/** > + * Return the qlm number based on the interface > + * > + * @param xiface Interface to look > + */ > +int cvmx_qlm_interface(int xiface); > + > +/** > + * Return the qlm number based for a port in the interface > + * > + * @param xiface interface to look up > + * @param index index in an interface > + * > + * @return the qlm number based on the xiface > + */ > +int cvmx_qlm_lmac(int xiface, int index); > + > +/** > + * Return if only DLM5/DLM6/DLM5+DLM6 is used by BGX > + * > + * @param BGX BGX to search for. > + * > + * @return muxes used 0 = DLM5+DLM6, 1 = DLM5, 2 = DLM6. > + */ > +int cvmx_qlm_mux_interface(int bgx); > + > +/** > + * Return number of lanes for a given qlm > + * > + * @param qlm QLM block to query > + * > + * @return Number of lanes > + */ > +int cvmx_qlm_get_lanes(int qlm); > + > +/** > + * Get the QLM JTAG fields based on Octeon model on the supported > chips. > + * > + * @return qlm_jtag_field_t structure > + */ > +const __cvmx_qlm_jtag_field_t *cvmx_qlm_jtag_get_field(void); > + > +/** > + * Get the QLM JTAG length by going through qlm_jtag_field for each > + * Octeon model that is supported > + * > + * @return return the length. > + */ > +int cvmx_qlm_jtag_get_length(void); > + > +/** > + * Initialize the QLM layer > + */ > +void cvmx_qlm_init(void); > + > +/** > + * Get a field in a QLM JTAG chain > + * > + * @param qlm QLM to get > + * @param lane Lane in QLM to get > + * @param name String name of field > + * > + * @return JTAG field value > + */ > +u64 cvmx_qlm_jtag_get(int qlm, int lane, const char *name); > + > +/** > + * Set a field in a QLM JTAG chain > + * > + * @param qlm QLM to set > + * @param lane Lane in QLM to set, or -1 for all lanes > + * @param name String name of field > + * @param value Value of the field > + */ > +void cvmx_qlm_jtag_set(int qlm, int lane, const char *name, u64 > value); > + > +/** > + * Errata G-16094: QLM Gen2 Equalizer Default Setting Change. > + * CN68XX pass 1.x and CN66XX pass 1.x QLM tweak. This function > tweaks the > + * JTAG setting for a QLMs to run better at 5 and 6.25Ghz. > + */ > +void __cvmx_qlm_speed_tweak(void); > + > +/** > + * Errata G-16174: QLM Gen2 PCIe IDLE DAC change. > + * CN68XX pass 1.x, CN66XX pass 1.x and CN63XX pass 1.0-2.2 QLM > tweak. > + * This function tweaks the JTAG setting for a QLMs for PCIe to run > better. > + */ > +void __cvmx_qlm_pcie_idle_dac_tweak(void); > + > +void __cvmx_qlm_pcie_cfg_rxd_set_tweak(int qlm, int lane); > + > +/** > + * Get the speed (Gbaud) of the QLM in Mhz. > + * > + * @param qlm QLM to examine > + * > + * @return Speed in Mhz > + */ > +int cvmx_qlm_get_gbaud_mhz(int qlm); > +/** > + * Get the speed (Gbaud) of the QLM in Mhz on specific node. > + * > + * @param node Target QLM node > + * @param qlm QLM to examine > + * > + * @return Speed in Mhz > + */ > +int cvmx_qlm_get_gbaud_mhz_node(int node, int qlm); > + > +enum cvmx_qlm_mode { > + CVMX_QLM_MODE_DISABLED = -1, > + CVMX_QLM_MODE_SGMII = 1, > + CVMX_QLM_MODE_XAUI, > + CVMX_QLM_MODE_RXAUI, > + CVMX_QLM_MODE_PCIE, /* gen3 / gen2 / gen1 */ > + CVMX_QLM_MODE_PCIE_1X2, /* 1x2 gen2 / gen1 */ > + CVMX_QLM_MODE_PCIE_2X1, /* 2x1 gen2 / gen1 */ > + CVMX_QLM_MODE_PCIE_1X1, /* 1x1 gen2 / gen1 */ > + CVMX_QLM_MODE_SRIO_1X4, /* 1x4 short / long */ > + CVMX_QLM_MODE_SRIO_2X2, /* 2x2 short / long */ > + CVMX_QLM_MODE_SRIO_4X1, /* 4x1 short / long */ > + CVMX_QLM_MODE_ILK, > + CVMX_QLM_MODE_QSGMII, > + CVMX_QLM_MODE_SGMII_SGMII, > + CVMX_QLM_MODE_SGMII_DISABLED, > + CVMX_QLM_MODE_DISABLED_SGMII, > + CVMX_QLM_MODE_SGMII_QSGMII, > + CVMX_QLM_MODE_QSGMII_QSGMII, > + CVMX_QLM_MODE_QSGMII_DISABLED, > + CVMX_QLM_MODE_DISABLED_QSGMII, > + CVMX_QLM_MODE_QSGMII_SGMII, > + CVMX_QLM_MODE_RXAUI_1X2, > + CVMX_QLM_MODE_SATA_2X1, > + CVMX_QLM_MODE_XLAUI, > + CVMX_QLM_MODE_XFI, > + CVMX_QLM_MODE_10G_KR, > + CVMX_QLM_MODE_40G_KR4, > + CVMX_QLM_MODE_PCIE_1X8, /* 1x8 gen3 / gen2 / gen1 */ > + CVMX_QLM_MODE_RGMII_SGMII, > + CVMX_QLM_MODE_RGMII_XFI, > + CVMX_QLM_MODE_RGMII_10G_KR, > + CVMX_QLM_MODE_RGMII_RXAUI, > + CVMX_QLM_MODE_RGMII_XAUI, > + CVMX_QLM_MODE_RGMII_XLAUI, > + CVMX_QLM_MODE_RGMII_40G_KR4, > + CVMX_QLM_MODE_MIXED, /* BGX2 is mixed mode, > DLM5(SGMII) & DLM6(XFI) */ > + CVMX_QLM_MODE_SGMII_2X1, /* Configure BGX2 separate for DLM5 & > DLM6 */ > + CVMX_QLM_MODE_10G_KR_1X2, /* Configure BGX2 separate for DLM5 & > DLM6 */ > + CVMX_QLM_MODE_XFI_1X2, /* Configure BGX2 separate > for DLM5 & DLM6 */ > + CVMX_QLM_MODE_RGMII_SGMII_1X1, /* Configure BGX2, applies to > DLM5 */ > + CVMX_QLM_MODE_RGMII_SGMII_2X1, /* Configure BGX2, applies to > DLM6 */ > + CVMX_QLM_MODE_RGMII_10G_KR_1X1, /* Configure BGX2, applies to > DLM6 */ > + CVMX_QLM_MODE_RGMII_XFI_1X1, /* Configure BGX2, applies to > DLM6 */ > + CVMX_QLM_MODE_SDL, /* RMAC Pipe */ > + CVMX_QLM_MODE_CPRI, /* RMAC */ > + CVMX_QLM_MODE_OCI > +}; > + > +enum cvmx_gmx_inf_mode { > + CVMX_GMX_INF_MODE_DISABLED = 0, > + CVMX_GMX_INF_MODE_SGMII = 1, /* Other interface can be SGMII > or QSGMII */ > + CVMX_GMX_INF_MODE_QSGMII = 2, /* Other interface can be SGMII > or QSGMII */ > + CVMX_GMX_INF_MODE_RXAUI = 3, /* Only interface 0, interface 1 > must be DISABLED */ > +}; > + > +/** > + * Eye diagram captures are stored in the following structure > + */ > +typedef struct { > + int width; /* Width in the x direction (time) */ > + int height; /* Height in the y direction (voltage) */ > + u32 data[64][128]; /* Error count at location, saturates as max > */ > +} cvmx_qlm_eye_t; > + > +/** > + * These apply to DLM1 and DLM2 if its not in SATA mode > + * Manual refers to lanes as follows: > + * DML 0 lane 0 == GSER0 lane 0 > + * DML 0 lane 1 == GSER0 lane 1 > + * DML 1 lane 2 == GSER1 lane 0 > + * DML 1 lane 3 == GSER1 lane 1 > + * DML 2 lane 4 == GSER2 lane 0 > + * DML 2 lane 5 == GSER2 lane 1 > + */ > +enum cvmx_pemx_cfg_mode { > + CVMX_PEM_MD_GEN2_2LANE = 0, /* Valid for PEM0(DLM1), PEM1(DLM2) > */ > + CVMX_PEM_MD_GEN2_1LANE = 1, /* Valid for PEM0(DLM1.0), > PEM1(DLM1.1,DLM2.0), PEM2(DLM2.1) */ > + CVMX_PEM_MD_GEN2_4LANE = 2, /* Valid for PEM0(DLM1-2) */ > + /* Reserved */ > + CVMX_PEM_MD_GEN1_2LANE = 4, /* Valid for PEM0(DLM1), PEM1(DLM2) > */ > + CVMX_PEM_MD_GEN1_1LANE = 5, /* Valid for PEM0(DLM1.0), > PEM1(DLM1.1,DLM2.0), PEM2(DLM2.1) */ > + CVMX_PEM_MD_GEN1_4LANE = 6, /* Valid for PEM0(DLM1-2) */ > + /* Reserved */ > +}; > + > +/* > + * Read QLM and return mode. > + */ > +enum cvmx_qlm_mode cvmx_qlm_get_mode(int qlm); > +enum cvmx_qlm_mode cvmx_qlm_get_mode_cn78xx(int node, int qlm); > +enum cvmx_qlm_mode cvmx_qlm_get_dlm_mode(int dlm_mode, int > interface); > +void __cvmx_qlm_set_mult(int qlm, int baud_mhz, int old_multiplier); > + > +void cvmx_qlm_display_registers(int qlm); > + > +int cvmx_qlm_measure_clock(int qlm); > + > +/** > + * Measure the reference clock of a QLM on a multi-node setup > + * > + * @param node node to measure > + * @param qlm QLM to measure > + * > + * @return Clock rate in Hz > + */ > +int cvmx_qlm_measure_clock_node(int node, int qlm); > + > +/* > + * Perform RX equalization on a QLM > + * > + * @param node Node the QLM is on > + * @param qlm QLM to perform RX equalization on > + * @param lane Lane to use, or -1 for all lanes > + * > + * @return Zero on success, negative if any lane failed RX > equalization > + */ > +int __cvmx_qlm_rx_equalization(int node, int qlm, int lane); > + > +/** > + * Errata GSER-27882 -GSER 10GBASE-KR Transmit Equalizer > + * Training may not update PHY Tx Taps. This function is not static > + * so we can share it with BGX KR > + * > + * @param node Node to apply errata workaround > + * @param qlm QLM to apply errata workaround > + * @param lane Lane to apply the errata > + */ > +int cvmx_qlm_gser_errata_27882(int node, int qlm, int lane); > + > +void cvmx_qlm_gser_errata_25992(int node, int qlm); > + > +#ifdef CVMX_DUMP_GSER > +/** > + * Dump GSER configuration for node 0 > + */ > +int cvmx_dump_gser_config(unsigned int gser); > +/** > + * Dump GSER status for node 0 > + */ > +int cvmx_dump_gser_status(unsigned int gser); > +/** > + * Dump GSER configuration > + */ > +int cvmx_dump_gser_config_node(unsigned int node, unsigned int > gser); > +/** > + * Dump GSER status > + */ > +int cvmx_dump_gser_status_node(unsigned int node, unsigned int > gser); > +#endif > + > +int cvmx_qlm_eye_display(int node, int qlm, int qlm_lane, int > format, const cvmx_qlm_eye_t *eye); > + > +void cvmx_prbs_process_cmd(int node, int qlm, int mode); > + > +#endif /* __CVMX_QLM_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-scratch.h > b/arch/mips/mach-octeon/include/mach/cvmx-scratch.h > new file mode 100644 > index 000000000000..d567a8453b7a > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-scratch.h > @@ -0,0 +1,113 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * This file provides support for the processor local scratch > memory. > + * Scratch memory is byte addressable - all addresses are byte > addresses. > + */ > + > +#ifndef __CVMX_SCRATCH_H__ > +#define __CVMX_SCRATCH_H__ > + > +/* Note: This define must be a long, not a long long in order to > compile > + without warnings for both 32bit and 64bit. */ > +#define CVMX_SCRATCH_BASE (-32768l) /* 0xffffffffffff8000 */ > + > +/* Scratch line for LMTST/LMTDMA on Octeon3 models */ > +#ifdef CVMX_CAVIUM_OCTEON3 > +#define CVMX_PKO_LMTLINE 2ull > +#endif > + > +/** > + * Reads an 8 bit value from the processor local scratchpad memory. > + * > + * @param address byte address to read from > + * > + * @return value read > + */ > +static inline u8 cvmx_scratch_read8(u64 address) > +{ > + return *CASTPTR(volatile u8, CVMX_SCRATCH_BASE + address); > +} > + > +/** > + * Reads a 16 bit value from the processor local scratchpad memory. > + * > + * @param address byte address to read from > + * > + * @return value read > + */ > +static inline u16 cvmx_scratch_read16(u64 address) > +{ > + return *CASTPTR(volatile u16, CVMX_SCRATCH_BASE + address); > +} > + > +/** > + * Reads a 32 bit value from the processor local scratchpad memory. > + * > + * @param address byte address to read from > + * > + * @return value read > + */ > +static inline u32 cvmx_scratch_read32(u64 address) > +{ > + return *CASTPTR(volatile u32, CVMX_SCRATCH_BASE + address); > +} > + > +/** > + * Reads a 64 bit value from the processor local scratchpad memory. > + * > + * @param address byte address to read from > + * > + * @return value read > + */ > +static inline u64 cvmx_scratch_read64(u64 address) > +{ > + return *CASTPTR(volatile u64, CVMX_SCRATCH_BASE + address); > +} > + > +/** > + * Writes an 8 bit value to the processor local scratchpad memory. > + * > + * @param address byte address to write to > + * @param value value to write > + */ > +static inline void cvmx_scratch_write8(u64 address, u64 value) > +{ > + *CASTPTR(volatile u8, CVMX_SCRATCH_BASE + address) = (u8)value; > +} > + > +/** > + * Writes a 32 bit value to the processor local scratchpad memory. > + * > + * @param address byte address to write to > + * @param value value to write > + */ > +static inline void cvmx_scratch_write16(u64 address, u64 value) > +{ > + *CASTPTR(volatile u16, CVMX_SCRATCH_BASE + address) = > (u16)value; > +} > + > +/** > + * Writes a 16 bit value to the processor local scratchpad memory. > + * > + * @param address byte address to write to > + * @param value value to write > + */ > +static inline void cvmx_scratch_write32(u64 address, u64 value) > +{ > + *CASTPTR(volatile u32, CVMX_SCRATCH_BASE + address) = > (u32)value; > +} > + > +/** > + * Writes a 64 bit value to the processor local scratchpad memory. > + * > + * @param address byte address to write to > + * @param value value to write > + */ > +static inline void cvmx_scratch_write64(u64 address, u64 value) > +{ > + *CASTPTR(volatile u64, CVMX_SCRATCH_BASE + address) = value; > +} > + > +#endif /* __CVMX_SCRATCH_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/cvmx-wqe.h > b/arch/mips/mach-octeon/include/mach/cvmx-wqe.h > new file mode 100644 > index 000000000000..c9e3c8312a65 > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/cvmx-wqe.h > @@ -0,0 +1,1462 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + * > + * This header file defines the work queue entry (wqe) data > structure. > + * Since this is a commonly used structure that depends on > structures > + * from several hardware blocks, those definitions have been placed > + * in this file to create a single point of definition of the wqe > + * format. > + * Data structures are still named according to the block that they > + * relate to. > + */ > + > +#ifndef __CVMX_WQE_H__ > +#define __CVMX_WQE_H__ > + > +#include "cvmx-packet.h" > +#include "cvmx-csr-enums.h" > +#include "cvmx-pki-defs.h" > +#include "cvmx-pip-defs.h" > +#include "octeon-feature.h" > + > +#define OCT_TAG_TYPE_STRING(x) > \ > + (((x) == CVMX_POW_TAG_TYPE_ORDERED) ? > \ > + "ORDERED" : > \ > + (((x) == CVMX_POW_TAG_TYPE_ATOMIC) ? > \ > + "ATOMIC" : > \ > + (((x) == CVMX_POW_TAG_TYPE_NULL) ? "NULL" : "NULL_NULL"))) > + > +/* Error levels in WQE WORD2 (ERRLEV).*/ > +#define PKI_ERRLEV_E__RE_M 0x0 > +#define PKI_ERRLEV_E__LA_M 0x1 > +#define PKI_ERRLEV_E__LB_M 0x2 > +#define PKI_ERRLEV_E__LC_M 0x3 > +#define PKI_ERRLEV_E__LD_M 0x4 > +#define PKI_ERRLEV_E__LE_M 0x5 > +#define PKI_ERRLEV_E__LF_M 0x6 > +#define PKI_ERRLEV_E__LG_M 0x7 > + > +enum cvmx_pki_errlevel { > + CVMX_PKI_ERRLEV_E_RE = PKI_ERRLEV_E__RE_M, > + CVMX_PKI_ERRLEV_E_LA = PKI_ERRLEV_E__LA_M, > + CVMX_PKI_ERRLEV_E_LB = PKI_ERRLEV_E__LB_M, > + CVMX_PKI_ERRLEV_E_LC = PKI_ERRLEV_E__LC_M, > + CVMX_PKI_ERRLEV_E_LD = PKI_ERRLEV_E__LD_M, > + CVMX_PKI_ERRLEV_E_LE = PKI_ERRLEV_E__LE_M, > + CVMX_PKI_ERRLEV_E_LF = PKI_ERRLEV_E__LF_M, > + CVMX_PKI_ERRLEV_E_LG = PKI_ERRLEV_E__LG_M > +}; > + > +#define CVMX_PKI_ERRLEV_MAX BIT(3) /* The size of WORD2:ERRLEV > field.*/ > + > +/* Error code in WQE WORD2 (OPCODE).*/ > +#define CVMX_PKI_OPCODE_RE_NONE 0x0 > +#define CVMX_PKI_OPCODE_RE_PARTIAL 0x1 > +#define CVMX_PKI_OPCODE_RE_JABBER 0x2 > +#define CVMX_PKI_OPCODE_RE_FCS 0x7 > +#define CVMX_PKI_OPCODE_RE_FCS_RCV 0x8 > +#define CVMX_PKI_OPCODE_RE_TERMINATE 0x9 > +#define CVMX_PKI_OPCODE_RE_RX_CTL 0xb > +#define CVMX_PKI_OPCODE_RE_SKIP 0xc > +#define CVMX_PKI_OPCODE_RE_DMAPKT 0xf > +#define CVMX_PKI_OPCODE_RE_PKIPAR 0x13 > +#define CVMX_PKI_OPCODE_RE_PKIPCAM 0x14 > +#define CVMX_PKI_OPCODE_RE_MEMOUT 0x15 > +#define CVMX_PKI_OPCODE_RE_BUFS_OFLOW 0x16 > +#define CVMX_PKI_OPCODE_L2_FRAGMENT 0x20 > +#define CVMX_PKI_OPCODE_L2_OVERRUN 0x21 > +#define CVMX_PKI_OPCODE_L2_PFCS 0x22 > +#define CVMX_PKI_OPCODE_L2_PUNY 0x23 > +#define CVMX_PKI_OPCODE_L2_MAL 0x24 > +#define CVMX_PKI_OPCODE_L2_OVERSIZE 0x25 > +#define CVMX_PKI_OPCODE_L2_UNDERSIZE 0x26 > +#define CVMX_PKI_OPCODE_L2_LENMISM 0x27 > +#define CVMX_PKI_OPCODE_IP_NOT 0x41 > +#define CVMX_PKI_OPCODE_IP_CHK 0x42 > +#define CVMX_PKI_OPCODE_IP_MAL 0x43 > +#define CVMX_PKI_OPCODE_IP_MALD 0x44 > +#define CVMX_PKI_OPCODE_IP_HOP 0x45 > +#define CVMX_PKI_OPCODE_L4_MAL 0x61 > +#define CVMX_PKI_OPCODE_L4_CHK 0x62 > +#define CVMX_PKI_OPCODE_L4_LEN 0x63 > +#define CVMX_PKI_OPCODE_L4_PORT 0x64 > +#define CVMX_PKI_OPCODE_TCP_FLAG 0x65 > + > +#define CVMX_PKI_OPCODE_MAX BIT(8) /* The size of WORD2:OPCODE > field.*/ > + > +/* Layer types in pki */ > +#define CVMX_PKI_LTYPE_E_NONE_M 0x0 > +#define CVMX_PKI_LTYPE_E_ENET_M 0x1 > +#define CVMX_PKI_LTYPE_E_VLAN_M 0x2 > +#define CVMX_PKI_LTYPE_E_SNAP_PAYLD_M 0x5 > +#define CVMX_PKI_LTYPE_E_ARP_M 0x6 > +#define CVMX_PKI_LTYPE_E_RARP_M 0x7 > +#define CVMX_PKI_LTYPE_E_IP4_M 0x8 > +#define CVMX_PKI_LTYPE_E_IP4_OPT_M 0x9 > +#define CVMX_PKI_LTYPE_E_IP6_M 0xA > +#define CVMX_PKI_LTYPE_E_IP6_OPT_M 0xB > +#define CVMX_PKI_LTYPE_E_IPSEC_ESP_M 0xC > +#define CVMX_PKI_LTYPE_E_IPFRAG_M 0xD > +#define CVMX_PKI_LTYPE_E_IPCOMP_M 0xE > +#define CVMX_PKI_LTYPE_E_TCP_M 0x10 > +#define CVMX_PKI_LTYPE_E_UDP_M 0x11 > +#define CVMX_PKI_LTYPE_E_SCTP_M 0x12 > +#define CVMX_PKI_LTYPE_E_UDP_VXLAN_M 0x13 > +#define CVMX_PKI_LTYPE_E_GRE_M 0x14 > +#define CVMX_PKI_LTYPE_E_NVGRE_M 0x15 > +#define CVMX_PKI_LTYPE_E_GTP_M 0x16 > +#define CVMX_PKI_LTYPE_E_SW28_M 0x1C > +#define CVMX_PKI_LTYPE_E_SW29_M 0x1D > +#define CVMX_PKI_LTYPE_E_SW30_M 0x1E > +#define CVMX_PKI_LTYPE_E_SW31_M 0x1F > + > +enum cvmx_pki_layer_type { > + CVMX_PKI_LTYPE_E_NONE = CVMX_PKI_LTYPE_E_NONE_M, > + CVMX_PKI_LTYPE_E_ENET = CVMX_PKI_LTYPE_E_ENET_M, > + CVMX_PKI_LTYPE_E_VLAN = CVMX_PKI_LTYPE_E_VLAN_M, > + CVMX_PKI_LTYPE_E_SNAP_PAYLD = CVMX_PKI_LTYPE_E_SNAP_PAYLD_M, > + CVMX_PKI_LTYPE_E_ARP = CVMX_PKI_LTYPE_E_ARP_M, > + CVMX_PKI_LTYPE_E_RARP = CVMX_PKI_LTYPE_E_RARP_M, > + CVMX_PKI_LTYPE_E_IP4 = CVMX_PKI_LTYPE_E_IP4_M, > + CVMX_PKI_LTYPE_E_IP4_OPT = CVMX_PKI_LTYPE_E_IP4_OPT_M, > + CVMX_PKI_LTYPE_E_IP6 = CVMX_PKI_LTYPE_E_IP6_M, > + CVMX_PKI_LTYPE_E_IP6_OPT = CVMX_PKI_LTYPE_E_IP6_OPT_M, > + CVMX_PKI_LTYPE_E_IPSEC_ESP = CVMX_PKI_LTYPE_E_IPSEC_ESP_M, > + CVMX_PKI_LTYPE_E_IPFRAG = CVMX_PKI_LTYPE_E_IPFRAG_M, > + CVMX_PKI_LTYPE_E_IPCOMP = CVMX_PKI_LTYPE_E_IPCOMP_M, > + CVMX_PKI_LTYPE_E_TCP = CVMX_PKI_LTYPE_E_TCP_M, > + CVMX_PKI_LTYPE_E_UDP = CVMX_PKI_LTYPE_E_UDP_M, > + CVMX_PKI_LTYPE_E_SCTP = CVMX_PKI_LTYPE_E_SCTP_M, > + CVMX_PKI_LTYPE_E_UDP_VXLAN = CVMX_PKI_LTYPE_E_UDP_VXLAN_M, > + CVMX_PKI_LTYPE_E_GRE = CVMX_PKI_LTYPE_E_GRE_M, > + CVMX_PKI_LTYPE_E_NVGRE = CVMX_PKI_LTYPE_E_NVGRE_M, > + CVMX_PKI_LTYPE_E_GTP = CVMX_PKI_LTYPE_E_GTP_M, > + CVMX_PKI_LTYPE_E_SW28 = CVMX_PKI_LTYPE_E_SW28_M, > + CVMX_PKI_LTYPE_E_SW29 = CVMX_PKI_LTYPE_E_SW29_M, > + CVMX_PKI_LTYPE_E_SW30 = CVMX_PKI_LTYPE_E_SW30_M, > + CVMX_PKI_LTYPE_E_SW31 = CVMX_PKI_LTYPE_E_SW31_M, > + CVMX_PKI_LTYPE_E_MAX = CVMX_PKI_LTYPE_E_SW31 > +}; > + > +typedef union { > + u64 u64; > + struct { > + u64 ptr_vlan : 8; > + u64 ptr_layer_g : 8; > + u64 ptr_layer_f : 8; > + u64 ptr_layer_e : 8; > + u64 ptr_layer_d : 8; > + u64 ptr_layer_c : 8; > + u64 ptr_layer_b : 8; > + u64 ptr_layer_a : 8; > + }; > +} cvmx_pki_wqe_word4_t; > + > +/** > + * HW decode / err_code in work queue entry > + */ > +typedef union { > + u64 u64; > + struct { > + u64 bufs : 8; > + u64 ip_offset : 8; > + u64 vlan_valid : 1; > + u64 vlan_stacked : 1; > + u64 unassigned : 1; > + u64 vlan_cfi : 1; > + u64 vlan_id : 12; > + u64 varies : 12; > + u64 dec_ipcomp : 1; > + u64 tcp_or_udp : 1; > + u64 dec_ipsec : 1; > + u64 is_v6 : 1; > + u64 software : 1; > + u64 L4_error : 1; > + u64 is_frag : 1; > + u64 IP_exc : 1; > + u64 is_bcast : 1; > + u64 is_mcast : 1; > + u64 not_IP : 1; > + u64 rcv_error : 1; > + u64 err_code : 8; > + } s; > + struct { > + u64 bufs : 8; > + u64 ip_offset : 8; > + u64 vlan_valid : 1; > + u64 vlan_stacked : 1; > + u64 unassigned : 1; > + u64 vlan_cfi : 1; > + u64 vlan_id : 12; > + u64 port : 12; > + u64 dec_ipcomp : 1; > + u64 tcp_or_udp : 1; > + u64 dec_ipsec : 1; > + u64 is_v6 : 1; > + u64 software : 1; > + u64 L4_error : 1; > + u64 is_frag : 1; > + u64 IP_exc : 1; > + u64 is_bcast : 1; > + u64 is_mcast : 1; > + u64 not_IP : 1; > + u64 rcv_error : 1; > + u64 err_code : 8; > + } s_cn68xx; > + struct { > + u64 bufs : 8; > + u64 ip_offset : 8; > + u64 vlan_valid : 1; > + u64 vlan_stacked : 1; > + u64 unassigned : 1; > + u64 vlan_cfi : 1; > + u64 vlan_id : 12; > + u64 pr : 4; > + u64 unassigned2a : 4; > + u64 unassigned2 : 4; > + u64 dec_ipcomp : 1; > + u64 tcp_or_udp : 1; > + u64 dec_ipsec : 1; > + u64 is_v6 : 1; > + u64 software : 1; > + u64 L4_error : 1; > + u64 is_frag : 1; > + u64 IP_exc : 1; > + u64 is_bcast : 1; > + u64 is_mcast : 1; > + u64 not_IP : 1; > + u64 rcv_error : 1; > + u64 err_code : 8; > + } s_cn38xx; > + struct { > + u64 unused1 : 16; > + u64 vlan : 16; > + u64 unused2 : 32; > + } svlan; > + struct { > + u64 bufs : 8; > + u64 unused : 8; > + u64 vlan_valid : 1; > + u64 vlan_stacked : 1; > + u64 unassigned : 1; > + u64 vlan_cfi : 1; > + u64 vlan_id : 12; > + u64 varies : 12; > + u64 unassigned2 : 4; > + u64 software : 1; > + u64 unassigned3 : 1; > + u64 is_rarp : 1; > + u64 is_arp : 1; > + u64 is_bcast : 1; > + u64 is_mcast : 1; > + u64 not_IP : 1; > + u64 rcv_error : 1; > + u64 err_code : 8; > + } snoip; > + struct { > + u64 bufs : 8; > + u64 unused : 8; > + u64 vlan_valid : 1; > + u64 vlan_stacked : 1; > + u64 unassigned : 1; > + u64 vlan_cfi : 1; > + u64 vlan_id : 12; > + u64 port : 12; > + u64 unassigned2 : 4; > + u64 software : 1; > + u64 unassigned3 : 1; > + u64 is_rarp : 1; > + u64 is_arp : 1; > + u64 is_bcast : 1; > + u64 is_mcast : 1; > + u64 not_IP : 1; > + u64 rcv_error : 1; > + u64 err_code : 8; > + } snoip_cn68xx; > + struct { > + u64 bufs : 8; > + u64 unused : 8; > + u64 vlan_valid : 1; > + u64 vlan_stacked : 1; > + u64 unassigned : 1; > + u64 vlan_cfi : 1; > + u64 vlan_id : 12; > + u64 pr : 4; > + u64 unassigned2a : 8; > + u64 unassigned2 : 4; > + u64 software : 1; > + u64 unassigned3 : 1; > + u64 is_rarp : 1; > + u64 is_arp : 1; > + u64 is_bcast : 1; > + u64 is_mcast : 1; > + u64 not_IP : 1; > + u64 rcv_error : 1; > + u64 err_code : 8; > + } snoip_cn38xx; > +} cvmx_pip_wqe_word2_t; > + > +typedef union { > + u64 u64; > + struct { > + u64 software : 1; > + u64 lg_hdr_type : 5; > + u64 lf_hdr_type : 5; > + u64 le_hdr_type : 5; > + u64 ld_hdr_type : 5; > + u64 lc_hdr_type : 5; > + u64 lb_hdr_type : 5; > + u64 is_la_ether : 1; > + u64 rsvd_0 : 8; > + u64 vlan_valid : 1; > + u64 vlan_stacked : 1; > + u64 stat_inc : 1; > + u64 pcam_flag4 : 1; > + u64 pcam_flag3 : 1; > + u64 pcam_flag2 : 1; > + u64 pcam_flag1 : 1; > + u64 is_frag : 1; > + u64 is_l3_bcast : 1; > + u64 is_l3_mcast : 1; > + u64 is_l2_bcast : 1; > + u64 is_l2_mcast : 1; > + u64 is_raw : 1; > + u64 err_level : 3; > + u64 err_code : 8; > + }; > +} cvmx_pki_wqe_word2_t; > + > +typedef union { > + u64 u64; > + cvmx_pki_wqe_word2_t pki; > + cvmx_pip_wqe_word2_t pip; > +} cvmx_wqe_word2_t; > + > +typedef union { > + u64 u64; > + struct { > + u16 hw_chksum; > + u8 unused; > + u64 next_ptr : 40; > + } cn38xx; > + struct { > + u64 l4ptr : 8; /* 56..63 */ > + u64 unused0 : 8; /* 48..55 */ > + u64 l3ptr : 8; /* 40..47 */ > + u64 l2ptr : 8; /* 32..39 */ > + u64 unused1 : 18; /* 14..31 */ > + u64 bpid : 6; /* 8..13 */ > + u64 unused2 : 2; /* 6..7 */ > + u64 pknd : 6; /* 0..5 */ > + } cn68xx; > +} cvmx_pip_wqe_word0_t; > + > +typedef union { > + u64 u64; > + struct { > + u64 rsvd_0 : 4; > + u64 aura : 12; > + u64 rsvd_1 : 1; > + u64 apad : 3; > + u64 channel : 12; > + u64 bufs : 8; > + u64 style : 8; > + u64 rsvd_2 : 10; > + u64 pknd : 6; > + }; > +} cvmx_pki_wqe_word0_t; > + > +/* Use reserved bit, set by HW to 0, to indicate buf_ptr legacy > translation*/ > +#define pki_wqe_translated word0.rsvd_1 > + > +typedef union { > + u64 u64; > + cvmx_pip_wqe_word0_t pip; > + cvmx_pki_wqe_word0_t pki; > + struct { > + u64 unused : 24; > + u64 next_ptr : 40; /* On cn68xx this is unused as well > */ > + } raw; > +} cvmx_wqe_word0_t; > + > +typedef union { > + u64 u64; > + struct { > + u64 len : 16; > + u64 rsvd_0 : 2; > + u64 rsvd_1 : 2; > + u64 grp : 10; > + cvmx_pow_tag_type_t tag_type : 2; > + u64 tag : 32; > + }; > +} cvmx_pki_wqe_word1_t; > + > +#define pki_errata20776 word1.rsvd_0 > + > +typedef union { > + u64 u64; > + struct { > + u64 len : 16; > + u64 varies : 14; > + cvmx_pow_tag_type_t tag_type : 2; > + u64 tag : 32; > + }; > + cvmx_pki_wqe_word1_t cn78xx; > + struct { > + u64 len : 16; > + u64 zero_0 : 1; > + u64 qos : 3; > + u64 zero_1 : 1; > + u64 grp : 6; > + u64 zero_2 : 3; > + cvmx_pow_tag_type_t tag_type : 2; > + u64 tag : 32; > + } cn68xx; > + struct { > + u64 len : 16; > + u64 ipprt : 6; > + u64 qos : 3; > + u64 grp : 4; > + u64 zero_2 : 1; > + cvmx_pow_tag_type_t tag_type : 2; > + u64 tag : 32; > + } cn38xx; > +} cvmx_wqe_word1_t; > + > +typedef union { > + u64 u64; > + struct { > + u64 rsvd_0 : 8; > + u64 hwerr : 8; > + u64 rsvd_1 : 24; > + u64 sqid : 8; > + u64 rsvd_2 : 4; > + u64 vfnum : 12; > + }; > +} cvmx_wqe_word3_t; > + > +typedef union { > + u64 u64; > + struct { > + u64 rsvd_0 : 21; > + u64 sqfc : 11; > + u64 rsvd_1 : 5; > + u64 sqtail : 11; > + u64 rsvd_2 : 3; > + u64 sqhead : 13; > + }; > +} cvmx_wqe_word4_t; > + > +/** > + * Work queue entry format. > + * Must be 8-byte aligned. > + */ > +typedef struct cvmx_wqe_s { > + /*------------------------------------------------------------- > ------*/ > + /* WORD > 0 */ > + /*------------------------------------------------------------- > ------*/ > + /* HW WRITE: the following 64 bits are filled by HW when a > packet > + * arrives. > + */ > + cvmx_wqe_word0_t word0; > + > + /*------------------------------------------------------------- > ------*/ > + /* WORD > 1 */ > + /*------------------------------------------------------------- > ------*/ > + /* HW WRITE: the following 64 bits are filled by HW when a > packet > + * arrives. > + */ > + cvmx_wqe_word1_t word1; > + > + /*------------------------------------------------------------- > ------*/ > + /* WORD > 2 */ > + /*------------------------------------------------------------- > ------*/ > + /* HW WRITE: the following 64-bits are filled in by hardware > when a > + * packet arrives. This indicates a variety of status and error > + *conditions. > + */ > + cvmx_pip_wqe_word2_t word2; > + > + /* Pointer to the first segment of the packet. */ > + cvmx_buf_ptr_t packet_ptr; > + > + /* HW WRITE: OCTEON will fill in a programmable amount from the > packet, > + * up to (at most, but perhaps less) the amount needed to fill > the work > + * queue entry to 128 bytes. If the packet is recognized to be > IP, the > + * hardware starts (except that the IPv4 header is padded for > + * appropriate alignment) writing here where the IP header > starts. > + * If the packet is not recognized to be IP, the hardware > starts > + * writing the beginning of the packet here. > + */ > + u8 packet_data[96]; > + > + /* If desired, SW can make the work Q entry any length. For the > purposes > + * of discussion here, Assume 128B always, as this is all that > the hardware > + * deals with. > + */ > +} CVMX_CACHE_LINE_ALIGNED cvmx_wqe_t; > + > +/** > + * Work queue entry format for NQM > + * Must be 8-byte aligned > + */ > +typedef struct cvmx_wqe_nqm_s { > + /*------------------------------------------------------------- > ------*/ > + /* WORD > 0 */ > + /*------------------------------------------------------------- > ------*/ > + /* HW WRITE: the following 64 bits are filled by HW when a > packet > + * arrives. > + */ > + cvmx_wqe_word0_t word0; > + > + /*------------------------------------------------------------- > ------*/ > + /* WORD > 1 */ > + /*------------------------------------------------------------- > ------*/ > + /* HW WRITE: the following 64 bits are filled by HW when a > packet > + * arrives. > + */ > + cvmx_wqe_word1_t word1; > + > + /*------------------------------------------------------------- > ------*/ > + /* WORD > 2 */ > + /*------------------------------------------------------------- > ------*/ > + /* Reserved */ > + u64 word2; > + > + /*------------------------------------------------------------- > ------*/ > + /* WORD > 3 */ > + /*------------------------------------------------------------- > ------*/ > + /* NVMe specific information.*/ > + cvmx_wqe_word3_t word3; > + > + /*------------------------------------------------------------- > ------*/ > + /* WORD > 4 */ > + /*------------------------------------------------------------- > ------*/ > + /* NVMe specific information.*/ > + cvmx_wqe_word4_t word4; > + > + /* HW WRITE: OCTEON will fill in a programmable amount from the > packet, > + * up to (at most, but perhaps less) the amount needed to fill > the work > + * queue entry to 128 bytes. If the packet is recognized to be > IP, the > + * hardware starts (except that the IPv4 header is padded for > + * appropriate alignment) writing here where the IP header > starts. > + * If the packet is not recognized to be IP, the hardware > starts > + * writing the beginning of the packet here. > + */ > + u8 packet_data[88]; > + > + /* If desired, SW can make the work Q entry any length. > + * For the purposes of discussion here, assume 128B always, as > this is > + * all that the hardware deals with. > + */ > +} CVMX_CACHE_LINE_ALIGNED cvmx_wqe_nqm_t; > + > +/** > + * Work queue entry format for 78XX. > + * In 78XX packet data always resides in WQE buffer unless option > + * DIS_WQ_DAT=1 in PKI_STYLE_BUF, which causes packet data to use > separate buffer. > + * > + * Must be 8-byte aligned. > + */ > +typedef struct { > + /*------------------------------------------------------------- > ------*/ > + /* WORD > 0 */ > + /*------------------------------------------------------------- > ------*/ > + /* HW WRITE: the following 64 bits are filled by HW when a > packet > + * arrives. > + */ > + cvmx_pki_wqe_word0_t word0; > + > + /*------------------------------------------------------------- > ------*/ > + /* WORD > 1 */ > + /*------------------------------------------------------------- > ------*/ > + /* HW WRITE: the following 64 bits are filled by HW when a > packet > + * arrives. > + */ > + cvmx_pki_wqe_word1_t word1; > + > + /*------------------------------------------------------------- > ------*/ > + /* WORD > 2 */ > + /*------------------------------------------------------------- > ------*/ > + /* HW WRITE: the following 64-bits are filled in by hardware > when a > + * packet arrives. This indicates a variety of status and error > + * conditions. > + */ > + cvmx_pki_wqe_word2_t word2; > + > + /*------------------------------------------------------------- > ------*/ > + /* WORD > 3 */ > + /*------------------------------------------------------------- > ------*/ > + /* Pointer to the first segment of the packet.*/ > + cvmx_buf_ptr_pki_t packet_ptr; > + > + /*------------------------------------------------------------- > ------*/ > + /* WORD > 4 */ > + /*------------------------------------------------------------- > ------*/ > + /* HW WRITE: the following 64-bits are filled in by hardware > when a > + * packet arrives contains a byte pointer to the start of Layer > + * A/B/C/D/E/F/G relative of start of packet. > + */ > + cvmx_pki_wqe_word4_t word4; > + > + /*------------------------------------------------------------- > ------*/ > + /* WORDs 5/6/7 may be extended there, if WQE_HSZ is > set. */ > + /*------------------------------------------------------------- > ------*/ > + u64 wqe_data[11]; > + > +} CVMX_CACHE_LINE_ALIGNED cvmx_wqe_78xx_t; > + > +/* Node LS-bit position in the WQE[grp] or PKI_QPG_TBL[grp_ok].*/ > +#define CVMX_WQE_GRP_NODE_SHIFT 8 > + > +/* > + * This is an accessor function into the WQE that retreives the > + * ingress port number, which can also be used as a destination > + * port number for the same port. > + * > + * @param work - Work Queue Entrey pointer > + * @returns returns the normalized port number, also known as "ipd" > port > + */ > +static inline int cvmx_wqe_get_port(cvmx_wqe_t *work) > +{ > + int port; > + > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + /* In 78xx wqe entry has channel number not port*/ > + port = work->word0.pki.channel; > + /* For BGX interfaces (0x800 - 0xdff) the 4 LSBs > indicate > + * the PFC channel, must be cleared to normalize to > "ipd" > + */ > + if (port & 0x800) > + port &= 0xff0; > + /* Node number is in AURA field, make it part of port # > */ > + port |= (work->word0.pki.aura >> 10) << 12; > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + port = work->word2.s_cn68xx.port; > + } else { > + port = work->word1.cn38xx.ipprt; > + } > + > + return port; > +} > + > +static inline void cvmx_wqe_set_port(cvmx_wqe_t *work, int port) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) > + work->word0.pki.channel = port; > + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) > + work->word2.s_cn68xx.port = port; > + else > + work->word1.cn38xx.ipprt = port; > +} > + > +static inline int cvmx_wqe_get_grp(cvmx_wqe_t *work) > +{ > + int grp; > + > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) > + /* legacy: GRP[0..2] :=QOS */ > + grp = (0xff & work->word1.cn78xx.grp) >> 3; > + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) > + grp = work->word1.cn68xx.grp; > + else > + grp = work->word1.cn38xx.grp; > + > + return grp; > +} > + > +static inline void cvmx_wqe_set_xgrp(cvmx_wqe_t *work, int grp) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) > + work->word1.cn78xx.grp = grp; > + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) > + work->word1.cn68xx.grp = grp; > + else > + work->word1.cn38xx.grp = grp; > +} > + > +static inline int cvmx_wqe_get_xgrp(cvmx_wqe_t *work) > +{ > + int grp; > + > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) > + grp = work->word1.cn78xx.grp; > + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) > + grp = work->word1.cn68xx.grp; > + else > + grp = work->word1.cn38xx.grp; > + > + return grp; > +} > + > +static inline void cvmx_wqe_set_grp(cvmx_wqe_t *work, int grp) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + unsigned int node = cvmx_get_node_num(); > + /* Legacy: GRP[0..2] :=QOS */ > + work->word1.cn78xx.grp &= 0x7; > + work->word1.cn78xx.grp |= 0xff & (grp << 3); > + work->word1.cn78xx.grp |= (node << 8); > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + work->word1.cn68xx.grp = grp; > + } else { > + work->word1.cn38xx.grp = grp; > + } > +} > + > +static inline int cvmx_wqe_get_qos(cvmx_wqe_t *work) > +{ > + int qos; > + > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + /* Legacy: GRP[0..2] :=QOS */ > + qos = work->word1.cn78xx.grp & 0x7; > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + qos = work->word1.cn68xx.qos; > + } else { > + qos = work->word1.cn38xx.qos; > + } > + > + return qos; > +} > + > +static inline void cvmx_wqe_set_qos(cvmx_wqe_t *work, int qos) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + /* legacy: GRP[0..2] :=QOS */ > + work->word1.cn78xx.grp &= ~0x7; > + work->word1.cn78xx.grp |= qos & 0x7; > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + work->word1.cn68xx.qos = qos; > + } else { > + work->word1.cn38xx.qos = qos; > + } > +} > + > +static inline int cvmx_wqe_get_len(cvmx_wqe_t *work) > +{ > + int len; > + > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) > + len = work->word1.cn78xx.len; > + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) > + len = work->word1.cn68xx.len; > + else > + len = work->word1.cn38xx.len; > + > + return len; > +} > + > +static inline void cvmx_wqe_set_len(cvmx_wqe_t *work, int len) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) > + work->word1.cn78xx.len = len; > + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) > + work->word1.cn68xx.len = len; > + else > + work->word1.cn38xx.len = len; > +} > + > +/** > + * This function returns, if there was L2/L1 errors detected in > packet. > + * > + * @param work pointer to work queue entry > + * > + * @return 0 if packet had no error, non-zero to indicate error > code. > + * > + * Please refer to HRM for the specific model for full enumaration > of error codes. > + * With Octeon1/Octeon2 models, the returned code indicates L1/L2 > errors. > + * On CN73XX/CN78XX, the return code is the value of PKI_OPCODE_E, > + * if it is non-zero, otherwise the returned code will be derived > from > + * PKI_ERRLEV_E such that an error indicated in LayerA will return > 0x20, > + * LayerB - 0x30, LayerC - 0x40 and so forth. > + */ > +static inline int cvmx_wqe_get_rcv_err(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + if (wqe->word2.err_level == CVMX_PKI_ERRLEV_E_RE || > wqe->word2.err_code != 0) > + return wqe->word2.err_code; > + else > + return (wqe->word2.err_level << 4) + 0x10; > + } else if (work->word2.snoip.rcv_error) { > + return work->word2.snoip.err_code; > + } > + > + return 0; > +} > + > +static inline u32 cvmx_wqe_get_tag(cvmx_wqe_t *work) > +{ > + return work->word1.tag; > +} > + > +static inline void cvmx_wqe_set_tag(cvmx_wqe_t *work, u32 tag) > +{ > + work->word1.tag = tag; > +} > + > +static inline int cvmx_wqe_get_tt(cvmx_wqe_t *work) > +{ > + return work->word1.tag_type; > +} > + > +static inline void cvmx_wqe_set_tt(cvmx_wqe_t *work, int tt) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + work->word1.cn78xx.tag_type = (cvmx_pow_tag_type_t)tt; > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + work->word1.cn68xx.tag_type = (cvmx_pow_tag_type_t)tt; > + work->word1.cn68xx.zero_2 = 0; > + } else { > + work->word1.cn38xx.tag_type = (cvmx_pow_tag_type_t)tt; > + work->word1.cn38xx.zero_2 = 0; > + } > +} > + > +static inline u8 cvmx_wqe_get_unused8(cvmx_wqe_t *work) > +{ > + u8 bits; > + > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + bits = wqe->word2.rsvd_0; > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + bits = work->word0.pip.cn68xx.unused1; > + } else { > + bits = work->word0.pip.cn38xx.unused; > + } > + > + return bits; > +} > + > +static inline void cvmx_wqe_set_unused8(cvmx_wqe_t *work, u8 v) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + wqe->word2.rsvd_0 = v; > + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { > + work->word0.pip.cn68xx.unused1 = v; > + } else { > + work->word0.pip.cn38xx.unused = v; > + } > +} > + > +static inline u8 cvmx_wqe_get_user_flags(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) > + return work->word0.pki.rsvd_2; > + else > + return 0; > +} > + > +static inline void cvmx_wqe_set_user_flags(cvmx_wqe_t *work, u8 v) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) > + work->word0.pki.rsvd_2 = v; > +} > + > +static inline int cvmx_wqe_get_channel(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) > + return (work->word0.pki.channel); > + else > + return cvmx_wqe_get_port(work); > +} > + > +static inline void cvmx_wqe_set_channel(cvmx_wqe_t *work, int > channel) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) > + work->word0.pki.channel = channel; > + else > + debug("%s: ERROR: not supported for model\n", > __func__); > +} > + > +static inline int cvmx_wqe_get_aura(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) > + return (work->word0.pki.aura); > + else > + return (work->packet_ptr.s.pool); > +} > + > +static inline void cvmx_wqe_set_aura(cvmx_wqe_t *work, int aura) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) > + work->word0.pki.aura = aura; > + else > + work->packet_ptr.s.pool = aura; > +} > + > +static inline int cvmx_wqe_get_style(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) > + return (work->word0.pki.style); > + return 0; > +} > + > +static inline void cvmx_wqe_set_style(cvmx_wqe_t *work, int style) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) > + work->word0.pki.style = style; > +} > + > +static inline int cvmx_wqe_is_l3_ip(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + /* Match all 4 values for v4/v6 with.without options */ > + if ((wqe->word2.lc_hdr_type & 0x1c) == > CVMX_PKI_LTYPE_E_IP4) > + return 1; > + if ((wqe->word2.le_hdr_type & 0x1c) == > CVMX_PKI_LTYPE_E_IP4) > + return 1; > + return 0; > + } else { > + return !work->word2.s_cn38xx.not_IP; > + } > +} > + > +static inline int cvmx_wqe_is_l3_ipv4(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + /* Match 2 values - with/wotuout options */ > + if ((wqe->word2.lc_hdr_type & 0x1e) == > CVMX_PKI_LTYPE_E_IP4) > + return 1; > + if ((wqe->word2.le_hdr_type & 0x1e) == > CVMX_PKI_LTYPE_E_IP4) > + return 1; > + return 0; > + } else { > + return (!work->word2.s_cn38xx.not_IP && > + !work->word2.s_cn38xx.is_v6); > + } > +} > + > +static inline int cvmx_wqe_is_l3_ipv6(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + /* Match 2 values - with/wotuout options */ > + if ((wqe->word2.lc_hdr_type & 0x1e) == > CVMX_PKI_LTYPE_E_IP6) > + return 1; > + if ((wqe->word2.le_hdr_type & 0x1e) == > CVMX_PKI_LTYPE_E_IP6) > + return 1; > + return 0; > + } else { > + return (!work->word2.s_cn38xx.not_IP && > + work->word2.s_cn38xx.is_v6); > + } > +} > + > +static inline bool cvmx_wqe_is_l4_udp_or_tcp(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + if (wqe->word2.lf_hdr_type == CVMX_PKI_LTYPE_E_TCP) > + return true; > + if (wqe->word2.lf_hdr_type == CVMX_PKI_LTYPE_E_UDP) > + return true; > + return false; > + } > + > + if (work->word2.s_cn38xx.not_IP) > + return false; > + > + return (work->word2.s_cn38xx.tcp_or_udp != 0); > +} > + > +static inline int cvmx_wqe_is_l2_bcast(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + return wqe->word2.is_l2_bcast; > + } else { > + return work->word2.s_cn38xx.is_bcast; > + } > +} > + > +static inline int cvmx_wqe_is_l2_mcast(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + return wqe->word2.is_l2_mcast; > + } else { > + return work->word2.s_cn38xx.is_mcast; > + } > +} > + > +static inline void cvmx_wqe_set_l2_bcast(cvmx_wqe_t *work, bool > bcast) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + wqe->word2.is_l2_bcast = bcast; > + } else { > + work->word2.s_cn38xx.is_bcast = bcast; > + } > +} > + > +static inline void cvmx_wqe_set_l2_mcast(cvmx_wqe_t *work, bool > mcast) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + wqe->word2.is_l2_mcast = mcast; > + } else { > + work->word2.s_cn38xx.is_mcast = mcast; > + } > +} > + > +static inline int cvmx_wqe_is_l3_bcast(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + return wqe->word2.is_l3_bcast; > + } > + debug("%s: ERROR: not supported for model\n", __func__); > + return 0; > +} > + > +static inline int cvmx_wqe_is_l3_mcast(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + return wqe->word2.is_l3_mcast; > + } > + debug("%s: ERROR: not supported for model\n", __func__); > + return 0; > +} > + > +/** > + * This function returns is there was IP error detected in packet. > + * For 78XX it does not flag ipv4 options and ipv6 extensions. > + * For older chips if PIP_GBL_CTL was proviosned to flag ip4_otions > and > + * ipv6 extension, it will be flag them. > + * @param work pointer to work queue entry > + * @return 1 -- If IP error was found in packet > + * 0 -- If no IP error was found in packet. > + */ > +static inline int cvmx_wqe_is_ip_exception(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + if (wqe->word2.err_level == CVMX_PKI_ERRLEV_E_LC) > + return 1; > + else > + return 0; > + } > + > + return work->word2.s.IP_exc; > +} > + > +static inline int cvmx_wqe_is_l4_error(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + if (wqe->word2.err_level == CVMX_PKI_ERRLEV_E_LF) > + return 1; > + else > + return 0; > + } else { > + return work->word2.s.L4_error; > + } > +} > + > +static inline void cvmx_wqe_set_vlan(cvmx_wqe_t *work, bool set) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + wqe->word2.vlan_valid = set; > + } else { > + work->word2.s.vlan_valid = set; > + } > +} > + > +static inline int cvmx_wqe_is_vlan(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + return wqe->word2.vlan_valid; > + } else { > + return work->word2.s.vlan_valid; > + } > +} > + > +static inline int cvmx_wqe_is_vlan_stacked(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + return wqe->word2.vlan_stacked; > + } else { > + return work->word2.s.vlan_stacked; > + } > +} > + > +/** > + * Extract packet data buffer pointer from work queue entry. > + * > + * Returns the legacy (Octeon1/Octeon2) buffer pointer structure > + * for the linked buffer list. > + * On CN78XX, the native buffer pointer structure is converted into > + * the legacy format. > + * The legacy buf_ptr is then stored in the WQE, and word0 reserved > + * field is set to indicate that the buffer pointers were > translated. > + * If the packet data is only found inside the work queue entry, > + * a standard buffer pointer structure is created for it. > + */ > +cvmx_buf_ptr_t cvmx_wqe_get_packet_ptr(cvmx_wqe_t *work); > + > +static inline int cvmx_wqe_get_bufs(cvmx_wqe_t *work) > +{ > + int bufs; > + > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + bufs = work->word0.pki.bufs; > + } else { > + /* Adjust for packet-in-WQE cases */ > + if (cvmx_unlikely(work->word2.s_cn38xx.bufs == 0 && > !work->word2.s.software)) > + (void)cvmx_wqe_get_packet_ptr(work); > + bufs = work->word2.s_cn38xx.bufs; > + } > + return bufs; > +} > + > +/** > + * Free Work Queue Entry memory > + * > + * Will return the WQE buffer to its pool, unless the WQE contains > + * non-redundant packet data. > + * This function is intended to be called AFTER the packet data > + * has been passed along to PKO for transmission and release. > + * It can also follow a call to cvmx_helper_free_packet_data() > + * to release the WQE after associated data was released. > + */ > +void cvmx_wqe_free(cvmx_wqe_t *work); > + > +/** > + * Check if a work entry has been intiated by software > + * > + */ > +static inline bool cvmx_wqe_is_soft(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + return wqe->word2.software; > + } else { > + return work->word2.s.software; > + } > +} > + > +/** > + * Allocate a work-queue entry for delivering software-initiated > + * event notifications. > + * The application data is copied into the work-queue entry, > + * if the space is sufficient. > + */ > +cvmx_wqe_t *cvmx_wqe_soft_create(void *data_p, unsigned int > data_sz); > + > +/* Errata (PKI-20776) PKI_BUFLINK_S's are endian-swapped > + * CN78XX pass 1.x has a bug where the packet pointer in each > segment is > + * written in the opposite endianness of the configured mode. Fix > these here. > + */ > +static inline void cvmx_wqe_pki_errata_20776(cvmx_wqe_t *work) > +{ > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X) && !wqe- > >pki_errata20776) { > + u64 bufs; > + cvmx_buf_ptr_pki_t buffer_next; > + > + bufs = wqe->word0.bufs; > + buffer_next = wqe->packet_ptr; > + while (bufs > 1) { > + cvmx_buf_ptr_pki_t next; > + void *nextaddr = > cvmx_phys_to_ptr(buffer_next.addr - 8); > + > + memcpy(&next, nextaddr, sizeof(next)); > + next.u64 = __builtin_bswap64(next.u64); > + memcpy(nextaddr, &next, sizeof(next)); > + buffer_next = next; > + bufs--; > + } > + wqe->pki_errata20776 = 1; > + } > +} > + > +/** > + * @INTERNAL > + * > + * Extract the native PKI-specific buffer pointer from WQE. > + * > + * NOTE: Provisional, may be superceded. > + */ > +static inline cvmx_buf_ptr_pki_t cvmx_wqe_get_pki_pkt_ptr(cvmx_wqe_t > *work) > +{ > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_buf_ptr_pki_t x = { 0 }; > + return x; > + } > + > + cvmx_wqe_pki_errata_20776(work); > + return wqe->packet_ptr; > +} > + > +/** > + * Set the buffer segment count for a packet. > + * > + * @return Returns the actual resulting value in the WQE fielda > + * > + */ > +static inline unsigned int cvmx_wqe_set_bufs(cvmx_wqe_t *work, > unsigned int bufs) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + work->word0.pki.bufs = bufs; > + return work->word0.pki.bufs; > + } > + > + work->word2.s.bufs = bufs; > + return work->word2.s.bufs; > +} > + > +/** > + * Get the offset of Layer-3 header, > + * only supported when Layer-3 protocol is IPv4 or IPv6. > + * > + * @return Returns the offset, or 0 if the offset is not known or > unsupported. > + * > + * FIXME: Assuming word4 is present. > + */ > +static inline unsigned int cvmx_wqe_get_l3_offset(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + /* Match 4 values: IPv4/v6 w/wo options */ > + if ((wqe->word2.lc_hdr_type & 0x1c) == > CVMX_PKI_LTYPE_E_IP4) > + return wqe->word4.ptr_layer_c; > + } else { > + return work->word2.s.ip_offset; > + } > + > + return 0; > +} > + > +/** > + * Set the offset of Layer-3 header in a packet. > + * Typically used when an IP packet is generated by software > + * or when the Layer-2 header length is modified, and > + * a subsequent recalculation of checksums is anticipated. > + * > + * @return Returns the actual value of the work entry offset field. > + * > + * FIXME: Assuming word4 is present. > + */ > +static inline unsigned int cvmx_wqe_set_l3_offset(cvmx_wqe_t *work, > unsigned int ip_off) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + /* Match 4 values: IPv4/v6 w/wo options */ > + if ((wqe->word2.lc_hdr_type & 0x1c) == > CVMX_PKI_LTYPE_E_IP4) > + wqe->word4.ptr_layer_c = ip_off; > + } else { > + work->word2.s.ip_offset = ip_off; > + } > + > + return cvmx_wqe_get_l3_offset(work); > +} > + > +/** > + * Set the indication that the packet contains a IPv4 Layer-3 * > header. > + * Use 'cvmx_wqe_set_l3_ipv6()' if the protocol is IPv6. > + * When 'set' is false, the call will result in an indication > + * that the Layer-3 protocol is neither IPv4 nor IPv6. > + * > + * FIXME: Add IPV4_OPT handling based on L3 header length. > + */ > +static inline void cvmx_wqe_set_l3_ipv4(cvmx_wqe_t *work, bool set) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + if (set) > + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_IP4; > + else > + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_NONE; > + } else { > + work->word2.s.not_IP = !set; > + if (set) > + work->word2.s_cn38xx.is_v6 = 0; > + } > +} > + > +/** > + * Set packet Layer-3 protocol to IPv6. > + * > + * FIXME: Add IPV6_OPT handling based on presence of extended > headers. > + */ > +static inline void cvmx_wqe_set_l3_ipv6(cvmx_wqe_t *work, bool set) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + if (set) > + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_IP6; > + else > + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_NONE; > + } else { > + work->word2.s_cn38xx.not_IP = !set; > + if (set) > + work->word2.s_cn38xx.is_v6 = 1; > + } > +} > + > +/** > + * Set a packet Layer-4 protocol type to UDP. > + */ > +static inline void cvmx_wqe_set_l4_udp(cvmx_wqe_t *work, bool set) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + if (set) > + wqe->word2.lf_hdr_type = CVMX_PKI_LTYPE_E_UDP; > + else > + wqe->word2.lf_hdr_type = CVMX_PKI_LTYPE_E_NONE; > + } else { > + if (!work->word2.s_cn38xx.not_IP) > + work->word2.s_cn38xx.tcp_or_udp = set; > + } > +} > + > +/** > + * Set a packet Layer-4 protocol type to TCP. > + */ > +static inline void cvmx_wqe_set_l4_tcp(cvmx_wqe_t *work, bool set) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + if (set) > + wqe->word2.lf_hdr_type = CVMX_PKI_LTYPE_E_TCP; > + else > + wqe->word2.lf_hdr_type = CVMX_PKI_LTYPE_E_NONE; > + } else { > + if (!work->word2.s_cn38xx.not_IP) > + work->word2.s_cn38xx.tcp_or_udp = set; > + } > +} > + > +/** > + * Set the "software" flag in a work entry. > + */ > +static inline void cvmx_wqe_set_soft(cvmx_wqe_t *work, bool set) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + wqe->word2.software = set; > + } else { > + work->word2.s.software = set; > + } > +} > + > +/** > + * Return true if the packet is an IP fragment. > + */ > +static inline bool cvmx_wqe_is_l3_frag(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + return (wqe->word2.is_frag != 0); > + } > + > + if (!work->word2.s_cn38xx.not_IP) > + return (work->word2.s.is_frag != 0); > + > + return false; > +} > + > +/** > + * Set the indicator that the packet is an fragmented IP packet. > + */ > +static inline void cvmx_wqe_set_l3_frag(cvmx_wqe_t *work, bool set) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + wqe->word2.is_frag = set; > + } else { > + if (!work->word2.s_cn38xx.not_IP) > + work->word2.s.is_frag = set; > + } > +} > + > +/** > + * Set the packet Layer-3 protocol to RARP. > + */ > +static inline void cvmx_wqe_set_l3_rarp(cvmx_wqe_t *work, bool set) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + if (set) > + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_RARP; > + else > + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_NONE; > + } else { > + work->word2.snoip.is_rarp = set; > + } > +} > + > +/** > + * Set the packet Layer-3 protocol to ARP. > + */ > +static inline void cvmx_wqe_set_l3_arp(cvmx_wqe_t *work, bool set) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + if (set) > + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_ARP; > + else > + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_NONE; > + } else { > + work->word2.snoip.is_arp = set; > + } > +} > + > +/** > + * Return true if the packet Layer-3 protocol is ARP. > + */ > +static inline bool cvmx_wqe_is_l3_arp(cvmx_wqe_t *work) > +{ > + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { > + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; > + > + return (wqe->word2.lc_hdr_type == > CVMX_PKI_LTYPE_E_ARP); > + } > + > + if (work->word2.s_cn38xx.not_IP) > + return (work->word2.snoip.is_arp != 0); > + > + return false; > +} > + > +#endif /* __CVMX_WQE_H__ */ > diff --git a/arch/mips/mach-octeon/include/mach/octeon_qlm.h > b/arch/mips/mach-octeon/include/mach/octeon_qlm.h > new file mode 100644 > index 000000000000..219625b25688 > --- /dev/null > +++ b/arch/mips/mach-octeon/include/mach/octeon_qlm.h > @@ -0,0 +1,109 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + */ > + > +#ifndef __OCTEON_QLM_H__ > +#define __OCTEON_QLM_H__ > + > +/* Reference clock selector values for ref_clk_sel */ > +#define OCTEON_QLM_REF_CLK_100MHZ 0 /** 100 MHz */ > +#define OCTEON_QLM_REF_CLK_125MHZ 1 /** 125 MHz */ > +#define OCTEON_QLM_REF_CLK_156MHZ 2 /** 156.25 MHz */ > +#define OCTEON_QLM_REF_CLK_161MHZ 3 /** 161.1328125 MHz */ > + > +/** > + * Configure qlm/dlm speed and mode. > + * @param qlm The QLM or DLM to configure > + * @param speed The speed the QLM needs to be configured in Mhz. > + * @param mode The QLM to be configured as SGMII/XAUI/PCIe. > + * @param rc Only used for PCIe, rc = 1 for root complex mode, > 0 for EP > + * mode. > + * @param pcie_mode Only used when qlm/dlm are in pcie mode. > + * @param ref_clk_sel Reference clock to use for 70XX where: > + * 0: 100MHz > + * 1: 125MHz > + * 2: 156.25MHz > + * 3: 161.1328125MHz (CN73XX and CN78XX only) > + * @param ref_clk_input This selects which reference clock > input to use. For > + * cn70xx: > + * 0: DLMC_REF_CLK0 > + * 1: DLMC_REF_CLK1 > + * 2: DLM0_REF_CLK > + * cn61xx: (not used) > + * cn78xx/cn76xx/cn73xx: > + * 0: Internal clock (QLM[0-7]_REF_CLK) > + * 1: QLMC_REF_CLK0 > + * 2: QLMC_REF_CLK1 > + * > + * @return Return 0 on success or -1. > + * > + * @note When the 161MHz clock is used it can only be used for > + * XLAUI mode with a 6316 speed or XFI mode with a 103125 > speed. > + * This rate is also only supported for CN73XX and CN78XX. > + */ > +int octeon_configure_qlm(int qlm, int speed, int mode, int rc, int > pcie_mode, int ref_clk_sel, > + int ref_clk_input); > + > +int octeon_configure_qlm_cn78xx(int node, int qlm, int speed, int > mode, int rc, int pcie_mode, > + int ref_clk_sel, int ref_clk_input); > + > +/** > + * Some QLM speeds need to override the default tuning parameters > + * > + * @param node Node to configure > + * @param qlm QLM to configure > + * @param baud_mhz Desired speed in MHz > + * @param lane Lane the apply the tuning parameters > + * @param tx_swing Voltage swing. The higher the value the lower > the voltage, > + * the default value is 7. > + * @param tx_pre pre-cursor pre-emphasis > + * @param tx_post post-cursor pre-emphasis. > + * @param tx_gain Transmit gain. Range 0-7 > + * @param tx_vboost Transmit voltage boost. Range 0-1 > + */ > +void octeon_qlm_tune_per_lane_v3(int node, int qlm, int baud_mhz, > int lane, int tx_swing, > + int tx_pre, int tx_post, int tx_gain, > int tx_vboost); > + > +/** > + * Some QLM speeds need to override the default tuning parameters > + * > + * @param node Node to configure > + * @param qlm QLM to configure > + * @param baud_mhz Desired speed in MHz > + * @param tx_swing Voltage swing. The higher the value the lower > the voltage, > + * the default value is 7. > + * @param tx_premptap bits [0:3] pre-cursor pre-emphasis, bits[4:8] > post-cursor > + * pre-emphasis. > + * @param tx_gain Transmit gain. Range 0-7 > + * @param tx_vboost Transmit voltage boost. Range 0-1 > + */ > +void octeon_qlm_tune_v3(int node, int qlm, int baud_mhz, int > tx_swing, int tx_premptap, int tx_gain, > + int tx_vboost); > + > +/** > + * Disables DFE for the specified QLM lane(s). > + * This function should only be called for low-loss channels. > + * > + * @param node Node to configure > + * @param qlm QLM to configure > + * @param lane Lane to configure, or -1 all lanes > + * @param baud_mhz The speed the QLM needs to be configured in Mhz. > + * @param mode The QLM to be configured as SGMII/XAUI/PCIe. > + */ > +void octeon_qlm_dfe_disable(int node, int qlm, int lane, int > baud_mhz, int mode); > + > +/** > + * Some QLMs need to override the default pre-ctle for low loss > channels. > + * > + * @param node Node to configure > + * @param qlm QLM to configure > + * @param pre_ctle pre-ctle settings for low loss channels > + */ > +void octeon_qlm_set_channel_v3(int node, int qlm, int pre_ctle); > + > +void octeon_init_qlm(int node); > + > +int octeon_mcu_probe(int node); > + > +#endif /* __OCTEON_QLM_H__ */
Hi Daniel, On 23.04.21 18:38, Daniel Schwierzeck wrote: > Hi Stefan, > > Am Freitag, den 23.04.2021, 05:56 +0200 schrieb Stefan Roese: >> From: Aaron Williams <awilliams@marvell.com> >> >> Import misc remaining header files from 2013 U-Boot. These will be >> used >> by the later added drivers to support PCIe and networking on the MIPS >> Octeon II / III platforms. >> >> Signed-off-by: Aaron Williams <awilliams@marvell.com> >> Signed-off-by: Stefan Roese <sr@denx.de> >> Cc: Aaron Williams <awilliams@marvell.com> >> Cc: Chandrakala Chavva <cchavva@marvell.com> >> Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com> >> --- >> v2: >> - Add missing mach/octeon_qlm.h file (forgot to commit it in v1) >> > > the patch didn't show up in patchwork. But when manually applying, > there is still a build error due to missing mach/octeon_fdt.h Ah, sorry. I still missed 2 additional headers to commit. v3 will follow very soon. Thanks, Stefan >> .../mach-octeon/include/mach/cvmx-address.h | 209 ++ >> .../mach-octeon/include/mach/cvmx-cmd-queue.h | 441 +++ >> .../mach-octeon/include/mach/cvmx-csr-enums.h | 87 + >> arch/mips/mach-octeon/include/mach/cvmx-csr.h | 78 + >> .../mach-octeon/include/mach/cvmx-error.h | 456 +++ >> arch/mips/mach-octeon/include/mach/cvmx-fpa.h | 217 ++ >> .../mips/mach-octeon/include/mach/cvmx-fpa1.h | 196 ++ >> .../mips/mach-octeon/include/mach/cvmx-fpa3.h | 566 ++++ >> .../include/mach/cvmx-global-resources.h | 213 ++ >> arch/mips/mach-octeon/include/mach/cvmx-gmx.h | 16 + >> .../mach-octeon/include/mach/cvmx-hwfau.h | 606 ++++ >> .../mach-octeon/include/mach/cvmx-hwpko.h | 570 ++++ >> arch/mips/mach-octeon/include/mach/cvmx-ilk.h | 154 + >> arch/mips/mach-octeon/include/mach/cvmx-ipd.h | 233 ++ >> .../mach-octeon/include/mach/cvmx-packet.h | 40 + >> .../mips/mach-octeon/include/mach/cvmx-pcie.h | 279 ++ >> arch/mips/mach-octeon/include/mach/cvmx-pip.h | 1080 ++++++ >> .../include/mach/cvmx-pki-resources.h | 157 + >> arch/mips/mach-octeon/include/mach/cvmx-pki.h | 970 ++++++ >> .../mach/cvmx-pko-internal-ports-range.h | 43 + >> .../include/mach/cvmx-pko3-queue.h | 175 + >> arch/mips/mach-octeon/include/mach/cvmx-pow.h | 2991 >> +++++++++++++++++ >> arch/mips/mach-octeon/include/mach/cvmx-qlm.h | 304 ++ >> .../mach-octeon/include/mach/cvmx-scratch.h | 113 + >> arch/mips/mach-octeon/include/mach/cvmx-wqe.h | 1462 ++++++++ >> .../mach-octeon/include/mach/octeon_qlm.h | 109 + >> 26 files changed, 11765 insertions(+) >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-address.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-cmd- >> queue.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-csr- >> enums.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-csr.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-error.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-fpa.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-fpa1.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-fpa3.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-global- >> resources.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-gmx.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-hwfau.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-hwpko.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-ilk.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-ipd.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-packet.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-pcie.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-pip.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-pki- >> resources.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-pki.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-pko- >> internal-ports-range.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-pko3- >> queue.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-pow.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-qlm.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-scratch.h >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-wqe.h >> create mode 100644 arch/mips/mach-octeon/include/mach/octeon_qlm.h >> >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-address.h >> b/arch/mips/mach-octeon/include/mach/cvmx-address.h >> new file mode 100644 >> index 000000000000..984f574a75bb >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-address.h >> @@ -0,0 +1,209 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Typedefs and defines for working with Octeon physical addresses. >> + */ >> + >> +#ifndef __CVMX_ADDRESS_H__ >> +#define __CVMX_ADDRESS_H__ >> + >> +typedef enum { >> + CVMX_MIPS_SPACE_XKSEG = 3LL, >> + CVMX_MIPS_SPACE_XKPHYS = 2LL, >> + CVMX_MIPS_SPACE_XSSEG = 1LL, >> + CVMX_MIPS_SPACE_XUSEG = 0LL >> +} cvmx_mips_space_t; >> + >> +typedef enum { >> + CVMX_MIPS_XKSEG_SPACE_KSEG0 = 0LL, >> + CVMX_MIPS_XKSEG_SPACE_KSEG1 = 1LL, >> + CVMX_MIPS_XKSEG_SPACE_SSEG = 2LL, >> + CVMX_MIPS_XKSEG_SPACE_KSEG3 = 3LL >> +} cvmx_mips_xkseg_space_t; >> + >> +/* decodes <14:13> of a kseg3 window address */ >> +typedef enum { >> + CVMX_ADD_WIN_SCR = 0L, >> + CVMX_ADD_WIN_DMA = 1L, >> + CVMX_ADD_WIN_UNUSED = 2L, >> + CVMX_ADD_WIN_UNUSED2 = 3L >> +} cvmx_add_win_dec_t; >> + >> +/* decode within DMA space */ >> +typedef enum { >> + CVMX_ADD_WIN_DMA_ADD = 0L, >> + CVMX_ADD_WIN_DMA_SENDMEM = 1L, >> + /* store data must be normal DRAM memory space address in this >> case */ >> + CVMX_ADD_WIN_DMA_SENDDMA = 2L, >> + /* see CVMX_ADD_WIN_DMA_SEND_DEC for data contents */ >> + CVMX_ADD_WIN_DMA_SENDIO = 3L, >> + /* store data must be normal IO space address in this case */ >> + CVMX_ADD_WIN_DMA_SENDSINGLE = 4L, >> + /* no write buffer data needed/used */ >> +} cvmx_add_win_dma_dec_t; >> + >> +/** >> + * Physical Address Decode >> + * >> + * Octeon-I HW never interprets this X (<39:36> reserved >> + * for future expansion), software should set to 0. >> + * >> + * - 0x0 XXX0 0000 0000 to DRAM Cached >> + * - 0x0 XXX0 0FFF FFFF >> + * >> + * - 0x0 XXX0 1000 0000 to Boot Bus Uncached (Converted >> to 0x1 00X0 1000 0000 >> + * - 0x0 XXX0 1FFF FFFF + >> EJTAG to 0x1 00X0 1FFF FFFF) >> + * >> + * - 0x0 XXX0 2000 0000 to DRAM Cached >> + * - 0x0 XXXF FFFF FFFF >> + * >> + * - 0x1 00X0 0000 0000 to Boot Bus Uncached >> + * - 0x1 00XF FFFF FFFF >> + * >> + * - 0x1 01X0 0000 0000 to Other NCB Uncached >> + * - 0x1 FFXF FFFF FFFF devices >> + * >> + * Decode of all Octeon addresses >> + */ >> +typedef union { >> + u64 u64; >> + struct { >> + cvmx_mips_space_t R : 2; >> + u64 offset : 62; >> + } sva; >> + >> + struct { >> + u64 zeroes : 33; >> + u64 offset : 31; >> + } suseg; >> + >> + struct { >> + u64 ones : 33; >> + cvmx_mips_xkseg_space_t sp : 2; >> + u64 offset : 29; >> + } sxkseg; >> + >> + struct { >> + cvmx_mips_space_t R : 2; >> + u64 cca : 3; >> + u64 mbz : 10; >> + u64 pa : 49; >> + } sxkphys; >> + >> + struct { >> + u64 mbz : 15; >> + u64 is_io : 1; >> + u64 did : 8; >> + u64 unaddr : 4; >> + u64 offset : 36; >> + } sphys; >> + >> + struct { >> + u64 zeroes : 24; >> + u64 unaddr : 4; >> + u64 offset : 36; >> + } smem; >> + >> + struct { >> + u64 mem_region : 2; >> + u64 mbz : 13; >> + u64 is_io : 1; >> + u64 did : 8; >> + u64 unaddr : 4; >> + u64 offset : 36; >> + } sio; >> + >> + struct { >> + u64 ones : 49; >> + cvmx_add_win_dec_t csrdec : 2; >> + u64 addr : 13; >> + } sscr; >> + >> + /* there should only be stores to IOBDMA space, no loads */ >> + struct { >> + u64 ones : 49; >> + cvmx_add_win_dec_t csrdec : 2; >> + u64 unused2 : 3; >> + cvmx_add_win_dma_dec_t type : 3; >> + u64 addr : 7; >> + } sdma; >> + >> + struct { >> + u64 didspace : 24; >> + u64 unused : 40; >> + } sfilldidspace; >> +} cvmx_addr_t; >> + >> +/* These macros for used by 32 bit applications */ >> + >> +#define CVMX_MIPS32_SPACE_KSEG0 1l >> +#define CVMX_ADD_SEG32(segment, add) (((s32)segment << 31) | >> (s32)(add)) >> + >> +/* >> + * Currently all IOs are performed using XKPHYS addressing. Linux >> uses the >> + * CvmMemCtl register to enable XKPHYS addressing to IO space from >> user mode. >> + * Future OSes may need to change the upper bits of IO addresses. >> The >> + * following define controls the upper two bits for all IO addresses >> generated >> + * by the simple executive library >> + */ >> +#define CVMX_IO_SEG CVMX_MIPS_SPACE_XKPHYS >> + >> +/* These macros simplify the process of creating common IO addresses >> */ >> +#define CVMX_ADD_SEG(segment, add) ((((u64)segment) << 62) | (add)) >> + >> +#define CVMX_ADD_IO_SEG(add) (add) >> + >> +#define CVMX_ADDR_DIDSPACE(did) (((CVMX_IO_SEG) << 22) | >> ((1ULL) << 8) | (did)) >> +#define CVMX_ADDR_DID(did) (CVMX_ADDR_DIDSPACE(did) << 40) >> +#define CVMX_FULL_DID(did, subdid) (((did) << 3) | (subdid)) >> + >> +/* from include/ncb_rsl_id.v */ >> +#define CVMX_OCT_DID_MIS 0ULL /* misc stuff */ >> +#define CVMX_OCT_DID_GMX0 1ULL >> +#define CVMX_OCT_DID_GMX1 2ULL >> +#define CVMX_OCT_DID_PCI 3ULL >> +#define CVMX_OCT_DID_KEY 4ULL >> +#define CVMX_OCT_DID_FPA 5ULL >> +#define CVMX_OCT_DID_DFA 6ULL >> +#define CVMX_OCT_DID_ZIP 7ULL >> +#define CVMX_OCT_DID_RNG 8ULL >> +#define CVMX_OCT_DID_IPD 9ULL >> +#define CVMX_OCT_DID_PKT 10ULL >> +#define CVMX_OCT_DID_TIM 11ULL >> +#define CVMX_OCT_DID_TAG 12ULL >> +/* the rest are not on the IO bus */ >> +#define CVMX_OCT_DID_L2C 16ULL >> +#define CVMX_OCT_DID_LMC 17ULL >> +#define CVMX_OCT_DID_SPX0 18ULL >> +#define CVMX_OCT_DID_SPX1 19ULL >> +#define CVMX_OCT_DID_PIP 20ULL >> +#define CVMX_OCT_DID_ASX0 22ULL >> +#define CVMX_OCT_DID_ASX1 23ULL >> +#define CVMX_OCT_DID_IOB 30ULL >> + >> +#define CVMX_OCT_DID_PKT_SEND CVMX_FULL_DID(CVMX_OCT_DID_PKT >> , 2ULL) >> +#define CVMX_OCT_DID_TAG_SWTAG CVMX_FULL_DID(CVMX_OCT_DID_TAG >> , 0ULL) >> +#define CVMX_OCT_DID_TAG_TAG1 CVMX_FULL_DID(CVMX_OCT_DID_TAG >> , 1ULL) >> +#define CVMX_OCT_DID_TAG_TAG2 CVMX_FULL_DID(CVMX_OCT_DID_TAG >> , 2ULL) >> +#define CVMX_OCT_DID_TAG_TAG3 CVMX_FULL_DID(CVMX_OCT_DID_TAG >> , 3ULL) >> +#define CVMX_OCT_DID_TAG_NULL_RD CVMX_FULL_DID(CVMX_OCT_DID_TAG, >> 4ULL) >> +#define CVMX_OCT_DID_TAG_TAG5 CVMX_FULL_DID(CVMX_OCT_DID_TAG >> , 5ULL) >> +#define CVMX_OCT_DID_TAG_CSR CVMX_FULL_DID(CVMX_OCT_DID_TAG, 7ULL) >> +#define CVMX_OCT_DID_FAU_FAI CVMX_FULL_DID(CVMX_OCT_DID_IOB, 0ULL) >> +#define CVMX_OCT_DID_TIM_CSR CVMX_FULL_DID(CVMX_OCT_DID_TIM, 0ULL) >> +#define CVMX_OCT_DID_KEY_RW CVMX_FULL_DID(CVMX_OCT_DID_KEY, 0ULL) >> +#define CVMX_OCT_DID_PCI_6 CVMX_FULL_DID(CVMX_OCT_DID_PCI, 6ULL) >> +#define CVMX_OCT_DID_MIS_BOO CVMX_FULL_DID(CVMX_OCT_DID_MIS, 0ULL) >> +#define CVMX_OCT_DID_PCI_RML CVMX_FULL_DID(CVMX_OCT_DID_PCI, 0ULL) >> +#define CVMX_OCT_DID_IPD_CSR CVMX_FULL_DID(CVMX_OCT_DID_IPD, 7ULL) >> +#define CVMX_OCT_DID_DFA_CSR CVMX_FULL_DID(CVMX_OCT_DID_DFA, 7ULL) >> +#define CVMX_OCT_DID_MIS_CSR CVMX_FULL_DID(CVMX_OCT_DID_MIS, 7ULL) >> +#define CVMX_OCT_DID_ZIP_CSR CVMX_FULL_DID(CVMX_OCT_DID_ZIP, 0ULL) >> + >> +/* Cast to unsigned long long, mainly for use in printfs. */ >> +#define CAST_ULL(v) ((unsigned long long)(v)) >> + >> +#define UNMAPPED_PTR(x) ((1ULL << 63) | (x)) >> + >> +#endif /* __CVMX_ADDRESS_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-cmd-queue.h >> b/arch/mips/mach-octeon/include/mach/cvmx-cmd-queue.h >> new file mode 100644 >> index 000000000000..ddc294348cb4 >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-cmd-queue.h >> @@ -0,0 +1,441 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Support functions for managing command queues used for >> + * various hardware blocks. >> + * >> + * The common command queue infrastructure abstracts out the >> + * software necessary for adding to Octeon's chained queue >> + * structures. These structures are used for commands to the >> + * PKO, ZIP, DFA, RAID, HNA, and DMA engine blocks. Although each >> + * hardware unit takes commands and CSRs of different types, >> + * they all use basic linked command buffers to store the >> + * pending request. In general, users of the CVMX API don't >> + * call cvmx-cmd-queue functions directly. Instead the hardware >> + * unit specific wrapper should be used. The wrappers perform >> + * unit specific validation and CSR writes to submit the >> + * commands. >> + * >> + * Even though most software will never directly interact with >> + * cvmx-cmd-queue, knowledge of its internal workings can help >> + * in diagnosing performance problems and help with debugging. >> + * >> + * Command queue pointers are stored in a global named block >> + * called "cvmx_cmd_queues". Except for the PKO queues, each >> + * hardware queue is stored in its own cache line to reduce SMP >> + * contention on spin locks. The PKO queues are stored such that >> + * every 16th queue is next to each other in memory. This scheme >> + * allows for queues being in separate cache lines when there >> + * are low number of queues per port. With 16 queues per port, >> + * the first queue for each port is in the same cache area. The >> + * second queues for each port are in another area, etc. This >> + * allows software to implement very efficient lockless PKO with >> + * 16 queues per port using a minimum of cache lines per core. >> + * All queues for a given core will be isolated in the same >> + * cache area. >> + * >> + * In addition to the memory pointer layout, cvmx-cmd-queue >> + * provides an optimized fair ll/sc locking mechanism for the >> + * queues. The lock uses a "ticket / now serving" model to >> + * maintain fair order on contended locks. In addition, it uses >> + * predicted locking time to limit cache contention. When a core >> + * know it must wait in line for a lock, it spins on the >> + * internal cycle counter to completely eliminate any causes of >> + * bus traffic. >> + */ >> + >> +#ifndef __CVMX_CMD_QUEUE_H__ >> +#define __CVMX_CMD_QUEUE_H__ >> + >> +/** >> + * By default we disable the max depth support. Most programs >> + * don't use it and it slows down the command queue processing >> + * significantly. >> + */ >> +#ifndef CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH >> +#define CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH 0 >> +#endif >> + >> +/** >> + * Enumeration representing all hardware blocks that use command >> + * queues. Each hardware block has up to 65536 sub identifiers for >> + * multiple command queues. Not all chips support all hardware >> + * units. >> + */ >> +typedef enum { >> + CVMX_CMD_QUEUE_PKO_BASE = 0x00000, >> +#define >> CVMX_CMD_QUEUE_PKO(queue) >> \ >> + ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_PKO_BASE + (0xffff & >> (queue)))) >> + CVMX_CMD_QUEUE_ZIP = 0x10000, >> +#define >> CVMX_CMD_QUEUE_ZIP_QUE(queue) >> \ >> + ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_ZIP + (0xffff & >> (queue)))) >> + CVMX_CMD_QUEUE_DFA = 0x20000, >> + CVMX_CMD_QUEUE_RAID = 0x30000, >> + CVMX_CMD_QUEUE_DMA_BASE = 0x40000, >> +#define >> CVMX_CMD_QUEUE_DMA(queue) >> \ >> + ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_DMA_BASE + (0xffff & >> (queue)))) >> + CVMX_CMD_QUEUE_BCH = 0x50000, >> +#define CVMX_CMD_QUEUE_BCH(queue) >> ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_BCH + (0xffff & (queue)))) >> + CVMX_CMD_QUEUE_HNA = 0x60000, >> + CVMX_CMD_QUEUE_END = 0x70000, >> +} cvmx_cmd_queue_id_t; >> + >> +#define CVMX_CMD_QUEUE_ZIP3_QUE(node, >> queue) \ >> + ((cvmx_cmd_queue_id_t)((node) << 24 | CVMX_CMD_QUEUE_ZIP | >> (0xffff & (queue)))) >> + >> +/** >> + * Command write operations can fail if the command queue needs >> + * a new buffer and the associated FPA pool is empty. It can also >> + * fail if the number of queued command words reaches the maximum >> + * set at initialization. >> + */ >> +typedef enum { >> + CVMX_CMD_QUEUE_SUCCESS = 0, >> + CVMX_CMD_QUEUE_NO_MEMORY = -1, >> + CVMX_CMD_QUEUE_FULL = -2, >> + CVMX_CMD_QUEUE_INVALID_PARAM = -3, >> + CVMX_CMD_QUEUE_ALREADY_SETUP = -4, >> +} cvmx_cmd_queue_result_t; >> + >> +typedef struct { >> + /* First 64-bit word: */ >> + u64 fpa_pool : 16; >> + u64 base_paddr : 48; >> + s32 index; >> + u16 max_depth; >> + u16 pool_size_m1; >> +} __cvmx_cmd_queue_state_t; >> + >> +/** >> + * command-queue locking uses a fair ticket spinlock algo, >> + * with 64-bit tickets for endianness-neutrality and >> + * counter overflow protection. >> + * Lock is free when both counters are of equal value. >> + */ >> +typedef struct { >> + u64 ticket; >> + u64 now_serving; >> +} __cvmx_cmd_queue_lock_t; >> + >> +/** >> + * @INTERNAL >> + * This structure contains the global state of all command queues. >> + * It is stored in a bootmem named block and shared by all >> + * applications running on Octeon. Tickets are stored in a different >> + * cache line that queue information to reduce the contention on the >> + * ll/sc used to get a ticket. If this is not the case, the update >> + * of queue state causes the ll/sc to fail quite often. >> + */ >> +typedef struct { >> + __cvmx_cmd_queue_lock_t lock[(CVMX_CMD_QUEUE_END >> 16) * 256]; >> + __cvmx_cmd_queue_state_t state[(CVMX_CMD_QUEUE_END >> 16) * >> 256]; >> +} __cvmx_cmd_queue_all_state_t; >> + >> +extern __cvmx_cmd_queue_all_state_t >> *__cvmx_cmd_queue_state_ptrs[CVMX_MAX_NODES]; >> + >> +/** >> + * @INTERNAL >> + * Internal function to handle the corner cases >> + * of adding command words to a queue when the current >> + * block is getting full. >> + */ >> +cvmx_cmd_queue_result_t >> __cvmx_cmd_queue_write_raw(cvmx_cmd_queue_id_t queue_id, >> + __cvmx_cmd_queue_sta >> te_t *qptr, int cmd_count, >> + const u64 *cmds); >> + >> +/** >> + * Initialize a command queue for use. The initial FPA buffer is >> + * allocated and the hardware unit is configured to point to the >> + * new command queue. >> + * >> + * @param queue_id Hardware command queue to initialize. >> + * @param max_depth Maximum outstanding commands that can be queued. >> + * @param fpa_pool FPA pool the command queues should come from. >> + * @param pool_size Size of each buffer in the FPA pool (bytes) >> + * >> + * @return CVMX_CMD_QUEUE_SUCCESS or a failure code >> + */ >> +cvmx_cmd_queue_result_t >> cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id, int >> max_depth, >> + int fpa_pool, int >> pool_size); >> + >> +/** >> + * Shutdown a queue a free it's command buffers to the FPA. The >> + * hardware connected to the queue must be stopped before this >> + * function is called. >> + * >> + * @param queue_id Queue to shutdown >> + * >> + * @return CVMX_CMD_QUEUE_SUCCESS or a failure code >> + */ >> +cvmx_cmd_queue_result_t cvmx_cmd_queue_shutdown(cvmx_cmd_queue_id_t >> queue_id); >> + >> +/** >> + * Return the number of command words pending in the queue. This >> + * function may be relatively slow for some hardware units. >> + * >> + * @param queue_id Hardware command queue to query >> + * >> + * @return Number of outstanding commands >> + */ >> +int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id); >> + >> +/** >> + * Return the command buffer to be written to. The purpose of this >> + * function is to allow CVMX routine access to the low level buffer >> + * for initial hardware setup. User applications should not call >> this >> + * function directly. >> + * >> + * @param queue_id Command queue to query >> + * >> + * @return Command buffer or NULL on failure >> + */ >> +void *cvmx_cmd_queue_buffer(cvmx_cmd_queue_id_t queue_id); >> + >> +/** >> + * @INTERNAL >> + * Retrieve or allocate command queue state named block >> + */ >> +cvmx_cmd_queue_result_t __cvmx_cmd_queue_init_state_ptr(unsigned int >> node); >> + >> +/** >> + * @INTERNAL >> + * Get the index into the state arrays for the supplied queue id. >> + * >> + * @param queue_id Queue ID to get an index for >> + * >> + * @return Index into the state arrays >> + */ >> +static inline unsigned int >> __cvmx_cmd_queue_get_index(cvmx_cmd_queue_id_t queue_id) >> +{ >> + /* Warning: This code currently only works with devices that >> have 256 >> + * queues or less. Devices with more than 16 queues are laid >> out in >> + * memory to allow cores quick access to every 16th queue. This >> reduces >> + * cache thrashing when you are running 16 queues per port to >> support >> + * lockless operation >> + */ >> + unsigned int unit = (queue_id >> 16) & 0xff; >> + unsigned int q = (queue_id >> 4) & 0xf; >> + unsigned int core = queue_id & 0xf; >> + >> + return (unit << 8) | (core << 4) | q; >> +} >> + >> +static inline int __cvmx_cmd_queue_get_node(cvmx_cmd_queue_id_t >> queue_id) >> +{ >> + unsigned int node = queue_id >> 24; >> + return node; >> +} >> + >> +/** >> + * @INTERNAL >> + * Lock the supplied queue so nobody else is updating it at the same >> + * time as us. >> + * >> + * @param queue_id Queue ID to lock >> + * >> + */ >> +static inline void __cvmx_cmd_queue_lock(cvmx_cmd_queue_id_t >> queue_id) >> +{ >> +} >> + >> +/** >> + * @INTERNAL >> + * Unlock the queue, flushing all writes. >> + * >> + * @param queue_id Queue ID to lock >> + * >> + */ >> +static inline void __cvmx_cmd_queue_unlock(cvmx_cmd_queue_id_t >> queue_id) >> +{ >> + CVMX_SYNCWS; /* nudge out the unlock. */ >> +} >> + >> +/** >> + * @INTERNAL >> + * Initialize a command-queue lock to "unlocked" state. >> + */ >> +static inline void __cvmx_cmd_queue_lock_init(cvmx_cmd_queue_id_t >> queue_id) >> +{ >> + unsigned int index = __cvmx_cmd_queue_get_index(queue_id); >> + unsigned int node = __cvmx_cmd_queue_get_node(queue_id); >> + >> + __cvmx_cmd_queue_state_ptrs[node]->lock[index] = >> (__cvmx_cmd_queue_lock_t){ 0, 0 }; >> + CVMX_SYNCWS; >> +} >> + >> +/** >> + * @INTERNAL >> + * Get the queue state structure for the given queue id >> + * >> + * @param queue_id Queue id to get >> + * >> + * @return Queue structure or NULL on failure >> + */ >> +static inline __cvmx_cmd_queue_state_t >> *__cvmx_cmd_queue_get_state(cvmx_cmd_queue_id_t queue_id) >> +{ >> + unsigned int index; >> + unsigned int node; >> + __cvmx_cmd_queue_state_t *qptr; >> + >> + node = __cvmx_cmd_queue_get_node(queue_id); >> + index = __cvmx_cmd_queue_get_index(queue_id); >> + >> + if (cvmx_unlikely(!__cvmx_cmd_queue_state_ptrs[node])) >> + __cvmx_cmd_queue_init_state_ptr(node); >> + >> + qptr = &__cvmx_cmd_queue_state_ptrs[node]->state[index]; >> + return qptr; >> +} >> + >> +/** >> + * Write an arbitrary number of command words to a command queue. >> + * This is a generic function; the fixed number of command word >> + * functions yield higher performance. >> + * >> + * @param queue_id Hardware command queue to write to >> + * @param use_locking >> + * Use internal locking to ensure exclusive access >> for queue >> + * updates. If you don't use this locking you must >> ensure >> + * exclusivity some other way. Locking is strongly >> recommended. >> + * @param cmd_count Number of command words to write >> + * @param cmds Array of commands to write >> + * >> + * @return CVMX_CMD_QUEUE_SUCCESS or a failure code >> + */ >> +static inline cvmx_cmd_queue_result_t >> +cvmx_cmd_queue_write(cvmx_cmd_queue_id_t queue_id, bool use_locking, >> int cmd_count, const u64 *cmds) >> +{ >> + cvmx_cmd_queue_result_t ret = CVMX_CMD_QUEUE_SUCCESS; >> + u64 *cmd_ptr; >> + >> + __cvmx_cmd_queue_state_t *qptr = >> __cvmx_cmd_queue_get_state(queue_id); >> + >> + /* Make sure nobody else is updating the same queue */ >> + if (cvmx_likely(use_locking)) >> + __cvmx_cmd_queue_lock(queue_id); >> + >> + /* Most of the time there is lots of free words in current >> block */ >> + if (cvmx_unlikely((qptr->index + cmd_count) >= qptr- >>> pool_size_m1)) { >> + /* The rare case when nearing end of block */ >> + ret = __cvmx_cmd_queue_write_raw(queue_id, qptr, >> cmd_count, cmds); >> + } else { >> + cmd_ptr = (u64 *)cvmx_phys_to_ptr((u64)qptr- >>> base_paddr); >> + /* Loop easy for compiler to unroll for the likely case >> */ >> + while (cmd_count > 0) { >> + cmd_ptr[qptr->index++] = *cmds++; >> + cmd_count--; >> + } >> + } >> + >> + /* All updates are complete. Release the lock and return */ >> + if (cvmx_likely(use_locking)) >> + __cvmx_cmd_queue_unlock(queue_id); >> + else >> + CVMX_SYNCWS; >> + >> + return ret; >> +} >> + >> +/** >> + * Simple function to write two command words to a command queue. >> + * >> + * @param queue_id Hardware command queue to write to >> + * @param use_locking >> + * Use internal locking to ensure exclusive access >> for queue >> + * updates. If you don't use this locking you must >> ensure >> + * exclusivity some other way. Locking is strongly >> recommended. >> + * @param cmd1 Command >> + * @param cmd2 Command >> + * >> + * @return CVMX_CMD_QUEUE_SUCCESS or a failure code >> + */ >> +static inline cvmx_cmd_queue_result_t >> cvmx_cmd_queue_write2(cvmx_cmd_queue_id_t queue_id, >> + bool >> use_locking, u64 cmd1, u64 cmd2) >> +{ >> + cvmx_cmd_queue_result_t ret = CVMX_CMD_QUEUE_SUCCESS; >> + u64 *cmd_ptr; >> + >> + __cvmx_cmd_queue_state_t *qptr = >> __cvmx_cmd_queue_get_state(queue_id); >> + >> + /* Make sure nobody else is updating the same queue */ >> + if (cvmx_likely(use_locking)) >> + __cvmx_cmd_queue_lock(queue_id); >> + >> + if (cvmx_unlikely((qptr->index + 2) >= qptr->pool_size_m1)) { >> + /* The rare case when nearing end of block */ >> + u64 cmds[2]; >> + >> + cmds[0] = cmd1; >> + cmds[1] = cmd2; >> + ret = __cvmx_cmd_queue_write_raw(queue_id, qptr, 2, >> cmds); >> + } else { >> + /* Likely case to work fast */ >> + cmd_ptr = (u64 *)cvmx_phys_to_ptr((u64)qptr- >>> base_paddr); >> + cmd_ptr += qptr->index; >> + qptr->index += 2; >> + cmd_ptr[0] = cmd1; >> + cmd_ptr[1] = cmd2; >> + } >> + >> + /* All updates are complete. Release the lock and return */ >> + if (cvmx_likely(use_locking)) >> + __cvmx_cmd_queue_unlock(queue_id); >> + else >> + CVMX_SYNCWS; >> + >> + return ret; >> +} >> + >> +/** >> + * Simple function to write three command words to a command queue. >> + * >> + * @param queue_id Hardware command queue to write to >> + * @param use_locking >> + * Use internal locking to ensure exclusive access >> for queue >> + * updates. If you don't use this locking you must >> ensure >> + * exclusivity some other way. Locking is strongly >> recommended. >> + * @param cmd1 Command >> + * @param cmd2 Command >> + * @param cmd3 Command >> + * >> + * @return CVMX_CMD_QUEUE_SUCCESS or a failure code >> + */ >> +static inline cvmx_cmd_queue_result_t >> +cvmx_cmd_queue_write3(cvmx_cmd_queue_id_t queue_id, bool >> use_locking, u64 cmd1, u64 cmd2, u64 cmd3) >> +{ >> + cvmx_cmd_queue_result_t ret = CVMX_CMD_QUEUE_SUCCESS; >> + __cvmx_cmd_queue_state_t *qptr = >> __cvmx_cmd_queue_get_state(queue_id); >> + u64 *cmd_ptr; >> + >> + /* Make sure nobody else is updating the same queue */ >> + if (cvmx_likely(use_locking)) >> + __cvmx_cmd_queue_lock(queue_id); >> + >> + if (cvmx_unlikely((qptr->index + 3) >= qptr->pool_size_m1)) { >> + /* Most of the time there is lots of free words in >> current block */ >> + u64 cmds[3]; >> + >> + cmds[0] = cmd1; >> + cmds[1] = cmd2; >> + cmds[2] = cmd3; >> + ret = __cvmx_cmd_queue_write_raw(queue_id, qptr, 3, >> cmds); >> + } else { >> + cmd_ptr = (u64 *)cvmx_phys_to_ptr((u64)qptr- >>> base_paddr); >> + cmd_ptr += qptr->index; >> + qptr->index += 3; >> + cmd_ptr[0] = cmd1; >> + cmd_ptr[1] = cmd2; >> + cmd_ptr[2] = cmd3; >> + } >> + >> + /* All updates are complete. Release the lock and return */ >> + if (cvmx_likely(use_locking)) >> + __cvmx_cmd_queue_unlock(queue_id); >> + else >> + CVMX_SYNCWS; >> + >> + return ret; >> +} >> + >> +#endif /* __CVMX_CMD_QUEUE_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-csr-enums.h >> b/arch/mips/mach-octeon/include/mach/cvmx-csr-enums.h >> new file mode 100644 >> index 000000000000..a8625b4228ac >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-csr-enums.h >> @@ -0,0 +1,87 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Definitions for enumerations used with Octeon CSRs. >> + */ >> + >> +#ifndef __CVMX_CSR_ENUMS_H__ >> +#define __CVMX_CSR_ENUMS_H__ >> + >> +typedef enum { >> + CVMX_IPD_OPC_MODE_STT = 0LL, >> + CVMX_IPD_OPC_MODE_STF = 1LL, >> + CVMX_IPD_OPC_MODE_STF1_STT = 2LL, >> + CVMX_IPD_OPC_MODE_STF2_STT = 3LL >> +} cvmx_ipd_mode_t; >> + >> +/** >> + * Enumeration representing the amount of packet processing >> + * and validation performed by the input hardware. >> + */ >> +typedef enum { >> + CVMX_PIP_PORT_CFG_MODE_NONE = 0ull, >> + CVMX_PIP_PORT_CFG_MODE_SKIPL2 = 1ull, >> + CVMX_PIP_PORT_CFG_MODE_SKIPIP = 2ull >> +} cvmx_pip_port_parse_mode_t; >> + >> +/** >> + * This enumeration controls how a QoS watcher matches a packet. >> + * >> + * @deprecated This enumeration was used with >> cvmx_pip_config_watcher which has >> + * been deprecated. >> + */ >> +typedef enum { >> + CVMX_PIP_QOS_WATCH_DISABLE = 0ull, >> + CVMX_PIP_QOS_WATCH_PROTNH = 1ull, >> + CVMX_PIP_QOS_WATCH_TCP = 2ull, >> + CVMX_PIP_QOS_WATCH_UDP = 3ull >> +} cvmx_pip_qos_watch_types; >> + >> +/** >> + * This enumeration is used in PIP tag config to control how >> + * POW tags are generated by the hardware. >> + */ >> +typedef enum { >> + CVMX_PIP_TAG_MODE_TUPLE = 0ull, >> + CVMX_PIP_TAG_MODE_MASK = 1ull, >> + CVMX_PIP_TAG_MODE_IP_OR_MASK = 2ull, >> + CVMX_PIP_TAG_MODE_TUPLE_XOR_MASK = 3ull >> +} cvmx_pip_tag_mode_t; >> + >> +/** >> + * Tag type definitions >> + */ >> +typedef enum { >> + CVMX_POW_TAG_TYPE_ORDERED = 0L, >> + CVMX_POW_TAG_TYPE_ATOMIC = 1L, >> + CVMX_POW_TAG_TYPE_NULL = 2L, >> + CVMX_POW_TAG_TYPE_NULL_NULL = 3L >> +} cvmx_pow_tag_type_t; >> + >> +/** >> + * LCR bits 0 and 1 control the number of bits per character. See >> the following table for encodings: >> + * >> + * - 00 = 5 bits (bits 0-4 sent) >> + * - 01 = 6 bits (bits 0-5 sent) >> + * - 10 = 7 bits (bits 0-6 sent) >> + * - 11 = 8 bits (all bits sent) >> + */ >> +typedef enum { >> + CVMX_UART_BITS5 = 0, >> + CVMX_UART_BITS6 = 1, >> + CVMX_UART_BITS7 = 2, >> + CVMX_UART_BITS8 = 3 >> +} cvmx_uart_bits_t; >> + >> +typedef enum { >> + CVMX_UART_IID_NONE = 1, >> + CVMX_UART_IID_RX_ERROR = 6, >> + CVMX_UART_IID_RX_DATA = 4, >> + CVMX_UART_IID_RX_TIMEOUT = 12, >> + CVMX_UART_IID_TX_EMPTY = 2, >> + CVMX_UART_IID_MODEM = 0, >> + CVMX_UART_IID_BUSY = 7 >> +} cvmx_uart_iid_t; >> + >> +#endif /* __CVMX_CSR_ENUMS_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-csr.h >> b/arch/mips/mach-octeon/include/mach/cvmx-csr.h >> new file mode 100644 >> index 000000000000..730d54bb9278 >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-csr.h >> @@ -0,0 +1,78 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Configuration and status register (CSR) address and type >> definitions for >> + * Octoen. >> + */ >> + >> +#ifndef __CVMX_CSR_H__ >> +#define __CVMX_CSR_H__ >> + >> +#include "cvmx-csr-enums.h" >> +#include "cvmx-pip-defs.h" >> + >> +typedef cvmx_pip_prt_cfgx_t cvmx_pip_port_cfg_t; >> + >> +/* The CSRs for bootbus region zero used to be independent of the >> + other 1-7. As of SDK 1.7.0 these were combined. These macros >> + are for backwards compactability */ >> +#define CVMX_MIO_BOOT_REG_CFG0 CVMX_MIO_BOOT_REG_CFGX(0) >> +#define CVMX_MIO_BOOT_REG_TIM0 CVMX_MIO_BOOT_REG_TIMX(0) >> + >> +/* The CN3XXX and CN58XX chips used to not have a LMC number >> + passed to the address macros. These are here to supply backwards >> + compatibility with old code. Code should really use the new >> addresses >> + with bus arguments for support on other chips */ >> +#define CVMX_LMC_BIST_CTL CVMX_LMCX_BIST_CTL(0) >> +#define CVMX_LMC_BIST_RESULT CVMX_LMCX_BIST_RESULT(0) >> +#define CVMX_LMC_COMP_CTL CVMX_LMCX_COMP_CTL(0) >> +#define CVMX_LMC_CTL CVMX_LMCX_CTL(0) >> +#define CVMX_LMC_CTL1 CVMX_LMCX_CTL1(0) >> +#define CVMX_LMC_DCLK_CNT_HI CVMX_LMCX_DCLK_CNT_HI(0) >> +#define CVMX_LMC_DCLK_CNT_LO CVMX_LMCX_DCLK_CNT_LO(0) >> +#define CVMX_LMC_DCLK_CTL CVMX_LMCX_DCLK_CTL(0) >> +#define CVMX_LMC_DDR2_CTL CVMX_LMCX_DDR2_CTL(0) >> +#define CVMX_LMC_DELAY_CFG CVMX_LMCX_DELAY_CFG(0) >> +#define CVMX_LMC_DLL_CTL CVMX_LMCX_DLL_CTL(0) >> +#define CVMX_LMC_DUAL_MEMCFG CVMX_LMCX_DUAL_MEMCFG(0) >> +#define CVMX_LMC_ECC_SYND CVMX_LMCX_ECC_SYND(0) >> +#define CVMX_LMC_FADR CVMX_LMCX_FADR(0) >> +#define CVMX_LMC_IFB_CNT_HI CVMX_LMCX_IFB_CNT_HI(0) >> +#define CVMX_LMC_IFB_CNT_LO CVMX_LMCX_IFB_CNT_LO(0) >> +#define CVMX_LMC_MEM_CFG0 CVMX_LMCX_MEM_CFG0(0) >> +#define CVMX_LMC_MEM_CFG1 CVMX_LMCX_MEM_CFG1(0) >> +#define CVMX_LMC_OPS_CNT_HI CVMX_LMCX_OPS_CNT_HI(0) >> +#define CVMX_LMC_OPS_CNT_LO CVMX_LMCX_OPS_CNT_LO(0) >> +#define CVMX_LMC_PLL_BWCTL CVMX_LMCX_PLL_BWCTL(0) >> +#define CVMX_LMC_PLL_CTL CVMX_LMCX_PLL_CTL(0) >> +#define CVMX_LMC_PLL_STATUS CVMX_LMCX_PLL_STATUS(0) >> +#define CVMX_LMC_READ_LEVEL_CTL CVMX_LMCX_READ_LEVEL_CTL(0) >> +#define CVMX_LMC_READ_LEVEL_DBG CVMX_LMCX_READ_LEVEL_DBG(0) >> +#define CVMX_LMC_READ_LEVEL_RANKX CVMX_LMCX_READ_LEVEL_RANKX(0) >> +#define CVMX_LMC_RODT_COMP_CTL CVMX_LMCX_RODT_COMP_CTL(0) >> +#define CVMX_LMC_RODT_CTL CVMX_LMCX_RODT_CTL(0) >> +#define CVMX_LMC_WODT_CTL CVMX_LMCX_WODT_CTL0(0) >> +#define CVMX_LMC_WODT_CTL0 CVMX_LMCX_WODT_CTL0(0) >> +#define CVMX_LMC_WODT_CTL1 CVMX_LMCX_WODT_CTL1(0) >> + >> +/* The CN3XXX and CN58XX chips used to not have a TWSI bus number >> + passed to the address macros. These are here to supply backwards >> + compatibility with old code. Code should really use the new >> addresses >> + with bus arguments for support on other chips */ >> +#define CVMX_MIO_TWS_INT CVMX_MIO_TWSX_INT(0) >> +#define CVMX_MIO_TWS_SW_TWSI CVMX_MIO_TWSX_SW_TWSI(0) >> +#define CVMX_MIO_TWS_SW_TWSI_EXT CVMX_MIO_TWSX_SW_TWSI_EXT(0) >> +#define CVMX_MIO_TWS_TWSI_SW CVMX_MIO_TWSX_TWSI_SW(0) >> + >> +/* The CN3XXX and CN58XX chips used to not have a SMI/MDIO bus >> number >> + passed to the address macros. These are here to supply backwards >> + compatibility with old code. Code should really use the new >> addresses >> + with bus arguments for support on other chips */ >> +#define CVMX_SMI_CLK CVMX_SMIX_CLK(0) >> +#define CVMX_SMI_CMD CVMX_SMIX_CMD(0) >> +#define CVMX_SMI_EN CVMX_SMIX_EN(0) >> +#define CVMX_SMI_RD_DAT CVMX_SMIX_RD_DAT(0) >> +#define CVMX_SMI_WR_DAT CVMX_SMIX_WR_DAT(0) >> + >> +#endif /* __CVMX_CSR_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-error.h >> b/arch/mips/mach-octeon/include/mach/cvmx-error.h >> new file mode 100644 >> index 000000000000..9a13ed422484 >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-error.h >> @@ -0,0 +1,456 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Interface to the Octeon extended error status. >> + */ >> + >> +#ifndef __CVMX_ERROR_H__ >> +#define __CVMX_ERROR_H__ >> + >> +/** >> + * There are generally many error status bits associated with a >> + * single logical group. The enumeration below is used to >> + * communicate high level groups to the error infastructure so >> + * error status bits can be enable or disabled in large groups. >> + */ >> +typedef enum { >> + CVMX_ERROR_GROUP_INTERNAL, >> + CVMX_ERROR_GROUP_L2C, >> + CVMX_ERROR_GROUP_ETHERNET, >> + CVMX_ERROR_GROUP_MGMT_PORT, >> + CVMX_ERROR_GROUP_PCI, >> + CVMX_ERROR_GROUP_SRIO, >> + CVMX_ERROR_GROUP_USB, >> + CVMX_ERROR_GROUP_LMC, >> + CVMX_ERROR_GROUP_ILK, >> + CVMX_ERROR_GROUP_DFM, >> + CVMX_ERROR_GROUP_ILA, >> +} cvmx_error_group_t; >> + >> +/** >> + * Flags representing special handling for some error registers. >> + * These flags are passed to cvmx_error_initialize() to control >> + * the handling of bits where the same flags were passed to the >> + * added cvmx_error_info_t. >> + */ >> +typedef enum { >> + CVMX_ERROR_TYPE_NONE = 0, >> + CVMX_ERROR_TYPE_SBE = 1 << 0, >> + CVMX_ERROR_TYPE_DBE = 1 << 1, >> +} cvmx_error_type_t; >> + >> +/** >> + * When registering for interest in an error status register, the >> + * type of the register needs to be known by cvmx-error. Most >> + * registers are either IO64 or IO32, but some blocks contain >> + * registers that can't be directly accessed. A good example of >> + * would be PCIe extended error state stored in config space. >> + */ >> +typedef enum { >> + __CVMX_ERROR_REGISTER_NONE, >> + CVMX_ERROR_REGISTER_IO64, >> + CVMX_ERROR_REGISTER_IO32, >> + CVMX_ERROR_REGISTER_PCICONFIG, >> + CVMX_ERROR_REGISTER_SRIOMAINT, >> +} cvmx_error_register_t; >> + >> +struct cvmx_error_info; >> +/** >> + * Error handling functions must have the following prototype. >> + */ >> +typedef int (*cvmx_error_func_t)(const struct cvmx_error_info >> *info); >> + >> +/** >> + * This structure is passed to all error handling functions. >> + */ >> +typedef struct cvmx_error_info { >> + cvmx_error_register_t reg_type; >> + u64 status_addr; >> + u64 status_mask; >> + u64 enable_addr; >> + u64 enable_mask; >> + cvmx_error_type_t flags; >> + cvmx_error_group_t group; >> + int group_index; >> + cvmx_error_func_t func; >> + u64 user_info; >> + struct { >> + cvmx_error_register_t reg_type; >> + u64 status_addr; >> + u64 status_mask; >> + } parent; >> +} cvmx_error_info_t; >> + >> +/** >> + * Initialize the error status system. This should be called once >> + * before any other functions are called. This function adds default >> + * handlers for most all error events but does not enable them. >> Later >> + * calls to cvmx_error_enable() are needed. >> + * >> + * @param flags Optional flags. >> + * >> + * @return Zero on success, negative on failure. >> + */ >> +int cvmx_error_initialize(void); >> + >> +/** >> + * Poll the error status registers and call the appropriate error >> + * handlers. This should be called in the RSL interrupt handler >> + * for your application or operating system. >> + * >> + * @return Number of error handlers called. Zero means this call >> + * found no errors and was spurious. >> + */ >> +int cvmx_error_poll(void); >> + >> +/** >> + * Register to be called when an error status bit is set. Most users >> + * will not need to call this function as cvmx_error_initialize() >> + * registers default handlers for most error conditions. This >> function >> + * is normally used to add more handlers without changing the >> existing >> + * handlers. >> + * >> + * @param new_info Information about the handler for a error >> register. The >> + * structure passed is copied and can be destroyed >> after the >> + * call. All members of the structure must be >> populated, even the >> + * parent information. >> + * >> + * @return Zero on success, negative on failure. >> + */ >> +int cvmx_error_add(const cvmx_error_info_t *new_info); >> + >> +/** >> + * Remove all handlers for a status register and mask. Normally >> + * this function should not be called. Instead a new handler should >> be >> + * installed to replace the existing handler. In the even that all >> + * reporting of a error bit should be removed, then use this >> + * function. >> + * >> + * @param reg_type Type of the status register to remove >> + * @param status_addr >> + * Status register to remove. >> + * @param status_mask >> + * All handlers for this status register with this >> mask will be >> + * removed. >> + * @param old_info If not NULL, this is filled with information >> about the handler >> + * that was removed. >> + * >> + * @return Zero on success, negative on failure (not found). >> + */ >> +int cvmx_error_remove(cvmx_error_register_t reg_type, u64 >> status_addr, u64 status_mask, >> + cvmx_error_info_t *old_info); >> + >> +/** >> + * Change the function and user_info for an existing error status >> + * register. This function should be used to replace the default >> + * handler with an application specific version as needed. >> + * >> + * @param reg_type Type of the status register to change >> + * @param status_addr >> + * Status register to change. >> + * @param status_mask >> + * All handlers for this status register with this >> mask will be >> + * changed. >> + * @param new_func New function to use to handle the error status >> + * @param new_user_info >> + * New user info parameter for the function >> + * @param old_func If not NULL, the old function is returned. Useful >> for restoring >> + * the old handler. >> + * @param old_user_info >> + * If not NULL, the old user info parameter. >> + * >> + * @return Zero on success, negative on failure >> + */ >> +int cvmx_error_change_handler(cvmx_error_register_t reg_type, u64 >> status_addr, u64 status_mask, >> + cvmx_error_func_t new_func, u64 >> new_user_info, >> + cvmx_error_func_t *old_func, u64 >> *old_user_info); >> + >> +/** >> + * Enable all error registers for a logical group. This should be >> + * called whenever a logical group is brought online. >> + * >> + * @param group Logical group to enable >> + * @param group_index >> + * Index for the group as defined in the >> cvmx_error_group_t >> + * comments. >> + * >> + * @return Zero on success, negative on failure. >> + */ >> +/* >> + * Rather than conditionalize the calls throughout the executive to >> not enable >> + * interrupts in Uboot, simply make the enable function do nothing >> + */ >> +static inline int cvmx_error_enable_group(cvmx_error_group_t group, >> int group_index) >> +{ >> + return 0; >> +} >> + >> +/** >> + * Disable all error registers for a logical group. This should be >> + * called whenever a logical group is brought offline. Many blocks >> + * will report spurious errors when offline unless this function >> + * is called. >> + * >> + * @param group Logical group to disable >> + * @param group_index >> + * Index for the group as defined in the >> cvmx_error_group_t >> + * comments. >> + * >> + * @return Zero on success, negative on failure. >> + */ >> +/* >> + * Rather than conditionalize the calls throughout the executive to >> not disable >> + * interrupts in Uboot, simply make the enable function do nothing >> + */ >> +static inline int cvmx_error_disable_group(cvmx_error_group_t group, >> int group_index) >> +{ >> + return 0; >> +} >> + >> +/** >> + * Enable all handlers for a specific status register mask. >> + * >> + * @param reg_type Type of the status register >> + * @param status_addr >> + * Status register address >> + * @param status_mask >> + * All handlers for this status register with this >> mask will be >> + * enabled. >> + * >> + * @return Zero on success, negative on failure. >> + */ >> +int cvmx_error_enable(cvmx_error_register_t reg_type, u64 >> status_addr, u64 status_mask); >> + >> +/** >> + * Disable all handlers for a specific status register and mask. >> + * >> + * @param reg_type Type of the status register >> + * @param status_addr >> + * Status register address >> + * @param status_mask >> + * All handlers for this status register with this >> mask will be >> + * disabled. >> + * >> + * @return Zero on success, negative on failure. >> + */ >> +int cvmx_error_disable(cvmx_error_register_t reg_type, u64 >> status_addr, u64 status_mask); >> + >> +/** >> + * @INTERNAL >> + * Function for processing non leaf error status registers. This >> function >> + * calls all handlers for this passed register and all children >> linked >> + * to it. >> + * >> + * @param info Error register to check >> + * >> + * @return Number of error status bits found or zero if no bits were >> set. >> + */ >> +int __cvmx_error_decode(const cvmx_error_info_t *info); >> + >> +/** >> + * @INTERNAL >> + * This error bit handler simply prints a message and clears the >> status bit >> + * >> + * @param info Error register to check >> + * >> + * @return >> + */ >> +int __cvmx_error_display(const cvmx_error_info_t *info); >> + >> +/** >> + * Find the handler for a specific status register and mask >> + * >> + * @param status_addr >> + * Status register address >> + * >> + * @return Return the handler on success or null on failure. >> + */ >> +cvmx_error_info_t *cvmx_error_get_index(u64 status_addr); >> + >> +void __cvmx_install_gmx_error_handler_for_xaui(void); >> + >> +/** >> + * 78xx related >> + */ >> +/** >> + * Compare two INTSN values. >> + * >> + * @param key INTSN value to search for >> + * @param data current entry from the searched array >> + * >> + * @return Negative, 0 or positive when respectively key is less >> than, >> + * equal or greater than data. >> + */ >> +int cvmx_error_intsn_cmp(const void *key, const void *data); >> + >> +/** >> + * @INTERNAL >> + * >> + * @param intsn Interrupt source number to display >> + * >> + * @param node Node number >> + * >> + * @return Zero on success, -1 on error >> + */ >> +int cvmx_error_intsn_display_v3(int node, u32 intsn); >> + >> +/** >> + * Initialize the error status system for cn78xx. This should be >> called once >> + * before any other functions are called. This function enables the >> interrupts >> + * described in the array. >> + * >> + * @param node Node number >> + * >> + * @return Zero on success, negative on failure. >> + */ >> +int cvmx_error_initialize_cn78xx(int node); >> + >> +/** >> + * Enable interrupt for a specific INTSN. >> + * >> + * @param node Node number >> + * @param intsn Interrupt source number >> + * >> + * @return Zero on success, negative on failure. >> + */ >> +int cvmx_error_intsn_enable_v3(int node, u32 intsn); >> + >> +/** >> + * Disable interrupt for a specific INTSN. >> + * >> + * @param node Node number >> + * @param intsn Interrupt source number >> + * >> + * @return Zero on success, negative on failure. >> + */ >> +int cvmx_error_intsn_disable_v3(int node, u32 intsn); >> + >> +/** >> + * Clear interrupt for a specific INTSN. >> + * >> + * @param intsn Interrupt source number >> + * >> + * @return Zero on success, negative on failure. >> + */ >> +int cvmx_error_intsn_clear_v3(int node, u32 intsn); >> + >> +/** >> + * Enable interrupts for a specific CSR(all the bits/intsn in the >> csr). >> + * >> + * @param node Node number >> + * @param csr_address CSR address >> + * >> + * @return Zero on success, negative on failure. >> + */ >> +int cvmx_error_csr_enable_v3(int node, u64 csr_address); >> + >> +/** >> + * Disable interrupts for a specific CSR (all the bits/intsn in the >> csr). >> + * >> + * @param node Node number >> + * @param csr_address CSR address >> + * >> + * @return Zero >> + */ >> +int cvmx_error_csr_disable_v3(int node, u64 csr_address); >> + >> +/** >> + * Enable all error registers for a logical group. This should be >> + * called whenever a logical group is brought online. >> + * >> + * @param group Logical group to enable >> + * @param xipd_port The IPD port value >> + * >> + * @return Zero. >> + */ >> +int cvmx_error_enable_group_v3(cvmx_error_group_t group, int >> xipd_port); >> + >> +/** >> + * Disable all error registers for a logical group. >> + * >> + * @param group Logical group to enable >> + * @param xipd_port The IPD port value >> + * >> + * @return Zero. >> + */ >> +int cvmx_error_disable_group_v3(cvmx_error_group_t group, int >> xipd_port); >> + >> +/** >> + * Enable all error registers for a specific category in a logical >> group. >> + * This should be called whenever a logical group is brought online. >> + * >> + * @param group Logical group to enable >> + * @param type Category in a logical group to enable >> + * @param xipd_port The IPD port value >> + * >> + * @return Zero. >> + */ >> +int cvmx_error_enable_group_type_v3(cvmx_error_group_t group, >> cvmx_error_type_t type, >> + int xipd_port); >> + >> +/** >> + * Disable all error registers for a specific category in a logical >> group. >> + * This should be called whenever a logical group is brought online. >> + * >> + * @param group Logical group to disable >> + * @param type Category in a logical group to disable >> + * @param xipd_port The IPD port value >> + * >> + * @return Zero. >> + */ >> +int cvmx_error_disable_group_type_v3(cvmx_error_group_t group, >> cvmx_error_type_t type, >> + int xipd_port); >> + >> +/** >> + * Clear all error registers for a logical group. >> + * >> + * @param group Logical group to disable >> + * @param xipd_port The IPD port value >> + * >> + * @return Zero. >> + */ >> +int cvmx_error_clear_group_v3(cvmx_error_group_t group, int >> xipd_port); >> + >> +/** >> + * Enable all error registers for a particular category. >> + * >> + * @param node CCPI node >> + * @param type category to enable >> + * >> + *@return Zero. >> + */ >> +int cvmx_error_enable_type_v3(int node, cvmx_error_type_t type); >> + >> +/** >> + * Disable all error registers for a particular category. >> + * >> + * @param node CCPI node >> + * @param type category to disable >> + * >> + *@return Zero. >> + */ >> +int cvmx_error_disable_type_v3(int node, cvmx_error_type_t type); >> + >> +void cvmx_octeon_hang(void) __attribute__((__noreturn__)); >> + >> +/** >> + * @INTERNAL >> + * >> + * Process L2C single and multi-bit ECC errors >> + * >> + */ >> +int __cvmx_cn7xxx_l2c_l2d_ecc_error_display(int node, int intsn); >> + >> +/** >> + * Handle L2 cache TAG ECC errors and noway errors >> + * >> + * @param CCPI node >> + * @param intsn intsn from error array. >> + * @param remote true for remote node (cn78xx only) >> + * >> + * @return 1 if handled, 0 if not handled >> + */ >> +int __cvmx_cn7xxx_l2c_tag_error_display(int node, int intsn, bool >> remote); >> + >> +#endif >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-fpa.h >> b/arch/mips/mach-octeon/include/mach/cvmx-fpa.h >> new file mode 100644 >> index 000000000000..297fb3f4a28c >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-fpa.h >> @@ -0,0 +1,217 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Interface to the hardware Free Pool Allocator. >> + */ >> + >> +#ifndef __CVMX_FPA_H__ >> +#define __CVMX_FPA_H__ >> + >> +#include "cvmx-scratch.h" >> +#include "cvmx-fpa-defs.h" >> +#include "cvmx-fpa1.h" >> +#include "cvmx-fpa3.h" >> + >> +#define CVMX_FPA_MIN_BLOCK_SIZE 128 >> +#define CVMX_FPA_ALIGNMENT 128 >> +#define CVMX_FPA_POOL_NAME_LEN 16 >> + >> +/* On CN78XX in backward-compatible mode, pool is mapped to AURA */ >> +#define >> CVMX_FPA_NUM_POOLS >> \ >> + (octeon_has_feature(OCTEON_FEATURE_FPA3) ? >> cvmx_fpa3_num_auras() : CVMX_FPA1_NUM_POOLS) >> + >> +/** >> + * Structure to store FPA pool configuration parameters. >> + */ >> +struct cvmx_fpa_pool_config { >> + s64 pool_num; >> + u64 buffer_size; >> + u64 buffer_count; >> +}; >> + >> +typedef struct cvmx_fpa_pool_config cvmx_fpa_pool_config_t; >> + >> +/** >> + * Return the name of the pool >> + * >> + * @param pool_num Pool to get the name of >> + * @return The name >> + */ >> +const char *cvmx_fpa_get_name(int pool_num); >> + >> +/** >> + * Initialize FPA per node >> + */ >> +int cvmx_fpa_global_init_node(int node); >> + >> +/** >> + * Enable the FPA >> + */ >> +static inline void cvmx_fpa_enable(void) >> +{ >> + if (!octeon_has_feature(OCTEON_FEATURE_FPA3)) >> + cvmx_fpa1_enable(); >> + else >> + cvmx_fpa_global_init_node(cvmx_get_node_num()); >> +} >> + >> +/** >> + * Disable the FPA >> + */ >> +static inline void cvmx_fpa_disable(void) >> +{ >> + if (!octeon_has_feature(OCTEON_FEATURE_FPA3)) >> + cvmx_fpa1_disable(); >> + /* FPA3 does not have a disable function */ >> +} >> + >> +/** >> + * @INTERNAL >> + * @deprecated OBSOLETE >> + * >> + * Kept for transition assistance only >> + */ >> +static inline void cvmx_fpa_global_initialize(void) >> +{ >> + cvmx_fpa_global_init_node(cvmx_get_node_num()); >> +} >> + >> +/** >> + * @INTERNAL >> + * >> + * Convert FPA1 style POOL into FPA3 AURA in >> + * backward compatibility mode. >> + */ >> +static inline cvmx_fpa3_gaura_t >> cvmx_fpa1_pool_to_fpa3_aura(cvmx_fpa1_pool_t pool) >> +{ >> + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) { >> + unsigned int node = cvmx_get_node_num(); >> + cvmx_fpa3_gaura_t aura = __cvmx_fpa3_gaura(node, pool); >> + return aura; >> + } >> + return CVMX_FPA3_INVALID_GAURA; >> +} >> + >> +/** >> + * Get a new block from the FPA >> + * >> + * @param pool Pool to get the block from >> + * @return Pointer to the block or NULL on failure >> + */ >> +static inline void *cvmx_fpa_alloc(u64 pool) >> +{ >> + /* FPA3 is handled differently */ >> + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) { >> + return >> cvmx_fpa3_alloc(cvmx_fpa1_pool_to_fpa3_aura(pool)); >> + } else >> + return cvmx_fpa1_alloc(pool); >> +} >> + >> +/** >> + * Asynchronously get a new block from the FPA >> + * >> + * The result of cvmx_fpa_async_alloc() may be retrieved using >> + * cvmx_fpa_async_alloc_finish(). >> + * >> + * @param scr_addr Local scratch address to put response in. This >> is a byte >> + * address but must be 8 byte aligned. >> + * @param pool Pool to get the block from >> + */ >> +static inline void cvmx_fpa_async_alloc(u64 scr_addr, u64 pool) >> +{ >> + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) { >> + return cvmx_fpa3_async_alloc(scr_addr, >> cvmx_fpa1_pool_to_fpa3_aura(pool)); >> + } else >> + return cvmx_fpa1_async_alloc(scr_addr, pool); >> +} >> + >> +/** >> + * Retrieve the result of cvmx_fpa_async_alloc >> + * >> + * @param scr_addr The Local scratch address. Must be the same >> value >> + * passed to cvmx_fpa_async_alloc(). >> + * >> + * @param pool Pool the block came from. Must be the same value >> + * passed to cvmx_fpa_async_alloc. >> + * >> + * @return Pointer to the block or NULL on failure >> + */ >> +static inline void *cvmx_fpa_async_alloc_finish(u64 scr_addr, u64 >> pool) >> +{ >> + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) >> + return cvmx_fpa3_async_alloc_finish(scr_addr, >> cvmx_fpa1_pool_to_fpa3_aura(pool)); >> + else >> + return cvmx_fpa1_async_alloc_finish(scr_addr, pool); >> +} >> + >> +/** >> + * Free a block allocated with a FPA pool. >> + * Does NOT provide memory ordering in cases where the memory block >> was >> + * modified by the core. >> + * >> + * @param ptr Block to free >> + * @param pool Pool to put it in >> + * @param num_cache_lines >> + * Cache lines to invalidate >> + */ >> +static inline void cvmx_fpa_free_nosync(void *ptr, u64 pool, u64 >> num_cache_lines) >> +{ >> + /* FPA3 is handled differently */ >> + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) >> + cvmx_fpa3_free_nosync(ptr, >> cvmx_fpa1_pool_to_fpa3_aura(pool), num_cache_lines); >> + else >> + cvmx_fpa1_free_nosync(ptr, pool, num_cache_lines); >> +} >> + >> +/** >> + * Free a block allocated with a FPA pool. Provides required memory >> + * ordering in cases where memory block was modified by core. >> + * >> + * @param ptr Block to free >> + * @param pool Pool to put it in >> + * @param num_cache_lines >> + * Cache lines to invalidate >> + */ >> +static inline void cvmx_fpa_free(void *ptr, u64 pool, u64 >> num_cache_lines) >> +{ >> + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) >> + cvmx_fpa3_free(ptr, cvmx_fpa1_pool_to_fpa3_aura(pool), >> num_cache_lines); >> + else >> + cvmx_fpa1_free(ptr, pool, num_cache_lines); >> +} >> + >> +/** >> + * Setup a FPA pool to control a new block of memory. >> + * This can only be called once per pool. Make sure proper >> + * locking enforces this. >> + * >> + * @param pool Pool to initialize >> + * @param name Constant character string to name this pool. >> + * String is not copied. >> + * @param buffer Pointer to the block of memory to use. This >> must be >> + * accessible by all processors and external >> hardware. >> + * @param block_size Size for each block controlled by the FPA >> + * @param num_blocks Number of blocks >> + * >> + * @return the pool number on Success, >> + * -1 on failure >> + */ >> +int cvmx_fpa_setup_pool(int pool, const char *name, void *buffer, >> u64 block_size, u64 num_blocks); >> + >> +int cvmx_fpa_shutdown_pool(int pool); >> + >> +/** >> + * Gets the block size of buffer in specified pool >> + * @param pool Pool to get the block size from >> + * @return Size of buffer in specified pool >> + */ >> +unsigned int cvmx_fpa_get_block_size(int pool); >> + >> +int cvmx_fpa_is_pool_available(int pool_num); >> +u64 cvmx_fpa_get_pool_owner(int pool_num); >> +int cvmx_fpa_get_max_pools(void); >> +int cvmx_fpa_get_current_count(int pool_num); >> +int cvmx_fpa_validate_pool(int pool); >> + >> +#endif /* __CVM_FPA_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-fpa1.h >> b/arch/mips/mach-octeon/include/mach/cvmx-fpa1.h >> new file mode 100644 >> index 000000000000..6985083a5d66 >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-fpa1.h >> @@ -0,0 +1,196 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Interface to the hardware Free Pool Allocator on Octeon chips. >> + * These are the legacy models, i.e. prior to CN78XX/CN76XX. >> + */ >> + >> +#ifndef __CVMX_FPA1_HW_H__ >> +#define __CVMX_FPA1_HW_H__ >> + >> +#include "cvmx-scratch.h" >> +#include "cvmx-fpa-defs.h" >> +#include "cvmx-fpa3.h" >> + >> +/* Legacy pool range is 0..7 and 8 on CN68XX */ >> +typedef int cvmx_fpa1_pool_t; >> + >> +#define CVMX_FPA1_NUM_POOLS 8 >> +#define CVMX_FPA1_INVALID_POOL ((cvmx_fpa1_pool_t)-1) >> +#define CVMX_FPA1_NAME_SIZE 16 >> + >> +/** >> + * Structure describing the data format used for stores to the FPA. >> + */ >> +typedef union { >> + u64 u64; >> + struct { >> + u64 scraddr : 8; >> + u64 len : 8; >> + u64 did : 8; >> + u64 addr : 40; >> + } s; >> +} cvmx_fpa1_iobdma_data_t; >> + >> +/* >> + * Allocate or reserve the specified fpa pool. >> + * >> + * @param pool FPA pool to allocate/reserve. If -1 it >> + * finds an empty pool to allocate. >> + * @return Alloctaed pool number or CVMX_FPA1_POOL_INVALID >> + * if fails to allocate the pool >> + */ >> +cvmx_fpa1_pool_t cvmx_fpa1_reserve_pool(cvmx_fpa1_pool_t pool); >> + >> +/** >> + * Free the specified fpa pool. >> + * @param pool Pool to free >> + * @return 0 for success -1 failure >> + */ >> +int cvmx_fpa1_release_pool(cvmx_fpa1_pool_t pool); >> + >> +static inline void cvmx_fpa1_free(void *ptr, cvmx_fpa1_pool_t pool, >> u64 num_cache_lines) >> +{ >> + cvmx_addr_t newptr; >> + >> + newptr.u64 = cvmx_ptr_to_phys(ptr); >> + newptr.sfilldidspace.didspace = >> CVMX_ADDR_DIDSPACE(CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool)); >> + /* Make sure that any previous writes to memory go out before >> we free >> + * this buffer. This also serves as a barrier to prevent GCC >> from >> + * reordering operations to after the free. >> + */ >> + CVMX_SYNCWS; >> + /* value written is number of cache lines not written back */ >> + cvmx_write_io(newptr.u64, num_cache_lines); >> +} >> + >> +static inline void cvmx_fpa1_free_nosync(void *ptr, cvmx_fpa1_pool_t >> pool, >> + unsigned int num_cache_lines) >> +{ >> + cvmx_addr_t newptr; >> + >> + newptr.u64 = cvmx_ptr_to_phys(ptr); >> + newptr.sfilldidspace.didspace = >> CVMX_ADDR_DIDSPACE(CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool)); >> + /* Prevent GCC from reordering around free */ >> + asm volatile("" : : : "memory"); >> + /* value written is number of cache lines not written back */ >> + cvmx_write_io(newptr.u64, num_cache_lines); >> +} >> + >> +/** >> + * Enable the FPA for use. Must be performed after any CSR >> + * configuration but before any other FPA functions. >> + */ >> +static inline void cvmx_fpa1_enable(void) >> +{ >> + cvmx_fpa_ctl_status_t status; >> + >> + status.u64 = csr_rd(CVMX_FPA_CTL_STATUS); >> + if (status.s.enb) { >> + /* >> + * CN68XXP1 should not reset the FPA (doing so may >> break >> + * the SSO, so we may end up enabling it more than >> once. >> + * Just return and don't spew messages. >> + */ >> + return; >> + } >> + >> + status.u64 = 0; >> + status.s.enb = 1; >> + csr_wr(CVMX_FPA_CTL_STATUS, status.u64); >> +} >> + >> +/** >> + * Reset FPA to disable. Make sure buffers from all FPA pools are >> freed >> + * before disabling FPA. >> + */ >> +static inline void cvmx_fpa1_disable(void) >> +{ >> + cvmx_fpa_ctl_status_t status; >> + >> + if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1)) >> + return; >> + >> + status.u64 = csr_rd(CVMX_FPA_CTL_STATUS); >> + status.s.reset = 1; >> + csr_wr(CVMX_FPA_CTL_STATUS, status.u64); >> +} >> + >> +static inline void *cvmx_fpa1_alloc(cvmx_fpa1_pool_t pool) >> +{ >> + u64 address; >> + >> + for (;;) { >> + address = >> csr_rd(CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool))); >> + if (cvmx_likely(address)) { >> + return cvmx_phys_to_ptr(address); >> + } else { >> + if (csr_rd(CVMX_FPA_QUEX_AVAILABLE(pool)) > 0) >> + udelay(50); >> + else >> + return NULL; >> + } >> + } >> +} >> + >> +/** >> + * Asynchronously get a new block from the FPA >> + * @INTERNAL >> + * >> + * The result of cvmx_fpa_async_alloc() may be retrieved using >> + * cvmx_fpa_async_alloc_finish(). >> + * >> + * @param scr_addr Local scratch address to put response in. This >> is a byte >> + * address but must be 8 byte aligned. >> + * @param pool Pool to get the block from >> + */ >> +static inline void cvmx_fpa1_async_alloc(u64 scr_addr, >> cvmx_fpa1_pool_t pool) >> +{ >> + cvmx_fpa1_iobdma_data_t data; >> + >> + /* Hardware only uses 64 bit aligned locations, so convert from >> byte >> + * address to 64-bit index >> + */ >> + data.u64 = 0ull; >> + data.s.scraddr = scr_addr >> 3; >> + data.s.len = 1; >> + data.s.did = CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool); >> + data.s.addr = 0; >> + >> + cvmx_scratch_write64(scr_addr, 0ull); >> + CVMX_SYNCW; >> + cvmx_send_single(data.u64); >> +} >> + >> +/** >> + * Retrieve the result of cvmx_fpa_async_alloc >> + * @INTERNAL >> + * >> + * @param scr_addr The Local scratch address. Must be the same >> value >> + * passed to cvmx_fpa_async_alloc(). >> + * >> + * @param pool Pool the block came from. Must be the same value >> + * passed to cvmx_fpa_async_alloc. >> + * >> + * @return Pointer to the block or NULL on failure >> + */ >> +static inline void *cvmx_fpa1_async_alloc_finish(u64 scr_addr, >> cvmx_fpa1_pool_t pool) >> +{ >> + u64 address; >> + >> + CVMX_SYNCIOBDMA; >> + >> + address = cvmx_scratch_read64(scr_addr); >> + if (cvmx_likely(address)) >> + return cvmx_phys_to_ptr(address); >> + else >> + return cvmx_fpa1_alloc(pool); >> +} >> + >> +static inline u64 cvmx_fpa1_get_available(cvmx_fpa1_pool_t pool) >> +{ >> + return csr_rd(CVMX_FPA_QUEX_AVAILABLE(pool)); >> +} >> + >> +#endif /* __CVMX_FPA1_HW_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-fpa3.h >> b/arch/mips/mach-octeon/include/mach/cvmx-fpa3.h >> new file mode 100644 >> index 000000000000..229982b83163 >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-fpa3.h >> @@ -0,0 +1,566 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Interface to the CN78XX Free Pool Allocator, a.k.a. FPA3 >> + */ >> + >> +#include "cvmx-address.h" >> +#include "cvmx-fpa-defs.h" >> +#include "cvmx-scratch.h" >> + >> +#ifndef __CVMX_FPA3_H__ >> +#define __CVMX_FPA3_H__ >> + >> +typedef struct { >> + unsigned res0 : 6; >> + unsigned node : 2; >> + unsigned res1 : 2; >> + unsigned lpool : 6; >> + unsigned valid_magic : 16; >> +} cvmx_fpa3_pool_t; >> + >> +typedef struct { >> + unsigned res0 : 6; >> + unsigned node : 2; >> + unsigned res1 : 6; >> + unsigned laura : 10; >> + unsigned valid_magic : 16; >> +} cvmx_fpa3_gaura_t; >> + >> +#define CVMX_FPA3_VALID_MAGIC 0xf9a3 >> +#define CVMX_FPA3_INVALID_GAURA ((cvmx_fpa3_gaura_t){ 0, 0, 0, 0, 0 >> }) >> +#define CVMX_FPA3_INVALID_POOL ((cvmx_fpa3_pool_t){ 0, 0, 0, >> 0, 0 }) >> + >> +static inline bool __cvmx_fpa3_aura_valid(cvmx_fpa3_gaura_t aura) >> +{ >> + if (aura.valid_magic != CVMX_FPA3_VALID_MAGIC) >> + return false; >> + return true; >> +} >> + >> +static inline bool __cvmx_fpa3_pool_valid(cvmx_fpa3_pool_t pool) >> +{ >> + if (pool.valid_magic != CVMX_FPA3_VALID_MAGIC) >> + return false; >> + return true; >> +} >> + >> +static inline cvmx_fpa3_gaura_t __cvmx_fpa3_gaura(int node, int >> laura) >> +{ >> + cvmx_fpa3_gaura_t aura; >> + >> + if (node < 0) >> + node = cvmx_get_node_num(); >> + if (laura < 0) >> + return CVMX_FPA3_INVALID_GAURA; >> + >> + aura.node = node; >> + aura.laura = laura; >> + aura.valid_magic = CVMX_FPA3_VALID_MAGIC; >> + return aura; >> +} >> + >> +static inline cvmx_fpa3_pool_t __cvmx_fpa3_pool(int node, int lpool) >> +{ >> + cvmx_fpa3_pool_t pool; >> + >> + if (node < 0) >> + node = cvmx_get_node_num(); >> + if (lpool < 0) >> + return CVMX_FPA3_INVALID_POOL; >> + >> + pool.node = node; >> + pool.lpool = lpool; >> + pool.valid_magic = CVMX_FPA3_VALID_MAGIC; >> + return pool; >> +} >> + >> +#undef CVMX_FPA3_VALID_MAGIC >> + >> +/** >> + * Structure describing the data format used for stores to the FPA. >> + */ >> +typedef union { >> + u64 u64; >> + struct { >> + u64 scraddr : 8; >> + u64 len : 8; >> + u64 did : 8; >> + u64 addr : 40; >> + } s; >> + struct { >> + u64 scraddr : 8; >> + u64 len : 8; >> + u64 did : 8; >> + u64 node : 4; >> + u64 red : 1; >> + u64 reserved2 : 9; >> + u64 aura : 10; >> + u64 reserved3 : 16; >> + } cn78xx; >> +} cvmx_fpa3_iobdma_data_t; >> + >> +/** >> + * Struct describing load allocate operation addresses for FPA pool. >> + */ >> +union cvmx_fpa3_load_data { >> + u64 u64; >> + struct { >> + u64 seg : 2; >> + u64 reserved1 : 13; >> + u64 io : 1; >> + u64 did : 8; >> + u64 node : 4; >> + u64 red : 1; >> + u64 reserved2 : 9; >> + u64 aura : 10; >> + u64 reserved3 : 16; >> + }; >> +}; >> + >> +typedef union cvmx_fpa3_load_data cvmx_fpa3_load_data_t; >> + >> +/** >> + * Struct describing store free operation addresses from FPA pool. >> + */ >> +union cvmx_fpa3_store_addr { >> + u64 u64; >> + struct { >> + u64 seg : 2; >> + u64 reserved1 : 13; >> + u64 io : 1; >> + u64 did : 8; >> + u64 node : 4; >> + u64 reserved2 : 10; >> + u64 aura : 10; >> + u64 fabs : 1; >> + u64 reserved3 : 3; >> + u64 dwb_count : 9; >> + u64 reserved4 : 3; >> + }; >> +}; >> + >> +typedef union cvmx_fpa3_store_addr cvmx_fpa3_store_addr_t; >> + >> +enum cvmx_fpa3_pool_alignment_e { >> + FPA_NATURAL_ALIGNMENT, >> + FPA_OFFSET_ALIGNMENT, >> + FPA_OPAQUE_ALIGNMENT >> +}; >> + >> +#define CVMX_FPA3_AURAX_LIMIT_MAX ((1ull << 40) - 1) >> + >> +/** >> + * @INTERNAL >> + * Accessor functions to return number of POOLS in an FPA3 >> + * depending on SoC model. >> + * The number is per-node for models supporting multi-node >> configurations. >> + */ >> +static inline int cvmx_fpa3_num_pools(void) >> +{ >> + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) >> + return 64; >> + if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) >> + return 32; >> + if (OCTEON_IS_MODEL(OCTEON_CN73XX)) >> + return 32; >> + printf("ERROR: %s: Unknowm model\n", __func__); >> + return -1; >> +} >> + >> +/** >> + * @INTERNAL >> + * Accessor functions to return number of AURAS in an FPA3 >> + * depending on SoC model. >> + * The number is per-node for models supporting multi-node >> configurations. >> + */ >> +static inline int cvmx_fpa3_num_auras(void) >> +{ >> + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) >> + return 1024; >> + if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) >> + return 512; >> + if (OCTEON_IS_MODEL(OCTEON_CN73XX)) >> + return 512; >> + printf("ERROR: %s: Unknowm model\n", __func__); >> + return -1; >> +} >> + >> +/** >> + * Get the FPA3 POOL underneath FPA3 AURA, containing all its >> buffers >> + * >> + */ >> +static inline cvmx_fpa3_pool_t >> cvmx_fpa3_aura_to_pool(cvmx_fpa3_gaura_t aura) >> +{ >> + cvmx_fpa3_pool_t pool; >> + cvmx_fpa_aurax_pool_t aurax_pool; >> + >> + aurax_pool.u64 = cvmx_read_csr_node(aura.node, >> CVMX_FPA_AURAX_POOL(aura.laura)); >> + >> + pool = __cvmx_fpa3_pool(aura.node, aurax_pool.s.pool); >> + return pool; >> +} >> + >> +/** >> + * Get a new block from the FPA pool >> + * >> + * @param aura - aura number >> + * @return pointer to the block or NULL on failure >> + */ >> +static inline void *cvmx_fpa3_alloc(cvmx_fpa3_gaura_t aura) >> +{ >> + u64 address; >> + cvmx_fpa3_load_data_t load_addr; >> + >> + load_addr.u64 = 0; >> + load_addr.seg = CVMX_MIPS_SPACE_XKPHYS; >> + load_addr.io = 1; >> + load_addr.did = 0x29; /* Device ID. Indicates FPA. */ >> + load_addr.node = aura.node; >> + load_addr.red = 0; /* Perform RED on allocation. >> + * FIXME to use config option >> + */ >> + load_addr.aura = aura.laura; >> + >> + address = cvmx_read64_uint64(load_addr.u64); >> + if (!address) >> + return NULL; >> + return cvmx_phys_to_ptr(address); >> +} >> + >> +/** >> + * Asynchronously get a new block from the FPA >> + * >> + * The result of cvmx_fpa_async_alloc() may be retrieved using >> + * cvmx_fpa_async_alloc_finish(). >> + * >> + * @param scr_addr Local scratch address to put response in. This >> is a byte >> + * address but must be 8 byte aligned. >> + * @param aura Global aura to get the block from >> + */ >> +static inline void cvmx_fpa3_async_alloc(u64 scr_addr, >> cvmx_fpa3_gaura_t aura) >> +{ >> + cvmx_fpa3_iobdma_data_t data; >> + >> + /* Hardware only uses 64 bit aligned locations, so convert from >> byte >> + * address to 64-bit index >> + */ >> + data.u64 = 0ull; >> + data.cn78xx.scraddr = scr_addr >> 3; >> + data.cn78xx.len = 1; >> + data.cn78xx.did = 0x29; >> + data.cn78xx.node = aura.node; >> + data.cn78xx.aura = aura.laura; >> + cvmx_scratch_write64(scr_addr, 0ull); >> + >> + CVMX_SYNCW; >> + cvmx_send_single(data.u64); >> +} >> + >> +/** >> + * Retrieve the result of cvmx_fpa3_async_alloc >> + * >> + * @param scr_addr The Local scratch address. Must be the same >> value >> + * passed to cvmx_fpa_async_alloc(). >> + * >> + * @param aura Global aura the block came from. Must be the same >> value >> + * passed to cvmx_fpa_async_alloc. >> + * >> + * @return Pointer to the block or NULL on failure >> + */ >> +static inline void *cvmx_fpa3_async_alloc_finish(u64 scr_addr, >> cvmx_fpa3_gaura_t aura) >> +{ >> + u64 address; >> + >> + CVMX_SYNCIOBDMA; >> + >> + address = cvmx_scratch_read64(scr_addr); >> + if (cvmx_likely(address)) >> + return cvmx_phys_to_ptr(address); >> + else >> + /* Try regular alloc if async failed */ >> + return cvmx_fpa3_alloc(aura); >> +} >> + >> +/** >> + * Free a pointer back to the pool. >> + * >> + * @param aura global aura number >> + * @param ptr physical address of block to free. >> + * @param num_cache_lines Cache lines to invalidate >> + */ >> +static inline void cvmx_fpa3_free(void *ptr, cvmx_fpa3_gaura_t aura, >> unsigned int num_cache_lines) >> +{ >> + cvmx_fpa3_store_addr_t newptr; >> + cvmx_addr_t newdata; >> + >> + newdata.u64 = cvmx_ptr_to_phys(ptr); >> + >> + /* Make sure that any previous writes to memory go out before >> we free >> + this buffer. This also serves as a barrier to prevent GCC >> from >> + reordering operations to after the free. */ >> + CVMX_SYNCWS; >> + >> + newptr.u64 = 0; >> + newptr.seg = CVMX_MIPS_SPACE_XKPHYS; >> + newptr.io = 1; >> + newptr.did = 0x29; /* Device id, indicates FPA */ >> + newptr.node = aura.node; >> + newptr.aura = aura.laura; >> + newptr.fabs = 0; /* Free absolute. FIXME to use config option >> */ >> + newptr.dwb_count = num_cache_lines; >> + >> + cvmx_write_io(newptr.u64, newdata.u64); >> +} >> + >> +/** >> + * Free a pointer back to the pool without flushing the write >> buffer. >> + * >> + * @param aura global aura number >> + * @param ptr physical address of block to free. >> + * @param num_cache_lines Cache lines to invalidate >> + */ >> +static inline void cvmx_fpa3_free_nosync(void *ptr, >> cvmx_fpa3_gaura_t aura, >> + unsigned int num_cache_lines) >> +{ >> + cvmx_fpa3_store_addr_t newptr; >> + cvmx_addr_t newdata; >> + >> + newdata.u64 = cvmx_ptr_to_phys(ptr); >> + >> + /* Prevent GCC from reordering writes to (*ptr) */ >> + asm volatile("" : : : "memory"); >> + >> + newptr.u64 = 0; >> + newptr.seg = CVMX_MIPS_SPACE_XKPHYS; >> + newptr.io = 1; >> + newptr.did = 0x29; /* Device id, indicates FPA */ >> + newptr.node = aura.node; >> + newptr.aura = aura.laura; >> + newptr.fabs = 0; /* Free absolute. FIXME to use config option >> */ >> + newptr.dwb_count = num_cache_lines; >> + >> + cvmx_write_io(newptr.u64, newdata.u64); >> +} >> + >> +static inline int cvmx_fpa3_pool_is_enabled(cvmx_fpa3_pool_t pool) >> +{ >> + cvmx_fpa_poolx_cfg_t pool_cfg; >> + >> + if (!__cvmx_fpa3_pool_valid(pool)) >> + return -1; >> + >> + pool_cfg.u64 = cvmx_read_csr_node(pool.node, >> CVMX_FPA_POOLX_CFG(pool.lpool)); >> + return pool_cfg.cn78xx.ena; >> +} >> + >> +static inline int cvmx_fpa3_config_red_params(unsigned int node, int >> qos_avg_en, int red_lvl_dly, >> + int avg_dly) >> +{ >> + cvmx_fpa_gen_cfg_t fpa_cfg; >> + cvmx_fpa_red_delay_t red_delay; >> + >> + fpa_cfg.u64 = cvmx_read_csr_node(node, CVMX_FPA_GEN_CFG); >> + fpa_cfg.s.avg_en = qos_avg_en; >> + fpa_cfg.s.lvl_dly = red_lvl_dly; >> + cvmx_write_csr_node(node, CVMX_FPA_GEN_CFG, fpa_cfg.u64); >> + >> + red_delay.u64 = cvmx_read_csr_node(node, CVMX_FPA_RED_DELAY); >> + red_delay.s.avg_dly = avg_dly; >> + cvmx_write_csr_node(node, CVMX_FPA_RED_DELAY, red_delay.u64); >> + return 0; >> +} >> + >> +/** >> + * Gets the buffer size of the specified pool, >> + * >> + * @param aura Global aura number >> + * @return Returns size of the buffers in the specified pool. >> + */ >> +static inline int cvmx_fpa3_get_aura_buf_size(cvmx_fpa3_gaura_t >> aura) >> +{ >> + cvmx_fpa3_pool_t pool; >> + cvmx_fpa_poolx_cfg_t pool_cfg; >> + int block_size; >> + >> + pool = cvmx_fpa3_aura_to_pool(aura); >> + >> + pool_cfg.u64 = cvmx_read_csr_node(pool.node, >> CVMX_FPA_POOLX_CFG(pool.lpool)); >> + block_size = pool_cfg.cn78xx.buf_size << 7; >> + return block_size; >> +} >> + >> +/** >> + * Return the number of available buffers in an AURA >> + * >> + * @param aura to receive count for >> + * @return available buffer count >> + */ >> +static inline long long cvmx_fpa3_get_available(cvmx_fpa3_gaura_t >> aura) >> +{ >> + cvmx_fpa3_pool_t pool; >> + cvmx_fpa_poolx_available_t avail_reg; >> + cvmx_fpa_aurax_cnt_t cnt_reg; >> + cvmx_fpa_aurax_cnt_limit_t limit_reg; >> + long long ret; >> + >> + pool = cvmx_fpa3_aura_to_pool(aura); >> + >> + /* Get POOL available buffer count */ >> + avail_reg.u64 = cvmx_read_csr_node(pool.node, >> CVMX_FPA_POOLX_AVAILABLE(pool.lpool)); >> + >> + /* Get AURA current available count */ >> + cnt_reg.u64 = cvmx_read_csr_node(aura.node, >> CVMX_FPA_AURAX_CNT(aura.laura)); >> + limit_reg.u64 = cvmx_read_csr_node(aura.node, >> CVMX_FPA_AURAX_CNT_LIMIT(aura.laura)); >> + >> + if (limit_reg.cn78xx.limit < cnt_reg.cn78xx.cnt) >> + return 0; >> + >> + /* Calculate AURA-based buffer allowance */ >> + ret = limit_reg.cn78xx.limit - cnt_reg.cn78xx.cnt; >> + >> + /* Use POOL real buffer availability when less then allowance >> */ >> + if (ret > (long long)avail_reg.cn78xx.count) >> + ret = avail_reg.cn78xx.count; >> + >> + return ret; >> +} >> + >> +/** >> + * Configure the QoS parameters of an FPA3 AURA >> + * >> + * @param aura is the FPA3 AURA handle >> + * @param ena_bp enables backpressure when outstanding count exceeds >> 'bp_thresh' >> + * @param ena_red enables random early discard when outstanding >> count exceeds 'pass_thresh' >> + * @param pass_thresh is the maximum count to invoke flow control >> + * @param drop_thresh is the count threshold to begin dropping >> packets >> + * @param bp_thresh is the back-pressure threshold >> + * >> + */ >> +static inline void cvmx_fpa3_setup_aura_qos(cvmx_fpa3_gaura_t aura, >> bool ena_red, u64 pass_thresh, >> + u64 drop_thresh, bool >> ena_bp, u64 bp_thresh) >> +{ >> + unsigned int shift = 0; >> + u64 shift_thresh; >> + cvmx_fpa_aurax_cnt_limit_t limit_reg; >> + cvmx_fpa_aurax_cnt_levels_t aura_level; >> + >> + if (!__cvmx_fpa3_aura_valid(aura)) >> + return; >> + >> + /* Get AURAX count limit for validation */ >> + limit_reg.u64 = cvmx_read_csr_node(aura.node, >> CVMX_FPA_AURAX_CNT_LIMIT(aura.laura)); >> + >> + if (pass_thresh < 256) >> + pass_thresh = 255; >> + >> + if (drop_thresh <= pass_thresh || drop_thresh > >> limit_reg.cn78xx.limit) >> + drop_thresh = limit_reg.cn78xx.limit; >> + >> + if (bp_thresh < 256 || bp_thresh > limit_reg.cn78xx.limit) >> + bp_thresh = limit_reg.cn78xx.limit >> 1; >> + >> + shift_thresh = (bp_thresh > drop_thresh) ? bp_thresh : >> drop_thresh; >> + >> + /* Calculate shift so that the largest threshold fits in 8 bits >> */ >> + for (shift = 0; shift < (1 << 6); shift++) { >> + if (0 == ((shift_thresh >> shift) & ~0xffull)) >> + break; >> + }; >> + >> + aura_level.u64 = cvmx_read_csr_node(aura.node, >> CVMX_FPA_AURAX_CNT_LEVELS(aura.laura)); >> + aura_level.s.pass = pass_thresh >> shift; >> + aura_level.s.drop = drop_thresh >> shift; >> + aura_level.s.bp = bp_thresh >> shift; >> + aura_level.s.shift = shift; >> + aura_level.s.red_ena = ena_red; >> + aura_level.s.bp_ena = ena_bp; >> + cvmx_write_csr_node(aura.node, >> CVMX_FPA_AURAX_CNT_LEVELS(aura.laura), aura_level.u64); >> +} >> + >> +cvmx_fpa3_gaura_t cvmx_fpa3_reserve_aura(int node, int >> desired_aura_num); >> +int cvmx_fpa3_release_aura(cvmx_fpa3_gaura_t aura); >> +cvmx_fpa3_pool_t cvmx_fpa3_reserve_pool(int node, int >> desired_pool_num); >> +int cvmx_fpa3_release_pool(cvmx_fpa3_pool_t pool); >> +int cvmx_fpa3_is_aura_available(int node, int aura_num); >> +int cvmx_fpa3_is_pool_available(int node, int pool_num); >> + >> +cvmx_fpa3_pool_t cvmx_fpa3_setup_fill_pool(int node, int >> desired_pool, const char *name, >> + unsigned int block_size, >> unsigned int num_blocks, >> + void *buffer); >> + >> +/** >> + * Function to attach an aura to an existing pool >> + * >> + * @param node - configure fpa on this node >> + * @param pool - configured pool to attach aura to >> + * @param desired_aura - pointer to aura to use, set to -1 to >> allocate >> + * @param name - name to register >> + * @param block_size - size of buffers to use >> + * @param num_blocks - number of blocks to allocate >> + * >> + * @return configured gaura on success, CVMX_FPA3_INVALID_GAURA on >> failure >> + */ >> +cvmx_fpa3_gaura_t cvmx_fpa3_set_aura_for_pool(cvmx_fpa3_pool_t pool, >> int desired_aura, >> + const char *name, >> unsigned int block_size, >> + unsigned int num_blocks); >> + >> +/** >> + * Function to setup and initialize a pool. >> + * >> + * @param node - configure fpa on this node >> + * @param desired_aura - aura to use, -1 for dynamic allocation >> + * @param name - name to register >> + * @param block_size - size of buffers in pool >> + * @param num_blocks - max number of buffers allowed >> + */ >> +cvmx_fpa3_gaura_t cvmx_fpa3_setup_aura_and_pool(int node, int >> desired_aura, const char *name, >> + void *buffer, unsigned >> int block_size, >> + unsigned int >> num_blocks); >> + >> +int cvmx_fpa3_shutdown_aura_and_pool(cvmx_fpa3_gaura_t aura); >> +int cvmx_fpa3_shutdown_aura(cvmx_fpa3_gaura_t aura); >> +int cvmx_fpa3_shutdown_pool(cvmx_fpa3_pool_t pool); >> +const char *cvmx_fpa3_get_pool_name(cvmx_fpa3_pool_t pool); >> +int cvmx_fpa3_get_pool_buf_size(cvmx_fpa3_pool_t pool); >> +const char *cvmx_fpa3_get_aura_name(cvmx_fpa3_gaura_t aura); >> + >> +/* FIXME: Need a different macro for stage2 of u-boot */ >> + >> +static inline void cvmx_fpa3_stage2_init(int aura, int pool, u64 >> stack_paddr, int stacklen, >> + int buffer_sz, int buf_cnt) >> +{ >> + cvmx_fpa_poolx_cfg_t pool_cfg; >> + >> + /* Configure pool stack */ >> + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_BASE(pool), >> stack_paddr); >> + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_ADDR(pool), >> stack_paddr); >> + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_END(pool), >> stack_paddr + stacklen); >> + >> + /* Configure pool with buffer size */ >> + pool_cfg.u64 = 0; >> + pool_cfg.cn78xx.nat_align = 1; >> + pool_cfg.cn78xx.buf_size = buffer_sz >> 7; >> + pool_cfg.cn78xx.l_type = 0x2; >> + pool_cfg.cn78xx.ena = 0; >> + cvmx_write_csr_node(0, CVMX_FPA_POOLX_CFG(pool), pool_cfg.u64); >> + /* Reset pool before starting */ >> + pool_cfg.cn78xx.ena = 1; >> + cvmx_write_csr_node(0, CVMX_FPA_POOLX_CFG(pool), pool_cfg.u64); >> + >> + cvmx_write_csr_node(0, CVMX_FPA_AURAX_CFG(aura), 0); >> + cvmx_write_csr_node(0, CVMX_FPA_AURAX_CNT_ADD(aura), buf_cnt); >> + cvmx_write_csr_node(0, CVMX_FPA_AURAX_POOL(aura), (u64)pool); >> +} >> + >> +static inline void cvmx_fpa3_stage2_disable(int aura, int pool) >> +{ >> + cvmx_write_csr_node(0, CVMX_FPA_AURAX_POOL(aura), 0); >> + cvmx_write_csr_node(0, CVMX_FPA_POOLX_CFG(pool), 0); >> + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_BASE(pool), 0); >> + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_ADDR(pool), 0); >> + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_END(pool), 0); >> +} >> + >> +#endif /* __CVMX_FPA3_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-global- >> resources.h b/arch/mips/mach-octeon/include/mach/cvmx-global- >> resources.h >> new file mode 100644 >> index 000000000000..28c32ddbe17a >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-global-resources.h >> @@ -0,0 +1,213 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + */ >> + >> +#ifndef _CVMX_GLOBAL_RESOURCES_T_ >> +#define _CVMX_GLOBAL_RESOURCES_T_ >> + >> +#define CVMX_GLOBAL_RESOURCES_DATA_NAME "cvmx-global-resources" >> + >> +/*In macros below abbreviation GR stands for global resources. */ >> +#define >> CVMX_GR_TAG_INVALID >> \ >> + cvmx_get_gr_tag('i', 'n', 'v', 'a', 'l', 'i', 'd', '.', '.', >> '.', '.', '.', '.', '.', '.', \ >> + '.') >> +/*Tag for pko que table range. */ >> +#define >> CVMX_GR_TAG_PKO_QUEUES >> \ >> + cvmx_get_gr_tag('c', 'v', 'm', '_', 'p', 'k', 'o', '_', 'q', >> 'u', 'e', 'u', 's', '.', '.', \ >> + '.') >> +/*Tag for a pko internal ports range */ >> +#define >> CVMX_GR_TAG_PKO_IPORTS >> \ >> + cvmx_get_gr_tag('c', 'v', 'm', '_', 'p', 'k', 'o', '_', 'i', >> 'p', 'o', 'r', 't', '.', '.', \ >> + '.') >> +#define >> CVMX_GR_TAG_FPA >> \ >> + cvmx_get_gr_tag('c', 'v', 'm', '_', 'f', 'p', 'a', '.', '.', >> '.', '.', '.', '.', '.', '.', \ >> + '.') >> +#define >> CVMX_GR_TAG_FAU >> \ >> + cvmx_get_gr_tag('c', 'v', 'm', '_', 'f', 'a', 'u', '.', '.', >> '.', '.', '.', '.', '.', '.', \ >> + '.') >> +#define >> CVMX_GR_TAG_SSO_GRP(n) >> \ >> + cvmx_get_gr_tag('c', 'v', 'm', '_', 's', 's', 'o', '_', '0', >> (n) + '0', '.', '.', '.', \ >> + '.', '.', '.'); >> +#define >> CVMX_GR_TAG_TIM(n) >> \ >> + cvmx_get_gr_tag('c', 'v', 'm', '_', 't', 'i', 'm', '_', (n) + >> '0', '.', '.', '.', '.', \ >> + '.', '.', '.') >> +#define >> CVMX_GR_TAG_CLUSTERS(x) >> \ >> + cvmx_get_gr_tag('c', 'v', 'm', '_', 'c', 'l', 'u', 's', 't', >> 'e', 'r', '_', (x + '0'), \ >> + '.', '.', '.') >> +#define >> CVMX_GR_TAG_CLUSTER_GRP(x) >> \ >> + cvmx_get_gr_tag('c', 'v', 'm', '_', 'c', 'l', 'g', 'r', 'p', >> '_', (x + '0'), '.', '.', \ >> + '.', '.', '.') >> +#define >> CVMX_GR_TAG_STYLE(x) >> \ >> + cvmx_get_gr_tag('c', 'v', 'm', '_', 's', 't', 'y', 'l', 'e', >> '_', (x + '0'), '.', '.', \ >> + '.', '.', '.') >> +#define >> CVMX_GR_TAG_QPG_ENTRY(x) >> \ >> + cvmx_get_gr_tag('c', 'v', 'm', '_', 'q', 'p', 'g', 'e', 't', >> '_', (x + '0'), '.', '.', \ >> + '.', '.', '.') >> +#define >> CVMX_GR_TAG_BPID(x) >> \ >> + cvmx_get_gr_tag('c', 'v', 'm', '_', 'b', 'p', 'i', 'd', 's', >> '_', (x + '0'), '.', '.', \ >> + '.', '.', '.') >> +#define >> CVMX_GR_TAG_MTAG_IDX(x) >> \ >> + cvmx_get_gr_tag('c', 'v', 'm', '_', 'm', 't', 'a', 'g', 'x', >> '_', (x + '0'), '.', '.', \ >> + '.', '.', '.') >> +#define CVMX_GR_TAG_PCAM(x, y, >> z) \ >> + cvmx_get_gr_tag('c', 'v', 'm', '_', 'p', 'c', 'a', 'm', '_', (x >> + '0'), (y + '0'), \ >> + (z + '0'), '.', '.', '.', '.') >> + >> +#define >> CVMX_GR_TAG_CIU3_IDT(_n) >> \ >> + cvmx_get_gr_tag('c', 'v', 'm', '_', 'c', 'i', 'u', '3', '_', >> ((_n) + '0'), '_', 'i', 'd', \ >> + 't', '.', '.') >> + >> +/* Allocation of the 512 SW INTSTs (in the 12 bit SW INTSN space) >> */ >> +#define >> CVMX_GR_TAG_CIU3_SWINTSN(_n) >> \ >> + cvmx_get_gr_tag('c', 'v', 'm', '_', 'c', 'i', 'u', '3', '_', >> ((_n) + '0'), '_', 's', 'w', \ >> + 'i', 's', 'n') >> + >> +#define TAG_INIT_PART(A, B, C, D, E, F, G, >> H) \ >> + ((((u64)(A) & 0xff) << 56) | (((u64)(B) & 0xff) << 48) | >> (((u64)(C) & 0xff) << 40) | \ >> + (((u64)(D) & 0xff) << 32) | (((u64)(E) & 0xff) << 24) | >> (((u64)(F) & 0xff) << 16) | \ >> + (((u64)(G) & 0xff) << 8) | (((u64)(H) & 0xff))) >> + >> +struct global_resource_tag { >> + u64 lo; >> + u64 hi; >> +}; >> + >> +enum cvmx_resource_err { CVMX_RESOURCE_ALLOC_FAILED = -1, >> CVMX_RESOURCE_ALREADY_RESERVED = -2 }; >> + >> +/* >> + * @INTERNAL >> + * Creates a tag from the specified characters. >> + */ >> +static inline struct global_resource_tag cvmx_get_gr_tag(char a, >> char b, char c, char d, char e, >> + char f, char >> g, char h, char i, char j, >> + char k, char >> l, char m, char n, char o, >> + char p) >> +{ >> + struct global_resource_tag tag; >> + >> + tag.lo = TAG_INIT_PART(a, b, c, d, e, f, g, h); >> + tag.hi = TAG_INIT_PART(i, j, k, l, m, n, o, p); >> + return tag; >> +} >> + >> +static inline int cvmx_gr_same_tag(struct global_resource_tag gr1, >> struct global_resource_tag gr2) >> +{ >> + return (gr1.hi == gr2.hi) && (gr1.lo == gr2.lo); >> +} >> + >> +/* >> + * @INTERNAL >> + * Creates a global resource range that can hold the specified >> number of >> + * elements >> + * @param tag is the tag of the range. The taga is created using the >> method >> + * cvmx_get_gr_tag() >> + * @param nelements is the number of elements to be held in the >> resource range. >> + */ >> +int cvmx_create_global_resource_range(struct global_resource_tag >> tag, int nelements); >> + >> +/* >> + * @INTERNAL >> + * Allocate nelements in the global resource range with the >> specified tag. It >> + * is assumed that prior >> + * to calling this the global resource range has already been >> created using >> + * cvmx_create_global_resource_range(). >> + * @param tag is the tag of the global resource range. >> + * @param nelements is the number of elements to be allocated. >> + * @param owner is a 64 bit number that identifes the owner of this >> range. >> + * @aligment specifes the required alignment of the returned base >> number. >> + * @return returns the base of the allocated range. -1 return value >> indicates >> + * failure. >> + */ >> +int cvmx_allocate_global_resource_range(struct global_resource_tag >> tag, u64 owner, int nelements, >> + int alignment); >> + >> +/* >> + * @INTERNAL >> + * Allocate nelements in the global resource range with the >> specified tag. >> + * The elements allocated need not be contiguous. It is assumed that >> prior to >> + * calling this the global resource range has already >> + * been created using cvmx_create_global_resource_range(). >> + * @param tag is the tag of the global resource range. >> + * @param nelements is the number of elements to be allocated. >> + * @param owner is a 64 bit number that identifes the owner of the >> allocated >> + * elements. >> + * @param allocated_elements returns indexs of the allocated >> entries. >> + * @return returns 0 on success and -1 on failure. >> + */ >> +int cvmx_resource_alloc_many(struct global_resource_tag tag, u64 >> owner, int nelements, >> + int allocated_elements[]); >> +int cvmx_resource_alloc_reverse(struct global_resource_tag, u64 >> owner); >> +/* >> + * @INTERNAL >> + * Reserve nelements starting from base in the global resource range >> with the >> + * specified tag. >> + * It is assumed that prior to calling this the global resource >> range has >> + * already been created using cvmx_create_global_resource_range(). >> + * @param tag is the tag of the global resource range. >> + * @param nelements is the number of elements to be allocated. >> + * @param owner is a 64 bit number that identifes the owner of this >> range. >> + * @base specifies the base start of nelements. >> + * @return returns the base of the allocated range. -1 return value >> indicates >> + * failure. >> + */ >> +int cvmx_reserve_global_resource_range(struct global_resource_tag >> tag, u64 owner, int base, >> + int nelements); >> +/* >> + * @INTERNAL >> + * Free nelements starting at base in the global resource range with >> the >> + * specified tag. >> + * @param tag is the tag of the global resource range. >> + * @param base is the base number >> + * @param nelements is the number of elements that are to be freed. >> + * @return returns 0 if successful and -1 on failure. >> + */ >> +int cvmx_free_global_resource_range_with_base(struct >> global_resource_tag tag, int base, >> + int nelements); >> + >> +/* >> + * @INTERNAL >> + * Free nelements with the bases specified in bases[] with the >> + * specified tag. >> + * @param tag is the tag of the global resource range. >> + * @param bases is an array containing the bases to be freed. >> + * @param nelements is the number of elements that are to be freed. >> + * @return returns 0 if successful and -1 on failure. >> + */ >> +int cvmx_free_global_resource_range_multiple(struct >> global_resource_tag tag, int bases[], >> + int nelements); >> +/* >> + * @INTERNAL >> + * Free elements from the specified owner in the global resource >> range with the >> + * specified tag. >> + * @param tag is the tag of the global resource range. >> + * @param owner is the owner of resources that are to be freed. >> + * @return returns 0 if successful and -1 on failure. >> + */ >> +int cvmx_free_global_resource_range_with_owner(struct >> global_resource_tag tag, int owner); >> + >> +/* >> + * @INTERNAL >> + * Frees all the global resources that have been created. >> + * For use only from the bootloader, when it shutdown and boots up >> the >> + * application or kernel. >> + */ >> +int free_global_resources(void); >> + >> +u64 cvmx_get_global_resource_owner(struct global_resource_tag tag, >> int base); >> +/* >> + * @INTERNAL >> + * Shows the global resource range with the specified tag. Use >> mainly for debug. >> + */ >> +void cvmx_show_global_resource_range(struct global_resource_tag >> tag); >> + >> +/* >> + * @INTERNAL >> + * Shows all the global resources. Used mainly for debug. >> + */ >> +void cvmx_global_resources_show(void); >> + >> +u64 cvmx_allocate_app_id(void); >> +u64 cvmx_get_app_id(void); >> + >> +#endif >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-gmx.h >> b/arch/mips/mach-octeon/include/mach/cvmx-gmx.h >> new file mode 100644 >> index 000000000000..2df7da102a0f >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-gmx.h >> @@ -0,0 +1,16 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Interface to the GMX hardware. >> + */ >> + >> +#ifndef __CVMX_GMX_H__ >> +#define __CVMX_GMX_H__ >> + >> +/* CSR typedefs have been moved to cvmx-gmx-defs.h */ >> + >> +int cvmx_gmx_set_backpressure_override(u32 interface, u32 >> port_mask); >> +int cvmx_agl_set_backpressure_override(u32 interface, u32 >> port_mask); >> + >> +#endif >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-hwfau.h >> b/arch/mips/mach-octeon/include/mach/cvmx-hwfau.h >> new file mode 100644 >> index 000000000000..59772190aa3b >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-hwfau.h >> @@ -0,0 +1,606 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Interface to the hardware Fetch and Add Unit. >> + */ >> + >> +/** >> + * @file >> + * >> + * Interface to the hardware Fetch and Add Unit. >> + * >> + */ >> + >> +#ifndef __CVMX_HWFAU_H__ >> +#define __CVMX_HWFAU_H__ >> + >> +typedef int cvmx_fau_reg64_t; >> +typedef int cvmx_fau_reg32_t; >> +typedef int cvmx_fau_reg16_t; >> +typedef int cvmx_fau_reg8_t; >> + >> +#define CVMX_FAU_REG_ANY -1 >> + >> +/* >> + * Octeon Fetch and Add Unit (FAU) >> + */ >> + >> +#define CVMX_FAU_LOAD_IO_ADDRESS cvmx_build_io_address(0x1e, 0) >> +#define CVMX_FAU_BITS_SCRADDR 63, 56 >> +#define CVMX_FAU_BITS_LEN 55, 48 >> +#define CVMX_FAU_BITS_INEVAL 35, 14 >> +#define CVMX_FAU_BITS_TAGWAIT 13, 13 >> +#define CVMX_FAU_BITS_NOADD 13, 13 >> +#define CVMX_FAU_BITS_SIZE 12, 11 >> +#define CVMX_FAU_BITS_REGISTER 10, 0 >> + >> +#define CVMX_FAU_MAX_REGISTERS_8 (2048) >> + >> +typedef enum { >> + CVMX_FAU_OP_SIZE_8 = 0, >> + CVMX_FAU_OP_SIZE_16 = 1, >> + CVMX_FAU_OP_SIZE_32 = 2, >> + CVMX_FAU_OP_SIZE_64 = 3 >> +} cvmx_fau_op_size_t; >> + >> +/** >> + * Tagwait return definition. If a timeout occurs, the error >> + * bit will be set. Otherwise the value of the register before >> + * the update will be returned. >> + */ >> +typedef struct { >> + u64 error : 1; >> + s64 value : 63; >> +} cvmx_fau_tagwait64_t; >> + >> +/** >> + * Tagwait return definition. If a timeout occurs, the error >> + * bit will be set. Otherwise the value of the register before >> + * the update will be returned. >> + */ >> +typedef struct { >> + u64 error : 1; >> + s32 value : 31; >> +} cvmx_fau_tagwait32_t; >> + >> +/** >> + * Tagwait return definition. If a timeout occurs, the error >> + * bit will be set. Otherwise the value of the register before >> + * the update will be returned. >> + */ >> +typedef struct { >> + u64 error : 1; >> + s16 value : 15; >> +} cvmx_fau_tagwait16_t; >> + >> +/** >> + * Tagwait return definition. If a timeout occurs, the error >> + * bit will be set. Otherwise the value of the register before >> + * the update will be returned. >> + */ >> +typedef struct { >> + u64 error : 1; >> + int8_t value : 7; >> +} cvmx_fau_tagwait8_t; >> + >> +/** >> + * Asynchronous tagwait return definition. If a timeout occurs, >> + * the error bit will be set. Otherwise the value of the >> + * register before the update will be returned. >> + */ >> +typedef union { >> + u64 u64; >> + struct { >> + u64 invalid : 1; >> + u64 data : 63; /* unpredictable if invalid is set */ >> + } s; >> +} cvmx_fau_async_tagwait_result_t; >> + >> +#define SWIZZLE_8 0 >> +#define SWIZZLE_16 0 >> +#define SWIZZLE_32 0 >> + >> +/** >> + * @INTERNAL >> + * Builds a store I/O address for writing to the FAU >> + * >> + * @param noadd 0 = Store value is atomically added to the current >> value >> + * 1 = Store value is atomically written over the >> current value >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 2 for 16 bit access. >> + * - Step by 4 for 32 bit access. >> + * - Step by 8 for 64 bit access. >> + * @return Address to store for atomic update >> + */ >> +static inline u64 __cvmx_hwfau_store_address(u64 noadd, u64 reg) >> +{ >> + return (CVMX_ADD_IO_SEG(CVMX_FAU_LOAD_IO_ADDRESS) | >> + cvmx_build_bits(CVMX_FAU_BITS_NOADD, noadd) | >> + cvmx_build_bits(CVMX_FAU_BITS_REGISTER, reg)); >> +} >> + >> +/** >> + * @INTERNAL >> + * Builds a I/O address for accessing the FAU >> + * >> + * @param tagwait Should the atomic add wait for the current tag >> switch >> + * operation to complete. >> + * - 0 = Don't wait >> + * - 1 = Wait for tag switch to complete >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 2 for 16 bit access. >> + * - Step by 4 for 32 bit access. >> + * - Step by 8 for 64 bit access. >> + * @param value Signed value to add. >> + * Note: When performing 32 and 64 bit access, only >> the low >> + * 22 bits are available. >> + * @return Address to read from for atomic update >> + */ >> +static inline u64 __cvmx_hwfau_atomic_address(u64 tagwait, u64 reg, >> s64 value) >> +{ >> + return (CVMX_ADD_IO_SEG(CVMX_FAU_LOAD_IO_ADDRESS) | >> + cvmx_build_bits(CVMX_FAU_BITS_INEVAL, value) | >> + cvmx_build_bits(CVMX_FAU_BITS_TAGWAIT, tagwait) | >> + cvmx_build_bits(CVMX_FAU_BITS_REGISTER, reg)); >> +} >> + >> +/** >> + * Perform an atomic 64 bit add >> + * >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 8 for 64 bit access. >> + * @param value Signed value to add. >> + * Note: Only the low 22 bits are available. >> + * @return Value of the register before the update >> + */ >> +static inline s64 cvmx_hwfau_fetch_and_add64(cvmx_fau_reg64_t reg, >> s64 value) >> +{ >> + return cvmx_read64_int64(__cvmx_hwfau_atomic_address(0, reg, >> value)); >> +} >> + >> +/** >> + * Perform an atomic 32 bit add >> + * >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 4 for 32 bit access. >> + * @param value Signed value to add. >> + * Note: Only the low 22 bits are available. >> + * @return Value of the register before the update >> + */ >> +static inline s32 cvmx_hwfau_fetch_and_add32(cvmx_fau_reg32_t reg, >> s32 value) >> +{ >> + reg ^= SWIZZLE_32; >> + return cvmx_read64_int32(__cvmx_hwfau_atomic_address(0, reg, >> value)); >> +} >> + >> +/** >> + * Perform an atomic 16 bit add >> + * >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 2 for 16 bit access. >> + * @param value Signed value to add. >> + * @return Value of the register before the update >> + */ >> +static inline s16 cvmx_hwfau_fetch_and_add16(cvmx_fau_reg16_t reg, >> s16 value) >> +{ >> + reg ^= SWIZZLE_16; >> + return cvmx_read64_int16(__cvmx_hwfau_atomic_address(0, reg, >> value)); >> +} >> + >> +/** >> + * Perform an atomic 8 bit add >> + * >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * @param value Signed value to add. >> + * @return Value of the register before the update >> + */ >> +static inline int8_t cvmx_hwfau_fetch_and_add8(cvmx_fau_reg8_t reg, >> int8_t value) >> +{ >> + reg ^= SWIZZLE_8; >> + return cvmx_read64_int8(__cvmx_hwfau_atomic_address(0, reg, >> value)); >> +} >> + >> +/** >> + * Perform an atomic 64 bit add after the current tag switch >> + * completes >> + * >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 8 for 64 bit access. >> + * @param value Signed value to add. >> + * Note: Only the low 22 bits are available. >> + * @return If a timeout occurs, the error bit will be set. Otherwise >> + * the value of the register before the update will be >> + * returned >> + */ >> +static inline cvmx_fau_tagwait64_t >> cvmx_hwfau_tagwait_fetch_and_add64(cvmx_fau_reg64_t reg, >> + s >> 64 value) >> +{ >> + union { >> + u64 i64; >> + cvmx_fau_tagwait64_t t; >> + } result; >> + result.i64 = cvmx_read64_int64(__cvmx_hwfau_atomic_address(1, >> reg, value)); >> + return result.t; >> +} >> + >> +/** >> + * Perform an atomic 32 bit add after the current tag switch >> + * completes >> + * >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 4 for 32 bit access. >> + * @param value Signed value to add. >> + * Note: Only the low 22 bits are available. >> + * @return If a timeout occurs, the error bit will be set. Otherwise >> + * the value of the register before the update will be >> + * returned >> + */ >> +static inline cvmx_fau_tagwait32_t >> cvmx_hwfau_tagwait_fetch_and_add32(cvmx_fau_reg32_t reg, >> + s >> 32 value) >> +{ >> + union { >> + u64 i32; >> + cvmx_fau_tagwait32_t t; >> + } result; >> + reg ^= SWIZZLE_32; >> + result.i32 = cvmx_read64_int32(__cvmx_hwfau_atomic_address(1, >> reg, value)); >> + return result.t; >> +} >> + >> +/** >> + * Perform an atomic 16 bit add after the current tag switch >> + * completes >> + * >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 2 for 16 bit access. >> + * @param value Signed value to add. >> + * @return If a timeout occurs, the error bit will be set. Otherwise >> + * the value of the register before the update will be >> + * returned >> + */ >> +static inline cvmx_fau_tagwait16_t >> cvmx_hwfau_tagwait_fetch_and_add16(cvmx_fau_reg16_t reg, >> + s >> 16 value) >> +{ >> + union { >> + u64 i16; >> + cvmx_fau_tagwait16_t t; >> + } result; >> + reg ^= SWIZZLE_16; >> + result.i16 = cvmx_read64_int16(__cvmx_hwfau_atomic_address(1, >> reg, value)); >> + return result.t; >> +} >> + >> +/** >> + * Perform an atomic 8 bit add after the current tag switch >> + * completes >> + * >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * @param value Signed value to add. >> + * @return If a timeout occurs, the error bit will be set. Otherwise >> + * the value of the register before the update will be >> + * returned >> + */ >> +static inline cvmx_fau_tagwait8_t >> cvmx_hwfau_tagwait_fetch_and_add8(cvmx_fau_reg8_t reg, >> + int >> 8_t value) >> +{ >> + union { >> + u64 i8; >> + cvmx_fau_tagwait8_t t; >> + } result; >> + reg ^= SWIZZLE_8; >> + result.i8 = cvmx_read64_int8(__cvmx_hwfau_atomic_address(1, >> reg, value)); >> + return result.t; >> +} >> + >> +/** >> + * @INTERNAL >> + * Builds I/O data for async operations >> + * >> + * @param scraddr Scratch pad byte address to write to. Must be 8 >> byte aligned >> + * @param value Signed value to add. >> + * Note: When performing 32 and 64 bit access, only >> the low >> + * 22 bits are available. >> + * @param tagwait Should the atomic add wait for the current tag >> switch >> + * operation to complete. >> + * - 0 = Don't wait >> + * - 1 = Wait for tag switch to complete >> + * @param size The size of the operation: >> + * - CVMX_FAU_OP_SIZE_8 (0) = 8 bits >> + * - CVMX_FAU_OP_SIZE_16 (1) = 16 bits >> + * - CVMX_FAU_OP_SIZE_32 (2) = 32 bits >> + * - CVMX_FAU_OP_SIZE_64 (3) = 64 bits >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 2 for 16 bit access. >> + * - Step by 4 for 32 bit access. >> + * - Step by 8 for 64 bit access. >> + * @return Data to write using cvmx_send_single >> + */ >> +static inline u64 __cvmx_fau_iobdma_data(u64 scraddr, s64 value, u64 >> tagwait, >> + cvmx_fau_op_size_t size, u64 >> reg) >> +{ >> + return (CVMX_FAU_LOAD_IO_ADDRESS | >> cvmx_build_bits(CVMX_FAU_BITS_SCRADDR, scraddr >> 3) | >> + cvmx_build_bits(CVMX_FAU_BITS_LEN, 1) | >> + cvmx_build_bits(CVMX_FAU_BITS_INEVAL, value) | >> + cvmx_build_bits(CVMX_FAU_BITS_TAGWAIT, tagwait) | >> + cvmx_build_bits(CVMX_FAU_BITS_SIZE, size) | >> + cvmx_build_bits(CVMX_FAU_BITS_REGISTER, reg)); >> +} >> + >> +/** >> + * Perform an async atomic 64 bit add. The old value is >> + * placed in the scratch memory at byte address scraddr. >> + * >> + * @param scraddr Scratch memory byte address to put response in. >> + * Must be 8 byte aligned. >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 8 for 64 bit access. >> + * @param value Signed value to add. >> + * Note: Only the low 22 bits are available. >> + * @return Placed in the scratch pad register >> + */ >> +static inline void cvmx_hwfau_async_fetch_and_add64(u64 scraddr, >> cvmx_fau_reg64_t reg, s64 value) >> +{ >> + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 0, >> CVMX_FAU_OP_SIZE_64, reg)); >> +} >> + >> +/** >> + * Perform an async atomic 32 bit add. The old value is >> + * placed in the scratch memory at byte address scraddr. >> + * >> + * @param scraddr Scratch memory byte address to put response in. >> + * Must be 8 byte aligned. >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 4 for 32 bit access. >> + * @param value Signed value to add. >> + * Note: Only the low 22 bits are available. >> + * @return Placed in the scratch pad register >> + */ >> +static inline void cvmx_hwfau_async_fetch_and_add32(u64 scraddr, >> cvmx_fau_reg32_t reg, s32 value) >> +{ >> + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 0, >> CVMX_FAU_OP_SIZE_32, reg)); >> +} >> + >> +/** >> + * Perform an async atomic 16 bit add. The old value is >> + * placed in the scratch memory at byte address scraddr. >> + * >> + * @param scraddr Scratch memory byte address to put response in. >> + * Must be 8 byte aligned. >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 2 for 16 bit access. >> + * @param value Signed value to add. >> + * @return Placed in the scratch pad register >> + */ >> +static inline void cvmx_hwfau_async_fetch_and_add16(u64 scraddr, >> cvmx_fau_reg16_t reg, s16 value) >> +{ >> + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 0, >> CVMX_FAU_OP_SIZE_16, reg)); >> +} >> + >> +/** >> + * Perform an async atomic 8 bit add. The old value is >> + * placed in the scratch memory at byte address scraddr. >> + * >> + * @param scraddr Scratch memory byte address to put response in. >> + * Must be 8 byte aligned. >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * @param value Signed value to add. >> + * @return Placed in the scratch pad register >> + */ >> +static inline void cvmx_hwfau_async_fetch_and_add8(u64 scraddr, >> cvmx_fau_reg8_t reg, int8_t value) >> +{ >> + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 0, >> CVMX_FAU_OP_SIZE_8, reg)); >> +} >> + >> +/** >> + * Perform an async atomic 64 bit add after the current tag >> + * switch completes. >> + * >> + * @param scraddr Scratch memory byte address to put response in. >> + * Must be 8 byte aligned. >> + * If a timeout occurs, the error bit (63) will be >> set. Otherwise >> + * the value of the register before the update will >> be >> + * returned >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 8 for 64 bit access. >> + * @param value Signed value to add. >> + * Note: Only the low 22 bits are available. >> + * @return Placed in the scratch pad register >> + */ >> +static inline void cvmx_hwfau_async_tagwait_fetch_and_add64(u64 >> scraddr, cvmx_fau_reg64_t reg, >> + s64 value) >> +{ >> + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 1, >> CVMX_FAU_OP_SIZE_64, reg)); >> +} >> + >> +/** >> + * Perform an async atomic 32 bit add after the current tag >> + * switch completes. >> + * >> + * @param scraddr Scratch memory byte address to put response in. >> + * Must be 8 byte aligned. >> + * If a timeout occurs, the error bit (63) will be >> set. Otherwise >> + * the value of the register before the update will >> be >> + * returned >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 4 for 32 bit access. >> + * @param value Signed value to add. >> + * Note: Only the low 22 bits are available. >> + * @return Placed in the scratch pad register >> + */ >> +static inline void cvmx_hwfau_async_tagwait_fetch_and_add32(u64 >> scraddr, cvmx_fau_reg32_t reg, >> + s32 value) >> +{ >> + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 1, >> CVMX_FAU_OP_SIZE_32, reg)); >> +} >> + >> +/** >> + * Perform an async atomic 16 bit add after the current tag >> + * switch completes. >> + * >> + * @param scraddr Scratch memory byte address to put response in. >> + * Must be 8 byte aligned. >> + * If a timeout occurs, the error bit (63) will be >> set. Otherwise >> + * the value of the register before the update will >> be >> + * returned >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 2 for 16 bit access. >> + * @param value Signed value to add. >> + * @return Placed in the scratch pad register >> + */ >> +static inline void cvmx_hwfau_async_tagwait_fetch_and_add16(u64 >> scraddr, cvmx_fau_reg16_t reg, >> + s16 value) >> +{ >> + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 1, >> CVMX_FAU_OP_SIZE_16, reg)); >> +} >> + >> +/** >> + * Perform an async atomic 8 bit add after the current tag >> + * switch completes. >> + * >> + * @param scraddr Scratch memory byte address to put response in. >> + * Must be 8 byte aligned. >> + * If a timeout occurs, the error bit (63) will be >> set. Otherwise >> + * the value of the register before the update will >> be >> + * returned >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * @param value Signed value to add. >> + * @return Placed in the scratch pad register >> + */ >> +static inline void cvmx_hwfau_async_tagwait_fetch_and_add8(u64 >> scraddr, cvmx_fau_reg8_t reg, >> + int8_t >> value) >> +{ >> + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 1, >> CVMX_FAU_OP_SIZE_8, reg)); >> +} >> + >> +/** >> + * Perform an atomic 64 bit add >> + * >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 8 for 64 bit access. >> + * @param value Signed value to add. >> + */ >> +static inline void cvmx_hwfau_atomic_add64(cvmx_fau_reg64_t reg, s64 >> value) >> +{ >> + cvmx_write64_int64(__cvmx_hwfau_store_address(0, reg), value); >> +} >> + >> +/** >> + * Perform an atomic 32 bit add >> + * >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 4 for 32 bit access. >> + * @param value Signed value to add. >> + */ >> +static inline void cvmx_hwfau_atomic_add32(cvmx_fau_reg32_t reg, s32 >> value) >> +{ >> + reg ^= SWIZZLE_32; >> + cvmx_write64_int32(__cvmx_hwfau_store_address(0, reg), value); >> +} >> + >> +/** >> + * Perform an atomic 16 bit add >> + * >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 2 for 16 bit access. >> + * @param value Signed value to add. >> + */ >> +static inline void cvmx_hwfau_atomic_add16(cvmx_fau_reg16_t reg, s16 >> value) >> +{ >> + reg ^= SWIZZLE_16; >> + cvmx_write64_int16(__cvmx_hwfau_store_address(0, reg), value); >> +} >> + >> +/** >> + * Perform an atomic 8 bit add >> + * >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * @param value Signed value to add. >> + */ >> +static inline void cvmx_hwfau_atomic_add8(cvmx_fau_reg8_t reg, >> int8_t value) >> +{ >> + reg ^= SWIZZLE_8; >> + cvmx_write64_int8(__cvmx_hwfau_store_address(0, reg), value); >> +} >> + >> +/** >> + * Perform an atomic 64 bit write >> + * >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 8 for 64 bit access. >> + * @param value Signed value to write. >> + */ >> +static inline void cvmx_hwfau_atomic_write64(cvmx_fau_reg64_t reg, >> s64 value) >> +{ >> + cvmx_write64_int64(__cvmx_hwfau_store_address(1, reg), value); >> +} >> + >> +/** >> + * Perform an atomic 32 bit write >> + * >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 4 for 32 bit access. >> + * @param value Signed value to write. >> + */ >> +static inline void cvmx_hwfau_atomic_write32(cvmx_fau_reg32_t reg, >> s32 value) >> +{ >> + reg ^= SWIZZLE_32; >> + cvmx_write64_int32(__cvmx_hwfau_store_address(1, reg), value); >> +} >> + >> +/** >> + * Perform an atomic 16 bit write >> + * >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * - Step by 2 for 16 bit access. >> + * @param value Signed value to write. >> + */ >> +static inline void cvmx_hwfau_atomic_write16(cvmx_fau_reg16_t reg, >> s16 value) >> +{ >> + reg ^= SWIZZLE_16; >> + cvmx_write64_int16(__cvmx_hwfau_store_address(1, reg), value); >> +} >> + >> +/** >> + * Perform an atomic 8 bit write >> + * >> + * @param reg FAU atomic register to access. 0 <= reg < 2048. >> + * @param value Signed value to write. >> + */ >> +static inline void cvmx_hwfau_atomic_write8(cvmx_fau_reg8_t reg, >> int8_t value) >> +{ >> + reg ^= SWIZZLE_8; >> + cvmx_write64_int8(__cvmx_hwfau_store_address(1, reg), value); >> +} >> + >> +/** Allocates 64bit FAU register. >> + * @return value is the base address of allocated FAU register >> + */ >> +int cvmx_fau64_alloc(int reserve); >> + >> +/** Allocates 32bit FAU register. >> + * @return value is the base address of allocated FAU register >> + */ >> +int cvmx_fau32_alloc(int reserve); >> + >> +/** Allocates 16bit FAU register. >> + * @return value is the base address of allocated FAU register >> + */ >> +int cvmx_fau16_alloc(int reserve); >> + >> +/** Allocates 8bit FAU register. >> + * @return value is the base address of allocated FAU register >> + */ >> +int cvmx_fau8_alloc(int reserve); >> + >> +/** Frees the specified FAU register. >> + * @param address Base address of register to release. >> + * @return 0 on success; -1 on failure >> + */ >> +int cvmx_fau_free(int address); >> + >> +/** Display the fau registers array >> + */ >> +void cvmx_fau_show(void); >> + >> +#endif /* __CVMX_HWFAU_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-hwpko.h >> b/arch/mips/mach-octeon/include/mach/cvmx-hwpko.h >> new file mode 100644 >> index 000000000000..459c19bbc0f1 >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-hwpko.h >> @@ -0,0 +1,570 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Interface to the hardware Packet Output unit. >> + * >> + * Starting with SDK 1.7.0, the PKO output functions now support >> + * two types of locking. CVMX_PKO_LOCK_ATOMIC_TAG continues to >> + * function similarly to previous SDKs by using POW atomic tags >> + * to preserve ordering and exclusivity. As a new option, you >> + * can now pass CVMX_PKO_LOCK_CMD_QUEUE which uses a ll/sc >> + * memory based locking instead. This locking has the advantage >> + * of not affecting the tag state but doesn't preserve packet >> + * ordering. CVMX_PKO_LOCK_CMD_QUEUE is appropriate in most >> + * generic code while CVMX_PKO_LOCK_CMD_QUEUE should be used >> + * with hand tuned fast path code. >> + * >> + * Some of other SDK differences visible to the command command >> + * queuing: >> + * - PKO indexes are no longer stored in the FAU. A large >> + * percentage of the FAU register block used to be tied up >> + * maintaining PKO queue pointers. These are now stored in a >> + * global named block. >> + * - The PKO <b>use_locking</b> parameter can now have a global >> + * effect. Since all application use the same named block, >> + * queue locking correctly applies across all operating >> + * systems when using CVMX_PKO_LOCK_CMD_QUEUE. >> + * - PKO 3 word commands are now supported. Use >> + * cvmx_pko_send_packet_finish3(). >> + */ >> + >> +#ifndef __CVMX_HWPKO_H__ >> +#define __CVMX_HWPKO_H__ >> + >> +#include "cvmx-hwfau.h" >> +#include "cvmx-fpa.h" >> +#include "cvmx-pow.h" >> +#include "cvmx-cmd-queue.h" >> +#include "cvmx-helper.h" >> +#include "cvmx-helper-util.h" >> +#include "cvmx-helper-cfg.h" >> + >> +/* Adjust the command buffer size by 1 word so that in the case of >> using only >> +** two word PKO commands no command words stradle buffers. The >> useful values >> +** for this are 0 and 1. */ >> +#define CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST (1) >> + >> +#define CVMX_PKO_MAX_OUTPUT_QUEUES_STATIC 256 >> +#define >> CVMX_PKO_MAX_OUTPUT_QUEUES >> \ >> + ((OCTEON_IS_OCTEON2() || OCTEON_IS_MODEL(OCTEON_CN70XX)) ? 256 >> : 128) >> +#define >> CVMX_PKO_NUM_OUTPUT_PORTS >> \ >> + ((OCTEON_IS_MODEL(OCTEON_CN63XX)) ? 44 : >> (OCTEON_IS_MODEL(OCTEON_CN66XX) ? 48 : 40)) >> +#define CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID 63 >> +#define CVMX_PKO_QUEUE_STATIC_PRIORITY 9 >> +#define CVMX_PKO_ILLEGAL_QUEUE 0xFFFF >> +#define CVMX_PKO_MAX_QUEUE_DEPTH 0 >> + >> +typedef enum { >> + CVMX_PKO_SUCCESS, >> + CVMX_PKO_INVALID_PORT, >> + CVMX_PKO_INVALID_QUEUE, >> + CVMX_PKO_INVALID_PRIORITY, >> + CVMX_PKO_NO_MEMORY, >> + CVMX_PKO_PORT_ALREADY_SETUP, >> + CVMX_PKO_CMD_QUEUE_INIT_ERROR >> +} cvmx_pko_return_value_t; >> + >> +/** >> + * This enumeration represents the differnet locking modes supported >> by PKO. >> + */ >> +typedef enum { >> + CVMX_PKO_LOCK_NONE = 0, >> + CVMX_PKO_LOCK_ATOMIC_TAG = 1, >> + CVMX_PKO_LOCK_CMD_QUEUE = 2, >> +} cvmx_pko_lock_t; >> + >> +typedef struct cvmx_pko_port_status { >> + u32 packets; >> + u64 octets; >> + u64 doorbell; >> +} cvmx_pko_port_status_t; >> + >> +/** >> + * This structure defines the address to use on a packet enqueue >> + */ >> +typedef union { >> + u64 u64; >> + struct { >> + cvmx_mips_space_t mem_space : 2; >> + u64 reserved : 13; >> + u64 is_io : 1; >> + u64 did : 8; >> + u64 reserved2 : 4; >> + u64 reserved3 : 15; >> + u64 port : 9; >> + u64 queue : 9; >> + u64 reserved4 : 3; >> + } s; >> +} cvmx_pko_doorbell_address_t; >> + >> +/** >> + * Structure of the first packet output command word. >> + */ >> +typedef union { >> + u64 u64; >> + struct { >> + cvmx_fau_op_size_t size1 : 2; >> + cvmx_fau_op_size_t size0 : 2; >> + u64 subone1 : 1; >> + u64 reg1 : 11; >> + u64 subone0 : 1; >> + u64 reg0 : 11; >> + u64 le : 1; >> + u64 n2 : 1; >> + u64 wqp : 1; >> + u64 rsp : 1; >> + u64 gather : 1; >> + u64 ipoffp1 : 7; >> + u64 ignore_i : 1; >> + u64 dontfree : 1; >> + u64 segs : 6; >> + u64 total_bytes : 16; >> + } s; >> +} cvmx_pko_command_word0_t; >> + >> +/** >> + * Call before any other calls to initialize the packet >> + * output system. >> + */ >> + >> +void cvmx_pko_hw_init(u8 pool, unsigned int bufsize); >> + >> +/** >> + * Enables the packet output hardware. It must already be >> + * configured. >> + */ >> +void cvmx_pko_enable(void); >> + >> +/** >> + * Disables the packet output. Does not affect any configuration. >> + */ >> +void cvmx_pko_disable(void); >> + >> +/** >> + * Shutdown and free resources required by packet output. >> + */ >> + >> +void cvmx_pko_shutdown(void); >> + >> +/** >> + * Configure a output port and the associated queues for use. >> + * >> + * @param port Port to configure. >> + * @param base_queue First queue number to associate with this port. >> + * @param num_queues Number of queues t oassociate with this port >> + * @param priority Array of priority levels for each queue. Values >> are >> + * allowed to be 1-8. A value of 8 get 8 times the >> traffic >> + * of a value of 1. There must be num_queues >> elements in the >> + * array. >> + */ >> +cvmx_pko_return_value_t cvmx_pko_config_port(int port, int >> base_queue, int num_queues, >> + const u8 priority[]); >> + >> +/** >> + * Ring the packet output doorbell. This tells the packet >> + * output hardware that "len" command words have been added >> + * to its pending list. This command includes the required >> + * CVMX_SYNCWS before the doorbell ring. >> + * >> + * WARNING: This function may have to look up the proper PKO port in >> + * the IPD port to PKO port map, and is thus slower than calling >> + * cvmx_pko_doorbell_pkoid() directly if the PKO port identifier is >> + * known. >> + * >> + * @param ipd_port The IPD port corresponding the to pko port the >> packet is for >> + * @param queue Queue the packet is for >> + * @param len Length of the command in 64 bit words >> + */ >> +static inline void cvmx_pko_doorbell(u64 ipd_port, u64 queue, u64 >> len) >> +{ >> + cvmx_pko_doorbell_address_t ptr; >> + u64 pko_port; >> + >> + pko_port = ipd_port; >> + if (octeon_has_feature(OCTEON_FEATURE_PKND)) >> + pko_port = cvmx_helper_cfg_ipd2pko_port_base(ipd_port); >> + >> + ptr.u64 = 0; >> + ptr.s.mem_space = CVMX_IO_SEG; >> + ptr.s.did = CVMX_OCT_DID_PKT_SEND; >> + ptr.s.is_io = 1; >> + ptr.s.port = pko_port; >> + ptr.s.queue = queue; >> + /* Need to make sure output queue data is in DRAM before >> doorbell write */ >> + CVMX_SYNCWS; >> + cvmx_write_io(ptr.u64, len); >> +} >> + >> +/** >> + * Prepare to send a packet. This may initiate a tag switch to >> + * get exclusive access to the output queue structure, and >> + * performs other prep work for the packet send operation. >> + * >> + * cvmx_pko_send_packet_finish() MUST be called after this function >> is called, >> + * and must be called with the same port/queue/use_locking >> arguments. >> + * >> + * The use_locking parameter allows the caller to use three >> + * possible locking modes. >> + * - CVMX_PKO_LOCK_NONE >> + * - PKO doesn't do any locking. It is the responsibility >> + * of the application to make sure that no other core >> + * is accessing the same queue at the same time. >> + * - CVMX_PKO_LOCK_ATOMIC_TAG >> + * - PKO performs an atomic tagswitch to insure exclusive >> + * access to the output queue. This will maintain >> + * packet ordering on output. >> + * - CVMX_PKO_LOCK_CMD_QUEUE >> + * - PKO uses the common command queue locks to insure >> + * exclusive access to the output queue. This is a >> + * memory based ll/sc. This is the most portable >> + * locking mechanism. >> + * >> + * NOTE: If atomic locking is used, the POW entry CANNOT be >> + * descheduled, as it does not contain a valid WQE pointer. >> + * >> + * @param port Port to send it on, this can be either IPD port or >> PKO >> + * port. >> + * @param queue Queue to use >> + * @param use_locking >> + * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or >> CVMX_PKO_LOCK_CMD_QUEUE >> + */ >> +static inline void cvmx_pko_send_packet_prepare(u64 port >> __attribute__((unused)), u64 queue, >> + cvmx_pko_lock_t >> use_locking) >> +{ >> + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) { >> + /* >> + * Must do a full switch here to handle all cases. We >> use a >> + * fake WQE pointer, as the POW does not access this >> memory. >> + * The WQE pointer and group are only used if this work >> is >> + * descheduled, which is not supported by the >> + * >> cvmx_pko_send_packet_prepare/cvmx_pko_send_packet_finish >> + * combination. Note that this is a special case in >> which these >> + * fake values can be used - this is not a general >> technique. >> + */ >> + u32 tag = CVMX_TAG_SW_BITS_INTERNAL << >> CVMX_TAG_SW_SHIFT | >> + CVMX_TAG_SUBGROUP_PKO << >> CVMX_TAG_SUBGROUP_SHIFT | >> + (CVMX_TAG_SUBGROUP_MASK & queue); >> + cvmx_pow_tag_sw_full((cvmx_wqe_t >> *)cvmx_phys_to_ptr(0x80), tag, >> + CVMX_POW_TAG_TYPE_ATOMIC, 0); >> + } >> +} >> + >> +#define cvmx_pko_send_packet_prepare_pkoid >> cvmx_pko_send_packet_prepare >> + >> +/** >> + * Complete packet output. cvmx_pko_send_packet_prepare() must be >> called exactly once before this, >> + * and the same parameters must be passed to both >> cvmx_pko_send_packet_prepare() and >> + * cvmx_pko_send_packet_finish(). >> + * >> + * WARNING: This function may have to look up the proper PKO port in >> + * the IPD port to PKO port map, and is thus slower than calling >> + * cvmx_pko_send_packet_finish_pkoid() directly if the PKO port >> + * identifier is known. >> + * >> + * @param ipd_port The IPD port corresponding the to pko port the >> packet is for >> + * @param queue Queue to use >> + * @param pko_command >> + * PKO HW command word >> + * @param packet Packet to send >> + * @param use_locking >> + * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or >> CVMX_PKO_LOCK_CMD_QUEUE >> + * >> + * @return returns CVMX_PKO_SUCCESS on success, or error code on >> failure of output >> + */ >> +static inline cvmx_pko_return_value_t >> +cvmx_hwpko_send_packet_finish(u64 ipd_port, u64 queue, >> cvmx_pko_command_word0_t pko_command, >> + cvmx_buf_ptr_t packet, cvmx_pko_lock_t >> use_locking) >> +{ >> + cvmx_cmd_queue_result_t result; >> + >> + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) >> + cvmx_pow_tag_sw_wait(); >> + >> + result = cvmx_cmd_queue_write2(CVMX_CMD_QUEUE_PKO(queue), >> + (use_locking == >> CVMX_PKO_LOCK_CMD_QUEUE), pko_command.u64, >> + packet.u64); >> + if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS)) { >> + cvmx_pko_doorbell(ipd_port, queue, 2); >> + return CVMX_PKO_SUCCESS; >> + } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == >> CVMX_CMD_QUEUE_FULL)) { >> + return CVMX_PKO_NO_MEMORY; >> + } else { >> + return CVMX_PKO_INVALID_QUEUE; >> + } >> +} >> + >> +/** >> + * Complete packet output. cvmx_pko_send_packet_prepare() must be >> called exactly once before this, >> + * and the same parameters must be passed to both >> cvmx_pko_send_packet_prepare() and >> + * cvmx_pko_send_packet_finish(). >> + * >> + * WARNING: This function may have to look up the proper PKO port in >> + * the IPD port to PKO port map, and is thus slower than calling >> + * cvmx_pko_send_packet_finish3_pkoid() directly if the PKO port >> + * identifier is known. >> + * >> + * @param ipd_port The IPD port corresponding the to pko port the >> packet is for >> + * @param queue Queue to use >> + * @param pko_command >> + * PKO HW command word >> + * @param packet Packet to send >> + * @param addr Plysical address of a work queue entry or physical >> address to zero on complete. >> + * @param use_locking >> + * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or >> CVMX_PKO_LOCK_CMD_QUEUE >> + * >> + * @return returns CVMX_PKO_SUCCESS on success, or error code on >> failure of output >> + */ >> +static inline cvmx_pko_return_value_t >> +cvmx_hwpko_send_packet_finish3(u64 ipd_port, u64 queue, >> cvmx_pko_command_word0_t pko_command, >> + cvmx_buf_ptr_t packet, u64 addr, >> cvmx_pko_lock_t use_locking) >> +{ >> + cvmx_cmd_queue_result_t result; >> + >> + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) >> + cvmx_pow_tag_sw_wait(); >> + >> + result = cvmx_cmd_queue_write3(CVMX_CMD_QUEUE_PKO(queue), >> + (use_locking == >> CVMX_PKO_LOCK_CMD_QUEUE), pko_command.u64, >> + packet.u64, addr); >> + if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS)) { >> + cvmx_pko_doorbell(ipd_port, queue, 3); >> + return CVMX_PKO_SUCCESS; >> + } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == >> CVMX_CMD_QUEUE_FULL)) { >> + return CVMX_PKO_NO_MEMORY; >> + } else { >> + return CVMX_PKO_INVALID_QUEUE; >> + } >> +} >> + >> +/** >> + * Get the first pko_port for the (interface, index) >> + * >> + * @param interface >> + * @param index >> + */ >> +int cvmx_pko_get_base_pko_port(int interface, int index); >> + >> +/** >> + * Get the number of pko_ports for the (interface, index) >> + * >> + * @param interface >> + * @param index >> + */ >> +int cvmx_pko_get_num_pko_ports(int interface, int index); >> + >> +/** >> + * For a given port number, return the base pko output queue >> + * for the port. >> + * >> + * @param port IPD port number >> + * @return Base output queue >> + */ >> +int cvmx_pko_get_base_queue(int port); >> + >> +/** >> + * For a given port number, return the number of pko output queues. >> + * >> + * @param port IPD port number >> + * @return Number of output queues >> + */ >> +int cvmx_pko_get_num_queues(int port); >> + >> +/** >> + * Sets the internal FPA pool data structure for PKO comamnd queue. >> + * @param pool fpa pool number yo use >> + * @param buffer_size buffer size of pool >> + * @param buffer_count number of buufers to allocate to pool >> + * >> + * @note the caller is responsable for setting up the pool with >> + * an appropriate buffer size and sufficient buffer count. >> + */ >> +void cvmx_pko_set_cmd_que_pool_config(s64 pool, u64 buffer_size, u64 >> buffer_count); >> + >> +/** >> + * Get the status counters for a port. >> + * >> + * @param ipd_port Port number (ipd_port) to get statistics for. >> + * @param clear Set to 1 to clear the counters after they are >> read >> + * @param status Where to put the results. >> + * >> + * Note: >> + * - Only the doorbell for the base queue of the ipd_port is >> + * collected. >> + * - Retrieving the stats involves writing the index through >> + * CVMX_PKO_REG_READ_IDX and reading the stat CSRs, in that >> + * order. It is not MP-safe and caller should guarantee >> + * atomicity. >> + */ >> +void cvmx_pko_get_port_status(u64 ipd_port, u64 clear, >> cvmx_pko_port_status_t *status); >> + >> +/** >> + * Rate limit a PKO port to a max packets/sec. This function is only >> + * supported on CN57XX, CN56XX, CN55XX, and CN54XX. >> + * >> + * @param port Port to rate limit >> + * @param packets_s Maximum packet/sec >> + * @param burst Maximum number of packets to burst in a row >> before rate >> + * limiting cuts in. >> + * >> + * @return Zero on success, negative on failure >> + */ >> +int cvmx_pko_rate_limit_packets(int port, int packets_s, int burst); >> + >> +/** >> + * Rate limit a PKO port to a max bits/sec. This function is only >> + * supported on CN57XX, CN56XX, CN55XX, and CN54XX. >> + * >> + * @param port Port to rate limit >> + * @param bits_s PKO rate limit in bits/sec >> + * @param burst Maximum number of bits to burst before rate >> + * limiting cuts in. >> + * >> + * @return Zero on success, negative on failure >> + */ >> +int cvmx_pko_rate_limit_bits(int port, u64 bits_s, int burst); >> + >> +/** >> + * @INTERNAL >> + * >> + * Retrieve the PKO pipe number for a port >> + * >> + * @param interface >> + * @param index >> + * >> + * @return negative on error. >> + * >> + * This applies only to the non-loopback interfaces. >> + * >> + */ >> +int __cvmx_pko_get_pipe(int interface, int index); >> + >> +/** >> + * For a given PKO port number, return the base output queue >> + * for the port. >> + * >> + * @param pko_port PKO port number >> + * @return Base output queue >> + */ >> +int cvmx_pko_get_base_queue_pkoid(int pko_port); >> + >> +/** >> + * For a given PKO port number, return the number of output queues >> + * for the port. >> + * >> + * @param pko_port PKO port number >> + * @return the number of output queues >> + */ >> +int cvmx_pko_get_num_queues_pkoid(int pko_port); >> + >> +/** >> + * Ring the packet output doorbell. This tells the packet >> + * output hardware that "len" command words have been added >> + * to its pending list. This command includes the required >> + * CVMX_SYNCWS before the doorbell ring. >> + * >> + * @param pko_port Port the packet is for >> + * @param queue Queue the packet is for >> + * @param len Length of the command in 64 bit words >> + */ >> +static inline void cvmx_pko_doorbell_pkoid(u64 pko_port, u64 queue, >> u64 len) >> +{ >> + cvmx_pko_doorbell_address_t ptr; >> + >> + ptr.u64 = 0; >> + ptr.s.mem_space = CVMX_IO_SEG; >> + ptr.s.did = CVMX_OCT_DID_PKT_SEND; >> + ptr.s.is_io = 1; >> + ptr.s.port = pko_port; >> + ptr.s.queue = queue; >> + /* Need to make sure output queue data is in DRAM before >> doorbell write */ >> + CVMX_SYNCWS; >> + cvmx_write_io(ptr.u64, len); >> +} >> + >> +/** >> + * Complete packet output. cvmx_pko_send_packet_prepare() must be >> called exactly once before this, >> + * and the same parameters must be passed to both >> cvmx_pko_send_packet_prepare() and >> + * cvmx_pko_send_packet_finish_pkoid(). >> + * >> + * @param pko_port Port to send it on >> + * @param queue Queue to use >> + * @param pko_command >> + * PKO HW command word >> + * @param packet Packet to send >> + * @param use_locking >> + * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or >> CVMX_PKO_LOCK_CMD_QUEUE >> + * >> + * @return returns CVMX_PKO_SUCCESS on success, or error code on >> failure of output >> + */ >> +static inline cvmx_pko_return_value_t >> +cvmx_hwpko_send_packet_finish_pkoid(int pko_port, u64 queue, >> cvmx_pko_command_word0_t pko_command, >> + cvmx_buf_ptr_t packet, >> cvmx_pko_lock_t use_locking) >> +{ >> + cvmx_cmd_queue_result_t result; >> + >> + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) >> + cvmx_pow_tag_sw_wait(); >> + >> + result = cvmx_cmd_queue_write2(CVMX_CMD_QUEUE_PKO(queue), >> + (use_locking == >> CVMX_PKO_LOCK_CMD_QUEUE), pko_command.u64, >> + packet.u64); >> + if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS)) { >> + cvmx_pko_doorbell_pkoid(pko_port, queue, 2); >> + return CVMX_PKO_SUCCESS; >> + } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == >> CVMX_CMD_QUEUE_FULL)) { >> + return CVMX_PKO_NO_MEMORY; >> + } else { >> + return CVMX_PKO_INVALID_QUEUE; >> + } >> +} >> + >> +/** >> + * Complete packet output. cvmx_pko_send_packet_prepare() must be >> called exactly once before this, >> + * and the same parameters must be passed to both >> cvmx_pko_send_packet_prepare() and >> + * cvmx_pko_send_packet_finish_pkoid(). >> + * >> + * @param pko_port The PKO port the packet is for >> + * @param queue Queue to use >> + * @param pko_command >> + * PKO HW command word >> + * @param packet Packet to send >> + * @param addr Plysical address of a work queue entry or physical >> address to zero on complete. >> + * @param use_locking >> + * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or >> CVMX_PKO_LOCK_CMD_QUEUE >> + * >> + * @return returns CVMX_PKO_SUCCESS on success, or error code on >> failure of output >> + */ >> +static inline cvmx_pko_return_value_t >> +cvmx_hwpko_send_packet_finish3_pkoid(u64 pko_port, u64 queue, >> cvmx_pko_command_word0_t pko_command, >> + cvmx_buf_ptr_t packet, u64 addr, >> cvmx_pko_lock_t use_locking) >> +{ >> + cvmx_cmd_queue_result_t result; >> + >> + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) >> + cvmx_pow_tag_sw_wait(); >> + >> + result = cvmx_cmd_queue_write3(CVMX_CMD_QUEUE_PKO(queue), >> + (use_locking == >> CVMX_PKO_LOCK_CMD_QUEUE), pko_command.u64, >> + packet.u64, addr); >> + if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS)) { >> + cvmx_pko_doorbell_pkoid(pko_port, queue, 3); >> + return CVMX_PKO_SUCCESS; >> + } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == >> CVMX_CMD_QUEUE_FULL)) { >> + return CVMX_PKO_NO_MEMORY; >> + } else { >> + return CVMX_PKO_INVALID_QUEUE; >> + } >> +} >> + >> +/* >> + * Obtain the number of PKO commands pending in a queue >> + * >> + * @param queue is the queue identifier to be queried >> + * @return the number of commands pending transmission or -1 on >> error >> + */ >> +int cvmx_pko_queue_pend_count(cvmx_cmd_queue_id_t queue); >> + >> +void cvmx_pko_set_cmd_queue_pool_buffer_count(u64 buffer_count); >> + >> +#endif /* __CVMX_HWPKO_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-ilk.h >> b/arch/mips/mach-octeon/include/mach/cvmx-ilk.h >> new file mode 100644 >> index 000000000000..727298352c28 >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-ilk.h >> @@ -0,0 +1,154 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * This file contains defines for the ILK interface >> + */ >> + >> +#ifndef __CVMX_ILK_H__ >> +#define __CVMX_ILK_H__ >> + >> +/* CSR typedefs have been moved to cvmx-ilk-defs.h */ >> + >> +/* >> + * Note: this macro must match the first ilk port in the >> ipd_port_map_68xx[] >> + * and ipd_port_map_78xx[] arrays. >> + */ >> +static inline int CVMX_ILK_GBL_BASE(void) >> +{ >> + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) >> + return 5; >> + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) >> + return 6; >> + return -1; >> +} >> + >> +static inline int CVMX_ILK_QLM_BASE(void) >> +{ >> + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) >> + return 1; >> + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) >> + return 4; >> + return -1; >> +} >> + >> +typedef struct { >> + int intf_en : 1; >> + int la_mode : 1; >> + int reserved : 14; /* unused */ >> + int lane_speed : 16; >> + /* add more here */ >> +} cvmx_ilk_intf_t; >> + >> +#define CVMX_NUM_ILK_INTF 2 >> +static inline int CVMX_ILK_MAX_LANES(void) >> +{ >> + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) >> + return 8; >> + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) >> + return 16; >> + return -1; >> +} >> + >> +extern unsigned short >> cvmx_ilk_lane_mask[CVMX_MAX_NODES][CVMX_NUM_ILK_INTF]; >> + >> +typedef struct { >> + unsigned int pipe; >> + unsigned int chan; >> +} cvmx_ilk_pipe_chan_t; >> + >> +#define CVMX_ILK_MAX_PIPES 45 >> +/* Max number of channels allowed */ >> +#define CVMX_ILK_MAX_CHANS 256 >> + >> +extern int cvmx_ilk_chans[CVMX_MAX_NODES][CVMX_NUM_ILK_INTF]; >> + >> +typedef struct { >> + unsigned int chan; >> + unsigned int pknd; >> +} cvmx_ilk_chan_pknd_t; >> + >> +#define CVMX_ILK_MAX_PKNDS 16 /* must be <45 */ >> + >> +typedef struct { >> + int *chan_list; /* for discrete channels. or, must be null */ >> + unsigned int num_chans; >> + >> + unsigned int chan_start; /* for continuous channels */ >> + unsigned int chan_end; >> + unsigned int chan_step; >> + >> + unsigned int clr_on_rd; >> +} cvmx_ilk_stats_ctrl_t; >> + >> +#define CVMX_ILK_MAX_CAL 288 >> +#define CVMX_ILK_MAX_CAL_IDX (CVMX_ILK_MAX_CAL / 8) >> +#define CVMX_ILK_TX_MIN_CAL 1 >> +#define CVMX_ILK_RX_MIN_CAL 1 >> +#define CVMX_ILK_CAL_GRP_SZ 8 >> +#define CVMX_ILK_PIPE_BPID_SZ 7 >> +#define CVMX_ILK_ENT_CTRL_SZ 2 >> +#define CVMX_ILK_RX_FIFO_WM 0x200 >> + >> +typedef enum { PIPE_BPID = 0, LINK, XOFF, XON } >> cvmx_ilk_cal_ent_ctrl_t; >> + >> +typedef struct { >> + unsigned char pipe_bpid; >> + cvmx_ilk_cal_ent_ctrl_t ent_ctrl; >> +} cvmx_ilk_cal_entry_t; >> + >> +typedef enum { CVMX_ILK_LPBK_DISA = 0, CVMX_ILK_LPBK_ENA } >> cvmx_ilk_lpbk_ena_t; >> + >> +typedef enum { CVMX_ILK_LPBK_INT = 0, CVMX_ILK_LPBK_EXT } >> cvmx_ilk_lpbk_mode_t; >> + >> +/** >> + * This header is placed in front of all received ILK look-aside >> mode packets >> + */ >> +typedef union { >> + u64 u64; >> + >> + struct { >> + u32 reserved_63_57 : 7; /* bits 63...57 */ >> + u32 nsp_cmd : 5; /* bits 56...52 */ >> + u32 nsp_flags : 4; /* bits 51...48 */ >> + u32 nsp_grp_id_upper : 6; /* bits 47...42 */ >> + u32 reserved_41_40 : 2; /* bits 41...40 */ >> + /* Protocol type, 1 for LA mode packet */ >> + u32 la_mode : 1; /* bit 39 */ >> + u32 nsp_grp_id_lower : 2; /* bits 38...37 */ >> + u32 nsp_xid_upper : 4; /* bits 36...33 */ >> + /* ILK channel number, 0 or 1 */ >> + u32 ilk_channel : 1; /* bit 32 */ >> + u32 nsp_xid_lower : 8; /* bits 31...24 */ >> + /* Unpredictable, may be any value */ >> + u32 reserved_23_0 : 24; /* bits 23...0 */ >> + } s; >> +} cvmx_ilk_la_nsp_compact_hdr_t; >> + >> +typedef struct cvmx_ilk_LA_mode_struct { >> + int ilk_LA_mode; >> + int ilk_LA_mode_cal_ena; >> +} cvmx_ilk_LA_mode_t; >> + >> +extern cvmx_ilk_LA_mode_t cvmx_ilk_LA_mode[CVMX_NUM_ILK_INTF]; >> + >> +int cvmx_ilk_use_la_mode(int interface, int channel); >> +int cvmx_ilk_start_interface(int interface, unsigned short >> num_lanes); >> +int cvmx_ilk_start_interface_la(int interface, unsigned char >> num_lanes); >> +int cvmx_ilk_set_pipe(int interface, int pipe_base, unsigned int >> pipe_len); >> +int cvmx_ilk_tx_set_channel(int interface, cvmx_ilk_pipe_chan_t >> *pch, unsigned int num_chs); >> +int cvmx_ilk_rx_set_pknd(int interface, cvmx_ilk_chan_pknd_t >> *chpknd, unsigned int num_pknd); >> +int cvmx_ilk_enable(int interface); >> +int cvmx_ilk_disable(int interface); >> +int cvmx_ilk_get_intf_ena(int interface); >> +int cvmx_ilk_get_chan_info(int interface, unsigned char **chans, >> unsigned char *num_chan); >> +cvmx_ilk_la_nsp_compact_hdr_t cvmx_ilk_enable_la_header(int >> ipd_port, int mode); >> +void cvmx_ilk_show_stats(int interface, cvmx_ilk_stats_ctrl_t >> *pstats); >> +int cvmx_ilk_cal_setup_rx(int interface, int cal_depth, >> cvmx_ilk_cal_entry_t *pent, int hi_wm, >> + unsigned char cal_ena); >> +int cvmx_ilk_cal_setup_tx(int interface, int cal_depth, >> cvmx_ilk_cal_entry_t *pent, >> + unsigned char cal_ena); >> +int cvmx_ilk_lpbk(int interface, cvmx_ilk_lpbk_ena_t enable, >> cvmx_ilk_lpbk_mode_t mode); >> +int cvmx_ilk_la_mode_enable_rx_calendar(int interface); >> + >> +#endif /* __CVMX_ILK_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-ipd.h >> b/arch/mips/mach-octeon/include/mach/cvmx-ipd.h >> new file mode 100644 >> index 000000000000..cdff36fffb56 >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-ipd.h >> @@ -0,0 +1,233 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Interface to the hardware Input Packet Data unit. >> + */ >> + >> +#ifndef __CVMX_IPD_H__ >> +#define __CVMX_IPD_H__ >> + >> +#include "cvmx-pki.h" >> + >> +/* CSR typedefs have been moved to cvmx-ipd-defs.h */ >> + >> +typedef cvmx_ipd_1st_mbuff_skip_t cvmx_ipd_mbuff_not_first_skip_t; >> +typedef cvmx_ipd_1st_next_ptr_back_t >> cvmx_ipd_second_next_ptr_back_t; >> + >> +typedef struct cvmx_ipd_tag_fields { >> + u64 ipv6_src_ip : 1; >> + u64 ipv6_dst_ip : 1; >> + u64 ipv6_src_port : 1; >> + u64 ipv6_dst_port : 1; >> + u64 ipv6_next_header : 1; >> + u64 ipv4_src_ip : 1; >> + u64 ipv4_dst_ip : 1; >> + u64 ipv4_src_port : 1; >> + u64 ipv4_dst_port : 1; >> + u64 ipv4_protocol : 1; >> + u64 input_port : 1; >> +} cvmx_ipd_tag_fields_t; >> + >> +typedef struct cvmx_pip_port_config { >> + u64 parse_mode; >> + u64 tag_type; >> + u64 tag_mode; >> + cvmx_ipd_tag_fields_t tag_fields; >> +} cvmx_pip_port_config_t; >> + >> +typedef struct cvmx_ipd_config_struct { >> + u64 first_mbuf_skip; >> + u64 not_first_mbuf_skip; >> + u64 ipd_enable; >> + u64 enable_len_M8_fix; >> + u64 cache_mode; >> + cvmx_fpa_pool_config_t packet_pool; >> + cvmx_fpa_pool_config_t wqe_pool; >> + cvmx_pip_port_config_t port_config; >> +} cvmx_ipd_config_t; >> + >> +extern cvmx_ipd_config_t cvmx_ipd_cfg; >> + >> +/** >> + * Gets the fpa pool number of packet pool >> + */ >> +static inline s64 cvmx_fpa_get_packet_pool(void) >> +{ >> + return (cvmx_ipd_cfg.packet_pool.pool_num); >> +} >> + >> +/** >> + * Gets the buffer size of packet pool buffer >> + */ >> +static inline u64 cvmx_fpa_get_packet_pool_block_size(void) >> +{ >> + return (cvmx_ipd_cfg.packet_pool.buffer_size); >> +} >> + >> +/** >> + * Gets the buffer count of packet pool >> + */ >> +static inline u64 cvmx_fpa_get_packet_pool_buffer_count(void) >> +{ >> + return (cvmx_ipd_cfg.packet_pool.buffer_count); >> +} >> + >> +/** >> + * Gets the fpa pool number of wqe pool >> + */ >> +static inline s64 cvmx_fpa_get_wqe_pool(void) >> +{ >> + return (cvmx_ipd_cfg.wqe_pool.pool_num); >> +} >> + >> +/** >> + * Gets the buffer size of wqe pool buffer >> + */ >> +static inline u64 cvmx_fpa_get_wqe_pool_block_size(void) >> +{ >> + return (cvmx_ipd_cfg.wqe_pool.buffer_size); >> +} >> + >> +/** >> + * Gets the buffer count of wqe pool >> + */ >> +static inline u64 cvmx_fpa_get_wqe_pool_buffer_count(void) >> +{ >> + return (cvmx_ipd_cfg.wqe_pool.buffer_count); >> +} >> + >> +/** >> + * Sets the ipd related configuration in internal structure which is >> then used >> + * for seting IPD hardware block >> + */ >> +int cvmx_ipd_set_config(cvmx_ipd_config_t ipd_config); >> + >> +/** >> + * Gets the ipd related configuration from internal structure. >> + */ >> +void cvmx_ipd_get_config(cvmx_ipd_config_t *ipd_config); >> + >> +/** >> + * Sets the internal FPA pool data structure for packet buffer pool. >> + * @param pool fpa pool number yo use >> + * @param buffer_size buffer size of pool >> + * @param buffer_count number of buufers to allocate to pool >> + */ >> +void cvmx_ipd_set_packet_pool_config(s64 pool, u64 buffer_size, u64 >> buffer_count); >> + >> +/** >> + * Sets the internal FPA pool data structure for wqe pool. >> + * @param pool fpa pool number yo use >> + * @param buffer_size buffer size of pool >> + * @param buffer_count number of buufers to allocate to pool >> + */ >> +void cvmx_ipd_set_wqe_pool_config(s64 pool, u64 buffer_size, u64 >> buffer_count); >> + >> +/** >> + * Gets the FPA packet buffer pool parameters. >> + */ >> +static inline void cvmx_fpa_get_packet_pool_config(s64 *pool, u64 >> *buffer_size, u64 *buffer_count) >> +{ >> + if (pool) >> + *pool = cvmx_ipd_cfg.packet_pool.pool_num; >> + if (buffer_size) >> + *buffer_size = cvmx_ipd_cfg.packet_pool.buffer_size; >> + if (buffer_count) >> + *buffer_count = cvmx_ipd_cfg.packet_pool.buffer_count; >> +} >> + >> +/** >> + * Sets the FPA packet buffer pool parameters. >> + */ >> +static inline void cvmx_fpa_set_packet_pool_config(s64 pool, u64 >> buffer_size, u64 buffer_count) >> +{ >> + cvmx_ipd_set_packet_pool_config(pool, buffer_size, >> buffer_count); >> +} >> + >> +/** >> + * Gets the FPA WQE pool parameters. >> + */ >> +static inline void cvmx_fpa_get_wqe_pool_config(s64 *pool, u64 >> *buffer_size, u64 *buffer_count) >> +{ >> + if (pool) >> + *pool = cvmx_ipd_cfg.wqe_pool.pool_num; >> + if (buffer_size) >> + *buffer_size = cvmx_ipd_cfg.wqe_pool.buffer_size; >> + if (buffer_count) >> + *buffer_count = cvmx_ipd_cfg.wqe_pool.buffer_count; >> +} >> + >> +/** >> + * Sets the FPA WQE pool parameters. >> + */ >> +static inline void cvmx_fpa_set_wqe_pool_config(s64 pool, u64 >> buffer_size, u64 buffer_count) >> +{ >> + cvmx_ipd_set_wqe_pool_config(pool, buffer_size, buffer_count); >> +} >> + >> +/** >> + * Configure IPD >> + * >> + * @param mbuff_size Packets buffer size in 8 byte words >> + * @param first_mbuff_skip >> + * Number of 8 byte words to skip in the first >> buffer >> + * @param not_first_mbuff_skip >> + * Number of 8 byte words to skip in each >> following buffer >> + * @param first_back Must be same as first_mbuff_skip / 128 >> + * @param second_back >> + * Must be same as not_first_mbuff_skip / 128 >> + * @param wqe_fpa_pool >> + * FPA pool to get work entries from >> + * @param cache_mode >> + * @param back_pres_enable_flag >> + * Enable or disable port back pressure at a >> global level. >> + * This should always be 1 as more accurate >> control can be >> + * found in IPD_PORTX_BP_PAGE_CNT[BP_ENB]. >> + */ >> +void cvmx_ipd_config(u64 mbuff_size, u64 first_mbuff_skip, u64 >> not_first_mbuff_skip, u64 first_back, >> + u64 second_back, u64 wqe_fpa_pool, cvmx_ipd_mode_t >> cache_mode, >> + u64 back_pres_enable_flag); >> +/** >> + * Enable IPD >> + */ >> +void cvmx_ipd_enable(void); >> + >> +/** >> + * Disable IPD >> + */ >> +void cvmx_ipd_disable(void); >> + >> +void __cvmx_ipd_free_ptr(void); >> + >> +void cvmx_ipd_set_packet_pool_buffer_count(u64 buffer_count); >> +void cvmx_ipd_set_wqe_pool_buffer_count(u64 buffer_count); >> + >> +/** >> + * Setup Random Early Drop on a specific input queue >> + * >> + * @param queue Input queue to setup RED on (0-7) >> + * @param pass_thresh >> + * Packets will begin slowly dropping when there are >> less than >> + * this many packet buffers free in FPA 0. >> + * @param drop_thresh >> + * All incoming packets will be dropped when there are >> less >> + * than this many free packet buffers in FPA 0. >> + * @return Zero on success. Negative on failure >> + */ >> +int cvmx_ipd_setup_red_queue(int queue, int pass_thresh, int >> drop_thresh); >> + >> +/** >> + * Setup Random Early Drop to automatically begin dropping packets. >> + * >> + * @param pass_thresh >> + * Packets will begin slowly dropping when there are >> less than >> + * this many packet buffers free in FPA 0. >> + * @param drop_thresh >> + * All incoming packets will be dropped when there are >> less >> + * than this many free packet buffers in FPA 0. >> + * @return Zero on success. Negative on failure >> + */ >> +int cvmx_ipd_setup_red(int pass_thresh, int drop_thresh); >> + >> +#endif /* __CVMX_IPD_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-packet.h >> b/arch/mips/mach-octeon/include/mach/cvmx-packet.h >> new file mode 100644 >> index 000000000000..f3cfe9c64f43 >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-packet.h >> @@ -0,0 +1,40 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Packet buffer defines. >> + */ >> + >> +#ifndef __CVMX_PACKET_H__ >> +#define __CVMX_PACKET_H__ >> + >> +union cvmx_buf_ptr_pki { >> + u64 u64; >> + struct { >> + u64 size : 16; >> + u64 packet_outside_wqe : 1; >> + u64 rsvd0 : 5; >> + u64 addr : 42; >> + }; >> +}; >> + >> +typedef union cvmx_buf_ptr_pki cvmx_buf_ptr_pki_t; >> + >> +/** >> + * This structure defines a buffer pointer on Octeon >> + */ >> +union cvmx_buf_ptr { >> + void *ptr; >> + u64 u64; >> + struct { >> + u64 i : 1; >> + u64 back : 4; >> + u64 pool : 3; >> + u64 size : 16; >> + u64 addr : 40; >> + } s; >> +}; >> + >> +typedef union cvmx_buf_ptr cvmx_buf_ptr_t; >> + >> +#endif /* __CVMX_PACKET_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pcie.h >> b/arch/mips/mach-octeon/include/mach/cvmx-pcie.h >> new file mode 100644 >> index 000000000000..a819196c021c >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-pcie.h >> @@ -0,0 +1,279 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + */ >> + >> +#ifndef __CVMX_PCIE_H__ >> +#define __CVMX_PCIE_H__ >> + >> +#define CVMX_PCIE_MAX_PORTS 4 >> +#define >> CVMX_PCIE_PORTS >> \ >> + ((OCTEON_IS_MODEL(OCTEON_CN78XX) || >> OCTEON_IS_MODEL(OCTEON_CN73XX)) ? \ >> + CVMX_PCIE_MAX_PORTS >> : \ >> + (OCTEON_IS_MODEL(OCTEON_CN70XX) ? 3 : 2)) >> + >> +/* >> + * The physical memory base mapped by BAR1. 256MB at the end of the >> + * first 4GB. >> + */ >> +#define CVMX_PCIE_BAR1_PHYS_BASE ((1ull << 32) - (1ull << 28)) >> +#define CVMX_PCIE_BAR1_PHYS_SIZE BIT_ULL(28) >> + >> +/* >> + * The RC base of BAR1. gen1 has a 39-bit BAR2, gen2 has 41-bit >> BAR2, >> + * place BAR1 so it is the same for both. >> + */ >> +#define CVMX_PCIE_BAR1_RC_BASE BIT_ULL(41) >> + >> +typedef union { >> + u64 u64; >> + struct { >> + u64 upper : 2; /* Normally 2 for XKPHYS */ >> + u64 reserved_49_61 : 13; /* Must be zero */ >> + u64 io : 1; /* 1 for IO space access */ >> + u64 did : 5; /* PCIe DID = 3 */ >> + u64 subdid : 3; /* PCIe SubDID = 1 */ >> + u64 reserved_38_39 : 2; /* Must be zero */ >> + u64 node : 2; /* Numa node number */ >> + u64 es : 2; /* Endian swap = 1 */ >> + u64 port : 2; /* PCIe port 0,1 */ >> + u64 reserved_29_31 : 3; /* Must be zero */ >> + u64 ty : 1; >> + u64 bus : 8; >> + u64 dev : 5; >> + u64 func : 3; >> + u64 reg : 12; >> + } config; >> + struct { >> + u64 upper : 2; /* Normally 2 for XKPHYS */ >> + u64 reserved_49_61 : 13; /* Must be zero */ >> + u64 io : 1; /* 1 for IO space access */ >> + u64 did : 5; /* PCIe DID = 3 */ >> + u64 subdid : 3; /* PCIe SubDID = 2 */ >> + u64 reserved_38_39 : 2; /* Must be zero */ >> + u64 node : 2; /* Numa node number */ >> + u64 es : 2; /* Endian swap = 1 */ >> + u64 port : 2; /* PCIe port 0,1 */ >> + u64 address : 32; /* PCIe IO address */ >> + } io; >> + struct { >> + u64 upper : 2; /* Normally 2 for XKPHYS */ >> + u64 reserved_49_61 : 13; /* Must be zero */ >> + u64 io : 1; /* 1 for IO space access */ >> + u64 did : 5; /* PCIe DID = 3 */ >> + u64 subdid : 3; /* PCIe SubDID = 3-6 */ >> + u64 reserved_38_39 : 2; /* Must be zero */ >> + u64 node : 2; /* Numa node number */ >> + u64 address : 36; /* PCIe Mem address */ >> + } mem; >> +} cvmx_pcie_address_t; >> + >> +/** >> + * Return the Core virtual base address for PCIe IO access. IOs are >> + * read/written as an offset from this address. >> + * >> + * @param pcie_port PCIe port the IO is for >> + * >> + * @return 64bit Octeon IO base address for read/write >> + */ >> +u64 cvmx_pcie_get_io_base_address(int pcie_port); >> + >> +/** >> + * Size of the IO address region returned at address >> + * cvmx_pcie_get_io_base_address() >> + * >> + * @param pcie_port PCIe port the IO is for >> + * >> + * @return Size of the IO window >> + */ >> +u64 cvmx_pcie_get_io_size(int pcie_port); >> + >> +/** >> + * Return the Core virtual base address for PCIe MEM access. Memory >> is >> + * read/written as an offset from this address. >> + * >> + * @param pcie_port PCIe port the IO is for >> + * >> + * @return 64bit Octeon IO base address for read/write >> + */ >> +u64 cvmx_pcie_get_mem_base_address(int pcie_port); >> + >> +/** >> + * Size of the Mem address region returned at address >> + * cvmx_pcie_get_mem_base_address() >> + * >> + * @param pcie_port PCIe port the IO is for >> + * >> + * @return Size of the Mem window >> + */ >> +u64 cvmx_pcie_get_mem_size(int pcie_port); >> + >> +/** >> + * Initialize a PCIe port for use in host(RC) mode. It doesn't >> enumerate the bus. >> + * >> + * @param pcie_port PCIe port to initialize >> + * >> + * @return Zero on success >> + */ >> +int cvmx_pcie_rc_initialize(int pcie_port); >> + >> +/** >> + * Shutdown a PCIe port and put it in reset >> + * >> + * @param pcie_port PCIe port to shutdown >> + * >> + * @return Zero on success >> + */ >> +int cvmx_pcie_rc_shutdown(int pcie_port); >> + >> +/** >> + * Read 8bits from a Device's config space >> + * >> + * @param pcie_port PCIe port the device is on >> + * @param bus Sub bus >> + * @param dev Device ID >> + * @param fn Device sub function >> + * @param reg Register to access >> + * >> + * @return Result of the read >> + */ >> +u8 cvmx_pcie_config_read8(int pcie_port, int bus, int dev, int fn, >> int reg); >> + >> +/** >> + * Read 16bits from a Device's config space >> + * >> + * @param pcie_port PCIe port the device is on >> + * @param bus Sub bus >> + * @param dev Device ID >> + * @param fn Device sub function >> + * @param reg Register to access >> + * >> + * @return Result of the read >> + */ >> +u16 cvmx_pcie_config_read16(int pcie_port, int bus, int dev, int fn, >> int reg); >> + >> +/** >> + * Read 32bits from a Device's config space >> + * >> + * @param pcie_port PCIe port the device is on >> + * @param bus Sub bus >> + * @param dev Device ID >> + * @param fn Device sub function >> + * @param reg Register to access >> + * >> + * @return Result of the read >> + */ >> +u32 cvmx_pcie_config_read32(int pcie_port, int bus, int dev, int fn, >> int reg); >> + >> +/** >> + * Write 8bits to a Device's config space >> + * >> + * @param pcie_port PCIe port the device is on >> + * @param bus Sub bus >> + * @param dev Device ID >> + * @param fn Device sub function >> + * @param reg Register to access >> + * @param val Value to write >> + */ >> +void cvmx_pcie_config_write8(int pcie_port, int bus, int dev, int >> fn, int reg, u8 val); >> + >> +/** >> + * Write 16bits to a Device's config space >> + * >> + * @param pcie_port PCIe port the device is on >> + * @param bus Sub bus >> + * @param dev Device ID >> + * @param fn Device sub function >> + * @param reg Register to access >> + * @param val Value to write >> + */ >> +void cvmx_pcie_config_write16(int pcie_port, int bus, int dev, int >> fn, int reg, u16 val); >> + >> +/** >> + * Write 32bits to a Device's config space >> + * >> + * @param pcie_port PCIe port the device is on >> + * @param bus Sub bus >> + * @param dev Device ID >> + * @param fn Device sub function >> + * @param reg Register to access >> + * @param val Value to write >> + */ >> +void cvmx_pcie_config_write32(int pcie_port, int bus, int dev, int >> fn, int reg, u32 val); >> + >> +/** >> + * Read a PCIe config space register indirectly. This is used for >> + * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???. >> + * >> + * @param pcie_port PCIe port to read from >> + * @param cfg_offset Address to read >> + * >> + * @return Value read >> + */ >> +u32 cvmx_pcie_cfgx_read(int pcie_port, u32 cfg_offset); >> +u32 cvmx_pcie_cfgx_read_node(int node, int pcie_port, u32 >> cfg_offset); >> + >> +/** >> + * Write a PCIe config space register indirectly. This is used for >> + * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???. >> + * >> + * @param pcie_port PCIe port to write to >> + * @param cfg_offset Address to write >> + * @param val Value to write >> + */ >> +void cvmx_pcie_cfgx_write(int pcie_port, u32 cfg_offset, u32 val); >> +void cvmx_pcie_cfgx_write_node(int node, int pcie_port, u32 >> cfg_offset, u32 val); >> + >> +/** >> + * Write a 32bit value to the Octeon NPEI register space >> + * >> + * @param address Address to write to >> + * @param val Value to write >> + */ >> +static inline void cvmx_pcie_npei_write32(u64 address, u32 val) >> +{ >> + cvmx_write64_uint32(address ^ 4, val); >> + cvmx_read64_uint32(address ^ 4); >> +} >> + >> +/** >> + * Read a 32bit value from the Octeon NPEI register space >> + * >> + * @param address Address to read >> + * @return The result >> + */ >> +static inline u32 cvmx_pcie_npei_read32(u64 address) >> +{ >> + return cvmx_read64_uint32(address ^ 4); >> +} >> + >> +/** >> + * Initialize a PCIe port for use in target(EP) mode. >> + * >> + * @param pcie_port PCIe port to initialize >> + * >> + * @return Zero on success >> + */ >> +int cvmx_pcie_ep_initialize(int pcie_port); >> + >> +/** >> + * Wait for posted PCIe read/writes to reach the other side of >> + * the internal PCIe switch. This will insure that core >> + * read/writes are posted before anything after this function >> + * is called. This may be necessary when writing to memory that >> + * will later be read using the DMA/PKT engines. >> + * >> + * @param pcie_port PCIe port to wait for >> + */ >> +void cvmx_pcie_wait_for_pending(int pcie_port); >> + >> +/** >> + * Returns if a PCIe port is in host or target mode. >> + * >> + * @param pcie_port PCIe port number (PEM number) >> + * >> + * @return 0 if PCIe port is in target mode, !0 if in host mode. >> + */ >> +int cvmx_pcie_is_host_mode(int pcie_port); >> + >> +#endif >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pip.h >> b/arch/mips/mach-octeon/include/mach/cvmx-pip.h >> new file mode 100644 >> index 000000000000..013f533fb7bb >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-pip.h >> @@ -0,0 +1,1080 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Interface to the hardware Packet Input Processing unit. >> + */ >> + >> +#ifndef __CVMX_PIP_H__ >> +#define __CVMX_PIP_H__ >> + >> +#include "cvmx-wqe.h" >> +#include "cvmx-pki.h" >> +#include "cvmx-helper-pki.h" >> + >> +#include "cvmx-helper.h" >> +#include "cvmx-helper-util.h" >> +#include "cvmx-pki-resources.h" >> + >> +#define CVMX_PIP_NUM_INPUT_PORTS 46 >> +#define CVMX_PIP_NUM_WATCHERS 8 >> + >> +/* >> + * Encodes the different error and exception codes >> + */ >> +typedef enum { >> + CVMX_PIP_L4_NO_ERR = 0ull, >> + /* 1 = TCP (UDP) packet not long enough to cover TCP >> (UDP) header */ >> + CVMX_PIP_L4_MAL_ERR = 1ull, >> + /* 2 = TCP/UDP checksum failure */ >> + CVMX_PIP_CHK_ERR = 2ull, >> + /* 3 = TCP/UDP length check (TCP/UDP length does not >> match IP length) */ >> + CVMX_PIP_L4_LENGTH_ERR = 3ull, >> + /* 4 = illegal TCP/UDP port (either source or dest port >> is zero) */ >> + CVMX_PIP_BAD_PRT_ERR = 4ull, >> + /* 8 = TCP flags = FIN only */ >> + CVMX_PIP_TCP_FLG8_ERR = 8ull, >> + /* 9 = TCP flags = 0 */ >> + CVMX_PIP_TCP_FLG9_ERR = 9ull, >> + /* 10 = TCP flags = FIN+RST+* */ >> + CVMX_PIP_TCP_FLG10_ERR = 10ull, >> + /* 11 = TCP flags = SYN+URG+* */ >> + CVMX_PIP_TCP_FLG11_ERR = 11ull, >> + /* 12 = TCP flags = SYN+RST+* */ >> + CVMX_PIP_TCP_FLG12_ERR = 12ull, >> + /* 13 = TCP flags = SYN+FIN+* */ >> + CVMX_PIP_TCP_FLG13_ERR = 13ull >> +} cvmx_pip_l4_err_t; >> + >> +typedef enum { >> + CVMX_PIP_IP_NO_ERR = 0ull, >> + /* 1 = not IPv4 or IPv6 */ >> + CVMX_PIP_NOT_IP = 1ull, >> + /* 2 = IPv4 header checksum violation */ >> + CVMX_PIP_IPV4_HDR_CHK = 2ull, >> + /* 3 = malformed (packet not long enough to cover IP >> hdr) */ >> + CVMX_PIP_IP_MAL_HDR = 3ull, >> + /* 4 = malformed (packet not long enough to cover len in >> IP hdr) */ >> + CVMX_PIP_IP_MAL_PKT = 4ull, >> + /* 5 = TTL / hop count equal zero */ >> + CVMX_PIP_TTL_HOP = 5ull, >> + /* 6 = IPv4 options / IPv6 early extension headers */ >> + CVMX_PIP_OPTS = 6ull >> +} cvmx_pip_ip_exc_t; >> + >> +/** >> + * NOTES >> + * late collision (data received before collision) >> + * late collisions cannot be detected by the receiver >> + * they would appear as JAM bits which would appear as >> bad FCS >> + * or carrier extend error which is CVMX_PIP_EXTEND_ERR >> + */ >> +typedef enum { >> + /** >> + * No error >> + */ >> + CVMX_PIP_RX_NO_ERR = 0ull, >> + >> + CVMX_PIP_PARTIAL_ERR = >> + 1ull, /* RGM+SPI 1 = partially received >> packet (buffering/bandwidth not adequate) */ >> + CVMX_PIP_JABBER_ERR = >> + 2ull, /* RGM+SPI 2 = receive packet too >> large and truncated */ >> + CVMX_PIP_OVER_FCS_ERR = >> + 3ull, /* RGM 3 = max frame error (pkt >> len > max frame len) (with FCS error) */ >> + CVMX_PIP_OVER_ERR = >> + 4ull, /* RGM+SPI 4 = max frame error (pkt >> len > max frame len) */ >> + CVMX_PIP_ALIGN_ERR = >> + 5ull, /* RGM 5 = nibble error (data not >> byte multiple - 100M and 10M only) */ >> + CVMX_PIP_UNDER_FCS_ERR = >> + 6ull, /* RGM 6 = min frame error (pkt >> len < min frame len) (with FCS error) */ >> + CVMX_PIP_GMX_FCS_ERR = 7ull, /* RGM 7 = FCS >> error */ >> + CVMX_PIP_UNDER_ERR = >> + 8ull, /* RGM+SPI 8 = min frame error (pkt >> len < min frame len) */ >> + CVMX_PIP_EXTEND_ERR = 9ull, /* RGM 9 = Frame >> carrier extend error */ >> + CVMX_PIP_TERMINATE_ERR = >> + 9ull, /* XAUI 9 = Packet was terminated >> with an idle cycle */ >> + CVMX_PIP_LENGTH_ERR = >> + 10ull, /* RGM 10 = length mismatch (len >> did not match len in L2 length/type) */ >> + CVMX_PIP_DAT_ERR = >> + 11ull, /* RGM 11 = Frame error (some or >> all data bits marked err) */ >> + CVMX_PIP_DIP_ERR = 11ull, /* SPI 11 = DIP4 error >> */ >> + CVMX_PIP_SKIP_ERR = >> + 12ull, /* RGM 12 = packet was not large >> enough to pass the skipper - no inspection could occur */ >> + CVMX_PIP_NIBBLE_ERR = >> + 13ull, /* RGM 13 = studder error (data >> not repeated - 100M and 10M only) */ >> + CVMX_PIP_PIP_FCS = 16L, /* RGM+SPI 16 = FCS error */ >> + CVMX_PIP_PIP_SKIP_ERR = >> + 17L, /* RGM+SPI+PCI 17 = packet was not large >> enough to pass the skipper - no inspection could occur */ >> + CVMX_PIP_PIP_L2_MAL_HDR = >> + 18L, /* RGM+SPI+PCI 18 = malformed l2 (packet not >> long enough to cover L2 hdr) */ >> + CVMX_PIP_PUNY_ERR = >> + 47L /* SGMII 47 = PUNY error (packet was 4B >> or less when FCS stripping is enabled) */ >> + /* NOTES >> + * xx = late collision (data received before collision) >> + * late collisions cannot be detected by the >> receiver >> + * they would appear as JAM bits which would appear >> as bad FCS >> + * or carrier extend error which is >> CVMX_PIP_EXTEND_ERR >> + */ >> +} cvmx_pip_rcv_err_t; >> + >> +/** >> + * This defines the err_code field errors in the work Q entry >> + */ >> +typedef union { >> + cvmx_pip_l4_err_t l4_err; >> + cvmx_pip_ip_exc_t ip_exc; >> + cvmx_pip_rcv_err_t rcv_err; >> +} cvmx_pip_err_t; >> + >> +/** >> + * Status statistics for a port >> + */ >> +typedef struct { >> + u64 dropped_octets; >> + u64 dropped_packets; >> + u64 pci_raw_packets; >> + u64 octets; >> + u64 packets; >> + u64 multicast_packets; >> + u64 broadcast_packets; >> + u64 len_64_packets; >> + u64 len_65_127_packets; >> + u64 len_128_255_packets; >> + u64 len_256_511_packets; >> + u64 len_512_1023_packets; >> + u64 len_1024_1518_packets; >> + u64 len_1519_max_packets; >> + u64 fcs_align_err_packets; >> + u64 runt_packets; >> + u64 runt_crc_packets; >> + u64 oversize_packets; >> + u64 oversize_crc_packets; >> + u64 inb_packets; >> + u64 inb_octets; >> + u64 inb_errors; >> + u64 mcast_l2_red_packets; >> + u64 bcast_l2_red_packets; >> + u64 mcast_l3_red_packets; >> + u64 bcast_l3_red_packets; >> +} cvmx_pip_port_status_t; >> + >> +/** >> + * Definition of the PIP custom header that can be prepended >> + * to a packet by external hardware. >> + */ >> +typedef union { >> + u64 u64; >> + struct { >> + u64 rawfull : 1; >> + u64 reserved0 : 5; >> + cvmx_pip_port_parse_mode_t parse_mode : 2; >> + u64 reserved1 : 1; >> + u64 skip_len : 7; >> + u64 grpext : 2; >> + u64 nqos : 1; >> + u64 ngrp : 1; >> + u64 ntt : 1; >> + u64 ntag : 1; >> + u64 qos : 3; >> + u64 grp : 4; >> + u64 rs : 1; >> + cvmx_pow_tag_type_t tag_type : 2; >> + u64 tag : 32; >> + } s; >> +} cvmx_pip_pkt_inst_hdr_t; >> + >> +enum cvmx_pki_pcam_match { >> + CVMX_PKI_PCAM_MATCH_IP, >> + CVMX_PKI_PCAM_MATCH_IPV4, >> + CVMX_PKI_PCAM_MATCH_IPV6, >> + CVMX_PKI_PCAM_MATCH_TCP >> +}; >> + >> +/* CSR typedefs have been moved to cvmx-pip-defs.h */ >> +static inline int cvmx_pip_config_watcher(int index, int type, u16 >> match, u16 mask, int grp, >> + int qos) >> +{ >> + if (index >= CVMX_PIP_NUM_WATCHERS) { >> + debug("ERROR: pip watcher %d is > than supported\n", >> index); >> + return -1; >> + } >> + if (octeon_has_feature(OCTEON_FEATURE_PKI)) { >> + /* store in software for now, only when the watcher is >> enabled program the entry*/ >> + if (type == CVMX_PIP_QOS_WATCH_PROTNH) { >> + qos_watcher[index].field = >> CVMX_PKI_PCAM_TERM_L3_FLAGS; >> + qos_watcher[index].data = (u32)(match << 16); >> + qos_watcher[index].data_mask = (u32)(mask << >> 16); >> + qos_watcher[index].advance = 0; >> + } else if (type == CVMX_PIP_QOS_WATCH_TCP) { >> + qos_watcher[index].field = >> CVMX_PKI_PCAM_TERM_L4_PORT; >> + qos_watcher[index].data = 0x060000; >> + qos_watcher[index].data |= (u32)match; >> + qos_watcher[index].data_mask = (u32)(mask); >> + qos_watcher[index].advance = 0; >> + } else if (type == CVMX_PIP_QOS_WATCH_UDP) { >> + qos_watcher[index].field = >> CVMX_PKI_PCAM_TERM_L4_PORT; >> + qos_watcher[index].data = 0x110000; >> + qos_watcher[index].data |= (u32)match; >> + qos_watcher[index].data_mask = (u32)(mask); >> + qos_watcher[index].advance = 0; >> + } else if (type == 0x4 >> /*CVMX_PIP_QOS_WATCH_ETHERTYPE*/) { >> + qos_watcher[index].field = >> CVMX_PKI_PCAM_TERM_ETHTYPE0; >> + if (match == 0x8100) { >> + debug("ERROR: default vlan entry >> already exist, cant set watcher\n"); >> + return -1; >> + } >> + qos_watcher[index].data = (u32)(match << 16); >> + qos_watcher[index].data_mask = (u32)(mask << >> 16); >> + qos_watcher[index].advance = 4; >> + } else { >> + debug("ERROR: Unsupported watcher type %d\n", >> type); >> + return -1; >> + } >> + if (grp >= 32) { >> + debug("ERROR: grp %d out of range for backward >> compat 78xx\n", grp); >> + return -1; >> + } >> + qos_watcher[index].sso_grp = (u8)(grp << 3 | qos); >> + qos_watcher[index].configured = 1; >> + } else { >> + /* Implement it later */ >> + } >> + return 0; >> +} >> + >> +static inline int __cvmx_pip_set_tag_type(int node, int style, int >> tag_type, int field) >> +{ >> + struct cvmx_pki_style_config style_cfg; >> + int style_num; >> + int pcam_offset; >> + int bank; >> + struct cvmx_pki_pcam_input pcam_input; >> + struct cvmx_pki_pcam_action pcam_action; >> + >> + /* All other style parameters remain same except tag type */ >> + cvmx_pki_read_style_config(node, style, CVMX_PKI_CLUSTER_ALL, >> &style_cfg); >> + style_cfg.parm_cfg.tag_type = (enum cvmx_sso_tag_type)tag_type; >> + style_num = cvmx_pki_style_alloc(node, -1); >> + if (style_num < 0) { >> + debug("ERROR: style not available to set tag type\n"); >> + return -1; >> + } >> + cvmx_pki_write_style_config(node, style_num, >> CVMX_PKI_CLUSTER_ALL, &style_cfg); >> + memset(&pcam_input, 0, sizeof(pcam_input)); >> + memset(&pcam_action, 0, sizeof(pcam_action)); >> + pcam_input.style = style; >> + pcam_input.style_mask = 0xff; >> + if (field == CVMX_PKI_PCAM_MATCH_IP) { >> + pcam_input.field = CVMX_PKI_PCAM_TERM_ETHTYPE0; >> + pcam_input.field_mask = 0xff; >> + pcam_input.data = 0x08000000; >> + pcam_input.data_mask = 0xffff0000; >> + pcam_action.pointer_advance = 4; >> + /* legacy will write to all clusters*/ >> + bank = 0; >> + pcam_offset = cvmx_pki_pcam_entry_alloc(node, >> CVMX_PKI_FIND_AVAL_ENTRY, bank, >> + CVMX_PKI_CLUSTE >> R_ALL); >> + if (pcam_offset < 0) { >> + debug("ERROR: pcam entry not available to >> enable qos watcher\n"); >> + cvmx_pki_style_free(node, style_num); >> + return -1; >> + } >> + pcam_action.parse_mode_chg = CVMX_PKI_PARSE_NO_CHG; >> + pcam_action.layer_type_set = CVMX_PKI_LTYPE_E_NONE; >> + pcam_action.style_add = (u8)(style_num - style); >> + cvmx_pki_pcam_write_entry(node, pcam_offset, >> CVMX_PKI_CLUSTER_ALL, pcam_input, >> + pcam_action); >> + field = CVMX_PKI_PCAM_MATCH_IPV6; >> + } >> + if (field == CVMX_PKI_PCAM_MATCH_IPV4) { >> + pcam_input.field = CVMX_PKI_PCAM_TERM_ETHTYPE0; >> + pcam_input.field_mask = 0xff; >> + pcam_input.data = 0x08000000; >> + pcam_input.data_mask = 0xffff0000; >> + pcam_action.pointer_advance = 4; >> + } else if (field == CVMX_PKI_PCAM_MATCH_IPV6) { >> + pcam_input.field = CVMX_PKI_PCAM_TERM_ETHTYPE0; >> + pcam_input.field_mask = 0xff; >> + pcam_input.data = 0x86dd00000; >> + pcam_input.data_mask = 0xffff0000; >> + pcam_action.pointer_advance = 4; >> + } else if (field == CVMX_PKI_PCAM_MATCH_TCP) { >> + pcam_input.field = CVMX_PKI_PCAM_TERM_L4_PORT; >> + pcam_input.field_mask = 0xff; >> + pcam_input.data = 0x60000; >> + pcam_input.data_mask = 0xff0000; >> + pcam_action.pointer_advance = 0; >> + } >> + pcam_action.parse_mode_chg = CVMX_PKI_PARSE_NO_CHG; >> + pcam_action.layer_type_set = CVMX_PKI_LTYPE_E_NONE; >> + pcam_action.style_add = (u8)(style_num - style); >> + bank = pcam_input.field & 0x01; >> + pcam_offset = cvmx_pki_pcam_entry_alloc(node, >> CVMX_PKI_FIND_AVAL_ENTRY, bank, >> + CVMX_PKI_CLUSTER_ALL); >> + if (pcam_offset < 0) { >> + debug("ERROR: pcam entry not available to enable qos >> watcher\n"); >> + cvmx_pki_style_free(node, style_num); >> + return -1; >> + } >> + cvmx_pki_pcam_write_entry(node, pcam_offset, >> CVMX_PKI_CLUSTER_ALL, pcam_input, pcam_action); >> + return style_num; >> +} >> + >> +/* Only for legacy internal use */ >> +static inline int __cvmx_pip_enable_watcher_78xx(int node, int >> index, int style) >> +{ >> + struct cvmx_pki_style_config style_cfg; >> + struct cvmx_pki_qpg_config qpg_cfg; >> + struct cvmx_pki_pcam_input pcam_input; >> + struct cvmx_pki_pcam_action pcam_action; >> + int style_num; >> + int qpg_offset; >> + int pcam_offset; >> + int bank; >> + >> + if (!qos_watcher[index].configured) { >> + debug("ERROR: qos watcher %d should be configured >> before enable\n", index); >> + return -1; >> + } >> + /* All other style parameters remain same except grp and qos >> and qps base */ >> + cvmx_pki_read_style_config(node, style, CVMX_PKI_CLUSTER_ALL, >> &style_cfg); >> + cvmx_pki_read_qpg_entry(node, style_cfg.parm_cfg.qpg_base, >> &qpg_cfg); >> + qpg_cfg.qpg_base = CVMX_PKI_FIND_AVAL_ENTRY; >> + qpg_cfg.grp_ok = qos_watcher[index].sso_grp; >> + qpg_cfg.grp_bad = qos_watcher[index].sso_grp; >> + qpg_offset = cvmx_helper_pki_set_qpg_entry(node, &qpg_cfg); >> + if (qpg_offset == -1) { >> + debug("Warning: no new qpg entry available to enable >> watcher\n"); >> + return -1; >> + } >> + /* try to reserve the style, if it is not configured already, >> reserve >> + and configure it */ >> + style_cfg.parm_cfg.qpg_base = qpg_offset; >> + style_num = cvmx_pki_style_alloc(node, -1); >> + if (style_num < 0) { >> + debug("ERROR: style not available to enable qos >> watcher\n"); >> + cvmx_pki_qpg_entry_free(node, qpg_offset, 1); >> + return -1; >> + } >> + cvmx_pki_write_style_config(node, style_num, >> CVMX_PKI_CLUSTER_ALL, &style_cfg); >> + /* legacy will write to all clusters*/ >> + bank = qos_watcher[index].field & 0x01; >> + pcam_offset = cvmx_pki_pcam_entry_alloc(node, >> CVMX_PKI_FIND_AVAL_ENTRY, bank, >> + CVMX_PKI_CLUSTER_ALL); >> + if (pcam_offset < 0) { >> + debug("ERROR: pcam entry not available to enable qos >> watcher\n"); >> + cvmx_pki_style_free(node, style_num); >> + cvmx_pki_qpg_entry_free(node, qpg_offset, 1); >> + return -1; >> + } >> + memset(&pcam_input, 0, sizeof(pcam_input)); >> + memset(&pcam_action, 0, sizeof(pcam_action)); >> + pcam_input.style = style; >> + pcam_input.style_mask = 0xff; >> + pcam_input.field = qos_watcher[index].field; >> + pcam_input.field_mask = 0xff; >> + pcam_input.data = qos_watcher[index].data; >> + pcam_input.data_mask = qos_watcher[index].data_mask; >> + pcam_action.parse_mode_chg = CVMX_PKI_PARSE_NO_CHG; >> + pcam_action.layer_type_set = CVMX_PKI_LTYPE_E_NONE; >> + pcam_action.style_add = (u8)(style_num - style); >> + pcam_action.pointer_advance = qos_watcher[index].advance; >> + cvmx_pki_pcam_write_entry(node, pcam_offset, >> CVMX_PKI_CLUSTER_ALL, pcam_input, pcam_action); >> + return 0; >> +} >> + >> +/** >> + * Configure an ethernet input port >> + * >> + * @param ipd_port Port number to configure >> + * @param port_cfg Port hardware configuration >> + * @param port_tag_cfg Port POW tagging configuration >> + */ >> +static inline void cvmx_pip_config_port(u64 ipd_port, >> cvmx_pip_prt_cfgx_t port_cfg, >> + cvmx_pip_prt_tagx_t >> port_tag_cfg) >> +{ >> + struct cvmx_pki_qpg_config qpg_cfg; >> + int qpg_offset; >> + u8 tcp_tag = 0xff; >> + u8 ip_tag = 0xaa; >> + int style, nstyle, n4style, n6style; >> + >> + if (octeon_has_feature(OCTEON_FEATURE_PKI)) { >> + struct cvmx_pki_port_config pki_prt_cfg; >> + struct cvmx_xport xp = >> cvmx_helper_ipd_port_to_xport(ipd_port); >> + >> + cvmx_pki_get_port_config(ipd_port, &pki_prt_cfg); >> + style = pki_prt_cfg.pkind_cfg.initial_style; >> + if (port_cfg.s.ih_pri || port_cfg.s.vlan_len || >> port_cfg.s.pad_len) >> + debug("Warning: 78xx: use different config for >> this option\n"); >> + pki_prt_cfg.style_cfg.parm_cfg.minmax_sel = >> port_cfg.s.len_chk_sel; >> + pki_prt_cfg.style_cfg.parm_cfg.lenerr_en = >> port_cfg.s.lenerr_en; >> + pki_prt_cfg.style_cfg.parm_cfg.maxerr_en = >> port_cfg.s.maxerr_en; >> + pki_prt_cfg.style_cfg.parm_cfg.minerr_en = >> port_cfg.s.minerr_en; >> + pki_prt_cfg.style_cfg.parm_cfg.fcs_chk = >> port_cfg.s.crc_en; >> + if (port_cfg.s.grp_wat || port_cfg.s.qos_wat || >> port_cfg.s.grp_wat_47 || >> + port_cfg.s.qos_wat_47) { >> + u8 group_mask = (u8)(port_cfg.s.grp_wat | >> (u8)(port_cfg.s.grp_wat_47 << 4)); >> + u8 qos_mask = (u8)(port_cfg.s.qos_wat | >> (u8)(port_cfg.s.qos_wat_47 << 4)); >> + int i; >> + >> + for (i = 0; i < CVMX_PIP_NUM_WATCHERS; i++) { >> + if ((group_mask & (1 << i)) || >> (qos_mask & (1 << i))) >> + __cvmx_pip_enable_watcher_78xx( >> xp.node, i, style); >> + } >> + } >> + if (port_tag_cfg.s.tag_mode) { >> + if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X)) >> + cvmx_printf("Warning: mask tag is not >> supported in 78xx pass1\n"); >> + else { >> + } >> + /* need to implement for 78xx*/ >> + } >> + if (port_cfg.s.tag_inc) >> + debug("Warning: 78xx uses differnet method for >> tag generation\n"); >> + pki_prt_cfg.style_cfg.parm_cfg.rawdrp = >> port_cfg.s.rawdrp; >> + pki_prt_cfg.pkind_cfg.parse_en.inst_hdr = >> port_cfg.s.inst_hdr; >> + if (port_cfg.s.hg_qos) >> + pki_prt_cfg.style_cfg.parm_cfg.qpg_qos = >> CVMX_PKI_QPG_QOS_HIGIG; >> + else if (port_cfg.s.qos_vlan) >> + pki_prt_cfg.style_cfg.parm_cfg.qpg_qos = >> CVMX_PKI_QPG_QOS_VLAN; >> + else if (port_cfg.s.qos_diff) >> + pki_prt_cfg.style_cfg.parm_cfg.qpg_qos = >> CVMX_PKI_QPG_QOS_DIFFSERV; >> + if (port_cfg.s.qos_vod) >> + debug("Warning: 78xx needs pcam entries >> installed to achieve qos_vod\n"); >> + if (port_cfg.s.qos) { >> + cvmx_pki_read_qpg_entry(xp.node, >> pki_prt_cfg.style_cfg.parm_cfg.qpg_base, >> + &qpg_cfg); >> + qpg_cfg.qpg_base = CVMX_PKI_FIND_AVAL_ENTRY; >> + qpg_cfg.grp_ok |= port_cfg.s.qos; >> + qpg_cfg.grp_bad |= port_cfg.s.qos; >> + qpg_offset = >> cvmx_helper_pki_set_qpg_entry(xp.node, &qpg_cfg); >> + if (qpg_offset == -1) >> + debug("Warning: no new qpg entry >> available, will not modify qos\n"); >> + else >> + pki_prt_cfg.style_cfg.parm_cfg.qpg_base >> = qpg_offset; >> + } >> + if (port_tag_cfg.s.grp != >> pki_dflt_sso_grp[xp.node].group) { >> + cvmx_pki_read_qpg_entry(xp.node, >> pki_prt_cfg.style_cfg.parm_cfg.qpg_base, >> + &qpg_cfg); >> + qpg_cfg.qpg_base = CVMX_PKI_FIND_AVAL_ENTRY; >> + qpg_cfg.grp_ok |= (u8)(port_tag_cfg.s.grp << >> 3); >> + qpg_cfg.grp_bad |= (u8)(port_tag_cfg.s.grp << >> 3); >> + qpg_offset = >> cvmx_helper_pki_set_qpg_entry(xp.node, &qpg_cfg); >> + if (qpg_offset == -1) >> + debug("Warning: no new qpg entry >> available, will not modify group\n"); >> + else >> + pki_prt_cfg.style_cfg.parm_cfg.qpg_base >> = qpg_offset; >> + } >> + pki_prt_cfg.pkind_cfg.parse_en.dsa_en = >> port_cfg.s.dsa_en; >> + pki_prt_cfg.pkind_cfg.parse_en.hg_en = >> port_cfg.s.higig_en; >> + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.layer_c_src = >> + port_tag_cfg.s.ip6_src_flag | >> port_tag_cfg.s.ip4_src_flag; >> + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.layer_c_dst = >> + port_tag_cfg.s.ip6_dst_flag | >> port_tag_cfg.s.ip4_dst_flag; >> + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.ip_prot_nexthd >> r = >> + port_tag_cfg.s.ip6_nxth_flag | >> port_tag_cfg.s.ip4_pctl_flag; >> + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.layer_d_src = >> + port_tag_cfg.s.ip6_sprt_flag | >> port_tag_cfg.s.ip4_sprt_flag; >> + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.layer_d_dst = >> + port_tag_cfg.s.ip6_dprt_flag | >> port_tag_cfg.s.ip4_dprt_flag; >> + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.input_port = >> port_tag_cfg.s.inc_prt_flag; >> + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.first_vlan = >> port_tag_cfg.s.inc_vlan; >> + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.second_vlan = >> port_tag_cfg.s.inc_vs; >> + >> + if (port_tag_cfg.s.tcp6_tag_type == >> port_tag_cfg.s.tcp4_tag_type) >> + tcp_tag = port_tag_cfg.s.tcp6_tag_type; >> + if (port_tag_cfg.s.ip6_tag_type == >> port_tag_cfg.s.ip4_tag_type) >> + ip_tag = port_tag_cfg.s.ip6_tag_type; >> + pki_prt_cfg.style_cfg.parm_cfg.tag_type = >> + (enum >> cvmx_sso_tag_type)port_tag_cfg.s.non_tag_type; >> + if (tcp_tag == ip_tag && tcp_tag == >> port_tag_cfg.s.non_tag_type) >> + pki_prt_cfg.style_cfg.parm_cfg.tag_type = (enum >> cvmx_sso_tag_type)tcp_tag; >> + else if (tcp_tag == ip_tag) { >> + /* allocate and copy style */ >> + /* modify tag type */ >> + /*pcam entry for ip6 && ip4 match*/ >> + /* default is non tag type */ >> + __cvmx_pip_set_tag_type(xp.node, style, ip_tag, >> CVMX_PKI_PCAM_MATCH_IP); >> + } else if (ip_tag == port_tag_cfg.s.non_tag_type) { >> + /* allocate and copy style */ >> + /* modify tag type */ >> + /*pcam entry for tcp6 & tcp4 match*/ >> + /* default is non tag type */ >> + __cvmx_pip_set_tag_type(xp.node, style, >> tcp_tag, CVMX_PKI_PCAM_MATCH_TCP); >> + } else { >> + if (ip_tag != 0xaa) { >> + nstyle = >> __cvmx_pip_set_tag_type(xp.node, style, ip_tag, >> + CVMX_P >> KI_PCAM_MATCH_IP); >> + if (tcp_tag != 0xff) >> + __cvmx_pip_set_tag_type(xp.node >> , nstyle, tcp_tag, >> + CVMX_PK >> I_PCAM_MATCH_TCP); >> + else { >> + n4style = >> __cvmx_pip_set_tag_type(xp.node, nstyle, ip_tag, >> + >> CVMX_PKI_PCAM_MATCH_IPV4); >> + __cvmx_pip_set_tag_type(xp.node >> , n4style, >> + port_ta >> g_cfg.s.tcp4_tag_type, >> + CVMX_PK >> I_PCAM_MATCH_TCP); >> + n6style = >> __cvmx_pip_set_tag_type(xp.node, nstyle, ip_tag, >> + >> CVMX_PKI_PCAM_MATCH_IPV6); >> + __cvmx_pip_set_tag_type(xp.node >> , n6style, >> + port_ta >> g_cfg.s.tcp6_tag_type, >> + CVMX_PK >> I_PCAM_MATCH_TCP); >> + } >> + } else { >> + n4style = >> __cvmx_pip_set_tag_type(xp.node, style, >> + port_ >> tag_cfg.s.ip4_tag_type, >> + CVMX_ >> PKI_PCAM_MATCH_IPV4); >> + n6style = >> __cvmx_pip_set_tag_type(xp.node, style, >> + port_ >> tag_cfg.s.ip6_tag_type, >> + CVMX_ >> PKI_PCAM_MATCH_IPV6); >> + if (tcp_tag != 0xff) { >> + __cvmx_pip_set_tag_type(xp.node >> , n4style, tcp_tag, >> + CVMX_PK >> I_PCAM_MATCH_TCP); >> + __cvmx_pip_set_tag_type(xp.node >> , n6style, tcp_tag, >> + CVMX_PK >> I_PCAM_MATCH_TCP); >> + } else { >> + __cvmx_pip_set_tag_type(xp.node >> , n4style, >> + port_ta >> g_cfg.s.tcp4_tag_type, >> + CVMX_PK >> I_PCAM_MATCH_TCP); >> + __cvmx_pip_set_tag_type(xp.node >> , n6style, >> + port_ta >> g_cfg.s.tcp6_tag_type, >> + CVMX_PK >> I_PCAM_MATCH_TCP); >> + } >> + } >> + } >> + pki_prt_cfg.style_cfg.parm_cfg.qpg_dis_padd = >> !port_tag_cfg.s.portadd_en; >> + >> + if (port_cfg.s.mode == 0x1) >> + pki_prt_cfg.pkind_cfg.initial_parse_mode = >> CVMX_PKI_PARSE_LA_TO_LG; >> + else if (port_cfg.s.mode == 0x2) >> + pki_prt_cfg.pkind_cfg.initial_parse_mode = >> CVMX_PKI_PARSE_LC_TO_LG; >> + else >> + pki_prt_cfg.pkind_cfg.initial_parse_mode = >> CVMX_PKI_PARSE_NOTHING; >> + /* This is only for backward compatibility, not all the >> parameters are supported in 78xx */ >> + cvmx_pki_set_port_config(ipd_port, &pki_prt_cfg); >> + } else { >> + if (octeon_has_feature(OCTEON_FEATURE_PKND)) { >> + int interface, index, pknd; >> + >> + interface = >> cvmx_helper_get_interface_num(ipd_port); >> + index = >> cvmx_helper_get_interface_index_num(ipd_port); >> + pknd = cvmx_helper_get_pknd(interface, index); >> + >> + ipd_port = pknd; /* overload port_num with pknd >> */ >> + } >> + csr_wr(CVMX_PIP_PRT_CFGX(ipd_port), port_cfg.u64); >> + csr_wr(CVMX_PIP_PRT_TAGX(ipd_port), port_tag_cfg.u64); >> + } >> +} >> + >> +/** >> + * Configure the VLAN priority to QoS queue mapping. >> + * >> + * @param vlan_priority >> + * VLAN priority (0-7) >> + * @param qos QoS queue for packets matching this watcher >> + */ >> +static inline void cvmx_pip_config_vlan_qos(u64 vlan_priority, u64 >> qos) >> +{ >> + if (!octeon_has_feature(OCTEON_FEATURE_PKND)) { >> + cvmx_pip_qos_vlanx_t pip_qos_vlanx; >> + >> + pip_qos_vlanx.u64 = 0; >> + pip_qos_vlanx.s.qos = qos; >> + csr_wr(CVMX_PIP_QOS_VLANX(vlan_priority), >> pip_qos_vlanx.u64); >> + } >> +} >> + >> +/** >> + * Configure the Diffserv to QoS queue mapping. >> + * >> + * @param diffserv Diffserv field value (0-63) >> + * @param qos QoS queue for packets matching this watcher >> + */ >> +static inline void cvmx_pip_config_diffserv_qos(u64 diffserv, u64 >> qos) >> +{ >> + if (!octeon_has_feature(OCTEON_FEATURE_PKND)) { >> + cvmx_pip_qos_diffx_t pip_qos_diffx; >> + >> + pip_qos_diffx.u64 = 0; >> + pip_qos_diffx.s.qos = qos; >> + csr_wr(CVMX_PIP_QOS_DIFFX(diffserv), >> pip_qos_diffx.u64); >> + } >> +} >> + >> +/** >> + * Get the status counters for a port for older non PKI chips. >> + * >> + * @param port_num Port number (ipd_port) to get statistics for. >> + * @param clear Set to 1 to clear the counters after they are >> read >> + * @param status Where to put the results. >> + */ >> +static inline void cvmx_pip_get_port_stats(u64 port_num, u64 clear, >> cvmx_pip_port_status_t *status) >> +{ >> + cvmx_pip_stat_ctl_t pip_stat_ctl; >> + cvmx_pip_stat0_prtx_t stat0; >> + cvmx_pip_stat1_prtx_t stat1; >> + cvmx_pip_stat2_prtx_t stat2; >> + cvmx_pip_stat3_prtx_t stat3; >> + cvmx_pip_stat4_prtx_t stat4; >> + cvmx_pip_stat5_prtx_t stat5; >> + cvmx_pip_stat6_prtx_t stat6; >> + cvmx_pip_stat7_prtx_t stat7; >> + cvmx_pip_stat8_prtx_t stat8; >> + cvmx_pip_stat9_prtx_t stat9; >> + cvmx_pip_stat10_x_t stat10; >> + cvmx_pip_stat11_x_t stat11; >> + cvmx_pip_stat_inb_pktsx_t pip_stat_inb_pktsx; >> + cvmx_pip_stat_inb_octsx_t pip_stat_inb_octsx; >> + cvmx_pip_stat_inb_errsx_t pip_stat_inb_errsx; >> + int interface = cvmx_helper_get_interface_num(port_num); >> + int index = cvmx_helper_get_interface_index_num(port_num); >> + >> + pip_stat_ctl.u64 = 0; >> + pip_stat_ctl.s.rdclr = clear; >> + csr_wr(CVMX_PIP_STAT_CTL, pip_stat_ctl.u64); >> + >> + if (octeon_has_feature(OCTEON_FEATURE_PKND)) { >> + int pknd = cvmx_helper_get_pknd(interface, index); >> + /* >> + * PIP_STAT_CTL[MODE] 0 means pkind. >> + */ >> + stat0.u64 = csr_rd(CVMX_PIP_STAT0_X(pknd)); >> + stat1.u64 = csr_rd(CVMX_PIP_STAT1_X(pknd)); >> + stat2.u64 = csr_rd(CVMX_PIP_STAT2_X(pknd)); >> + stat3.u64 = csr_rd(CVMX_PIP_STAT3_X(pknd)); >> + stat4.u64 = csr_rd(CVMX_PIP_STAT4_X(pknd)); >> + stat5.u64 = csr_rd(CVMX_PIP_STAT5_X(pknd)); >> + stat6.u64 = csr_rd(CVMX_PIP_STAT6_X(pknd)); >> + stat7.u64 = csr_rd(CVMX_PIP_STAT7_X(pknd)); >> + stat8.u64 = csr_rd(CVMX_PIP_STAT8_X(pknd)); >> + stat9.u64 = csr_rd(CVMX_PIP_STAT9_X(pknd)); >> + stat10.u64 = csr_rd(CVMX_PIP_STAT10_X(pknd)); >> + stat11.u64 = csr_rd(CVMX_PIP_STAT11_X(pknd)); >> + } else { >> + if (port_num >= 40) { >> + stat0.u64 = >> csr_rd(CVMX_PIP_XSTAT0_PRTX(port_num)); >> + stat1.u64 = >> csr_rd(CVMX_PIP_XSTAT1_PRTX(port_num)); >> + stat2.u64 = >> csr_rd(CVMX_PIP_XSTAT2_PRTX(port_num)); >> + stat3.u64 = >> csr_rd(CVMX_PIP_XSTAT3_PRTX(port_num)); >> + stat4.u64 = >> csr_rd(CVMX_PIP_XSTAT4_PRTX(port_num)); >> + stat5.u64 = >> csr_rd(CVMX_PIP_XSTAT5_PRTX(port_num)); >> + stat6.u64 = >> csr_rd(CVMX_PIP_XSTAT6_PRTX(port_num)); >> + stat7.u64 = >> csr_rd(CVMX_PIP_XSTAT7_PRTX(port_num)); >> + stat8.u64 = >> csr_rd(CVMX_PIP_XSTAT8_PRTX(port_num)); >> + stat9.u64 = >> csr_rd(CVMX_PIP_XSTAT9_PRTX(port_num)); >> + if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { >> + stat10.u64 = >> csr_rd(CVMX_PIP_XSTAT10_PRTX(port_num)); >> + stat11.u64 = >> csr_rd(CVMX_PIP_XSTAT11_PRTX(port_num)); >> + } >> + } else { >> + stat0.u64 = >> csr_rd(CVMX_PIP_STAT0_PRTX(port_num)); >> + stat1.u64 = >> csr_rd(CVMX_PIP_STAT1_PRTX(port_num)); >> + stat2.u64 = >> csr_rd(CVMX_PIP_STAT2_PRTX(port_num)); >> + stat3.u64 = >> csr_rd(CVMX_PIP_STAT3_PRTX(port_num)); >> + stat4.u64 = >> csr_rd(CVMX_PIP_STAT4_PRTX(port_num)); >> + stat5.u64 = >> csr_rd(CVMX_PIP_STAT5_PRTX(port_num)); >> + stat6.u64 = >> csr_rd(CVMX_PIP_STAT6_PRTX(port_num)); >> + stat7.u64 = >> csr_rd(CVMX_PIP_STAT7_PRTX(port_num)); >> + stat8.u64 = >> csr_rd(CVMX_PIP_STAT8_PRTX(port_num)); >> + stat9.u64 = >> csr_rd(CVMX_PIP_STAT9_PRTX(port_num)); >> + if (OCTEON_IS_OCTEON2() || >> OCTEON_IS_MODEL(OCTEON_CN70XX)) { >> + stat10.u64 = >> csr_rd(CVMX_PIP_STAT10_PRTX(port_num)); >> + stat11.u64 = >> csr_rd(CVMX_PIP_STAT11_PRTX(port_num)); >> + } >> + } >> + } >> + if (octeon_has_feature(OCTEON_FEATURE_PKND)) { >> + int pknd = cvmx_helper_get_pknd(interface, index); >> + >> + pip_stat_inb_pktsx.u64 = >> csr_rd(CVMX_PIP_STAT_INB_PKTS_PKNDX(pknd)); >> + pip_stat_inb_octsx.u64 = >> csr_rd(CVMX_PIP_STAT_INB_OCTS_PKNDX(pknd)); >> + pip_stat_inb_errsx.u64 = >> csr_rd(CVMX_PIP_STAT_INB_ERRS_PKNDX(pknd)); >> + } else { >> + pip_stat_inb_pktsx.u64 = >> csr_rd(CVMX_PIP_STAT_INB_PKTSX(port_num)); >> + pip_stat_inb_octsx.u64 = >> csr_rd(CVMX_PIP_STAT_INB_OCTSX(port_num)); >> + pip_stat_inb_errsx.u64 = >> csr_rd(CVMX_PIP_STAT_INB_ERRSX(port_num)); >> + } >> + >> + status->dropped_octets = stat0.s.drp_octs; >> + status->dropped_packets = stat0.s.drp_pkts; >> + status->octets = stat1.s.octs; >> + status->pci_raw_packets = stat2.s.raw; >> + status->packets = stat2.s.pkts; >> + status->multicast_packets = stat3.s.mcst; >> + status->broadcast_packets = stat3.s.bcst; >> + status->len_64_packets = stat4.s.h64; >> + status->len_65_127_packets = stat4.s.h65to127; >> + status->len_128_255_packets = stat5.s.h128to255; >> + status->len_256_511_packets = stat5.s.h256to511; >> + status->len_512_1023_packets = stat6.s.h512to1023; >> + status->len_1024_1518_packets = stat6.s.h1024to1518; >> + status->len_1519_max_packets = stat7.s.h1519; >> + status->fcs_align_err_packets = stat7.s.fcs; >> + status->runt_packets = stat8.s.undersz; >> + status->runt_crc_packets = stat8.s.frag; >> + status->oversize_packets = stat9.s.oversz; >> + status->oversize_crc_packets = stat9.s.jabber; >> + if (OCTEON_IS_OCTEON2() || OCTEON_IS_MODEL(OCTEON_CN70XX)) { >> + status->mcast_l2_red_packets = stat10.s.mcast; >> + status->bcast_l2_red_packets = stat10.s.bcast; >> + status->mcast_l3_red_packets = stat11.s.mcast; >> + status->bcast_l3_red_packets = stat11.s.bcast; >> + } >> + status->inb_packets = pip_stat_inb_pktsx.s.pkts; >> + status->inb_octets = pip_stat_inb_octsx.s.octs; >> + status->inb_errors = pip_stat_inb_errsx.s.errs; >> +} >> + >> +/** >> + * Get the status counters for a port. >> + * >> + * @param port_num Port number (ipd_port) to get statistics for. >> + * @param clear Set to 1 to clear the counters after they are >> read >> + * @param status Where to put the results. >> + */ >> +static inline void cvmx_pip_get_port_status(u64 port_num, u64 clear, >> cvmx_pip_port_status_t *status) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_PKI)) { >> + unsigned int node = cvmx_get_node_num(); >> + >> + cvmx_pki_get_port_stats(node, port_num, (struct >> cvmx_pki_port_stats *)status); >> + } else { >> + cvmx_pip_get_port_stats(port_num, clear, status); >> + } >> +} >> + >> +/** >> + * Configure the hardware CRC engine >> + * >> + * @param interface Interface to configure (0 or 1) >> + * @param invert_result >> + * Invert the result of the CRC >> + * @param reflect Reflect >> + * @param initialization_vector >> + * CRC initialization vector >> + */ >> +static inline void cvmx_pip_config_crc(u64 interface, u64 >> invert_result, u64 reflect, >> + u32 initialization_vector) >> +{ >> + /* Only CN38XX & CN58XX */ >> +} >> + >> +/** >> + * Clear all bits in a tag mask. This should be called on >> + * startup before any calls to cvmx_pip_tag_mask_set. Each bit >> + * set in the final mask represent a byte used in the packet for >> + * tag generation. >> + * >> + * @param mask_index Which tag mask to clear (0..3) >> + */ >> +static inline void cvmx_pip_tag_mask_clear(u64 mask_index) >> +{ >> + u64 index; >> + cvmx_pip_tag_incx_t pip_tag_incx; >> + >> + pip_tag_incx.u64 = 0; >> + pip_tag_incx.s.en = 0; >> + for (index = mask_index * 16; index < (mask_index + 1) * 16; >> index++) >> + csr_wr(CVMX_PIP_TAG_INCX(index), pip_tag_incx.u64); >> +} >> + >> +/** >> + * Sets a range of bits in the tag mask. The tag mask is used >> + * when the cvmx_pip_port_tag_cfg_t tag_mode is non zero. >> + * There are four separate masks that can be configured. >> + * >> + * @param mask_index Which tag mask to modify (0..3) >> + * @param offset Offset into the bitmask to set bits at. Use the >> GCC macro >> + * offsetof() to determine the offsets into packet >> headers. >> + * For example, offsetof(ethhdr, protocol) returns >> the offset >> + * of the ethernet protocol field. The bitmask >> selects which bytes >> + * to include the the tag, with bit offset X >> selecting byte at offset X >> + * from the beginning of the packet data. >> + * @param len Number of bytes to include. Usually this is the >> sizeof() >> + * the field. >> + */ >> +static inline void cvmx_pip_tag_mask_set(u64 mask_index, u64 offset, >> u64 len) >> +{ >> + while (len--) { >> + cvmx_pip_tag_incx_t pip_tag_incx; >> + u64 index = mask_index * 16 + offset / 8; >> + >> + pip_tag_incx.u64 = csr_rd(CVMX_PIP_TAG_INCX(index)); >> + pip_tag_incx.s.en |= 0x80 >> (offset & 0x7); >> + csr_wr(CVMX_PIP_TAG_INCX(index), pip_tag_incx.u64); >> + offset++; >> + } >> +} >> + >> +/** >> + * Set byte count for Max-Sized and Min Sized frame check. >> + * >> + * @param interface Which interface to set the limit >> + * @param max_size Byte count for Max-Size frame check >> + */ >> +static inline void cvmx_pip_set_frame_check(int interface, u32 >> max_size) >> +{ >> + cvmx_pip_frm_len_chkx_t frm_len; >> + >> + /* max_size and min_size are passed as 0, reset to default >> values. */ >> + if (max_size < 1536) >> + max_size = 1536; >> + >> + /* On CN68XX frame check is enabled for a pkind n and >> + PIP_PRT_CFG[len_chk_sel] selects which set of >> + MAXLEN/MINLEN to use. */ >> + if (octeon_has_feature(OCTEON_FEATURE_PKND)) { >> + int port; >> + int num_ports = >> cvmx_helper_ports_on_interface(interface); >> + >> + for (port = 0; port < num_ports; port++) { >> + if (octeon_has_feature(OCTEON_FEATURE_PKI)) { >> + int ipd_port; >> + >> + ipd_port = >> cvmx_helper_get_ipd_port(interface, port); >> + cvmx_pki_set_max_frm_len(ipd_port, >> max_size); >> + } else { >> + int pknd; >> + int sel; >> + cvmx_pip_prt_cfgx_t config; >> + >> + pknd = cvmx_helper_get_pknd(interface, >> port); >> + config.u64 = >> csr_rd(CVMX_PIP_PRT_CFGX(pknd)); >> + sel = config.s.len_chk_sel; >> + frm_len.u64 = >> csr_rd(CVMX_PIP_FRM_LEN_CHKX(sel)); >> + frm_len.s.maxlen = max_size; >> + csr_wr(CVMX_PIP_FRM_LEN_CHKX(sel), >> frm_len.u64); >> + } >> + } >> + } >> + /* on cn6xxx and cn7xxx models, PIP_FRM_LEN_CHK0 applies to >> + * all incoming traffic */ >> + else if (OCTEON_IS_OCTEON2() || OCTEON_IS_MODEL(OCTEON_CN70XX)) >> { >> + frm_len.u64 = csr_rd(CVMX_PIP_FRM_LEN_CHKX(0)); >> + frm_len.s.maxlen = max_size; >> + csr_wr(CVMX_PIP_FRM_LEN_CHKX(0), frm_len.u64); >> + } >> +} >> + >> +/** >> + * Initialize Bit Select Extractor config. Their are 8 bit positions >> and valids >> + * to be used when using the corresponding extractor. >> + * >> + * @param bit Bit Select Extractor to use >> + * @param pos Which position to update >> + * @param val The value to update the position with >> + */ >> +static inline void cvmx_pip_set_bsel_pos(int bit, int pos, int val) >> +{ >> + cvmx_pip_bsel_ext_posx_t bsel_pos; >> + >> + /* The bit select extractor is available in CN61XX and CN68XX >> pass2.0 onwards. */ >> + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) >> + return; >> + >> + if (bit < 0 || bit > 3) { >> + debug("ERROR: cvmx_pip_set_bsel_pos: Invalid Bit-Select >> Extractor (%d) passed\n", >> + bit); >> + return; >> + } >> + >> + bsel_pos.u64 = csr_rd(CVMX_PIP_BSEL_EXT_POSX(bit)); >> + switch (pos) { >> + case 0: >> + bsel_pos.s.pos0_val = 1; >> + bsel_pos.s.pos0 = val & 0x7f; >> + break; >> + case 1: >> + bsel_pos.s.pos1_val = 1; >> + bsel_pos.s.pos1 = val & 0x7f; >> + break; >> + case 2: >> + bsel_pos.s.pos2_val = 1; >> + bsel_pos.s.pos2 = val & 0x7f; >> + break; >> + case 3: >> + bsel_pos.s.pos3_val = 1; >> + bsel_pos.s.pos3 = val & 0x7f; >> + break; >> + case 4: >> + bsel_pos.s.pos4_val = 1; >> + bsel_pos.s.pos4 = val & 0x7f; >> + break; >> + case 5: >> + bsel_pos.s.pos5_val = 1; >> + bsel_pos.s.pos5 = val & 0x7f; >> + break; >> + case 6: >> + bsel_pos.s.pos6_val = 1; >> + bsel_pos.s.pos6 = val & 0x7f; >> + break; >> + case 7: >> + bsel_pos.s.pos7_val = 1; >> + bsel_pos.s.pos7 = val & 0x7f; >> + break; >> + default: >> + debug("Warning: cvmx_pip_set_bsel_pos: Invalid >> pos(%d)\n", pos); >> + break; >> + } >> + csr_wr(CVMX_PIP_BSEL_EXT_POSX(bit), bsel_pos.u64); >> +} >> + >> +/** >> + * Initialize offset and skip values to use by bit select extractor. >> + >> + * @param bit Bit Select Extractor to use >> + * @param offset Offset to add to extractor mem addr to get >> final address >> + * to lookup table. >> + * @param skip Number of bytes to skip from start of >> packet 0-64 >> + */ >> +static inline void cvmx_pip_bsel_config(int bit, int offset, int >> skip) >> +{ >> + cvmx_pip_bsel_ext_cfgx_t bsel_cfg; >> + >> + /* The bit select extractor is available in CN61XX and CN68XX >> pass2.0 onwards. */ >> + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) >> + return; >> + >> + bsel_cfg.u64 = csr_rd(CVMX_PIP_BSEL_EXT_CFGX(bit)); >> + bsel_cfg.s.offset = offset; >> + bsel_cfg.s.skip = skip; >> + csr_wr(CVMX_PIP_BSEL_EXT_CFGX(bit), bsel_cfg.u64); >> +} >> + >> +/** >> + * Get the entry for the Bit Select Extractor Table. >> + * @param work pointer to work queue entry >> + * @return Index of the Bit Select Extractor Table >> + */ >> +static inline int cvmx_pip_get_bsel_table_index(cvmx_wqe_t *work) >> +{ >> + int bit = cvmx_wqe_get_port(work) & 0x3; >> + /* Get the Bit select table index. */ >> + int index; >> + int y; >> + cvmx_pip_bsel_ext_cfgx_t bsel_cfg; >> + cvmx_pip_bsel_ext_posx_t bsel_pos; >> + >> + /* The bit select extractor is available in CN61XX and CN68XX >> pass2.0 onwards. */ >> + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) >> + return -1; >> + >> + bsel_cfg.u64 = csr_rd(CVMX_PIP_BSEL_EXT_CFGX(bit)); >> + bsel_pos.u64 = csr_rd(CVMX_PIP_BSEL_EXT_POSX(bit)); >> + >> + for (y = 0; y < 8; y++) { >> + char *ptr = (char *)cvmx_phys_to_ptr(work- >>> packet_ptr.s.addr); >> + int bit_loc = 0; >> + int bit; >> + >> + ptr += bsel_cfg.s.skip; >> + switch (y) { >> + case 0: >> + ptr += (bsel_pos.s.pos0 >> 3); >> + bit_loc = 7 - (bsel_pos.s.pos0 & 0x3); >> + break; >> + case 1: >> + ptr += (bsel_pos.s.pos1 >> 3); >> + bit_loc = 7 - (bsel_pos.s.pos1 & 0x3); >> + break; >> + case 2: >> + ptr += (bsel_pos.s.pos2 >> 3); >> + bit_loc = 7 - (bsel_pos.s.pos2 & 0x3); >> + break; >> + case 3: >> + ptr += (bsel_pos.s.pos3 >> 3); >> + bit_loc = 7 - (bsel_pos.s.pos3 & 0x3); >> + break; >> + case 4: >> + ptr += (bsel_pos.s.pos4 >> 3); >> + bit_loc = 7 - (bsel_pos.s.pos4 & 0x3); >> + break; >> + case 5: >> + ptr += (bsel_pos.s.pos5 >> 3); >> + bit_loc = 7 - (bsel_pos.s.pos5 & 0x3); >> + break; >> + case 6: >> + ptr += (bsel_pos.s.pos6 >> 3); >> + bit_loc = 7 - (bsel_pos.s.pos6 & 0x3); >> + break; >> + case 7: >> + ptr += (bsel_pos.s.pos7 >> 3); >> + bit_loc = 7 - (bsel_pos.s.pos7 & 0x3); >> + break; >> + } >> + bit = (*ptr >> bit_loc) & 1; >> + index |= bit << y; >> + } >> + index += bsel_cfg.s.offset; >> + index &= 0x1ff; >> + return index; >> +} >> + >> +static inline int cvmx_pip_get_bsel_qos(cvmx_wqe_t *work) >> +{ >> + int index = cvmx_pip_get_bsel_table_index(work); >> + cvmx_pip_bsel_tbl_entx_t bsel_tbl; >> + >> + /* The bit select extractor is available in CN61XX and CN68XX >> pass2.0 onwards. */ >> + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) >> + return -1; >> + >> + bsel_tbl.u64 = csr_rd(CVMX_PIP_BSEL_TBL_ENTX(index)); >> + >> + return bsel_tbl.s.qos; >> +} >> + >> +static inline int cvmx_pip_get_bsel_grp(cvmx_wqe_t *work) >> +{ >> + int index = cvmx_pip_get_bsel_table_index(work); >> + cvmx_pip_bsel_tbl_entx_t bsel_tbl; >> + >> + /* The bit select extractor is available in CN61XX and CN68XX >> pass2.0 onwards. */ >> + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) >> + return -1; >> + >> + bsel_tbl.u64 = csr_rd(CVMX_PIP_BSEL_TBL_ENTX(index)); >> + >> + return bsel_tbl.s.grp; >> +} >> + >> +static inline int cvmx_pip_get_bsel_tt(cvmx_wqe_t *work) >> +{ >> + int index = cvmx_pip_get_bsel_table_index(work); >> + cvmx_pip_bsel_tbl_entx_t bsel_tbl; >> + >> + /* The bit select extractor is available in CN61XX and CN68XX >> pass2.0 onwards. */ >> + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) >> + return -1; >> + >> + bsel_tbl.u64 = csr_rd(CVMX_PIP_BSEL_TBL_ENTX(index)); >> + >> + return bsel_tbl.s.tt; >> +} >> + >> +static inline int cvmx_pip_get_bsel_tag(cvmx_wqe_t *work) >> +{ >> + int index = cvmx_pip_get_bsel_table_index(work); >> + int port = cvmx_wqe_get_port(work); >> + int bit = port & 0x3; >> + int upper_tag = 0; >> + cvmx_pip_bsel_tbl_entx_t bsel_tbl; >> + cvmx_pip_bsel_ext_cfgx_t bsel_cfg; >> + cvmx_pip_prt_tagx_t prt_tag; >> + >> + /* The bit select extractor is available in CN61XX and CN68XX >> pass2.0 onwards. */ >> + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) >> + return -1; >> + >> + bsel_tbl.u64 = csr_rd(CVMX_PIP_BSEL_TBL_ENTX(index)); >> + bsel_cfg.u64 = csr_rd(CVMX_PIP_BSEL_EXT_CFGX(bit)); >> + >> + prt_tag.u64 = csr_rd(CVMX_PIP_PRT_TAGX(port)); >> + if (prt_tag.s.inc_prt_flag == 0) >> + upper_tag = bsel_cfg.s.upper_tag; >> + return bsel_tbl.s.tag | ((bsel_cfg.s.tag << 8) & 0xff00) | >> ((upper_tag << 16) & 0xffff0000); >> +} >> + >> +#endif /* __CVMX_PIP_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pki-resources.h >> b/arch/mips/mach-octeon/include/mach/cvmx-pki-resources.h >> new file mode 100644 >> index 000000000000..79b99b0bd7c2 >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-pki-resources.h >> @@ -0,0 +1,157 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Resource management for PKI resources. >> + */ >> + >> +#ifndef __CVMX_PKI_RESOURCES_H__ >> +#define __CVMX_PKI_RESOURCES_H__ >> + >> +/** >> + * This function allocates/reserves a style from pool of global >> styles per node. >> + * @param node node to allocate style from. >> + * @param style style to allocate, if -1 it will be allocated >> + first available style from style resource. If index is >> positive >> + number and in range, it will try to allocate specified >> style. >> + * @return style number on success, -1 on failure. >> + */ >> +int cvmx_pki_style_alloc(int node, int style); >> + >> +/** >> + * This function allocates/reserves a cluster group from per node >> + cluster group resources. >> + * @param node node to allocate cluster group from. >> + @param cl_grp cluster group to allocate/reserve, if -1 , >> + allocate any available cluster group. >> + * @return cluster group number or -1 on failure >> + */ >> +int cvmx_pki_cluster_grp_alloc(int node, int cl_grp); >> + >> +/** >> + * This function allocates/reserves a cluster from per node >> + cluster resources. >> + * @param node node to allocate cluster group from. >> + @param cluster_mask mask of clusters to allocate/reserve, >> if -1 , >> + allocate any available clusters. >> + * @param num_clusters number of clusters that will be >> allocated >> + */ >> +int cvmx_pki_cluster_alloc(int node, int num_clusters, u64 >> *cluster_mask); >> + >> +/** >> + * This function allocates/reserves a pcam entry from node >> + * @param node node to allocate pcam entry from. >> + @param index index of pacm entry (0-191), if -1 , >> + allocate any available pcam entry. >> + * @param bank pcam bank where to allocate/reserve >> pcan entry from >> + * @param cluster_mask mask of clusters from which pcam entry is >> needed. >> + * @return pcam entry of -1 on failure >> + */ >> +int cvmx_pki_pcam_entry_alloc(int node, int index, int bank, u64 >> cluster_mask); >> + >> +/** >> + * This function allocates/reserves QPG table entries per node. >> + * @param node node number. >> + * @param base_offset base_offset in qpg table. If -1, first >> available >> + qpg base_offset will be allocated. If >> base_offset is positive >> + number and in range, it will try to allocate >> specified base_offset. >> + @param count number of consecutive qpg entries to >> allocate. They will be consecutive >> + from base offset. >> + * @return qpg table base offset number on success, -1 on >> failure. >> + */ >> +int cvmx_pki_qpg_entry_alloc(int node, int base_offset, int count); >> + >> +/** >> + * This function frees a style from pool of global styles per node. >> + * @param node node to free style from. >> + * @param style style to free >> + * @return 0 on success, -1 on failure. >> + */ >> +int cvmx_pki_style_free(int node, int style); >> + >> +/** >> + * This function frees a cluster group from per node >> + cluster group resources. >> + * @param node node to free cluster group from. >> + @param cl_grp cluster group to free >> + * @return 0 on success or -1 on failure >> + */ >> +int cvmx_pki_cluster_grp_free(int node, int cl_grp); >> + >> +/** >> + * This function frees QPG table entries per node. >> + * @param node node number. >> + * @param base_offset base_offset in qpg table. If -1, first >> available >> + * qpg base_offset will be allocated. If >> base_offset is positive >> + * number and in range, it will try to allocate >> specified base_offset. >> + * @param count number of consecutive qpg entries to >> allocate. They will be consecutive >> + * from base offset. >> + * @return qpg table base offset number on success, -1 on >> failure. >> + */ >> +int cvmx_pki_qpg_entry_free(int node, int base_offset, int count); >> + >> +/** >> + * This function frees clusters from per node >> + clusters resources. >> + * @param node node to free clusters from. >> + * @param cluster_mask mask of clusters need freeing >> + * @return 0 on success or -1 on failure >> + */ >> +int cvmx_pki_cluster_free(int node, u64 cluster_mask); >> + >> +/** >> + * This function frees a pcam entry from node >> + * @param node node to allocate pcam entry from. >> + @param index index of pacm entry (0-191) needs to be freed. >> + * @param bank pcam bank where to free pcam entry from >> + * @param cluster_mask mask of clusters from which pcam entry is >> freed. >> + * @return 0 on success OR -1 on failure >> + */ >> +int cvmx_pki_pcam_entry_free(int node, int index, int bank, u64 >> cluster_mask); >> + >> +/** >> + * This function allocates/reserves a bpid from pool of global bpid >> per node. >> + * @param node node to allocate bpid from. >> + * @param bpid bpid to allocate, if -1 it will be allocated >> + * first available boid from bpid resource. If index is >> positive >> + * number and in range, it will try to allocate specified >> bpid. >> + * @return bpid number on success, >> + * -1 on alloc failure. >> + * -2 on resource already reserved. >> + */ >> +int cvmx_pki_bpid_alloc(int node, int bpid); >> + >> +/** >> + * This function frees a bpid from pool of global bpid per node. >> + * @param node node to free bpid from. >> + * @param bpid bpid to free >> + * @return 0 on success, -1 on failure or >> + */ >> +int cvmx_pki_bpid_free(int node, int bpid); >> + >> +/** >> + * This function frees all the PKI software resources >> + * (clusters, styles, qpg_entry, pcam_entry etc) for the specified >> node >> + */ >> + >> +/** >> + * This function allocates/reserves an index from pool of global >> MTAG-IDX per node. >> + * @param node node to allocate index from. >> + * @param idx index to allocate, if -1 it will be allocated >> + * @return MTAG index number on success, >> + * -1 on alloc failure. >> + * -2 on resource already reserved. >> + */ >> +int cvmx_pki_mtag_idx_alloc(int node, int idx); >> + >> +/** >> + * This function frees an index from pool of global MTAG-IDX per >> node. >> + * @param node node to free bpid from. >> + * @param bpid bpid to free >> + * @return 0 on success, -1 on failure or >> + */ >> +int cvmx_pki_mtag_idx_free(int node, int idx); >> + >> +void __cvmx_pki_global_rsrc_free(int node); >> + >> +#endif /* __CVM_PKI_RESOURCES_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pki.h >> b/arch/mips/mach-octeon/include/mach/cvmx-pki.h >> new file mode 100644 >> index 000000000000..c1feb55a1f01 >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-pki.h >> @@ -0,0 +1,970 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Interface to the hardware Packet Input Data unit. >> + */ >> + >> +#ifndef __CVMX_PKI_H__ >> +#define __CVMX_PKI_H__ >> + >> +#include "cvmx-fpa3.h" >> +#include "cvmx-helper-util.h" >> +#include "cvmx-helper-cfg.h" >> +#include "cvmx-error.h" >> + >> +/* PKI AURA and BPID count are equal to FPA AURA count */ >> +#define CVMX_PKI_NUM_AURA (cvmx_fpa3_num_auras()) >> +#define CVMX_PKI_NUM_BPID (cvmx_fpa3_num_auras()) >> +#define CVMX_PKI_NUM_SSO_GROUP (cvmx_sso_num_xgrp()) >> +#define CVMX_PKI_NUM_CLUSTER_GROUP_MAX 1 >> +#define CVMX_PKI_NUM_CLUSTER_GROUP (cvmx_pki_num_cl_grp()) >> +#define CVMX_PKI_NUM_CLUSTER (cvmx_pki_num_clusters()) >> + >> +/* FIXME: Reduce some of these values, convert to routines XXX */ >> +#define CVMX_PKI_NUM_CHANNEL 4096 >> +#define CVMX_PKI_NUM_PKIND 64 >> +#define CVMX_PKI_NUM_INTERNAL_STYLE 256 >> +#define CVMX_PKI_NUM_FINAL_STYLE 64 >> +#define CVMX_PKI_NUM_QPG_ENTRY 2048 >> +#define CVMX_PKI_NUM_MTAG_IDX (32 / 4) /* 32 registers >> grouped by 4*/ >> +#define CVMX_PKI_NUM_LTYPE 32 >> +#define CVMX_PKI_NUM_PCAM_BANK 2 >> +#define CVMX_PKI_NUM_PCAM_ENTRY 192 >> +#define CVMX_PKI_NUM_FRAME_CHECK 2 >> +#define CVMX_PKI_NUM_BELTYPE 32 >> +#define CVMX_PKI_MAX_FRAME_SIZE 65535 >> +#define CVMX_PKI_FIND_AVAL_ENTRY (-1) >> +#define CVMX_PKI_CLUSTER_ALL 0xf >> + >> +#ifdef CVMX_SUPPORT_SEPARATE_CLUSTER_CONFIG >> +#define >> CVMX_PKI_TOTAL_PCAM_ENTRY >> \ >> + ((CVMX_PKI_NUM_CLUSTER) * (CVMX_PKI_NUM_PCAM_BANK) * >> (CVMX_PKI_NUM_PCAM_ENTRY)) >> +#else >> +#define CVMX_PKI_TOTAL_PCAM_ENTRY (CVMX_PKI_NUM_PCAM_BANK * >> CVMX_PKI_NUM_PCAM_ENTRY) >> +#endif >> + >> +static inline unsigned int cvmx_pki_num_clusters(void) >> +{ >> + if (OCTEON_IS_MODEL(OCTEON_CN73XX) || >> OCTEON_IS_MODEL(OCTEON_CNF75XX)) >> + return 2; >> + return 4; >> +} >> + >> +static inline unsigned int cvmx_pki_num_cl_grp(void) >> +{ >> + if (OCTEON_IS_MODEL(OCTEON_CN73XX) || >> OCTEON_IS_MODEL(OCTEON_CNF75XX) || >> + OCTEON_IS_MODEL(OCTEON_CN78XX)) >> + return 1; >> + return 0; >> +} >> + >> +enum cvmx_pki_pkind_parse_mode { >> + CVMX_PKI_PARSE_LA_TO_LG = 0, /* Parse LA(L2) to LG */ >> + CVMX_PKI_PARSE_LB_TO_LG = 1, /* Parse LB(custom) to LG */ >> + CVMX_PKI_PARSE_LC_TO_LG = 3, /* Parse LC(L3) to LG */ >> + CVMX_PKI_PARSE_LG = 0x3f, /* Parse LG */ >> + CVMX_PKI_PARSE_NOTHING = 0x7f /* Parse nothing */ >> +}; >> + >> +enum cvmx_pki_parse_mode_chg { >> + CVMX_PKI_PARSE_NO_CHG = 0x0, >> + CVMX_PKI_PARSE_SKIP_TO_LB = 0x1, >> + CVMX_PKI_PARSE_SKIP_TO_LC = 0x3, >> + CVMX_PKI_PARSE_SKIP_TO_LD = 0x7, >> + CVMX_PKI_PARSE_SKIP_TO_LG = 0x3f, >> + CVMX_PKI_PARSE_SKIP_ALL = 0x7f, >> +}; >> + >> +enum cvmx_pki_l2_len_mode { PKI_L2_LENCHK_EQUAL_GREATER = 0, >> PKI_L2_LENCHK_EQUAL_ONLY }; >> + >> +enum cvmx_pki_cache_mode { >> + CVMX_PKI_OPC_MODE_STT = 0LL, /* All blocks write through >> DRAM,*/ >> + CVMX_PKI_OPC_MODE_STF = 1LL, /* All blocks into L2 */ >> + CVMX_PKI_OPC_MODE_STF1_STT = 2LL, /* 1st block L2, rest DRAM */ >> + CVMX_PKI_OPC_MODE_STF2_STT = 3LL /* 1st, 2nd blocks L2, rest >> DRAM */ >> +}; >> + >> +/** >> + * Tag type definitions >> + */ >> +enum cvmx_sso_tag_type { >> + CVMX_SSO_TAG_TYPE_ORDERED = 0L, >> + CVMX_SSO_TAG_TYPE_ATOMIC = 1L, >> + CVMX_SSO_TAG_TYPE_UNTAGGED = 2L, >> + CVMX_SSO_TAG_TYPE_EMPTY = 3L >> +}; >> + >> +enum cvmx_pki_qpg_qos { >> + CVMX_PKI_QPG_QOS_NONE = 0, >> + CVMX_PKI_QPG_QOS_VLAN, >> + CVMX_PKI_QPG_QOS_MPLS, >> + CVMX_PKI_QPG_QOS_DSA_SRC, >> + CVMX_PKI_QPG_QOS_DIFFSERV, >> + CVMX_PKI_QPG_QOS_HIGIG, >> +}; >> + >> +enum cvmx_pki_wqe_vlan { CVMX_PKI_USE_FIRST_VLAN = 0, >> CVMX_PKI_USE_SECOND_VLAN }; >> + >> +/** >> + * Controls how the PKI statistics counters are handled >> + * The PKI_STAT*_X registers can be indexed either by port kind >> (pkind), or >> + * final style. (Does not apply to the PKI_STAT_INB* registers.) >> + * 0 = X represents the packet’s pkind >> + * 1 = X represents the low 6-bits of packet’s final style >> + */ >> +enum cvmx_pki_stats_mode { CVMX_PKI_STAT_MODE_PKIND, >> CVMX_PKI_STAT_MODE_STYLE }; >> + >> +enum cvmx_pki_fpa_wait { CVMX_PKI_DROP_PKT, CVMX_PKI_WAIT_PKT }; >> + >> +#define PKI_BELTYPE_E__NONE_M 0x0 >> +#define PKI_BELTYPE_E__MISC_M 0x1 >> +#define PKI_BELTYPE_E__IP4_M 0x2 >> +#define PKI_BELTYPE_E__IP6_M 0x3 >> +#define PKI_BELTYPE_E__TCP_M 0x4 >> +#define PKI_BELTYPE_E__UDP_M 0x5 >> +#define PKI_BELTYPE_E__SCTP_M 0x6 >> +#define PKI_BELTYPE_E__SNAP_M 0x7 >> + >> +/* PKI_BELTYPE_E_t */ >> +enum cvmx_pki_beltype { >> + CVMX_PKI_BELTYPE_NONE = PKI_BELTYPE_E__NONE_M, >> + CVMX_PKI_BELTYPE_MISC = PKI_BELTYPE_E__MISC_M, >> + CVMX_PKI_BELTYPE_IP4 = PKI_BELTYPE_E__IP4_M, >> + CVMX_PKI_BELTYPE_IP6 = PKI_BELTYPE_E__IP6_M, >> + CVMX_PKI_BELTYPE_TCP = PKI_BELTYPE_E__TCP_M, >> + CVMX_PKI_BELTYPE_UDP = PKI_BELTYPE_E__UDP_M, >> + CVMX_PKI_BELTYPE_SCTP = PKI_BELTYPE_E__SCTP_M, >> + CVMX_PKI_BELTYPE_SNAP = PKI_BELTYPE_E__SNAP_M, >> + CVMX_PKI_BELTYPE_MAX = CVMX_PKI_BELTYPE_SNAP >> +}; >> + >> +struct cvmx_pki_frame_len { >> + u16 maxlen; >> + u16 minlen; >> +}; >> + >> +struct cvmx_pki_tag_fields { >> + u64 layer_g_src : 1; >> + u64 layer_f_src : 1; >> + u64 layer_e_src : 1; >> + u64 layer_d_src : 1; >> + u64 layer_c_src : 1; >> + u64 layer_b_src : 1; >> + u64 layer_g_dst : 1; >> + u64 layer_f_dst : 1; >> + u64 layer_e_dst : 1; >> + u64 layer_d_dst : 1; >> + u64 layer_c_dst : 1; >> + u64 layer_b_dst : 1; >> + u64 input_port : 1; >> + u64 mpls_label : 1; >> + u64 first_vlan : 1; >> + u64 second_vlan : 1; >> + u64 ip_prot_nexthdr : 1; >> + u64 tag_sync : 1; >> + u64 tag_spi : 1; >> + u64 tag_gtp : 1; >> + u64 tag_vni : 1; >> +}; >> + >> +struct cvmx_pki_pkind_parse { >> + u64 mpls_en : 1; >> + u64 inst_hdr : 1; >> + u64 lg_custom : 1; >> + u64 fulc_en : 1; >> + u64 dsa_en : 1; >> + u64 hg2_en : 1; >> + u64 hg_en : 1; >> +}; >> + >> +struct cvmx_pki_pool_config { >> + int pool_num; >> + cvmx_fpa3_pool_t pool; >> + u64 buffer_size; >> + u64 buffer_count; >> +}; >> + >> +struct cvmx_pki_qpg_config { >> + int qpg_base; >> + int port_add; >> + int aura_num; >> + int grp_ok; >> + int grp_bad; >> + int grptag_ok; >> + int grptag_bad; >> +}; >> + >> +struct cvmx_pki_aura_config { >> + int aura_num; >> + int pool_num; >> + cvmx_fpa3_pool_t pool; >> + cvmx_fpa3_gaura_t aura; >> + int buffer_count; >> +}; >> + >> +struct cvmx_pki_cluster_grp_config { >> + int grp_num; >> + u64 cluster_mask; /* Bit mask of cluster assigned to this >> cluster group */ >> +}; >> + >> +struct cvmx_pki_sso_grp_config { >> + int group; >> + int priority; >> + int weight; >> + int affinity; >> + u64 core_mask; >> + u8 core_mask_set; >> +}; >> + >> +/* This is per style structure for configuring port parameters, >> + * it is kind of of profile which can be assigned to any port. >> + * If multiple ports are assigned same style be aware that modifying >> + * that style will modify the respective parameters for all the >> ports >> + * which are using this style >> + */ >> +struct cvmx_pki_style_parm { >> + bool ip6_udp_opt; >> + bool lenerr_en; >> + bool maxerr_en; >> + bool minerr_en; >> + u8 lenerr_eqpad; >> + u8 minmax_sel; >> + bool qpg_dis_grptag; >> + bool fcs_strip; >> + bool fcs_chk; >> + bool rawdrp; >> + bool force_drop; >> + bool nodrop; >> + bool qpg_dis_padd; >> + bool qpg_dis_grp; >> + bool qpg_dis_aura; >> + u16 qpg_base; >> + enum cvmx_pki_qpg_qos qpg_qos; >> + u8 qpg_port_sh; >> + u8 qpg_port_msb; >> + u8 apad_nip; >> + u8 wqe_vs; >> + enum cvmx_sso_tag_type tag_type; >> + bool pkt_lend; >> + u8 wqe_hsz; >> + u16 wqe_skip; >> + u16 first_skip; >> + u16 later_skip; >> + enum cvmx_pki_cache_mode cache_mode; >> + u8 dis_wq_dat; >> + u64 mbuff_size; >> + bool len_lg; >> + bool len_lf; >> + bool len_le; >> + bool len_ld; >> + bool len_lc; >> + bool len_lb; >> + bool csum_lg; >> + bool csum_lf; >> + bool csum_le; >> + bool csum_ld; >> + bool csum_lc; >> + bool csum_lb; >> +}; >> + >> +/* This is per style structure for configuring port's tag >> configuration, >> + * it is kind of of profile which can be assigned to any port. >> + * If multiple ports are assigned same style be aware that modiying >> that style >> + * will modify the respective parameters for all the ports which are >> + * using this style */ >> +enum cvmx_pki_mtag_ptrsel { >> + CVMX_PKI_MTAG_PTRSEL_SOP = 0, >> + CVMX_PKI_MTAG_PTRSEL_LA = 8, >> + CVMX_PKI_MTAG_PTRSEL_LB = 9, >> + CVMX_PKI_MTAG_PTRSEL_LC = 10, >> + CVMX_PKI_MTAG_PTRSEL_LD = 11, >> + CVMX_PKI_MTAG_PTRSEL_LE = 12, >> + CVMX_PKI_MTAG_PTRSEL_LF = 13, >> + CVMX_PKI_MTAG_PTRSEL_LG = 14, >> + CVMX_PKI_MTAG_PTRSEL_VL = 15, >> +}; >> + >> +struct cvmx_pki_mask_tag { >> + bool enable; >> + int base; /* CVMX_PKI_MTAG_PTRSEL_XXX */ >> + int offset; /* Offset from base. */ >> + u64 val; /* Bitmask: >> + 1 = enable, 0 = disabled for each byte in the 64-byte >> array.*/ >> +}; >> + >> +struct cvmx_pki_style_tag_cfg { >> + struct cvmx_pki_tag_fields tag_fields; >> + struct cvmx_pki_mask_tag mask_tag[4]; >> +}; >> + >> +struct cvmx_pki_style_config { >> + struct cvmx_pki_style_parm parm_cfg; >> + struct cvmx_pki_style_tag_cfg tag_cfg; >> +}; >> + >> +struct cvmx_pki_pkind_config { >> + u8 cluster_grp; >> + bool fcs_pres; >> + struct cvmx_pki_pkind_parse parse_en; >> + enum cvmx_pki_pkind_parse_mode initial_parse_mode; >> + u8 fcs_skip; >> + u8 inst_skip; >> + int initial_style; >> + bool custom_l2_hdr; >> + u8 l2_scan_offset; >> + u64 lg_scan_offset; >> +}; >> + >> +struct cvmx_pki_port_config { >> + struct cvmx_pki_pkind_config pkind_cfg; >> + struct cvmx_pki_style_config style_cfg; >> +}; >> + >> +struct cvmx_pki_global_parse { >> + u64 virt_pen : 1; >> + u64 clg_pen : 1; >> + u64 cl2_pen : 1; >> + u64 l4_pen : 1; >> + u64 il3_pen : 1; >> + u64 l3_pen : 1; >> + u64 mpls_pen : 1; >> + u64 fulc_pen : 1; >> + u64 dsa_pen : 1; >> + u64 hg_pen : 1; >> +}; >> + >> +struct cvmx_pki_tag_sec { >> + u16 dst6; >> + u16 src6; >> + u16 dst; >> + u16 src; >> +}; >> + >> +struct cvmx_pki_global_config { >> + u64 cluster_mask[CVMX_PKI_NUM_CLUSTER_GROUP_MAX]; >> + enum cvmx_pki_stats_mode stat_mode; >> + enum cvmx_pki_fpa_wait fpa_wait; >> + struct cvmx_pki_global_parse gbl_pen; >> + struct cvmx_pki_tag_sec tag_secret; >> + struct cvmx_pki_frame_len frm_len[CVMX_PKI_NUM_FRAME_CHECK]; >> + enum cvmx_pki_beltype ltype_map[CVMX_PKI_NUM_BELTYPE]; >> + int pki_enable; >> +}; >> + >> +#define CVMX_PKI_PCAM_TERM_E_NONE_M 0x0 >> +#define CVMX_PKI_PCAM_TERM_E_L2_CUSTOM_M 0x2 >> +#define CVMX_PKI_PCAM_TERM_E_HIGIGD_M 0x4 >> +#define CVMX_PKI_PCAM_TERM_E_HIGIG_M 0x5 >> +#define CVMX_PKI_PCAM_TERM_E_SMACH_M 0x8 >> +#define CVMX_PKI_PCAM_TERM_E_SMACL_M 0x9 >> +#define CVMX_PKI_PCAM_TERM_E_DMACH_M 0xA >> +#define CVMX_PKI_PCAM_TERM_E_DMACL_M 0xB >> +#define CVMX_PKI_PCAM_TERM_E_GLORT_M 0x12 >> +#define CVMX_PKI_PCAM_TERM_E_DSA_M 0x13 >> +#define CVMX_PKI_PCAM_TERM_E_ETHTYPE0_M 0x18 >> +#define CVMX_PKI_PCAM_TERM_E_ETHTYPE1_M 0x19 >> +#define CVMX_PKI_PCAM_TERM_E_ETHTYPE2_M 0x1A >> +#define CVMX_PKI_PCAM_TERM_E_ETHTYPE3_M 0x1B >> +#define CVMX_PKI_PCAM_TERM_E_MPLS0_M 0x1E >> +#define CVMX_PKI_PCAM_TERM_E_L3_SIPHH_M 0x1F >> +#define CVMX_PKI_PCAM_TERM_E_L3_SIPMH_M 0x20 >> +#define CVMX_PKI_PCAM_TERM_E_L3_SIPML_M 0x21 >> +#define CVMX_PKI_PCAM_TERM_E_L3_SIPLL_M 0x22 >> +#define CVMX_PKI_PCAM_TERM_E_L3_FLAGS_M 0x23 >> +#define CVMX_PKI_PCAM_TERM_E_L3_DIPHH_M 0x24 >> +#define CVMX_PKI_PCAM_TERM_E_L3_DIPMH_M 0x25 >> +#define CVMX_PKI_PCAM_TERM_E_L3_DIPML_M 0x26 >> +#define CVMX_PKI_PCAM_TERM_E_L3_DIPLL_M 0x27 >> +#define CVMX_PKI_PCAM_TERM_E_LD_VNI_M 0x28 >> +#define CVMX_PKI_PCAM_TERM_E_IL3_FLAGS_M 0x2B >> +#define CVMX_PKI_PCAM_TERM_E_LF_SPI_M 0x2E >> +#define CVMX_PKI_PCAM_TERM_E_L4_SPORT_M 0x2f >> +#define CVMX_PKI_PCAM_TERM_E_L4_PORT_M 0x30 >> +#define CVMX_PKI_PCAM_TERM_E_LG_CUSTOM_M 0x39 >> + >> +enum cvmx_pki_term { >> + CVMX_PKI_PCAM_TERM_NONE = CVMX_PKI_PCAM_TERM_E_NONE_M, >> + CVMX_PKI_PCAM_TERM_L2_CUSTOM = >> CVMX_PKI_PCAM_TERM_E_L2_CUSTOM_M, >> + CVMX_PKI_PCAM_TERM_HIGIGD = CVMX_PKI_PCAM_TERM_E_HIGIGD_M, >> + CVMX_PKI_PCAM_TERM_HIGIG = CVMX_PKI_PCAM_TERM_E_HIGIG_M, >> + CVMX_PKI_PCAM_TERM_SMACH = CVMX_PKI_PCAM_TERM_E_SMACH_M, >> + CVMX_PKI_PCAM_TERM_SMACL = CVMX_PKI_PCAM_TERM_E_SMACL_M, >> + CVMX_PKI_PCAM_TERM_DMACH = CVMX_PKI_PCAM_TERM_E_DMACH_M, >> + CVMX_PKI_PCAM_TERM_DMACL = CVMX_PKI_PCAM_TERM_E_DMACL_M, >> + CVMX_PKI_PCAM_TERM_GLORT = CVMX_PKI_PCAM_TERM_E_GLORT_M, >> + CVMX_PKI_PCAM_TERM_DSA = CVMX_PKI_PCAM_TERM_E_DSA_M, >> + CVMX_PKI_PCAM_TERM_ETHTYPE0 = CVMX_PKI_PCAM_TERM_E_ETHTYPE0_M, >> + CVMX_PKI_PCAM_TERM_ETHTYPE1 = CVMX_PKI_PCAM_TERM_E_ETHTYPE1_M, >> + CVMX_PKI_PCAM_TERM_ETHTYPE2 = CVMX_PKI_PCAM_TERM_E_ETHTYPE2_M, >> + CVMX_PKI_PCAM_TERM_ETHTYPE3 = CVMX_PKI_PCAM_TERM_E_ETHTYPE3_M, >> + CVMX_PKI_PCAM_TERM_MPLS0 = CVMX_PKI_PCAM_TERM_E_MPLS0_M, >> + CVMX_PKI_PCAM_TERM_L3_SIPHH = CVMX_PKI_PCAM_TERM_E_L3_SIPHH_M, >> + CVMX_PKI_PCAM_TERM_L3_SIPMH = CVMX_PKI_PCAM_TERM_E_L3_SIPMH_M, >> + CVMX_PKI_PCAM_TERM_L3_SIPML = CVMX_PKI_PCAM_TERM_E_L3_SIPML_M, >> + CVMX_PKI_PCAM_TERM_L3_SIPLL = CVMX_PKI_PCAM_TERM_E_L3_SIPLL_M, >> + CVMX_PKI_PCAM_TERM_L3_FLAGS = CVMX_PKI_PCAM_TERM_E_L3_FLAGS_M, >> + CVMX_PKI_PCAM_TERM_L3_DIPHH = CVMX_PKI_PCAM_TERM_E_L3_DIPHH_M, >> + CVMX_PKI_PCAM_TERM_L3_DIPMH = CVMX_PKI_PCAM_TERM_E_L3_DIPMH_M, >> + CVMX_PKI_PCAM_TERM_L3_DIPML = CVMX_PKI_PCAM_TERM_E_L3_DIPML_M, >> + CVMX_PKI_PCAM_TERM_L3_DIPLL = CVMX_PKI_PCAM_TERM_E_L3_DIPLL_M, >> + CVMX_PKI_PCAM_TERM_LD_VNI = CVMX_PKI_PCAM_TERM_E_LD_VNI_M, >> + CVMX_PKI_PCAM_TERM_IL3_FLAGS = >> CVMX_PKI_PCAM_TERM_E_IL3_FLAGS_M, >> + CVMX_PKI_PCAM_TERM_LF_SPI = CVMX_PKI_PCAM_TERM_E_LF_SPI_M, >> + CVMX_PKI_PCAM_TERM_L4_PORT = CVMX_PKI_PCAM_TERM_E_L4_PORT_M, >> + CVMX_PKI_PCAM_TERM_L4_SPORT = CVMX_PKI_PCAM_TERM_E_L4_SPORT_M, >> + CVMX_PKI_PCAM_TERM_LG_CUSTOM = CVMX_PKI_PCAM_TERM_E_LG_CUSTOM_M >> +}; >> + >> +#define CVMX_PKI_DMACH_SHIFT 32 >> +#define CVMX_PKI_DMACH_MASK cvmx_build_mask(16) >> +#define CVMX_PKI_DMACL_MASK CVMX_PKI_DATA_MASK_32 >> +#define CVMX_PKI_DATA_MASK_32 cvmx_build_mask(32) >> +#define CVMX_PKI_DATA_MASK_16 cvmx_build_mask(16) >> +#define CVMX_PKI_DMAC_MATCH_EXACT cvmx_build_mask(48) >> + >> +struct cvmx_pki_pcam_input { >> + u64 style; >> + u64 style_mask; /* bits: 1-match, 0-dont care */ >> + enum cvmx_pki_term field; >> + u32 field_mask; /* bits: 1-match, 0-dont care */ >> + u64 data; >> + u64 data_mask; /* bits: 1-match, 0-dont care */ >> +}; >> + >> +struct cvmx_pki_pcam_action { >> + enum cvmx_pki_parse_mode_chg parse_mode_chg; >> + enum cvmx_pki_layer_type layer_type_set; >> + int style_add; >> + int parse_flag_set; >> + int pointer_advance; >> +}; >> + >> +struct cvmx_pki_pcam_config { >> + int in_use; >> + int entry_num; >> + u64 cluster_mask; >> + struct cvmx_pki_pcam_input pcam_input; >> + struct cvmx_pki_pcam_action pcam_action; >> +}; >> + >> +/** >> + * Status statistics for a port >> + */ >> +struct cvmx_pki_port_stats { >> + u64 dropped_octets; >> + u64 dropped_packets; >> + u64 pci_raw_packets; >> + u64 octets; >> + u64 packets; >> + u64 multicast_packets; >> + u64 broadcast_packets; >> + u64 len_64_packets; >> + u64 len_65_127_packets; >> + u64 len_128_255_packets; >> + u64 len_256_511_packets; >> + u64 len_512_1023_packets; >> + u64 len_1024_1518_packets; >> + u64 len_1519_max_packets; >> + u64 fcs_align_err_packets; >> + u64 runt_packets; >> + u64 runt_crc_packets; >> + u64 oversize_packets; >> + u64 oversize_crc_packets; >> + u64 inb_packets; >> + u64 inb_octets; >> + u64 inb_errors; >> + u64 mcast_l2_red_packets; >> + u64 bcast_l2_red_packets; >> + u64 mcast_l3_red_packets; >> + u64 bcast_l3_red_packets; >> +}; >> + >> +/** >> + * PKI Packet Instruction Header Structure (PKI_INST_HDR_S) >> + */ >> +typedef union { >> + u64 u64; >> + struct { >> + u64 w : 1; /* INST_HDR size: 0 = 2 bytes, 1 = 4 or 8 >> bytes */ >> + u64 raw : 1; /* RAW packet indicator in WQE[RAW]: 1 = >> enable */ >> + u64 utag : 1; /* Use INST_HDR[TAG] to compute WQE[TAG]: >> 1 = enable */ >> + u64 uqpg : 1; /* Use INST_HDR[QPG] to compute QPG: 1 = >> enable */ >> + u64 rsvd1 : 1; >> + u64 pm : 3; /* Packet parsing mode. Legal values = >> 0x0..0x7 */ >> + u64 sl : 8; /* Number of bytes in INST_HDR. */ >> + /* The following fields are not present, if INST_HDR[W] >> = 0: */ >> + u64 utt : 1; /* Use INST_HDR[TT] to compute WQE[TT]: 1 >> = enable */ >> + u64 tt : 2; /* INST_HDR[TT] => WQE[TT], if >> INST_HDR[UTT] = 1 */ >> + u64 rsvd2 : 2; >> + u64 qpg : 11; /* INST_HDR[QPG] => QPG, if >> INST_HDR[UQPG] = 1 */ >> + u64 tag : 32; /* INST_HDR[TAG] => WQE[TAG], if >> INST_HDR[UTAG] = 1 */ >> + } s; >> +} cvmx_pki_inst_hdr_t; >> + >> +/** >> + * This function assignes the clusters to a group, later pkind can >> be >> + * configured to use that group depending on number of clusters >> pkind >> + * would use. A given cluster can only be enabled in a single >> cluster group. >> + * Number of clusters assign to that group determines how many >> engine can work >> + * in parallel to process the packet. Eack cluster can process x >> MPPS. >> + * >> + * @param node Node >> + * @param cluster_group Group to attach clusters to. >> + * @param cluster_mask The mask of clusters which needs to be >> assigned to the group. >> + */ >> +static inline int cvmx_pki_attach_cluster_to_group(int node, u64 >> cluster_group, u64 cluster_mask) >> +{ >> + cvmx_pki_icgx_cfg_t pki_cl_grp; >> + >> + if (cluster_group >= CVMX_PKI_NUM_CLUSTER_GROUP) { >> + debug("ERROR: config cluster group %d", >> (int)cluster_group); >> + return -1; >> + } >> + pki_cl_grp.u64 = cvmx_read_csr_node(node, >> CVMX_PKI_ICGX_CFG(cluster_group)); >> + pki_cl_grp.s.clusters = cluster_mask; >> + cvmx_write_csr_node(node, CVMX_PKI_ICGX_CFG(cluster_group), >> pki_cl_grp.u64); >> + return 0; >> +} >> + >> +static inline void cvmx_pki_write_global_parse(int node, struct >> cvmx_pki_global_parse gbl_pen) >> +{ >> + cvmx_pki_gbl_pen_t gbl_pen_reg; >> + >> + gbl_pen_reg.u64 = cvmx_read_csr_node(node, CVMX_PKI_GBL_PEN); >> + gbl_pen_reg.s.virt_pen = gbl_pen.virt_pen; >> + gbl_pen_reg.s.clg_pen = gbl_pen.clg_pen; >> + gbl_pen_reg.s.cl2_pen = gbl_pen.cl2_pen; >> + gbl_pen_reg.s.l4_pen = gbl_pen.l4_pen; >> + gbl_pen_reg.s.il3_pen = gbl_pen.il3_pen; >> + gbl_pen_reg.s.l3_pen = gbl_pen.l3_pen; >> + gbl_pen_reg.s.mpls_pen = gbl_pen.mpls_pen; >> + gbl_pen_reg.s.fulc_pen = gbl_pen.fulc_pen; >> + gbl_pen_reg.s.dsa_pen = gbl_pen.dsa_pen; >> + gbl_pen_reg.s.hg_pen = gbl_pen.hg_pen; >> + cvmx_write_csr_node(node, CVMX_PKI_GBL_PEN, gbl_pen_reg.u64); >> +} >> + >> +static inline void cvmx_pki_write_tag_secret(int node, struct >> cvmx_pki_tag_sec tag_secret) >> +{ >> + cvmx_pki_tag_secret_t tag_secret_reg; >> + >> + tag_secret_reg.u64 = cvmx_read_csr_node(node, >> CVMX_PKI_TAG_SECRET); >> + tag_secret_reg.s.dst6 = tag_secret.dst6; >> + tag_secret_reg.s.src6 = tag_secret.src6; >> + tag_secret_reg.s.dst = tag_secret.dst; >> + tag_secret_reg.s.src = tag_secret.src; >> + cvmx_write_csr_node(node, CVMX_PKI_TAG_SECRET, >> tag_secret_reg.u64); >> +} >> + >> +static inline void cvmx_pki_write_ltype_map(int node, enum >> cvmx_pki_layer_type layer, >> + enum cvmx_pki_beltype >> backend) >> +{ >> + cvmx_pki_ltypex_map_t ltype_map; >> + >> + if (layer > CVMX_PKI_LTYPE_E_MAX || backend > >> CVMX_PKI_BELTYPE_MAX) { >> + debug("ERROR: invalid ltype beltype mapping\n"); >> + return; >> + } >> + ltype_map.u64 = cvmx_read_csr_node(node, >> CVMX_PKI_LTYPEX_MAP(layer)); >> + ltype_map.s.beltype = backend; >> + cvmx_write_csr_node(node, CVMX_PKI_LTYPEX_MAP(layer), >> ltype_map.u64); >> +} >> + >> +/** >> + * This function enables the cluster group to start parsing. >> + * >> + * @param node Node number. >> + * @param cl_grp Cluster group to enable parsing. >> + */ >> +static inline int cvmx_pki_parse_enable(int node, unsigned int >> cl_grp) >> +{ >> + cvmx_pki_icgx_cfg_t pki_cl_grp; >> + >> + if (cl_grp >= CVMX_PKI_NUM_CLUSTER_GROUP) { >> + debug("ERROR: pki parse en group %d", (int)cl_grp); >> + return -1; >> + } >> + pki_cl_grp.u64 = cvmx_read_csr_node(node, >> CVMX_PKI_ICGX_CFG(cl_grp)); >> + pki_cl_grp.s.pena = 1; >> + cvmx_write_csr_node(node, CVMX_PKI_ICGX_CFG(cl_grp), >> pki_cl_grp.u64); >> + return 0; >> +} >> + >> +/** >> + * This function enables the PKI to send bpid level backpressure to >> CN78XX inputs. >> + * >> + * @param node Node number. >> + */ >> +static inline void cvmx_pki_enable_backpressure(int node) >> +{ >> + cvmx_pki_buf_ctl_t pki_buf_ctl; >> + >> + pki_buf_ctl.u64 = cvmx_read_csr_node(node, CVMX_PKI_BUF_CTL); >> + pki_buf_ctl.s.pbp_en = 1; >> + cvmx_write_csr_node(node, CVMX_PKI_BUF_CTL, pki_buf_ctl.u64); >> +} >> + >> +/** >> + * Clear the statistics counters for a port. >> + * >> + * @param node Node number. >> + * @param port Port number (ipd_port) to get statistics for. >> + * Make sure PKI_STATS_CTL:mode is set to 0 for collecting per >> port/pkind stats. >> + */ >> +void cvmx_pki_clear_port_stats(int node, u64 port); >> + >> +/** >> + * Get the status counters for index from PKI. >> + * >> + * @param node Node number. >> + * @param index PKIND number, if PKI_STATS_CTL:mode = 0 or >> + * style(flow) number, if PKI_STATS_CTL:mode = 1 >> + * @param status Where to put the results. >> + */ >> +void cvmx_pki_get_stats(int node, int index, struct >> cvmx_pki_port_stats *status); >> + >> +/** >> + * Get the statistics counters for a port. >> + * >> + * @param node Node number >> + * @param port Port number (ipd_port) to get statistics for. >> + * Make sure PKI_STATS_CTL:mode is set to 0 for collecting per >> port/pkind stats. >> + * @param status Where to put the results. >> + */ >> +static inline void cvmx_pki_get_port_stats(int node, u64 port, >> struct cvmx_pki_port_stats *status) >> +{ >> + int xipd = cvmx_helper_node_to_ipd_port(node, port); >> + int xiface = cvmx_helper_get_interface_num(xipd); >> + int index = cvmx_helper_get_interface_index_num(port); >> + int pknd = cvmx_helper_get_pknd(xiface, index); >> + >> + cvmx_pki_get_stats(node, pknd, status); >> +} >> + >> +/** >> + * Get the statistics counters for a flow represented by style in >> PKI. >> + * >> + * @param node Node number. >> + * @param style_num Style number to get statistics for. >> + * Make sure PKI_STATS_CTL:mode is set to 1 for collecting per >> style/flow stats. >> + * @param status Where to put the results. >> + */ >> +static inline void cvmx_pki_get_flow_stats(int node, u64 style_num, >> + struct cvmx_pki_port_stats >> *status) >> +{ >> + cvmx_pki_get_stats(node, style_num, status); >> +} >> + >> +/** >> + * Show integrated PKI configuration. >> + * >> + * @param node node number >> + */ >> +int cvmx_pki_config_dump(unsigned int node); >> + >> +/** >> + * Show integrated PKI statistics. >> + * >> + * @param node node number >> + */ >> +int cvmx_pki_stats_dump(unsigned int node); >> + >> +/** >> + * Clear PKI statistics. >> + * >> + * @param node node number >> + */ >> +void cvmx_pki_stats_clear(unsigned int node); >> + >> +/** >> + * This function enables PKI. >> + * >> + * @param node node to enable pki in. >> + */ >> +void cvmx_pki_enable(int node); >> + >> +/** >> + * This function disables PKI. >> + * >> + * @param node node to disable pki in. >> + */ >> +void cvmx_pki_disable(int node); >> + >> +/** >> + * This function soft resets PKI. >> + * >> + * @param node node to enable pki in. >> + */ >> +void cvmx_pki_reset(int node); >> + >> +/** >> + * This function sets the clusters in PKI. >> + * >> + * @param node node to set clusters in. >> + */ >> +int cvmx_pki_setup_clusters(int node); >> + >> +/** >> + * This function reads global configuration of PKI block. >> + * >> + * @param node Node number. >> + * @param gbl_cfg Pointer to struct to read global configuration >> + */ >> +void cvmx_pki_read_global_config(int node, struct >> cvmx_pki_global_config *gbl_cfg); >> + >> +/** >> + * This function writes global configuration of PKI into hw. >> + * >> + * @param node Node number. >> + * @param gbl_cfg Pointer to struct to global configuration >> + */ >> +void cvmx_pki_write_global_config(int node, struct >> cvmx_pki_global_config *gbl_cfg); >> + >> +/** >> + * This function reads per pkind parameters in hardware which >> defines how >> + * the incoming packet is processed. >> + * >> + * @param node Node number. >> + * @param pkind PKI supports a large number of incoming interfaces >> and packets >> + * arriving on different interfaces or channels may want to be >> processed >> + * differently. PKI uses the pkind to determine how the incoming >> packet >> + * is processed. >> + * @param pkind_cfg Pointer to struct conatining pkind >> configuration read >> + * from hardware. >> + */ >> +int cvmx_pki_read_pkind_config(int node, int pkind, struct >> cvmx_pki_pkind_config *pkind_cfg); >> + >> +/** >> + * This function writes per pkind parameters in hardware which >> defines how >> + * the incoming packet is processed. >> + * >> + * @param node Node number. >> + * @param pkind PKI supports a large number of incoming interfaces >> and packets >> + * arriving on different interfaces or channels may want to be >> processed >> + * differently. PKI uses the pkind to determine how the incoming >> packet >> + * is processed. >> + * @param pkind_cfg Pointer to struct conatining pkind >> configuration need >> + * to be written in hardware. >> + */ >> +int cvmx_pki_write_pkind_config(int node, int pkind, struct >> cvmx_pki_pkind_config *pkind_cfg); >> + >> +/** >> + * This function reads parameters associated with tag configuration >> in hardware. >> + * >> + * @param node Node number. >> + * @param style Style to configure tag for. >> + * @param cluster_mask Mask of clusters to configure the style for. >> + * @param tag_cfg Pointer to tag configuration struct. >> + */ >> +void cvmx_pki_read_tag_config(int node, int style, u64 cluster_mask, >> + struct cvmx_pki_style_tag_cfg *tag_cfg); >> + >> +/** >> + * This function writes/configures parameters associated with tag >> + * configuration in hardware. >> + * >> + * @param node Node number. >> + * @param style Style to configure tag for. >> + * @param cluster_mask Mask of clusters to configure the style for. >> + * @param tag_cfg Pointer to taf configuration struct. >> + */ >> +void cvmx_pki_write_tag_config(int node, int style, u64 >> cluster_mask, >> + struct cvmx_pki_style_tag_cfg *tag_cfg); >> + >> +/** >> + * This function reads parameters associated with style in hardware. >> + * >> + * @param node Node number. >> + * @param style Style to read from. >> + * @param cluster_mask Mask of clusters style belongs to. >> + * @param style_cfg Pointer to style config struct. >> + */ >> +void cvmx_pki_read_style_config(int node, int style, u64 >> cluster_mask, >> + struct cvmx_pki_style_config >> *style_cfg); >> + >> +/** >> + * This function writes/configures parameters associated with style >> in hardware. >> + * >> + * @param node Node number. >> + * @param style Style to configure. >> + * @param cluster_mask Mask of clusters to configure the style for. >> + * @param style_cfg Pointer to style config struct. >> + */ >> +void cvmx_pki_write_style_config(int node, u64 style, u64 >> cluster_mask, >> + struct cvmx_pki_style_config >> *style_cfg); >> +/** >> + * This function reads qpg entry at specified offset from qpg table >> + * >> + * @param node Node number. >> + * @param offset Offset in qpg table to read from. >> + * @param qpg_cfg Pointer to structure containing qpg values >> + */ >> +int cvmx_pki_read_qpg_entry(int node, int offset, struct >> cvmx_pki_qpg_config *qpg_cfg); >> + >> +/** >> + * This function writes qpg entry at specified offset in qpg table >> + * >> + * @param node Node number. >> + * @param offset Offset in qpg table to write to. >> + * @param qpg_cfg Pointer to stricture containing qpg values. >> + */ >> +void cvmx_pki_write_qpg_entry(int node, int offset, struct >> cvmx_pki_qpg_config *qpg_cfg); >> + >> +/** >> + * This function writes pcam entry at given offset in pcam table in >> hardware >> + * >> + * @param node Node number. >> + * @param index Offset in pcam table. >> + * @param cluster_mask Mask of clusters in which to write pcam >> entry. >> + * @param input Input keys to pcam match passed as struct. >> + * @param action PCAM match action passed as struct >> + */ >> +int cvmx_pki_pcam_write_entry(int node, int index, u64 cluster_mask, >> + struct cvmx_pki_pcam_input input, struct >> cvmx_pki_pcam_action action); >> +/** >> + * Configures the channel which will receive backpressure from the >> specified bpid. >> + * Each channel listens for backpressure on a specific bpid. >> + * Each bpid can backpressure multiple channels. >> + * @param node Node number. >> + * @param bpid BPID from which channel will receive backpressure. >> + * @param channel Channel number to receive backpressue. >> + */ >> +int cvmx_pki_write_channel_bpid(int node, int channel, int bpid); >> + >> +/** >> + * Configures the bpid on which, specified channel will >> + * assert backpressure. >> + * Each bpid receives backpressure from auras. >> + * Multiple auras can backpressure single bpid. >> + * @param node Node number. >> + * @param aura Number which will assert backpressure on that bpid. >> + * @param bpid To assert backpressure on. >> + */ >> +int cvmx_pki_write_aura_bpid(int node, int aura, int bpid); >> + >> +/** >> + * Enables/Disabled QoS (RED Drop, Tail Drop & backpressure) for >> the* PKI aura. >> + * >> + * @param node Node number >> + * @param aura To enable/disable QoS on. >> + * @param ena_red Enable/Disable RED drop between pass and drop >> level >> + * 1-enable 0-disable >> + * @param ena_drop Enable/disable tail drop when max drop level >> exceeds >> + * 1-enable 0-disable >> + * @param ena_bp Enable/Disable asserting backpressure on bpid when >> + * max DROP level exceeds. >> + * 1-enable 0-disable >> + */ >> +int cvmx_pki_enable_aura_qos(int node, int aura, bool ena_red, bool >> ena_drop, bool ena_bp); >> + >> +/** >> + * This function gives the initial style used by that pkind. >> + * >> + * @param node Node number. >> + * @param pkind PKIND number. >> + */ >> +int cvmx_pki_get_pkind_style(int node, int pkind); >> + >> +/** >> + * This function sets the wqe buffer mode. First packet data buffer >> can reside >> + * either in same buffer as wqe OR it can go in separate buffer. If >> used the later mode, >> + * make sure software allocate enough buffers to now have wqe >> separate from packet data. >> + * >> + * @param node Node number. >> + * @param style Style to configure. >> + * @param pkt_outside_wqe >> + * 0 = The packet link pointer will be at word [FIRST_SKIP] >> immediately >> + * followed by packet data, in the same buffer as the work queue >> entry. >> + * 1 = The packet link pointer will be at word [FIRST_SKIP] in a >> new >> + * buffer separate from the work queue entry. Words following the >> + * WQE in the same cache line will be zeroed, other lines in the >> + * buffer will not be modified and will retain stale data (from >> the >> + * buffer’s previous use). This setting may decrease the peak PKI >> + * performance by up to half on small packets. >> + */ >> +void cvmx_pki_set_wqe_mode(int node, u64 style, bool >> pkt_outside_wqe); >> + >> +/** >> + * This function sets the Packet mode of all ports and styles to >> little-endian. >> + * It Changes write operations of packet data to L2C to >> + * be in little-endian. Does not change the WQE header format, which >> is >> + * properly endian neutral. >> + * >> + * @param node Node number. >> + * @param style Style to configure. >> + */ >> +void cvmx_pki_set_little_endian(int node, u64 style); >> + >> +/** >> + * Enables/Disables L2 length error check and max & min frame length >> checks. >> + * >> + * @param node Node number. >> + * @param pknd PKIND to disable error for. >> + * @param l2len_err L2 length error check enable. >> + * @param maxframe_err Max frame error check enable. >> + * @param minframe_err Min frame error check enable. >> + * 1 -- Enabel err checks >> + * 0 -- Disable error checks >> + */ >> +void cvmx_pki_endis_l2_errs(int node, int pknd, bool l2len_err, bool >> maxframe_err, >> + bool minframe_err); >> + >> +/** >> + * Enables/Disables fcs check and fcs stripping on the pkind. >> + * >> + * @param node Node number. >> + * @param pknd PKIND to apply settings on. >> + * @param fcs_chk Enable/disable fcs check. >> + * 1 -- enable fcs error check. >> + * 0 -- disable fcs error check. >> + * @param fcs_strip Strip L2 FCS bytes from packet, decrease >> WQE[LEN] by 4 bytes >> + * 1 -- strip L2 FCS. >> + * 0 -- Do not strip L2 FCS. >> + */ >> +void cvmx_pki_endis_fcs_check(int node, int pknd, bool fcs_chk, bool >> fcs_strip); >> + >> +/** >> + * This function shows the qpg table entries, read directly from >> hardware. >> + * >> + * @param node Node number. >> + * @param num_entry Number of entries to print. >> + */ >> +void cvmx_pki_show_qpg_entries(int node, u16 num_entry); >> + >> +/** >> + * This function shows the pcam table in raw format read directly >> from hardware. >> + * >> + * @param node Node number. >> + */ >> +void cvmx_pki_show_pcam_entries(int node); >> + >> +/** >> + * This function shows the valid entries in readable format, >> + * read directly from hardware. >> + * >> + * @param node Node number. >> + */ >> +void cvmx_pki_show_valid_pcam_entries(int node); >> + >> +/** >> + * This function shows the pkind attributes in readable format, >> + * read directly from hardware. >> + * @param node Node number. >> + * @param pkind PKIND number to print. >> + */ >> +void cvmx_pki_show_pkind_attributes(int node, int pkind); >> + >> +/** >> + * @INTERNAL >> + * This function is called by cvmx_helper_shutdown() to extract all >> FPA buffers >> + * out of the PKI. After this function completes, all FPA buffers >> that were >> + * prefetched by PKI will be in the appropriate FPA pool. >> + * This functions does not reset the PKI. >> + * WARNING: It is very important that PKI be reset soon after a call >> to this function. >> + * >> + * @param node Node number. >> + */ >> +void __cvmx_pki_free_ptr(int node); >> + >> +#endif >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pko-internal- >> ports-range.h b/arch/mips/mach-octeon/include/mach/cvmx-pko-internal- >> ports-range.h >> new file mode 100644 >> index 000000000000..1fb49b3fb6de >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-pko-internal-ports- >> range.h >> @@ -0,0 +1,43 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + */ >> + >> +#ifndef __CVMX_INTERNAL_PORTS_RANGE__ >> +#define __CVMX_INTERNAL_PORTS_RANGE__ >> + >> +/* >> + * Allocated a block of internal ports for the specified >> interface/port >> + * >> + * @param interface the interface for which the internal ports are >> requested >> + * @param port the index of the port within in the interface >> for which the internal ports >> + * are requested. >> + * @param count the number of internal ports requested >> + * >> + * @return 0 on success >> + * -1 on failure >> + */ >> +int cvmx_pko_internal_ports_alloc(int interface, int port, u64 >> count); >> + >> +/* >> + * Free the internal ports associated with the specified >> interface/port >> + * >> + * @param interface the interface for which the internal ports are >> requested >> + * @param port the index of the port within in the interface >> for which the internal ports >> + * are requested. >> + * >> + * @return 0 on success >> + * -1 on failure >> + */ >> +int cvmx_pko_internal_ports_free(int interface, int port); >> + >> +/* >> + * Frees up all the allocated internal ports. >> + */ >> +void cvmx_pko_internal_ports_range_free_all(void); >> + >> +void cvmx_pko_internal_ports_range_show(void); >> + >> +int __cvmx_pko_internal_ports_range_init(void); >> + >> +#endif >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pko3-queue.h >> b/arch/mips/mach-octeon/include/mach/cvmx-pko3-queue.h >> new file mode 100644 >> index 000000000000..5f8398904953 >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-pko3-queue.h >> @@ -0,0 +1,175 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + */ >> + >> +#ifndef __CVMX_PKO3_QUEUE_H__ >> +#define __CVMX_PKO3_QUEUE_H__ >> + >> +/** >> + * @INTERNAL >> + * >> + * Find or allocate global port/dq map table >> + * which is a named table, contains entries for >> + * all possible OCI nodes. >> + * >> + * The table global pointer is stored in core-local variable >> + * so that every core will call this function once, on first use. >> + */ >> +int __cvmx_pko3_dq_table_setup(void); >> + >> +/* >> + * Get the base Descriptor Queue number for an IPD port on the local >> node >> + */ >> +int cvmx_pko3_get_queue_base(int ipd_port); >> + >> +/* >> + * Get the number of Descriptor Queues assigned for an IPD port >> + */ >> +int cvmx_pko3_get_queue_num(int ipd_port); >> + >> +/** >> + * Get L1/Port Queue number assigned to interface port. >> + * >> + * @param xiface is interface number. >> + * @param index is port index. >> + */ >> +int cvmx_pko3_get_port_queue(int xiface, int index); >> + >> +/* >> + * Configure L3 through L5 Scheduler Queues and Descriptor Queues >> + * >> + * The Scheduler Queues in Levels 3 to 5 and Descriptor Queues are >> + * configured one-to-one or many-to-one to a single parent Scheduler >> + * Queues. The level of the parent SQ is specified in an argument, >> + * as well as the number of children to attach to the specific >> parent. >> + * The children can have fair round-robin or priority-based >> scheduling >> + * when multiple children are assigned a single parent. >> + * >> + * @param node is the OCI node location for the queues to be >> configured >> + * @param parent_level is the level of the parent queue, 2 to 5. >> + * @param parent_queue is the number of the parent Scheduler Queue >> + * @param child_base is the number of the first child SQ or DQ to >> assign to >> + * @param parent >> + * @param child_count is the number of consecutive children to >> assign >> + * @param stat_prio_count is the priority setting for the children >> L2 SQs >> + * >> + * If <stat_prio_count> is -1, the Ln children will have equal >> Round-Robin >> + * relationship with eachother. If <stat_prio_count> is 0, all Ln >> children >> + * will be arranged in Weighted-Round-Robin, with the first having >> the most >> + * precedence. If <stat_prio_count> is between 1 and 8, it indicates >> how >> + * many children will have static priority settings (with the first >> having >> + * the most precedence), with the remaining Ln children having WRR >> scheduling. >> + * >> + * @returns 0 on success, -1 on failure. >> + * >> + * Note: this function supports the configuration of node-local >> unit. >> + */ >> +int cvmx_pko3_sq_config_children(unsigned int node, unsigned int >> parent_level, >> + unsigned int parent_queue, unsigned >> int child_base, >> + unsigned int child_count, int >> stat_prio_count); >> + >> +/* >> + * @INTERNAL >> + * Register a range of Descriptor Queues wth an interface port >> + * >> + * This function poulates the DQ-to-IPD translation table >> + * used by the application to retrieve the DQ range (typically >> ordered >> + * by priority) for a given IPD-port, which is either a physical >> port, >> + * or a channel on a channelized interface (i.e. ILK). >> + * >> + * @param xiface is the physical interface number >> + * @param index is either a physical port on an interface >> + * @param or a channel of an ILK interface >> + * @param dq_base is the first Descriptor Queue number in a >> consecutive range >> + * @param dq_count is the number of consecutive Descriptor Queues >> leading >> + * @param the same channel or port. >> + * >> + * Only a consecurive range of Descriptor Queues can be associated >> with any >> + * given channel/port, and usually they are ordered from most to >> least >> + * in terms of scheduling priority. >> + * >> + * Note: thus function only populates the node-local translation >> table. >> + * >> + * @returns 0 on success, -1 on failure. >> + */ >> +int __cvmx_pko3_ipd_dq_register(int xiface, int index, unsigned int >> dq_base, unsigned int dq_count); >> + >> +/** >> + * @INTERNAL >> + * >> + * Unregister DQs associated with CHAN_E (IPD port) >> + */ >> +int __cvmx_pko3_ipd_dq_unregister(int xiface, int index); >> + >> +/* >> + * Map channel number in PKO >> + * >> + * @param node is to specify the node to which this configuration is >> applied. >> + * @param pq_num specifies the Port Queue (i.e. L1) queue number. >> + * @param l2_l3_q_num specifies L2/L3 queue number. >> + * @param channel specifies the channel number to map to the queue. >> + * >> + * The channel assignment applies to L2 or L3 Shaper Queues >> depending >> + * on the setting of channel credit level. >> + * >> + * @return returns none. >> + */ >> +void cvmx_pko3_map_channel(unsigned int node, unsigned int pq_num, >> unsigned int l2_l3_q_num, >> + u16 channel); >> + >> +int cvmx_pko3_pq_config(unsigned int node, unsigned int mac_num, >> unsigned int pq_num); >> + >> +int cvmx_pko3_port_cir_set(unsigned int node, unsigned int pq_num, >> unsigned long rate_kbips, >> + unsigned int burst_bytes, int adj_bytes); >> +int cvmx_pko3_dq_cir_set(unsigned int node, unsigned int pq_num, >> unsigned long rate_kbips, >> + unsigned int burst_bytes); >> +int cvmx_pko3_dq_pir_set(unsigned int node, unsigned int pq_num, >> unsigned long rate_kbips, >> + unsigned int burst_bytes); >> +typedef enum { >> + CVMX_PKO3_SHAPE_RED_STALL, >> + CVMX_PKO3_SHAPE_RED_DISCARD, >> + CVMX_PKO3_SHAPE_RED_PASS >> +} red_action_t; >> + >> +void cvmx_pko3_dq_red(unsigned int node, unsigned int dq_num, >> red_action_t red_act, >> + int8_t len_adjust); >> + >> +/** >> + * Macros to deal with short floating point numbers, >> + * where unsigned exponent, and an unsigned normalized >> + * mantissa are represented each with a defined field width. >> + * >> + */ >> +#define CVMX_SHOFT_MANT_BITS 8 >> +#define CVMX_SHOFT_EXP_BITS 4 >> + >> +/** >> + * Convert short-float to an unsigned integer >> + * Note that it will lose precision. >> + */ >> +#define CVMX_SHOFT_TO_U64(m, >> e) >> \ >> + ((((1ull << CVMX_SHOFT_MANT_BITS) | (m)) << (e)) >> >> CVMX_SHOFT_MANT_BITS) >> + >> +/** >> + * Convert to short-float from an unsigned integer >> + */ >> +#define CVMX_SHOFT_FROM_U64(ui, m, >> e) \ >> + do >> { >> \ >> + unsigned long long >> u; \ >> + unsigned int >> k; >> \ >> + k = (1ull << (CVMX_SHOFT_MANT_BITS + 1)) - >> 1; \ >> + (e) = >> 0; >> \ >> + u = (ui) << >> CVMX_SHOFT_MANT_BITS; >> \ >> + while ((u) > k) >> { \ >> + u >>= >> 1; >> \ >> + (e)++; >> \ >> + } >> \ >> + (m) = u & (k >> >> 1); \ >> + } while (0); >> + >> +#define >> CVMX_SHOFT_MAX() >> \ >> + CVMX_SHOFT_TO_U64((1 << CVMX_SHOFT_MANT_BITS) - 1, (1 << >> CVMX_SHOFT_EXP_BITS) - 1) >> +#define CVMX_SHOFT_MIN() CVMX_SHOFT_TO_U64(0, 0) >> + >> +#endif /* __CVMX_PKO3_QUEUE_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pow.h >> b/arch/mips/mach-octeon/include/mach/cvmx-pow.h >> new file mode 100644 >> index 000000000000..0680ca258f12 >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-pow.h >> @@ -0,0 +1,2991 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * Interface to the hardware Scheduling unit. >> + * >> + * New, starting with SDK 1.7.0, cvmx-pow supports a number of >> + * extended consistency checks. The define >> + * CVMX_ENABLE_POW_CHECKS controls the runtime insertion of POW >> + * internal state checks to find common programming errors. If >> + * CVMX_ENABLE_POW_CHECKS is not defined, checks are by default >> + * enabled. For example, cvmx-pow will check for the following >> + * program errors or POW state inconsistency. >> + * - Requesting a POW operation with an active tag switch in >> + * progress. >> + * - Waiting for a tag switch to complete for an excessively >> + * long period. This is normally a sign of an error in locking >> + * causing deadlock. >> + * - Illegal tag switches from NULL_NULL. >> + * - Illegal tag switches from NULL. >> + * - Illegal deschedule request. >> + * - WQE pointer not matching the one attached to the core by >> + * the POW. >> + */ >> + >> +#ifndef __CVMX_POW_H__ >> +#define __CVMX_POW_H__ >> + >> +#include "cvmx-wqe.h" >> +#include "cvmx-pow-defs.h" >> +#include "cvmx-sso-defs.h" >> +#include "cvmx-address.h" >> +#include "cvmx-coremask.h" >> + >> +/* Default to having all POW constancy checks turned on */ >> +#ifndef CVMX_ENABLE_POW_CHECKS >> +#define CVMX_ENABLE_POW_CHECKS 1 >> +#endif >> + >> +/* >> + * Special type for CN78XX style SSO groups (0..255), >> + * for distinction from legacy-style groups (0..15) >> + */ >> +typedef union { >> + u8 xgrp; >> + /* Fields that map XGRP for backwards compatibility */ >> + struct __attribute__((__packed__)) { >> + u8 group : 5; >> + u8 qus : 3; >> + }; >> +} cvmx_xgrp_t; >> + >> +/* >> + * Softwsare-only structure to convey a return value >> + * containing multiple information fields about an work queue entry >> + */ >> +typedef struct { >> + u32 tag; >> + u16 index; >> + u8 grp; /* Legacy group # (0..15) */ >> + u8 tag_type; >> +} cvmx_pow_tag_info_t; >> + >> +/** >> + * Wait flag values for pow functions. >> + */ >> +typedef enum { >> + CVMX_POW_WAIT = 1, >> + CVMX_POW_NO_WAIT = 0, >> +} cvmx_pow_wait_t; >> + >> +/** >> + * POW tag operations. These are used in the data stored to the >> POW. >> + */ >> +typedef enum { >> + CVMX_POW_TAG_OP_SWTAG = 0L, >> + CVMX_POW_TAG_OP_SWTAG_FULL = 1L, >> + CVMX_POW_TAG_OP_SWTAG_DESCH = 2L, >> + CVMX_POW_TAG_OP_DESCH = 3L, >> + CVMX_POW_TAG_OP_ADDWQ = 4L, >> + CVMX_POW_TAG_OP_UPDATE_WQP_GRP = 5L, >> + CVMX_POW_TAG_OP_SET_NSCHED = 6L, >> + CVMX_POW_TAG_OP_CLR_NSCHED = 7L, >> + CVMX_POW_TAG_OP_NOP = 15L >> +} cvmx_pow_tag_op_t; >> + >> +/** >> + * This structure defines the store data on a store to POW >> + */ >> +typedef union { >> + u64 u64; >> + struct { >> + u64 no_sched : 1; >> + u64 unused : 2; >> + u64 index : 13; >> + cvmx_pow_tag_op_t op : 4; >> + u64 unused2 : 2; >> + u64 qos : 3; >> + u64 grp : 4; >> + cvmx_pow_tag_type_t type : 3; >> + u64 tag : 32; >> + } s_cn38xx; >> + struct { >> + u64 no_sched : 1; >> + cvmx_pow_tag_op_t op : 4; >> + u64 unused1 : 4; >> + u64 index : 11; >> + u64 unused2 : 1; >> + u64 grp : 6; >> + u64 unused3 : 3; >> + cvmx_pow_tag_type_t type : 2; >> + u64 tag : 32; >> + } s_cn68xx_clr; >> + struct { >> + u64 no_sched : 1; >> + cvmx_pow_tag_op_t op : 4; >> + u64 unused1 : 12; >> + u64 qos : 3; >> + u64 unused2 : 1; >> + u64 grp : 6; >> + u64 unused3 : 3; >> + cvmx_pow_tag_type_t type : 2; >> + u64 tag : 32; >> + } s_cn68xx_add; >> + struct { >> + u64 no_sched : 1; >> + cvmx_pow_tag_op_t op : 4; >> + u64 unused1 : 16; >> + u64 grp : 6; >> + u64 unused3 : 3; >> + cvmx_pow_tag_type_t type : 2; >> + u64 tag : 32; >> + } s_cn68xx_other; >> + struct { >> + u64 rsvd_62_63 : 2; >> + u64 grp : 10; >> + cvmx_pow_tag_type_t type : 2; >> + u64 no_sched : 1; >> + u64 rsvd_48 : 1; >> + cvmx_pow_tag_op_t op : 4; >> + u64 rsvd_42_43 : 2; >> + u64 wqp : 42; >> + } s_cn78xx_other; >> + >> +} cvmx_pow_tag_req_t; >> + >> +union cvmx_pow_tag_req_addr { >> + u64 u64; >> + struct { >> + u64 mem_region : 2; >> + u64 reserved_49_61 : 13; >> + u64 is_io : 1; >> + u64 did : 8; >> + u64 addr : 40; >> + } s; >> + struct { >> + u64 mem_region : 2; >> + u64 reserved_49_61 : 13; >> + u64 is_io : 1; >> + u64 did : 8; >> + u64 node : 4; >> + u64 tag : 32; >> + u64 reserved_0_3 : 4; >> + } s_cn78xx; >> +}; >> + >> +/** >> + * This structure describes the address to load stuff from POW >> + */ >> +typedef union { >> + u64 u64; >> + /** >> + * Address for new work request loads (did<2:0> == 0) >> + */ >> + struct { >> + u64 mem_region : 2; >> + u64 reserved_49_61 : 13; >> + u64 is_io : 1; >> + u64 did : 8; >> + u64 reserved_4_39 : 36; >> + u64 wait : 1; >> + u64 reserved_0_2 : 3; >> + } swork; >> + struct { >> + u64 mem_region : 2; >> + u64 reserved_49_61 : 13; >> + u64 is_io : 1; >> + u64 did : 8; >> + u64 node : 4; >> + u64 reserved_32_35 : 4; >> + u64 indexed : 1; >> + u64 grouped : 1; >> + u64 rtngrp : 1; >> + u64 reserved_16_28 : 13; >> + u64 index : 12; >> + u64 wait : 1; >> + u64 reserved_0_2 : 3; >> + } swork_78xx; >> + /** >> + * Address for loads to get POW internal status >> + */ >> + struct { >> + u64 mem_region : 2; >> + u64 reserved_49_61 : 13; >> + u64 is_io : 1; >> + u64 did : 8; >> + u64 reserved_10_39 : 30; >> + u64 coreid : 4; >> + u64 get_rev : 1; >> + u64 get_cur : 1; >> + u64 get_wqp : 1; >> + u64 reserved_0_2 : 3; >> + } sstatus; >> + /** >> + * Address for loads to get 68XX SS0 internal status >> + */ >> + struct { >> + u64 mem_region : 2; >> + u64 reserved_49_61 : 13; >> + u64 is_io : 1; >> + u64 did : 8; >> + u64 reserved_14_39 : 26; >> + u64 coreid : 5; >> + u64 reserved_6_8 : 3; >> + u64 opcode : 3; >> + u64 reserved_0_2 : 3; >> + } sstatus_cn68xx; >> + /** >> + * Address for memory loads to get POW internal state >> + */ >> + struct { >> + u64 mem_region : 2; >> + u64 reserved_49_61 : 13; >> + u64 is_io : 1; >> + u64 did : 8; >> + u64 reserved_16_39 : 24; >> + u64 index : 11; >> + u64 get_des : 1; >> + u64 get_wqp : 1; >> + u64 reserved_0_2 : 3; >> + } smemload; >> + /** >> + * Address for memory loads to get SSO internal state >> + */ >> + struct { >> + u64 mem_region : 2; >> + u64 reserved_49_61 : 13; >> + u64 is_io : 1; >> + u64 did : 8; >> + u64 reserved_20_39 : 20; >> + u64 index : 11; >> + u64 reserved_6_8 : 3; >> + u64 opcode : 3; >> + u64 reserved_0_2 : 3; >> + } smemload_cn68xx; >> + /** >> + * Address for index/pointer loads >> + */ >> + struct { >> + u64 mem_region : 2; >> + u64 reserved_49_61 : 13; >> + u64 is_io : 1; >> + u64 did : 8; >> + u64 reserved_9_39 : 31; >> + u64 qosgrp : 4; >> + u64 get_des_get_tail : 1; >> + u64 get_rmt : 1; >> + u64 reserved_0_2 : 3; >> + } sindexload; >> + /** >> + * Address for a Index/Pointer loads to get SSO internal state >> + */ >> + struct { >> + u64 mem_region : 2; >> + u64 reserved_49_61 : 13; >> + u64 is_io : 1; >> + u64 did : 8; >> + u64 reserved_15_39 : 25; >> + u64 qos_grp : 6; >> + u64 reserved_6_8 : 3; >> + u64 opcode : 3; >> + u64 reserved_0_2 : 3; >> + } sindexload_cn68xx; >> + /** >> + * Address for NULL_RD request (did<2:0> == 4) >> + * when this is read, HW attempts to change the state to NULL >> if it is NULL_NULL >> + * (the hardware cannot switch from NULL_NULL to NULL if a POW >> entry is not available - >> + * software may need to recover by finishing another piece of >> work before a POW >> + * entry can ever become available.) >> + */ >> + struct { >> + u64 mem_region : 2; >> + u64 reserved_49_61 : 13; >> + u64 is_io : 1; >> + u64 did : 8; >> + u64 reserved_0_39 : 40; >> + } snull_rd; >> +} cvmx_pow_load_addr_t; >> + >> +/** >> + * This structure defines the response to a load/SENDSINGLE to POW >> (except CSR reads) >> + */ >> +typedef union { >> + u64 u64; >> + /** >> + * Response to new work request loads >> + */ >> + struct { >> + u64 no_work : 1; >> + u64 pend_switch : 1; >> + u64 tt : 2; >> + u64 reserved_58_59 : 2; >> + u64 grp : 10; >> + u64 reserved_42_47 : 6; >> + u64 addr : 42; >> + } s_work; >> + >> + /** >> + * Result for a POW Status Load (when get_cur==0 and >> get_wqp==0) >> + */ >> + struct { >> + u64 reserved_62_63 : 2; >> + u64 pend_switch : 1; >> + u64 pend_switch_full : 1; >> + u64 pend_switch_null : 1; >> + u64 pend_desched : 1; >> + u64 pend_desched_switch : 1; >> + u64 pend_nosched : 1; >> + u64 pend_new_work : 1; >> + u64 pend_new_work_wait : 1; >> + u64 pend_null_rd : 1; >> + u64 pend_nosched_clr : 1; >> + u64 reserved_51 : 1; >> + u64 pend_index : 11; >> + u64 pend_grp : 4; >> + u64 reserved_34_35 : 2; >> + u64 pend_type : 2; >> + u64 pend_tag : 32; >> + } s_sstatus0; >> + /** >> + * Result for a SSO Status Load (when opcode is SL_PENDTAG) >> + */ >> + struct { >> + u64 pend_switch : 1; >> + u64 pend_get_work : 1; >> + u64 pend_get_work_wait : 1; >> + u64 pend_nosched : 1; >> + u64 pend_nosched_clr : 1; >> + u64 pend_desched : 1; >> + u64 pend_alloc_we : 1; >> + u64 reserved_48_56 : 9; >> + u64 pend_index : 11; >> + u64 reserved_34_36 : 3; >> + u64 pend_type : 2; >> + u64 pend_tag : 32; >> + } s_sstatus0_cn68xx; >> + /** >> + * Result for a POW Status Load (when get_cur==0 and >> get_wqp==1) >> + */ >> + struct { >> + u64 reserved_62_63 : 2; >> + u64 pend_switch : 1; >> + u64 pend_switch_full : 1; >> + u64 pend_switch_null : 1; >> + u64 pend_desched : 1; >> + u64 pend_desched_switch : 1; >> + u64 pend_nosched : 1; >> + u64 pend_new_work : 1; >> + u64 pend_new_work_wait : 1; >> + u64 pend_null_rd : 1; >> + u64 pend_nosched_clr : 1; >> + u64 reserved_51 : 1; >> + u64 pend_index : 11; >> + u64 pend_grp : 4; >> + u64 pend_wqp : 36; >> + } s_sstatus1; >> + /** >> + * Result for a SSO Status Load (when opcode is SL_PENDWQP) >> + */ >> + struct { >> + u64 pend_switch : 1; >> + u64 pend_get_work : 1; >> + u64 pend_get_work_wait : 1; >> + u64 pend_nosched : 1; >> + u64 pend_nosched_clr : 1; >> + u64 pend_desched : 1; >> + u64 pend_alloc_we : 1; >> + u64 reserved_51_56 : 6; >> + u64 pend_index : 11; >> + u64 reserved_38_39 : 2; >> + u64 pend_wqp : 38; >> + } s_sstatus1_cn68xx; >> + >> + struct { >> + u64 pend_switch : 1; >> + u64 pend_get_work : 1; >> + u64 pend_get_work_wait : 1; >> + u64 pend_nosched : 1; >> + u64 pend_nosched_clr : 1; >> + u64 pend_desched : 1; >> + u64 pend_alloc_we : 1; >> + u64 reserved_56 : 1; >> + u64 prep_index : 12; >> + u64 reserved_42_43 : 2; >> + u64 pend_tag : 42; >> + } s_sso_ppx_pendwqp_cn78xx; >> + /** >> + * Result for a POW Status Load (when get_cur==1, get_wqp==0, >> and get_rev==0) >> + */ >> + struct { >> + u64 reserved_62_63 : 2; >> + u64 link_index : 11; >> + u64 index : 11; >> + u64 grp : 4; >> + u64 head : 1; >> + u64 tail : 1; >> + u64 tag_type : 2; >> + u64 tag : 32; >> + } s_sstatus2; >> + /** >> + * Result for a SSO Status Load (when opcode is SL_TAG) >> + */ >> + struct { >> + u64 reserved_57_63 : 7; >> + u64 index : 11; >> + u64 reserved_45 : 1; >> + u64 grp : 6; >> + u64 head : 1; >> + u64 tail : 1; >> + u64 reserved_34_36 : 3; >> + u64 tag_type : 2; >> + u64 tag : 32; >> + } s_sstatus2_cn68xx; >> + >> + struct { >> + u64 tailc : 1; >> + u64 reserved_60_62 : 3; >> + u64 index : 12; >> + u64 reserved_46_47 : 2; >> + u64 grp : 10; >> + u64 head : 1; >> + u64 tail : 1; >> + u64 tt : 2; >> + u64 tag : 32; >> + } s_sso_ppx_tag_cn78xx; >> + /** >> + * Result for a POW Status Load (when get_cur==1, get_wqp==0, >> and get_rev==1) >> + */ >> + struct { >> + u64 reserved_62_63 : 2; >> + u64 revlink_index : 11; >> + u64 index : 11; >> + u64 grp : 4; >> + u64 head : 1; >> + u64 tail : 1; >> + u64 tag_type : 2; >> + u64 tag : 32; >> + } s_sstatus3; >> + /** >> + * Result for a SSO Status Load (when opcode is SL_WQP) >> + */ >> + struct { >> + u64 reserved_58_63 : 6; >> + u64 index : 11; >> + u64 reserved_46 : 1; >> + u64 grp : 6; >> + u64 reserved_38_39 : 2; >> + u64 wqp : 38; >> + } s_sstatus3_cn68xx; >> + >> + struct { >> + u64 reserved_58_63 : 6; >> + u64 grp : 10; >> + u64 reserved_42_47 : 6; >> + u64 tag : 42; >> + } s_sso_ppx_wqp_cn78xx; >> + /** >> + * Result for a POW Status Load (when get_cur==1, get_wqp==1, >> and get_rev==0) >> + */ >> + struct { >> + u64 reserved_62_63 : 2; >> + u64 link_index : 11; >> + u64 index : 11; >> + u64 grp : 4; >> + u64 wqp : 36; >> + } s_sstatus4; >> + /** >> + * Result for a SSO Status Load (when opcode is SL_LINKS) >> + */ >> + struct { >> + u64 reserved_46_63 : 18; >> + u64 index : 11; >> + u64 reserved_34 : 1; >> + u64 grp : 6; >> + u64 head : 1; >> + u64 tail : 1; >> + u64 reserved_24_25 : 2; >> + u64 revlink_index : 11; >> + u64 reserved_11_12 : 2; >> + u64 link_index : 11; >> + } s_sstatus4_cn68xx; >> + >> + struct { >> + u64 tailc : 1; >> + u64 reserved_60_62 : 3; >> + u64 index : 12; >> + u64 reserved_38_47 : 10; >> + u64 grp : 10; >> + u64 head : 1; >> + u64 tail : 1; >> + u64 reserved_25 : 1; >> + u64 revlink_index : 12; >> + u64 link_index_vld : 1; >> + u64 link_index : 12; >> + } s_sso_ppx_links_cn78xx; >> + /** >> + * Result for a POW Status Load (when get_cur==1, get_wqp==1, >> and get_rev==1) >> + */ >> + struct { >> + u64 reserved_62_63 : 2; >> + u64 revlink_index : 11; >> + u64 index : 11; >> + u64 grp : 4; >> + u64 wqp : 36; >> + } s_sstatus5; >> + /** >> + * Result For POW Memory Load (get_des == 0 and get_wqp == 0) >> + */ >> + struct { >> + u64 reserved_51_63 : 13; >> + u64 next_index : 11; >> + u64 grp : 4; >> + u64 reserved_35 : 1; >> + u64 tail : 1; >> + u64 tag_type : 2; >> + u64 tag : 32; >> + } s_smemload0; >> + /** >> + * Result For SSO Memory Load (opcode is ML_TAG) >> + */ >> + struct { >> + u64 reserved_38_63 : 26; >> + u64 tail : 1; >> + u64 reserved_34_36 : 3; >> + u64 tag_type : 2; >> + u64 tag : 32; >> + } s_smemload0_cn68xx; >> + >> + struct { >> + u64 reserved_39_63 : 25; >> + u64 tail : 1; >> + u64 reserved_34_36 : 3; >> + u64 tag_type : 2; >> + u64 tag : 32; >> + } s_sso_iaq_ppx_tag_cn78xx; >> + /** >> + * Result For POW Memory Load (get_des == 0 and get_wqp == 1) >> + */ >> + struct { >> + u64 reserved_51_63 : 13; >> + u64 next_index : 11; >> + u64 grp : 4; >> + u64 wqp : 36; >> + } s_smemload1; >> + /** >> + * Result For SSO Memory Load (opcode is ML_WQPGRP) >> + */ >> + struct { >> + u64 reserved_48_63 : 16; >> + u64 nosched : 1; >> + u64 reserved_46 : 1; >> + u64 grp : 6; >> + u64 reserved_38_39 : 2; >> + u64 wqp : 38; >> + } s_smemload1_cn68xx; >> + >> + /** >> + * Entry structures for the CN7XXX chips. >> + */ >> + struct { >> + u64 reserved_39_63 : 25; >> + u64 tailc : 1; >> + u64 tail : 1; >> + u64 reserved_34_36 : 3; >> + u64 tt : 2; >> + u64 tag : 32; >> + } s_sso_ientx_tag_cn78xx; >> + >> + struct { >> + u64 reserved_62_63 : 2; >> + u64 head : 1; >> + u64 nosched : 1; >> + u64 reserved_56_59 : 4; >> + u64 grp : 8; >> + u64 reserved_42_47 : 6; >> + u64 wqp : 42; >> + } s_sso_ientx_wqpgrp_cn73xx; >> + >> + struct { >> + u64 reserved_62_63 : 2; >> + u64 head : 1; >> + u64 nosched : 1; >> + u64 reserved_58_59 : 2; >> + u64 grp : 10; >> + u64 reserved_42_47 : 6; >> + u64 wqp : 42; >> + } s_sso_ientx_wqpgrp_cn78xx; >> + >> + struct { >> + u64 reserved_38_63 : 26; >> + u64 pend_switch : 1; >> + u64 reserved_34_36 : 3; >> + u64 pend_tt : 2; >> + u64 pend_tag : 32; >> + } s_sso_ientx_pendtag_cn78xx; >> + >> + struct { >> + u64 reserved_26_63 : 38; >> + u64 prev_index : 10; >> + u64 reserved_11_15 : 5; >> + u64 next_index_vld : 1; >> + u64 next_index : 10; >> + } s_sso_ientx_links_cn73xx; >> + >> + struct { >> + u64 reserved_28_63 : 36; >> + u64 prev_index : 12; >> + u64 reserved_13_15 : 3; >> + u64 next_index_vld : 1; >> + u64 next_index : 12; >> + } s_sso_ientx_links_cn78xx; >> + >> + /** >> + * Result For POW Memory Load (get_des == 1) >> + */ >> + struct { >> + u64 reserved_51_63 : 13; >> + u64 fwd_index : 11; >> + u64 grp : 4; >> + u64 nosched : 1; >> + u64 pend_switch : 1; >> + u64 pend_type : 2; >> + u64 pend_tag : 32; >> + } s_smemload2; >> + /** >> + * Result For SSO Memory Load (opcode is ML_PENTAG) >> + */ >> + struct { >> + u64 reserved_38_63 : 26; >> + u64 pend_switch : 1; >> + u64 reserved_34_36 : 3; >> + u64 pend_type : 2; >> + u64 pend_tag : 32; >> + } s_smemload2_cn68xx; >> + >> + struct { >> + u64 pend_switch : 1; >> + u64 pend_get_work : 1; >> + u64 pend_get_work_wait : 1; >> + u64 pend_nosched : 1; >> + u64 pend_nosched_clr : 1; >> + u64 pend_desched : 1; >> + u64 pend_alloc_we : 1; >> + u64 reserved_34_56 : 23; >> + u64 pend_tt : 2; >> + u64 pend_tag : 32; >> + } s_sso_ppx_pendtag_cn78xx; >> + /** >> + * Result For SSO Memory Load (opcode is ML_LINKS) >> + */ >> + struct { >> + u64 reserved_24_63 : 40; >> + u64 fwd_index : 11; >> + u64 reserved_11_12 : 2; >> + u64 next_index : 11; >> + } s_smemload3_cn68xx; >> + >> + /** >> + * Result For POW Index/Pointer Load (get_rmt == >> 0/get_des_get_tail == 0) >> + */ >> + struct { >> + u64 reserved_52_63 : 12; >> + u64 free_val : 1; >> + u64 free_one : 1; >> + u64 reserved_49 : 1; >> + u64 free_head : 11; >> + u64 reserved_37 : 1; >> + u64 free_tail : 11; >> + u64 loc_val : 1; >> + u64 loc_one : 1; >> + u64 reserved_23 : 1; >> + u64 loc_head : 11; >> + u64 reserved_11 : 1; >> + u64 loc_tail : 11; >> + } sindexload0; >> + /** >> + * Result for SSO Index/Pointer Load(opcode == >> + * IPL_IQ/IPL_DESCHED/IPL_NOSCHED) >> + */ >> + struct { >> + u64 reserved_28_63 : 36; >> + u64 queue_val : 1; >> + u64 queue_one : 1; >> + u64 reserved_24_25 : 2; >> + u64 queue_head : 11; >> + u64 reserved_11_12 : 2; >> + u64 queue_tail : 11; >> + } sindexload0_cn68xx; >> + /** >> + * Result For POW Index/Pointer Load (get_rmt == >> 0/get_des_get_tail == 1) >> + */ >> + struct { >> + u64 reserved_52_63 : 12; >> + u64 nosched_val : 1; >> + u64 nosched_one : 1; >> + u64 reserved_49 : 1; >> + u64 nosched_head : 11; >> + u64 reserved_37 : 1; >> + u64 nosched_tail : 11; >> + u64 des_val : 1; >> + u64 des_one : 1; >> + u64 reserved_23 : 1; >> + u64 des_head : 11; >> + u64 reserved_11 : 1; >> + u64 des_tail : 11; >> + } sindexload1; >> + /** >> + * Result for SSO Index/Pointer Load(opcode == >> IPL_FREE0/IPL_FREE1/IPL_FREE2) >> + */ >> + struct { >> + u64 reserved_60_63 : 4; >> + u64 qnum_head : 2; >> + u64 qnum_tail : 2; >> + u64 reserved_28_55 : 28; >> + u64 queue_val : 1; >> + u64 queue_one : 1; >> + u64 reserved_24_25 : 2; >> + u64 queue_head : 11; >> + u64 reserved_11_12 : 2; >> + u64 queue_tail : 11; >> + } sindexload1_cn68xx; >> + /** >> + * Result For POW Index/Pointer Load (get_rmt == >> 1/get_des_get_tail == 0) >> + */ >> + struct { >> + u64 reserved_39_63 : 25; >> + u64 rmt_is_head : 1; >> + u64 rmt_val : 1; >> + u64 rmt_one : 1; >> + u64 rmt_head : 36; >> + } sindexload2; >> + /** >> + * Result For POW Index/Pointer Load (get_rmt == >> 1/get_des_get_tail == 1) >> + */ >> + struct { >> + u64 reserved_39_63 : 25; >> + u64 rmt_is_head : 1; >> + u64 rmt_val : 1; >> + u64 rmt_one : 1; >> + u64 rmt_tail : 36; >> + } sindexload3; >> + /** >> + * Response to NULL_RD request loads >> + */ >> + struct { >> + u64 unused : 62; >> + u64 state : 2; >> + } s_null_rd; >> + >> +} cvmx_pow_tag_load_resp_t; >> + >> +typedef union { >> + u64 u64; >> + struct { >> + u64 reserved_57_63 : 7; >> + u64 index : 11; >> + u64 reserved_45 : 1; >> + u64 grp : 6; >> + u64 head : 1; >> + u64 tail : 1; >> + u64 reserved_34_36 : 3; >> + u64 tag_type : 2; >> + u64 tag : 32; >> + } s; >> +} cvmx_pow_sl_tag_resp_t; >> + >> +/** >> + * This structure describes the address used for stores to the POW. >> + * The store address is meaningful on stores to the POW. The >> hardware assumes that an aligned >> + * 64-bit store was used for all these stores. >> + * Note the assumption that the work queue entry is aligned on an >> 8-byte >> + * boundary (since the low-order 3 address bits must be zero). >> + * Note that not all fields are used by all operations. >> + * >> + * NOTE: The following is the behavior of the pending switch bit at >> the PP >> + * for POW stores (i.e. when did<7:3> == 0xc) >> + * - did<2:0> == 0 => pending switch bit is set >> + * - did<2:0> == 1 => no affect on the pending switch bit >> + * - did<2:0> == 3 => pending switch bit is cleared >> + * - did<2:0> == 7 => no affect on the pending switch bit >> + * - did<2:0> == others => must not be used >> + * - No other loads/stores have an affect on the pending switch >> bit >> + * - The switch bus from POW can clear the pending switch bit >> + * >> + * NOTE: did<2:0> == 2 is used by the HW for a special single-cycle >> ADDWQ command >> + * that only contains the pointer). SW must never use did<2:0> == >> 2. >> + */ >> +typedef union { >> + u64 u64; >> + struct { >> + u64 mem_reg : 2; >> + u64 reserved_49_61 : 13; >> + u64 is_io : 1; >> + u64 did : 8; >> + u64 addr : 40; >> + } stag; >> +} cvmx_pow_tag_store_addr_t; /* FIXME- this type is unused */ >> + >> +/** >> + * Decode of the store data when an IOBDMA SENDSINGLE is sent to POW >> + */ >> +typedef union { >> + u64 u64; >> + struct { >> + u64 scraddr : 8; >> + u64 len : 8; >> + u64 did : 8; >> + u64 unused : 36; >> + u64 wait : 1; >> + u64 unused2 : 3; >> + } s; >> + struct { >> + u64 scraddr : 8; >> + u64 len : 8; >> + u64 did : 8; >> + u64 node : 4; >> + u64 unused1 : 4; >> + u64 indexed : 1; >> + u64 grouped : 1; >> + u64 rtngrp : 1; >> + u64 unused2 : 13; >> + u64 index_grp_mask : 12; >> + u64 wait : 1; >> + u64 unused3 : 3; >> + } s_cn78xx; >> +} cvmx_pow_iobdma_store_t; >> + >> +/* CSR typedefs have been moved to cvmx-pow-defs.h */ >> + >> +/*enum for group priority parameters which needs modification*/ >> +enum cvmx_sso_group_modify_mask { >> + CVMX_SSO_MODIFY_GROUP_PRIORITY = 0x01, >> + CVMX_SSO_MODIFY_GROUP_WEIGHT = 0x02, >> + CVMX_SSO_MODIFY_GROUP_AFFINITY = 0x04 >> +}; >> + >> +/** >> + * @INTERNAL >> + * Return the number of SSO groups for a given SoC model >> + */ >> +static inline unsigned int cvmx_sso_num_xgrp(void) >> +{ >> + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) >> + return 256; >> + if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) >> + return 64; >> + if (OCTEON_IS_MODEL(OCTEON_CN73XX)) >> + return 64; >> + printf("ERROR: %s: Unknown model\n", __func__); >> + return 0; >> +} >> + >> +/** >> + * @INTERNAL >> + * Return the number of POW groups on current model. >> + * In case of CN78XX/CN73XX this is the number of equivalent >> + * "legacy groups" on the chip when it is used in backward >> + * compatible mode. >> + */ >> +static inline unsigned int cvmx_pow_num_groups(void) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) >> + return cvmx_sso_num_xgrp() >> 3; >> + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) >> + return 64; >> + else >> + return 16; >> +} >> + >> +/** >> + * @INTERNAL >> + * Return the number of mask-set registers. >> + */ >> +static inline unsigned int cvmx_sso_num_maskset(void) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) >> + return 2; >> + else >> + return 1; >> +} >> + >> +/** >> + * Get the POW tag for this core. This returns the current >> + * tag type, tag, group, and POW entry index associated with >> + * this core. Index is only valid if the tag type isn't NULL_NULL. >> + * If a tag switch is pending this routine returns the tag before >> + * the tag switch, not after. >> + * >> + * @return Current tag >> + */ >> +static inline cvmx_pow_tag_info_t cvmx_pow_get_current_tag(void) >> +{ >> + cvmx_pow_load_addr_t load_addr; >> + cvmx_pow_tag_info_t result; >> + >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_sso_sl_ppx_tag_t sl_ppx_tag; >> + cvmx_xgrp_t xgrp; >> + int node, core; >> + >> + CVMX_SYNCS; >> + node = cvmx_get_node_num(); >> + core = cvmx_get_local_core_num(); >> + sl_ppx_tag.u64 = csr_rd_node(node, >> CVMX_SSO_SL_PPX_TAG(core)); >> + result.index = sl_ppx_tag.s.index; >> + result.tag_type = sl_ppx_tag.s.tt; >> + result.tag = sl_ppx_tag.s.tag; >> + >> + /* Get native XGRP value */ >> + xgrp.xgrp = sl_ppx_tag.s.grp; >> + >> + /* Return legacy style group 0..15 */ >> + result.grp = xgrp.group; >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + cvmx_pow_sl_tag_resp_t load_resp; >> + >> + load_addr.u64 = 0; >> + load_addr.sstatus_cn68xx.mem_region = CVMX_IO_SEG; >> + load_addr.sstatus_cn68xx.is_io = 1; >> + load_addr.sstatus_cn68xx.did = CVMX_OCT_DID_TAG_TAG5; >> + load_addr.sstatus_cn68xx.coreid = cvmx_get_core_num(); >> + load_addr.sstatus_cn68xx.opcode = 3; >> + load_resp.u64 = csr_rd(load_addr.u64); >> + result.grp = load_resp.s.grp; >> + result.index = load_resp.s.index; >> + result.tag_type = load_resp.s.tag_type; >> + result.tag = load_resp.s.tag; >> + } else { >> + cvmx_pow_tag_load_resp_t load_resp; >> + >> + load_addr.u64 = 0; >> + load_addr.sstatus.mem_region = CVMX_IO_SEG; >> + load_addr.sstatus.is_io = 1; >> + load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1; >> + load_addr.sstatus.coreid = cvmx_get_core_num(); >> + load_addr.sstatus.get_cur = 1; >> + load_resp.u64 = csr_rd(load_addr.u64); >> + result.grp = load_resp.s_sstatus2.grp; >> + result.index = load_resp.s_sstatus2.index; >> + result.tag_type = load_resp.s_sstatus2.tag_type; >> + result.tag = load_resp.s_sstatus2.tag; >> + } >> + return result; >> +} >> + >> +/** >> + * Get the POW WQE for this core. This returns the work queue >> + * entry currently associated with this core. >> + * >> + * @return WQE pointer >> + */ >> +static inline cvmx_wqe_t *cvmx_pow_get_current_wqp(void) >> +{ >> + cvmx_pow_load_addr_t load_addr; >> + cvmx_pow_tag_load_resp_t load_resp; >> + >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_sso_sl_ppx_wqp_t sso_wqp; >> + int node = cvmx_get_node_num(); >> + int core = cvmx_get_local_core_num(); >> + >> + sso_wqp.u64 = csr_rd_node(node, >> CVMX_SSO_SL_PPX_WQP(core)); >> + if (sso_wqp.s.wqp) >> + return (cvmx_wqe_t >> *)cvmx_phys_to_ptr(sso_wqp.s.wqp); >> + return (cvmx_wqe_t *)0; >> + } >> + if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + load_addr.u64 = 0; >> + load_addr.sstatus_cn68xx.mem_region = CVMX_IO_SEG; >> + load_addr.sstatus_cn68xx.is_io = 1; >> + load_addr.sstatus_cn68xx.did = CVMX_OCT_DID_TAG_TAG5; >> + load_addr.sstatus_cn68xx.coreid = cvmx_get_core_num(); >> + load_addr.sstatus_cn68xx.opcode = 4; >> + load_resp.u64 = csr_rd(load_addr.u64); >> + if (load_resp.s_sstatus3_cn68xx.wqp) >> + return (cvmx_wqe_t >> *)cvmx_phys_to_ptr(load_resp.s_sstatus3_cn68xx.wqp); >> + else >> + return (cvmx_wqe_t *)0; >> + } else { >> + load_addr.u64 = 0; >> + load_addr.sstatus.mem_region = CVMX_IO_SEG; >> + load_addr.sstatus.is_io = 1; >> + load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1; >> + load_addr.sstatus.coreid = cvmx_get_core_num(); >> + load_addr.sstatus.get_cur = 1; >> + load_addr.sstatus.get_wqp = 1; >> + load_resp.u64 = csr_rd(load_addr.u64); >> + return (cvmx_wqe_t >> *)cvmx_phys_to_ptr(load_resp.s_sstatus4.wqp); >> + } >> +} >> + >> +/** >> + * @INTERNAL >> + * Print a warning if a tag switch is pending for this core >> + * >> + * @param function Function name checking for a pending tag switch >> + */ >> +static inline void __cvmx_pow_warn_if_pending_switch(const char >> *function) >> +{ >> + u64 switch_complete; >> + >> + CVMX_MF_CHORD(switch_complete); >> + cvmx_warn_if(!switch_complete, "%s called with tag switch in >> progress\n", function); >> +} >> + >> +/** >> + * Waits for a tag switch to complete by polling the completion bit. >> + * Note that switches to NULL complete immediately and do not need >> + * to be waited for. >> + */ >> +static inline void cvmx_pow_tag_sw_wait(void) >> +{ >> + const u64 TIMEOUT_MS = 10; /* 10ms timeout */ >> + u64 switch_complete; >> + u64 start_cycle; >> + >> + if (CVMX_ENABLE_POW_CHECKS) >> + start_cycle = get_timer(0); >> + >> + while (1) { >> + CVMX_MF_CHORD(switch_complete); >> + if (cvmx_likely(switch_complete)) >> + break; >> + >> + if (CVMX_ENABLE_POW_CHECKS) { >> + if (cvmx_unlikely(get_timer(start_cycle) > >> TIMEOUT_MS)) { >> + debug("WARNING: %s: Tag switch is >> taking a long time, possible deadlock\n", >> + __func__); >> + } >> + } >> + } >> +} >> + >> +/** >> + * Synchronous work request. Requests work from the POW. >> + * This function does NOT wait for previous tag switches to >> complete, >> + * so the caller must ensure that there is not a pending tag switch. >> + * >> + * @param wait When set, call stalls until work becomes available, >> or >> + * times out. If not set, returns immediately. >> + * >> + * @return Returns the WQE pointer from POW. Returns NULL if no work >> was >> + * available. >> + */ >> +static inline cvmx_wqe_t >> *cvmx_pow_work_request_sync_nocheck(cvmx_pow_wait_t wait) >> +{ >> + cvmx_pow_load_addr_t ptr; >> + cvmx_pow_tag_load_resp_t result; >> + >> + if (CVMX_ENABLE_POW_CHECKS) >> + __cvmx_pow_warn_if_pending_switch(__func__); >> + >> + ptr.u64 = 0; >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + ptr.swork_78xx.node = cvmx_get_node_num(); >> + ptr.swork_78xx.mem_region = CVMX_IO_SEG; >> + ptr.swork_78xx.is_io = 1; >> + ptr.swork_78xx.did = CVMX_OCT_DID_TAG_SWTAG; >> + ptr.swork_78xx.wait = wait; >> + } else { >> + ptr.swork.mem_region = CVMX_IO_SEG; >> + ptr.swork.is_io = 1; >> + ptr.swork.did = CVMX_OCT_DID_TAG_SWTAG; >> + ptr.swork.wait = wait; >> + } >> + >> + result.u64 = csr_rd(ptr.u64); >> + if (result.s_work.no_work) >> + return NULL; >> + else >> + return (cvmx_wqe_t >> *)cvmx_phys_to_ptr(result.s_work.addr); >> +} >> + >> +/** >> + * Synchronous work request. Requests work from the POW. >> + * This function waits for any previous tag switch to complete >> before >> + * requesting the new work. >> + * >> + * @param wait When set, call stalls until work becomes available, >> or >> + * times out. If not set, returns immediately. >> + * >> + * @return Returns the WQE pointer from POW. Returns NULL if no work >> was >> + * available. >> + */ >> +static inline cvmx_wqe_t *cvmx_pow_work_request_sync(cvmx_pow_wait_t >> wait) >> +{ >> + /* Must not have a switch pending when requesting work */ >> + cvmx_pow_tag_sw_wait(); >> + return (cvmx_pow_work_request_sync_nocheck(wait)); >> +} >> + >> +/** >> + * Synchronous null_rd request. Requests a switch out of NULL_NULL >> POW state. >> + * This function waits for any previous tag switch to complete >> before >> + * requesting the null_rd. >> + * >> + * @return Returns the POW state of type cvmx_pow_tag_type_t. >> + */ >> +static inline cvmx_pow_tag_type_t >> cvmx_pow_work_request_null_rd(void) >> +{ >> + cvmx_pow_load_addr_t ptr; >> + cvmx_pow_tag_load_resp_t result; >> + >> + /* Must not have a switch pending when requesting work */ >> + cvmx_pow_tag_sw_wait(); >> + >> + ptr.u64 = 0; >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + ptr.swork_78xx.mem_region = CVMX_IO_SEG; >> + ptr.swork_78xx.is_io = 1; >> + ptr.swork_78xx.did = CVMX_OCT_DID_TAG_NULL_RD; >> + ptr.swork_78xx.node = cvmx_get_node_num(); >> + } else { >> + ptr.snull_rd.mem_region = CVMX_IO_SEG; >> + ptr.snull_rd.is_io = 1; >> + ptr.snull_rd.did = CVMX_OCT_DID_TAG_NULL_RD; >> + } >> + result.u64 = csr_rd(ptr.u64); >> + return (cvmx_pow_tag_type_t)result.s_null_rd.state; >> +} >> + >> +/** >> + * Asynchronous work request. >> + * Work is requested from the POW unit, and should later be checked >> with >> + * function cvmx_pow_work_response_async. >> + * This function does NOT wait for previous tag switches to >> complete, >> + * so the caller must ensure that there is not a pending tag switch. >> + * >> + * @param scr_addr Scratch memory address that response will be >> returned to, >> + * which is either a valid WQE, or a response with the invalid >> bit set. >> + * Byte address, must be 8 byte aligned. >> + * @param wait 1 to cause response to wait for work to become >> available >> + * (or timeout) >> + * 0 to cause response to return immediately >> + */ >> +static inline void cvmx_pow_work_request_async_nocheck(int scr_addr, >> cvmx_pow_wait_t wait) >> +{ >> + cvmx_pow_iobdma_store_t data; >> + >> + if (CVMX_ENABLE_POW_CHECKS) >> + __cvmx_pow_warn_if_pending_switch(__func__); >> + >> + /* scr_addr must be 8 byte aligned */ >> + data.u64 = 0; >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + data.s_cn78xx.node = cvmx_get_node_num(); >> + data.s_cn78xx.scraddr = scr_addr >> 3; >> + data.s_cn78xx.len = 1; >> + data.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; >> + data.s_cn78xx.wait = wait; >> + } else { >> + data.s.scraddr = scr_addr >> 3; >> + data.s.len = 1; >> + data.s.did = CVMX_OCT_DID_TAG_SWTAG; >> + data.s.wait = wait; >> + } >> + cvmx_send_single(data.u64); >> +} >> + >> +/** >> + * Asynchronous work request. >> + * Work is requested from the POW unit, and should later be checked >> with >> + * function cvmx_pow_work_response_async. >> + * This function waits for any previous tag switch to complete >> before >> + * requesting the new work. >> + * >> + * @param scr_addr Scratch memory address that response will be >> returned to, >> + * which is either a valid WQE, or a response with the invalid >> bit set. >> + * Byte address, must be 8 byte aligned. >> + * @param wait 1 to cause response to wait for work to become >> available >> + * (or timeout) >> + * 0 to cause response to return immediately >> + */ >> +static inline void cvmx_pow_work_request_async(int scr_addr, >> cvmx_pow_wait_t wait) >> +{ >> + /* Must not have a switch pending when requesting work */ >> + cvmx_pow_tag_sw_wait(); >> + cvmx_pow_work_request_async_nocheck(scr_addr, wait); >> +} >> + >> +/** >> + * Gets result of asynchronous work request. Performs a IOBDMA sync >> + * to wait for the response. >> + * >> + * @param scr_addr Scratch memory address to get result from >> + * Byte address, must be 8 byte aligned. >> + * @return Returns the WQE from the scratch register, or NULL if no >> work was >> + * available. >> + */ >> +static inline cvmx_wqe_t *cvmx_pow_work_response_async(int scr_addr) >> +{ >> + cvmx_pow_tag_load_resp_t result; >> + >> + CVMX_SYNCIOBDMA; >> + result.u64 = cvmx_scratch_read64(scr_addr); >> + if (result.s_work.no_work) >> + return NULL; >> + else >> + return (cvmx_wqe_t >> *)cvmx_phys_to_ptr(result.s_work.addr); >> +} >> + >> +/** >> + * Checks if a work queue entry pointer returned by a work >> + * request is valid. It may be invalid due to no work >> + * being available or due to a timeout. >> + * >> + * @param wqe_ptr pointer to a work queue entry returned by the POW >> + * >> + * @return 0 if pointer is valid >> + * 1 if invalid (no work was returned) >> + */ >> +static inline u64 cvmx_pow_work_invalid(cvmx_wqe_t *wqe_ptr) >> +{ >> + return (!wqe_ptr); /* FIXME: improve */ >> +} >> + >> +/** >> + * Starts a tag switch to the provided tag value and tag >> type. Completion for >> + * the tag switch must be checked for separately. >> + * This function does NOT update the >> + * work queue entry in dram to match tag value and type, so the >> application must >> + * keep track of these if they are important to the application. >> + * This tag switch command must not be used for switches to NULL, as >> the tag >> + * switch pending bit will be set by the switch request, but never >> cleared by >> + * the hardware. >> + * >> + * NOTE: This should not be used when switching from a NULL >> tag. Use >> + * cvmx_pow_tag_sw_full() instead. >> + * >> + * This function does no checks, so the caller must ensure that any >> previous tag >> + * switch has completed. >> + * >> + * @param tag new tag value >> + * @param tag_type new tag type (ordered or atomic) >> + */ >> +static inline void cvmx_pow_tag_sw_nocheck(u32 tag, >> cvmx_pow_tag_type_t tag_type) >> +{ >> + union cvmx_pow_tag_req_addr ptr; >> + cvmx_pow_tag_req_t tag_req; >> + >> + if (CVMX_ENABLE_POW_CHECKS) { >> + cvmx_pow_tag_info_t current_tag; >> + >> + __cvmx_pow_warn_if_pending_switch(__func__); >> + current_tag = cvmx_pow_get_current_tag(); >> + cvmx_warn_if(current_tag.tag_type == >> CVMX_POW_TAG_TYPE_NULL_NULL, >> + "%s called with NULL_NULL tag\n", >> __func__); >> + cvmx_warn_if(current_tag.tag_type == >> CVMX_POW_TAG_TYPE_NULL, >> + "%s called with NULL tag\n", __func__); >> + cvmx_warn_if((current_tag.tag_type == tag_type) && >> (current_tag.tag == tag), >> + "%s called to perform a tag switch to the >> same tag\n", __func__); >> + cvmx_warn_if( >> + tag_type == CVMX_POW_TAG_TYPE_NULL, >> + "%s called to perform a tag switch to NULL. Use >> cvmx_pow_tag_sw_null() instead\n", >> + __func__); >> + } >> + >> + /* >> + * Note that WQE in DRAM is not updated here, as the POW does >> not read >> + * from DRAM once the WQE is in flight. See hardware manual >> for >> + * complete details. >> + * It is the application's responsibility to keep track of the >> + * current tag value if that is important. >> + */ >> + tag_req.u64 = 0; >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG; >> + tag_req.s_cn78xx_other.type = tag_type; >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + tag_req.s_cn68xx_other.op = CVMX_POW_TAG_OP_SWTAG; >> + tag_req.s_cn68xx_other.tag = tag; >> + tag_req.s_cn68xx_other.type = tag_type; >> + } else { >> + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_SWTAG; >> + tag_req.s_cn38xx.tag = tag; >> + tag_req.s_cn38xx.type = tag_type; >> + } >> + ptr.u64 = 0; >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; >> + ptr.s_cn78xx.is_io = 1; >> + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; >> + ptr.s_cn78xx.node = cvmx_get_node_num(); >> + ptr.s_cn78xx.tag = tag; >> + } else { >> + ptr.s.mem_region = CVMX_IO_SEG; >> + ptr.s.is_io = 1; >> + ptr.s.did = CVMX_OCT_DID_TAG_SWTAG; >> + } >> + /* Once this store arrives at POW, it will attempt the switch >> + software must wait for the switch to complete separately */ >> + cvmx_write_io(ptr.u64, tag_req.u64); >> +} >> + >> +/** >> + * Starts a tag switch to the provided tag value and tag >> type. Completion for >> + * the tag switch must be checked for separately. >> + * This function does NOT update the >> + * work queue entry in dram to match tag value and type, so the >> application must >> + * keep track of these if they are important to the application. >> + * This tag switch command must not be used for switches to NULL, as >> the tag >> + * switch pending bit will be set by the switch request, but never >> cleared by >> + * the hardware. >> + * >> + * NOTE: This should not be used when switching from a NULL >> tag. Use >> + * cvmx_pow_tag_sw_full() instead. >> + * >> + * This function waits for any previous tag switch to complete, and >> also >> + * displays an error on tag switches to NULL. >> + * >> + * @param tag new tag value >> + * @param tag_type new tag type (ordered or atomic) >> + */ >> +static inline void cvmx_pow_tag_sw(u32 tag, cvmx_pow_tag_type_t >> tag_type) >> +{ >> + /* >> + * Note that WQE in DRAM is not updated here, as the POW does >> not read >> + * from DRAM once the WQE is in flight. See hardware manual >> for >> + * complete details. It is the application's responsibility to >> keep >> + * track of the current tag value if that is important. >> + */ >> + >> + /* >> + * Ensure that there is not a pending tag switch, as a tag >> switch >> + * cannot be started if a previous switch is still pending. >> + */ >> + cvmx_pow_tag_sw_wait(); >> + cvmx_pow_tag_sw_nocheck(tag, tag_type); >> +} >> + >> +/** >> + * Starts a tag switch to the provided tag value and tag >> type. Completion for >> + * the tag switch must be checked for separately. >> + * This function does NOT update the >> + * work queue entry in dram to match tag value and type, so the >> application must >> + * keep track of these if they are important to the application. >> + * This tag switch command must not be used for switches to NULL, as >> the tag >> + * switch pending bit will be set by the switch request, but never >> cleared by >> + * the hardware. >> + * >> + * This function must be used for tag switches from NULL. >> + * >> + * This function does no checks, so the caller must ensure that any >> previous tag >> + * switch has completed. >> + * >> + * @param wqp pointer to work queue entry to submit. This >> entry is >> + * updated to match the other parameters >> + * @param tag tag value to be assigned to work queue entry >> + * @param tag_type type of tag >> + * @param group group value for the work queue entry. >> + */ >> +static inline void cvmx_pow_tag_sw_full_nocheck(cvmx_wqe_t *wqp, u32 >> tag, >> + cvmx_pow_tag_type_t >> tag_type, u64 group) >> +{ >> + union cvmx_pow_tag_req_addr ptr; >> + cvmx_pow_tag_req_t tag_req; >> + unsigned int node = cvmx_get_node_num(); >> + u64 wqp_phys = cvmx_ptr_to_phys(wqp); >> + >> + if (CVMX_ENABLE_POW_CHECKS) { >> + cvmx_pow_tag_info_t current_tag; >> + >> + __cvmx_pow_warn_if_pending_switch(__func__); >> + current_tag = cvmx_pow_get_current_tag(); >> + cvmx_warn_if(current_tag.tag_type == >> CVMX_POW_TAG_TYPE_NULL_NULL, >> + "%s called with NULL_NULL tag\n", >> __func__); >> + cvmx_warn_if((current_tag.tag_type == tag_type) && >> (current_tag.tag == tag), >> + "%s called to perform a tag switch to the >> same tag\n", __func__); >> + cvmx_warn_if( >> + tag_type == CVMX_POW_TAG_TYPE_NULL, >> + "%s called to perform a tag switch to NULL. Use >> cvmx_pow_tag_sw_null() instead\n", >> + __func__); >> + if ((wqp != cvmx_phys_to_ptr(0x80)) && >> cvmx_pow_get_current_wqp()) >> + cvmx_warn_if(wqp != cvmx_pow_get_current_wqp(), >> + "%s passed WQE(%p) doesn't match >> the address in the POW(%p)\n", >> + __func__, wqp, >> cvmx_pow_get_current_wqp()); >> + } >> + >> + /* >> + * Note that WQE in DRAM is not updated here, as the POW does >> not >> + * read from DRAM once the WQE is in flight. See hardware >> manual >> + * for complete details. It is the application's responsibility >> to >> + * keep track of the current tag value if that is important. >> + */ >> + tag_req.u64 = 0; >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + unsigned int xgrp; >> + >> + if (wqp_phys != 0x80) { >> + /* If WQE is valid, use its XGRP: >> + * WQE GRP is 10 bits, and is mapped >> + * to legacy GRP + QoS, includes node number. >> + */ >> + xgrp = wqp->word1.cn78xx.grp; >> + /* Use XGRP[node] too */ >> + node = xgrp >> 8; >> + /* Modify XGRP with legacy group # from arg */ >> + xgrp &= ~0xf8; >> + xgrp |= 0xf8 & (group << 3); >> + >> + } else { >> + /* If no WQE, build XGRP with QoS=0 and current >> node */ >> + xgrp = group << 3; >> + xgrp |= node << 8; >> + } >> + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG_FULL; >> + tag_req.s_cn78xx_other.type = tag_type; >> + tag_req.s_cn78xx_other.grp = xgrp; >> + tag_req.s_cn78xx_other.wqp = wqp_phys; >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + tag_req.s_cn68xx_other.op = CVMX_POW_TAG_OP_SWTAG_FULL; >> + tag_req.s_cn68xx_other.tag = tag; >> + tag_req.s_cn68xx_other.type = tag_type; >> + tag_req.s_cn68xx_other.grp = group; >> + } else { >> + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_SWTAG_FULL; >> + tag_req.s_cn38xx.tag = tag; >> + tag_req.s_cn38xx.type = tag_type; >> + tag_req.s_cn38xx.grp = group; >> + } >> + ptr.u64 = 0; >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; >> + ptr.s_cn78xx.is_io = 1; >> + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; >> + ptr.s_cn78xx.node = node; >> + ptr.s_cn78xx.tag = tag; >> + } else { >> + ptr.s.mem_region = CVMX_IO_SEG; >> + ptr.s.is_io = 1; >> + ptr.s.did = CVMX_OCT_DID_TAG_SWTAG; >> + ptr.s.addr = wqp_phys; >> + } >> + /* Once this store arrives at POW, it will attempt the switch >> + software must wait for the switch to complete separately */ >> + cvmx_write_io(ptr.u64, tag_req.u64); >> +} >> + >> +/** >> + * Starts a tag switch to the provided tag value and tag type. >> + * Completion for the tag switch must be checked for separately. >> + * This function does NOT update the work queue entry in dram to >> match tag value >> + * and type, so the application must keep track of these if they are >> important >> + * to the application. This tag switch command must not be used for >> switches >> + * to NULL, as the tag switch pending bit will be set by the switch >> request, >> + * but never cleared by the hardware. >> + * >> + * This function must be used for tag switches from NULL. >> + * >> + * This function waits for any pending tag switches to complete >> + * before requesting the tag switch. >> + * >> + * @param wqp Pointer to work queue entry to submit. >> + * This entry is updated to match the other parameters >> + * @param tag Tag value to be assigned to work queue entry >> + * @param tag_type Type of tag >> + * @param group Group value for the work queue entry. >> + */ >> +static inline void cvmx_pow_tag_sw_full(cvmx_wqe_t *wqp, u32 tag, >> cvmx_pow_tag_type_t tag_type, >> + u64 group) >> +{ >> + /* >> + * Ensure that there is not a pending tag switch, as a tag >> switch cannot >> + * be started if a previous switch is still pending. >> + */ >> + cvmx_pow_tag_sw_wait(); >> + cvmx_pow_tag_sw_full_nocheck(wqp, tag, tag_type, group); >> +} >> + >> +/** >> + * Switch to a NULL tag, which ends any ordering or >> + * synchronization provided by the POW for the current >> + * work queue entry. This operation completes immediately, >> + * so completion should not be waited for. >> + * This function does NOT wait for previous tag switches to >> complete, >> + * so the caller must ensure that any previous tag switches have >> completed. >> + */ >> +static inline void cvmx_pow_tag_sw_null_nocheck(void) >> +{ >> + union cvmx_pow_tag_req_addr ptr; >> + cvmx_pow_tag_req_t tag_req; >> + >> + if (CVMX_ENABLE_POW_CHECKS) { >> + cvmx_pow_tag_info_t current_tag; >> + >> + __cvmx_pow_warn_if_pending_switch(__func__); >> + current_tag = cvmx_pow_get_current_tag(); >> + cvmx_warn_if(current_tag.tag_type == >> CVMX_POW_TAG_TYPE_NULL_NULL, >> + "%s called with NULL_NULL tag\n", >> __func__); >> + cvmx_warn_if(current_tag.tag_type == >> CVMX_POW_TAG_TYPE_NULL, >> + "%s called when we already have a NULL >> tag\n", __func__); >> + } >> + tag_req.u64 = 0; >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG; >> + tag_req.s_cn78xx_other.type = CVMX_POW_TAG_TYPE_NULL; >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + tag_req.s_cn68xx_other.op = CVMX_POW_TAG_OP_SWTAG; >> + tag_req.s_cn68xx_other.type = CVMX_POW_TAG_TYPE_NULL; >> + } else { >> + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_SWTAG; >> + tag_req.s_cn38xx.type = CVMX_POW_TAG_TYPE_NULL; >> + } >> + ptr.u64 = 0; >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; >> + ptr.s_cn78xx.is_io = 1; >> + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_TAG1; >> + ptr.s_cn78xx.node = cvmx_get_node_num(); >> + } else { >> + ptr.s.mem_region = CVMX_IO_SEG; >> + ptr.s.is_io = 1; >> + ptr.s.did = CVMX_OCT_DID_TAG_TAG1; >> + } >> + cvmx_write_io(ptr.u64, tag_req.u64); >> +} >> + >> +/** >> + * Switch to a NULL tag, which ends any ordering or >> + * synchronization provided by the POW for the current >> + * work queue entry. This operation completes immediately, >> + * so completion should not be waited for. >> + * This function waits for any pending tag switches to complete >> + * before requesting the switch to NULL. >> + */ >> +static inline void cvmx_pow_tag_sw_null(void) >> +{ >> + /* >> + * Ensure that there is not a pending tag switch, as a tag >> switch cannot >> + * be started if a previous switch is still pending. >> + */ >> + cvmx_pow_tag_sw_wait(); >> + cvmx_pow_tag_sw_null_nocheck(); >> +} >> + >> +/** >> + * Submits work to an input queue. >> + * This function updates the work queue entry in DRAM to match the >> arguments given. >> + * Note that the tag provided is for the work queue entry submitted, >> and >> + * is unrelated to the tag that the core currently holds. >> + * >> + * @param wqp pointer to work queue entry to submit. >> + * This entry is updated to match the other >> parameters >> + * @param tag tag value to be assigned to work queue entry >> + * @param tag_type type of tag >> + * @param qos Input queue to add to. >> + * @param grp group value for the work queue entry. >> + */ >> +static inline void cvmx_pow_work_submit(cvmx_wqe_t *wqp, u32 tag, >> cvmx_pow_tag_type_t tag_type, >> + u64 qos, u64 grp) >> +{ >> + union cvmx_pow_tag_req_addr ptr; >> + cvmx_pow_tag_req_t tag_req; >> + >> + tag_req.u64 = 0; >> + ptr.u64 = 0; >> + >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + unsigned int node = cvmx_get_node_num(); >> + unsigned int xgrp; >> + >> + xgrp = (grp & 0x1f) << 3; >> + xgrp |= (qos & 7); >> + xgrp |= 0x300 & (node << 8); >> + >> + wqp->word1.cn78xx.rsvd_0 = 0; >> + wqp->word1.cn78xx.rsvd_1 = 0; >> + wqp->word1.cn78xx.tag = tag; >> + wqp->word1.cn78xx.tag_type = tag_type; >> + wqp->word1.cn78xx.grp = xgrp; >> + CVMX_SYNCWS; >> + >> + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_ADDWQ; >> + tag_req.s_cn78xx_other.type = tag_type; >> + tag_req.s_cn78xx_other.wqp = cvmx_ptr_to_phys(wqp); >> + tag_req.s_cn78xx_other.grp = xgrp; >> + >> + ptr.s_cn78xx.did = 0x66; // CVMX_OCT_DID_TAG_TAG6; >> + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; >> + ptr.s_cn78xx.is_io = 1; >> + ptr.s_cn78xx.node = node; >> + ptr.s_cn78xx.tag = tag; >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + /* Reset all reserved bits */ >> + wqp->word1.cn68xx.zero_0 = 0; >> + wqp->word1.cn68xx.zero_1 = 0; >> + wqp->word1.cn68xx.zero_2 = 0; >> + wqp->word1.cn68xx.qos = qos; >> + wqp->word1.cn68xx.grp = grp; >> + >> + wqp->word1.tag = tag; >> + wqp->word1.tag_type = tag_type; >> + >> + tag_req.s_cn68xx_add.op = CVMX_POW_TAG_OP_ADDWQ; >> + tag_req.s_cn68xx_add.type = tag_type; >> + tag_req.s_cn68xx_add.tag = tag; >> + tag_req.s_cn68xx_add.qos = qos; >> + tag_req.s_cn68xx_add.grp = grp; >> + >> + ptr.s.mem_region = CVMX_IO_SEG; >> + ptr.s.is_io = 1; >> + ptr.s.did = CVMX_OCT_DID_TAG_TAG1; >> + ptr.s.addr = cvmx_ptr_to_phys(wqp); >> + } else { >> + /* Reset all reserved bits */ >> + wqp->word1.cn38xx.zero_2 = 0; >> + wqp->word1.cn38xx.qos = qos; >> + wqp->word1.cn38xx.grp = grp; >> + >> + wqp->word1.tag = tag; >> + wqp->word1.tag_type = tag_type; >> + >> + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_ADDWQ; >> + tag_req.s_cn38xx.type = tag_type; >> + tag_req.s_cn38xx.tag = tag; >> + tag_req.s_cn38xx.qos = qos; >> + tag_req.s_cn38xx.grp = grp; >> + >> + ptr.s.mem_region = CVMX_IO_SEG; >> + ptr.s.is_io = 1; >> + ptr.s.did = CVMX_OCT_DID_TAG_TAG1; >> + ptr.s.addr = cvmx_ptr_to_phys(wqp); >> + } >> + /* SYNC write to memory before the work submit. >> + * This is necessary as POW may read values from DRAM at this >> time */ >> + CVMX_SYNCWS; >> + cvmx_write_io(ptr.u64, tag_req.u64); >> +} >> + >> +/** >> + * This function sets the group mask for a core. The group mask >> + * indicates which groups each core will accept work from. There are >> + * 16 groups. >> + * >> + * @param core_num core to apply mask to >> + * @param mask Group mask, one bit for up to 64 groups. >> + * Each 1 bit in the mask enables the core to accept >> work from >> + * the corresponding group. >> + * The CN68XX supports 64 groups, earlier models only >> support >> + * 16 groups. >> + * >> + * The CN78XX in backwards compatibility mode allows up to 32 >> groups, >> + * so the 'mask' argument has one bit for every of the legacy >> + * groups, and a '1' in the mask causes a total of 8 groups >> + * which share the legacy group numbher and 8 qos levels, >> + * to be enabled for the calling processor core. >> + * A '0' in the mask will disable the current core >> + * from receiving work from the associated group. >> + */ >> +static inline void cvmx_pow_set_group_mask(u64 core_num, u64 mask) >> +{ >> + u64 valid_mask; >> + int num_groups = cvmx_pow_num_groups(); >> + >> + if (num_groups >= 64) >> + valid_mask = ~0ull; >> + else >> + valid_mask = (1ull << num_groups) - 1; >> + >> + if ((mask & valid_mask) == 0) { >> + printf("ERROR: %s empty group mask disables work on >> core# %llu, ignored.\n", >> + __func__, (unsigned long long)core_num); >> + return; >> + } >> + cvmx_warn_if(mask & (~valid_mask), "%s group number range >> exceeded: %#llx\n", __func__, >> + (unsigned long long)mask); >> + >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + unsigned int mask_set; >> + cvmx_sso_ppx_sx_grpmskx_t grp_msk; >> + unsigned int core, node; >> + unsigned int rix; /* Register index */ >> + unsigned int grp; /* Legacy group # */ >> + unsigned int bit; /* bit index */ >> + unsigned int xgrp; /* native group # */ >> + >> + node = cvmx_coremask_core_to_node(core_num); >> + core = cvmx_coremask_core_on_node(core_num); >> + >> + /* 78xx: 256 groups divided into 4 X 64 bit registers >> */ >> + /* 73xx: 64 groups are in one register */ >> + for (rix = 0; rix < (cvmx_sso_num_xgrp() >> 6); rix++) >> { >> + grp_msk.u64 = 0; >> + for (bit = 0; bit < 64; bit++) { >> + /* 8-bit native XGRP number */ >> + xgrp = (rix << 6) | bit; >> + /* Legacy 5-bit group number */ >> + grp = (xgrp >> 3) & 0x1f; >> + /* Inspect legacy mask by legacy group >> */ >> + if (mask & (1ull << grp)) >> + grp_msk.s.grp_msk |= 1ull << >> bit; >> + /* Pre-set to all 0's */ >> + } >> + for (mask_set = 0; mask_set < >> cvmx_sso_num_maskset(); mask_set++) { >> + csr_wr_node(node, >> CVMX_SSO_PPX_SX_GRPMSKX(core, mask_set, rix), >> + grp_msk.u64); >> + } >> + } >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + cvmx_sso_ppx_grp_msk_t grp_msk; >> + >> + grp_msk.s.grp_msk = mask; >> + csr_wr(CVMX_SSO_PPX_GRP_MSK(core_num), grp_msk.u64); >> + } else { >> + cvmx_pow_pp_grp_mskx_t grp_msk; >> + >> + grp_msk.u64 = csr_rd(CVMX_POW_PP_GRP_MSKX(core_num)); >> + grp_msk.s.grp_msk = mask & 0xffff; >> + csr_wr(CVMX_POW_PP_GRP_MSKX(core_num), grp_msk.u64); >> + } >> +} >> + >> +/** >> + * This function gets the group mask for a core. The group mask >> + * indicates which groups each core will accept work from. >> + * >> + * @param core_num core to apply mask to >> + * @return Group mask, one bit for up to 64 groups. >> + * Each 1 bit in the mask enables the core to accept >> work from >> + * the corresponding group. >> + * The CN68XX supports 64 groups, earlier models only >> support >> + * 16 groups. >> + * >> + * The CN78XX in backwards compatibility mode allows up to 32 >> groups, >> + * so the 'mask' argument has one bit for every of the legacy >> + * groups, and a '1' in the mask causes a total of 8 groups >> + * which share the legacy group numbher and 8 qos levels, >> + * to be enabled for the calling processor core. >> + * A '0' in the mask will disable the current core >> + * from receiving work from the associated group. >> + */ >> +static inline u64 cvmx_pow_get_group_mask(u64 core_num) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_sso_ppx_sx_grpmskx_t grp_msk; >> + unsigned int core, node, i; >> + int rix; /* Register index */ >> + u64 mask = 0; >> + >> + node = cvmx_coremask_core_to_node(core_num); >> + core = cvmx_coremask_core_on_node(core_num); >> + >> + /* 78xx: 256 groups divided into 4 X 64 bit registers >> */ >> + /* 73xx: 64 groups are in one register */ >> + for (rix = (cvmx_sso_num_xgrp() >> 6) - 1; rix >= 0; >> rix--) { >> + /* read only mask_set=0 (both 'set' was written >> same) */ >> + grp_msk.u64 = csr_rd_node(node, >> CVMX_SSO_PPX_SX_GRPMSKX(core, 0, rix)); >> + /* ASSUME: (this is how mask bits got written) >> */ >> + /* grp_mask[7:0]: all bits 0..7 are same */ >> + /* grp_mask[15:8]: all bits 8..15 are same, etc >> */ >> + /* DO: mask[7:0] = >> grp_mask.u64[56,48,40,32,24,16,8,0] */ >> + for (i = 0; i < 8; i++) >> + mask |= (grp_msk.u64 & ((u64)1 << (i * >> 8))) >> (7 * i); >> + /* we collected 8 MSBs in mask[7:0], <<=8 and >> continue */ >> + if (cvmx_likely(rix != 0)) >> + mask <<= 8; >> + } >> + return mask & 0xFFFFFFFF; >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + cvmx_sso_ppx_grp_msk_t grp_msk; >> + >> + grp_msk.u64 = csr_rd(CVMX_SSO_PPX_GRP_MSK(core_num)); >> + return grp_msk.u64; >> + } else { >> + cvmx_pow_pp_grp_mskx_t grp_msk; >> + >> + grp_msk.u64 = csr_rd(CVMX_POW_PP_GRP_MSKX(core_num)); >> + return grp_msk.u64 & 0xffff; >> + } >> +} >> + >> +/* >> + * Returns 0 if 78xx(73xx,75xx) is not programmed in legacy >> compatible mode >> + * Returns 1 if 78xx(73xx,75xx) is programmed in legacy compatible >> mode >> + * Returns 1 if octeon model is not 78xx(73xx,75xx) >> + */ >> +static inline u64 cvmx_pow_is_legacy78mode(u64 core_num) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_sso_ppx_sx_grpmskx_t grp_msk0, grp_msk1; >> + unsigned int core, node, i; >> + int rix; /* Register index */ >> + u64 mask = 0; >> + >> + node = cvmx_coremask_core_to_node(core_num); >> + core = cvmx_coremask_core_on_node(core_num); >> + >> + /* 78xx: 256 groups divided into 4 X 64 bit registers >> */ >> + /* 73xx: 64 groups are in one register */ >> + /* 1) in order for the 78_SSO to be in legacy >> compatible mode >> + * the both mask_sets should be programmed the same */ >> + for (rix = (cvmx_sso_num_xgrp() >> 6) - 1; rix >= 0; >> rix--) { >> + /* read mask_set=0 (both 'set' was written >> same) */ >> + grp_msk0.u64 = csr_rd_node(node, >> CVMX_SSO_PPX_SX_GRPMSKX(core, 0, rix)); >> + grp_msk1.u64 = csr_rd_node(node, >> CVMX_SSO_PPX_SX_GRPMSKX(core, 1, rix)); >> + if (grp_msk0.u64 != grp_msk1.u64) { >> + return 0; >> + } >> + /* (this is how mask bits should be written) */ >> + /* grp_mask[7:0]: all bits 0..7 are same */ >> + /* grp_mask[15:8]: all bits 8..15 are same, etc >> */ >> + /* 2) in order for the 78_SSO to be in legacy >> compatible >> + * mode above should be true (test only >> mask_set=0 */ >> + for (i = 0; i < 8; i++) { >> + mask = (grp_msk0.u64 >> (i << 3)) & >> 0xFF; >> + if (!(mask == 0 || mask == 0xFF)) { >> + return 0; >> + } >> + } >> + } >> + /* if we come here, the 78_SSO is in legacy compatible >> mode */ >> + } >> + return 1; /* the SSO/POW is in legacy (or compatible) mode */ >> +} >> + >> +/** >> + * This function sets POW static priorities for a core. Each input >> queue has >> + * an associated priority value. >> + * >> + * @param core_num core to apply priorities to >> + * @param priority Vector of 8 priorities, one per POW Input Queue >> (0-7). >> + * Highest priority is 0 and lowest is 7. A >> priority value >> + * of 0xF instructs POW to skip the Input Queue >> when >> + * scheduling to this specific core. >> + * NOTE: priorities should not have gaps in >> values, meaning >> + * {0,1,1,1,1,1,1,1} is a valid >> configuration while >> + * {0,2,2,2,2,2,2,2} is not. >> + */ >> +static inline void cvmx_pow_set_priority(u64 core_num, const u8 >> priority[]) >> +{ >> + /* Detect gaps between priorities and flag error */ >> + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + int i; >> + u32 prio_mask = 0; >> + >> + for (i = 0; i < 8; i++) >> + if (priority[i] != 0xF) >> + prio_mask |= 1 << priority[i]; >> + >> + if (prio_mask ^ ((1 << cvmx_pop(prio_mask)) - 1)) { >> + debug("ERROR: POW static priorities should be >> contiguous (0x%llx)\n", >> + (unsigned long long)prio_mask); >> + return; >> + } >> + } >> + >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + unsigned int group; >> + unsigned int node = cvmx_get_node_num(); >> + cvmx_sso_grpx_pri_t grp_pri; >> + >> + /*grp_pri.s.weight = 0x3f; these will be anyway >> overwritten */ >> + /*grp_pri.s.affinity = 0xf; by the next >> csr_rd_node(..), */ >> + >> + for (group = 0; group < cvmx_sso_num_xgrp(); group++) { >> + grp_pri.u64 = csr_rd_node(node, >> CVMX_SSO_GRPX_PRI(group)); >> + grp_pri.s.pri = priority[group & 0x7]; >> + csr_wr_node(node, CVMX_SSO_GRPX_PRI(group), >> grp_pri.u64); >> + } >> + >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + cvmx_sso_ppx_qos_pri_t qos_pri; >> + >> + qos_pri.u64 = csr_rd(CVMX_SSO_PPX_QOS_PRI(core_num)); >> + qos_pri.s.qos0_pri = priority[0]; >> + qos_pri.s.qos1_pri = priority[1]; >> + qos_pri.s.qos2_pri = priority[2]; >> + qos_pri.s.qos3_pri = priority[3]; >> + qos_pri.s.qos4_pri = priority[4]; >> + qos_pri.s.qos5_pri = priority[5]; >> + qos_pri.s.qos6_pri = priority[6]; >> + qos_pri.s.qos7_pri = priority[7]; >> + csr_wr(CVMX_SSO_PPX_QOS_PRI(core_num), qos_pri.u64); >> + } else { >> + /* POW priorities on CN5xxx .. CN66XX */ >> + cvmx_pow_pp_grp_mskx_t grp_msk; >> + >> + grp_msk.u64 = csr_rd(CVMX_POW_PP_GRP_MSKX(core_num)); >> + grp_msk.s.qos0_pri = priority[0]; >> + grp_msk.s.qos1_pri = priority[1]; >> + grp_msk.s.qos2_pri = priority[2]; >> + grp_msk.s.qos3_pri = priority[3]; >> + grp_msk.s.qos4_pri = priority[4]; >> + grp_msk.s.qos5_pri = priority[5]; >> + grp_msk.s.qos6_pri = priority[6]; >> + grp_msk.s.qos7_pri = priority[7]; >> + >> + csr_wr(CVMX_POW_PP_GRP_MSKX(core_num), grp_msk.u64); >> + } >> +} >> + >> +/** >> + * This function gets POW static priorities for a core. Each input >> queue has >> + * an associated priority value. >> + * >> + * @param[in] core_num core to get priorities for >> + * @param[out] priority Pointer to u8[] where to return priorities >> + * Vector of 8 priorities, one per POW Input Queue >> (0-7). >> + * Highest priority is 0 and lowest is 7. A >> priority value >> + * of 0xF instructs POW to skip the Input Queue >> when >> + * scheduling to this specific core. >> + * NOTE: priorities should not have gaps in >> values, meaning >> + * {0,1,1,1,1,1,1,1} is a valid >> configuration while >> + * {0,2,2,2,2,2,2,2} is not. >> + */ >> +static inline void cvmx_pow_get_priority(u64 core_num, u8 >> priority[]) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + unsigned int group; >> + unsigned int node = cvmx_get_node_num(); >> + cvmx_sso_grpx_pri_t grp_pri; >> + >> + /* read priority only from the first 8 groups */ >> + /* the next groups are programmed the same >> (periodicaly) */ >> + for (group = 0; group < 8 /*cvmx_sso_num_xgrp() */; >> group++) { >> + grp_pri.u64 = csr_rd_node(node, >> CVMX_SSO_GRPX_PRI(group)); >> + priority[group /* & 0x7 */] = grp_pri.s.pri; >> + } >> + >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + cvmx_sso_ppx_qos_pri_t qos_pri; >> + >> + qos_pri.u64 = csr_rd(CVMX_SSO_PPX_QOS_PRI(core_num)); >> + priority[0] = qos_pri.s.qos0_pri; >> + priority[1] = qos_pri.s.qos1_pri; >> + priority[2] = qos_pri.s.qos2_pri; >> + priority[3] = qos_pri.s.qos3_pri; >> + priority[4] = qos_pri.s.qos4_pri; >> + priority[5] = qos_pri.s.qos5_pri; >> + priority[6] = qos_pri.s.qos6_pri; >> + priority[7] = qos_pri.s.qos7_pri; >> + } else { >> + /* POW priorities on CN5xxx .. CN66XX */ >> + cvmx_pow_pp_grp_mskx_t grp_msk; >> + >> + grp_msk.u64 = csr_rd(CVMX_POW_PP_GRP_MSKX(core_num)); >> + priority[0] = grp_msk.s.qos0_pri; >> + priority[1] = grp_msk.s.qos1_pri; >> + priority[2] = grp_msk.s.qos2_pri; >> + priority[3] = grp_msk.s.qos3_pri; >> + priority[4] = grp_msk.s.qos4_pri; >> + priority[5] = grp_msk.s.qos5_pri; >> + priority[6] = grp_msk.s.qos6_pri; >> + priority[7] = grp_msk.s.qos7_pri; >> + } >> + >> + /* Detect gaps between priorities and flag error - (optional) >> */ >> + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + int i; >> + u32 prio_mask = 0; >> + >> + for (i = 0; i < 8; i++) >> + if (priority[i] != 0xF) >> + prio_mask |= 1 << priority[i]; >> + >> + if (prio_mask ^ ((1 << cvmx_pop(prio_mask)) - 1)) { >> + debug("ERROR:%s: POW static priorities should >> be contiguous (0x%llx)\n", >> + __func__, (unsigned long long)prio_mask); >> + return; >> + } >> + } >> +} >> + >> +static inline void cvmx_sso_get_group_priority(int node, cvmx_xgrp_t >> xgrp, int *priority, >> + int *weight, int >> *affinity) >> +{ >> + cvmx_sso_grpx_pri_t grp_pri; >> + >> + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + debug("ERROR: %s is not supported on this chip)\n", >> __func__); >> + return; >> + } >> + >> + grp_pri.u64 = csr_rd_node(node, CVMX_SSO_GRPX_PRI(xgrp.xgrp)); >> + *affinity = grp_pri.s.affinity; >> + *priority = grp_pri.s.pri; >> + *weight = grp_pri.s.weight; >> +} >> + >> +/** >> + * Performs a tag switch and then an immediate deschedule. This >> completes >> + * immediately, so completion must not be waited for. This function >> does NOT >> + * update the wqe in DRAM to match arguments. >> + * >> + * This function does NOT wait for any prior tag switches to >> complete, so the >> + * calling code must do this. >> + * >> + * Note the following CAVEAT of the Octeon HW behavior when >> + * re-scheduling DE-SCHEDULEd items whose (next) state is >> + * ORDERED: >> + * - If there are no switches pending at the time that the >> + * HW executes the de-schedule, the HW will only re-schedule >> + * the head of the FIFO associated with the given tag. This >> + * means that in many respects, the HW treats this ORDERED >> + * tag as an ATOMIC tag. Note that in the SWTAG_DESCH >> + * case (to an ORDERED tag), the HW will do the switch >> + * before the deschedule whenever it is possible to do >> + * the switch immediately, so it may often look like >> + * this case. >> + * - If there is a pending switch to ORDERED at the time >> + * the HW executes the de-schedule, the HW will perform >> + * the switch at the time it re-schedules, and will be >> + * able to reschedule any/all of the entries with the >> + * same tag. >> + * Due to this behavior, the RECOMMENDATION to software is >> + * that they have a (next) state of ATOMIC when they >> + * DE-SCHEDULE. If an ORDERED tag is what was really desired, >> + * SW can choose to immediately switch to an ORDERED tag >> + * after the work (that has an ATOMIC tag) is re-scheduled. >> + * Note that since there are never any tag switches pending >> + * when the HW re-schedules, this switch can be IMMEDIATE upon >> + * the reception of the pointer during the re-schedule. >> + * >> + * @param tag New tag value >> + * @param tag_type New tag type >> + * @param group New group value >> + * @param no_sched Control whether this work queue entry will be >> rescheduled. >> + * - 1 : don't schedule this work >> + * - 0 : allow this work to be scheduled. >> + */ >> +static inline void cvmx_pow_tag_sw_desched_nocheck(u32 tag, >> cvmx_pow_tag_type_t tag_type, u64 group, >> + u64 no_sched) >> +{ >> + union cvmx_pow_tag_req_addr ptr; >> + cvmx_pow_tag_req_t tag_req; >> + >> + if (CVMX_ENABLE_POW_CHECKS) { >> + cvmx_pow_tag_info_t current_tag; >> + >> + __cvmx_pow_warn_if_pending_switch(__func__); >> + current_tag = cvmx_pow_get_current_tag(); >> + cvmx_warn_if(current_tag.tag_type == >> CVMX_POW_TAG_TYPE_NULL_NULL, >> + "%s called with NULL_NULL tag\n", >> __func__); >> + cvmx_warn_if(current_tag.tag_type == >> CVMX_POW_TAG_TYPE_NULL, >> + "%s called with NULL tag. Deschedule not >> allowed from NULL state\n", >> + __func__); >> + cvmx_warn_if((current_tag.tag_type != >> CVMX_POW_TAG_TYPE_ATOMIC) && >> + (tag_type != CVMX_POW_TAG_TYPE_ATOMIC), >> + "%s called where neither the before or >> after tag is ATOMIC\n", >> + __func__); >> + } >> + tag_req.u64 = 0; >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_t *wqp = cvmx_pow_get_current_wqp(); >> + >> + if (!wqp) { >> + debug("ERROR: Failed to get WQE, %s\n", >> __func__); >> + return; >> + } >> + group &= 0x1f; >> + wqp->word1.cn78xx.tag = tag; >> + wqp->word1.cn78xx.tag_type = tag_type; >> + wqp->word1.cn78xx.grp = group << 3; >> + CVMX_SYNCWS; >> + tag_req.s_cn78xx_other.op = >> CVMX_POW_TAG_OP_SWTAG_DESCH; >> + tag_req.s_cn78xx_other.type = tag_type; >> + tag_req.s_cn78xx_other.grp = group << 3; >> + tag_req.s_cn78xx_other.no_sched = no_sched; >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + group &= 0x3f; >> + tag_req.s_cn68xx_other.op = >> CVMX_POW_TAG_OP_SWTAG_DESCH; >> + tag_req.s_cn68xx_other.tag = tag; >> + tag_req.s_cn68xx_other.type = tag_type; >> + tag_req.s_cn68xx_other.grp = group; >> + tag_req.s_cn68xx_other.no_sched = no_sched; >> + } else { >> + group &= 0x0f; >> + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_SWTAG_DESCH; >> + tag_req.s_cn38xx.tag = tag; >> + tag_req.s_cn38xx.type = tag_type; >> + tag_req.s_cn38xx.grp = group; >> + tag_req.s_cn38xx.no_sched = no_sched; >> + } >> + ptr.u64 = 0; >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + ptr.s.mem_region = CVMX_IO_SEG; >> + ptr.s.is_io = 1; >> + ptr.s.did = CVMX_OCT_DID_TAG_TAG3; >> + ptr.s_cn78xx.node = cvmx_get_node_num(); >> + ptr.s_cn78xx.tag = tag; >> + } else { >> + ptr.s.mem_region = CVMX_IO_SEG; >> + ptr.s.is_io = 1; >> + ptr.s.did = CVMX_OCT_DID_TAG_TAG3; >> + } >> + cvmx_write_io(ptr.u64, tag_req.u64); >> +} >> + >> +/** >> + * Performs a tag switch and then an immediate deschedule. This >> completes >> + * immediately, so completion must not be waited for. This function >> does NOT >> + * update the wqe in DRAM to match arguments. >> + * >> + * This function waits for any prior tag switches to complete, so >> the >> + * calling code may call this function with a pending tag switch. >> + * >> + * Note the following CAVEAT of the Octeon HW behavior when >> + * re-scheduling DE-SCHEDULEd items whose (next) state is >> + * ORDERED: >> + * - If there are no switches pending at the time that the >> + * HW executes the de-schedule, the HW will only re-schedule >> + * the head of the FIFO associated with the given tag. This >> + * means that in many respects, the HW treats this ORDERED >> + * tag as an ATOMIC tag. Note that in the SWTAG_DESCH >> + * case (to an ORDERED tag), the HW will do the switch >> + * before the deschedule whenever it is possible to do >> + * the switch immediately, so it may often look like >> + * this case. >> + * - If there is a pending switch to ORDERED at the time >> + * the HW executes the de-schedule, the HW will perform >> + * the switch at the time it re-schedules, and will be >> + * able to reschedule any/all of the entries with the >> + * same tag. >> + * Due to this behavior, the RECOMMENDATION to software is >> + * that they have a (next) state of ATOMIC when they >> + * DE-SCHEDULE. If an ORDERED tag is what was really desired, >> + * SW can choose to immediately switch to an ORDERED tag >> + * after the work (that has an ATOMIC tag) is re-scheduled. >> + * Note that since there are never any tag switches pending >> + * when the HW re-schedules, this switch can be IMMEDIATE upon >> + * the reception of the pointer during the re-schedule. >> + * >> + * @param tag New tag value >> + * @param tag_type New tag type >> + * @param group New group value >> + * @param no_sched Control whether this work queue entry will be >> rescheduled. >> + * - 1 : don't schedule this work >> + * - 0 : allow this work to be scheduled. >> + */ >> +static inline void cvmx_pow_tag_sw_desched(u32 tag, >> cvmx_pow_tag_type_t tag_type, u64 group, >> + u64 no_sched) >> +{ >> + /* Need to make sure any writes to the work queue entry are >> complete */ >> + CVMX_SYNCWS; >> + /* Ensure that there is not a pending tag switch, as a tag >> switch cannot be started >> + * if a previous switch is still pending. */ >> + cvmx_pow_tag_sw_wait(); >> + cvmx_pow_tag_sw_desched_nocheck(tag, tag_type, group, >> no_sched); >> +} >> + >> +/** >> + * Descchedules the current work queue entry. >> + * >> + * @param no_sched no schedule flag value to be set on the work >> queue entry. >> + * If this is set the entry will not be rescheduled. >> + */ >> +static inline void cvmx_pow_desched(u64 no_sched) >> +{ >> + union cvmx_pow_tag_req_addr ptr; >> + cvmx_pow_tag_req_t tag_req; >> + >> + if (CVMX_ENABLE_POW_CHECKS) { >> + cvmx_pow_tag_info_t current_tag; >> + >> + __cvmx_pow_warn_if_pending_switch(__func__); >> + current_tag = cvmx_pow_get_current_tag(); >> + cvmx_warn_if(current_tag.tag_type == >> CVMX_POW_TAG_TYPE_NULL_NULL, >> + "%s called with NULL_NULL tag\n", >> __func__); >> + cvmx_warn_if(current_tag.tag_type == >> CVMX_POW_TAG_TYPE_NULL, >> + "%s called with NULL tag. Deschedule not >> expected from NULL state\n", >> + __func__); >> + } >> + /* Need to make sure any writes to the work queue entry are >> complete */ >> + CVMX_SYNCWS; >> + >> + tag_req.u64 = 0; >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_DESCH; >> + tag_req.s_cn78xx_other.no_sched = no_sched; >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + tag_req.s_cn68xx_other.op = CVMX_POW_TAG_OP_DESCH; >> + tag_req.s_cn68xx_other.no_sched = no_sched; >> + } else { >> + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_DESCH; >> + tag_req.s_cn38xx.no_sched = no_sched; >> + } >> + ptr.u64 = 0; >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; >> + ptr.s_cn78xx.is_io = 1; >> + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_TAG3; >> + ptr.s_cn78xx.node = cvmx_get_node_num(); >> + } else { >> + ptr.s.mem_region = CVMX_IO_SEG; >> + ptr.s.is_io = 1; >> + ptr.s.did = CVMX_OCT_DID_TAG_TAG3; >> + } >> + cvmx_write_io(ptr.u64, tag_req.u64); >> +} >> + >> +/******************************************************************* >> ***********/ >> +/* OCTEON3-specific >> functions. */ >> +/******************************************************************* >> ***********/ >> +/** >> + * This function sets the the affinity of group to the cores in >> 78xx. >> + * It sets up all the cores in core_mask to accept work from the >> specified group. >> + * >> + * @param xgrp Group to accept work from, 0 - 255. >> + * @param core_mask Mask of all the cores which will accept work >> from this group >> + * @param mask_set Every core has set of 2 masks which can be set >> to accept work >> + * from 256 groups. At the time of get_work, cores can choose >> which mask_set >> + * to get work from. 'mask_set' values range from 0 to 3, where >> each of the >> + * two bits represents a mask set. Cores will be added to the >> mask set with >> + * corresponding bit set, and removed from the mask set with >> corresponding >> + * bit clear. >> + * Note: cores can only accept work from SSO groups on the same >> node, >> + * so the node number for the group is derived from the core number. >> + */ >> +static inline void cvmx_sso_set_group_core_affinity(cvmx_xgrp_t >> xgrp, >> + const struct >> cvmx_coremask *core_mask, >> + u8 mask_set) >> +{ >> + cvmx_sso_ppx_sx_grpmskx_t grp_msk; >> + int core; >> + int grp_index = xgrp.xgrp >> 6; >> + int bit_pos = xgrp.xgrp % 64; >> + >> + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + debug("ERROR: %s is not supported on this chip)\n", >> __func__); >> + return; >> + } >> + cvmx_coremask_for_each_core(core, core_mask) >> + { >> + unsigned int node, ncore; >> + u64 reg_addr; >> + >> + node = cvmx_coremask_core_to_node(core); >> + ncore = cvmx_coremask_core_on_node(core); >> + >> + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(ncore, 0, >> grp_index); >> + grp_msk.u64 = csr_rd_node(node, reg_addr); >> + >> + if (mask_set & 1) >> + grp_msk.s.grp_msk |= (1ull << bit_pos); >> + else >> + grp_msk.s.grp_msk &= ~(1ull << bit_pos); >> + >> + csr_wr_node(node, reg_addr, grp_msk.u64); >> + >> + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(ncore, 1, >> grp_index); >> + grp_msk.u64 = csr_rd_node(node, reg_addr); >> + >> + if (mask_set & 2) >> + grp_msk.s.grp_msk |= (1ull << bit_pos); >> + else >> + grp_msk.s.grp_msk &= ~(1ull << bit_pos); >> + >> + csr_wr_node(node, reg_addr, grp_msk.u64); >> + } >> +} >> + >> +/** >> + * This function sets the priority and group affinity arbitration >> for each group. >> + * >> + * @param node Node number >> + * @param xgrp Group 0 - 255 to apply mask parameters to >> + * @param priority Priority of the group relative to other groups >> + * 0x0 - highest priority >> + * 0x7 - lowest priority >> + * @param weight Cross-group arbitration weight to apply to this >> group. >> + * valid values are 1-63 >> + * h/w default is 0x3f >> + * @param affinity Processor affinity arbitration weight to apply >> to this group. >> + * If zero, affinity is disabled. >> + * valid values are 0-15 >> + * h/w default which is 0xf. >> + * @param modify_mask mask of the parameters which needs to be >> modified. >> + * enum cvmx_sso_group_modify_mask >> + * to modify only priority -- set bit0 >> + * to modify only weight -- set bit1 >> + * to modify only affinity -- set bit2 >> + */ >> +static inline void cvmx_sso_set_group_priority(int node, cvmx_xgrp_t >> xgrp, int priority, int weight, >> + int affinity, >> + enum >> cvmx_sso_group_modify_mask modify_mask) >> +{ >> + cvmx_sso_grpx_pri_t grp_pri; >> + >> + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + debug("ERROR: %s is not supported on this chip)\n", >> __func__); >> + return; >> + } >> + if (weight <= 0) >> + weight = 0x3f; /* Force HW default when out of range */ >> + >> + grp_pri.u64 = csr_rd_node(node, CVMX_SSO_GRPX_PRI(xgrp.xgrp)); >> + if (grp_pri.s.weight == 0) >> + grp_pri.s.weight = 0x3f; >> + if (modify_mask & CVMX_SSO_MODIFY_GROUP_PRIORITY) >> + grp_pri.s.pri = priority; >> + if (modify_mask & CVMX_SSO_MODIFY_GROUP_WEIGHT) >> + grp_pri.s.weight = weight; >> + if (modify_mask & CVMX_SSO_MODIFY_GROUP_AFFINITY) >> + grp_pri.s.affinity = affinity; >> + csr_wr_node(node, CVMX_SSO_GRPX_PRI(xgrp.xgrp), grp_pri.u64); >> +} >> + >> +/** >> + * Asynchronous work request. >> + * Only works on CN78XX style SSO. >> + * >> + * Work is requested from the SSO unit, and should later be checked >> with >> + * function cvmx_pow_work_response_async. >> + * This function does NOT wait for previous tag switches to >> complete, >> + * so the caller must ensure that there is not a pending tag switch. >> + * >> + * @param scr_addr Scratch memory address that response will be >> returned to, >> + * which is either a valid WQE, or a response with the invalid >> bit set. >> + * Byte address, must be 8 byte aligned. >> + * @param xgrp Group to receive work for (0-255). >> + * @param wait >> + * 1 to cause response to wait for work to become available (or >> timeout) >> + * 0 to cause response to return immediately >> + */ >> +static inline void cvmx_sso_work_request_grp_async_nocheck(int >> scr_addr, cvmx_xgrp_t xgrp, >> + cvmx_pow_wai >> t_t wait) >> +{ >> + cvmx_pow_iobdma_store_t data; >> + unsigned int node = cvmx_get_node_num(); >> + >> + if (CVMX_ENABLE_POW_CHECKS) { >> + __cvmx_pow_warn_if_pending_switch(__func__); >> + cvmx_warn_if(!octeon_has_feature(OCTEON_FEATURE_CN78XX_ >> WQE), "Not CN78XX"); >> + } >> + /* scr_addr must be 8 byte aligned */ >> + data.u64 = 0; >> + data.s_cn78xx.scraddr = scr_addr >> 3; >> + data.s_cn78xx.len = 1; >> + data.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; >> + data.s_cn78xx.grouped = 1; >> + data.s_cn78xx.index_grp_mask = (node << 8) | xgrp.xgrp; >> + data.s_cn78xx.wait = wait; >> + data.s_cn78xx.node = node; >> + >> + cvmx_send_single(data.u64); >> +} >> + >> +/** >> + * Synchronous work request from the node-local SSO without >> verifying >> + * pending tag switch. It requests work from a specific SSO group. >> + * >> + * @param lgrp The local group number (within the SSO of the node of >> the caller) >> + * from which to get the work. >> + * @param wait When set, call stalls until work becomes available, >> or times out. >> + * If not set, returns immediately. >> + * >> + * @return Returns the WQE pointer from SSO. >> + * Returns NULL if no work was available. >> + */ >> +static inline void *cvmx_sso_work_request_grp_sync_nocheck(unsigned >> int lgrp, cvmx_pow_wait_t wait) >> +{ >> + cvmx_pow_load_addr_t ptr; >> + cvmx_pow_tag_load_resp_t result; >> + unsigned int node = cvmx_get_node_num() & 3; >> + >> + if (CVMX_ENABLE_POW_CHECKS) { >> + __cvmx_pow_warn_if_pending_switch(__func__); >> + cvmx_warn_if(!octeon_has_feature(OCTEON_FEATURE_CN78XX_ >> WQE), "Not CN78XX"); >> + } >> + ptr.u64 = 0; >> + ptr.swork_78xx.mem_region = CVMX_IO_SEG; >> + ptr.swork_78xx.is_io = 1; >> + ptr.swork_78xx.did = CVMX_OCT_DID_TAG_SWTAG; >> + ptr.swork_78xx.node = node; >> + ptr.swork_78xx.grouped = 1; >> + ptr.swork_78xx.index = (lgrp & 0xff) | node << 8; >> + ptr.swork_78xx.wait = wait; >> + >> + result.u64 = csr_rd(ptr.u64); >> + if (result.s_work.no_work) >> + return NULL; >> + else >> + return cvmx_phys_to_ptr(result.s_work.addr); >> +} >> + >> +/** >> + * Synchronous work request from the node-local SSO. >> + * It requests work from a specific SSO group. >> + * This function waits for any previous tag switch to complete >> before >> + * requesting the new work. >> + * >> + * @param lgrp The node-local group number from which to get the >> work. >> + * @param wait When set, call stalls until work becomes available, >> or times out. >> + * If not set, returns immediately. >> + * >> + * @return The WQE pointer or NULL, if work is not available. >> + */ >> +static inline void *cvmx_sso_work_request_grp_sync(unsigned int >> lgrp, cvmx_pow_wait_t wait) >> +{ >> + cvmx_pow_tag_sw_wait(); >> + return cvmx_sso_work_request_grp_sync_nocheck(lgrp, wait); >> +} >> + >> +/** >> + * This function sets the group mask for a core. The group mask >> bits >> + * indicate which groups each core will accept work from. >> + * >> + * @param core_num Processor core to apply mask to. >> + * @param mask_set 7XXX has 2 sets of masks per core. >> + * Bit 0 represents the first mask set, bit 1 -- the second. >> + * @param xgrp_mask Group mask array. >> + * Total number of groups is divided into a number of >> + * 64-bits mask sets. Each bit in the mask, if set, enables >> + * the core to accept work from the corresponding group. >> + * >> + * NOTE: Each core can be configured to accept work in accordance to >> both >> + * mask sets, with the first having higher precedence over the >> second, >> + * or to accept work in accordance to just one of the two mask sets. >> + * The 'core_num' argument represents a processor core on any node >> + * in a coherent multi-chip system. >> + * >> + * If the 'mask_set' argument is 3, both mask sets are configured >> + * with the same value (which is not typically the intention), >> + * so keep in mind the function needs to be called twice >> + * to set a different value into each of the mask sets, >> + * once with 'mask_set=1' and second time with 'mask_set=2'. >> + */ >> +static inline void cvmx_pow_set_xgrp_mask(u64 core_num, u8 mask_set, >> const u64 xgrp_mask[]) >> +{ >> + unsigned int grp, node, core; >> + u64 reg_addr; >> + >> + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + debug("ERROR: %s is not supported on this chip)\n", >> __func__); >> + return; >> + } >> + >> + if (CVMX_ENABLE_POW_CHECKS) { >> + cvmx_warn_if(((mask_set < 1) || (mask_set > 3)), >> "Invalid mask set"); >> + } >> + >> + if ((mask_set < 1) || (mask_set > 3)) >> + mask_set = 3; >> + >> + node = cvmx_coremask_core_to_node(core_num); >> + core = cvmx_coremask_core_on_node(core_num); >> + >> + for (grp = 0; grp < (cvmx_sso_num_xgrp() >> 6); grp++) { >> + if (mask_set & 1) { >> + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(core, 0, >> grp), >> + csr_wr_node(node, reg_addr, xgrp_mask[grp]); >> + } >> + if (mask_set & 2) { >> + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(core, 1, >> grp), >> + csr_wr_node(node, reg_addr, xgrp_mask[grp]); >> + } >> + } >> +} >> + >> +/** >> + * This function gets the group mask for a core. The group mask >> bits >> + * indicate which groups each core will accept work from. >> + * >> + * @param core_num Processor core to apply mask to. >> + * @param mask_set 7XXX has 2 sets of masks per core. >> + * Bit 0 represents the first mask set, bit 1 -- the second. >> + * @param xgrp_mask Provide pointer to u64 mask[8] output array. >> + * Total number of groups is divided into a number of >> + * 64-bits mask sets. Each bit in the mask represents >> + * the core accepts work from the corresponding group. >> + * >> + * NOTE: Each core can be configured to accept work in accordance to >> both >> + * mask sets, with the first having higher precedence over the >> second, >> + * or to accept work in accordance to just one of the two mask sets. >> + * The 'core_num' argument represents a processor core on any node >> + * in a coherent multi-chip system. >> + */ >> +static inline void cvmx_pow_get_xgrp_mask(u64 core_num, u8 mask_set, >> u64 *xgrp_mask) >> +{ >> + cvmx_sso_ppx_sx_grpmskx_t grp_msk; >> + unsigned int grp, node, core; >> + u64 reg_addr; >> + >> + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + debug("ERROR: %s is not supported on this chip)\n", >> __func__); >> + return; >> + } >> + >> + if (CVMX_ENABLE_POW_CHECKS) { >> + cvmx_warn_if(mask_set != 1 && mask_set != 2, "Invalid >> mask set"); >> + } >> + >> + node = cvmx_coremask_core_to_node(core_num); >> + core = cvmx_coremask_core_on_node(core_num); >> + >> + for (grp = 0; grp < cvmx_sso_num_xgrp() >> 6; grp++) { >> + if (mask_set & 1) { >> + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(core, 0, >> grp), >> + grp_msk.u64 = csr_rd_node(node, reg_addr); >> + xgrp_mask[grp] = grp_msk.s.grp_msk; >> + } >> + if (mask_set & 2) { >> + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(core, 1, >> grp), >> + grp_msk.u64 = csr_rd_node(node, reg_addr); >> + xgrp_mask[grp] = grp_msk.s.grp_msk; >> + } >> + } >> +} >> + >> +/** >> + * Executes SSO SWTAG command. >> + * This is similar to cvmx_pow_tag_sw() function, but uses linear >> + * (vs. integrated group-qos) group index. >> + */ >> +static inline void cvmx_pow_tag_sw_node(cvmx_wqe_t *wqp, u32 tag, >> cvmx_pow_tag_type_t tag_type, >> + int node) >> +{ >> + union cvmx_pow_tag_req_addr ptr; >> + cvmx_pow_tag_req_t tag_req; >> + >> + if >> (cvmx_unlikely(!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE))) { >> + debug("ERROR: %s is supported on OCTEON3 only\n", >> __func__); >> + return; >> + } >> + CVMX_SYNCWS; >> + cvmx_pow_tag_sw_wait(); >> + >> + if (CVMX_ENABLE_POW_CHECKS) { >> + cvmx_pow_tag_info_t current_tag; >> + >> + __cvmx_pow_warn_if_pending_switch(__func__); >> + current_tag = cvmx_pow_get_current_tag(); >> + cvmx_warn_if(current_tag.tag_type == >> CVMX_POW_TAG_TYPE_NULL_NULL, >> + "%s called with NULL_NULL tag\n", >> __func__); >> + cvmx_warn_if(current_tag.tag_type == >> CVMX_POW_TAG_TYPE_NULL, >> + "%s called with NULL tag\n", __func__); >> + cvmx_warn_if((current_tag.tag_type == tag_type) && >> (current_tag.tag == tag), >> + "%s called to perform a tag switch to the >> same tag\n", __func__); >> + cvmx_warn_if( >> + tag_type == CVMX_POW_TAG_TYPE_NULL, >> + "%s called to perform a tag switch to NULL. Use >> cvmx_pow_tag_sw_null() instead\n", >> + __func__); >> + } >> + wqp->word1.cn78xx.tag = tag; >> + wqp->word1.cn78xx.tag_type = tag_type; >> + CVMX_SYNCWS; >> + >> + tag_req.u64 = 0; >> + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG; >> + tag_req.s_cn78xx_other.type = tag_type; >> + >> + ptr.u64 = 0; >> + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; >> + ptr.s_cn78xx.is_io = 1; >> + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; >> + ptr.s_cn78xx.node = node; >> + ptr.s_cn78xx.tag = tag; >> + cvmx_write_io(ptr.u64, tag_req.u64); >> +} >> + >> +/** >> + * Executes SSO SWTAG_FULL command. >> + * This is similar to cvmx_pow_tag_sw_full() function, but >> + * uses linear (vs. integrated group-qos) group index. >> + */ >> +static inline void cvmx_pow_tag_sw_full_node(cvmx_wqe_t *wqp, u32 >> tag, cvmx_pow_tag_type_t tag_type, >> + u8 xgrp, int node) >> +{ >> + union cvmx_pow_tag_req_addr ptr; >> + cvmx_pow_tag_req_t tag_req; >> + u16 gxgrp; >> + >> + if >> (cvmx_unlikely(!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE))) { >> + debug("ERROR: %s is supported on OCTEON3 only\n", >> __func__); >> + return; >> + } >> + /* Ensure that there is not a pending tag switch, as a tag >> switch cannot be >> + * started, if a previous switch is still pending. */ >> + CVMX_SYNCWS; >> + cvmx_pow_tag_sw_wait(); >> + >> + if (CVMX_ENABLE_POW_CHECKS) { >> + cvmx_pow_tag_info_t current_tag; >> + >> + __cvmx_pow_warn_if_pending_switch(__func__); >> + current_tag = cvmx_pow_get_current_tag(); >> + cvmx_warn_if(current_tag.tag_type == >> CVMX_POW_TAG_TYPE_NULL_NULL, >> + "%s called with NULL_NULL tag\n", >> __func__); >> + cvmx_warn_if((current_tag.tag_type == tag_type) && >> (current_tag.tag == tag), >> + "%s called to perform a tag switch to the >> same tag\n", __func__); >> + cvmx_warn_if( >> + tag_type == CVMX_POW_TAG_TYPE_NULL, >> + "%s called to perform a tag switch to NULL. Use >> cvmx_pow_tag_sw_null() instead\n", >> + __func__); >> + if ((wqp != cvmx_phys_to_ptr(0x80)) && >> cvmx_pow_get_current_wqp()) >> + cvmx_warn_if(wqp != cvmx_pow_get_current_wqp(), >> + "%s passed WQE(%p) doesn't match >> the address in the POW(%p)\n", >> + __func__, wqp, >> cvmx_pow_get_current_wqp()); >> + } >> + gxgrp = node; >> + gxgrp = gxgrp << 8 | xgrp; >> + wqp->word1.cn78xx.grp = gxgrp; >> + wqp->word1.cn78xx.tag = tag; >> + wqp->word1.cn78xx.tag_type = tag_type; >> + CVMX_SYNCWS; >> + >> + tag_req.u64 = 0; >> + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG_FULL; >> + tag_req.s_cn78xx_other.type = tag_type; >> + tag_req.s_cn78xx_other.grp = gxgrp; >> + tag_req.s_cn78xx_other.wqp = cvmx_ptr_to_phys(wqp); >> + >> + ptr.u64 = 0; >> + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; >> + ptr.s_cn78xx.is_io = 1; >> + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; >> + ptr.s_cn78xx.node = node; >> + ptr.s_cn78xx.tag = tag; >> + cvmx_write_io(ptr.u64, tag_req.u64); >> +} >> + >> +/** >> + * Submits work to an SSO group on any OCI node. >> + * This function updates the work queue entry in DRAM to match >> + * the arguments given. >> + * Note that the tag provided is for the work queue entry submitted, >> + * and is unrelated to the tag that the core currently holds. >> + * >> + * @param wqp pointer to work queue entry to submit. >> + * This entry is updated to match the other parameters >> + * @param tag tag value to be assigned to work queue entry >> + * @param tag_type type of tag >> + * @param xgrp native CN78XX group in the range 0..255 >> + * @param node The OCI node number for the target group >> + * >> + * When this function is called on a model prior to CN78XX, which >> does >> + * not support OCI nodes, the 'node' argument is ignored, and the >> 'xgrp' >> + * parameter is converted into 'qos' (the lower 3 bits) and 'grp' >> (the higher >> + * 5 bits), following the backward-compatibility scheme of >> translating >> + * between new and old style group numbers. >> + */ >> +static inline void cvmx_pow_work_submit_node(cvmx_wqe_t *wqp, u32 >> tag, cvmx_pow_tag_type_t tag_type, >> + u8 xgrp, u8 node) >> +{ >> + union cvmx_pow_tag_req_addr ptr; >> + cvmx_pow_tag_req_t tag_req; >> + u16 group; >> + >> + if >> (cvmx_unlikely(!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE))) { >> + debug("ERROR: %s is supported on OCTEON3 only\n", >> __func__); >> + return; >> + } >> + group = node; >> + group = group << 8 | xgrp; >> + wqp->word1.cn78xx.tag = tag; >> + wqp->word1.cn78xx.tag_type = tag_type; >> + wqp->word1.cn78xx.grp = group; >> + CVMX_SYNCWS; >> + >> + tag_req.u64 = 0; >> + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_ADDWQ; >> + tag_req.s_cn78xx_other.type = tag_type; >> + tag_req.s_cn78xx_other.wqp = cvmx_ptr_to_phys(wqp); >> + tag_req.s_cn78xx_other.grp = group; >> + >> + ptr.u64 = 0; >> + ptr.s_cn78xx.did = 0x66; // CVMX_OCT_DID_TAG_TAG6; >> + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; >> + ptr.s_cn78xx.is_io = 1; >> + ptr.s_cn78xx.node = node; >> + ptr.s_cn78xx.tag = tag; >> + >> + /* SYNC write to memory before the work submit. This is >> necessary >> + ** as POW may read values from DRAM at this time */ >> + CVMX_SYNCWS; >> + cvmx_write_io(ptr.u64, tag_req.u64); >> +} >> + >> +/** >> + * Executes the SSO SWTAG_DESCHED operation. >> + * This is similar to the cvmx_pow_tag_sw_desched() function, but >> + * uses linear (vs. unified group-qos) group index. >> + */ >> +static inline void cvmx_pow_tag_sw_desched_node(cvmx_wqe_t *wqe, u32 >> tag, >> + cvmx_pow_tag_type_t >> tag_type, u8 xgrp, u64 no_sched, >> + u8 node) >> +{ >> + union cvmx_pow_tag_req_addr ptr; >> + cvmx_pow_tag_req_t tag_req; >> + u16 group; >> + >> + if >> (cvmx_unlikely(!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE))) { >> + debug("ERROR: %s is supported on OCTEON3 only\n", >> __func__); >> + return; >> + } >> + /* Need to make sure any writes to the work queue entry are >> complete */ >> + CVMX_SYNCWS; >> + /* >> + * Ensure that there is not a pending tag switch, as a tag >> switch cannot >> + * be started if a previous switch is still pending. >> + */ >> + cvmx_pow_tag_sw_wait(); >> + >> + if (CVMX_ENABLE_POW_CHECKS) { >> + cvmx_pow_tag_info_t current_tag; >> + >> + __cvmx_pow_warn_if_pending_switch(__func__); >> + current_tag = cvmx_pow_get_current_tag(); >> + cvmx_warn_if(current_tag.tag_type == >> CVMX_POW_TAG_TYPE_NULL_NULL, >> + "%s called with NULL_NULL tag\n", >> __func__); >> + cvmx_warn_if(current_tag.tag_type == >> CVMX_POW_TAG_TYPE_NULL, >> + "%s called with NULL tag. Deschedule not >> allowed from NULL state\n", >> + __func__); >> + cvmx_warn_if((current_tag.tag_type != >> CVMX_POW_TAG_TYPE_ATOMIC) && >> + (tag_type != CVMX_POW_TAG_TYPE_ATOMIC), >> + "%s called where neither the before or >> after tag is ATOMIC\n", >> + __func__); >> + } >> + group = node; >> + group = group << 8 | xgrp; >> + wqe->word1.cn78xx.tag = tag; >> + wqe->word1.cn78xx.tag_type = tag_type; >> + wqe->word1.cn78xx.grp = group; >> + CVMX_SYNCWS; >> + >> + tag_req.u64 = 0; >> + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG_DESCH; >> + tag_req.s_cn78xx_other.type = tag_type; >> + tag_req.s_cn78xx_other.grp = group; >> + tag_req.s_cn78xx_other.no_sched = no_sched; >> + >> + ptr.u64 = 0; >> + ptr.s.mem_region = CVMX_IO_SEG; >> + ptr.s.is_io = 1; >> + ptr.s.did = CVMX_OCT_DID_TAG_TAG3; >> + ptr.s_cn78xx.node = node; >> + ptr.s_cn78xx.tag = tag; >> + cvmx_write_io(ptr.u64, tag_req.u64); >> +} >> + >> +/* Executes the UPD_WQP_GRP SSO operation. >> + * >> + * @param wqp Pointer to the new work queue entry to switch to. >> + * @param xgrp SSO group in the range 0..255 >> + * >> + * NOTE: The operation can be performed only on the local node. >> + */ >> +static inline void cvmx_sso_update_wqp_group(cvmx_wqe_t *wqp, u8 >> xgrp) >> +{ >> + union cvmx_pow_tag_req_addr addr; >> + cvmx_pow_tag_req_t data; >> + int node = cvmx_get_node_num(); >> + int group = node << 8 | xgrp; >> + >> + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + debug("ERROR: %s is not supported on this chip)\n", >> __func__); >> + return; >> + } >> + wqp->word1.cn78xx.grp = group; >> + CVMX_SYNCWS; >> + >> + data.u64 = 0; >> + data.s_cn78xx_other.op = CVMX_POW_TAG_OP_UPDATE_WQP_GRP; >> + data.s_cn78xx_other.grp = group; >> + data.s_cn78xx_other.wqp = cvmx_ptr_to_phys(wqp); >> + >> + addr.u64 = 0; >> + addr.s_cn78xx.mem_region = CVMX_IO_SEG; >> + addr.s_cn78xx.is_io = 1; >> + addr.s_cn78xx.did = CVMX_OCT_DID_TAG_TAG1; >> + addr.s_cn78xx.node = node; >> + cvmx_write_io(addr.u64, data.u64); >> +} >> + >> +/******************************************************************* >> ***********/ >> +/* Define usage of bits within the 32 bit tag >> values. */ >> +/******************************************************************* >> ***********/ >> +/* >> + * Number of bits of the tag used by software. The SW bits >> + * are always a contiguous block of the high starting at bit 31. >> + * The hardware bits are always the low bits. By default, the top 8 >> bits >> + * of the tag are reserved for software, and the low 24 are set by >> the IPD unit. >> + */ >> +#define CVMX_TAG_SW_BITS (8) >> +#define CVMX_TAG_SW_SHIFT (32 - CVMX_TAG_SW_BITS) >> + >> +/* Below is the list of values for the top 8 bits of the tag. */ >> +/* >> + * Tag values with top byte of this value are reserved for internal >> executive >> + * uses >> + */ >> +#define CVMX_TAG_SW_BITS_INTERNAL 0x1 >> + >> +/* >> + * The executive divides the remaining 24 bits as follows: >> + * the upper 8 bits (bits 23 - 16 of the tag) define a subgroup >> + * the lower 16 bits (bits 15 - 0 of the tag) define are the value >> with >> + * the subgroup. Note that this section describes the format of tags >> generated >> + * by software - refer to the hardware documentation for a >> description of the >> + * tags values generated by the packet input hardware. >> + * Subgroups are defined here >> + */ >> + >> +/* Mask for the value portion of the tag */ >> +#define CVMX_TAG_SUBGROUP_MASK 0xFFFF >> +#define CVMX_TAG_SUBGROUP_SHIFT 16 >> +#define CVMX_TAG_SUBGROUP_PKO 0x1 >> + >> +/* End of executive tag subgroup definitions */ >> + >> +/* The remaining values software bit values 0x2 - 0xff are available >> + * for application use */ >> + >> +/** >> + * This function creates a 32 bit tag value from the two values >> provided. >> + * >> + * @param sw_bits The upper bits (number depends on configuration) >> are set >> + * to this value. The remainder of bits are set by the hw_bits >> parameter. >> + * @param hw_bits The lower bits (number depends on configuration) >> are set >> + * to this value. The remainder of bits are set by the sw_bits >> parameter. >> + * >> + * @return 32 bit value of the combined hw and sw bits. >> + */ >> +static inline u32 cvmx_pow_tag_compose(u64 sw_bits, u64 hw_bits) >> +{ >> + return (((sw_bits & cvmx_build_mask(CVMX_TAG_SW_BITS)) << >> CVMX_TAG_SW_SHIFT) | >> + (hw_bits & cvmx_build_mask(32 - CVMX_TAG_SW_BITS))); >> +} >> + >> +/** >> + * Extracts the bits allocated for software use from the tag >> + * >> + * @param tag 32 bit tag value >> + * >> + * @return N bit software tag value, where N is configurable with >> + * the CVMX_TAG_SW_BITS define >> + */ >> +static inline u32 cvmx_pow_tag_get_sw_bits(u64 tag) >> +{ >> + return ((tag >> (32 - CVMX_TAG_SW_BITS)) & >> cvmx_build_mask(CVMX_TAG_SW_BITS)); >> +} >> + >> +/** >> + * >> + * Extracts the bits allocated for hardware use from the tag >> + * >> + * @param tag 32 bit tag value >> + * >> + * @return (32 - N) bit software tag value, where N is configurable >> with >> + * the CVMX_TAG_SW_BITS define >> + */ >> +static inline u32 cvmx_pow_tag_get_hw_bits(u64 tag) >> +{ >> + return (tag & cvmx_build_mask(32 - CVMX_TAG_SW_BITS)); >> +} >> + >> +static inline u64 cvmx_sso3_get_wqe_count(int node) >> +{ >> + cvmx_sso_grpx_aq_cnt_t aq_cnt; >> + unsigned int grp = 0; >> + u64 cnt = 0; >> + >> + for (grp = 0; grp < cvmx_sso_num_xgrp(); grp++) { >> + aq_cnt.u64 = csr_rd_node(node, >> CVMX_SSO_GRPX_AQ_CNT(grp)); >> + cnt += aq_cnt.s.aq_cnt; >> + } >> + return cnt; >> +} >> + >> +static inline u64 cvmx_sso_get_total_wqe_count(void) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + int node = cvmx_get_node_num(); >> + >> + return cvmx_sso3_get_wqe_count(node); >> + } else if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { >> + cvmx_sso_iq_com_cnt_t sso_iq_com_cnt; >> + >> + sso_iq_com_cnt.u64 = csr_rd(CVMX_SSO_IQ_COM_CNT); >> + return (sso_iq_com_cnt.s.iq_cnt); >> + } else { >> + cvmx_pow_iq_com_cnt_t pow_iq_com_cnt; >> + >> + pow_iq_com_cnt.u64 = csr_rd(CVMX_POW_IQ_COM_CNT); >> + return (pow_iq_com_cnt.s.iq_cnt); >> + } >> +} >> + >> +/** >> + * Store the current POW internal state into the supplied >> + * buffer. It is recommended that you pass a buffer of at least >> + * 128KB. The format of the capture may change based on SDK >> + * version and Octeon chip. >> + * >> + * @param buffer Buffer to store capture into >> + * @param buffer_size The size of the supplied buffer >> + * >> + * @return Zero on success, negative on failure >> + */ >> +int cvmx_pow_capture(void *buffer, int buffer_size); >> + >> +/** >> + * Dump a POW capture to the console in a human readable format. >> + * >> + * @param buffer POW capture from cvmx_pow_capture() >> + * @param buffer_size Size of the buffer >> + */ >> +void cvmx_pow_display(void *buffer, int buffer_size); >> + >> +/** >> + * Return the number of POW entries supported by this chip >> + * >> + * @return Number of POW entries >> + */ >> +int cvmx_pow_get_num_entries(void); >> +int cvmx_pow_get_dump_size(void); >> + >> +/** >> + * This will allocate count number of SSO groups on the specified >> node to the >> + * calling application. These groups will be for exclusive use of >> the >> + * application until they are freed. >> + * @param node The numa node for the allocation. >> + * @param base_group Pointer to the initial group, -1 to allocate >> anywhere. >> + * @param count The number of consecutive groups to allocate. >> + * @return 0 on success and -1 on failure. >> + */ >> +int cvmx_sso_reserve_group_range(int node, int *base_group, int >> count); >> +#define cvmx_sso_allocate_group_range cvmx_sso_reserve_group_range >> +int cvmx_sso_reserve_group(int node); >> +#define cvmx_sso_allocate_group cvmx_sso_reserve_group >> +int cvmx_sso_release_group_range(int node, int base_group, int >> count); >> +int cvmx_sso_release_group(int node, int group); >> + >> +/** >> + * Show integrated SSO configuration. >> + * >> + * @param node node number >> + */ >> +int cvmx_sso_config_dump(unsigned int node); >> + >> +/** >> + * Show integrated SSO statistics. >> + * >> + * @param node node number >> + */ >> +int cvmx_sso_stats_dump(unsigned int node); >> + >> +/** >> + * Clear integrated SSO statistics. >> + * >> + * @param node node number >> + */ >> +int cvmx_sso_stats_clear(unsigned int node); >> + >> +/** >> + * Show SSO core-group affinity and priority per node (multi-node >> systems) >> + */ >> +void cvmx_pow_mask_priority_dump_node(unsigned int node, struct >> cvmx_coremask *avail_coremask); >> + >> +/** >> + * Show POW/SSO core-group affinity and priority (legacy, single- >> node systems) >> + */ >> +static inline void cvmx_pow_mask_priority_dump(struct cvmx_coremask >> *avail_coremask) >> +{ >> + cvmx_pow_mask_priority_dump_node(0 /*node */, avail_coremask); >> +} >> + >> +/** >> + * Show SSO performance counters (multi-node systems) >> + */ >> +void cvmx_pow_show_perf_counters_node(unsigned int node); >> + >> +/** >> + * Show POW/SSO performance counters (legacy, single-node systems) >> + */ >> +static inline void cvmx_pow_show_perf_counters(void) >> +{ >> + cvmx_pow_show_perf_counters_node(0 /*node */); >> +} >> + >> +#endif /* __CVMX_POW_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-qlm.h >> b/arch/mips/mach-octeon/include/mach/cvmx-qlm.h >> new file mode 100644 >> index 000000000000..19915eb82c51 >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-qlm.h >> @@ -0,0 +1,304 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + */ >> + >> +#ifndef __CVMX_QLM_H__ >> +#define __CVMX_QLM_H__ >> + >> +/* >> + * Interface 0 on the 78xx can be connected to qlm 0 or qlm 2. When >> interface >> + * 0 is connected to qlm 0, this macro must be set to 0. When >> interface 0 is >> + * connected to qlm 2, this macro must be set to 1. >> + */ >> +#define MUX_78XX_IFACE0 0 >> + >> +/* >> + * Interface 1 on the 78xx can be connected to qlm 1 or qlm 3. When >> interface >> + * 1 is connected to qlm 1, this macro must be set to 0. When >> interface 1 is >> + * connected to qlm 3, this macro must be set to 1. >> + */ >> +#define MUX_78XX_IFACE1 0 >> + >> +/* Uncomment this line to print QLM JTAG state */ >> +/* #define CVMX_QLM_DUMP_STATE 1 */ >> + >> +typedef struct { >> + const char *name; >> + int stop_bit; >> + int start_bit; >> +} __cvmx_qlm_jtag_field_t; >> + >> +/** >> + * Return the number of QLMs supported by the chip >> + * >> + * @return Number of QLMs >> + */ >> +int cvmx_qlm_get_num(void); >> + >> +/** >> + * Return the qlm number based on the interface >> + * >> + * @param xiface Interface to look >> + */ >> +int cvmx_qlm_interface(int xiface); >> + >> +/** >> + * Return the qlm number based for a port in the interface >> + * >> + * @param xiface interface to look up >> + * @param index index in an interface >> + * >> + * @return the qlm number based on the xiface >> + */ >> +int cvmx_qlm_lmac(int xiface, int index); >> + >> +/** >> + * Return if only DLM5/DLM6/DLM5+DLM6 is used by BGX >> + * >> + * @param BGX BGX to search for. >> + * >> + * @return muxes used 0 = DLM5+DLM6, 1 = DLM5, 2 = DLM6. >> + */ >> +int cvmx_qlm_mux_interface(int bgx); >> + >> +/** >> + * Return number of lanes for a given qlm >> + * >> + * @param qlm QLM block to query >> + * >> + * @return Number of lanes >> + */ >> +int cvmx_qlm_get_lanes(int qlm); >> + >> +/** >> + * Get the QLM JTAG fields based on Octeon model on the supported >> chips. >> + * >> + * @return qlm_jtag_field_t structure >> + */ >> +const __cvmx_qlm_jtag_field_t *cvmx_qlm_jtag_get_field(void); >> + >> +/** >> + * Get the QLM JTAG length by going through qlm_jtag_field for each >> + * Octeon model that is supported >> + * >> + * @return return the length. >> + */ >> +int cvmx_qlm_jtag_get_length(void); >> + >> +/** >> + * Initialize the QLM layer >> + */ >> +void cvmx_qlm_init(void); >> + >> +/** >> + * Get a field in a QLM JTAG chain >> + * >> + * @param qlm QLM to get >> + * @param lane Lane in QLM to get >> + * @param name String name of field >> + * >> + * @return JTAG field value >> + */ >> +u64 cvmx_qlm_jtag_get(int qlm, int lane, const char *name); >> + >> +/** >> + * Set a field in a QLM JTAG chain >> + * >> + * @param qlm QLM to set >> + * @param lane Lane in QLM to set, or -1 for all lanes >> + * @param name String name of field >> + * @param value Value of the field >> + */ >> +void cvmx_qlm_jtag_set(int qlm, int lane, const char *name, u64 >> value); >> + >> +/** >> + * Errata G-16094: QLM Gen2 Equalizer Default Setting Change. >> + * CN68XX pass 1.x and CN66XX pass 1.x QLM tweak. This function >> tweaks the >> + * JTAG setting for a QLMs to run better at 5 and 6.25Ghz. >> + */ >> +void __cvmx_qlm_speed_tweak(void); >> + >> +/** >> + * Errata G-16174: QLM Gen2 PCIe IDLE DAC change. >> + * CN68XX pass 1.x, CN66XX pass 1.x and CN63XX pass 1.0-2.2 QLM >> tweak. >> + * This function tweaks the JTAG setting for a QLMs for PCIe to run >> better. >> + */ >> +void __cvmx_qlm_pcie_idle_dac_tweak(void); >> + >> +void __cvmx_qlm_pcie_cfg_rxd_set_tweak(int qlm, int lane); >> + >> +/** >> + * Get the speed (Gbaud) of the QLM in Mhz. >> + * >> + * @param qlm QLM to examine >> + * >> + * @return Speed in Mhz >> + */ >> +int cvmx_qlm_get_gbaud_mhz(int qlm); >> +/** >> + * Get the speed (Gbaud) of the QLM in Mhz on specific node. >> + * >> + * @param node Target QLM node >> + * @param qlm QLM to examine >> + * >> + * @return Speed in Mhz >> + */ >> +int cvmx_qlm_get_gbaud_mhz_node(int node, int qlm); >> + >> +enum cvmx_qlm_mode { >> + CVMX_QLM_MODE_DISABLED = -1, >> + CVMX_QLM_MODE_SGMII = 1, >> + CVMX_QLM_MODE_XAUI, >> + CVMX_QLM_MODE_RXAUI, >> + CVMX_QLM_MODE_PCIE, /* gen3 / gen2 / gen1 */ >> + CVMX_QLM_MODE_PCIE_1X2, /* 1x2 gen2 / gen1 */ >> + CVMX_QLM_MODE_PCIE_2X1, /* 2x1 gen2 / gen1 */ >> + CVMX_QLM_MODE_PCIE_1X1, /* 1x1 gen2 / gen1 */ >> + CVMX_QLM_MODE_SRIO_1X4, /* 1x4 short / long */ >> + CVMX_QLM_MODE_SRIO_2X2, /* 2x2 short / long */ >> + CVMX_QLM_MODE_SRIO_4X1, /* 4x1 short / long */ >> + CVMX_QLM_MODE_ILK, >> + CVMX_QLM_MODE_QSGMII, >> + CVMX_QLM_MODE_SGMII_SGMII, >> + CVMX_QLM_MODE_SGMII_DISABLED, >> + CVMX_QLM_MODE_DISABLED_SGMII, >> + CVMX_QLM_MODE_SGMII_QSGMII, >> + CVMX_QLM_MODE_QSGMII_QSGMII, >> + CVMX_QLM_MODE_QSGMII_DISABLED, >> + CVMX_QLM_MODE_DISABLED_QSGMII, >> + CVMX_QLM_MODE_QSGMII_SGMII, >> + CVMX_QLM_MODE_RXAUI_1X2, >> + CVMX_QLM_MODE_SATA_2X1, >> + CVMX_QLM_MODE_XLAUI, >> + CVMX_QLM_MODE_XFI, >> + CVMX_QLM_MODE_10G_KR, >> + CVMX_QLM_MODE_40G_KR4, >> + CVMX_QLM_MODE_PCIE_1X8, /* 1x8 gen3 / gen2 / gen1 */ >> + CVMX_QLM_MODE_RGMII_SGMII, >> + CVMX_QLM_MODE_RGMII_XFI, >> + CVMX_QLM_MODE_RGMII_10G_KR, >> + CVMX_QLM_MODE_RGMII_RXAUI, >> + CVMX_QLM_MODE_RGMII_XAUI, >> + CVMX_QLM_MODE_RGMII_XLAUI, >> + CVMX_QLM_MODE_RGMII_40G_KR4, >> + CVMX_QLM_MODE_MIXED, /* BGX2 is mixed mode, >> DLM5(SGMII) & DLM6(XFI) */ >> + CVMX_QLM_MODE_SGMII_2X1, /* Configure BGX2 separate for DLM5 & >> DLM6 */ >> + CVMX_QLM_MODE_10G_KR_1X2, /* Configure BGX2 separate for DLM5 & >> DLM6 */ >> + CVMX_QLM_MODE_XFI_1X2, /* Configure BGX2 separate >> for DLM5 & DLM6 */ >> + CVMX_QLM_MODE_RGMII_SGMII_1X1, /* Configure BGX2, applies to >> DLM5 */ >> + CVMX_QLM_MODE_RGMII_SGMII_2X1, /* Configure BGX2, applies to >> DLM6 */ >> + CVMX_QLM_MODE_RGMII_10G_KR_1X1, /* Configure BGX2, applies to >> DLM6 */ >> + CVMX_QLM_MODE_RGMII_XFI_1X1, /* Configure BGX2, applies to >> DLM6 */ >> + CVMX_QLM_MODE_SDL, /* RMAC Pipe */ >> + CVMX_QLM_MODE_CPRI, /* RMAC */ >> + CVMX_QLM_MODE_OCI >> +}; >> + >> +enum cvmx_gmx_inf_mode { >> + CVMX_GMX_INF_MODE_DISABLED = 0, >> + CVMX_GMX_INF_MODE_SGMII = 1, /* Other interface can be SGMII >> or QSGMII */ >> + CVMX_GMX_INF_MODE_QSGMII = 2, /* Other interface can be SGMII >> or QSGMII */ >> + CVMX_GMX_INF_MODE_RXAUI = 3, /* Only interface 0, interface 1 >> must be DISABLED */ >> +}; >> + >> +/** >> + * Eye diagram captures are stored in the following structure >> + */ >> +typedef struct { >> + int width; /* Width in the x direction (time) */ >> + int height; /* Height in the y direction (voltage) */ >> + u32 data[64][128]; /* Error count at location, saturates as max >> */ >> +} cvmx_qlm_eye_t; >> + >> +/** >> + * These apply to DLM1 and DLM2 if its not in SATA mode >> + * Manual refers to lanes as follows: >> + * DML 0 lane 0 == GSER0 lane 0 >> + * DML 0 lane 1 == GSER0 lane 1 >> + * DML 1 lane 2 == GSER1 lane 0 >> + * DML 1 lane 3 == GSER1 lane 1 >> + * DML 2 lane 4 == GSER2 lane 0 >> + * DML 2 lane 5 == GSER2 lane 1 >> + */ >> +enum cvmx_pemx_cfg_mode { >> + CVMX_PEM_MD_GEN2_2LANE = 0, /* Valid for PEM0(DLM1), PEM1(DLM2) >> */ >> + CVMX_PEM_MD_GEN2_1LANE = 1, /* Valid for PEM0(DLM1.0), >> PEM1(DLM1.1,DLM2.0), PEM2(DLM2.1) */ >> + CVMX_PEM_MD_GEN2_4LANE = 2, /* Valid for PEM0(DLM1-2) */ >> + /* Reserved */ >> + CVMX_PEM_MD_GEN1_2LANE = 4, /* Valid for PEM0(DLM1), PEM1(DLM2) >> */ >> + CVMX_PEM_MD_GEN1_1LANE = 5, /* Valid for PEM0(DLM1.0), >> PEM1(DLM1.1,DLM2.0), PEM2(DLM2.1) */ >> + CVMX_PEM_MD_GEN1_4LANE = 6, /* Valid for PEM0(DLM1-2) */ >> + /* Reserved */ >> +}; >> + >> +/* >> + * Read QLM and return mode. >> + */ >> +enum cvmx_qlm_mode cvmx_qlm_get_mode(int qlm); >> +enum cvmx_qlm_mode cvmx_qlm_get_mode_cn78xx(int node, int qlm); >> +enum cvmx_qlm_mode cvmx_qlm_get_dlm_mode(int dlm_mode, int >> interface); >> +void __cvmx_qlm_set_mult(int qlm, int baud_mhz, int old_multiplier); >> + >> +void cvmx_qlm_display_registers(int qlm); >> + >> +int cvmx_qlm_measure_clock(int qlm); >> + >> +/** >> + * Measure the reference clock of a QLM on a multi-node setup >> + * >> + * @param node node to measure >> + * @param qlm QLM to measure >> + * >> + * @return Clock rate in Hz >> + */ >> +int cvmx_qlm_measure_clock_node(int node, int qlm); >> + >> +/* >> + * Perform RX equalization on a QLM >> + * >> + * @param node Node the QLM is on >> + * @param qlm QLM to perform RX equalization on >> + * @param lane Lane to use, or -1 for all lanes >> + * >> + * @return Zero on success, negative if any lane failed RX >> equalization >> + */ >> +int __cvmx_qlm_rx_equalization(int node, int qlm, int lane); >> + >> +/** >> + * Errata GSER-27882 -GSER 10GBASE-KR Transmit Equalizer >> + * Training may not update PHY Tx Taps. This function is not static >> + * so we can share it with BGX KR >> + * >> + * @param node Node to apply errata workaround >> + * @param qlm QLM to apply errata workaround >> + * @param lane Lane to apply the errata >> + */ >> +int cvmx_qlm_gser_errata_27882(int node, int qlm, int lane); >> + >> +void cvmx_qlm_gser_errata_25992(int node, int qlm); >> + >> +#ifdef CVMX_DUMP_GSER >> +/** >> + * Dump GSER configuration for node 0 >> + */ >> +int cvmx_dump_gser_config(unsigned int gser); >> +/** >> + * Dump GSER status for node 0 >> + */ >> +int cvmx_dump_gser_status(unsigned int gser); >> +/** >> + * Dump GSER configuration >> + */ >> +int cvmx_dump_gser_config_node(unsigned int node, unsigned int >> gser); >> +/** >> + * Dump GSER status >> + */ >> +int cvmx_dump_gser_status_node(unsigned int node, unsigned int >> gser); >> +#endif >> + >> +int cvmx_qlm_eye_display(int node, int qlm, int qlm_lane, int >> format, const cvmx_qlm_eye_t *eye); >> + >> +void cvmx_prbs_process_cmd(int node, int qlm, int mode); >> + >> +#endif /* __CVMX_QLM_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-scratch.h >> b/arch/mips/mach-octeon/include/mach/cvmx-scratch.h >> new file mode 100644 >> index 000000000000..d567a8453b7a >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-scratch.h >> @@ -0,0 +1,113 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * This file provides support for the processor local scratch >> memory. >> + * Scratch memory is byte addressable - all addresses are byte >> addresses. >> + */ >> + >> +#ifndef __CVMX_SCRATCH_H__ >> +#define __CVMX_SCRATCH_H__ >> + >> +/* Note: This define must be a long, not a long long in order to >> compile >> + without warnings for both 32bit and 64bit. */ >> +#define CVMX_SCRATCH_BASE (-32768l) /* 0xffffffffffff8000 */ >> + >> +/* Scratch line for LMTST/LMTDMA on Octeon3 models */ >> +#ifdef CVMX_CAVIUM_OCTEON3 >> +#define CVMX_PKO_LMTLINE 2ull >> +#endif >> + >> +/** >> + * Reads an 8 bit value from the processor local scratchpad memory. >> + * >> + * @param address byte address to read from >> + * >> + * @return value read >> + */ >> +static inline u8 cvmx_scratch_read8(u64 address) >> +{ >> + return *CASTPTR(volatile u8, CVMX_SCRATCH_BASE + address); >> +} >> + >> +/** >> + * Reads a 16 bit value from the processor local scratchpad memory. >> + * >> + * @param address byte address to read from >> + * >> + * @return value read >> + */ >> +static inline u16 cvmx_scratch_read16(u64 address) >> +{ >> + return *CASTPTR(volatile u16, CVMX_SCRATCH_BASE + address); >> +} >> + >> +/** >> + * Reads a 32 bit value from the processor local scratchpad memory. >> + * >> + * @param address byte address to read from >> + * >> + * @return value read >> + */ >> +static inline u32 cvmx_scratch_read32(u64 address) >> +{ >> + return *CASTPTR(volatile u32, CVMX_SCRATCH_BASE + address); >> +} >> + >> +/** >> + * Reads a 64 bit value from the processor local scratchpad memory. >> + * >> + * @param address byte address to read from >> + * >> + * @return value read >> + */ >> +static inline u64 cvmx_scratch_read64(u64 address) >> +{ >> + return *CASTPTR(volatile u64, CVMX_SCRATCH_BASE + address); >> +} >> + >> +/** >> + * Writes an 8 bit value to the processor local scratchpad memory. >> + * >> + * @param address byte address to write to >> + * @param value value to write >> + */ >> +static inline void cvmx_scratch_write8(u64 address, u64 value) >> +{ >> + *CASTPTR(volatile u8, CVMX_SCRATCH_BASE + address) = (u8)value; >> +} >> + >> +/** >> + * Writes a 32 bit value to the processor local scratchpad memory. >> + * >> + * @param address byte address to write to >> + * @param value value to write >> + */ >> +static inline void cvmx_scratch_write16(u64 address, u64 value) >> +{ >> + *CASTPTR(volatile u16, CVMX_SCRATCH_BASE + address) = >> (u16)value; >> +} >> + >> +/** >> + * Writes a 16 bit value to the processor local scratchpad memory. >> + * >> + * @param address byte address to write to >> + * @param value value to write >> + */ >> +static inline void cvmx_scratch_write32(u64 address, u64 value) >> +{ >> + *CASTPTR(volatile u32, CVMX_SCRATCH_BASE + address) = >> (u32)value; >> +} >> + >> +/** >> + * Writes a 64 bit value to the processor local scratchpad memory. >> + * >> + * @param address byte address to write to >> + * @param value value to write >> + */ >> +static inline void cvmx_scratch_write64(u64 address, u64 value) >> +{ >> + *CASTPTR(volatile u64, CVMX_SCRATCH_BASE + address) = value; >> +} >> + >> +#endif /* __CVMX_SCRATCH_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/cvmx-wqe.h >> b/arch/mips/mach-octeon/include/mach/cvmx-wqe.h >> new file mode 100644 >> index 000000000000..c9e3c8312a65 >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/cvmx-wqe.h >> @@ -0,0 +1,1462 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + * >> + * This header file defines the work queue entry (wqe) data >> structure. >> + * Since this is a commonly used structure that depends on >> structures >> + * from several hardware blocks, those definitions have been placed >> + * in this file to create a single point of definition of the wqe >> + * format. >> + * Data structures are still named according to the block that they >> + * relate to. >> + */ >> + >> +#ifndef __CVMX_WQE_H__ >> +#define __CVMX_WQE_H__ >> + >> +#include "cvmx-packet.h" >> +#include "cvmx-csr-enums.h" >> +#include "cvmx-pki-defs.h" >> +#include "cvmx-pip-defs.h" >> +#include "octeon-feature.h" >> + >> +#define OCT_TAG_TYPE_STRING(x) >> \ >> + (((x) == CVMX_POW_TAG_TYPE_ORDERED) ? >> \ >> + "ORDERED" : >> \ >> + (((x) == CVMX_POW_TAG_TYPE_ATOMIC) ? >> \ >> + "ATOMIC" : >> \ >> + (((x) == CVMX_POW_TAG_TYPE_NULL) ? "NULL" : "NULL_NULL"))) >> + >> +/* Error levels in WQE WORD2 (ERRLEV).*/ >> +#define PKI_ERRLEV_E__RE_M 0x0 >> +#define PKI_ERRLEV_E__LA_M 0x1 >> +#define PKI_ERRLEV_E__LB_M 0x2 >> +#define PKI_ERRLEV_E__LC_M 0x3 >> +#define PKI_ERRLEV_E__LD_M 0x4 >> +#define PKI_ERRLEV_E__LE_M 0x5 >> +#define PKI_ERRLEV_E__LF_M 0x6 >> +#define PKI_ERRLEV_E__LG_M 0x7 >> + >> +enum cvmx_pki_errlevel { >> + CVMX_PKI_ERRLEV_E_RE = PKI_ERRLEV_E__RE_M, >> + CVMX_PKI_ERRLEV_E_LA = PKI_ERRLEV_E__LA_M, >> + CVMX_PKI_ERRLEV_E_LB = PKI_ERRLEV_E__LB_M, >> + CVMX_PKI_ERRLEV_E_LC = PKI_ERRLEV_E__LC_M, >> + CVMX_PKI_ERRLEV_E_LD = PKI_ERRLEV_E__LD_M, >> + CVMX_PKI_ERRLEV_E_LE = PKI_ERRLEV_E__LE_M, >> + CVMX_PKI_ERRLEV_E_LF = PKI_ERRLEV_E__LF_M, >> + CVMX_PKI_ERRLEV_E_LG = PKI_ERRLEV_E__LG_M >> +}; >> + >> +#define CVMX_PKI_ERRLEV_MAX BIT(3) /* The size of WORD2:ERRLEV >> field.*/ >> + >> +/* Error code in WQE WORD2 (OPCODE).*/ >> +#define CVMX_PKI_OPCODE_RE_NONE 0x0 >> +#define CVMX_PKI_OPCODE_RE_PARTIAL 0x1 >> +#define CVMX_PKI_OPCODE_RE_JABBER 0x2 >> +#define CVMX_PKI_OPCODE_RE_FCS 0x7 >> +#define CVMX_PKI_OPCODE_RE_FCS_RCV 0x8 >> +#define CVMX_PKI_OPCODE_RE_TERMINATE 0x9 >> +#define CVMX_PKI_OPCODE_RE_RX_CTL 0xb >> +#define CVMX_PKI_OPCODE_RE_SKIP 0xc >> +#define CVMX_PKI_OPCODE_RE_DMAPKT 0xf >> +#define CVMX_PKI_OPCODE_RE_PKIPAR 0x13 >> +#define CVMX_PKI_OPCODE_RE_PKIPCAM 0x14 >> +#define CVMX_PKI_OPCODE_RE_MEMOUT 0x15 >> +#define CVMX_PKI_OPCODE_RE_BUFS_OFLOW 0x16 >> +#define CVMX_PKI_OPCODE_L2_FRAGMENT 0x20 >> +#define CVMX_PKI_OPCODE_L2_OVERRUN 0x21 >> +#define CVMX_PKI_OPCODE_L2_PFCS 0x22 >> +#define CVMX_PKI_OPCODE_L2_PUNY 0x23 >> +#define CVMX_PKI_OPCODE_L2_MAL 0x24 >> +#define CVMX_PKI_OPCODE_L2_OVERSIZE 0x25 >> +#define CVMX_PKI_OPCODE_L2_UNDERSIZE 0x26 >> +#define CVMX_PKI_OPCODE_L2_LENMISM 0x27 >> +#define CVMX_PKI_OPCODE_IP_NOT 0x41 >> +#define CVMX_PKI_OPCODE_IP_CHK 0x42 >> +#define CVMX_PKI_OPCODE_IP_MAL 0x43 >> +#define CVMX_PKI_OPCODE_IP_MALD 0x44 >> +#define CVMX_PKI_OPCODE_IP_HOP 0x45 >> +#define CVMX_PKI_OPCODE_L4_MAL 0x61 >> +#define CVMX_PKI_OPCODE_L4_CHK 0x62 >> +#define CVMX_PKI_OPCODE_L4_LEN 0x63 >> +#define CVMX_PKI_OPCODE_L4_PORT 0x64 >> +#define CVMX_PKI_OPCODE_TCP_FLAG 0x65 >> + >> +#define CVMX_PKI_OPCODE_MAX BIT(8) /* The size of WORD2:OPCODE >> field.*/ >> + >> +/* Layer types in pki */ >> +#define CVMX_PKI_LTYPE_E_NONE_M 0x0 >> +#define CVMX_PKI_LTYPE_E_ENET_M 0x1 >> +#define CVMX_PKI_LTYPE_E_VLAN_M 0x2 >> +#define CVMX_PKI_LTYPE_E_SNAP_PAYLD_M 0x5 >> +#define CVMX_PKI_LTYPE_E_ARP_M 0x6 >> +#define CVMX_PKI_LTYPE_E_RARP_M 0x7 >> +#define CVMX_PKI_LTYPE_E_IP4_M 0x8 >> +#define CVMX_PKI_LTYPE_E_IP4_OPT_M 0x9 >> +#define CVMX_PKI_LTYPE_E_IP6_M 0xA >> +#define CVMX_PKI_LTYPE_E_IP6_OPT_M 0xB >> +#define CVMX_PKI_LTYPE_E_IPSEC_ESP_M 0xC >> +#define CVMX_PKI_LTYPE_E_IPFRAG_M 0xD >> +#define CVMX_PKI_LTYPE_E_IPCOMP_M 0xE >> +#define CVMX_PKI_LTYPE_E_TCP_M 0x10 >> +#define CVMX_PKI_LTYPE_E_UDP_M 0x11 >> +#define CVMX_PKI_LTYPE_E_SCTP_M 0x12 >> +#define CVMX_PKI_LTYPE_E_UDP_VXLAN_M 0x13 >> +#define CVMX_PKI_LTYPE_E_GRE_M 0x14 >> +#define CVMX_PKI_LTYPE_E_NVGRE_M 0x15 >> +#define CVMX_PKI_LTYPE_E_GTP_M 0x16 >> +#define CVMX_PKI_LTYPE_E_SW28_M 0x1C >> +#define CVMX_PKI_LTYPE_E_SW29_M 0x1D >> +#define CVMX_PKI_LTYPE_E_SW30_M 0x1E >> +#define CVMX_PKI_LTYPE_E_SW31_M 0x1F >> + >> +enum cvmx_pki_layer_type { >> + CVMX_PKI_LTYPE_E_NONE = CVMX_PKI_LTYPE_E_NONE_M, >> + CVMX_PKI_LTYPE_E_ENET = CVMX_PKI_LTYPE_E_ENET_M, >> + CVMX_PKI_LTYPE_E_VLAN = CVMX_PKI_LTYPE_E_VLAN_M, >> + CVMX_PKI_LTYPE_E_SNAP_PAYLD = CVMX_PKI_LTYPE_E_SNAP_PAYLD_M, >> + CVMX_PKI_LTYPE_E_ARP = CVMX_PKI_LTYPE_E_ARP_M, >> + CVMX_PKI_LTYPE_E_RARP = CVMX_PKI_LTYPE_E_RARP_M, >> + CVMX_PKI_LTYPE_E_IP4 = CVMX_PKI_LTYPE_E_IP4_M, >> + CVMX_PKI_LTYPE_E_IP4_OPT = CVMX_PKI_LTYPE_E_IP4_OPT_M, >> + CVMX_PKI_LTYPE_E_IP6 = CVMX_PKI_LTYPE_E_IP6_M, >> + CVMX_PKI_LTYPE_E_IP6_OPT = CVMX_PKI_LTYPE_E_IP6_OPT_M, >> + CVMX_PKI_LTYPE_E_IPSEC_ESP = CVMX_PKI_LTYPE_E_IPSEC_ESP_M, >> + CVMX_PKI_LTYPE_E_IPFRAG = CVMX_PKI_LTYPE_E_IPFRAG_M, >> + CVMX_PKI_LTYPE_E_IPCOMP = CVMX_PKI_LTYPE_E_IPCOMP_M, >> + CVMX_PKI_LTYPE_E_TCP = CVMX_PKI_LTYPE_E_TCP_M, >> + CVMX_PKI_LTYPE_E_UDP = CVMX_PKI_LTYPE_E_UDP_M, >> + CVMX_PKI_LTYPE_E_SCTP = CVMX_PKI_LTYPE_E_SCTP_M, >> + CVMX_PKI_LTYPE_E_UDP_VXLAN = CVMX_PKI_LTYPE_E_UDP_VXLAN_M, >> + CVMX_PKI_LTYPE_E_GRE = CVMX_PKI_LTYPE_E_GRE_M, >> + CVMX_PKI_LTYPE_E_NVGRE = CVMX_PKI_LTYPE_E_NVGRE_M, >> + CVMX_PKI_LTYPE_E_GTP = CVMX_PKI_LTYPE_E_GTP_M, >> + CVMX_PKI_LTYPE_E_SW28 = CVMX_PKI_LTYPE_E_SW28_M, >> + CVMX_PKI_LTYPE_E_SW29 = CVMX_PKI_LTYPE_E_SW29_M, >> + CVMX_PKI_LTYPE_E_SW30 = CVMX_PKI_LTYPE_E_SW30_M, >> + CVMX_PKI_LTYPE_E_SW31 = CVMX_PKI_LTYPE_E_SW31_M, >> + CVMX_PKI_LTYPE_E_MAX = CVMX_PKI_LTYPE_E_SW31 >> +}; >> + >> +typedef union { >> + u64 u64; >> + struct { >> + u64 ptr_vlan : 8; >> + u64 ptr_layer_g : 8; >> + u64 ptr_layer_f : 8; >> + u64 ptr_layer_e : 8; >> + u64 ptr_layer_d : 8; >> + u64 ptr_layer_c : 8; >> + u64 ptr_layer_b : 8; >> + u64 ptr_layer_a : 8; >> + }; >> +} cvmx_pki_wqe_word4_t; >> + >> +/** >> + * HW decode / err_code in work queue entry >> + */ >> +typedef union { >> + u64 u64; >> + struct { >> + u64 bufs : 8; >> + u64 ip_offset : 8; >> + u64 vlan_valid : 1; >> + u64 vlan_stacked : 1; >> + u64 unassigned : 1; >> + u64 vlan_cfi : 1; >> + u64 vlan_id : 12; >> + u64 varies : 12; >> + u64 dec_ipcomp : 1; >> + u64 tcp_or_udp : 1; >> + u64 dec_ipsec : 1; >> + u64 is_v6 : 1; >> + u64 software : 1; >> + u64 L4_error : 1; >> + u64 is_frag : 1; >> + u64 IP_exc : 1; >> + u64 is_bcast : 1; >> + u64 is_mcast : 1; >> + u64 not_IP : 1; >> + u64 rcv_error : 1; >> + u64 err_code : 8; >> + } s; >> + struct { >> + u64 bufs : 8; >> + u64 ip_offset : 8; >> + u64 vlan_valid : 1; >> + u64 vlan_stacked : 1; >> + u64 unassigned : 1; >> + u64 vlan_cfi : 1; >> + u64 vlan_id : 12; >> + u64 port : 12; >> + u64 dec_ipcomp : 1; >> + u64 tcp_or_udp : 1; >> + u64 dec_ipsec : 1; >> + u64 is_v6 : 1; >> + u64 software : 1; >> + u64 L4_error : 1; >> + u64 is_frag : 1; >> + u64 IP_exc : 1; >> + u64 is_bcast : 1; >> + u64 is_mcast : 1; >> + u64 not_IP : 1; >> + u64 rcv_error : 1; >> + u64 err_code : 8; >> + } s_cn68xx; >> + struct { >> + u64 bufs : 8; >> + u64 ip_offset : 8; >> + u64 vlan_valid : 1; >> + u64 vlan_stacked : 1; >> + u64 unassigned : 1; >> + u64 vlan_cfi : 1; >> + u64 vlan_id : 12; >> + u64 pr : 4; >> + u64 unassigned2a : 4; >> + u64 unassigned2 : 4; >> + u64 dec_ipcomp : 1; >> + u64 tcp_or_udp : 1; >> + u64 dec_ipsec : 1; >> + u64 is_v6 : 1; >> + u64 software : 1; >> + u64 L4_error : 1; >> + u64 is_frag : 1; >> + u64 IP_exc : 1; >> + u64 is_bcast : 1; >> + u64 is_mcast : 1; >> + u64 not_IP : 1; >> + u64 rcv_error : 1; >> + u64 err_code : 8; >> + } s_cn38xx; >> + struct { >> + u64 unused1 : 16; >> + u64 vlan : 16; >> + u64 unused2 : 32; >> + } svlan; >> + struct { >> + u64 bufs : 8; >> + u64 unused : 8; >> + u64 vlan_valid : 1; >> + u64 vlan_stacked : 1; >> + u64 unassigned : 1; >> + u64 vlan_cfi : 1; >> + u64 vlan_id : 12; >> + u64 varies : 12; >> + u64 unassigned2 : 4; >> + u64 software : 1; >> + u64 unassigned3 : 1; >> + u64 is_rarp : 1; >> + u64 is_arp : 1; >> + u64 is_bcast : 1; >> + u64 is_mcast : 1; >> + u64 not_IP : 1; >> + u64 rcv_error : 1; >> + u64 err_code : 8; >> + } snoip; >> + struct { >> + u64 bufs : 8; >> + u64 unused : 8; >> + u64 vlan_valid : 1; >> + u64 vlan_stacked : 1; >> + u64 unassigned : 1; >> + u64 vlan_cfi : 1; >> + u64 vlan_id : 12; >> + u64 port : 12; >> + u64 unassigned2 : 4; >> + u64 software : 1; >> + u64 unassigned3 : 1; >> + u64 is_rarp : 1; >> + u64 is_arp : 1; >> + u64 is_bcast : 1; >> + u64 is_mcast : 1; >> + u64 not_IP : 1; >> + u64 rcv_error : 1; >> + u64 err_code : 8; >> + } snoip_cn68xx; >> + struct { >> + u64 bufs : 8; >> + u64 unused : 8; >> + u64 vlan_valid : 1; >> + u64 vlan_stacked : 1; >> + u64 unassigned : 1; >> + u64 vlan_cfi : 1; >> + u64 vlan_id : 12; >> + u64 pr : 4; >> + u64 unassigned2a : 8; >> + u64 unassigned2 : 4; >> + u64 software : 1; >> + u64 unassigned3 : 1; >> + u64 is_rarp : 1; >> + u64 is_arp : 1; >> + u64 is_bcast : 1; >> + u64 is_mcast : 1; >> + u64 not_IP : 1; >> + u64 rcv_error : 1; >> + u64 err_code : 8; >> + } snoip_cn38xx; >> +} cvmx_pip_wqe_word2_t; >> + >> +typedef union { >> + u64 u64; >> + struct { >> + u64 software : 1; >> + u64 lg_hdr_type : 5; >> + u64 lf_hdr_type : 5; >> + u64 le_hdr_type : 5; >> + u64 ld_hdr_type : 5; >> + u64 lc_hdr_type : 5; >> + u64 lb_hdr_type : 5; >> + u64 is_la_ether : 1; >> + u64 rsvd_0 : 8; >> + u64 vlan_valid : 1; >> + u64 vlan_stacked : 1; >> + u64 stat_inc : 1; >> + u64 pcam_flag4 : 1; >> + u64 pcam_flag3 : 1; >> + u64 pcam_flag2 : 1; >> + u64 pcam_flag1 : 1; >> + u64 is_frag : 1; >> + u64 is_l3_bcast : 1; >> + u64 is_l3_mcast : 1; >> + u64 is_l2_bcast : 1; >> + u64 is_l2_mcast : 1; >> + u64 is_raw : 1; >> + u64 err_level : 3; >> + u64 err_code : 8; >> + }; >> +} cvmx_pki_wqe_word2_t; >> + >> +typedef union { >> + u64 u64; >> + cvmx_pki_wqe_word2_t pki; >> + cvmx_pip_wqe_word2_t pip; >> +} cvmx_wqe_word2_t; >> + >> +typedef union { >> + u64 u64; >> + struct { >> + u16 hw_chksum; >> + u8 unused; >> + u64 next_ptr : 40; >> + } cn38xx; >> + struct { >> + u64 l4ptr : 8; /* 56..63 */ >> + u64 unused0 : 8; /* 48..55 */ >> + u64 l3ptr : 8; /* 40..47 */ >> + u64 l2ptr : 8; /* 32..39 */ >> + u64 unused1 : 18; /* 14..31 */ >> + u64 bpid : 6; /* 8..13 */ >> + u64 unused2 : 2; /* 6..7 */ >> + u64 pknd : 6; /* 0..5 */ >> + } cn68xx; >> +} cvmx_pip_wqe_word0_t; >> + >> +typedef union { >> + u64 u64; >> + struct { >> + u64 rsvd_0 : 4; >> + u64 aura : 12; >> + u64 rsvd_1 : 1; >> + u64 apad : 3; >> + u64 channel : 12; >> + u64 bufs : 8; >> + u64 style : 8; >> + u64 rsvd_2 : 10; >> + u64 pknd : 6; >> + }; >> +} cvmx_pki_wqe_word0_t; >> + >> +/* Use reserved bit, set by HW to 0, to indicate buf_ptr legacy >> translation*/ >> +#define pki_wqe_translated word0.rsvd_1 >> + >> +typedef union { >> + u64 u64; >> + cvmx_pip_wqe_word0_t pip; >> + cvmx_pki_wqe_word0_t pki; >> + struct { >> + u64 unused : 24; >> + u64 next_ptr : 40; /* On cn68xx this is unused as well >> */ >> + } raw; >> +} cvmx_wqe_word0_t; >> + >> +typedef union { >> + u64 u64; >> + struct { >> + u64 len : 16; >> + u64 rsvd_0 : 2; >> + u64 rsvd_1 : 2; >> + u64 grp : 10; >> + cvmx_pow_tag_type_t tag_type : 2; >> + u64 tag : 32; >> + }; >> +} cvmx_pki_wqe_word1_t; >> + >> +#define pki_errata20776 word1.rsvd_0 >> + >> +typedef union { >> + u64 u64; >> + struct { >> + u64 len : 16; >> + u64 varies : 14; >> + cvmx_pow_tag_type_t tag_type : 2; >> + u64 tag : 32; >> + }; >> + cvmx_pki_wqe_word1_t cn78xx; >> + struct { >> + u64 len : 16; >> + u64 zero_0 : 1; >> + u64 qos : 3; >> + u64 zero_1 : 1; >> + u64 grp : 6; >> + u64 zero_2 : 3; >> + cvmx_pow_tag_type_t tag_type : 2; >> + u64 tag : 32; >> + } cn68xx; >> + struct { >> + u64 len : 16; >> + u64 ipprt : 6; >> + u64 qos : 3; >> + u64 grp : 4; >> + u64 zero_2 : 1; >> + cvmx_pow_tag_type_t tag_type : 2; >> + u64 tag : 32; >> + } cn38xx; >> +} cvmx_wqe_word1_t; >> + >> +typedef union { >> + u64 u64; >> + struct { >> + u64 rsvd_0 : 8; >> + u64 hwerr : 8; >> + u64 rsvd_1 : 24; >> + u64 sqid : 8; >> + u64 rsvd_2 : 4; >> + u64 vfnum : 12; >> + }; >> +} cvmx_wqe_word3_t; >> + >> +typedef union { >> + u64 u64; >> + struct { >> + u64 rsvd_0 : 21; >> + u64 sqfc : 11; >> + u64 rsvd_1 : 5; >> + u64 sqtail : 11; >> + u64 rsvd_2 : 3; >> + u64 sqhead : 13; >> + }; >> +} cvmx_wqe_word4_t; >> + >> +/** >> + * Work queue entry format. >> + * Must be 8-byte aligned. >> + */ >> +typedef struct cvmx_wqe_s { >> + /*------------------------------------------------------------- >> ------*/ >> + /* WORD >> 0 */ >> + /*------------------------------------------------------------- >> ------*/ >> + /* HW WRITE: the following 64 bits are filled by HW when a >> packet >> + * arrives. >> + */ >> + cvmx_wqe_word0_t word0; >> + >> + /*------------------------------------------------------------- >> ------*/ >> + /* WORD >> 1 */ >> + /*------------------------------------------------------------- >> ------*/ >> + /* HW WRITE: the following 64 bits are filled by HW when a >> packet >> + * arrives. >> + */ >> + cvmx_wqe_word1_t word1; >> + >> + /*------------------------------------------------------------- >> ------*/ >> + /* WORD >> 2 */ >> + /*------------------------------------------------------------- >> ------*/ >> + /* HW WRITE: the following 64-bits are filled in by hardware >> when a >> + * packet arrives. This indicates a variety of status and error >> + *conditions. >> + */ >> + cvmx_pip_wqe_word2_t word2; >> + >> + /* Pointer to the first segment of the packet. */ >> + cvmx_buf_ptr_t packet_ptr; >> + >> + /* HW WRITE: OCTEON will fill in a programmable amount from the >> packet, >> + * up to (at most, but perhaps less) the amount needed to fill >> the work >> + * queue entry to 128 bytes. If the packet is recognized to be >> IP, the >> + * hardware starts (except that the IPv4 header is padded for >> + * appropriate alignment) writing here where the IP header >> starts. >> + * If the packet is not recognized to be IP, the hardware >> starts >> + * writing the beginning of the packet here. >> + */ >> + u8 packet_data[96]; >> + >> + /* If desired, SW can make the work Q entry any length. For the >> purposes >> + * of discussion here, Assume 128B always, as this is all that >> the hardware >> + * deals with. >> + */ >> +} CVMX_CACHE_LINE_ALIGNED cvmx_wqe_t; >> + >> +/** >> + * Work queue entry format for NQM >> + * Must be 8-byte aligned >> + */ >> +typedef struct cvmx_wqe_nqm_s { >> + /*------------------------------------------------------------- >> ------*/ >> + /* WORD >> 0 */ >> + /*------------------------------------------------------------- >> ------*/ >> + /* HW WRITE: the following 64 bits are filled by HW when a >> packet >> + * arrives. >> + */ >> + cvmx_wqe_word0_t word0; >> + >> + /*------------------------------------------------------------- >> ------*/ >> + /* WORD >> 1 */ >> + /*------------------------------------------------------------- >> ------*/ >> + /* HW WRITE: the following 64 bits are filled by HW when a >> packet >> + * arrives. >> + */ >> + cvmx_wqe_word1_t word1; >> + >> + /*------------------------------------------------------------- >> ------*/ >> + /* WORD >> 2 */ >> + /*------------------------------------------------------------- >> ------*/ >> + /* Reserved */ >> + u64 word2; >> + >> + /*------------------------------------------------------------- >> ------*/ >> + /* WORD >> 3 */ >> + /*------------------------------------------------------------- >> ------*/ >> + /* NVMe specific information.*/ >> + cvmx_wqe_word3_t word3; >> + >> + /*------------------------------------------------------------- >> ------*/ >> + /* WORD >> 4 */ >> + /*------------------------------------------------------------- >> ------*/ >> + /* NVMe specific information.*/ >> + cvmx_wqe_word4_t word4; >> + >> + /* HW WRITE: OCTEON will fill in a programmable amount from the >> packet, >> + * up to (at most, but perhaps less) the amount needed to fill >> the work >> + * queue entry to 128 bytes. If the packet is recognized to be >> IP, the >> + * hardware starts (except that the IPv4 header is padded for >> + * appropriate alignment) writing here where the IP header >> starts. >> + * If the packet is not recognized to be IP, the hardware >> starts >> + * writing the beginning of the packet here. >> + */ >> + u8 packet_data[88]; >> + >> + /* If desired, SW can make the work Q entry any length. >> + * For the purposes of discussion here, assume 128B always, as >> this is >> + * all that the hardware deals with. >> + */ >> +} CVMX_CACHE_LINE_ALIGNED cvmx_wqe_nqm_t; >> + >> +/** >> + * Work queue entry format for 78XX. >> + * In 78XX packet data always resides in WQE buffer unless option >> + * DIS_WQ_DAT=1 in PKI_STYLE_BUF, which causes packet data to use >> separate buffer. >> + * >> + * Must be 8-byte aligned. >> + */ >> +typedef struct { >> + /*------------------------------------------------------------- >> ------*/ >> + /* WORD >> 0 */ >> + /*------------------------------------------------------------- >> ------*/ >> + /* HW WRITE: the following 64 bits are filled by HW when a >> packet >> + * arrives. >> + */ >> + cvmx_pki_wqe_word0_t word0; >> + >> + /*------------------------------------------------------------- >> ------*/ >> + /* WORD >> 1 */ >> + /*------------------------------------------------------------- >> ------*/ >> + /* HW WRITE: the following 64 bits are filled by HW when a >> packet >> + * arrives. >> + */ >> + cvmx_pki_wqe_word1_t word1; >> + >> + /*------------------------------------------------------------- >> ------*/ >> + /* WORD >> 2 */ >> + /*------------------------------------------------------------- >> ------*/ >> + /* HW WRITE: the following 64-bits are filled in by hardware >> when a >> + * packet arrives. This indicates a variety of status and error >> + * conditions. >> + */ >> + cvmx_pki_wqe_word2_t word2; >> + >> + /*------------------------------------------------------------- >> ------*/ >> + /* WORD >> 3 */ >> + /*------------------------------------------------------------- >> ------*/ >> + /* Pointer to the first segment of the packet.*/ >> + cvmx_buf_ptr_pki_t packet_ptr; >> + >> + /*------------------------------------------------------------- >> ------*/ >> + /* WORD >> 4 */ >> + /*------------------------------------------------------------- >> ------*/ >> + /* HW WRITE: the following 64-bits are filled in by hardware >> when a >> + * packet arrives contains a byte pointer to the start of Layer >> + * A/B/C/D/E/F/G relative of start of packet. >> + */ >> + cvmx_pki_wqe_word4_t word4; >> + >> + /*------------------------------------------------------------- >> ------*/ >> + /* WORDs 5/6/7 may be extended there, if WQE_HSZ is >> set. */ >> + /*------------------------------------------------------------- >> ------*/ >> + u64 wqe_data[11]; >> + >> +} CVMX_CACHE_LINE_ALIGNED cvmx_wqe_78xx_t; >> + >> +/* Node LS-bit position in the WQE[grp] or PKI_QPG_TBL[grp_ok].*/ >> +#define CVMX_WQE_GRP_NODE_SHIFT 8 >> + >> +/* >> + * This is an accessor function into the WQE that retreives the >> + * ingress port number, which can also be used as a destination >> + * port number for the same port. >> + * >> + * @param work - Work Queue Entrey pointer >> + * @returns returns the normalized port number, also known as "ipd" >> port >> + */ >> +static inline int cvmx_wqe_get_port(cvmx_wqe_t *work) >> +{ >> + int port; >> + >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + /* In 78xx wqe entry has channel number not port*/ >> + port = work->word0.pki.channel; >> + /* For BGX interfaces (0x800 - 0xdff) the 4 LSBs >> indicate >> + * the PFC channel, must be cleared to normalize to >> "ipd" >> + */ >> + if (port & 0x800) >> + port &= 0xff0; >> + /* Node number is in AURA field, make it part of port # >> */ >> + port |= (work->word0.pki.aura >> 10) << 12; >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + port = work->word2.s_cn68xx.port; >> + } else { >> + port = work->word1.cn38xx.ipprt; >> + } >> + >> + return port; >> +} >> + >> +static inline void cvmx_wqe_set_port(cvmx_wqe_t *work, int port) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) >> + work->word0.pki.channel = port; >> + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) >> + work->word2.s_cn68xx.port = port; >> + else >> + work->word1.cn38xx.ipprt = port; >> +} >> + >> +static inline int cvmx_wqe_get_grp(cvmx_wqe_t *work) >> +{ >> + int grp; >> + >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) >> + /* legacy: GRP[0..2] :=QOS */ >> + grp = (0xff & work->word1.cn78xx.grp) >> 3; >> + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) >> + grp = work->word1.cn68xx.grp; >> + else >> + grp = work->word1.cn38xx.grp; >> + >> + return grp; >> +} >> + >> +static inline void cvmx_wqe_set_xgrp(cvmx_wqe_t *work, int grp) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) >> + work->word1.cn78xx.grp = grp; >> + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) >> + work->word1.cn68xx.grp = grp; >> + else >> + work->word1.cn38xx.grp = grp; >> +} >> + >> +static inline int cvmx_wqe_get_xgrp(cvmx_wqe_t *work) >> +{ >> + int grp; >> + >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) >> + grp = work->word1.cn78xx.grp; >> + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) >> + grp = work->word1.cn68xx.grp; >> + else >> + grp = work->word1.cn38xx.grp; >> + >> + return grp; >> +} >> + >> +static inline void cvmx_wqe_set_grp(cvmx_wqe_t *work, int grp) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + unsigned int node = cvmx_get_node_num(); >> + /* Legacy: GRP[0..2] :=QOS */ >> + work->word1.cn78xx.grp &= 0x7; >> + work->word1.cn78xx.grp |= 0xff & (grp << 3); >> + work->word1.cn78xx.grp |= (node << 8); >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + work->word1.cn68xx.grp = grp; >> + } else { >> + work->word1.cn38xx.grp = grp; >> + } >> +} >> + >> +static inline int cvmx_wqe_get_qos(cvmx_wqe_t *work) >> +{ >> + int qos; >> + >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + /* Legacy: GRP[0..2] :=QOS */ >> + qos = work->word1.cn78xx.grp & 0x7; >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + qos = work->word1.cn68xx.qos; >> + } else { >> + qos = work->word1.cn38xx.qos; >> + } >> + >> + return qos; >> +} >> + >> +static inline void cvmx_wqe_set_qos(cvmx_wqe_t *work, int qos) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + /* legacy: GRP[0..2] :=QOS */ >> + work->word1.cn78xx.grp &= ~0x7; >> + work->word1.cn78xx.grp |= qos & 0x7; >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + work->word1.cn68xx.qos = qos; >> + } else { >> + work->word1.cn38xx.qos = qos; >> + } >> +} >> + >> +static inline int cvmx_wqe_get_len(cvmx_wqe_t *work) >> +{ >> + int len; >> + >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) >> + len = work->word1.cn78xx.len; >> + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) >> + len = work->word1.cn68xx.len; >> + else >> + len = work->word1.cn38xx.len; >> + >> + return len; >> +} >> + >> +static inline void cvmx_wqe_set_len(cvmx_wqe_t *work, int len) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) >> + work->word1.cn78xx.len = len; >> + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) >> + work->word1.cn68xx.len = len; >> + else >> + work->word1.cn38xx.len = len; >> +} >> + >> +/** >> + * This function returns, if there was L2/L1 errors detected in >> packet. >> + * >> + * @param work pointer to work queue entry >> + * >> + * @return 0 if packet had no error, non-zero to indicate error >> code. >> + * >> + * Please refer to HRM for the specific model for full enumaration >> of error codes. >> + * With Octeon1/Octeon2 models, the returned code indicates L1/L2 >> errors. >> + * On CN73XX/CN78XX, the return code is the value of PKI_OPCODE_E, >> + * if it is non-zero, otherwise the returned code will be derived >> from >> + * PKI_ERRLEV_E such that an error indicated in LayerA will return >> 0x20, >> + * LayerB - 0x30, LayerC - 0x40 and so forth. >> + */ >> +static inline int cvmx_wqe_get_rcv_err(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + if (wqe->word2.err_level == CVMX_PKI_ERRLEV_E_RE || >> wqe->word2.err_code != 0) >> + return wqe->word2.err_code; >> + else >> + return (wqe->word2.err_level << 4) + 0x10; >> + } else if (work->word2.snoip.rcv_error) { >> + return work->word2.snoip.err_code; >> + } >> + >> + return 0; >> +} >> + >> +static inline u32 cvmx_wqe_get_tag(cvmx_wqe_t *work) >> +{ >> + return work->word1.tag; >> +} >> + >> +static inline void cvmx_wqe_set_tag(cvmx_wqe_t *work, u32 tag) >> +{ >> + work->word1.tag = tag; >> +} >> + >> +static inline int cvmx_wqe_get_tt(cvmx_wqe_t *work) >> +{ >> + return work->word1.tag_type; >> +} >> + >> +static inline void cvmx_wqe_set_tt(cvmx_wqe_t *work, int tt) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + work->word1.cn78xx.tag_type = (cvmx_pow_tag_type_t)tt; >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + work->word1.cn68xx.tag_type = (cvmx_pow_tag_type_t)tt; >> + work->word1.cn68xx.zero_2 = 0; >> + } else { >> + work->word1.cn38xx.tag_type = (cvmx_pow_tag_type_t)tt; >> + work->word1.cn38xx.zero_2 = 0; >> + } >> +} >> + >> +static inline u8 cvmx_wqe_get_unused8(cvmx_wqe_t *work) >> +{ >> + u8 bits; >> + >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + bits = wqe->word2.rsvd_0; >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + bits = work->word0.pip.cn68xx.unused1; >> + } else { >> + bits = work->word0.pip.cn38xx.unused; >> + } >> + >> + return bits; >> +} >> + >> +static inline void cvmx_wqe_set_unused8(cvmx_wqe_t *work, u8 v) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + wqe->word2.rsvd_0 = v; >> + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { >> + work->word0.pip.cn68xx.unused1 = v; >> + } else { >> + work->word0.pip.cn38xx.unused = v; >> + } >> +} >> + >> +static inline u8 cvmx_wqe_get_user_flags(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) >> + return work->word0.pki.rsvd_2; >> + else >> + return 0; >> +} >> + >> +static inline void cvmx_wqe_set_user_flags(cvmx_wqe_t *work, u8 v) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) >> + work->word0.pki.rsvd_2 = v; >> +} >> + >> +static inline int cvmx_wqe_get_channel(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) >> + return (work->word0.pki.channel); >> + else >> + return cvmx_wqe_get_port(work); >> +} >> + >> +static inline void cvmx_wqe_set_channel(cvmx_wqe_t *work, int >> channel) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) >> + work->word0.pki.channel = channel; >> + else >> + debug("%s: ERROR: not supported for model\n", >> __func__); >> +} >> + >> +static inline int cvmx_wqe_get_aura(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) >> + return (work->word0.pki.aura); >> + else >> + return (work->packet_ptr.s.pool); >> +} >> + >> +static inline void cvmx_wqe_set_aura(cvmx_wqe_t *work, int aura) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) >> + work->word0.pki.aura = aura; >> + else >> + work->packet_ptr.s.pool = aura; >> +} >> + >> +static inline int cvmx_wqe_get_style(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) >> + return (work->word0.pki.style); >> + return 0; >> +} >> + >> +static inline void cvmx_wqe_set_style(cvmx_wqe_t *work, int style) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) >> + work->word0.pki.style = style; >> +} >> + >> +static inline int cvmx_wqe_is_l3_ip(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + /* Match all 4 values for v4/v6 with.without options */ >> + if ((wqe->word2.lc_hdr_type & 0x1c) == >> CVMX_PKI_LTYPE_E_IP4) >> + return 1; >> + if ((wqe->word2.le_hdr_type & 0x1c) == >> CVMX_PKI_LTYPE_E_IP4) >> + return 1; >> + return 0; >> + } else { >> + return !work->word2.s_cn38xx.not_IP; >> + } >> +} >> + >> +static inline int cvmx_wqe_is_l3_ipv4(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + /* Match 2 values - with/wotuout options */ >> + if ((wqe->word2.lc_hdr_type & 0x1e) == >> CVMX_PKI_LTYPE_E_IP4) >> + return 1; >> + if ((wqe->word2.le_hdr_type & 0x1e) == >> CVMX_PKI_LTYPE_E_IP4) >> + return 1; >> + return 0; >> + } else { >> + return (!work->word2.s_cn38xx.not_IP && >> + !work->word2.s_cn38xx.is_v6); >> + } >> +} >> + >> +static inline int cvmx_wqe_is_l3_ipv6(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + /* Match 2 values - with/wotuout options */ >> + if ((wqe->word2.lc_hdr_type & 0x1e) == >> CVMX_PKI_LTYPE_E_IP6) >> + return 1; >> + if ((wqe->word2.le_hdr_type & 0x1e) == >> CVMX_PKI_LTYPE_E_IP6) >> + return 1; >> + return 0; >> + } else { >> + return (!work->word2.s_cn38xx.not_IP && >> + work->word2.s_cn38xx.is_v6); >> + } >> +} >> + >> +static inline bool cvmx_wqe_is_l4_udp_or_tcp(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + if (wqe->word2.lf_hdr_type == CVMX_PKI_LTYPE_E_TCP) >> + return true; >> + if (wqe->word2.lf_hdr_type == CVMX_PKI_LTYPE_E_UDP) >> + return true; >> + return false; >> + } >> + >> + if (work->word2.s_cn38xx.not_IP) >> + return false; >> + >> + return (work->word2.s_cn38xx.tcp_or_udp != 0); >> +} >> + >> +static inline int cvmx_wqe_is_l2_bcast(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + return wqe->word2.is_l2_bcast; >> + } else { >> + return work->word2.s_cn38xx.is_bcast; >> + } >> +} >> + >> +static inline int cvmx_wqe_is_l2_mcast(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + return wqe->word2.is_l2_mcast; >> + } else { >> + return work->word2.s_cn38xx.is_mcast; >> + } >> +} >> + >> +static inline void cvmx_wqe_set_l2_bcast(cvmx_wqe_t *work, bool >> bcast) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + wqe->word2.is_l2_bcast = bcast; >> + } else { >> + work->word2.s_cn38xx.is_bcast = bcast; >> + } >> +} >> + >> +static inline void cvmx_wqe_set_l2_mcast(cvmx_wqe_t *work, bool >> mcast) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + wqe->word2.is_l2_mcast = mcast; >> + } else { >> + work->word2.s_cn38xx.is_mcast = mcast; >> + } >> +} >> + >> +static inline int cvmx_wqe_is_l3_bcast(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + return wqe->word2.is_l3_bcast; >> + } >> + debug("%s: ERROR: not supported for model\n", __func__); >> + return 0; >> +} >> + >> +static inline int cvmx_wqe_is_l3_mcast(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + return wqe->word2.is_l3_mcast; >> + } >> + debug("%s: ERROR: not supported for model\n", __func__); >> + return 0; >> +} >> + >> +/** >> + * This function returns is there was IP error detected in packet. >> + * For 78XX it does not flag ipv4 options and ipv6 extensions. >> + * For older chips if PIP_GBL_CTL was proviosned to flag ip4_otions >> and >> + * ipv6 extension, it will be flag them. >> + * @param work pointer to work queue entry >> + * @return 1 -- If IP error was found in packet >> + * 0 -- If no IP error was found in packet. >> + */ >> +static inline int cvmx_wqe_is_ip_exception(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + if (wqe->word2.err_level == CVMX_PKI_ERRLEV_E_LC) >> + return 1; >> + else >> + return 0; >> + } >> + >> + return work->word2.s.IP_exc; >> +} >> + >> +static inline int cvmx_wqe_is_l4_error(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + if (wqe->word2.err_level == CVMX_PKI_ERRLEV_E_LF) >> + return 1; >> + else >> + return 0; >> + } else { >> + return work->word2.s.L4_error; >> + } >> +} >> + >> +static inline void cvmx_wqe_set_vlan(cvmx_wqe_t *work, bool set) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + wqe->word2.vlan_valid = set; >> + } else { >> + work->word2.s.vlan_valid = set; >> + } >> +} >> + >> +static inline int cvmx_wqe_is_vlan(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + return wqe->word2.vlan_valid; >> + } else { >> + return work->word2.s.vlan_valid; >> + } >> +} >> + >> +static inline int cvmx_wqe_is_vlan_stacked(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + return wqe->word2.vlan_stacked; >> + } else { >> + return work->word2.s.vlan_stacked; >> + } >> +} >> + >> +/** >> + * Extract packet data buffer pointer from work queue entry. >> + * >> + * Returns the legacy (Octeon1/Octeon2) buffer pointer structure >> + * for the linked buffer list. >> + * On CN78XX, the native buffer pointer structure is converted into >> + * the legacy format. >> + * The legacy buf_ptr is then stored in the WQE, and word0 reserved >> + * field is set to indicate that the buffer pointers were >> translated. >> + * If the packet data is only found inside the work queue entry, >> + * a standard buffer pointer structure is created for it. >> + */ >> +cvmx_buf_ptr_t cvmx_wqe_get_packet_ptr(cvmx_wqe_t *work); >> + >> +static inline int cvmx_wqe_get_bufs(cvmx_wqe_t *work) >> +{ >> + int bufs; >> + >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + bufs = work->word0.pki.bufs; >> + } else { >> + /* Adjust for packet-in-WQE cases */ >> + if (cvmx_unlikely(work->word2.s_cn38xx.bufs == 0 && >> !work->word2.s.software)) >> + (void)cvmx_wqe_get_packet_ptr(work); >> + bufs = work->word2.s_cn38xx.bufs; >> + } >> + return bufs; >> +} >> + >> +/** >> + * Free Work Queue Entry memory >> + * >> + * Will return the WQE buffer to its pool, unless the WQE contains >> + * non-redundant packet data. >> + * This function is intended to be called AFTER the packet data >> + * has been passed along to PKO for transmission and release. >> + * It can also follow a call to cvmx_helper_free_packet_data() >> + * to release the WQE after associated data was released. >> + */ >> +void cvmx_wqe_free(cvmx_wqe_t *work); >> + >> +/** >> + * Check if a work entry has been intiated by software >> + * >> + */ >> +static inline bool cvmx_wqe_is_soft(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + return wqe->word2.software; >> + } else { >> + return work->word2.s.software; >> + } >> +} >> + >> +/** >> + * Allocate a work-queue entry for delivering software-initiated >> + * event notifications. >> + * The application data is copied into the work-queue entry, >> + * if the space is sufficient. >> + */ >> +cvmx_wqe_t *cvmx_wqe_soft_create(void *data_p, unsigned int >> data_sz); >> + >> +/* Errata (PKI-20776) PKI_BUFLINK_S's are endian-swapped >> + * CN78XX pass 1.x has a bug where the packet pointer in each >> segment is >> + * written in the opposite endianness of the configured mode. Fix >> these here. >> + */ >> +static inline void cvmx_wqe_pki_errata_20776(cvmx_wqe_t *work) >> +{ >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X) && !wqe- >>> pki_errata20776) { >> + u64 bufs; >> + cvmx_buf_ptr_pki_t buffer_next; >> + >> + bufs = wqe->word0.bufs; >> + buffer_next = wqe->packet_ptr; >> + while (bufs > 1) { >> + cvmx_buf_ptr_pki_t next; >> + void *nextaddr = >> cvmx_phys_to_ptr(buffer_next.addr - 8); >> + >> + memcpy(&next, nextaddr, sizeof(next)); >> + next.u64 = __builtin_bswap64(next.u64); >> + memcpy(nextaddr, &next, sizeof(next)); >> + buffer_next = next; >> + bufs--; >> + } >> + wqe->pki_errata20776 = 1; >> + } >> +} >> + >> +/** >> + * @INTERNAL >> + * >> + * Extract the native PKI-specific buffer pointer from WQE. >> + * >> + * NOTE: Provisional, may be superceded. >> + */ >> +static inline cvmx_buf_ptr_pki_t cvmx_wqe_get_pki_pkt_ptr(cvmx_wqe_t >> *work) >> +{ >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_buf_ptr_pki_t x = { 0 }; >> + return x; >> + } >> + >> + cvmx_wqe_pki_errata_20776(work); >> + return wqe->packet_ptr; >> +} >> + >> +/** >> + * Set the buffer segment count for a packet. >> + * >> + * @return Returns the actual resulting value in the WQE fielda >> + * >> + */ >> +static inline unsigned int cvmx_wqe_set_bufs(cvmx_wqe_t *work, >> unsigned int bufs) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + work->word0.pki.bufs = bufs; >> + return work->word0.pki.bufs; >> + } >> + >> + work->word2.s.bufs = bufs; >> + return work->word2.s.bufs; >> +} >> + >> +/** >> + * Get the offset of Layer-3 header, >> + * only supported when Layer-3 protocol is IPv4 or IPv6. >> + * >> + * @return Returns the offset, or 0 if the offset is not known or >> unsupported. >> + * >> + * FIXME: Assuming word4 is present. >> + */ >> +static inline unsigned int cvmx_wqe_get_l3_offset(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + /* Match 4 values: IPv4/v6 w/wo options */ >> + if ((wqe->word2.lc_hdr_type & 0x1c) == >> CVMX_PKI_LTYPE_E_IP4) >> + return wqe->word4.ptr_layer_c; >> + } else { >> + return work->word2.s.ip_offset; >> + } >> + >> + return 0; >> +} >> + >> +/** >> + * Set the offset of Layer-3 header in a packet. >> + * Typically used when an IP packet is generated by software >> + * or when the Layer-2 header length is modified, and >> + * a subsequent recalculation of checksums is anticipated. >> + * >> + * @return Returns the actual value of the work entry offset field. >> + * >> + * FIXME: Assuming word4 is present. >> + */ >> +static inline unsigned int cvmx_wqe_set_l3_offset(cvmx_wqe_t *work, >> unsigned int ip_off) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + /* Match 4 values: IPv4/v6 w/wo options */ >> + if ((wqe->word2.lc_hdr_type & 0x1c) == >> CVMX_PKI_LTYPE_E_IP4) >> + wqe->word4.ptr_layer_c = ip_off; >> + } else { >> + work->word2.s.ip_offset = ip_off; >> + } >> + >> + return cvmx_wqe_get_l3_offset(work); >> +} >> + >> +/** >> + * Set the indication that the packet contains a IPv4 Layer-3 * >> header. >> + * Use 'cvmx_wqe_set_l3_ipv6()' if the protocol is IPv6. >> + * When 'set' is false, the call will result in an indication >> + * that the Layer-3 protocol is neither IPv4 nor IPv6. >> + * >> + * FIXME: Add IPV4_OPT handling based on L3 header length. >> + */ >> +static inline void cvmx_wqe_set_l3_ipv4(cvmx_wqe_t *work, bool set) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + if (set) >> + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_IP4; >> + else >> + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_NONE; >> + } else { >> + work->word2.s.not_IP = !set; >> + if (set) >> + work->word2.s_cn38xx.is_v6 = 0; >> + } >> +} >> + >> +/** >> + * Set packet Layer-3 protocol to IPv6. >> + * >> + * FIXME: Add IPV6_OPT handling based on presence of extended >> headers. >> + */ >> +static inline void cvmx_wqe_set_l3_ipv6(cvmx_wqe_t *work, bool set) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + if (set) >> + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_IP6; >> + else >> + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_NONE; >> + } else { >> + work->word2.s_cn38xx.not_IP = !set; >> + if (set) >> + work->word2.s_cn38xx.is_v6 = 1; >> + } >> +} >> + >> +/** >> + * Set a packet Layer-4 protocol type to UDP. >> + */ >> +static inline void cvmx_wqe_set_l4_udp(cvmx_wqe_t *work, bool set) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + if (set) >> + wqe->word2.lf_hdr_type = CVMX_PKI_LTYPE_E_UDP; >> + else >> + wqe->word2.lf_hdr_type = CVMX_PKI_LTYPE_E_NONE; >> + } else { >> + if (!work->word2.s_cn38xx.not_IP) >> + work->word2.s_cn38xx.tcp_or_udp = set; >> + } >> +} >> + >> +/** >> + * Set a packet Layer-4 protocol type to TCP. >> + */ >> +static inline void cvmx_wqe_set_l4_tcp(cvmx_wqe_t *work, bool set) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + if (set) >> + wqe->word2.lf_hdr_type = CVMX_PKI_LTYPE_E_TCP; >> + else >> + wqe->word2.lf_hdr_type = CVMX_PKI_LTYPE_E_NONE; >> + } else { >> + if (!work->word2.s_cn38xx.not_IP) >> + work->word2.s_cn38xx.tcp_or_udp = set; >> + } >> +} >> + >> +/** >> + * Set the "software" flag in a work entry. >> + */ >> +static inline void cvmx_wqe_set_soft(cvmx_wqe_t *work, bool set) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + wqe->word2.software = set; >> + } else { >> + work->word2.s.software = set; >> + } >> +} >> + >> +/** >> + * Return true if the packet is an IP fragment. >> + */ >> +static inline bool cvmx_wqe_is_l3_frag(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + return (wqe->word2.is_frag != 0); >> + } >> + >> + if (!work->word2.s_cn38xx.not_IP) >> + return (work->word2.s.is_frag != 0); >> + >> + return false; >> +} >> + >> +/** >> + * Set the indicator that the packet is an fragmented IP packet. >> + */ >> +static inline void cvmx_wqe_set_l3_frag(cvmx_wqe_t *work, bool set) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + wqe->word2.is_frag = set; >> + } else { >> + if (!work->word2.s_cn38xx.not_IP) >> + work->word2.s.is_frag = set; >> + } >> +} >> + >> +/** >> + * Set the packet Layer-3 protocol to RARP. >> + */ >> +static inline void cvmx_wqe_set_l3_rarp(cvmx_wqe_t *work, bool set) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + if (set) >> + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_RARP; >> + else >> + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_NONE; >> + } else { >> + work->word2.snoip.is_rarp = set; >> + } >> +} >> + >> +/** >> + * Set the packet Layer-3 protocol to ARP. >> + */ >> +static inline void cvmx_wqe_set_l3_arp(cvmx_wqe_t *work, bool set) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + if (set) >> + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_ARP; >> + else >> + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_NONE; >> + } else { >> + work->word2.snoip.is_arp = set; >> + } >> +} >> + >> +/** >> + * Return true if the packet Layer-3 protocol is ARP. >> + */ >> +static inline bool cvmx_wqe_is_l3_arp(cvmx_wqe_t *work) >> +{ >> + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { >> + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; >> + >> + return (wqe->word2.lc_hdr_type == >> CVMX_PKI_LTYPE_E_ARP); >> + } >> + >> + if (work->word2.s_cn38xx.not_IP) >> + return (work->word2.snoip.is_arp != 0); >> + >> + return false; >> +} >> + >> +#endif /* __CVMX_WQE_H__ */ >> diff --git a/arch/mips/mach-octeon/include/mach/octeon_qlm.h >> b/arch/mips/mach-octeon/include/mach/octeon_qlm.h >> new file mode 100644 >> index 000000000000..219625b25688 >> --- /dev/null >> +++ b/arch/mips/mach-octeon/include/mach/octeon_qlm.h >> @@ -0,0 +1,109 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + */ >> + >> +#ifndef __OCTEON_QLM_H__ >> +#define __OCTEON_QLM_H__ >> + >> +/* Reference clock selector values for ref_clk_sel */ >> +#define OCTEON_QLM_REF_CLK_100MHZ 0 /** 100 MHz */ >> +#define OCTEON_QLM_REF_CLK_125MHZ 1 /** 125 MHz */ >> +#define OCTEON_QLM_REF_CLK_156MHZ 2 /** 156.25 MHz */ >> +#define OCTEON_QLM_REF_CLK_161MHZ 3 /** 161.1328125 MHz */ >> + >> +/** >> + * Configure qlm/dlm speed and mode. >> + * @param qlm The QLM or DLM to configure >> + * @param speed The speed the QLM needs to be configured in Mhz. >> + * @param mode The QLM to be configured as SGMII/XAUI/PCIe. >> + * @param rc Only used for PCIe, rc = 1 for root complex mode, >> 0 for EP >> + * mode. >> + * @param pcie_mode Only used when qlm/dlm are in pcie mode. >> + * @param ref_clk_sel Reference clock to use for 70XX where: >> + * 0: 100MHz >> + * 1: 125MHz >> + * 2: 156.25MHz >> + * 3: 161.1328125MHz (CN73XX and CN78XX only) >> + * @param ref_clk_input This selects which reference clock >> input to use. For >> + * cn70xx: >> + * 0: DLMC_REF_CLK0 >> + * 1: DLMC_REF_CLK1 >> + * 2: DLM0_REF_CLK >> + * cn61xx: (not used) >> + * cn78xx/cn76xx/cn73xx: >> + * 0: Internal clock (QLM[0-7]_REF_CLK) >> + * 1: QLMC_REF_CLK0 >> + * 2: QLMC_REF_CLK1 >> + * >> + * @return Return 0 on success or -1. >> + * >> + * @note When the 161MHz clock is used it can only be used for >> + * XLAUI mode with a 6316 speed or XFI mode with a 103125 >> speed. >> + * This rate is also only supported for CN73XX and CN78XX. >> + */ >> +int octeon_configure_qlm(int qlm, int speed, int mode, int rc, int >> pcie_mode, int ref_clk_sel, >> + int ref_clk_input); >> + >> +int octeon_configure_qlm_cn78xx(int node, int qlm, int speed, int >> mode, int rc, int pcie_mode, >> + int ref_clk_sel, int ref_clk_input); >> + >> +/** >> + * Some QLM speeds need to override the default tuning parameters >> + * >> + * @param node Node to configure >> + * @param qlm QLM to configure >> + * @param baud_mhz Desired speed in MHz >> + * @param lane Lane the apply the tuning parameters >> + * @param tx_swing Voltage swing. The higher the value the lower >> the voltage, >> + * the default value is 7. >> + * @param tx_pre pre-cursor pre-emphasis >> + * @param tx_post post-cursor pre-emphasis. >> + * @param tx_gain Transmit gain. Range 0-7 >> + * @param tx_vboost Transmit voltage boost. Range 0-1 >> + */ >> +void octeon_qlm_tune_per_lane_v3(int node, int qlm, int baud_mhz, >> int lane, int tx_swing, >> + int tx_pre, int tx_post, int tx_gain, >> int tx_vboost); >> + >> +/** >> + * Some QLM speeds need to override the default tuning parameters >> + * >> + * @param node Node to configure >> + * @param qlm QLM to configure >> + * @param baud_mhz Desired speed in MHz >> + * @param tx_swing Voltage swing. The higher the value the lower >> the voltage, >> + * the default value is 7. >> + * @param tx_premptap bits [0:3] pre-cursor pre-emphasis, bits[4:8] >> post-cursor >> + * pre-emphasis. >> + * @param tx_gain Transmit gain. Range 0-7 >> + * @param tx_vboost Transmit voltage boost. Range 0-1 >> + */ >> +void octeon_qlm_tune_v3(int node, int qlm, int baud_mhz, int >> tx_swing, int tx_premptap, int tx_gain, >> + int tx_vboost); >> + >> +/** >> + * Disables DFE for the specified QLM lane(s). >> + * This function should only be called for low-loss channels. >> + * >> + * @param node Node to configure >> + * @param qlm QLM to configure >> + * @param lane Lane to configure, or -1 all lanes >> + * @param baud_mhz The speed the QLM needs to be configured in Mhz. >> + * @param mode The QLM to be configured as SGMII/XAUI/PCIe. >> + */ >> +void octeon_qlm_dfe_disable(int node, int qlm, int lane, int >> baud_mhz, int mode); >> + >> +/** >> + * Some QLMs need to override the default pre-ctle for low loss >> channels. >> + * >> + * @param node Node to configure >> + * @param qlm QLM to configure >> + * @param pre_ctle pre-ctle settings for low loss channels >> + */ >> +void octeon_qlm_set_channel_v3(int node, int qlm, int pre_ctle); >> + >> +void octeon_init_qlm(int node); >> + >> +int octeon_mcu_probe(int node); >> + >> +#endif /* __OCTEON_QLM_H__ */ Viele Grüße, Stefan
diff --git a/arch/mips/mach-octeon/include/mach/cvmx-address.h b/arch/mips/mach-octeon/include/mach/cvmx-address.h new file mode 100644 index 000000000000..984f574a75bb --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-address.h @@ -0,0 +1,209 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Typedefs and defines for working with Octeon physical addresses. + */ + +#ifndef __CVMX_ADDRESS_H__ +#define __CVMX_ADDRESS_H__ + +typedef enum { + CVMX_MIPS_SPACE_XKSEG = 3LL, + CVMX_MIPS_SPACE_XKPHYS = 2LL, + CVMX_MIPS_SPACE_XSSEG = 1LL, + CVMX_MIPS_SPACE_XUSEG = 0LL +} cvmx_mips_space_t; + +typedef enum { + CVMX_MIPS_XKSEG_SPACE_KSEG0 = 0LL, + CVMX_MIPS_XKSEG_SPACE_KSEG1 = 1LL, + CVMX_MIPS_XKSEG_SPACE_SSEG = 2LL, + CVMX_MIPS_XKSEG_SPACE_KSEG3 = 3LL +} cvmx_mips_xkseg_space_t; + +/* decodes <14:13> of a kseg3 window address */ +typedef enum { + CVMX_ADD_WIN_SCR = 0L, + CVMX_ADD_WIN_DMA = 1L, + CVMX_ADD_WIN_UNUSED = 2L, + CVMX_ADD_WIN_UNUSED2 = 3L +} cvmx_add_win_dec_t; + +/* decode within DMA space */ +typedef enum { + CVMX_ADD_WIN_DMA_ADD = 0L, + CVMX_ADD_WIN_DMA_SENDMEM = 1L, + /* store data must be normal DRAM memory space address in this case */ + CVMX_ADD_WIN_DMA_SENDDMA = 2L, + /* see CVMX_ADD_WIN_DMA_SEND_DEC for data contents */ + CVMX_ADD_WIN_DMA_SENDIO = 3L, + /* store data must be normal IO space address in this case */ + CVMX_ADD_WIN_DMA_SENDSINGLE = 4L, + /* no write buffer data needed/used */ +} cvmx_add_win_dma_dec_t; + +/** + * Physical Address Decode + * + * Octeon-I HW never interprets this X (<39:36> reserved + * for future expansion), software should set to 0. + * + * - 0x0 XXX0 0000 0000 to DRAM Cached + * - 0x0 XXX0 0FFF FFFF + * + * - 0x0 XXX0 1000 0000 to Boot Bus Uncached (Converted to 0x1 00X0 1000 0000 + * - 0x0 XXX0 1FFF FFFF + EJTAG to 0x1 00X0 1FFF FFFF) + * + * - 0x0 XXX0 2000 0000 to DRAM Cached + * - 0x0 XXXF FFFF FFFF + * + * - 0x1 00X0 0000 0000 to Boot Bus Uncached + * - 0x1 00XF FFFF FFFF + * + * - 0x1 01X0 0000 0000 to Other NCB Uncached + * - 0x1 FFXF FFFF FFFF devices + * + * Decode of all Octeon addresses + */ +typedef union { + u64 u64; + struct { + cvmx_mips_space_t R : 2; + u64 offset : 62; + } sva; + + struct { + u64 zeroes : 33; + u64 offset : 31; + } suseg; + + struct { + u64 ones : 33; + cvmx_mips_xkseg_space_t sp : 2; + u64 offset : 29; + } sxkseg; + + struct { + cvmx_mips_space_t R : 2; + u64 cca : 3; + u64 mbz : 10; + u64 pa : 49; + } sxkphys; + + struct { + u64 mbz : 15; + u64 is_io : 1; + u64 did : 8; + u64 unaddr : 4; + u64 offset : 36; + } sphys; + + struct { + u64 zeroes : 24; + u64 unaddr : 4; + u64 offset : 36; + } smem; + + struct { + u64 mem_region : 2; + u64 mbz : 13; + u64 is_io : 1; + u64 did : 8; + u64 unaddr : 4; + u64 offset : 36; + } sio; + + struct { + u64 ones : 49; + cvmx_add_win_dec_t csrdec : 2; + u64 addr : 13; + } sscr; + + /* there should only be stores to IOBDMA space, no loads */ + struct { + u64 ones : 49; + cvmx_add_win_dec_t csrdec : 2; + u64 unused2 : 3; + cvmx_add_win_dma_dec_t type : 3; + u64 addr : 7; + } sdma; + + struct { + u64 didspace : 24; + u64 unused : 40; + } sfilldidspace; +} cvmx_addr_t; + +/* These macros for used by 32 bit applications */ + +#define CVMX_MIPS32_SPACE_KSEG0 1l +#define CVMX_ADD_SEG32(segment, add) (((s32)segment << 31) | (s32)(add)) + +/* + * Currently all IOs are performed using XKPHYS addressing. Linux uses the + * CvmMemCtl register to enable XKPHYS addressing to IO space from user mode. + * Future OSes may need to change the upper bits of IO addresses. The + * following define controls the upper two bits for all IO addresses generated + * by the simple executive library + */ +#define CVMX_IO_SEG CVMX_MIPS_SPACE_XKPHYS + +/* These macros simplify the process of creating common IO addresses */ +#define CVMX_ADD_SEG(segment, add) ((((u64)segment) << 62) | (add)) + +#define CVMX_ADD_IO_SEG(add) (add) + +#define CVMX_ADDR_DIDSPACE(did) (((CVMX_IO_SEG) << 22) | ((1ULL) << 8) | (did)) +#define CVMX_ADDR_DID(did) (CVMX_ADDR_DIDSPACE(did) << 40) +#define CVMX_FULL_DID(did, subdid) (((did) << 3) | (subdid)) + +/* from include/ncb_rsl_id.v */ +#define CVMX_OCT_DID_MIS 0ULL /* misc stuff */ +#define CVMX_OCT_DID_GMX0 1ULL +#define CVMX_OCT_DID_GMX1 2ULL +#define CVMX_OCT_DID_PCI 3ULL +#define CVMX_OCT_DID_KEY 4ULL +#define CVMX_OCT_DID_FPA 5ULL +#define CVMX_OCT_DID_DFA 6ULL +#define CVMX_OCT_DID_ZIP 7ULL +#define CVMX_OCT_DID_RNG 8ULL +#define CVMX_OCT_DID_IPD 9ULL +#define CVMX_OCT_DID_PKT 10ULL +#define CVMX_OCT_DID_TIM 11ULL +#define CVMX_OCT_DID_TAG 12ULL +/* the rest are not on the IO bus */ +#define CVMX_OCT_DID_L2C 16ULL +#define CVMX_OCT_DID_LMC 17ULL +#define CVMX_OCT_DID_SPX0 18ULL +#define CVMX_OCT_DID_SPX1 19ULL +#define CVMX_OCT_DID_PIP 20ULL +#define CVMX_OCT_DID_ASX0 22ULL +#define CVMX_OCT_DID_ASX1 23ULL +#define CVMX_OCT_DID_IOB 30ULL + +#define CVMX_OCT_DID_PKT_SEND CVMX_FULL_DID(CVMX_OCT_DID_PKT, 2ULL) +#define CVMX_OCT_DID_TAG_SWTAG CVMX_FULL_DID(CVMX_OCT_DID_TAG, 0ULL) +#define CVMX_OCT_DID_TAG_TAG1 CVMX_FULL_DID(CVMX_OCT_DID_TAG, 1ULL) +#define CVMX_OCT_DID_TAG_TAG2 CVMX_FULL_DID(CVMX_OCT_DID_TAG, 2ULL) +#define CVMX_OCT_DID_TAG_TAG3 CVMX_FULL_DID(CVMX_OCT_DID_TAG, 3ULL) +#define CVMX_OCT_DID_TAG_NULL_RD CVMX_FULL_DID(CVMX_OCT_DID_TAG, 4ULL) +#define CVMX_OCT_DID_TAG_TAG5 CVMX_FULL_DID(CVMX_OCT_DID_TAG, 5ULL) +#define CVMX_OCT_DID_TAG_CSR CVMX_FULL_DID(CVMX_OCT_DID_TAG, 7ULL) +#define CVMX_OCT_DID_FAU_FAI CVMX_FULL_DID(CVMX_OCT_DID_IOB, 0ULL) +#define CVMX_OCT_DID_TIM_CSR CVMX_FULL_DID(CVMX_OCT_DID_TIM, 0ULL) +#define CVMX_OCT_DID_KEY_RW CVMX_FULL_DID(CVMX_OCT_DID_KEY, 0ULL) +#define CVMX_OCT_DID_PCI_6 CVMX_FULL_DID(CVMX_OCT_DID_PCI, 6ULL) +#define CVMX_OCT_DID_MIS_BOO CVMX_FULL_DID(CVMX_OCT_DID_MIS, 0ULL) +#define CVMX_OCT_DID_PCI_RML CVMX_FULL_DID(CVMX_OCT_DID_PCI, 0ULL) +#define CVMX_OCT_DID_IPD_CSR CVMX_FULL_DID(CVMX_OCT_DID_IPD, 7ULL) +#define CVMX_OCT_DID_DFA_CSR CVMX_FULL_DID(CVMX_OCT_DID_DFA, 7ULL) +#define CVMX_OCT_DID_MIS_CSR CVMX_FULL_DID(CVMX_OCT_DID_MIS, 7ULL) +#define CVMX_OCT_DID_ZIP_CSR CVMX_FULL_DID(CVMX_OCT_DID_ZIP, 0ULL) + +/* Cast to unsigned long long, mainly for use in printfs. */ +#define CAST_ULL(v) ((unsigned long long)(v)) + +#define UNMAPPED_PTR(x) ((1ULL << 63) | (x)) + +#endif /* __CVMX_ADDRESS_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-cmd-queue.h b/arch/mips/mach-octeon/include/mach/cvmx-cmd-queue.h new file mode 100644 index 000000000000..ddc294348cb4 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-cmd-queue.h @@ -0,0 +1,441 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Support functions for managing command queues used for + * various hardware blocks. + * + * The common command queue infrastructure abstracts out the + * software necessary for adding to Octeon's chained queue + * structures. These structures are used for commands to the + * PKO, ZIP, DFA, RAID, HNA, and DMA engine blocks. Although each + * hardware unit takes commands and CSRs of different types, + * they all use basic linked command buffers to store the + * pending request. In general, users of the CVMX API don't + * call cvmx-cmd-queue functions directly. Instead the hardware + * unit specific wrapper should be used. The wrappers perform + * unit specific validation and CSR writes to submit the + * commands. + * + * Even though most software will never directly interact with + * cvmx-cmd-queue, knowledge of its internal workings can help + * in diagnosing performance problems and help with debugging. + * + * Command queue pointers are stored in a global named block + * called "cvmx_cmd_queues". Except for the PKO queues, each + * hardware queue is stored in its own cache line to reduce SMP + * contention on spin locks. The PKO queues are stored such that + * every 16th queue is next to each other in memory. This scheme + * allows for queues being in separate cache lines when there + * are low number of queues per port. With 16 queues per port, + * the first queue for each port is in the same cache area. The + * second queues for each port are in another area, etc. This + * allows software to implement very efficient lockless PKO with + * 16 queues per port using a minimum of cache lines per core. + * All queues for a given core will be isolated in the same + * cache area. + * + * In addition to the memory pointer layout, cvmx-cmd-queue + * provides an optimized fair ll/sc locking mechanism for the + * queues. The lock uses a "ticket / now serving" model to + * maintain fair order on contended locks. In addition, it uses + * predicted locking time to limit cache contention. When a core + * know it must wait in line for a lock, it spins on the + * internal cycle counter to completely eliminate any causes of + * bus traffic. + */ + +#ifndef __CVMX_CMD_QUEUE_H__ +#define __CVMX_CMD_QUEUE_H__ + +/** + * By default we disable the max depth support. Most programs + * don't use it and it slows down the command queue processing + * significantly. + */ +#ifndef CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH +#define CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH 0 +#endif + +/** + * Enumeration representing all hardware blocks that use command + * queues. Each hardware block has up to 65536 sub identifiers for + * multiple command queues. Not all chips support all hardware + * units. + */ +typedef enum { + CVMX_CMD_QUEUE_PKO_BASE = 0x00000, +#define CVMX_CMD_QUEUE_PKO(queue) \ + ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_PKO_BASE + (0xffff & (queue)))) + CVMX_CMD_QUEUE_ZIP = 0x10000, +#define CVMX_CMD_QUEUE_ZIP_QUE(queue) \ + ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_ZIP + (0xffff & (queue)))) + CVMX_CMD_QUEUE_DFA = 0x20000, + CVMX_CMD_QUEUE_RAID = 0x30000, + CVMX_CMD_QUEUE_DMA_BASE = 0x40000, +#define CVMX_CMD_QUEUE_DMA(queue) \ + ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_DMA_BASE + (0xffff & (queue)))) + CVMX_CMD_QUEUE_BCH = 0x50000, +#define CVMX_CMD_QUEUE_BCH(queue) ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_BCH + (0xffff & (queue)))) + CVMX_CMD_QUEUE_HNA = 0x60000, + CVMX_CMD_QUEUE_END = 0x70000, +} cvmx_cmd_queue_id_t; + +#define CVMX_CMD_QUEUE_ZIP3_QUE(node, queue) \ + ((cvmx_cmd_queue_id_t)((node) << 24 | CVMX_CMD_QUEUE_ZIP | (0xffff & (queue)))) + +/** + * Command write operations can fail if the command queue needs + * a new buffer and the associated FPA pool is empty. It can also + * fail if the number of queued command words reaches the maximum + * set at initialization. + */ +typedef enum { + CVMX_CMD_QUEUE_SUCCESS = 0, + CVMX_CMD_QUEUE_NO_MEMORY = -1, + CVMX_CMD_QUEUE_FULL = -2, + CVMX_CMD_QUEUE_INVALID_PARAM = -3, + CVMX_CMD_QUEUE_ALREADY_SETUP = -4, +} cvmx_cmd_queue_result_t; + +typedef struct { + /* First 64-bit word: */ + u64 fpa_pool : 16; + u64 base_paddr : 48; + s32 index; + u16 max_depth; + u16 pool_size_m1; +} __cvmx_cmd_queue_state_t; + +/** + * command-queue locking uses a fair ticket spinlock algo, + * with 64-bit tickets for endianness-neutrality and + * counter overflow protection. + * Lock is free when both counters are of equal value. + */ +typedef struct { + u64 ticket; + u64 now_serving; +} __cvmx_cmd_queue_lock_t; + +/** + * @INTERNAL + * This structure contains the global state of all command queues. + * It is stored in a bootmem named block and shared by all + * applications running on Octeon. Tickets are stored in a different + * cache line that queue information to reduce the contention on the + * ll/sc used to get a ticket. If this is not the case, the update + * of queue state causes the ll/sc to fail quite often. + */ +typedef struct { + __cvmx_cmd_queue_lock_t lock[(CVMX_CMD_QUEUE_END >> 16) * 256]; + __cvmx_cmd_queue_state_t state[(CVMX_CMD_QUEUE_END >> 16) * 256]; +} __cvmx_cmd_queue_all_state_t; + +extern __cvmx_cmd_queue_all_state_t *__cvmx_cmd_queue_state_ptrs[CVMX_MAX_NODES]; + +/** + * @INTERNAL + * Internal function to handle the corner cases + * of adding command words to a queue when the current + * block is getting full. + */ +cvmx_cmd_queue_result_t __cvmx_cmd_queue_write_raw(cvmx_cmd_queue_id_t queue_id, + __cvmx_cmd_queue_state_t *qptr, int cmd_count, + const u64 *cmds); + +/** + * Initialize a command queue for use. The initial FPA buffer is + * allocated and the hardware unit is configured to point to the + * new command queue. + * + * @param queue_id Hardware command queue to initialize. + * @param max_depth Maximum outstanding commands that can be queued. + * @param fpa_pool FPA pool the command queues should come from. + * @param pool_size Size of each buffer in the FPA pool (bytes) + * + * @return CVMX_CMD_QUEUE_SUCCESS or a failure code + */ +cvmx_cmd_queue_result_t cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id, int max_depth, + int fpa_pool, int pool_size); + +/** + * Shutdown a queue a free it's command buffers to the FPA. The + * hardware connected to the queue must be stopped before this + * function is called. + * + * @param queue_id Queue to shutdown + * + * @return CVMX_CMD_QUEUE_SUCCESS or a failure code + */ +cvmx_cmd_queue_result_t cvmx_cmd_queue_shutdown(cvmx_cmd_queue_id_t queue_id); + +/** + * Return the number of command words pending in the queue. This + * function may be relatively slow for some hardware units. + * + * @param queue_id Hardware command queue to query + * + * @return Number of outstanding commands + */ +int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id); + +/** + * Return the command buffer to be written to. The purpose of this + * function is to allow CVMX routine access to the low level buffer + * for initial hardware setup. User applications should not call this + * function directly. + * + * @param queue_id Command queue to query + * + * @return Command buffer or NULL on failure + */ +void *cvmx_cmd_queue_buffer(cvmx_cmd_queue_id_t queue_id); + +/** + * @INTERNAL + * Retrieve or allocate command queue state named block + */ +cvmx_cmd_queue_result_t __cvmx_cmd_queue_init_state_ptr(unsigned int node); + +/** + * @INTERNAL + * Get the index into the state arrays for the supplied queue id. + * + * @param queue_id Queue ID to get an index for + * + * @return Index into the state arrays + */ +static inline unsigned int __cvmx_cmd_queue_get_index(cvmx_cmd_queue_id_t queue_id) +{ + /* Warning: This code currently only works with devices that have 256 + * queues or less. Devices with more than 16 queues are laid out in + * memory to allow cores quick access to every 16th queue. This reduces + * cache thrashing when you are running 16 queues per port to support + * lockless operation + */ + unsigned int unit = (queue_id >> 16) & 0xff; + unsigned int q = (queue_id >> 4) & 0xf; + unsigned int core = queue_id & 0xf; + + return (unit << 8) | (core << 4) | q; +} + +static inline int __cvmx_cmd_queue_get_node(cvmx_cmd_queue_id_t queue_id) +{ + unsigned int node = queue_id >> 24; + return node; +} + +/** + * @INTERNAL + * Lock the supplied queue so nobody else is updating it at the same + * time as us. + * + * @param queue_id Queue ID to lock + * + */ +static inline void __cvmx_cmd_queue_lock(cvmx_cmd_queue_id_t queue_id) +{ +} + +/** + * @INTERNAL + * Unlock the queue, flushing all writes. + * + * @param queue_id Queue ID to lock + * + */ +static inline void __cvmx_cmd_queue_unlock(cvmx_cmd_queue_id_t queue_id) +{ + CVMX_SYNCWS; /* nudge out the unlock. */ +} + +/** + * @INTERNAL + * Initialize a command-queue lock to "unlocked" state. + */ +static inline void __cvmx_cmd_queue_lock_init(cvmx_cmd_queue_id_t queue_id) +{ + unsigned int index = __cvmx_cmd_queue_get_index(queue_id); + unsigned int node = __cvmx_cmd_queue_get_node(queue_id); + + __cvmx_cmd_queue_state_ptrs[node]->lock[index] = (__cvmx_cmd_queue_lock_t){ 0, 0 }; + CVMX_SYNCWS; +} + +/** + * @INTERNAL + * Get the queue state structure for the given queue id + * + * @param queue_id Queue id to get + * + * @return Queue structure or NULL on failure + */ +static inline __cvmx_cmd_queue_state_t *__cvmx_cmd_queue_get_state(cvmx_cmd_queue_id_t queue_id) +{ + unsigned int index; + unsigned int node; + __cvmx_cmd_queue_state_t *qptr; + + node = __cvmx_cmd_queue_get_node(queue_id); + index = __cvmx_cmd_queue_get_index(queue_id); + + if (cvmx_unlikely(!__cvmx_cmd_queue_state_ptrs[node])) + __cvmx_cmd_queue_init_state_ptr(node); + + qptr = &__cvmx_cmd_queue_state_ptrs[node]->state[index]; + return qptr; +} + +/** + * Write an arbitrary number of command words to a command queue. + * This is a generic function; the fixed number of command word + * functions yield higher performance. + * + * @param queue_id Hardware command queue to write to + * @param use_locking + * Use internal locking to ensure exclusive access for queue + * updates. If you don't use this locking you must ensure + * exclusivity some other way. Locking is strongly recommended. + * @param cmd_count Number of command words to write + * @param cmds Array of commands to write + * + * @return CVMX_CMD_QUEUE_SUCCESS or a failure code + */ +static inline cvmx_cmd_queue_result_t +cvmx_cmd_queue_write(cvmx_cmd_queue_id_t queue_id, bool use_locking, int cmd_count, const u64 *cmds) +{ + cvmx_cmd_queue_result_t ret = CVMX_CMD_QUEUE_SUCCESS; + u64 *cmd_ptr; + + __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id); + + /* Make sure nobody else is updating the same queue */ + if (cvmx_likely(use_locking)) + __cvmx_cmd_queue_lock(queue_id); + + /* Most of the time there is lots of free words in current block */ + if (cvmx_unlikely((qptr->index + cmd_count) >= qptr->pool_size_m1)) { + /* The rare case when nearing end of block */ + ret = __cvmx_cmd_queue_write_raw(queue_id, qptr, cmd_count, cmds); + } else { + cmd_ptr = (u64 *)cvmx_phys_to_ptr((u64)qptr->base_paddr); + /* Loop easy for compiler to unroll for the likely case */ + while (cmd_count > 0) { + cmd_ptr[qptr->index++] = *cmds++; + cmd_count--; + } + } + + /* All updates are complete. Release the lock and return */ + if (cvmx_likely(use_locking)) + __cvmx_cmd_queue_unlock(queue_id); + else + CVMX_SYNCWS; + + return ret; +} + +/** + * Simple function to write two command words to a command queue. + * + * @param queue_id Hardware command queue to write to + * @param use_locking + * Use internal locking to ensure exclusive access for queue + * updates. If you don't use this locking you must ensure + * exclusivity some other way. Locking is strongly recommended. + * @param cmd1 Command + * @param cmd2 Command + * + * @return CVMX_CMD_QUEUE_SUCCESS or a failure code + */ +static inline cvmx_cmd_queue_result_t cvmx_cmd_queue_write2(cvmx_cmd_queue_id_t queue_id, + bool use_locking, u64 cmd1, u64 cmd2) +{ + cvmx_cmd_queue_result_t ret = CVMX_CMD_QUEUE_SUCCESS; + u64 *cmd_ptr; + + __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id); + + /* Make sure nobody else is updating the same queue */ + if (cvmx_likely(use_locking)) + __cvmx_cmd_queue_lock(queue_id); + + if (cvmx_unlikely((qptr->index + 2) >= qptr->pool_size_m1)) { + /* The rare case when nearing end of block */ + u64 cmds[2]; + + cmds[0] = cmd1; + cmds[1] = cmd2; + ret = __cvmx_cmd_queue_write_raw(queue_id, qptr, 2, cmds); + } else { + /* Likely case to work fast */ + cmd_ptr = (u64 *)cvmx_phys_to_ptr((u64)qptr->base_paddr); + cmd_ptr += qptr->index; + qptr->index += 2; + cmd_ptr[0] = cmd1; + cmd_ptr[1] = cmd2; + } + + /* All updates are complete. Release the lock and return */ + if (cvmx_likely(use_locking)) + __cvmx_cmd_queue_unlock(queue_id); + else + CVMX_SYNCWS; + + return ret; +} + +/** + * Simple function to write three command words to a command queue. + * + * @param queue_id Hardware command queue to write to + * @param use_locking + * Use internal locking to ensure exclusive access for queue + * updates. If you don't use this locking you must ensure + * exclusivity some other way. Locking is strongly recommended. + * @param cmd1 Command + * @param cmd2 Command + * @param cmd3 Command + * + * @return CVMX_CMD_QUEUE_SUCCESS or a failure code + */ +static inline cvmx_cmd_queue_result_t +cvmx_cmd_queue_write3(cvmx_cmd_queue_id_t queue_id, bool use_locking, u64 cmd1, u64 cmd2, u64 cmd3) +{ + cvmx_cmd_queue_result_t ret = CVMX_CMD_QUEUE_SUCCESS; + __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id); + u64 *cmd_ptr; + + /* Make sure nobody else is updating the same queue */ + if (cvmx_likely(use_locking)) + __cvmx_cmd_queue_lock(queue_id); + + if (cvmx_unlikely((qptr->index + 3) >= qptr->pool_size_m1)) { + /* Most of the time there is lots of free words in current block */ + u64 cmds[3]; + + cmds[0] = cmd1; + cmds[1] = cmd2; + cmds[2] = cmd3; + ret = __cvmx_cmd_queue_write_raw(queue_id, qptr, 3, cmds); + } else { + cmd_ptr = (u64 *)cvmx_phys_to_ptr((u64)qptr->base_paddr); + cmd_ptr += qptr->index; + qptr->index += 3; + cmd_ptr[0] = cmd1; + cmd_ptr[1] = cmd2; + cmd_ptr[2] = cmd3; + } + + /* All updates are complete. Release the lock and return */ + if (cvmx_likely(use_locking)) + __cvmx_cmd_queue_unlock(queue_id); + else + CVMX_SYNCWS; + + return ret; +} + +#endif /* __CVMX_CMD_QUEUE_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-csr-enums.h b/arch/mips/mach-octeon/include/mach/cvmx-csr-enums.h new file mode 100644 index 000000000000..a8625b4228ac --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-csr-enums.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Definitions for enumerations used with Octeon CSRs. + */ + +#ifndef __CVMX_CSR_ENUMS_H__ +#define __CVMX_CSR_ENUMS_H__ + +typedef enum { + CVMX_IPD_OPC_MODE_STT = 0LL, + CVMX_IPD_OPC_MODE_STF = 1LL, + CVMX_IPD_OPC_MODE_STF1_STT = 2LL, + CVMX_IPD_OPC_MODE_STF2_STT = 3LL +} cvmx_ipd_mode_t; + +/** + * Enumeration representing the amount of packet processing + * and validation performed by the input hardware. + */ +typedef enum { + CVMX_PIP_PORT_CFG_MODE_NONE = 0ull, + CVMX_PIP_PORT_CFG_MODE_SKIPL2 = 1ull, + CVMX_PIP_PORT_CFG_MODE_SKIPIP = 2ull +} cvmx_pip_port_parse_mode_t; + +/** + * This enumeration controls how a QoS watcher matches a packet. + * + * @deprecated This enumeration was used with cvmx_pip_config_watcher which has + * been deprecated. + */ +typedef enum { + CVMX_PIP_QOS_WATCH_DISABLE = 0ull, + CVMX_PIP_QOS_WATCH_PROTNH = 1ull, + CVMX_PIP_QOS_WATCH_TCP = 2ull, + CVMX_PIP_QOS_WATCH_UDP = 3ull +} cvmx_pip_qos_watch_types; + +/** + * This enumeration is used in PIP tag config to control how + * POW tags are generated by the hardware. + */ +typedef enum { + CVMX_PIP_TAG_MODE_TUPLE = 0ull, + CVMX_PIP_TAG_MODE_MASK = 1ull, + CVMX_PIP_TAG_MODE_IP_OR_MASK = 2ull, + CVMX_PIP_TAG_MODE_TUPLE_XOR_MASK = 3ull +} cvmx_pip_tag_mode_t; + +/** + * Tag type definitions + */ +typedef enum { + CVMX_POW_TAG_TYPE_ORDERED = 0L, + CVMX_POW_TAG_TYPE_ATOMIC = 1L, + CVMX_POW_TAG_TYPE_NULL = 2L, + CVMX_POW_TAG_TYPE_NULL_NULL = 3L +} cvmx_pow_tag_type_t; + +/** + * LCR bits 0 and 1 control the number of bits per character. See the following table for encodings: + * + * - 00 = 5 bits (bits 0-4 sent) + * - 01 = 6 bits (bits 0-5 sent) + * - 10 = 7 bits (bits 0-6 sent) + * - 11 = 8 bits (all bits sent) + */ +typedef enum { + CVMX_UART_BITS5 = 0, + CVMX_UART_BITS6 = 1, + CVMX_UART_BITS7 = 2, + CVMX_UART_BITS8 = 3 +} cvmx_uart_bits_t; + +typedef enum { + CVMX_UART_IID_NONE = 1, + CVMX_UART_IID_RX_ERROR = 6, + CVMX_UART_IID_RX_DATA = 4, + CVMX_UART_IID_RX_TIMEOUT = 12, + CVMX_UART_IID_TX_EMPTY = 2, + CVMX_UART_IID_MODEM = 0, + CVMX_UART_IID_BUSY = 7 +} cvmx_uart_iid_t; + +#endif /* __CVMX_CSR_ENUMS_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-csr.h b/arch/mips/mach-octeon/include/mach/cvmx-csr.h new file mode 100644 index 000000000000..730d54bb9278 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-csr.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Configuration and status register (CSR) address and type definitions for + * Octoen. + */ + +#ifndef __CVMX_CSR_H__ +#define __CVMX_CSR_H__ + +#include "cvmx-csr-enums.h" +#include "cvmx-pip-defs.h" + +typedef cvmx_pip_prt_cfgx_t cvmx_pip_port_cfg_t; + +/* The CSRs for bootbus region zero used to be independent of the + other 1-7. As of SDK 1.7.0 these were combined. These macros + are for backwards compactability */ +#define CVMX_MIO_BOOT_REG_CFG0 CVMX_MIO_BOOT_REG_CFGX(0) +#define CVMX_MIO_BOOT_REG_TIM0 CVMX_MIO_BOOT_REG_TIMX(0) + +/* The CN3XXX and CN58XX chips used to not have a LMC number + passed to the address macros. These are here to supply backwards + compatibility with old code. Code should really use the new addresses + with bus arguments for support on other chips */ +#define CVMX_LMC_BIST_CTL CVMX_LMCX_BIST_CTL(0) +#define CVMX_LMC_BIST_RESULT CVMX_LMCX_BIST_RESULT(0) +#define CVMX_LMC_COMP_CTL CVMX_LMCX_COMP_CTL(0) +#define CVMX_LMC_CTL CVMX_LMCX_CTL(0) +#define CVMX_LMC_CTL1 CVMX_LMCX_CTL1(0) +#define CVMX_LMC_DCLK_CNT_HI CVMX_LMCX_DCLK_CNT_HI(0) +#define CVMX_LMC_DCLK_CNT_LO CVMX_LMCX_DCLK_CNT_LO(0) +#define CVMX_LMC_DCLK_CTL CVMX_LMCX_DCLK_CTL(0) +#define CVMX_LMC_DDR2_CTL CVMX_LMCX_DDR2_CTL(0) +#define CVMX_LMC_DELAY_CFG CVMX_LMCX_DELAY_CFG(0) +#define CVMX_LMC_DLL_CTL CVMX_LMCX_DLL_CTL(0) +#define CVMX_LMC_DUAL_MEMCFG CVMX_LMCX_DUAL_MEMCFG(0) +#define CVMX_LMC_ECC_SYND CVMX_LMCX_ECC_SYND(0) +#define CVMX_LMC_FADR CVMX_LMCX_FADR(0) +#define CVMX_LMC_IFB_CNT_HI CVMX_LMCX_IFB_CNT_HI(0) +#define CVMX_LMC_IFB_CNT_LO CVMX_LMCX_IFB_CNT_LO(0) +#define CVMX_LMC_MEM_CFG0 CVMX_LMCX_MEM_CFG0(0) +#define CVMX_LMC_MEM_CFG1 CVMX_LMCX_MEM_CFG1(0) +#define CVMX_LMC_OPS_CNT_HI CVMX_LMCX_OPS_CNT_HI(0) +#define CVMX_LMC_OPS_CNT_LO CVMX_LMCX_OPS_CNT_LO(0) +#define CVMX_LMC_PLL_BWCTL CVMX_LMCX_PLL_BWCTL(0) +#define CVMX_LMC_PLL_CTL CVMX_LMCX_PLL_CTL(0) +#define CVMX_LMC_PLL_STATUS CVMX_LMCX_PLL_STATUS(0) +#define CVMX_LMC_READ_LEVEL_CTL CVMX_LMCX_READ_LEVEL_CTL(0) +#define CVMX_LMC_READ_LEVEL_DBG CVMX_LMCX_READ_LEVEL_DBG(0) +#define CVMX_LMC_READ_LEVEL_RANKX CVMX_LMCX_READ_LEVEL_RANKX(0) +#define CVMX_LMC_RODT_COMP_CTL CVMX_LMCX_RODT_COMP_CTL(0) +#define CVMX_LMC_RODT_CTL CVMX_LMCX_RODT_CTL(0) +#define CVMX_LMC_WODT_CTL CVMX_LMCX_WODT_CTL0(0) +#define CVMX_LMC_WODT_CTL0 CVMX_LMCX_WODT_CTL0(0) +#define CVMX_LMC_WODT_CTL1 CVMX_LMCX_WODT_CTL1(0) + +/* The CN3XXX and CN58XX chips used to not have a TWSI bus number + passed to the address macros. These are here to supply backwards + compatibility with old code. Code should really use the new addresses + with bus arguments for support on other chips */ +#define CVMX_MIO_TWS_INT CVMX_MIO_TWSX_INT(0) +#define CVMX_MIO_TWS_SW_TWSI CVMX_MIO_TWSX_SW_TWSI(0) +#define CVMX_MIO_TWS_SW_TWSI_EXT CVMX_MIO_TWSX_SW_TWSI_EXT(0) +#define CVMX_MIO_TWS_TWSI_SW CVMX_MIO_TWSX_TWSI_SW(0) + +/* The CN3XXX and CN58XX chips used to not have a SMI/MDIO bus number + passed to the address macros. These are here to supply backwards + compatibility with old code. Code should really use the new addresses + with bus arguments for support on other chips */ +#define CVMX_SMI_CLK CVMX_SMIX_CLK(0) +#define CVMX_SMI_CMD CVMX_SMIX_CMD(0) +#define CVMX_SMI_EN CVMX_SMIX_EN(0) +#define CVMX_SMI_RD_DAT CVMX_SMIX_RD_DAT(0) +#define CVMX_SMI_WR_DAT CVMX_SMIX_WR_DAT(0) + +#endif /* __CVMX_CSR_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-error.h b/arch/mips/mach-octeon/include/mach/cvmx-error.h new file mode 100644 index 000000000000..9a13ed422484 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-error.h @@ -0,0 +1,456 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Interface to the Octeon extended error status. + */ + +#ifndef __CVMX_ERROR_H__ +#define __CVMX_ERROR_H__ + +/** + * There are generally many error status bits associated with a + * single logical group. The enumeration below is used to + * communicate high level groups to the error infastructure so + * error status bits can be enable or disabled in large groups. + */ +typedef enum { + CVMX_ERROR_GROUP_INTERNAL, + CVMX_ERROR_GROUP_L2C, + CVMX_ERROR_GROUP_ETHERNET, + CVMX_ERROR_GROUP_MGMT_PORT, + CVMX_ERROR_GROUP_PCI, + CVMX_ERROR_GROUP_SRIO, + CVMX_ERROR_GROUP_USB, + CVMX_ERROR_GROUP_LMC, + CVMX_ERROR_GROUP_ILK, + CVMX_ERROR_GROUP_DFM, + CVMX_ERROR_GROUP_ILA, +} cvmx_error_group_t; + +/** + * Flags representing special handling for some error registers. + * These flags are passed to cvmx_error_initialize() to control + * the handling of bits where the same flags were passed to the + * added cvmx_error_info_t. + */ +typedef enum { + CVMX_ERROR_TYPE_NONE = 0, + CVMX_ERROR_TYPE_SBE = 1 << 0, + CVMX_ERROR_TYPE_DBE = 1 << 1, +} cvmx_error_type_t; + +/** + * When registering for interest in an error status register, the + * type of the register needs to be known by cvmx-error. Most + * registers are either IO64 or IO32, but some blocks contain + * registers that can't be directly accessed. A good example of + * would be PCIe extended error state stored in config space. + */ +typedef enum { + __CVMX_ERROR_REGISTER_NONE, + CVMX_ERROR_REGISTER_IO64, + CVMX_ERROR_REGISTER_IO32, + CVMX_ERROR_REGISTER_PCICONFIG, + CVMX_ERROR_REGISTER_SRIOMAINT, +} cvmx_error_register_t; + +struct cvmx_error_info; +/** + * Error handling functions must have the following prototype. + */ +typedef int (*cvmx_error_func_t)(const struct cvmx_error_info *info); + +/** + * This structure is passed to all error handling functions. + */ +typedef struct cvmx_error_info { + cvmx_error_register_t reg_type; + u64 status_addr; + u64 status_mask; + u64 enable_addr; + u64 enable_mask; + cvmx_error_type_t flags; + cvmx_error_group_t group; + int group_index; + cvmx_error_func_t func; + u64 user_info; + struct { + cvmx_error_register_t reg_type; + u64 status_addr; + u64 status_mask; + } parent; +} cvmx_error_info_t; + +/** + * Initialize the error status system. This should be called once + * before any other functions are called. This function adds default + * handlers for most all error events but does not enable them. Later + * calls to cvmx_error_enable() are needed. + * + * @param flags Optional flags. + * + * @return Zero on success, negative on failure. + */ +int cvmx_error_initialize(void); + +/** + * Poll the error status registers and call the appropriate error + * handlers. This should be called in the RSL interrupt handler + * for your application or operating system. + * + * @return Number of error handlers called. Zero means this call + * found no errors and was spurious. + */ +int cvmx_error_poll(void); + +/** + * Register to be called when an error status bit is set. Most users + * will not need to call this function as cvmx_error_initialize() + * registers default handlers for most error conditions. This function + * is normally used to add more handlers without changing the existing + * handlers. + * + * @param new_info Information about the handler for a error register. The + * structure passed is copied and can be destroyed after the + * call. All members of the structure must be populated, even the + * parent information. + * + * @return Zero on success, negative on failure. + */ +int cvmx_error_add(const cvmx_error_info_t *new_info); + +/** + * Remove all handlers for a status register and mask. Normally + * this function should not be called. Instead a new handler should be + * installed to replace the existing handler. In the even that all + * reporting of a error bit should be removed, then use this + * function. + * + * @param reg_type Type of the status register to remove + * @param status_addr + * Status register to remove. + * @param status_mask + * All handlers for this status register with this mask will be + * removed. + * @param old_info If not NULL, this is filled with information about the handler + * that was removed. + * + * @return Zero on success, negative on failure (not found). + */ +int cvmx_error_remove(cvmx_error_register_t reg_type, u64 status_addr, u64 status_mask, + cvmx_error_info_t *old_info); + +/** + * Change the function and user_info for an existing error status + * register. This function should be used to replace the default + * handler with an application specific version as needed. + * + * @param reg_type Type of the status register to change + * @param status_addr + * Status register to change. + * @param status_mask + * All handlers for this status register with this mask will be + * changed. + * @param new_func New function to use to handle the error status + * @param new_user_info + * New user info parameter for the function + * @param old_func If not NULL, the old function is returned. Useful for restoring + * the old handler. + * @param old_user_info + * If not NULL, the old user info parameter. + * + * @return Zero on success, negative on failure + */ +int cvmx_error_change_handler(cvmx_error_register_t reg_type, u64 status_addr, u64 status_mask, + cvmx_error_func_t new_func, u64 new_user_info, + cvmx_error_func_t *old_func, u64 *old_user_info); + +/** + * Enable all error registers for a logical group. This should be + * called whenever a logical group is brought online. + * + * @param group Logical group to enable + * @param group_index + * Index for the group as defined in the cvmx_error_group_t + * comments. + * + * @return Zero on success, negative on failure. + */ +/* + * Rather than conditionalize the calls throughout the executive to not enable + * interrupts in Uboot, simply make the enable function do nothing + */ +static inline int cvmx_error_enable_group(cvmx_error_group_t group, int group_index) +{ + return 0; +} + +/** + * Disable all error registers for a logical group. This should be + * called whenever a logical group is brought offline. Many blocks + * will report spurious errors when offline unless this function + * is called. + * + * @param group Logical group to disable + * @param group_index + * Index for the group as defined in the cvmx_error_group_t + * comments. + * + * @return Zero on success, negative on failure. + */ +/* + * Rather than conditionalize the calls throughout the executive to not disable + * interrupts in Uboot, simply make the enable function do nothing + */ +static inline int cvmx_error_disable_group(cvmx_error_group_t group, int group_index) +{ + return 0; +} + +/** + * Enable all handlers for a specific status register mask. + * + * @param reg_type Type of the status register + * @param status_addr + * Status register address + * @param status_mask + * All handlers for this status register with this mask will be + * enabled. + * + * @return Zero on success, negative on failure. + */ +int cvmx_error_enable(cvmx_error_register_t reg_type, u64 status_addr, u64 status_mask); + +/** + * Disable all handlers for a specific status register and mask. + * + * @param reg_type Type of the status register + * @param status_addr + * Status register address + * @param status_mask + * All handlers for this status register with this mask will be + * disabled. + * + * @return Zero on success, negative on failure. + */ +int cvmx_error_disable(cvmx_error_register_t reg_type, u64 status_addr, u64 status_mask); + +/** + * @INTERNAL + * Function for processing non leaf error status registers. This function + * calls all handlers for this passed register and all children linked + * to it. + * + * @param info Error register to check + * + * @return Number of error status bits found or zero if no bits were set. + */ +int __cvmx_error_decode(const cvmx_error_info_t *info); + +/** + * @INTERNAL + * This error bit handler simply prints a message and clears the status bit + * + * @param info Error register to check + * + * @return + */ +int __cvmx_error_display(const cvmx_error_info_t *info); + +/** + * Find the handler for a specific status register and mask + * + * @param status_addr + * Status register address + * + * @return Return the handler on success or null on failure. + */ +cvmx_error_info_t *cvmx_error_get_index(u64 status_addr); + +void __cvmx_install_gmx_error_handler_for_xaui(void); + +/** + * 78xx related + */ +/** + * Compare two INTSN values. + * + * @param key INTSN value to search for + * @param data current entry from the searched array + * + * @return Negative, 0 or positive when respectively key is less than, + * equal or greater than data. + */ +int cvmx_error_intsn_cmp(const void *key, const void *data); + +/** + * @INTERNAL + * + * @param intsn Interrupt source number to display + * + * @param node Node number + * + * @return Zero on success, -1 on error + */ +int cvmx_error_intsn_display_v3(int node, u32 intsn); + +/** + * Initialize the error status system for cn78xx. This should be called once + * before any other functions are called. This function enables the interrupts + * described in the array. + * + * @param node Node number + * + * @return Zero on success, negative on failure. + */ +int cvmx_error_initialize_cn78xx(int node); + +/** + * Enable interrupt for a specific INTSN. + * + * @param node Node number + * @param intsn Interrupt source number + * + * @return Zero on success, negative on failure. + */ +int cvmx_error_intsn_enable_v3(int node, u32 intsn); + +/** + * Disable interrupt for a specific INTSN. + * + * @param node Node number + * @param intsn Interrupt source number + * + * @return Zero on success, negative on failure. + */ +int cvmx_error_intsn_disable_v3(int node, u32 intsn); + +/** + * Clear interrupt for a specific INTSN. + * + * @param intsn Interrupt source number + * + * @return Zero on success, negative on failure. + */ +int cvmx_error_intsn_clear_v3(int node, u32 intsn); + +/** + * Enable interrupts for a specific CSR(all the bits/intsn in the csr). + * + * @param node Node number + * @param csr_address CSR address + * + * @return Zero on success, negative on failure. + */ +int cvmx_error_csr_enable_v3(int node, u64 csr_address); + +/** + * Disable interrupts for a specific CSR (all the bits/intsn in the csr). + * + * @param node Node number + * @param csr_address CSR address + * + * @return Zero + */ +int cvmx_error_csr_disable_v3(int node, u64 csr_address); + +/** + * Enable all error registers for a logical group. This should be + * called whenever a logical group is brought online. + * + * @param group Logical group to enable + * @param xipd_port The IPD port value + * + * @return Zero. + */ +int cvmx_error_enable_group_v3(cvmx_error_group_t group, int xipd_port); + +/** + * Disable all error registers for a logical group. + * + * @param group Logical group to enable + * @param xipd_port The IPD port value + * + * @return Zero. + */ +int cvmx_error_disable_group_v3(cvmx_error_group_t group, int xipd_port); + +/** + * Enable all error registers for a specific category in a logical group. + * This should be called whenever a logical group is brought online. + * + * @param group Logical group to enable + * @param type Category in a logical group to enable + * @param xipd_port The IPD port value + * + * @return Zero. + */ +int cvmx_error_enable_group_type_v3(cvmx_error_group_t group, cvmx_error_type_t type, + int xipd_port); + +/** + * Disable all error registers for a specific category in a logical group. + * This should be called whenever a logical group is brought online. + * + * @param group Logical group to disable + * @param type Category in a logical group to disable + * @param xipd_port The IPD port value + * + * @return Zero. + */ +int cvmx_error_disable_group_type_v3(cvmx_error_group_t group, cvmx_error_type_t type, + int xipd_port); + +/** + * Clear all error registers for a logical group. + * + * @param group Logical group to disable + * @param xipd_port The IPD port value + * + * @return Zero. + */ +int cvmx_error_clear_group_v3(cvmx_error_group_t group, int xipd_port); + +/** + * Enable all error registers for a particular category. + * + * @param node CCPI node + * @param type category to enable + * + *@return Zero. + */ +int cvmx_error_enable_type_v3(int node, cvmx_error_type_t type); + +/** + * Disable all error registers for a particular category. + * + * @param node CCPI node + * @param type category to disable + * + *@return Zero. + */ +int cvmx_error_disable_type_v3(int node, cvmx_error_type_t type); + +void cvmx_octeon_hang(void) __attribute__((__noreturn__)); + +/** + * @INTERNAL + * + * Process L2C single and multi-bit ECC errors + * + */ +int __cvmx_cn7xxx_l2c_l2d_ecc_error_display(int node, int intsn); + +/** + * Handle L2 cache TAG ECC errors and noway errors + * + * @param CCPI node + * @param intsn intsn from error array. + * @param remote true for remote node (cn78xx only) + * + * @return 1 if handled, 0 if not handled + */ +int __cvmx_cn7xxx_l2c_tag_error_display(int node, int intsn, bool remote); + +#endif diff --git a/arch/mips/mach-octeon/include/mach/cvmx-fpa.h b/arch/mips/mach-octeon/include/mach/cvmx-fpa.h new file mode 100644 index 000000000000..297fb3f4a28c --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-fpa.h @@ -0,0 +1,217 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Interface to the hardware Free Pool Allocator. + */ + +#ifndef __CVMX_FPA_H__ +#define __CVMX_FPA_H__ + +#include "cvmx-scratch.h" +#include "cvmx-fpa-defs.h" +#include "cvmx-fpa1.h" +#include "cvmx-fpa3.h" + +#define CVMX_FPA_MIN_BLOCK_SIZE 128 +#define CVMX_FPA_ALIGNMENT 128 +#define CVMX_FPA_POOL_NAME_LEN 16 + +/* On CN78XX in backward-compatible mode, pool is mapped to AURA */ +#define CVMX_FPA_NUM_POOLS \ + (octeon_has_feature(OCTEON_FEATURE_FPA3) ? cvmx_fpa3_num_auras() : CVMX_FPA1_NUM_POOLS) + +/** + * Structure to store FPA pool configuration parameters. + */ +struct cvmx_fpa_pool_config { + s64 pool_num; + u64 buffer_size; + u64 buffer_count; +}; + +typedef struct cvmx_fpa_pool_config cvmx_fpa_pool_config_t; + +/** + * Return the name of the pool + * + * @param pool_num Pool to get the name of + * @return The name + */ +const char *cvmx_fpa_get_name(int pool_num); + +/** + * Initialize FPA per node + */ +int cvmx_fpa_global_init_node(int node); + +/** + * Enable the FPA + */ +static inline void cvmx_fpa_enable(void) +{ + if (!octeon_has_feature(OCTEON_FEATURE_FPA3)) + cvmx_fpa1_enable(); + else + cvmx_fpa_global_init_node(cvmx_get_node_num()); +} + +/** + * Disable the FPA + */ +static inline void cvmx_fpa_disable(void) +{ + if (!octeon_has_feature(OCTEON_FEATURE_FPA3)) + cvmx_fpa1_disable(); + /* FPA3 does not have a disable function */ +} + +/** + * @INTERNAL + * @deprecated OBSOLETE + * + * Kept for transition assistance only + */ +static inline void cvmx_fpa_global_initialize(void) +{ + cvmx_fpa_global_init_node(cvmx_get_node_num()); +} + +/** + * @INTERNAL + * + * Convert FPA1 style POOL into FPA3 AURA in + * backward compatibility mode. + */ +static inline cvmx_fpa3_gaura_t cvmx_fpa1_pool_to_fpa3_aura(cvmx_fpa1_pool_t pool) +{ + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) { + unsigned int node = cvmx_get_node_num(); + cvmx_fpa3_gaura_t aura = __cvmx_fpa3_gaura(node, pool); + return aura; + } + return CVMX_FPA3_INVALID_GAURA; +} + +/** + * Get a new block from the FPA + * + * @param pool Pool to get the block from + * @return Pointer to the block or NULL on failure + */ +static inline void *cvmx_fpa_alloc(u64 pool) +{ + /* FPA3 is handled differently */ + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) { + return cvmx_fpa3_alloc(cvmx_fpa1_pool_to_fpa3_aura(pool)); + } else + return cvmx_fpa1_alloc(pool); +} + +/** + * Asynchronously get a new block from the FPA + * + * The result of cvmx_fpa_async_alloc() may be retrieved using + * cvmx_fpa_async_alloc_finish(). + * + * @param scr_addr Local scratch address to put response in. This is a byte + * address but must be 8 byte aligned. + * @param pool Pool to get the block from + */ +static inline void cvmx_fpa_async_alloc(u64 scr_addr, u64 pool) +{ + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) { + return cvmx_fpa3_async_alloc(scr_addr, cvmx_fpa1_pool_to_fpa3_aura(pool)); + } else + return cvmx_fpa1_async_alloc(scr_addr, pool); +} + +/** + * Retrieve the result of cvmx_fpa_async_alloc + * + * @param scr_addr The Local scratch address. Must be the same value + * passed to cvmx_fpa_async_alloc(). + * + * @param pool Pool the block came from. Must be the same value + * passed to cvmx_fpa_async_alloc. + * + * @return Pointer to the block or NULL on failure + */ +static inline void *cvmx_fpa_async_alloc_finish(u64 scr_addr, u64 pool) +{ + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) + return cvmx_fpa3_async_alloc_finish(scr_addr, cvmx_fpa1_pool_to_fpa3_aura(pool)); + else + return cvmx_fpa1_async_alloc_finish(scr_addr, pool); +} + +/** + * Free a block allocated with a FPA pool. + * Does NOT provide memory ordering in cases where the memory block was + * modified by the core. + * + * @param ptr Block to free + * @param pool Pool to put it in + * @param num_cache_lines + * Cache lines to invalidate + */ +static inline void cvmx_fpa_free_nosync(void *ptr, u64 pool, u64 num_cache_lines) +{ + /* FPA3 is handled differently */ + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) + cvmx_fpa3_free_nosync(ptr, cvmx_fpa1_pool_to_fpa3_aura(pool), num_cache_lines); + else + cvmx_fpa1_free_nosync(ptr, pool, num_cache_lines); +} + +/** + * Free a block allocated with a FPA pool. Provides required memory + * ordering in cases where memory block was modified by core. + * + * @param ptr Block to free + * @param pool Pool to put it in + * @param num_cache_lines + * Cache lines to invalidate + */ +static inline void cvmx_fpa_free(void *ptr, u64 pool, u64 num_cache_lines) +{ + if ((octeon_has_feature(OCTEON_FEATURE_FPA3))) + cvmx_fpa3_free(ptr, cvmx_fpa1_pool_to_fpa3_aura(pool), num_cache_lines); + else + cvmx_fpa1_free(ptr, pool, num_cache_lines); +} + +/** + * Setup a FPA pool to control a new block of memory. + * This can only be called once per pool. Make sure proper + * locking enforces this. + * + * @param pool Pool to initialize + * @param name Constant character string to name this pool. + * String is not copied. + * @param buffer Pointer to the block of memory to use. This must be + * accessible by all processors and external hardware. + * @param block_size Size for each block controlled by the FPA + * @param num_blocks Number of blocks + * + * @return the pool number on Success, + * -1 on failure + */ +int cvmx_fpa_setup_pool(int pool, const char *name, void *buffer, u64 block_size, u64 num_blocks); + +int cvmx_fpa_shutdown_pool(int pool); + +/** + * Gets the block size of buffer in specified pool + * @param pool Pool to get the block size from + * @return Size of buffer in specified pool + */ +unsigned int cvmx_fpa_get_block_size(int pool); + +int cvmx_fpa_is_pool_available(int pool_num); +u64 cvmx_fpa_get_pool_owner(int pool_num); +int cvmx_fpa_get_max_pools(void); +int cvmx_fpa_get_current_count(int pool_num); +int cvmx_fpa_validate_pool(int pool); + +#endif /* __CVM_FPA_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-fpa1.h b/arch/mips/mach-octeon/include/mach/cvmx-fpa1.h new file mode 100644 index 000000000000..6985083a5d66 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-fpa1.h @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Interface to the hardware Free Pool Allocator on Octeon chips. + * These are the legacy models, i.e. prior to CN78XX/CN76XX. + */ + +#ifndef __CVMX_FPA1_HW_H__ +#define __CVMX_FPA1_HW_H__ + +#include "cvmx-scratch.h" +#include "cvmx-fpa-defs.h" +#include "cvmx-fpa3.h" + +/* Legacy pool range is 0..7 and 8 on CN68XX */ +typedef int cvmx_fpa1_pool_t; + +#define CVMX_FPA1_NUM_POOLS 8 +#define CVMX_FPA1_INVALID_POOL ((cvmx_fpa1_pool_t)-1) +#define CVMX_FPA1_NAME_SIZE 16 + +/** + * Structure describing the data format used for stores to the FPA. + */ +typedef union { + u64 u64; + struct { + u64 scraddr : 8; + u64 len : 8; + u64 did : 8; + u64 addr : 40; + } s; +} cvmx_fpa1_iobdma_data_t; + +/* + * Allocate or reserve the specified fpa pool. + * + * @param pool FPA pool to allocate/reserve. If -1 it + * finds an empty pool to allocate. + * @return Alloctaed pool number or CVMX_FPA1_POOL_INVALID + * if fails to allocate the pool + */ +cvmx_fpa1_pool_t cvmx_fpa1_reserve_pool(cvmx_fpa1_pool_t pool); + +/** + * Free the specified fpa pool. + * @param pool Pool to free + * @return 0 for success -1 failure + */ +int cvmx_fpa1_release_pool(cvmx_fpa1_pool_t pool); + +static inline void cvmx_fpa1_free(void *ptr, cvmx_fpa1_pool_t pool, u64 num_cache_lines) +{ + cvmx_addr_t newptr; + + newptr.u64 = cvmx_ptr_to_phys(ptr); + newptr.sfilldidspace.didspace = CVMX_ADDR_DIDSPACE(CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool)); + /* Make sure that any previous writes to memory go out before we free + * this buffer. This also serves as a barrier to prevent GCC from + * reordering operations to after the free. + */ + CVMX_SYNCWS; + /* value written is number of cache lines not written back */ + cvmx_write_io(newptr.u64, num_cache_lines); +} + +static inline void cvmx_fpa1_free_nosync(void *ptr, cvmx_fpa1_pool_t pool, + unsigned int num_cache_lines) +{ + cvmx_addr_t newptr; + + newptr.u64 = cvmx_ptr_to_phys(ptr); + newptr.sfilldidspace.didspace = CVMX_ADDR_DIDSPACE(CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool)); + /* Prevent GCC from reordering around free */ + asm volatile("" : : : "memory"); + /* value written is number of cache lines not written back */ + cvmx_write_io(newptr.u64, num_cache_lines); +} + +/** + * Enable the FPA for use. Must be performed after any CSR + * configuration but before any other FPA functions. + */ +static inline void cvmx_fpa1_enable(void) +{ + cvmx_fpa_ctl_status_t status; + + status.u64 = csr_rd(CVMX_FPA_CTL_STATUS); + if (status.s.enb) { + /* + * CN68XXP1 should not reset the FPA (doing so may break + * the SSO, so we may end up enabling it more than once. + * Just return and don't spew messages. + */ + return; + } + + status.u64 = 0; + status.s.enb = 1; + csr_wr(CVMX_FPA_CTL_STATUS, status.u64); +} + +/** + * Reset FPA to disable. Make sure buffers from all FPA pools are freed + * before disabling FPA. + */ +static inline void cvmx_fpa1_disable(void) +{ + cvmx_fpa_ctl_status_t status; + + if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1)) + return; + + status.u64 = csr_rd(CVMX_FPA_CTL_STATUS); + status.s.reset = 1; + csr_wr(CVMX_FPA_CTL_STATUS, status.u64); +} + +static inline void *cvmx_fpa1_alloc(cvmx_fpa1_pool_t pool) +{ + u64 address; + + for (;;) { + address = csr_rd(CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool))); + if (cvmx_likely(address)) { + return cvmx_phys_to_ptr(address); + } else { + if (csr_rd(CVMX_FPA_QUEX_AVAILABLE(pool)) > 0) + udelay(50); + else + return NULL; + } + } +} + +/** + * Asynchronously get a new block from the FPA + * @INTERNAL + * + * The result of cvmx_fpa_async_alloc() may be retrieved using + * cvmx_fpa_async_alloc_finish(). + * + * @param scr_addr Local scratch address to put response in. This is a byte + * address but must be 8 byte aligned. + * @param pool Pool to get the block from + */ +static inline void cvmx_fpa1_async_alloc(u64 scr_addr, cvmx_fpa1_pool_t pool) +{ + cvmx_fpa1_iobdma_data_t data; + + /* Hardware only uses 64 bit aligned locations, so convert from byte + * address to 64-bit index + */ + data.u64 = 0ull; + data.s.scraddr = scr_addr >> 3; + data.s.len = 1; + data.s.did = CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool); + data.s.addr = 0; + + cvmx_scratch_write64(scr_addr, 0ull); + CVMX_SYNCW; + cvmx_send_single(data.u64); +} + +/** + * Retrieve the result of cvmx_fpa_async_alloc + * @INTERNAL + * + * @param scr_addr The Local scratch address. Must be the same value + * passed to cvmx_fpa_async_alloc(). + * + * @param pool Pool the block came from. Must be the same value + * passed to cvmx_fpa_async_alloc. + * + * @return Pointer to the block or NULL on failure + */ +static inline void *cvmx_fpa1_async_alloc_finish(u64 scr_addr, cvmx_fpa1_pool_t pool) +{ + u64 address; + + CVMX_SYNCIOBDMA; + + address = cvmx_scratch_read64(scr_addr); + if (cvmx_likely(address)) + return cvmx_phys_to_ptr(address); + else + return cvmx_fpa1_alloc(pool); +} + +static inline u64 cvmx_fpa1_get_available(cvmx_fpa1_pool_t pool) +{ + return csr_rd(CVMX_FPA_QUEX_AVAILABLE(pool)); +} + +#endif /* __CVMX_FPA1_HW_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-fpa3.h b/arch/mips/mach-octeon/include/mach/cvmx-fpa3.h new file mode 100644 index 000000000000..229982b83163 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-fpa3.h @@ -0,0 +1,566 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Interface to the CN78XX Free Pool Allocator, a.k.a. FPA3 + */ + +#include "cvmx-address.h" +#include "cvmx-fpa-defs.h" +#include "cvmx-scratch.h" + +#ifndef __CVMX_FPA3_H__ +#define __CVMX_FPA3_H__ + +typedef struct { + unsigned res0 : 6; + unsigned node : 2; + unsigned res1 : 2; + unsigned lpool : 6; + unsigned valid_magic : 16; +} cvmx_fpa3_pool_t; + +typedef struct { + unsigned res0 : 6; + unsigned node : 2; + unsigned res1 : 6; + unsigned laura : 10; + unsigned valid_magic : 16; +} cvmx_fpa3_gaura_t; + +#define CVMX_FPA3_VALID_MAGIC 0xf9a3 +#define CVMX_FPA3_INVALID_GAURA ((cvmx_fpa3_gaura_t){ 0, 0, 0, 0, 0 }) +#define CVMX_FPA3_INVALID_POOL ((cvmx_fpa3_pool_t){ 0, 0, 0, 0, 0 }) + +static inline bool __cvmx_fpa3_aura_valid(cvmx_fpa3_gaura_t aura) +{ + if (aura.valid_magic != CVMX_FPA3_VALID_MAGIC) + return false; + return true; +} + +static inline bool __cvmx_fpa3_pool_valid(cvmx_fpa3_pool_t pool) +{ + if (pool.valid_magic != CVMX_FPA3_VALID_MAGIC) + return false; + return true; +} + +static inline cvmx_fpa3_gaura_t __cvmx_fpa3_gaura(int node, int laura) +{ + cvmx_fpa3_gaura_t aura; + + if (node < 0) + node = cvmx_get_node_num(); + if (laura < 0) + return CVMX_FPA3_INVALID_GAURA; + + aura.node = node; + aura.laura = laura; + aura.valid_magic = CVMX_FPA3_VALID_MAGIC; + return aura; +} + +static inline cvmx_fpa3_pool_t __cvmx_fpa3_pool(int node, int lpool) +{ + cvmx_fpa3_pool_t pool; + + if (node < 0) + node = cvmx_get_node_num(); + if (lpool < 0) + return CVMX_FPA3_INVALID_POOL; + + pool.node = node; + pool.lpool = lpool; + pool.valid_magic = CVMX_FPA3_VALID_MAGIC; + return pool; +} + +#undef CVMX_FPA3_VALID_MAGIC + +/** + * Structure describing the data format used for stores to the FPA. + */ +typedef union { + u64 u64; + struct { + u64 scraddr : 8; + u64 len : 8; + u64 did : 8; + u64 addr : 40; + } s; + struct { + u64 scraddr : 8; + u64 len : 8; + u64 did : 8; + u64 node : 4; + u64 red : 1; + u64 reserved2 : 9; + u64 aura : 10; + u64 reserved3 : 16; + } cn78xx; +} cvmx_fpa3_iobdma_data_t; + +/** + * Struct describing load allocate operation addresses for FPA pool. + */ +union cvmx_fpa3_load_data { + u64 u64; + struct { + u64 seg : 2; + u64 reserved1 : 13; + u64 io : 1; + u64 did : 8; + u64 node : 4; + u64 red : 1; + u64 reserved2 : 9; + u64 aura : 10; + u64 reserved3 : 16; + }; +}; + +typedef union cvmx_fpa3_load_data cvmx_fpa3_load_data_t; + +/** + * Struct describing store free operation addresses from FPA pool. + */ +union cvmx_fpa3_store_addr { + u64 u64; + struct { + u64 seg : 2; + u64 reserved1 : 13; + u64 io : 1; + u64 did : 8; + u64 node : 4; + u64 reserved2 : 10; + u64 aura : 10; + u64 fabs : 1; + u64 reserved3 : 3; + u64 dwb_count : 9; + u64 reserved4 : 3; + }; +}; + +typedef union cvmx_fpa3_store_addr cvmx_fpa3_store_addr_t; + +enum cvmx_fpa3_pool_alignment_e { + FPA_NATURAL_ALIGNMENT, + FPA_OFFSET_ALIGNMENT, + FPA_OPAQUE_ALIGNMENT +}; + +#define CVMX_FPA3_AURAX_LIMIT_MAX ((1ull << 40) - 1) + +/** + * @INTERNAL + * Accessor functions to return number of POOLS in an FPA3 + * depending on SoC model. + * The number is per-node for models supporting multi-node configurations. + */ +static inline int cvmx_fpa3_num_pools(void) +{ + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) + return 64; + if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) + return 32; + if (OCTEON_IS_MODEL(OCTEON_CN73XX)) + return 32; + printf("ERROR: %s: Unknowm model\n", __func__); + return -1; +} + +/** + * @INTERNAL + * Accessor functions to return number of AURAS in an FPA3 + * depending on SoC model. + * The number is per-node for models supporting multi-node configurations. + */ +static inline int cvmx_fpa3_num_auras(void) +{ + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) + return 1024; + if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) + return 512; + if (OCTEON_IS_MODEL(OCTEON_CN73XX)) + return 512; + printf("ERROR: %s: Unknowm model\n", __func__); + return -1; +} + +/** + * Get the FPA3 POOL underneath FPA3 AURA, containing all its buffers + * + */ +static inline cvmx_fpa3_pool_t cvmx_fpa3_aura_to_pool(cvmx_fpa3_gaura_t aura) +{ + cvmx_fpa3_pool_t pool; + cvmx_fpa_aurax_pool_t aurax_pool; + + aurax_pool.u64 = cvmx_read_csr_node(aura.node, CVMX_FPA_AURAX_POOL(aura.laura)); + + pool = __cvmx_fpa3_pool(aura.node, aurax_pool.s.pool); + return pool; +} + +/** + * Get a new block from the FPA pool + * + * @param aura - aura number + * @return pointer to the block or NULL on failure + */ +static inline void *cvmx_fpa3_alloc(cvmx_fpa3_gaura_t aura) +{ + u64 address; + cvmx_fpa3_load_data_t load_addr; + + load_addr.u64 = 0; + load_addr.seg = CVMX_MIPS_SPACE_XKPHYS; + load_addr.io = 1; + load_addr.did = 0x29; /* Device ID. Indicates FPA. */ + load_addr.node = aura.node; + load_addr.red = 0; /* Perform RED on allocation. + * FIXME to use config option + */ + load_addr.aura = aura.laura; + + address = cvmx_read64_uint64(load_addr.u64); + if (!address) + return NULL; + return cvmx_phys_to_ptr(address); +} + +/** + * Asynchronously get a new block from the FPA + * + * The result of cvmx_fpa_async_alloc() may be retrieved using + * cvmx_fpa_async_alloc_finish(). + * + * @param scr_addr Local scratch address to put response in. This is a byte + * address but must be 8 byte aligned. + * @param aura Global aura to get the block from + */ +static inline void cvmx_fpa3_async_alloc(u64 scr_addr, cvmx_fpa3_gaura_t aura) +{ + cvmx_fpa3_iobdma_data_t data; + + /* Hardware only uses 64 bit aligned locations, so convert from byte + * address to 64-bit index + */ + data.u64 = 0ull; + data.cn78xx.scraddr = scr_addr >> 3; + data.cn78xx.len = 1; + data.cn78xx.did = 0x29; + data.cn78xx.node = aura.node; + data.cn78xx.aura = aura.laura; + cvmx_scratch_write64(scr_addr, 0ull); + + CVMX_SYNCW; + cvmx_send_single(data.u64); +} + +/** + * Retrieve the result of cvmx_fpa3_async_alloc + * + * @param scr_addr The Local scratch address. Must be the same value + * passed to cvmx_fpa_async_alloc(). + * + * @param aura Global aura the block came from. Must be the same value + * passed to cvmx_fpa_async_alloc. + * + * @return Pointer to the block or NULL on failure + */ +static inline void *cvmx_fpa3_async_alloc_finish(u64 scr_addr, cvmx_fpa3_gaura_t aura) +{ + u64 address; + + CVMX_SYNCIOBDMA; + + address = cvmx_scratch_read64(scr_addr); + if (cvmx_likely(address)) + return cvmx_phys_to_ptr(address); + else + /* Try regular alloc if async failed */ + return cvmx_fpa3_alloc(aura); +} + +/** + * Free a pointer back to the pool. + * + * @param aura global aura number + * @param ptr physical address of block to free. + * @param num_cache_lines Cache lines to invalidate + */ +static inline void cvmx_fpa3_free(void *ptr, cvmx_fpa3_gaura_t aura, unsigned int num_cache_lines) +{ + cvmx_fpa3_store_addr_t newptr; + cvmx_addr_t newdata; + + newdata.u64 = cvmx_ptr_to_phys(ptr); + + /* Make sure that any previous writes to memory go out before we free + this buffer. This also serves as a barrier to prevent GCC from + reordering operations to after the free. */ + CVMX_SYNCWS; + + newptr.u64 = 0; + newptr.seg = CVMX_MIPS_SPACE_XKPHYS; + newptr.io = 1; + newptr.did = 0x29; /* Device id, indicates FPA */ + newptr.node = aura.node; + newptr.aura = aura.laura; + newptr.fabs = 0; /* Free absolute. FIXME to use config option */ + newptr.dwb_count = num_cache_lines; + + cvmx_write_io(newptr.u64, newdata.u64); +} + +/** + * Free a pointer back to the pool without flushing the write buffer. + * + * @param aura global aura number + * @param ptr physical address of block to free. + * @param num_cache_lines Cache lines to invalidate + */ +static inline void cvmx_fpa3_free_nosync(void *ptr, cvmx_fpa3_gaura_t aura, + unsigned int num_cache_lines) +{ + cvmx_fpa3_store_addr_t newptr; + cvmx_addr_t newdata; + + newdata.u64 = cvmx_ptr_to_phys(ptr); + + /* Prevent GCC from reordering writes to (*ptr) */ + asm volatile("" : : : "memory"); + + newptr.u64 = 0; + newptr.seg = CVMX_MIPS_SPACE_XKPHYS; + newptr.io = 1; + newptr.did = 0x29; /* Device id, indicates FPA */ + newptr.node = aura.node; + newptr.aura = aura.laura; + newptr.fabs = 0; /* Free absolute. FIXME to use config option */ + newptr.dwb_count = num_cache_lines; + + cvmx_write_io(newptr.u64, newdata.u64); +} + +static inline int cvmx_fpa3_pool_is_enabled(cvmx_fpa3_pool_t pool) +{ + cvmx_fpa_poolx_cfg_t pool_cfg; + + if (!__cvmx_fpa3_pool_valid(pool)) + return -1; + + pool_cfg.u64 = cvmx_read_csr_node(pool.node, CVMX_FPA_POOLX_CFG(pool.lpool)); + return pool_cfg.cn78xx.ena; +} + +static inline int cvmx_fpa3_config_red_params(unsigned int node, int qos_avg_en, int red_lvl_dly, + int avg_dly) +{ + cvmx_fpa_gen_cfg_t fpa_cfg; + cvmx_fpa_red_delay_t red_delay; + + fpa_cfg.u64 = cvmx_read_csr_node(node, CVMX_FPA_GEN_CFG); + fpa_cfg.s.avg_en = qos_avg_en; + fpa_cfg.s.lvl_dly = red_lvl_dly; + cvmx_write_csr_node(node, CVMX_FPA_GEN_CFG, fpa_cfg.u64); + + red_delay.u64 = cvmx_read_csr_node(node, CVMX_FPA_RED_DELAY); + red_delay.s.avg_dly = avg_dly; + cvmx_write_csr_node(node, CVMX_FPA_RED_DELAY, red_delay.u64); + return 0; +} + +/** + * Gets the buffer size of the specified pool, + * + * @param aura Global aura number + * @return Returns size of the buffers in the specified pool. + */ +static inline int cvmx_fpa3_get_aura_buf_size(cvmx_fpa3_gaura_t aura) +{ + cvmx_fpa3_pool_t pool; + cvmx_fpa_poolx_cfg_t pool_cfg; + int block_size; + + pool = cvmx_fpa3_aura_to_pool(aura); + + pool_cfg.u64 = cvmx_read_csr_node(pool.node, CVMX_FPA_POOLX_CFG(pool.lpool)); + block_size = pool_cfg.cn78xx.buf_size << 7; + return block_size; +} + +/** + * Return the number of available buffers in an AURA + * + * @param aura to receive count for + * @return available buffer count + */ +static inline long long cvmx_fpa3_get_available(cvmx_fpa3_gaura_t aura) +{ + cvmx_fpa3_pool_t pool; + cvmx_fpa_poolx_available_t avail_reg; + cvmx_fpa_aurax_cnt_t cnt_reg; + cvmx_fpa_aurax_cnt_limit_t limit_reg; + long long ret; + + pool = cvmx_fpa3_aura_to_pool(aura); + + /* Get POOL available buffer count */ + avail_reg.u64 = cvmx_read_csr_node(pool.node, CVMX_FPA_POOLX_AVAILABLE(pool.lpool)); + + /* Get AURA current available count */ + cnt_reg.u64 = cvmx_read_csr_node(aura.node, CVMX_FPA_AURAX_CNT(aura.laura)); + limit_reg.u64 = cvmx_read_csr_node(aura.node, CVMX_FPA_AURAX_CNT_LIMIT(aura.laura)); + + if (limit_reg.cn78xx.limit < cnt_reg.cn78xx.cnt) + return 0; + + /* Calculate AURA-based buffer allowance */ + ret = limit_reg.cn78xx.limit - cnt_reg.cn78xx.cnt; + + /* Use POOL real buffer availability when less then allowance */ + if (ret > (long long)avail_reg.cn78xx.count) + ret = avail_reg.cn78xx.count; + + return ret; +} + +/** + * Configure the QoS parameters of an FPA3 AURA + * + * @param aura is the FPA3 AURA handle + * @param ena_bp enables backpressure when outstanding count exceeds 'bp_thresh' + * @param ena_red enables random early discard when outstanding count exceeds 'pass_thresh' + * @param pass_thresh is the maximum count to invoke flow control + * @param drop_thresh is the count threshold to begin dropping packets + * @param bp_thresh is the back-pressure threshold + * + */ +static inline void cvmx_fpa3_setup_aura_qos(cvmx_fpa3_gaura_t aura, bool ena_red, u64 pass_thresh, + u64 drop_thresh, bool ena_bp, u64 bp_thresh) +{ + unsigned int shift = 0; + u64 shift_thresh; + cvmx_fpa_aurax_cnt_limit_t limit_reg; + cvmx_fpa_aurax_cnt_levels_t aura_level; + + if (!__cvmx_fpa3_aura_valid(aura)) + return; + + /* Get AURAX count limit for validation */ + limit_reg.u64 = cvmx_read_csr_node(aura.node, CVMX_FPA_AURAX_CNT_LIMIT(aura.laura)); + + if (pass_thresh < 256) + pass_thresh = 255; + + if (drop_thresh <= pass_thresh || drop_thresh > limit_reg.cn78xx.limit) + drop_thresh = limit_reg.cn78xx.limit; + + if (bp_thresh < 256 || bp_thresh > limit_reg.cn78xx.limit) + bp_thresh = limit_reg.cn78xx.limit >> 1; + + shift_thresh = (bp_thresh > drop_thresh) ? bp_thresh : drop_thresh; + + /* Calculate shift so that the largest threshold fits in 8 bits */ + for (shift = 0; shift < (1 << 6); shift++) { + if (0 == ((shift_thresh >> shift) & ~0xffull)) + break; + }; + + aura_level.u64 = cvmx_read_csr_node(aura.node, CVMX_FPA_AURAX_CNT_LEVELS(aura.laura)); + aura_level.s.pass = pass_thresh >> shift; + aura_level.s.drop = drop_thresh >> shift; + aura_level.s.bp = bp_thresh >> shift; + aura_level.s.shift = shift; + aura_level.s.red_ena = ena_red; + aura_level.s.bp_ena = ena_bp; + cvmx_write_csr_node(aura.node, CVMX_FPA_AURAX_CNT_LEVELS(aura.laura), aura_level.u64); +} + +cvmx_fpa3_gaura_t cvmx_fpa3_reserve_aura(int node, int desired_aura_num); +int cvmx_fpa3_release_aura(cvmx_fpa3_gaura_t aura); +cvmx_fpa3_pool_t cvmx_fpa3_reserve_pool(int node, int desired_pool_num); +int cvmx_fpa3_release_pool(cvmx_fpa3_pool_t pool); +int cvmx_fpa3_is_aura_available(int node, int aura_num); +int cvmx_fpa3_is_pool_available(int node, int pool_num); + +cvmx_fpa3_pool_t cvmx_fpa3_setup_fill_pool(int node, int desired_pool, const char *name, + unsigned int block_size, unsigned int num_blocks, + void *buffer); + +/** + * Function to attach an aura to an existing pool + * + * @param node - configure fpa on this node + * @param pool - configured pool to attach aura to + * @param desired_aura - pointer to aura to use, set to -1 to allocate + * @param name - name to register + * @param block_size - size of buffers to use + * @param num_blocks - number of blocks to allocate + * + * @return configured gaura on success, CVMX_FPA3_INVALID_GAURA on failure + */ +cvmx_fpa3_gaura_t cvmx_fpa3_set_aura_for_pool(cvmx_fpa3_pool_t pool, int desired_aura, + const char *name, unsigned int block_size, + unsigned int num_blocks); + +/** + * Function to setup and initialize a pool. + * + * @param node - configure fpa on this node + * @param desired_aura - aura to use, -1 for dynamic allocation + * @param name - name to register + * @param block_size - size of buffers in pool + * @param num_blocks - max number of buffers allowed + */ +cvmx_fpa3_gaura_t cvmx_fpa3_setup_aura_and_pool(int node, int desired_aura, const char *name, + void *buffer, unsigned int block_size, + unsigned int num_blocks); + +int cvmx_fpa3_shutdown_aura_and_pool(cvmx_fpa3_gaura_t aura); +int cvmx_fpa3_shutdown_aura(cvmx_fpa3_gaura_t aura); +int cvmx_fpa3_shutdown_pool(cvmx_fpa3_pool_t pool); +const char *cvmx_fpa3_get_pool_name(cvmx_fpa3_pool_t pool); +int cvmx_fpa3_get_pool_buf_size(cvmx_fpa3_pool_t pool); +const char *cvmx_fpa3_get_aura_name(cvmx_fpa3_gaura_t aura); + +/* FIXME: Need a different macro for stage2 of u-boot */ + +static inline void cvmx_fpa3_stage2_init(int aura, int pool, u64 stack_paddr, int stacklen, + int buffer_sz, int buf_cnt) +{ + cvmx_fpa_poolx_cfg_t pool_cfg; + + /* Configure pool stack */ + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_BASE(pool), stack_paddr); + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_ADDR(pool), stack_paddr); + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_END(pool), stack_paddr + stacklen); + + /* Configure pool with buffer size */ + pool_cfg.u64 = 0; + pool_cfg.cn78xx.nat_align = 1; + pool_cfg.cn78xx.buf_size = buffer_sz >> 7; + pool_cfg.cn78xx.l_type = 0x2; + pool_cfg.cn78xx.ena = 0; + cvmx_write_csr_node(0, CVMX_FPA_POOLX_CFG(pool), pool_cfg.u64); + /* Reset pool before starting */ + pool_cfg.cn78xx.ena = 1; + cvmx_write_csr_node(0, CVMX_FPA_POOLX_CFG(pool), pool_cfg.u64); + + cvmx_write_csr_node(0, CVMX_FPA_AURAX_CFG(aura), 0); + cvmx_write_csr_node(0, CVMX_FPA_AURAX_CNT_ADD(aura), buf_cnt); + cvmx_write_csr_node(0, CVMX_FPA_AURAX_POOL(aura), (u64)pool); +} + +static inline void cvmx_fpa3_stage2_disable(int aura, int pool) +{ + cvmx_write_csr_node(0, CVMX_FPA_AURAX_POOL(aura), 0); + cvmx_write_csr_node(0, CVMX_FPA_POOLX_CFG(pool), 0); + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_BASE(pool), 0); + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_ADDR(pool), 0); + cvmx_write_csr_node(0, CVMX_FPA_POOLX_STACK_END(pool), 0); +} + +#endif /* __CVMX_FPA3_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-global-resources.h b/arch/mips/mach-octeon/include/mach/cvmx-global-resources.h new file mode 100644 index 000000000000..28c32ddbe17a --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-global-resources.h @@ -0,0 +1,213 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +#ifndef _CVMX_GLOBAL_RESOURCES_T_ +#define _CVMX_GLOBAL_RESOURCES_T_ + +#define CVMX_GLOBAL_RESOURCES_DATA_NAME "cvmx-global-resources" + +/*In macros below abbreviation GR stands for global resources. */ +#define CVMX_GR_TAG_INVALID \ + cvmx_get_gr_tag('i', 'n', 'v', 'a', 'l', 'i', 'd', '.', '.', '.', '.', '.', '.', '.', '.', \ + '.') +/*Tag for pko que table range. */ +#define CVMX_GR_TAG_PKO_QUEUES \ + cvmx_get_gr_tag('c', 'v', 'm', '_', 'p', 'k', 'o', '_', 'q', 'u', 'e', 'u', 's', '.', '.', \ + '.') +/*Tag for a pko internal ports range */ +#define CVMX_GR_TAG_PKO_IPORTS \ + cvmx_get_gr_tag('c', 'v', 'm', '_', 'p', 'k', 'o', '_', 'i', 'p', 'o', 'r', 't', '.', '.', \ + '.') +#define CVMX_GR_TAG_FPA \ + cvmx_get_gr_tag('c', 'v', 'm', '_', 'f', 'p', 'a', '.', '.', '.', '.', '.', '.', '.', '.', \ + '.') +#define CVMX_GR_TAG_FAU \ + cvmx_get_gr_tag('c', 'v', 'm', '_', 'f', 'a', 'u', '.', '.', '.', '.', '.', '.', '.', '.', \ + '.') +#define CVMX_GR_TAG_SSO_GRP(n) \ + cvmx_get_gr_tag('c', 'v', 'm', '_', 's', 's', 'o', '_', '0', (n) + '0', '.', '.', '.', \ + '.', '.', '.'); +#define CVMX_GR_TAG_TIM(n) \ + cvmx_get_gr_tag('c', 'v', 'm', '_', 't', 'i', 'm', '_', (n) + '0', '.', '.', '.', '.', \ + '.', '.', '.') +#define CVMX_GR_TAG_CLUSTERS(x) \ + cvmx_get_gr_tag('c', 'v', 'm', '_', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', (x + '0'), \ + '.', '.', '.') +#define CVMX_GR_TAG_CLUSTER_GRP(x) \ + cvmx_get_gr_tag('c', 'v', 'm', '_', 'c', 'l', 'g', 'r', 'p', '_', (x + '0'), '.', '.', \ + '.', '.', '.') +#define CVMX_GR_TAG_STYLE(x) \ + cvmx_get_gr_tag('c', 'v', 'm', '_', 's', 't', 'y', 'l', 'e', '_', (x + '0'), '.', '.', \ + '.', '.', '.') +#define CVMX_GR_TAG_QPG_ENTRY(x) \ + cvmx_get_gr_tag('c', 'v', 'm', '_', 'q', 'p', 'g', 'e', 't', '_', (x + '0'), '.', '.', \ + '.', '.', '.') +#define CVMX_GR_TAG_BPID(x) \ + cvmx_get_gr_tag('c', 'v', 'm', '_', 'b', 'p', 'i', 'd', 's', '_', (x + '0'), '.', '.', \ + '.', '.', '.') +#define CVMX_GR_TAG_MTAG_IDX(x) \ + cvmx_get_gr_tag('c', 'v', 'm', '_', 'm', 't', 'a', 'g', 'x', '_', (x + '0'), '.', '.', \ + '.', '.', '.') +#define CVMX_GR_TAG_PCAM(x, y, z) \ + cvmx_get_gr_tag('c', 'v', 'm', '_', 'p', 'c', 'a', 'm', '_', (x + '0'), (y + '0'), \ + (z + '0'), '.', '.', '.', '.') + +#define CVMX_GR_TAG_CIU3_IDT(_n) \ + cvmx_get_gr_tag('c', 'v', 'm', '_', 'c', 'i', 'u', '3', '_', ((_n) + '0'), '_', 'i', 'd', \ + 't', '.', '.') + +/* Allocation of the 512 SW INTSTs (in the 12 bit SW INTSN space) */ +#define CVMX_GR_TAG_CIU3_SWINTSN(_n) \ + cvmx_get_gr_tag('c', 'v', 'm', '_', 'c', 'i', 'u', '3', '_', ((_n) + '0'), '_', 's', 'w', \ + 'i', 's', 'n') + +#define TAG_INIT_PART(A, B, C, D, E, F, G, H) \ + ((((u64)(A) & 0xff) << 56) | (((u64)(B) & 0xff) << 48) | (((u64)(C) & 0xff) << 40) | \ + (((u64)(D) & 0xff) << 32) | (((u64)(E) & 0xff) << 24) | (((u64)(F) & 0xff) << 16) | \ + (((u64)(G) & 0xff) << 8) | (((u64)(H) & 0xff))) + +struct global_resource_tag { + u64 lo; + u64 hi; +}; + +enum cvmx_resource_err { CVMX_RESOURCE_ALLOC_FAILED = -1, CVMX_RESOURCE_ALREADY_RESERVED = -2 }; + +/* + * @INTERNAL + * Creates a tag from the specified characters. + */ +static inline struct global_resource_tag cvmx_get_gr_tag(char a, char b, char c, char d, char e, + char f, char g, char h, char i, char j, + char k, char l, char m, char n, char o, + char p) +{ + struct global_resource_tag tag; + + tag.lo = TAG_INIT_PART(a, b, c, d, e, f, g, h); + tag.hi = TAG_INIT_PART(i, j, k, l, m, n, o, p); + return tag; +} + +static inline int cvmx_gr_same_tag(struct global_resource_tag gr1, struct global_resource_tag gr2) +{ + return (gr1.hi == gr2.hi) && (gr1.lo == gr2.lo); +} + +/* + * @INTERNAL + * Creates a global resource range that can hold the specified number of + * elements + * @param tag is the tag of the range. The taga is created using the method + * cvmx_get_gr_tag() + * @param nelements is the number of elements to be held in the resource range. + */ +int cvmx_create_global_resource_range(struct global_resource_tag tag, int nelements); + +/* + * @INTERNAL + * Allocate nelements in the global resource range with the specified tag. It + * is assumed that prior + * to calling this the global resource range has already been created using + * cvmx_create_global_resource_range(). + * @param tag is the tag of the global resource range. + * @param nelements is the number of elements to be allocated. + * @param owner is a 64 bit number that identifes the owner of this range. + * @aligment specifes the required alignment of the returned base number. + * @return returns the base of the allocated range. -1 return value indicates + * failure. + */ +int cvmx_allocate_global_resource_range(struct global_resource_tag tag, u64 owner, int nelements, + int alignment); + +/* + * @INTERNAL + * Allocate nelements in the global resource range with the specified tag. + * The elements allocated need not be contiguous. It is assumed that prior to + * calling this the global resource range has already + * been created using cvmx_create_global_resource_range(). + * @param tag is the tag of the global resource range. + * @param nelements is the number of elements to be allocated. + * @param owner is a 64 bit number that identifes the owner of the allocated + * elements. + * @param allocated_elements returns indexs of the allocated entries. + * @return returns 0 on success and -1 on failure. + */ +int cvmx_resource_alloc_many(struct global_resource_tag tag, u64 owner, int nelements, + int allocated_elements[]); +int cvmx_resource_alloc_reverse(struct global_resource_tag, u64 owner); +/* + * @INTERNAL + * Reserve nelements starting from base in the global resource range with the + * specified tag. + * It is assumed that prior to calling this the global resource range has + * already been created using cvmx_create_global_resource_range(). + * @param tag is the tag of the global resource range. + * @param nelements is the number of elements to be allocated. + * @param owner is a 64 bit number that identifes the owner of this range. + * @base specifies the base start of nelements. + * @return returns the base of the allocated range. -1 return value indicates + * failure. + */ +int cvmx_reserve_global_resource_range(struct global_resource_tag tag, u64 owner, int base, + int nelements); +/* + * @INTERNAL + * Free nelements starting at base in the global resource range with the + * specified tag. + * @param tag is the tag of the global resource range. + * @param base is the base number + * @param nelements is the number of elements that are to be freed. + * @return returns 0 if successful and -1 on failure. + */ +int cvmx_free_global_resource_range_with_base(struct global_resource_tag tag, int base, + int nelements); + +/* + * @INTERNAL + * Free nelements with the bases specified in bases[] with the + * specified tag. + * @param tag is the tag of the global resource range. + * @param bases is an array containing the bases to be freed. + * @param nelements is the number of elements that are to be freed. + * @return returns 0 if successful and -1 on failure. + */ +int cvmx_free_global_resource_range_multiple(struct global_resource_tag tag, int bases[], + int nelements); +/* + * @INTERNAL + * Free elements from the specified owner in the global resource range with the + * specified tag. + * @param tag is the tag of the global resource range. + * @param owner is the owner of resources that are to be freed. + * @return returns 0 if successful and -1 on failure. + */ +int cvmx_free_global_resource_range_with_owner(struct global_resource_tag tag, int owner); + +/* + * @INTERNAL + * Frees all the global resources that have been created. + * For use only from the bootloader, when it shutdown and boots up the + * application or kernel. + */ +int free_global_resources(void); + +u64 cvmx_get_global_resource_owner(struct global_resource_tag tag, int base); +/* + * @INTERNAL + * Shows the global resource range with the specified tag. Use mainly for debug. + */ +void cvmx_show_global_resource_range(struct global_resource_tag tag); + +/* + * @INTERNAL + * Shows all the global resources. Used mainly for debug. + */ +void cvmx_global_resources_show(void); + +u64 cvmx_allocate_app_id(void); +u64 cvmx_get_app_id(void); + +#endif diff --git a/arch/mips/mach-octeon/include/mach/cvmx-gmx.h b/arch/mips/mach-octeon/include/mach/cvmx-gmx.h new file mode 100644 index 000000000000..2df7da102a0f --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-gmx.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Interface to the GMX hardware. + */ + +#ifndef __CVMX_GMX_H__ +#define __CVMX_GMX_H__ + +/* CSR typedefs have been moved to cvmx-gmx-defs.h */ + +int cvmx_gmx_set_backpressure_override(u32 interface, u32 port_mask); +int cvmx_agl_set_backpressure_override(u32 interface, u32 port_mask); + +#endif diff --git a/arch/mips/mach-octeon/include/mach/cvmx-hwfau.h b/arch/mips/mach-octeon/include/mach/cvmx-hwfau.h new file mode 100644 index 000000000000..59772190aa3b --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-hwfau.h @@ -0,0 +1,606 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Interface to the hardware Fetch and Add Unit. + */ + +/** + * @file + * + * Interface to the hardware Fetch and Add Unit. + * + */ + +#ifndef __CVMX_HWFAU_H__ +#define __CVMX_HWFAU_H__ + +typedef int cvmx_fau_reg64_t; +typedef int cvmx_fau_reg32_t; +typedef int cvmx_fau_reg16_t; +typedef int cvmx_fau_reg8_t; + +#define CVMX_FAU_REG_ANY -1 + +/* + * Octeon Fetch and Add Unit (FAU) + */ + +#define CVMX_FAU_LOAD_IO_ADDRESS cvmx_build_io_address(0x1e, 0) +#define CVMX_FAU_BITS_SCRADDR 63, 56 +#define CVMX_FAU_BITS_LEN 55, 48 +#define CVMX_FAU_BITS_INEVAL 35, 14 +#define CVMX_FAU_BITS_TAGWAIT 13, 13 +#define CVMX_FAU_BITS_NOADD 13, 13 +#define CVMX_FAU_BITS_SIZE 12, 11 +#define CVMX_FAU_BITS_REGISTER 10, 0 + +#define CVMX_FAU_MAX_REGISTERS_8 (2048) + +typedef enum { + CVMX_FAU_OP_SIZE_8 = 0, + CVMX_FAU_OP_SIZE_16 = 1, + CVMX_FAU_OP_SIZE_32 = 2, + CVMX_FAU_OP_SIZE_64 = 3 +} cvmx_fau_op_size_t; + +/** + * Tagwait return definition. If a timeout occurs, the error + * bit will be set. Otherwise the value of the register before + * the update will be returned. + */ +typedef struct { + u64 error : 1; + s64 value : 63; +} cvmx_fau_tagwait64_t; + +/** + * Tagwait return definition. If a timeout occurs, the error + * bit will be set. Otherwise the value of the register before + * the update will be returned. + */ +typedef struct { + u64 error : 1; + s32 value : 31; +} cvmx_fau_tagwait32_t; + +/** + * Tagwait return definition. If a timeout occurs, the error + * bit will be set. Otherwise the value of the register before + * the update will be returned. + */ +typedef struct { + u64 error : 1; + s16 value : 15; +} cvmx_fau_tagwait16_t; + +/** + * Tagwait return definition. If a timeout occurs, the error + * bit will be set. Otherwise the value of the register before + * the update will be returned. + */ +typedef struct { + u64 error : 1; + int8_t value : 7; +} cvmx_fau_tagwait8_t; + +/** + * Asynchronous tagwait return definition. If a timeout occurs, + * the error bit will be set. Otherwise the value of the + * register before the update will be returned. + */ +typedef union { + u64 u64; + struct { + u64 invalid : 1; + u64 data : 63; /* unpredictable if invalid is set */ + } s; +} cvmx_fau_async_tagwait_result_t; + +#define SWIZZLE_8 0 +#define SWIZZLE_16 0 +#define SWIZZLE_32 0 + +/** + * @INTERNAL + * Builds a store I/O address for writing to the FAU + * + * @param noadd 0 = Store value is atomically added to the current value + * 1 = Store value is atomically written over the current value + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * - Step by 4 for 32 bit access. + * - Step by 8 for 64 bit access. + * @return Address to store for atomic update + */ +static inline u64 __cvmx_hwfau_store_address(u64 noadd, u64 reg) +{ + return (CVMX_ADD_IO_SEG(CVMX_FAU_LOAD_IO_ADDRESS) | + cvmx_build_bits(CVMX_FAU_BITS_NOADD, noadd) | + cvmx_build_bits(CVMX_FAU_BITS_REGISTER, reg)); +} + +/** + * @INTERNAL + * Builds a I/O address for accessing the FAU + * + * @param tagwait Should the atomic add wait for the current tag switch + * operation to complete. + * - 0 = Don't wait + * - 1 = Wait for tag switch to complete + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * - Step by 4 for 32 bit access. + * - Step by 8 for 64 bit access. + * @param value Signed value to add. + * Note: When performing 32 and 64 bit access, only the low + * 22 bits are available. + * @return Address to read from for atomic update + */ +static inline u64 __cvmx_hwfau_atomic_address(u64 tagwait, u64 reg, s64 value) +{ + return (CVMX_ADD_IO_SEG(CVMX_FAU_LOAD_IO_ADDRESS) | + cvmx_build_bits(CVMX_FAU_BITS_INEVAL, value) | + cvmx_build_bits(CVMX_FAU_BITS_TAGWAIT, tagwait) | + cvmx_build_bits(CVMX_FAU_BITS_REGISTER, reg)); +} + +/** + * Perform an atomic 64 bit add + * + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 8 for 64 bit access. + * @param value Signed value to add. + * Note: Only the low 22 bits are available. + * @return Value of the register before the update + */ +static inline s64 cvmx_hwfau_fetch_and_add64(cvmx_fau_reg64_t reg, s64 value) +{ + return cvmx_read64_int64(__cvmx_hwfau_atomic_address(0, reg, value)); +} + +/** + * Perform an atomic 32 bit add + * + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 4 for 32 bit access. + * @param value Signed value to add. + * Note: Only the low 22 bits are available. + * @return Value of the register before the update + */ +static inline s32 cvmx_hwfau_fetch_and_add32(cvmx_fau_reg32_t reg, s32 value) +{ + reg ^= SWIZZLE_32; + return cvmx_read64_int32(__cvmx_hwfau_atomic_address(0, reg, value)); +} + +/** + * Perform an atomic 16 bit add + * + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * @param value Signed value to add. + * @return Value of the register before the update + */ +static inline s16 cvmx_hwfau_fetch_and_add16(cvmx_fau_reg16_t reg, s16 value) +{ + reg ^= SWIZZLE_16; + return cvmx_read64_int16(__cvmx_hwfau_atomic_address(0, reg, value)); +} + +/** + * Perform an atomic 8 bit add + * + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * @param value Signed value to add. + * @return Value of the register before the update + */ +static inline int8_t cvmx_hwfau_fetch_and_add8(cvmx_fau_reg8_t reg, int8_t value) +{ + reg ^= SWIZZLE_8; + return cvmx_read64_int8(__cvmx_hwfau_atomic_address(0, reg, value)); +} + +/** + * Perform an atomic 64 bit add after the current tag switch + * completes + * + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 8 for 64 bit access. + * @param value Signed value to add. + * Note: Only the low 22 bits are available. + * @return If a timeout occurs, the error bit will be set. Otherwise + * the value of the register before the update will be + * returned + */ +static inline cvmx_fau_tagwait64_t cvmx_hwfau_tagwait_fetch_and_add64(cvmx_fau_reg64_t reg, + s64 value) +{ + union { + u64 i64; + cvmx_fau_tagwait64_t t; + } result; + result.i64 = cvmx_read64_int64(__cvmx_hwfau_atomic_address(1, reg, value)); + return result.t; +} + +/** + * Perform an atomic 32 bit add after the current tag switch + * completes + * + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 4 for 32 bit access. + * @param value Signed value to add. + * Note: Only the low 22 bits are available. + * @return If a timeout occurs, the error bit will be set. Otherwise + * the value of the register before the update will be + * returned + */ +static inline cvmx_fau_tagwait32_t cvmx_hwfau_tagwait_fetch_and_add32(cvmx_fau_reg32_t reg, + s32 value) +{ + union { + u64 i32; + cvmx_fau_tagwait32_t t; + } result; + reg ^= SWIZZLE_32; + result.i32 = cvmx_read64_int32(__cvmx_hwfau_atomic_address(1, reg, value)); + return result.t; +} + +/** + * Perform an atomic 16 bit add after the current tag switch + * completes + * + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * @param value Signed value to add. + * @return If a timeout occurs, the error bit will be set. Otherwise + * the value of the register before the update will be + * returned + */ +static inline cvmx_fau_tagwait16_t cvmx_hwfau_tagwait_fetch_and_add16(cvmx_fau_reg16_t reg, + s16 value) +{ + union { + u64 i16; + cvmx_fau_tagwait16_t t; + } result; + reg ^= SWIZZLE_16; + result.i16 = cvmx_read64_int16(__cvmx_hwfau_atomic_address(1, reg, value)); + return result.t; +} + +/** + * Perform an atomic 8 bit add after the current tag switch + * completes + * + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * @param value Signed value to add. + * @return If a timeout occurs, the error bit will be set. Otherwise + * the value of the register before the update will be + * returned + */ +static inline cvmx_fau_tagwait8_t cvmx_hwfau_tagwait_fetch_and_add8(cvmx_fau_reg8_t reg, + int8_t value) +{ + union { + u64 i8; + cvmx_fau_tagwait8_t t; + } result; + reg ^= SWIZZLE_8; + result.i8 = cvmx_read64_int8(__cvmx_hwfau_atomic_address(1, reg, value)); + return result.t; +} + +/** + * @INTERNAL + * Builds I/O data for async operations + * + * @param scraddr Scratch pad byte address to write to. Must be 8 byte aligned + * @param value Signed value to add. + * Note: When performing 32 and 64 bit access, only the low + * 22 bits are available. + * @param tagwait Should the atomic add wait for the current tag switch + * operation to complete. + * - 0 = Don't wait + * - 1 = Wait for tag switch to complete + * @param size The size of the operation: + * - CVMX_FAU_OP_SIZE_8 (0) = 8 bits + * - CVMX_FAU_OP_SIZE_16 (1) = 16 bits + * - CVMX_FAU_OP_SIZE_32 (2) = 32 bits + * - CVMX_FAU_OP_SIZE_64 (3) = 64 bits + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * - Step by 4 for 32 bit access. + * - Step by 8 for 64 bit access. + * @return Data to write using cvmx_send_single + */ +static inline u64 __cvmx_fau_iobdma_data(u64 scraddr, s64 value, u64 tagwait, + cvmx_fau_op_size_t size, u64 reg) +{ + return (CVMX_FAU_LOAD_IO_ADDRESS | cvmx_build_bits(CVMX_FAU_BITS_SCRADDR, scraddr >> 3) | + cvmx_build_bits(CVMX_FAU_BITS_LEN, 1) | + cvmx_build_bits(CVMX_FAU_BITS_INEVAL, value) | + cvmx_build_bits(CVMX_FAU_BITS_TAGWAIT, tagwait) | + cvmx_build_bits(CVMX_FAU_BITS_SIZE, size) | + cvmx_build_bits(CVMX_FAU_BITS_REGISTER, reg)); +} + +/** + * Perform an async atomic 64 bit add. The old value is + * placed in the scratch memory at byte address scraddr. + * + * @param scraddr Scratch memory byte address to put response in. + * Must be 8 byte aligned. + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 8 for 64 bit access. + * @param value Signed value to add. + * Note: Only the low 22 bits are available. + * @return Placed in the scratch pad register + */ +static inline void cvmx_hwfau_async_fetch_and_add64(u64 scraddr, cvmx_fau_reg64_t reg, s64 value) +{ + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 0, CVMX_FAU_OP_SIZE_64, reg)); +} + +/** + * Perform an async atomic 32 bit add. The old value is + * placed in the scratch memory at byte address scraddr. + * + * @param scraddr Scratch memory byte address to put response in. + * Must be 8 byte aligned. + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 4 for 32 bit access. + * @param value Signed value to add. + * Note: Only the low 22 bits are available. + * @return Placed in the scratch pad register + */ +static inline void cvmx_hwfau_async_fetch_and_add32(u64 scraddr, cvmx_fau_reg32_t reg, s32 value) +{ + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 0, CVMX_FAU_OP_SIZE_32, reg)); +} + +/** + * Perform an async atomic 16 bit add. The old value is + * placed in the scratch memory at byte address scraddr. + * + * @param scraddr Scratch memory byte address to put response in. + * Must be 8 byte aligned. + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * @param value Signed value to add. + * @return Placed in the scratch pad register + */ +static inline void cvmx_hwfau_async_fetch_and_add16(u64 scraddr, cvmx_fau_reg16_t reg, s16 value) +{ + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 0, CVMX_FAU_OP_SIZE_16, reg)); +} + +/** + * Perform an async atomic 8 bit add. The old value is + * placed in the scratch memory at byte address scraddr. + * + * @param scraddr Scratch memory byte address to put response in. + * Must be 8 byte aligned. + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * @param value Signed value to add. + * @return Placed in the scratch pad register + */ +static inline void cvmx_hwfau_async_fetch_and_add8(u64 scraddr, cvmx_fau_reg8_t reg, int8_t value) +{ + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 0, CVMX_FAU_OP_SIZE_8, reg)); +} + +/** + * Perform an async atomic 64 bit add after the current tag + * switch completes. + * + * @param scraddr Scratch memory byte address to put response in. + * Must be 8 byte aligned. + * If a timeout occurs, the error bit (63) will be set. Otherwise + * the value of the register before the update will be + * returned + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 8 for 64 bit access. + * @param value Signed value to add. + * Note: Only the low 22 bits are available. + * @return Placed in the scratch pad register + */ +static inline void cvmx_hwfau_async_tagwait_fetch_and_add64(u64 scraddr, cvmx_fau_reg64_t reg, + s64 value) +{ + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 1, CVMX_FAU_OP_SIZE_64, reg)); +} + +/** + * Perform an async atomic 32 bit add after the current tag + * switch completes. + * + * @param scraddr Scratch memory byte address to put response in. + * Must be 8 byte aligned. + * If a timeout occurs, the error bit (63) will be set. Otherwise + * the value of the register before the update will be + * returned + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 4 for 32 bit access. + * @param value Signed value to add. + * Note: Only the low 22 bits are available. + * @return Placed in the scratch pad register + */ +static inline void cvmx_hwfau_async_tagwait_fetch_and_add32(u64 scraddr, cvmx_fau_reg32_t reg, + s32 value) +{ + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 1, CVMX_FAU_OP_SIZE_32, reg)); +} + +/** + * Perform an async atomic 16 bit add after the current tag + * switch completes. + * + * @param scraddr Scratch memory byte address to put response in. + * Must be 8 byte aligned. + * If a timeout occurs, the error bit (63) will be set. Otherwise + * the value of the register before the update will be + * returned + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * @param value Signed value to add. + * @return Placed in the scratch pad register + */ +static inline void cvmx_hwfau_async_tagwait_fetch_and_add16(u64 scraddr, cvmx_fau_reg16_t reg, + s16 value) +{ + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 1, CVMX_FAU_OP_SIZE_16, reg)); +} + +/** + * Perform an async atomic 8 bit add after the current tag + * switch completes. + * + * @param scraddr Scratch memory byte address to put response in. + * Must be 8 byte aligned. + * If a timeout occurs, the error bit (63) will be set. Otherwise + * the value of the register before the update will be + * returned + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * @param value Signed value to add. + * @return Placed in the scratch pad register + */ +static inline void cvmx_hwfau_async_tagwait_fetch_and_add8(u64 scraddr, cvmx_fau_reg8_t reg, + int8_t value) +{ + cvmx_send_single(__cvmx_fau_iobdma_data(scraddr, value, 1, CVMX_FAU_OP_SIZE_8, reg)); +} + +/** + * Perform an atomic 64 bit add + * + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 8 for 64 bit access. + * @param value Signed value to add. + */ +static inline void cvmx_hwfau_atomic_add64(cvmx_fau_reg64_t reg, s64 value) +{ + cvmx_write64_int64(__cvmx_hwfau_store_address(0, reg), value); +} + +/** + * Perform an atomic 32 bit add + * + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 4 for 32 bit access. + * @param value Signed value to add. + */ +static inline void cvmx_hwfau_atomic_add32(cvmx_fau_reg32_t reg, s32 value) +{ + reg ^= SWIZZLE_32; + cvmx_write64_int32(__cvmx_hwfau_store_address(0, reg), value); +} + +/** + * Perform an atomic 16 bit add + * + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * @param value Signed value to add. + */ +static inline void cvmx_hwfau_atomic_add16(cvmx_fau_reg16_t reg, s16 value) +{ + reg ^= SWIZZLE_16; + cvmx_write64_int16(__cvmx_hwfau_store_address(0, reg), value); +} + +/** + * Perform an atomic 8 bit add + * + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * @param value Signed value to add. + */ +static inline void cvmx_hwfau_atomic_add8(cvmx_fau_reg8_t reg, int8_t value) +{ + reg ^= SWIZZLE_8; + cvmx_write64_int8(__cvmx_hwfau_store_address(0, reg), value); +} + +/** + * Perform an atomic 64 bit write + * + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 8 for 64 bit access. + * @param value Signed value to write. + */ +static inline void cvmx_hwfau_atomic_write64(cvmx_fau_reg64_t reg, s64 value) +{ + cvmx_write64_int64(__cvmx_hwfau_store_address(1, reg), value); +} + +/** + * Perform an atomic 32 bit write + * + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 4 for 32 bit access. + * @param value Signed value to write. + */ +static inline void cvmx_hwfau_atomic_write32(cvmx_fau_reg32_t reg, s32 value) +{ + reg ^= SWIZZLE_32; + cvmx_write64_int32(__cvmx_hwfau_store_address(1, reg), value); +} + +/** + * Perform an atomic 16 bit write + * + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * @param value Signed value to write. + */ +static inline void cvmx_hwfau_atomic_write16(cvmx_fau_reg16_t reg, s16 value) +{ + reg ^= SWIZZLE_16; + cvmx_write64_int16(__cvmx_hwfau_store_address(1, reg), value); +} + +/** + * Perform an atomic 8 bit write + * + * @param reg FAU atomic register to access. 0 <= reg < 2048. + * @param value Signed value to write. + */ +static inline void cvmx_hwfau_atomic_write8(cvmx_fau_reg8_t reg, int8_t value) +{ + reg ^= SWIZZLE_8; + cvmx_write64_int8(__cvmx_hwfau_store_address(1, reg), value); +} + +/** Allocates 64bit FAU register. + * @return value is the base address of allocated FAU register + */ +int cvmx_fau64_alloc(int reserve); + +/** Allocates 32bit FAU register. + * @return value is the base address of allocated FAU register + */ +int cvmx_fau32_alloc(int reserve); + +/** Allocates 16bit FAU register. + * @return value is the base address of allocated FAU register + */ +int cvmx_fau16_alloc(int reserve); + +/** Allocates 8bit FAU register. + * @return value is the base address of allocated FAU register + */ +int cvmx_fau8_alloc(int reserve); + +/** Frees the specified FAU register. + * @param address Base address of register to release. + * @return 0 on success; -1 on failure + */ +int cvmx_fau_free(int address); + +/** Display the fau registers array + */ +void cvmx_fau_show(void); + +#endif /* __CVMX_HWFAU_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-hwpko.h b/arch/mips/mach-octeon/include/mach/cvmx-hwpko.h new file mode 100644 index 000000000000..459c19bbc0f1 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-hwpko.h @@ -0,0 +1,570 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Interface to the hardware Packet Output unit. + * + * Starting with SDK 1.7.0, the PKO output functions now support + * two types of locking. CVMX_PKO_LOCK_ATOMIC_TAG continues to + * function similarly to previous SDKs by using POW atomic tags + * to preserve ordering and exclusivity. As a new option, you + * can now pass CVMX_PKO_LOCK_CMD_QUEUE which uses a ll/sc + * memory based locking instead. This locking has the advantage + * of not affecting the tag state but doesn't preserve packet + * ordering. CVMX_PKO_LOCK_CMD_QUEUE is appropriate in most + * generic code while CVMX_PKO_LOCK_CMD_QUEUE should be used + * with hand tuned fast path code. + * + * Some of other SDK differences visible to the command command + * queuing: + * - PKO indexes are no longer stored in the FAU. A large + * percentage of the FAU register block used to be tied up + * maintaining PKO queue pointers. These are now stored in a + * global named block. + * - The PKO <b>use_locking</b> parameter can now have a global + * effect. Since all application use the same named block, + * queue locking correctly applies across all operating + * systems when using CVMX_PKO_LOCK_CMD_QUEUE. + * - PKO 3 word commands are now supported. Use + * cvmx_pko_send_packet_finish3(). + */ + +#ifndef __CVMX_HWPKO_H__ +#define __CVMX_HWPKO_H__ + +#include "cvmx-hwfau.h" +#include "cvmx-fpa.h" +#include "cvmx-pow.h" +#include "cvmx-cmd-queue.h" +#include "cvmx-helper.h" +#include "cvmx-helper-util.h" +#include "cvmx-helper-cfg.h" + +/* Adjust the command buffer size by 1 word so that in the case of using only +** two word PKO commands no command words stradle buffers. The useful values +** for this are 0 and 1. */ +#define CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST (1) + +#define CVMX_PKO_MAX_OUTPUT_QUEUES_STATIC 256 +#define CVMX_PKO_MAX_OUTPUT_QUEUES \ + ((OCTEON_IS_OCTEON2() || OCTEON_IS_MODEL(OCTEON_CN70XX)) ? 256 : 128) +#define CVMX_PKO_NUM_OUTPUT_PORTS \ + ((OCTEON_IS_MODEL(OCTEON_CN63XX)) ? 44 : (OCTEON_IS_MODEL(OCTEON_CN66XX) ? 48 : 40)) +#define CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID 63 +#define CVMX_PKO_QUEUE_STATIC_PRIORITY 9 +#define CVMX_PKO_ILLEGAL_QUEUE 0xFFFF +#define CVMX_PKO_MAX_QUEUE_DEPTH 0 + +typedef enum { + CVMX_PKO_SUCCESS, + CVMX_PKO_INVALID_PORT, + CVMX_PKO_INVALID_QUEUE, + CVMX_PKO_INVALID_PRIORITY, + CVMX_PKO_NO_MEMORY, + CVMX_PKO_PORT_ALREADY_SETUP, + CVMX_PKO_CMD_QUEUE_INIT_ERROR +} cvmx_pko_return_value_t; + +/** + * This enumeration represents the differnet locking modes supported by PKO. + */ +typedef enum { + CVMX_PKO_LOCK_NONE = 0, + CVMX_PKO_LOCK_ATOMIC_TAG = 1, + CVMX_PKO_LOCK_CMD_QUEUE = 2, +} cvmx_pko_lock_t; + +typedef struct cvmx_pko_port_status { + u32 packets; + u64 octets; + u64 doorbell; +} cvmx_pko_port_status_t; + +/** + * This structure defines the address to use on a packet enqueue + */ +typedef union { + u64 u64; + struct { + cvmx_mips_space_t mem_space : 2; + u64 reserved : 13; + u64 is_io : 1; + u64 did : 8; + u64 reserved2 : 4; + u64 reserved3 : 15; + u64 port : 9; + u64 queue : 9; + u64 reserved4 : 3; + } s; +} cvmx_pko_doorbell_address_t; + +/** + * Structure of the first packet output command word. + */ +typedef union { + u64 u64; + struct { + cvmx_fau_op_size_t size1 : 2; + cvmx_fau_op_size_t size0 : 2; + u64 subone1 : 1; + u64 reg1 : 11; + u64 subone0 : 1; + u64 reg0 : 11; + u64 le : 1; + u64 n2 : 1; + u64 wqp : 1; + u64 rsp : 1; + u64 gather : 1; + u64 ipoffp1 : 7; + u64 ignore_i : 1; + u64 dontfree : 1; + u64 segs : 6; + u64 total_bytes : 16; + } s; +} cvmx_pko_command_word0_t; + +/** + * Call before any other calls to initialize the packet + * output system. + */ + +void cvmx_pko_hw_init(u8 pool, unsigned int bufsize); + +/** + * Enables the packet output hardware. It must already be + * configured. + */ +void cvmx_pko_enable(void); + +/** + * Disables the packet output. Does not affect any configuration. + */ +void cvmx_pko_disable(void); + +/** + * Shutdown and free resources required by packet output. + */ + +void cvmx_pko_shutdown(void); + +/** + * Configure a output port and the associated queues for use. + * + * @param port Port to configure. + * @param base_queue First queue number to associate with this port. + * @param num_queues Number of queues t oassociate with this port + * @param priority Array of priority levels for each queue. Values are + * allowed to be 1-8. A value of 8 get 8 times the traffic + * of a value of 1. There must be num_queues elements in the + * array. + */ +cvmx_pko_return_value_t cvmx_pko_config_port(int port, int base_queue, int num_queues, + const u8 priority[]); + +/** + * Ring the packet output doorbell. This tells the packet + * output hardware that "len" command words have been added + * to its pending list. This command includes the required + * CVMX_SYNCWS before the doorbell ring. + * + * WARNING: This function may have to look up the proper PKO port in + * the IPD port to PKO port map, and is thus slower than calling + * cvmx_pko_doorbell_pkoid() directly if the PKO port identifier is + * known. + * + * @param ipd_port The IPD port corresponding the to pko port the packet is for + * @param queue Queue the packet is for + * @param len Length of the command in 64 bit words + */ +static inline void cvmx_pko_doorbell(u64 ipd_port, u64 queue, u64 len) +{ + cvmx_pko_doorbell_address_t ptr; + u64 pko_port; + + pko_port = ipd_port; + if (octeon_has_feature(OCTEON_FEATURE_PKND)) + pko_port = cvmx_helper_cfg_ipd2pko_port_base(ipd_port); + + ptr.u64 = 0; + ptr.s.mem_space = CVMX_IO_SEG; + ptr.s.did = CVMX_OCT_DID_PKT_SEND; + ptr.s.is_io = 1; + ptr.s.port = pko_port; + ptr.s.queue = queue; + /* Need to make sure output queue data is in DRAM before doorbell write */ + CVMX_SYNCWS; + cvmx_write_io(ptr.u64, len); +} + +/** + * Prepare to send a packet. This may initiate a tag switch to + * get exclusive access to the output queue structure, and + * performs other prep work for the packet send operation. + * + * cvmx_pko_send_packet_finish() MUST be called after this function is called, + * and must be called with the same port/queue/use_locking arguments. + * + * The use_locking parameter allows the caller to use three + * possible locking modes. + * - CVMX_PKO_LOCK_NONE + * - PKO doesn't do any locking. It is the responsibility + * of the application to make sure that no other core + * is accessing the same queue at the same time. + * - CVMX_PKO_LOCK_ATOMIC_TAG + * - PKO performs an atomic tagswitch to insure exclusive + * access to the output queue. This will maintain + * packet ordering on output. + * - CVMX_PKO_LOCK_CMD_QUEUE + * - PKO uses the common command queue locks to insure + * exclusive access to the output queue. This is a + * memory based ll/sc. This is the most portable + * locking mechanism. + * + * NOTE: If atomic locking is used, the POW entry CANNOT be + * descheduled, as it does not contain a valid WQE pointer. + * + * @param port Port to send it on, this can be either IPD port or PKO + * port. + * @param queue Queue to use + * @param use_locking + * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or CVMX_PKO_LOCK_CMD_QUEUE + */ +static inline void cvmx_pko_send_packet_prepare(u64 port __attribute__((unused)), u64 queue, + cvmx_pko_lock_t use_locking) +{ + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) { + /* + * Must do a full switch here to handle all cases. We use a + * fake WQE pointer, as the POW does not access this memory. + * The WQE pointer and group are only used if this work is + * descheduled, which is not supported by the + * cvmx_pko_send_packet_prepare/cvmx_pko_send_packet_finish + * combination. Note that this is a special case in which these + * fake values can be used - this is not a general technique. + */ + u32 tag = CVMX_TAG_SW_BITS_INTERNAL << CVMX_TAG_SW_SHIFT | + CVMX_TAG_SUBGROUP_PKO << CVMX_TAG_SUBGROUP_SHIFT | + (CVMX_TAG_SUBGROUP_MASK & queue); + cvmx_pow_tag_sw_full((cvmx_wqe_t *)cvmx_phys_to_ptr(0x80), tag, + CVMX_POW_TAG_TYPE_ATOMIC, 0); + } +} + +#define cvmx_pko_send_packet_prepare_pkoid cvmx_pko_send_packet_prepare + +/** + * Complete packet output. cvmx_pko_send_packet_prepare() must be called exactly once before this, + * and the same parameters must be passed to both cvmx_pko_send_packet_prepare() and + * cvmx_pko_send_packet_finish(). + * + * WARNING: This function may have to look up the proper PKO port in + * the IPD port to PKO port map, and is thus slower than calling + * cvmx_pko_send_packet_finish_pkoid() directly if the PKO port + * identifier is known. + * + * @param ipd_port The IPD port corresponding the to pko port the packet is for + * @param queue Queue to use + * @param pko_command + * PKO HW command word + * @param packet Packet to send + * @param use_locking + * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or CVMX_PKO_LOCK_CMD_QUEUE + * + * @return returns CVMX_PKO_SUCCESS on success, or error code on failure of output + */ +static inline cvmx_pko_return_value_t +cvmx_hwpko_send_packet_finish(u64 ipd_port, u64 queue, cvmx_pko_command_word0_t pko_command, + cvmx_buf_ptr_t packet, cvmx_pko_lock_t use_locking) +{ + cvmx_cmd_queue_result_t result; + + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) + cvmx_pow_tag_sw_wait(); + + result = cvmx_cmd_queue_write2(CVMX_CMD_QUEUE_PKO(queue), + (use_locking == CVMX_PKO_LOCK_CMD_QUEUE), pko_command.u64, + packet.u64); + if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS)) { + cvmx_pko_doorbell(ipd_port, queue, 2); + return CVMX_PKO_SUCCESS; + } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == CVMX_CMD_QUEUE_FULL)) { + return CVMX_PKO_NO_MEMORY; + } else { + return CVMX_PKO_INVALID_QUEUE; + } +} + +/** + * Complete packet output. cvmx_pko_send_packet_prepare() must be called exactly once before this, + * and the same parameters must be passed to both cvmx_pko_send_packet_prepare() and + * cvmx_pko_send_packet_finish(). + * + * WARNING: This function may have to look up the proper PKO port in + * the IPD port to PKO port map, and is thus slower than calling + * cvmx_pko_send_packet_finish3_pkoid() directly if the PKO port + * identifier is known. + * + * @param ipd_port The IPD port corresponding the to pko port the packet is for + * @param queue Queue to use + * @param pko_command + * PKO HW command word + * @param packet Packet to send + * @param addr Plysical address of a work queue entry or physical address to zero on complete. + * @param use_locking + * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or CVMX_PKO_LOCK_CMD_QUEUE + * + * @return returns CVMX_PKO_SUCCESS on success, or error code on failure of output + */ +static inline cvmx_pko_return_value_t +cvmx_hwpko_send_packet_finish3(u64 ipd_port, u64 queue, cvmx_pko_command_word0_t pko_command, + cvmx_buf_ptr_t packet, u64 addr, cvmx_pko_lock_t use_locking) +{ + cvmx_cmd_queue_result_t result; + + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) + cvmx_pow_tag_sw_wait(); + + result = cvmx_cmd_queue_write3(CVMX_CMD_QUEUE_PKO(queue), + (use_locking == CVMX_PKO_LOCK_CMD_QUEUE), pko_command.u64, + packet.u64, addr); + if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS)) { + cvmx_pko_doorbell(ipd_port, queue, 3); + return CVMX_PKO_SUCCESS; + } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == CVMX_CMD_QUEUE_FULL)) { + return CVMX_PKO_NO_MEMORY; + } else { + return CVMX_PKO_INVALID_QUEUE; + } +} + +/** + * Get the first pko_port for the (interface, index) + * + * @param interface + * @param index + */ +int cvmx_pko_get_base_pko_port(int interface, int index); + +/** + * Get the number of pko_ports for the (interface, index) + * + * @param interface + * @param index + */ +int cvmx_pko_get_num_pko_ports(int interface, int index); + +/** + * For a given port number, return the base pko output queue + * for the port. + * + * @param port IPD port number + * @return Base output queue + */ +int cvmx_pko_get_base_queue(int port); + +/** + * For a given port number, return the number of pko output queues. + * + * @param port IPD port number + * @return Number of output queues + */ +int cvmx_pko_get_num_queues(int port); + +/** + * Sets the internal FPA pool data structure for PKO comamnd queue. + * @param pool fpa pool number yo use + * @param buffer_size buffer size of pool + * @param buffer_count number of buufers to allocate to pool + * + * @note the caller is responsable for setting up the pool with + * an appropriate buffer size and sufficient buffer count. + */ +void cvmx_pko_set_cmd_que_pool_config(s64 pool, u64 buffer_size, u64 buffer_count); + +/** + * Get the status counters for a port. + * + * @param ipd_port Port number (ipd_port) to get statistics for. + * @param clear Set to 1 to clear the counters after they are read + * @param status Where to put the results. + * + * Note: + * - Only the doorbell for the base queue of the ipd_port is + * collected. + * - Retrieving the stats involves writing the index through + * CVMX_PKO_REG_READ_IDX and reading the stat CSRs, in that + * order. It is not MP-safe and caller should guarantee + * atomicity. + */ +void cvmx_pko_get_port_status(u64 ipd_port, u64 clear, cvmx_pko_port_status_t *status); + +/** + * Rate limit a PKO port to a max packets/sec. This function is only + * supported on CN57XX, CN56XX, CN55XX, and CN54XX. + * + * @param port Port to rate limit + * @param packets_s Maximum packet/sec + * @param burst Maximum number of packets to burst in a row before rate + * limiting cuts in. + * + * @return Zero on success, negative on failure + */ +int cvmx_pko_rate_limit_packets(int port, int packets_s, int burst); + +/** + * Rate limit a PKO port to a max bits/sec. This function is only + * supported on CN57XX, CN56XX, CN55XX, and CN54XX. + * + * @param port Port to rate limit + * @param bits_s PKO rate limit in bits/sec + * @param burst Maximum number of bits to burst before rate + * limiting cuts in. + * + * @return Zero on success, negative on failure + */ +int cvmx_pko_rate_limit_bits(int port, u64 bits_s, int burst); + +/** + * @INTERNAL + * + * Retrieve the PKO pipe number for a port + * + * @param interface + * @param index + * + * @return negative on error. + * + * This applies only to the non-loopback interfaces. + * + */ +int __cvmx_pko_get_pipe(int interface, int index); + +/** + * For a given PKO port number, return the base output queue + * for the port. + * + * @param pko_port PKO port number + * @return Base output queue + */ +int cvmx_pko_get_base_queue_pkoid(int pko_port); + +/** + * For a given PKO port number, return the number of output queues + * for the port. + * + * @param pko_port PKO port number + * @return the number of output queues + */ +int cvmx_pko_get_num_queues_pkoid(int pko_port); + +/** + * Ring the packet output doorbell. This tells the packet + * output hardware that "len" command words have been added + * to its pending list. This command includes the required + * CVMX_SYNCWS before the doorbell ring. + * + * @param pko_port Port the packet is for + * @param queue Queue the packet is for + * @param len Length of the command in 64 bit words + */ +static inline void cvmx_pko_doorbell_pkoid(u64 pko_port, u64 queue, u64 len) +{ + cvmx_pko_doorbell_address_t ptr; + + ptr.u64 = 0; + ptr.s.mem_space = CVMX_IO_SEG; + ptr.s.did = CVMX_OCT_DID_PKT_SEND; + ptr.s.is_io = 1; + ptr.s.port = pko_port; + ptr.s.queue = queue; + /* Need to make sure output queue data is in DRAM before doorbell write */ + CVMX_SYNCWS; + cvmx_write_io(ptr.u64, len); +} + +/** + * Complete packet output. cvmx_pko_send_packet_prepare() must be called exactly once before this, + * and the same parameters must be passed to both cvmx_pko_send_packet_prepare() and + * cvmx_pko_send_packet_finish_pkoid(). + * + * @param pko_port Port to send it on + * @param queue Queue to use + * @param pko_command + * PKO HW command word + * @param packet Packet to send + * @param use_locking + * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or CVMX_PKO_LOCK_CMD_QUEUE + * + * @return returns CVMX_PKO_SUCCESS on success, or error code on failure of output + */ +static inline cvmx_pko_return_value_t +cvmx_hwpko_send_packet_finish_pkoid(int pko_port, u64 queue, cvmx_pko_command_word0_t pko_command, + cvmx_buf_ptr_t packet, cvmx_pko_lock_t use_locking) +{ + cvmx_cmd_queue_result_t result; + + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) + cvmx_pow_tag_sw_wait(); + + result = cvmx_cmd_queue_write2(CVMX_CMD_QUEUE_PKO(queue), + (use_locking == CVMX_PKO_LOCK_CMD_QUEUE), pko_command.u64, + packet.u64); + if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS)) { + cvmx_pko_doorbell_pkoid(pko_port, queue, 2); + return CVMX_PKO_SUCCESS; + } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == CVMX_CMD_QUEUE_FULL)) { + return CVMX_PKO_NO_MEMORY; + } else { + return CVMX_PKO_INVALID_QUEUE; + } +} + +/** + * Complete packet output. cvmx_pko_send_packet_prepare() must be called exactly once before this, + * and the same parameters must be passed to both cvmx_pko_send_packet_prepare() and + * cvmx_pko_send_packet_finish_pkoid(). + * + * @param pko_port The PKO port the packet is for + * @param queue Queue to use + * @param pko_command + * PKO HW command word + * @param packet Packet to send + * @param addr Plysical address of a work queue entry or physical address to zero on complete. + * @param use_locking + * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or CVMX_PKO_LOCK_CMD_QUEUE + * + * @return returns CVMX_PKO_SUCCESS on success, or error code on failure of output + */ +static inline cvmx_pko_return_value_t +cvmx_hwpko_send_packet_finish3_pkoid(u64 pko_port, u64 queue, cvmx_pko_command_word0_t pko_command, + cvmx_buf_ptr_t packet, u64 addr, cvmx_pko_lock_t use_locking) +{ + cvmx_cmd_queue_result_t result; + + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) + cvmx_pow_tag_sw_wait(); + + result = cvmx_cmd_queue_write3(CVMX_CMD_QUEUE_PKO(queue), + (use_locking == CVMX_PKO_LOCK_CMD_QUEUE), pko_command.u64, + packet.u64, addr); + if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS)) { + cvmx_pko_doorbell_pkoid(pko_port, queue, 3); + return CVMX_PKO_SUCCESS; + } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == CVMX_CMD_QUEUE_FULL)) { + return CVMX_PKO_NO_MEMORY; + } else { + return CVMX_PKO_INVALID_QUEUE; + } +} + +/* + * Obtain the number of PKO commands pending in a queue + * + * @param queue is the queue identifier to be queried + * @return the number of commands pending transmission or -1 on error + */ +int cvmx_pko_queue_pend_count(cvmx_cmd_queue_id_t queue); + +void cvmx_pko_set_cmd_queue_pool_buffer_count(u64 buffer_count); + +#endif /* __CVMX_HWPKO_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-ilk.h b/arch/mips/mach-octeon/include/mach/cvmx-ilk.h new file mode 100644 index 000000000000..727298352c28 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-ilk.h @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * This file contains defines for the ILK interface + */ + +#ifndef __CVMX_ILK_H__ +#define __CVMX_ILK_H__ + +/* CSR typedefs have been moved to cvmx-ilk-defs.h */ + +/* + * Note: this macro must match the first ilk port in the ipd_port_map_68xx[] + * and ipd_port_map_78xx[] arrays. + */ +static inline int CVMX_ILK_GBL_BASE(void) +{ + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + return 5; + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) + return 6; + return -1; +} + +static inline int CVMX_ILK_QLM_BASE(void) +{ + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + return 1; + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) + return 4; + return -1; +} + +typedef struct { + int intf_en : 1; + int la_mode : 1; + int reserved : 14; /* unused */ + int lane_speed : 16; + /* add more here */ +} cvmx_ilk_intf_t; + +#define CVMX_NUM_ILK_INTF 2 +static inline int CVMX_ILK_MAX_LANES(void) +{ + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + return 8; + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) + return 16; + return -1; +} + +extern unsigned short cvmx_ilk_lane_mask[CVMX_MAX_NODES][CVMX_NUM_ILK_INTF]; + +typedef struct { + unsigned int pipe; + unsigned int chan; +} cvmx_ilk_pipe_chan_t; + +#define CVMX_ILK_MAX_PIPES 45 +/* Max number of channels allowed */ +#define CVMX_ILK_MAX_CHANS 256 + +extern int cvmx_ilk_chans[CVMX_MAX_NODES][CVMX_NUM_ILK_INTF]; + +typedef struct { + unsigned int chan; + unsigned int pknd; +} cvmx_ilk_chan_pknd_t; + +#define CVMX_ILK_MAX_PKNDS 16 /* must be <45 */ + +typedef struct { + int *chan_list; /* for discrete channels. or, must be null */ + unsigned int num_chans; + + unsigned int chan_start; /* for continuous channels */ + unsigned int chan_end; + unsigned int chan_step; + + unsigned int clr_on_rd; +} cvmx_ilk_stats_ctrl_t; + +#define CVMX_ILK_MAX_CAL 288 +#define CVMX_ILK_MAX_CAL_IDX (CVMX_ILK_MAX_CAL / 8) +#define CVMX_ILK_TX_MIN_CAL 1 +#define CVMX_ILK_RX_MIN_CAL 1 +#define CVMX_ILK_CAL_GRP_SZ 8 +#define CVMX_ILK_PIPE_BPID_SZ 7 +#define CVMX_ILK_ENT_CTRL_SZ 2 +#define CVMX_ILK_RX_FIFO_WM 0x200 + +typedef enum { PIPE_BPID = 0, LINK, XOFF, XON } cvmx_ilk_cal_ent_ctrl_t; + +typedef struct { + unsigned char pipe_bpid; + cvmx_ilk_cal_ent_ctrl_t ent_ctrl; +} cvmx_ilk_cal_entry_t; + +typedef enum { CVMX_ILK_LPBK_DISA = 0, CVMX_ILK_LPBK_ENA } cvmx_ilk_lpbk_ena_t; + +typedef enum { CVMX_ILK_LPBK_INT = 0, CVMX_ILK_LPBK_EXT } cvmx_ilk_lpbk_mode_t; + +/** + * This header is placed in front of all received ILK look-aside mode packets + */ +typedef union { + u64 u64; + + struct { + u32 reserved_63_57 : 7; /* bits 63...57 */ + u32 nsp_cmd : 5; /* bits 56...52 */ + u32 nsp_flags : 4; /* bits 51...48 */ + u32 nsp_grp_id_upper : 6; /* bits 47...42 */ + u32 reserved_41_40 : 2; /* bits 41...40 */ + /* Protocol type, 1 for LA mode packet */ + u32 la_mode : 1; /* bit 39 */ + u32 nsp_grp_id_lower : 2; /* bits 38...37 */ + u32 nsp_xid_upper : 4; /* bits 36...33 */ + /* ILK channel number, 0 or 1 */ + u32 ilk_channel : 1; /* bit 32 */ + u32 nsp_xid_lower : 8; /* bits 31...24 */ + /* Unpredictable, may be any value */ + u32 reserved_23_0 : 24; /* bits 23...0 */ + } s; +} cvmx_ilk_la_nsp_compact_hdr_t; + +typedef struct cvmx_ilk_LA_mode_struct { + int ilk_LA_mode; + int ilk_LA_mode_cal_ena; +} cvmx_ilk_LA_mode_t; + +extern cvmx_ilk_LA_mode_t cvmx_ilk_LA_mode[CVMX_NUM_ILK_INTF]; + +int cvmx_ilk_use_la_mode(int interface, int channel); +int cvmx_ilk_start_interface(int interface, unsigned short num_lanes); +int cvmx_ilk_start_interface_la(int interface, unsigned char num_lanes); +int cvmx_ilk_set_pipe(int interface, int pipe_base, unsigned int pipe_len); +int cvmx_ilk_tx_set_channel(int interface, cvmx_ilk_pipe_chan_t *pch, unsigned int num_chs); +int cvmx_ilk_rx_set_pknd(int interface, cvmx_ilk_chan_pknd_t *chpknd, unsigned int num_pknd); +int cvmx_ilk_enable(int interface); +int cvmx_ilk_disable(int interface); +int cvmx_ilk_get_intf_ena(int interface); +int cvmx_ilk_get_chan_info(int interface, unsigned char **chans, unsigned char *num_chan); +cvmx_ilk_la_nsp_compact_hdr_t cvmx_ilk_enable_la_header(int ipd_port, int mode); +void cvmx_ilk_show_stats(int interface, cvmx_ilk_stats_ctrl_t *pstats); +int cvmx_ilk_cal_setup_rx(int interface, int cal_depth, cvmx_ilk_cal_entry_t *pent, int hi_wm, + unsigned char cal_ena); +int cvmx_ilk_cal_setup_tx(int interface, int cal_depth, cvmx_ilk_cal_entry_t *pent, + unsigned char cal_ena); +int cvmx_ilk_lpbk(int interface, cvmx_ilk_lpbk_ena_t enable, cvmx_ilk_lpbk_mode_t mode); +int cvmx_ilk_la_mode_enable_rx_calendar(int interface); + +#endif /* __CVMX_ILK_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-ipd.h b/arch/mips/mach-octeon/include/mach/cvmx-ipd.h new file mode 100644 index 000000000000..cdff36fffb56 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-ipd.h @@ -0,0 +1,233 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Interface to the hardware Input Packet Data unit. + */ + +#ifndef __CVMX_IPD_H__ +#define __CVMX_IPD_H__ + +#include "cvmx-pki.h" + +/* CSR typedefs have been moved to cvmx-ipd-defs.h */ + +typedef cvmx_ipd_1st_mbuff_skip_t cvmx_ipd_mbuff_not_first_skip_t; +typedef cvmx_ipd_1st_next_ptr_back_t cvmx_ipd_second_next_ptr_back_t; + +typedef struct cvmx_ipd_tag_fields { + u64 ipv6_src_ip : 1; + u64 ipv6_dst_ip : 1; + u64 ipv6_src_port : 1; + u64 ipv6_dst_port : 1; + u64 ipv6_next_header : 1; + u64 ipv4_src_ip : 1; + u64 ipv4_dst_ip : 1; + u64 ipv4_src_port : 1; + u64 ipv4_dst_port : 1; + u64 ipv4_protocol : 1; + u64 input_port : 1; +} cvmx_ipd_tag_fields_t; + +typedef struct cvmx_pip_port_config { + u64 parse_mode; + u64 tag_type; + u64 tag_mode; + cvmx_ipd_tag_fields_t tag_fields; +} cvmx_pip_port_config_t; + +typedef struct cvmx_ipd_config_struct { + u64 first_mbuf_skip; + u64 not_first_mbuf_skip; + u64 ipd_enable; + u64 enable_len_M8_fix; + u64 cache_mode; + cvmx_fpa_pool_config_t packet_pool; + cvmx_fpa_pool_config_t wqe_pool; + cvmx_pip_port_config_t port_config; +} cvmx_ipd_config_t; + +extern cvmx_ipd_config_t cvmx_ipd_cfg; + +/** + * Gets the fpa pool number of packet pool + */ +static inline s64 cvmx_fpa_get_packet_pool(void) +{ + return (cvmx_ipd_cfg.packet_pool.pool_num); +} + +/** + * Gets the buffer size of packet pool buffer + */ +static inline u64 cvmx_fpa_get_packet_pool_block_size(void) +{ + return (cvmx_ipd_cfg.packet_pool.buffer_size); +} + +/** + * Gets the buffer count of packet pool + */ +static inline u64 cvmx_fpa_get_packet_pool_buffer_count(void) +{ + return (cvmx_ipd_cfg.packet_pool.buffer_count); +} + +/** + * Gets the fpa pool number of wqe pool + */ +static inline s64 cvmx_fpa_get_wqe_pool(void) +{ + return (cvmx_ipd_cfg.wqe_pool.pool_num); +} + +/** + * Gets the buffer size of wqe pool buffer + */ +static inline u64 cvmx_fpa_get_wqe_pool_block_size(void) +{ + return (cvmx_ipd_cfg.wqe_pool.buffer_size); +} + +/** + * Gets the buffer count of wqe pool + */ +static inline u64 cvmx_fpa_get_wqe_pool_buffer_count(void) +{ + return (cvmx_ipd_cfg.wqe_pool.buffer_count); +} + +/** + * Sets the ipd related configuration in internal structure which is then used + * for seting IPD hardware block + */ +int cvmx_ipd_set_config(cvmx_ipd_config_t ipd_config); + +/** + * Gets the ipd related configuration from internal structure. + */ +void cvmx_ipd_get_config(cvmx_ipd_config_t *ipd_config); + +/** + * Sets the internal FPA pool data structure for packet buffer pool. + * @param pool fpa pool number yo use + * @param buffer_size buffer size of pool + * @param buffer_count number of buufers to allocate to pool + */ +void cvmx_ipd_set_packet_pool_config(s64 pool, u64 buffer_size, u64 buffer_count); + +/** + * Sets the internal FPA pool data structure for wqe pool. + * @param pool fpa pool number yo use + * @param buffer_size buffer size of pool + * @param buffer_count number of buufers to allocate to pool + */ +void cvmx_ipd_set_wqe_pool_config(s64 pool, u64 buffer_size, u64 buffer_count); + +/** + * Gets the FPA packet buffer pool parameters. + */ +static inline void cvmx_fpa_get_packet_pool_config(s64 *pool, u64 *buffer_size, u64 *buffer_count) +{ + if (pool) + *pool = cvmx_ipd_cfg.packet_pool.pool_num; + if (buffer_size) + *buffer_size = cvmx_ipd_cfg.packet_pool.buffer_size; + if (buffer_count) + *buffer_count = cvmx_ipd_cfg.packet_pool.buffer_count; +} + +/** + * Sets the FPA packet buffer pool parameters. + */ +static inline void cvmx_fpa_set_packet_pool_config(s64 pool, u64 buffer_size, u64 buffer_count) +{ + cvmx_ipd_set_packet_pool_config(pool, buffer_size, buffer_count); +} + +/** + * Gets the FPA WQE pool parameters. + */ +static inline void cvmx_fpa_get_wqe_pool_config(s64 *pool, u64 *buffer_size, u64 *buffer_count) +{ + if (pool) + *pool = cvmx_ipd_cfg.wqe_pool.pool_num; + if (buffer_size) + *buffer_size = cvmx_ipd_cfg.wqe_pool.buffer_size; + if (buffer_count) + *buffer_count = cvmx_ipd_cfg.wqe_pool.buffer_count; +} + +/** + * Sets the FPA WQE pool parameters. + */ +static inline void cvmx_fpa_set_wqe_pool_config(s64 pool, u64 buffer_size, u64 buffer_count) +{ + cvmx_ipd_set_wqe_pool_config(pool, buffer_size, buffer_count); +} + +/** + * Configure IPD + * + * @param mbuff_size Packets buffer size in 8 byte words + * @param first_mbuff_skip + * Number of 8 byte words to skip in the first buffer + * @param not_first_mbuff_skip + * Number of 8 byte words to skip in each following buffer + * @param first_back Must be same as first_mbuff_skip / 128 + * @param second_back + * Must be same as not_first_mbuff_skip / 128 + * @param wqe_fpa_pool + * FPA pool to get work entries from + * @param cache_mode + * @param back_pres_enable_flag + * Enable or disable port back pressure at a global level. + * This should always be 1 as more accurate control can be + * found in IPD_PORTX_BP_PAGE_CNT[BP_ENB]. + */ +void cvmx_ipd_config(u64 mbuff_size, u64 first_mbuff_skip, u64 not_first_mbuff_skip, u64 first_back, + u64 second_back, u64 wqe_fpa_pool, cvmx_ipd_mode_t cache_mode, + u64 back_pres_enable_flag); +/** + * Enable IPD + */ +void cvmx_ipd_enable(void); + +/** + * Disable IPD + */ +void cvmx_ipd_disable(void); + +void __cvmx_ipd_free_ptr(void); + +void cvmx_ipd_set_packet_pool_buffer_count(u64 buffer_count); +void cvmx_ipd_set_wqe_pool_buffer_count(u64 buffer_count); + +/** + * Setup Random Early Drop on a specific input queue + * + * @param queue Input queue to setup RED on (0-7) + * @param pass_thresh + * Packets will begin slowly dropping when there are less than + * this many packet buffers free in FPA 0. + * @param drop_thresh + * All incoming packets will be dropped when there are less + * than this many free packet buffers in FPA 0. + * @return Zero on success. Negative on failure + */ +int cvmx_ipd_setup_red_queue(int queue, int pass_thresh, int drop_thresh); + +/** + * Setup Random Early Drop to automatically begin dropping packets. + * + * @param pass_thresh + * Packets will begin slowly dropping when there are less than + * this many packet buffers free in FPA 0. + * @param drop_thresh + * All incoming packets will be dropped when there are less + * than this many free packet buffers in FPA 0. + * @return Zero on success. Negative on failure + */ +int cvmx_ipd_setup_red(int pass_thresh, int drop_thresh); + +#endif /* __CVMX_IPD_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-packet.h b/arch/mips/mach-octeon/include/mach/cvmx-packet.h new file mode 100644 index 000000000000..f3cfe9c64f43 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-packet.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Packet buffer defines. + */ + +#ifndef __CVMX_PACKET_H__ +#define __CVMX_PACKET_H__ + +union cvmx_buf_ptr_pki { + u64 u64; + struct { + u64 size : 16; + u64 packet_outside_wqe : 1; + u64 rsvd0 : 5; + u64 addr : 42; + }; +}; + +typedef union cvmx_buf_ptr_pki cvmx_buf_ptr_pki_t; + +/** + * This structure defines a buffer pointer on Octeon + */ +union cvmx_buf_ptr { + void *ptr; + u64 u64; + struct { + u64 i : 1; + u64 back : 4; + u64 pool : 3; + u64 size : 16; + u64 addr : 40; + } s; +}; + +typedef union cvmx_buf_ptr cvmx_buf_ptr_t; + +#endif /* __CVMX_PACKET_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pcie.h b/arch/mips/mach-octeon/include/mach/cvmx-pcie.h new file mode 100644 index 000000000000..a819196c021c --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-pcie.h @@ -0,0 +1,279 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +#ifndef __CVMX_PCIE_H__ +#define __CVMX_PCIE_H__ + +#define CVMX_PCIE_MAX_PORTS 4 +#define CVMX_PCIE_PORTS \ + ((OCTEON_IS_MODEL(OCTEON_CN78XX) || OCTEON_IS_MODEL(OCTEON_CN73XX)) ? \ + CVMX_PCIE_MAX_PORTS : \ + (OCTEON_IS_MODEL(OCTEON_CN70XX) ? 3 : 2)) + +/* + * The physical memory base mapped by BAR1. 256MB at the end of the + * first 4GB. + */ +#define CVMX_PCIE_BAR1_PHYS_BASE ((1ull << 32) - (1ull << 28)) +#define CVMX_PCIE_BAR1_PHYS_SIZE BIT_ULL(28) + +/* + * The RC base of BAR1. gen1 has a 39-bit BAR2, gen2 has 41-bit BAR2, + * place BAR1 so it is the same for both. + */ +#define CVMX_PCIE_BAR1_RC_BASE BIT_ULL(41) + +typedef union { + u64 u64; + struct { + u64 upper : 2; /* Normally 2 for XKPHYS */ + u64 reserved_49_61 : 13; /* Must be zero */ + u64 io : 1; /* 1 for IO space access */ + u64 did : 5; /* PCIe DID = 3 */ + u64 subdid : 3; /* PCIe SubDID = 1 */ + u64 reserved_38_39 : 2; /* Must be zero */ + u64 node : 2; /* Numa node number */ + u64 es : 2; /* Endian swap = 1 */ + u64 port : 2; /* PCIe port 0,1 */ + u64 reserved_29_31 : 3; /* Must be zero */ + u64 ty : 1; + u64 bus : 8; + u64 dev : 5; + u64 func : 3; + u64 reg : 12; + } config; + struct { + u64 upper : 2; /* Normally 2 for XKPHYS */ + u64 reserved_49_61 : 13; /* Must be zero */ + u64 io : 1; /* 1 for IO space access */ + u64 did : 5; /* PCIe DID = 3 */ + u64 subdid : 3; /* PCIe SubDID = 2 */ + u64 reserved_38_39 : 2; /* Must be zero */ + u64 node : 2; /* Numa node number */ + u64 es : 2; /* Endian swap = 1 */ + u64 port : 2; /* PCIe port 0,1 */ + u64 address : 32; /* PCIe IO address */ + } io; + struct { + u64 upper : 2; /* Normally 2 for XKPHYS */ + u64 reserved_49_61 : 13; /* Must be zero */ + u64 io : 1; /* 1 for IO space access */ + u64 did : 5; /* PCIe DID = 3 */ + u64 subdid : 3; /* PCIe SubDID = 3-6 */ + u64 reserved_38_39 : 2; /* Must be zero */ + u64 node : 2; /* Numa node number */ + u64 address : 36; /* PCIe Mem address */ + } mem; +} cvmx_pcie_address_t; + +/** + * Return the Core virtual base address for PCIe IO access. IOs are + * read/written as an offset from this address. + * + * @param pcie_port PCIe port the IO is for + * + * @return 64bit Octeon IO base address for read/write + */ +u64 cvmx_pcie_get_io_base_address(int pcie_port); + +/** + * Size of the IO address region returned at address + * cvmx_pcie_get_io_base_address() + * + * @param pcie_port PCIe port the IO is for + * + * @return Size of the IO window + */ +u64 cvmx_pcie_get_io_size(int pcie_port); + +/** + * Return the Core virtual base address for PCIe MEM access. Memory is + * read/written as an offset from this address. + * + * @param pcie_port PCIe port the IO is for + * + * @return 64bit Octeon IO base address for read/write + */ +u64 cvmx_pcie_get_mem_base_address(int pcie_port); + +/** + * Size of the Mem address region returned at address + * cvmx_pcie_get_mem_base_address() + * + * @param pcie_port PCIe port the IO is for + * + * @return Size of the Mem window + */ +u64 cvmx_pcie_get_mem_size(int pcie_port); + +/** + * Initialize a PCIe port for use in host(RC) mode. It doesn't enumerate the bus. + * + * @param pcie_port PCIe port to initialize + * + * @return Zero on success + */ +int cvmx_pcie_rc_initialize(int pcie_port); + +/** + * Shutdown a PCIe port and put it in reset + * + * @param pcie_port PCIe port to shutdown + * + * @return Zero on success + */ +int cvmx_pcie_rc_shutdown(int pcie_port); + +/** + * Read 8bits from a Device's config space + * + * @param pcie_port PCIe port the device is on + * @param bus Sub bus + * @param dev Device ID + * @param fn Device sub function + * @param reg Register to access + * + * @return Result of the read + */ +u8 cvmx_pcie_config_read8(int pcie_port, int bus, int dev, int fn, int reg); + +/** + * Read 16bits from a Device's config space + * + * @param pcie_port PCIe port the device is on + * @param bus Sub bus + * @param dev Device ID + * @param fn Device sub function + * @param reg Register to access + * + * @return Result of the read + */ +u16 cvmx_pcie_config_read16(int pcie_port, int bus, int dev, int fn, int reg); + +/** + * Read 32bits from a Device's config space + * + * @param pcie_port PCIe port the device is on + * @param bus Sub bus + * @param dev Device ID + * @param fn Device sub function + * @param reg Register to access + * + * @return Result of the read + */ +u32 cvmx_pcie_config_read32(int pcie_port, int bus, int dev, int fn, int reg); + +/** + * Write 8bits to a Device's config space + * + * @param pcie_port PCIe port the device is on + * @param bus Sub bus + * @param dev Device ID + * @param fn Device sub function + * @param reg Register to access + * @param val Value to write + */ +void cvmx_pcie_config_write8(int pcie_port, int bus, int dev, int fn, int reg, u8 val); + +/** + * Write 16bits to a Device's config space + * + * @param pcie_port PCIe port the device is on + * @param bus Sub bus + * @param dev Device ID + * @param fn Device sub function + * @param reg Register to access + * @param val Value to write + */ +void cvmx_pcie_config_write16(int pcie_port, int bus, int dev, int fn, int reg, u16 val); + +/** + * Write 32bits to a Device's config space + * + * @param pcie_port PCIe port the device is on + * @param bus Sub bus + * @param dev Device ID + * @param fn Device sub function + * @param reg Register to access + * @param val Value to write + */ +void cvmx_pcie_config_write32(int pcie_port, int bus, int dev, int fn, int reg, u32 val); + +/** + * Read a PCIe config space register indirectly. This is used for + * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???. + * + * @param pcie_port PCIe port to read from + * @param cfg_offset Address to read + * + * @return Value read + */ +u32 cvmx_pcie_cfgx_read(int pcie_port, u32 cfg_offset); +u32 cvmx_pcie_cfgx_read_node(int node, int pcie_port, u32 cfg_offset); + +/** + * Write a PCIe config space register indirectly. This is used for + * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???. + * + * @param pcie_port PCIe port to write to + * @param cfg_offset Address to write + * @param val Value to write + */ +void cvmx_pcie_cfgx_write(int pcie_port, u32 cfg_offset, u32 val); +void cvmx_pcie_cfgx_write_node(int node, int pcie_port, u32 cfg_offset, u32 val); + +/** + * Write a 32bit value to the Octeon NPEI register space + * + * @param address Address to write to + * @param val Value to write + */ +static inline void cvmx_pcie_npei_write32(u64 address, u32 val) +{ + cvmx_write64_uint32(address ^ 4, val); + cvmx_read64_uint32(address ^ 4); +} + +/** + * Read a 32bit value from the Octeon NPEI register space + * + * @param address Address to read + * @return The result + */ +static inline u32 cvmx_pcie_npei_read32(u64 address) +{ + return cvmx_read64_uint32(address ^ 4); +} + +/** + * Initialize a PCIe port for use in target(EP) mode. + * + * @param pcie_port PCIe port to initialize + * + * @return Zero on success + */ +int cvmx_pcie_ep_initialize(int pcie_port); + +/** + * Wait for posted PCIe read/writes to reach the other side of + * the internal PCIe switch. This will insure that core + * read/writes are posted before anything after this function + * is called. This may be necessary when writing to memory that + * will later be read using the DMA/PKT engines. + * + * @param pcie_port PCIe port to wait for + */ +void cvmx_pcie_wait_for_pending(int pcie_port); + +/** + * Returns if a PCIe port is in host or target mode. + * + * @param pcie_port PCIe port number (PEM number) + * + * @return 0 if PCIe port is in target mode, !0 if in host mode. + */ +int cvmx_pcie_is_host_mode(int pcie_port); + +#endif diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pip.h b/arch/mips/mach-octeon/include/mach/cvmx-pip.h new file mode 100644 index 000000000000..013f533fb7bb --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-pip.h @@ -0,0 +1,1080 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Interface to the hardware Packet Input Processing unit. + */ + +#ifndef __CVMX_PIP_H__ +#define __CVMX_PIP_H__ + +#include "cvmx-wqe.h" +#include "cvmx-pki.h" +#include "cvmx-helper-pki.h" + +#include "cvmx-helper.h" +#include "cvmx-helper-util.h" +#include "cvmx-pki-resources.h" + +#define CVMX_PIP_NUM_INPUT_PORTS 46 +#define CVMX_PIP_NUM_WATCHERS 8 + +/* + * Encodes the different error and exception codes + */ +typedef enum { + CVMX_PIP_L4_NO_ERR = 0ull, + /* 1 = TCP (UDP) packet not long enough to cover TCP (UDP) header */ + CVMX_PIP_L4_MAL_ERR = 1ull, + /* 2 = TCP/UDP checksum failure */ + CVMX_PIP_CHK_ERR = 2ull, + /* 3 = TCP/UDP length check (TCP/UDP length does not match IP length) */ + CVMX_PIP_L4_LENGTH_ERR = 3ull, + /* 4 = illegal TCP/UDP port (either source or dest port is zero) */ + CVMX_PIP_BAD_PRT_ERR = 4ull, + /* 8 = TCP flags = FIN only */ + CVMX_PIP_TCP_FLG8_ERR = 8ull, + /* 9 = TCP flags = 0 */ + CVMX_PIP_TCP_FLG9_ERR = 9ull, + /* 10 = TCP flags = FIN+RST+* */ + CVMX_PIP_TCP_FLG10_ERR = 10ull, + /* 11 = TCP flags = SYN+URG+* */ + CVMX_PIP_TCP_FLG11_ERR = 11ull, + /* 12 = TCP flags = SYN+RST+* */ + CVMX_PIP_TCP_FLG12_ERR = 12ull, + /* 13 = TCP flags = SYN+FIN+* */ + CVMX_PIP_TCP_FLG13_ERR = 13ull +} cvmx_pip_l4_err_t; + +typedef enum { + CVMX_PIP_IP_NO_ERR = 0ull, + /* 1 = not IPv4 or IPv6 */ + CVMX_PIP_NOT_IP = 1ull, + /* 2 = IPv4 header checksum violation */ + CVMX_PIP_IPV4_HDR_CHK = 2ull, + /* 3 = malformed (packet not long enough to cover IP hdr) */ + CVMX_PIP_IP_MAL_HDR = 3ull, + /* 4 = malformed (packet not long enough to cover len in IP hdr) */ + CVMX_PIP_IP_MAL_PKT = 4ull, + /* 5 = TTL / hop count equal zero */ + CVMX_PIP_TTL_HOP = 5ull, + /* 6 = IPv4 options / IPv6 early extension headers */ + CVMX_PIP_OPTS = 6ull +} cvmx_pip_ip_exc_t; + +/** + * NOTES + * late collision (data received before collision) + * late collisions cannot be detected by the receiver + * they would appear as JAM bits which would appear as bad FCS + * or carrier extend error which is CVMX_PIP_EXTEND_ERR + */ +typedef enum { + /** + * No error + */ + CVMX_PIP_RX_NO_ERR = 0ull, + + CVMX_PIP_PARTIAL_ERR = + 1ull, /* RGM+SPI 1 = partially received packet (buffering/bandwidth not adequate) */ + CVMX_PIP_JABBER_ERR = + 2ull, /* RGM+SPI 2 = receive packet too large and truncated */ + CVMX_PIP_OVER_FCS_ERR = + 3ull, /* RGM 3 = max frame error (pkt len > max frame len) (with FCS error) */ + CVMX_PIP_OVER_ERR = + 4ull, /* RGM+SPI 4 = max frame error (pkt len > max frame len) */ + CVMX_PIP_ALIGN_ERR = + 5ull, /* RGM 5 = nibble error (data not byte multiple - 100M and 10M only) */ + CVMX_PIP_UNDER_FCS_ERR = + 6ull, /* RGM 6 = min frame error (pkt len < min frame len) (with FCS error) */ + CVMX_PIP_GMX_FCS_ERR = 7ull, /* RGM 7 = FCS error */ + CVMX_PIP_UNDER_ERR = + 8ull, /* RGM+SPI 8 = min frame error (pkt len < min frame len) */ + CVMX_PIP_EXTEND_ERR = 9ull, /* RGM 9 = Frame carrier extend error */ + CVMX_PIP_TERMINATE_ERR = + 9ull, /* XAUI 9 = Packet was terminated with an idle cycle */ + CVMX_PIP_LENGTH_ERR = + 10ull, /* RGM 10 = length mismatch (len did not match len in L2 length/type) */ + CVMX_PIP_DAT_ERR = + 11ull, /* RGM 11 = Frame error (some or all data bits marked err) */ + CVMX_PIP_DIP_ERR = 11ull, /* SPI 11 = DIP4 error */ + CVMX_PIP_SKIP_ERR = + 12ull, /* RGM 12 = packet was not large enough to pass the skipper - no inspection could occur */ + CVMX_PIP_NIBBLE_ERR = + 13ull, /* RGM 13 = studder error (data not repeated - 100M and 10M only) */ + CVMX_PIP_PIP_FCS = 16L, /* RGM+SPI 16 = FCS error */ + CVMX_PIP_PIP_SKIP_ERR = + 17L, /* RGM+SPI+PCI 17 = packet was not large enough to pass the skipper - no inspection could occur */ + CVMX_PIP_PIP_L2_MAL_HDR = + 18L, /* RGM+SPI+PCI 18 = malformed l2 (packet not long enough to cover L2 hdr) */ + CVMX_PIP_PUNY_ERR = + 47L /* SGMII 47 = PUNY error (packet was 4B or less when FCS stripping is enabled) */ + /* NOTES + * xx = late collision (data received before collision) + * late collisions cannot be detected by the receiver + * they would appear as JAM bits which would appear as bad FCS + * or carrier extend error which is CVMX_PIP_EXTEND_ERR + */ +} cvmx_pip_rcv_err_t; + +/** + * This defines the err_code field errors in the work Q entry + */ +typedef union { + cvmx_pip_l4_err_t l4_err; + cvmx_pip_ip_exc_t ip_exc; + cvmx_pip_rcv_err_t rcv_err; +} cvmx_pip_err_t; + +/** + * Status statistics for a port + */ +typedef struct { + u64 dropped_octets; + u64 dropped_packets; + u64 pci_raw_packets; + u64 octets; + u64 packets; + u64 multicast_packets; + u64 broadcast_packets; + u64 len_64_packets; + u64 len_65_127_packets; + u64 len_128_255_packets; + u64 len_256_511_packets; + u64 len_512_1023_packets; + u64 len_1024_1518_packets; + u64 len_1519_max_packets; + u64 fcs_align_err_packets; + u64 runt_packets; + u64 runt_crc_packets; + u64 oversize_packets; + u64 oversize_crc_packets; + u64 inb_packets; + u64 inb_octets; + u64 inb_errors; + u64 mcast_l2_red_packets; + u64 bcast_l2_red_packets; + u64 mcast_l3_red_packets; + u64 bcast_l3_red_packets; +} cvmx_pip_port_status_t; + +/** + * Definition of the PIP custom header that can be prepended + * to a packet by external hardware. + */ +typedef union { + u64 u64; + struct { + u64 rawfull : 1; + u64 reserved0 : 5; + cvmx_pip_port_parse_mode_t parse_mode : 2; + u64 reserved1 : 1; + u64 skip_len : 7; + u64 grpext : 2; + u64 nqos : 1; + u64 ngrp : 1; + u64 ntt : 1; + u64 ntag : 1; + u64 qos : 3; + u64 grp : 4; + u64 rs : 1; + cvmx_pow_tag_type_t tag_type : 2; + u64 tag : 32; + } s; +} cvmx_pip_pkt_inst_hdr_t; + +enum cvmx_pki_pcam_match { + CVMX_PKI_PCAM_MATCH_IP, + CVMX_PKI_PCAM_MATCH_IPV4, + CVMX_PKI_PCAM_MATCH_IPV6, + CVMX_PKI_PCAM_MATCH_TCP +}; + +/* CSR typedefs have been moved to cvmx-pip-defs.h */ +static inline int cvmx_pip_config_watcher(int index, int type, u16 match, u16 mask, int grp, + int qos) +{ + if (index >= CVMX_PIP_NUM_WATCHERS) { + debug("ERROR: pip watcher %d is > than supported\n", index); + return -1; + } + if (octeon_has_feature(OCTEON_FEATURE_PKI)) { + /* store in software for now, only when the watcher is enabled program the entry*/ + if (type == CVMX_PIP_QOS_WATCH_PROTNH) { + qos_watcher[index].field = CVMX_PKI_PCAM_TERM_L3_FLAGS; + qos_watcher[index].data = (u32)(match << 16); + qos_watcher[index].data_mask = (u32)(mask << 16); + qos_watcher[index].advance = 0; + } else if (type == CVMX_PIP_QOS_WATCH_TCP) { + qos_watcher[index].field = CVMX_PKI_PCAM_TERM_L4_PORT; + qos_watcher[index].data = 0x060000; + qos_watcher[index].data |= (u32)match; + qos_watcher[index].data_mask = (u32)(mask); + qos_watcher[index].advance = 0; + } else if (type == CVMX_PIP_QOS_WATCH_UDP) { + qos_watcher[index].field = CVMX_PKI_PCAM_TERM_L4_PORT; + qos_watcher[index].data = 0x110000; + qos_watcher[index].data |= (u32)match; + qos_watcher[index].data_mask = (u32)(mask); + qos_watcher[index].advance = 0; + } else if (type == 0x4 /*CVMX_PIP_QOS_WATCH_ETHERTYPE*/) { + qos_watcher[index].field = CVMX_PKI_PCAM_TERM_ETHTYPE0; + if (match == 0x8100) { + debug("ERROR: default vlan entry already exist, cant set watcher\n"); + return -1; + } + qos_watcher[index].data = (u32)(match << 16); + qos_watcher[index].data_mask = (u32)(mask << 16); + qos_watcher[index].advance = 4; + } else { + debug("ERROR: Unsupported watcher type %d\n", type); + return -1; + } + if (grp >= 32) { + debug("ERROR: grp %d out of range for backward compat 78xx\n", grp); + return -1; + } + qos_watcher[index].sso_grp = (u8)(grp << 3 | qos); + qos_watcher[index].configured = 1; + } else { + /* Implement it later */ + } + return 0; +} + +static inline int __cvmx_pip_set_tag_type(int node, int style, int tag_type, int field) +{ + struct cvmx_pki_style_config style_cfg; + int style_num; + int pcam_offset; + int bank; + struct cvmx_pki_pcam_input pcam_input; + struct cvmx_pki_pcam_action pcam_action; + + /* All other style parameters remain same except tag type */ + cvmx_pki_read_style_config(node, style, CVMX_PKI_CLUSTER_ALL, &style_cfg); + style_cfg.parm_cfg.tag_type = (enum cvmx_sso_tag_type)tag_type; + style_num = cvmx_pki_style_alloc(node, -1); + if (style_num < 0) { + debug("ERROR: style not available to set tag type\n"); + return -1; + } + cvmx_pki_write_style_config(node, style_num, CVMX_PKI_CLUSTER_ALL, &style_cfg); + memset(&pcam_input, 0, sizeof(pcam_input)); + memset(&pcam_action, 0, sizeof(pcam_action)); + pcam_input.style = style; + pcam_input.style_mask = 0xff; + if (field == CVMX_PKI_PCAM_MATCH_IP) { + pcam_input.field = CVMX_PKI_PCAM_TERM_ETHTYPE0; + pcam_input.field_mask = 0xff; + pcam_input.data = 0x08000000; + pcam_input.data_mask = 0xffff0000; + pcam_action.pointer_advance = 4; + /* legacy will write to all clusters*/ + bank = 0; + pcam_offset = cvmx_pki_pcam_entry_alloc(node, CVMX_PKI_FIND_AVAL_ENTRY, bank, + CVMX_PKI_CLUSTER_ALL); + if (pcam_offset < 0) { + debug("ERROR: pcam entry not available to enable qos watcher\n"); + cvmx_pki_style_free(node, style_num); + return -1; + } + pcam_action.parse_mode_chg = CVMX_PKI_PARSE_NO_CHG; + pcam_action.layer_type_set = CVMX_PKI_LTYPE_E_NONE; + pcam_action.style_add = (u8)(style_num - style); + cvmx_pki_pcam_write_entry(node, pcam_offset, CVMX_PKI_CLUSTER_ALL, pcam_input, + pcam_action); + field = CVMX_PKI_PCAM_MATCH_IPV6; + } + if (field == CVMX_PKI_PCAM_MATCH_IPV4) { + pcam_input.field = CVMX_PKI_PCAM_TERM_ETHTYPE0; + pcam_input.field_mask = 0xff; + pcam_input.data = 0x08000000; + pcam_input.data_mask = 0xffff0000; + pcam_action.pointer_advance = 4; + } else if (field == CVMX_PKI_PCAM_MATCH_IPV6) { + pcam_input.field = CVMX_PKI_PCAM_TERM_ETHTYPE0; + pcam_input.field_mask = 0xff; + pcam_input.data = 0x86dd00000; + pcam_input.data_mask = 0xffff0000; + pcam_action.pointer_advance = 4; + } else if (field == CVMX_PKI_PCAM_MATCH_TCP) { + pcam_input.field = CVMX_PKI_PCAM_TERM_L4_PORT; + pcam_input.field_mask = 0xff; + pcam_input.data = 0x60000; + pcam_input.data_mask = 0xff0000; + pcam_action.pointer_advance = 0; + } + pcam_action.parse_mode_chg = CVMX_PKI_PARSE_NO_CHG; + pcam_action.layer_type_set = CVMX_PKI_LTYPE_E_NONE; + pcam_action.style_add = (u8)(style_num - style); + bank = pcam_input.field & 0x01; + pcam_offset = cvmx_pki_pcam_entry_alloc(node, CVMX_PKI_FIND_AVAL_ENTRY, bank, + CVMX_PKI_CLUSTER_ALL); + if (pcam_offset < 0) { + debug("ERROR: pcam entry not available to enable qos watcher\n"); + cvmx_pki_style_free(node, style_num); + return -1; + } + cvmx_pki_pcam_write_entry(node, pcam_offset, CVMX_PKI_CLUSTER_ALL, pcam_input, pcam_action); + return style_num; +} + +/* Only for legacy internal use */ +static inline int __cvmx_pip_enable_watcher_78xx(int node, int index, int style) +{ + struct cvmx_pki_style_config style_cfg; + struct cvmx_pki_qpg_config qpg_cfg; + struct cvmx_pki_pcam_input pcam_input; + struct cvmx_pki_pcam_action pcam_action; + int style_num; + int qpg_offset; + int pcam_offset; + int bank; + + if (!qos_watcher[index].configured) { + debug("ERROR: qos watcher %d should be configured before enable\n", index); + return -1; + } + /* All other style parameters remain same except grp and qos and qps base */ + cvmx_pki_read_style_config(node, style, CVMX_PKI_CLUSTER_ALL, &style_cfg); + cvmx_pki_read_qpg_entry(node, style_cfg.parm_cfg.qpg_base, &qpg_cfg); + qpg_cfg.qpg_base = CVMX_PKI_FIND_AVAL_ENTRY; + qpg_cfg.grp_ok = qos_watcher[index].sso_grp; + qpg_cfg.grp_bad = qos_watcher[index].sso_grp; + qpg_offset = cvmx_helper_pki_set_qpg_entry(node, &qpg_cfg); + if (qpg_offset == -1) { + debug("Warning: no new qpg entry available to enable watcher\n"); + return -1; + } + /* try to reserve the style, if it is not configured already, reserve + and configure it */ + style_cfg.parm_cfg.qpg_base = qpg_offset; + style_num = cvmx_pki_style_alloc(node, -1); + if (style_num < 0) { + debug("ERROR: style not available to enable qos watcher\n"); + cvmx_pki_qpg_entry_free(node, qpg_offset, 1); + return -1; + } + cvmx_pki_write_style_config(node, style_num, CVMX_PKI_CLUSTER_ALL, &style_cfg); + /* legacy will write to all clusters*/ + bank = qos_watcher[index].field & 0x01; + pcam_offset = cvmx_pki_pcam_entry_alloc(node, CVMX_PKI_FIND_AVAL_ENTRY, bank, + CVMX_PKI_CLUSTER_ALL); + if (pcam_offset < 0) { + debug("ERROR: pcam entry not available to enable qos watcher\n"); + cvmx_pki_style_free(node, style_num); + cvmx_pki_qpg_entry_free(node, qpg_offset, 1); + return -1; + } + memset(&pcam_input, 0, sizeof(pcam_input)); + memset(&pcam_action, 0, sizeof(pcam_action)); + pcam_input.style = style; + pcam_input.style_mask = 0xff; + pcam_input.field = qos_watcher[index].field; + pcam_input.field_mask = 0xff; + pcam_input.data = qos_watcher[index].data; + pcam_input.data_mask = qos_watcher[index].data_mask; + pcam_action.parse_mode_chg = CVMX_PKI_PARSE_NO_CHG; + pcam_action.layer_type_set = CVMX_PKI_LTYPE_E_NONE; + pcam_action.style_add = (u8)(style_num - style); + pcam_action.pointer_advance = qos_watcher[index].advance; + cvmx_pki_pcam_write_entry(node, pcam_offset, CVMX_PKI_CLUSTER_ALL, pcam_input, pcam_action); + return 0; +} + +/** + * Configure an ethernet input port + * + * @param ipd_port Port number to configure + * @param port_cfg Port hardware configuration + * @param port_tag_cfg Port POW tagging configuration + */ +static inline void cvmx_pip_config_port(u64 ipd_port, cvmx_pip_prt_cfgx_t port_cfg, + cvmx_pip_prt_tagx_t port_tag_cfg) +{ + struct cvmx_pki_qpg_config qpg_cfg; + int qpg_offset; + u8 tcp_tag = 0xff; + u8 ip_tag = 0xaa; + int style, nstyle, n4style, n6style; + + if (octeon_has_feature(OCTEON_FEATURE_PKI)) { + struct cvmx_pki_port_config pki_prt_cfg; + struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port); + + cvmx_pki_get_port_config(ipd_port, &pki_prt_cfg); + style = pki_prt_cfg.pkind_cfg.initial_style; + if (port_cfg.s.ih_pri || port_cfg.s.vlan_len || port_cfg.s.pad_len) + debug("Warning: 78xx: use different config for this option\n"); + pki_prt_cfg.style_cfg.parm_cfg.minmax_sel = port_cfg.s.len_chk_sel; + pki_prt_cfg.style_cfg.parm_cfg.lenerr_en = port_cfg.s.lenerr_en; + pki_prt_cfg.style_cfg.parm_cfg.maxerr_en = port_cfg.s.maxerr_en; + pki_prt_cfg.style_cfg.parm_cfg.minerr_en = port_cfg.s.minerr_en; + pki_prt_cfg.style_cfg.parm_cfg.fcs_chk = port_cfg.s.crc_en; + if (port_cfg.s.grp_wat || port_cfg.s.qos_wat || port_cfg.s.grp_wat_47 || + port_cfg.s.qos_wat_47) { + u8 group_mask = (u8)(port_cfg.s.grp_wat | (u8)(port_cfg.s.grp_wat_47 << 4)); + u8 qos_mask = (u8)(port_cfg.s.qos_wat | (u8)(port_cfg.s.qos_wat_47 << 4)); + int i; + + for (i = 0; i < CVMX_PIP_NUM_WATCHERS; i++) { + if ((group_mask & (1 << i)) || (qos_mask & (1 << i))) + __cvmx_pip_enable_watcher_78xx(xp.node, i, style); + } + } + if (port_tag_cfg.s.tag_mode) { + if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X)) + cvmx_printf("Warning: mask tag is not supported in 78xx pass1\n"); + else { + } + /* need to implement for 78xx*/ + } + if (port_cfg.s.tag_inc) + debug("Warning: 78xx uses differnet method for tag generation\n"); + pki_prt_cfg.style_cfg.parm_cfg.rawdrp = port_cfg.s.rawdrp; + pki_prt_cfg.pkind_cfg.parse_en.inst_hdr = port_cfg.s.inst_hdr; + if (port_cfg.s.hg_qos) + pki_prt_cfg.style_cfg.parm_cfg.qpg_qos = CVMX_PKI_QPG_QOS_HIGIG; + else if (port_cfg.s.qos_vlan) + pki_prt_cfg.style_cfg.parm_cfg.qpg_qos = CVMX_PKI_QPG_QOS_VLAN; + else if (port_cfg.s.qos_diff) + pki_prt_cfg.style_cfg.parm_cfg.qpg_qos = CVMX_PKI_QPG_QOS_DIFFSERV; + if (port_cfg.s.qos_vod) + debug("Warning: 78xx needs pcam entries installed to achieve qos_vod\n"); + if (port_cfg.s.qos) { + cvmx_pki_read_qpg_entry(xp.node, pki_prt_cfg.style_cfg.parm_cfg.qpg_base, + &qpg_cfg); + qpg_cfg.qpg_base = CVMX_PKI_FIND_AVAL_ENTRY; + qpg_cfg.grp_ok |= port_cfg.s.qos; + qpg_cfg.grp_bad |= port_cfg.s.qos; + qpg_offset = cvmx_helper_pki_set_qpg_entry(xp.node, &qpg_cfg); + if (qpg_offset == -1) + debug("Warning: no new qpg entry available, will not modify qos\n"); + else + pki_prt_cfg.style_cfg.parm_cfg.qpg_base = qpg_offset; + } + if (port_tag_cfg.s.grp != pki_dflt_sso_grp[xp.node].group) { + cvmx_pki_read_qpg_entry(xp.node, pki_prt_cfg.style_cfg.parm_cfg.qpg_base, + &qpg_cfg); + qpg_cfg.qpg_base = CVMX_PKI_FIND_AVAL_ENTRY; + qpg_cfg.grp_ok |= (u8)(port_tag_cfg.s.grp << 3); + qpg_cfg.grp_bad |= (u8)(port_tag_cfg.s.grp << 3); + qpg_offset = cvmx_helper_pki_set_qpg_entry(xp.node, &qpg_cfg); + if (qpg_offset == -1) + debug("Warning: no new qpg entry available, will not modify group\n"); + else + pki_prt_cfg.style_cfg.parm_cfg.qpg_base = qpg_offset; + } + pki_prt_cfg.pkind_cfg.parse_en.dsa_en = port_cfg.s.dsa_en; + pki_prt_cfg.pkind_cfg.parse_en.hg_en = port_cfg.s.higig_en; + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.layer_c_src = + port_tag_cfg.s.ip6_src_flag | port_tag_cfg.s.ip4_src_flag; + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.layer_c_dst = + port_tag_cfg.s.ip6_dst_flag | port_tag_cfg.s.ip4_dst_flag; + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.ip_prot_nexthdr = + port_tag_cfg.s.ip6_nxth_flag | port_tag_cfg.s.ip4_pctl_flag; + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.layer_d_src = + port_tag_cfg.s.ip6_sprt_flag | port_tag_cfg.s.ip4_sprt_flag; + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.layer_d_dst = + port_tag_cfg.s.ip6_dprt_flag | port_tag_cfg.s.ip4_dprt_flag; + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.input_port = port_tag_cfg.s.inc_prt_flag; + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.first_vlan = port_tag_cfg.s.inc_vlan; + pki_prt_cfg.style_cfg.tag_cfg.tag_fields.second_vlan = port_tag_cfg.s.inc_vs; + + if (port_tag_cfg.s.tcp6_tag_type == port_tag_cfg.s.tcp4_tag_type) + tcp_tag = port_tag_cfg.s.tcp6_tag_type; + if (port_tag_cfg.s.ip6_tag_type == port_tag_cfg.s.ip4_tag_type) + ip_tag = port_tag_cfg.s.ip6_tag_type; + pki_prt_cfg.style_cfg.parm_cfg.tag_type = + (enum cvmx_sso_tag_type)port_tag_cfg.s.non_tag_type; + if (tcp_tag == ip_tag && tcp_tag == port_tag_cfg.s.non_tag_type) + pki_prt_cfg.style_cfg.parm_cfg.tag_type = (enum cvmx_sso_tag_type)tcp_tag; + else if (tcp_tag == ip_tag) { + /* allocate and copy style */ + /* modify tag type */ + /*pcam entry for ip6 && ip4 match*/ + /* default is non tag type */ + __cvmx_pip_set_tag_type(xp.node, style, ip_tag, CVMX_PKI_PCAM_MATCH_IP); + } else if (ip_tag == port_tag_cfg.s.non_tag_type) { + /* allocate and copy style */ + /* modify tag type */ + /*pcam entry for tcp6 & tcp4 match*/ + /* default is non tag type */ + __cvmx_pip_set_tag_type(xp.node, style, tcp_tag, CVMX_PKI_PCAM_MATCH_TCP); + } else { + if (ip_tag != 0xaa) { + nstyle = __cvmx_pip_set_tag_type(xp.node, style, ip_tag, + CVMX_PKI_PCAM_MATCH_IP); + if (tcp_tag != 0xff) + __cvmx_pip_set_tag_type(xp.node, nstyle, tcp_tag, + CVMX_PKI_PCAM_MATCH_TCP); + else { + n4style = __cvmx_pip_set_tag_type(xp.node, nstyle, ip_tag, + CVMX_PKI_PCAM_MATCH_IPV4); + __cvmx_pip_set_tag_type(xp.node, n4style, + port_tag_cfg.s.tcp4_tag_type, + CVMX_PKI_PCAM_MATCH_TCP); + n6style = __cvmx_pip_set_tag_type(xp.node, nstyle, ip_tag, + CVMX_PKI_PCAM_MATCH_IPV6); + __cvmx_pip_set_tag_type(xp.node, n6style, + port_tag_cfg.s.tcp6_tag_type, + CVMX_PKI_PCAM_MATCH_TCP); + } + } else { + n4style = __cvmx_pip_set_tag_type(xp.node, style, + port_tag_cfg.s.ip4_tag_type, + CVMX_PKI_PCAM_MATCH_IPV4); + n6style = __cvmx_pip_set_tag_type(xp.node, style, + port_tag_cfg.s.ip6_tag_type, + CVMX_PKI_PCAM_MATCH_IPV6); + if (tcp_tag != 0xff) { + __cvmx_pip_set_tag_type(xp.node, n4style, tcp_tag, + CVMX_PKI_PCAM_MATCH_TCP); + __cvmx_pip_set_tag_type(xp.node, n6style, tcp_tag, + CVMX_PKI_PCAM_MATCH_TCP); + } else { + __cvmx_pip_set_tag_type(xp.node, n4style, + port_tag_cfg.s.tcp4_tag_type, + CVMX_PKI_PCAM_MATCH_TCP); + __cvmx_pip_set_tag_type(xp.node, n6style, + port_tag_cfg.s.tcp6_tag_type, + CVMX_PKI_PCAM_MATCH_TCP); + } + } + } + pki_prt_cfg.style_cfg.parm_cfg.qpg_dis_padd = !port_tag_cfg.s.portadd_en; + + if (port_cfg.s.mode == 0x1) + pki_prt_cfg.pkind_cfg.initial_parse_mode = CVMX_PKI_PARSE_LA_TO_LG; + else if (port_cfg.s.mode == 0x2) + pki_prt_cfg.pkind_cfg.initial_parse_mode = CVMX_PKI_PARSE_LC_TO_LG; + else + pki_prt_cfg.pkind_cfg.initial_parse_mode = CVMX_PKI_PARSE_NOTHING; + /* This is only for backward compatibility, not all the parameters are supported in 78xx */ + cvmx_pki_set_port_config(ipd_port, &pki_prt_cfg); + } else { + if (octeon_has_feature(OCTEON_FEATURE_PKND)) { + int interface, index, pknd; + + interface = cvmx_helper_get_interface_num(ipd_port); + index = cvmx_helper_get_interface_index_num(ipd_port); + pknd = cvmx_helper_get_pknd(interface, index); + + ipd_port = pknd; /* overload port_num with pknd */ + } + csr_wr(CVMX_PIP_PRT_CFGX(ipd_port), port_cfg.u64); + csr_wr(CVMX_PIP_PRT_TAGX(ipd_port), port_tag_cfg.u64); + } +} + +/** + * Configure the VLAN priority to QoS queue mapping. + * + * @param vlan_priority + * VLAN priority (0-7) + * @param qos QoS queue for packets matching this watcher + */ +static inline void cvmx_pip_config_vlan_qos(u64 vlan_priority, u64 qos) +{ + if (!octeon_has_feature(OCTEON_FEATURE_PKND)) { + cvmx_pip_qos_vlanx_t pip_qos_vlanx; + + pip_qos_vlanx.u64 = 0; + pip_qos_vlanx.s.qos = qos; + csr_wr(CVMX_PIP_QOS_VLANX(vlan_priority), pip_qos_vlanx.u64); + } +} + +/** + * Configure the Diffserv to QoS queue mapping. + * + * @param diffserv Diffserv field value (0-63) + * @param qos QoS queue for packets matching this watcher + */ +static inline void cvmx_pip_config_diffserv_qos(u64 diffserv, u64 qos) +{ + if (!octeon_has_feature(OCTEON_FEATURE_PKND)) { + cvmx_pip_qos_diffx_t pip_qos_diffx; + + pip_qos_diffx.u64 = 0; + pip_qos_diffx.s.qos = qos; + csr_wr(CVMX_PIP_QOS_DIFFX(diffserv), pip_qos_diffx.u64); + } +} + +/** + * Get the status counters for a port for older non PKI chips. + * + * @param port_num Port number (ipd_port) to get statistics for. + * @param clear Set to 1 to clear the counters after they are read + * @param status Where to put the results. + */ +static inline void cvmx_pip_get_port_stats(u64 port_num, u64 clear, cvmx_pip_port_status_t *status) +{ + cvmx_pip_stat_ctl_t pip_stat_ctl; + cvmx_pip_stat0_prtx_t stat0; + cvmx_pip_stat1_prtx_t stat1; + cvmx_pip_stat2_prtx_t stat2; + cvmx_pip_stat3_prtx_t stat3; + cvmx_pip_stat4_prtx_t stat4; + cvmx_pip_stat5_prtx_t stat5; + cvmx_pip_stat6_prtx_t stat6; + cvmx_pip_stat7_prtx_t stat7; + cvmx_pip_stat8_prtx_t stat8; + cvmx_pip_stat9_prtx_t stat9; + cvmx_pip_stat10_x_t stat10; + cvmx_pip_stat11_x_t stat11; + cvmx_pip_stat_inb_pktsx_t pip_stat_inb_pktsx; + cvmx_pip_stat_inb_octsx_t pip_stat_inb_octsx; + cvmx_pip_stat_inb_errsx_t pip_stat_inb_errsx; + int interface = cvmx_helper_get_interface_num(port_num); + int index = cvmx_helper_get_interface_index_num(port_num); + + pip_stat_ctl.u64 = 0; + pip_stat_ctl.s.rdclr = clear; + csr_wr(CVMX_PIP_STAT_CTL, pip_stat_ctl.u64); + + if (octeon_has_feature(OCTEON_FEATURE_PKND)) { + int pknd = cvmx_helper_get_pknd(interface, index); + /* + * PIP_STAT_CTL[MODE] 0 means pkind. + */ + stat0.u64 = csr_rd(CVMX_PIP_STAT0_X(pknd)); + stat1.u64 = csr_rd(CVMX_PIP_STAT1_X(pknd)); + stat2.u64 = csr_rd(CVMX_PIP_STAT2_X(pknd)); + stat3.u64 = csr_rd(CVMX_PIP_STAT3_X(pknd)); + stat4.u64 = csr_rd(CVMX_PIP_STAT4_X(pknd)); + stat5.u64 = csr_rd(CVMX_PIP_STAT5_X(pknd)); + stat6.u64 = csr_rd(CVMX_PIP_STAT6_X(pknd)); + stat7.u64 = csr_rd(CVMX_PIP_STAT7_X(pknd)); + stat8.u64 = csr_rd(CVMX_PIP_STAT8_X(pknd)); + stat9.u64 = csr_rd(CVMX_PIP_STAT9_X(pknd)); + stat10.u64 = csr_rd(CVMX_PIP_STAT10_X(pknd)); + stat11.u64 = csr_rd(CVMX_PIP_STAT11_X(pknd)); + } else { + if (port_num >= 40) { + stat0.u64 = csr_rd(CVMX_PIP_XSTAT0_PRTX(port_num)); + stat1.u64 = csr_rd(CVMX_PIP_XSTAT1_PRTX(port_num)); + stat2.u64 = csr_rd(CVMX_PIP_XSTAT2_PRTX(port_num)); + stat3.u64 = csr_rd(CVMX_PIP_XSTAT3_PRTX(port_num)); + stat4.u64 = csr_rd(CVMX_PIP_XSTAT4_PRTX(port_num)); + stat5.u64 = csr_rd(CVMX_PIP_XSTAT5_PRTX(port_num)); + stat6.u64 = csr_rd(CVMX_PIP_XSTAT6_PRTX(port_num)); + stat7.u64 = csr_rd(CVMX_PIP_XSTAT7_PRTX(port_num)); + stat8.u64 = csr_rd(CVMX_PIP_XSTAT8_PRTX(port_num)); + stat9.u64 = csr_rd(CVMX_PIP_XSTAT9_PRTX(port_num)); + if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { + stat10.u64 = csr_rd(CVMX_PIP_XSTAT10_PRTX(port_num)); + stat11.u64 = csr_rd(CVMX_PIP_XSTAT11_PRTX(port_num)); + } + } else { + stat0.u64 = csr_rd(CVMX_PIP_STAT0_PRTX(port_num)); + stat1.u64 = csr_rd(CVMX_PIP_STAT1_PRTX(port_num)); + stat2.u64 = csr_rd(CVMX_PIP_STAT2_PRTX(port_num)); + stat3.u64 = csr_rd(CVMX_PIP_STAT3_PRTX(port_num)); + stat4.u64 = csr_rd(CVMX_PIP_STAT4_PRTX(port_num)); + stat5.u64 = csr_rd(CVMX_PIP_STAT5_PRTX(port_num)); + stat6.u64 = csr_rd(CVMX_PIP_STAT6_PRTX(port_num)); + stat7.u64 = csr_rd(CVMX_PIP_STAT7_PRTX(port_num)); + stat8.u64 = csr_rd(CVMX_PIP_STAT8_PRTX(port_num)); + stat9.u64 = csr_rd(CVMX_PIP_STAT9_PRTX(port_num)); + if (OCTEON_IS_OCTEON2() || OCTEON_IS_MODEL(OCTEON_CN70XX)) { + stat10.u64 = csr_rd(CVMX_PIP_STAT10_PRTX(port_num)); + stat11.u64 = csr_rd(CVMX_PIP_STAT11_PRTX(port_num)); + } + } + } + if (octeon_has_feature(OCTEON_FEATURE_PKND)) { + int pknd = cvmx_helper_get_pknd(interface, index); + + pip_stat_inb_pktsx.u64 = csr_rd(CVMX_PIP_STAT_INB_PKTS_PKNDX(pknd)); + pip_stat_inb_octsx.u64 = csr_rd(CVMX_PIP_STAT_INB_OCTS_PKNDX(pknd)); + pip_stat_inb_errsx.u64 = csr_rd(CVMX_PIP_STAT_INB_ERRS_PKNDX(pknd)); + } else { + pip_stat_inb_pktsx.u64 = csr_rd(CVMX_PIP_STAT_INB_PKTSX(port_num)); + pip_stat_inb_octsx.u64 = csr_rd(CVMX_PIP_STAT_INB_OCTSX(port_num)); + pip_stat_inb_errsx.u64 = csr_rd(CVMX_PIP_STAT_INB_ERRSX(port_num)); + } + + status->dropped_octets = stat0.s.drp_octs; + status->dropped_packets = stat0.s.drp_pkts; + status->octets = stat1.s.octs; + status->pci_raw_packets = stat2.s.raw; + status->packets = stat2.s.pkts; + status->multicast_packets = stat3.s.mcst; + status->broadcast_packets = stat3.s.bcst; + status->len_64_packets = stat4.s.h64; + status->len_65_127_packets = stat4.s.h65to127; + status->len_128_255_packets = stat5.s.h128to255; + status->len_256_511_packets = stat5.s.h256to511; + status->len_512_1023_packets = stat6.s.h512to1023; + status->len_1024_1518_packets = stat6.s.h1024to1518; + status->len_1519_max_packets = stat7.s.h1519; + status->fcs_align_err_packets = stat7.s.fcs; + status->runt_packets = stat8.s.undersz; + status->runt_crc_packets = stat8.s.frag; + status->oversize_packets = stat9.s.oversz; + status->oversize_crc_packets = stat9.s.jabber; + if (OCTEON_IS_OCTEON2() || OCTEON_IS_MODEL(OCTEON_CN70XX)) { + status->mcast_l2_red_packets = stat10.s.mcast; + status->bcast_l2_red_packets = stat10.s.bcast; + status->mcast_l3_red_packets = stat11.s.mcast; + status->bcast_l3_red_packets = stat11.s.bcast; + } + status->inb_packets = pip_stat_inb_pktsx.s.pkts; + status->inb_octets = pip_stat_inb_octsx.s.octs; + status->inb_errors = pip_stat_inb_errsx.s.errs; +} + +/** + * Get the status counters for a port. + * + * @param port_num Port number (ipd_port) to get statistics for. + * @param clear Set to 1 to clear the counters after they are read + * @param status Where to put the results. + */ +static inline void cvmx_pip_get_port_status(u64 port_num, u64 clear, cvmx_pip_port_status_t *status) +{ + if (octeon_has_feature(OCTEON_FEATURE_PKI)) { + unsigned int node = cvmx_get_node_num(); + + cvmx_pki_get_port_stats(node, port_num, (struct cvmx_pki_port_stats *)status); + } else { + cvmx_pip_get_port_stats(port_num, clear, status); + } +} + +/** + * Configure the hardware CRC engine + * + * @param interface Interface to configure (0 or 1) + * @param invert_result + * Invert the result of the CRC + * @param reflect Reflect + * @param initialization_vector + * CRC initialization vector + */ +static inline void cvmx_pip_config_crc(u64 interface, u64 invert_result, u64 reflect, + u32 initialization_vector) +{ + /* Only CN38XX & CN58XX */ +} + +/** + * Clear all bits in a tag mask. This should be called on + * startup before any calls to cvmx_pip_tag_mask_set. Each bit + * set in the final mask represent a byte used in the packet for + * tag generation. + * + * @param mask_index Which tag mask to clear (0..3) + */ +static inline void cvmx_pip_tag_mask_clear(u64 mask_index) +{ + u64 index; + cvmx_pip_tag_incx_t pip_tag_incx; + + pip_tag_incx.u64 = 0; + pip_tag_incx.s.en = 0; + for (index = mask_index * 16; index < (mask_index + 1) * 16; index++) + csr_wr(CVMX_PIP_TAG_INCX(index), pip_tag_incx.u64); +} + +/** + * Sets a range of bits in the tag mask. The tag mask is used + * when the cvmx_pip_port_tag_cfg_t tag_mode is non zero. + * There are four separate masks that can be configured. + * + * @param mask_index Which tag mask to modify (0..3) + * @param offset Offset into the bitmask to set bits at. Use the GCC macro + * offsetof() to determine the offsets into packet headers. + * For example, offsetof(ethhdr, protocol) returns the offset + * of the ethernet protocol field. The bitmask selects which bytes + * to include the the tag, with bit offset X selecting byte at offset X + * from the beginning of the packet data. + * @param len Number of bytes to include. Usually this is the sizeof() + * the field. + */ +static inline void cvmx_pip_tag_mask_set(u64 mask_index, u64 offset, u64 len) +{ + while (len--) { + cvmx_pip_tag_incx_t pip_tag_incx; + u64 index = mask_index * 16 + offset / 8; + + pip_tag_incx.u64 = csr_rd(CVMX_PIP_TAG_INCX(index)); + pip_tag_incx.s.en |= 0x80 >> (offset & 0x7); + csr_wr(CVMX_PIP_TAG_INCX(index), pip_tag_incx.u64); + offset++; + } +} + +/** + * Set byte count for Max-Sized and Min Sized frame check. + * + * @param interface Which interface to set the limit + * @param max_size Byte count for Max-Size frame check + */ +static inline void cvmx_pip_set_frame_check(int interface, u32 max_size) +{ + cvmx_pip_frm_len_chkx_t frm_len; + + /* max_size and min_size are passed as 0, reset to default values. */ + if (max_size < 1536) + max_size = 1536; + + /* On CN68XX frame check is enabled for a pkind n and + PIP_PRT_CFG[len_chk_sel] selects which set of + MAXLEN/MINLEN to use. */ + if (octeon_has_feature(OCTEON_FEATURE_PKND)) { + int port; + int num_ports = cvmx_helper_ports_on_interface(interface); + + for (port = 0; port < num_ports; port++) { + if (octeon_has_feature(OCTEON_FEATURE_PKI)) { + int ipd_port; + + ipd_port = cvmx_helper_get_ipd_port(interface, port); + cvmx_pki_set_max_frm_len(ipd_port, max_size); + } else { + int pknd; + int sel; + cvmx_pip_prt_cfgx_t config; + + pknd = cvmx_helper_get_pknd(interface, port); + config.u64 = csr_rd(CVMX_PIP_PRT_CFGX(pknd)); + sel = config.s.len_chk_sel; + frm_len.u64 = csr_rd(CVMX_PIP_FRM_LEN_CHKX(sel)); + frm_len.s.maxlen = max_size; + csr_wr(CVMX_PIP_FRM_LEN_CHKX(sel), frm_len.u64); + } + } + } + /* on cn6xxx and cn7xxx models, PIP_FRM_LEN_CHK0 applies to + * all incoming traffic */ + else if (OCTEON_IS_OCTEON2() || OCTEON_IS_MODEL(OCTEON_CN70XX)) { + frm_len.u64 = csr_rd(CVMX_PIP_FRM_LEN_CHKX(0)); + frm_len.s.maxlen = max_size; + csr_wr(CVMX_PIP_FRM_LEN_CHKX(0), frm_len.u64); + } +} + +/** + * Initialize Bit Select Extractor config. Their are 8 bit positions and valids + * to be used when using the corresponding extractor. + * + * @param bit Bit Select Extractor to use + * @param pos Which position to update + * @param val The value to update the position with + */ +static inline void cvmx_pip_set_bsel_pos(int bit, int pos, int val) +{ + cvmx_pip_bsel_ext_posx_t bsel_pos; + + /* The bit select extractor is available in CN61XX and CN68XX pass2.0 onwards. */ + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) + return; + + if (bit < 0 || bit > 3) { + debug("ERROR: cvmx_pip_set_bsel_pos: Invalid Bit-Select Extractor (%d) passed\n", + bit); + return; + } + + bsel_pos.u64 = csr_rd(CVMX_PIP_BSEL_EXT_POSX(bit)); + switch (pos) { + case 0: + bsel_pos.s.pos0_val = 1; + bsel_pos.s.pos0 = val & 0x7f; + break; + case 1: + bsel_pos.s.pos1_val = 1; + bsel_pos.s.pos1 = val & 0x7f; + break; + case 2: + bsel_pos.s.pos2_val = 1; + bsel_pos.s.pos2 = val & 0x7f; + break; + case 3: + bsel_pos.s.pos3_val = 1; + bsel_pos.s.pos3 = val & 0x7f; + break; + case 4: + bsel_pos.s.pos4_val = 1; + bsel_pos.s.pos4 = val & 0x7f; + break; + case 5: + bsel_pos.s.pos5_val = 1; + bsel_pos.s.pos5 = val & 0x7f; + break; + case 6: + bsel_pos.s.pos6_val = 1; + bsel_pos.s.pos6 = val & 0x7f; + break; + case 7: + bsel_pos.s.pos7_val = 1; + bsel_pos.s.pos7 = val & 0x7f; + break; + default: + debug("Warning: cvmx_pip_set_bsel_pos: Invalid pos(%d)\n", pos); + break; + } + csr_wr(CVMX_PIP_BSEL_EXT_POSX(bit), bsel_pos.u64); +} + +/** + * Initialize offset and skip values to use by bit select extractor. + + * @param bit Bit Select Extractor to use + * @param offset Offset to add to extractor mem addr to get final address + * to lookup table. + * @param skip Number of bytes to skip from start of packet 0-64 + */ +static inline void cvmx_pip_bsel_config(int bit, int offset, int skip) +{ + cvmx_pip_bsel_ext_cfgx_t bsel_cfg; + + /* The bit select extractor is available in CN61XX and CN68XX pass2.0 onwards. */ + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) + return; + + bsel_cfg.u64 = csr_rd(CVMX_PIP_BSEL_EXT_CFGX(bit)); + bsel_cfg.s.offset = offset; + bsel_cfg.s.skip = skip; + csr_wr(CVMX_PIP_BSEL_EXT_CFGX(bit), bsel_cfg.u64); +} + +/** + * Get the entry for the Bit Select Extractor Table. + * @param work pointer to work queue entry + * @return Index of the Bit Select Extractor Table + */ +static inline int cvmx_pip_get_bsel_table_index(cvmx_wqe_t *work) +{ + int bit = cvmx_wqe_get_port(work) & 0x3; + /* Get the Bit select table index. */ + int index; + int y; + cvmx_pip_bsel_ext_cfgx_t bsel_cfg; + cvmx_pip_bsel_ext_posx_t bsel_pos; + + /* The bit select extractor is available in CN61XX and CN68XX pass2.0 onwards. */ + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) + return -1; + + bsel_cfg.u64 = csr_rd(CVMX_PIP_BSEL_EXT_CFGX(bit)); + bsel_pos.u64 = csr_rd(CVMX_PIP_BSEL_EXT_POSX(bit)); + + for (y = 0; y < 8; y++) { + char *ptr = (char *)cvmx_phys_to_ptr(work->packet_ptr.s.addr); + int bit_loc = 0; + int bit; + + ptr += bsel_cfg.s.skip; + switch (y) { + case 0: + ptr += (bsel_pos.s.pos0 >> 3); + bit_loc = 7 - (bsel_pos.s.pos0 & 0x3); + break; + case 1: + ptr += (bsel_pos.s.pos1 >> 3); + bit_loc = 7 - (bsel_pos.s.pos1 & 0x3); + break; + case 2: + ptr += (bsel_pos.s.pos2 >> 3); + bit_loc = 7 - (bsel_pos.s.pos2 & 0x3); + break; + case 3: + ptr += (bsel_pos.s.pos3 >> 3); + bit_loc = 7 - (bsel_pos.s.pos3 & 0x3); + break; + case 4: + ptr += (bsel_pos.s.pos4 >> 3); + bit_loc = 7 - (bsel_pos.s.pos4 & 0x3); + break; + case 5: + ptr += (bsel_pos.s.pos5 >> 3); + bit_loc = 7 - (bsel_pos.s.pos5 & 0x3); + break; + case 6: + ptr += (bsel_pos.s.pos6 >> 3); + bit_loc = 7 - (bsel_pos.s.pos6 & 0x3); + break; + case 7: + ptr += (bsel_pos.s.pos7 >> 3); + bit_loc = 7 - (bsel_pos.s.pos7 & 0x3); + break; + } + bit = (*ptr >> bit_loc) & 1; + index |= bit << y; + } + index += bsel_cfg.s.offset; + index &= 0x1ff; + return index; +} + +static inline int cvmx_pip_get_bsel_qos(cvmx_wqe_t *work) +{ + int index = cvmx_pip_get_bsel_table_index(work); + cvmx_pip_bsel_tbl_entx_t bsel_tbl; + + /* The bit select extractor is available in CN61XX and CN68XX pass2.0 onwards. */ + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) + return -1; + + bsel_tbl.u64 = csr_rd(CVMX_PIP_BSEL_TBL_ENTX(index)); + + return bsel_tbl.s.qos; +} + +static inline int cvmx_pip_get_bsel_grp(cvmx_wqe_t *work) +{ + int index = cvmx_pip_get_bsel_table_index(work); + cvmx_pip_bsel_tbl_entx_t bsel_tbl; + + /* The bit select extractor is available in CN61XX and CN68XX pass2.0 onwards. */ + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) + return -1; + + bsel_tbl.u64 = csr_rd(CVMX_PIP_BSEL_TBL_ENTX(index)); + + return bsel_tbl.s.grp; +} + +static inline int cvmx_pip_get_bsel_tt(cvmx_wqe_t *work) +{ + int index = cvmx_pip_get_bsel_table_index(work); + cvmx_pip_bsel_tbl_entx_t bsel_tbl; + + /* The bit select extractor is available in CN61XX and CN68XX pass2.0 onwards. */ + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) + return -1; + + bsel_tbl.u64 = csr_rd(CVMX_PIP_BSEL_TBL_ENTX(index)); + + return bsel_tbl.s.tt; +} + +static inline int cvmx_pip_get_bsel_tag(cvmx_wqe_t *work) +{ + int index = cvmx_pip_get_bsel_table_index(work); + int port = cvmx_wqe_get_port(work); + int bit = port & 0x3; + int upper_tag = 0; + cvmx_pip_bsel_tbl_entx_t bsel_tbl; + cvmx_pip_bsel_ext_cfgx_t bsel_cfg; + cvmx_pip_prt_tagx_t prt_tag; + + /* The bit select extractor is available in CN61XX and CN68XX pass2.0 onwards. */ + if (!octeon_has_feature(OCTEON_FEATURE_BIT_EXTRACTOR)) + return -1; + + bsel_tbl.u64 = csr_rd(CVMX_PIP_BSEL_TBL_ENTX(index)); + bsel_cfg.u64 = csr_rd(CVMX_PIP_BSEL_EXT_CFGX(bit)); + + prt_tag.u64 = csr_rd(CVMX_PIP_PRT_TAGX(port)); + if (prt_tag.s.inc_prt_flag == 0) + upper_tag = bsel_cfg.s.upper_tag; + return bsel_tbl.s.tag | ((bsel_cfg.s.tag << 8) & 0xff00) | ((upper_tag << 16) & 0xffff0000); +} + +#endif /* __CVMX_PIP_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pki-resources.h b/arch/mips/mach-octeon/include/mach/cvmx-pki-resources.h new file mode 100644 index 000000000000..79b99b0bd7c2 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-pki-resources.h @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Resource management for PKI resources. + */ + +#ifndef __CVMX_PKI_RESOURCES_H__ +#define __CVMX_PKI_RESOURCES_H__ + +/** + * This function allocates/reserves a style from pool of global styles per node. + * @param node node to allocate style from. + * @param style style to allocate, if -1 it will be allocated + first available style from style resource. If index is positive + number and in range, it will try to allocate specified style. + * @return style number on success, -1 on failure. + */ +int cvmx_pki_style_alloc(int node, int style); + +/** + * This function allocates/reserves a cluster group from per node + cluster group resources. + * @param node node to allocate cluster group from. + @param cl_grp cluster group to allocate/reserve, if -1 , + allocate any available cluster group. + * @return cluster group number or -1 on failure + */ +int cvmx_pki_cluster_grp_alloc(int node, int cl_grp); + +/** + * This function allocates/reserves a cluster from per node + cluster resources. + * @param node node to allocate cluster group from. + @param cluster_mask mask of clusters to allocate/reserve, if -1 , + allocate any available clusters. + * @param num_clusters number of clusters that will be allocated + */ +int cvmx_pki_cluster_alloc(int node, int num_clusters, u64 *cluster_mask); + +/** + * This function allocates/reserves a pcam entry from node + * @param node node to allocate pcam entry from. + @param index index of pacm entry (0-191), if -1 , + allocate any available pcam entry. + * @param bank pcam bank where to allocate/reserve pcan entry from + * @param cluster_mask mask of clusters from which pcam entry is needed. + * @return pcam entry of -1 on failure + */ +int cvmx_pki_pcam_entry_alloc(int node, int index, int bank, u64 cluster_mask); + +/** + * This function allocates/reserves QPG table entries per node. + * @param node node number. + * @param base_offset base_offset in qpg table. If -1, first available + qpg base_offset will be allocated. If base_offset is positive + number and in range, it will try to allocate specified base_offset. + @param count number of consecutive qpg entries to allocate. They will be consecutive + from base offset. + * @return qpg table base offset number on success, -1 on failure. + */ +int cvmx_pki_qpg_entry_alloc(int node, int base_offset, int count); + +/** + * This function frees a style from pool of global styles per node. + * @param node node to free style from. + * @param style style to free + * @return 0 on success, -1 on failure. + */ +int cvmx_pki_style_free(int node, int style); + +/** + * This function frees a cluster group from per node + cluster group resources. + * @param node node to free cluster group from. + @param cl_grp cluster group to free + * @return 0 on success or -1 on failure + */ +int cvmx_pki_cluster_grp_free(int node, int cl_grp); + +/** + * This function frees QPG table entries per node. + * @param node node number. + * @param base_offset base_offset in qpg table. If -1, first available + * qpg base_offset will be allocated. If base_offset is positive + * number and in range, it will try to allocate specified base_offset. + * @param count number of consecutive qpg entries to allocate. They will be consecutive + * from base offset. + * @return qpg table base offset number on success, -1 on failure. + */ +int cvmx_pki_qpg_entry_free(int node, int base_offset, int count); + +/** + * This function frees clusters from per node + clusters resources. + * @param node node to free clusters from. + * @param cluster_mask mask of clusters need freeing + * @return 0 on success or -1 on failure + */ +int cvmx_pki_cluster_free(int node, u64 cluster_mask); + +/** + * This function frees a pcam entry from node + * @param node node to allocate pcam entry from. + @param index index of pacm entry (0-191) needs to be freed. + * @param bank pcam bank where to free pcam entry from + * @param cluster_mask mask of clusters from which pcam entry is freed. + * @return 0 on success OR -1 on failure + */ +int cvmx_pki_pcam_entry_free(int node, int index, int bank, u64 cluster_mask); + +/** + * This function allocates/reserves a bpid from pool of global bpid per node. + * @param node node to allocate bpid from. + * @param bpid bpid to allocate, if -1 it will be allocated + * first available boid from bpid resource. If index is positive + * number and in range, it will try to allocate specified bpid. + * @return bpid number on success, + * -1 on alloc failure. + * -2 on resource already reserved. + */ +int cvmx_pki_bpid_alloc(int node, int bpid); + +/** + * This function frees a bpid from pool of global bpid per node. + * @param node node to free bpid from. + * @param bpid bpid to free + * @return 0 on success, -1 on failure or + */ +int cvmx_pki_bpid_free(int node, int bpid); + +/** + * This function frees all the PKI software resources + * (clusters, styles, qpg_entry, pcam_entry etc) for the specified node + */ + +/** + * This function allocates/reserves an index from pool of global MTAG-IDX per node. + * @param node node to allocate index from. + * @param idx index to allocate, if -1 it will be allocated + * @return MTAG index number on success, + * -1 on alloc failure. + * -2 on resource already reserved. + */ +int cvmx_pki_mtag_idx_alloc(int node, int idx); + +/** + * This function frees an index from pool of global MTAG-IDX per node. + * @param node node to free bpid from. + * @param bpid bpid to free + * @return 0 on success, -1 on failure or + */ +int cvmx_pki_mtag_idx_free(int node, int idx); + +void __cvmx_pki_global_rsrc_free(int node); + +#endif /* __CVM_PKI_RESOURCES_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pki.h b/arch/mips/mach-octeon/include/mach/cvmx-pki.h new file mode 100644 index 000000000000..c1feb55a1f01 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-pki.h @@ -0,0 +1,970 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Interface to the hardware Packet Input Data unit. + */ + +#ifndef __CVMX_PKI_H__ +#define __CVMX_PKI_H__ + +#include "cvmx-fpa3.h" +#include "cvmx-helper-util.h" +#include "cvmx-helper-cfg.h" +#include "cvmx-error.h" + +/* PKI AURA and BPID count are equal to FPA AURA count */ +#define CVMX_PKI_NUM_AURA (cvmx_fpa3_num_auras()) +#define CVMX_PKI_NUM_BPID (cvmx_fpa3_num_auras()) +#define CVMX_PKI_NUM_SSO_GROUP (cvmx_sso_num_xgrp()) +#define CVMX_PKI_NUM_CLUSTER_GROUP_MAX 1 +#define CVMX_PKI_NUM_CLUSTER_GROUP (cvmx_pki_num_cl_grp()) +#define CVMX_PKI_NUM_CLUSTER (cvmx_pki_num_clusters()) + +/* FIXME: Reduce some of these values, convert to routines XXX */ +#define CVMX_PKI_NUM_CHANNEL 4096 +#define CVMX_PKI_NUM_PKIND 64 +#define CVMX_PKI_NUM_INTERNAL_STYLE 256 +#define CVMX_PKI_NUM_FINAL_STYLE 64 +#define CVMX_PKI_NUM_QPG_ENTRY 2048 +#define CVMX_PKI_NUM_MTAG_IDX (32 / 4) /* 32 registers grouped by 4*/ +#define CVMX_PKI_NUM_LTYPE 32 +#define CVMX_PKI_NUM_PCAM_BANK 2 +#define CVMX_PKI_NUM_PCAM_ENTRY 192 +#define CVMX_PKI_NUM_FRAME_CHECK 2 +#define CVMX_PKI_NUM_BELTYPE 32 +#define CVMX_PKI_MAX_FRAME_SIZE 65535 +#define CVMX_PKI_FIND_AVAL_ENTRY (-1) +#define CVMX_PKI_CLUSTER_ALL 0xf + +#ifdef CVMX_SUPPORT_SEPARATE_CLUSTER_CONFIG +#define CVMX_PKI_TOTAL_PCAM_ENTRY \ + ((CVMX_PKI_NUM_CLUSTER) * (CVMX_PKI_NUM_PCAM_BANK) * (CVMX_PKI_NUM_PCAM_ENTRY)) +#else +#define CVMX_PKI_TOTAL_PCAM_ENTRY (CVMX_PKI_NUM_PCAM_BANK * CVMX_PKI_NUM_PCAM_ENTRY) +#endif + +static inline unsigned int cvmx_pki_num_clusters(void) +{ + if (OCTEON_IS_MODEL(OCTEON_CN73XX) || OCTEON_IS_MODEL(OCTEON_CNF75XX)) + return 2; + return 4; +} + +static inline unsigned int cvmx_pki_num_cl_grp(void) +{ + if (OCTEON_IS_MODEL(OCTEON_CN73XX) || OCTEON_IS_MODEL(OCTEON_CNF75XX) || + OCTEON_IS_MODEL(OCTEON_CN78XX)) + return 1; + return 0; +} + +enum cvmx_pki_pkind_parse_mode { + CVMX_PKI_PARSE_LA_TO_LG = 0, /* Parse LA(L2) to LG */ + CVMX_PKI_PARSE_LB_TO_LG = 1, /* Parse LB(custom) to LG */ + CVMX_PKI_PARSE_LC_TO_LG = 3, /* Parse LC(L3) to LG */ + CVMX_PKI_PARSE_LG = 0x3f, /* Parse LG */ + CVMX_PKI_PARSE_NOTHING = 0x7f /* Parse nothing */ +}; + +enum cvmx_pki_parse_mode_chg { + CVMX_PKI_PARSE_NO_CHG = 0x0, + CVMX_PKI_PARSE_SKIP_TO_LB = 0x1, + CVMX_PKI_PARSE_SKIP_TO_LC = 0x3, + CVMX_PKI_PARSE_SKIP_TO_LD = 0x7, + CVMX_PKI_PARSE_SKIP_TO_LG = 0x3f, + CVMX_PKI_PARSE_SKIP_ALL = 0x7f, +}; + +enum cvmx_pki_l2_len_mode { PKI_L2_LENCHK_EQUAL_GREATER = 0, PKI_L2_LENCHK_EQUAL_ONLY }; + +enum cvmx_pki_cache_mode { + CVMX_PKI_OPC_MODE_STT = 0LL, /* All blocks write through DRAM,*/ + CVMX_PKI_OPC_MODE_STF = 1LL, /* All blocks into L2 */ + CVMX_PKI_OPC_MODE_STF1_STT = 2LL, /* 1st block L2, rest DRAM */ + CVMX_PKI_OPC_MODE_STF2_STT = 3LL /* 1st, 2nd blocks L2, rest DRAM */ +}; + +/** + * Tag type definitions + */ +enum cvmx_sso_tag_type { + CVMX_SSO_TAG_TYPE_ORDERED = 0L, + CVMX_SSO_TAG_TYPE_ATOMIC = 1L, + CVMX_SSO_TAG_TYPE_UNTAGGED = 2L, + CVMX_SSO_TAG_TYPE_EMPTY = 3L +}; + +enum cvmx_pki_qpg_qos { + CVMX_PKI_QPG_QOS_NONE = 0, + CVMX_PKI_QPG_QOS_VLAN, + CVMX_PKI_QPG_QOS_MPLS, + CVMX_PKI_QPG_QOS_DSA_SRC, + CVMX_PKI_QPG_QOS_DIFFSERV, + CVMX_PKI_QPG_QOS_HIGIG, +}; + +enum cvmx_pki_wqe_vlan { CVMX_PKI_USE_FIRST_VLAN = 0, CVMX_PKI_USE_SECOND_VLAN }; + +/** + * Controls how the PKI statistics counters are handled + * The PKI_STAT*_X registers can be indexed either by port kind (pkind), or + * final style. (Does not apply to the PKI_STAT_INB* registers.) + * 0 = X represents the packet’s pkind + * 1 = X represents the low 6-bits of packet’s final style + */ +enum cvmx_pki_stats_mode { CVMX_PKI_STAT_MODE_PKIND, CVMX_PKI_STAT_MODE_STYLE }; + +enum cvmx_pki_fpa_wait { CVMX_PKI_DROP_PKT, CVMX_PKI_WAIT_PKT }; + +#define PKI_BELTYPE_E__NONE_M 0x0 +#define PKI_BELTYPE_E__MISC_M 0x1 +#define PKI_BELTYPE_E__IP4_M 0x2 +#define PKI_BELTYPE_E__IP6_M 0x3 +#define PKI_BELTYPE_E__TCP_M 0x4 +#define PKI_BELTYPE_E__UDP_M 0x5 +#define PKI_BELTYPE_E__SCTP_M 0x6 +#define PKI_BELTYPE_E__SNAP_M 0x7 + +/* PKI_BELTYPE_E_t */ +enum cvmx_pki_beltype { + CVMX_PKI_BELTYPE_NONE = PKI_BELTYPE_E__NONE_M, + CVMX_PKI_BELTYPE_MISC = PKI_BELTYPE_E__MISC_M, + CVMX_PKI_BELTYPE_IP4 = PKI_BELTYPE_E__IP4_M, + CVMX_PKI_BELTYPE_IP6 = PKI_BELTYPE_E__IP6_M, + CVMX_PKI_BELTYPE_TCP = PKI_BELTYPE_E__TCP_M, + CVMX_PKI_BELTYPE_UDP = PKI_BELTYPE_E__UDP_M, + CVMX_PKI_BELTYPE_SCTP = PKI_BELTYPE_E__SCTP_M, + CVMX_PKI_BELTYPE_SNAP = PKI_BELTYPE_E__SNAP_M, + CVMX_PKI_BELTYPE_MAX = CVMX_PKI_BELTYPE_SNAP +}; + +struct cvmx_pki_frame_len { + u16 maxlen; + u16 minlen; +}; + +struct cvmx_pki_tag_fields { + u64 layer_g_src : 1; + u64 layer_f_src : 1; + u64 layer_e_src : 1; + u64 layer_d_src : 1; + u64 layer_c_src : 1; + u64 layer_b_src : 1; + u64 layer_g_dst : 1; + u64 layer_f_dst : 1; + u64 layer_e_dst : 1; + u64 layer_d_dst : 1; + u64 layer_c_dst : 1; + u64 layer_b_dst : 1; + u64 input_port : 1; + u64 mpls_label : 1; + u64 first_vlan : 1; + u64 second_vlan : 1; + u64 ip_prot_nexthdr : 1; + u64 tag_sync : 1; + u64 tag_spi : 1; + u64 tag_gtp : 1; + u64 tag_vni : 1; +}; + +struct cvmx_pki_pkind_parse { + u64 mpls_en : 1; + u64 inst_hdr : 1; + u64 lg_custom : 1; + u64 fulc_en : 1; + u64 dsa_en : 1; + u64 hg2_en : 1; + u64 hg_en : 1; +}; + +struct cvmx_pki_pool_config { + int pool_num; + cvmx_fpa3_pool_t pool; + u64 buffer_size; + u64 buffer_count; +}; + +struct cvmx_pki_qpg_config { + int qpg_base; + int port_add; + int aura_num; + int grp_ok; + int grp_bad; + int grptag_ok; + int grptag_bad; +}; + +struct cvmx_pki_aura_config { + int aura_num; + int pool_num; + cvmx_fpa3_pool_t pool; + cvmx_fpa3_gaura_t aura; + int buffer_count; +}; + +struct cvmx_pki_cluster_grp_config { + int grp_num; + u64 cluster_mask; /* Bit mask of cluster assigned to this cluster group */ +}; + +struct cvmx_pki_sso_grp_config { + int group; + int priority; + int weight; + int affinity; + u64 core_mask; + u8 core_mask_set; +}; + +/* This is per style structure for configuring port parameters, + * it is kind of of profile which can be assigned to any port. + * If multiple ports are assigned same style be aware that modifying + * that style will modify the respective parameters for all the ports + * which are using this style + */ +struct cvmx_pki_style_parm { + bool ip6_udp_opt; + bool lenerr_en; + bool maxerr_en; + bool minerr_en; + u8 lenerr_eqpad; + u8 minmax_sel; + bool qpg_dis_grptag; + bool fcs_strip; + bool fcs_chk; + bool rawdrp; + bool force_drop; + bool nodrop; + bool qpg_dis_padd; + bool qpg_dis_grp; + bool qpg_dis_aura; + u16 qpg_base; + enum cvmx_pki_qpg_qos qpg_qos; + u8 qpg_port_sh; + u8 qpg_port_msb; + u8 apad_nip; + u8 wqe_vs; + enum cvmx_sso_tag_type tag_type; + bool pkt_lend; + u8 wqe_hsz; + u16 wqe_skip; + u16 first_skip; + u16 later_skip; + enum cvmx_pki_cache_mode cache_mode; + u8 dis_wq_dat; + u64 mbuff_size; + bool len_lg; + bool len_lf; + bool len_le; + bool len_ld; + bool len_lc; + bool len_lb; + bool csum_lg; + bool csum_lf; + bool csum_le; + bool csum_ld; + bool csum_lc; + bool csum_lb; +}; + +/* This is per style structure for configuring port's tag configuration, + * it is kind of of profile which can be assigned to any port. + * If multiple ports are assigned same style be aware that modiying that style + * will modify the respective parameters for all the ports which are + * using this style */ +enum cvmx_pki_mtag_ptrsel { + CVMX_PKI_MTAG_PTRSEL_SOP = 0, + CVMX_PKI_MTAG_PTRSEL_LA = 8, + CVMX_PKI_MTAG_PTRSEL_LB = 9, + CVMX_PKI_MTAG_PTRSEL_LC = 10, + CVMX_PKI_MTAG_PTRSEL_LD = 11, + CVMX_PKI_MTAG_PTRSEL_LE = 12, + CVMX_PKI_MTAG_PTRSEL_LF = 13, + CVMX_PKI_MTAG_PTRSEL_LG = 14, + CVMX_PKI_MTAG_PTRSEL_VL = 15, +}; + +struct cvmx_pki_mask_tag { + bool enable; + int base; /* CVMX_PKI_MTAG_PTRSEL_XXX */ + int offset; /* Offset from base. */ + u64 val; /* Bitmask: + 1 = enable, 0 = disabled for each byte in the 64-byte array.*/ +}; + +struct cvmx_pki_style_tag_cfg { + struct cvmx_pki_tag_fields tag_fields; + struct cvmx_pki_mask_tag mask_tag[4]; +}; + +struct cvmx_pki_style_config { + struct cvmx_pki_style_parm parm_cfg; + struct cvmx_pki_style_tag_cfg tag_cfg; +}; + +struct cvmx_pki_pkind_config { + u8 cluster_grp; + bool fcs_pres; + struct cvmx_pki_pkind_parse parse_en; + enum cvmx_pki_pkind_parse_mode initial_parse_mode; + u8 fcs_skip; + u8 inst_skip; + int initial_style; + bool custom_l2_hdr; + u8 l2_scan_offset; + u64 lg_scan_offset; +}; + +struct cvmx_pki_port_config { + struct cvmx_pki_pkind_config pkind_cfg; + struct cvmx_pki_style_config style_cfg; +}; + +struct cvmx_pki_global_parse { + u64 virt_pen : 1; + u64 clg_pen : 1; + u64 cl2_pen : 1; + u64 l4_pen : 1; + u64 il3_pen : 1; + u64 l3_pen : 1; + u64 mpls_pen : 1; + u64 fulc_pen : 1; + u64 dsa_pen : 1; + u64 hg_pen : 1; +}; + +struct cvmx_pki_tag_sec { + u16 dst6; + u16 src6; + u16 dst; + u16 src; +}; + +struct cvmx_pki_global_config { + u64 cluster_mask[CVMX_PKI_NUM_CLUSTER_GROUP_MAX]; + enum cvmx_pki_stats_mode stat_mode; + enum cvmx_pki_fpa_wait fpa_wait; + struct cvmx_pki_global_parse gbl_pen; + struct cvmx_pki_tag_sec tag_secret; + struct cvmx_pki_frame_len frm_len[CVMX_PKI_NUM_FRAME_CHECK]; + enum cvmx_pki_beltype ltype_map[CVMX_PKI_NUM_BELTYPE]; + int pki_enable; +}; + +#define CVMX_PKI_PCAM_TERM_E_NONE_M 0x0 +#define CVMX_PKI_PCAM_TERM_E_L2_CUSTOM_M 0x2 +#define CVMX_PKI_PCAM_TERM_E_HIGIGD_M 0x4 +#define CVMX_PKI_PCAM_TERM_E_HIGIG_M 0x5 +#define CVMX_PKI_PCAM_TERM_E_SMACH_M 0x8 +#define CVMX_PKI_PCAM_TERM_E_SMACL_M 0x9 +#define CVMX_PKI_PCAM_TERM_E_DMACH_M 0xA +#define CVMX_PKI_PCAM_TERM_E_DMACL_M 0xB +#define CVMX_PKI_PCAM_TERM_E_GLORT_M 0x12 +#define CVMX_PKI_PCAM_TERM_E_DSA_M 0x13 +#define CVMX_PKI_PCAM_TERM_E_ETHTYPE0_M 0x18 +#define CVMX_PKI_PCAM_TERM_E_ETHTYPE1_M 0x19 +#define CVMX_PKI_PCAM_TERM_E_ETHTYPE2_M 0x1A +#define CVMX_PKI_PCAM_TERM_E_ETHTYPE3_M 0x1B +#define CVMX_PKI_PCAM_TERM_E_MPLS0_M 0x1E +#define CVMX_PKI_PCAM_TERM_E_L3_SIPHH_M 0x1F +#define CVMX_PKI_PCAM_TERM_E_L3_SIPMH_M 0x20 +#define CVMX_PKI_PCAM_TERM_E_L3_SIPML_M 0x21 +#define CVMX_PKI_PCAM_TERM_E_L3_SIPLL_M 0x22 +#define CVMX_PKI_PCAM_TERM_E_L3_FLAGS_M 0x23 +#define CVMX_PKI_PCAM_TERM_E_L3_DIPHH_M 0x24 +#define CVMX_PKI_PCAM_TERM_E_L3_DIPMH_M 0x25 +#define CVMX_PKI_PCAM_TERM_E_L3_DIPML_M 0x26 +#define CVMX_PKI_PCAM_TERM_E_L3_DIPLL_M 0x27 +#define CVMX_PKI_PCAM_TERM_E_LD_VNI_M 0x28 +#define CVMX_PKI_PCAM_TERM_E_IL3_FLAGS_M 0x2B +#define CVMX_PKI_PCAM_TERM_E_LF_SPI_M 0x2E +#define CVMX_PKI_PCAM_TERM_E_L4_SPORT_M 0x2f +#define CVMX_PKI_PCAM_TERM_E_L4_PORT_M 0x30 +#define CVMX_PKI_PCAM_TERM_E_LG_CUSTOM_M 0x39 + +enum cvmx_pki_term { + CVMX_PKI_PCAM_TERM_NONE = CVMX_PKI_PCAM_TERM_E_NONE_M, + CVMX_PKI_PCAM_TERM_L2_CUSTOM = CVMX_PKI_PCAM_TERM_E_L2_CUSTOM_M, + CVMX_PKI_PCAM_TERM_HIGIGD = CVMX_PKI_PCAM_TERM_E_HIGIGD_M, + CVMX_PKI_PCAM_TERM_HIGIG = CVMX_PKI_PCAM_TERM_E_HIGIG_M, + CVMX_PKI_PCAM_TERM_SMACH = CVMX_PKI_PCAM_TERM_E_SMACH_M, + CVMX_PKI_PCAM_TERM_SMACL = CVMX_PKI_PCAM_TERM_E_SMACL_M, + CVMX_PKI_PCAM_TERM_DMACH = CVMX_PKI_PCAM_TERM_E_DMACH_M, + CVMX_PKI_PCAM_TERM_DMACL = CVMX_PKI_PCAM_TERM_E_DMACL_M, + CVMX_PKI_PCAM_TERM_GLORT = CVMX_PKI_PCAM_TERM_E_GLORT_M, + CVMX_PKI_PCAM_TERM_DSA = CVMX_PKI_PCAM_TERM_E_DSA_M, + CVMX_PKI_PCAM_TERM_ETHTYPE0 = CVMX_PKI_PCAM_TERM_E_ETHTYPE0_M, + CVMX_PKI_PCAM_TERM_ETHTYPE1 = CVMX_PKI_PCAM_TERM_E_ETHTYPE1_M, + CVMX_PKI_PCAM_TERM_ETHTYPE2 = CVMX_PKI_PCAM_TERM_E_ETHTYPE2_M, + CVMX_PKI_PCAM_TERM_ETHTYPE3 = CVMX_PKI_PCAM_TERM_E_ETHTYPE3_M, + CVMX_PKI_PCAM_TERM_MPLS0 = CVMX_PKI_PCAM_TERM_E_MPLS0_M, + CVMX_PKI_PCAM_TERM_L3_SIPHH = CVMX_PKI_PCAM_TERM_E_L3_SIPHH_M, + CVMX_PKI_PCAM_TERM_L3_SIPMH = CVMX_PKI_PCAM_TERM_E_L3_SIPMH_M, + CVMX_PKI_PCAM_TERM_L3_SIPML = CVMX_PKI_PCAM_TERM_E_L3_SIPML_M, + CVMX_PKI_PCAM_TERM_L3_SIPLL = CVMX_PKI_PCAM_TERM_E_L3_SIPLL_M, + CVMX_PKI_PCAM_TERM_L3_FLAGS = CVMX_PKI_PCAM_TERM_E_L3_FLAGS_M, + CVMX_PKI_PCAM_TERM_L3_DIPHH = CVMX_PKI_PCAM_TERM_E_L3_DIPHH_M, + CVMX_PKI_PCAM_TERM_L3_DIPMH = CVMX_PKI_PCAM_TERM_E_L3_DIPMH_M, + CVMX_PKI_PCAM_TERM_L3_DIPML = CVMX_PKI_PCAM_TERM_E_L3_DIPML_M, + CVMX_PKI_PCAM_TERM_L3_DIPLL = CVMX_PKI_PCAM_TERM_E_L3_DIPLL_M, + CVMX_PKI_PCAM_TERM_LD_VNI = CVMX_PKI_PCAM_TERM_E_LD_VNI_M, + CVMX_PKI_PCAM_TERM_IL3_FLAGS = CVMX_PKI_PCAM_TERM_E_IL3_FLAGS_M, + CVMX_PKI_PCAM_TERM_LF_SPI = CVMX_PKI_PCAM_TERM_E_LF_SPI_M, + CVMX_PKI_PCAM_TERM_L4_PORT = CVMX_PKI_PCAM_TERM_E_L4_PORT_M, + CVMX_PKI_PCAM_TERM_L4_SPORT = CVMX_PKI_PCAM_TERM_E_L4_SPORT_M, + CVMX_PKI_PCAM_TERM_LG_CUSTOM = CVMX_PKI_PCAM_TERM_E_LG_CUSTOM_M +}; + +#define CVMX_PKI_DMACH_SHIFT 32 +#define CVMX_PKI_DMACH_MASK cvmx_build_mask(16) +#define CVMX_PKI_DMACL_MASK CVMX_PKI_DATA_MASK_32 +#define CVMX_PKI_DATA_MASK_32 cvmx_build_mask(32) +#define CVMX_PKI_DATA_MASK_16 cvmx_build_mask(16) +#define CVMX_PKI_DMAC_MATCH_EXACT cvmx_build_mask(48) + +struct cvmx_pki_pcam_input { + u64 style; + u64 style_mask; /* bits: 1-match, 0-dont care */ + enum cvmx_pki_term field; + u32 field_mask; /* bits: 1-match, 0-dont care */ + u64 data; + u64 data_mask; /* bits: 1-match, 0-dont care */ +}; + +struct cvmx_pki_pcam_action { + enum cvmx_pki_parse_mode_chg parse_mode_chg; + enum cvmx_pki_layer_type layer_type_set; + int style_add; + int parse_flag_set; + int pointer_advance; +}; + +struct cvmx_pki_pcam_config { + int in_use; + int entry_num; + u64 cluster_mask; + struct cvmx_pki_pcam_input pcam_input; + struct cvmx_pki_pcam_action pcam_action; +}; + +/** + * Status statistics for a port + */ +struct cvmx_pki_port_stats { + u64 dropped_octets; + u64 dropped_packets; + u64 pci_raw_packets; + u64 octets; + u64 packets; + u64 multicast_packets; + u64 broadcast_packets; + u64 len_64_packets; + u64 len_65_127_packets; + u64 len_128_255_packets; + u64 len_256_511_packets; + u64 len_512_1023_packets; + u64 len_1024_1518_packets; + u64 len_1519_max_packets; + u64 fcs_align_err_packets; + u64 runt_packets; + u64 runt_crc_packets; + u64 oversize_packets; + u64 oversize_crc_packets; + u64 inb_packets; + u64 inb_octets; + u64 inb_errors; + u64 mcast_l2_red_packets; + u64 bcast_l2_red_packets; + u64 mcast_l3_red_packets; + u64 bcast_l3_red_packets; +}; + +/** + * PKI Packet Instruction Header Structure (PKI_INST_HDR_S) + */ +typedef union { + u64 u64; + struct { + u64 w : 1; /* INST_HDR size: 0 = 2 bytes, 1 = 4 or 8 bytes */ + u64 raw : 1; /* RAW packet indicator in WQE[RAW]: 1 = enable */ + u64 utag : 1; /* Use INST_HDR[TAG] to compute WQE[TAG]: 1 = enable */ + u64 uqpg : 1; /* Use INST_HDR[QPG] to compute QPG: 1 = enable */ + u64 rsvd1 : 1; + u64 pm : 3; /* Packet parsing mode. Legal values = 0x0..0x7 */ + u64 sl : 8; /* Number of bytes in INST_HDR. */ + /* The following fields are not present, if INST_HDR[W] = 0: */ + u64 utt : 1; /* Use INST_HDR[TT] to compute WQE[TT]: 1 = enable */ + u64 tt : 2; /* INST_HDR[TT] => WQE[TT], if INST_HDR[UTT] = 1 */ + u64 rsvd2 : 2; + u64 qpg : 11; /* INST_HDR[QPG] => QPG, if INST_HDR[UQPG] = 1 */ + u64 tag : 32; /* INST_HDR[TAG] => WQE[TAG], if INST_HDR[UTAG] = 1 */ + } s; +} cvmx_pki_inst_hdr_t; + +/** + * This function assignes the clusters to a group, later pkind can be + * configured to use that group depending on number of clusters pkind + * would use. A given cluster can only be enabled in a single cluster group. + * Number of clusters assign to that group determines how many engine can work + * in parallel to process the packet. Eack cluster can process x MPPS. + * + * @param node Node + * @param cluster_group Group to attach clusters to. + * @param cluster_mask The mask of clusters which needs to be assigned to the group. + */ +static inline int cvmx_pki_attach_cluster_to_group(int node, u64 cluster_group, u64 cluster_mask) +{ + cvmx_pki_icgx_cfg_t pki_cl_grp; + + if (cluster_group >= CVMX_PKI_NUM_CLUSTER_GROUP) { + debug("ERROR: config cluster group %d", (int)cluster_group); + return -1; + } + pki_cl_grp.u64 = cvmx_read_csr_node(node, CVMX_PKI_ICGX_CFG(cluster_group)); + pki_cl_grp.s.clusters = cluster_mask; + cvmx_write_csr_node(node, CVMX_PKI_ICGX_CFG(cluster_group), pki_cl_grp.u64); + return 0; +} + +static inline void cvmx_pki_write_global_parse(int node, struct cvmx_pki_global_parse gbl_pen) +{ + cvmx_pki_gbl_pen_t gbl_pen_reg; + + gbl_pen_reg.u64 = cvmx_read_csr_node(node, CVMX_PKI_GBL_PEN); + gbl_pen_reg.s.virt_pen = gbl_pen.virt_pen; + gbl_pen_reg.s.clg_pen = gbl_pen.clg_pen; + gbl_pen_reg.s.cl2_pen = gbl_pen.cl2_pen; + gbl_pen_reg.s.l4_pen = gbl_pen.l4_pen; + gbl_pen_reg.s.il3_pen = gbl_pen.il3_pen; + gbl_pen_reg.s.l3_pen = gbl_pen.l3_pen; + gbl_pen_reg.s.mpls_pen = gbl_pen.mpls_pen; + gbl_pen_reg.s.fulc_pen = gbl_pen.fulc_pen; + gbl_pen_reg.s.dsa_pen = gbl_pen.dsa_pen; + gbl_pen_reg.s.hg_pen = gbl_pen.hg_pen; + cvmx_write_csr_node(node, CVMX_PKI_GBL_PEN, gbl_pen_reg.u64); +} + +static inline void cvmx_pki_write_tag_secret(int node, struct cvmx_pki_tag_sec tag_secret) +{ + cvmx_pki_tag_secret_t tag_secret_reg; + + tag_secret_reg.u64 = cvmx_read_csr_node(node, CVMX_PKI_TAG_SECRET); + tag_secret_reg.s.dst6 = tag_secret.dst6; + tag_secret_reg.s.src6 = tag_secret.src6; + tag_secret_reg.s.dst = tag_secret.dst; + tag_secret_reg.s.src = tag_secret.src; + cvmx_write_csr_node(node, CVMX_PKI_TAG_SECRET, tag_secret_reg.u64); +} + +static inline void cvmx_pki_write_ltype_map(int node, enum cvmx_pki_layer_type layer, + enum cvmx_pki_beltype backend) +{ + cvmx_pki_ltypex_map_t ltype_map; + + if (layer > CVMX_PKI_LTYPE_E_MAX || backend > CVMX_PKI_BELTYPE_MAX) { + debug("ERROR: invalid ltype beltype mapping\n"); + return; + } + ltype_map.u64 = cvmx_read_csr_node(node, CVMX_PKI_LTYPEX_MAP(layer)); + ltype_map.s.beltype = backend; + cvmx_write_csr_node(node, CVMX_PKI_LTYPEX_MAP(layer), ltype_map.u64); +} + +/** + * This function enables the cluster group to start parsing. + * + * @param node Node number. + * @param cl_grp Cluster group to enable parsing. + */ +static inline int cvmx_pki_parse_enable(int node, unsigned int cl_grp) +{ + cvmx_pki_icgx_cfg_t pki_cl_grp; + + if (cl_grp >= CVMX_PKI_NUM_CLUSTER_GROUP) { + debug("ERROR: pki parse en group %d", (int)cl_grp); + return -1; + } + pki_cl_grp.u64 = cvmx_read_csr_node(node, CVMX_PKI_ICGX_CFG(cl_grp)); + pki_cl_grp.s.pena = 1; + cvmx_write_csr_node(node, CVMX_PKI_ICGX_CFG(cl_grp), pki_cl_grp.u64); + return 0; +} + +/** + * This function enables the PKI to send bpid level backpressure to CN78XX inputs. + * + * @param node Node number. + */ +static inline void cvmx_pki_enable_backpressure(int node) +{ + cvmx_pki_buf_ctl_t pki_buf_ctl; + + pki_buf_ctl.u64 = cvmx_read_csr_node(node, CVMX_PKI_BUF_CTL); + pki_buf_ctl.s.pbp_en = 1; + cvmx_write_csr_node(node, CVMX_PKI_BUF_CTL, pki_buf_ctl.u64); +} + +/** + * Clear the statistics counters for a port. + * + * @param node Node number. + * @param port Port number (ipd_port) to get statistics for. + * Make sure PKI_STATS_CTL:mode is set to 0 for collecting per port/pkind stats. + */ +void cvmx_pki_clear_port_stats(int node, u64 port); + +/** + * Get the status counters for index from PKI. + * + * @param node Node number. + * @param index PKIND number, if PKI_STATS_CTL:mode = 0 or + * style(flow) number, if PKI_STATS_CTL:mode = 1 + * @param status Where to put the results. + */ +void cvmx_pki_get_stats(int node, int index, struct cvmx_pki_port_stats *status); + +/** + * Get the statistics counters for a port. + * + * @param node Node number + * @param port Port number (ipd_port) to get statistics for. + * Make sure PKI_STATS_CTL:mode is set to 0 for collecting per port/pkind stats. + * @param status Where to put the results. + */ +static inline void cvmx_pki_get_port_stats(int node, u64 port, struct cvmx_pki_port_stats *status) +{ + int xipd = cvmx_helper_node_to_ipd_port(node, port); + int xiface = cvmx_helper_get_interface_num(xipd); + int index = cvmx_helper_get_interface_index_num(port); + int pknd = cvmx_helper_get_pknd(xiface, index); + + cvmx_pki_get_stats(node, pknd, status); +} + +/** + * Get the statistics counters for a flow represented by style in PKI. + * + * @param node Node number. + * @param style_num Style number to get statistics for. + * Make sure PKI_STATS_CTL:mode is set to 1 for collecting per style/flow stats. + * @param status Where to put the results. + */ +static inline void cvmx_pki_get_flow_stats(int node, u64 style_num, + struct cvmx_pki_port_stats *status) +{ + cvmx_pki_get_stats(node, style_num, status); +} + +/** + * Show integrated PKI configuration. + * + * @param node node number + */ +int cvmx_pki_config_dump(unsigned int node); + +/** + * Show integrated PKI statistics. + * + * @param node node number + */ +int cvmx_pki_stats_dump(unsigned int node); + +/** + * Clear PKI statistics. + * + * @param node node number + */ +void cvmx_pki_stats_clear(unsigned int node); + +/** + * This function enables PKI. + * + * @param node node to enable pki in. + */ +void cvmx_pki_enable(int node); + +/** + * This function disables PKI. + * + * @param node node to disable pki in. + */ +void cvmx_pki_disable(int node); + +/** + * This function soft resets PKI. + * + * @param node node to enable pki in. + */ +void cvmx_pki_reset(int node); + +/** + * This function sets the clusters in PKI. + * + * @param node node to set clusters in. + */ +int cvmx_pki_setup_clusters(int node); + +/** + * This function reads global configuration of PKI block. + * + * @param node Node number. + * @param gbl_cfg Pointer to struct to read global configuration + */ +void cvmx_pki_read_global_config(int node, struct cvmx_pki_global_config *gbl_cfg); + +/** + * This function writes global configuration of PKI into hw. + * + * @param node Node number. + * @param gbl_cfg Pointer to struct to global configuration + */ +void cvmx_pki_write_global_config(int node, struct cvmx_pki_global_config *gbl_cfg); + +/** + * This function reads per pkind parameters in hardware which defines how + * the incoming packet is processed. + * + * @param node Node number. + * @param pkind PKI supports a large number of incoming interfaces and packets + * arriving on different interfaces or channels may want to be processed + * differently. PKI uses the pkind to determine how the incoming packet + * is processed. + * @param pkind_cfg Pointer to struct conatining pkind configuration read + * from hardware. + */ +int cvmx_pki_read_pkind_config(int node, int pkind, struct cvmx_pki_pkind_config *pkind_cfg); + +/** + * This function writes per pkind parameters in hardware which defines how + * the incoming packet is processed. + * + * @param node Node number. + * @param pkind PKI supports a large number of incoming interfaces and packets + * arriving on different interfaces or channels may want to be processed + * differently. PKI uses the pkind to determine how the incoming packet + * is processed. + * @param pkind_cfg Pointer to struct conatining pkind configuration need + * to be written in hardware. + */ +int cvmx_pki_write_pkind_config(int node, int pkind, struct cvmx_pki_pkind_config *pkind_cfg); + +/** + * This function reads parameters associated with tag configuration in hardware. + * + * @param node Node number. + * @param style Style to configure tag for. + * @param cluster_mask Mask of clusters to configure the style for. + * @param tag_cfg Pointer to tag configuration struct. + */ +void cvmx_pki_read_tag_config(int node, int style, u64 cluster_mask, + struct cvmx_pki_style_tag_cfg *tag_cfg); + +/** + * This function writes/configures parameters associated with tag + * configuration in hardware. + * + * @param node Node number. + * @param style Style to configure tag for. + * @param cluster_mask Mask of clusters to configure the style for. + * @param tag_cfg Pointer to taf configuration struct. + */ +void cvmx_pki_write_tag_config(int node, int style, u64 cluster_mask, + struct cvmx_pki_style_tag_cfg *tag_cfg); + +/** + * This function reads parameters associated with style in hardware. + * + * @param node Node number. + * @param style Style to read from. + * @param cluster_mask Mask of clusters style belongs to. + * @param style_cfg Pointer to style config struct. + */ +void cvmx_pki_read_style_config(int node, int style, u64 cluster_mask, + struct cvmx_pki_style_config *style_cfg); + +/** + * This function writes/configures parameters associated with style in hardware. + * + * @param node Node number. + * @param style Style to configure. + * @param cluster_mask Mask of clusters to configure the style for. + * @param style_cfg Pointer to style config struct. + */ +void cvmx_pki_write_style_config(int node, u64 style, u64 cluster_mask, + struct cvmx_pki_style_config *style_cfg); +/** + * This function reads qpg entry at specified offset from qpg table + * + * @param node Node number. + * @param offset Offset in qpg table to read from. + * @param qpg_cfg Pointer to structure containing qpg values + */ +int cvmx_pki_read_qpg_entry(int node, int offset, struct cvmx_pki_qpg_config *qpg_cfg); + +/** + * This function writes qpg entry at specified offset in qpg table + * + * @param node Node number. + * @param offset Offset in qpg table to write to. + * @param qpg_cfg Pointer to stricture containing qpg values. + */ +void cvmx_pki_write_qpg_entry(int node, int offset, struct cvmx_pki_qpg_config *qpg_cfg); + +/** + * This function writes pcam entry at given offset in pcam table in hardware + * + * @param node Node number. + * @param index Offset in pcam table. + * @param cluster_mask Mask of clusters in which to write pcam entry. + * @param input Input keys to pcam match passed as struct. + * @param action PCAM match action passed as struct + */ +int cvmx_pki_pcam_write_entry(int node, int index, u64 cluster_mask, + struct cvmx_pki_pcam_input input, struct cvmx_pki_pcam_action action); +/** + * Configures the channel which will receive backpressure from the specified bpid. + * Each channel listens for backpressure on a specific bpid. + * Each bpid can backpressure multiple channels. + * @param node Node number. + * @param bpid BPID from which channel will receive backpressure. + * @param channel Channel number to receive backpressue. + */ +int cvmx_pki_write_channel_bpid(int node, int channel, int bpid); + +/** + * Configures the bpid on which, specified channel will + * assert backpressure. + * Each bpid receives backpressure from auras. + * Multiple auras can backpressure single bpid. + * @param node Node number. + * @param aura Number which will assert backpressure on that bpid. + * @param bpid To assert backpressure on. + */ +int cvmx_pki_write_aura_bpid(int node, int aura, int bpid); + +/** + * Enables/Disabled QoS (RED Drop, Tail Drop & backpressure) for the* PKI aura. + * + * @param node Node number + * @param aura To enable/disable QoS on. + * @param ena_red Enable/Disable RED drop between pass and drop level + * 1-enable 0-disable + * @param ena_drop Enable/disable tail drop when max drop level exceeds + * 1-enable 0-disable + * @param ena_bp Enable/Disable asserting backpressure on bpid when + * max DROP level exceeds. + * 1-enable 0-disable + */ +int cvmx_pki_enable_aura_qos(int node, int aura, bool ena_red, bool ena_drop, bool ena_bp); + +/** + * This function gives the initial style used by that pkind. + * + * @param node Node number. + * @param pkind PKIND number. + */ +int cvmx_pki_get_pkind_style(int node, int pkind); + +/** + * This function sets the wqe buffer mode. First packet data buffer can reside + * either in same buffer as wqe OR it can go in separate buffer. If used the later mode, + * make sure software allocate enough buffers to now have wqe separate from packet data. + * + * @param node Node number. + * @param style Style to configure. + * @param pkt_outside_wqe + * 0 = The packet link pointer will be at word [FIRST_SKIP] immediately + * followed by packet data, in the same buffer as the work queue entry. + * 1 = The packet link pointer will be at word [FIRST_SKIP] in a new + * buffer separate from the work queue entry. Words following the + * WQE in the same cache line will be zeroed, other lines in the + * buffer will not be modified and will retain stale data (from the + * buffer’s previous use). This setting may decrease the peak PKI + * performance by up to half on small packets. + */ +void cvmx_pki_set_wqe_mode(int node, u64 style, bool pkt_outside_wqe); + +/** + * This function sets the Packet mode of all ports and styles to little-endian. + * It Changes write operations of packet data to L2C to + * be in little-endian. Does not change the WQE header format, which is + * properly endian neutral. + * + * @param node Node number. + * @param style Style to configure. + */ +void cvmx_pki_set_little_endian(int node, u64 style); + +/** + * Enables/Disables L2 length error check and max & min frame length checks. + * + * @param node Node number. + * @param pknd PKIND to disable error for. + * @param l2len_err L2 length error check enable. + * @param maxframe_err Max frame error check enable. + * @param minframe_err Min frame error check enable. + * 1 -- Enabel err checks + * 0 -- Disable error checks + */ +void cvmx_pki_endis_l2_errs(int node, int pknd, bool l2len_err, bool maxframe_err, + bool minframe_err); + +/** + * Enables/Disables fcs check and fcs stripping on the pkind. + * + * @param node Node number. + * @param pknd PKIND to apply settings on. + * @param fcs_chk Enable/disable fcs check. + * 1 -- enable fcs error check. + * 0 -- disable fcs error check. + * @param fcs_strip Strip L2 FCS bytes from packet, decrease WQE[LEN] by 4 bytes + * 1 -- strip L2 FCS. + * 0 -- Do not strip L2 FCS. + */ +void cvmx_pki_endis_fcs_check(int node, int pknd, bool fcs_chk, bool fcs_strip); + +/** + * This function shows the qpg table entries, read directly from hardware. + * + * @param node Node number. + * @param num_entry Number of entries to print. + */ +void cvmx_pki_show_qpg_entries(int node, u16 num_entry); + +/** + * This function shows the pcam table in raw format read directly from hardware. + * + * @param node Node number. + */ +void cvmx_pki_show_pcam_entries(int node); + +/** + * This function shows the valid entries in readable format, + * read directly from hardware. + * + * @param node Node number. + */ +void cvmx_pki_show_valid_pcam_entries(int node); + +/** + * This function shows the pkind attributes in readable format, + * read directly from hardware. + * @param node Node number. + * @param pkind PKIND number to print. + */ +void cvmx_pki_show_pkind_attributes(int node, int pkind); + +/** + * @INTERNAL + * This function is called by cvmx_helper_shutdown() to extract all FPA buffers + * out of the PKI. After this function completes, all FPA buffers that were + * prefetched by PKI will be in the appropriate FPA pool. + * This functions does not reset the PKI. + * WARNING: It is very important that PKI be reset soon after a call to this function. + * + * @param node Node number. + */ +void __cvmx_pki_free_ptr(int node); + +#endif diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pko-internal-ports-range.h b/arch/mips/mach-octeon/include/mach/cvmx-pko-internal-ports-range.h new file mode 100644 index 000000000000..1fb49b3fb6de --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-pko-internal-ports-range.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +#ifndef __CVMX_INTERNAL_PORTS_RANGE__ +#define __CVMX_INTERNAL_PORTS_RANGE__ + +/* + * Allocated a block of internal ports for the specified interface/port + * + * @param interface the interface for which the internal ports are requested + * @param port the index of the port within in the interface for which the internal ports + * are requested. + * @param count the number of internal ports requested + * + * @return 0 on success + * -1 on failure + */ +int cvmx_pko_internal_ports_alloc(int interface, int port, u64 count); + +/* + * Free the internal ports associated with the specified interface/port + * + * @param interface the interface for which the internal ports are requested + * @param port the index of the port within in the interface for which the internal ports + * are requested. + * + * @return 0 on success + * -1 on failure + */ +int cvmx_pko_internal_ports_free(int interface, int port); + +/* + * Frees up all the allocated internal ports. + */ +void cvmx_pko_internal_ports_range_free_all(void); + +void cvmx_pko_internal_ports_range_show(void); + +int __cvmx_pko_internal_ports_range_init(void); + +#endif diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pko3-queue.h b/arch/mips/mach-octeon/include/mach/cvmx-pko3-queue.h new file mode 100644 index 000000000000..5f8398904953 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-pko3-queue.h @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +#ifndef __CVMX_PKO3_QUEUE_H__ +#define __CVMX_PKO3_QUEUE_H__ + +/** + * @INTERNAL + * + * Find or allocate global port/dq map table + * which is a named table, contains entries for + * all possible OCI nodes. + * + * The table global pointer is stored in core-local variable + * so that every core will call this function once, on first use. + */ +int __cvmx_pko3_dq_table_setup(void); + +/* + * Get the base Descriptor Queue number for an IPD port on the local node + */ +int cvmx_pko3_get_queue_base(int ipd_port); + +/* + * Get the number of Descriptor Queues assigned for an IPD port + */ +int cvmx_pko3_get_queue_num(int ipd_port); + +/** + * Get L1/Port Queue number assigned to interface port. + * + * @param xiface is interface number. + * @param index is port index. + */ +int cvmx_pko3_get_port_queue(int xiface, int index); + +/* + * Configure L3 through L5 Scheduler Queues and Descriptor Queues + * + * The Scheduler Queues in Levels 3 to 5 and Descriptor Queues are + * configured one-to-one or many-to-one to a single parent Scheduler + * Queues. The level of the parent SQ is specified in an argument, + * as well as the number of children to attach to the specific parent. + * The children can have fair round-robin or priority-based scheduling + * when multiple children are assigned a single parent. + * + * @param node is the OCI node location for the queues to be configured + * @param parent_level is the level of the parent queue, 2 to 5. + * @param parent_queue is the number of the parent Scheduler Queue + * @param child_base is the number of the first child SQ or DQ to assign to + * @param parent + * @param child_count is the number of consecutive children to assign + * @param stat_prio_count is the priority setting for the children L2 SQs + * + * If <stat_prio_count> is -1, the Ln children will have equal Round-Robin + * relationship with eachother. If <stat_prio_count> is 0, all Ln children + * will be arranged in Weighted-Round-Robin, with the first having the most + * precedence. If <stat_prio_count> is between 1 and 8, it indicates how + * many children will have static priority settings (with the first having + * the most precedence), with the remaining Ln children having WRR scheduling. + * + * @returns 0 on success, -1 on failure. + * + * Note: this function supports the configuration of node-local unit. + */ +int cvmx_pko3_sq_config_children(unsigned int node, unsigned int parent_level, + unsigned int parent_queue, unsigned int child_base, + unsigned int child_count, int stat_prio_count); + +/* + * @INTERNAL + * Register a range of Descriptor Queues wth an interface port + * + * This function poulates the DQ-to-IPD translation table + * used by the application to retrieve the DQ range (typically ordered + * by priority) for a given IPD-port, which is either a physical port, + * or a channel on a channelized interface (i.e. ILK). + * + * @param xiface is the physical interface number + * @param index is either a physical port on an interface + * @param or a channel of an ILK interface + * @param dq_base is the first Descriptor Queue number in a consecutive range + * @param dq_count is the number of consecutive Descriptor Queues leading + * @param the same channel or port. + * + * Only a consecurive range of Descriptor Queues can be associated with any + * given channel/port, and usually they are ordered from most to least + * in terms of scheduling priority. + * + * Note: thus function only populates the node-local translation table. + * + * @returns 0 on success, -1 on failure. + */ +int __cvmx_pko3_ipd_dq_register(int xiface, int index, unsigned int dq_base, unsigned int dq_count); + +/** + * @INTERNAL + * + * Unregister DQs associated with CHAN_E (IPD port) + */ +int __cvmx_pko3_ipd_dq_unregister(int xiface, int index); + +/* + * Map channel number in PKO + * + * @param node is to specify the node to which this configuration is applied. + * @param pq_num specifies the Port Queue (i.e. L1) queue number. + * @param l2_l3_q_num specifies L2/L3 queue number. + * @param channel specifies the channel number to map to the queue. + * + * The channel assignment applies to L2 or L3 Shaper Queues depending + * on the setting of channel credit level. + * + * @return returns none. + */ +void cvmx_pko3_map_channel(unsigned int node, unsigned int pq_num, unsigned int l2_l3_q_num, + u16 channel); + +int cvmx_pko3_pq_config(unsigned int node, unsigned int mac_num, unsigned int pq_num); + +int cvmx_pko3_port_cir_set(unsigned int node, unsigned int pq_num, unsigned long rate_kbips, + unsigned int burst_bytes, int adj_bytes); +int cvmx_pko3_dq_cir_set(unsigned int node, unsigned int pq_num, unsigned long rate_kbips, + unsigned int burst_bytes); +int cvmx_pko3_dq_pir_set(unsigned int node, unsigned int pq_num, unsigned long rate_kbips, + unsigned int burst_bytes); +typedef enum { + CVMX_PKO3_SHAPE_RED_STALL, + CVMX_PKO3_SHAPE_RED_DISCARD, + CVMX_PKO3_SHAPE_RED_PASS +} red_action_t; + +void cvmx_pko3_dq_red(unsigned int node, unsigned int dq_num, red_action_t red_act, + int8_t len_adjust); + +/** + * Macros to deal with short floating point numbers, + * where unsigned exponent, and an unsigned normalized + * mantissa are represented each with a defined field width. + * + */ +#define CVMX_SHOFT_MANT_BITS 8 +#define CVMX_SHOFT_EXP_BITS 4 + +/** + * Convert short-float to an unsigned integer + * Note that it will lose precision. + */ +#define CVMX_SHOFT_TO_U64(m, e) \ + ((((1ull << CVMX_SHOFT_MANT_BITS) | (m)) << (e)) >> CVMX_SHOFT_MANT_BITS) + +/** + * Convert to short-float from an unsigned integer + */ +#define CVMX_SHOFT_FROM_U64(ui, m, e) \ + do { \ + unsigned long long u; \ + unsigned int k; \ + k = (1ull << (CVMX_SHOFT_MANT_BITS + 1)) - 1; \ + (e) = 0; \ + u = (ui) << CVMX_SHOFT_MANT_BITS; \ + while ((u) > k) { \ + u >>= 1; \ + (e)++; \ + } \ + (m) = u & (k >> 1); \ + } while (0); + +#define CVMX_SHOFT_MAX() \ + CVMX_SHOFT_TO_U64((1 << CVMX_SHOFT_MANT_BITS) - 1, (1 << CVMX_SHOFT_EXP_BITS) - 1) +#define CVMX_SHOFT_MIN() CVMX_SHOFT_TO_U64(0, 0) + +#endif /* __CVMX_PKO3_QUEUE_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-pow.h b/arch/mips/mach-octeon/include/mach/cvmx-pow.h new file mode 100644 index 000000000000..0680ca258f12 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-pow.h @@ -0,0 +1,2991 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * Interface to the hardware Scheduling unit. + * + * New, starting with SDK 1.7.0, cvmx-pow supports a number of + * extended consistency checks. The define + * CVMX_ENABLE_POW_CHECKS controls the runtime insertion of POW + * internal state checks to find common programming errors. If + * CVMX_ENABLE_POW_CHECKS is not defined, checks are by default + * enabled. For example, cvmx-pow will check for the following + * program errors or POW state inconsistency. + * - Requesting a POW operation with an active tag switch in + * progress. + * - Waiting for a tag switch to complete for an excessively + * long period. This is normally a sign of an error in locking + * causing deadlock. + * - Illegal tag switches from NULL_NULL. + * - Illegal tag switches from NULL. + * - Illegal deschedule request. + * - WQE pointer not matching the one attached to the core by + * the POW. + */ + +#ifndef __CVMX_POW_H__ +#define __CVMX_POW_H__ + +#include "cvmx-wqe.h" +#include "cvmx-pow-defs.h" +#include "cvmx-sso-defs.h" +#include "cvmx-address.h" +#include "cvmx-coremask.h" + +/* Default to having all POW constancy checks turned on */ +#ifndef CVMX_ENABLE_POW_CHECKS +#define CVMX_ENABLE_POW_CHECKS 1 +#endif + +/* + * Special type for CN78XX style SSO groups (0..255), + * for distinction from legacy-style groups (0..15) + */ +typedef union { + u8 xgrp; + /* Fields that map XGRP for backwards compatibility */ + struct __attribute__((__packed__)) { + u8 group : 5; + u8 qus : 3; + }; +} cvmx_xgrp_t; + +/* + * Softwsare-only structure to convey a return value + * containing multiple information fields about an work queue entry + */ +typedef struct { + u32 tag; + u16 index; + u8 grp; /* Legacy group # (0..15) */ + u8 tag_type; +} cvmx_pow_tag_info_t; + +/** + * Wait flag values for pow functions. + */ +typedef enum { + CVMX_POW_WAIT = 1, + CVMX_POW_NO_WAIT = 0, +} cvmx_pow_wait_t; + +/** + * POW tag operations. These are used in the data stored to the POW. + */ +typedef enum { + CVMX_POW_TAG_OP_SWTAG = 0L, + CVMX_POW_TAG_OP_SWTAG_FULL = 1L, + CVMX_POW_TAG_OP_SWTAG_DESCH = 2L, + CVMX_POW_TAG_OP_DESCH = 3L, + CVMX_POW_TAG_OP_ADDWQ = 4L, + CVMX_POW_TAG_OP_UPDATE_WQP_GRP = 5L, + CVMX_POW_TAG_OP_SET_NSCHED = 6L, + CVMX_POW_TAG_OP_CLR_NSCHED = 7L, + CVMX_POW_TAG_OP_NOP = 15L +} cvmx_pow_tag_op_t; + +/** + * This structure defines the store data on a store to POW + */ +typedef union { + u64 u64; + struct { + u64 no_sched : 1; + u64 unused : 2; + u64 index : 13; + cvmx_pow_tag_op_t op : 4; + u64 unused2 : 2; + u64 qos : 3; + u64 grp : 4; + cvmx_pow_tag_type_t type : 3; + u64 tag : 32; + } s_cn38xx; + struct { + u64 no_sched : 1; + cvmx_pow_tag_op_t op : 4; + u64 unused1 : 4; + u64 index : 11; + u64 unused2 : 1; + u64 grp : 6; + u64 unused3 : 3; + cvmx_pow_tag_type_t type : 2; + u64 tag : 32; + } s_cn68xx_clr; + struct { + u64 no_sched : 1; + cvmx_pow_tag_op_t op : 4; + u64 unused1 : 12; + u64 qos : 3; + u64 unused2 : 1; + u64 grp : 6; + u64 unused3 : 3; + cvmx_pow_tag_type_t type : 2; + u64 tag : 32; + } s_cn68xx_add; + struct { + u64 no_sched : 1; + cvmx_pow_tag_op_t op : 4; + u64 unused1 : 16; + u64 grp : 6; + u64 unused3 : 3; + cvmx_pow_tag_type_t type : 2; + u64 tag : 32; + } s_cn68xx_other; + struct { + u64 rsvd_62_63 : 2; + u64 grp : 10; + cvmx_pow_tag_type_t type : 2; + u64 no_sched : 1; + u64 rsvd_48 : 1; + cvmx_pow_tag_op_t op : 4; + u64 rsvd_42_43 : 2; + u64 wqp : 42; + } s_cn78xx_other; + +} cvmx_pow_tag_req_t; + +union cvmx_pow_tag_req_addr { + u64 u64; + struct { + u64 mem_region : 2; + u64 reserved_49_61 : 13; + u64 is_io : 1; + u64 did : 8; + u64 addr : 40; + } s; + struct { + u64 mem_region : 2; + u64 reserved_49_61 : 13; + u64 is_io : 1; + u64 did : 8; + u64 node : 4; + u64 tag : 32; + u64 reserved_0_3 : 4; + } s_cn78xx; +}; + +/** + * This structure describes the address to load stuff from POW + */ +typedef union { + u64 u64; + /** + * Address for new work request loads (did<2:0> == 0) + */ + struct { + u64 mem_region : 2; + u64 reserved_49_61 : 13; + u64 is_io : 1; + u64 did : 8; + u64 reserved_4_39 : 36; + u64 wait : 1; + u64 reserved_0_2 : 3; + } swork; + struct { + u64 mem_region : 2; + u64 reserved_49_61 : 13; + u64 is_io : 1; + u64 did : 8; + u64 node : 4; + u64 reserved_32_35 : 4; + u64 indexed : 1; + u64 grouped : 1; + u64 rtngrp : 1; + u64 reserved_16_28 : 13; + u64 index : 12; + u64 wait : 1; + u64 reserved_0_2 : 3; + } swork_78xx; + /** + * Address for loads to get POW internal status + */ + struct { + u64 mem_region : 2; + u64 reserved_49_61 : 13; + u64 is_io : 1; + u64 did : 8; + u64 reserved_10_39 : 30; + u64 coreid : 4; + u64 get_rev : 1; + u64 get_cur : 1; + u64 get_wqp : 1; + u64 reserved_0_2 : 3; + } sstatus; + /** + * Address for loads to get 68XX SS0 internal status + */ + struct { + u64 mem_region : 2; + u64 reserved_49_61 : 13; + u64 is_io : 1; + u64 did : 8; + u64 reserved_14_39 : 26; + u64 coreid : 5; + u64 reserved_6_8 : 3; + u64 opcode : 3; + u64 reserved_0_2 : 3; + } sstatus_cn68xx; + /** + * Address for memory loads to get POW internal state + */ + struct { + u64 mem_region : 2; + u64 reserved_49_61 : 13; + u64 is_io : 1; + u64 did : 8; + u64 reserved_16_39 : 24; + u64 index : 11; + u64 get_des : 1; + u64 get_wqp : 1; + u64 reserved_0_2 : 3; + } smemload; + /** + * Address for memory loads to get SSO internal state + */ + struct { + u64 mem_region : 2; + u64 reserved_49_61 : 13; + u64 is_io : 1; + u64 did : 8; + u64 reserved_20_39 : 20; + u64 index : 11; + u64 reserved_6_8 : 3; + u64 opcode : 3; + u64 reserved_0_2 : 3; + } smemload_cn68xx; + /** + * Address for index/pointer loads + */ + struct { + u64 mem_region : 2; + u64 reserved_49_61 : 13; + u64 is_io : 1; + u64 did : 8; + u64 reserved_9_39 : 31; + u64 qosgrp : 4; + u64 get_des_get_tail : 1; + u64 get_rmt : 1; + u64 reserved_0_2 : 3; + } sindexload; + /** + * Address for a Index/Pointer loads to get SSO internal state + */ + struct { + u64 mem_region : 2; + u64 reserved_49_61 : 13; + u64 is_io : 1; + u64 did : 8; + u64 reserved_15_39 : 25; + u64 qos_grp : 6; + u64 reserved_6_8 : 3; + u64 opcode : 3; + u64 reserved_0_2 : 3; + } sindexload_cn68xx; + /** + * Address for NULL_RD request (did<2:0> == 4) + * when this is read, HW attempts to change the state to NULL if it is NULL_NULL + * (the hardware cannot switch from NULL_NULL to NULL if a POW entry is not available - + * software may need to recover by finishing another piece of work before a POW + * entry can ever become available.) + */ + struct { + u64 mem_region : 2; + u64 reserved_49_61 : 13; + u64 is_io : 1; + u64 did : 8; + u64 reserved_0_39 : 40; + } snull_rd; +} cvmx_pow_load_addr_t; + +/** + * This structure defines the response to a load/SENDSINGLE to POW (except CSR reads) + */ +typedef union { + u64 u64; + /** + * Response to new work request loads + */ + struct { + u64 no_work : 1; + u64 pend_switch : 1; + u64 tt : 2; + u64 reserved_58_59 : 2; + u64 grp : 10; + u64 reserved_42_47 : 6; + u64 addr : 42; + } s_work; + + /** + * Result for a POW Status Load (when get_cur==0 and get_wqp==0) + */ + struct { + u64 reserved_62_63 : 2; + u64 pend_switch : 1; + u64 pend_switch_full : 1; + u64 pend_switch_null : 1; + u64 pend_desched : 1; + u64 pend_desched_switch : 1; + u64 pend_nosched : 1; + u64 pend_new_work : 1; + u64 pend_new_work_wait : 1; + u64 pend_null_rd : 1; + u64 pend_nosched_clr : 1; + u64 reserved_51 : 1; + u64 pend_index : 11; + u64 pend_grp : 4; + u64 reserved_34_35 : 2; + u64 pend_type : 2; + u64 pend_tag : 32; + } s_sstatus0; + /** + * Result for a SSO Status Load (when opcode is SL_PENDTAG) + */ + struct { + u64 pend_switch : 1; + u64 pend_get_work : 1; + u64 pend_get_work_wait : 1; + u64 pend_nosched : 1; + u64 pend_nosched_clr : 1; + u64 pend_desched : 1; + u64 pend_alloc_we : 1; + u64 reserved_48_56 : 9; + u64 pend_index : 11; + u64 reserved_34_36 : 3; + u64 pend_type : 2; + u64 pend_tag : 32; + } s_sstatus0_cn68xx; + /** + * Result for a POW Status Load (when get_cur==0 and get_wqp==1) + */ + struct { + u64 reserved_62_63 : 2; + u64 pend_switch : 1; + u64 pend_switch_full : 1; + u64 pend_switch_null : 1; + u64 pend_desched : 1; + u64 pend_desched_switch : 1; + u64 pend_nosched : 1; + u64 pend_new_work : 1; + u64 pend_new_work_wait : 1; + u64 pend_null_rd : 1; + u64 pend_nosched_clr : 1; + u64 reserved_51 : 1; + u64 pend_index : 11; + u64 pend_grp : 4; + u64 pend_wqp : 36; + } s_sstatus1; + /** + * Result for a SSO Status Load (when opcode is SL_PENDWQP) + */ + struct { + u64 pend_switch : 1; + u64 pend_get_work : 1; + u64 pend_get_work_wait : 1; + u64 pend_nosched : 1; + u64 pend_nosched_clr : 1; + u64 pend_desched : 1; + u64 pend_alloc_we : 1; + u64 reserved_51_56 : 6; + u64 pend_index : 11; + u64 reserved_38_39 : 2; + u64 pend_wqp : 38; + } s_sstatus1_cn68xx; + + struct { + u64 pend_switch : 1; + u64 pend_get_work : 1; + u64 pend_get_work_wait : 1; + u64 pend_nosched : 1; + u64 pend_nosched_clr : 1; + u64 pend_desched : 1; + u64 pend_alloc_we : 1; + u64 reserved_56 : 1; + u64 prep_index : 12; + u64 reserved_42_43 : 2; + u64 pend_tag : 42; + } s_sso_ppx_pendwqp_cn78xx; + /** + * Result for a POW Status Load (when get_cur==1, get_wqp==0, and get_rev==0) + */ + struct { + u64 reserved_62_63 : 2; + u64 link_index : 11; + u64 index : 11; + u64 grp : 4; + u64 head : 1; + u64 tail : 1; + u64 tag_type : 2; + u64 tag : 32; + } s_sstatus2; + /** + * Result for a SSO Status Load (when opcode is SL_TAG) + */ + struct { + u64 reserved_57_63 : 7; + u64 index : 11; + u64 reserved_45 : 1; + u64 grp : 6; + u64 head : 1; + u64 tail : 1; + u64 reserved_34_36 : 3; + u64 tag_type : 2; + u64 tag : 32; + } s_sstatus2_cn68xx; + + struct { + u64 tailc : 1; + u64 reserved_60_62 : 3; + u64 index : 12; + u64 reserved_46_47 : 2; + u64 grp : 10; + u64 head : 1; + u64 tail : 1; + u64 tt : 2; + u64 tag : 32; + } s_sso_ppx_tag_cn78xx; + /** + * Result for a POW Status Load (when get_cur==1, get_wqp==0, and get_rev==1) + */ + struct { + u64 reserved_62_63 : 2; + u64 revlink_index : 11; + u64 index : 11; + u64 grp : 4; + u64 head : 1; + u64 tail : 1; + u64 tag_type : 2; + u64 tag : 32; + } s_sstatus3; + /** + * Result for a SSO Status Load (when opcode is SL_WQP) + */ + struct { + u64 reserved_58_63 : 6; + u64 index : 11; + u64 reserved_46 : 1; + u64 grp : 6; + u64 reserved_38_39 : 2; + u64 wqp : 38; + } s_sstatus3_cn68xx; + + struct { + u64 reserved_58_63 : 6; + u64 grp : 10; + u64 reserved_42_47 : 6; + u64 tag : 42; + } s_sso_ppx_wqp_cn78xx; + /** + * Result for a POW Status Load (when get_cur==1, get_wqp==1, and get_rev==0) + */ + struct { + u64 reserved_62_63 : 2; + u64 link_index : 11; + u64 index : 11; + u64 grp : 4; + u64 wqp : 36; + } s_sstatus4; + /** + * Result for a SSO Status Load (when opcode is SL_LINKS) + */ + struct { + u64 reserved_46_63 : 18; + u64 index : 11; + u64 reserved_34 : 1; + u64 grp : 6; + u64 head : 1; + u64 tail : 1; + u64 reserved_24_25 : 2; + u64 revlink_index : 11; + u64 reserved_11_12 : 2; + u64 link_index : 11; + } s_sstatus4_cn68xx; + + struct { + u64 tailc : 1; + u64 reserved_60_62 : 3; + u64 index : 12; + u64 reserved_38_47 : 10; + u64 grp : 10; + u64 head : 1; + u64 tail : 1; + u64 reserved_25 : 1; + u64 revlink_index : 12; + u64 link_index_vld : 1; + u64 link_index : 12; + } s_sso_ppx_links_cn78xx; + /** + * Result for a POW Status Load (when get_cur==1, get_wqp==1, and get_rev==1) + */ + struct { + u64 reserved_62_63 : 2; + u64 revlink_index : 11; + u64 index : 11; + u64 grp : 4; + u64 wqp : 36; + } s_sstatus5; + /** + * Result For POW Memory Load (get_des == 0 and get_wqp == 0) + */ + struct { + u64 reserved_51_63 : 13; + u64 next_index : 11; + u64 grp : 4; + u64 reserved_35 : 1; + u64 tail : 1; + u64 tag_type : 2; + u64 tag : 32; + } s_smemload0; + /** + * Result For SSO Memory Load (opcode is ML_TAG) + */ + struct { + u64 reserved_38_63 : 26; + u64 tail : 1; + u64 reserved_34_36 : 3; + u64 tag_type : 2; + u64 tag : 32; + } s_smemload0_cn68xx; + + struct { + u64 reserved_39_63 : 25; + u64 tail : 1; + u64 reserved_34_36 : 3; + u64 tag_type : 2; + u64 tag : 32; + } s_sso_iaq_ppx_tag_cn78xx; + /** + * Result For POW Memory Load (get_des == 0 and get_wqp == 1) + */ + struct { + u64 reserved_51_63 : 13; + u64 next_index : 11; + u64 grp : 4; + u64 wqp : 36; + } s_smemload1; + /** + * Result For SSO Memory Load (opcode is ML_WQPGRP) + */ + struct { + u64 reserved_48_63 : 16; + u64 nosched : 1; + u64 reserved_46 : 1; + u64 grp : 6; + u64 reserved_38_39 : 2; + u64 wqp : 38; + } s_smemload1_cn68xx; + + /** + * Entry structures for the CN7XXX chips. + */ + struct { + u64 reserved_39_63 : 25; + u64 tailc : 1; + u64 tail : 1; + u64 reserved_34_36 : 3; + u64 tt : 2; + u64 tag : 32; + } s_sso_ientx_tag_cn78xx; + + struct { + u64 reserved_62_63 : 2; + u64 head : 1; + u64 nosched : 1; + u64 reserved_56_59 : 4; + u64 grp : 8; + u64 reserved_42_47 : 6; + u64 wqp : 42; + } s_sso_ientx_wqpgrp_cn73xx; + + struct { + u64 reserved_62_63 : 2; + u64 head : 1; + u64 nosched : 1; + u64 reserved_58_59 : 2; + u64 grp : 10; + u64 reserved_42_47 : 6; + u64 wqp : 42; + } s_sso_ientx_wqpgrp_cn78xx; + + struct { + u64 reserved_38_63 : 26; + u64 pend_switch : 1; + u64 reserved_34_36 : 3; + u64 pend_tt : 2; + u64 pend_tag : 32; + } s_sso_ientx_pendtag_cn78xx; + + struct { + u64 reserved_26_63 : 38; + u64 prev_index : 10; + u64 reserved_11_15 : 5; + u64 next_index_vld : 1; + u64 next_index : 10; + } s_sso_ientx_links_cn73xx; + + struct { + u64 reserved_28_63 : 36; + u64 prev_index : 12; + u64 reserved_13_15 : 3; + u64 next_index_vld : 1; + u64 next_index : 12; + } s_sso_ientx_links_cn78xx; + + /** + * Result For POW Memory Load (get_des == 1) + */ + struct { + u64 reserved_51_63 : 13; + u64 fwd_index : 11; + u64 grp : 4; + u64 nosched : 1; + u64 pend_switch : 1; + u64 pend_type : 2; + u64 pend_tag : 32; + } s_smemload2; + /** + * Result For SSO Memory Load (opcode is ML_PENTAG) + */ + struct { + u64 reserved_38_63 : 26; + u64 pend_switch : 1; + u64 reserved_34_36 : 3; + u64 pend_type : 2; + u64 pend_tag : 32; + } s_smemload2_cn68xx; + + struct { + u64 pend_switch : 1; + u64 pend_get_work : 1; + u64 pend_get_work_wait : 1; + u64 pend_nosched : 1; + u64 pend_nosched_clr : 1; + u64 pend_desched : 1; + u64 pend_alloc_we : 1; + u64 reserved_34_56 : 23; + u64 pend_tt : 2; + u64 pend_tag : 32; + } s_sso_ppx_pendtag_cn78xx; + /** + * Result For SSO Memory Load (opcode is ML_LINKS) + */ + struct { + u64 reserved_24_63 : 40; + u64 fwd_index : 11; + u64 reserved_11_12 : 2; + u64 next_index : 11; + } s_smemload3_cn68xx; + + /** + * Result For POW Index/Pointer Load (get_rmt == 0/get_des_get_tail == 0) + */ + struct { + u64 reserved_52_63 : 12; + u64 free_val : 1; + u64 free_one : 1; + u64 reserved_49 : 1; + u64 free_head : 11; + u64 reserved_37 : 1; + u64 free_tail : 11; + u64 loc_val : 1; + u64 loc_one : 1; + u64 reserved_23 : 1; + u64 loc_head : 11; + u64 reserved_11 : 1; + u64 loc_tail : 11; + } sindexload0; + /** + * Result for SSO Index/Pointer Load(opcode == + * IPL_IQ/IPL_DESCHED/IPL_NOSCHED) + */ + struct { + u64 reserved_28_63 : 36; + u64 queue_val : 1; + u64 queue_one : 1; + u64 reserved_24_25 : 2; + u64 queue_head : 11; + u64 reserved_11_12 : 2; + u64 queue_tail : 11; + } sindexload0_cn68xx; + /** + * Result For POW Index/Pointer Load (get_rmt == 0/get_des_get_tail == 1) + */ + struct { + u64 reserved_52_63 : 12; + u64 nosched_val : 1; + u64 nosched_one : 1; + u64 reserved_49 : 1; + u64 nosched_head : 11; + u64 reserved_37 : 1; + u64 nosched_tail : 11; + u64 des_val : 1; + u64 des_one : 1; + u64 reserved_23 : 1; + u64 des_head : 11; + u64 reserved_11 : 1; + u64 des_tail : 11; + } sindexload1; + /** + * Result for SSO Index/Pointer Load(opcode == IPL_FREE0/IPL_FREE1/IPL_FREE2) + */ + struct { + u64 reserved_60_63 : 4; + u64 qnum_head : 2; + u64 qnum_tail : 2; + u64 reserved_28_55 : 28; + u64 queue_val : 1; + u64 queue_one : 1; + u64 reserved_24_25 : 2; + u64 queue_head : 11; + u64 reserved_11_12 : 2; + u64 queue_tail : 11; + } sindexload1_cn68xx; + /** + * Result For POW Index/Pointer Load (get_rmt == 1/get_des_get_tail == 0) + */ + struct { + u64 reserved_39_63 : 25; + u64 rmt_is_head : 1; + u64 rmt_val : 1; + u64 rmt_one : 1; + u64 rmt_head : 36; + } sindexload2; + /** + * Result For POW Index/Pointer Load (get_rmt == 1/get_des_get_tail == 1) + */ + struct { + u64 reserved_39_63 : 25; + u64 rmt_is_head : 1; + u64 rmt_val : 1; + u64 rmt_one : 1; + u64 rmt_tail : 36; + } sindexload3; + /** + * Response to NULL_RD request loads + */ + struct { + u64 unused : 62; + u64 state : 2; + } s_null_rd; + +} cvmx_pow_tag_load_resp_t; + +typedef union { + u64 u64; + struct { + u64 reserved_57_63 : 7; + u64 index : 11; + u64 reserved_45 : 1; + u64 grp : 6; + u64 head : 1; + u64 tail : 1; + u64 reserved_34_36 : 3; + u64 tag_type : 2; + u64 tag : 32; + } s; +} cvmx_pow_sl_tag_resp_t; + +/** + * This structure describes the address used for stores to the POW. + * The store address is meaningful on stores to the POW. The hardware assumes that an aligned + * 64-bit store was used for all these stores. + * Note the assumption that the work queue entry is aligned on an 8-byte + * boundary (since the low-order 3 address bits must be zero). + * Note that not all fields are used by all operations. + * + * NOTE: The following is the behavior of the pending switch bit at the PP + * for POW stores (i.e. when did<7:3> == 0xc) + * - did<2:0> == 0 => pending switch bit is set + * - did<2:0> == 1 => no affect on the pending switch bit + * - did<2:0> == 3 => pending switch bit is cleared + * - did<2:0> == 7 => no affect on the pending switch bit + * - did<2:0> == others => must not be used + * - No other loads/stores have an affect on the pending switch bit + * - The switch bus from POW can clear the pending switch bit + * + * NOTE: did<2:0> == 2 is used by the HW for a special single-cycle ADDWQ command + * that only contains the pointer). SW must never use did<2:0> == 2. + */ +typedef union { + u64 u64; + struct { + u64 mem_reg : 2; + u64 reserved_49_61 : 13; + u64 is_io : 1; + u64 did : 8; + u64 addr : 40; + } stag; +} cvmx_pow_tag_store_addr_t; /* FIXME- this type is unused */ + +/** + * Decode of the store data when an IOBDMA SENDSINGLE is sent to POW + */ +typedef union { + u64 u64; + struct { + u64 scraddr : 8; + u64 len : 8; + u64 did : 8; + u64 unused : 36; + u64 wait : 1; + u64 unused2 : 3; + } s; + struct { + u64 scraddr : 8; + u64 len : 8; + u64 did : 8; + u64 node : 4; + u64 unused1 : 4; + u64 indexed : 1; + u64 grouped : 1; + u64 rtngrp : 1; + u64 unused2 : 13; + u64 index_grp_mask : 12; + u64 wait : 1; + u64 unused3 : 3; + } s_cn78xx; +} cvmx_pow_iobdma_store_t; + +/* CSR typedefs have been moved to cvmx-pow-defs.h */ + +/*enum for group priority parameters which needs modification*/ +enum cvmx_sso_group_modify_mask { + CVMX_SSO_MODIFY_GROUP_PRIORITY = 0x01, + CVMX_SSO_MODIFY_GROUP_WEIGHT = 0x02, + CVMX_SSO_MODIFY_GROUP_AFFINITY = 0x04 +}; + +/** + * @INTERNAL + * Return the number of SSO groups for a given SoC model + */ +static inline unsigned int cvmx_sso_num_xgrp(void) +{ + if (OCTEON_IS_MODEL(OCTEON_CN78XX)) + return 256; + if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) + return 64; + if (OCTEON_IS_MODEL(OCTEON_CN73XX)) + return 64; + printf("ERROR: %s: Unknown model\n", __func__); + return 0; +} + +/** + * @INTERNAL + * Return the number of POW groups on current model. + * In case of CN78XX/CN73XX this is the number of equivalent + * "legacy groups" on the chip when it is used in backward + * compatible mode. + */ +static inline unsigned int cvmx_pow_num_groups(void) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) + return cvmx_sso_num_xgrp() >> 3; + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + return 64; + else + return 16; +} + +/** + * @INTERNAL + * Return the number of mask-set registers. + */ +static inline unsigned int cvmx_sso_num_maskset(void) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) + return 2; + else + return 1; +} + +/** + * Get the POW tag for this core. This returns the current + * tag type, tag, group, and POW entry index associated with + * this core. Index is only valid if the tag type isn't NULL_NULL. + * If a tag switch is pending this routine returns the tag before + * the tag switch, not after. + * + * @return Current tag + */ +static inline cvmx_pow_tag_info_t cvmx_pow_get_current_tag(void) +{ + cvmx_pow_load_addr_t load_addr; + cvmx_pow_tag_info_t result; + + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_sso_sl_ppx_tag_t sl_ppx_tag; + cvmx_xgrp_t xgrp; + int node, core; + + CVMX_SYNCS; + node = cvmx_get_node_num(); + core = cvmx_get_local_core_num(); + sl_ppx_tag.u64 = csr_rd_node(node, CVMX_SSO_SL_PPX_TAG(core)); + result.index = sl_ppx_tag.s.index; + result.tag_type = sl_ppx_tag.s.tt; + result.tag = sl_ppx_tag.s.tag; + + /* Get native XGRP value */ + xgrp.xgrp = sl_ppx_tag.s.grp; + + /* Return legacy style group 0..15 */ + result.grp = xgrp.group; + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + cvmx_pow_sl_tag_resp_t load_resp; + + load_addr.u64 = 0; + load_addr.sstatus_cn68xx.mem_region = CVMX_IO_SEG; + load_addr.sstatus_cn68xx.is_io = 1; + load_addr.sstatus_cn68xx.did = CVMX_OCT_DID_TAG_TAG5; + load_addr.sstatus_cn68xx.coreid = cvmx_get_core_num(); + load_addr.sstatus_cn68xx.opcode = 3; + load_resp.u64 = csr_rd(load_addr.u64); + result.grp = load_resp.s.grp; + result.index = load_resp.s.index; + result.tag_type = load_resp.s.tag_type; + result.tag = load_resp.s.tag; + } else { + cvmx_pow_tag_load_resp_t load_resp; + + load_addr.u64 = 0; + load_addr.sstatus.mem_region = CVMX_IO_SEG; + load_addr.sstatus.is_io = 1; + load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1; + load_addr.sstatus.coreid = cvmx_get_core_num(); + load_addr.sstatus.get_cur = 1; + load_resp.u64 = csr_rd(load_addr.u64); + result.grp = load_resp.s_sstatus2.grp; + result.index = load_resp.s_sstatus2.index; + result.tag_type = load_resp.s_sstatus2.tag_type; + result.tag = load_resp.s_sstatus2.tag; + } + return result; +} + +/** + * Get the POW WQE for this core. This returns the work queue + * entry currently associated with this core. + * + * @return WQE pointer + */ +static inline cvmx_wqe_t *cvmx_pow_get_current_wqp(void) +{ + cvmx_pow_load_addr_t load_addr; + cvmx_pow_tag_load_resp_t load_resp; + + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_sso_sl_ppx_wqp_t sso_wqp; + int node = cvmx_get_node_num(); + int core = cvmx_get_local_core_num(); + + sso_wqp.u64 = csr_rd_node(node, CVMX_SSO_SL_PPX_WQP(core)); + if (sso_wqp.s.wqp) + return (cvmx_wqe_t *)cvmx_phys_to_ptr(sso_wqp.s.wqp); + return (cvmx_wqe_t *)0; + } + if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + load_addr.u64 = 0; + load_addr.sstatus_cn68xx.mem_region = CVMX_IO_SEG; + load_addr.sstatus_cn68xx.is_io = 1; + load_addr.sstatus_cn68xx.did = CVMX_OCT_DID_TAG_TAG5; + load_addr.sstatus_cn68xx.coreid = cvmx_get_core_num(); + load_addr.sstatus_cn68xx.opcode = 4; + load_resp.u64 = csr_rd(load_addr.u64); + if (load_resp.s_sstatus3_cn68xx.wqp) + return (cvmx_wqe_t *)cvmx_phys_to_ptr(load_resp.s_sstatus3_cn68xx.wqp); + else + return (cvmx_wqe_t *)0; + } else { + load_addr.u64 = 0; + load_addr.sstatus.mem_region = CVMX_IO_SEG; + load_addr.sstatus.is_io = 1; + load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1; + load_addr.sstatus.coreid = cvmx_get_core_num(); + load_addr.sstatus.get_cur = 1; + load_addr.sstatus.get_wqp = 1; + load_resp.u64 = csr_rd(load_addr.u64); + return (cvmx_wqe_t *)cvmx_phys_to_ptr(load_resp.s_sstatus4.wqp); + } +} + +/** + * @INTERNAL + * Print a warning if a tag switch is pending for this core + * + * @param function Function name checking for a pending tag switch + */ +static inline void __cvmx_pow_warn_if_pending_switch(const char *function) +{ + u64 switch_complete; + + CVMX_MF_CHORD(switch_complete); + cvmx_warn_if(!switch_complete, "%s called with tag switch in progress\n", function); +} + +/** + * Waits for a tag switch to complete by polling the completion bit. + * Note that switches to NULL complete immediately and do not need + * to be waited for. + */ +static inline void cvmx_pow_tag_sw_wait(void) +{ + const u64 TIMEOUT_MS = 10; /* 10ms timeout */ + u64 switch_complete; + u64 start_cycle; + + if (CVMX_ENABLE_POW_CHECKS) + start_cycle = get_timer(0); + + while (1) { + CVMX_MF_CHORD(switch_complete); + if (cvmx_likely(switch_complete)) + break; + + if (CVMX_ENABLE_POW_CHECKS) { + if (cvmx_unlikely(get_timer(start_cycle) > TIMEOUT_MS)) { + debug("WARNING: %s: Tag switch is taking a long time, possible deadlock\n", + __func__); + } + } + } +} + +/** + * Synchronous work request. Requests work from the POW. + * This function does NOT wait for previous tag switches to complete, + * so the caller must ensure that there is not a pending tag switch. + * + * @param wait When set, call stalls until work becomes available, or + * times out. If not set, returns immediately. + * + * @return Returns the WQE pointer from POW. Returns NULL if no work was + * available. + */ +static inline cvmx_wqe_t *cvmx_pow_work_request_sync_nocheck(cvmx_pow_wait_t wait) +{ + cvmx_pow_load_addr_t ptr; + cvmx_pow_tag_load_resp_t result; + + if (CVMX_ENABLE_POW_CHECKS) + __cvmx_pow_warn_if_pending_switch(__func__); + + ptr.u64 = 0; + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + ptr.swork_78xx.node = cvmx_get_node_num(); + ptr.swork_78xx.mem_region = CVMX_IO_SEG; + ptr.swork_78xx.is_io = 1; + ptr.swork_78xx.did = CVMX_OCT_DID_TAG_SWTAG; + ptr.swork_78xx.wait = wait; + } else { + ptr.swork.mem_region = CVMX_IO_SEG; + ptr.swork.is_io = 1; + ptr.swork.did = CVMX_OCT_DID_TAG_SWTAG; + ptr.swork.wait = wait; + } + + result.u64 = csr_rd(ptr.u64); + if (result.s_work.no_work) + return NULL; + else + return (cvmx_wqe_t *)cvmx_phys_to_ptr(result.s_work.addr); +} + +/** + * Synchronous work request. Requests work from the POW. + * This function waits for any previous tag switch to complete before + * requesting the new work. + * + * @param wait When set, call stalls until work becomes available, or + * times out. If not set, returns immediately. + * + * @return Returns the WQE pointer from POW. Returns NULL if no work was + * available. + */ +static inline cvmx_wqe_t *cvmx_pow_work_request_sync(cvmx_pow_wait_t wait) +{ + /* Must not have a switch pending when requesting work */ + cvmx_pow_tag_sw_wait(); + return (cvmx_pow_work_request_sync_nocheck(wait)); +} + +/** + * Synchronous null_rd request. Requests a switch out of NULL_NULL POW state. + * This function waits for any previous tag switch to complete before + * requesting the null_rd. + * + * @return Returns the POW state of type cvmx_pow_tag_type_t. + */ +static inline cvmx_pow_tag_type_t cvmx_pow_work_request_null_rd(void) +{ + cvmx_pow_load_addr_t ptr; + cvmx_pow_tag_load_resp_t result; + + /* Must not have a switch pending when requesting work */ + cvmx_pow_tag_sw_wait(); + + ptr.u64 = 0; + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + ptr.swork_78xx.mem_region = CVMX_IO_SEG; + ptr.swork_78xx.is_io = 1; + ptr.swork_78xx.did = CVMX_OCT_DID_TAG_NULL_RD; + ptr.swork_78xx.node = cvmx_get_node_num(); + } else { + ptr.snull_rd.mem_region = CVMX_IO_SEG; + ptr.snull_rd.is_io = 1; + ptr.snull_rd.did = CVMX_OCT_DID_TAG_NULL_RD; + } + result.u64 = csr_rd(ptr.u64); + return (cvmx_pow_tag_type_t)result.s_null_rd.state; +} + +/** + * Asynchronous work request. + * Work is requested from the POW unit, and should later be checked with + * function cvmx_pow_work_response_async. + * This function does NOT wait for previous tag switches to complete, + * so the caller must ensure that there is not a pending tag switch. + * + * @param scr_addr Scratch memory address that response will be returned to, + * which is either a valid WQE, or a response with the invalid bit set. + * Byte address, must be 8 byte aligned. + * @param wait 1 to cause response to wait for work to become available + * (or timeout) + * 0 to cause response to return immediately + */ +static inline void cvmx_pow_work_request_async_nocheck(int scr_addr, cvmx_pow_wait_t wait) +{ + cvmx_pow_iobdma_store_t data; + + if (CVMX_ENABLE_POW_CHECKS) + __cvmx_pow_warn_if_pending_switch(__func__); + + /* scr_addr must be 8 byte aligned */ + data.u64 = 0; + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + data.s_cn78xx.node = cvmx_get_node_num(); + data.s_cn78xx.scraddr = scr_addr >> 3; + data.s_cn78xx.len = 1; + data.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; + data.s_cn78xx.wait = wait; + } else { + data.s.scraddr = scr_addr >> 3; + data.s.len = 1; + data.s.did = CVMX_OCT_DID_TAG_SWTAG; + data.s.wait = wait; + } + cvmx_send_single(data.u64); +} + +/** + * Asynchronous work request. + * Work is requested from the POW unit, and should later be checked with + * function cvmx_pow_work_response_async. + * This function waits for any previous tag switch to complete before + * requesting the new work. + * + * @param scr_addr Scratch memory address that response will be returned to, + * which is either a valid WQE, or a response with the invalid bit set. + * Byte address, must be 8 byte aligned. + * @param wait 1 to cause response to wait for work to become available + * (or timeout) + * 0 to cause response to return immediately + */ +static inline void cvmx_pow_work_request_async(int scr_addr, cvmx_pow_wait_t wait) +{ + /* Must not have a switch pending when requesting work */ + cvmx_pow_tag_sw_wait(); + cvmx_pow_work_request_async_nocheck(scr_addr, wait); +} + +/** + * Gets result of asynchronous work request. Performs a IOBDMA sync + * to wait for the response. + * + * @param scr_addr Scratch memory address to get result from + * Byte address, must be 8 byte aligned. + * @return Returns the WQE from the scratch register, or NULL if no work was + * available. + */ +static inline cvmx_wqe_t *cvmx_pow_work_response_async(int scr_addr) +{ + cvmx_pow_tag_load_resp_t result; + + CVMX_SYNCIOBDMA; + result.u64 = cvmx_scratch_read64(scr_addr); + if (result.s_work.no_work) + return NULL; + else + return (cvmx_wqe_t *)cvmx_phys_to_ptr(result.s_work.addr); +} + +/** + * Checks if a work queue entry pointer returned by a work + * request is valid. It may be invalid due to no work + * being available or due to a timeout. + * + * @param wqe_ptr pointer to a work queue entry returned by the POW + * + * @return 0 if pointer is valid + * 1 if invalid (no work was returned) + */ +static inline u64 cvmx_pow_work_invalid(cvmx_wqe_t *wqe_ptr) +{ + return (!wqe_ptr); /* FIXME: improve */ +} + +/** + * Starts a tag switch to the provided tag value and tag type. Completion for + * the tag switch must be checked for separately. + * This function does NOT update the + * work queue entry in dram to match tag value and type, so the application must + * keep track of these if they are important to the application. + * This tag switch command must not be used for switches to NULL, as the tag + * switch pending bit will be set by the switch request, but never cleared by + * the hardware. + * + * NOTE: This should not be used when switching from a NULL tag. Use + * cvmx_pow_tag_sw_full() instead. + * + * This function does no checks, so the caller must ensure that any previous tag + * switch has completed. + * + * @param tag new tag value + * @param tag_type new tag type (ordered or atomic) + */ +static inline void cvmx_pow_tag_sw_nocheck(u32 tag, cvmx_pow_tag_type_t tag_type) +{ + union cvmx_pow_tag_req_addr ptr; + cvmx_pow_tag_req_t tag_req; + + if (CVMX_ENABLE_POW_CHECKS) { + cvmx_pow_tag_info_t current_tag; + + __cvmx_pow_warn_if_pending_switch(__func__); + current_tag = cvmx_pow_get_current_tag(); + cvmx_warn_if(current_tag.tag_type == CVMX_POW_TAG_TYPE_NULL_NULL, + "%s called with NULL_NULL tag\n", __func__); + cvmx_warn_if(current_tag.tag_type == CVMX_POW_TAG_TYPE_NULL, + "%s called with NULL tag\n", __func__); + cvmx_warn_if((current_tag.tag_type == tag_type) && (current_tag.tag == tag), + "%s called to perform a tag switch to the same tag\n", __func__); + cvmx_warn_if( + tag_type == CVMX_POW_TAG_TYPE_NULL, + "%s called to perform a tag switch to NULL. Use cvmx_pow_tag_sw_null() instead\n", + __func__); + } + + /* + * Note that WQE in DRAM is not updated here, as the POW does not read + * from DRAM once the WQE is in flight. See hardware manual for + * complete details. + * It is the application's responsibility to keep track of the + * current tag value if that is important. + */ + tag_req.u64 = 0; + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG; + tag_req.s_cn78xx_other.type = tag_type; + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + tag_req.s_cn68xx_other.op = CVMX_POW_TAG_OP_SWTAG; + tag_req.s_cn68xx_other.tag = tag; + tag_req.s_cn68xx_other.type = tag_type; + } else { + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_SWTAG; + tag_req.s_cn38xx.tag = tag; + tag_req.s_cn38xx.type = tag_type; + } + ptr.u64 = 0; + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; + ptr.s_cn78xx.is_io = 1; + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; + ptr.s_cn78xx.node = cvmx_get_node_num(); + ptr.s_cn78xx.tag = tag; + } else { + ptr.s.mem_region = CVMX_IO_SEG; + ptr.s.is_io = 1; + ptr.s.did = CVMX_OCT_DID_TAG_SWTAG; + } + /* Once this store arrives at POW, it will attempt the switch + software must wait for the switch to complete separately */ + cvmx_write_io(ptr.u64, tag_req.u64); +} + +/** + * Starts a tag switch to the provided tag value and tag type. Completion for + * the tag switch must be checked for separately. + * This function does NOT update the + * work queue entry in dram to match tag value and type, so the application must + * keep track of these if they are important to the application. + * This tag switch command must not be used for switches to NULL, as the tag + * switch pending bit will be set by the switch request, but never cleared by + * the hardware. + * + * NOTE: This should not be used when switching from a NULL tag. Use + * cvmx_pow_tag_sw_full() instead. + * + * This function waits for any previous tag switch to complete, and also + * displays an error on tag switches to NULL. + * + * @param tag new tag value + * @param tag_type new tag type (ordered or atomic) + */ +static inline void cvmx_pow_tag_sw(u32 tag, cvmx_pow_tag_type_t tag_type) +{ + /* + * Note that WQE in DRAM is not updated here, as the POW does not read + * from DRAM once the WQE is in flight. See hardware manual for + * complete details. It is the application's responsibility to keep + * track of the current tag value if that is important. + */ + + /* + * Ensure that there is not a pending tag switch, as a tag switch + * cannot be started if a previous switch is still pending. + */ + cvmx_pow_tag_sw_wait(); + cvmx_pow_tag_sw_nocheck(tag, tag_type); +} + +/** + * Starts a tag switch to the provided tag value and tag type. Completion for + * the tag switch must be checked for separately. + * This function does NOT update the + * work queue entry in dram to match tag value and type, so the application must + * keep track of these if they are important to the application. + * This tag switch command must not be used for switches to NULL, as the tag + * switch pending bit will be set by the switch request, but never cleared by + * the hardware. + * + * This function must be used for tag switches from NULL. + * + * This function does no checks, so the caller must ensure that any previous tag + * switch has completed. + * + * @param wqp pointer to work queue entry to submit. This entry is + * updated to match the other parameters + * @param tag tag value to be assigned to work queue entry + * @param tag_type type of tag + * @param group group value for the work queue entry. + */ +static inline void cvmx_pow_tag_sw_full_nocheck(cvmx_wqe_t *wqp, u32 tag, + cvmx_pow_tag_type_t tag_type, u64 group) +{ + union cvmx_pow_tag_req_addr ptr; + cvmx_pow_tag_req_t tag_req; + unsigned int node = cvmx_get_node_num(); + u64 wqp_phys = cvmx_ptr_to_phys(wqp); + + if (CVMX_ENABLE_POW_CHECKS) { + cvmx_pow_tag_info_t current_tag; + + __cvmx_pow_warn_if_pending_switch(__func__); + current_tag = cvmx_pow_get_current_tag(); + cvmx_warn_if(current_tag.tag_type == CVMX_POW_TAG_TYPE_NULL_NULL, + "%s called with NULL_NULL tag\n", __func__); + cvmx_warn_if((current_tag.tag_type == tag_type) && (current_tag.tag == tag), + "%s called to perform a tag switch to the same tag\n", __func__); + cvmx_warn_if( + tag_type == CVMX_POW_TAG_TYPE_NULL, + "%s called to perform a tag switch to NULL. Use cvmx_pow_tag_sw_null() instead\n", + __func__); + if ((wqp != cvmx_phys_to_ptr(0x80)) && cvmx_pow_get_current_wqp()) + cvmx_warn_if(wqp != cvmx_pow_get_current_wqp(), + "%s passed WQE(%p) doesn't match the address in the POW(%p)\n", + __func__, wqp, cvmx_pow_get_current_wqp()); + } + + /* + * Note that WQE in DRAM is not updated here, as the POW does not + * read from DRAM once the WQE is in flight. See hardware manual + * for complete details. It is the application's responsibility to + * keep track of the current tag value if that is important. + */ + tag_req.u64 = 0; + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + unsigned int xgrp; + + if (wqp_phys != 0x80) { + /* If WQE is valid, use its XGRP: + * WQE GRP is 10 bits, and is mapped + * to legacy GRP + QoS, includes node number. + */ + xgrp = wqp->word1.cn78xx.grp; + /* Use XGRP[node] too */ + node = xgrp >> 8; + /* Modify XGRP with legacy group # from arg */ + xgrp &= ~0xf8; + xgrp |= 0xf8 & (group << 3); + + } else { + /* If no WQE, build XGRP with QoS=0 and current node */ + xgrp = group << 3; + xgrp |= node << 8; + } + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG_FULL; + tag_req.s_cn78xx_other.type = tag_type; + tag_req.s_cn78xx_other.grp = xgrp; + tag_req.s_cn78xx_other.wqp = wqp_phys; + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + tag_req.s_cn68xx_other.op = CVMX_POW_TAG_OP_SWTAG_FULL; + tag_req.s_cn68xx_other.tag = tag; + tag_req.s_cn68xx_other.type = tag_type; + tag_req.s_cn68xx_other.grp = group; + } else { + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_SWTAG_FULL; + tag_req.s_cn38xx.tag = tag; + tag_req.s_cn38xx.type = tag_type; + tag_req.s_cn38xx.grp = group; + } + ptr.u64 = 0; + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; + ptr.s_cn78xx.is_io = 1; + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; + ptr.s_cn78xx.node = node; + ptr.s_cn78xx.tag = tag; + } else { + ptr.s.mem_region = CVMX_IO_SEG; + ptr.s.is_io = 1; + ptr.s.did = CVMX_OCT_DID_TAG_SWTAG; + ptr.s.addr = wqp_phys; + } + /* Once this store arrives at POW, it will attempt the switch + software must wait for the switch to complete separately */ + cvmx_write_io(ptr.u64, tag_req.u64); +} + +/** + * Starts a tag switch to the provided tag value and tag type. + * Completion for the tag switch must be checked for separately. + * This function does NOT update the work queue entry in dram to match tag value + * and type, so the application must keep track of these if they are important + * to the application. This tag switch command must not be used for switches + * to NULL, as the tag switch pending bit will be set by the switch request, + * but never cleared by the hardware. + * + * This function must be used for tag switches from NULL. + * + * This function waits for any pending tag switches to complete + * before requesting the tag switch. + * + * @param wqp Pointer to work queue entry to submit. + * This entry is updated to match the other parameters + * @param tag Tag value to be assigned to work queue entry + * @param tag_type Type of tag + * @param group Group value for the work queue entry. + */ +static inline void cvmx_pow_tag_sw_full(cvmx_wqe_t *wqp, u32 tag, cvmx_pow_tag_type_t tag_type, + u64 group) +{ + /* + * Ensure that there is not a pending tag switch, as a tag switch cannot + * be started if a previous switch is still pending. + */ + cvmx_pow_tag_sw_wait(); + cvmx_pow_tag_sw_full_nocheck(wqp, tag, tag_type, group); +} + +/** + * Switch to a NULL tag, which ends any ordering or + * synchronization provided by the POW for the current + * work queue entry. This operation completes immediately, + * so completion should not be waited for. + * This function does NOT wait for previous tag switches to complete, + * so the caller must ensure that any previous tag switches have completed. + */ +static inline void cvmx_pow_tag_sw_null_nocheck(void) +{ + union cvmx_pow_tag_req_addr ptr; + cvmx_pow_tag_req_t tag_req; + + if (CVMX_ENABLE_POW_CHECKS) { + cvmx_pow_tag_info_t current_tag; + + __cvmx_pow_warn_if_pending_switch(__func__); + current_tag = cvmx_pow_get_current_tag(); + cvmx_warn_if(current_tag.tag_type == CVMX_POW_TAG_TYPE_NULL_NULL, + "%s called with NULL_NULL tag\n", __func__); + cvmx_warn_if(current_tag.tag_type == CVMX_POW_TAG_TYPE_NULL, + "%s called when we already have a NULL tag\n", __func__); + } + tag_req.u64 = 0; + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG; + tag_req.s_cn78xx_other.type = CVMX_POW_TAG_TYPE_NULL; + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + tag_req.s_cn68xx_other.op = CVMX_POW_TAG_OP_SWTAG; + tag_req.s_cn68xx_other.type = CVMX_POW_TAG_TYPE_NULL; + } else { + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_SWTAG; + tag_req.s_cn38xx.type = CVMX_POW_TAG_TYPE_NULL; + } + ptr.u64 = 0; + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; + ptr.s_cn78xx.is_io = 1; + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_TAG1; + ptr.s_cn78xx.node = cvmx_get_node_num(); + } else { + ptr.s.mem_region = CVMX_IO_SEG; + ptr.s.is_io = 1; + ptr.s.did = CVMX_OCT_DID_TAG_TAG1; + } + cvmx_write_io(ptr.u64, tag_req.u64); +} + +/** + * Switch to a NULL tag, which ends any ordering or + * synchronization provided by the POW for the current + * work queue entry. This operation completes immediately, + * so completion should not be waited for. + * This function waits for any pending tag switches to complete + * before requesting the switch to NULL. + */ +static inline void cvmx_pow_tag_sw_null(void) +{ + /* + * Ensure that there is not a pending tag switch, as a tag switch cannot + * be started if a previous switch is still pending. + */ + cvmx_pow_tag_sw_wait(); + cvmx_pow_tag_sw_null_nocheck(); +} + +/** + * Submits work to an input queue. + * This function updates the work queue entry in DRAM to match the arguments given. + * Note that the tag provided is for the work queue entry submitted, and + * is unrelated to the tag that the core currently holds. + * + * @param wqp pointer to work queue entry to submit. + * This entry is updated to match the other parameters + * @param tag tag value to be assigned to work queue entry + * @param tag_type type of tag + * @param qos Input queue to add to. + * @param grp group value for the work queue entry. + */ +static inline void cvmx_pow_work_submit(cvmx_wqe_t *wqp, u32 tag, cvmx_pow_tag_type_t tag_type, + u64 qos, u64 grp) +{ + union cvmx_pow_tag_req_addr ptr; + cvmx_pow_tag_req_t tag_req; + + tag_req.u64 = 0; + ptr.u64 = 0; + + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + unsigned int node = cvmx_get_node_num(); + unsigned int xgrp; + + xgrp = (grp & 0x1f) << 3; + xgrp |= (qos & 7); + xgrp |= 0x300 & (node << 8); + + wqp->word1.cn78xx.rsvd_0 = 0; + wqp->word1.cn78xx.rsvd_1 = 0; + wqp->word1.cn78xx.tag = tag; + wqp->word1.cn78xx.tag_type = tag_type; + wqp->word1.cn78xx.grp = xgrp; + CVMX_SYNCWS; + + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_ADDWQ; + tag_req.s_cn78xx_other.type = tag_type; + tag_req.s_cn78xx_other.wqp = cvmx_ptr_to_phys(wqp); + tag_req.s_cn78xx_other.grp = xgrp; + + ptr.s_cn78xx.did = 0x66; // CVMX_OCT_DID_TAG_TAG6; + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; + ptr.s_cn78xx.is_io = 1; + ptr.s_cn78xx.node = node; + ptr.s_cn78xx.tag = tag; + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + /* Reset all reserved bits */ + wqp->word1.cn68xx.zero_0 = 0; + wqp->word1.cn68xx.zero_1 = 0; + wqp->word1.cn68xx.zero_2 = 0; + wqp->word1.cn68xx.qos = qos; + wqp->word1.cn68xx.grp = grp; + + wqp->word1.tag = tag; + wqp->word1.tag_type = tag_type; + + tag_req.s_cn68xx_add.op = CVMX_POW_TAG_OP_ADDWQ; + tag_req.s_cn68xx_add.type = tag_type; + tag_req.s_cn68xx_add.tag = tag; + tag_req.s_cn68xx_add.qos = qos; + tag_req.s_cn68xx_add.grp = grp; + + ptr.s.mem_region = CVMX_IO_SEG; + ptr.s.is_io = 1; + ptr.s.did = CVMX_OCT_DID_TAG_TAG1; + ptr.s.addr = cvmx_ptr_to_phys(wqp); + } else { + /* Reset all reserved bits */ + wqp->word1.cn38xx.zero_2 = 0; + wqp->word1.cn38xx.qos = qos; + wqp->word1.cn38xx.grp = grp; + + wqp->word1.tag = tag; + wqp->word1.tag_type = tag_type; + + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_ADDWQ; + tag_req.s_cn38xx.type = tag_type; + tag_req.s_cn38xx.tag = tag; + tag_req.s_cn38xx.qos = qos; + tag_req.s_cn38xx.grp = grp; + + ptr.s.mem_region = CVMX_IO_SEG; + ptr.s.is_io = 1; + ptr.s.did = CVMX_OCT_DID_TAG_TAG1; + ptr.s.addr = cvmx_ptr_to_phys(wqp); + } + /* SYNC write to memory before the work submit. + * This is necessary as POW may read values from DRAM at this time */ + CVMX_SYNCWS; + cvmx_write_io(ptr.u64, tag_req.u64); +} + +/** + * This function sets the group mask for a core. The group mask + * indicates which groups each core will accept work from. There are + * 16 groups. + * + * @param core_num core to apply mask to + * @param mask Group mask, one bit for up to 64 groups. + * Each 1 bit in the mask enables the core to accept work from + * the corresponding group. + * The CN68XX supports 64 groups, earlier models only support + * 16 groups. + * + * The CN78XX in backwards compatibility mode allows up to 32 groups, + * so the 'mask' argument has one bit for every of the legacy + * groups, and a '1' in the mask causes a total of 8 groups + * which share the legacy group numbher and 8 qos levels, + * to be enabled for the calling processor core. + * A '0' in the mask will disable the current core + * from receiving work from the associated group. + */ +static inline void cvmx_pow_set_group_mask(u64 core_num, u64 mask) +{ + u64 valid_mask; + int num_groups = cvmx_pow_num_groups(); + + if (num_groups >= 64) + valid_mask = ~0ull; + else + valid_mask = (1ull << num_groups) - 1; + + if ((mask & valid_mask) == 0) { + printf("ERROR: %s empty group mask disables work on core# %llu, ignored.\n", + __func__, (unsigned long long)core_num); + return; + } + cvmx_warn_if(mask & (~valid_mask), "%s group number range exceeded: %#llx\n", __func__, + (unsigned long long)mask); + + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + unsigned int mask_set; + cvmx_sso_ppx_sx_grpmskx_t grp_msk; + unsigned int core, node; + unsigned int rix; /* Register index */ + unsigned int grp; /* Legacy group # */ + unsigned int bit; /* bit index */ + unsigned int xgrp; /* native group # */ + + node = cvmx_coremask_core_to_node(core_num); + core = cvmx_coremask_core_on_node(core_num); + + /* 78xx: 256 groups divided into 4 X 64 bit registers */ + /* 73xx: 64 groups are in one register */ + for (rix = 0; rix < (cvmx_sso_num_xgrp() >> 6); rix++) { + grp_msk.u64 = 0; + for (bit = 0; bit < 64; bit++) { + /* 8-bit native XGRP number */ + xgrp = (rix << 6) | bit; + /* Legacy 5-bit group number */ + grp = (xgrp >> 3) & 0x1f; + /* Inspect legacy mask by legacy group */ + if (mask & (1ull << grp)) + grp_msk.s.grp_msk |= 1ull << bit; + /* Pre-set to all 0's */ + } + for (mask_set = 0; mask_set < cvmx_sso_num_maskset(); mask_set++) { + csr_wr_node(node, CVMX_SSO_PPX_SX_GRPMSKX(core, mask_set, rix), + grp_msk.u64); + } + } + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + cvmx_sso_ppx_grp_msk_t grp_msk; + + grp_msk.s.grp_msk = mask; + csr_wr(CVMX_SSO_PPX_GRP_MSK(core_num), grp_msk.u64); + } else { + cvmx_pow_pp_grp_mskx_t grp_msk; + + grp_msk.u64 = csr_rd(CVMX_POW_PP_GRP_MSKX(core_num)); + grp_msk.s.grp_msk = mask & 0xffff; + csr_wr(CVMX_POW_PP_GRP_MSKX(core_num), grp_msk.u64); + } +} + +/** + * This function gets the group mask for a core. The group mask + * indicates which groups each core will accept work from. + * + * @param core_num core to apply mask to + * @return Group mask, one bit for up to 64 groups. + * Each 1 bit in the mask enables the core to accept work from + * the corresponding group. + * The CN68XX supports 64 groups, earlier models only support + * 16 groups. + * + * The CN78XX in backwards compatibility mode allows up to 32 groups, + * so the 'mask' argument has one bit for every of the legacy + * groups, and a '1' in the mask causes a total of 8 groups + * which share the legacy group numbher and 8 qos levels, + * to be enabled for the calling processor core. + * A '0' in the mask will disable the current core + * from receiving work from the associated group. + */ +static inline u64 cvmx_pow_get_group_mask(u64 core_num) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_sso_ppx_sx_grpmskx_t grp_msk; + unsigned int core, node, i; + int rix; /* Register index */ + u64 mask = 0; + + node = cvmx_coremask_core_to_node(core_num); + core = cvmx_coremask_core_on_node(core_num); + + /* 78xx: 256 groups divided into 4 X 64 bit registers */ + /* 73xx: 64 groups are in one register */ + for (rix = (cvmx_sso_num_xgrp() >> 6) - 1; rix >= 0; rix--) { + /* read only mask_set=0 (both 'set' was written same) */ + grp_msk.u64 = csr_rd_node(node, CVMX_SSO_PPX_SX_GRPMSKX(core, 0, rix)); + /* ASSUME: (this is how mask bits got written) */ + /* grp_mask[7:0]: all bits 0..7 are same */ + /* grp_mask[15:8]: all bits 8..15 are same, etc */ + /* DO: mask[7:0] = grp_mask.u64[56,48,40,32,24,16,8,0] */ + for (i = 0; i < 8; i++) + mask |= (grp_msk.u64 & ((u64)1 << (i * 8))) >> (7 * i); + /* we collected 8 MSBs in mask[7:0], <<=8 and continue */ + if (cvmx_likely(rix != 0)) + mask <<= 8; + } + return mask & 0xFFFFFFFF; + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + cvmx_sso_ppx_grp_msk_t grp_msk; + + grp_msk.u64 = csr_rd(CVMX_SSO_PPX_GRP_MSK(core_num)); + return grp_msk.u64; + } else { + cvmx_pow_pp_grp_mskx_t grp_msk; + + grp_msk.u64 = csr_rd(CVMX_POW_PP_GRP_MSKX(core_num)); + return grp_msk.u64 & 0xffff; + } +} + +/* + * Returns 0 if 78xx(73xx,75xx) is not programmed in legacy compatible mode + * Returns 1 if 78xx(73xx,75xx) is programmed in legacy compatible mode + * Returns 1 if octeon model is not 78xx(73xx,75xx) + */ +static inline u64 cvmx_pow_is_legacy78mode(u64 core_num) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_sso_ppx_sx_grpmskx_t grp_msk0, grp_msk1; + unsigned int core, node, i; + int rix; /* Register index */ + u64 mask = 0; + + node = cvmx_coremask_core_to_node(core_num); + core = cvmx_coremask_core_on_node(core_num); + + /* 78xx: 256 groups divided into 4 X 64 bit registers */ + /* 73xx: 64 groups are in one register */ + /* 1) in order for the 78_SSO to be in legacy compatible mode + * the both mask_sets should be programmed the same */ + for (rix = (cvmx_sso_num_xgrp() >> 6) - 1; rix >= 0; rix--) { + /* read mask_set=0 (both 'set' was written same) */ + grp_msk0.u64 = csr_rd_node(node, CVMX_SSO_PPX_SX_GRPMSKX(core, 0, rix)); + grp_msk1.u64 = csr_rd_node(node, CVMX_SSO_PPX_SX_GRPMSKX(core, 1, rix)); + if (grp_msk0.u64 != grp_msk1.u64) { + return 0; + } + /* (this is how mask bits should be written) */ + /* grp_mask[7:0]: all bits 0..7 are same */ + /* grp_mask[15:8]: all bits 8..15 are same, etc */ + /* 2) in order for the 78_SSO to be in legacy compatible + * mode above should be true (test only mask_set=0 */ + for (i = 0; i < 8; i++) { + mask = (grp_msk0.u64 >> (i << 3)) & 0xFF; + if (!(mask == 0 || mask == 0xFF)) { + return 0; + } + } + } + /* if we come here, the 78_SSO is in legacy compatible mode */ + } + return 1; /* the SSO/POW is in legacy (or compatible) mode */ +} + +/** + * This function sets POW static priorities for a core. Each input queue has + * an associated priority value. + * + * @param core_num core to apply priorities to + * @param priority Vector of 8 priorities, one per POW Input Queue (0-7). + * Highest priority is 0 and lowest is 7. A priority value + * of 0xF instructs POW to skip the Input Queue when + * scheduling to this specific core. + * NOTE: priorities should not have gaps in values, meaning + * {0,1,1,1,1,1,1,1} is a valid configuration while + * {0,2,2,2,2,2,2,2} is not. + */ +static inline void cvmx_pow_set_priority(u64 core_num, const u8 priority[]) +{ + /* Detect gaps between priorities and flag error */ + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + int i; + u32 prio_mask = 0; + + for (i = 0; i < 8; i++) + if (priority[i] != 0xF) + prio_mask |= 1 << priority[i]; + + if (prio_mask ^ ((1 << cvmx_pop(prio_mask)) - 1)) { + debug("ERROR: POW static priorities should be contiguous (0x%llx)\n", + (unsigned long long)prio_mask); + return; + } + } + + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + unsigned int group; + unsigned int node = cvmx_get_node_num(); + cvmx_sso_grpx_pri_t grp_pri; + + /*grp_pri.s.weight = 0x3f; these will be anyway overwritten */ + /*grp_pri.s.affinity = 0xf; by the next csr_rd_node(..), */ + + for (group = 0; group < cvmx_sso_num_xgrp(); group++) { + grp_pri.u64 = csr_rd_node(node, CVMX_SSO_GRPX_PRI(group)); + grp_pri.s.pri = priority[group & 0x7]; + csr_wr_node(node, CVMX_SSO_GRPX_PRI(group), grp_pri.u64); + } + + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + cvmx_sso_ppx_qos_pri_t qos_pri; + + qos_pri.u64 = csr_rd(CVMX_SSO_PPX_QOS_PRI(core_num)); + qos_pri.s.qos0_pri = priority[0]; + qos_pri.s.qos1_pri = priority[1]; + qos_pri.s.qos2_pri = priority[2]; + qos_pri.s.qos3_pri = priority[3]; + qos_pri.s.qos4_pri = priority[4]; + qos_pri.s.qos5_pri = priority[5]; + qos_pri.s.qos6_pri = priority[6]; + qos_pri.s.qos7_pri = priority[7]; + csr_wr(CVMX_SSO_PPX_QOS_PRI(core_num), qos_pri.u64); + } else { + /* POW priorities on CN5xxx .. CN66XX */ + cvmx_pow_pp_grp_mskx_t grp_msk; + + grp_msk.u64 = csr_rd(CVMX_POW_PP_GRP_MSKX(core_num)); + grp_msk.s.qos0_pri = priority[0]; + grp_msk.s.qos1_pri = priority[1]; + grp_msk.s.qos2_pri = priority[2]; + grp_msk.s.qos3_pri = priority[3]; + grp_msk.s.qos4_pri = priority[4]; + grp_msk.s.qos5_pri = priority[5]; + grp_msk.s.qos6_pri = priority[6]; + grp_msk.s.qos7_pri = priority[7]; + + csr_wr(CVMX_POW_PP_GRP_MSKX(core_num), grp_msk.u64); + } +} + +/** + * This function gets POW static priorities for a core. Each input queue has + * an associated priority value. + * + * @param[in] core_num core to get priorities for + * @param[out] priority Pointer to u8[] where to return priorities + * Vector of 8 priorities, one per POW Input Queue (0-7). + * Highest priority is 0 and lowest is 7. A priority value + * of 0xF instructs POW to skip the Input Queue when + * scheduling to this specific core. + * NOTE: priorities should not have gaps in values, meaning + * {0,1,1,1,1,1,1,1} is a valid configuration while + * {0,2,2,2,2,2,2,2} is not. + */ +static inline void cvmx_pow_get_priority(u64 core_num, u8 priority[]) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + unsigned int group; + unsigned int node = cvmx_get_node_num(); + cvmx_sso_grpx_pri_t grp_pri; + + /* read priority only from the first 8 groups */ + /* the next groups are programmed the same (periodicaly) */ + for (group = 0; group < 8 /*cvmx_sso_num_xgrp() */; group++) { + grp_pri.u64 = csr_rd_node(node, CVMX_SSO_GRPX_PRI(group)); + priority[group /* & 0x7 */] = grp_pri.s.pri; + } + + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + cvmx_sso_ppx_qos_pri_t qos_pri; + + qos_pri.u64 = csr_rd(CVMX_SSO_PPX_QOS_PRI(core_num)); + priority[0] = qos_pri.s.qos0_pri; + priority[1] = qos_pri.s.qos1_pri; + priority[2] = qos_pri.s.qos2_pri; + priority[3] = qos_pri.s.qos3_pri; + priority[4] = qos_pri.s.qos4_pri; + priority[5] = qos_pri.s.qos5_pri; + priority[6] = qos_pri.s.qos6_pri; + priority[7] = qos_pri.s.qos7_pri; + } else { + /* POW priorities on CN5xxx .. CN66XX */ + cvmx_pow_pp_grp_mskx_t grp_msk; + + grp_msk.u64 = csr_rd(CVMX_POW_PP_GRP_MSKX(core_num)); + priority[0] = grp_msk.s.qos0_pri; + priority[1] = grp_msk.s.qos1_pri; + priority[2] = grp_msk.s.qos2_pri; + priority[3] = grp_msk.s.qos3_pri; + priority[4] = grp_msk.s.qos4_pri; + priority[5] = grp_msk.s.qos5_pri; + priority[6] = grp_msk.s.qos6_pri; + priority[7] = grp_msk.s.qos7_pri; + } + + /* Detect gaps between priorities and flag error - (optional) */ + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + int i; + u32 prio_mask = 0; + + for (i = 0; i < 8; i++) + if (priority[i] != 0xF) + prio_mask |= 1 << priority[i]; + + if (prio_mask ^ ((1 << cvmx_pop(prio_mask)) - 1)) { + debug("ERROR:%s: POW static priorities should be contiguous (0x%llx)\n", + __func__, (unsigned long long)prio_mask); + return; + } + } +} + +static inline void cvmx_sso_get_group_priority(int node, cvmx_xgrp_t xgrp, int *priority, + int *weight, int *affinity) +{ + cvmx_sso_grpx_pri_t grp_pri; + + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + debug("ERROR: %s is not supported on this chip)\n", __func__); + return; + } + + grp_pri.u64 = csr_rd_node(node, CVMX_SSO_GRPX_PRI(xgrp.xgrp)); + *affinity = grp_pri.s.affinity; + *priority = grp_pri.s.pri; + *weight = grp_pri.s.weight; +} + +/** + * Performs a tag switch and then an immediate deschedule. This completes + * immediately, so completion must not be waited for. This function does NOT + * update the wqe in DRAM to match arguments. + * + * This function does NOT wait for any prior tag switches to complete, so the + * calling code must do this. + * + * Note the following CAVEAT of the Octeon HW behavior when + * re-scheduling DE-SCHEDULEd items whose (next) state is + * ORDERED: + * - If there are no switches pending at the time that the + * HW executes the de-schedule, the HW will only re-schedule + * the head of the FIFO associated with the given tag. This + * means that in many respects, the HW treats this ORDERED + * tag as an ATOMIC tag. Note that in the SWTAG_DESCH + * case (to an ORDERED tag), the HW will do the switch + * before the deschedule whenever it is possible to do + * the switch immediately, so it may often look like + * this case. + * - If there is a pending switch to ORDERED at the time + * the HW executes the de-schedule, the HW will perform + * the switch at the time it re-schedules, and will be + * able to reschedule any/all of the entries with the + * same tag. + * Due to this behavior, the RECOMMENDATION to software is + * that they have a (next) state of ATOMIC when they + * DE-SCHEDULE. If an ORDERED tag is what was really desired, + * SW can choose to immediately switch to an ORDERED tag + * after the work (that has an ATOMIC tag) is re-scheduled. + * Note that since there are never any tag switches pending + * when the HW re-schedules, this switch can be IMMEDIATE upon + * the reception of the pointer during the re-schedule. + * + * @param tag New tag value + * @param tag_type New tag type + * @param group New group value + * @param no_sched Control whether this work queue entry will be rescheduled. + * - 1 : don't schedule this work + * - 0 : allow this work to be scheduled. + */ +static inline void cvmx_pow_tag_sw_desched_nocheck(u32 tag, cvmx_pow_tag_type_t tag_type, u64 group, + u64 no_sched) +{ + union cvmx_pow_tag_req_addr ptr; + cvmx_pow_tag_req_t tag_req; + + if (CVMX_ENABLE_POW_CHECKS) { + cvmx_pow_tag_info_t current_tag; + + __cvmx_pow_warn_if_pending_switch(__func__); + current_tag = cvmx_pow_get_current_tag(); + cvmx_warn_if(current_tag.tag_type == CVMX_POW_TAG_TYPE_NULL_NULL, + "%s called with NULL_NULL tag\n", __func__); + cvmx_warn_if(current_tag.tag_type == CVMX_POW_TAG_TYPE_NULL, + "%s called with NULL tag. Deschedule not allowed from NULL state\n", + __func__); + cvmx_warn_if((current_tag.tag_type != CVMX_POW_TAG_TYPE_ATOMIC) && + (tag_type != CVMX_POW_TAG_TYPE_ATOMIC), + "%s called where neither the before or after tag is ATOMIC\n", + __func__); + } + tag_req.u64 = 0; + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_t *wqp = cvmx_pow_get_current_wqp(); + + if (!wqp) { + debug("ERROR: Failed to get WQE, %s\n", __func__); + return; + } + group &= 0x1f; + wqp->word1.cn78xx.tag = tag; + wqp->word1.cn78xx.tag_type = tag_type; + wqp->word1.cn78xx.grp = group << 3; + CVMX_SYNCWS; + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG_DESCH; + tag_req.s_cn78xx_other.type = tag_type; + tag_req.s_cn78xx_other.grp = group << 3; + tag_req.s_cn78xx_other.no_sched = no_sched; + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + group &= 0x3f; + tag_req.s_cn68xx_other.op = CVMX_POW_TAG_OP_SWTAG_DESCH; + tag_req.s_cn68xx_other.tag = tag; + tag_req.s_cn68xx_other.type = tag_type; + tag_req.s_cn68xx_other.grp = group; + tag_req.s_cn68xx_other.no_sched = no_sched; + } else { + group &= 0x0f; + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_SWTAG_DESCH; + tag_req.s_cn38xx.tag = tag; + tag_req.s_cn38xx.type = tag_type; + tag_req.s_cn38xx.grp = group; + tag_req.s_cn38xx.no_sched = no_sched; + } + ptr.u64 = 0; + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + ptr.s.mem_region = CVMX_IO_SEG; + ptr.s.is_io = 1; + ptr.s.did = CVMX_OCT_DID_TAG_TAG3; + ptr.s_cn78xx.node = cvmx_get_node_num(); + ptr.s_cn78xx.tag = tag; + } else { + ptr.s.mem_region = CVMX_IO_SEG; + ptr.s.is_io = 1; + ptr.s.did = CVMX_OCT_DID_TAG_TAG3; + } + cvmx_write_io(ptr.u64, tag_req.u64); +} + +/** + * Performs a tag switch and then an immediate deschedule. This completes + * immediately, so completion must not be waited for. This function does NOT + * update the wqe in DRAM to match arguments. + * + * This function waits for any prior tag switches to complete, so the + * calling code may call this function with a pending tag switch. + * + * Note the following CAVEAT of the Octeon HW behavior when + * re-scheduling DE-SCHEDULEd items whose (next) state is + * ORDERED: + * - If there are no switches pending at the time that the + * HW executes the de-schedule, the HW will only re-schedule + * the head of the FIFO associated with the given tag. This + * means that in many respects, the HW treats this ORDERED + * tag as an ATOMIC tag. Note that in the SWTAG_DESCH + * case (to an ORDERED tag), the HW will do the switch + * before the deschedule whenever it is possible to do + * the switch immediately, so it may often look like + * this case. + * - If there is a pending switch to ORDERED at the time + * the HW executes the de-schedule, the HW will perform + * the switch at the time it re-schedules, and will be + * able to reschedule any/all of the entries with the + * same tag. + * Due to this behavior, the RECOMMENDATION to software is + * that they have a (next) state of ATOMIC when they + * DE-SCHEDULE. If an ORDERED tag is what was really desired, + * SW can choose to immediately switch to an ORDERED tag + * after the work (that has an ATOMIC tag) is re-scheduled. + * Note that since there are never any tag switches pending + * when the HW re-schedules, this switch can be IMMEDIATE upon + * the reception of the pointer during the re-schedule. + * + * @param tag New tag value + * @param tag_type New tag type + * @param group New group value + * @param no_sched Control whether this work queue entry will be rescheduled. + * - 1 : don't schedule this work + * - 0 : allow this work to be scheduled. + */ +static inline void cvmx_pow_tag_sw_desched(u32 tag, cvmx_pow_tag_type_t tag_type, u64 group, + u64 no_sched) +{ + /* Need to make sure any writes to the work queue entry are complete */ + CVMX_SYNCWS; + /* Ensure that there is not a pending tag switch, as a tag switch cannot be started + * if a previous switch is still pending. */ + cvmx_pow_tag_sw_wait(); + cvmx_pow_tag_sw_desched_nocheck(tag, tag_type, group, no_sched); +} + +/** + * Descchedules the current work queue entry. + * + * @param no_sched no schedule flag value to be set on the work queue entry. + * If this is set the entry will not be rescheduled. + */ +static inline void cvmx_pow_desched(u64 no_sched) +{ + union cvmx_pow_tag_req_addr ptr; + cvmx_pow_tag_req_t tag_req; + + if (CVMX_ENABLE_POW_CHECKS) { + cvmx_pow_tag_info_t current_tag; + + __cvmx_pow_warn_if_pending_switch(__func__); + current_tag = cvmx_pow_get_current_tag(); + cvmx_warn_if(current_tag.tag_type == CVMX_POW_TAG_TYPE_NULL_NULL, + "%s called with NULL_NULL tag\n", __func__); + cvmx_warn_if(current_tag.tag_type == CVMX_POW_TAG_TYPE_NULL, + "%s called with NULL tag. Deschedule not expected from NULL state\n", + __func__); + } + /* Need to make sure any writes to the work queue entry are complete */ + CVMX_SYNCWS; + + tag_req.u64 = 0; + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_DESCH; + tag_req.s_cn78xx_other.no_sched = no_sched; + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + tag_req.s_cn68xx_other.op = CVMX_POW_TAG_OP_DESCH; + tag_req.s_cn68xx_other.no_sched = no_sched; + } else { + tag_req.s_cn38xx.op = CVMX_POW_TAG_OP_DESCH; + tag_req.s_cn38xx.no_sched = no_sched; + } + ptr.u64 = 0; + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; + ptr.s_cn78xx.is_io = 1; + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_TAG3; + ptr.s_cn78xx.node = cvmx_get_node_num(); + } else { + ptr.s.mem_region = CVMX_IO_SEG; + ptr.s.is_io = 1; + ptr.s.did = CVMX_OCT_DID_TAG_TAG3; + } + cvmx_write_io(ptr.u64, tag_req.u64); +} + +/******************************************************************************/ +/* OCTEON3-specific functions. */ +/******************************************************************************/ +/** + * This function sets the the affinity of group to the cores in 78xx. + * It sets up all the cores in core_mask to accept work from the specified group. + * + * @param xgrp Group to accept work from, 0 - 255. + * @param core_mask Mask of all the cores which will accept work from this group + * @param mask_set Every core has set of 2 masks which can be set to accept work + * from 256 groups. At the time of get_work, cores can choose which mask_set + * to get work from. 'mask_set' values range from 0 to 3, where each of the + * two bits represents a mask set. Cores will be added to the mask set with + * corresponding bit set, and removed from the mask set with corresponding + * bit clear. + * Note: cores can only accept work from SSO groups on the same node, + * so the node number for the group is derived from the core number. + */ +static inline void cvmx_sso_set_group_core_affinity(cvmx_xgrp_t xgrp, + const struct cvmx_coremask *core_mask, + u8 mask_set) +{ + cvmx_sso_ppx_sx_grpmskx_t grp_msk; + int core; + int grp_index = xgrp.xgrp >> 6; + int bit_pos = xgrp.xgrp % 64; + + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + debug("ERROR: %s is not supported on this chip)\n", __func__); + return; + } + cvmx_coremask_for_each_core(core, core_mask) + { + unsigned int node, ncore; + u64 reg_addr; + + node = cvmx_coremask_core_to_node(core); + ncore = cvmx_coremask_core_on_node(core); + + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(ncore, 0, grp_index); + grp_msk.u64 = csr_rd_node(node, reg_addr); + + if (mask_set & 1) + grp_msk.s.grp_msk |= (1ull << bit_pos); + else + grp_msk.s.grp_msk &= ~(1ull << bit_pos); + + csr_wr_node(node, reg_addr, grp_msk.u64); + + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(ncore, 1, grp_index); + grp_msk.u64 = csr_rd_node(node, reg_addr); + + if (mask_set & 2) + grp_msk.s.grp_msk |= (1ull << bit_pos); + else + grp_msk.s.grp_msk &= ~(1ull << bit_pos); + + csr_wr_node(node, reg_addr, grp_msk.u64); + } +} + +/** + * This function sets the priority and group affinity arbitration for each group. + * + * @param node Node number + * @param xgrp Group 0 - 255 to apply mask parameters to + * @param priority Priority of the group relative to other groups + * 0x0 - highest priority + * 0x7 - lowest priority + * @param weight Cross-group arbitration weight to apply to this group. + * valid values are 1-63 + * h/w default is 0x3f + * @param affinity Processor affinity arbitration weight to apply to this group. + * If zero, affinity is disabled. + * valid values are 0-15 + * h/w default which is 0xf. + * @param modify_mask mask of the parameters which needs to be modified. + * enum cvmx_sso_group_modify_mask + * to modify only priority -- set bit0 + * to modify only weight -- set bit1 + * to modify only affinity -- set bit2 + */ +static inline void cvmx_sso_set_group_priority(int node, cvmx_xgrp_t xgrp, int priority, int weight, + int affinity, + enum cvmx_sso_group_modify_mask modify_mask) +{ + cvmx_sso_grpx_pri_t grp_pri; + + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + debug("ERROR: %s is not supported on this chip)\n", __func__); + return; + } + if (weight <= 0) + weight = 0x3f; /* Force HW default when out of range */ + + grp_pri.u64 = csr_rd_node(node, CVMX_SSO_GRPX_PRI(xgrp.xgrp)); + if (grp_pri.s.weight == 0) + grp_pri.s.weight = 0x3f; + if (modify_mask & CVMX_SSO_MODIFY_GROUP_PRIORITY) + grp_pri.s.pri = priority; + if (modify_mask & CVMX_SSO_MODIFY_GROUP_WEIGHT) + grp_pri.s.weight = weight; + if (modify_mask & CVMX_SSO_MODIFY_GROUP_AFFINITY) + grp_pri.s.affinity = affinity; + csr_wr_node(node, CVMX_SSO_GRPX_PRI(xgrp.xgrp), grp_pri.u64); +} + +/** + * Asynchronous work request. + * Only works on CN78XX style SSO. + * + * Work is requested from the SSO unit, and should later be checked with + * function cvmx_pow_work_response_async. + * This function does NOT wait for previous tag switches to complete, + * so the caller must ensure that there is not a pending tag switch. + * + * @param scr_addr Scratch memory address that response will be returned to, + * which is either a valid WQE, or a response with the invalid bit set. + * Byte address, must be 8 byte aligned. + * @param xgrp Group to receive work for (0-255). + * @param wait + * 1 to cause response to wait for work to become available (or timeout) + * 0 to cause response to return immediately + */ +static inline void cvmx_sso_work_request_grp_async_nocheck(int scr_addr, cvmx_xgrp_t xgrp, + cvmx_pow_wait_t wait) +{ + cvmx_pow_iobdma_store_t data; + unsigned int node = cvmx_get_node_num(); + + if (CVMX_ENABLE_POW_CHECKS) { + __cvmx_pow_warn_if_pending_switch(__func__); + cvmx_warn_if(!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE), "Not CN78XX"); + } + /* scr_addr must be 8 byte aligned */ + data.u64 = 0; + data.s_cn78xx.scraddr = scr_addr >> 3; + data.s_cn78xx.len = 1; + data.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; + data.s_cn78xx.grouped = 1; + data.s_cn78xx.index_grp_mask = (node << 8) | xgrp.xgrp; + data.s_cn78xx.wait = wait; + data.s_cn78xx.node = node; + + cvmx_send_single(data.u64); +} + +/** + * Synchronous work request from the node-local SSO without verifying + * pending tag switch. It requests work from a specific SSO group. + * + * @param lgrp The local group number (within the SSO of the node of the caller) + * from which to get the work. + * @param wait When set, call stalls until work becomes available, or times out. + * If not set, returns immediately. + * + * @return Returns the WQE pointer from SSO. + * Returns NULL if no work was available. + */ +static inline void *cvmx_sso_work_request_grp_sync_nocheck(unsigned int lgrp, cvmx_pow_wait_t wait) +{ + cvmx_pow_load_addr_t ptr; + cvmx_pow_tag_load_resp_t result; + unsigned int node = cvmx_get_node_num() & 3; + + if (CVMX_ENABLE_POW_CHECKS) { + __cvmx_pow_warn_if_pending_switch(__func__); + cvmx_warn_if(!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE), "Not CN78XX"); + } + ptr.u64 = 0; + ptr.swork_78xx.mem_region = CVMX_IO_SEG; + ptr.swork_78xx.is_io = 1; + ptr.swork_78xx.did = CVMX_OCT_DID_TAG_SWTAG; + ptr.swork_78xx.node = node; + ptr.swork_78xx.grouped = 1; + ptr.swork_78xx.index = (lgrp & 0xff) | node << 8; + ptr.swork_78xx.wait = wait; + + result.u64 = csr_rd(ptr.u64); + if (result.s_work.no_work) + return NULL; + else + return cvmx_phys_to_ptr(result.s_work.addr); +} + +/** + * Synchronous work request from the node-local SSO. + * It requests work from a specific SSO group. + * This function waits for any previous tag switch to complete before + * requesting the new work. + * + * @param lgrp The node-local group number from which to get the work. + * @param wait When set, call stalls until work becomes available, or times out. + * If not set, returns immediately. + * + * @return The WQE pointer or NULL, if work is not available. + */ +static inline void *cvmx_sso_work_request_grp_sync(unsigned int lgrp, cvmx_pow_wait_t wait) +{ + cvmx_pow_tag_sw_wait(); + return cvmx_sso_work_request_grp_sync_nocheck(lgrp, wait); +} + +/** + * This function sets the group mask for a core. The group mask bits + * indicate which groups each core will accept work from. + * + * @param core_num Processor core to apply mask to. + * @param mask_set 7XXX has 2 sets of masks per core. + * Bit 0 represents the first mask set, bit 1 -- the second. + * @param xgrp_mask Group mask array. + * Total number of groups is divided into a number of + * 64-bits mask sets. Each bit in the mask, if set, enables + * the core to accept work from the corresponding group. + * + * NOTE: Each core can be configured to accept work in accordance to both + * mask sets, with the first having higher precedence over the second, + * or to accept work in accordance to just one of the two mask sets. + * The 'core_num' argument represents a processor core on any node + * in a coherent multi-chip system. + * + * If the 'mask_set' argument is 3, both mask sets are configured + * with the same value (which is not typically the intention), + * so keep in mind the function needs to be called twice + * to set a different value into each of the mask sets, + * once with 'mask_set=1' and second time with 'mask_set=2'. + */ +static inline void cvmx_pow_set_xgrp_mask(u64 core_num, u8 mask_set, const u64 xgrp_mask[]) +{ + unsigned int grp, node, core; + u64 reg_addr; + + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + debug("ERROR: %s is not supported on this chip)\n", __func__); + return; + } + + if (CVMX_ENABLE_POW_CHECKS) { + cvmx_warn_if(((mask_set < 1) || (mask_set > 3)), "Invalid mask set"); + } + + if ((mask_set < 1) || (mask_set > 3)) + mask_set = 3; + + node = cvmx_coremask_core_to_node(core_num); + core = cvmx_coremask_core_on_node(core_num); + + for (grp = 0; grp < (cvmx_sso_num_xgrp() >> 6); grp++) { + if (mask_set & 1) { + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(core, 0, grp), + csr_wr_node(node, reg_addr, xgrp_mask[grp]); + } + if (mask_set & 2) { + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(core, 1, grp), + csr_wr_node(node, reg_addr, xgrp_mask[grp]); + } + } +} + +/** + * This function gets the group mask for a core. The group mask bits + * indicate which groups each core will accept work from. + * + * @param core_num Processor core to apply mask to. + * @param mask_set 7XXX has 2 sets of masks per core. + * Bit 0 represents the first mask set, bit 1 -- the second. + * @param xgrp_mask Provide pointer to u64 mask[8] output array. + * Total number of groups is divided into a number of + * 64-bits mask sets. Each bit in the mask represents + * the core accepts work from the corresponding group. + * + * NOTE: Each core can be configured to accept work in accordance to both + * mask sets, with the first having higher precedence over the second, + * or to accept work in accordance to just one of the two mask sets. + * The 'core_num' argument represents a processor core on any node + * in a coherent multi-chip system. + */ +static inline void cvmx_pow_get_xgrp_mask(u64 core_num, u8 mask_set, u64 *xgrp_mask) +{ + cvmx_sso_ppx_sx_grpmskx_t grp_msk; + unsigned int grp, node, core; + u64 reg_addr; + + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + debug("ERROR: %s is not supported on this chip)\n", __func__); + return; + } + + if (CVMX_ENABLE_POW_CHECKS) { + cvmx_warn_if(mask_set != 1 && mask_set != 2, "Invalid mask set"); + } + + node = cvmx_coremask_core_to_node(core_num); + core = cvmx_coremask_core_on_node(core_num); + + for (grp = 0; grp < cvmx_sso_num_xgrp() >> 6; grp++) { + if (mask_set & 1) { + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(core, 0, grp), + grp_msk.u64 = csr_rd_node(node, reg_addr); + xgrp_mask[grp] = grp_msk.s.grp_msk; + } + if (mask_set & 2) { + reg_addr = CVMX_SSO_PPX_SX_GRPMSKX(core, 1, grp), + grp_msk.u64 = csr_rd_node(node, reg_addr); + xgrp_mask[grp] = grp_msk.s.grp_msk; + } + } +} + +/** + * Executes SSO SWTAG command. + * This is similar to cvmx_pow_tag_sw() function, but uses linear + * (vs. integrated group-qos) group index. + */ +static inline void cvmx_pow_tag_sw_node(cvmx_wqe_t *wqp, u32 tag, cvmx_pow_tag_type_t tag_type, + int node) +{ + union cvmx_pow_tag_req_addr ptr; + cvmx_pow_tag_req_t tag_req; + + if (cvmx_unlikely(!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE))) { + debug("ERROR: %s is supported on OCTEON3 only\n", __func__); + return; + } + CVMX_SYNCWS; + cvmx_pow_tag_sw_wait(); + + if (CVMX_ENABLE_POW_CHECKS) { + cvmx_pow_tag_info_t current_tag; + + __cvmx_pow_warn_if_pending_switch(__func__); + current_tag = cvmx_pow_get_current_tag(); + cvmx_warn_if(current_tag.tag_type == CVMX_POW_TAG_TYPE_NULL_NULL, + "%s called with NULL_NULL tag\n", __func__); + cvmx_warn_if(current_tag.tag_type == CVMX_POW_TAG_TYPE_NULL, + "%s called with NULL tag\n", __func__); + cvmx_warn_if((current_tag.tag_type == tag_type) && (current_tag.tag == tag), + "%s called to perform a tag switch to the same tag\n", __func__); + cvmx_warn_if( + tag_type == CVMX_POW_TAG_TYPE_NULL, + "%s called to perform a tag switch to NULL. Use cvmx_pow_tag_sw_null() instead\n", + __func__); + } + wqp->word1.cn78xx.tag = tag; + wqp->word1.cn78xx.tag_type = tag_type; + CVMX_SYNCWS; + + tag_req.u64 = 0; + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG; + tag_req.s_cn78xx_other.type = tag_type; + + ptr.u64 = 0; + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; + ptr.s_cn78xx.is_io = 1; + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; + ptr.s_cn78xx.node = node; + ptr.s_cn78xx.tag = tag; + cvmx_write_io(ptr.u64, tag_req.u64); +} + +/** + * Executes SSO SWTAG_FULL command. + * This is similar to cvmx_pow_tag_sw_full() function, but + * uses linear (vs. integrated group-qos) group index. + */ +static inline void cvmx_pow_tag_sw_full_node(cvmx_wqe_t *wqp, u32 tag, cvmx_pow_tag_type_t tag_type, + u8 xgrp, int node) +{ + union cvmx_pow_tag_req_addr ptr; + cvmx_pow_tag_req_t tag_req; + u16 gxgrp; + + if (cvmx_unlikely(!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE))) { + debug("ERROR: %s is supported on OCTEON3 only\n", __func__); + return; + } + /* Ensure that there is not a pending tag switch, as a tag switch cannot be + * started, if a previous switch is still pending. */ + CVMX_SYNCWS; + cvmx_pow_tag_sw_wait(); + + if (CVMX_ENABLE_POW_CHECKS) { + cvmx_pow_tag_info_t current_tag; + + __cvmx_pow_warn_if_pending_switch(__func__); + current_tag = cvmx_pow_get_current_tag(); + cvmx_warn_if(current_tag.tag_type == CVMX_POW_TAG_TYPE_NULL_NULL, + "%s called with NULL_NULL tag\n", __func__); + cvmx_warn_if((current_tag.tag_type == tag_type) && (current_tag.tag == tag), + "%s called to perform a tag switch to the same tag\n", __func__); + cvmx_warn_if( + tag_type == CVMX_POW_TAG_TYPE_NULL, + "%s called to perform a tag switch to NULL. Use cvmx_pow_tag_sw_null() instead\n", + __func__); + if ((wqp != cvmx_phys_to_ptr(0x80)) && cvmx_pow_get_current_wqp()) + cvmx_warn_if(wqp != cvmx_pow_get_current_wqp(), + "%s passed WQE(%p) doesn't match the address in the POW(%p)\n", + __func__, wqp, cvmx_pow_get_current_wqp()); + } + gxgrp = node; + gxgrp = gxgrp << 8 | xgrp; + wqp->word1.cn78xx.grp = gxgrp; + wqp->word1.cn78xx.tag = tag; + wqp->word1.cn78xx.tag_type = tag_type; + CVMX_SYNCWS; + + tag_req.u64 = 0; + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG_FULL; + tag_req.s_cn78xx_other.type = tag_type; + tag_req.s_cn78xx_other.grp = gxgrp; + tag_req.s_cn78xx_other.wqp = cvmx_ptr_to_phys(wqp); + + ptr.u64 = 0; + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; + ptr.s_cn78xx.is_io = 1; + ptr.s_cn78xx.did = CVMX_OCT_DID_TAG_SWTAG; + ptr.s_cn78xx.node = node; + ptr.s_cn78xx.tag = tag; + cvmx_write_io(ptr.u64, tag_req.u64); +} + +/** + * Submits work to an SSO group on any OCI node. + * This function updates the work queue entry in DRAM to match + * the arguments given. + * Note that the tag provided is for the work queue entry submitted, + * and is unrelated to the tag that the core currently holds. + * + * @param wqp pointer to work queue entry to submit. + * This entry is updated to match the other parameters + * @param tag tag value to be assigned to work queue entry + * @param tag_type type of tag + * @param xgrp native CN78XX group in the range 0..255 + * @param node The OCI node number for the target group + * + * When this function is called on a model prior to CN78XX, which does + * not support OCI nodes, the 'node' argument is ignored, and the 'xgrp' + * parameter is converted into 'qos' (the lower 3 bits) and 'grp' (the higher + * 5 bits), following the backward-compatibility scheme of translating + * between new and old style group numbers. + */ +static inline void cvmx_pow_work_submit_node(cvmx_wqe_t *wqp, u32 tag, cvmx_pow_tag_type_t tag_type, + u8 xgrp, u8 node) +{ + union cvmx_pow_tag_req_addr ptr; + cvmx_pow_tag_req_t tag_req; + u16 group; + + if (cvmx_unlikely(!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE))) { + debug("ERROR: %s is supported on OCTEON3 only\n", __func__); + return; + } + group = node; + group = group << 8 | xgrp; + wqp->word1.cn78xx.tag = tag; + wqp->word1.cn78xx.tag_type = tag_type; + wqp->word1.cn78xx.grp = group; + CVMX_SYNCWS; + + tag_req.u64 = 0; + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_ADDWQ; + tag_req.s_cn78xx_other.type = tag_type; + tag_req.s_cn78xx_other.wqp = cvmx_ptr_to_phys(wqp); + tag_req.s_cn78xx_other.grp = group; + + ptr.u64 = 0; + ptr.s_cn78xx.did = 0x66; // CVMX_OCT_DID_TAG_TAG6; + ptr.s_cn78xx.mem_region = CVMX_IO_SEG; + ptr.s_cn78xx.is_io = 1; + ptr.s_cn78xx.node = node; + ptr.s_cn78xx.tag = tag; + + /* SYNC write to memory before the work submit. This is necessary + ** as POW may read values from DRAM at this time */ + CVMX_SYNCWS; + cvmx_write_io(ptr.u64, tag_req.u64); +} + +/** + * Executes the SSO SWTAG_DESCHED operation. + * This is similar to the cvmx_pow_tag_sw_desched() function, but + * uses linear (vs. unified group-qos) group index. + */ +static inline void cvmx_pow_tag_sw_desched_node(cvmx_wqe_t *wqe, u32 tag, + cvmx_pow_tag_type_t tag_type, u8 xgrp, u64 no_sched, + u8 node) +{ + union cvmx_pow_tag_req_addr ptr; + cvmx_pow_tag_req_t tag_req; + u16 group; + + if (cvmx_unlikely(!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE))) { + debug("ERROR: %s is supported on OCTEON3 only\n", __func__); + return; + } + /* Need to make sure any writes to the work queue entry are complete */ + CVMX_SYNCWS; + /* + * Ensure that there is not a pending tag switch, as a tag switch cannot + * be started if a previous switch is still pending. + */ + cvmx_pow_tag_sw_wait(); + + if (CVMX_ENABLE_POW_CHECKS) { + cvmx_pow_tag_info_t current_tag; + + __cvmx_pow_warn_if_pending_switch(__func__); + current_tag = cvmx_pow_get_current_tag(); + cvmx_warn_if(current_tag.tag_type == CVMX_POW_TAG_TYPE_NULL_NULL, + "%s called with NULL_NULL tag\n", __func__); + cvmx_warn_if(current_tag.tag_type == CVMX_POW_TAG_TYPE_NULL, + "%s called with NULL tag. Deschedule not allowed from NULL state\n", + __func__); + cvmx_warn_if((current_tag.tag_type != CVMX_POW_TAG_TYPE_ATOMIC) && + (tag_type != CVMX_POW_TAG_TYPE_ATOMIC), + "%s called where neither the before or after tag is ATOMIC\n", + __func__); + } + group = node; + group = group << 8 | xgrp; + wqe->word1.cn78xx.tag = tag; + wqe->word1.cn78xx.tag_type = tag_type; + wqe->word1.cn78xx.grp = group; + CVMX_SYNCWS; + + tag_req.u64 = 0; + tag_req.s_cn78xx_other.op = CVMX_POW_TAG_OP_SWTAG_DESCH; + tag_req.s_cn78xx_other.type = tag_type; + tag_req.s_cn78xx_other.grp = group; + tag_req.s_cn78xx_other.no_sched = no_sched; + + ptr.u64 = 0; + ptr.s.mem_region = CVMX_IO_SEG; + ptr.s.is_io = 1; + ptr.s.did = CVMX_OCT_DID_TAG_TAG3; + ptr.s_cn78xx.node = node; + ptr.s_cn78xx.tag = tag; + cvmx_write_io(ptr.u64, tag_req.u64); +} + +/* Executes the UPD_WQP_GRP SSO operation. + * + * @param wqp Pointer to the new work queue entry to switch to. + * @param xgrp SSO group in the range 0..255 + * + * NOTE: The operation can be performed only on the local node. + */ +static inline void cvmx_sso_update_wqp_group(cvmx_wqe_t *wqp, u8 xgrp) +{ + union cvmx_pow_tag_req_addr addr; + cvmx_pow_tag_req_t data; + int node = cvmx_get_node_num(); + int group = node << 8 | xgrp; + + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + debug("ERROR: %s is not supported on this chip)\n", __func__); + return; + } + wqp->word1.cn78xx.grp = group; + CVMX_SYNCWS; + + data.u64 = 0; + data.s_cn78xx_other.op = CVMX_POW_TAG_OP_UPDATE_WQP_GRP; + data.s_cn78xx_other.grp = group; + data.s_cn78xx_other.wqp = cvmx_ptr_to_phys(wqp); + + addr.u64 = 0; + addr.s_cn78xx.mem_region = CVMX_IO_SEG; + addr.s_cn78xx.is_io = 1; + addr.s_cn78xx.did = CVMX_OCT_DID_TAG_TAG1; + addr.s_cn78xx.node = node; + cvmx_write_io(addr.u64, data.u64); +} + +/******************************************************************************/ +/* Define usage of bits within the 32 bit tag values. */ +/******************************************************************************/ +/* + * Number of bits of the tag used by software. The SW bits + * are always a contiguous block of the high starting at bit 31. + * The hardware bits are always the low bits. By default, the top 8 bits + * of the tag are reserved for software, and the low 24 are set by the IPD unit. + */ +#define CVMX_TAG_SW_BITS (8) +#define CVMX_TAG_SW_SHIFT (32 - CVMX_TAG_SW_BITS) + +/* Below is the list of values for the top 8 bits of the tag. */ +/* + * Tag values with top byte of this value are reserved for internal executive + * uses + */ +#define CVMX_TAG_SW_BITS_INTERNAL 0x1 + +/* + * The executive divides the remaining 24 bits as follows: + * the upper 8 bits (bits 23 - 16 of the tag) define a subgroup + * the lower 16 bits (bits 15 - 0 of the tag) define are the value with + * the subgroup. Note that this section describes the format of tags generated + * by software - refer to the hardware documentation for a description of the + * tags values generated by the packet input hardware. + * Subgroups are defined here + */ + +/* Mask for the value portion of the tag */ +#define CVMX_TAG_SUBGROUP_MASK 0xFFFF +#define CVMX_TAG_SUBGROUP_SHIFT 16 +#define CVMX_TAG_SUBGROUP_PKO 0x1 + +/* End of executive tag subgroup definitions */ + +/* The remaining values software bit values 0x2 - 0xff are available + * for application use */ + +/** + * This function creates a 32 bit tag value from the two values provided. + * + * @param sw_bits The upper bits (number depends on configuration) are set + * to this value. The remainder of bits are set by the hw_bits parameter. + * @param hw_bits The lower bits (number depends on configuration) are set + * to this value. The remainder of bits are set by the sw_bits parameter. + * + * @return 32 bit value of the combined hw and sw bits. + */ +static inline u32 cvmx_pow_tag_compose(u64 sw_bits, u64 hw_bits) +{ + return (((sw_bits & cvmx_build_mask(CVMX_TAG_SW_BITS)) << CVMX_TAG_SW_SHIFT) | + (hw_bits & cvmx_build_mask(32 - CVMX_TAG_SW_BITS))); +} + +/** + * Extracts the bits allocated for software use from the tag + * + * @param tag 32 bit tag value + * + * @return N bit software tag value, where N is configurable with + * the CVMX_TAG_SW_BITS define + */ +static inline u32 cvmx_pow_tag_get_sw_bits(u64 tag) +{ + return ((tag >> (32 - CVMX_TAG_SW_BITS)) & cvmx_build_mask(CVMX_TAG_SW_BITS)); +} + +/** + * + * Extracts the bits allocated for hardware use from the tag + * + * @param tag 32 bit tag value + * + * @return (32 - N) bit software tag value, where N is configurable with + * the CVMX_TAG_SW_BITS define + */ +static inline u32 cvmx_pow_tag_get_hw_bits(u64 tag) +{ + return (tag & cvmx_build_mask(32 - CVMX_TAG_SW_BITS)); +} + +static inline u64 cvmx_sso3_get_wqe_count(int node) +{ + cvmx_sso_grpx_aq_cnt_t aq_cnt; + unsigned int grp = 0; + u64 cnt = 0; + + for (grp = 0; grp < cvmx_sso_num_xgrp(); grp++) { + aq_cnt.u64 = csr_rd_node(node, CVMX_SSO_GRPX_AQ_CNT(grp)); + cnt += aq_cnt.s.aq_cnt; + } + return cnt; +} + +static inline u64 cvmx_sso_get_total_wqe_count(void) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + int node = cvmx_get_node_num(); + + return cvmx_sso3_get_wqe_count(node); + } else if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + cvmx_sso_iq_com_cnt_t sso_iq_com_cnt; + + sso_iq_com_cnt.u64 = csr_rd(CVMX_SSO_IQ_COM_CNT); + return (sso_iq_com_cnt.s.iq_cnt); + } else { + cvmx_pow_iq_com_cnt_t pow_iq_com_cnt; + + pow_iq_com_cnt.u64 = csr_rd(CVMX_POW_IQ_COM_CNT); + return (pow_iq_com_cnt.s.iq_cnt); + } +} + +/** + * Store the current POW internal state into the supplied + * buffer. It is recommended that you pass a buffer of at least + * 128KB. The format of the capture may change based on SDK + * version and Octeon chip. + * + * @param buffer Buffer to store capture into + * @param buffer_size The size of the supplied buffer + * + * @return Zero on success, negative on failure + */ +int cvmx_pow_capture(void *buffer, int buffer_size); + +/** + * Dump a POW capture to the console in a human readable format. + * + * @param buffer POW capture from cvmx_pow_capture() + * @param buffer_size Size of the buffer + */ +void cvmx_pow_display(void *buffer, int buffer_size); + +/** + * Return the number of POW entries supported by this chip + * + * @return Number of POW entries + */ +int cvmx_pow_get_num_entries(void); +int cvmx_pow_get_dump_size(void); + +/** + * This will allocate count number of SSO groups on the specified node to the + * calling application. These groups will be for exclusive use of the + * application until they are freed. + * @param node The numa node for the allocation. + * @param base_group Pointer to the initial group, -1 to allocate anywhere. + * @param count The number of consecutive groups to allocate. + * @return 0 on success and -1 on failure. + */ +int cvmx_sso_reserve_group_range(int node, int *base_group, int count); +#define cvmx_sso_allocate_group_range cvmx_sso_reserve_group_range +int cvmx_sso_reserve_group(int node); +#define cvmx_sso_allocate_group cvmx_sso_reserve_group +int cvmx_sso_release_group_range(int node, int base_group, int count); +int cvmx_sso_release_group(int node, int group); + +/** + * Show integrated SSO configuration. + * + * @param node node number + */ +int cvmx_sso_config_dump(unsigned int node); + +/** + * Show integrated SSO statistics. + * + * @param node node number + */ +int cvmx_sso_stats_dump(unsigned int node); + +/** + * Clear integrated SSO statistics. + * + * @param node node number + */ +int cvmx_sso_stats_clear(unsigned int node); + +/** + * Show SSO core-group affinity and priority per node (multi-node systems) + */ +void cvmx_pow_mask_priority_dump_node(unsigned int node, struct cvmx_coremask *avail_coremask); + +/** + * Show POW/SSO core-group affinity and priority (legacy, single-node systems) + */ +static inline void cvmx_pow_mask_priority_dump(struct cvmx_coremask *avail_coremask) +{ + cvmx_pow_mask_priority_dump_node(0 /*node */, avail_coremask); +} + +/** + * Show SSO performance counters (multi-node systems) + */ +void cvmx_pow_show_perf_counters_node(unsigned int node); + +/** + * Show POW/SSO performance counters (legacy, single-node systems) + */ +static inline void cvmx_pow_show_perf_counters(void) +{ + cvmx_pow_show_perf_counters_node(0 /*node */); +} + +#endif /* __CVMX_POW_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-qlm.h b/arch/mips/mach-octeon/include/mach/cvmx-qlm.h new file mode 100644 index 000000000000..19915eb82c51 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-qlm.h @@ -0,0 +1,304 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +#ifndef __CVMX_QLM_H__ +#define __CVMX_QLM_H__ + +/* + * Interface 0 on the 78xx can be connected to qlm 0 or qlm 2. When interface + * 0 is connected to qlm 0, this macro must be set to 0. When interface 0 is + * connected to qlm 2, this macro must be set to 1. + */ +#define MUX_78XX_IFACE0 0 + +/* + * Interface 1 on the 78xx can be connected to qlm 1 or qlm 3. When interface + * 1 is connected to qlm 1, this macro must be set to 0. When interface 1 is + * connected to qlm 3, this macro must be set to 1. + */ +#define MUX_78XX_IFACE1 0 + +/* Uncomment this line to print QLM JTAG state */ +/* #define CVMX_QLM_DUMP_STATE 1 */ + +typedef struct { + const char *name; + int stop_bit; + int start_bit; +} __cvmx_qlm_jtag_field_t; + +/** + * Return the number of QLMs supported by the chip + * + * @return Number of QLMs + */ +int cvmx_qlm_get_num(void); + +/** + * Return the qlm number based on the interface + * + * @param xiface Interface to look + */ +int cvmx_qlm_interface(int xiface); + +/** + * Return the qlm number based for a port in the interface + * + * @param xiface interface to look up + * @param index index in an interface + * + * @return the qlm number based on the xiface + */ +int cvmx_qlm_lmac(int xiface, int index); + +/** + * Return if only DLM5/DLM6/DLM5+DLM6 is used by BGX + * + * @param BGX BGX to search for. + * + * @return muxes used 0 = DLM5+DLM6, 1 = DLM5, 2 = DLM6. + */ +int cvmx_qlm_mux_interface(int bgx); + +/** + * Return number of lanes for a given qlm + * + * @param qlm QLM block to query + * + * @return Number of lanes + */ +int cvmx_qlm_get_lanes(int qlm); + +/** + * Get the QLM JTAG fields based on Octeon model on the supported chips. + * + * @return qlm_jtag_field_t structure + */ +const __cvmx_qlm_jtag_field_t *cvmx_qlm_jtag_get_field(void); + +/** + * Get the QLM JTAG length by going through qlm_jtag_field for each + * Octeon model that is supported + * + * @return return the length. + */ +int cvmx_qlm_jtag_get_length(void); + +/** + * Initialize the QLM layer + */ +void cvmx_qlm_init(void); + +/** + * Get a field in a QLM JTAG chain + * + * @param qlm QLM to get + * @param lane Lane in QLM to get + * @param name String name of field + * + * @return JTAG field value + */ +u64 cvmx_qlm_jtag_get(int qlm, int lane, const char *name); + +/** + * Set a field in a QLM JTAG chain + * + * @param qlm QLM to set + * @param lane Lane in QLM to set, or -1 for all lanes + * @param name String name of field + * @param value Value of the field + */ +void cvmx_qlm_jtag_set(int qlm, int lane, const char *name, u64 value); + +/** + * Errata G-16094: QLM Gen2 Equalizer Default Setting Change. + * CN68XX pass 1.x and CN66XX pass 1.x QLM tweak. This function tweaks the + * JTAG setting for a QLMs to run better at 5 and 6.25Ghz. + */ +void __cvmx_qlm_speed_tweak(void); + +/** + * Errata G-16174: QLM Gen2 PCIe IDLE DAC change. + * CN68XX pass 1.x, CN66XX pass 1.x and CN63XX pass 1.0-2.2 QLM tweak. + * This function tweaks the JTAG setting for a QLMs for PCIe to run better. + */ +void __cvmx_qlm_pcie_idle_dac_tweak(void); + +void __cvmx_qlm_pcie_cfg_rxd_set_tweak(int qlm, int lane); + +/** + * Get the speed (Gbaud) of the QLM in Mhz. + * + * @param qlm QLM to examine + * + * @return Speed in Mhz + */ +int cvmx_qlm_get_gbaud_mhz(int qlm); +/** + * Get the speed (Gbaud) of the QLM in Mhz on specific node. + * + * @param node Target QLM node + * @param qlm QLM to examine + * + * @return Speed in Mhz + */ +int cvmx_qlm_get_gbaud_mhz_node(int node, int qlm); + +enum cvmx_qlm_mode { + CVMX_QLM_MODE_DISABLED = -1, + CVMX_QLM_MODE_SGMII = 1, + CVMX_QLM_MODE_XAUI, + CVMX_QLM_MODE_RXAUI, + CVMX_QLM_MODE_PCIE, /* gen3 / gen2 / gen1 */ + CVMX_QLM_MODE_PCIE_1X2, /* 1x2 gen2 / gen1 */ + CVMX_QLM_MODE_PCIE_2X1, /* 2x1 gen2 / gen1 */ + CVMX_QLM_MODE_PCIE_1X1, /* 1x1 gen2 / gen1 */ + CVMX_QLM_MODE_SRIO_1X4, /* 1x4 short / long */ + CVMX_QLM_MODE_SRIO_2X2, /* 2x2 short / long */ + CVMX_QLM_MODE_SRIO_4X1, /* 4x1 short / long */ + CVMX_QLM_MODE_ILK, + CVMX_QLM_MODE_QSGMII, + CVMX_QLM_MODE_SGMII_SGMII, + CVMX_QLM_MODE_SGMII_DISABLED, + CVMX_QLM_MODE_DISABLED_SGMII, + CVMX_QLM_MODE_SGMII_QSGMII, + CVMX_QLM_MODE_QSGMII_QSGMII, + CVMX_QLM_MODE_QSGMII_DISABLED, + CVMX_QLM_MODE_DISABLED_QSGMII, + CVMX_QLM_MODE_QSGMII_SGMII, + CVMX_QLM_MODE_RXAUI_1X2, + CVMX_QLM_MODE_SATA_2X1, + CVMX_QLM_MODE_XLAUI, + CVMX_QLM_MODE_XFI, + CVMX_QLM_MODE_10G_KR, + CVMX_QLM_MODE_40G_KR4, + CVMX_QLM_MODE_PCIE_1X8, /* 1x8 gen3 / gen2 / gen1 */ + CVMX_QLM_MODE_RGMII_SGMII, + CVMX_QLM_MODE_RGMII_XFI, + CVMX_QLM_MODE_RGMII_10G_KR, + CVMX_QLM_MODE_RGMII_RXAUI, + CVMX_QLM_MODE_RGMII_XAUI, + CVMX_QLM_MODE_RGMII_XLAUI, + CVMX_QLM_MODE_RGMII_40G_KR4, + CVMX_QLM_MODE_MIXED, /* BGX2 is mixed mode, DLM5(SGMII) & DLM6(XFI) */ + CVMX_QLM_MODE_SGMII_2X1, /* Configure BGX2 separate for DLM5 & DLM6 */ + CVMX_QLM_MODE_10G_KR_1X2, /* Configure BGX2 separate for DLM5 & DLM6 */ + CVMX_QLM_MODE_XFI_1X2, /* Configure BGX2 separate for DLM5 & DLM6 */ + CVMX_QLM_MODE_RGMII_SGMII_1X1, /* Configure BGX2, applies to DLM5 */ + CVMX_QLM_MODE_RGMII_SGMII_2X1, /* Configure BGX2, applies to DLM6 */ + CVMX_QLM_MODE_RGMII_10G_KR_1X1, /* Configure BGX2, applies to DLM6 */ + CVMX_QLM_MODE_RGMII_XFI_1X1, /* Configure BGX2, applies to DLM6 */ + CVMX_QLM_MODE_SDL, /* RMAC Pipe */ + CVMX_QLM_MODE_CPRI, /* RMAC */ + CVMX_QLM_MODE_OCI +}; + +enum cvmx_gmx_inf_mode { + CVMX_GMX_INF_MODE_DISABLED = 0, + CVMX_GMX_INF_MODE_SGMII = 1, /* Other interface can be SGMII or QSGMII */ + CVMX_GMX_INF_MODE_QSGMII = 2, /* Other interface can be SGMII or QSGMII */ + CVMX_GMX_INF_MODE_RXAUI = 3, /* Only interface 0, interface 1 must be DISABLED */ +}; + +/** + * Eye diagram captures are stored in the following structure + */ +typedef struct { + int width; /* Width in the x direction (time) */ + int height; /* Height in the y direction (voltage) */ + u32 data[64][128]; /* Error count at location, saturates as max */ +} cvmx_qlm_eye_t; + +/** + * These apply to DLM1 and DLM2 if its not in SATA mode + * Manual refers to lanes as follows: + * DML 0 lane 0 == GSER0 lane 0 + * DML 0 lane 1 == GSER0 lane 1 + * DML 1 lane 2 == GSER1 lane 0 + * DML 1 lane 3 == GSER1 lane 1 + * DML 2 lane 4 == GSER2 lane 0 + * DML 2 lane 5 == GSER2 lane 1 + */ +enum cvmx_pemx_cfg_mode { + CVMX_PEM_MD_GEN2_2LANE = 0, /* Valid for PEM0(DLM1), PEM1(DLM2) */ + CVMX_PEM_MD_GEN2_1LANE = 1, /* Valid for PEM0(DLM1.0), PEM1(DLM1.1,DLM2.0), PEM2(DLM2.1) */ + CVMX_PEM_MD_GEN2_4LANE = 2, /* Valid for PEM0(DLM1-2) */ + /* Reserved */ + CVMX_PEM_MD_GEN1_2LANE = 4, /* Valid for PEM0(DLM1), PEM1(DLM2) */ + CVMX_PEM_MD_GEN1_1LANE = 5, /* Valid for PEM0(DLM1.0), PEM1(DLM1.1,DLM2.0), PEM2(DLM2.1) */ + CVMX_PEM_MD_GEN1_4LANE = 6, /* Valid for PEM0(DLM1-2) */ + /* Reserved */ +}; + +/* + * Read QLM and return mode. + */ +enum cvmx_qlm_mode cvmx_qlm_get_mode(int qlm); +enum cvmx_qlm_mode cvmx_qlm_get_mode_cn78xx(int node, int qlm); +enum cvmx_qlm_mode cvmx_qlm_get_dlm_mode(int dlm_mode, int interface); +void __cvmx_qlm_set_mult(int qlm, int baud_mhz, int old_multiplier); + +void cvmx_qlm_display_registers(int qlm); + +int cvmx_qlm_measure_clock(int qlm); + +/** + * Measure the reference clock of a QLM on a multi-node setup + * + * @param node node to measure + * @param qlm QLM to measure + * + * @return Clock rate in Hz + */ +int cvmx_qlm_measure_clock_node(int node, int qlm); + +/* + * Perform RX equalization on a QLM + * + * @param node Node the QLM is on + * @param qlm QLM to perform RX equalization on + * @param lane Lane to use, or -1 for all lanes + * + * @return Zero on success, negative if any lane failed RX equalization + */ +int __cvmx_qlm_rx_equalization(int node, int qlm, int lane); + +/** + * Errata GSER-27882 -GSER 10GBASE-KR Transmit Equalizer + * Training may not update PHY Tx Taps. This function is not static + * so we can share it with BGX KR + * + * @param node Node to apply errata workaround + * @param qlm QLM to apply errata workaround + * @param lane Lane to apply the errata + */ +int cvmx_qlm_gser_errata_27882(int node, int qlm, int lane); + +void cvmx_qlm_gser_errata_25992(int node, int qlm); + +#ifdef CVMX_DUMP_GSER +/** + * Dump GSER configuration for node 0 + */ +int cvmx_dump_gser_config(unsigned int gser); +/** + * Dump GSER status for node 0 + */ +int cvmx_dump_gser_status(unsigned int gser); +/** + * Dump GSER configuration + */ +int cvmx_dump_gser_config_node(unsigned int node, unsigned int gser); +/** + * Dump GSER status + */ +int cvmx_dump_gser_status_node(unsigned int node, unsigned int gser); +#endif + +int cvmx_qlm_eye_display(int node, int qlm, int qlm_lane, int format, const cvmx_qlm_eye_t *eye); + +void cvmx_prbs_process_cmd(int node, int qlm, int mode); + +#endif /* __CVMX_QLM_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-scratch.h b/arch/mips/mach-octeon/include/mach/cvmx-scratch.h new file mode 100644 index 000000000000..d567a8453b7a --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-scratch.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * This file provides support for the processor local scratch memory. + * Scratch memory is byte addressable - all addresses are byte addresses. + */ + +#ifndef __CVMX_SCRATCH_H__ +#define __CVMX_SCRATCH_H__ + +/* Note: This define must be a long, not a long long in order to compile + without warnings for both 32bit and 64bit. */ +#define CVMX_SCRATCH_BASE (-32768l) /* 0xffffffffffff8000 */ + +/* Scratch line for LMTST/LMTDMA on Octeon3 models */ +#ifdef CVMX_CAVIUM_OCTEON3 +#define CVMX_PKO_LMTLINE 2ull +#endif + +/** + * Reads an 8 bit value from the processor local scratchpad memory. + * + * @param address byte address to read from + * + * @return value read + */ +static inline u8 cvmx_scratch_read8(u64 address) +{ + return *CASTPTR(volatile u8, CVMX_SCRATCH_BASE + address); +} + +/** + * Reads a 16 bit value from the processor local scratchpad memory. + * + * @param address byte address to read from + * + * @return value read + */ +static inline u16 cvmx_scratch_read16(u64 address) +{ + return *CASTPTR(volatile u16, CVMX_SCRATCH_BASE + address); +} + +/** + * Reads a 32 bit value from the processor local scratchpad memory. + * + * @param address byte address to read from + * + * @return value read + */ +static inline u32 cvmx_scratch_read32(u64 address) +{ + return *CASTPTR(volatile u32, CVMX_SCRATCH_BASE + address); +} + +/** + * Reads a 64 bit value from the processor local scratchpad memory. + * + * @param address byte address to read from + * + * @return value read + */ +static inline u64 cvmx_scratch_read64(u64 address) +{ + return *CASTPTR(volatile u64, CVMX_SCRATCH_BASE + address); +} + +/** + * Writes an 8 bit value to the processor local scratchpad memory. + * + * @param address byte address to write to + * @param value value to write + */ +static inline void cvmx_scratch_write8(u64 address, u64 value) +{ + *CASTPTR(volatile u8, CVMX_SCRATCH_BASE + address) = (u8)value; +} + +/** + * Writes a 32 bit value to the processor local scratchpad memory. + * + * @param address byte address to write to + * @param value value to write + */ +static inline void cvmx_scratch_write16(u64 address, u64 value) +{ + *CASTPTR(volatile u16, CVMX_SCRATCH_BASE + address) = (u16)value; +} + +/** + * Writes a 16 bit value to the processor local scratchpad memory. + * + * @param address byte address to write to + * @param value value to write + */ +static inline void cvmx_scratch_write32(u64 address, u64 value) +{ + *CASTPTR(volatile u32, CVMX_SCRATCH_BASE + address) = (u32)value; +} + +/** + * Writes a 64 bit value to the processor local scratchpad memory. + * + * @param address byte address to write to + * @param value value to write + */ +static inline void cvmx_scratch_write64(u64 address, u64 value) +{ + *CASTPTR(volatile u64, CVMX_SCRATCH_BASE + address) = value; +} + +#endif /* __CVMX_SCRATCH_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-wqe.h b/arch/mips/mach-octeon/include/mach/cvmx-wqe.h new file mode 100644 index 000000000000..c9e3c8312a65 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-wqe.h @@ -0,0 +1,1462 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * This header file defines the work queue entry (wqe) data structure. + * Since this is a commonly used structure that depends on structures + * from several hardware blocks, those definitions have been placed + * in this file to create a single point of definition of the wqe + * format. + * Data structures are still named according to the block that they + * relate to. + */ + +#ifndef __CVMX_WQE_H__ +#define __CVMX_WQE_H__ + +#include "cvmx-packet.h" +#include "cvmx-csr-enums.h" +#include "cvmx-pki-defs.h" +#include "cvmx-pip-defs.h" +#include "octeon-feature.h" + +#define OCT_TAG_TYPE_STRING(x) \ + (((x) == CVMX_POW_TAG_TYPE_ORDERED) ? \ + "ORDERED" : \ + (((x) == CVMX_POW_TAG_TYPE_ATOMIC) ? \ + "ATOMIC" : \ + (((x) == CVMX_POW_TAG_TYPE_NULL) ? "NULL" : "NULL_NULL"))) + +/* Error levels in WQE WORD2 (ERRLEV).*/ +#define PKI_ERRLEV_E__RE_M 0x0 +#define PKI_ERRLEV_E__LA_M 0x1 +#define PKI_ERRLEV_E__LB_M 0x2 +#define PKI_ERRLEV_E__LC_M 0x3 +#define PKI_ERRLEV_E__LD_M 0x4 +#define PKI_ERRLEV_E__LE_M 0x5 +#define PKI_ERRLEV_E__LF_M 0x6 +#define PKI_ERRLEV_E__LG_M 0x7 + +enum cvmx_pki_errlevel { + CVMX_PKI_ERRLEV_E_RE = PKI_ERRLEV_E__RE_M, + CVMX_PKI_ERRLEV_E_LA = PKI_ERRLEV_E__LA_M, + CVMX_PKI_ERRLEV_E_LB = PKI_ERRLEV_E__LB_M, + CVMX_PKI_ERRLEV_E_LC = PKI_ERRLEV_E__LC_M, + CVMX_PKI_ERRLEV_E_LD = PKI_ERRLEV_E__LD_M, + CVMX_PKI_ERRLEV_E_LE = PKI_ERRLEV_E__LE_M, + CVMX_PKI_ERRLEV_E_LF = PKI_ERRLEV_E__LF_M, + CVMX_PKI_ERRLEV_E_LG = PKI_ERRLEV_E__LG_M +}; + +#define CVMX_PKI_ERRLEV_MAX BIT(3) /* The size of WORD2:ERRLEV field.*/ + +/* Error code in WQE WORD2 (OPCODE).*/ +#define CVMX_PKI_OPCODE_RE_NONE 0x0 +#define CVMX_PKI_OPCODE_RE_PARTIAL 0x1 +#define CVMX_PKI_OPCODE_RE_JABBER 0x2 +#define CVMX_PKI_OPCODE_RE_FCS 0x7 +#define CVMX_PKI_OPCODE_RE_FCS_RCV 0x8 +#define CVMX_PKI_OPCODE_RE_TERMINATE 0x9 +#define CVMX_PKI_OPCODE_RE_RX_CTL 0xb +#define CVMX_PKI_OPCODE_RE_SKIP 0xc +#define CVMX_PKI_OPCODE_RE_DMAPKT 0xf +#define CVMX_PKI_OPCODE_RE_PKIPAR 0x13 +#define CVMX_PKI_OPCODE_RE_PKIPCAM 0x14 +#define CVMX_PKI_OPCODE_RE_MEMOUT 0x15 +#define CVMX_PKI_OPCODE_RE_BUFS_OFLOW 0x16 +#define CVMX_PKI_OPCODE_L2_FRAGMENT 0x20 +#define CVMX_PKI_OPCODE_L2_OVERRUN 0x21 +#define CVMX_PKI_OPCODE_L2_PFCS 0x22 +#define CVMX_PKI_OPCODE_L2_PUNY 0x23 +#define CVMX_PKI_OPCODE_L2_MAL 0x24 +#define CVMX_PKI_OPCODE_L2_OVERSIZE 0x25 +#define CVMX_PKI_OPCODE_L2_UNDERSIZE 0x26 +#define CVMX_PKI_OPCODE_L2_LENMISM 0x27 +#define CVMX_PKI_OPCODE_IP_NOT 0x41 +#define CVMX_PKI_OPCODE_IP_CHK 0x42 +#define CVMX_PKI_OPCODE_IP_MAL 0x43 +#define CVMX_PKI_OPCODE_IP_MALD 0x44 +#define CVMX_PKI_OPCODE_IP_HOP 0x45 +#define CVMX_PKI_OPCODE_L4_MAL 0x61 +#define CVMX_PKI_OPCODE_L4_CHK 0x62 +#define CVMX_PKI_OPCODE_L4_LEN 0x63 +#define CVMX_PKI_OPCODE_L4_PORT 0x64 +#define CVMX_PKI_OPCODE_TCP_FLAG 0x65 + +#define CVMX_PKI_OPCODE_MAX BIT(8) /* The size of WORD2:OPCODE field.*/ + +/* Layer types in pki */ +#define CVMX_PKI_LTYPE_E_NONE_M 0x0 +#define CVMX_PKI_LTYPE_E_ENET_M 0x1 +#define CVMX_PKI_LTYPE_E_VLAN_M 0x2 +#define CVMX_PKI_LTYPE_E_SNAP_PAYLD_M 0x5 +#define CVMX_PKI_LTYPE_E_ARP_M 0x6 +#define CVMX_PKI_LTYPE_E_RARP_M 0x7 +#define CVMX_PKI_LTYPE_E_IP4_M 0x8 +#define CVMX_PKI_LTYPE_E_IP4_OPT_M 0x9 +#define CVMX_PKI_LTYPE_E_IP6_M 0xA +#define CVMX_PKI_LTYPE_E_IP6_OPT_M 0xB +#define CVMX_PKI_LTYPE_E_IPSEC_ESP_M 0xC +#define CVMX_PKI_LTYPE_E_IPFRAG_M 0xD +#define CVMX_PKI_LTYPE_E_IPCOMP_M 0xE +#define CVMX_PKI_LTYPE_E_TCP_M 0x10 +#define CVMX_PKI_LTYPE_E_UDP_M 0x11 +#define CVMX_PKI_LTYPE_E_SCTP_M 0x12 +#define CVMX_PKI_LTYPE_E_UDP_VXLAN_M 0x13 +#define CVMX_PKI_LTYPE_E_GRE_M 0x14 +#define CVMX_PKI_LTYPE_E_NVGRE_M 0x15 +#define CVMX_PKI_LTYPE_E_GTP_M 0x16 +#define CVMX_PKI_LTYPE_E_SW28_M 0x1C +#define CVMX_PKI_LTYPE_E_SW29_M 0x1D +#define CVMX_PKI_LTYPE_E_SW30_M 0x1E +#define CVMX_PKI_LTYPE_E_SW31_M 0x1F + +enum cvmx_pki_layer_type { + CVMX_PKI_LTYPE_E_NONE = CVMX_PKI_LTYPE_E_NONE_M, + CVMX_PKI_LTYPE_E_ENET = CVMX_PKI_LTYPE_E_ENET_M, + CVMX_PKI_LTYPE_E_VLAN = CVMX_PKI_LTYPE_E_VLAN_M, + CVMX_PKI_LTYPE_E_SNAP_PAYLD = CVMX_PKI_LTYPE_E_SNAP_PAYLD_M, + CVMX_PKI_LTYPE_E_ARP = CVMX_PKI_LTYPE_E_ARP_M, + CVMX_PKI_LTYPE_E_RARP = CVMX_PKI_LTYPE_E_RARP_M, + CVMX_PKI_LTYPE_E_IP4 = CVMX_PKI_LTYPE_E_IP4_M, + CVMX_PKI_LTYPE_E_IP4_OPT = CVMX_PKI_LTYPE_E_IP4_OPT_M, + CVMX_PKI_LTYPE_E_IP6 = CVMX_PKI_LTYPE_E_IP6_M, + CVMX_PKI_LTYPE_E_IP6_OPT = CVMX_PKI_LTYPE_E_IP6_OPT_M, + CVMX_PKI_LTYPE_E_IPSEC_ESP = CVMX_PKI_LTYPE_E_IPSEC_ESP_M, + CVMX_PKI_LTYPE_E_IPFRAG = CVMX_PKI_LTYPE_E_IPFRAG_M, + CVMX_PKI_LTYPE_E_IPCOMP = CVMX_PKI_LTYPE_E_IPCOMP_M, + CVMX_PKI_LTYPE_E_TCP = CVMX_PKI_LTYPE_E_TCP_M, + CVMX_PKI_LTYPE_E_UDP = CVMX_PKI_LTYPE_E_UDP_M, + CVMX_PKI_LTYPE_E_SCTP = CVMX_PKI_LTYPE_E_SCTP_M, + CVMX_PKI_LTYPE_E_UDP_VXLAN = CVMX_PKI_LTYPE_E_UDP_VXLAN_M, + CVMX_PKI_LTYPE_E_GRE = CVMX_PKI_LTYPE_E_GRE_M, + CVMX_PKI_LTYPE_E_NVGRE = CVMX_PKI_LTYPE_E_NVGRE_M, + CVMX_PKI_LTYPE_E_GTP = CVMX_PKI_LTYPE_E_GTP_M, + CVMX_PKI_LTYPE_E_SW28 = CVMX_PKI_LTYPE_E_SW28_M, + CVMX_PKI_LTYPE_E_SW29 = CVMX_PKI_LTYPE_E_SW29_M, + CVMX_PKI_LTYPE_E_SW30 = CVMX_PKI_LTYPE_E_SW30_M, + CVMX_PKI_LTYPE_E_SW31 = CVMX_PKI_LTYPE_E_SW31_M, + CVMX_PKI_LTYPE_E_MAX = CVMX_PKI_LTYPE_E_SW31 +}; + +typedef union { + u64 u64; + struct { + u64 ptr_vlan : 8; + u64 ptr_layer_g : 8; + u64 ptr_layer_f : 8; + u64 ptr_layer_e : 8; + u64 ptr_layer_d : 8; + u64 ptr_layer_c : 8; + u64 ptr_layer_b : 8; + u64 ptr_layer_a : 8; + }; +} cvmx_pki_wqe_word4_t; + +/** + * HW decode / err_code in work queue entry + */ +typedef union { + u64 u64; + struct { + u64 bufs : 8; + u64 ip_offset : 8; + u64 vlan_valid : 1; + u64 vlan_stacked : 1; + u64 unassigned : 1; + u64 vlan_cfi : 1; + u64 vlan_id : 12; + u64 varies : 12; + u64 dec_ipcomp : 1; + u64 tcp_or_udp : 1; + u64 dec_ipsec : 1; + u64 is_v6 : 1; + u64 software : 1; + u64 L4_error : 1; + u64 is_frag : 1; + u64 IP_exc : 1; + u64 is_bcast : 1; + u64 is_mcast : 1; + u64 not_IP : 1; + u64 rcv_error : 1; + u64 err_code : 8; + } s; + struct { + u64 bufs : 8; + u64 ip_offset : 8; + u64 vlan_valid : 1; + u64 vlan_stacked : 1; + u64 unassigned : 1; + u64 vlan_cfi : 1; + u64 vlan_id : 12; + u64 port : 12; + u64 dec_ipcomp : 1; + u64 tcp_or_udp : 1; + u64 dec_ipsec : 1; + u64 is_v6 : 1; + u64 software : 1; + u64 L4_error : 1; + u64 is_frag : 1; + u64 IP_exc : 1; + u64 is_bcast : 1; + u64 is_mcast : 1; + u64 not_IP : 1; + u64 rcv_error : 1; + u64 err_code : 8; + } s_cn68xx; + struct { + u64 bufs : 8; + u64 ip_offset : 8; + u64 vlan_valid : 1; + u64 vlan_stacked : 1; + u64 unassigned : 1; + u64 vlan_cfi : 1; + u64 vlan_id : 12; + u64 pr : 4; + u64 unassigned2a : 4; + u64 unassigned2 : 4; + u64 dec_ipcomp : 1; + u64 tcp_or_udp : 1; + u64 dec_ipsec : 1; + u64 is_v6 : 1; + u64 software : 1; + u64 L4_error : 1; + u64 is_frag : 1; + u64 IP_exc : 1; + u64 is_bcast : 1; + u64 is_mcast : 1; + u64 not_IP : 1; + u64 rcv_error : 1; + u64 err_code : 8; + } s_cn38xx; + struct { + u64 unused1 : 16; + u64 vlan : 16; + u64 unused2 : 32; + } svlan; + struct { + u64 bufs : 8; + u64 unused : 8; + u64 vlan_valid : 1; + u64 vlan_stacked : 1; + u64 unassigned : 1; + u64 vlan_cfi : 1; + u64 vlan_id : 12; + u64 varies : 12; + u64 unassigned2 : 4; + u64 software : 1; + u64 unassigned3 : 1; + u64 is_rarp : 1; + u64 is_arp : 1; + u64 is_bcast : 1; + u64 is_mcast : 1; + u64 not_IP : 1; + u64 rcv_error : 1; + u64 err_code : 8; + } snoip; + struct { + u64 bufs : 8; + u64 unused : 8; + u64 vlan_valid : 1; + u64 vlan_stacked : 1; + u64 unassigned : 1; + u64 vlan_cfi : 1; + u64 vlan_id : 12; + u64 port : 12; + u64 unassigned2 : 4; + u64 software : 1; + u64 unassigned3 : 1; + u64 is_rarp : 1; + u64 is_arp : 1; + u64 is_bcast : 1; + u64 is_mcast : 1; + u64 not_IP : 1; + u64 rcv_error : 1; + u64 err_code : 8; + } snoip_cn68xx; + struct { + u64 bufs : 8; + u64 unused : 8; + u64 vlan_valid : 1; + u64 vlan_stacked : 1; + u64 unassigned : 1; + u64 vlan_cfi : 1; + u64 vlan_id : 12; + u64 pr : 4; + u64 unassigned2a : 8; + u64 unassigned2 : 4; + u64 software : 1; + u64 unassigned3 : 1; + u64 is_rarp : 1; + u64 is_arp : 1; + u64 is_bcast : 1; + u64 is_mcast : 1; + u64 not_IP : 1; + u64 rcv_error : 1; + u64 err_code : 8; + } snoip_cn38xx; +} cvmx_pip_wqe_word2_t; + +typedef union { + u64 u64; + struct { + u64 software : 1; + u64 lg_hdr_type : 5; + u64 lf_hdr_type : 5; + u64 le_hdr_type : 5; + u64 ld_hdr_type : 5; + u64 lc_hdr_type : 5; + u64 lb_hdr_type : 5; + u64 is_la_ether : 1; + u64 rsvd_0 : 8; + u64 vlan_valid : 1; + u64 vlan_stacked : 1; + u64 stat_inc : 1; + u64 pcam_flag4 : 1; + u64 pcam_flag3 : 1; + u64 pcam_flag2 : 1; + u64 pcam_flag1 : 1; + u64 is_frag : 1; + u64 is_l3_bcast : 1; + u64 is_l3_mcast : 1; + u64 is_l2_bcast : 1; + u64 is_l2_mcast : 1; + u64 is_raw : 1; + u64 err_level : 3; + u64 err_code : 8; + }; +} cvmx_pki_wqe_word2_t; + +typedef union { + u64 u64; + cvmx_pki_wqe_word2_t pki; + cvmx_pip_wqe_word2_t pip; +} cvmx_wqe_word2_t; + +typedef union { + u64 u64; + struct { + u16 hw_chksum; + u8 unused; + u64 next_ptr : 40; + } cn38xx; + struct { + u64 l4ptr : 8; /* 56..63 */ + u64 unused0 : 8; /* 48..55 */ + u64 l3ptr : 8; /* 40..47 */ + u64 l2ptr : 8; /* 32..39 */ + u64 unused1 : 18; /* 14..31 */ + u64 bpid : 6; /* 8..13 */ + u64 unused2 : 2; /* 6..7 */ + u64 pknd : 6; /* 0..5 */ + } cn68xx; +} cvmx_pip_wqe_word0_t; + +typedef union { + u64 u64; + struct { + u64 rsvd_0 : 4; + u64 aura : 12; + u64 rsvd_1 : 1; + u64 apad : 3; + u64 channel : 12; + u64 bufs : 8; + u64 style : 8; + u64 rsvd_2 : 10; + u64 pknd : 6; + }; +} cvmx_pki_wqe_word0_t; + +/* Use reserved bit, set by HW to 0, to indicate buf_ptr legacy translation*/ +#define pki_wqe_translated word0.rsvd_1 + +typedef union { + u64 u64; + cvmx_pip_wqe_word0_t pip; + cvmx_pki_wqe_word0_t pki; + struct { + u64 unused : 24; + u64 next_ptr : 40; /* On cn68xx this is unused as well */ + } raw; +} cvmx_wqe_word0_t; + +typedef union { + u64 u64; + struct { + u64 len : 16; + u64 rsvd_0 : 2; + u64 rsvd_1 : 2; + u64 grp : 10; + cvmx_pow_tag_type_t tag_type : 2; + u64 tag : 32; + }; +} cvmx_pki_wqe_word1_t; + +#define pki_errata20776 word1.rsvd_0 + +typedef union { + u64 u64; + struct { + u64 len : 16; + u64 varies : 14; + cvmx_pow_tag_type_t tag_type : 2; + u64 tag : 32; + }; + cvmx_pki_wqe_word1_t cn78xx; + struct { + u64 len : 16; + u64 zero_0 : 1; + u64 qos : 3; + u64 zero_1 : 1; + u64 grp : 6; + u64 zero_2 : 3; + cvmx_pow_tag_type_t tag_type : 2; + u64 tag : 32; + } cn68xx; + struct { + u64 len : 16; + u64 ipprt : 6; + u64 qos : 3; + u64 grp : 4; + u64 zero_2 : 1; + cvmx_pow_tag_type_t tag_type : 2; + u64 tag : 32; + } cn38xx; +} cvmx_wqe_word1_t; + +typedef union { + u64 u64; + struct { + u64 rsvd_0 : 8; + u64 hwerr : 8; + u64 rsvd_1 : 24; + u64 sqid : 8; + u64 rsvd_2 : 4; + u64 vfnum : 12; + }; +} cvmx_wqe_word3_t; + +typedef union { + u64 u64; + struct { + u64 rsvd_0 : 21; + u64 sqfc : 11; + u64 rsvd_1 : 5; + u64 sqtail : 11; + u64 rsvd_2 : 3; + u64 sqhead : 13; + }; +} cvmx_wqe_word4_t; + +/** + * Work queue entry format. + * Must be 8-byte aligned. + */ +typedef struct cvmx_wqe_s { + /*-------------------------------------------------------------------*/ + /* WORD 0 */ + /*-------------------------------------------------------------------*/ + /* HW WRITE: the following 64 bits are filled by HW when a packet + * arrives. + */ + cvmx_wqe_word0_t word0; + + /*-------------------------------------------------------------------*/ + /* WORD 1 */ + /*-------------------------------------------------------------------*/ + /* HW WRITE: the following 64 bits are filled by HW when a packet + * arrives. + */ + cvmx_wqe_word1_t word1; + + /*-------------------------------------------------------------------*/ + /* WORD 2 */ + /*-------------------------------------------------------------------*/ + /* HW WRITE: the following 64-bits are filled in by hardware when a + * packet arrives. This indicates a variety of status and error + *conditions. + */ + cvmx_pip_wqe_word2_t word2; + + /* Pointer to the first segment of the packet. */ + cvmx_buf_ptr_t packet_ptr; + + /* HW WRITE: OCTEON will fill in a programmable amount from the packet, + * up to (at most, but perhaps less) the amount needed to fill the work + * queue entry to 128 bytes. If the packet is recognized to be IP, the + * hardware starts (except that the IPv4 header is padded for + * appropriate alignment) writing here where the IP header starts. + * If the packet is not recognized to be IP, the hardware starts + * writing the beginning of the packet here. + */ + u8 packet_data[96]; + + /* If desired, SW can make the work Q entry any length. For the purposes + * of discussion here, Assume 128B always, as this is all that the hardware + * deals with. + */ +} CVMX_CACHE_LINE_ALIGNED cvmx_wqe_t; + +/** + * Work queue entry format for NQM + * Must be 8-byte aligned + */ +typedef struct cvmx_wqe_nqm_s { + /*-------------------------------------------------------------------*/ + /* WORD 0 */ + /*-------------------------------------------------------------------*/ + /* HW WRITE: the following 64 bits are filled by HW when a packet + * arrives. + */ + cvmx_wqe_word0_t word0; + + /*-------------------------------------------------------------------*/ + /* WORD 1 */ + /*-------------------------------------------------------------------*/ + /* HW WRITE: the following 64 bits are filled by HW when a packet + * arrives. + */ + cvmx_wqe_word1_t word1; + + /*-------------------------------------------------------------------*/ + /* WORD 2 */ + /*-------------------------------------------------------------------*/ + /* Reserved */ + u64 word2; + + /*-------------------------------------------------------------------*/ + /* WORD 3 */ + /*-------------------------------------------------------------------*/ + /* NVMe specific information.*/ + cvmx_wqe_word3_t word3; + + /*-------------------------------------------------------------------*/ + /* WORD 4 */ + /*-------------------------------------------------------------------*/ + /* NVMe specific information.*/ + cvmx_wqe_word4_t word4; + + /* HW WRITE: OCTEON will fill in a programmable amount from the packet, + * up to (at most, but perhaps less) the amount needed to fill the work + * queue entry to 128 bytes. If the packet is recognized to be IP, the + * hardware starts (except that the IPv4 header is padded for + * appropriate alignment) writing here where the IP header starts. + * If the packet is not recognized to be IP, the hardware starts + * writing the beginning of the packet here. + */ + u8 packet_data[88]; + + /* If desired, SW can make the work Q entry any length. + * For the purposes of discussion here, assume 128B always, as this is + * all that the hardware deals with. + */ +} CVMX_CACHE_LINE_ALIGNED cvmx_wqe_nqm_t; + +/** + * Work queue entry format for 78XX. + * In 78XX packet data always resides in WQE buffer unless option + * DIS_WQ_DAT=1 in PKI_STYLE_BUF, which causes packet data to use separate buffer. + * + * Must be 8-byte aligned. + */ +typedef struct { + /*-------------------------------------------------------------------*/ + /* WORD 0 */ + /*-------------------------------------------------------------------*/ + /* HW WRITE: the following 64 bits are filled by HW when a packet + * arrives. + */ + cvmx_pki_wqe_word0_t word0; + + /*-------------------------------------------------------------------*/ + /* WORD 1 */ + /*-------------------------------------------------------------------*/ + /* HW WRITE: the following 64 bits are filled by HW when a packet + * arrives. + */ + cvmx_pki_wqe_word1_t word1; + + /*-------------------------------------------------------------------*/ + /* WORD 2 */ + /*-------------------------------------------------------------------*/ + /* HW WRITE: the following 64-bits are filled in by hardware when a + * packet arrives. This indicates a variety of status and error + * conditions. + */ + cvmx_pki_wqe_word2_t word2; + + /*-------------------------------------------------------------------*/ + /* WORD 3 */ + /*-------------------------------------------------------------------*/ + /* Pointer to the first segment of the packet.*/ + cvmx_buf_ptr_pki_t packet_ptr; + + /*-------------------------------------------------------------------*/ + /* WORD 4 */ + /*-------------------------------------------------------------------*/ + /* HW WRITE: the following 64-bits are filled in by hardware when a + * packet arrives contains a byte pointer to the start of Layer + * A/B/C/D/E/F/G relative of start of packet. + */ + cvmx_pki_wqe_word4_t word4; + + /*-------------------------------------------------------------------*/ + /* WORDs 5/6/7 may be extended there, if WQE_HSZ is set. */ + /*-------------------------------------------------------------------*/ + u64 wqe_data[11]; + +} CVMX_CACHE_LINE_ALIGNED cvmx_wqe_78xx_t; + +/* Node LS-bit position in the WQE[grp] or PKI_QPG_TBL[grp_ok].*/ +#define CVMX_WQE_GRP_NODE_SHIFT 8 + +/* + * This is an accessor function into the WQE that retreives the + * ingress port number, which can also be used as a destination + * port number for the same port. + * + * @param work - Work Queue Entrey pointer + * @returns returns the normalized port number, also known as "ipd" port + */ +static inline int cvmx_wqe_get_port(cvmx_wqe_t *work) +{ + int port; + + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + /* In 78xx wqe entry has channel number not port*/ + port = work->word0.pki.channel; + /* For BGX interfaces (0x800 - 0xdff) the 4 LSBs indicate + * the PFC channel, must be cleared to normalize to "ipd" + */ + if (port & 0x800) + port &= 0xff0; + /* Node number is in AURA field, make it part of port # */ + port |= (work->word0.pki.aura >> 10) << 12; + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + port = work->word2.s_cn68xx.port; + } else { + port = work->word1.cn38xx.ipprt; + } + + return port; +} + +static inline void cvmx_wqe_set_port(cvmx_wqe_t *work, int port) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) + work->word0.pki.channel = port; + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + work->word2.s_cn68xx.port = port; + else + work->word1.cn38xx.ipprt = port; +} + +static inline int cvmx_wqe_get_grp(cvmx_wqe_t *work) +{ + int grp; + + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) + /* legacy: GRP[0..2] :=QOS */ + grp = (0xff & work->word1.cn78xx.grp) >> 3; + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + grp = work->word1.cn68xx.grp; + else + grp = work->word1.cn38xx.grp; + + return grp; +} + +static inline void cvmx_wqe_set_xgrp(cvmx_wqe_t *work, int grp) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) + work->word1.cn78xx.grp = grp; + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + work->word1.cn68xx.grp = grp; + else + work->word1.cn38xx.grp = grp; +} + +static inline int cvmx_wqe_get_xgrp(cvmx_wqe_t *work) +{ + int grp; + + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) + grp = work->word1.cn78xx.grp; + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + grp = work->word1.cn68xx.grp; + else + grp = work->word1.cn38xx.grp; + + return grp; +} + +static inline void cvmx_wqe_set_grp(cvmx_wqe_t *work, int grp) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + unsigned int node = cvmx_get_node_num(); + /* Legacy: GRP[0..2] :=QOS */ + work->word1.cn78xx.grp &= 0x7; + work->word1.cn78xx.grp |= 0xff & (grp << 3); + work->word1.cn78xx.grp |= (node << 8); + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + work->word1.cn68xx.grp = grp; + } else { + work->word1.cn38xx.grp = grp; + } +} + +static inline int cvmx_wqe_get_qos(cvmx_wqe_t *work) +{ + int qos; + + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + /* Legacy: GRP[0..2] :=QOS */ + qos = work->word1.cn78xx.grp & 0x7; + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + qos = work->word1.cn68xx.qos; + } else { + qos = work->word1.cn38xx.qos; + } + + return qos; +} + +static inline void cvmx_wqe_set_qos(cvmx_wqe_t *work, int qos) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + /* legacy: GRP[0..2] :=QOS */ + work->word1.cn78xx.grp &= ~0x7; + work->word1.cn78xx.grp |= qos & 0x7; + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + work->word1.cn68xx.qos = qos; + } else { + work->word1.cn38xx.qos = qos; + } +} + +static inline int cvmx_wqe_get_len(cvmx_wqe_t *work) +{ + int len; + + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) + len = work->word1.cn78xx.len; + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + len = work->word1.cn68xx.len; + else + len = work->word1.cn38xx.len; + + return len; +} + +static inline void cvmx_wqe_set_len(cvmx_wqe_t *work, int len) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) + work->word1.cn78xx.len = len; + else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + work->word1.cn68xx.len = len; + else + work->word1.cn38xx.len = len; +} + +/** + * This function returns, if there was L2/L1 errors detected in packet. + * + * @param work pointer to work queue entry + * + * @return 0 if packet had no error, non-zero to indicate error code. + * + * Please refer to HRM for the specific model for full enumaration of error codes. + * With Octeon1/Octeon2 models, the returned code indicates L1/L2 errors. + * On CN73XX/CN78XX, the return code is the value of PKI_OPCODE_E, + * if it is non-zero, otherwise the returned code will be derived from + * PKI_ERRLEV_E such that an error indicated in LayerA will return 0x20, + * LayerB - 0x30, LayerC - 0x40 and so forth. + */ +static inline int cvmx_wqe_get_rcv_err(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + if (wqe->word2.err_level == CVMX_PKI_ERRLEV_E_RE || wqe->word2.err_code != 0) + return wqe->word2.err_code; + else + return (wqe->word2.err_level << 4) + 0x10; + } else if (work->word2.snoip.rcv_error) { + return work->word2.snoip.err_code; + } + + return 0; +} + +static inline u32 cvmx_wqe_get_tag(cvmx_wqe_t *work) +{ + return work->word1.tag; +} + +static inline void cvmx_wqe_set_tag(cvmx_wqe_t *work, u32 tag) +{ + work->word1.tag = tag; +} + +static inline int cvmx_wqe_get_tt(cvmx_wqe_t *work) +{ + return work->word1.tag_type; +} + +static inline void cvmx_wqe_set_tt(cvmx_wqe_t *work, int tt) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + work->word1.cn78xx.tag_type = (cvmx_pow_tag_type_t)tt; + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + work->word1.cn68xx.tag_type = (cvmx_pow_tag_type_t)tt; + work->word1.cn68xx.zero_2 = 0; + } else { + work->word1.cn38xx.tag_type = (cvmx_pow_tag_type_t)tt; + work->word1.cn38xx.zero_2 = 0; + } +} + +static inline u8 cvmx_wqe_get_unused8(cvmx_wqe_t *work) +{ + u8 bits; + + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + bits = wqe->word2.rsvd_0; + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + bits = work->word0.pip.cn68xx.unused1; + } else { + bits = work->word0.pip.cn38xx.unused; + } + + return bits; +} + +static inline void cvmx_wqe_set_unused8(cvmx_wqe_t *work, u8 v) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + wqe->word2.rsvd_0 = v; + } else if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) { + work->word0.pip.cn68xx.unused1 = v; + } else { + work->word0.pip.cn38xx.unused = v; + } +} + +static inline u8 cvmx_wqe_get_user_flags(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) + return work->word0.pki.rsvd_2; + else + return 0; +} + +static inline void cvmx_wqe_set_user_flags(cvmx_wqe_t *work, u8 v) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) + work->word0.pki.rsvd_2 = v; +} + +static inline int cvmx_wqe_get_channel(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) + return (work->word0.pki.channel); + else + return cvmx_wqe_get_port(work); +} + +static inline void cvmx_wqe_set_channel(cvmx_wqe_t *work, int channel) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) + work->word0.pki.channel = channel; + else + debug("%s: ERROR: not supported for model\n", __func__); +} + +static inline int cvmx_wqe_get_aura(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) + return (work->word0.pki.aura); + else + return (work->packet_ptr.s.pool); +} + +static inline void cvmx_wqe_set_aura(cvmx_wqe_t *work, int aura) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) + work->word0.pki.aura = aura; + else + work->packet_ptr.s.pool = aura; +} + +static inline int cvmx_wqe_get_style(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) + return (work->word0.pki.style); + return 0; +} + +static inline void cvmx_wqe_set_style(cvmx_wqe_t *work, int style) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) + work->word0.pki.style = style; +} + +static inline int cvmx_wqe_is_l3_ip(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + /* Match all 4 values for v4/v6 with.without options */ + if ((wqe->word2.lc_hdr_type & 0x1c) == CVMX_PKI_LTYPE_E_IP4) + return 1; + if ((wqe->word2.le_hdr_type & 0x1c) == CVMX_PKI_LTYPE_E_IP4) + return 1; + return 0; + } else { + return !work->word2.s_cn38xx.not_IP; + } +} + +static inline int cvmx_wqe_is_l3_ipv4(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + /* Match 2 values - with/wotuout options */ + if ((wqe->word2.lc_hdr_type & 0x1e) == CVMX_PKI_LTYPE_E_IP4) + return 1; + if ((wqe->word2.le_hdr_type & 0x1e) == CVMX_PKI_LTYPE_E_IP4) + return 1; + return 0; + } else { + return (!work->word2.s_cn38xx.not_IP && + !work->word2.s_cn38xx.is_v6); + } +} + +static inline int cvmx_wqe_is_l3_ipv6(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + /* Match 2 values - with/wotuout options */ + if ((wqe->word2.lc_hdr_type & 0x1e) == CVMX_PKI_LTYPE_E_IP6) + return 1; + if ((wqe->word2.le_hdr_type & 0x1e) == CVMX_PKI_LTYPE_E_IP6) + return 1; + return 0; + } else { + return (!work->word2.s_cn38xx.not_IP && + work->word2.s_cn38xx.is_v6); + } +} + +static inline bool cvmx_wqe_is_l4_udp_or_tcp(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + if (wqe->word2.lf_hdr_type == CVMX_PKI_LTYPE_E_TCP) + return true; + if (wqe->word2.lf_hdr_type == CVMX_PKI_LTYPE_E_UDP) + return true; + return false; + } + + if (work->word2.s_cn38xx.not_IP) + return false; + + return (work->word2.s_cn38xx.tcp_or_udp != 0); +} + +static inline int cvmx_wqe_is_l2_bcast(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + return wqe->word2.is_l2_bcast; + } else { + return work->word2.s_cn38xx.is_bcast; + } +} + +static inline int cvmx_wqe_is_l2_mcast(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + return wqe->word2.is_l2_mcast; + } else { + return work->word2.s_cn38xx.is_mcast; + } +} + +static inline void cvmx_wqe_set_l2_bcast(cvmx_wqe_t *work, bool bcast) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + wqe->word2.is_l2_bcast = bcast; + } else { + work->word2.s_cn38xx.is_bcast = bcast; + } +} + +static inline void cvmx_wqe_set_l2_mcast(cvmx_wqe_t *work, bool mcast) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + wqe->word2.is_l2_mcast = mcast; + } else { + work->word2.s_cn38xx.is_mcast = mcast; + } +} + +static inline int cvmx_wqe_is_l3_bcast(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + return wqe->word2.is_l3_bcast; + } + debug("%s: ERROR: not supported for model\n", __func__); + return 0; +} + +static inline int cvmx_wqe_is_l3_mcast(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + return wqe->word2.is_l3_mcast; + } + debug("%s: ERROR: not supported for model\n", __func__); + return 0; +} + +/** + * This function returns is there was IP error detected in packet. + * For 78XX it does not flag ipv4 options and ipv6 extensions. + * For older chips if PIP_GBL_CTL was proviosned to flag ip4_otions and + * ipv6 extension, it will be flag them. + * @param work pointer to work queue entry + * @return 1 -- If IP error was found in packet + * 0 -- If no IP error was found in packet. + */ +static inline int cvmx_wqe_is_ip_exception(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + if (wqe->word2.err_level == CVMX_PKI_ERRLEV_E_LC) + return 1; + else + return 0; + } + + return work->word2.s.IP_exc; +} + +static inline int cvmx_wqe_is_l4_error(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + if (wqe->word2.err_level == CVMX_PKI_ERRLEV_E_LF) + return 1; + else + return 0; + } else { + return work->word2.s.L4_error; + } +} + +static inline void cvmx_wqe_set_vlan(cvmx_wqe_t *work, bool set) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + wqe->word2.vlan_valid = set; + } else { + work->word2.s.vlan_valid = set; + } +} + +static inline int cvmx_wqe_is_vlan(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + return wqe->word2.vlan_valid; + } else { + return work->word2.s.vlan_valid; + } +} + +static inline int cvmx_wqe_is_vlan_stacked(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + return wqe->word2.vlan_stacked; + } else { + return work->word2.s.vlan_stacked; + } +} + +/** + * Extract packet data buffer pointer from work queue entry. + * + * Returns the legacy (Octeon1/Octeon2) buffer pointer structure + * for the linked buffer list. + * On CN78XX, the native buffer pointer structure is converted into + * the legacy format. + * The legacy buf_ptr is then stored in the WQE, and word0 reserved + * field is set to indicate that the buffer pointers were translated. + * If the packet data is only found inside the work queue entry, + * a standard buffer pointer structure is created for it. + */ +cvmx_buf_ptr_t cvmx_wqe_get_packet_ptr(cvmx_wqe_t *work); + +static inline int cvmx_wqe_get_bufs(cvmx_wqe_t *work) +{ + int bufs; + + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + bufs = work->word0.pki.bufs; + } else { + /* Adjust for packet-in-WQE cases */ + if (cvmx_unlikely(work->word2.s_cn38xx.bufs == 0 && !work->word2.s.software)) + (void)cvmx_wqe_get_packet_ptr(work); + bufs = work->word2.s_cn38xx.bufs; + } + return bufs; +} + +/** + * Free Work Queue Entry memory + * + * Will return the WQE buffer to its pool, unless the WQE contains + * non-redundant packet data. + * This function is intended to be called AFTER the packet data + * has been passed along to PKO for transmission and release. + * It can also follow a call to cvmx_helper_free_packet_data() + * to release the WQE after associated data was released. + */ +void cvmx_wqe_free(cvmx_wqe_t *work); + +/** + * Check if a work entry has been intiated by software + * + */ +static inline bool cvmx_wqe_is_soft(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + return wqe->word2.software; + } else { + return work->word2.s.software; + } +} + +/** + * Allocate a work-queue entry for delivering software-initiated + * event notifications. + * The application data is copied into the work-queue entry, + * if the space is sufficient. + */ +cvmx_wqe_t *cvmx_wqe_soft_create(void *data_p, unsigned int data_sz); + +/* Errata (PKI-20776) PKI_BUFLINK_S's are endian-swapped + * CN78XX pass 1.x has a bug where the packet pointer in each segment is + * written in the opposite endianness of the configured mode. Fix these here. + */ +static inline void cvmx_wqe_pki_errata_20776(cvmx_wqe_t *work) +{ + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X) && !wqe->pki_errata20776) { + u64 bufs; + cvmx_buf_ptr_pki_t buffer_next; + + bufs = wqe->word0.bufs; + buffer_next = wqe->packet_ptr; + while (bufs > 1) { + cvmx_buf_ptr_pki_t next; + void *nextaddr = cvmx_phys_to_ptr(buffer_next.addr - 8); + + memcpy(&next, nextaddr, sizeof(next)); + next.u64 = __builtin_bswap64(next.u64); + memcpy(nextaddr, &next, sizeof(next)); + buffer_next = next; + bufs--; + } + wqe->pki_errata20776 = 1; + } +} + +/** + * @INTERNAL + * + * Extract the native PKI-specific buffer pointer from WQE. + * + * NOTE: Provisional, may be superceded. + */ +static inline cvmx_buf_ptr_pki_t cvmx_wqe_get_pki_pkt_ptr(cvmx_wqe_t *work) +{ + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + if (!octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_buf_ptr_pki_t x = { 0 }; + return x; + } + + cvmx_wqe_pki_errata_20776(work); + return wqe->packet_ptr; +} + +/** + * Set the buffer segment count for a packet. + * + * @return Returns the actual resulting value in the WQE fielda + * + */ +static inline unsigned int cvmx_wqe_set_bufs(cvmx_wqe_t *work, unsigned int bufs) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + work->word0.pki.bufs = bufs; + return work->word0.pki.bufs; + } + + work->word2.s.bufs = bufs; + return work->word2.s.bufs; +} + +/** + * Get the offset of Layer-3 header, + * only supported when Layer-3 protocol is IPv4 or IPv6. + * + * @return Returns the offset, or 0 if the offset is not known or unsupported. + * + * FIXME: Assuming word4 is present. + */ +static inline unsigned int cvmx_wqe_get_l3_offset(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + /* Match 4 values: IPv4/v6 w/wo options */ + if ((wqe->word2.lc_hdr_type & 0x1c) == CVMX_PKI_LTYPE_E_IP4) + return wqe->word4.ptr_layer_c; + } else { + return work->word2.s.ip_offset; + } + + return 0; +} + +/** + * Set the offset of Layer-3 header in a packet. + * Typically used when an IP packet is generated by software + * or when the Layer-2 header length is modified, and + * a subsequent recalculation of checksums is anticipated. + * + * @return Returns the actual value of the work entry offset field. + * + * FIXME: Assuming word4 is present. + */ +static inline unsigned int cvmx_wqe_set_l3_offset(cvmx_wqe_t *work, unsigned int ip_off) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + /* Match 4 values: IPv4/v6 w/wo options */ + if ((wqe->word2.lc_hdr_type & 0x1c) == CVMX_PKI_LTYPE_E_IP4) + wqe->word4.ptr_layer_c = ip_off; + } else { + work->word2.s.ip_offset = ip_off; + } + + return cvmx_wqe_get_l3_offset(work); +} + +/** + * Set the indication that the packet contains a IPv4 Layer-3 * header. + * Use 'cvmx_wqe_set_l3_ipv6()' if the protocol is IPv6. + * When 'set' is false, the call will result in an indication + * that the Layer-3 protocol is neither IPv4 nor IPv6. + * + * FIXME: Add IPV4_OPT handling based on L3 header length. + */ +static inline void cvmx_wqe_set_l3_ipv4(cvmx_wqe_t *work, bool set) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + if (set) + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_IP4; + else + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_NONE; + } else { + work->word2.s.not_IP = !set; + if (set) + work->word2.s_cn38xx.is_v6 = 0; + } +} + +/** + * Set packet Layer-3 protocol to IPv6. + * + * FIXME: Add IPV6_OPT handling based on presence of extended headers. + */ +static inline void cvmx_wqe_set_l3_ipv6(cvmx_wqe_t *work, bool set) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + if (set) + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_IP6; + else + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_NONE; + } else { + work->word2.s_cn38xx.not_IP = !set; + if (set) + work->word2.s_cn38xx.is_v6 = 1; + } +} + +/** + * Set a packet Layer-4 protocol type to UDP. + */ +static inline void cvmx_wqe_set_l4_udp(cvmx_wqe_t *work, bool set) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + if (set) + wqe->word2.lf_hdr_type = CVMX_PKI_LTYPE_E_UDP; + else + wqe->word2.lf_hdr_type = CVMX_PKI_LTYPE_E_NONE; + } else { + if (!work->word2.s_cn38xx.not_IP) + work->word2.s_cn38xx.tcp_or_udp = set; + } +} + +/** + * Set a packet Layer-4 protocol type to TCP. + */ +static inline void cvmx_wqe_set_l4_tcp(cvmx_wqe_t *work, bool set) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + if (set) + wqe->word2.lf_hdr_type = CVMX_PKI_LTYPE_E_TCP; + else + wqe->word2.lf_hdr_type = CVMX_PKI_LTYPE_E_NONE; + } else { + if (!work->word2.s_cn38xx.not_IP) + work->word2.s_cn38xx.tcp_or_udp = set; + } +} + +/** + * Set the "software" flag in a work entry. + */ +static inline void cvmx_wqe_set_soft(cvmx_wqe_t *work, bool set) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + wqe->word2.software = set; + } else { + work->word2.s.software = set; + } +} + +/** + * Return true if the packet is an IP fragment. + */ +static inline bool cvmx_wqe_is_l3_frag(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + return (wqe->word2.is_frag != 0); + } + + if (!work->word2.s_cn38xx.not_IP) + return (work->word2.s.is_frag != 0); + + return false; +} + +/** + * Set the indicator that the packet is an fragmented IP packet. + */ +static inline void cvmx_wqe_set_l3_frag(cvmx_wqe_t *work, bool set) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + wqe->word2.is_frag = set; + } else { + if (!work->word2.s_cn38xx.not_IP) + work->word2.s.is_frag = set; + } +} + +/** + * Set the packet Layer-3 protocol to RARP. + */ +static inline void cvmx_wqe_set_l3_rarp(cvmx_wqe_t *work, bool set) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + if (set) + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_RARP; + else + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_NONE; + } else { + work->word2.snoip.is_rarp = set; + } +} + +/** + * Set the packet Layer-3 protocol to ARP. + */ +static inline void cvmx_wqe_set_l3_arp(cvmx_wqe_t *work, bool set) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + if (set) + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_ARP; + else + wqe->word2.lc_hdr_type = CVMX_PKI_LTYPE_E_NONE; + } else { + work->word2.snoip.is_arp = set; + } +} + +/** + * Return true if the packet Layer-3 protocol is ARP. + */ +static inline bool cvmx_wqe_is_l3_arp(cvmx_wqe_t *work) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) { + cvmx_wqe_78xx_t *wqe = (cvmx_wqe_78xx_t *)work; + + return (wqe->word2.lc_hdr_type == CVMX_PKI_LTYPE_E_ARP); + } + + if (work->word2.s_cn38xx.not_IP) + return (work->word2.snoip.is_arp != 0); + + return false; +} + +#endif /* __CVMX_WQE_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/octeon_qlm.h b/arch/mips/mach-octeon/include/mach/octeon_qlm.h new file mode 100644 index 000000000000..219625b25688 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/octeon_qlm.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +#ifndef __OCTEON_QLM_H__ +#define __OCTEON_QLM_H__ + +/* Reference clock selector values for ref_clk_sel */ +#define OCTEON_QLM_REF_CLK_100MHZ 0 /** 100 MHz */ +#define OCTEON_QLM_REF_CLK_125MHZ 1 /** 125 MHz */ +#define OCTEON_QLM_REF_CLK_156MHZ 2 /** 156.25 MHz */ +#define OCTEON_QLM_REF_CLK_161MHZ 3 /** 161.1328125 MHz */ + +/** + * Configure qlm/dlm speed and mode. + * @param qlm The QLM or DLM to configure + * @param speed The speed the QLM needs to be configured in Mhz. + * @param mode The QLM to be configured as SGMII/XAUI/PCIe. + * @param rc Only used for PCIe, rc = 1 for root complex mode, 0 for EP + * mode. + * @param pcie_mode Only used when qlm/dlm are in pcie mode. + * @param ref_clk_sel Reference clock to use for 70XX where: + * 0: 100MHz + * 1: 125MHz + * 2: 156.25MHz + * 3: 161.1328125MHz (CN73XX and CN78XX only) + * @param ref_clk_input This selects which reference clock input to use. For + * cn70xx: + * 0: DLMC_REF_CLK0 + * 1: DLMC_REF_CLK1 + * 2: DLM0_REF_CLK + * cn61xx: (not used) + * cn78xx/cn76xx/cn73xx: + * 0: Internal clock (QLM[0-7]_REF_CLK) + * 1: QLMC_REF_CLK0 + * 2: QLMC_REF_CLK1 + * + * @return Return 0 on success or -1. + * + * @note When the 161MHz clock is used it can only be used for + * XLAUI mode with a 6316 speed or XFI mode with a 103125 speed. + * This rate is also only supported for CN73XX and CN78XX. + */ +int octeon_configure_qlm(int qlm, int speed, int mode, int rc, int pcie_mode, int ref_clk_sel, + int ref_clk_input); + +int octeon_configure_qlm_cn78xx(int node, int qlm, int speed, int mode, int rc, int pcie_mode, + int ref_clk_sel, int ref_clk_input); + +/** + * Some QLM speeds need to override the default tuning parameters + * + * @param node Node to configure + * @param qlm QLM to configure + * @param baud_mhz Desired speed in MHz + * @param lane Lane the apply the tuning parameters + * @param tx_swing Voltage swing. The higher the value the lower the voltage, + * the default value is 7. + * @param tx_pre pre-cursor pre-emphasis + * @param tx_post post-cursor pre-emphasis. + * @param tx_gain Transmit gain. Range 0-7 + * @param tx_vboost Transmit voltage boost. Range 0-1 + */ +void octeon_qlm_tune_per_lane_v3(int node, int qlm, int baud_mhz, int lane, int tx_swing, + int tx_pre, int tx_post, int tx_gain, int tx_vboost); + +/** + * Some QLM speeds need to override the default tuning parameters + * + * @param node Node to configure + * @param qlm QLM to configure + * @param baud_mhz Desired speed in MHz + * @param tx_swing Voltage swing. The higher the value the lower the voltage, + * the default value is 7. + * @param tx_premptap bits [0:3] pre-cursor pre-emphasis, bits[4:8] post-cursor + * pre-emphasis. + * @param tx_gain Transmit gain. Range 0-7 + * @param tx_vboost Transmit voltage boost. Range 0-1 + */ +void octeon_qlm_tune_v3(int node, int qlm, int baud_mhz, int tx_swing, int tx_premptap, int tx_gain, + int tx_vboost); + +/** + * Disables DFE for the specified QLM lane(s). + * This function should only be called for low-loss channels. + * + * @param node Node to configure + * @param qlm QLM to configure + * @param lane Lane to configure, or -1 all lanes + * @param baud_mhz The speed the QLM needs to be configured in Mhz. + * @param mode The QLM to be configured as SGMII/XAUI/PCIe. + */ +void octeon_qlm_dfe_disable(int node, int qlm, int lane, int baud_mhz, int mode); + +/** + * Some QLMs need to override the default pre-ctle for low loss channels. + * + * @param node Node to configure + * @param qlm QLM to configure + * @param pre_ctle pre-ctle settings for low loss channels + */ +void octeon_qlm_set_channel_v3(int node, int qlm, int pre_ctle); + +void octeon_init_qlm(int node); + +int octeon_mcu_probe(int node); + +#endif /* __OCTEON_QLM_H__ */