0001
0002
0003
0004
0005
0006
0007
0008
0009
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
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
0034
0035
0036
0037
0038
0039
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
0057
0058
0059
0060
0061
0062
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
0078
0079
0080
0081
0082
0083
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
0101
0102
0103
0104
0105
0106
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
0121
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 ®);
0130 if (err < 0)
0131 return err;
0132
0133 *model = reg & NFP_PL_DEVICE_MODEL_MASK;
0134
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
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
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
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
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 }