dbb53051c33a8891ceb7cea03ffe7c1812174b0e
[dpdk.git] / drivers / net / nfp / nfp_nspu.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6
7 #include <rte_log.h>
8
9 #include "nfp_nfpu.h"
10
11 #define CFG_EXP_BAR_ADDR_SZ     1
12 #define CFG_EXP_BAR_MAP_TYPE    1
13
14 #define EXP_BAR_TARGET_SHIFT     23
15 #define EXP_BAR_LENGTH_SHIFT     27 /* 0=32, 1=64 bit increment */
16 #define EXP_BAR_MAP_TYPE_SHIFT   29 /* Bulk BAR map */
17
18 /* NFP target for NSP access */
19 #define NFP_NSP_TARGET   7
20
21 /*
22  * This is an NFP internal address used for configuring properly an NFP
23  * expansion BAR.
24  */
25 #define MEM_CMD_BASE_ADDR       0x8100000000
26
27 /* NSP interface registers */
28 #define NSP_BASE                (MEM_CMD_BASE_ADDR + 0x22100)
29 #define NSP_STATUS              0x00
30 #define NSP_COMMAND             0x08
31 #define NSP_BUFFER              0x10
32 #define NSP_DEFAULT_BUF         0x18
33 #define NSP_DEFAULT_BUF_CFG  0x20
34
35 #define NSP_MAGIC                0xab10
36 #define NSP_STATUS_MAGIC(x)      (((x) >> 48) & 0xffff)
37 #define NSP_STATUS_MAJOR(x)      (int)(((x) >> 44) & 0xf)
38 #define NSP_STATUS_MINOR(x)      (int)(((x) >> 32) & 0xfff)
39
40 /* NSP commands */
41 #define NSP_CMD_RESET                   1
42
43 #define NSP_BUFFER_CFG_SIZE_MASK        (0xff)
44
45 #define NSP_REG_ADDR(d, off, reg) ((uint8_t *)(d)->mem_base + (off) + (reg))
46 #define NSP_REG_VAL(p) (*(uint64_t *)(p))
47
48 /*
49  * An NFP expansion BAR is configured for allowing access to a specific NFP
50  * target:
51  *
52  *  IN:
53  *      desc: struct with basic NSP addresses to work with
54  *      expbar: NFP PF expansion BAR index to configure
55  *      tgt: NFP target to configure access
56  *      addr: NFP target address
57  *
58  *  OUT:
59  *      pcie_offset: NFP PCI BAR offset to work with
60  */
61 static void
62 nfp_nspu_mem_bar_cfg(nspu_desc_t *desc, int expbar, int tgt,
63                      uint64_t addr, uint64_t *pcie_offset)
64 {
65         uint64_t x, y, barsz;
66         uint32_t *expbar_ptr;
67
68         barsz = desc->barsz;
69
70         /*
71          * NFP CPP address to configure. This comes from NFP 6000
72          * datasheet document based on Bulk mapping.
73          */
74         x = (addr >> (barsz - 3)) << (21 - (40 - (barsz - 3)));
75         x |= CFG_EXP_BAR_MAP_TYPE << EXP_BAR_MAP_TYPE_SHIFT;
76         x |= CFG_EXP_BAR_ADDR_SZ << EXP_BAR_LENGTH_SHIFT;
77         x |= tgt << EXP_BAR_TARGET_SHIFT;
78
79         /* Getting expansion bar configuration register address */
80         expbar_ptr = (uint32_t *)desc->cfg_base;
81         /* Each physical PCI BAR has 8 NFP expansion BARs */
82         expbar_ptr += (desc->pcie_bar * 8) + expbar;
83
84         /* Writing to the expansion BAR register */
85         *expbar_ptr = (uint32_t)x;
86
87         /* Getting the pcie offset to work with from userspace */
88         y = addr & ((uint64_t)(1 << (barsz - 3)) - 1);
89         *pcie_offset = y;
90 }
91
92 /*
93  * Configuring an expansion bar for accessing NSP userspace interface. This
94  * function configures always the same expansion bar, which implies access to
95  * previously configured NFP target is lost.
96  */
97 static void
98 nspu_xlate(nspu_desc_t *desc, uint64_t addr, uint64_t *pcie_offset)
99 {
100         nfp_nspu_mem_bar_cfg(desc, desc->exp_bar, NFP_NSP_TARGET, addr,
101                              pcie_offset);
102 }
103
104 int
105 nfp_nsp_get_abi_version(nspu_desc_t *desc, int *major, int *minor)
106 {
107         uint64_t pcie_offset;
108         uint64_t nsp_reg;
109
110         nspu_xlate(desc, NSP_BASE, &pcie_offset);
111         nsp_reg = NSP_REG_VAL(NSP_REG_ADDR(desc, pcie_offset, NSP_STATUS));
112
113         if (NSP_STATUS_MAGIC(nsp_reg) != NSP_MAGIC)
114                 return -1;
115
116         *major = NSP_STATUS_MAJOR(nsp_reg);
117         *minor = NSP_STATUS_MINOR(nsp_reg);
118
119         return 0;
120 }
121
122 int
123 nfp_nspu_init(nspu_desc_t *desc, int nfp, int pcie_bar, size_t pcie_barsz,
124               int exp_bar, void *exp_bar_cfg_base, void *exp_bar_mmap)
125 {
126         uint64_t offset, buffaddr;
127         uint64_t nsp_reg;
128
129         desc->nfp = nfp;
130         desc->pcie_bar = pcie_bar;
131         desc->exp_bar = exp_bar;
132         desc->barsz = pcie_barsz;
133         desc->windowsz = 1 << (desc->barsz - 3);
134         desc->cfg_base = exp_bar_cfg_base;
135         desc->mem_base = exp_bar_mmap;
136
137         nspu_xlate(desc, NSP_BASE, &offset);
138
139         /*
140          * Other NSPU clients can use other buffers. Let's tell NSPU we use the
141          * default buffer.
142          */
143         buffaddr = NSP_REG_VAL(NSP_REG_ADDR(desc, offset, NSP_DEFAULT_BUF));
144         NSP_REG_VAL(NSP_REG_ADDR(desc, offset, NSP_BUFFER)) = buffaddr;
145
146         /* NFP internal addresses are 40 bits. Clean all other bits here */
147         buffaddr = buffaddr & (((uint64_t)1 << 40) - 1);
148         desc->bufaddr = buffaddr;
149
150         /* Lets get information about the buffer */
151         nsp_reg = NSP_REG_VAL(NSP_REG_ADDR(desc, offset, NSP_DEFAULT_BUF_CFG));
152
153         /* Buffer size comes in MBs. Coversion to bytes */
154         desc->buf_size = ((size_t)nsp_reg & NSP_BUFFER_CFG_SIZE_MASK) << 20;
155
156         return 0;
157 }
158
159 #define NSPU_NFP_BUF(addr, base, off) \
160         (*(uint64_t *)((uint8_t *)(addr)->mem_base + ((base) | (off))))
161
162 #define NSPU_HOST_BUF(base, off) (*(uint64_t *)((uint8_t *)(base) + (off)))
163
164 static int
165 nspu_buff_write(nspu_desc_t *desc, void *buffer, size_t size)
166 {
167         uint64_t pcie_offset, pcie_window_base, pcie_window_offset;
168         uint64_t windowsz = desc->windowsz;
169         uint64_t buffaddr, j, i = 0;
170         int ret = 0;
171
172         if (size > desc->buf_size)
173                 return -1;
174
175         buffaddr = desc->bufaddr;
176         windowsz = desc->windowsz;
177
178         while (i < size) {
179                 /* Expansion bar reconfiguration per window size */
180                 nspu_xlate(desc, buffaddr + i, &pcie_offset);
181                 pcie_window_base = pcie_offset & (~(windowsz - 1));
182                 pcie_window_offset = pcie_offset & (windowsz - 1);
183                 for (j = pcie_window_offset; ((j < windowsz) && (i < size));
184                      j += 8) {
185                         NSPU_NFP_BUF(desc, pcie_window_base, j) =
186                                 NSPU_HOST_BUF(buffer, i);
187                         i += 8;
188                 }
189         }
190
191         return ret;
192 }
193
194 static int
195 nspu_buff_read(nspu_desc_t *desc, void *buffer, size_t size)
196 {
197         uint64_t pcie_offset, pcie_window_base, pcie_window_offset;
198         uint64_t windowsz, i = 0, j;
199         uint64_t buffaddr;
200         int ret = 0;
201
202         if (size > desc->buf_size)
203                 return -1;
204
205         buffaddr = desc->bufaddr;
206         windowsz = desc->windowsz;
207
208         while (i < size) {
209                 /* Expansion bar reconfiguration per window size */
210                 nspu_xlate(desc, buffaddr + i, &pcie_offset);
211                 pcie_window_base = pcie_offset & (~(windowsz - 1));
212                 pcie_window_offset = pcie_offset & (windowsz - 1);
213                 for (j = pcie_window_offset; ((j < windowsz) && (i < size));
214                      j += 8) {
215                         NSPU_HOST_BUF(buffer, i) =
216                                 NSPU_NFP_BUF(desc, pcie_window_base, j);
217                         i += 8;
218                 }
219         }
220
221         return ret;
222 }
223
224 static int
225 nspu_command(nspu_desc_t *desc, uint16_t cmd, int read, int write,
226                  void *buffer, size_t rsize, size_t wsize)
227 {
228         uint64_t status, cmd_reg;
229         uint64_t offset;
230         int retry = 0;
231         int retries = 120;
232         int ret = 0;
233
234         /* Same expansion BAR is used for different things */
235         nspu_xlate(desc, NSP_BASE, &offset);
236
237         status = NSP_REG_VAL(NSP_REG_ADDR(desc, offset, NSP_STATUS));
238
239         while ((status & 0x1) && (retry < retries)) {
240                 status = NSP_REG_VAL(NSP_REG_ADDR(desc, offset, NSP_STATUS));
241                 retry++;
242                 sleep(1);
243         }
244
245         if (retry == retries)
246                 return -1;
247
248         if (write) {
249                 ret = nspu_buff_write(desc, buffer, wsize);
250                 if (ret)
251                         return ret;
252
253                 /* Expansion BAR changes when writing the buffer */
254                 nspu_xlate(desc, NSP_BASE, &offset);
255         }
256
257         NSP_REG_VAL(NSP_REG_ADDR(desc, offset, NSP_COMMAND)) =
258                 (uint64_t)wsize << 32 | (uint64_t)cmd << 16 | 1;
259
260         retry = 0;
261
262         cmd_reg = NSP_REG_VAL(NSP_REG_ADDR(desc, offset, NSP_COMMAND));
263         while ((cmd_reg & 0x1) && (retry < retries)) {
264                 cmd_reg = NSP_REG_VAL(NSP_REG_ADDR(desc, offset, NSP_COMMAND));
265                 retry++;
266                 sleep(1);
267         }
268         if (retry == retries)
269                 return -1;
270
271         retry = 0;
272         status = NSP_REG_VAL(NSP_REG_ADDR(desc, offset, NSP_STATUS));
273         while ((status & 0x1) && (retry < retries)) {
274                 status = NSP_REG_VAL(NSP_REG_ADDR(desc, offset, NSP_STATUS));
275                 retry++;
276                 sleep(1);
277         }
278
279         if (retry == retries)
280                 return -1;
281
282         ret = status & (0xff << 8);
283         if (ret)
284                 return ret;
285
286         if (read) {
287                 ret = nspu_buff_read(desc, buffer, rsize);
288                 if (ret)
289                         return ret;
290         }
291
292         return ret;
293 }
294
295 int
296 nfp_fw_reset(nspu_desc_t *nspu_desc)
297 {
298         int res;
299
300         res = nspu_command(nspu_desc, NSP_CMD_RESET, 0, 0, 0, 0, 0);
301
302         if (res < 0)
303                 RTE_LOG(INFO, PMD, "fw reset failed: error %d", res);
304
305         return res;
306 }