Skip to content

Commit c856e2b

Browse files
chelsiocudbgdavem330
authored andcommitted
cxgb4: fix Tx multi channel port rate limit
T6 can support 2 egress traffic management channels per port to double the total number of traffic classes that can be configured. In this configuration, if the class belongs to the other channel, then all the queues must be bound again explicitly to the new class, for the rate limit parameters on the other channel to take effect. So, always explicitly bind all queues to the port rate limit traffic class, regardless of the traffic management channel that it belongs to. Also, only bind queues to port rate limit traffic class, if all the queues don't already belong to an existing different traffic class. Fixes: 4ec4762 ("cxgb4: add TC-MATCHALL classifier egress offload") Signed-off-by: Rahul Lakkireddy <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 09d4f10 commit c856e2b

File tree

4 files changed

+96
-3
lines changed

4 files changed

+96
-3
lines changed

drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3135,9 +3135,9 @@ static int cxgb_set_tx_maxrate(struct net_device *dev, int index, u32 rate)
31353135
{
31363136
struct port_info *pi = netdev_priv(dev);
31373137
struct adapter *adap = pi->adapter;
3138+
struct ch_sched_queue qe = { 0 };
3139+
struct ch_sched_params p = { 0 };
31383140
struct sched_class *e;
3139-
struct ch_sched_params p;
3140-
struct ch_sched_queue qe;
31413141
u32 req_rate;
31423142
int err = 0;
31433143

@@ -3154,6 +3154,15 @@ static int cxgb_set_tx_maxrate(struct net_device *dev, int index, u32 rate)
31543154
return -EINVAL;
31553155
}
31563156

3157+
qe.queue = index;
3158+
e = cxgb4_sched_queue_lookup(dev, &qe);
3159+
if (e && e->info.u.params.level != SCHED_CLASS_LEVEL_CL_RL) {
3160+
dev_err(adap->pdev_dev,
3161+
"Queue %u already bound to class %u of type: %u\n",
3162+
index, e->idx, e->info.u.params.level);
3163+
return -EBUSY;
3164+
}
3165+
31573166
/* Convert from Mbps to Kbps */
31583167
req_rate = rate * 1000;
31593168

@@ -3183,7 +3192,6 @@ static int cxgb_set_tx_maxrate(struct net_device *dev, int index, u32 rate)
31833192
return 0;
31843193

31853194
/* Fetch any available unused or matching scheduling class */
3186-
memset(&p, 0, sizeof(p));
31873195
p.type = SCHED_CLASS_TYPE_PACKET;
31883196
p.u.params.level = SCHED_CLASS_LEVEL_CL_RL;
31893197
p.u.params.mode = SCHED_CLASS_MODE_CLASS;

drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ static int cxgb4_matchall_egress_validate(struct net_device *dev,
1515
struct flow_action *actions = &cls->rule->action;
1616
struct port_info *pi = netdev2pinfo(dev);
1717
struct flow_action_entry *entry;
18+
struct ch_sched_queue qe;
19+
struct sched_class *e;
1820
u64 max_link_rate;
1921
u32 i, speed;
2022
int ret;
@@ -60,9 +62,61 @@ static int cxgb4_matchall_egress_validate(struct net_device *dev,
6062
}
6163
}
6264

65+
for (i = 0; i < pi->nqsets; i++) {
66+
memset(&qe, 0, sizeof(qe));
67+
qe.queue = i;
68+
69+
e = cxgb4_sched_queue_lookup(dev, &qe);
70+
if (e && e->info.u.params.level != SCHED_CLASS_LEVEL_CH_RL) {
71+
NL_SET_ERR_MSG_MOD(extack,
72+
"Some queues are already bound to different class");
73+
return -EBUSY;
74+
}
75+
}
76+
6377
return 0;
6478
}
6579

80+
static int cxgb4_matchall_tc_bind_queues(struct net_device *dev, u32 tc)
81+
{
82+
struct port_info *pi = netdev2pinfo(dev);
83+
struct ch_sched_queue qe;
84+
int ret;
85+
u32 i;
86+
87+
for (i = 0; i < pi->nqsets; i++) {
88+
qe.queue = i;
89+
qe.class = tc;
90+
ret = cxgb4_sched_class_bind(dev, &qe, SCHED_QUEUE);
91+
if (ret)
92+
goto out_free;
93+
}
94+
95+
return 0;
96+
97+
out_free:
98+
while (i--) {
99+
qe.queue = i;
100+
qe.class = SCHED_CLS_NONE;
101+
cxgb4_sched_class_unbind(dev, &qe, SCHED_QUEUE);
102+
}
103+
104+
return ret;
105+
}
106+
107+
static void cxgb4_matchall_tc_unbind_queues(struct net_device *dev)
108+
{
109+
struct port_info *pi = netdev2pinfo(dev);
110+
struct ch_sched_queue qe;
111+
u32 i;
112+
113+
for (i = 0; i < pi->nqsets; i++) {
114+
qe.queue = i;
115+
qe.class = SCHED_CLS_NONE;
116+
cxgb4_sched_class_unbind(dev, &qe, SCHED_QUEUE);
117+
}
118+
}
119+
66120
static int cxgb4_matchall_alloc_tc(struct net_device *dev,
67121
struct tc_cls_matchall_offload *cls)
68122
{
@@ -83,6 +137,7 @@ static int cxgb4_matchall_alloc_tc(struct net_device *dev,
83137
struct adapter *adap = netdev2adap(dev);
84138
struct flow_action_entry *entry;
85139
struct sched_class *e;
140+
int ret;
86141
u32 i;
87142

88143
tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];
@@ -101,10 +156,21 @@ static int cxgb4_matchall_alloc_tc(struct net_device *dev,
101156
return -ENOMEM;
102157
}
103158

159+
ret = cxgb4_matchall_tc_bind_queues(dev, e->idx);
160+
if (ret) {
161+
NL_SET_ERR_MSG_MOD(extack,
162+
"Could not bind queues to traffic class");
163+
goto out_free;
164+
}
165+
104166
tc_port_matchall->egress.hwtc = e->idx;
105167
tc_port_matchall->egress.cookie = cls->cookie;
106168
tc_port_matchall->egress.state = CXGB4_MATCHALL_STATE_ENABLED;
107169
return 0;
170+
171+
out_free:
172+
cxgb4_sched_class_free(dev, e->idx);
173+
return ret;
108174
}
109175

110176
static void cxgb4_matchall_free_tc(struct net_device *dev)
@@ -114,6 +180,7 @@ static void cxgb4_matchall_free_tc(struct net_device *dev)
114180
struct adapter *adap = netdev2adap(dev);
115181

116182
tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];
183+
cxgb4_matchall_tc_unbind_queues(dev);
117184
cxgb4_sched_class_free(dev, tc_port_matchall->egress.hwtc);
118185

119186
tc_port_matchall->egress.hwtc = SCHED_CLS_NONE;

drivers/net/ethernet/chelsio/cxgb4/sched.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,22 @@ static void *t4_sched_entry_lookup(struct port_info *pi,
165165
return found;
166166
}
167167

168+
struct sched_class *cxgb4_sched_queue_lookup(struct net_device *dev,
169+
struct ch_sched_queue *p)
170+
{
171+
struct port_info *pi = netdev2pinfo(dev);
172+
struct sched_queue_entry *qe = NULL;
173+
struct adapter *adap = pi->adapter;
174+
struct sge_eth_txq *txq;
175+
176+
if (p->queue < 0 || p->queue >= pi->nqsets)
177+
return NULL;
178+
179+
txq = &adap->sge.ethtxq[pi->first_qset + p->queue];
180+
qe = t4_sched_entry_lookup(pi, SCHED_QUEUE, txq->q.cntxt_id);
181+
return qe ? &pi->sched_tbl->tab[qe->param.class] : NULL;
182+
}
183+
168184
static int t4_sched_queue_unbind(struct port_info *pi, struct ch_sched_queue *p)
169185
{
170186
struct sched_queue_entry *qe = NULL;

drivers/net/ethernet/chelsio/cxgb4/sched.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ static inline bool valid_class_id(struct net_device *dev, u8 class_id)
103103
return true;
104104
}
105105

106+
struct sched_class *cxgb4_sched_queue_lookup(struct net_device *dev,
107+
struct ch_sched_queue *p);
106108
int cxgb4_sched_class_bind(struct net_device *dev, void *arg,
107109
enum sched_bind_type type);
108110
int cxgb4_sched_class_unbind(struct net_device *dev, void *arg,

0 commit comments

Comments
 (0)