cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nfp_cpplib.c (7105B)


      1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
      2/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
      3
      4/*
      5 * nfp_cpplib.c
      6 * Library of functions to access the NFP's CPP bus
      7 * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
      8 *          Jason McMullan <jason.mcmullan@netronome.com>
      9 *          Rolf Neugebauer <rolf.neugebauer@netronome.com>
     10 */
     11
     12#include <asm/unaligned.h>
     13#include <linux/bitfield.h>
     14#include <linux/delay.h>
     15#include <linux/kernel.h>
     16#include <linux/module.h>
     17#include <linux/slab.h>
     18#include <linux/sched.h>
     19
     20#include "nfp_cpp.h"
     21#include "nfp6000/nfp6000.h"
     22#include "nfp6000/nfp_xpb.h"
     23
     24/* NFP6000 PL */
     25#define NFP_PL_DEVICE_PART_NFP6000		0x6200
     26#define NFP_PL_DEVICE_ID			0x00000004
     27#define   NFP_PL_DEVICE_ID_MASK			GENMASK(7, 0)
     28#define   NFP_PL_DEVICE_PART_MASK		GENMASK(31, 16)
     29#define NFP_PL_DEVICE_MODEL_MASK		(NFP_PL_DEVICE_PART_MASK | \
     30						 NFP_PL_DEVICE_ID_MASK)
     31
     32/**
     33 * nfp_cpp_readl() - Read a u32 word from a CPP location
     34 * @cpp:	CPP device handle
     35 * @cpp_id:	CPP ID for operation
     36 * @address:	Address for operation
     37 * @value:	Pointer to read buffer
     38 *
     39 * Return: 0 on success, or -ERRNO
     40 */
     41int nfp_cpp_readl(struct nfp_cpp *cpp, u32 cpp_id,
     42		  unsigned long long address, u32 *value)
     43{
     44	u8 tmp[4];
     45	int n;
     46
     47	n = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
     48	if (n != sizeof(tmp))
     49		return n < 0 ? n : -EIO;
     50
     51	*value = get_unaligned_le32(tmp);
     52	return 0;
     53}
     54
     55/**
     56 * nfp_cpp_writel() - Write a u32 word to a CPP location
     57 * @cpp:	CPP device handle
     58 * @cpp_id:	CPP ID for operation
     59 * @address:	Address for operation
     60 * @value:	Value to write
     61 *
     62 * Return: 0 on success, or -ERRNO
     63 */
     64int nfp_cpp_writel(struct nfp_cpp *cpp, u32 cpp_id,
     65		   unsigned long long address, u32 value)
     66{
     67	u8 tmp[4];
     68	int n;
     69
     70	put_unaligned_le32(value, tmp);
     71	n = nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
     72
     73	return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
     74}
     75
     76/**
     77 * nfp_cpp_readq() - Read a u64 word from a CPP location
     78 * @cpp:	CPP device handle
     79 * @cpp_id:	CPP ID for operation
     80 * @address:	Address for operation
     81 * @value:	Pointer to read buffer
     82 *
     83 * Return: 0 on success, or -ERRNO
     84 */
     85int nfp_cpp_readq(struct nfp_cpp *cpp, u32 cpp_id,
     86		  unsigned long long address, u64 *value)
     87{
     88	u8 tmp[8];
     89	int n;
     90
     91	n = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
     92	if (n != sizeof(tmp))
     93		return n < 0 ? n : -EIO;
     94
     95	*value = get_unaligned_le64(tmp);
     96	return 0;
     97}
     98
     99/**
    100 * nfp_cpp_writeq() - Write a u64 word to a CPP location
    101 * @cpp:	CPP device handle
    102 * @cpp_id:	CPP ID for operation
    103 * @address:	Address for operation
    104 * @value:	Value to write
    105 *
    106 * Return: 0 on success, or -ERRNO
    107 */
    108int nfp_cpp_writeq(struct nfp_cpp *cpp, u32 cpp_id,
    109		   unsigned long long address, u64 value)
    110{
    111	u8 tmp[8];
    112	int n;
    113
    114	put_unaligned_le64(value, tmp);
    115	n = nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
    116
    117	return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
    118}
    119
    120/* NOTE: This code should not use nfp_xpb_* functions,
    121 * as those are model-specific
    122 */
    123int nfp_cpp_model_autodetect(struct nfp_cpp *cpp, u32 *model)
    124{
    125	u32 reg;
    126	int err;
    127
    128	err = nfp_xpb_readl(cpp, NFP_XPB_DEVICE(1, 1, 16) + NFP_PL_DEVICE_ID,
    129			    &reg);
    130	if (err < 0)
    131		return err;
    132
    133	*model = reg & NFP_PL_DEVICE_MODEL_MASK;
    134	/* Disambiguate the NFP4000/NFP5000/NFP6000 chips */
    135	if (FIELD_GET(NFP_PL_DEVICE_PART_MASK, reg) ==
    136	    NFP_PL_DEVICE_PART_NFP6000) {
    137		if (*model & NFP_PL_DEVICE_ID_MASK)
    138			*model -= 0x10;
    139	}
    140
    141	return 0;
    142}
    143
    144static u8 nfp_bytemask(int width, u64 addr)
    145{
    146	if (width == 8)
    147		return 0xff;
    148	else if (width == 4)
    149		return 0x0f << (addr & 4);
    150	else if (width == 2)
    151		return 0x03 << (addr & 6);
    152	else if (width == 1)
    153		return 0x01 << (addr & 7);
    154	else
    155		return 0;
    156}
    157
    158int nfp_cpp_explicit_read(struct nfp_cpp *cpp, u32 cpp_id,
    159			  u64 addr, void *buff, size_t len, int width_read)
    160{
    161	struct nfp_cpp_explicit *expl;
    162	char *tmp = buff;
    163	int err, i, incr;
    164	u8 byte_mask;
    165
    166	if (len & (width_read - 1))
    167		return -EINVAL;
    168
    169	expl = nfp_cpp_explicit_acquire(cpp);
    170	if (!expl)
    171		return -EBUSY;
    172
    173	incr = min_t(int, 16 * width_read, 128);
    174	incr = min_t(int, incr, len);
    175
    176	/* Translate a NFP_CPP_ACTION_RW to action 0 */
    177	if (NFP_CPP_ID_ACTION_of(cpp_id) == NFP_CPP_ACTION_RW)
    178		cpp_id = NFP_CPP_ID(NFP_CPP_ID_TARGET_of(cpp_id), 0,
    179				    NFP_CPP_ID_TOKEN_of(cpp_id));
    180
    181	byte_mask = nfp_bytemask(width_read, addr);
    182
    183	nfp_cpp_explicit_set_target(expl, cpp_id,
    184				    incr / width_read - 1, byte_mask);
    185	nfp_cpp_explicit_set_posted(expl, 1, 0, NFP_SIGNAL_PUSH,
    186				    0, NFP_SIGNAL_NONE);
    187
    188	for (i = 0; i < len; i += incr, addr += incr, tmp += incr) {
    189		if (i + incr > len) {
    190			incr = len - i;
    191			nfp_cpp_explicit_set_target(expl, cpp_id,
    192						    incr / width_read - 1,
    193						    0xff);
    194		}
    195
    196		err = nfp_cpp_explicit_do(expl, addr);
    197		if (err < 0)
    198			goto exit_release;
    199
    200		err = nfp_cpp_explicit_get(expl, tmp, incr);
    201		if (err < 0)
    202			goto exit_release;
    203	}
    204	err = len;
    205exit_release:
    206	nfp_cpp_explicit_release(expl);
    207
    208	return err;
    209}
    210
    211int nfp_cpp_explicit_write(struct nfp_cpp *cpp, u32 cpp_id, u64 addr,
    212			   const void *buff, size_t len, int width_write)
    213{
    214	struct nfp_cpp_explicit *expl;
    215	const char *tmp = buff;
    216	int err, i, incr;
    217	u8 byte_mask;
    218
    219	if (len & (width_write - 1))
    220		return -EINVAL;
    221
    222	expl = nfp_cpp_explicit_acquire(cpp);
    223	if (!expl)
    224		return -EBUSY;
    225
    226	incr = min_t(int, 16 * width_write, 128);
    227	incr = min_t(int, incr, len);
    228
    229	/* Translate a NFP_CPP_ACTION_RW to action 1 */
    230	if (NFP_CPP_ID_ACTION_of(cpp_id) == NFP_CPP_ACTION_RW)
    231		cpp_id = NFP_CPP_ID(NFP_CPP_ID_TARGET_of(cpp_id), 1,
    232				    NFP_CPP_ID_TOKEN_of(cpp_id));
    233
    234	byte_mask = nfp_bytemask(width_write, addr);
    235
    236	nfp_cpp_explicit_set_target(expl, cpp_id,
    237				    incr / width_write - 1, byte_mask);
    238	nfp_cpp_explicit_set_posted(expl, 1, 0, NFP_SIGNAL_PULL,
    239				    0, NFP_SIGNAL_NONE);
    240
    241	for (i = 0; i < len; i += incr, addr += incr, tmp += incr) {
    242		if (i + incr > len) {
    243			incr = len - i;
    244			nfp_cpp_explicit_set_target(expl, cpp_id,
    245						    incr / width_write - 1,
    246						    0xff);
    247		}
    248
    249		err = nfp_cpp_explicit_put(expl, tmp, incr);
    250		if (err < 0)
    251			goto exit_release;
    252
    253		err = nfp_cpp_explicit_do(expl, addr);
    254		if (err < 0)
    255			goto exit_release;
    256	}
    257	err = len;
    258exit_release:
    259	nfp_cpp_explicit_release(expl);
    260
    261	return err;
    262}
    263
    264/**
    265 * nfp_cpp_map_area() - Helper function to map an area
    266 * @cpp:    NFP CPP handler
    267 * @name:   Name for the area
    268 * @cpp_id: CPP ID for operation
    269 * @addr:   CPP address
    270 * @size:   Size of the area
    271 * @area:   Area handle (output)
    272 *
    273 * Map an area of IOMEM access.  To undo the effect of this function call
    274 * @nfp_cpp_area_release_free(*area).
    275 *
    276 * Return: Pointer to memory mapped area or ERR_PTR
    277 */
    278u8 __iomem *
    279nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, u32 cpp_id, u64 addr,
    280		 unsigned long size, struct nfp_cpp_area **area)
    281{
    282	u8 __iomem *res;
    283
    284	*area = nfp_cpp_area_alloc_acquire(cpp, name, cpp_id, addr, size);
    285	if (!*area)
    286		goto err_eio;
    287
    288	res = nfp_cpp_area_iomem(*area);
    289	if (!res)
    290		goto err_release_free;
    291
    292	return res;
    293
    294err_release_free:
    295	nfp_cpp_area_release_free(*area);
    296err_eio:
    297	return (u8 __iomem *)ERR_PTR(-EIO);
    298}