1ae06c70bSJeff Kirsher // SPDX-License-Identifier: GPL-2.0
2d5c2f395SJacob Keller /* Copyright(c) 2013 - 2019 Intel Corporation. */
35cb8db4aSAlexander Duyck
4e383353bSJesse Brandeburg #include <linux/bitfield.h>
55cb8db4aSAlexander Duyck #include "fm10k_vf.h"
65cb8db4aSAlexander Duyck
75cb8db4aSAlexander Duyck /**
85cb8db4aSAlexander Duyck * fm10k_stop_hw_vf - Stop Tx/Rx units
95cb8db4aSAlexander Duyck * @hw: pointer to hardware structure
105cb8db4aSAlexander Duyck *
115cb8db4aSAlexander Duyck **/
fm10k_stop_hw_vf(struct fm10k_hw * hw)125cb8db4aSAlexander Duyck static s32 fm10k_stop_hw_vf(struct fm10k_hw *hw)
135cb8db4aSAlexander Duyck {
145cb8db4aSAlexander Duyck u8 *perm_addr = hw->mac.perm_addr;
1520076fa1SJacob Keller u32 bal = 0, bah = 0, tdlen;
165cb8db4aSAlexander Duyck s32 err;
175cb8db4aSAlexander Duyck u16 i;
185cb8db4aSAlexander Duyck
195cb8db4aSAlexander Duyck /* we need to disable the queues before taking further steps */
205cb8db4aSAlexander Duyck err = fm10k_stop_hw_generic(hw);
21ce33624fSJacob Keller if (err && err != FM10K_ERR_REQUESTS_PENDING)
225cb8db4aSAlexander Duyck return err;
235cb8db4aSAlexander Duyck
24eca32047SMatthew Vick /* If permanent address is set then we need to restore it */
255cb8db4aSAlexander Duyck if (is_valid_ether_addr(perm_addr)) {
265cb8db4aSAlexander Duyck bal = (((u32)perm_addr[3]) << 24) |
275cb8db4aSAlexander Duyck (((u32)perm_addr[4]) << 16) |
285cb8db4aSAlexander Duyck (((u32)perm_addr[5]) << 8);
295cb8db4aSAlexander Duyck bah = (((u32)0xFF) << 24) |
305cb8db4aSAlexander Duyck (((u32)perm_addr[0]) << 16) |
315cb8db4aSAlexander Duyck (((u32)perm_addr[1]) << 8) |
325cb8db4aSAlexander Duyck ((u32)perm_addr[2]);
335cb8db4aSAlexander Duyck }
345cb8db4aSAlexander Duyck
3520076fa1SJacob Keller /* restore default itr_scale for next VF initialization */
3620076fa1SJacob Keller tdlen = hw->mac.itr_scale << FM10K_TDLEN_ITR_SCALE_SHIFT;
3720076fa1SJacob Keller
385cb8db4aSAlexander Duyck /* The queues have already been disabled so we just need to
395cb8db4aSAlexander Duyck * update their base address registers
405cb8db4aSAlexander Duyck */
415cb8db4aSAlexander Duyck for (i = 0; i < hw->mac.max_queues; i++) {
425cb8db4aSAlexander Duyck fm10k_write_reg(hw, FM10K_TDBAL(i), bal);
435cb8db4aSAlexander Duyck fm10k_write_reg(hw, FM10K_TDBAH(i), bah);
445cb8db4aSAlexander Duyck fm10k_write_reg(hw, FM10K_RDBAL(i), bal);
455cb8db4aSAlexander Duyck fm10k_write_reg(hw, FM10K_RDBAH(i), bah);
4620076fa1SJacob Keller /* Restore ITR scale in software-defined mechanism in TDLEN
4720076fa1SJacob Keller * for next VF initialization. See definition of
4820076fa1SJacob Keller * FM10K_TDLEN_ITR_SCALE_SHIFT for more details on the use of
4920076fa1SJacob Keller * TDLEN here.
5020076fa1SJacob Keller */
5120076fa1SJacob Keller fm10k_write_reg(hw, FM10K_TDLEN(i), tdlen);
525cb8db4aSAlexander Duyck }
535cb8db4aSAlexander Duyck
54ce33624fSJacob Keller return err;
555cb8db4aSAlexander Duyck }
565cb8db4aSAlexander Duyck
575cb8db4aSAlexander Duyck /**
585cb8db4aSAlexander Duyck * fm10k_reset_hw_vf - VF hardware reset
595cb8db4aSAlexander Duyck * @hw: pointer to hardware structure
605cb8db4aSAlexander Duyck *
61eca32047SMatthew Vick * This function should return the hardware to a state similar to the
625cb8db4aSAlexander Duyck * one it is in after just being initialized.
635cb8db4aSAlexander Duyck **/
fm10k_reset_hw_vf(struct fm10k_hw * hw)645cb8db4aSAlexander Duyck static s32 fm10k_reset_hw_vf(struct fm10k_hw *hw)
655cb8db4aSAlexander Duyck {
665cb8db4aSAlexander Duyck s32 err;
675cb8db4aSAlexander Duyck
685cb8db4aSAlexander Duyck /* shut down queues we own and reset DMA configuration */
695cb8db4aSAlexander Duyck err = fm10k_stop_hw_vf(hw);
70ce33624fSJacob Keller if (err == FM10K_ERR_REQUESTS_PENDING)
71ce33624fSJacob Keller hw->mac.reset_while_pending++;
72ce33624fSJacob Keller else if (err)
735cb8db4aSAlexander Duyck return err;
745cb8db4aSAlexander Duyck
755cb8db4aSAlexander Duyck /* Inititate VF reset */
765cb8db4aSAlexander Duyck fm10k_write_reg(hw, FM10K_VFCTRL, FM10K_VFCTRL_RST);
775cb8db4aSAlexander Duyck
785cb8db4aSAlexander Duyck /* Flush write and allow 100us for reset to complete */
795cb8db4aSAlexander Duyck fm10k_write_flush(hw);
805cb8db4aSAlexander Duyck udelay(FM10K_RESET_TIMEOUT);
815cb8db4aSAlexander Duyck
825cb8db4aSAlexander Duyck /* Clear reset bit and verify it was cleared */
835cb8db4aSAlexander Duyck fm10k_write_reg(hw, FM10K_VFCTRL, 0);
845cb8db4aSAlexander Duyck if (fm10k_read_reg(hw, FM10K_VFCTRL) & FM10K_VFCTRL_RST)
85ce33624fSJacob Keller return FM10K_ERR_RESET_FAILED;
865cb8db4aSAlexander Duyck
87ce33624fSJacob Keller return 0;
885cb8db4aSAlexander Duyck }
895cb8db4aSAlexander Duyck
905cb8db4aSAlexander Duyck /**
915cb8db4aSAlexander Duyck * fm10k_init_hw_vf - VF hardware initialization
925cb8db4aSAlexander Duyck * @hw: pointer to hardware structure
935cb8db4aSAlexander Duyck *
945cb8db4aSAlexander Duyck **/
fm10k_init_hw_vf(struct fm10k_hw * hw)955cb8db4aSAlexander Duyck static s32 fm10k_init_hw_vf(struct fm10k_hw *hw)
965cb8db4aSAlexander Duyck {
975cb8db4aSAlexander Duyck u32 tqdloc, tqdloc0 = ~fm10k_read_reg(hw, FM10K_TQDLOC(0));
985cb8db4aSAlexander Duyck s32 err;
995cb8db4aSAlexander Duyck u16 i;
1005cb8db4aSAlexander Duyck
1011340181fSJacob Keller /* verify we have at least 1 queue */
1021340181fSJacob Keller if (!~fm10k_read_reg(hw, FM10K_TXQCTL(0)) ||
1030e8d5b59SJacob Keller !~fm10k_read_reg(hw, FM10K_RXQCTL(0))) {
1040e8d5b59SJacob Keller err = FM10K_ERR_NO_RESOURCES;
1050e8d5b59SJacob Keller goto reset_max_queues;
1060e8d5b59SJacob Keller }
1071340181fSJacob Keller
1081340181fSJacob Keller /* determine how many queues we have */
1095cb8db4aSAlexander Duyck for (i = 1; tqdloc0 && (i < FM10K_MAX_QUEUES_POOL); i++) {
1105cb8db4aSAlexander Duyck /* verify the Descriptor cache offsets are increasing */
1115cb8db4aSAlexander Duyck tqdloc = ~fm10k_read_reg(hw, FM10K_TQDLOC(i));
1125cb8db4aSAlexander Duyck if (!tqdloc || (tqdloc == tqdloc0))
1135cb8db4aSAlexander Duyck break;
1145cb8db4aSAlexander Duyck
1155cb8db4aSAlexander Duyck /* check to verify the PF doesn't own any of our queues */
1165cb8db4aSAlexander Duyck if (!~fm10k_read_reg(hw, FM10K_TXQCTL(i)) ||
1175cb8db4aSAlexander Duyck !~fm10k_read_reg(hw, FM10K_RXQCTL(i)))
1185cb8db4aSAlexander Duyck break;
1195cb8db4aSAlexander Duyck }
1205cb8db4aSAlexander Duyck
1215cb8db4aSAlexander Duyck /* shut down queues we own and reset DMA configuration */
1225cb8db4aSAlexander Duyck err = fm10k_disable_queues_generic(hw, i);
1235cb8db4aSAlexander Duyck if (err)
1240e8d5b59SJacob Keller goto reset_max_queues;
1255cb8db4aSAlexander Duyck
1265cb8db4aSAlexander Duyck /* record maximum queue count */
1275cb8db4aSAlexander Duyck hw->mac.max_queues = i;
1285cb8db4aSAlexander Duyck
12920076fa1SJacob Keller /* fetch default VLAN and ITR scale */
130*d5752c7bSJesse Brandeburg hw->mac.default_vid = FIELD_GET(FM10K_TXQCTL_VID_MASK,
131*d5752c7bSJesse Brandeburg fm10k_read_reg(hw, FM10K_TXQCTL(0)));
13220076fa1SJacob Keller /* Read the ITR scale from TDLEN. See the definition of
13320076fa1SJacob Keller * FM10K_TDLEN_ITR_SCALE_SHIFT for more information about how TDLEN is
13420076fa1SJacob Keller * used here.
13520076fa1SJacob Keller */
136*d5752c7bSJesse Brandeburg hw->mac.itr_scale = FIELD_GET(FM10K_TDLEN_ITR_SCALE_MASK,
137*d5752c7bSJesse Brandeburg fm10k_read_reg(hw, FM10K_TDLEN(0)));
1384c16ceaeSJeff Kirsher
1395cb8db4aSAlexander Duyck return 0;
1400e8d5b59SJacob Keller
1410e8d5b59SJacob Keller reset_max_queues:
1420e8d5b59SJacob Keller hw->mac.max_queues = 0;
1430e8d5b59SJacob Keller
1440e8d5b59SJacob Keller return err;
1455cb8db4aSAlexander Duyck }
1465cb8db4aSAlexander Duyck
1475cb8db4aSAlexander Duyck /* This structure defines the attibutes to be parsed below */
1485cb8db4aSAlexander Duyck const struct fm10k_tlv_attr fm10k_mac_vlan_msg_attr[] = {
1495cb8db4aSAlexander Duyck FM10K_TLV_ATTR_U32(FM10K_MAC_VLAN_MSG_VLAN),
1505cb8db4aSAlexander Duyck FM10K_TLV_ATTR_BOOL(FM10K_MAC_VLAN_MSG_SET),
1515cb8db4aSAlexander Duyck FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_MAC),
1525cb8db4aSAlexander Duyck FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_DEFAULT_MAC),
1535cb8db4aSAlexander Duyck FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_MULTICAST),
1545cb8db4aSAlexander Duyck FM10K_TLV_ATTR_LAST
1555cb8db4aSAlexander Duyck };
1565cb8db4aSAlexander Duyck
1575cb8db4aSAlexander Duyck /**
1585cb8db4aSAlexander Duyck * fm10k_update_vlan_vf - Update status of VLAN ID in VLAN filter table
1595cb8db4aSAlexander Duyck * @hw: pointer to hardware structure
1605cb8db4aSAlexander Duyck * @vid: VLAN ID to add to table
1615cb8db4aSAlexander Duyck * @vsi: Reserved, should always be 0
1625cb8db4aSAlexander Duyck * @set: Indicates if this is a set or clear operation
1635cb8db4aSAlexander Duyck *
1645cb8db4aSAlexander Duyck * This function adds or removes the corresponding VLAN ID from the VLAN
1655cb8db4aSAlexander Duyck * filter table for this VF.
1665cb8db4aSAlexander Duyck **/
fm10k_update_vlan_vf(struct fm10k_hw * hw,u32 vid,u8 vsi,bool set)1675cb8db4aSAlexander Duyck static s32 fm10k_update_vlan_vf(struct fm10k_hw *hw, u32 vid, u8 vsi, bool set)
1685cb8db4aSAlexander Duyck {
1695cb8db4aSAlexander Duyck struct fm10k_mbx_info *mbx = &hw->mbx;
1705cb8db4aSAlexander Duyck u32 msg[4];
1715cb8db4aSAlexander Duyck
1725cb8db4aSAlexander Duyck /* verify the index is not set */
1735cb8db4aSAlexander Duyck if (vsi)
1745cb8db4aSAlexander Duyck return FM10K_ERR_PARAM;
1755cb8db4aSAlexander Duyck
176fb6515c8SJacob Keller /* clever trick to verify reserved bits in both vid and length */
1775cb8db4aSAlexander Duyck if ((vid << 16 | vid) >> 28)
1785cb8db4aSAlexander Duyck return FM10K_ERR_PARAM;
1795cb8db4aSAlexander Duyck
1805cb8db4aSAlexander Duyck /* encode set bit into the VLAN ID */
1815cb8db4aSAlexander Duyck if (!set)
1825cb8db4aSAlexander Duyck vid |= FM10K_VLAN_CLEAR;
1835cb8db4aSAlexander Duyck
1845cb8db4aSAlexander Duyck /* generate VLAN request */
1855cb8db4aSAlexander Duyck fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN);
1865cb8db4aSAlexander Duyck fm10k_tlv_attr_put_u32(msg, FM10K_MAC_VLAN_MSG_VLAN, vid);
1875cb8db4aSAlexander Duyck
1885cb8db4aSAlexander Duyck /* load onto outgoing mailbox */
1895cb8db4aSAlexander Duyck return mbx->ops.enqueue_tx(hw, mbx, msg);
1905cb8db4aSAlexander Duyck }
1915cb8db4aSAlexander Duyck
1925cb8db4aSAlexander Duyck /**
1935cb8db4aSAlexander Duyck * fm10k_msg_mac_vlan_vf - Read device MAC address from mailbox message
1945cb8db4aSAlexander Duyck * @hw: pointer to the HW structure
1955cb8db4aSAlexander Duyck * @results: Attributes for message
1965cb8db4aSAlexander Duyck * @mbx: unused mailbox data
1975cb8db4aSAlexander Duyck *
1985cb8db4aSAlexander Duyck * This function should determine the MAC address for the VF
1995cb8db4aSAlexander Duyck **/
fm10k_msg_mac_vlan_vf(struct fm10k_hw * hw,u32 ** results,struct fm10k_mbx_info __always_unused * mbx)2005cb8db4aSAlexander Duyck s32 fm10k_msg_mac_vlan_vf(struct fm10k_hw *hw, u32 **results,
201d5c2f395SJacob Keller struct fm10k_mbx_info __always_unused *mbx)
2025cb8db4aSAlexander Duyck {
2035cb8db4aSAlexander Duyck u8 perm_addr[ETH_ALEN];
2045cb8db4aSAlexander Duyck u16 vid;
2055cb8db4aSAlexander Duyck s32 err;
2065cb8db4aSAlexander Duyck
2075cb8db4aSAlexander Duyck /* record MAC address requested */
2085cb8db4aSAlexander Duyck err = fm10k_tlv_attr_get_mac_vlan(
2095cb8db4aSAlexander Duyck results[FM10K_MAC_VLAN_MSG_DEFAULT_MAC],
2105cb8db4aSAlexander Duyck perm_addr, &vid);
2115cb8db4aSAlexander Duyck if (err)
2125cb8db4aSAlexander Duyck return err;
2135cb8db4aSAlexander Duyck
2145cb8db4aSAlexander Duyck ether_addr_copy(hw->mac.perm_addr, perm_addr);
2155cb8db4aSAlexander Duyck hw->mac.default_vid = vid & (FM10K_VLAN_TABLE_VID_MAX - 1);
2165c69df8aSJacob Keller hw->mac.vlan_override = !!(vid & FM10K_VLAN_OVERRIDE);
2175cb8db4aSAlexander Duyck
2185cb8db4aSAlexander Duyck return 0;
2195cb8db4aSAlexander Duyck }
2205cb8db4aSAlexander Duyck
2215cb8db4aSAlexander Duyck /**
2225cb8db4aSAlexander Duyck * fm10k_read_mac_addr_vf - Read device MAC address
2235cb8db4aSAlexander Duyck * @hw: pointer to the HW structure
2245cb8db4aSAlexander Duyck *
2255cb8db4aSAlexander Duyck * This function should determine the MAC address for the VF
2265cb8db4aSAlexander Duyck **/
fm10k_read_mac_addr_vf(struct fm10k_hw * hw)2275cb8db4aSAlexander Duyck static s32 fm10k_read_mac_addr_vf(struct fm10k_hw *hw)
2285cb8db4aSAlexander Duyck {
2295cb8db4aSAlexander Duyck u8 perm_addr[ETH_ALEN];
2305cb8db4aSAlexander Duyck u32 base_addr;
2315cb8db4aSAlexander Duyck
2325cb8db4aSAlexander Duyck base_addr = fm10k_read_reg(hw, FM10K_TDBAL(0));
2335cb8db4aSAlexander Duyck
2345cb8db4aSAlexander Duyck /* last byte should be 0 */
2355cb8db4aSAlexander Duyck if (base_addr << 24)
2365cb8db4aSAlexander Duyck return FM10K_ERR_INVALID_MAC_ADDR;
2375cb8db4aSAlexander Duyck
2385cb8db4aSAlexander Duyck perm_addr[3] = (u8)(base_addr >> 24);
2395cb8db4aSAlexander Duyck perm_addr[4] = (u8)(base_addr >> 16);
2405cb8db4aSAlexander Duyck perm_addr[5] = (u8)(base_addr >> 8);
2415cb8db4aSAlexander Duyck
2425cb8db4aSAlexander Duyck base_addr = fm10k_read_reg(hw, FM10K_TDBAH(0));
2435cb8db4aSAlexander Duyck
2445cb8db4aSAlexander Duyck /* first byte should be all 1's */
2455cb8db4aSAlexander Duyck if ((~base_addr) >> 24)
2465cb8db4aSAlexander Duyck return FM10K_ERR_INVALID_MAC_ADDR;
2475cb8db4aSAlexander Duyck
2485cb8db4aSAlexander Duyck perm_addr[0] = (u8)(base_addr >> 16);
2495cb8db4aSAlexander Duyck perm_addr[1] = (u8)(base_addr >> 8);
2505cb8db4aSAlexander Duyck perm_addr[2] = (u8)(base_addr);
2515cb8db4aSAlexander Duyck
2525cb8db4aSAlexander Duyck ether_addr_copy(hw->mac.perm_addr, perm_addr);
2535cb8db4aSAlexander Duyck ether_addr_copy(hw->mac.addr, perm_addr);
2545cb8db4aSAlexander Duyck
2555cb8db4aSAlexander Duyck return 0;
2565cb8db4aSAlexander Duyck }
2575cb8db4aSAlexander Duyck
2585cb8db4aSAlexander Duyck /**
259eca32047SMatthew Vick * fm10k_update_uc_addr_vf - Update device unicast addresses
2605cb8db4aSAlexander Duyck * @hw: pointer to the HW structure
2615cb8db4aSAlexander Duyck * @glort: unused
2625cb8db4aSAlexander Duyck * @mac: MAC address to add/remove from table
2635cb8db4aSAlexander Duyck * @vid: VLAN ID to add/remove from table
2645cb8db4aSAlexander Duyck * @add: Indicates if this is an add or remove operation
2655cb8db4aSAlexander Duyck * @flags: flags field to indicate add and secure - unused
2665cb8db4aSAlexander Duyck *
2675cb8db4aSAlexander Duyck * This function is used to add or remove unicast MAC addresses for
2685cb8db4aSAlexander Duyck * the VF.
2695cb8db4aSAlexander Duyck **/
fm10k_update_uc_addr_vf(struct fm10k_hw * hw,u16 __always_unused glort,const u8 * mac,u16 vid,bool add,u8 __always_unused flags)270d5c2f395SJacob Keller static s32 fm10k_update_uc_addr_vf(struct fm10k_hw *hw,
271d5c2f395SJacob Keller u16 __always_unused glort,
272d5c2f395SJacob Keller const u8 *mac, u16 vid, bool add,
273d5c2f395SJacob Keller u8 __always_unused flags)
2745cb8db4aSAlexander Duyck {
2755cb8db4aSAlexander Duyck struct fm10k_mbx_info *mbx = &hw->mbx;
2765cb8db4aSAlexander Duyck u32 msg[7];
2775cb8db4aSAlexander Duyck
2785cb8db4aSAlexander Duyck /* verify VLAN ID is valid */
2795cb8db4aSAlexander Duyck if (vid >= FM10K_VLAN_TABLE_VID_MAX)
2805cb8db4aSAlexander Duyck return FM10K_ERR_PARAM;
2815cb8db4aSAlexander Duyck
2825cb8db4aSAlexander Duyck /* verify MAC address is valid */
2835cb8db4aSAlexander Duyck if (!is_valid_ether_addr(mac))
2845cb8db4aSAlexander Duyck return FM10K_ERR_PARAM;
2855cb8db4aSAlexander Duyck
2865cb8db4aSAlexander Duyck /* verify we are not locked down on the MAC address */
2875cb8db4aSAlexander Duyck if (is_valid_ether_addr(hw->mac.perm_addr) &&
2886186ddf0SJacob Keller !ether_addr_equal(hw->mac.perm_addr, mac))
2895cb8db4aSAlexander Duyck return FM10K_ERR_PARAM;
2905cb8db4aSAlexander Duyck
291eca32047SMatthew Vick /* add bit to notify us if this is a set or clear operation */
2925cb8db4aSAlexander Duyck if (!add)
2935cb8db4aSAlexander Duyck vid |= FM10K_VLAN_CLEAR;
2945cb8db4aSAlexander Duyck
2955cb8db4aSAlexander Duyck /* generate VLAN request */
2965cb8db4aSAlexander Duyck fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN);
2975cb8db4aSAlexander Duyck fm10k_tlv_attr_put_mac_vlan(msg, FM10K_MAC_VLAN_MSG_MAC, mac, vid);
2985cb8db4aSAlexander Duyck
2995cb8db4aSAlexander Duyck /* load onto outgoing mailbox */
3005cb8db4aSAlexander Duyck return mbx->ops.enqueue_tx(hw, mbx, msg);
3015cb8db4aSAlexander Duyck }
3025cb8db4aSAlexander Duyck
3035cb8db4aSAlexander Duyck /**
304eca32047SMatthew Vick * fm10k_update_mc_addr_vf - Update device multicast addresses
3055cb8db4aSAlexander Duyck * @hw: pointer to the HW structure
3065cb8db4aSAlexander Duyck * @glort: unused
3075cb8db4aSAlexander Duyck * @mac: MAC address to add/remove from table
3085cb8db4aSAlexander Duyck * @vid: VLAN ID to add/remove from table
3095cb8db4aSAlexander Duyck * @add: Indicates if this is an add or remove operation
3105cb8db4aSAlexander Duyck *
3115cb8db4aSAlexander Duyck * This function is used to add or remove multicast MAC addresses for
3125cb8db4aSAlexander Duyck * the VF.
3135cb8db4aSAlexander Duyck **/
fm10k_update_mc_addr_vf(struct fm10k_hw * hw,u16 __always_unused glort,const u8 * mac,u16 vid,bool add)314d5c2f395SJacob Keller static s32 fm10k_update_mc_addr_vf(struct fm10k_hw *hw,
315d5c2f395SJacob Keller u16 __always_unused glort,
3165cb8db4aSAlexander Duyck const u8 *mac, u16 vid, bool add)
3175cb8db4aSAlexander Duyck {
3185cb8db4aSAlexander Duyck struct fm10k_mbx_info *mbx = &hw->mbx;
3195cb8db4aSAlexander Duyck u32 msg[7];
3205cb8db4aSAlexander Duyck
3215cb8db4aSAlexander Duyck /* verify VLAN ID is valid */
3225cb8db4aSAlexander Duyck if (vid >= FM10K_VLAN_TABLE_VID_MAX)
3235cb8db4aSAlexander Duyck return FM10K_ERR_PARAM;
3245cb8db4aSAlexander Duyck
3255cb8db4aSAlexander Duyck /* verify multicast address is valid */
3265cb8db4aSAlexander Duyck if (!is_multicast_ether_addr(mac))
3275cb8db4aSAlexander Duyck return FM10K_ERR_PARAM;
3285cb8db4aSAlexander Duyck
329eca32047SMatthew Vick /* add bit to notify us if this is a set or clear operation */
3305cb8db4aSAlexander Duyck if (!add)
3315cb8db4aSAlexander Duyck vid |= FM10K_VLAN_CLEAR;
3325cb8db4aSAlexander Duyck
3335cb8db4aSAlexander Duyck /* generate VLAN request */
3345cb8db4aSAlexander Duyck fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN);
3355cb8db4aSAlexander Duyck fm10k_tlv_attr_put_mac_vlan(msg, FM10K_MAC_VLAN_MSG_MULTICAST,
3365cb8db4aSAlexander Duyck mac, vid);
3375cb8db4aSAlexander Duyck
3385cb8db4aSAlexander Duyck /* load onto outgoing mailbox */
3395cb8db4aSAlexander Duyck return mbx->ops.enqueue_tx(hw, mbx, msg);
3405cb8db4aSAlexander Duyck }
3415cb8db4aSAlexander Duyck
3425cb8db4aSAlexander Duyck /**
3435cb8db4aSAlexander Duyck * fm10k_update_int_moderator_vf - Request update of interrupt moderator list
3445cb8db4aSAlexander Duyck * @hw: pointer to hardware structure
3455cb8db4aSAlexander Duyck *
3465cb8db4aSAlexander Duyck * This function will issue a request to the PF to rescan our MSI-X table
3475cb8db4aSAlexander Duyck * and to update the interrupt moderator linked list.
3485cb8db4aSAlexander Duyck **/
fm10k_update_int_moderator_vf(struct fm10k_hw * hw)3495cb8db4aSAlexander Duyck static void fm10k_update_int_moderator_vf(struct fm10k_hw *hw)
3505cb8db4aSAlexander Duyck {
3515cb8db4aSAlexander Duyck struct fm10k_mbx_info *mbx = &hw->mbx;
3525cb8db4aSAlexander Duyck u32 msg[1];
3535cb8db4aSAlexander Duyck
3545cb8db4aSAlexander Duyck /* generate MSI-X request */
3555cb8db4aSAlexander Duyck fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MSIX);
3565cb8db4aSAlexander Duyck
3575cb8db4aSAlexander Duyck /* load onto outgoing mailbox */
3585cb8db4aSAlexander Duyck mbx->ops.enqueue_tx(hw, mbx, msg);
3595cb8db4aSAlexander Duyck }
3605cb8db4aSAlexander Duyck
3615cb8db4aSAlexander Duyck /* This structure defines the attibutes to be parsed below */
3625cb8db4aSAlexander Duyck const struct fm10k_tlv_attr fm10k_lport_state_msg_attr[] = {
3635cb8db4aSAlexander Duyck FM10K_TLV_ATTR_BOOL(FM10K_LPORT_STATE_MSG_DISABLE),
3645cb8db4aSAlexander Duyck FM10K_TLV_ATTR_U8(FM10K_LPORT_STATE_MSG_XCAST_MODE),
3655cb8db4aSAlexander Duyck FM10K_TLV_ATTR_BOOL(FM10K_LPORT_STATE_MSG_READY),
3665cb8db4aSAlexander Duyck FM10K_TLV_ATTR_LAST
3675cb8db4aSAlexander Duyck };
3685cb8db4aSAlexander Duyck
3695cb8db4aSAlexander Duyck /**
3705cb8db4aSAlexander Duyck * fm10k_msg_lport_state_vf - Message handler for lport_state message from PF
3715cb8db4aSAlexander Duyck * @hw: Pointer to hardware structure
3725cb8db4aSAlexander Duyck * @results: pointer array containing parsed data
3735cb8db4aSAlexander Duyck * @mbx: Pointer to mailbox information structure
3745cb8db4aSAlexander Duyck *
3755cb8db4aSAlexander Duyck * This handler is meant to capture the indication from the PF that we
3765cb8db4aSAlexander Duyck * are ready to bring up the interface.
3775cb8db4aSAlexander Duyck **/
fm10k_msg_lport_state_vf(struct fm10k_hw * hw,u32 ** results,struct fm10k_mbx_info __always_unused * mbx)3785cb8db4aSAlexander Duyck s32 fm10k_msg_lport_state_vf(struct fm10k_hw *hw, u32 **results,
379d5c2f395SJacob Keller struct fm10k_mbx_info __always_unused *mbx)
3805cb8db4aSAlexander Duyck {
3815cb8db4aSAlexander Duyck hw->mac.dglort_map = !results[FM10K_LPORT_STATE_MSG_READY] ?
3825cb8db4aSAlexander Duyck FM10K_DGLORTMAP_NONE : FM10K_DGLORTMAP_ZERO;
3835cb8db4aSAlexander Duyck
3845cb8db4aSAlexander Duyck return 0;
3855cb8db4aSAlexander Duyck }
3865cb8db4aSAlexander Duyck
3875cb8db4aSAlexander Duyck /**
3885cb8db4aSAlexander Duyck * fm10k_update_lport_state_vf - Update device state in lower device
3895cb8db4aSAlexander Duyck * @hw: pointer to the HW structure
3905cb8db4aSAlexander Duyck * @glort: unused
3915cb8db4aSAlexander Duyck * @count: number of logical ports to enable - unused (always 1)
3925cb8db4aSAlexander Duyck * @enable: boolean value indicating if this is an enable or disable request
3935cb8db4aSAlexander Duyck *
3945cb8db4aSAlexander Duyck * Notify the lower device of a state change. If the lower device is
3955cb8db4aSAlexander Duyck * enabled we can add filters, if it is disabled all filters for this
3965cb8db4aSAlexander Duyck * logical port are flushed.
3975cb8db4aSAlexander Duyck **/
fm10k_update_lport_state_vf(struct fm10k_hw * hw,u16 __always_unused glort,u16 __always_unused count,bool enable)398d5c2f395SJacob Keller static s32 fm10k_update_lport_state_vf(struct fm10k_hw *hw,
399d5c2f395SJacob Keller u16 __always_unused glort,
400d5c2f395SJacob Keller u16 __always_unused count, bool enable)
4015cb8db4aSAlexander Duyck {
4025cb8db4aSAlexander Duyck struct fm10k_mbx_info *mbx = &hw->mbx;
4035cb8db4aSAlexander Duyck u32 msg[2];
4045cb8db4aSAlexander Duyck
4055cb8db4aSAlexander Duyck /* reset glort mask 0 as we have to wait to be enabled */
4065cb8db4aSAlexander Duyck hw->mac.dglort_map = FM10K_DGLORTMAP_NONE;
4075cb8db4aSAlexander Duyck
4085cb8db4aSAlexander Duyck /* generate port state request */
4095cb8db4aSAlexander Duyck fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE);
4105cb8db4aSAlexander Duyck if (!enable)
4115cb8db4aSAlexander Duyck fm10k_tlv_attr_put_bool(msg, FM10K_LPORT_STATE_MSG_DISABLE);
4125cb8db4aSAlexander Duyck
4135cb8db4aSAlexander Duyck /* load onto outgoing mailbox */
4145cb8db4aSAlexander Duyck return mbx->ops.enqueue_tx(hw, mbx, msg);
4155cb8db4aSAlexander Duyck }
4165cb8db4aSAlexander Duyck
4175cb8db4aSAlexander Duyck /**
4185cb8db4aSAlexander Duyck * fm10k_update_xcast_mode_vf - Request update of multicast mode
4195cb8db4aSAlexander Duyck * @hw: pointer to hardware structure
4205cb8db4aSAlexander Duyck * @glort: unused
4215cb8db4aSAlexander Duyck * @mode: integer value indicating mode being requested
4225cb8db4aSAlexander Duyck *
4235cb8db4aSAlexander Duyck * This function will attempt to request a higher mode for the port
4245cb8db4aSAlexander Duyck * so that it can enable either multicast, multicast promiscuous, or
4255cb8db4aSAlexander Duyck * promiscuous mode of operation.
4265cb8db4aSAlexander Duyck **/
fm10k_update_xcast_mode_vf(struct fm10k_hw * hw,u16 __always_unused glort,u8 mode)427d5c2f395SJacob Keller static s32 fm10k_update_xcast_mode_vf(struct fm10k_hw *hw,
428d5c2f395SJacob Keller u16 __always_unused glort, u8 mode)
4295cb8db4aSAlexander Duyck {
4305cb8db4aSAlexander Duyck struct fm10k_mbx_info *mbx = &hw->mbx;
4315cb8db4aSAlexander Duyck u32 msg[3];
4325cb8db4aSAlexander Duyck
4335cb8db4aSAlexander Duyck if (mode > FM10K_XCAST_MODE_NONE)
4345cb8db4aSAlexander Duyck return FM10K_ERR_PARAM;
435a4fcad65SBruce Allan
4365cb8db4aSAlexander Duyck /* generate message requesting to change xcast mode */
4375cb8db4aSAlexander Duyck fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE);
4385cb8db4aSAlexander Duyck fm10k_tlv_attr_put_u8(msg, FM10K_LPORT_STATE_MSG_XCAST_MODE, mode);
4395cb8db4aSAlexander Duyck
4405cb8db4aSAlexander Duyck /* load onto outgoing mailbox */
4415cb8db4aSAlexander Duyck return mbx->ops.enqueue_tx(hw, mbx, msg);
4425cb8db4aSAlexander Duyck }
4435cb8db4aSAlexander Duyck
4445cb8db4aSAlexander Duyck /**
4455cb8db4aSAlexander Duyck * fm10k_update_hw_stats_vf - Updates hardware related statistics of VF
4465cb8db4aSAlexander Duyck * @hw: pointer to hardware structure
4475cb8db4aSAlexander Duyck * @stats: pointer to statistics structure
4485cb8db4aSAlexander Duyck *
4495cb8db4aSAlexander Duyck * This function collects and aggregates per queue hardware statistics.
4505cb8db4aSAlexander Duyck **/
fm10k_update_hw_stats_vf(struct fm10k_hw * hw,struct fm10k_hw_stats * stats)4515cb8db4aSAlexander Duyck static void fm10k_update_hw_stats_vf(struct fm10k_hw *hw,
4525cb8db4aSAlexander Duyck struct fm10k_hw_stats *stats)
4535cb8db4aSAlexander Duyck {
4545cb8db4aSAlexander Duyck fm10k_update_hw_stats_q(hw, stats->q, 0, hw->mac.max_queues);
4555cb8db4aSAlexander Duyck }
4565cb8db4aSAlexander Duyck
4575cb8db4aSAlexander Duyck /**
4585cb8db4aSAlexander Duyck * fm10k_rebind_hw_stats_vf - Resets base for hardware statistics of VF
4595cb8db4aSAlexander Duyck * @hw: pointer to hardware structure
4605cb8db4aSAlexander Duyck * @stats: pointer to the stats structure to update
4615cb8db4aSAlexander Duyck *
4625cb8db4aSAlexander Duyck * This function resets the base for queue hardware statistics.
4635cb8db4aSAlexander Duyck **/
fm10k_rebind_hw_stats_vf(struct fm10k_hw * hw,struct fm10k_hw_stats * stats)4645cb8db4aSAlexander Duyck static void fm10k_rebind_hw_stats_vf(struct fm10k_hw *hw,
4655cb8db4aSAlexander Duyck struct fm10k_hw_stats *stats)
4665cb8db4aSAlexander Duyck {
4675cb8db4aSAlexander Duyck /* Unbind Queue Statistics */
4685cb8db4aSAlexander Duyck fm10k_unbind_hw_stats_q(stats->q, 0, hw->mac.max_queues);
4695cb8db4aSAlexander Duyck
4705cb8db4aSAlexander Duyck /* Reinitialize bases for all stats */
4715cb8db4aSAlexander Duyck fm10k_update_hw_stats_vf(hw, stats);
4725cb8db4aSAlexander Duyck }
4735cb8db4aSAlexander Duyck
4745cb8db4aSAlexander Duyck /**
4755cb8db4aSAlexander Duyck * fm10k_configure_dglort_map_vf - Configures GLORT entry and queues
4765cb8db4aSAlexander Duyck * @hw: pointer to hardware structure
4775cb8db4aSAlexander Duyck * @dglort: pointer to dglort configuration structure
4785cb8db4aSAlexander Duyck *
4795cb8db4aSAlexander Duyck * Reads the configuration structure contained in dglort_cfg and uses
4805cb8db4aSAlexander Duyck * that information to then populate a DGLORTMAP/DEC entry and the queues
4815cb8db4aSAlexander Duyck * to which it has been assigned.
4825cb8db4aSAlexander Duyck **/
fm10k_configure_dglort_map_vf(struct fm10k_hw __always_unused * hw,struct fm10k_dglort_cfg * dglort)483d5c2f395SJacob Keller static s32 fm10k_configure_dglort_map_vf(struct fm10k_hw __always_unused *hw,
4845cb8db4aSAlexander Duyck struct fm10k_dglort_cfg *dglort)
4855cb8db4aSAlexander Duyck {
4865cb8db4aSAlexander Duyck /* verify the dglort pointer */
4875cb8db4aSAlexander Duyck if (!dglort)
4885cb8db4aSAlexander Duyck return FM10K_ERR_PARAM;
4895cb8db4aSAlexander Duyck
4905cb8db4aSAlexander Duyck /* stub for now until we determine correct message for this */
4915cb8db4aSAlexander Duyck
4925cb8db4aSAlexander Duyck return 0;
4935cb8db4aSAlexander Duyck }
4945cb8db4aSAlexander Duyck
4955cb8db4aSAlexander Duyck static const struct fm10k_msg_data fm10k_msg_data_vf[] = {
4965cb8db4aSAlexander Duyck FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test),
4975cb8db4aSAlexander Duyck FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_msg_mac_vlan_vf),
4985cb8db4aSAlexander Duyck FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_msg_lport_state_vf),
4995cb8db4aSAlexander Duyck FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error),
5005cb8db4aSAlexander Duyck };
5015cb8db4aSAlexander Duyck
502f329ad73SBruce Allan static const struct fm10k_mac_ops mac_ops_vf = {
5034e458cfbSBruce Allan .get_bus_info = fm10k_get_bus_info_generic,
5044e458cfbSBruce Allan .reset_hw = fm10k_reset_hw_vf,
5054e458cfbSBruce Allan .init_hw = fm10k_init_hw_vf,
5064e458cfbSBruce Allan .start_hw = fm10k_start_hw_generic,
5074e458cfbSBruce Allan .stop_hw = fm10k_stop_hw_vf,
5084e458cfbSBruce Allan .update_vlan = fm10k_update_vlan_vf,
5094e458cfbSBruce Allan .read_mac_addr = fm10k_read_mac_addr_vf,
5104e458cfbSBruce Allan .update_uc_addr = fm10k_update_uc_addr_vf,
5114e458cfbSBruce Allan .update_mc_addr = fm10k_update_mc_addr_vf,
5124e458cfbSBruce Allan .update_xcast_mode = fm10k_update_xcast_mode_vf,
5134e458cfbSBruce Allan .update_int_moderator = fm10k_update_int_moderator_vf,
5144e458cfbSBruce Allan .update_lport_state = fm10k_update_lport_state_vf,
5154e458cfbSBruce Allan .update_hw_stats = fm10k_update_hw_stats_vf,
5164e458cfbSBruce Allan .rebind_hw_stats = fm10k_rebind_hw_stats_vf,
5174e458cfbSBruce Allan .configure_dglort_map = fm10k_configure_dglort_map_vf,
5184e458cfbSBruce Allan .get_host_state = fm10k_get_host_state_generic,
5195cb8db4aSAlexander Duyck };
5205cb8db4aSAlexander Duyck
fm10k_get_invariants_vf(struct fm10k_hw * hw)5215cb8db4aSAlexander Duyck static s32 fm10k_get_invariants_vf(struct fm10k_hw *hw)
5225cb8db4aSAlexander Duyck {
5235cb8db4aSAlexander Duyck fm10k_get_invariants_generic(hw);
5245cb8db4aSAlexander Duyck
5255cb8db4aSAlexander Duyck return fm10k_pfvf_mbx_init(hw, &hw->mbx, fm10k_msg_data_vf, 0);
5265cb8db4aSAlexander Duyck }
5275cb8db4aSAlexander Duyck
528f329ad73SBruce Allan const struct fm10k_info fm10k_vf_info = {
5295cb8db4aSAlexander Duyck .mac = fm10k_mac_vf,
5304e458cfbSBruce Allan .get_invariants = fm10k_get_invariants_vf,
5315cb8db4aSAlexander Duyck .mac_ops = &mac_ops_vf,
5325cb8db4aSAlexander Duyck };
533