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 14 static 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 35 static 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 101 static 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 118 static 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 148 static u8 xgbe_dcb_getdcbx(struct net_device *netdev) 149 { 150 return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE; 151 } 152 153 static 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 169 static 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 181 const struct dcbnl_rtnl_ops *xgbe_get_dcbnl_ops(void) 182 { 183 return &xgbe_dcbnl_ops; 184 } 185