i40e_dcb_nl.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*******************************************************************************
  3. *
  4. * Intel Ethernet Controller XL710 Family Linux Driver
  5. * Copyright(c) 2013 - 2014 Intel Corporation.
  6. *
  7. * This program is free software; you can redistribute it and/or modify it
  8. * under the terms and conditions of the GNU General Public License,
  9. * version 2, as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  14. * more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. * The full GNU General Public License is included in this distribution in
  20. * the file called "COPYING".
  21. *
  22. * Contact Information:
  23. * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
  24. * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  25. *
  26. ******************************************************************************/
  27. #ifdef CONFIG_I40E_DCB
  28. #include "i40e.h"
  29. #include <net/dcbnl.h>
  30. /**
  31. * i40e_get_pfc_delay - retrieve PFC Link Delay
  32. * @hw: pointer to hardware struct
  33. * @delay: holds the PFC Link delay value
  34. *
  35. * Returns PFC Link Delay from the PRTDCB_GENC.PFCLDA
  36. **/
  37. static void i40e_get_pfc_delay(struct i40e_hw *hw, u16 *delay)
  38. {
  39. u32 val;
  40. val = rd32(hw, I40E_PRTDCB_GENC);
  41. *delay = (u16)((val & I40E_PRTDCB_GENC_PFCLDA_MASK) >>
  42. I40E_PRTDCB_GENC_PFCLDA_SHIFT);
  43. }
  44. /**
  45. * i40e_dcbnl_ieee_getets - retrieve local IEEE ETS configuration
  46. * @netdev: the corresponding netdev
  47. * @ets: structure to hold the ETS information
  48. *
  49. * Returns local IEEE ETS configuration
  50. **/
  51. static int i40e_dcbnl_ieee_getets(struct net_device *dev,
  52. struct ieee_ets *ets)
  53. {
  54. struct i40e_pf *pf = i40e_netdev_to_pf(dev);
  55. struct i40e_dcbx_config *dcbxcfg;
  56. struct i40e_hw *hw = &pf->hw;
  57. if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
  58. return -EINVAL;
  59. dcbxcfg = &hw->local_dcbx_config;
  60. ets->willing = dcbxcfg->etscfg.willing;
  61. ets->ets_cap = dcbxcfg->etscfg.maxtcs;
  62. ets->cbs = dcbxcfg->etscfg.cbs;
  63. memcpy(ets->tc_tx_bw, dcbxcfg->etscfg.tcbwtable,
  64. sizeof(ets->tc_tx_bw));
  65. memcpy(ets->tc_rx_bw, dcbxcfg->etscfg.tcbwtable,
  66. sizeof(ets->tc_rx_bw));
  67. memcpy(ets->tc_tsa, dcbxcfg->etscfg.tsatable,
  68. sizeof(ets->tc_tsa));
  69. memcpy(ets->prio_tc, dcbxcfg->etscfg.prioritytable,
  70. sizeof(ets->prio_tc));
  71. memcpy(ets->tc_reco_bw, dcbxcfg->etsrec.tcbwtable,
  72. sizeof(ets->tc_reco_bw));
  73. memcpy(ets->tc_reco_tsa, dcbxcfg->etsrec.tsatable,
  74. sizeof(ets->tc_reco_tsa));
  75. memcpy(ets->reco_prio_tc, dcbxcfg->etscfg.prioritytable,
  76. sizeof(ets->reco_prio_tc));
  77. return 0;
  78. }
  79. /**
  80. * i40e_dcbnl_ieee_getpfc - retrieve local IEEE PFC configuration
  81. * @netdev: the corresponding netdev
  82. * @ets: structure to hold the PFC information
  83. *
  84. * Returns local IEEE PFC configuration
  85. **/
  86. static int i40e_dcbnl_ieee_getpfc(struct net_device *dev,
  87. struct ieee_pfc *pfc)
  88. {
  89. struct i40e_pf *pf = i40e_netdev_to_pf(dev);
  90. struct i40e_dcbx_config *dcbxcfg;
  91. struct i40e_hw *hw = &pf->hw;
  92. int i;
  93. if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
  94. return -EINVAL;
  95. dcbxcfg = &hw->local_dcbx_config;
  96. pfc->pfc_cap = dcbxcfg->pfc.pfccap;
  97. pfc->pfc_en = dcbxcfg->pfc.pfcenable;
  98. pfc->mbc = dcbxcfg->pfc.mbc;
  99. i40e_get_pfc_delay(hw, &pfc->delay);
  100. /* Get Requests/Indicatiosn */
  101. for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
  102. pfc->requests[i] = pf->stats.priority_xoff_tx[i];
  103. pfc->indications[i] = pf->stats.priority_xoff_rx[i];
  104. }
  105. return 0;
  106. }
  107. /**
  108. * i40e_dcbnl_getdcbx - retrieve current DCBx capability
  109. * @netdev: the corresponding netdev
  110. *
  111. * Returns DCBx capability features
  112. **/
  113. static u8 i40e_dcbnl_getdcbx(struct net_device *dev)
  114. {
  115. struct i40e_pf *pf = i40e_netdev_to_pf(dev);
  116. return pf->dcbx_cap;
  117. }
  118. /**
  119. * i40e_dcbnl_get_perm_hw_addr - MAC address used by DCBx
  120. * @netdev: the corresponding netdev
  121. *
  122. * Returns the SAN MAC address used for LLDP exchange
  123. **/
  124. static void i40e_dcbnl_get_perm_hw_addr(struct net_device *dev,
  125. u8 *perm_addr)
  126. {
  127. struct i40e_pf *pf = i40e_netdev_to_pf(dev);
  128. int i, j;
  129. memset(perm_addr, 0xff, MAX_ADDR_LEN);
  130. for (i = 0; i < dev->addr_len; i++)
  131. perm_addr[i] = pf->hw.mac.perm_addr[i];
  132. for (j = 0; j < dev->addr_len; j++, i++)
  133. perm_addr[i] = pf->hw.mac.san_addr[j];
  134. }
  135. static const struct dcbnl_rtnl_ops dcbnl_ops = {
  136. .ieee_getets = i40e_dcbnl_ieee_getets,
  137. .ieee_getpfc = i40e_dcbnl_ieee_getpfc,
  138. .getdcbx = i40e_dcbnl_getdcbx,
  139. .getpermhwaddr = i40e_dcbnl_get_perm_hw_addr,
  140. };
  141. /**
  142. * i40e_dcbnl_set_all - set all the apps and ieee data from DCBx config
  143. * @vsi: the corresponding vsi
  144. *
  145. * Set up all the IEEE APPs in the DCBNL App Table and generate event for
  146. * other settings
  147. **/
  148. void i40e_dcbnl_set_all(struct i40e_vsi *vsi)
  149. {
  150. struct net_device *dev = vsi->netdev;
  151. struct i40e_pf *pf = i40e_netdev_to_pf(dev);
  152. struct i40e_dcbx_config *dcbxcfg;
  153. struct i40e_hw *hw = &pf->hw;
  154. struct dcb_app sapp;
  155. u8 prio, tc_map;
  156. int i;
  157. /* DCB not enabled */
  158. if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
  159. return;
  160. /* MFP mode but not an iSCSI PF so return */
  161. if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(pf->hw.func_caps.iscsi))
  162. return;
  163. dcbxcfg = &hw->local_dcbx_config;
  164. /* Set up all the App TLVs if DCBx is negotiated */
  165. for (i = 0; i < dcbxcfg->numapps; i++) {
  166. prio = dcbxcfg->app[i].priority;
  167. tc_map = BIT(dcbxcfg->etscfg.prioritytable[prio]);
  168. /* Add APP only if the TC is enabled for this VSI */
  169. if (tc_map & vsi->tc_config.enabled_tc) {
  170. sapp.selector = dcbxcfg->app[i].selector;
  171. sapp.protocol = dcbxcfg->app[i].protocolid;
  172. sapp.priority = prio;
  173. dcb_ieee_setapp(dev, &sapp);
  174. }
  175. }
  176. /* Notify user-space of the changes */
  177. dcbnl_ieee_notify(dev, RTM_SETDCB, DCB_CMD_IEEE_SET, 0, 0);
  178. }
  179. /**
  180. * i40e_dcbnl_vsi_del_app - Delete APP for given VSI
  181. * @vsi: the corresponding vsi
  182. * @app: APP to delete
  183. *
  184. * Delete given APP from the DCBNL APP table for given
  185. * VSI
  186. **/
  187. static int i40e_dcbnl_vsi_del_app(struct i40e_vsi *vsi,
  188. struct i40e_dcb_app_priority_table *app)
  189. {
  190. struct net_device *dev = vsi->netdev;
  191. struct dcb_app sapp;
  192. if (!dev)
  193. return -EINVAL;
  194. sapp.selector = app->selector;
  195. sapp.protocol = app->protocolid;
  196. sapp.priority = app->priority;
  197. return dcb_ieee_delapp(dev, &sapp);
  198. }
  199. /**
  200. * i40e_dcbnl_del_app - Delete APP on all VSIs
  201. * @pf: the corresponding PF
  202. * @app: APP to delete
  203. *
  204. * Delete given APP from all the VSIs for given PF
  205. **/
  206. static void i40e_dcbnl_del_app(struct i40e_pf *pf,
  207. struct i40e_dcb_app_priority_table *app)
  208. {
  209. int v, err;
  210. for (v = 0; v < pf->num_alloc_vsi; v++) {
  211. if (pf->vsi[v] && pf->vsi[v]->netdev) {
  212. err = i40e_dcbnl_vsi_del_app(pf->vsi[v], app);
  213. dev_dbg(&pf->pdev->dev, "Deleting app for VSI seid=%d err=%d sel=%d proto=0x%x prio=%d\n",
  214. pf->vsi[v]->seid, err, app->selector,
  215. app->protocolid, app->priority);
  216. }
  217. }
  218. }
  219. /**
  220. * i40e_dcbnl_find_app - Search APP in given DCB config
  221. * @cfg: DCBX configuration data
  222. * @app: APP to search for
  223. *
  224. * Find given APP in the DCB configuration
  225. **/
  226. static bool i40e_dcbnl_find_app(struct i40e_dcbx_config *cfg,
  227. struct i40e_dcb_app_priority_table *app)
  228. {
  229. int i;
  230. for (i = 0; i < cfg->numapps; i++) {
  231. if (app->selector == cfg->app[i].selector &&
  232. app->protocolid == cfg->app[i].protocolid &&
  233. app->priority == cfg->app[i].priority)
  234. return true;
  235. }
  236. return false;
  237. }
  238. /**
  239. * i40e_dcbnl_flush_apps - Delete all removed APPs
  240. * @pf: the corresponding PF
  241. * @old_cfg: old DCBX configuration data
  242. * @new_cfg: new DCBX configuration data
  243. *
  244. * Find and delete all APPs that are not present in the passed
  245. * DCB configuration
  246. **/
  247. void i40e_dcbnl_flush_apps(struct i40e_pf *pf,
  248. struct i40e_dcbx_config *old_cfg,
  249. struct i40e_dcbx_config *new_cfg)
  250. {
  251. struct i40e_dcb_app_priority_table app;
  252. int i;
  253. /* MFP mode but not an iSCSI PF so return */
  254. if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(pf->hw.func_caps.iscsi))
  255. return;
  256. for (i = 0; i < old_cfg->numapps; i++) {
  257. app = old_cfg->app[i];
  258. /* The APP is not available anymore delete it */
  259. if (!i40e_dcbnl_find_app(new_cfg, &app))
  260. i40e_dcbnl_del_app(pf, &app);
  261. }
  262. }
  263. /**
  264. * i40e_dcbnl_setup - DCBNL setup
  265. * @vsi: the corresponding vsi
  266. *
  267. * Set up DCBNL ops and initial APP TLVs
  268. **/
  269. void i40e_dcbnl_setup(struct i40e_vsi *vsi)
  270. {
  271. struct net_device *dev = vsi->netdev;
  272. struct i40e_pf *pf = i40e_netdev_to_pf(dev);
  273. /* Not DCB capable */
  274. if (!(pf->flags & I40E_FLAG_DCB_CAPABLE))
  275. return;
  276. dev->dcbnl_ops = &dcbnl_ops;
  277. /* Set initial IEEE DCB settings */
  278. i40e_dcbnl_set_all(vsi);
  279. }
  280. #endif /* CONFIG_I40E_DCB */