68
68
#define BYTES_PER_KBIT (1000LL / 8)
69
69
70
70
struct cbs_sched_data {
71
+ bool offload ;
72
+ int queue ;
71
73
s64 port_rate ; /* in bytes/s */
72
74
s64 last ; /* timestamp in ns */
73
75
s64 credits ; /* in bytes */
@@ -80,6 +82,11 @@ struct cbs_sched_data {
80
82
struct sk_buff * (* dequeue )(struct Qdisc * sch );
81
83
};
82
84
85
+ static int cbs_enqueue_offload (struct sk_buff * skb , struct Qdisc * sch )
86
+ {
87
+ return qdisc_enqueue_tail (skb , sch );
88
+ }
89
+
83
90
static int cbs_enqueue_soft (struct sk_buff * skb , struct Qdisc * sch )
84
91
{
85
92
struct cbs_sched_data * q = qdisc_priv (sch );
@@ -169,6 +176,11 @@ static struct sk_buff *cbs_dequeue_soft(struct Qdisc *sch)
169
176
return skb ;
170
177
}
171
178
179
+ static struct sk_buff * cbs_dequeue_offload (struct Qdisc * sch )
180
+ {
181
+ return qdisc_dequeue_head (sch );
182
+ }
183
+
172
184
static struct sk_buff * cbs_dequeue (struct Qdisc * sch )
173
185
{
174
186
struct cbs_sched_data * q = qdisc_priv (sch );
@@ -180,14 +192,66 @@ static const struct nla_policy cbs_policy[TCA_CBS_MAX + 1] = {
180
192
[TCA_CBS_PARMS ] = { .len = sizeof (struct tc_cbs_qopt ) },
181
193
};
182
194
195
+ static void cbs_disable_offload (struct net_device * dev ,
196
+ struct cbs_sched_data * q )
197
+ {
198
+ struct tc_cbs_qopt_offload cbs = { };
199
+ const struct net_device_ops * ops ;
200
+ int err ;
201
+
202
+ if (!q -> offload )
203
+ return ;
204
+
205
+ q -> enqueue = cbs_enqueue_soft ;
206
+ q -> dequeue = cbs_dequeue_soft ;
207
+
208
+ ops = dev -> netdev_ops ;
209
+ if (!ops -> ndo_setup_tc )
210
+ return ;
211
+
212
+ cbs .queue = q -> queue ;
213
+ cbs .enable = 0 ;
214
+
215
+ err = ops -> ndo_setup_tc (dev , TC_SETUP_CBS , & cbs );
216
+ if (err < 0 )
217
+ pr_warn ("Couldn't disable CBS offload for queue %d\n" ,
218
+ cbs .queue );
219
+ }
220
+
221
+ static int cbs_enable_offload (struct net_device * dev , struct cbs_sched_data * q ,
222
+ const struct tc_cbs_qopt * opt )
223
+ {
224
+ const struct net_device_ops * ops = dev -> netdev_ops ;
225
+ struct tc_cbs_qopt_offload cbs = { };
226
+ int err ;
227
+
228
+ if (!ops -> ndo_setup_tc )
229
+ return - EOPNOTSUPP ;
230
+
231
+ cbs .queue = q -> queue ;
232
+
233
+ cbs .enable = 1 ;
234
+ cbs .hicredit = opt -> hicredit ;
235
+ cbs .locredit = opt -> locredit ;
236
+ cbs .idleslope = opt -> idleslope ;
237
+ cbs .sendslope = opt -> sendslope ;
238
+
239
+ err = ops -> ndo_setup_tc (dev , TC_SETUP_CBS , & cbs );
240
+ if (err < 0 )
241
+ return err ;
242
+
243
+ q -> enqueue = cbs_enqueue_offload ;
244
+ q -> dequeue = cbs_dequeue_offload ;
245
+
246
+ return 0 ;
247
+ }
248
+
183
249
static int cbs_change (struct Qdisc * sch , struct nlattr * opt )
184
250
{
185
251
struct cbs_sched_data * q = qdisc_priv (sch );
186
252
struct net_device * dev = qdisc_dev (sch );
187
253
struct nlattr * tb [TCA_CBS_MAX + 1 ];
188
- struct ethtool_link_ksettings ecmd ;
189
254
struct tc_cbs_qopt * qopt ;
190
- s64 link_speed ;
191
255
int err ;
192
256
193
257
err = nla_parse_nested (tb , TCA_CBS_MAX , opt , cbs_policy , NULL );
@@ -199,34 +263,47 @@ static int cbs_change(struct Qdisc *sch, struct nlattr *opt)
199
263
200
264
qopt = nla_data (tb [TCA_CBS_PARMS ]);
201
265
202
- if (qopt -> offload )
203
- return - EOPNOTSUPP ;
266
+ if (!qopt -> offload ) {
267
+ struct ethtool_link_ksettings ecmd ;
268
+ s64 link_speed ;
204
269
205
- if (!__ethtool_get_link_ksettings (dev , & ecmd ))
206
- link_speed = ecmd .base .speed ;
207
- else
208
- link_speed = SPEED_1000 ;
270
+ if (!__ethtool_get_link_ksettings (dev , & ecmd ))
271
+ link_speed = ecmd .base .speed ;
272
+ else
273
+ link_speed = SPEED_1000 ;
209
274
210
- q -> port_rate = link_speed * 1000 * BYTES_PER_KBIT ;
275
+ q -> port_rate = link_speed * 1000 * BYTES_PER_KBIT ;
211
276
212
- q -> enqueue = cbs_enqueue_soft ;
213
- q -> dequeue = cbs_dequeue_soft ;
277
+ cbs_disable_offload (dev , q );
278
+ } else {
279
+ err = cbs_enable_offload (dev , q , qopt );
280
+ if (err < 0 )
281
+ return err ;
282
+ }
214
283
284
+ /* Everything went OK, save the parameters used. */
215
285
q -> hicredit = qopt -> hicredit ;
216
286
q -> locredit = qopt -> locredit ;
217
287
q -> idleslope = qopt -> idleslope * BYTES_PER_KBIT ;
218
288
q -> sendslope = qopt -> sendslope * BYTES_PER_KBIT ;
289
+ q -> offload = qopt -> offload ;
219
290
220
291
return 0 ;
221
292
}
222
293
223
294
static int cbs_init (struct Qdisc * sch , struct nlattr * opt )
224
295
{
225
296
struct cbs_sched_data * q = qdisc_priv (sch );
297
+ struct net_device * dev = qdisc_dev (sch );
226
298
227
299
if (!opt )
228
300
return - EINVAL ;
229
301
302
+ q -> queue = sch -> dev_queue - netdev_get_tx_queue (dev , 0 );
303
+
304
+ q -> enqueue = cbs_enqueue_soft ;
305
+ q -> dequeue = cbs_dequeue_soft ;
306
+
230
307
qdisc_watchdog_init (& q -> watchdog , sch );
231
308
232
309
return cbs_change (sch , opt );
@@ -235,8 +312,11 @@ static int cbs_init(struct Qdisc *sch, struct nlattr *opt)
235
312
static void cbs_destroy (struct Qdisc * sch )
236
313
{
237
314
struct cbs_sched_data * q = qdisc_priv (sch );
315
+ struct net_device * dev = qdisc_dev (sch );
238
316
239
317
qdisc_watchdog_cancel (& q -> watchdog );
318
+
319
+ cbs_disable_offload (dev , q );
240
320
}
241
321
242
322
static int cbs_dump (struct Qdisc * sch , struct sk_buff * skb )
@@ -253,7 +333,7 @@ static int cbs_dump(struct Qdisc *sch, struct sk_buff *skb)
253
333
opt .locredit = q -> locredit ;
254
334
opt .sendslope = div64_s64 (q -> sendslope , BYTES_PER_KBIT );
255
335
opt .idleslope = div64_s64 (q -> idleslope , BYTES_PER_KBIT );
256
- opt .offload = 0 ;
336
+ opt .offload = q -> offload ;
257
337
258
338
if (nla_put (skb , TCA_CBS_PARMS , sizeof (opt ), & opt ))
259
339
goto nla_put_failure ;
0 commit comments