| @@ -102,6 +102,91 @@ static u32 ets_class_id(struct Qdisc *sch, const struct ets_class *cl) · 101 unmodified lines |
| 102 | 102 | return TC_H_MAKE(sch->handle, band + 1); |
| 103 | 103 | } |
| 104 | 104 | |
| 105 | +static void ets_offload_change(struct Qdisc *sch) |
| 106 | +{ |
| 107 | + struct net_device *dev = qdisc_dev(sch); |
| 108 | + struct ets_sched *q = qdisc_priv(sch); |
| 109 | + struct tc_ets_qopt_offload qopt; |
| 110 | + unsigned int w_psum_prev = 0; |
| 111 | + unsigned int q_psum = 0; |
| 112 | + unsigned int q_sum = 0; |
| 113 | + unsigned int quantum; |
| 114 | + unsigned int w_psum; |
| 115 | + unsigned int weight; |
| 116 | + unsigned int i; |
| 117 | + |
| 118 | + if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc) |
| 119 | + return; |
| 120 | + |
| 121 | + qopt.command = TC_ETS_REPLACE; |
| 122 | + qopt.handle = sch->handle; |
| 123 | + qopt.parent = sch->parent; |
| 124 | + qopt.replace_params.bands = q->nbands; |
| 125 | + qopt.replace_params.qstats = &sch->qstats; |
| 126 | + memcpy(&qopt.replace_params.priomap, |
| 127 | + q->prio2band, sizeof(q->prio2band)); |
| 128 | + |
| 129 | + for (i = 0; i < q->nbands; i++) |
| 130 | + q_sum += q->classes[i].quantum; |
| 131 | + |
| 132 | + for (i = 0; i < q->nbands; i++) { |
| 133 | + quantum = q->classes[i].quantum; |
| 134 | + q_psum += quantum; |
| 135 | + w_psum = quantum ? q_psum * 100 / q_sum : 0; |
| 136 | + weight = w_psum - w_psum_prev; |
| 137 | + w_psum_prev = w_psum; |
| 138 | + |
| 139 | + qopt.replace_params.quanta[i] = quantum; |
| 140 | + qopt.replace_params.weights[i] = weight; |
| 141 | + } |
| 142 | + |
| 143 | + dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_ETS, &qopt); |
| 144 | +} |
| 145 | + |
| 146 | +static void ets_offload_destroy(struct Qdisc *sch) |
| 147 | +{ |
| 148 | + struct net_device *dev = qdisc_dev(sch); |
| 149 | + struct tc_ets_qopt_offload qopt; |
| 150 | + |
| 151 | + if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc) |
| 152 | + return; |
| 153 | + |
| 154 | + qopt.command = TC_ETS_DESTROY; |
| 155 | + qopt.handle = sch->handle; |
| 156 | + qopt.parent = sch->parent; |
| 157 | + dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_ETS, &qopt); |
| 158 | +} |
| 159 | + |
| 160 | +static void ets_offload_graft(struct Qdisc *sch, struct Qdisc *new, |
| 161 | + struct Qdisc *old, unsigned long arg, |
| 162 | + struct netlink_ext_ack *extack) |
| 163 | +{ |
| 164 | + struct net_device *dev = qdisc_dev(sch); |
| 165 | + struct tc_ets_qopt_offload qopt; |
| 166 | + |
| 167 | + qopt.command = TC_ETS_GRAFT; |
| 168 | + qopt.handle = sch->handle; |
| 169 | + qopt.parent = sch->parent; |
| 170 | + qopt.graft_params.band = arg - 1; |
| 171 | + qopt.graft_params.child_handle = new->handle; |
| 172 | + |
| 173 | + qdisc_offload_graft_helper(dev, sch, new, old, TC_SETUP_QDISC_ETS, |
| 174 | + &qopt, extack); |
| 175 | +} |
| 176 | + |
| 177 | +static int ets_offload_dump(struct Qdisc *sch) |
| 178 | +{ |
| 179 | + struct tc_ets_qopt_offload qopt; |
| 180 | + |
| 181 | + qopt.command = TC_ETS_STATS; |
| 182 | + qopt.handle = sch->handle; |
| 183 | + qopt.parent = sch->parent; |
| 184 | + qopt.stats.bstats = &sch->bstats; |
| 185 | + qopt.stats.qstats = &sch->qstats; |
| 186 | + |
| 187 | + return qdisc_offload_dump_helper(sch, TC_SETUP_QDISC_ETS, &qopt); |
| 188 | +} |
| 189 | + |
| 105 | 190 | static bool ets_class_is_strict(struct ets_sched *q, const struct ets_class *cl) |
| 106 | 191 | { |
| 107 | 192 | unsigned int band = cl - q->classes; |
| @@ -154,6 +239,8 @@ static int ets_class_change(struct Qdisc *sch, u32 classid, u32 parentid, · 46 unmodified lines |
| 154 | 239 | sch_tree_lock(sch); |
| 155 | 240 | cl->quantum = quantum; |
| 156 | 241 | sch_tree_unlock(sch); |
| 242 | + |
| 243 | + ets_offload_change(sch); |
| 157 | 244 | return 0; |
| 158 | 245 | } |
| 159 | 246 | |
| @@ -173,6 +260,7 @@ static int ets_class_graft(struct Qdisc *sch, unsigned long arg, · 13 unmodified lines |
| 173 | 260 | } |
| 174 | 261 | |
| 175 | 262 | *old = qdisc_replace(sch, new, &cl->qdisc); |
| 263 | + ets_offload_graft(sch, new, *old, arg, extack); |
| 176 | 264 | return 0; |
| 177 | 265 | } |
| 178 | 266 | |
| @@ -589,6 +677,7 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt, · 410 unmodified lines |
| 589 | 677 | |
| 590 | 678 | sch_tree_unlock(sch); |
| 591 | 679 | |
| 680 | + ets_offload_change(sch); |
| 592 | 681 | for (i = q->nbands; i < oldbands; i++) { |
| 593 | 682 | qdisc_put(q->classes[i].qdisc); |
| 594 | 683 | memset(&q->classes[i], 0, sizeof(q->classes[i])); |
| @@ -633,6 +722,7 @@ static void ets_qdisc_destroy(struct Qdisc *sch) · 38 unmodified lines |
| 633 | 722 | struct ets_sched *q = qdisc_priv(sch); |
| 634 | 723 | int band; |
| 635 | 724 | |
| 725 | + ets_offload_destroy(sch); |
| 636 | 726 | tcf_block_put(q->block); |
| 637 | 727 | for (band = 0; band < q->nbands; band++) |
| 638 | 728 | qdisc_put(q->classes[band].qdisc); |
| @@ -645,6 +735,11 @@ static int ets_qdisc_dump(struct Qdisc *sch, struct sk_buff *skb) · 6 unmodified lines |
| 645 | 735 | struct nlattr *nest; |
| 646 | 736 | int band; |
| 647 | 737 | int prio; |
| 738 | + int err; |
| 739 | + |
| 740 | + err = ets_offload_dump(sch); |
| 741 | + if (err) |
| 742 | + return err; |
| 648 | 743 | |
| 649 | 744 | opts = nla_nest_start_noflag(skb, TCA_OPTIONS); |
| 650 | 745 | if (!opts) |