Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
0002 /* Copyright (C) 2015-2018 Netronome Systems, Inc. */
0003 
0004 /*
0005  * nfp_cpplib.c
0006  * Library of functions to access the NFP's CPP bus
0007  * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
0008  *          Jason McMullan <jason.mcmullan@netronome.com>
0009  *          Rolf Neugebauer <rolf.neugebauer@netronome.com>
0010  */
0011 
0012 #include <asm/unaligned.h>
0013 #include <linux/bitfield.h>
0014 #include <linux/delay.h>
0015 #include <linux/kernel.h>
0016 #include <linux/module.h>
0017 #include <linux/slab.h>
0018 #include <linux/sched.h>
0019 
0020 #include "nfp_cpp.h"
0021 #include "nfp6000/nfp6000.h"
0022 #include "nfp6000/nfp_xpb.h"
0023 
0024 /* NFP6000 PL */
0025 #define NFP_PL_DEVICE_PART_NFP6000      0x6200
0026 #define NFP_PL_DEVICE_ID            0x00000004
0027 #define   NFP_PL_DEVICE_ID_MASK         GENMASK(7, 0)
0028 #define   NFP_PL_DEVICE_PART_MASK       GENMASK(31, 16)
0029 #define NFP_PL_DEVICE_MODEL_MASK        (NFP_PL_DEVICE_PART_MASK | \
0030                          NFP_PL_DEVICE_ID_MASK)
0031 
0032 /**
0033  * nfp_cpp_readl() - Read a u32 word from a CPP location
0034  * @cpp:    CPP device handle
0035  * @cpp_id: CPP ID for operation
0036  * @address:    Address for operation
0037  * @value:  Pointer to read buffer
0038  *
0039  * Return: 0 on success, or -ERRNO
0040  */
0041 int nfp_cpp_readl(struct nfp_cpp *cpp, u32 cpp_id,
0042           unsigned long long address, u32 *value)
0043 {
0044     u8 tmp[4];
0045     int n;
0046 
0047     n = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
0048     if (n != sizeof(tmp))
0049         return n < 0 ? n : -EIO;
0050 
0051     *value = get_unaligned_le32(tmp);
0052     return 0;
0053 }
0054 
0055 /**
0056  * nfp_cpp_writel() - Write a u32 word to a CPP location
0057  * @cpp:    CPP device handle
0058  * @cpp_id: CPP ID for operation
0059  * @address:    Address for operation
0060  * @value:  Value to write
0061  *
0062  * Return: 0 on success, or -ERRNO
0063  */
0064 int nfp_cpp_writel(struct nfp_cpp *cpp, u32 cpp_id,
0065            unsigned long long address, u32 value)
0066 {
0067     u8 tmp[4];
0068     int n;
0069 
0070     put_unaligned_le32(value, tmp);
0071     n = nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
0072 
0073     return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
0074 }
0075 
0076 /**
0077  * nfp_cpp_readq() - Read a u64 word from a CPP location
0078  * @cpp:    CPP device handle
0079  * @cpp_id: CPP ID for operation
0080  * @address:    Address for operation
0081  * @value:  Pointer to read buffer
0082  *
0083  * Return: 0 on success, or -ERRNO
0084  */
0085 int nfp_cpp_readq(struct nfp_cpp *cpp, u32 cpp_id,
0086           unsigned long long address, u64 *value)
0087 {
0088     u8 tmp[8];
0089     int n;
0090 
0091     n = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
0092     if (n != sizeof(tmp))
0093         return n < 0 ? n : -EIO;
0094 
0095     *value = get_unaligned_le64(tmp);
0096     return 0;
0097 }
0098 
0099 /**
0100  * nfp_cpp_writeq() - Write a u64 word to a CPP location
0101  * @cpp:    CPP device handle
0102  * @cpp_id: CPP ID for operation
0103  * @address:    Address for operation
0104  * @value:  Value to write
0105  *
0106  * Return: 0 on success, or -ERRNO
0107  */
0108 int nfp_cpp_writeq(struct nfp_cpp *cpp, u32 cpp_id,
0109            unsigned long long address, u64 value)
0110 {
0111     u8 tmp[8];
0112     int n;
0113 
0114     put_unaligned_le64(value, tmp);
0115     n = nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
0116 
0117     return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
0118 }
0119 
0120 /* NOTE: This code should not use nfp_xpb_* functions,
0121  * as those are model-specific
0122  */
0123 int nfp_cpp_model_autodetect(struct nfp_cpp *cpp, u32 *model)
0124 {
0125     u32 reg;
0126     int err;
0127 
0128     err = nfp_xpb_readl(cpp, NFP_XPB_DEVICE(1, 1, 16) + NFP_PL_DEVICE_ID,
0129                 &reg);
0130     if (err < 0)
0131         return err;
0132 
0133     *model = reg & NFP_PL_DEVICE_MODEL_MASK;
0134     /* Disambiguate the NFP4000/NFP5000/NFP6000 chips */
0135     if (FIELD_GET(NFP_PL_DEVICE_PART_MASK, reg) ==
0136         NFP_PL_DEVICE_PART_NFP6000) {
0137         if (*model & NFP_PL_DEVICE_ID_MASK)
0138             *model -= 0x10;
0139     }
0140 
0141     return 0;
0142 }
0143 
0144 static u8 nfp_bytemask(int width, u64 addr)
0145 {
0146     if (width == 8)
0147         return 0xff;
0148     else if (width == 4)
0149         return 0x0f << (addr & 4);
0150     else if (width == 2)
0151         return 0x03 << (addr & 6);
0152     else if (width == 1)
0153         return 0x01 << (addr & 7);
0154     else
0155         return 0;
0156 }
0157 
0158 int nfp_cpp_explicit_read(struct nfp_cpp *cpp, u32 cpp_id,
0159               u64 addr, void *buff, size_t len, int width_read)
0160 {
0161     struct nfp_cpp_explicit *expl;
0162     char *tmp = buff;
0163     int err, i, incr;
0164     u8 byte_mask;
0165 
0166     if (len & (width_read - 1))
0167         return -EINVAL;
0168 
0169     expl = nfp_cpp_explicit_acquire(cpp);
0170     if (!expl)
0171         return -EBUSY;
0172 
0173     incr = min_t(int, 16 * width_read, 128);
0174     incr = min_t(int, incr, len);
0175 
0176     /* Translate a NFP_CPP_ACTION_RW to action 0 */
0177     if (NFP_CPP_ID_ACTION_of(cpp_id) == NFP_CPP_ACTION_RW)
0178         cpp_id = NFP_CPP_ID(NFP_CPP_ID_TARGET_of(cpp_id), 0,
0179                     NFP_CPP_ID_TOKEN_of(cpp_id));
0180 
0181     byte_mask = nfp_bytemask(width_read, addr);
0182 
0183     nfp_cpp_explicit_set_target(expl, cpp_id,
0184                     incr / width_read - 1, byte_mask);
0185     nfp_cpp_explicit_set_posted(expl, 1, 0, NFP_SIGNAL_PUSH,
0186                     0, NFP_SIGNAL_NONE);
0187 
0188     for (i = 0; i < len; i += incr, addr += incr, tmp += incr) {
0189         if (i + incr > len) {
0190             incr = len - i;
0191             nfp_cpp_explicit_set_target(expl, cpp_id,
0192                             incr / width_read - 1,
0193                             0xff);
0194         }
0195 
0196         err = nfp_cpp_explicit_do(expl, addr);
0197         if (err < 0)
0198             goto exit_release;
0199 
0200         err = nfp_cpp_explicit_get(expl, tmp, incr);
0201         if (err < 0)
0202             goto exit_release;
0203     }
0204     err = len;
0205 exit_release:
0206     nfp_cpp_explicit_release(expl);
0207 
0208     return err;
0209 }
0210 
0211 int nfp_cpp_explicit_write(struct nfp_cpp *cpp, u32 cpp_id, u64 addr,
0212                const void *buff, size_t len, int width_write)
0213 {
0214     struct nfp_cpp_explicit *expl;
0215     const char *tmp = buff;
0216     int err, i, incr;
0217     u8 byte_mask;
0218 
0219     if (len & (width_write - 1))
0220         return -EINVAL;
0221 
0222     expl = nfp_cpp_explicit_acquire(cpp);
0223     if (!expl)
0224         return -EBUSY;
0225 
0226     incr = min_t(int, 16 * width_write, 128);
0227     incr = min_t(int, incr, len);
0228 
0229     /* Translate a NFP_CPP_ACTION_RW to action 1 */
0230     if (NFP_CPP_ID_ACTION_of(cpp_id) == NFP_CPP_ACTION_RW)
0231         cpp_id = NFP_CPP_ID(NFP_CPP_ID_TARGET_of(cpp_id), 1,
0232                     NFP_CPP_ID_TOKEN_of(cpp_id));
0233 
0234     byte_mask = nfp_bytemask(width_write, addr);
0235 
0236     nfp_cpp_explicit_set_target(expl, cpp_id,
0237                     incr / width_write - 1, byte_mask);
0238     nfp_cpp_explicit_set_posted(expl, 1, 0, NFP_SIGNAL_PULL,
0239                     0, NFP_SIGNAL_NONE);
0240 
0241     for (i = 0; i < len; i += incr, addr += incr, tmp += incr) {
0242         if (i + incr > len) {
0243             incr = len - i;
0244             nfp_cpp_explicit_set_target(expl, cpp_id,
0245                             incr / width_write - 1,
0246                             0xff);
0247         }
0248 
0249         err = nfp_cpp_explicit_put(expl, tmp, incr);
0250         if (err < 0)
0251             goto exit_release;
0252 
0253         err = nfp_cpp_explicit_do(expl, addr);
0254         if (err < 0)
0255             goto exit_release;
0256     }
0257     err = len;
0258 exit_release:
0259     nfp_cpp_explicit_release(expl);
0260 
0261     return err;
0262 }
0263 
0264 /**
0265  * nfp_cpp_map_area() - Helper function to map an area
0266  * @cpp:    NFP CPP handler
0267  * @name:   Name for the area
0268  * @cpp_id: CPP ID for operation
0269  * @addr:   CPP address
0270  * @size:   Size of the area
0271  * @area:   Area handle (output)
0272  *
0273  * Map an area of IOMEM access.  To undo the effect of this function call
0274  * @nfp_cpp_area_release_free(*area).
0275  *
0276  * Return: Pointer to memory mapped area or ERR_PTR
0277  */
0278 u8 __iomem *
0279 nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, u32 cpp_id, u64 addr,
0280          unsigned long size, struct nfp_cpp_area **area)
0281 {
0282     u8 __iomem *res;
0283 
0284     *area = nfp_cpp_area_alloc_acquire(cpp, name, cpp_id, addr, size);
0285     if (!*area)
0286         goto err_eio;
0287 
0288     res = nfp_cpp_area_iomem(*area);
0289     if (!res)
0290         goto err_release_free;
0291 
0292     return res;
0293 
0294 err_release_free:
0295     nfp_cpp_area_release_free(*area);
0296 err_eio:
0297     return (u8 __iomem *)ERR_PTR(-EIO);
0298 }