This patch is meant to allow for support of multiple hardware offload type for a single device. There is currently no bounds checking for the hw member of the mqprio_qopt structure. This results in us being able to pass values from 1 to 255 with all being treated the same. On retreiving the value it is returned as 1 for anything 1 or greater being set. With this change we are currently adding limited bounds checking by defining an enum and using those values to limit the reported hardware offloads.
Unified · Split
| @@ -617,6 +617,14 @@ struct tc_drr_stats { · 616 unmodified lines | ||
| 617 | 617 | #define TC_QOPT_BITMASK 15 |
| 618 | 618 | #define TC_QOPT_MAX_QUEUE 16 |
| 619 | 619 | |
| 620 | +enum { | |
| 621 | + TC_MQPRIO_HW_OFFLOAD_NONE, /* no offload requested */ | |
| 622 | + TC_MQPRIO_HW_OFFLOAD_TCS, /* offload TCs, no queue counts */ | |
| 623 | + __TC_MQPRIO_HW_OFFLOAD_MAX | |
| 624 | +}; | |
| 625 | + | |
| 626 | +#define TC_MQPRIO_HW_OFFLOAD_MAX (__TC_MQPRIO_HW_OFFLOAD_MAX - 1) | |
| 627 | + | |
| 620 | 628 | struct tc_mqprio_qopt { |
| 621 | 629 | __u8 num_tc; |
| 622 | 630 | __u8 prio_tc_map[TC_QOPT_BITMASK + 1]; |
| @@ -21,7 +21,7 @@ · 20 unmodified lines | ||
| 21 | 21 | |
| 22 | 22 | struct mqprio_sched { |
| 23 | 23 | struct Qdisc **qdiscs; |
| 24 | − int hw_owned; | |
| 24 | + int hw_offload; | |
| 25 | 25 | }; |
| 26 | 26 | |
| 27 | 27 | static void mqprio_destroy(struct Qdisc *sch) |
| @@ -39,7 +39,7 @@ static void mqprio_destroy(struct Qdisc *sch) · 11 unmodified lines | ||
| 39 | 39 | kfree(priv->qdiscs); |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | − if (priv->hw_owned && dev->netdev_ops->ndo_setup_tc) | |
| 42 | + if (priv->hw_offload && dev->netdev_ops->ndo_setup_tc) | |
| 43 | 43 | dev->netdev_ops->ndo_setup_tc(dev, sch->handle, 0, &tc); |
| 44 | 44 | else |
| 45 | 45 | netdev_set_num_tc(dev, 0); |
| @@ -59,15 +59,20 @@ static int mqprio_parse_opt(struct net_device *dev, struct tc_mqprio_qopt *qopt) · 13 unmodified lines | ||
| 59 | 59 | return -EINVAL; |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | − /* net_device does not support requested operation */ | |
| 63 | − if (qopt->hw && !dev->netdev_ops->ndo_setup_tc) | |
| 64 | − return -EINVAL; | |
| 62 | + /* Limit qopt->hw to maximum supported offload value. Drivers have | |
| 63 | + * the option of overriding this later if they don't support the a | |
| 64 | + * given offload type. | |
| 65 | + */ | |
| 66 | + if (qopt->hw > TC_MQPRIO_HW_OFFLOAD_MAX) | |
| 67 | + qopt->hw = TC_MQPRIO_HW_OFFLOAD_MAX; | |
| 65 | 68 | |
| 66 | − /* if hw owned qcount and qoffset are taken from LLD so | |
| 67 | − * no reason to verify them here | |
| 69 | + /* If hardware offload is requested we will leave it to the device | |
| 70 | + * to either populate the queue counts itself or to validate the | |
| 71 | + * provided queue counts. If ndo_setup_tc is not present then | |
| 72 | + * hardware doesn't support offload and we should return an error. | |
| 68 | 73 | */ |
| 69 | 74 | if (qopt->hw) |
| 70 | − return 0; | |
| 75 | + return dev->netdev_ops->ndo_setup_tc ? 0 : -EINVAL; | |
| 71 | 76 | |
| 72 | 77 | for (i = 0; i < qopt->num_tc; i++) { |
| 73 | 78 | unsigned int last = qopt->offset[i] + qopt->count[i]; |
| @@ -142,10 +147,11 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt) · 68 unmodified lines | ||
| 142 | 147 | struct tc_to_netdev tc = {.type = TC_SETUP_MQPRIO, |
| 143 | 148 | { .tc = qopt->num_tc }}; |
| 144 | 149 | |
| 145 | − priv->hw_owned = 1; | |
| 146 | 150 | err = dev->netdev_ops->ndo_setup_tc(dev, sch->handle, 0, &tc); |
| 147 | 151 | if (err) |
| 148 | 152 | return err; |
| 153 | + | |
| 154 | + priv->hw_offload = qopt->hw; | |
| 149 | 155 | } else { |
| 150 | 156 | netdev_set_num_tc(dev, qopt->num_tc); |
| 151 | 157 | for (i = 0; i < qopt->num_tc; i++) |
| @@ -243,7 +249,7 @@ static int mqprio_dump(struct Qdisc *sch, struct sk_buff *skb) · 91 unmodified lines | ||
| 243 | 249 | |
| 244 | 250 | opt.num_tc = netdev_get_num_tc(dev); |
| 245 | 251 | memcpy(opt.prio_tc_map, dev->prio_tc_map, sizeof(opt.prio_tc_map)); |
| 246 | − opt.hw = priv->hw_owned; | |
| 252 | + opt.hw = priv->hw_offload; | |
| 247 | 253 | |
| 248 | 254 | for (i = 0; i < netdev_get_num_tc(dev); i++) { |
| 249 | 255 | opt.count[i] = dev->tc_to_txq[i].count; |