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 | #define TC_QOPT_BITMASK 15 | 617 | #define TC_QOPT_BITMASK 15 |
| 618 | #define TC_QOPT_MAX_QUEUE 16 | 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 | struct tc_mqprio_qopt { | 628 | struct tc_mqprio_qopt { |
| 621 | __u8 num_tc; | 629 | __u8 num_tc; |
| 622 | __u8 prio_tc_map[TC_QOPT_BITMASK + 1]; | 630 | __u8 prio_tc_map[TC_QOPT_BITMASK + 1]; |
| @@ -21,7 +21,7 @@ · 20 unmodified lines | |||
| 21 | 21 | ||
| 22 | struct mqprio_sched { | 22 | struct mqprio_sched { |
| 23 | struct Qdisc **qdiscs; | 23 | struct Qdisc **qdiscs; |
| 24 | int hw_owned; | 24 | int hw_offload; |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | static void mqprio_destroy(struct Qdisc *sch) | 27 | static void mqprio_destroy(struct Qdisc *sch) |
| @@ -39,7 +39,7 @@ static void mqprio_destroy(struct Qdisc *sch) · 11 unmodified lines | |||
| 39 | kfree(priv->qdiscs); | 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 | dev->netdev_ops->ndo_setup_tc(dev, sch->handle, 0, &tc); | 43 | dev->netdev_ops->ndo_setup_tc(dev, sch->handle, 0, &tc); |
| 44 | else | 44 | else |
| 45 | netdev_set_num_tc(dev, 0); | 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 | return -EINVAL; | 59 | return -EINVAL; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | /* net_device does not support requested operation */ | 62 | /* Limit qopt->hw to maximum supported offload value. Drivers have |
| 63 | if (qopt->hw && !dev->netdev_ops->ndo_setup_tc) | 63 | * the option of overriding this later if they don't support the a |
| 64 | return -EINVAL; | 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 | 69 | /* If hardware offload is requested we will leave it to the device |
| 67 | * no reason to verify them here | 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 | if (qopt->hw) | 74 | if (qopt->hw) |
| 70 | return 0; | 75 | return dev->netdev_ops->ndo_setup_tc ? 0 : -EINVAL; |
| 71 | 76 | ||
| 72 | for (i = 0; i < qopt->num_tc; i++) { | 77 | for (i = 0; i < qopt->num_tc; i++) { |
| 73 | unsigned int last = qopt->offset[i] + qopt->count[i]; | 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 | struct tc_to_netdev tc = {.type = TC_SETUP_MQPRIO, | 147 | struct tc_to_netdev tc = {.type = TC_SETUP_MQPRIO, |
| 143 | { .tc = qopt->num_tc }}; | 148 | { .tc = qopt->num_tc }}; |
| 144 | 149 | ||
| 145 | priv->hw_owned = 1; | ||
| 146 | err = dev->netdev_ops->ndo_setup_tc(dev, sch->handle, 0, &tc); | 150 | err = dev->netdev_ops->ndo_setup_tc(dev, sch->handle, 0, &tc); |
| 147 | if (err) | 151 | if (err) |
| 148 | return err; | 152 | return err; |
| 153 | |||
| 154 | priv->hw_offload = qopt->hw; | ||
| 149 | } else { | 155 | } else { |
| 150 | netdev_set_num_tc(dev, qopt->num_tc); | 156 | netdev_set_num_tc(dev, qopt->num_tc); |
| 151 | for (i = 0; i < qopt->num_tc; i++) | 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 | opt.num_tc = netdev_get_num_tc(dev); | 250 | opt.num_tc = netdev_get_num_tc(dev); |
| 245 | memcpy(opt.prio_tc_map, dev->prio_tc_map, sizeof(opt.prio_tc_map)); | 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 | for (i = 0; i < netdev_get_num_tc(dev); i++) { | 254 | for (i = 0; i < netdev_get_num_tc(dev); i++) { |
| 249 | opt.count[i] = dev->tc_to_txq[i].count; | 255 | opt.count[i] = dev->tc_to_txq[i].count; |