New upstream version 17.11-rc3
[deb_dpdk.git] / drivers / bus / fslmc / qbman / qbman_sys.h
1 /*-
2  *   BSD LICENSE
3  *
4  * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *     * Redistributions of source code must retain the above copyright
9  *       notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above copyright
11  *       notice, this list of conditions and the following disclaimer in the
12  *       documentation and/or other materials provided with the distribution.
13  *     * Neither the name of Freescale Semiconductor nor the
14  *       names of its contributors may be used to endorse or promote products
15  *       derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 /* qbman_sys_decl.h and qbman_sys.h are the two platform-specific files in the
29  * driver. They are only included via qbman_private.h, which is itself a
30  * platform-independent file and is included by all the other driver source.
31  *
32  * qbman_sys_decl.h is included prior to all other declarations and logic, and
33  * it exists to provide compatibility with any linux interfaces our
34  * single-source driver code is dependent on (eg. kmalloc). Ie. this file
35  * provides linux compatibility.
36  *
37  * This qbman_sys.h header, on the other hand, is included *after* any common
38  * and platform-neutral declarations and logic in qbman_private.h, and exists to
39  * implement any platform-specific logic of the qbman driver itself. Ie. it is
40  * *not* to provide linux compatibility.
41  */
42
43 #include "qbman_sys_decl.h"
44
45 /* Debugging assists */
46 static inline void __hexdump(unsigned long start, unsigned long end,
47                              unsigned long p, size_t sz, const unsigned char *c)
48 {
49         while (start < end) {
50                 unsigned int pos = 0;
51                 char buf[64];
52                 int nl = 0;
53
54                 pos += sprintf(buf + pos, "%08lx: ", start);
55                 do {
56                         if ((start < p) || (start >= (p + sz)))
57                                 pos += sprintf(buf + pos, "..");
58                         else
59                                 pos += sprintf(buf + pos, "%02x", *(c++));
60                         if (!(++start & 15)) {
61                                 buf[pos++] = '\n';
62                                 nl = 1;
63                         } else {
64                                 nl = 0;
65                                 if (!(start & 1))
66                                         buf[pos++] = ' ';
67                                 if (!(start & 3))
68                                         buf[pos++] = ' ';
69                         }
70                 } while (start & 15);
71                 if (!nl)
72                         buf[pos++] = '\n';
73                 buf[pos] = '\0';
74                 pr_info("%s", buf);
75         }
76 }
77
78 static inline void hexdump(const void *ptr, size_t sz)
79 {
80         unsigned long p = (unsigned long)ptr;
81         unsigned long start = p & ~15;
82         unsigned long end = (p + sz + 15) & ~15;
83         const unsigned char *c = ptr;
84
85         __hexdump(start, end, p, sz, c);
86 }
87
88 /* Currently, the CENA support code expects each 32-bit word to be written in
89  * host order, and these are converted to hardware (little-endian) order on
90  * command submission. However, 64-bit quantities are must be written (and read)
91  * as two 32-bit words with the least-significant word first, irrespective of
92  * host endianness.
93  */
94 static inline void u64_to_le32_copy(void *d, const uint64_t *s,
95                                     unsigned int cnt)
96 {
97         uint32_t *dd = d;
98         const uint32_t *ss = (const uint32_t *)s;
99
100         while (cnt--) {
101                 /* TBD: the toolchain was choking on the use of 64-bit types up
102                  * until recently so this works entirely with 32-bit variables.
103                  * When 64-bit types become usable again, investigate better
104                  * ways of doing this.
105                  */
106 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
107                 *(dd++) = ss[1];
108                 *(dd++) = ss[0];
109                 ss += 2;
110 #else
111                 *(dd++) = *(ss++);
112                 *(dd++) = *(ss++);
113 #endif
114         }
115 }
116
117 static inline void u64_from_le32_copy(uint64_t *d, const void *s,
118                                       unsigned int cnt)
119 {
120         const uint32_t *ss = s;
121         uint32_t *dd = (uint32_t *)d;
122
123         while (cnt--) {
124 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
125                 dd[1] = *(ss++);
126                 dd[0] = *(ss++);
127                 dd += 2;
128 #else
129                 *(dd++) = *(ss++);
130                 *(dd++) = *(ss++);
131 #endif
132         }
133 }
134
135         /******************/
136         /* Portal access  */
137         /******************/
138 struct qbman_swp_sys {
139         /* On GPP, the sys support for qbman_swp is here. The CENA region isi
140          * not an mmap() of the real portal registers, but an allocated
141          * place-holder, because the actual writes/reads to/from the portal are
142          * marshalled from these allocated areas using QBMan's "MC access
143          * registers". CINH accesses are atomic so there's no need for a
144          * place-holder.
145          */
146         uint8_t *cena;
147         uint8_t __iomem *addr_cena;
148         uint8_t __iomem *addr_cinh;
149         uint32_t idx;
150         enum qbman_eqcr_mode eqcr_mode;
151 };
152
153 /* P_OFFSET is (ACCESS_CMD,0,12) - offset within the portal
154  * C is (ACCESS_CMD,12,1) - is inhibited? (0==CENA, 1==CINH)
155  * SWP_IDX is (ACCESS_CMD,16,10) - Software portal index
156  * P is (ACCESS_CMD,28,1) - (0==special portal, 1==any portal)
157  * T is (ACCESS_CMD,29,1) - Command type (0==READ, 1==WRITE)
158  * E is (ACCESS_CMD,31,1) - Command execute (1 to issue, poll for 0==complete)
159  */
160
161 static inline void qbman_cinh_write(struct qbman_swp_sys *s, uint32_t offset,
162                                     uint32_t val)
163 {
164         __raw_writel(val, s->addr_cinh + offset);
165 #ifdef QBMAN_CINH_TRACE
166         pr_info("qbman_cinh_write(%p:%d:0x%03x) 0x%08x\n",
167                 s->addr_cinh, s->idx, offset, val);
168 #endif
169 }
170
171 static inline uint32_t qbman_cinh_read(struct qbman_swp_sys *s, uint32_t offset)
172 {
173         uint32_t reg = __raw_readl(s->addr_cinh + offset);
174 #ifdef QBMAN_CINH_TRACE
175         pr_info("qbman_cinh_read(%p:%d:0x%03x) 0x%08x\n",
176                 s->addr_cinh, s->idx, offset, reg);
177 #endif
178         return reg;
179 }
180
181 static inline void *qbman_cena_write_start(struct qbman_swp_sys *s,
182                                            uint32_t offset)
183 {
184         void *shadow = s->cena + offset;
185
186 #ifdef QBMAN_CENA_TRACE
187         pr_info("qbman_cena_write_start(%p:%d:0x%03x) %p\n",
188                 s->addr_cena, s->idx, offset, shadow);
189 #endif
190         QBMAN_BUG_ON(offset & 63);
191         dcbz(shadow);
192         return shadow;
193 }
194
195 static inline void *qbman_cena_write_start_wo_shadow(struct qbman_swp_sys *s,
196                                                      uint32_t offset)
197 {
198 #ifdef QBMAN_CENA_TRACE
199         pr_info("qbman_cena_write_start(%p:%d:0x%03x)\n",
200                 s->addr_cena, s->idx, offset);
201 #endif
202         QBMAN_BUG_ON(offset & 63);
203         return (s->addr_cena + offset);
204 }
205
206 static inline void qbman_cena_write_complete(struct qbman_swp_sys *s,
207                                              uint32_t offset, void *cmd)
208 {
209         const uint32_t *shadow = cmd;
210         int loop;
211 #ifdef QBMAN_CENA_TRACE
212         pr_info("qbman_cena_write_complete(%p:%d:0x%03x) %p\n",
213                 s->addr_cena, s->idx, offset, shadow);
214         hexdump(cmd, 64);
215 #endif
216         for (loop = 15; loop >= 1; loop--)
217                 __raw_writel(shadow[loop], s->addr_cena +
218                                          offset + loop * 4);
219         lwsync();
220                 __raw_writel(shadow[0], s->addr_cena + offset);
221         dcbf(s->addr_cena + offset);
222 }
223
224 static inline void qbman_cena_write_complete_wo_shadow(struct qbman_swp_sys *s,
225                                                        uint32_t offset)
226 {
227 #ifdef QBMAN_CENA_TRACE
228         pr_info("qbman_cena_write_complete(%p:%d:0x%03x)\n",
229                 s->addr_cena, s->idx, offset);
230 #endif
231         dcbf(s->addr_cena + offset);
232 }
233
234 static inline uint32_t qbman_cena_read_reg(struct qbman_swp_sys *s,
235                                            uint32_t offset)
236 {
237         return __raw_readl(s->addr_cena + offset);
238 }
239
240 static inline void *qbman_cena_read(struct qbman_swp_sys *s, uint32_t offset)
241 {
242         uint32_t *shadow = (uint32_t *)(s->cena + offset);
243         unsigned int loop;
244 #ifdef QBMAN_CENA_TRACE
245         pr_info("qbman_cena_read(%p:%d:0x%03x) %p\n",
246                 s->addr_cena, s->idx, offset, shadow);
247 #endif
248
249         for (loop = 0; loop < 16; loop++)
250                 shadow[loop] = __raw_readl(s->addr_cena + offset
251                                         + loop * 4);
252 #ifdef QBMAN_CENA_TRACE
253         hexdump(shadow, 64);
254 #endif
255         return shadow;
256 }
257
258 static inline void *qbman_cena_read_wo_shadow(struct qbman_swp_sys *s,
259                                               uint32_t offset)
260 {
261 #ifdef QBMAN_CENA_TRACE
262         pr_info("qbman_cena_read(%p:%d:0x%03x)\n",
263                 s->addr_cena, s->idx, offset);
264 #endif
265         return s->addr_cena + offset;
266 }
267
268 static inline void qbman_cena_invalidate(struct qbman_swp_sys *s,
269                                          uint32_t offset)
270 {
271         dccivac(s->addr_cena + offset);
272 }
273
274 static inline void qbman_cena_invalidate_prefetch(struct qbman_swp_sys *s,
275                                                   uint32_t offset)
276 {
277         dccivac(s->addr_cena + offset);
278         prefetch_for_load(s->addr_cena + offset);
279 }
280
281 static inline void qbman_cena_prefetch(struct qbman_swp_sys *s,
282                                        uint32_t offset)
283 {
284         prefetch_for_load(s->addr_cena + offset);
285 }
286
287         /******************/
288         /* Portal support */
289         /******************/
290
291 /* The SWP_CFG portal register is special, in that it is used by the
292  * platform-specific code rather than the platform-independent code in
293  * qbman_portal.c. So use of it is declared locally here.
294  */
295 #define QBMAN_CINH_SWP_CFG   0xd00
296 #define QBMAN_CINH_SWP_CFG   0xd00
297 #define SWP_CFG_DQRR_MF_SHIFT 20
298 #define SWP_CFG_EST_SHIFT     16
299 #define SWP_CFG_WN_SHIFT      14
300 #define SWP_CFG_RPM_SHIFT     12
301 #define SWP_CFG_DCM_SHIFT     10
302 #define SWP_CFG_EPM_SHIFT     8
303 #define SWP_CFG_SD_SHIFT      5
304 #define SWP_CFG_SP_SHIFT      4
305 #define SWP_CFG_SE_SHIFT      3
306 #define SWP_CFG_DP_SHIFT      2
307 #define SWP_CFG_DE_SHIFT      1
308 #define SWP_CFG_EP_SHIFT      0
309
310 static inline uint32_t qbman_set_swp_cfg(uint8_t max_fill, uint8_t wn,
311                                          uint8_t est, uint8_t rpm, uint8_t dcm,
312                                         uint8_t epm, int sd, int sp, int se,
313                                         int dp, int de, int ep)
314 {
315         uint32_t reg;
316
317         reg = (max_fill << SWP_CFG_DQRR_MF_SHIFT |
318                 est << SWP_CFG_EST_SHIFT |
319                 wn << SWP_CFG_WN_SHIFT |
320                 rpm << SWP_CFG_RPM_SHIFT |
321                 dcm << SWP_CFG_DCM_SHIFT |
322                 epm << SWP_CFG_EPM_SHIFT |
323                 sd << SWP_CFG_SD_SHIFT |
324                 sp << SWP_CFG_SP_SHIFT |
325                 se << SWP_CFG_SE_SHIFT |
326                 dp << SWP_CFG_DP_SHIFT |
327                 de << SWP_CFG_DE_SHIFT |
328                 ep << SWP_CFG_EP_SHIFT);
329
330         return reg;
331 }
332
333 static inline int qbman_swp_sys_init(struct qbman_swp_sys *s,
334                                      const struct qbman_swp_desc *d,
335                                      uint8_t dqrr_size)
336 {
337         uint32_t reg;
338
339         s->addr_cena = d->cena_bar;
340         s->addr_cinh = d->cinh_bar;
341         s->idx = (uint32_t)d->idx;
342         s->cena = malloc(4096);
343         if (!s->cena) {
344                 pr_err("Could not allocate page for cena shadow\n");
345                 return -1;
346         }
347         s->eqcr_mode = d->eqcr_mode;
348         QBMAN_BUG_ON(d->idx < 0);
349 #ifdef QBMAN_CHECKING
350         /* We should never be asked to initialise for a portal that isn't in
351          * the power-on state. (Ie. don't forget to reset portals when they are
352          * decommissioned!)
353          */
354         reg = qbman_cinh_read(s, QBMAN_CINH_SWP_CFG);
355         QBMAN_BUG_ON(reg);
356 #endif
357         if (s->eqcr_mode == qman_eqcr_vb_array)
358                 reg = qbman_set_swp_cfg(dqrr_size, 0, 0, 3, 2, 3, 1, 1, 1, 1,
359                                         1, 1);
360         else
361                 reg = qbman_set_swp_cfg(dqrr_size, 0, 2, 3, 2, 2, 1, 1, 1, 1,
362                                         1, 1);
363         qbman_cinh_write(s, QBMAN_CINH_SWP_CFG, reg);
364         reg = qbman_cinh_read(s, QBMAN_CINH_SWP_CFG);
365         if (!reg) {
366                 pr_err("The portal %d is not enabled!\n", s->idx);
367                 free(s->cena);
368                 return -1;
369         }
370         return 0;
371 }
372
373 static inline void qbman_swp_sys_finish(struct qbman_swp_sys *s)
374 {
375         free(s->cena);
376 }