1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later |
2 | /* |
3 | * Copyright 2008 - 2015 Freescale Semiconductor Inc. |
4 | */ |
5 | |
6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
7 | |
8 | #include <linux/io.h> |
9 | #include <linux/platform_device.h> |
10 | #include <linux/slab.h> |
11 | #include <linux/module.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/of_platform.h> |
14 | #include <linux/of_address.h> |
15 | #include <linux/delay.h> |
16 | #include <linux/libfdt_env.h> |
17 | |
18 | #include "fman.h" |
19 | #include "fman_port.h" |
20 | #include "fman_sp.h" |
21 | #include "fman_keygen.h" |
22 | |
23 | /* Queue ID */ |
24 | #define DFLT_FQ_ID 0x00FFFFFF |
25 | |
26 | /* General defines */ |
27 | #define PORT_BMI_FIFO_UNITS 0x100 |
28 | |
29 | #define MAX_PORT_FIFO_SIZE(bmi_max_fifo_size) \ |
30 | min((u32)bmi_max_fifo_size, (u32)1024 * FMAN_BMI_FIFO_UNITS) |
31 | |
32 | #define PORT_CG_MAP_NUM 8 |
33 | #define PORT_PRS_RESULT_WORDS_NUM 8 |
34 | #define PORT_IC_OFFSET_UNITS 0x10 |
35 | |
36 | #define MIN_EXT_BUF_SIZE 64 |
37 | |
38 | #define BMI_PORT_REGS_OFFSET 0 |
39 | #define QMI_PORT_REGS_OFFSET 0x400 |
40 | #define HWP_PORT_REGS_OFFSET 0x800 |
41 | |
42 | /* Default values */ |
43 | #define DFLT_PORT_BUFFER_PREFIX_CONTEXT_DATA_ALIGN \ |
44 | DFLT_FM_SP_BUFFER_PREFIX_CONTEXT_DATA_ALIGN |
45 | |
46 | #define DFLT_PORT_CUT_BYTES_FROM_END 4 |
47 | |
48 | #define DFLT_PORT_ERRORS_TO_DISCARD FM_PORT_FRM_ERR_CLS_DISCARD |
49 | #define DFLT_PORT_MAX_FRAME_LENGTH 9600 |
50 | |
51 | #define DFLT_PORT_RX_FIFO_PRI_ELEVATION_LEV(bmi_max_fifo_size) \ |
52 | MAX_PORT_FIFO_SIZE(bmi_max_fifo_size) |
53 | |
54 | #define DFLT_PORT_RX_FIFO_THRESHOLD(major, bmi_max_fifo_size) \ |
55 | (major == 6 ? \ |
56 | MAX_PORT_FIFO_SIZE(bmi_max_fifo_size) : \ |
57 | (MAX_PORT_FIFO_SIZE(bmi_max_fifo_size) * 3 / 4)) \ |
58 | |
59 | #define 0 |
60 | |
61 | /* QMI defines */ |
62 | #define QMI_DEQ_CFG_SUBPORTAL_MASK 0x1f |
63 | |
64 | #define QMI_PORT_CFG_EN 0x80000000 |
65 | #define QMI_PORT_STATUS_DEQ_FD_BSY 0x20000000 |
66 | |
67 | #define QMI_DEQ_CFG_PRI 0x80000000 |
68 | #define QMI_DEQ_CFG_TYPE1 0x10000000 |
69 | #define QMI_DEQ_CFG_TYPE2 0x20000000 |
70 | #define QMI_DEQ_CFG_TYPE3 0x30000000 |
71 | #define QMI_DEQ_CFG_PREFETCH_PARTIAL 0x01000000 |
72 | #define QMI_DEQ_CFG_PREFETCH_FULL 0x03000000 |
73 | #define QMI_DEQ_CFG_SP_MASK 0xf |
74 | #define QMI_DEQ_CFG_SP_SHIFT 20 |
75 | |
76 | #define QMI_BYTE_COUNT_LEVEL_CONTROL(_type) \ |
77 | (_type == FMAN_PORT_TYPE_TX ? 0x1400 : 0x400) |
78 | |
79 | /* BMI defins */ |
80 | #define BMI_EBD_EN 0x80000000 |
81 | |
82 | #define BMI_PORT_CFG_EN 0x80000000 |
83 | |
84 | #define BMI_PORT_STATUS_BSY 0x80000000 |
85 | |
86 | #define BMI_DMA_ATTR_SWP_SHIFT FMAN_SP_DMA_ATTR_SWP_SHIFT |
87 | #define BMI_DMA_ATTR_WRITE_OPTIMIZE FMAN_SP_DMA_ATTR_WRITE_OPTIMIZE |
88 | |
89 | #define BMI_RX_FIFO_PRI_ELEVATION_SHIFT 16 |
90 | #define BMI_RX_FIFO_THRESHOLD_ETHE 0x80000000 |
91 | |
92 | #define BMI_FRAME_END_CS_IGNORE_SHIFT 24 |
93 | #define BMI_FRAME_END_CS_IGNORE_MASK 0x0000001f |
94 | |
95 | #define BMI_RX_FRAME_END_CUT_SHIFT 16 |
96 | #define BMI_RX_FRAME_END_CUT_MASK 0x0000001f |
97 | |
98 | #define BMI_IC_TO_EXT_SHIFT FMAN_SP_IC_TO_EXT_SHIFT |
99 | #define BMI_IC_TO_EXT_MASK 0x0000001f |
100 | #define BMI_IC_FROM_INT_SHIFT FMAN_SP_IC_FROM_INT_SHIFT |
101 | #define BMI_IC_FROM_INT_MASK 0x0000000f |
102 | #define BMI_IC_SIZE_MASK 0x0000001f |
103 | |
104 | #define BMI_INT_BUF_MARG_SHIFT 28 |
105 | #define BMI_INT_BUF_MARG_MASK 0x0000000f |
106 | #define BMI_EXT_BUF_MARG_START_SHIFT FMAN_SP_EXT_BUF_MARG_START_SHIFT |
107 | #define BMI_EXT_BUF_MARG_START_MASK 0x000001ff |
108 | #define BMI_EXT_BUF_MARG_END_MASK 0x000001ff |
109 | |
110 | #define BMI_CMD_MR_LEAC 0x00200000 |
111 | #define BMI_CMD_MR_SLEAC 0x00100000 |
112 | #define BMI_CMD_MR_MA 0x00080000 |
113 | #define BMI_CMD_MR_DEAS 0x00040000 |
114 | #define BMI_CMD_RX_MR_DEF (BMI_CMD_MR_LEAC | \ |
115 | BMI_CMD_MR_SLEAC | \ |
116 | BMI_CMD_MR_MA | \ |
117 | BMI_CMD_MR_DEAS) |
118 | #define BMI_CMD_TX_MR_DEF 0 |
119 | |
120 | #define BMI_CMD_ATTR_ORDER 0x80000000 |
121 | #define BMI_CMD_ATTR_SYNC 0x02000000 |
122 | #define BMI_CMD_ATTR_COLOR_SHIFT 26 |
123 | |
124 | #define BMI_FIFO_PIPELINE_DEPTH_SHIFT 12 |
125 | #define BMI_FIFO_PIPELINE_DEPTH_MASK 0x0000000f |
126 | #define BMI_NEXT_ENG_FD_BITS_SHIFT 24 |
127 | |
128 | #define BMI_EXT_BUF_POOL_VALID FMAN_SP_EXT_BUF_POOL_VALID |
129 | #define BMI_EXT_BUF_POOL_EN_COUNTER FMAN_SP_EXT_BUF_POOL_EN_COUNTER |
130 | #define BMI_EXT_BUF_POOL_BACKUP FMAN_SP_EXT_BUF_POOL_BACKUP |
131 | #define BMI_EXT_BUF_POOL_ID_SHIFT 16 |
132 | #define BMI_EXT_BUF_POOL_ID_MASK 0x003F0000 |
133 | #define BMI_POOL_DEP_NUM_OF_POOLS_SHIFT 16 |
134 | |
135 | #define BMI_TX_FIFO_MIN_FILL_SHIFT 16 |
136 | |
137 | #define BMI_PRIORITY_ELEVATION_LEVEL ((0x3FF + 1) * PORT_BMI_FIFO_UNITS) |
138 | #define BMI_FIFO_THRESHOLD ((0x3FF + 1) * PORT_BMI_FIFO_UNITS) |
139 | |
140 | #define BMI_DEQUEUE_PIPELINE_DEPTH(_type, _speed) \ |
141 | ((_type == FMAN_PORT_TYPE_TX && _speed == 10000) ? 4 : 1) |
142 | |
143 | #define RX_ERRS_TO_ENQ \ |
144 | (FM_PORT_FRM_ERR_DMA | \ |
145 | FM_PORT_FRM_ERR_PHYSICAL | \ |
146 | FM_PORT_FRM_ERR_SIZE | \ |
147 | FM_PORT_FRM_ERR_EXTRACTION | \ |
148 | FM_PORT_FRM_ERR_NO_SCHEME | \ |
149 | FM_PORT_FRM_ERR_PRS_TIMEOUT | \ |
150 | FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | \ |
151 | FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED | \ |
152 | FM_PORT_FRM_ERR_PRS_HDR_ERR | \ |
153 | FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW | \ |
154 | FM_PORT_FRM_ERR_IPRE) |
155 | |
156 | /* NIA defines */ |
157 | #define NIA_ORDER_RESTOR 0x00800000 |
158 | #define NIA_ENG_BMI 0x00500000 |
159 | #define NIA_ENG_QMI_ENQ 0x00540000 |
160 | #define NIA_ENG_QMI_DEQ 0x00580000 |
161 | #define NIA_ENG_HWP 0x00440000 |
162 | #define NIA_ENG_HWK 0x00480000 |
163 | #define NIA_BMI_AC_ENQ_FRAME 0x00000002 |
164 | #define NIA_BMI_AC_TX_RELEASE 0x000002C0 |
165 | #define NIA_BMI_AC_RELEASE 0x000000C0 |
166 | #define NIA_BMI_AC_TX 0x00000274 |
167 | #define NIA_BMI_AC_FETCH_ALL_FRAME 0x0000020c |
168 | |
169 | /* Port IDs */ |
170 | #define TX_10G_PORT_BASE 0x30 |
171 | #define RX_10G_PORT_BASE 0x10 |
172 | |
173 | /* BMI Rx port register map */ |
174 | struct fman_port_rx_bmi_regs { |
175 | u32 fmbm_rcfg; /* Rx Configuration */ |
176 | u32 fmbm_rst; /* Rx Status */ |
177 | u32 fmbm_rda; /* Rx DMA attributes */ |
178 | u32 fmbm_rfp; /* Rx FIFO Parameters */ |
179 | u32 fmbm_rfed; /* Rx Frame End Data */ |
180 | u32 fmbm_ricp; /* Rx Internal Context Parameters */ |
181 | u32 fmbm_rim; /* Rx Internal Buffer Margins */ |
182 | u32 fmbm_rebm; /* Rx External Buffer Margins */ |
183 | u32 fmbm_rfne; /* Rx Frame Next Engine */ |
184 | u32 fmbm_rfca; /* Rx Frame Command Attributes. */ |
185 | u32 fmbm_rfpne; /* Rx Frame Parser Next Engine */ |
186 | u32 fmbm_rpso; /* Rx Parse Start Offset */ |
187 | u32 fmbm_rpp; /* Rx Policer Profile */ |
188 | u32 fmbm_rccb; /* Rx Coarse Classification Base */ |
189 | u32 fmbm_reth; /* Rx Excessive Threshold */ |
190 | u32 reserved003c[1]; /* (0x03C 0x03F) */ |
191 | u32 fmbm_rprai[PORT_PRS_RESULT_WORDS_NUM]; |
192 | /* Rx Parse Results Array Init */ |
193 | u32 fmbm_rfqid; /* Rx Frame Queue ID */ |
194 | u32 fmbm_refqid; /* Rx Error Frame Queue ID */ |
195 | u32 fmbm_rfsdm; /* Rx Frame Status Discard Mask */ |
196 | u32 fmbm_rfsem; /* Rx Frame Status Error Mask */ |
197 | u32 fmbm_rfene; /* Rx Frame Enqueue Next Engine */ |
198 | u32 reserved0074[0x2]; /* (0x074-0x07C) */ |
199 | u32 fmbm_rcmne; /* Rx Frame Continuous Mode Next Engine */ |
200 | u32 reserved0080[0x20]; /* (0x080 0x0FF) */ |
201 | u32 fmbm_ebmpi[FMAN_PORT_MAX_EXT_POOLS_NUM]; |
202 | /* Buffer Manager pool Information- */ |
203 | u32 fmbm_acnt[FMAN_PORT_MAX_EXT_POOLS_NUM]; /* Allocate Counter- */ |
204 | u32 reserved0130[8]; /* 0x130/0x140 - 0x15F reserved - */ |
205 | u32 fmbm_rcgm[PORT_CG_MAP_NUM]; /* Congestion Group Map */ |
206 | u32 fmbm_mpd; /* BM Pool Depletion */ |
207 | u32 reserved0184[0x1F]; /* (0x184 0x1FF) */ |
208 | u32 fmbm_rstc; /* Rx Statistics Counters */ |
209 | u32 fmbm_rfrc; /* Rx Frame Counter */ |
210 | u32 fmbm_rfbc; /* Rx Bad Frames Counter */ |
211 | u32 fmbm_rlfc; /* Rx Large Frames Counter */ |
212 | u32 fmbm_rffc; /* Rx Filter Frames Counter */ |
213 | u32 fmbm_rfdc; /* Rx Frame Discard Counter */ |
214 | u32 fmbm_rfldec; /* Rx Frames List DMA Error Counter */ |
215 | u32 fmbm_rodc; /* Rx Out of Buffers Discard nntr */ |
216 | u32 fmbm_rbdc; /* Rx Buffers Deallocate Counter */ |
217 | u32 fmbm_rpec; /* RX Prepare to enqueue Counte */ |
218 | u32 reserved0224[0x16]; /* (0x224 0x27F) */ |
219 | u32 fmbm_rpc; /* Rx Performance Counters */ |
220 | u32 fmbm_rpcp; /* Rx Performance Count Parameters */ |
221 | u32 fmbm_rccn; /* Rx Cycle Counter */ |
222 | u32 fmbm_rtuc; /* Rx Tasks Utilization Counter */ |
223 | u32 fmbm_rrquc; /* Rx Receive Queue Utilization cntr */ |
224 | u32 fmbm_rduc; /* Rx DMA Utilization Counter */ |
225 | u32 fmbm_rfuc; /* Rx FIFO Utilization Counter */ |
226 | u32 fmbm_rpac; /* Rx Pause Activation Counter */ |
227 | u32 reserved02a0[0x18]; /* (0x2A0 0x2FF) */ |
228 | u32 fmbm_rdcfg[0x3]; /* Rx Debug Configuration */ |
229 | u32 fmbm_rgpr; /* Rx General Purpose Register */ |
230 | u32 reserved0310[0x3a]; |
231 | }; |
232 | |
233 | /* BMI Tx port register map */ |
234 | struct fman_port_tx_bmi_regs { |
235 | u32 fmbm_tcfg; /* Tx Configuration */ |
236 | u32 fmbm_tst; /* Tx Status */ |
237 | u32 fmbm_tda; /* Tx DMA attributes */ |
238 | u32 fmbm_tfp; /* Tx FIFO Parameters */ |
239 | u32 fmbm_tfed; /* Tx Frame End Data */ |
240 | u32 fmbm_ticp; /* Tx Internal Context Parameters */ |
241 | u32 fmbm_tfdne; /* Tx Frame Dequeue Next Engine. */ |
242 | u32 fmbm_tfca; /* Tx Frame Command attribute. */ |
243 | u32 fmbm_tcfqid; /* Tx Confirmation Frame Queue ID. */ |
244 | u32 fmbm_tefqid; /* Tx Frame Error Queue ID */ |
245 | u32 fmbm_tfene; /* Tx Frame Enqueue Next Engine */ |
246 | u32 fmbm_trlmts; /* Tx Rate Limiter Scale */ |
247 | u32 fmbm_trlmt; /* Tx Rate Limiter */ |
248 | u32 reserved0034[0x0e]; /* (0x034-0x6c) */ |
249 | u32 fmbm_tccb; /* Tx Coarse Classification base */ |
250 | u32 fmbm_tfne; /* Tx Frame Next Engine */ |
251 | u32 fmbm_tpfcm[0x02]; |
252 | /* Tx Priority based Flow Control (PFC) Mapping */ |
253 | u32 fmbm_tcmne; /* Tx Frame Continuous Mode Next Engine */ |
254 | u32 reserved0080[0x60]; /* (0x080-0x200) */ |
255 | u32 fmbm_tstc; /* Tx Statistics Counters */ |
256 | u32 fmbm_tfrc; /* Tx Frame Counter */ |
257 | u32 fmbm_tfdc; /* Tx Frames Discard Counter */ |
258 | u32 fmbm_tfledc; /* Tx Frame len error discard cntr */ |
259 | u32 fmbm_tfufdc; /* Tx Frame unsprt frmt discard cntr */ |
260 | u32 fmbm_tbdc; /* Tx Buffers Deallocate Counter */ |
261 | u32 reserved0218[0x1A]; /* (0x218-0x280) */ |
262 | u32 fmbm_tpc; /* Tx Performance Counters */ |
263 | u32 fmbm_tpcp; /* Tx Performance Count Parameters */ |
264 | u32 fmbm_tccn; /* Tx Cycle Counter */ |
265 | u32 fmbm_ttuc; /* Tx Tasks Utilization Counter */ |
266 | u32 fmbm_ttcquc; /* Tx Transmit conf Q util Counter */ |
267 | u32 fmbm_tduc; /* Tx DMA Utilization Counter */ |
268 | u32 fmbm_tfuc; /* Tx FIFO Utilization Counter */ |
269 | u32 reserved029c[16]; /* (0x29C-0x2FF) */ |
270 | u32 fmbm_tdcfg[0x3]; /* Tx Debug Configuration */ |
271 | u32 fmbm_tgpr; /* Tx General Purpose Register */ |
272 | u32 reserved0310[0x3a]; /* (0x310-0x3FF) */ |
273 | }; |
274 | |
275 | /* BMI port register map */ |
276 | union fman_port_bmi_regs { |
277 | struct fman_port_rx_bmi_regs rx; |
278 | struct fman_port_tx_bmi_regs tx; |
279 | }; |
280 | |
281 | /* QMI port register map */ |
282 | struct fman_port_qmi_regs { |
283 | u32 fmqm_pnc; /* PortID n Configuration Register */ |
284 | u32 fmqm_pns; /* PortID n Status Register */ |
285 | u32 fmqm_pnts; /* PortID n Task Status Register */ |
286 | u32 reserved00c[4]; /* 0xn00C - 0xn01B */ |
287 | u32 fmqm_pnen; /* PortID n Enqueue NIA Register */ |
288 | u32 fmqm_pnetfc; /* PortID n Enq Total Frame Counter */ |
289 | u32 reserved024[2]; /* 0xn024 - 0x02B */ |
290 | u32 fmqm_pndn; /* PortID n Dequeue NIA Register */ |
291 | u32 fmqm_pndc; /* PortID n Dequeue Config Register */ |
292 | u32 fmqm_pndtfc; /* PortID n Dequeue tot Frame cntr */ |
293 | u32 fmqm_pndfdc; /* PortID n Dequeue FQID Dflt Cntr */ |
294 | u32 fmqm_pndcc; /* PortID n Dequeue Confirm Counter */ |
295 | }; |
296 | |
297 | #define HWP_HXS_COUNT 16 |
298 | #define HWP_HXS_PHE_REPORT 0x00000800 |
299 | #define HWP_HXS_PCAC_PSTAT 0x00000100 |
300 | #define HWP_HXS_PCAC_PSTOP 0x00000001 |
301 | #define HWP_HXS_TCP_OFFSET 0xA |
302 | #define HWP_HXS_UDP_OFFSET 0xB |
303 | #define HWP_HXS_SH_PAD_REM 0x80000000 |
304 | |
305 | struct fman_port_hwp_regs { |
306 | struct { |
307 | u32 ssa; /* Soft Sequence Attachment */ |
308 | u32 lcv; /* Line-up Enable Confirmation Mask */ |
309 | } pmda[HWP_HXS_COUNT]; /* Parse Memory Direct Access Registers */ |
310 | u32 reserved080[(0x3f8 - 0x080) / 4]; /* (0x080-0x3f7) */ |
311 | u32 fmpr_pcac; /* Configuration Access Control */ |
312 | }; |
313 | |
314 | /* QMI dequeue prefetch modes */ |
315 | enum fman_port_deq_prefetch { |
316 | FMAN_PORT_DEQ_NO_PREFETCH, /* No prefetch mode */ |
317 | FMAN_PORT_DEQ_PART_PREFETCH, /* Partial prefetch mode */ |
318 | FMAN_PORT_DEQ_FULL_PREFETCH /* Full prefetch mode */ |
319 | }; |
320 | |
321 | /* A structure for defining FM port resources */ |
322 | struct fman_port_rsrc { |
323 | u32 num; /* Committed required resource */ |
324 | u32 ; /* Extra (not committed) required resource */ |
325 | }; |
326 | |
327 | enum fman_port_dma_swap { |
328 | FMAN_PORT_DMA_NO_SWAP, /* No swap, transfer data as is */ |
329 | FMAN_PORT_DMA_SWAP_LE, |
330 | /* The transferred data should be swapped in PPC Little Endian mode */ |
331 | FMAN_PORT_DMA_SWAP_BE |
332 | /* The transferred data should be swapped in Big Endian mode */ |
333 | }; |
334 | |
335 | /* Default port color */ |
336 | enum fman_port_color { |
337 | FMAN_PORT_COLOR_GREEN, /* Default port color is green */ |
338 | FMAN_PORT_COLOR_YELLOW, /* Default port color is yellow */ |
339 | FMAN_PORT_COLOR_RED, /* Default port color is red */ |
340 | FMAN_PORT_COLOR_OVERRIDE /* Ignore color */ |
341 | }; |
342 | |
343 | /* QMI dequeue from the SP channel - types */ |
344 | enum fman_port_deq_type { |
345 | FMAN_PORT_DEQ_BY_PRI, |
346 | /* Priority precedence and Intra-Class scheduling */ |
347 | FMAN_PORT_DEQ_ACTIVE_FQ, |
348 | /* Active FQ precedence and Intra-Class scheduling */ |
349 | FMAN_PORT_DEQ_ACTIVE_FQ_NO_ICS |
350 | /* Active FQ precedence and override Intra-Class scheduling */ |
351 | }; |
352 | |
353 | /* External buffer pools configuration */ |
354 | struct fman_port_bpools { |
355 | u8 count; /* Num of pools to set up */ |
356 | bool counters_enable; /* Enable allocate counters */ |
357 | u8 grp_bp_depleted_num; |
358 | /* Number of depleted pools - if reached the BMI indicates |
359 | * the MAC to send a pause frame |
360 | */ |
361 | struct { |
362 | u8 bpid; /* BM pool ID */ |
363 | u16 size; |
364 | /* Pool's size - must be in ascending order */ |
365 | bool is_backup; |
366 | /* If this is a backup pool */ |
367 | bool grp_bp_depleted; |
368 | /* Consider this buffer in multiple pools depletion criteria */ |
369 | bool single_bp_depleted; |
370 | /* Consider this buffer in single pool depletion criteria */ |
371 | } bpool[FMAN_PORT_MAX_EXT_POOLS_NUM]; |
372 | }; |
373 | |
374 | struct fman_port_cfg { |
375 | u32 dflt_fqid; |
376 | u32 err_fqid; |
377 | u32 pcd_base_fqid; |
378 | u32 pcd_fqs_count; |
379 | u8 deq_sp; |
380 | bool deq_high_priority; |
381 | enum fman_port_deq_type deq_type; |
382 | enum fman_port_deq_prefetch deq_prefetch_option; |
383 | u16 deq_byte_cnt; |
384 | u8 cheksum_last_bytes_ignore; |
385 | u8 rx_cut_end_bytes; |
386 | struct fman_buf_pool_depletion buf_pool_depletion; |
387 | struct fman_ext_pools ext_buf_pools; |
388 | u32 tx_fifo_min_level; |
389 | u32 tx_fifo_low_comf_level; |
390 | u32 rx_pri_elevation; |
391 | u32 rx_fifo_thr; |
392 | struct fman_sp_buf_margins buf_margins; |
393 | u32 int_buf_start_margin; |
394 | struct fman_sp_int_context_data_copy int_context; |
395 | u32 discard_mask; |
396 | u32 err_mask; |
397 | struct fman_buffer_prefix_content buffer_prefix_content; |
398 | bool dont_release_buf; |
399 | |
400 | u8 rx_fd_bits; |
401 | u32 tx_fifo_deq_pipeline_depth; |
402 | bool errata_A006320; |
403 | bool excessive_threshold_register; |
404 | bool fmbm_tfne_has_features; |
405 | |
406 | enum fman_port_dma_swap dma_swap_data; |
407 | enum fman_port_color color; |
408 | }; |
409 | |
410 | struct fman_port_rx_pools_params { |
411 | u8 num_of_pools; |
412 | u16 largest_buf_size; |
413 | }; |
414 | |
415 | struct fman_port_dts_params { |
416 | void __iomem *base_addr; /* FMan port virtual memory */ |
417 | enum fman_port_type type; /* Port type */ |
418 | u16 speed; /* Port speed */ |
419 | u8 id; /* HW Port Id */ |
420 | u32 qman_channel_id; /* QMan channel id (non RX only) */ |
421 | struct fman *fman; /* FMan Handle */ |
422 | }; |
423 | |
424 | struct fman_port { |
425 | void *fm; |
426 | struct device *dev; |
427 | struct fman_rev_info rev_info; |
428 | u8 port_id; |
429 | enum fman_port_type port_type; |
430 | u16 port_speed; |
431 | |
432 | union fman_port_bmi_regs __iomem *bmi_regs; |
433 | struct fman_port_qmi_regs __iomem *qmi_regs; |
434 | struct fman_port_hwp_regs __iomem *hwp_regs; |
435 | |
436 | struct fman_sp_buffer_offsets buffer_offsets; |
437 | |
438 | u8 internal_buf_offset; |
439 | struct fman_ext_pools ext_buf_pools; |
440 | |
441 | u16 max_frame_length; |
442 | struct fman_port_rsrc open_dmas; |
443 | struct fman_port_rsrc tasks; |
444 | struct fman_port_rsrc fifo_bufs; |
445 | struct fman_port_rx_pools_params rx_pools_params; |
446 | |
447 | struct fman_port_cfg *cfg; |
448 | struct fman_port_dts_params dts_params; |
449 | |
450 | u8 ext_pools_num; |
451 | u32 max_port_fifo_size; |
452 | u32 max_num_of_ext_pools; |
453 | u32 max_num_of_sub_portals; |
454 | u32 bm_max_num_of_pools; |
455 | }; |
456 | |
457 | static int init_bmi_rx(struct fman_port *port) |
458 | { |
459 | struct fman_port_rx_bmi_regs __iomem *regs = &port->bmi_regs->rx; |
460 | struct fman_port_cfg *cfg = port->cfg; |
461 | u32 tmp; |
462 | |
463 | /* DMA attributes */ |
464 | tmp = (u32)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT; |
465 | /* Enable write optimization */ |
466 | tmp |= BMI_DMA_ATTR_WRITE_OPTIMIZE; |
467 | iowrite32be(tmp, ®s->fmbm_rda); |
468 | |
469 | /* Rx FIFO parameters */ |
470 | tmp = (cfg->rx_pri_elevation / PORT_BMI_FIFO_UNITS - 1) << |
471 | BMI_RX_FIFO_PRI_ELEVATION_SHIFT; |
472 | tmp |= cfg->rx_fifo_thr / PORT_BMI_FIFO_UNITS - 1; |
473 | iowrite32be(tmp, ®s->fmbm_rfp); |
474 | |
475 | if (cfg->excessive_threshold_register) |
476 | /* always allow access to the extra resources */ |
477 | iowrite32be(BMI_RX_FIFO_THRESHOLD_ETHE, ®s->fmbm_reth); |
478 | |
479 | /* Frame end data */ |
480 | tmp = (cfg->cheksum_last_bytes_ignore & BMI_FRAME_END_CS_IGNORE_MASK) << |
481 | BMI_FRAME_END_CS_IGNORE_SHIFT; |
482 | tmp |= (cfg->rx_cut_end_bytes & BMI_RX_FRAME_END_CUT_MASK) << |
483 | BMI_RX_FRAME_END_CUT_SHIFT; |
484 | if (cfg->errata_A006320) |
485 | tmp &= 0xffe0ffff; |
486 | iowrite32be(tmp, ®s->fmbm_rfed); |
487 | |
488 | /* Internal context parameters */ |
489 | tmp = ((cfg->int_context.ext_buf_offset / PORT_IC_OFFSET_UNITS) & |
490 | BMI_IC_TO_EXT_MASK) << BMI_IC_TO_EXT_SHIFT; |
491 | tmp |= ((cfg->int_context.int_context_offset / PORT_IC_OFFSET_UNITS) & |
492 | BMI_IC_FROM_INT_MASK) << BMI_IC_FROM_INT_SHIFT; |
493 | tmp |= (cfg->int_context.size / PORT_IC_OFFSET_UNITS) & |
494 | BMI_IC_SIZE_MASK; |
495 | iowrite32be(tmp, ®s->fmbm_ricp); |
496 | |
497 | /* Internal buffer offset */ |
498 | tmp = ((cfg->int_buf_start_margin / PORT_IC_OFFSET_UNITS) & |
499 | BMI_INT_BUF_MARG_MASK) << BMI_INT_BUF_MARG_SHIFT; |
500 | iowrite32be(tmp, ®s->fmbm_rim); |
501 | |
502 | /* External buffer margins */ |
503 | tmp = (cfg->buf_margins.start_margins & BMI_EXT_BUF_MARG_START_MASK) << |
504 | BMI_EXT_BUF_MARG_START_SHIFT; |
505 | tmp |= cfg->buf_margins.end_margins & BMI_EXT_BUF_MARG_END_MASK; |
506 | iowrite32be(tmp, ®s->fmbm_rebm); |
507 | |
508 | /* Frame attributes */ |
509 | tmp = BMI_CMD_RX_MR_DEF; |
510 | tmp |= BMI_CMD_ATTR_ORDER; |
511 | tmp |= (u32)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT; |
512 | /* Synchronization request */ |
513 | tmp |= BMI_CMD_ATTR_SYNC; |
514 | |
515 | iowrite32be(tmp, ®s->fmbm_rfca); |
516 | |
517 | /* NIA */ |
518 | tmp = (u32)cfg->rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT; |
519 | |
520 | tmp |= NIA_ENG_HWP; |
521 | iowrite32be(tmp, ®s->fmbm_rfne); |
522 | |
523 | /* Parser Next Engine NIA */ |
524 | iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME, ®s->fmbm_rfpne); |
525 | |
526 | /* Enqueue NIA */ |
527 | iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, ®s->fmbm_rfene); |
528 | |
529 | /* Default/error queues */ |
530 | iowrite32be((cfg->dflt_fqid & DFLT_FQ_ID), ®s->fmbm_rfqid); |
531 | iowrite32be((cfg->err_fqid & DFLT_FQ_ID), ®s->fmbm_refqid); |
532 | |
533 | /* Discard/error masks */ |
534 | iowrite32be(cfg->discard_mask, ®s->fmbm_rfsdm); |
535 | iowrite32be(cfg->err_mask, ®s->fmbm_rfsem); |
536 | |
537 | return 0; |
538 | } |
539 | |
540 | static int init_bmi_tx(struct fman_port *port) |
541 | { |
542 | struct fman_port_tx_bmi_regs __iomem *regs = &port->bmi_regs->tx; |
543 | struct fman_port_cfg *cfg = port->cfg; |
544 | u32 tmp; |
545 | |
546 | /* Tx Configuration register */ |
547 | tmp = 0; |
548 | iowrite32be(tmp, ®s->fmbm_tcfg); |
549 | |
550 | /* DMA attributes */ |
551 | tmp = (u32)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT; |
552 | iowrite32be(tmp, ®s->fmbm_tda); |
553 | |
554 | /* Tx FIFO parameters */ |
555 | tmp = (cfg->tx_fifo_min_level / PORT_BMI_FIFO_UNITS) << |
556 | BMI_TX_FIFO_MIN_FILL_SHIFT; |
557 | tmp |= ((cfg->tx_fifo_deq_pipeline_depth - 1) & |
558 | BMI_FIFO_PIPELINE_DEPTH_MASK) << BMI_FIFO_PIPELINE_DEPTH_SHIFT; |
559 | tmp |= (cfg->tx_fifo_low_comf_level / PORT_BMI_FIFO_UNITS) - 1; |
560 | iowrite32be(tmp, ®s->fmbm_tfp); |
561 | |
562 | /* Frame end data */ |
563 | tmp = (cfg->cheksum_last_bytes_ignore & BMI_FRAME_END_CS_IGNORE_MASK) << |
564 | BMI_FRAME_END_CS_IGNORE_SHIFT; |
565 | iowrite32be(tmp, ®s->fmbm_tfed); |
566 | |
567 | /* Internal context parameters */ |
568 | tmp = ((cfg->int_context.ext_buf_offset / PORT_IC_OFFSET_UNITS) & |
569 | BMI_IC_TO_EXT_MASK) << BMI_IC_TO_EXT_SHIFT; |
570 | tmp |= ((cfg->int_context.int_context_offset / PORT_IC_OFFSET_UNITS) & |
571 | BMI_IC_FROM_INT_MASK) << BMI_IC_FROM_INT_SHIFT; |
572 | tmp |= (cfg->int_context.size / PORT_IC_OFFSET_UNITS) & |
573 | BMI_IC_SIZE_MASK; |
574 | iowrite32be(tmp, ®s->fmbm_ticp); |
575 | |
576 | /* Frame attributes */ |
577 | tmp = BMI_CMD_TX_MR_DEF; |
578 | tmp |= BMI_CMD_ATTR_ORDER; |
579 | tmp |= (u32)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT; |
580 | iowrite32be(tmp, ®s->fmbm_tfca); |
581 | |
582 | /* Dequeue NIA + enqueue NIA */ |
583 | iowrite32be(NIA_ENG_QMI_DEQ, ®s->fmbm_tfdne); |
584 | iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, ®s->fmbm_tfene); |
585 | if (cfg->fmbm_tfne_has_features) |
586 | iowrite32be(!cfg->dflt_fqid ? |
587 | BMI_EBD_EN | NIA_BMI_AC_FETCH_ALL_FRAME : |
588 | NIA_BMI_AC_FETCH_ALL_FRAME, ®s->fmbm_tfne); |
589 | if (!cfg->dflt_fqid && cfg->dont_release_buf) { |
590 | iowrite32be(DFLT_FQ_ID, ®s->fmbm_tcfqid); |
591 | iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE, |
592 | ®s->fmbm_tfene); |
593 | if (cfg->fmbm_tfne_has_features) |
594 | iowrite32be(ioread32be(®s->fmbm_tfne) & ~BMI_EBD_EN, |
595 | ®s->fmbm_tfne); |
596 | } |
597 | |
598 | /* Confirmation/error queues */ |
599 | if (cfg->dflt_fqid || !cfg->dont_release_buf) |
600 | iowrite32be(cfg->dflt_fqid & DFLT_FQ_ID, ®s->fmbm_tcfqid); |
601 | iowrite32be((cfg->err_fqid & DFLT_FQ_ID), ®s->fmbm_tefqid); |
602 | |
603 | return 0; |
604 | } |
605 | |
606 | static int init_qmi(struct fman_port *port) |
607 | { |
608 | struct fman_port_qmi_regs __iomem *regs = port->qmi_regs; |
609 | struct fman_port_cfg *cfg = port->cfg; |
610 | u32 tmp; |
611 | |
612 | /* Rx port configuration */ |
613 | if (port->port_type == FMAN_PORT_TYPE_RX) { |
614 | /* Enqueue NIA */ |
615 | iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_RELEASE, ®s->fmqm_pnen); |
616 | return 0; |
617 | } |
618 | |
619 | /* Continue with Tx port configuration */ |
620 | if (port->port_type == FMAN_PORT_TYPE_TX) { |
621 | /* Enqueue NIA */ |
622 | iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE, |
623 | ®s->fmqm_pnen); |
624 | /* Dequeue NIA */ |
625 | iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX, ®s->fmqm_pndn); |
626 | } |
627 | |
628 | /* Dequeue Configuration register */ |
629 | tmp = 0; |
630 | if (cfg->deq_high_priority) |
631 | tmp |= QMI_DEQ_CFG_PRI; |
632 | |
633 | switch (cfg->deq_type) { |
634 | case FMAN_PORT_DEQ_BY_PRI: |
635 | tmp |= QMI_DEQ_CFG_TYPE1; |
636 | break; |
637 | case FMAN_PORT_DEQ_ACTIVE_FQ: |
638 | tmp |= QMI_DEQ_CFG_TYPE2; |
639 | break; |
640 | case FMAN_PORT_DEQ_ACTIVE_FQ_NO_ICS: |
641 | tmp |= QMI_DEQ_CFG_TYPE3; |
642 | break; |
643 | default: |
644 | return -EINVAL; |
645 | } |
646 | |
647 | switch (cfg->deq_prefetch_option) { |
648 | case FMAN_PORT_DEQ_NO_PREFETCH: |
649 | break; |
650 | case FMAN_PORT_DEQ_PART_PREFETCH: |
651 | tmp |= QMI_DEQ_CFG_PREFETCH_PARTIAL; |
652 | break; |
653 | case FMAN_PORT_DEQ_FULL_PREFETCH: |
654 | tmp |= QMI_DEQ_CFG_PREFETCH_FULL; |
655 | break; |
656 | default: |
657 | return -EINVAL; |
658 | } |
659 | |
660 | tmp |= (cfg->deq_sp & QMI_DEQ_CFG_SP_MASK) << QMI_DEQ_CFG_SP_SHIFT; |
661 | tmp |= cfg->deq_byte_cnt; |
662 | iowrite32be(tmp, ®s->fmqm_pndc); |
663 | |
664 | return 0; |
665 | } |
666 | |
667 | static void stop_port_hwp(struct fman_port *port) |
668 | { |
669 | struct fman_port_hwp_regs __iomem *regs = port->hwp_regs; |
670 | int cnt = 100; |
671 | |
672 | iowrite32be(HWP_HXS_PCAC_PSTOP, ®s->fmpr_pcac); |
673 | |
674 | while (cnt-- > 0 && |
675 | (ioread32be(®s->fmpr_pcac) & HWP_HXS_PCAC_PSTAT)) |
676 | udelay(10); |
677 | if (!cnt) |
678 | pr_err("Timeout stopping HW Parser\n" ); |
679 | } |
680 | |
681 | static void start_port_hwp(struct fman_port *port) |
682 | { |
683 | struct fman_port_hwp_regs __iomem *regs = port->hwp_regs; |
684 | int cnt = 100; |
685 | |
686 | iowrite32be(0, ®s->fmpr_pcac); |
687 | |
688 | while (cnt-- > 0 && |
689 | !(ioread32be(®s->fmpr_pcac) & HWP_HXS_PCAC_PSTAT)) |
690 | udelay(10); |
691 | if (!cnt) |
692 | pr_err("Timeout starting HW Parser\n" ); |
693 | } |
694 | |
695 | static void init_hwp(struct fman_port *port) |
696 | { |
697 | struct fman_port_hwp_regs __iomem *regs = port->hwp_regs; |
698 | int i; |
699 | |
700 | stop_port_hwp(port); |
701 | |
702 | for (i = 0; i < HWP_HXS_COUNT; i++) { |
703 | /* enable HXS error reporting into FD[STATUS] PHE */ |
704 | iowrite32be(0x00000000, ®s->pmda[i].ssa); |
705 | iowrite32be(0xffffffff, ®s->pmda[i].lcv); |
706 | } |
707 | |
708 | /* Short packet padding removal from checksum calculation */ |
709 | iowrite32be(HWP_HXS_SH_PAD_REM, ®s->pmda[HWP_HXS_TCP_OFFSET].ssa); |
710 | iowrite32be(HWP_HXS_SH_PAD_REM, ®s->pmda[HWP_HXS_UDP_OFFSET].ssa); |
711 | |
712 | start_port_hwp(port); |
713 | } |
714 | |
715 | static int init(struct fman_port *port) |
716 | { |
717 | int err; |
718 | |
719 | /* Init BMI registers */ |
720 | switch (port->port_type) { |
721 | case FMAN_PORT_TYPE_RX: |
722 | err = init_bmi_rx(port); |
723 | if (!err) |
724 | init_hwp(port); |
725 | break; |
726 | case FMAN_PORT_TYPE_TX: |
727 | err = init_bmi_tx(port); |
728 | break; |
729 | default: |
730 | return -EINVAL; |
731 | } |
732 | |
733 | if (err) |
734 | return err; |
735 | |
736 | /* Init QMI registers */ |
737 | err = init_qmi(port); |
738 | if (err) |
739 | return err; |
740 | |
741 | return 0; |
742 | } |
743 | |
744 | static int set_bpools(const struct fman_port *port, |
745 | const struct fman_port_bpools *bp) |
746 | { |
747 | u32 __iomem *bp_reg, *bp_depl_reg; |
748 | u32 tmp; |
749 | u8 i, max_bp_num; |
750 | bool grp_depl_used = false, rx_port; |
751 | |
752 | switch (port->port_type) { |
753 | case FMAN_PORT_TYPE_RX: |
754 | max_bp_num = port->ext_pools_num; |
755 | rx_port = true; |
756 | bp_reg = port->bmi_regs->rx.fmbm_ebmpi; |
757 | bp_depl_reg = &port->bmi_regs->rx.fmbm_mpd; |
758 | break; |
759 | default: |
760 | return -EINVAL; |
761 | } |
762 | |
763 | if (rx_port) { |
764 | /* Check buffers are provided in ascending order */ |
765 | for (i = 0; (i < (bp->count - 1) && |
766 | (i < FMAN_PORT_MAX_EXT_POOLS_NUM - 1)); i++) { |
767 | if (bp->bpool[i].size > bp->bpool[i + 1].size) |
768 | return -EINVAL; |
769 | } |
770 | } |
771 | |
772 | /* Set up external buffers pools */ |
773 | for (i = 0; i < bp->count; i++) { |
774 | tmp = BMI_EXT_BUF_POOL_VALID; |
775 | tmp |= ((u32)bp->bpool[i].bpid << |
776 | BMI_EXT_BUF_POOL_ID_SHIFT) & BMI_EXT_BUF_POOL_ID_MASK; |
777 | |
778 | if (rx_port) { |
779 | if (bp->counters_enable) |
780 | tmp |= BMI_EXT_BUF_POOL_EN_COUNTER; |
781 | |
782 | if (bp->bpool[i].is_backup) |
783 | tmp |= BMI_EXT_BUF_POOL_BACKUP; |
784 | |
785 | tmp |= (u32)bp->bpool[i].size; |
786 | } |
787 | |
788 | iowrite32be(tmp, &bp_reg[i]); |
789 | } |
790 | |
791 | /* Clear unused pools */ |
792 | for (i = bp->count; i < max_bp_num; i++) |
793 | iowrite32be(0, &bp_reg[i]); |
794 | |
795 | /* Pools depletion */ |
796 | tmp = 0; |
797 | for (i = 0; i < FMAN_PORT_MAX_EXT_POOLS_NUM; i++) { |
798 | if (bp->bpool[i].grp_bp_depleted) { |
799 | grp_depl_used = true; |
800 | tmp |= 0x80000000 >> i; |
801 | } |
802 | |
803 | if (bp->bpool[i].single_bp_depleted) |
804 | tmp |= 0x80 >> i; |
805 | } |
806 | |
807 | if (grp_depl_used) |
808 | tmp |= ((u32)bp->grp_bp_depleted_num - 1) << |
809 | BMI_POOL_DEP_NUM_OF_POOLS_SHIFT; |
810 | |
811 | iowrite32be(tmp, bp_depl_reg); |
812 | return 0; |
813 | } |
814 | |
815 | static bool is_init_done(struct fman_port_cfg *cfg) |
816 | { |
817 | /* Checks if FMan port driver parameters were initialized */ |
818 | if (!cfg) |
819 | return true; |
820 | |
821 | return false; |
822 | } |
823 | |
824 | static int verify_size_of_fifo(struct fman_port *port) |
825 | { |
826 | u32 min_fifo_size_required = 0, opt_fifo_size_for_b2b = 0; |
827 | |
828 | /* TX Ports */ |
829 | if (port->port_type == FMAN_PORT_TYPE_TX) { |
830 | min_fifo_size_required = (u32) |
831 | (roundup(port->max_frame_length, |
832 | FMAN_BMI_FIFO_UNITS) + (3 * FMAN_BMI_FIFO_UNITS)); |
833 | |
834 | min_fifo_size_required += |
835 | port->cfg->tx_fifo_deq_pipeline_depth * |
836 | FMAN_BMI_FIFO_UNITS; |
837 | |
838 | opt_fifo_size_for_b2b = min_fifo_size_required; |
839 | |
840 | /* Add some margin for back-to-back capability to improve |
841 | * performance, allows the hardware to pipeline new frame dma |
842 | * while the previous frame not yet transmitted. |
843 | */ |
844 | if (port->port_speed == 10000) |
845 | opt_fifo_size_for_b2b += 3 * FMAN_BMI_FIFO_UNITS; |
846 | else |
847 | opt_fifo_size_for_b2b += 2 * FMAN_BMI_FIFO_UNITS; |
848 | } |
849 | |
850 | /* RX Ports */ |
851 | else if (port->port_type == FMAN_PORT_TYPE_RX) { |
852 | if (port->rev_info.major >= 6) |
853 | min_fifo_size_required = (u32) |
854 | (roundup(port->max_frame_length, |
855 | FMAN_BMI_FIFO_UNITS) + |
856 | (5 * FMAN_BMI_FIFO_UNITS)); |
857 | /* 4 according to spec + 1 for FOF>0 */ |
858 | else |
859 | min_fifo_size_required = (u32) |
860 | (roundup(min(port->max_frame_length, |
861 | port->rx_pools_params.largest_buf_size), |
862 | FMAN_BMI_FIFO_UNITS) + |
863 | (7 * FMAN_BMI_FIFO_UNITS)); |
864 | |
865 | opt_fifo_size_for_b2b = min_fifo_size_required; |
866 | |
867 | /* Add some margin for back-to-back capability to improve |
868 | * performance,allows the hardware to pipeline new frame dma |
869 | * while the previous frame not yet transmitted. |
870 | */ |
871 | if (port->port_speed == 10000) |
872 | opt_fifo_size_for_b2b += 8 * FMAN_BMI_FIFO_UNITS; |
873 | else |
874 | opt_fifo_size_for_b2b += 3 * FMAN_BMI_FIFO_UNITS; |
875 | } |
876 | |
877 | WARN_ON(min_fifo_size_required <= 0); |
878 | WARN_ON(opt_fifo_size_for_b2b < min_fifo_size_required); |
879 | |
880 | /* Verify the size */ |
881 | if (port->fifo_bufs.num < min_fifo_size_required) |
882 | dev_dbg(port->dev, "%s: FIFO size should be enlarged to %d bytes\n" , |
883 | __func__, min_fifo_size_required); |
884 | else if (port->fifo_bufs.num < opt_fifo_size_for_b2b) |
885 | dev_dbg(port->dev, "%s: For b2b processing,FIFO may be enlarged to %d bytes\n" , |
886 | __func__, opt_fifo_size_for_b2b); |
887 | |
888 | return 0; |
889 | } |
890 | |
891 | static int set_ext_buffer_pools(struct fman_port *port) |
892 | { |
893 | struct fman_ext_pools *ext_buf_pools = &port->cfg->ext_buf_pools; |
894 | struct fman_buf_pool_depletion *buf_pool_depletion = |
895 | &port->cfg->buf_pool_depletion; |
896 | u8 ordered_array[FMAN_PORT_MAX_EXT_POOLS_NUM]; |
897 | u16 sizes_array[BM_MAX_NUM_OF_POOLS]; |
898 | int i = 0, j = 0, err; |
899 | struct fman_port_bpools bpools; |
900 | |
901 | memset(&ordered_array, 0, sizeof(u8) * FMAN_PORT_MAX_EXT_POOLS_NUM); |
902 | memset(&sizes_array, 0, sizeof(u16) * BM_MAX_NUM_OF_POOLS); |
903 | memcpy(&port->ext_buf_pools, ext_buf_pools, |
904 | sizeof(struct fman_ext_pools)); |
905 | |
906 | fman_sp_set_buf_pools_in_asc_order_of_buf_sizes(fm_ext_pools: ext_buf_pools, |
907 | ordered_array, |
908 | sizes_array); |
909 | |
910 | memset(&bpools, 0, sizeof(struct fman_port_bpools)); |
911 | bpools.count = ext_buf_pools->num_of_pools_used; |
912 | bpools.counters_enable = true; |
913 | for (i = 0; i < ext_buf_pools->num_of_pools_used; i++) { |
914 | bpools.bpool[i].bpid = ordered_array[i]; |
915 | bpools.bpool[i].size = sizes_array[ordered_array[i]]; |
916 | } |
917 | |
918 | /* save pools parameters for later use */ |
919 | port->rx_pools_params.num_of_pools = ext_buf_pools->num_of_pools_used; |
920 | port->rx_pools_params.largest_buf_size = |
921 | sizes_array[ordered_array[ext_buf_pools->num_of_pools_used - 1]]; |
922 | |
923 | /* FMBM_RMPD reg. - pool depletion */ |
924 | if (buf_pool_depletion->pools_grp_mode_enable) { |
925 | bpools.grp_bp_depleted_num = buf_pool_depletion->num_of_pools; |
926 | for (i = 0; i < port->bm_max_num_of_pools; i++) { |
927 | if (buf_pool_depletion->pools_to_consider[i]) { |
928 | for (j = 0; j < ext_buf_pools-> |
929 | num_of_pools_used; j++) { |
930 | if (i == ordered_array[j]) { |
931 | bpools.bpool[j]. |
932 | grp_bp_depleted = true; |
933 | break; |
934 | } |
935 | } |
936 | } |
937 | } |
938 | } |
939 | |
940 | if (buf_pool_depletion->single_pool_mode_enable) { |
941 | for (i = 0; i < port->bm_max_num_of_pools; i++) { |
942 | if (buf_pool_depletion-> |
943 | pools_to_consider_for_single_mode[i]) { |
944 | for (j = 0; j < ext_buf_pools-> |
945 | num_of_pools_used; j++) { |
946 | if (i == ordered_array[j]) { |
947 | bpools.bpool[j]. |
948 | single_bp_depleted = true; |
949 | break; |
950 | } |
951 | } |
952 | } |
953 | } |
954 | } |
955 | |
956 | err = set_bpools(port, bp: &bpools); |
957 | if (err != 0) { |
958 | dev_err(port->dev, "%s: set_bpools() failed\n" , __func__); |
959 | return -EINVAL; |
960 | } |
961 | |
962 | return 0; |
963 | } |
964 | |
965 | static int init_low_level_driver(struct fman_port *port) |
966 | { |
967 | struct fman_port_cfg *cfg = port->cfg; |
968 | u32 tmp_val; |
969 | |
970 | switch (port->port_type) { |
971 | case FMAN_PORT_TYPE_RX: |
972 | cfg->err_mask = (RX_ERRS_TO_ENQ & ~cfg->discard_mask); |
973 | break; |
974 | default: |
975 | break; |
976 | } |
977 | |
978 | tmp_val = (u32)((port->internal_buf_offset % OFFSET_UNITS) ? |
979 | (port->internal_buf_offset / OFFSET_UNITS + 1) : |
980 | (port->internal_buf_offset / OFFSET_UNITS)); |
981 | port->internal_buf_offset = (u8)(tmp_val * OFFSET_UNITS); |
982 | port->cfg->int_buf_start_margin = port->internal_buf_offset; |
983 | |
984 | if (init(port) != 0) { |
985 | dev_err(port->dev, "%s: fman port initialization failed\n" , |
986 | __func__); |
987 | return -ENODEV; |
988 | } |
989 | |
990 | /* The code bellow is a trick so the FM will not release the buffer |
991 | * to BM nor will try to enqueue the frame to QM |
992 | */ |
993 | if (port->port_type == FMAN_PORT_TYPE_TX) { |
994 | if (!cfg->dflt_fqid && cfg->dont_release_buf) { |
995 | /* override fmbm_tcfqid 0 with a false non-0 value. |
996 | * This will force FM to act according to tfene. |
997 | * Otherwise, if fmbm_tcfqid is 0 the FM will release |
998 | * buffers to BM regardless of fmbm_tfene |
999 | */ |
1000 | iowrite32be(0xFFFFFF, &port->bmi_regs->tx.fmbm_tcfqid); |
1001 | iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE, |
1002 | &port->bmi_regs->tx.fmbm_tfene); |
1003 | } |
1004 | } |
1005 | |
1006 | return 0; |
1007 | } |
1008 | |
1009 | static int fill_soc_specific_params(struct fman_port *port) |
1010 | { |
1011 | u32 bmi_max_fifo_size; |
1012 | |
1013 | bmi_max_fifo_size = fman_get_bmi_max_fifo_size(fman: port->fm); |
1014 | port->max_port_fifo_size = MAX_PORT_FIFO_SIZE(bmi_max_fifo_size); |
1015 | port->bm_max_num_of_pools = 64; |
1016 | |
1017 | /* P4080 - Major 2 |
1018 | * P2041/P3041/P5020/P5040 - Major 3 |
1019 | * Tx/Bx - Major 6 |
1020 | */ |
1021 | switch (port->rev_info.major) { |
1022 | case 2: |
1023 | case 3: |
1024 | port->max_num_of_ext_pools = 4; |
1025 | port->max_num_of_sub_portals = 12; |
1026 | break; |
1027 | |
1028 | case 6: |
1029 | port->max_num_of_ext_pools = 8; |
1030 | port->max_num_of_sub_portals = 16; |
1031 | break; |
1032 | |
1033 | default: |
1034 | dev_err(port->dev, "%s: Unsupported FMan version\n" , __func__); |
1035 | return -EINVAL; |
1036 | } |
1037 | |
1038 | return 0; |
1039 | } |
1040 | |
1041 | static int get_dflt_fifo_deq_pipeline_depth(u8 major, enum fman_port_type type, |
1042 | u16 speed) |
1043 | { |
1044 | switch (type) { |
1045 | case FMAN_PORT_TYPE_RX: |
1046 | case FMAN_PORT_TYPE_TX: |
1047 | switch (speed) { |
1048 | case 10000: |
1049 | return 4; |
1050 | case 1000: |
1051 | if (major >= 6) |
1052 | return 2; |
1053 | else |
1054 | return 1; |
1055 | default: |
1056 | return 0; |
1057 | } |
1058 | default: |
1059 | return 0; |
1060 | } |
1061 | } |
1062 | |
1063 | static int get_dflt_num_of_tasks(u8 major, enum fman_port_type type, |
1064 | u16 speed) |
1065 | { |
1066 | switch (type) { |
1067 | case FMAN_PORT_TYPE_RX: |
1068 | case FMAN_PORT_TYPE_TX: |
1069 | switch (speed) { |
1070 | case 10000: |
1071 | return 16; |
1072 | case 1000: |
1073 | if (major >= 6) |
1074 | return 4; |
1075 | else |
1076 | return 3; |
1077 | default: |
1078 | return 0; |
1079 | } |
1080 | default: |
1081 | return 0; |
1082 | } |
1083 | } |
1084 | |
1085 | static int (u8 major, enum fman_port_type type, |
1086 | u16 speed) |
1087 | { |
1088 | switch (type) { |
1089 | case FMAN_PORT_TYPE_RX: |
1090 | /* FMan V3 */ |
1091 | if (major >= 6) |
1092 | return 0; |
1093 | |
1094 | /* FMan V2 */ |
1095 | if (speed == 10000) |
1096 | return 8; |
1097 | else |
1098 | return 2; |
1099 | case FMAN_PORT_TYPE_TX: |
1100 | default: |
1101 | return 0; |
1102 | } |
1103 | } |
1104 | |
1105 | static int get_dflt_num_of_open_dmas(u8 major, enum fman_port_type type, |
1106 | u16 speed) |
1107 | { |
1108 | int val; |
1109 | |
1110 | if (major >= 6) { |
1111 | switch (type) { |
1112 | case FMAN_PORT_TYPE_TX: |
1113 | if (speed == 10000) |
1114 | val = 12; |
1115 | else |
1116 | val = 3; |
1117 | break; |
1118 | case FMAN_PORT_TYPE_RX: |
1119 | if (speed == 10000) |
1120 | val = 8; |
1121 | else |
1122 | val = 2; |
1123 | break; |
1124 | default: |
1125 | return 0; |
1126 | } |
1127 | } else { |
1128 | switch (type) { |
1129 | case FMAN_PORT_TYPE_TX: |
1130 | case FMAN_PORT_TYPE_RX: |
1131 | if (speed == 10000) |
1132 | val = 8; |
1133 | else |
1134 | val = 1; |
1135 | break; |
1136 | default: |
1137 | val = 0; |
1138 | } |
1139 | } |
1140 | |
1141 | return val; |
1142 | } |
1143 | |
1144 | static int (u8 major, enum fman_port_type type, |
1145 | u16 speed) |
1146 | { |
1147 | /* FMan V3 */ |
1148 | if (major >= 6) |
1149 | return 0; |
1150 | |
1151 | /* FMan V2 */ |
1152 | switch (type) { |
1153 | case FMAN_PORT_TYPE_RX: |
1154 | case FMAN_PORT_TYPE_TX: |
1155 | if (speed == 10000) |
1156 | return 8; |
1157 | else |
1158 | return 1; |
1159 | default: |
1160 | return 0; |
1161 | } |
1162 | } |
1163 | |
1164 | static int get_dflt_num_of_fifo_bufs(u8 major, enum fman_port_type type, |
1165 | u16 speed) |
1166 | { |
1167 | int val; |
1168 | |
1169 | if (major >= 6) { |
1170 | switch (type) { |
1171 | case FMAN_PORT_TYPE_TX: |
1172 | if (speed == 10000) |
1173 | val = 64; |
1174 | else |
1175 | val = 50; |
1176 | break; |
1177 | case FMAN_PORT_TYPE_RX: |
1178 | if (speed == 10000) |
1179 | val = 96; |
1180 | else |
1181 | val = 50; |
1182 | break; |
1183 | default: |
1184 | val = 0; |
1185 | } |
1186 | } else { |
1187 | switch (type) { |
1188 | case FMAN_PORT_TYPE_TX: |
1189 | if (speed == 10000) |
1190 | val = 48; |
1191 | else |
1192 | val = 44; |
1193 | break; |
1194 | case FMAN_PORT_TYPE_RX: |
1195 | if (speed == 10000) |
1196 | val = 48; |
1197 | else |
1198 | val = 45; |
1199 | break; |
1200 | default: |
1201 | val = 0; |
1202 | } |
1203 | } |
1204 | |
1205 | return val; |
1206 | } |
1207 | |
1208 | static void set_dflt_cfg(struct fman_port *port, |
1209 | struct fman_port_params *port_params) |
1210 | { |
1211 | struct fman_port_cfg *cfg = port->cfg; |
1212 | |
1213 | cfg->dma_swap_data = FMAN_PORT_DMA_NO_SWAP; |
1214 | cfg->color = FMAN_PORT_COLOR_GREEN; |
1215 | cfg->rx_cut_end_bytes = DFLT_PORT_CUT_BYTES_FROM_END; |
1216 | cfg->rx_pri_elevation = BMI_PRIORITY_ELEVATION_LEVEL; |
1217 | cfg->rx_fifo_thr = BMI_FIFO_THRESHOLD; |
1218 | cfg->tx_fifo_low_comf_level = (5 * 1024); |
1219 | cfg->deq_type = FMAN_PORT_DEQ_BY_PRI; |
1220 | cfg->deq_prefetch_option = FMAN_PORT_DEQ_FULL_PREFETCH; |
1221 | cfg->tx_fifo_deq_pipeline_depth = |
1222 | BMI_DEQUEUE_PIPELINE_DEPTH(port->port_type, port->port_speed); |
1223 | cfg->deq_byte_cnt = QMI_BYTE_COUNT_LEVEL_CONTROL(port->port_type); |
1224 | |
1225 | cfg->rx_pri_elevation = |
1226 | DFLT_PORT_RX_FIFO_PRI_ELEVATION_LEV(port->max_port_fifo_size); |
1227 | port->cfg->rx_fifo_thr = |
1228 | DFLT_PORT_RX_FIFO_THRESHOLD(port->rev_info.major, |
1229 | port->max_port_fifo_size); |
1230 | |
1231 | if ((port->rev_info.major == 6) && |
1232 | ((port->rev_info.minor == 0) || (port->rev_info.minor == 3))) |
1233 | cfg->errata_A006320 = true; |
1234 | |
1235 | /* Excessive Threshold register - exists for pre-FMv3 chips only */ |
1236 | if (port->rev_info.major < 6) |
1237 | cfg->excessive_threshold_register = true; |
1238 | else |
1239 | cfg->fmbm_tfne_has_features = true; |
1240 | |
1241 | cfg->buffer_prefix_content.data_align = |
1242 | DFLT_PORT_BUFFER_PREFIX_CONTEXT_DATA_ALIGN; |
1243 | } |
1244 | |
1245 | static void set_rx_dflt_cfg(struct fman_port *port, |
1246 | struct fman_port_params *port_params) |
1247 | { |
1248 | port->cfg->discard_mask = DFLT_PORT_ERRORS_TO_DISCARD; |
1249 | |
1250 | memcpy(&port->cfg->ext_buf_pools, |
1251 | &port_params->specific_params.rx_params.ext_buf_pools, |
1252 | sizeof(struct fman_ext_pools)); |
1253 | port->cfg->err_fqid = |
1254 | port_params->specific_params.rx_params.err_fqid; |
1255 | port->cfg->dflt_fqid = |
1256 | port_params->specific_params.rx_params.dflt_fqid; |
1257 | port->cfg->pcd_base_fqid = |
1258 | port_params->specific_params.rx_params.pcd_base_fqid; |
1259 | port->cfg->pcd_fqs_count = |
1260 | port_params->specific_params.rx_params.pcd_fqs_count; |
1261 | } |
1262 | |
1263 | static void set_tx_dflt_cfg(struct fman_port *port, |
1264 | struct fman_port_params *port_params, |
1265 | struct fman_port_dts_params *dts_params) |
1266 | { |
1267 | port->cfg->tx_fifo_deq_pipeline_depth = |
1268 | get_dflt_fifo_deq_pipeline_depth(major: port->rev_info.major, |
1269 | type: port->port_type, |
1270 | speed: port->port_speed); |
1271 | port->cfg->err_fqid = |
1272 | port_params->specific_params.non_rx_params.err_fqid; |
1273 | port->cfg->deq_sp = |
1274 | (u8)(dts_params->qman_channel_id & QMI_DEQ_CFG_SUBPORTAL_MASK); |
1275 | port->cfg->dflt_fqid = |
1276 | port_params->specific_params.non_rx_params.dflt_fqid; |
1277 | port->cfg->deq_high_priority = true; |
1278 | } |
1279 | |
1280 | /** |
1281 | * fman_port_config |
1282 | * @port: Pointer to the port structure |
1283 | * @params: Pointer to data structure of parameters |
1284 | * |
1285 | * Creates a descriptor for the FM PORT module. |
1286 | * The routine returns a pointer to the FM PORT object. |
1287 | * This descriptor must be passed as first parameter to all other FM PORT |
1288 | * function calls. |
1289 | * No actual initialization or configuration of FM hardware is done by this |
1290 | * routine. |
1291 | * |
1292 | * Return: 0 on success; Error code otherwise. |
1293 | */ |
1294 | int fman_port_config(struct fman_port *port, struct fman_port_params *params) |
1295 | { |
1296 | void __iomem *base_addr = port->dts_params.base_addr; |
1297 | int err; |
1298 | |
1299 | /* Allocate the FM driver's parameters structure */ |
1300 | port->cfg = kzalloc(size: sizeof(*port->cfg), GFP_KERNEL); |
1301 | if (!port->cfg) |
1302 | return -EINVAL; |
1303 | |
1304 | /* Initialize FM port parameters which will be kept by the driver */ |
1305 | port->port_type = port->dts_params.type; |
1306 | port->port_speed = port->dts_params.speed; |
1307 | port->port_id = port->dts_params.id; |
1308 | port->fm = port->dts_params.fman; |
1309 | port->ext_pools_num = (u8)8; |
1310 | |
1311 | /* get FM revision */ |
1312 | fman_get_revision(fman: port->fm, rev_info: &port->rev_info); |
1313 | |
1314 | err = fill_soc_specific_params(port); |
1315 | if (err) |
1316 | goto err_port_cfg; |
1317 | |
1318 | switch (port->port_type) { |
1319 | case FMAN_PORT_TYPE_RX: |
1320 | set_rx_dflt_cfg(port, port_params: params); |
1321 | fallthrough; |
1322 | case FMAN_PORT_TYPE_TX: |
1323 | set_tx_dflt_cfg(port, port_params: params, dts_params: &port->dts_params); |
1324 | fallthrough; |
1325 | default: |
1326 | set_dflt_cfg(port, port_params: params); |
1327 | } |
1328 | |
1329 | /* Continue with other parameters */ |
1330 | /* set memory map pointers */ |
1331 | port->bmi_regs = base_addr + BMI_PORT_REGS_OFFSET; |
1332 | port->qmi_regs = base_addr + QMI_PORT_REGS_OFFSET; |
1333 | port->hwp_regs = base_addr + HWP_PORT_REGS_OFFSET; |
1334 | |
1335 | port->max_frame_length = DFLT_PORT_MAX_FRAME_LENGTH; |
1336 | /* resource distribution. */ |
1337 | |
1338 | port->fifo_bufs.num = |
1339 | get_dflt_num_of_fifo_bufs(major: port->rev_info.major, type: port->port_type, |
1340 | speed: port->port_speed) * FMAN_BMI_FIFO_UNITS; |
1341 | port->fifo_bufs.extra = |
1342 | DFLT_PORT_EXTRA_NUM_OF_FIFO_BUFS * FMAN_BMI_FIFO_UNITS; |
1343 | |
1344 | port->open_dmas.num = |
1345 | get_dflt_num_of_open_dmas(major: port->rev_info.major, |
1346 | type: port->port_type, speed: port->port_speed); |
1347 | port->open_dmas.extra = |
1348 | get_dflt_extra_num_of_open_dmas(major: port->rev_info.major, |
1349 | type: port->port_type, speed: port->port_speed); |
1350 | port->tasks.num = |
1351 | get_dflt_num_of_tasks(major: port->rev_info.major, |
1352 | type: port->port_type, speed: port->port_speed); |
1353 | port->tasks.extra = |
1354 | get_dflt_extra_num_of_tasks(major: port->rev_info.major, |
1355 | type: port->port_type, speed: port->port_speed); |
1356 | |
1357 | /* FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 errata |
1358 | * workaround |
1359 | */ |
1360 | if ((port->rev_info.major == 6) && (port->rev_info.minor == 0) && |
1361 | (((port->port_type == FMAN_PORT_TYPE_TX) && |
1362 | (port->port_speed == 1000)))) { |
1363 | port->open_dmas.num = 16; |
1364 | port->open_dmas.extra = 0; |
1365 | } |
1366 | |
1367 | if (port->rev_info.major >= 6 && |
1368 | port->port_type == FMAN_PORT_TYPE_TX && |
1369 | port->port_speed == 1000) { |
1370 | /* FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 Errata |
1371 | * workaround |
1372 | */ |
1373 | u32 reg; |
1374 | |
1375 | reg = 0x00001013; |
1376 | iowrite32be(reg, &port->bmi_regs->tx.fmbm_tfp); |
1377 | } |
1378 | |
1379 | return 0; |
1380 | |
1381 | err_port_cfg: |
1382 | kfree(objp: port->cfg); |
1383 | return -EINVAL; |
1384 | } |
1385 | EXPORT_SYMBOL(fman_port_config); |
1386 | |
1387 | /* |
1388 | * fman_port_use_kg_hash |
1389 | * @port: A pointer to a FM Port module. |
1390 | * @enable: enable or disable |
1391 | * |
1392 | * Sets the HW KeyGen or the BMI as HW Parser next engine, enabling |
1393 | * or bypassing the KeyGen hashing of Rx traffic |
1394 | */ |
1395 | void fman_port_use_kg_hash(struct fman_port *port, bool enable) |
1396 | { |
1397 | if (enable) |
1398 | /* After the Parser frames go to KeyGen */ |
1399 | iowrite32be(NIA_ENG_HWK, &port->bmi_regs->rx.fmbm_rfpne); |
1400 | else |
1401 | /* After the Parser frames go to BMI */ |
1402 | iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME, |
1403 | &port->bmi_regs->rx.fmbm_rfpne); |
1404 | } |
1405 | EXPORT_SYMBOL(fman_port_use_kg_hash); |
1406 | |
1407 | /** |
1408 | * fman_port_init |
1409 | * @port: A pointer to a FM Port module. |
1410 | * |
1411 | * Initializes the FM PORT module by defining the software structure and |
1412 | * configuring the hardware registers. |
1413 | * |
1414 | * Return: 0 on success; Error code otherwise. |
1415 | */ |
1416 | int fman_port_init(struct fman_port *port) |
1417 | { |
1418 | struct fman_port_init_params params; |
1419 | struct fman_keygen *keygen; |
1420 | struct fman_port_cfg *cfg; |
1421 | int err; |
1422 | |
1423 | if (is_init_done(cfg: port->cfg)) |
1424 | return -EINVAL; |
1425 | |
1426 | err = fman_sp_build_buffer_struct(int_context_data_copy: &port->cfg->int_context, |
1427 | buffer_prefix_content: &port->cfg->buffer_prefix_content, |
1428 | buf_margins: &port->cfg->buf_margins, |
1429 | buffer_offsets: &port->buffer_offsets, |
1430 | internal_buf_offset: &port->internal_buf_offset); |
1431 | if (err) |
1432 | return err; |
1433 | |
1434 | cfg = port->cfg; |
1435 | |
1436 | if (port->port_type == FMAN_PORT_TYPE_RX) { |
1437 | /* Call the external Buffer routine which also checks fifo |
1438 | * size and updates it if necessary |
1439 | */ |
1440 | /* define external buffer pools and pool depletion */ |
1441 | err = set_ext_buffer_pools(port); |
1442 | if (err) |
1443 | return err; |
1444 | /* check if the largest external buffer pool is large enough */ |
1445 | if (cfg->buf_margins.start_margins + MIN_EXT_BUF_SIZE + |
1446 | cfg->buf_margins.end_margins > |
1447 | port->rx_pools_params.largest_buf_size) { |
1448 | dev_err(port->dev, "%s: buf_margins.start_margins (%d) + minimum buf size (64) + buf_margins.end_margins (%d) is larger than maximum external buffer size (%d)\n" , |
1449 | __func__, cfg->buf_margins.start_margins, |
1450 | cfg->buf_margins.end_margins, |
1451 | port->rx_pools_params.largest_buf_size); |
1452 | return -EINVAL; |
1453 | } |
1454 | } |
1455 | |
1456 | /* Call FM module routine for communicating parameters */ |
1457 | memset(¶ms, 0, sizeof(params)); |
1458 | params.port_id = port->port_id; |
1459 | params.port_type = port->port_type; |
1460 | params.port_speed = port->port_speed; |
1461 | params.num_of_tasks = (u8)port->tasks.num; |
1462 | params.num_of_extra_tasks = (u8)port->tasks.extra; |
1463 | params.num_of_open_dmas = (u8)port->open_dmas.num; |
1464 | params.num_of_extra_open_dmas = (u8)port->open_dmas.extra; |
1465 | |
1466 | if (port->fifo_bufs.num) { |
1467 | err = verify_size_of_fifo(port); |
1468 | if (err) |
1469 | return err; |
1470 | } |
1471 | params.size_of_fifo = port->fifo_bufs.num; |
1472 | params.extra_size_of_fifo = port->fifo_bufs.extra; |
1473 | params.deq_pipeline_depth = port->cfg->tx_fifo_deq_pipeline_depth; |
1474 | params.max_frame_length = port->max_frame_length; |
1475 | |
1476 | err = fman_set_port_params(fman: port->fm, port_params: ¶ms); |
1477 | if (err) |
1478 | return err; |
1479 | |
1480 | err = init_low_level_driver(port); |
1481 | if (err) |
1482 | return err; |
1483 | |
1484 | if (port->cfg->pcd_fqs_count) { |
1485 | keygen = port->dts_params.fman->keygen; |
1486 | err = keygen_port_hashing_init(keygen, hw_port_id: port->port_id, |
1487 | hash_base_fqid: port->cfg->pcd_base_fqid, |
1488 | hash_size: port->cfg->pcd_fqs_count); |
1489 | if (err) |
1490 | return err; |
1491 | |
1492 | fman_port_use_kg_hash(port, true); |
1493 | } |
1494 | |
1495 | kfree(objp: port->cfg); |
1496 | port->cfg = NULL; |
1497 | |
1498 | return 0; |
1499 | } |
1500 | EXPORT_SYMBOL(fman_port_init); |
1501 | |
1502 | /** |
1503 | * fman_port_cfg_buf_prefix_content |
1504 | * @port: A pointer to a FM Port module. |
1505 | * @buffer_prefix_content: A structure of parameters describing |
1506 | * the structure of the buffer. |
1507 | * Out parameter: |
1508 | * Start margin - offset of data from |
1509 | * start of external buffer. |
1510 | * Defines the structure, size and content of the application buffer. |
1511 | * The prefix, in Tx ports, if 'pass_prs_result', the application should set |
1512 | * a value to their offsets in the prefix of the FM will save the first |
1513 | * 'priv_data_size', than, depending on 'pass_prs_result' and |
1514 | * 'pass_time_stamp', copy parse result and timeStamp, and the packet itself |
1515 | * (in this order), to the application buffer, and to offset. |
1516 | * Calling this routine changes the buffer margins definitions in the internal |
1517 | * driver data base from its default configuration: |
1518 | * Data size: [DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PRIV_DATA_SIZE] |
1519 | * Pass Parser result: [DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PASS_PRS_RESULT]. |
1520 | * Pass timestamp: [DEFAULT_PORT_BUFFER_PREFIX_CONTENT_PASS_TIME_STAMP]. |
1521 | * May be used for all ports |
1522 | * |
1523 | * Allowed only following fman_port_config() and before fman_port_init(). |
1524 | * |
1525 | * Return: 0 on success; Error code otherwise. |
1526 | */ |
1527 | int fman_port_cfg_buf_prefix_content(struct fman_port *port, |
1528 | struct fman_buffer_prefix_content * |
1529 | buffer_prefix_content) |
1530 | { |
1531 | if (is_init_done(cfg: port->cfg)) |
1532 | return -EINVAL; |
1533 | |
1534 | memcpy(&port->cfg->buffer_prefix_content, |
1535 | buffer_prefix_content, |
1536 | sizeof(struct fman_buffer_prefix_content)); |
1537 | /* if data_align was not initialized by user, |
1538 | * we return to driver's default |
1539 | */ |
1540 | if (!port->cfg->buffer_prefix_content.data_align) |
1541 | port->cfg->buffer_prefix_content.data_align = |
1542 | DFLT_PORT_BUFFER_PREFIX_CONTEXT_DATA_ALIGN; |
1543 | |
1544 | return 0; |
1545 | } |
1546 | EXPORT_SYMBOL(fman_port_cfg_buf_prefix_content); |
1547 | |
1548 | /** |
1549 | * fman_port_disable |
1550 | * @port: A pointer to a FM Port module. |
1551 | * |
1552 | * Gracefully disable an FM port. The port will not start new tasks after all |
1553 | * tasks associated with the port are terminated. |
1554 | * |
1555 | * This is a blocking routine, it returns after port is gracefully stopped, |
1556 | * i.e. the port will not except new frames, but it will finish all frames |
1557 | * or tasks which were already began. |
1558 | * Allowed only following fman_port_init(). |
1559 | * |
1560 | * Return: 0 on success; Error code otherwise. |
1561 | */ |
1562 | int fman_port_disable(struct fman_port *port) |
1563 | { |
1564 | u32 __iomem *bmi_cfg_reg, *bmi_status_reg; |
1565 | u32 tmp; |
1566 | bool rx_port, failure = false; |
1567 | int count; |
1568 | |
1569 | if (!is_init_done(cfg: port->cfg)) |
1570 | return -EINVAL; |
1571 | |
1572 | switch (port->port_type) { |
1573 | case FMAN_PORT_TYPE_RX: |
1574 | bmi_cfg_reg = &port->bmi_regs->rx.fmbm_rcfg; |
1575 | bmi_status_reg = &port->bmi_regs->rx.fmbm_rst; |
1576 | rx_port = true; |
1577 | break; |
1578 | case FMAN_PORT_TYPE_TX: |
1579 | bmi_cfg_reg = &port->bmi_regs->tx.fmbm_tcfg; |
1580 | bmi_status_reg = &port->bmi_regs->tx.fmbm_tst; |
1581 | rx_port = false; |
1582 | break; |
1583 | default: |
1584 | return -EINVAL; |
1585 | } |
1586 | |
1587 | /* Disable QMI */ |
1588 | if (!rx_port) { |
1589 | tmp = ioread32be(&port->qmi_regs->fmqm_pnc) & ~QMI_PORT_CFG_EN; |
1590 | iowrite32be(tmp, &port->qmi_regs->fmqm_pnc); |
1591 | |
1592 | /* Wait for QMI to finish FD handling */ |
1593 | count = 100; |
1594 | do { |
1595 | udelay(10); |
1596 | tmp = ioread32be(&port->qmi_regs->fmqm_pns); |
1597 | } while ((tmp & QMI_PORT_STATUS_DEQ_FD_BSY) && --count); |
1598 | |
1599 | if (count == 0) { |
1600 | /* Timeout */ |
1601 | failure = true; |
1602 | } |
1603 | } |
1604 | |
1605 | /* Disable BMI */ |
1606 | tmp = ioread32be(bmi_cfg_reg) & ~BMI_PORT_CFG_EN; |
1607 | iowrite32be(tmp, bmi_cfg_reg); |
1608 | |
1609 | /* Wait for graceful stop end */ |
1610 | count = 500; |
1611 | do { |
1612 | udelay(10); |
1613 | tmp = ioread32be(bmi_status_reg); |
1614 | } while ((tmp & BMI_PORT_STATUS_BSY) && --count); |
1615 | |
1616 | if (count == 0) { |
1617 | /* Timeout */ |
1618 | failure = true; |
1619 | } |
1620 | |
1621 | if (failure) |
1622 | dev_dbg(port->dev, "%s: FMan Port[%d]: BMI or QMI is Busy. Port forced down\n" , |
1623 | __func__, port->port_id); |
1624 | |
1625 | return 0; |
1626 | } |
1627 | EXPORT_SYMBOL(fman_port_disable); |
1628 | |
1629 | /** |
1630 | * fman_port_enable |
1631 | * @port: A pointer to a FM Port module. |
1632 | * |
1633 | * A runtime routine provided to allow disable/enable of port. |
1634 | * |
1635 | * Allowed only following fman_port_init(). |
1636 | * |
1637 | * Return: 0 on success; Error code otherwise. |
1638 | */ |
1639 | int fman_port_enable(struct fman_port *port) |
1640 | { |
1641 | u32 __iomem *bmi_cfg_reg; |
1642 | u32 tmp; |
1643 | bool rx_port; |
1644 | |
1645 | if (!is_init_done(cfg: port->cfg)) |
1646 | return -EINVAL; |
1647 | |
1648 | switch (port->port_type) { |
1649 | case FMAN_PORT_TYPE_RX: |
1650 | bmi_cfg_reg = &port->bmi_regs->rx.fmbm_rcfg; |
1651 | rx_port = true; |
1652 | break; |
1653 | case FMAN_PORT_TYPE_TX: |
1654 | bmi_cfg_reg = &port->bmi_regs->tx.fmbm_tcfg; |
1655 | rx_port = false; |
1656 | break; |
1657 | default: |
1658 | return -EINVAL; |
1659 | } |
1660 | |
1661 | /* Enable QMI */ |
1662 | if (!rx_port) { |
1663 | tmp = ioread32be(&port->qmi_regs->fmqm_pnc) | QMI_PORT_CFG_EN; |
1664 | iowrite32be(tmp, &port->qmi_regs->fmqm_pnc); |
1665 | } |
1666 | |
1667 | /* Enable BMI */ |
1668 | tmp = ioread32be(bmi_cfg_reg) | BMI_PORT_CFG_EN; |
1669 | iowrite32be(tmp, bmi_cfg_reg); |
1670 | |
1671 | return 0; |
1672 | } |
1673 | EXPORT_SYMBOL(fman_port_enable); |
1674 | |
1675 | /** |
1676 | * fman_port_bind |
1677 | * @dev: FMan Port OF device pointer |
1678 | * |
1679 | * Bind to a specific FMan Port. |
1680 | * |
1681 | * Allowed only after the port was created. |
1682 | * |
1683 | * Return: A pointer to the FMan port device. |
1684 | */ |
1685 | struct fman_port *fman_port_bind(struct device *dev) |
1686 | { |
1687 | return (struct fman_port *)(dev_get_drvdata(dev: get_device(dev))); |
1688 | } |
1689 | EXPORT_SYMBOL(fman_port_bind); |
1690 | |
1691 | /** |
1692 | * fman_port_get_qman_channel_id |
1693 | * @port: Pointer to the FMan port devuce |
1694 | * |
1695 | * Get the QMan channel ID for the specific port |
1696 | * |
1697 | * Return: QMan channel ID |
1698 | */ |
1699 | u32 fman_port_get_qman_channel_id(struct fman_port *port) |
1700 | { |
1701 | return port->dts_params.qman_channel_id; |
1702 | } |
1703 | EXPORT_SYMBOL(fman_port_get_qman_channel_id); |
1704 | |
1705 | /** |
1706 | * fman_port_get_device |
1707 | * @port: Pointer to the FMan port device |
1708 | * |
1709 | * Get the 'struct device' associated to the specified FMan port device |
1710 | * |
1711 | * Return: pointer to associated 'struct device' |
1712 | */ |
1713 | struct device *fman_port_get_device(struct fman_port *port) |
1714 | { |
1715 | return port->dev; |
1716 | } |
1717 | EXPORT_SYMBOL(fman_port_get_device); |
1718 | |
1719 | int fman_port_get_hash_result_offset(struct fman_port *port, u32 *offset) |
1720 | { |
1721 | if (port->buffer_offsets.hash_result_offset == ILLEGAL_BASE) |
1722 | return -EINVAL; |
1723 | |
1724 | *offset = port->buffer_offsets.hash_result_offset; |
1725 | |
1726 | return 0; |
1727 | } |
1728 | EXPORT_SYMBOL(fman_port_get_hash_result_offset); |
1729 | |
1730 | int fman_port_get_tstamp(struct fman_port *port, const void *data, u64 *tstamp) |
1731 | { |
1732 | if (port->buffer_offsets.time_stamp_offset == ILLEGAL_BASE) |
1733 | return -EINVAL; |
1734 | |
1735 | *tstamp = be64_to_cpu(*(__be64 *)(data + |
1736 | port->buffer_offsets.time_stamp_offset)); |
1737 | |
1738 | return 0; |
1739 | } |
1740 | EXPORT_SYMBOL(fman_port_get_tstamp); |
1741 | |
1742 | static int fman_port_probe(struct platform_device *of_dev) |
1743 | { |
1744 | struct fman_port *port; |
1745 | struct fman *fman; |
1746 | struct device_node *fm_node, *port_node; |
1747 | struct platform_device *fm_pdev; |
1748 | struct resource res; |
1749 | struct resource *dev_res; |
1750 | u32 val; |
1751 | int err = 0, lenp; |
1752 | enum fman_port_type port_type; |
1753 | u16 port_speed; |
1754 | u8 port_id; |
1755 | |
1756 | port = kzalloc(size: sizeof(*port), GFP_KERNEL); |
1757 | if (!port) |
1758 | return -ENOMEM; |
1759 | |
1760 | port->dev = &of_dev->dev; |
1761 | |
1762 | port_node = of_node_get(node: of_dev->dev.of_node); |
1763 | |
1764 | /* Get the FM node */ |
1765 | fm_node = of_get_parent(node: port_node); |
1766 | if (!fm_node) { |
1767 | dev_err(port->dev, "%s: of_get_parent() failed\n" , __func__); |
1768 | err = -ENODEV; |
1769 | goto return_err; |
1770 | } |
1771 | |
1772 | fm_pdev = of_find_device_by_node(np: fm_node); |
1773 | of_node_put(node: fm_node); |
1774 | if (!fm_pdev) { |
1775 | err = -EINVAL; |
1776 | goto return_err; |
1777 | } |
1778 | |
1779 | fman = dev_get_drvdata(dev: &fm_pdev->dev); |
1780 | if (!fman) { |
1781 | err = -EINVAL; |
1782 | goto put_device; |
1783 | } |
1784 | |
1785 | err = of_property_read_u32(np: port_node, propname: "cell-index" , out_value: &val); |
1786 | if (err) { |
1787 | dev_err(port->dev, "%s: reading cell-index for %pOF failed\n" , |
1788 | __func__, port_node); |
1789 | err = -EINVAL; |
1790 | goto put_device; |
1791 | } |
1792 | port_id = (u8)val; |
1793 | port->dts_params.id = port_id; |
1794 | |
1795 | if (of_device_is_compatible(device: port_node, "fsl,fman-v3-port-tx" )) { |
1796 | port_type = FMAN_PORT_TYPE_TX; |
1797 | port_speed = 1000; |
1798 | if (of_find_property(np: port_node, name: "fsl,fman-10g-port" , lenp: &lenp)) |
1799 | port_speed = 10000; |
1800 | |
1801 | } else if (of_device_is_compatible(device: port_node, "fsl,fman-v2-port-tx" )) { |
1802 | if (port_id >= TX_10G_PORT_BASE) |
1803 | port_speed = 10000; |
1804 | else |
1805 | port_speed = 1000; |
1806 | port_type = FMAN_PORT_TYPE_TX; |
1807 | |
1808 | } else if (of_device_is_compatible(device: port_node, "fsl,fman-v3-port-rx" )) { |
1809 | port_type = FMAN_PORT_TYPE_RX; |
1810 | port_speed = 1000; |
1811 | if (of_find_property(np: port_node, name: "fsl,fman-10g-port" , lenp: &lenp)) |
1812 | port_speed = 10000; |
1813 | |
1814 | } else if (of_device_is_compatible(device: port_node, "fsl,fman-v2-port-rx" )) { |
1815 | if (port_id >= RX_10G_PORT_BASE) |
1816 | port_speed = 10000; |
1817 | else |
1818 | port_speed = 1000; |
1819 | port_type = FMAN_PORT_TYPE_RX; |
1820 | |
1821 | } else { |
1822 | dev_err(port->dev, "%s: Illegal port type\n" , __func__); |
1823 | err = -EINVAL; |
1824 | goto put_device; |
1825 | } |
1826 | |
1827 | port->dts_params.type = port_type; |
1828 | port->dts_params.speed = port_speed; |
1829 | |
1830 | if (port_type == FMAN_PORT_TYPE_TX) { |
1831 | u32 qman_channel_id; |
1832 | |
1833 | qman_channel_id = fman_get_qman_channel_id(fman, port_id); |
1834 | if (qman_channel_id == 0) { |
1835 | dev_err(port->dev, "%s: incorrect qman-channel-id\n" , |
1836 | __func__); |
1837 | err = -EINVAL; |
1838 | goto put_device; |
1839 | } |
1840 | port->dts_params.qman_channel_id = qman_channel_id; |
1841 | } |
1842 | |
1843 | err = of_address_to_resource(dev: port_node, index: 0, r: &res); |
1844 | if (err < 0) { |
1845 | dev_err(port->dev, "%s: of_address_to_resource() failed\n" , |
1846 | __func__); |
1847 | err = -ENOMEM; |
1848 | goto put_device; |
1849 | } |
1850 | |
1851 | port->dts_params.fman = fman; |
1852 | |
1853 | of_node_put(node: port_node); |
1854 | |
1855 | dev_res = __devm_request_region(dev: port->dev, parent: &res, start: res.start, |
1856 | n: resource_size(res: &res), name: "fman-port" ); |
1857 | if (!dev_res) { |
1858 | dev_err(port->dev, "%s: __devm_request_region() failed\n" , |
1859 | __func__); |
1860 | err = -EINVAL; |
1861 | goto free_port; |
1862 | } |
1863 | |
1864 | port->dts_params.base_addr = devm_ioremap(dev: port->dev, offset: res.start, |
1865 | size: resource_size(res: &res)); |
1866 | if (!port->dts_params.base_addr) |
1867 | dev_err(port->dev, "%s: devm_ioremap() failed\n" , __func__); |
1868 | |
1869 | dev_set_drvdata(dev: &of_dev->dev, data: port); |
1870 | |
1871 | return 0; |
1872 | |
1873 | put_device: |
1874 | put_device(dev: &fm_pdev->dev); |
1875 | return_err: |
1876 | of_node_put(node: port_node); |
1877 | free_port: |
1878 | kfree(objp: port); |
1879 | return err; |
1880 | } |
1881 | |
1882 | static const struct of_device_id fman_port_match[] = { |
1883 | {.compatible = "fsl,fman-v3-port-rx" }, |
1884 | {.compatible = "fsl,fman-v2-port-rx" }, |
1885 | {.compatible = "fsl,fman-v3-port-tx" }, |
1886 | {.compatible = "fsl,fman-v2-port-tx" }, |
1887 | {} |
1888 | }; |
1889 | |
1890 | MODULE_DEVICE_TABLE(of, fman_port_match); |
1891 | |
1892 | static struct platform_driver fman_port_driver = { |
1893 | .driver = { |
1894 | .name = "fsl-fman-port" , |
1895 | .of_match_table = fman_port_match, |
1896 | }, |
1897 | .probe = fman_port_probe, |
1898 | }; |
1899 | |
1900 | static int __init fman_port_load(void) |
1901 | { |
1902 | int err; |
1903 | |
1904 | pr_debug("FSL DPAA FMan driver\n" ); |
1905 | |
1906 | err = platform_driver_register(&fman_port_driver); |
1907 | if (err < 0) |
1908 | pr_err("Error, platform_driver_register() = %d\n" , err); |
1909 | |
1910 | return err; |
1911 | } |
1912 | module_init(fman_port_load); |
1913 | |
1914 | static void __exit fman_port_unload(void) |
1915 | { |
1916 | platform_driver_unregister(&fman_port_driver); |
1917 | } |
1918 | module_exit(fman_port_unload); |
1919 | |
1920 | MODULE_LICENSE("Dual BSD/GPL" ); |
1921 | MODULE_DESCRIPTION("Freescale DPAA Frame Manager Port driver" ); |
1922 | |