numam-dpdk/drivers/net/nfp/nfpcore/nfp_target.h
Alejandro Lucero c7e9729da6 net/nfp: support CPP
CPP refers to the internal NFP Command Push Pull bus. This patch allows
to create CPP commands from user space allowing to access any single
part of the chip.

This CPP interface is the base for having other functionalities like
mutexes when accessing specific chip components, chip resources management,
firmware upload or using the NSP, an embedded arm processor which can
perform tasks on demand.

NSP was the previous only way for doing things in the chip by the PMD,
where a NSPU interface was used for commands like firmware upload or
port link configuration. CPP interface supersedes NSPU, but it is still
possible to use NSP through CPP.

CPP interface adds a great flexibility for doing things like extended
stats or firmware debugging.

Signed-off-by: Alejandro Lucero <alejandro.lucero@netronome.com>
2018-04-14 00:40:21 +02:00

580 lines
15 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2018 Netronome Systems, Inc.
* All rights reserved.
*/
#ifndef NFP_TARGET_H
#define NFP_TARGET_H
#include "nfp-common/nfp_resid.h"
#include "nfp-common/nfp_cppat.h"
#include "nfp-common/nfp_platform.h"
#include "nfp_cpp.h"
#define P32 1
#define P64 2
#define PUSHPULL(_pull, _push) (((_pull) << 4) | ((_push) << 0))
#ifndef NFP_ERRNO
#include <errno.h>
#define NFP_ERRNO(x) (errno = (x), -1)
#endif
static inline int
pushpull_width(int pp)
{
pp &= 0xf;
if (pp == 0)
return NFP_ERRNO(EINVAL);
return (2 << pp);
}
#define PUSH_WIDTH(_pushpull) pushpull_width((_pushpull) >> 0)
#define PULL_WIDTH(_pushpull) pushpull_width((_pushpull) >> 4)
static inline int
target_rw(uint32_t cpp_id, int pp, int start, int len)
{
int island = NFP_CPP_ID_ISLAND_of(cpp_id);
if (island && (island < start || island > (start + len)))
return NFP_ERRNO(EINVAL);
switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
case NFP_CPP_ID(0, 0, 0):
return PUSHPULL(0, pp);
case NFP_CPP_ID(0, 1, 0):
return PUSHPULL(pp, 0);
case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 0):
return PUSHPULL(pp, pp);
default:
return NFP_ERRNO(EINVAL);
}
}
static inline int
nfp6000_nbi_dma(uint32_t cpp_id)
{
switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
case NFP_CPP_ID(0, 0, 0): /* ReadNbiDma */
return PUSHPULL(0, P64);
case NFP_CPP_ID(0, 1, 0): /* WriteNbiDma */
return PUSHPULL(P64, 0);
case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 0):
return PUSHPULL(P64, P64);
default:
return NFP_ERRNO(EINVAL);
}
}
static inline int
nfp6000_nbi_stats(uint32_t cpp_id)
{
switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
case NFP_CPP_ID(0, 0, 0): /* ReadNbiStats */
return PUSHPULL(0, P64);
case NFP_CPP_ID(0, 1, 0): /* WriteNbiStats */
return PUSHPULL(P64, 0);
case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 0):
return PUSHPULL(P64, P64);
default:
return NFP_ERRNO(EINVAL);
}
}
static inline int
nfp6000_nbi_tm(uint32_t cpp_id)
{
switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
case NFP_CPP_ID(0, 0, 0): /* ReadNbiTM */
return PUSHPULL(0, P64);
case NFP_CPP_ID(0, 1, 0): /* WriteNbiTM */
return PUSHPULL(P64, 0);
case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 0):
return PUSHPULL(P64, P64);
default:
return NFP_ERRNO(EINVAL);
}
}
static inline int
nfp6000_nbi_ppc(uint32_t cpp_id)
{
switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
case NFP_CPP_ID(0, 0, 0): /* ReadNbiPreclassifier */
return PUSHPULL(0, P64);
case NFP_CPP_ID(0, 1, 0): /* WriteNbiPreclassifier */
return PUSHPULL(P64, 0);
case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 0):
return PUSHPULL(P64, P64);
default:
return NFP_ERRNO(EINVAL);
}
}
static inline int
nfp6000_nbi(uint32_t cpp_id, uint64_t address)
{
int island = NFP_CPP_ID_ISLAND_of(cpp_id);
uint64_t rel_addr = address & 0x3fFFFF;
if (island && (island < 8 || island > 9))
return NFP_ERRNO(EINVAL);
if (rel_addr < (1 << 20))
return nfp6000_nbi_dma(cpp_id);
if (rel_addr < (2 << 20))
return nfp6000_nbi_stats(cpp_id);
if (rel_addr < (3 << 20))
return nfp6000_nbi_tm(cpp_id);
return nfp6000_nbi_ppc(cpp_id);
}
/*
* This structure ONLY includes items that can be done with a read or write of
* 32-bit or 64-bit words. All others are not listed.
*/
static inline int
nfp6000_mu_common(uint32_t cpp_id)
{
switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 0): /* read_be/write_be */
return PUSHPULL(P64, P64);
case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 1): /* read_le/write_le */
return PUSHPULL(P64, P64);
case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 2): /* {read/write}_swap_be */
return PUSHPULL(P64, P64);
case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 3): /* {read/write}_swap_le */
return PUSHPULL(P64, P64);
case NFP_CPP_ID(0, 0, 0): /* read_be */
return PUSHPULL(0, P64);
case NFP_CPP_ID(0, 0, 1): /* read_le */
return PUSHPULL(0, P64);
case NFP_CPP_ID(0, 0, 2): /* read_swap_be */
return PUSHPULL(0, P64);
case NFP_CPP_ID(0, 0, 3): /* read_swap_le */
return PUSHPULL(0, P64);
case NFP_CPP_ID(0, 1, 0): /* write_be */
return PUSHPULL(P64, 0);
case NFP_CPP_ID(0, 1, 1): /* write_le */
return PUSHPULL(P64, 0);
case NFP_CPP_ID(0, 1, 2): /* write_swap_be */
return PUSHPULL(P64, 0);
case NFP_CPP_ID(0, 1, 3): /* write_swap_le */
return PUSHPULL(P64, 0);
case NFP_CPP_ID(0, 3, 0): /* atomic_read */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 3, 2): /* mask_compare_write */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 4, 0): /* atomic_write */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 4, 2): /* atomic_write_imm */
return PUSHPULL(0, 0);
case NFP_CPP_ID(0, 4, 3): /* swap_imm */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 5, 0): /* set */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 5, 3): /* test_set_imm */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 6, 0): /* clr */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 6, 3): /* test_clr_imm */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 7, 0): /* add */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 7, 3): /* test_add_imm */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 8, 0): /* addsat */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 8, 3): /* test_subsat_imm */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 9, 0): /* sub */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 9, 3): /* test_sub_imm */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 10, 0): /* subsat */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 10, 3): /* test_subsat_imm */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 13, 0): /* microq128_get */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 13, 1): /* microq128_pop */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 13, 2): /* microq128_put */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 15, 0): /* xor */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 15, 3): /* test_xor_imm */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 28, 0): /* read32_be */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 28, 1): /* read32_le */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 28, 2): /* read32_swap_be */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 28, 3): /* read32_swap_le */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 31, 0): /* write32_be */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 31, 1): /* write32_le */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 31, 2): /* write32_swap_be */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 31, 3): /* write32_swap_le */
return PUSHPULL(P32, 0);
default:
return NFP_ERRNO(EINVAL);
}
}
static inline int
nfp6000_mu_ctm(uint32_t cpp_id)
{
switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
case NFP_CPP_ID(0, 16, 1): /* packet_read_packet_status */
return PUSHPULL(0, P32);
default:
return nfp6000_mu_common(cpp_id);
}
}
static inline int
nfp6000_mu_emu(uint32_t cpp_id)
{
switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
case NFP_CPP_ID(0, 18, 0): /* read_queue */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 18, 1): /* read_queue_ring */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 18, 2): /* write_queue */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 18, 3): /* write_queue_ring */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 20, 2): /* journal */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 21, 0): /* get */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 21, 1): /* get_eop */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 21, 2): /* get_freely */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 22, 0): /* pop */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 22, 1): /* pop_eop */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 22, 2): /* pop_freely */
return PUSHPULL(0, P32);
default:
return nfp6000_mu_common(cpp_id);
}
}
static inline int
nfp6000_mu_imu(uint32_t cpp_id)
{
return nfp6000_mu_common(cpp_id);
}
static inline int
nfp6000_mu(uint32_t cpp_id, uint64_t address)
{
int pp;
int island = NFP_CPP_ID_ISLAND_of(cpp_id);
if (island == 0) {
if (address < 0x2000000000ULL)
pp = nfp6000_mu_ctm(cpp_id);
else if (address < 0x8000000000ULL)
pp = nfp6000_mu_emu(cpp_id);
else if (address < 0x9800000000ULL)
pp = nfp6000_mu_ctm(cpp_id);
else if (address < 0x9C00000000ULL)
pp = nfp6000_mu_emu(cpp_id);
else if (address < 0xA000000000ULL)
pp = nfp6000_mu_imu(cpp_id);
else
pp = nfp6000_mu_ctm(cpp_id);
} else if (island >= 24 && island <= 27) {
pp = nfp6000_mu_emu(cpp_id);
} else if (island >= 28 && island <= 31) {
pp = nfp6000_mu_imu(cpp_id);
} else if (island == 1 ||
(island >= 4 && island <= 7) ||
(island >= 12 && island <= 13) ||
(island >= 32 && island <= 47) ||
(island >= 48 && island <= 51)) {
pp = nfp6000_mu_ctm(cpp_id);
} else {
pp = NFP_ERRNO(EINVAL);
}
return pp;
}
static inline int
nfp6000_ila(uint32_t cpp_id)
{
int island = NFP_CPP_ID_ISLAND_of(cpp_id);
if (island && (island < 48 || island > 51))
return NFP_ERRNO(EINVAL);
switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
case NFP_CPP_ID(0, 0, 1): /* read_check_error */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 2, 0): /* read_int */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 3, 0): /* write_int */
return PUSHPULL(P32, 0);
default:
return target_rw(cpp_id, P32, 48, 4);
}
}
static inline int
nfp6000_pci(uint32_t cpp_id)
{
int island = NFP_CPP_ID_ISLAND_of(cpp_id);
if (island && (island < 4 || island > 7))
return NFP_ERRNO(EINVAL);
switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
case NFP_CPP_ID(0, 2, 0):
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 3, 0):
return PUSHPULL(P32, 0);
default:
return target_rw(cpp_id, P32, 4, 4);
}
}
static inline int
nfp6000_crypto(uint32_t cpp_id)
{
int island = NFP_CPP_ID_ISLAND_of(cpp_id);
if (island && (island < 12 || island > 15))
return NFP_ERRNO(EINVAL);
switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
case NFP_CPP_ID(0, 2, 0):
return PUSHPULL(P64, 0);
default:
return target_rw(cpp_id, P64, 12, 4);
}
}
static inline int
nfp6000_cap_xpb(uint32_t cpp_id)
{
int island = NFP_CPP_ID_ISLAND_of(cpp_id);
if (island && (island < 1 || island > 63))
return NFP_ERRNO(EINVAL);
switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
case NFP_CPP_ID(0, 0, 1): /* RingGet */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 0, 2): /* Interthread Signal */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 1, 1): /* RingPut */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 1, 2): /* CTNNWr */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 2, 0): /* ReflectRd, signal none */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 2, 1): /* ReflectRd, signal self */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 2, 2): /* ReflectRd, signal remote */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 2, 3): /* ReflectRd, signal both */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 3, 0): /* ReflectWr, signal none */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 3, 1): /* ReflectWr, signal self */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 3, 2): /* ReflectWr, signal remote */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 3, 3): /* ReflectWr, signal both */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, NFP_CPP_ACTION_RW, 1):
return PUSHPULL(P32, P32);
default:
return target_rw(cpp_id, P32, 1, 63);
}
}
static inline int
nfp6000_cls(uint32_t cpp_id)
{
int island = NFP_CPP_ID_ISLAND_of(cpp_id);
if (island && (island < 1 || island > 63))
return NFP_ERRNO(EINVAL);
switch (cpp_id & NFP_CPP_ID(0, ~0, ~0)) {
case NFP_CPP_ID(0, 0, 3): /* xor */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 2, 0): /* set */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 2, 1): /* clr */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 4, 0): /* add */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 4, 1): /* add64 */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 6, 0): /* sub */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 6, 1): /* sub64 */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 6, 2): /* subsat */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 8, 2): /* hash_mask */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 8, 3): /* hash_clear */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 9, 0): /* ring_get */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 9, 1): /* ring_pop */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 9, 2): /* ring_get_freely */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 9, 3): /* ring_pop_freely */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 10, 0): /* ring_put */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 10, 2): /* ring_journal */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 14, 0): /* reflect_write_sig_local */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 15, 1): /* reflect_read_sig_local */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 17, 2): /* statistic */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 24, 0): /* ring_read */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 24, 1): /* ring_write */
return PUSHPULL(P32, 0);
case NFP_CPP_ID(0, 25, 0): /* ring_workq_add_thread */
return PUSHPULL(0, P32);
case NFP_CPP_ID(0, 25, 1): /* ring_workq_add_work */
return PUSHPULL(P32, 0);
default:
return target_rw(cpp_id, P32, 0, 64);
}
}
static inline int
nfp6000_target_pushpull(uint32_t cpp_id, uint64_t address)
{
switch (NFP_CPP_ID_TARGET_of(cpp_id)) {
case NFP6000_CPPTGT_NBI:
return nfp6000_nbi(cpp_id, address);
case NFP6000_CPPTGT_VQDR:
return target_rw(cpp_id, P32, 24, 4);
case NFP6000_CPPTGT_ILA:
return nfp6000_ila(cpp_id);
case NFP6000_CPPTGT_MU:
return nfp6000_mu(cpp_id, address);
case NFP6000_CPPTGT_PCIE:
return nfp6000_pci(cpp_id);
case NFP6000_CPPTGT_ARM:
if (address < 0x10000)
return target_rw(cpp_id, P64, 1, 1);
else
return target_rw(cpp_id, P32, 1, 1);
case NFP6000_CPPTGT_CRYPTO:
return nfp6000_crypto(cpp_id);
case NFP6000_CPPTGT_CTXPB:
return nfp6000_cap_xpb(cpp_id);
case NFP6000_CPPTGT_CLS:
return nfp6000_cls(cpp_id);
case 0:
return target_rw(cpp_id, P32, 4, 4);
default:
return NFP_ERRNO(EINVAL);
}
}
static inline int
nfp_target_pushpull_width(int pp, int write_not_read)
{
if (pp < 0)
return pp;
if (write_not_read)
return PULL_WIDTH(pp);
else
return PUSH_WIDTH(pp);
}
static inline int
nfp6000_target_action_width(uint32_t cpp_id, uint64_t address,
int write_not_read)
{
int pp;
pp = nfp6000_target_pushpull(cpp_id, address);
return nfp_target_pushpull_width(pp, write_not_read);
}
static inline int
nfp_target_action_width(uint32_t model, uint32_t cpp_id, uint64_t address,
int write_not_read)
{
if (NFP_CPP_MODEL_IS_6000(model)) {
return nfp6000_target_action_width(cpp_id, address,
write_not_read);
} else {
return NFP_ERRNO(EINVAL);
}
}
static inline int
nfp_target_cpp(uint32_t cpp_island_id, uint64_t cpp_island_address,
uint32_t *cpp_target_id, uint64_t *cpp_target_address,
const uint32_t *imb_table)
{
int err;
int island = NFP_CPP_ID_ISLAND_of(cpp_island_id);
int target = NFP_CPP_ID_TARGET_of(cpp_island_id);
uint32_t imb;
if (target < 0 || target >= 16)
return NFP_ERRNO(EINVAL);
if (island == 0) {
/* Already translated */
*cpp_target_id = cpp_island_id;
*cpp_target_address = cpp_island_address;
return 0;
}
if (!imb_table) {
/* CPP + Island only allowed on systems with IMB tables */
return NFP_ERRNO(EINVAL);
}
imb = imb_table[target];
*cpp_target_address = cpp_island_address;
err = _nfp6000_cppat_addr_encode(cpp_target_address, island, target,
((imb >> 13) & 7),
((imb >> 12) & 1),
((imb >> 6) & 0x3f),
((imb >> 0) & 0x3f));
if (err == 0) {
*cpp_target_id =
NFP_CPP_ID(target, NFP_CPP_ID_ACTION_of(cpp_island_id),
NFP_CPP_ID_TOKEN_of(cpp_island_id));
}
return err;
}
#endif /* NFP_TARGET_H */