1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Microsemi Ocelot Switch driver
4 * Copyright (c) 2019 Microsemi Corporation
7 #include <soc/mscc/ocelot.h>
8 #include "ocelot_police.h"
10 /* Types for ANA:POL[0-192]:POL_MODE_CFG.FRM_MODE */
11 #define POL_MODE_LINERATE 0 /* Incl IPG. Unit: 33 1/3 kbps, 4096 bytes */
12 #define POL_MODE_DATARATE 1 /* Excl IPG. Unit: 33 1/3 kbps, 4096 bytes */
13 #define POL_MODE_FRMRATE_HI 2 /* Unit: 33 1/3 fps, 32.8 frames */
14 #define POL_MODE_FRMRATE_LO 3 /* Unit: 1/3 fps, 0.3 frames */
17 #define POL_IX_PORT 0 /* 0-11 : Port policers */
18 #define POL_IX_QUEUE 32 /* 32-127 : Queue policers */
20 /* Default policer order */
21 #define POL_ORDER 0x1d3 /* Ocelot policer order: Serial (QoS -> Port -> VCAP) */
23 int qos_policer_conf_set(struct ocelot
*ocelot
, int port
, u32 pol_ix
,
24 struct qos_policer_conf
*conf
)
26 u32 cf
= 0, cir_ena
= 0, frm_mode
= POL_MODE_LINERATE
;
27 u32 cir
= 0, cbs
= 0, pir
= 0, pbs
= 0;
28 bool cir_discard
= 0, pir_discard
= 0;
29 u32 pbs_max
= 0, cbs_max
= 0;
37 case MSCC_QOS_RATE_MODE_LINE
:
38 case MSCC_QOS_RATE_MODE_DATA
:
39 if (conf
->mode
== MSCC_QOS_RATE_MODE_LINE
) {
40 frm_mode
= POL_MODE_LINERATE
;
41 ipg
= min_t(u8
, GENMASK(4, 0), conf
->ipg
);
43 frm_mode
= POL_MODE_DATARATE
;
49 if (cir
== 0 && cbs
== 0) {
50 /* Discard cir frames */
53 cir
= DIV_ROUND_UP(cir
, 100);
54 cir
*= 3; /* 33 1/3 kbps */
55 cbs
= DIV_ROUND_UP(cbs
, 4096);
56 cbs
= (cbs
? cbs
: 1); /* No zero burst size */
57 cbs_max
= 60; /* Limit burst size */
63 if (pir
== 0 && pbs
== 0) {
64 /* Discard PIR frames */
67 pir
= DIV_ROUND_UP(pir
, 100);
68 pir
*= 3; /* 33 1/3 kbps */
69 pbs
= DIV_ROUND_UP(pbs
, 4096);
70 pbs
= (pbs
? pbs
: 1); /* No zero burst size */
71 pbs_max
= 60; /* Limit burst size */
74 case MSCC_QOS_RATE_MODE_FRAME
:
76 frm_mode
= POL_MODE_FRMRATE_HI
;
77 pir
= DIV_ROUND_UP(pir
, 100);
78 pir
*= 3; /* 33 1/3 fps */
79 pbs
= (pbs
* 10) / 328; /* 32.8 frames */
80 pbs
= (pbs
? pbs
: 1); /* No zero burst size */
81 pbs_max
= GENMASK(6, 0); /* Limit burst size */
83 frm_mode
= POL_MODE_FRMRATE_LO
;
84 if (pir
== 0 && pbs
== 0) {
85 /* Discard all frames */
89 pir
*= 3; /* 1/3 fps */
90 pbs
= (pbs
* 10) / 3; /* 0.3 frames */
91 pbs
= (pbs
? pbs
: 1); /* No zero burst size */
92 pbs_max
= 61; /* Limit burst size */
96 default: /* MSCC_QOS_RATE_MODE_DISABLED */
97 /* Disable policer using maximum rate and zero burst */
104 if (pir
> GENMASK(15, 0)) {
105 dev_err(ocelot
->dev
, "Invalid pir for port %d: %u (max %lu)\n",
106 port
, pir
, GENMASK(15, 0));
110 if (cir
> GENMASK(15, 0)) {
111 dev_err(ocelot
->dev
, "Invalid cir for port %d: %u (max %lu)\n",
112 port
, cir
, GENMASK(15, 0));
117 dev_err(ocelot
->dev
, "Invalid pbs for port %d: %u (max %u)\n",
123 dev_err(ocelot
->dev
, "Invalid cbs for port %d: %u (max %u)\n",
128 value
= (ANA_POL_MODE_CFG_IPG_SIZE(ipg
) |
129 ANA_POL_MODE_CFG_FRM_MODE(frm_mode
) |
130 (cf
? ANA_POL_MODE_CFG_DLB_COUPLED
: 0) |
131 (cir_ena
? ANA_POL_MODE_CFG_CIR_ENA
: 0) |
132 ANA_POL_MODE_CFG_OVERSHOOT_ENA
);
134 ocelot_write_gix(ocelot
, value
, ANA_POL_MODE_CFG
, pol_ix
);
136 ocelot_write_gix(ocelot
,
137 ANA_POL_PIR_CFG_PIR_RATE(pir
) |
138 ANA_POL_PIR_CFG_PIR_BURST(pbs
),
139 ANA_POL_PIR_CFG
, pol_ix
);
141 ocelot_write_gix(ocelot
,
142 (pir_discard
? GENMASK(22, 0) : 0),
143 ANA_POL_PIR_STATE
, pol_ix
);
145 ocelot_write_gix(ocelot
,
146 ANA_POL_CIR_CFG_CIR_RATE(cir
) |
147 ANA_POL_CIR_CFG_CIR_BURST(cbs
),
148 ANA_POL_CIR_CFG
, pol_ix
);
150 ocelot_write_gix(ocelot
,
151 (cir_discard
? GENMASK(22, 0) : 0),
152 ANA_POL_CIR_STATE
, pol_ix
);
157 int ocelot_port_policer_add(struct ocelot
*ocelot
, int port
,
158 struct ocelot_policer
*pol
)
160 struct qos_policer_conf pp
= { 0 };
166 pp
.mode
= MSCC_QOS_RATE_MODE_DATA
;
170 dev_dbg(ocelot
->dev
, "%s: port %u pir %u kbps, pbs %u bytes\n",
171 __func__
, port
, pp
.pir
, pp
.pbs
);
173 err
= qos_policer_conf_set(ocelot
, port
, POL_IX_PORT
+ port
, &pp
);
177 ocelot_rmw_gix(ocelot
,
178 ANA_PORT_POL_CFG_PORT_POL_ENA
|
179 ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER
),
180 ANA_PORT_POL_CFG_PORT_POL_ENA
|
181 ANA_PORT_POL_CFG_POL_ORDER_M
,
182 ANA_PORT_POL_CFG
, port
);
186 EXPORT_SYMBOL(ocelot_port_policer_add
);
188 int ocelot_port_policer_del(struct ocelot
*ocelot
, int port
)
190 struct qos_policer_conf pp
= { 0 };
193 dev_dbg(ocelot
->dev
, "%s: port %u\n", __func__
, port
);
195 pp
.mode
= MSCC_QOS_RATE_MODE_DISABLED
;
197 err
= qos_policer_conf_set(ocelot
, port
, POL_IX_PORT
+ port
, &pp
);
201 ocelot_rmw_gix(ocelot
,
202 ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER
),
203 ANA_PORT_POL_CFG_PORT_POL_ENA
|
204 ANA_PORT_POL_CFG_POL_ORDER_M
,
205 ANA_PORT_POL_CFG
, port
);
209 EXPORT_SYMBOL(ocelot_port_policer_del
);