Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'add-new-pcp-and-apptrust-attributes-to-dcbnl'

Daniel Machon says:

====================
Add new PCP and APPTRUST attributes to dcbnl

This patch series adds new extension attributes to dcbnl, to support PCP
prioritization (and thereby hw offloadable pcp-based queue
classification) and per-selector trust and trust order. Additionally,
the microchip sparx5 driver has been dcb-enabled to make use of the new
attributes to offload PCP, DSCP and Default prio to the switch, and
implement trust order of selectors.

For pre-RFC discussion see:
https://lore.kernel.org/netdev/Yv9VO1DYAxNduw6A@DEN-LT-70577/

For RFC series see:
https://lore.kernel.org/netdev/20220915095757.2861822-1-daniel.machon@microchip.com/

In summary: there currently exist no convenient way to offload per-port
PCP-based queue classification to hardware. The DCB subsystem offers
different ways to prioritize through its APP table, but lacks an option
for PCP. Similarly, there is no way to indicate the notion of trust for
APP table selectors. This patch series addresses both topics.

PCP based queue classification:
- 8021Q standardizes the Priority Code Point table (see 6.9.3 of IEEE
Std 802.1Q-2018). This patch series makes it possible, to offload
the PCP classification to said table. The new PCP selector is not a
standard part of the APP managed object, therefore it is
encapsulated in a new non-std extension attribute.

Selector trust:
- ASIC's often has the notion of trust DSCP and trust PCP. The new
attribute makes it possible to specify a trust order of app
selectors, which drivers can then react on.

DCB-enable sparx5 driver:
- Now supports offloading of DSCP, PCP and default priority. Only one
mapping of protocol:priority is allowed. Consecutive mappings of the
same protocol to some new priority, will overwrite the previous. This
is to keep a consistent view of the app table and the hardware.
- Now supports dscp and pcp trust, by use of the introduced
dcbnl_set/getapptrust ops. Sparx5 supports trust orders: [], [dscp],
[pcp] and [dscp, pcp]. For now, only DSCP and PCP selectors are
supported by the driver, everything else is bounced.

Patch #1 introduces a new PCP selector to the APP object, which makes it
possible to encode PCP and DEI in the app triplet and offload it to the
PCP table of the ASIC.

Patch #2 Introduces the new extension attributes
DCB_ATTR_DCB_APP_TRUST_TABLE and DCB_ATTR_DCB_APP_TRUST. Trusted
selectors are passed in the nested DCB_ATTR_DCB_APP_TRUST_TABLE
attribute, and assembled into an array of selectors:

u8 selectors[256];

where lower indexes has higher precedence. In the array, selectors are
stored consecutively, starting from index zero. With a maximum number of
256 unique selectors, the list has the same maximum size.

Patch #3 Sets up the dcbnl ops hook, and adds support for offloading pcp
app entries, to the PCP table of the switch.

Patch #4 Makes use of the dcbnl_set/getapptrust ops, to set a per-port
trust order.

Patch #5 Adds support for offloading dscp app entries to the DSCP table
of the switch.

Patch #6 Adds support for offloading default prio app entries to the
switch.

====================

Link: https://lore.kernel.org/r/20221101094834.2726202-1-daniel.machon@microchip.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

+744 -8
+11
drivers/net/ethernet/microchip/sparx5/Kconfig
··· 12 12 select VCAP 13 13 help 14 14 This driver supports the Sparx5 network switch device. 15 + 16 + config SPARX5_DCB 17 + bool "Data Center Bridging (DCB) support" 18 + depends on SPARX5_SWITCH && DCB 19 + default y 20 + help 21 + Say Y here if you want to use Data Center Bridging (DCB) in the 22 + driver. This can be used to assign priority to traffic, based on 23 + DSCP and PCP. 24 + 25 + If unsure, set to Y.
+2
drivers/net/ethernet/microchip/sparx5/Makefile
··· 11 11 sparx5_ptp.o sparx5_pgid.o sparx5_tc.o sparx5_qos.o \ 12 12 sparx5_vcap_impl.o sparx5_vcap_ag_api.o sparx5_tc_flower.o 13 13 14 + sparx5-switch-$(CONFIG_SPARX5_DCB) += sparx5_dcb.o 15 + 14 16 # Provide include files 15 17 ccflags-y += -I$(srctree)/drivers/net/ethernet/microchip/vcap
+310
drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* Microchip Sparx5 Switch driver 3 + * 4 + * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries. 5 + */ 6 + 7 + #include <net/dcbnl.h> 8 + 9 + #include "sparx5_port.h" 10 + 11 + enum sparx5_dcb_apptrust_values { 12 + SPARX5_DCB_APPTRUST_EMPTY, 13 + SPARX5_DCB_APPTRUST_DSCP, 14 + SPARX5_DCB_APPTRUST_PCP, 15 + SPARX5_DCB_APPTRUST_DSCP_PCP, 16 + __SPARX5_DCB_APPTRUST_MAX 17 + }; 18 + 19 + static const struct sparx5_dcb_apptrust { 20 + u8 selectors[IEEE_8021QAZ_APP_SEL_MAX + 1]; 21 + int nselectors; 22 + } *sparx5_port_apptrust[SPX5_PORTS]; 23 + 24 + static const char *sparx5_dcb_apptrust_names[__SPARX5_DCB_APPTRUST_MAX] = { 25 + [SPARX5_DCB_APPTRUST_EMPTY] = "empty", 26 + [SPARX5_DCB_APPTRUST_DSCP] = "dscp", 27 + [SPARX5_DCB_APPTRUST_PCP] = "pcp", 28 + [SPARX5_DCB_APPTRUST_DSCP_PCP] = "dscp pcp" 29 + }; 30 + 31 + /* Sparx5 supported apptrust policies */ 32 + static const struct sparx5_dcb_apptrust 33 + sparx5_dcb_apptrust_policies[__SPARX5_DCB_APPTRUST_MAX] = { 34 + /* Empty *must* be first */ 35 + [SPARX5_DCB_APPTRUST_EMPTY] = { { 0 }, 0 }, 36 + [SPARX5_DCB_APPTRUST_DSCP] = { { IEEE_8021QAZ_APP_SEL_DSCP }, 1 }, 37 + [SPARX5_DCB_APPTRUST_PCP] = { { DCB_APP_SEL_PCP }, 1 }, 38 + [SPARX5_DCB_APPTRUST_DSCP_PCP] = { { IEEE_8021QAZ_APP_SEL_DSCP, 39 + DCB_APP_SEL_PCP }, 2 }, 40 + }; 41 + 42 + /* Validate app entry. 43 + * 44 + * Check for valid selectors and valid protocol and priority ranges. 45 + */ 46 + static int sparx5_dcb_app_validate(struct net_device *dev, 47 + const struct dcb_app *app) 48 + { 49 + int err = 0; 50 + 51 + switch (app->selector) { 52 + /* Default priority checks */ 53 + case IEEE_8021QAZ_APP_SEL_ETHERTYPE: 54 + if (app->protocol != 0) 55 + err = -EINVAL; 56 + else if (app->priority >= SPX5_PRIOS) 57 + err = -ERANGE; 58 + break; 59 + /* Dscp checks */ 60 + case IEEE_8021QAZ_APP_SEL_DSCP: 61 + if (app->protocol >= SPARX5_PORT_QOS_DSCP_COUNT) 62 + err = -EINVAL; 63 + else if (app->priority >= SPX5_PRIOS) 64 + err = -ERANGE; 65 + break; 66 + /* Pcp checks */ 67 + case DCB_APP_SEL_PCP: 68 + if (app->protocol >= SPARX5_PORT_QOS_PCP_DEI_COUNT) 69 + err = -EINVAL; 70 + else if (app->priority >= SPX5_PRIOS) 71 + err = -ERANGE; 72 + break; 73 + default: 74 + err = -EINVAL; 75 + break; 76 + } 77 + 78 + if (err) 79 + netdev_err(dev, "Invalid entry: %d:%d\n", app->protocol, 80 + app->priority); 81 + 82 + return err; 83 + } 84 + 85 + /* Validate apptrust configuration. 86 + * 87 + * Return index of supported apptrust configuration if valid, otherwise return 88 + * error. 89 + */ 90 + static int sparx5_dcb_apptrust_validate(struct net_device *dev, u8 *selectors, 91 + int nselectors, int *err) 92 + { 93 + bool match; 94 + int i, ii; 95 + 96 + for (i = 0; i < ARRAY_SIZE(sparx5_dcb_apptrust_policies); i++) { 97 + if (sparx5_dcb_apptrust_policies[i].nselectors != nselectors) 98 + continue; 99 + match = true; 100 + for (ii = 0; ii < nselectors; ii++) { 101 + if (sparx5_dcb_apptrust_policies[i].selectors[ii] != 102 + *(selectors + ii)) { 103 + match = false; 104 + break; 105 + } 106 + } 107 + if (match) 108 + break; 109 + } 110 + 111 + /* Requested trust configuration is not supported */ 112 + if (!match) { 113 + netdev_err(dev, "Valid apptrust configurations are:\n"); 114 + for (i = 0; i < ARRAY_SIZE(sparx5_dcb_apptrust_names); i++) 115 + pr_info("order: %s\n", sparx5_dcb_apptrust_names[i]); 116 + *err = -EOPNOTSUPP; 117 + } 118 + 119 + return i; 120 + } 121 + 122 + static bool sparx5_dcb_apptrust_contains(int portno, u8 selector) 123 + { 124 + const struct sparx5_dcb_apptrust *conf = sparx5_port_apptrust[portno]; 125 + int i; 126 + 127 + for (i = 0; i < conf->nselectors; i++) 128 + if (conf->selectors[i] == selector) 129 + return true; 130 + 131 + return false; 132 + } 133 + 134 + static int sparx5_dcb_app_update(struct net_device *dev) 135 + { 136 + struct sparx5_port *port = netdev_priv(dev); 137 + struct sparx5_port_qos_dscp_map *dscp_map; 138 + struct sparx5_port_qos_pcp_map *pcp_map; 139 + struct sparx5_port_qos qos = {0}; 140 + struct dcb_app app_itr = {0}; 141 + int portno = port->portno; 142 + int i; 143 + 144 + dscp_map = &qos.dscp.map; 145 + pcp_map = &qos.pcp.map; 146 + 147 + /* Get default prio. */ 148 + qos.default_prio = dcb_ieee_getapp_default_prio_mask(dev); 149 + if (qos.default_prio) 150 + qos.default_prio = fls(qos.default_prio) - 1; 151 + 152 + /* Get dscp ingress mapping */ 153 + for (i = 0; i < ARRAY_SIZE(dscp_map->map); i++) { 154 + app_itr.selector = IEEE_8021QAZ_APP_SEL_DSCP; 155 + app_itr.protocol = i; 156 + dscp_map->map[i] = dcb_getapp(dev, &app_itr); 157 + } 158 + 159 + /* Get pcp ingress mapping */ 160 + for (i = 0; i < ARRAY_SIZE(pcp_map->map); i++) { 161 + app_itr.selector = DCB_APP_SEL_PCP; 162 + app_itr.protocol = i; 163 + pcp_map->map[i] = dcb_getapp(dev, &app_itr); 164 + } 165 + 166 + /* Enable use of pcp for queue classification ? */ 167 + if (sparx5_dcb_apptrust_contains(portno, DCB_APP_SEL_PCP)) { 168 + qos.pcp.qos_enable = true; 169 + qos.pcp.dp_enable = qos.pcp.qos_enable; 170 + } 171 + 172 + /* Enable use of dscp for queue classification ? */ 173 + if (sparx5_dcb_apptrust_contains(portno, IEEE_8021QAZ_APP_SEL_DSCP)) { 174 + qos.dscp.qos_enable = true; 175 + qos.dscp.dp_enable = qos.dscp.qos_enable; 176 + } 177 + 178 + return sparx5_port_qos_set(port, &qos); 179 + } 180 + 181 + /* Set or delete dscp app entry. 182 + * 183 + * Dscp mapping is global for all ports, so set and delete app entries are 184 + * replicated for each port. 185 + */ 186 + static int sparx5_dcb_ieee_dscp_setdel_app(struct net_device *dev, 187 + struct dcb_app *app, bool del) 188 + { 189 + struct sparx5_port *port = netdev_priv(dev); 190 + struct dcb_app apps[SPX5_PORTS]; 191 + struct sparx5_port *port_itr; 192 + int err, i; 193 + 194 + for (i = 0; i < SPX5_PORTS; i++) { 195 + port_itr = port->sparx5->ports[i]; 196 + if (!port_itr) 197 + continue; 198 + memcpy(&apps[i], app, sizeof(struct dcb_app)); 199 + if (del) 200 + err = dcb_ieee_delapp(port_itr->ndev, &apps[i]); 201 + else 202 + err = dcb_ieee_setapp(port_itr->ndev, &apps[i]); 203 + if (err) 204 + return err; 205 + } 206 + 207 + return 0; 208 + } 209 + 210 + static int sparx5_dcb_ieee_setapp(struct net_device *dev, struct dcb_app *app) 211 + { 212 + struct dcb_app app_itr; 213 + int err = 0; 214 + u8 prio; 215 + 216 + err = sparx5_dcb_app_validate(dev, app); 217 + if (err) 218 + goto out; 219 + 220 + /* Delete current mapping, if it exists */ 221 + prio = dcb_getapp(dev, app); 222 + if (prio) { 223 + app_itr = *app; 224 + app_itr.priority = prio; 225 + dcb_ieee_delapp(dev, &app_itr); 226 + } 227 + 228 + if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP) 229 + err = sparx5_dcb_ieee_dscp_setdel_app(dev, app, false); 230 + else 231 + err = dcb_ieee_setapp(dev, app); 232 + 233 + if (err) 234 + goto out; 235 + 236 + sparx5_dcb_app_update(dev); 237 + 238 + out: 239 + return err; 240 + } 241 + 242 + static int sparx5_dcb_ieee_delapp(struct net_device *dev, struct dcb_app *app) 243 + { 244 + int err; 245 + 246 + if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP) 247 + err = sparx5_dcb_ieee_dscp_setdel_app(dev, app, true); 248 + else 249 + err = dcb_ieee_delapp(dev, app); 250 + 251 + if (err < 0) 252 + return err; 253 + 254 + return sparx5_dcb_app_update(dev); 255 + } 256 + 257 + static int sparx5_dcb_setapptrust(struct net_device *dev, u8 *selectors, 258 + int nselectors) 259 + { 260 + struct sparx5_port *port = netdev_priv(dev); 261 + int err = 0, idx; 262 + 263 + idx = sparx5_dcb_apptrust_validate(dev, selectors, nselectors, &err); 264 + if (err < 0) 265 + return err; 266 + 267 + sparx5_port_apptrust[port->portno] = &sparx5_dcb_apptrust_policies[idx]; 268 + 269 + return sparx5_dcb_app_update(dev); 270 + } 271 + 272 + static int sparx5_dcb_getapptrust(struct net_device *dev, u8 *selectors, 273 + int *nselectors) 274 + { 275 + struct sparx5_port *port = netdev_priv(dev); 276 + const struct sparx5_dcb_apptrust *trust; 277 + 278 + trust = sparx5_port_apptrust[port->portno]; 279 + 280 + memcpy(selectors, trust->selectors, trust->nselectors); 281 + *nselectors = trust->nselectors; 282 + 283 + return 0; 284 + } 285 + 286 + const struct dcbnl_rtnl_ops sparx5_dcbnl_ops = { 287 + .ieee_setapp = sparx5_dcb_ieee_setapp, 288 + .ieee_delapp = sparx5_dcb_ieee_delapp, 289 + .dcbnl_setapptrust = sparx5_dcb_setapptrust, 290 + .dcbnl_getapptrust = sparx5_dcb_getapptrust, 291 + }; 292 + 293 + int sparx5_dcb_init(struct sparx5 *sparx5) 294 + { 295 + struct sparx5_port *port; 296 + int i; 297 + 298 + for (i = 0; i < SPX5_PORTS; i++) { 299 + port = sparx5->ports[i]; 300 + if (!port) 301 + continue; 302 + port->ndev->dcbnl_ops = &sparx5_dcbnl_ops; 303 + /* Initialize [dscp, pcp] default trust */ 304 + sparx5_port_apptrust[port->portno] = 305 + &sparx5_dcb_apptrust_policies 306 + [SPARX5_DCB_APPTRUST_DSCP_PCP]; 307 + } 308 + 309 + return 0; 310 + }
+11
drivers/net/ethernet/microchip/sparx5/sparx5_main.h
··· 359 359 void sparx5_get_stats64(struct net_device *ndev, struct rtnl_link_stats64 *stats); 360 360 int sparx_stats_init(struct sparx5 *sparx5); 361 361 362 + /* sparx5_dcb.c */ 363 + #ifdef CONFIG_SPARX5_DCB 364 + int sparx5_dcb_init(struct sparx5 *sparx5); 365 + #else 366 + static inline int sparx5_dcb_init(struct sparx5 *sparx5) 367 + { 368 + return 0; 369 + } 370 + #endif 371 + 362 372 /* sparx5_netdev.c */ 363 373 void sparx5_set_port_ifh_timestamp(void *ifh_hdr, u64 timestamp); 364 374 void sparx5_set_port_ifh_rew_op(void *ifh_hdr, u32 rew_op); ··· 434 424 extern const struct phylink_mac_ops sparx5_phylink_mac_ops; 435 425 extern const struct phylink_pcs_ops sparx5_phylink_pcs_ops; 436 426 extern const struct ethtool_ops sparx5_ethtool_ops; 427 + extern const struct dcbnl_rtnl_ops sparx5_dcbnl_ops; 437 428 438 429 /* Calculate raw offset */ 439 430 static inline __pure int spx5_offset(int id, int tinst, int tcnt,
+125 -2
drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h
··· 4 4 * Copyright (c) 2021 Microchip Technology Inc. 5 5 */ 6 6 7 - /* This file is autogenerated by cml-utils 2022-09-12 14:22:42 +0200. 8 - * Commit ID: 06aecbca4eab6e85d87f665fe6b6348c48146245 7 + /* This file is autogenerated by cml-utils 2022-09-28 11:17:02 +0200. 8 + * Commit ID: 385c8a11d71a9f6a60368d3a3cb648fa257b479a 9 9 */ 10 10 11 11 #ifndef _SPARX5_MAIN_REGS_H_ ··· 750 750 #define ANA_CL_VLAN_CTRL_2_VLAN_PUSH_CNT_GET(x)\ 751 751 FIELD_GET(ANA_CL_VLAN_CTRL_2_VLAN_PUSH_CNT, x) 752 752 753 + /* ANA_CL:PORT:PCP_DEI_MAP_CFG */ 754 + #define ANA_CL_PCP_DEI_MAP_CFG(g, r) __REG(TARGET_ANA_CL, 0, 1, 131072, g, 70, 512, 108, r, 16, 4) 755 + 756 + #define ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_DP_VAL GENMASK(4, 3) 757 + #define ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_DP_VAL_SET(x)\ 758 + FIELD_PREP(ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_DP_VAL, x) 759 + #define ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_DP_VAL_GET(x)\ 760 + FIELD_GET(ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_DP_VAL, x) 761 + 762 + #define ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_QOS_VAL GENMASK(2, 0) 763 + #define ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_QOS_VAL_SET(x)\ 764 + FIELD_PREP(ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_QOS_VAL, x) 765 + #define ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_QOS_VAL_GET(x)\ 766 + FIELD_GET(ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_QOS_VAL, x) 767 + 768 + /* ANA_CL:PORT:QOS_CFG */ 769 + #define ANA_CL_QOS_CFG(g) __REG(TARGET_ANA_CL, 0, 1, 131072, g, 70, 512, 172, 0, 1, 4) 770 + 771 + #define ANA_CL_QOS_CFG_DEFAULT_COSID_ENA BIT(17) 772 + #define ANA_CL_QOS_CFG_DEFAULT_COSID_ENA_SET(x)\ 773 + FIELD_PREP(ANA_CL_QOS_CFG_DEFAULT_COSID_ENA, x) 774 + #define ANA_CL_QOS_CFG_DEFAULT_COSID_ENA_GET(x)\ 775 + FIELD_GET(ANA_CL_QOS_CFG_DEFAULT_COSID_ENA, x) 776 + 777 + #define ANA_CL_QOS_CFG_DEFAULT_COSID_VAL GENMASK(16, 14) 778 + #define ANA_CL_QOS_CFG_DEFAULT_COSID_VAL_SET(x)\ 779 + FIELD_PREP(ANA_CL_QOS_CFG_DEFAULT_COSID_VAL, x) 780 + #define ANA_CL_QOS_CFG_DEFAULT_COSID_VAL_GET(x)\ 781 + FIELD_GET(ANA_CL_QOS_CFG_DEFAULT_COSID_VAL, x) 782 + 783 + #define ANA_CL_QOS_CFG_DSCP_REWR_MODE_SEL GENMASK(13, 12) 784 + #define ANA_CL_QOS_CFG_DSCP_REWR_MODE_SEL_SET(x)\ 785 + FIELD_PREP(ANA_CL_QOS_CFG_DSCP_REWR_MODE_SEL, x) 786 + #define ANA_CL_QOS_CFG_DSCP_REWR_MODE_SEL_GET(x)\ 787 + FIELD_GET(ANA_CL_QOS_CFG_DSCP_REWR_MODE_SEL, x) 788 + 789 + #define ANA_CL_QOS_CFG_DSCP_TRANSLATE_ENA BIT(11) 790 + #define ANA_CL_QOS_CFG_DSCP_TRANSLATE_ENA_SET(x)\ 791 + FIELD_PREP(ANA_CL_QOS_CFG_DSCP_TRANSLATE_ENA, x) 792 + #define ANA_CL_QOS_CFG_DSCP_TRANSLATE_ENA_GET(x)\ 793 + FIELD_GET(ANA_CL_QOS_CFG_DSCP_TRANSLATE_ENA, x) 794 + 795 + #define ANA_CL_QOS_CFG_DSCP_KEEP_ENA BIT(10) 796 + #define ANA_CL_QOS_CFG_DSCP_KEEP_ENA_SET(x)\ 797 + FIELD_PREP(ANA_CL_QOS_CFG_DSCP_KEEP_ENA, x) 798 + #define ANA_CL_QOS_CFG_DSCP_KEEP_ENA_GET(x)\ 799 + FIELD_GET(ANA_CL_QOS_CFG_DSCP_KEEP_ENA, x) 800 + 801 + #define ANA_CL_QOS_CFG_KEEP_ENA BIT(9) 802 + #define ANA_CL_QOS_CFG_KEEP_ENA_SET(x)\ 803 + FIELD_PREP(ANA_CL_QOS_CFG_KEEP_ENA, x) 804 + #define ANA_CL_QOS_CFG_KEEP_ENA_GET(x)\ 805 + FIELD_GET(ANA_CL_QOS_CFG_KEEP_ENA, x) 806 + 807 + #define ANA_CL_QOS_CFG_PCP_DEI_DP_ENA BIT(8) 808 + #define ANA_CL_QOS_CFG_PCP_DEI_DP_ENA_SET(x)\ 809 + FIELD_PREP(ANA_CL_QOS_CFG_PCP_DEI_DP_ENA, x) 810 + #define ANA_CL_QOS_CFG_PCP_DEI_DP_ENA_GET(x)\ 811 + FIELD_GET(ANA_CL_QOS_CFG_PCP_DEI_DP_ENA, x) 812 + 813 + #define ANA_CL_QOS_CFG_PCP_DEI_QOS_ENA BIT(7) 814 + #define ANA_CL_QOS_CFG_PCP_DEI_QOS_ENA_SET(x)\ 815 + FIELD_PREP(ANA_CL_QOS_CFG_PCP_DEI_QOS_ENA, x) 816 + #define ANA_CL_QOS_CFG_PCP_DEI_QOS_ENA_GET(x)\ 817 + FIELD_GET(ANA_CL_QOS_CFG_PCP_DEI_QOS_ENA, x) 818 + 819 + #define ANA_CL_QOS_CFG_DSCP_DP_ENA BIT(6) 820 + #define ANA_CL_QOS_CFG_DSCP_DP_ENA_SET(x)\ 821 + FIELD_PREP(ANA_CL_QOS_CFG_DSCP_DP_ENA, x) 822 + #define ANA_CL_QOS_CFG_DSCP_DP_ENA_GET(x)\ 823 + FIELD_GET(ANA_CL_QOS_CFG_DSCP_DP_ENA, x) 824 + 825 + #define ANA_CL_QOS_CFG_DSCP_QOS_ENA BIT(5) 826 + #define ANA_CL_QOS_CFG_DSCP_QOS_ENA_SET(x)\ 827 + FIELD_PREP(ANA_CL_QOS_CFG_DSCP_QOS_ENA, x) 828 + #define ANA_CL_QOS_CFG_DSCP_QOS_ENA_GET(x)\ 829 + FIELD_GET(ANA_CL_QOS_CFG_DSCP_QOS_ENA, x) 830 + 831 + #define ANA_CL_QOS_CFG_DEFAULT_DP_VAL GENMASK(4, 3) 832 + #define ANA_CL_QOS_CFG_DEFAULT_DP_VAL_SET(x)\ 833 + FIELD_PREP(ANA_CL_QOS_CFG_DEFAULT_DP_VAL, x) 834 + #define ANA_CL_QOS_CFG_DEFAULT_DP_VAL_GET(x)\ 835 + FIELD_GET(ANA_CL_QOS_CFG_DEFAULT_DP_VAL, x) 836 + 837 + #define ANA_CL_QOS_CFG_DEFAULT_QOS_VAL GENMASK(2, 0) 838 + #define ANA_CL_QOS_CFG_DEFAULT_QOS_VAL_SET(x)\ 839 + FIELD_PREP(ANA_CL_QOS_CFG_DEFAULT_QOS_VAL, x) 840 + #define ANA_CL_QOS_CFG_DEFAULT_QOS_VAL_GET(x)\ 841 + FIELD_GET(ANA_CL_QOS_CFG_DEFAULT_QOS_VAL, x) 842 + 753 843 /* ANA_CL:PORT:CAPTURE_BPDU_CFG */ 754 844 #define ANA_CL_CAPTURE_BPDU_CFG(g) __REG(TARGET_ANA_CL, 0, 1, 131072, g, 70, 512, 196, 0, 1, 4) 755 845 ··· 851 761 FIELD_PREP(ANA_CL_OWN_UPSID_OWN_UPSID, x) 852 762 #define ANA_CL_OWN_UPSID_OWN_UPSID_GET(x)\ 853 763 FIELD_GET(ANA_CL_OWN_UPSID_OWN_UPSID, x) 764 + 765 + /* ANA_CL:COMMON:DSCP_CFG */ 766 + #define ANA_CL_DSCP_CFG(r) __REG(TARGET_ANA_CL, 0, 1, 166912, 0, 1, 756, 256, r, 64, 4) 767 + 768 + #define ANA_CL_DSCP_CFG_DSCP_TRANSLATE_VAL GENMASK(12, 7) 769 + #define ANA_CL_DSCP_CFG_DSCP_TRANSLATE_VAL_SET(x)\ 770 + FIELD_PREP(ANA_CL_DSCP_CFG_DSCP_TRANSLATE_VAL, x) 771 + #define ANA_CL_DSCP_CFG_DSCP_TRANSLATE_VAL_GET(x)\ 772 + FIELD_GET(ANA_CL_DSCP_CFG_DSCP_TRANSLATE_VAL, x) 773 + 774 + #define ANA_CL_DSCP_CFG_DSCP_QOS_VAL GENMASK(6, 4) 775 + #define ANA_CL_DSCP_CFG_DSCP_QOS_VAL_SET(x)\ 776 + FIELD_PREP(ANA_CL_DSCP_CFG_DSCP_QOS_VAL, x) 777 + #define ANA_CL_DSCP_CFG_DSCP_QOS_VAL_GET(x)\ 778 + FIELD_GET(ANA_CL_DSCP_CFG_DSCP_QOS_VAL, x) 779 + 780 + #define ANA_CL_DSCP_CFG_DSCP_DP_VAL GENMASK(3, 2) 781 + #define ANA_CL_DSCP_CFG_DSCP_DP_VAL_SET(x)\ 782 + FIELD_PREP(ANA_CL_DSCP_CFG_DSCP_DP_VAL, x) 783 + #define ANA_CL_DSCP_CFG_DSCP_DP_VAL_GET(x)\ 784 + FIELD_GET(ANA_CL_DSCP_CFG_DSCP_DP_VAL, x) 785 + 786 + #define ANA_CL_DSCP_CFG_DSCP_REWR_ENA BIT(1) 787 + #define ANA_CL_DSCP_CFG_DSCP_REWR_ENA_SET(x)\ 788 + FIELD_PREP(ANA_CL_DSCP_CFG_DSCP_REWR_ENA, x) 789 + #define ANA_CL_DSCP_CFG_DSCP_REWR_ENA_GET(x)\ 790 + FIELD_GET(ANA_CL_DSCP_CFG_DSCP_REWR_ENA, x) 791 + 792 + #define ANA_CL_DSCP_CFG_DSCP_TRUST_ENA BIT(0) 793 + #define ANA_CL_DSCP_CFG_DSCP_TRUST_ENA_SET(x)\ 794 + FIELD_PREP(ANA_CL_DSCP_CFG_DSCP_TRUST_ENA, x) 795 + #define ANA_CL_DSCP_CFG_DSCP_TRUST_ENA_GET(x)\ 796 + FIELD_GET(ANA_CL_DSCP_CFG_DSCP_TRUST_ENA, x) 854 797 855 798 /* ANA_L2:COMMON:AUTO_LRN_CFG */ 856 799 #define ANA_L2_AUTO_LRN_CFG __REG(TARGET_ANA_L2, 0, 1, 566024, 0, 1, 700, 24, 0, 1, 4)
+99
drivers/net/ethernet/microchip/sparx5/sparx5_port.c
··· 6 6 7 7 #include <linux/module.h> 8 8 #include <linux/phy/phy.h> 9 + #include <net/dcbnl.h> 9 10 10 11 #include "sparx5_main_regs.h" 11 12 #include "sparx5_main.h" ··· 1144 1143 QFWD_SWITCH_PORT_MODE_PORT_ENA, 1145 1144 sparx5, 1146 1145 QFWD_SWITCH_PORT_MODE(port->portno)); 1146 + } 1147 + 1148 + int sparx5_port_qos_set(struct sparx5_port *port, 1149 + struct sparx5_port_qos *qos) 1150 + { 1151 + sparx5_port_qos_dscp_set(port, &qos->dscp); 1152 + sparx5_port_qos_pcp_set(port, &qos->pcp); 1153 + sparx5_port_qos_default_set(port, qos); 1154 + 1155 + return 0; 1156 + } 1157 + 1158 + int sparx5_port_qos_pcp_set(const struct sparx5_port *port, 1159 + struct sparx5_port_qos_pcp *qos) 1160 + { 1161 + struct sparx5 *sparx5 = port->sparx5; 1162 + u8 *pcp_itr = qos->map.map; 1163 + u8 pcp, dp; 1164 + int i; 1165 + 1166 + /* Enable/disable pcp and dp for qos classification. */ 1167 + spx5_rmw(ANA_CL_QOS_CFG_PCP_DEI_QOS_ENA_SET(qos->qos_enable) | 1168 + ANA_CL_QOS_CFG_PCP_DEI_DP_ENA_SET(qos->dp_enable), 1169 + ANA_CL_QOS_CFG_PCP_DEI_QOS_ENA | ANA_CL_QOS_CFG_PCP_DEI_DP_ENA, 1170 + sparx5, ANA_CL_QOS_CFG(port->portno)); 1171 + 1172 + /* Map each pcp and dei value to priority and dp */ 1173 + for (i = 0; i < ARRAY_SIZE(qos->map.map); i++) { 1174 + pcp = *(pcp_itr + i); 1175 + dp = (i < SPARX5_PORT_QOS_PCP_COUNT) ? 0 : 1; 1176 + spx5_rmw(ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_QOS_VAL_SET(pcp) | 1177 + ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_DP_VAL_SET(dp), 1178 + ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_QOS_VAL | 1179 + ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_DP_VAL, sparx5, 1180 + ANA_CL_PCP_DEI_MAP_CFG(port->portno, i)); 1181 + } 1182 + 1183 + return 0; 1184 + } 1185 + 1186 + int sparx5_port_qos_dscp_set(const struct sparx5_port *port, 1187 + struct sparx5_port_qos_dscp *qos) 1188 + { 1189 + struct sparx5 *sparx5 = port->sparx5; 1190 + u8 *dscp = qos->map.map; 1191 + int i; 1192 + 1193 + /* Enable/disable dscp and dp for qos classification. 1194 + * Disable rewrite of dscp values for now. 1195 + */ 1196 + spx5_rmw(ANA_CL_QOS_CFG_DSCP_QOS_ENA_SET(qos->qos_enable) | 1197 + ANA_CL_QOS_CFG_DSCP_DP_ENA_SET(qos->dp_enable) | 1198 + ANA_CL_QOS_CFG_DSCP_KEEP_ENA_SET(1), 1199 + ANA_CL_QOS_CFG_DSCP_QOS_ENA | ANA_CL_QOS_CFG_DSCP_DP_ENA | 1200 + ANA_CL_QOS_CFG_DSCP_KEEP_ENA, sparx5, 1201 + ANA_CL_QOS_CFG(port->portno)); 1202 + 1203 + /* Map each dscp value to priority and dp */ 1204 + for (i = 0; i < ARRAY_SIZE(qos->map.map); i++) { 1205 + spx5_rmw(ANA_CL_DSCP_CFG_DSCP_QOS_VAL_SET(*(dscp + i)) | 1206 + ANA_CL_DSCP_CFG_DSCP_DP_VAL_SET(0), 1207 + ANA_CL_DSCP_CFG_DSCP_QOS_VAL | 1208 + ANA_CL_DSCP_CFG_DSCP_DP_VAL, sparx5, 1209 + ANA_CL_DSCP_CFG(i)); 1210 + } 1211 + 1212 + /* Set per-dscp trust */ 1213 + for (i = 0; i < ARRAY_SIZE(qos->map.map); i++) { 1214 + if (qos->qos_enable) { 1215 + spx5_rmw(ANA_CL_DSCP_CFG_DSCP_TRUST_ENA_SET(1), 1216 + ANA_CL_DSCP_CFG_DSCP_TRUST_ENA, sparx5, 1217 + ANA_CL_DSCP_CFG(i)); 1218 + } 1219 + } 1220 + 1221 + return 0; 1222 + } 1223 + 1224 + int sparx5_port_qos_default_set(const struct sparx5_port *port, 1225 + const struct sparx5_port_qos *qos) 1226 + { 1227 + struct sparx5 *sparx5 = port->sparx5; 1228 + 1229 + /* Set default prio and dp level */ 1230 + spx5_rmw(ANA_CL_QOS_CFG_DEFAULT_QOS_VAL_SET(qos->default_prio) | 1231 + ANA_CL_QOS_CFG_DEFAULT_DP_VAL_SET(0), 1232 + ANA_CL_QOS_CFG_DEFAULT_QOS_VAL | 1233 + ANA_CL_QOS_CFG_DEFAULT_DP_VAL, 1234 + sparx5, ANA_CL_QOS_CFG(port->portno)); 1235 + 1236 + /* Set default pcp and dei for untagged frames */ 1237 + spx5_rmw(ANA_CL_VLAN_CTRL_PORT_PCP_SET(0) | 1238 + ANA_CL_VLAN_CTRL_PORT_DEI_SET(0), 1239 + ANA_CL_VLAN_CTRL_PORT_PCP | 1240 + ANA_CL_VLAN_CTRL_PORT_DEI, 1241 + sparx5, ANA_CL_VLAN_CTRL(port->portno)); 1242 + 1243 + return 0; 1147 1244 }
+42
drivers/net/ethernet/microchip/sparx5/sparx5_port.h
··· 91 91 void sparx5_port_enable(struct sparx5_port *port, bool enable); 92 92 int sparx5_port_fwd_urg(struct sparx5 *sparx5, u32 speed); 93 93 94 + #define SPARX5_PORT_QOS_PCP_COUNT 8 95 + #define SPARX5_PORT_QOS_DEI_COUNT 8 96 + #define SPARX5_PORT_QOS_PCP_DEI_COUNT \ 97 + (SPARX5_PORT_QOS_PCP_COUNT + SPARX5_PORT_QOS_DEI_COUNT) 98 + struct sparx5_port_qos_pcp_map { 99 + u8 map[SPARX5_PORT_QOS_PCP_DEI_COUNT]; 100 + }; 101 + 102 + #define SPARX5_PORT_QOS_DSCP_COUNT 64 103 + struct sparx5_port_qos_dscp_map { 104 + u8 map[SPARX5_PORT_QOS_DSCP_COUNT]; 105 + }; 106 + 107 + struct sparx5_port_qos_pcp { 108 + struct sparx5_port_qos_pcp_map map; 109 + bool qos_enable; 110 + bool dp_enable; 111 + }; 112 + 113 + struct sparx5_port_qos_dscp { 114 + struct sparx5_port_qos_dscp_map map; 115 + bool qos_enable; 116 + bool dp_enable; 117 + }; 118 + 119 + struct sparx5_port_qos { 120 + struct sparx5_port_qos_pcp pcp; 121 + struct sparx5_port_qos_dscp dscp; 122 + u8 default_prio; 123 + }; 124 + 125 + int sparx5_port_qos_set(struct sparx5_port *port, struct sparx5_port_qos *qos); 126 + 127 + int sparx5_port_qos_pcp_set(const struct sparx5_port *port, 128 + struct sparx5_port_qos_pcp *qos); 129 + 130 + int sparx5_port_qos_dscp_set(const struct sparx5_port *port, 131 + struct sparx5_port_qos_dscp *qos); 132 + 133 + int sparx5_port_qos_default_set(const struct sparx5_port *port, 134 + const struct sparx5_port_qos *qos); 135 + 94 136 #endif /* __SPARX5_PORT_H__ */
+4
drivers/net/ethernet/microchip/sparx5/sparx5_qos.c
··· 389 389 if (ret < 0) 390 390 return ret; 391 391 392 + ret = sparx5_dcb_init(sparx5); 393 + if (ret < 0) 394 + return ret; 395 + 392 396 return 0; 393 397 } 394 398
+4
include/net/dcbnl.h
··· 109 109 /* buffer settings */ 110 110 int (*dcbnl_getbuffer)(struct net_device *, struct dcbnl_buffer *); 111 111 int (*dcbnl_setbuffer)(struct net_device *, struct dcbnl_buffer *); 112 + 113 + /* apptrust */ 114 + int (*dcbnl_setapptrust)(struct net_device *, u8 *, int); 115 + int (*dcbnl_getapptrust)(struct net_device *, u8 *, int *); 112 116 }; 113 117 114 118 #endif /* __NET_DCBNL_H__ */
+8
include/uapi/linux/dcbnl.h
··· 218 218 #define IEEE_8021QAZ_APP_SEL_ANY 4 219 219 #define IEEE_8021QAZ_APP_SEL_DSCP 5 220 220 221 + /* Non-std selector values */ 222 + #define DCB_APP_SEL_PCP 255 223 + 221 224 /* This structure contains the IEEE 802.1Qaz APP managed object. This 222 225 * object is also used for the CEE std as well. 223 226 * ··· 249 246 __u8 priority; 250 247 __u16 protocol; 251 248 }; 249 + 250 + #define IEEE_8021QAZ_APP_SEL_MAX 255 252 251 253 252 /** 254 253 * struct dcb_peer_app_info - APP feature information sent by the peer ··· 410 405 * @DCB_ATTR_IEEE_PEER_ETS: peer ETS configuration - get only 411 406 * @DCB_ATTR_IEEE_PEER_PFC: peer PFC configuration - get only 412 407 * @DCB_ATTR_IEEE_PEER_APP: peer APP tlv - get only 408 + * @DCB_ATTR_DCB_APP_TRUST_TABLE: selector trust table 413 409 */ 414 410 enum ieee_attrs { 415 411 DCB_ATTR_IEEE_UNSPEC, ··· 424 418 DCB_ATTR_IEEE_QCN, 425 419 DCB_ATTR_IEEE_QCN_STATS, 426 420 DCB_ATTR_DCB_BUFFER, 421 + DCB_ATTR_DCB_APP_TRUST_TABLE, 427 422 __DCB_ATTR_IEEE_MAX 428 423 }; 429 424 #define DCB_ATTR_IEEE_MAX (__DCB_ATTR_IEEE_MAX - 1) ··· 432 425 enum ieee_attrs_app { 433 426 DCB_ATTR_IEEE_APP_UNSPEC, 434 427 DCB_ATTR_IEEE_APP, 428 + DCB_ATTR_DCB_APP, 435 429 __DCB_ATTR_IEEE_APP_MAX 436 430 }; 437 431 #define DCB_ATTR_IEEE_APP_MAX (__DCB_ATTR_IEEE_APP_MAX - 1)
+128 -6
net/dcb/dcbnl.c
··· 166 166 [DCB_ATTR_IEEE_QCN] = {.len = sizeof(struct ieee_qcn)}, 167 167 [DCB_ATTR_IEEE_QCN_STATS] = {.len = sizeof(struct ieee_qcn_stats)}, 168 168 [DCB_ATTR_DCB_BUFFER] = {.len = sizeof(struct dcbnl_buffer)}, 169 + [DCB_ATTR_DCB_APP_TRUST_TABLE] = {.type = NLA_NESTED}, 169 170 }; 170 171 171 172 /* DCB number of traffic classes nested attributes. */ ··· 179 178 180 179 static LIST_HEAD(dcb_app_list); 181 180 static DEFINE_SPINLOCK(dcb_lock); 181 + 182 + static enum ieee_attrs_app dcbnl_app_attr_type_get(u8 selector) 183 + { 184 + switch (selector) { 185 + case IEEE_8021QAZ_APP_SEL_ETHERTYPE: 186 + case IEEE_8021QAZ_APP_SEL_STREAM: 187 + case IEEE_8021QAZ_APP_SEL_DGRAM: 188 + case IEEE_8021QAZ_APP_SEL_ANY: 189 + case IEEE_8021QAZ_APP_SEL_DSCP: 190 + return DCB_ATTR_IEEE_APP; 191 + case DCB_APP_SEL_PCP: 192 + return DCB_ATTR_DCB_APP; 193 + default: 194 + return DCB_ATTR_IEEE_APP_UNSPEC; 195 + } 196 + } 197 + 198 + static bool dcbnl_app_attr_type_validate(enum ieee_attrs_app type) 199 + { 200 + switch (type) { 201 + case DCB_ATTR_IEEE_APP: 202 + case DCB_ATTR_DCB_APP: 203 + return true; 204 + default: 205 + return false; 206 + } 207 + } 208 + 209 + static bool dcbnl_app_selector_validate(enum ieee_attrs_app type, u8 selector) 210 + { 211 + return dcbnl_app_attr_type_get(selector) == type; 212 + } 182 213 183 214 static struct sk_buff *dcbnl_newmsg(int type, u8 cmd, u32 port, u32 seq, 184 215 u32 flags, struct nlmsghdr **nlhp) ··· 1063 1030 /* Handle IEEE 802.1Qaz/802.1Qau/802.1Qbb GET commands. */ 1064 1031 static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev) 1065 1032 { 1066 - struct nlattr *ieee, *app; 1067 - struct dcb_app_type *itr; 1068 1033 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1034 + struct nlattr *ieee, *app, *apptrust; 1035 + struct dcb_app_type *itr; 1069 1036 int dcbx; 1070 1037 int err; 1071 1038 ··· 1149 1116 spin_lock_bh(&dcb_lock); 1150 1117 list_for_each_entry(itr, &dcb_app_list, list) { 1151 1118 if (itr->ifindex == netdev->ifindex) { 1152 - err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app), 1153 - &itr->app); 1119 + enum ieee_attrs_app type = 1120 + dcbnl_app_attr_type_get(itr->app.selector); 1121 + err = nla_put(skb, type, sizeof(itr->app), &itr->app); 1154 1122 if (err) { 1155 1123 spin_unlock_bh(&dcb_lock); 1156 1124 return -EMSGSIZE; ··· 1166 1132 1167 1133 spin_unlock_bh(&dcb_lock); 1168 1134 nla_nest_end(skb, app); 1135 + 1136 + if (ops->dcbnl_getapptrust) { 1137 + u8 selectors[IEEE_8021QAZ_APP_SEL_MAX + 1] = {0}; 1138 + int nselectors, i; 1139 + 1140 + apptrust = nla_nest_start(skb, DCB_ATTR_DCB_APP_TRUST_TABLE); 1141 + if (!apptrust) 1142 + return -EMSGSIZE; 1143 + 1144 + err = ops->dcbnl_getapptrust(netdev, selectors, &nselectors); 1145 + if (!err) { 1146 + for (i = 0; i < nselectors; i++) { 1147 + enum ieee_attrs_app type = 1148 + dcbnl_app_attr_type_get(selectors[i]); 1149 + err = nla_put_u8(skb, type, selectors[i]); 1150 + if (err) { 1151 + nla_nest_cancel(skb, apptrust); 1152 + return err; 1153 + } 1154 + } 1155 + } 1156 + 1157 + nla_nest_end(skb, apptrust); 1158 + } 1169 1159 1170 1160 /* get peer info if available */ 1171 1161 if (ops->ieee_peer_getets) { ··· 1551 1493 int rem; 1552 1494 1553 1495 nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { 1496 + enum ieee_attrs_app type = nla_type(attr); 1554 1497 struct dcb_app *app_data; 1555 1498 1556 - if (nla_type(attr) != DCB_ATTR_IEEE_APP) 1499 + if (!dcbnl_app_attr_type_validate(type)) 1557 1500 continue; 1558 1501 1559 1502 if (nla_len(attr) < sizeof(struct dcb_app)) { ··· 1563 1504 } 1564 1505 1565 1506 app_data = nla_data(attr); 1507 + 1508 + if (!dcbnl_app_selector_validate(type, 1509 + app_data->selector)) { 1510 + err = -EINVAL; 1511 + goto err; 1512 + } 1513 + 1566 1514 if (ops->ieee_setapp) 1567 1515 err = ops->ieee_setapp(netdev, app_data); 1568 1516 else ··· 1577 1511 if (err) 1578 1512 goto err; 1579 1513 } 1514 + } 1515 + 1516 + if (ieee[DCB_ATTR_DCB_APP_TRUST_TABLE]) { 1517 + u8 selectors[IEEE_8021QAZ_APP_SEL_MAX + 1] = {0}; 1518 + struct nlattr *attr; 1519 + int nselectors = 0; 1520 + int rem; 1521 + 1522 + if (!ops->dcbnl_setapptrust) { 1523 + err = -EOPNOTSUPP; 1524 + goto err; 1525 + } 1526 + 1527 + nla_for_each_nested(attr, ieee[DCB_ATTR_DCB_APP_TRUST_TABLE], 1528 + rem) { 1529 + enum ieee_attrs_app type = nla_type(attr); 1530 + u8 selector; 1531 + int i; 1532 + 1533 + if (!dcbnl_app_attr_type_validate(type) || 1534 + nla_len(attr) != 1 || 1535 + nselectors >= sizeof(selectors)) { 1536 + err = -EINVAL; 1537 + goto err; 1538 + } 1539 + 1540 + selector = nla_get_u8(attr); 1541 + 1542 + if (!dcbnl_app_selector_validate(type, selector)) { 1543 + err = -EINVAL; 1544 + goto err; 1545 + } 1546 + 1547 + /* Duplicate selector ? */ 1548 + for (i = 0; i < nselectors; i++) { 1549 + if (selectors[i] == selector) { 1550 + err = -EINVAL; 1551 + goto err; 1552 + } 1553 + } 1554 + 1555 + selectors[nselectors++] = selector; 1556 + } 1557 + 1558 + err = ops->dcbnl_setapptrust(netdev, selectors, nselectors); 1559 + if (err) 1560 + goto err; 1580 1561 } 1581 1562 1582 1563 err: ··· 1667 1554 int rem; 1668 1555 1669 1556 nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { 1557 + enum ieee_attrs_app type = nla_type(attr); 1670 1558 struct dcb_app *app_data; 1671 1559 1672 - if (nla_type(attr) != DCB_ATTR_IEEE_APP) 1560 + if (!dcbnl_app_attr_type_validate(type)) 1673 1561 continue; 1562 + 1674 1563 app_data = nla_data(attr); 1564 + 1565 + if (!dcbnl_app_selector_validate(type, 1566 + app_data->selector)) { 1567 + err = -EINVAL; 1568 + goto err; 1569 + } 1570 + 1675 1571 if (ops->ieee_delapp) 1676 1572 err = ops->ieee_delapp(netdev, app_data); 1677 1573 else