1 // SPDX-License-Identifier: GPL-2.0+
2 /* Microchip Sparx5 Switch driver
4 * Copyright (c) 2023 Microchip Technology Inc. and its subsidiaries.
7 #include "sparx5_main_regs.h"
8 #include "sparx5_main.h"
10 #define SPX5_PSFP_SF_CNT 1024
11 #define SPX5_PSFP_SG_CONFIG_CHANGE_SLEEP 1000
12 #define SPX5_PSFP_SG_CONFIG_CHANGE_TIMEO 100000
14 /* Pool of available service policers */
15 static struct sparx5_pool_entry sparx5_psfp_fm_pool
[SPX5_SDLB_CNT
];
17 /* Pool of available stream gates */
18 static struct sparx5_pool_entry sparx5_psfp_sg_pool
[SPX5_PSFP_SG_CNT
];
20 /* Pool of available stream filters */
21 static struct sparx5_pool_entry sparx5_psfp_sf_pool
[SPX5_PSFP_SF_CNT
];
23 static int sparx5_psfp_sf_get(struct sparx5
*sparx5
, u32
*id
)
25 return sparx5_pool_get(sparx5_psfp_sf_pool
,
26 sparx5
->data
->consts
->n_filters
, id
);
29 static int sparx5_psfp_sf_put(struct sparx5
*sparx5
, u32 id
)
31 return sparx5_pool_put(sparx5_psfp_sf_pool
,
32 sparx5
->data
->consts
->n_filters
, id
);
35 static int sparx5_psfp_sg_get(struct sparx5
*sparx5
, u32 idx
, u32
*id
)
37 return sparx5_pool_get_with_idx(sparx5_psfp_sg_pool
,
38 sparx5
->data
->consts
->n_gates
, idx
, id
);
41 static int sparx5_psfp_sg_put(struct sparx5
*sparx5
, u32 id
)
43 return sparx5_pool_put(sparx5_psfp_sg_pool
,
44 sparx5
->data
->consts
->n_gates
, id
);
47 static int sparx5_psfp_fm_get(struct sparx5
*sparx5
, u32 idx
, u32
*id
)
49 return sparx5_pool_get_with_idx(sparx5_psfp_fm_pool
,
50 sparx5
->data
->consts
->n_sdlbs
, idx
, id
);
53 static int sparx5_psfp_fm_put(struct sparx5
*sparx5
, u32 id
)
55 return sparx5_pool_put(sparx5_psfp_fm_pool
,
56 sparx5
->data
->consts
->n_sdlbs
, id
);
59 u32
sparx5_psfp_isdx_get_sf(struct sparx5
*sparx5
, u32 isdx
)
61 return ANA_L2_TSN_CFG_TSN_SFID_GET(spx5_rd(sparx5
,
62 ANA_L2_TSN_CFG(isdx
)));
65 u32
sparx5_psfp_isdx_get_fm(struct sparx5
*sparx5
, u32 isdx
)
67 return ANA_L2_DLB_CFG_DLB_IDX_GET(spx5_rd(sparx5
,
68 ANA_L2_DLB_CFG(isdx
)));
71 u32
sparx5_psfp_sf_get_sg(struct sparx5
*sparx5
, u32 sfid
)
73 return ANA_AC_TSN_SF_CFG_TSN_SGID_GET(spx5_rd(sparx5
,
74 ANA_AC_TSN_SF_CFG(sfid
)));
77 void sparx5_isdx_conf_set(struct sparx5
*sparx5
, u32 isdx
, u32 sfid
, u32 fmid
)
79 spx5_rmw(ANA_L2_TSN_CFG_TSN_SFID_SET(sfid
), ANA_L2_TSN_CFG_TSN_SFID
,
80 sparx5
, ANA_L2_TSN_CFG(isdx
));
82 spx5_rmw(ANA_L2_DLB_CFG_DLB_IDX_SET(fmid
), ANA_L2_DLB_CFG_DLB_IDX
,
83 sparx5
, ANA_L2_DLB_CFG(isdx
));
86 /* Internal priority value to internal priority selector */
87 static u32
sparx5_psfp_ipv_to_ips(s32 ipv
)
89 return ipv
> 0 ? (ipv
| BIT(3)) : 0;
92 static int sparx5_psfp_sgid_get_status(struct sparx5
*sparx5
)
94 return spx5_rd(sparx5
, ANA_AC_SG_ACCESS_CTRL
);
97 static int sparx5_psfp_sgid_wait_for_completion(struct sparx5
*sparx5
)
101 return readx_poll_timeout(sparx5_psfp_sgid_get_status
, sparx5
, val
,
102 !ANA_AC_SG_ACCESS_CTRL_CONFIG_CHANGE_GET(val
),
103 SPX5_PSFP_SG_CONFIG_CHANGE_SLEEP
,
104 SPX5_PSFP_SG_CONFIG_CHANGE_TIMEO
);
107 static void sparx5_psfp_sg_config_change(struct sparx5
*sparx5
, u32 id
)
109 spx5_wr(ANA_AC_SG_ACCESS_CTRL_SGID_SET(id
), sparx5
,
110 ANA_AC_SG_ACCESS_CTRL
);
112 spx5_wr(ANA_AC_SG_ACCESS_CTRL_CONFIG_CHANGE_SET(1) |
113 ANA_AC_SG_ACCESS_CTRL_SGID_SET(id
),
114 sparx5
, ANA_AC_SG_ACCESS_CTRL
);
116 if (sparx5_psfp_sgid_wait_for_completion(sparx5
) < 0)
117 pr_debug("%s:%d timed out waiting for sgid completion",
121 static void sparx5_psfp_sf_set(struct sparx5
*sparx5
, u32 id
,
122 const struct sparx5_psfp_sf
*sf
)
124 /* Configure stream gate*/
125 spx5_rmw(ANA_AC_TSN_SF_CFG_TSN_SGID_SET(sf
->sgid
) |
126 ANA_AC_TSN_SF_CFG_TSN_MAX_SDU_SET(sf
->max_sdu
) |
127 ANA_AC_TSN_SF_CFG_BLOCK_OVERSIZE_STATE_SET(sf
->sblock_osize
) |
128 ANA_AC_TSN_SF_CFG_BLOCK_OVERSIZE_ENA_SET(sf
->sblock_osize_ena
),
129 ANA_AC_TSN_SF_CFG_TSN_SGID
| ANA_AC_TSN_SF_CFG_TSN_MAX_SDU
|
130 ANA_AC_TSN_SF_CFG_BLOCK_OVERSIZE_STATE
|
131 ANA_AC_TSN_SF_CFG_BLOCK_OVERSIZE_ENA
,
132 sparx5
, ANA_AC_TSN_SF_CFG(id
));
135 static int sparx5_psfp_sg_set(struct sparx5
*sparx5
, u32 id
,
136 const struct sparx5_psfp_sg
*sg
)
138 u32 ips
, base_lsb
, base_msb
, accum_time_interval
= 0;
139 const struct sparx5_psfp_gce
*gce
;
142 ips
= sparx5_psfp_ipv_to_ips(sg
->ipv
);
143 base_lsb
= sg
->basetime
.tv_sec
& 0xffffffff;
144 base_msb
= sg
->basetime
.tv_sec
>> 32;
146 /* Set stream gate id */
147 spx5_wr(ANA_AC_SG_ACCESS_CTRL_SGID_SET(id
), sparx5
,
148 ANA_AC_SG_ACCESS_CTRL
);
150 /* Write AdminPSFP values */
151 spx5_wr(sg
->basetime
.tv_nsec
, sparx5
, ANA_AC_SG_CONFIG_REG_1
);
152 spx5_wr(base_lsb
, sparx5
, ANA_AC_SG_CONFIG_REG_2
);
154 spx5_rmw(ANA_AC_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB_SET(base_msb
) |
155 ANA_AC_SG_CONFIG_REG_3_INIT_IPS_SET(ips
) |
156 ANA_AC_SG_CONFIG_REG_3_LIST_LENGTH_SET(sg
->num_entries
) |
157 ANA_AC_SG_CONFIG_REG_3_INIT_GATE_STATE_SET(sg
->gate_state
) |
158 ANA_AC_SG_CONFIG_REG_3_GATE_ENABLE_SET(1),
159 ANA_AC_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB
|
160 ANA_AC_SG_CONFIG_REG_3_INIT_IPS
|
161 ANA_AC_SG_CONFIG_REG_3_LIST_LENGTH
|
162 ANA_AC_SG_CONFIG_REG_3_INIT_GATE_STATE
|
163 ANA_AC_SG_CONFIG_REG_3_GATE_ENABLE
,
164 sparx5
, ANA_AC_SG_CONFIG_REG_3
);
166 spx5_wr(sg
->cycletime
, sparx5
, ANA_AC_SG_CONFIG_REG_4
);
167 spx5_wr(sg
->cycletimeext
, sparx5
, ANA_AC_SG_CONFIG_REG_5
);
169 /* For each scheduling entry */
170 for (i
= 0; i
< sg
->num_entries
; i
++) {
172 ips
= sparx5_psfp_ipv_to_ips(gce
->ipv
);
173 /* hardware needs TimeInterval to be cumulative */
174 accum_time_interval
+= gce
->interval
;
176 spx5_wr(ANA_AC_SG_GCL_GS_CONFIG_IPS_SET(ips
) |
177 ANA_AC_SG_GCL_GS_CONFIG_GATE_STATE_SET(gce
->gate_state
),
178 sparx5
, ANA_AC_SG_GCL_GS_CONFIG(i
));
180 /* Set time interval */
181 spx5_wr(accum_time_interval
, sparx5
,
182 ANA_AC_SG_GCL_TI_CONFIG(i
));
184 /* Set maximum octets */
185 spx5_wr(gce
->maxoctets
, sparx5
, ANA_AC_SG_GCL_OCT_CONFIG(i
));
191 static int sparx5_sdlb_conf_set(struct sparx5
*sparx5
,
192 struct sparx5_psfp_fm
*fm
)
194 int (*sparx5_sdlb_group_action
)(struct sparx5
*sparx5
, u32 group
,
197 if (!fm
->pol
.rate
&& !fm
->pol
.burst
)
198 sparx5_sdlb_group_action
= &sparx5_sdlb_group_del
;
200 sparx5_sdlb_group_action
= &sparx5_sdlb_group_add
;
202 sparx5_policer_conf_set(sparx5
, &fm
->pol
);
204 return sparx5_sdlb_group_action(sparx5
, fm
->pol
.group
, fm
->pol
.idx
);
207 int sparx5_psfp_sf_add(struct sparx5
*sparx5
, const struct sparx5_psfp_sf
*sf
,
212 ret
= sparx5_psfp_sf_get(sparx5
, id
);
216 sparx5_psfp_sf_set(sparx5
, *id
, sf
);
221 int sparx5_psfp_sf_del(struct sparx5
*sparx5
, u32 id
)
223 const struct sparx5_psfp_sf sf
= { 0 };
225 sparx5_psfp_sf_set(sparx5
, id
, &sf
);
227 return sparx5_psfp_sf_put(sparx5
, id
);
230 int sparx5_psfp_sg_add(struct sparx5
*sparx5
, u32 uidx
,
231 struct sparx5_psfp_sg
*sg
, u32
*id
)
236 ret
= sparx5_psfp_sg_get(sparx5
, uidx
, id
);
239 /* Was already in use, no need to reconfigure */
243 /* Calculate basetime for this stream gate */
244 sparx5_new_base_time(sparx5
, sg
->cycletime
, 0, &basetime
);
245 sg
->basetime
= ktime_to_timespec64(basetime
);
247 sparx5_psfp_sg_set(sparx5
, *id
, sg
);
249 /* Signal hardware to copy AdminPSFP values into OperPSFP values */
250 sparx5_psfp_sg_config_change(sparx5
, *id
);
255 int sparx5_psfp_sg_del(struct sparx5
*sparx5
, u32 id
)
257 const struct sparx5_psfp_sg sg
= { 0 };
260 ret
= sparx5_psfp_sg_put(sparx5
, id
);
263 /* Stream gate still in use ? */
267 return sparx5_psfp_sg_set(sparx5
, id
, &sg
);
270 int sparx5_psfp_fm_add(struct sparx5
*sparx5
, u32 uidx
,
271 struct sparx5_psfp_fm
*fm
, u32
*id
)
273 struct sparx5_policer
*pol
= &fm
->pol
;
277 ret
= sparx5_psfp_fm_get(sparx5
, uidx
, &fm
->pol
.idx
);
280 /* Was already in use, no need to reconfigure */
284 ret
= sparx5_sdlb_group_get_by_rate(sparx5
, pol
->rate
, pol
->burst
);
290 ret
= sparx5_sdlb_conf_set(sparx5
, fm
);
299 int sparx5_psfp_fm_del(struct sparx5
*sparx5
, u32 id
)
301 struct sparx5_psfp_fm fm
= { .pol
.idx
= id
,
302 .pol
.type
= SPX5_POL_SERVICE
};
305 /* Find the group that this lb belongs to */
306 ret
= sparx5_sdlb_group_get_by_index(sparx5
, id
, &fm
.pol
.group
);
310 ret
= sparx5_psfp_fm_put(sparx5
, id
);
313 /* Do not reset flow-meter if still in use. */
317 return sparx5_sdlb_conf_set(sparx5
, &fm
);
320 void sparx5_psfp_init(struct sparx5
*sparx5
)
322 const struct sparx5_ops
*ops
= sparx5
->data
->ops
;
323 const struct sparx5_sdlb_group
*group
;
326 for (i
= 0; i
< sparx5
->data
->consts
->n_lb_groups
; i
++) {
327 group
= ops
->get_sdlb_group(i
);
328 sparx5_sdlb_group_init(sparx5
, group
->max_rate
,
329 group
->min_burst
, group
->frame_size
, i
);
332 spx5_wr(ANA_AC_SG_CYCLETIME_UPDATE_PERIOD_SG_CT_UPDATE_ENA_SET(1),
333 sparx5
, ANA_AC_SG_CYCLETIME_UPDATE_PERIOD
);
335 spx5_rmw(ANA_L2_FWD_CFG_ISDX_LOOKUP_ENA_SET(1),
336 ANA_L2_FWD_CFG_ISDX_LOOKUP_ENA
, sparx5
, ANA_L2_FWD_CFG
);