Skip to content

Commit 2deac71

Browse files
mstarovodavem330
authored andcommitted
net: atlantic: QoS implementation: min_rate
This patch adds support for mqprio min_rate limiters. A2 HW supports Weighted Strict Priority (WSP) arbitration for Tx Descriptor Queue scheduling among TCs, which can be used for min_rate shaping. Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com> Signed-off-by: Igor Russkikh <irusskikh@marvell.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent b64f2ac commit 2deac71

File tree

10 files changed

+286
-54
lines changed

10 files changed

+286
-54
lines changed

drivers/net/ethernet/aquantia/atlantic/aq_hw.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,8 @@ struct aq_hw_ops {
280280
int (*hw_rss_hash_set)(struct aq_hw_s *self,
281281
struct aq_rss_parameters *rss_params);
282282

283+
int (*hw_tc_rate_limit_set)(struct aq_hw_s *self);
284+
283285
int (*hw_get_regs)(struct aq_hw_s *self,
284286
const struct aq_hw_caps_s *aq_hw_caps,
285287
u32 *regs_buff);

drivers/net/ethernet/aquantia/atlantic/aq_main.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,6 @@ static int aq_validate_mqprio_opt(struct aq_nic_s *self,
340340
struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(self);
341341
const unsigned int tcs_max = min_t(u8, aq_nic_cfg->aq_hw_caps->tcs_max,
342342
AQ_CFG_TCS_MAX);
343-
int i;
344343

345344
if (num_tc > tcs_max) {
346345
netdev_err(self->ndev, "Too many TCs requested\n");
@@ -352,12 +351,9 @@ static int aq_validate_mqprio_opt(struct aq_nic_s *self,
352351
return -EOPNOTSUPP;
353352
}
354353

355-
for (i = 0; i < num_tc; i++) {
356-
if (has_min_rate && mqprio->min_rate[i]) {
357-
netdev_err(self->ndev,
358-
"Min tx rate is not supported\n");
359-
return -EOPNOTSUPP;
360-
}
354+
if (has_min_rate && !ATL_HW_IS_CHIP_FEATURE(self->aq_hw, ANTIGUA)) {
355+
netdev_err(self->ndev, "Min tx rate is not supported\n");
356+
return -EOPNOTSUPP;
361357
}
362358

363359
return 0;
@@ -368,23 +364,35 @@ static int aq_ndo_setup_tc(struct net_device *dev, enum tc_setup_type type,
368364
{
369365
struct tc_mqprio_qopt_offload *mqprio = type_data;
370366
struct aq_nic_s *aq_nic = netdev_priv(dev);
367+
bool has_min_rate;
368+
bool has_max_rate;
371369
int err;
372370
int i;
373371

374372
if (type != TC_SETUP_QDISC_MQPRIO)
375373
return -EOPNOTSUPP;
376374

375+
has_min_rate = !!(mqprio->flags & TC_MQPRIO_F_MIN_RATE);
376+
has_max_rate = !!(mqprio->flags & TC_MQPRIO_F_MAX_RATE);
377+
377378
err = aq_validate_mqprio_opt(aq_nic, mqprio, mqprio->qopt.num_tc);
378379
if (err)
379380
return err;
380381

381-
if (mqprio->flags & TC_MQPRIO_F_MAX_RATE) {
382-
for (i = 0; i < mqprio->qopt.num_tc; i++) {
382+
for (i = 0; i < mqprio->qopt.num_tc; i++) {
383+
if (has_max_rate) {
383384
u64 max_rate = mqprio->max_rate[i];
384385

385386
do_div(max_rate, AQ_MBPS_DIVISOR);
386387
aq_nic_setup_tc_max_rate(aq_nic, i, (u32)max_rate);
387388
}
389+
390+
if (has_min_rate) {
391+
u64 min_rate = mqprio->min_rate[i];
392+
393+
do_div(min_rate, AQ_MBPS_DIVISOR);
394+
aq_nic_setup_tc_min_rate(aq_nic, i, (u32)min_rate);
395+
}
388396
}
389397

390398
return aq_nic_setup_tc_mqprio(aq_nic, mqprio->qopt.num_tc,

drivers/net/ethernet/aquantia/atlantic/aq_nic.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ static int aq_nic_update_link_status(struct aq_nic_s *self)
196196
#if IS_ENABLED(CONFIG_MACSEC)
197197
aq_macsec_enable(self);
198198
#endif
199+
if (self->aq_hw_ops->hw_tc_rate_limit_set)
200+
self->aq_hw_ops->hw_tc_rate_limit_set(self->aq_hw);
201+
199202
netif_tx_wake_all_queues(self->ndev);
200203
}
201204
if (netif_carrier_ok(self->ndev) && !self->link_status.mbps) {
@@ -1374,3 +1377,28 @@ int aq_nic_setup_tc_max_rate(struct aq_nic_s *self, const unsigned int tc,
13741377

13751378
return 0;
13761379
}
1380+
1381+
int aq_nic_setup_tc_min_rate(struct aq_nic_s *self, const unsigned int tc,
1382+
const u32 min_rate)
1383+
{
1384+
struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
1385+
1386+
if (tc >= AQ_CFG_TCS_MAX)
1387+
return -EINVAL;
1388+
1389+
if (min_rate)
1390+
set_bit(tc, &cfg->tc_min_rate_msk);
1391+
else
1392+
clear_bit(tc, &cfg->tc_min_rate_msk);
1393+
1394+
if (min_rate && min_rate < 20) {
1395+
netdev_warn(self->ndev,
1396+
"Setting %s to the minimum usable value of %dMbps.\n",
1397+
"min rate", 20);
1398+
cfg->tc_min_rate[tc] = 20;
1399+
} else {
1400+
cfg->tc_min_rate[tc] = min_rate;
1401+
}
1402+
1403+
return 0;
1404+
}

drivers/net/ethernet/aquantia/atlantic/aq_nic.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ struct aq_nic_cfg_s {
6666
u8 tcs;
6767
u8 prio_tc_map[8];
6868
u32 tc_max_rate[AQ_CFG_TCS_MAX];
69+
unsigned long tc_min_rate_msk;
70+
u32 tc_min_rate[AQ_CFG_TCS_MAX];
6971
struct aq_rss_parameters aq_rss;
7072
u32 eee_speeds;
7173
};
@@ -198,4 +200,6 @@ void aq_nic_release_filter(struct aq_nic_s *self, enum aq_rx_filter_type type,
198200
int aq_nic_setup_tc_mqprio(struct aq_nic_s *self, u32 tcs, u8 *prio_tc_map);
199201
int aq_nic_setup_tc_max_rate(struct aq_nic_s *self, const unsigned int tc,
200202
const u32 max_rate);
203+
int aq_nic_setup_tc_min_rate(struct aq_nic_s *self, const unsigned int tc,
204+
const u32 min_rate);
201205
#endif /* AQ_NIC_H */

drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,6 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self)
138138
unsigned int prio = 0U;
139139
u32 tc = 0U;
140140

141-
hw_atl_b0_hw_init_tx_tc_rate_limit(self);
142-
143141
if (cfg->is_ptp) {
144142
tx_buff_size -= HW_ATL_B0_PTP_TXBUF_SIZE;
145143
rx_buff_size -= HW_ATL_B0_PTP_RXBUF_SIZE;
@@ -152,18 +150,11 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self)
152150
/* TPS VM init */
153151
hw_atl_tps_tx_pkt_shed_desc_vm_arb_mode_set(self, 0U);
154152

155-
/* TPS TC credits init */
156-
hw_atl_tps_tx_pkt_shed_data_arb_mode_set(self, 0U);
157-
158153
tx_buff_size /= cfg->tcs;
159154
rx_buff_size /= cfg->tcs;
160155
for (tc = 0; tc < cfg->tcs; tc++) {
161156
u32 threshold = 0U;
162157

163-
/* TX Packet Scheduler Data TC0 */
164-
hw_atl_tps_tx_pkt_shed_tc_data_max_credit_set(self, tc, 0xFFF);
165-
hw_atl_tps_tx_pkt_shed_tc_data_weight_set(self, tc, 0x64);
166-
167158
/* Tx buf size TC0 */
168159
hw_atl_tpb_tx_pkt_buff_size_per_tc_set(self, tx_buff_size, tc);
169160

@@ -319,24 +310,87 @@ int hw_atl_b0_hw_offload_set(struct aq_hw_s *self,
319310
return aq_hw_err_from_flags(self);
320311
}
321312

322-
int hw_atl_b0_hw_init_tx_tc_rate_limit(struct aq_hw_s *self)
313+
static int hw_atl_b0_hw_init_tx_tc_rate_limit(struct aq_hw_s *self)
323314
{
315+
static const u32 max_weight = BIT(HW_ATL_TPS_DATA_TCTWEIGHT_WIDTH) - 1;
324316
/* Scale factor is based on the number of bits in fractional portion */
325317
static const u32 scale = BIT(HW_ATL_TPS_DESC_RATE_Y_WIDTH);
326318
static const u32 frac_msk = HW_ATL_TPS_DESC_RATE_Y_MSK >>
327319
HW_ATL_TPS_DESC_RATE_Y_SHIFT;
320+
const u32 link_speed = self->aq_link_status.mbps;
328321
struct aq_nic_cfg_s *nic_cfg = self->aq_nic_cfg;
322+
unsigned long num_min_rated_tcs = 0;
323+
u32 tc_weight[AQ_CFG_TCS_MAX];
324+
u32 fixed_max_credit;
325+
u8 min_rate_msk = 0;
326+
u32 sum_weight = 0;
329327
int tc;
330328

329+
/* By default max_credit is based upon MTU (in unit of 64b) */
330+
fixed_max_credit = nic_cfg->aq_hw_caps->mtu / 64;
331+
332+
if (link_speed) {
333+
min_rate_msk = nic_cfg->tc_min_rate_msk &
334+
(BIT(nic_cfg->tcs) - 1);
335+
num_min_rated_tcs = hweight8(min_rate_msk);
336+
}
337+
338+
/* First, calculate weights where min_rate is specified */
339+
if (num_min_rated_tcs) {
340+
for (tc = 0; tc != nic_cfg->tcs; tc++) {
341+
if (!nic_cfg->tc_min_rate[tc]) {
342+
tc_weight[tc] = 0;
343+
continue;
344+
}
345+
346+
tc_weight[tc] = (-1L + link_speed +
347+
nic_cfg->tc_min_rate[tc] *
348+
max_weight) /
349+
link_speed;
350+
tc_weight[tc] = min(tc_weight[tc], max_weight);
351+
sum_weight += tc_weight[tc];
352+
}
353+
}
354+
355+
/* WSP, if min_rate is set for at least one TC.
356+
* RR otherwise.
357+
*/
358+
hw_atl_tps_tx_pkt_shed_data_arb_mode_set(self, min_rate_msk ? 1U : 0U);
359+
/* Data TC Arbiter takes precedence over Descriptor TC Arbiter,
360+
* leave Descriptor TC Arbiter as RR.
361+
*/
331362
hw_atl_tps_tx_pkt_shed_desc_tc_arb_mode_set(self, 0U);
363+
332364
hw_atl_tps_tx_desc_rate_mode_set(self, nic_cfg->is_qos ? 1U : 0U);
365+
333366
for (tc = 0; tc != nic_cfg->tcs; tc++) {
334367
const u32 en = (nic_cfg->tc_max_rate[tc] != 0) ? 1U : 0U;
335368
const u32 desc = AQ_NIC_CFG_TCVEC2RING(nic_cfg, tc, 0);
369+
u32 weight, max_credit;
336370

337-
hw_atl_tps_tx_pkt_shed_desc_tc_max_credit_set(self, tc, 0x50);
371+
hw_atl_tps_tx_pkt_shed_desc_tc_max_credit_set(self, tc,
372+
fixed_max_credit);
338373
hw_atl_tps_tx_pkt_shed_desc_tc_weight_set(self, tc, 0x1E);
339374

375+
if (num_min_rated_tcs) {
376+
weight = tc_weight[tc];
377+
378+
if (!weight && sum_weight < max_weight)
379+
weight = (max_weight - sum_weight) /
380+
(nic_cfg->tcs - num_min_rated_tcs);
381+
else if (!weight)
382+
weight = 0x64;
383+
384+
max_credit = max(8 * weight, fixed_max_credit);
385+
} else {
386+
weight = 0x64;
387+
max_credit = 0xFFF;
388+
}
389+
390+
hw_atl_tps_tx_pkt_shed_tc_data_weight_set(self, tc, weight);
391+
hw_atl_tps_tx_pkt_shed_tc_data_max_credit_set(self, tc,
392+
max_credit);
393+
340394
hw_atl_tps_tx_desc_rate_en_set(self, desc, en);
341395

342396
if (en) {
@@ -1550,6 +1604,7 @@ const struct aq_hw_ops hw_atl_ops_b0 = {
15501604
.hw_interrupt_moderation_set = hw_atl_b0_hw_interrupt_moderation_set,
15511605
.hw_rss_set = hw_atl_b0_hw_rss_set,
15521606
.hw_rss_hash_set = hw_atl_b0_hw_rss_hash_set,
1607+
.hw_tc_rate_limit_set = hw_atl_b0_hw_init_tx_tc_rate_limit,
15531608
.hw_get_regs = hw_atl_utils_hw_get_regs,
15541609
.hw_get_hw_stats = hw_atl_utils_get_hw_stats,
15551610
.hw_get_fw_version = hw_atl_utils_get_fw_version,

drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,6 @@ int hw_atl_b0_hw_mac_addr_set(struct aq_hw_s *self, u8 *mac_addr);
6262

6363
int hw_atl_b0_hw_start(struct aq_hw_s *self);
6464

65-
int hw_atl_b0_hw_init_tx_tc_rate_limit(struct aq_hw_s *self);
66-
6765
int hw_atl_b0_hw_irq_enable(struct aq_hw_s *self, u64 mask);
6866
int hw_atl_b0_hw_irq_disable(struct aq_hw_s *self, u64 mask);
6967
int hw_atl_b0_hw_irq_read(struct aq_hw_s *self, u64 *mask);

0 commit comments

Comments
 (0)