| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- // SPDX-License-Identifier: GPL-2.0+
- #include "lan966x_main.h"
- enum lan966x_dcb_apptrust_values {
- LAN966X_DCB_APPTRUST_EMPTY,
- LAN966X_DCB_APPTRUST_DSCP,
- LAN966X_DCB_APPTRUST_PCP,
- LAN966X_DCB_APPTRUST_DSCP_PCP,
- __LAN966X_DCB_APPTRUST_MAX
- };
- static const struct lan966x_dcb_apptrust {
- u8 selectors[IEEE_8021QAZ_APP_SEL_MAX + 1];
- int nselectors;
- } *lan966x_port_apptrust[NUM_PHYS_PORTS];
- static const char *lan966x_dcb_apptrust_names[__LAN966X_DCB_APPTRUST_MAX] = {
- [LAN966X_DCB_APPTRUST_EMPTY] = "empty",
- [LAN966X_DCB_APPTRUST_DSCP] = "dscp",
- [LAN966X_DCB_APPTRUST_PCP] = "pcp",
- [LAN966X_DCB_APPTRUST_DSCP_PCP] = "dscp pcp"
- };
- /* Lan966x supported apptrust policies */
- static const struct lan966x_dcb_apptrust
- lan966x_dcb_apptrust_policies[__LAN966X_DCB_APPTRUST_MAX] = {
- /* Empty *must* be first */
- [LAN966X_DCB_APPTRUST_EMPTY] = { { 0 }, 0 },
- [LAN966X_DCB_APPTRUST_DSCP] = { { IEEE_8021QAZ_APP_SEL_DSCP }, 1 },
- [LAN966X_DCB_APPTRUST_PCP] = { { DCB_APP_SEL_PCP }, 1 },
- [LAN966X_DCB_APPTRUST_DSCP_PCP] = { { IEEE_8021QAZ_APP_SEL_DSCP,
- DCB_APP_SEL_PCP }, 2 },
- };
- static bool lan966x_dcb_apptrust_contains(int portno, u8 selector)
- {
- const struct lan966x_dcb_apptrust *conf = lan966x_port_apptrust[portno];
- for (int i = 0; i < conf->nselectors; i++)
- if (conf->selectors[i] == selector)
- return true;
- return false;
- }
- static void lan966x_dcb_app_update(struct net_device *dev)
- {
- struct dcb_ieee_app_prio_map dscp_rewr_map = {0};
- struct dcb_rewr_prio_pcp_map pcp_rewr_map = {0};
- struct lan966x_port *port = netdev_priv(dev);
- struct lan966x_port_qos qos = {0};
- struct dcb_app app_itr;
- bool dscp_rewr = false;
- bool pcp_rewr = false;
- /* Get pcp ingress mapping */
- for (int i = 0; i < ARRAY_SIZE(qos.pcp.map); i++) {
- app_itr.selector = DCB_APP_SEL_PCP;
- app_itr.protocol = i;
- qos.pcp.map[i] = dcb_getapp(dev, &app_itr);
- }
- /* Get dscp ingress mapping */
- for (int i = 0; i < ARRAY_SIZE(qos.dscp.map); i++) {
- app_itr.selector = IEEE_8021QAZ_APP_SEL_DSCP;
- app_itr.protocol = i;
- qos.dscp.map[i] = dcb_getapp(dev, &app_itr);
- }
- /* Get default prio */
- qos.default_prio = dcb_ieee_getapp_default_prio_mask(dev);
- if (qos.default_prio)
- qos.default_prio = fls(qos.default_prio) - 1;
- /* Get pcp rewrite mapping */
- dcb_getrewr_prio_pcp_mask_map(dev, &pcp_rewr_map);
- for (int i = 0; i < ARRAY_SIZE(pcp_rewr_map.map); i++) {
- if (!pcp_rewr_map.map[i])
- continue;
- pcp_rewr = true;
- qos.pcp_rewr.map[i] = fls(pcp_rewr_map.map[i]) - 1;
- }
- /* Get dscp rewrite mapping */
- dcb_getrewr_prio_dscp_mask_map(dev, &dscp_rewr_map);
- for (int i = 0; i < ARRAY_SIZE(dscp_rewr_map.map); i++) {
- if (!dscp_rewr_map.map[i])
- continue;
- dscp_rewr = true;
- qos.dscp_rewr.map[i] = fls64(dscp_rewr_map.map[i]) - 1;
- }
- /* Enable use of pcp for queue classification */
- if (lan966x_dcb_apptrust_contains(port->chip_port, DCB_APP_SEL_PCP)) {
- qos.pcp.enable = true;
- if (pcp_rewr)
- qos.pcp_rewr.enable = true;
- }
- /* Enable use of dscp for queue classification */
- if (lan966x_dcb_apptrust_contains(port->chip_port, IEEE_8021QAZ_APP_SEL_DSCP)) {
- qos.dscp.enable = true;
- if (dscp_rewr)
- qos.dscp_rewr.enable = true;
- }
- lan966x_port_qos_set(port, &qos);
- }
- /* DSCP mapping is global for all ports, so set and delete app entries are
- * replicated for each port.
- */
- static int lan966x_dcb_ieee_dscp_setdel(struct net_device *dev,
- struct dcb_app *app,
- int (*setdel)(struct net_device *,
- struct dcb_app *))
- {
- struct lan966x_port *port = netdev_priv(dev);
- struct lan966x *lan966x = port->lan966x;
- int err;
- for (int i = 0; i < NUM_PHYS_PORTS; i++) {
- port = lan966x->ports[i];
- if (!port)
- continue;
- err = setdel(port->dev, app);
- if (err)
- return err;
- }
- return 0;
- }
- static int lan966x_dcb_app_validate(struct net_device *dev,
- const struct dcb_app *app)
- {
- int err = 0;
- switch (app->selector) {
- /* Default priority checks */
- case IEEE_8021QAZ_APP_SEL_ETHERTYPE:
- if (app->protocol)
- err = -EINVAL;
- else if (app->priority >= NUM_PRIO_QUEUES)
- err = -ERANGE;
- break;
- /* Dscp checks */
- case IEEE_8021QAZ_APP_SEL_DSCP:
- if (app->protocol >= LAN966X_PORT_QOS_DSCP_COUNT)
- err = -EINVAL;
- else if (app->priority >= NUM_PRIO_QUEUES)
- err = -ERANGE;
- break;
- /* Pcp checks */
- case DCB_APP_SEL_PCP:
- if (app->protocol >= LAN966X_PORT_QOS_PCP_DEI_COUNT)
- err = -EINVAL;
- else if (app->priority >= NUM_PRIO_QUEUES)
- err = -ERANGE;
- break;
- default:
- err = -EINVAL;
- break;
- }
- if (err)
- netdev_err(dev, "Invalid entry: %d:%d\n", app->protocol,
- app->priority);
- return err;
- }
- static int lan966x_dcb_ieee_delapp(struct net_device *dev, struct dcb_app *app)
- {
- int err;
- if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP)
- err = lan966x_dcb_ieee_dscp_setdel(dev, app, dcb_ieee_delapp);
- else
- err = dcb_ieee_delapp(dev, app);
- if (err)
- return err;
- lan966x_dcb_app_update(dev);
- return 0;
- }
- static int lan966x_dcb_ieee_setapp(struct net_device *dev, struct dcb_app *app)
- {
- struct dcb_app app_itr;
- int err;
- u8 prio;
- err = lan966x_dcb_app_validate(dev, app);
- if (err)
- return err;
- /* Delete current mapping, if it exists */
- prio = dcb_getapp(dev, app);
- if (prio) {
- app_itr = *app;
- app_itr.priority = prio;
- lan966x_dcb_ieee_delapp(dev, &app_itr);
- }
- if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP)
- err = lan966x_dcb_ieee_dscp_setdel(dev, app, dcb_ieee_setapp);
- else
- err = dcb_ieee_setapp(dev, app);
- if (err)
- return err;
- lan966x_dcb_app_update(dev);
- return 0;
- }
- static int lan966x_dcb_apptrust_validate(struct net_device *dev,
- u8 *selectors,
- int nselectors)
- {
- for (int i = 0; i < ARRAY_SIZE(lan966x_dcb_apptrust_policies); i++) {
- bool match;
- if (lan966x_dcb_apptrust_policies[i].nselectors != nselectors)
- continue;
- match = true;
- for (int j = 0; j < nselectors; j++) {
- if (lan966x_dcb_apptrust_policies[i].selectors[j] !=
- *(selectors + j)) {
- match = false;
- break;
- }
- }
- if (match)
- return i;
- }
- netdev_err(dev, "Valid apptrust configurations are:\n");
- for (int i = 0; i < ARRAY_SIZE(lan966x_dcb_apptrust_names); i++)
- pr_info("order: %s\n", lan966x_dcb_apptrust_names[i]);
- return -EOPNOTSUPP;
- }
- static int lan966x_dcb_setapptrust(struct net_device *dev,
- u8 *selectors,
- int nselectors)
- {
- struct lan966x_port *port = netdev_priv(dev);
- int idx;
- idx = lan966x_dcb_apptrust_validate(dev, selectors, nselectors);
- if (idx < 0)
- return idx;
- lan966x_port_apptrust[port->chip_port] = &lan966x_dcb_apptrust_policies[idx];
- lan966x_dcb_app_update(dev);
- return 0;
- }
- static int lan966x_dcb_getapptrust(struct net_device *dev, u8 *selectors,
- int *nselectors)
- {
- struct lan966x_port *port = netdev_priv(dev);
- const struct lan966x_dcb_apptrust *trust;
- trust = lan966x_port_apptrust[port->chip_port];
- memcpy(selectors, trust->selectors, trust->nselectors);
- *nselectors = trust->nselectors;
- return 0;
- }
- static int lan966x_dcb_delrewr(struct net_device *dev, struct dcb_app *app)
- {
- int err;
- if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP)
- err = lan966x_dcb_ieee_dscp_setdel(dev, app, dcb_delrewr);
- else
- err = dcb_delrewr(dev, app);
- if (err < 0)
- return err;
- lan966x_dcb_app_update(dev);
- return 0;
- }
- static int lan966x_dcb_setrewr(struct net_device *dev, struct dcb_app *app)
- {
- struct dcb_app app_itr;
- u16 proto;
- int err;
- err = lan966x_dcb_app_validate(dev, app);
- if (err)
- goto out;
- /* Delete current mapping, if it exists. */
- proto = dcb_getrewr(dev, app);
- if (proto) {
- app_itr = *app;
- app_itr.protocol = proto;
- lan966x_dcb_delrewr(dev, &app_itr);
- }
- if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP)
- err = lan966x_dcb_ieee_dscp_setdel(dev, app, dcb_setrewr);
- else
- err = dcb_setrewr(dev, app);
- if (err)
- goto out;
- lan966x_dcb_app_update(dev);
- out:
- return err;
- }
- static const struct dcbnl_rtnl_ops lan966x_dcbnl_ops = {
- .ieee_setapp = lan966x_dcb_ieee_setapp,
- .ieee_delapp = lan966x_dcb_ieee_delapp,
- .dcbnl_setapptrust = lan966x_dcb_setapptrust,
- .dcbnl_getapptrust = lan966x_dcb_getapptrust,
- .dcbnl_setrewr = lan966x_dcb_setrewr,
- .dcbnl_delrewr = lan966x_dcb_delrewr,
- };
- void lan966x_dcb_init(struct lan966x *lan966x)
- {
- for (int p = 0; p < lan966x->num_phys_ports; ++p) {
- struct lan966x_port *port;
- port = lan966x->ports[p];
- if (!port)
- continue;
- port->dev->dcbnl_ops = &lan966x_dcbnl_ops;
- lan966x_port_apptrust[port->chip_port] =
- &lan966x_dcb_apptrust_policies[LAN966X_DCB_APPTRUST_DSCP_PCP];
- /* Enable DSCP classification based on classified QoS class and
- * DP, for all DSCP values, for all ports.
- */
- lan966x_port_qos_dscp_rewr_mode_set(port,
- LAN966X_PORT_QOS_REWR_DSCP_ALL);
- }
- }
|