fm10k_vf.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. /* Intel(R) Ethernet Switch Host Interface Driver
  2. * Copyright(c) 2013 - 2016 Intel Corporation.
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms and conditions of the GNU General Public License,
  6. * version 2, as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope it will be useful, but WITHOUT
  9. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11. * more details.
  12. *
  13. * The full GNU General Public License is included in this distribution in
  14. * the file called "COPYING".
  15. *
  16. * Contact Information:
  17. * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
  18. * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  19. */
  20. #include "fm10k_vf.h"
  21. /**
  22. * fm10k_stop_hw_vf - Stop Tx/Rx units
  23. * @hw: pointer to hardware structure
  24. *
  25. **/
  26. static s32 fm10k_stop_hw_vf(struct fm10k_hw *hw)
  27. {
  28. u8 *perm_addr = hw->mac.perm_addr;
  29. u32 bal = 0, bah = 0, tdlen;
  30. s32 err;
  31. u16 i;
  32. /* we need to disable the queues before taking further steps */
  33. err = fm10k_stop_hw_generic(hw);
  34. if (err && err != FM10K_ERR_REQUESTS_PENDING)
  35. return err;
  36. /* If permanent address is set then we need to restore it */
  37. if (is_valid_ether_addr(perm_addr)) {
  38. bal = (((u32)perm_addr[3]) << 24) |
  39. (((u32)perm_addr[4]) << 16) |
  40. (((u32)perm_addr[5]) << 8);
  41. bah = (((u32)0xFF) << 24) |
  42. (((u32)perm_addr[0]) << 16) |
  43. (((u32)perm_addr[1]) << 8) |
  44. ((u32)perm_addr[2]);
  45. }
  46. /* restore default itr_scale for next VF initialization */
  47. tdlen = hw->mac.itr_scale << FM10K_TDLEN_ITR_SCALE_SHIFT;
  48. /* The queues have already been disabled so we just need to
  49. * update their base address registers
  50. */
  51. for (i = 0; i < hw->mac.max_queues; i++) {
  52. fm10k_write_reg(hw, FM10K_TDBAL(i), bal);
  53. fm10k_write_reg(hw, FM10K_TDBAH(i), bah);
  54. fm10k_write_reg(hw, FM10K_RDBAL(i), bal);
  55. fm10k_write_reg(hw, FM10K_RDBAH(i), bah);
  56. /* Restore ITR scale in software-defined mechanism in TDLEN
  57. * for next VF initialization. See definition of
  58. * FM10K_TDLEN_ITR_SCALE_SHIFT for more details on the use of
  59. * TDLEN here.
  60. */
  61. fm10k_write_reg(hw, FM10K_TDLEN(i), tdlen);
  62. }
  63. return err;
  64. }
  65. /**
  66. * fm10k_reset_hw_vf - VF hardware reset
  67. * @hw: pointer to hardware structure
  68. *
  69. * This function should return the hardware to a state similar to the
  70. * one it is in after just being initialized.
  71. **/
  72. static s32 fm10k_reset_hw_vf(struct fm10k_hw *hw)
  73. {
  74. s32 err;
  75. /* shut down queues we own and reset DMA configuration */
  76. err = fm10k_stop_hw_vf(hw);
  77. if (err == FM10K_ERR_REQUESTS_PENDING)
  78. hw->mac.reset_while_pending++;
  79. else if (err)
  80. return err;
  81. /* Inititate VF reset */
  82. fm10k_write_reg(hw, FM10K_VFCTRL, FM10K_VFCTRL_RST);
  83. /* Flush write and allow 100us for reset to complete */
  84. fm10k_write_flush(hw);
  85. udelay(FM10K_RESET_TIMEOUT);
  86. /* Clear reset bit and verify it was cleared */
  87. fm10k_write_reg(hw, FM10K_VFCTRL, 0);
  88. if (fm10k_read_reg(hw, FM10K_VFCTRL) & FM10K_VFCTRL_RST)
  89. return FM10K_ERR_RESET_FAILED;
  90. return 0;
  91. }
  92. /**
  93. * fm10k_init_hw_vf - VF hardware initialization
  94. * @hw: pointer to hardware structure
  95. *
  96. **/
  97. static s32 fm10k_init_hw_vf(struct fm10k_hw *hw)
  98. {
  99. u32 tqdloc, tqdloc0 = ~fm10k_read_reg(hw, FM10K_TQDLOC(0));
  100. s32 err;
  101. u16 i;
  102. /* verify we have at least 1 queue */
  103. if (!~fm10k_read_reg(hw, FM10K_TXQCTL(0)) ||
  104. !~fm10k_read_reg(hw, FM10K_RXQCTL(0))) {
  105. err = FM10K_ERR_NO_RESOURCES;
  106. goto reset_max_queues;
  107. }
  108. /* determine how many queues we have */
  109. for (i = 1; tqdloc0 && (i < FM10K_MAX_QUEUES_POOL); i++) {
  110. /* verify the Descriptor cache offsets are increasing */
  111. tqdloc = ~fm10k_read_reg(hw, FM10K_TQDLOC(i));
  112. if (!tqdloc || (tqdloc == tqdloc0))
  113. break;
  114. /* check to verify the PF doesn't own any of our queues */
  115. if (!~fm10k_read_reg(hw, FM10K_TXQCTL(i)) ||
  116. !~fm10k_read_reg(hw, FM10K_RXQCTL(i)))
  117. break;
  118. }
  119. /* shut down queues we own and reset DMA configuration */
  120. err = fm10k_disable_queues_generic(hw, i);
  121. if (err)
  122. goto reset_max_queues;
  123. /* record maximum queue count */
  124. hw->mac.max_queues = i;
  125. /* fetch default VLAN and ITR scale */
  126. hw->mac.default_vid = (fm10k_read_reg(hw, FM10K_TXQCTL(0)) &
  127. FM10K_TXQCTL_VID_MASK) >> FM10K_TXQCTL_VID_SHIFT;
  128. /* Read the ITR scale from TDLEN. See the definition of
  129. * FM10K_TDLEN_ITR_SCALE_SHIFT for more information about how TDLEN is
  130. * used here.
  131. */
  132. hw->mac.itr_scale = (fm10k_read_reg(hw, FM10K_TDLEN(0)) &
  133. FM10K_TDLEN_ITR_SCALE_MASK) >>
  134. FM10K_TDLEN_ITR_SCALE_SHIFT;
  135. return 0;
  136. reset_max_queues:
  137. hw->mac.max_queues = 0;
  138. return err;
  139. }
  140. /* This structure defines the attibutes to be parsed below */
  141. const struct fm10k_tlv_attr fm10k_mac_vlan_msg_attr[] = {
  142. FM10K_TLV_ATTR_U32(FM10K_MAC_VLAN_MSG_VLAN),
  143. FM10K_TLV_ATTR_BOOL(FM10K_MAC_VLAN_MSG_SET),
  144. FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_MAC),
  145. FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_DEFAULT_MAC),
  146. FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_MULTICAST),
  147. FM10K_TLV_ATTR_LAST
  148. };
  149. /**
  150. * fm10k_update_vlan_vf - Update status of VLAN ID in VLAN filter table
  151. * @hw: pointer to hardware structure
  152. * @vid: VLAN ID to add to table
  153. * @vsi: Reserved, should always be 0
  154. * @set: Indicates if this is a set or clear operation
  155. *
  156. * This function adds or removes the corresponding VLAN ID from the VLAN
  157. * filter table for this VF.
  158. **/
  159. static s32 fm10k_update_vlan_vf(struct fm10k_hw *hw, u32 vid, u8 vsi, bool set)
  160. {
  161. struct fm10k_mbx_info *mbx = &hw->mbx;
  162. u32 msg[4];
  163. /* verify the index is not set */
  164. if (vsi)
  165. return FM10K_ERR_PARAM;
  166. /* clever trick to verify reserved bits in both vid and length */
  167. if ((vid << 16 | vid) >> 28)
  168. return FM10K_ERR_PARAM;
  169. /* encode set bit into the VLAN ID */
  170. if (!set)
  171. vid |= FM10K_VLAN_CLEAR;
  172. /* generate VLAN request */
  173. fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN);
  174. fm10k_tlv_attr_put_u32(msg, FM10K_MAC_VLAN_MSG_VLAN, vid);
  175. /* load onto outgoing mailbox */
  176. return mbx->ops.enqueue_tx(hw, mbx, msg);
  177. }
  178. /**
  179. * fm10k_msg_mac_vlan_vf - Read device MAC address from mailbox message
  180. * @hw: pointer to the HW structure
  181. * @results: Attributes for message
  182. * @mbx: unused mailbox data
  183. *
  184. * This function should determine the MAC address for the VF
  185. **/
  186. s32 fm10k_msg_mac_vlan_vf(struct fm10k_hw *hw, u32 **results,
  187. struct fm10k_mbx_info *mbx)
  188. {
  189. u8 perm_addr[ETH_ALEN];
  190. u16 vid;
  191. s32 err;
  192. /* record MAC address requested */
  193. err = fm10k_tlv_attr_get_mac_vlan(
  194. results[FM10K_MAC_VLAN_MSG_DEFAULT_MAC],
  195. perm_addr, &vid);
  196. if (err)
  197. return err;
  198. ether_addr_copy(hw->mac.perm_addr, perm_addr);
  199. hw->mac.default_vid = vid & (FM10K_VLAN_TABLE_VID_MAX - 1);
  200. hw->mac.vlan_override = !!(vid & FM10K_VLAN_OVERRIDE);
  201. return 0;
  202. }
  203. /**
  204. * fm10k_read_mac_addr_vf - Read device MAC address
  205. * @hw: pointer to the HW structure
  206. *
  207. * This function should determine the MAC address for the VF
  208. **/
  209. static s32 fm10k_read_mac_addr_vf(struct fm10k_hw *hw)
  210. {
  211. u8 perm_addr[ETH_ALEN];
  212. u32 base_addr;
  213. base_addr = fm10k_read_reg(hw, FM10K_TDBAL(0));
  214. /* last byte should be 0 */
  215. if (base_addr << 24)
  216. return FM10K_ERR_INVALID_MAC_ADDR;
  217. perm_addr[3] = (u8)(base_addr >> 24);
  218. perm_addr[4] = (u8)(base_addr >> 16);
  219. perm_addr[5] = (u8)(base_addr >> 8);
  220. base_addr = fm10k_read_reg(hw, FM10K_TDBAH(0));
  221. /* first byte should be all 1's */
  222. if ((~base_addr) >> 24)
  223. return FM10K_ERR_INVALID_MAC_ADDR;
  224. perm_addr[0] = (u8)(base_addr >> 16);
  225. perm_addr[1] = (u8)(base_addr >> 8);
  226. perm_addr[2] = (u8)(base_addr);
  227. ether_addr_copy(hw->mac.perm_addr, perm_addr);
  228. ether_addr_copy(hw->mac.addr, perm_addr);
  229. return 0;
  230. }
  231. /**
  232. * fm10k_update_uc_addr_vf - Update device unicast addresses
  233. * @hw: pointer to the HW structure
  234. * @glort: unused
  235. * @mac: MAC address to add/remove from table
  236. * @vid: VLAN ID to add/remove from table
  237. * @add: Indicates if this is an add or remove operation
  238. * @flags: flags field to indicate add and secure - unused
  239. *
  240. * This function is used to add or remove unicast MAC addresses for
  241. * the VF.
  242. **/
  243. static s32 fm10k_update_uc_addr_vf(struct fm10k_hw *hw, u16 glort,
  244. const u8 *mac, u16 vid, bool add, u8 flags)
  245. {
  246. struct fm10k_mbx_info *mbx = &hw->mbx;
  247. u32 msg[7];
  248. /* verify VLAN ID is valid */
  249. if (vid >= FM10K_VLAN_TABLE_VID_MAX)
  250. return FM10K_ERR_PARAM;
  251. /* verify MAC address is valid */
  252. if (!is_valid_ether_addr(mac))
  253. return FM10K_ERR_PARAM;
  254. /* verify we are not locked down on the MAC address */
  255. if (is_valid_ether_addr(hw->mac.perm_addr) &&
  256. !ether_addr_equal(hw->mac.perm_addr, mac))
  257. return FM10K_ERR_PARAM;
  258. /* add bit to notify us if this is a set or clear operation */
  259. if (!add)
  260. vid |= FM10K_VLAN_CLEAR;
  261. /* generate VLAN request */
  262. fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN);
  263. fm10k_tlv_attr_put_mac_vlan(msg, FM10K_MAC_VLAN_MSG_MAC, mac, vid);
  264. /* load onto outgoing mailbox */
  265. return mbx->ops.enqueue_tx(hw, mbx, msg);
  266. }
  267. /**
  268. * fm10k_update_mc_addr_vf - Update device multicast addresses
  269. * @hw: pointer to the HW structure
  270. * @glort: unused
  271. * @mac: MAC address to add/remove from table
  272. * @vid: VLAN ID to add/remove from table
  273. * @add: Indicates if this is an add or remove operation
  274. *
  275. * This function is used to add or remove multicast MAC addresses for
  276. * the VF.
  277. **/
  278. static s32 fm10k_update_mc_addr_vf(struct fm10k_hw *hw, u16 glort,
  279. const u8 *mac, u16 vid, bool add)
  280. {
  281. struct fm10k_mbx_info *mbx = &hw->mbx;
  282. u32 msg[7];
  283. /* verify VLAN ID is valid */
  284. if (vid >= FM10K_VLAN_TABLE_VID_MAX)
  285. return FM10K_ERR_PARAM;
  286. /* verify multicast address is valid */
  287. if (!is_multicast_ether_addr(mac))
  288. return FM10K_ERR_PARAM;
  289. /* add bit to notify us if this is a set or clear operation */
  290. if (!add)
  291. vid |= FM10K_VLAN_CLEAR;
  292. /* generate VLAN request */
  293. fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN);
  294. fm10k_tlv_attr_put_mac_vlan(msg, FM10K_MAC_VLAN_MSG_MULTICAST,
  295. mac, vid);
  296. /* load onto outgoing mailbox */
  297. return mbx->ops.enqueue_tx(hw, mbx, msg);
  298. }
  299. /**
  300. * fm10k_update_int_moderator_vf - Request update of interrupt moderator list
  301. * @hw: pointer to hardware structure
  302. *
  303. * This function will issue a request to the PF to rescan our MSI-X table
  304. * and to update the interrupt moderator linked list.
  305. **/
  306. static void fm10k_update_int_moderator_vf(struct fm10k_hw *hw)
  307. {
  308. struct fm10k_mbx_info *mbx = &hw->mbx;
  309. u32 msg[1];
  310. /* generate MSI-X request */
  311. fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MSIX);
  312. /* load onto outgoing mailbox */
  313. mbx->ops.enqueue_tx(hw, mbx, msg);
  314. }
  315. /* This structure defines the attibutes to be parsed below */
  316. const struct fm10k_tlv_attr fm10k_lport_state_msg_attr[] = {
  317. FM10K_TLV_ATTR_BOOL(FM10K_LPORT_STATE_MSG_DISABLE),
  318. FM10K_TLV_ATTR_U8(FM10K_LPORT_STATE_MSG_XCAST_MODE),
  319. FM10K_TLV_ATTR_BOOL(FM10K_LPORT_STATE_MSG_READY),
  320. FM10K_TLV_ATTR_LAST
  321. };
  322. /**
  323. * fm10k_msg_lport_state_vf - Message handler for lport_state message from PF
  324. * @hw: Pointer to hardware structure
  325. * @results: pointer array containing parsed data
  326. * @mbx: Pointer to mailbox information structure
  327. *
  328. * This handler is meant to capture the indication from the PF that we
  329. * are ready to bring up the interface.
  330. **/
  331. s32 fm10k_msg_lport_state_vf(struct fm10k_hw *hw, u32 **results,
  332. struct fm10k_mbx_info *mbx)
  333. {
  334. hw->mac.dglort_map = !results[FM10K_LPORT_STATE_MSG_READY] ?
  335. FM10K_DGLORTMAP_NONE : FM10K_DGLORTMAP_ZERO;
  336. return 0;
  337. }
  338. /**
  339. * fm10k_update_lport_state_vf - Update device state in lower device
  340. * @hw: pointer to the HW structure
  341. * @glort: unused
  342. * @count: number of logical ports to enable - unused (always 1)
  343. * @enable: boolean value indicating if this is an enable or disable request
  344. *
  345. * Notify the lower device of a state change. If the lower device is
  346. * enabled we can add filters, if it is disabled all filters for this
  347. * logical port are flushed.
  348. **/
  349. static s32 fm10k_update_lport_state_vf(struct fm10k_hw *hw, u16 glort,
  350. u16 count, bool enable)
  351. {
  352. struct fm10k_mbx_info *mbx = &hw->mbx;
  353. u32 msg[2];
  354. /* reset glort mask 0 as we have to wait to be enabled */
  355. hw->mac.dglort_map = FM10K_DGLORTMAP_NONE;
  356. /* generate port state request */
  357. fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE);
  358. if (!enable)
  359. fm10k_tlv_attr_put_bool(msg, FM10K_LPORT_STATE_MSG_DISABLE);
  360. /* load onto outgoing mailbox */
  361. return mbx->ops.enqueue_tx(hw, mbx, msg);
  362. }
  363. /**
  364. * fm10k_update_xcast_mode_vf - Request update of multicast mode
  365. * @hw: pointer to hardware structure
  366. * @glort: unused
  367. * @mode: integer value indicating mode being requested
  368. *
  369. * This function will attempt to request a higher mode for the port
  370. * so that it can enable either multicast, multicast promiscuous, or
  371. * promiscuous mode of operation.
  372. **/
  373. static s32 fm10k_update_xcast_mode_vf(struct fm10k_hw *hw, u16 glort, u8 mode)
  374. {
  375. struct fm10k_mbx_info *mbx = &hw->mbx;
  376. u32 msg[3];
  377. if (mode > FM10K_XCAST_MODE_NONE)
  378. return FM10K_ERR_PARAM;
  379. /* generate message requesting to change xcast mode */
  380. fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE);
  381. fm10k_tlv_attr_put_u8(msg, FM10K_LPORT_STATE_MSG_XCAST_MODE, mode);
  382. /* load onto outgoing mailbox */
  383. return mbx->ops.enqueue_tx(hw, mbx, msg);
  384. }
  385. /**
  386. * fm10k_update_hw_stats_vf - Updates hardware related statistics of VF
  387. * @hw: pointer to hardware structure
  388. * @stats: pointer to statistics structure
  389. *
  390. * This function collects and aggregates per queue hardware statistics.
  391. **/
  392. static void fm10k_update_hw_stats_vf(struct fm10k_hw *hw,
  393. struct fm10k_hw_stats *stats)
  394. {
  395. fm10k_update_hw_stats_q(hw, stats->q, 0, hw->mac.max_queues);
  396. }
  397. /**
  398. * fm10k_rebind_hw_stats_vf - Resets base for hardware statistics of VF
  399. * @hw: pointer to hardware structure
  400. * @stats: pointer to the stats structure to update
  401. *
  402. * This function resets the base for queue hardware statistics.
  403. **/
  404. static void fm10k_rebind_hw_stats_vf(struct fm10k_hw *hw,
  405. struct fm10k_hw_stats *stats)
  406. {
  407. /* Unbind Queue Statistics */
  408. fm10k_unbind_hw_stats_q(stats->q, 0, hw->mac.max_queues);
  409. /* Reinitialize bases for all stats */
  410. fm10k_update_hw_stats_vf(hw, stats);
  411. }
  412. /**
  413. * fm10k_configure_dglort_map_vf - Configures GLORT entry and queues
  414. * @hw: pointer to hardware structure
  415. * @dglort: pointer to dglort configuration structure
  416. *
  417. * Reads the configuration structure contained in dglort_cfg and uses
  418. * that information to then populate a DGLORTMAP/DEC entry and the queues
  419. * to which it has been assigned.
  420. **/
  421. static s32 fm10k_configure_dglort_map_vf(struct fm10k_hw *hw,
  422. struct fm10k_dglort_cfg *dglort)
  423. {
  424. /* verify the dglort pointer */
  425. if (!dglort)
  426. return FM10K_ERR_PARAM;
  427. /* stub for now until we determine correct message for this */
  428. return 0;
  429. }
  430. static const struct fm10k_msg_data fm10k_msg_data_vf[] = {
  431. FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test),
  432. FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_msg_mac_vlan_vf),
  433. FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_msg_lport_state_vf),
  434. FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error),
  435. };
  436. static const struct fm10k_mac_ops mac_ops_vf = {
  437. .get_bus_info = fm10k_get_bus_info_generic,
  438. .reset_hw = fm10k_reset_hw_vf,
  439. .init_hw = fm10k_init_hw_vf,
  440. .start_hw = fm10k_start_hw_generic,
  441. .stop_hw = fm10k_stop_hw_vf,
  442. .update_vlan = fm10k_update_vlan_vf,
  443. .read_mac_addr = fm10k_read_mac_addr_vf,
  444. .update_uc_addr = fm10k_update_uc_addr_vf,
  445. .update_mc_addr = fm10k_update_mc_addr_vf,
  446. .update_xcast_mode = fm10k_update_xcast_mode_vf,
  447. .update_int_moderator = fm10k_update_int_moderator_vf,
  448. .update_lport_state = fm10k_update_lport_state_vf,
  449. .update_hw_stats = fm10k_update_hw_stats_vf,
  450. .rebind_hw_stats = fm10k_rebind_hw_stats_vf,
  451. .configure_dglort_map = fm10k_configure_dglort_map_vf,
  452. .get_host_state = fm10k_get_host_state_generic,
  453. };
  454. static s32 fm10k_get_invariants_vf(struct fm10k_hw *hw)
  455. {
  456. fm10k_get_invariants_generic(hw);
  457. return fm10k_pfvf_mbx_init(hw, &hw->mbx, fm10k_msg_data_vf, 0);
  458. }
  459. const struct fm10k_info fm10k_vf_info = {
  460. .mac = fm10k_mac_vf,
  461. .get_invariants = fm10k_get_invariants_vf,
  462. .mac_ops = &mac_ops_vf,
  463. };