Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause)
2/*
3 * Copyright (c) 2014-2025, Advanced Micro Devices, Inc.
4 * Copyright (c) 2014, Synopsys, Inc.
5 * All rights reserved
6 */
7
8#include <linux/netdevice.h>
9#include <net/dcbnl.h>
10
11#include "xgbe.h"
12#include "xgbe-common.h"
13
14static int xgbe_dcb_ieee_getets(struct net_device *netdev,
15 struct ieee_ets *ets)
16{
17 struct xgbe_prv_data *pdata = netdev_priv(netdev);
18
19 /* Set number of supported traffic classes */
20 ets->ets_cap = pdata->hw_feat.tc_cnt;
21
22 if (pdata->ets) {
23 ets->cbs = pdata->ets->cbs;
24 memcpy(ets->tc_tx_bw, pdata->ets->tc_tx_bw,
25 sizeof(ets->tc_tx_bw));
26 memcpy(ets->tc_tsa, pdata->ets->tc_tsa,
27 sizeof(ets->tc_tsa));
28 memcpy(ets->prio_tc, pdata->ets->prio_tc,
29 sizeof(ets->prio_tc));
30 }
31
32 return 0;
33}
34
35static int xgbe_dcb_ieee_setets(struct net_device *netdev,
36 struct ieee_ets *ets)
37{
38 struct xgbe_prv_data *pdata = netdev_priv(netdev);
39 unsigned int i, tc_ets, tc_ets_weight;
40 u8 max_tc = 0;
41
42 tc_ets = 0;
43 tc_ets_weight = 0;
44 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
45 netif_dbg(pdata, drv, netdev,
46 "TC%u: tx_bw=%hhu, rx_bw=%hhu, tsa=%hhu\n", i,
47 ets->tc_tx_bw[i], ets->tc_rx_bw[i],
48 ets->tc_tsa[i]);
49 netif_dbg(pdata, drv, netdev, "PRIO%u: TC=%hhu\n", i,
50 ets->prio_tc[i]);
51
52 max_tc = max_t(u8, max_tc, ets->prio_tc[i]);
53 if ((ets->tc_tx_bw[i] || ets->tc_tsa[i]))
54 max_tc = max_t(u8, max_tc, i);
55
56 switch (ets->tc_tsa[i]) {
57 case IEEE_8021QAZ_TSA_STRICT:
58 break;
59 case IEEE_8021QAZ_TSA_ETS:
60 tc_ets = 1;
61 tc_ets_weight += ets->tc_tx_bw[i];
62 break;
63 default:
64 netif_err(pdata, drv, netdev,
65 "unsupported TSA algorithm (%hhu)\n",
66 ets->tc_tsa[i]);
67 return -EINVAL;
68 }
69 }
70
71 /* Check maximum traffic class requested */
72 if (max_tc >= pdata->hw_feat.tc_cnt) {
73 netif_err(pdata, drv, netdev,
74 "exceeded number of supported traffic classes\n");
75 return -EINVAL;
76 }
77
78 /* Weights must add up to 100% */
79 if (tc_ets && (tc_ets_weight != 100)) {
80 netif_err(pdata, drv, netdev,
81 "sum of ETS algorithm weights is not 100 (%u)\n",
82 tc_ets_weight);
83 return -EINVAL;
84 }
85
86 if (!pdata->ets) {
87 pdata->ets = devm_kzalloc(pdata->dev, sizeof(*pdata->ets),
88 GFP_KERNEL);
89 if (!pdata->ets)
90 return -ENOMEM;
91 }
92
93 pdata->num_tcs = max_tc + 1;
94 memcpy(pdata->ets, ets, sizeof(*pdata->ets));
95
96 pdata->hw_if.config_dcb_tc(pdata);
97
98 return 0;
99}
100
101static int xgbe_dcb_ieee_getpfc(struct net_device *netdev,
102 struct ieee_pfc *pfc)
103{
104 struct xgbe_prv_data *pdata = netdev_priv(netdev);
105
106 /* Set number of supported PFC traffic classes */
107 pfc->pfc_cap = pdata->hw_feat.tc_cnt;
108
109 if (pdata->pfc) {
110 pfc->pfc_en = pdata->pfc->pfc_en;
111 pfc->mbc = pdata->pfc->mbc;
112 pfc->delay = pdata->pfc->delay;
113 }
114
115 return 0;
116}
117
118static int xgbe_dcb_ieee_setpfc(struct net_device *netdev,
119 struct ieee_pfc *pfc)
120{
121 struct xgbe_prv_data *pdata = netdev_priv(netdev);
122
123 netif_dbg(pdata, drv, netdev,
124 "cap=%d, en=%#x, mbc=%d, delay=%d\n",
125 pfc->pfc_cap, pfc->pfc_en, pfc->mbc, pfc->delay);
126
127 /* Check PFC for supported number of traffic classes */
128 if (pfc->pfc_en & ~((1 << pdata->hw_feat.tc_cnt) - 1)) {
129 netif_err(pdata, drv, netdev,
130 "PFC requested for unsupported traffic class\n");
131 return -EINVAL;
132 }
133
134 if (!pdata->pfc) {
135 pdata->pfc = devm_kzalloc(pdata->dev, sizeof(*pdata->pfc),
136 GFP_KERNEL);
137 if (!pdata->pfc)
138 return -ENOMEM;
139 }
140
141 memcpy(pdata->pfc, pfc, sizeof(*pdata->pfc));
142
143 pdata->hw_if.config_dcb_pfc(pdata);
144
145 return 0;
146}
147
148static u8 xgbe_dcb_getdcbx(struct net_device *netdev)
149{
150 return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE;
151}
152
153static u8 xgbe_dcb_setdcbx(struct net_device *netdev, u8 dcbx)
154{
155 struct xgbe_prv_data *pdata = netdev_priv(netdev);
156 u8 support = xgbe_dcb_getdcbx(netdev);
157
158 netif_dbg(pdata, drv, netdev, "DCBX=%#hhx\n", dcbx);
159
160 if (dcbx & ~support)
161 return 1;
162
163 if ((dcbx & support) != support)
164 return 1;
165
166 return 0;
167}
168
169static const struct dcbnl_rtnl_ops xgbe_dcbnl_ops = {
170 /* IEEE 802.1Qaz std */
171 .ieee_getets = xgbe_dcb_ieee_getets,
172 .ieee_setets = xgbe_dcb_ieee_setets,
173 .ieee_getpfc = xgbe_dcb_ieee_getpfc,
174 .ieee_setpfc = xgbe_dcb_ieee_setpfc,
175
176 /* DCBX configuration */
177 .getdcbx = xgbe_dcb_getdcbx,
178 .setdcbx = xgbe_dcb_setdcbx,
179};
180
181const struct dcbnl_rtnl_ops *xgbe_get_dcbnl_ops(void)
182{
183 return &xgbe_dcbnl_ops;
184}