root/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nfp_cpp_readl
  2. nfp_cpp_writel
  3. nfp_cpp_readq
  4. nfp_cpp_writeq
  5. nfp_cpp_model_autodetect
  6. nfp_bytemask
  7. nfp_cpp_explicit_read
  8. nfp_cpp_explicit_write
  9. nfp_cpp_map_area

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

/* [<][>][^][v][top][bottom][index][help] */