xref: /freebsd/sys/dev/ixgbe/if_sriov.c (revision c19c7afee3c8bb5e3046be27d083f4fa51ee5d73)
18eb6488eSEric Joyner /******************************************************************************
28eb6488eSEric Joyner 
38eb6488eSEric Joyner   Copyright (c) 2001-2017, Intel Corporation
48eb6488eSEric Joyner   All rights reserved.
58eb6488eSEric Joyner 
68eb6488eSEric Joyner   Redistribution and use in source and binary forms, with or without
78eb6488eSEric Joyner   modification, are permitted provided that the following conditions are met:
88eb6488eSEric Joyner 
98eb6488eSEric Joyner    1. Redistributions of source code must retain the above copyright notice,
108eb6488eSEric Joyner       this list of conditions and the following disclaimer.
118eb6488eSEric Joyner 
128eb6488eSEric Joyner    2. Redistributions in binary form must reproduce the above copyright
138eb6488eSEric Joyner       notice, this list of conditions and the following disclaimer in the
148eb6488eSEric Joyner       documentation and/or other materials provided with the distribution.
158eb6488eSEric Joyner 
168eb6488eSEric Joyner    3. Neither the name of the Intel Corporation nor the names of its
178eb6488eSEric Joyner       contributors may be used to endorse or promote products derived from
188eb6488eSEric Joyner       this software without specific prior written permission.
198eb6488eSEric Joyner 
208eb6488eSEric Joyner   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
218eb6488eSEric Joyner   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
228eb6488eSEric Joyner   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
238eb6488eSEric Joyner   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
248eb6488eSEric Joyner   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
258eb6488eSEric Joyner   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
268eb6488eSEric Joyner   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
278eb6488eSEric Joyner   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
288eb6488eSEric Joyner   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
298eb6488eSEric Joyner   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
308eb6488eSEric Joyner   POSSIBILITY OF SUCH DAMAGE.
318eb6488eSEric Joyner 
328eb6488eSEric Joyner ******************************************************************************/
338eb6488eSEric Joyner /*$FreeBSD$*/
348eb6488eSEric Joyner 
358eb6488eSEric Joyner #include "ixgbe.h"
36*c19c7afeSEric Joyner #include "ixgbe_sriov.h"
378eb6488eSEric Joyner 
388eb6488eSEric Joyner #ifdef PCI_IOV
398eb6488eSEric Joyner 
408eb6488eSEric Joyner MALLOC_DEFINE(M_IXGBE_SRIOV, "ix_sriov", "ix SR-IOV allocations");
418eb6488eSEric Joyner 
428eb6488eSEric Joyner /************************************************************************
438eb6488eSEric Joyner  * ixgbe_pci_iov_detach
448eb6488eSEric Joyner  ************************************************************************/
458eb6488eSEric Joyner int
468eb6488eSEric Joyner ixgbe_pci_iov_detach(device_t dev)
478eb6488eSEric Joyner {
488eb6488eSEric Joyner 	return pci_iov_detach(dev);
498eb6488eSEric Joyner }
508eb6488eSEric Joyner 
518eb6488eSEric Joyner /************************************************************************
528eb6488eSEric Joyner  * ixgbe_define_iov_schemas
538eb6488eSEric Joyner  ************************************************************************/
548eb6488eSEric Joyner void
558eb6488eSEric Joyner ixgbe_define_iov_schemas(device_t dev, int *error)
568eb6488eSEric Joyner {
578eb6488eSEric Joyner 	nvlist_t *pf_schema, *vf_schema;
588eb6488eSEric Joyner 
598eb6488eSEric Joyner 	pf_schema = pci_iov_schema_alloc_node();
608eb6488eSEric Joyner 	vf_schema = pci_iov_schema_alloc_node();
618eb6488eSEric Joyner 	pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
628eb6488eSEric Joyner 	pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof",
638eb6488eSEric Joyner 	    IOV_SCHEMA_HASDEFAULT, TRUE);
648eb6488eSEric Joyner 	pci_iov_schema_add_bool(vf_schema, "allow-set-mac",
658eb6488eSEric Joyner 	    IOV_SCHEMA_HASDEFAULT, FALSE);
668eb6488eSEric Joyner 	pci_iov_schema_add_bool(vf_schema, "allow-promisc",
678eb6488eSEric Joyner 	    IOV_SCHEMA_HASDEFAULT, FALSE);
688eb6488eSEric Joyner 	*error = pci_iov_attach(dev, pf_schema, vf_schema);
698eb6488eSEric Joyner 	if (*error != 0) {
708eb6488eSEric Joyner 		device_printf(dev,
718eb6488eSEric Joyner 		    "Error %d setting up SR-IOV\n", *error);
728eb6488eSEric Joyner 	}
738eb6488eSEric Joyner } /* ixgbe_define_iov_schemas */
748eb6488eSEric Joyner 
758eb6488eSEric Joyner /************************************************************************
768eb6488eSEric Joyner  * ixgbe_align_all_queue_indices
778eb6488eSEric Joyner  ************************************************************************/
788eb6488eSEric Joyner inline void
798eb6488eSEric Joyner ixgbe_align_all_queue_indices(struct adapter *adapter)
808eb6488eSEric Joyner {
818eb6488eSEric Joyner 	int i;
828eb6488eSEric Joyner 	int index;
838eb6488eSEric Joyner 
84*c19c7afeSEric Joyner 	for (i = 0; i < adapter->num_rx_queues; i++) {
858eb6488eSEric Joyner 		index = ixgbe_vf_que_index(adapter->iov_mode, adapter->pool, i);
86*c19c7afeSEric Joyner 		adapter->rx_queues[i].rxr.me = index;
87*c19c7afeSEric Joyner 	}
88*c19c7afeSEric Joyner 
89*c19c7afeSEric Joyner 	for (i = 0; i < adapter->num_tx_queues; i++) {
90*c19c7afeSEric Joyner 		index = ixgbe_vf_que_index(adapter->iov_mode, adapter->pool, i);
91*c19c7afeSEric Joyner 		adapter->tx_queues[i].txr.me = index;
928eb6488eSEric Joyner 	}
938eb6488eSEric Joyner }
948eb6488eSEric Joyner 
958eb6488eSEric Joyner /* Support functions for SR-IOV/VF management */
968eb6488eSEric Joyner static inline void
978eb6488eSEric Joyner ixgbe_send_vf_msg(struct adapter *adapter, struct ixgbe_vf *vf, u32 msg)
988eb6488eSEric Joyner {
998eb6488eSEric Joyner 	if (vf->flags & IXGBE_VF_CTS)
1008eb6488eSEric Joyner 		msg |= IXGBE_VT_MSGTYPE_CTS;
1018eb6488eSEric Joyner 
1028eb6488eSEric Joyner 	adapter->hw.mbx.ops.write(&adapter->hw, &msg, 1, vf->pool);
1038eb6488eSEric Joyner }
1048eb6488eSEric Joyner 
1058eb6488eSEric Joyner static inline void
1068eb6488eSEric Joyner ixgbe_send_vf_ack(struct adapter *adapter, struct ixgbe_vf *vf, u32 msg)
1078eb6488eSEric Joyner {
1088eb6488eSEric Joyner 	msg &= IXGBE_VT_MSG_MASK;
1098eb6488eSEric Joyner 	ixgbe_send_vf_msg(adapter, vf, msg | IXGBE_VT_MSGTYPE_ACK);
1108eb6488eSEric Joyner }
1118eb6488eSEric Joyner 
1128eb6488eSEric Joyner static inline void
1138eb6488eSEric Joyner ixgbe_send_vf_nack(struct adapter *adapter, struct ixgbe_vf *vf, u32 msg)
1148eb6488eSEric Joyner {
1158eb6488eSEric Joyner 	msg &= IXGBE_VT_MSG_MASK;
1168eb6488eSEric Joyner 	ixgbe_send_vf_msg(adapter, vf, msg | IXGBE_VT_MSGTYPE_NACK);
1178eb6488eSEric Joyner }
1188eb6488eSEric Joyner 
1198eb6488eSEric Joyner static inline void
1208eb6488eSEric Joyner ixgbe_process_vf_ack(struct adapter *adapter, struct ixgbe_vf *vf)
1218eb6488eSEric Joyner {
1228eb6488eSEric Joyner 	if (!(vf->flags & IXGBE_VF_CTS))
1238eb6488eSEric Joyner 		ixgbe_send_vf_nack(adapter, vf, 0);
1248eb6488eSEric Joyner }
1258eb6488eSEric Joyner 
1268eb6488eSEric Joyner static inline boolean_t
1278eb6488eSEric Joyner ixgbe_vf_mac_changed(struct ixgbe_vf *vf, const uint8_t *mac)
1288eb6488eSEric Joyner {
1298eb6488eSEric Joyner 	return (bcmp(mac, vf->ether_addr, ETHER_ADDR_LEN) != 0);
1308eb6488eSEric Joyner }
1318eb6488eSEric Joyner 
1328eb6488eSEric Joyner static inline int
1338eb6488eSEric Joyner ixgbe_vf_queues(int mode)
1348eb6488eSEric Joyner {
1358eb6488eSEric Joyner 	switch (mode) {
1368eb6488eSEric Joyner 	case IXGBE_64_VM:
1378eb6488eSEric Joyner 		return (2);
1388eb6488eSEric Joyner 	case IXGBE_32_VM:
1398eb6488eSEric Joyner 		return (4);
1408eb6488eSEric Joyner 	case IXGBE_NO_VM:
1418eb6488eSEric Joyner 	default:
1428eb6488eSEric Joyner 		return (0);
1438eb6488eSEric Joyner 	}
1448eb6488eSEric Joyner }
1458eb6488eSEric Joyner 
1468eb6488eSEric Joyner inline int
1478eb6488eSEric Joyner ixgbe_vf_que_index(int mode, int vfnum, int num)
1488eb6488eSEric Joyner {
1498eb6488eSEric Joyner 	return ((vfnum * ixgbe_vf_queues(mode)) + num);
1508eb6488eSEric Joyner }
1518eb6488eSEric Joyner 
1528eb6488eSEric Joyner static inline void
1538eb6488eSEric Joyner ixgbe_update_max_frame(struct adapter * adapter, int max_frame)
1548eb6488eSEric Joyner {
1558eb6488eSEric Joyner 	if (adapter->max_frame_size < max_frame)
1568eb6488eSEric Joyner 		adapter->max_frame_size = max_frame;
1578eb6488eSEric Joyner }
1588eb6488eSEric Joyner 
1598eb6488eSEric Joyner inline u32
1608eb6488eSEric Joyner ixgbe_get_mrqc(int iov_mode)
1618eb6488eSEric Joyner {
1628eb6488eSEric Joyner 	u32 mrqc;
1638eb6488eSEric Joyner 
1648eb6488eSEric Joyner 	switch (iov_mode) {
1658eb6488eSEric Joyner 	case IXGBE_64_VM:
1668eb6488eSEric Joyner 		mrqc = IXGBE_MRQC_VMDQRSS64EN;
1678eb6488eSEric Joyner 		break;
1688eb6488eSEric Joyner 	case IXGBE_32_VM:
1698eb6488eSEric Joyner 		mrqc = IXGBE_MRQC_VMDQRSS32EN;
1708eb6488eSEric Joyner 		break;
1718eb6488eSEric Joyner 	case IXGBE_NO_VM:
1728eb6488eSEric Joyner 		mrqc = 0;
1738eb6488eSEric Joyner 		break;
1748eb6488eSEric Joyner 	default:
1758eb6488eSEric Joyner 		panic("Unexpected SR-IOV mode %d", iov_mode);
1768eb6488eSEric Joyner 	}
1778eb6488eSEric Joyner 
1788eb6488eSEric Joyner 	return mrqc;
1798eb6488eSEric Joyner }
1808eb6488eSEric Joyner 
1818eb6488eSEric Joyner 
1828eb6488eSEric Joyner inline u32
1838eb6488eSEric Joyner ixgbe_get_mtqc(int iov_mode)
1848eb6488eSEric Joyner {
1858eb6488eSEric Joyner 	uint32_t mtqc;
1868eb6488eSEric Joyner 
1878eb6488eSEric Joyner 	switch (iov_mode) {
1888eb6488eSEric Joyner 	case IXGBE_64_VM:
1898eb6488eSEric Joyner 		mtqc = IXGBE_MTQC_64VF | IXGBE_MTQC_VT_ENA;
1908eb6488eSEric Joyner 		break;
1918eb6488eSEric Joyner 	case IXGBE_32_VM:
1928eb6488eSEric Joyner 		mtqc = IXGBE_MTQC_32VF | IXGBE_MTQC_VT_ENA;
1938eb6488eSEric Joyner 		break;
1948eb6488eSEric Joyner 	case IXGBE_NO_VM:
1958eb6488eSEric Joyner 		mtqc = IXGBE_MTQC_64Q_1PB;
1968eb6488eSEric Joyner 		break;
1978eb6488eSEric Joyner 	default:
1988eb6488eSEric Joyner 		panic("Unexpected SR-IOV mode %d", iov_mode);
1998eb6488eSEric Joyner 	}
2008eb6488eSEric Joyner 
2018eb6488eSEric Joyner 	return mtqc;
2028eb6488eSEric Joyner }
2038eb6488eSEric Joyner 
2048eb6488eSEric Joyner void
2058eb6488eSEric Joyner ixgbe_ping_all_vfs(struct adapter *adapter)
2068eb6488eSEric Joyner {
2078eb6488eSEric Joyner 	struct ixgbe_vf *vf;
2088eb6488eSEric Joyner 
2098eb6488eSEric Joyner 	for (int i = 0; i < adapter->num_vfs; i++) {
2108eb6488eSEric Joyner 		vf = &adapter->vfs[i];
2118eb6488eSEric Joyner 		if (vf->flags & IXGBE_VF_ACTIVE)
2128eb6488eSEric Joyner 			ixgbe_send_vf_msg(adapter, vf, IXGBE_PF_CONTROL_MSG);
2138eb6488eSEric Joyner 	}
2148eb6488eSEric Joyner } /* ixgbe_ping_all_vfs */
2158eb6488eSEric Joyner 
2168eb6488eSEric Joyner 
2178eb6488eSEric Joyner static void
2188eb6488eSEric Joyner ixgbe_vf_set_default_vlan(struct adapter *adapter, struct ixgbe_vf *vf,
2198eb6488eSEric Joyner                           uint16_t tag)
2208eb6488eSEric Joyner {
2218eb6488eSEric Joyner 	struct ixgbe_hw *hw;
2228eb6488eSEric Joyner 	uint32_t vmolr, vmvir;
2238eb6488eSEric Joyner 
2248eb6488eSEric Joyner 	hw = &adapter->hw;
2258eb6488eSEric Joyner 
2268eb6488eSEric Joyner 	vf->vlan_tag = tag;
2278eb6488eSEric Joyner 
2288eb6488eSEric Joyner 	vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf->pool));
2298eb6488eSEric Joyner 
2308eb6488eSEric Joyner 	/* Do not receive packets that pass inexact filters. */
2318eb6488eSEric Joyner 	vmolr &= ~(IXGBE_VMOLR_ROMPE | IXGBE_VMOLR_ROPE);
2328eb6488eSEric Joyner 
2338eb6488eSEric Joyner 	/* Disable Multicast Promicuous Mode. */
2348eb6488eSEric Joyner 	vmolr &= ~IXGBE_VMOLR_MPE;
2358eb6488eSEric Joyner 
2368eb6488eSEric Joyner 	/* Accept broadcasts. */
2378eb6488eSEric Joyner 	vmolr |= IXGBE_VMOLR_BAM;
2388eb6488eSEric Joyner 
2398eb6488eSEric Joyner 	if (tag == 0) {
2408eb6488eSEric Joyner 		/* Accept non-vlan tagged traffic. */
241*c19c7afeSEric Joyner 		vmolr |= IXGBE_VMOLR_AUPE;
2428eb6488eSEric Joyner 
2438eb6488eSEric Joyner 		/* Allow VM to tag outgoing traffic; no default tag. */
2448eb6488eSEric Joyner 		vmvir = 0;
2458eb6488eSEric Joyner 	} else {
2468eb6488eSEric Joyner 		/* Require vlan-tagged traffic. */
2478eb6488eSEric Joyner 		vmolr &= ~IXGBE_VMOLR_AUPE;
2488eb6488eSEric Joyner 
2498eb6488eSEric Joyner 		/* Tag all traffic with provided vlan tag. */
2508eb6488eSEric Joyner 		vmvir = (tag | IXGBE_VMVIR_VLANA_DEFAULT);
2518eb6488eSEric Joyner 	}
2528eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf->pool), vmolr);
2538eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf->pool), vmvir);
2548eb6488eSEric Joyner } /* ixgbe_vf_set_default_vlan */
2558eb6488eSEric Joyner 
2568eb6488eSEric Joyner 
2578eb6488eSEric Joyner static boolean_t
2588eb6488eSEric Joyner ixgbe_vf_frame_size_compatible(struct adapter *adapter, struct ixgbe_vf *vf)
2598eb6488eSEric Joyner {
2608eb6488eSEric Joyner 
2618eb6488eSEric Joyner 	/*
2628eb6488eSEric Joyner 	 * Frame size compatibility between PF and VF is only a problem on
2638eb6488eSEric Joyner 	 * 82599-based cards.  X540 and later support any combination of jumbo
2648eb6488eSEric Joyner 	 * frames on PFs and VFs.
2658eb6488eSEric Joyner 	 */
2668eb6488eSEric Joyner 	if (adapter->hw.mac.type != ixgbe_mac_82599EB)
2678eb6488eSEric Joyner 		return (TRUE);
2688eb6488eSEric Joyner 
2698eb6488eSEric Joyner 	switch (vf->api_ver) {
2708eb6488eSEric Joyner 	case IXGBE_API_VER_1_0:
2718eb6488eSEric Joyner 	case IXGBE_API_VER_UNKNOWN:
2728eb6488eSEric Joyner 		/*
2738eb6488eSEric Joyner 		 * On legacy (1.0 and older) VF versions, we don't support jumbo
2748eb6488eSEric Joyner 		 * frames on either the PF or the VF.
2758eb6488eSEric Joyner 		 */
2768eb6488eSEric Joyner 		if (adapter->max_frame_size > ETHER_MAX_LEN ||
277*c19c7afeSEric Joyner 		    vf->maximum_frame_size > ETHER_MAX_LEN)
2788eb6488eSEric Joyner 			return (FALSE);
2798eb6488eSEric Joyner 
2808eb6488eSEric Joyner 		return (TRUE);
2818eb6488eSEric Joyner 
2828eb6488eSEric Joyner 		break;
2838eb6488eSEric Joyner 	case IXGBE_API_VER_1_1:
2848eb6488eSEric Joyner 	default:
2858eb6488eSEric Joyner 		/*
2868eb6488eSEric Joyner 		 * 1.1 or later VF versions always work if they aren't using
2878eb6488eSEric Joyner 		 * jumbo frames.
2888eb6488eSEric Joyner 		 */
289*c19c7afeSEric Joyner 		if (vf->maximum_frame_size <= ETHER_MAX_LEN)
2908eb6488eSEric Joyner 			return (TRUE);
2918eb6488eSEric Joyner 
2928eb6488eSEric Joyner 		/*
2938eb6488eSEric Joyner 		 * Jumbo frames only work with VFs if the PF is also using jumbo
2948eb6488eSEric Joyner 		 * frames.
2958eb6488eSEric Joyner 		 */
2968eb6488eSEric Joyner 		if (adapter->max_frame_size <= ETHER_MAX_LEN)
2978eb6488eSEric Joyner 			return (TRUE);
2988eb6488eSEric Joyner 
2998eb6488eSEric Joyner 		return (FALSE);
3008eb6488eSEric Joyner 	}
3018eb6488eSEric Joyner } /* ixgbe_vf_frame_size_compatible */
3028eb6488eSEric Joyner 
3038eb6488eSEric Joyner 
3048eb6488eSEric Joyner static void
3058eb6488eSEric Joyner ixgbe_process_vf_reset(struct adapter *adapter, struct ixgbe_vf *vf)
3068eb6488eSEric Joyner {
3078eb6488eSEric Joyner 	ixgbe_vf_set_default_vlan(adapter, vf, vf->default_vlan);
3088eb6488eSEric Joyner 
3098eb6488eSEric Joyner 	// XXX clear multicast addresses
3108eb6488eSEric Joyner 
3118eb6488eSEric Joyner 	ixgbe_clear_rar(&adapter->hw, vf->rar_index);
3128eb6488eSEric Joyner 
3138eb6488eSEric Joyner 	vf->api_ver = IXGBE_API_VER_UNKNOWN;
3148eb6488eSEric Joyner } /* ixgbe_process_vf_reset */
3158eb6488eSEric Joyner 
3168eb6488eSEric Joyner 
3178eb6488eSEric Joyner static void
3188eb6488eSEric Joyner ixgbe_vf_enable_transmit(struct adapter *adapter, struct ixgbe_vf *vf)
3198eb6488eSEric Joyner {
3208eb6488eSEric Joyner 	struct ixgbe_hw *hw;
3218eb6488eSEric Joyner 	uint32_t vf_index, vfte;
3228eb6488eSEric Joyner 
3238eb6488eSEric Joyner 	hw = &adapter->hw;
3248eb6488eSEric Joyner 
3258eb6488eSEric Joyner 	vf_index = IXGBE_VF_INDEX(vf->pool);
3268eb6488eSEric Joyner 	vfte = IXGBE_READ_REG(hw, IXGBE_VFTE(vf_index));
3278eb6488eSEric Joyner 	vfte |= IXGBE_VF_BIT(vf->pool);
3288eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_index), vfte);
3298eb6488eSEric Joyner } /* ixgbe_vf_enable_transmit */
3308eb6488eSEric Joyner 
3318eb6488eSEric Joyner 
3328eb6488eSEric Joyner static void
3338eb6488eSEric Joyner ixgbe_vf_enable_receive(struct adapter *adapter, struct ixgbe_vf *vf)
3348eb6488eSEric Joyner {
3358eb6488eSEric Joyner 	struct ixgbe_hw *hw;
3368eb6488eSEric Joyner 	uint32_t vf_index, vfre;
3378eb6488eSEric Joyner 
3388eb6488eSEric Joyner 	hw = &adapter->hw;
3398eb6488eSEric Joyner 
3408eb6488eSEric Joyner 	vf_index = IXGBE_VF_INDEX(vf->pool);
3418eb6488eSEric Joyner 	vfre = IXGBE_READ_REG(hw, IXGBE_VFRE(vf_index));
3428eb6488eSEric Joyner 	if (ixgbe_vf_frame_size_compatible(adapter, vf))
3438eb6488eSEric Joyner 		vfre |= IXGBE_VF_BIT(vf->pool);
3448eb6488eSEric Joyner 	else
3458eb6488eSEric Joyner 		vfre &= ~IXGBE_VF_BIT(vf->pool);
3468eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_index), vfre);
3478eb6488eSEric Joyner } /* ixgbe_vf_enable_receive */
3488eb6488eSEric Joyner 
3498eb6488eSEric Joyner 
3508eb6488eSEric Joyner static void
3518eb6488eSEric Joyner ixgbe_vf_reset_msg(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg)
3528eb6488eSEric Joyner {
3538eb6488eSEric Joyner 	struct ixgbe_hw *hw;
3548eb6488eSEric Joyner 	uint32_t ack;
3558eb6488eSEric Joyner 	uint32_t resp[IXGBE_VF_PERMADDR_MSG_LEN];
3568eb6488eSEric Joyner 
3578eb6488eSEric Joyner 	hw = &adapter->hw;
3588eb6488eSEric Joyner 
3598eb6488eSEric Joyner 	ixgbe_process_vf_reset(adapter, vf);
3608eb6488eSEric Joyner 
3618eb6488eSEric Joyner 	if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) {
3628eb6488eSEric Joyner 		ixgbe_set_rar(&adapter->hw, vf->rar_index, vf->ether_addr,
3638eb6488eSEric Joyner 		    vf->pool, TRUE);
3648eb6488eSEric Joyner 		ack = IXGBE_VT_MSGTYPE_ACK;
3658eb6488eSEric Joyner 	} else
3668eb6488eSEric Joyner 		ack = IXGBE_VT_MSGTYPE_NACK;
3678eb6488eSEric Joyner 
3688eb6488eSEric Joyner 	ixgbe_vf_enable_transmit(adapter, vf);
3698eb6488eSEric Joyner 	ixgbe_vf_enable_receive(adapter, vf);
3708eb6488eSEric Joyner 
3718eb6488eSEric Joyner 	vf->flags |= IXGBE_VF_CTS;
3728eb6488eSEric Joyner 
3738eb6488eSEric Joyner 	resp[0] = IXGBE_VF_RESET | ack | IXGBE_VT_MSGTYPE_CTS;
3748eb6488eSEric Joyner 	bcopy(vf->ether_addr, &resp[1], ETHER_ADDR_LEN);
3758eb6488eSEric Joyner 	resp[3] = hw->mac.mc_filter_type;
3768eb6488eSEric Joyner 	hw->mbx.ops.write(hw, resp, IXGBE_VF_PERMADDR_MSG_LEN, vf->pool);
3778eb6488eSEric Joyner } /* ixgbe_vf_reset_msg */
3788eb6488eSEric Joyner 
3798eb6488eSEric Joyner 
3808eb6488eSEric Joyner static void
3818eb6488eSEric Joyner ixgbe_vf_set_mac(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg)
3828eb6488eSEric Joyner {
3838eb6488eSEric Joyner 	uint8_t *mac;
3848eb6488eSEric Joyner 
3858eb6488eSEric Joyner 	mac = (uint8_t*)&msg[1];
3868eb6488eSEric Joyner 
3878eb6488eSEric Joyner 	/* Check that the VF has permission to change the MAC address. */
3888eb6488eSEric Joyner 	if (!(vf->flags & IXGBE_VF_CAP_MAC) && ixgbe_vf_mac_changed(vf, mac)) {
3898eb6488eSEric Joyner 		ixgbe_send_vf_nack(adapter, vf, msg[0]);
3908eb6488eSEric Joyner 		return;
3918eb6488eSEric Joyner 	}
3928eb6488eSEric Joyner 
3938eb6488eSEric Joyner 	if (ixgbe_validate_mac_addr(mac) != 0) {
3948eb6488eSEric Joyner 		ixgbe_send_vf_nack(adapter, vf, msg[0]);
3958eb6488eSEric Joyner 		return;
3968eb6488eSEric Joyner 	}
3978eb6488eSEric Joyner 
3988eb6488eSEric Joyner 	bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN);
3998eb6488eSEric Joyner 
4008eb6488eSEric Joyner 	ixgbe_set_rar(&adapter->hw, vf->rar_index, vf->ether_addr, vf->pool,
4018eb6488eSEric Joyner 	    TRUE);
4028eb6488eSEric Joyner 
4038eb6488eSEric Joyner 	ixgbe_send_vf_ack(adapter, vf, msg[0]);
4048eb6488eSEric Joyner } /* ixgbe_vf_set_mac */
4058eb6488eSEric Joyner 
4068eb6488eSEric Joyner 
4078eb6488eSEric Joyner /*
4088eb6488eSEric Joyner  * VF multicast addresses are set by using the appropriate bit in
4098eb6488eSEric Joyner  * 1 of 128 32 bit addresses (4096 possible).
4108eb6488eSEric Joyner  */
4118eb6488eSEric Joyner static void
4128eb6488eSEric Joyner ixgbe_vf_set_mc_addr(struct adapter *adapter, struct ixgbe_vf *vf, u32 *msg)
4138eb6488eSEric Joyner {
4148eb6488eSEric Joyner 	u16	*list = (u16*)&msg[1];
4158eb6488eSEric Joyner 	int	entries;
4168eb6488eSEric Joyner 	u32	vmolr, vec_bit, vec_reg, mta_reg;
4178eb6488eSEric Joyner 
4188eb6488eSEric Joyner 	entries = (msg[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT;
4198eb6488eSEric Joyner 	entries = min(entries, IXGBE_MAX_VF_MC);
4208eb6488eSEric Joyner 
4218eb6488eSEric Joyner 	vmolr = IXGBE_READ_REG(&adapter->hw, IXGBE_VMOLR(vf->pool));
4228eb6488eSEric Joyner 
4238eb6488eSEric Joyner 	vf->num_mc_hashes = entries;
4248eb6488eSEric Joyner 
4258eb6488eSEric Joyner 	/* Set the appropriate MTA bit */
4268eb6488eSEric Joyner 	for (int i = 0; i < entries; i++) {
4278eb6488eSEric Joyner 		vf->mc_hash[i] = list[i];
4288eb6488eSEric Joyner 		vec_reg = (vf->mc_hash[i] >> 5) & 0x7F;
4298eb6488eSEric Joyner 		vec_bit = vf->mc_hash[i] & 0x1F;
4308eb6488eSEric Joyner 		mta_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_MTA(vec_reg));
4318eb6488eSEric Joyner 		mta_reg |= (1 << vec_bit);
4328eb6488eSEric Joyner 		IXGBE_WRITE_REG(&adapter->hw, IXGBE_MTA(vec_reg), mta_reg);
4338eb6488eSEric Joyner 	}
4348eb6488eSEric Joyner 
4358eb6488eSEric Joyner 	vmolr |= IXGBE_VMOLR_ROMPE;
4368eb6488eSEric Joyner 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_VMOLR(vf->pool), vmolr);
4378eb6488eSEric Joyner 	ixgbe_send_vf_ack(adapter, vf, msg[0]);
4388eb6488eSEric Joyner } /* ixgbe_vf_set_mc_addr */
4398eb6488eSEric Joyner 
4408eb6488eSEric Joyner 
4418eb6488eSEric Joyner static void
4428eb6488eSEric Joyner ixgbe_vf_set_vlan(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg)
4438eb6488eSEric Joyner {
4448eb6488eSEric Joyner 	struct ixgbe_hw *hw;
4458eb6488eSEric Joyner 	int enable;
4468eb6488eSEric Joyner 	uint16_t tag;
4478eb6488eSEric Joyner 
4488eb6488eSEric Joyner 	hw = &adapter->hw;
4498eb6488eSEric Joyner 	enable = IXGBE_VT_MSGINFO(msg[0]);
4508eb6488eSEric Joyner 	tag = msg[1] & IXGBE_VLVF_VLANID_MASK;
4518eb6488eSEric Joyner 
4528eb6488eSEric Joyner 	if (!(vf->flags & IXGBE_VF_CAP_VLAN)) {
4538eb6488eSEric Joyner 		ixgbe_send_vf_nack(adapter, vf, msg[0]);
4548eb6488eSEric Joyner 		return;
4558eb6488eSEric Joyner 	}
4568eb6488eSEric Joyner 
4578eb6488eSEric Joyner 	/* It is illegal to enable vlan tag 0. */
4588eb6488eSEric Joyner 	if (tag == 0 && enable != 0) {
4598eb6488eSEric Joyner 		ixgbe_send_vf_nack(adapter, vf, msg[0]);
4608eb6488eSEric Joyner 		return;
4618eb6488eSEric Joyner 	}
4628eb6488eSEric Joyner 
4638eb6488eSEric Joyner 	ixgbe_set_vfta(hw, tag, vf->pool, enable, false);
4648eb6488eSEric Joyner 	ixgbe_send_vf_ack(adapter, vf, msg[0]);
4658eb6488eSEric Joyner } /* ixgbe_vf_set_vlan */
4668eb6488eSEric Joyner 
4678eb6488eSEric Joyner 
4688eb6488eSEric Joyner static void
4698eb6488eSEric Joyner ixgbe_vf_set_lpe(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg)
4708eb6488eSEric Joyner {
4718eb6488eSEric Joyner 	struct ixgbe_hw *hw;
4728eb6488eSEric Joyner 	uint32_t vf_max_size, pf_max_size, mhadd;
4738eb6488eSEric Joyner 
4748eb6488eSEric Joyner 	hw = &adapter->hw;
4758eb6488eSEric Joyner 	vf_max_size = msg[1];
4768eb6488eSEric Joyner 
4778eb6488eSEric Joyner 	if (vf_max_size < ETHER_CRC_LEN) {
4788eb6488eSEric Joyner 		/* We intentionally ACK invalid LPE requests. */
4798eb6488eSEric Joyner 		ixgbe_send_vf_ack(adapter, vf, msg[0]);
4808eb6488eSEric Joyner 		return;
4818eb6488eSEric Joyner 	}
4828eb6488eSEric Joyner 
4838eb6488eSEric Joyner 	vf_max_size -= ETHER_CRC_LEN;
4848eb6488eSEric Joyner 
4858eb6488eSEric Joyner 	if (vf_max_size > IXGBE_MAX_FRAME_SIZE) {
4868eb6488eSEric Joyner 		/* We intentionally ACK invalid LPE requests. */
4878eb6488eSEric Joyner 		ixgbe_send_vf_ack(adapter, vf, msg[0]);
4888eb6488eSEric Joyner 		return;
4898eb6488eSEric Joyner 	}
4908eb6488eSEric Joyner 
491*c19c7afeSEric Joyner 	vf->maximum_frame_size = vf_max_size;
492*c19c7afeSEric Joyner 	ixgbe_update_max_frame(adapter, vf->maximum_frame_size);
4938eb6488eSEric Joyner 
4948eb6488eSEric Joyner 	/*
4958eb6488eSEric Joyner 	 * We might have to disable reception to this VF if the frame size is
4968eb6488eSEric Joyner 	 * not compatible with the config on the PF.
4978eb6488eSEric Joyner 	 */
4988eb6488eSEric Joyner 	ixgbe_vf_enable_receive(adapter, vf);
4998eb6488eSEric Joyner 
5008eb6488eSEric Joyner 	mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
5018eb6488eSEric Joyner 	pf_max_size = (mhadd & IXGBE_MHADD_MFS_MASK) >> IXGBE_MHADD_MFS_SHIFT;
5028eb6488eSEric Joyner 
5038eb6488eSEric Joyner 	if (pf_max_size < adapter->max_frame_size) {
5048eb6488eSEric Joyner 		mhadd &= ~IXGBE_MHADD_MFS_MASK;
5058eb6488eSEric Joyner 		mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT;
5068eb6488eSEric Joyner 		IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd);
5078eb6488eSEric Joyner 	}
5088eb6488eSEric Joyner 
5098eb6488eSEric Joyner 	ixgbe_send_vf_ack(adapter, vf, msg[0]);
5108eb6488eSEric Joyner } /* ixgbe_vf_set_lpe */
5118eb6488eSEric Joyner 
5128eb6488eSEric Joyner 
5138eb6488eSEric Joyner static void
5148eb6488eSEric Joyner ixgbe_vf_set_macvlan(struct adapter *adapter, struct ixgbe_vf *vf,
5158eb6488eSEric Joyner                      uint32_t *msg)
5168eb6488eSEric Joyner {
5178eb6488eSEric Joyner 	//XXX implement this
5188eb6488eSEric Joyner 	ixgbe_send_vf_nack(adapter, vf, msg[0]);
5198eb6488eSEric Joyner } /* ixgbe_vf_set_macvlan */
5208eb6488eSEric Joyner 
5218eb6488eSEric Joyner 
5228eb6488eSEric Joyner static void
5238eb6488eSEric Joyner ixgbe_vf_api_negotiate(struct adapter *adapter, struct ixgbe_vf *vf,
5248eb6488eSEric Joyner     uint32_t *msg)
5258eb6488eSEric Joyner {
5268eb6488eSEric Joyner 
5278eb6488eSEric Joyner 	switch (msg[1]) {
5288eb6488eSEric Joyner 	case IXGBE_API_VER_1_0:
5298eb6488eSEric Joyner 	case IXGBE_API_VER_1_1:
5308eb6488eSEric Joyner 		vf->api_ver = msg[1];
5318eb6488eSEric Joyner 		ixgbe_send_vf_ack(adapter, vf, msg[0]);
5328eb6488eSEric Joyner 		break;
5338eb6488eSEric Joyner 	default:
5348eb6488eSEric Joyner 		vf->api_ver = IXGBE_API_VER_UNKNOWN;
5358eb6488eSEric Joyner 		ixgbe_send_vf_nack(adapter, vf, msg[0]);
5368eb6488eSEric Joyner 		break;
5378eb6488eSEric Joyner 	}
5388eb6488eSEric Joyner } /* ixgbe_vf_api_negotiate */
5398eb6488eSEric Joyner 
5408eb6488eSEric Joyner 
5418eb6488eSEric Joyner static void
5428eb6488eSEric Joyner ixgbe_vf_get_queues(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg)
5438eb6488eSEric Joyner {
5448eb6488eSEric Joyner 	struct ixgbe_hw *hw;
5458eb6488eSEric Joyner 	uint32_t resp[IXGBE_VF_GET_QUEUES_RESP_LEN];
5468eb6488eSEric Joyner 	int num_queues;
5478eb6488eSEric Joyner 
5488eb6488eSEric Joyner 	hw = &adapter->hw;
5498eb6488eSEric Joyner 
5508eb6488eSEric Joyner 	/* GET_QUEUES is not supported on pre-1.1 APIs. */
5518eb6488eSEric Joyner 	switch (msg[0]) {
5528eb6488eSEric Joyner 	case IXGBE_API_VER_1_0:
5538eb6488eSEric Joyner 	case IXGBE_API_VER_UNKNOWN:
5548eb6488eSEric Joyner 		ixgbe_send_vf_nack(adapter, vf, msg[0]);
5558eb6488eSEric Joyner 		return;
5568eb6488eSEric Joyner 	}
5578eb6488eSEric Joyner 
5588eb6488eSEric Joyner 	resp[0] = IXGBE_VF_GET_QUEUES | IXGBE_VT_MSGTYPE_ACK |
5598eb6488eSEric Joyner 	    IXGBE_VT_MSGTYPE_CTS;
5608eb6488eSEric Joyner 
5618eb6488eSEric Joyner 	num_queues = ixgbe_vf_queues(adapter->iov_mode);
5628eb6488eSEric Joyner 	resp[IXGBE_VF_TX_QUEUES] = num_queues;
5638eb6488eSEric Joyner 	resp[IXGBE_VF_RX_QUEUES] = num_queues;
5648eb6488eSEric Joyner 	resp[IXGBE_VF_TRANS_VLAN] = (vf->default_vlan != 0);
5658eb6488eSEric Joyner 	resp[IXGBE_VF_DEF_QUEUE] = 0;
5668eb6488eSEric Joyner 
5678eb6488eSEric Joyner 	hw->mbx.ops.write(hw, resp, IXGBE_VF_GET_QUEUES_RESP_LEN, vf->pool);
5688eb6488eSEric Joyner } /* ixgbe_vf_get_queues */
5698eb6488eSEric Joyner 
5708eb6488eSEric Joyner 
5718eb6488eSEric Joyner static void
572*c19c7afeSEric Joyner ixgbe_process_vf_msg(if_ctx_t ctx, struct ixgbe_vf *vf)
5738eb6488eSEric Joyner {
574*c19c7afeSEric Joyner 	struct adapter  *adapter = iflib_get_softc(ctx);
575*c19c7afeSEric Joyner #ifdef KTR
576*c19c7afeSEric Joyner 	struct ifnet	*ifp = iflib_get_ifp(ctx);
577*c19c7afeSEric Joyner #endif
5788eb6488eSEric Joyner 	struct ixgbe_hw *hw;
5798eb6488eSEric Joyner 	uint32_t msg[IXGBE_VFMAILBOX_SIZE];
5808eb6488eSEric Joyner 	int error;
5818eb6488eSEric Joyner 
5828eb6488eSEric Joyner 	hw = &adapter->hw;
5838eb6488eSEric Joyner 
5848eb6488eSEric Joyner 	error = hw->mbx.ops.read(hw, msg, IXGBE_VFMAILBOX_SIZE, vf->pool);
5858eb6488eSEric Joyner 
5868eb6488eSEric Joyner 	if (error != 0)
5878eb6488eSEric Joyner 		return;
5888eb6488eSEric Joyner 
589*c19c7afeSEric Joyner 	CTR3(KTR_MALLOC, "%s: received msg %x from %d", ifp->if_xname,
590*c19c7afeSEric Joyner 	    msg[0], vf->pool);
5918eb6488eSEric Joyner 	if (msg[0] == IXGBE_VF_RESET) {
5928eb6488eSEric Joyner 		ixgbe_vf_reset_msg(adapter, vf, msg);
5938eb6488eSEric Joyner 		return;
5948eb6488eSEric Joyner 	}
5958eb6488eSEric Joyner 
5968eb6488eSEric Joyner 	if (!(vf->flags & IXGBE_VF_CTS)) {
5978eb6488eSEric Joyner 		ixgbe_send_vf_nack(adapter, vf, msg[0]);
5988eb6488eSEric Joyner 		return;
5998eb6488eSEric Joyner 	}
6008eb6488eSEric Joyner 
6018eb6488eSEric Joyner 	switch (msg[0] & IXGBE_VT_MSG_MASK) {
6028eb6488eSEric Joyner 	case IXGBE_VF_SET_MAC_ADDR:
6038eb6488eSEric Joyner 		ixgbe_vf_set_mac(adapter, vf, msg);
6048eb6488eSEric Joyner 		break;
6058eb6488eSEric Joyner 	case IXGBE_VF_SET_MULTICAST:
6068eb6488eSEric Joyner 		ixgbe_vf_set_mc_addr(adapter, vf, msg);
6078eb6488eSEric Joyner 		break;
6088eb6488eSEric Joyner 	case IXGBE_VF_SET_VLAN:
6098eb6488eSEric Joyner 		ixgbe_vf_set_vlan(adapter, vf, msg);
6108eb6488eSEric Joyner 		break;
6118eb6488eSEric Joyner 	case IXGBE_VF_SET_LPE:
6128eb6488eSEric Joyner 		ixgbe_vf_set_lpe(adapter, vf, msg);
6138eb6488eSEric Joyner 		break;
6148eb6488eSEric Joyner 	case IXGBE_VF_SET_MACVLAN:
6158eb6488eSEric Joyner 		ixgbe_vf_set_macvlan(adapter, vf, msg);
6168eb6488eSEric Joyner 		break;
6178eb6488eSEric Joyner 	case IXGBE_VF_API_NEGOTIATE:
6188eb6488eSEric Joyner 		ixgbe_vf_api_negotiate(adapter, vf, msg);
6198eb6488eSEric Joyner 		break;
6208eb6488eSEric Joyner 	case IXGBE_VF_GET_QUEUES:
6218eb6488eSEric Joyner 		ixgbe_vf_get_queues(adapter, vf, msg);
6228eb6488eSEric Joyner 		break;
6238eb6488eSEric Joyner 	default:
6248eb6488eSEric Joyner 		ixgbe_send_vf_nack(adapter, vf, msg[0]);
6258eb6488eSEric Joyner 	}
6268eb6488eSEric Joyner } /* ixgbe_process_vf_msg */
6278eb6488eSEric Joyner 
6288eb6488eSEric Joyner 
6298eb6488eSEric Joyner /* Tasklet for handling VF -> PF mailbox messages */
6308eb6488eSEric Joyner void
631*c19c7afeSEric Joyner ixgbe_handle_mbx(void *context)
6328eb6488eSEric Joyner {
633*c19c7afeSEric Joyner 	if_ctx_t        ctx = context;
634*c19c7afeSEric Joyner 	struct adapter  *adapter = iflib_get_softc(ctx);
6358eb6488eSEric Joyner 	struct ixgbe_hw *hw;
6368eb6488eSEric Joyner 	struct ixgbe_vf *vf;
6378eb6488eSEric Joyner 	int i;
6388eb6488eSEric Joyner 
6398eb6488eSEric Joyner 	hw = &adapter->hw;
6408eb6488eSEric Joyner 
6418eb6488eSEric Joyner 	for (i = 0; i < adapter->num_vfs; i++) {
6428eb6488eSEric Joyner 		vf = &adapter->vfs[i];
6438eb6488eSEric Joyner 
6448eb6488eSEric Joyner 		if (vf->flags & IXGBE_VF_ACTIVE) {
6458eb6488eSEric Joyner 			if (hw->mbx.ops.check_for_rst(hw, vf->pool) == 0)
6468eb6488eSEric Joyner 				ixgbe_process_vf_reset(adapter, vf);
6478eb6488eSEric Joyner 
6488eb6488eSEric Joyner 			if (hw->mbx.ops.check_for_msg(hw, vf->pool) == 0)
649*c19c7afeSEric Joyner 				ixgbe_process_vf_msg(ctx, vf);
6508eb6488eSEric Joyner 
6518eb6488eSEric Joyner 			if (hw->mbx.ops.check_for_ack(hw, vf->pool) == 0)
6528eb6488eSEric Joyner 				ixgbe_process_vf_ack(adapter, vf);
6538eb6488eSEric Joyner 		}
6548eb6488eSEric Joyner 	}
6558eb6488eSEric Joyner } /* ixgbe_handle_mbx */
6568eb6488eSEric Joyner 
6578eb6488eSEric Joyner int
658*c19c7afeSEric Joyner ixgbe_if_iov_init(if_ctx_t ctx, u16 num_vfs, const nvlist_t *config)
6598eb6488eSEric Joyner {
6608eb6488eSEric Joyner 	struct adapter *adapter;
6618eb6488eSEric Joyner 	int retval = 0;
6628eb6488eSEric Joyner 
663*c19c7afeSEric Joyner 	adapter = iflib_get_softc(ctx);
6648eb6488eSEric Joyner 	adapter->iov_mode = IXGBE_NO_VM;
6658eb6488eSEric Joyner 
6668eb6488eSEric Joyner 	if (num_vfs == 0) {
6678eb6488eSEric Joyner 		/* Would we ever get num_vfs = 0? */
6688eb6488eSEric Joyner 		retval = EINVAL;
6698eb6488eSEric Joyner 		goto err_init_iov;
6708eb6488eSEric Joyner 	}
6718eb6488eSEric Joyner 
6728eb6488eSEric Joyner 	/*
6738eb6488eSEric Joyner 	 * We've got to reserve a VM's worth of queues for the PF,
6748eb6488eSEric Joyner 	 * thus we go into "64 VF mode" if 32+ VFs are requested.
6758eb6488eSEric Joyner 	 * With 64 VFs, you can only have two queues per VF.
6768eb6488eSEric Joyner 	 * With 32 VFs, you can have up to four queues per VF.
6778eb6488eSEric Joyner 	 */
6788eb6488eSEric Joyner 	if (num_vfs >= IXGBE_32_VM)
6798eb6488eSEric Joyner 		adapter->iov_mode = IXGBE_64_VM;
6808eb6488eSEric Joyner 	else
6818eb6488eSEric Joyner 		adapter->iov_mode = IXGBE_32_VM;
6828eb6488eSEric Joyner 
6838eb6488eSEric Joyner 	/* Again, reserving 1 VM's worth of queues for the PF */
6848eb6488eSEric Joyner 	adapter->pool = adapter->iov_mode - 1;
6858eb6488eSEric Joyner 
6868eb6488eSEric Joyner 	if ((num_vfs > adapter->pool) || (num_vfs >= IXGBE_64_VM)) {
6878eb6488eSEric Joyner 		retval = ENOSPC;
6888eb6488eSEric Joyner 		goto err_init_iov;
6898eb6488eSEric Joyner 	}
6908eb6488eSEric Joyner 
6918eb6488eSEric Joyner 	adapter->vfs = malloc(sizeof(*adapter->vfs) * num_vfs, M_IXGBE_SRIOV,
6928eb6488eSEric Joyner 	    M_NOWAIT | M_ZERO);
6938eb6488eSEric Joyner 
6948eb6488eSEric Joyner 	if (adapter->vfs == NULL) {
6958eb6488eSEric Joyner 		retval = ENOMEM;
6968eb6488eSEric Joyner 		goto err_init_iov;
6978eb6488eSEric Joyner 	}
6988eb6488eSEric Joyner 
6998eb6488eSEric Joyner 	adapter->num_vfs = num_vfs;
700*c19c7afeSEric Joyner 	ixgbe_if_init(adapter->ctx);
7018eb6488eSEric Joyner 	adapter->feat_en |= IXGBE_FEATURE_SRIOV;
7028eb6488eSEric Joyner 
703*c19c7afeSEric Joyner 	return (retval);
7048eb6488eSEric Joyner 
7058eb6488eSEric Joyner err_init_iov:
7068eb6488eSEric Joyner 	adapter->num_vfs = 0;
7078eb6488eSEric Joyner 	adapter->pool = 0;
7088eb6488eSEric Joyner 	adapter->iov_mode = IXGBE_NO_VM;
7098eb6488eSEric Joyner 
710*c19c7afeSEric Joyner 	return (retval);
711*c19c7afeSEric Joyner } /* ixgbe_if_iov_init */
7128eb6488eSEric Joyner 
7138eb6488eSEric Joyner void
714*c19c7afeSEric Joyner ixgbe_if_iov_uninit(if_ctx_t ctx)
7158eb6488eSEric Joyner {
7168eb6488eSEric Joyner 	struct ixgbe_hw *hw;
7178eb6488eSEric Joyner 	struct adapter *adapter;
7188eb6488eSEric Joyner 	uint32_t pf_reg, vf_reg;
7198eb6488eSEric Joyner 
720*c19c7afeSEric Joyner 	adapter = iflib_get_softc(ctx);
7218eb6488eSEric Joyner 	hw = &adapter->hw;
7228eb6488eSEric Joyner 
7238eb6488eSEric Joyner 	/* Enable rx/tx for the PF and disable it for all VFs. */
7248eb6488eSEric Joyner 	pf_reg = IXGBE_VF_INDEX(adapter->pool);
7258eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_VFRE(pf_reg), IXGBE_VF_BIT(adapter->pool));
7268eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_VFTE(pf_reg), IXGBE_VF_BIT(adapter->pool));
7278eb6488eSEric Joyner 
7288eb6488eSEric Joyner 	if (pf_reg == 0)
7298eb6488eSEric Joyner 		vf_reg = 1;
7308eb6488eSEric Joyner 	else
7318eb6488eSEric Joyner 		vf_reg = 0;
7328eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), 0);
7338eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), 0);
7348eb6488eSEric Joyner 
7358eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, 0);
7368eb6488eSEric Joyner 
7378eb6488eSEric Joyner 	free(adapter->vfs, M_IXGBE_SRIOV);
7388eb6488eSEric Joyner 	adapter->vfs = NULL;
7398eb6488eSEric Joyner 	adapter->num_vfs = 0;
7408eb6488eSEric Joyner 	adapter->feat_en &= ~IXGBE_FEATURE_SRIOV;
741*c19c7afeSEric Joyner } /* ixgbe_if_iov_uninit */
7428eb6488eSEric Joyner 
7438eb6488eSEric Joyner static void
7448eb6488eSEric Joyner ixgbe_init_vf(struct adapter *adapter, struct ixgbe_vf *vf)
7458eb6488eSEric Joyner {
7468eb6488eSEric Joyner 	struct ixgbe_hw *hw;
7478eb6488eSEric Joyner 	uint32_t vf_index, pfmbimr;
7488eb6488eSEric Joyner 
7498eb6488eSEric Joyner 	hw = &adapter->hw;
7508eb6488eSEric Joyner 
7518eb6488eSEric Joyner 	if (!(vf->flags & IXGBE_VF_ACTIVE))
7528eb6488eSEric Joyner 		return;
7538eb6488eSEric Joyner 
7548eb6488eSEric Joyner 	vf_index = IXGBE_VF_INDEX(vf->pool);
7558eb6488eSEric Joyner 	pfmbimr = IXGBE_READ_REG(hw, IXGBE_PFMBIMR(vf_index));
7568eb6488eSEric Joyner 	pfmbimr |= IXGBE_VF_BIT(vf->pool);
7578eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_PFMBIMR(vf_index), pfmbimr);
7588eb6488eSEric Joyner 
7598eb6488eSEric Joyner 	ixgbe_vf_set_default_vlan(adapter, vf, vf->vlan_tag);
7608eb6488eSEric Joyner 
7618eb6488eSEric Joyner 	// XXX multicast addresses
7628eb6488eSEric Joyner 
7638eb6488eSEric Joyner 	if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) {
7648eb6488eSEric Joyner 		ixgbe_set_rar(&adapter->hw, vf->rar_index,
7658eb6488eSEric Joyner 		    vf->ether_addr, vf->pool, TRUE);
7668eb6488eSEric Joyner 	}
7678eb6488eSEric Joyner 
7688eb6488eSEric Joyner 	ixgbe_vf_enable_transmit(adapter, vf);
7698eb6488eSEric Joyner 	ixgbe_vf_enable_receive(adapter, vf);
7708eb6488eSEric Joyner 
7718eb6488eSEric Joyner 	ixgbe_send_vf_msg(adapter, vf, IXGBE_PF_CONTROL_MSG);
7728eb6488eSEric Joyner } /* ixgbe_init_vf */
7738eb6488eSEric Joyner 
7748eb6488eSEric Joyner void
7758eb6488eSEric Joyner ixgbe_initialize_iov(struct adapter *adapter)
7768eb6488eSEric Joyner {
7778eb6488eSEric Joyner 	struct ixgbe_hw *hw = &adapter->hw;
7788eb6488eSEric Joyner 	uint32_t mrqc, mtqc, vt_ctl, vf_reg, gcr_ext, gpie;
7798eb6488eSEric Joyner 	int i;
7808eb6488eSEric Joyner 
7818eb6488eSEric Joyner 	if (adapter->iov_mode == IXGBE_NO_VM)
7828eb6488eSEric Joyner 		return;
7838eb6488eSEric Joyner 
7848eb6488eSEric Joyner 	/* RMW appropriate registers based on IOV mode */
7858eb6488eSEric Joyner 	/* Read... */
7868eb6488eSEric Joyner 	mrqc    = IXGBE_READ_REG(hw, IXGBE_MRQC);
7878eb6488eSEric Joyner 	gcr_ext = IXGBE_READ_REG(hw, IXGBE_GCR_EXT);
7888eb6488eSEric Joyner 	gpie    = IXGBE_READ_REG(hw, IXGBE_GPIE);
7898eb6488eSEric Joyner 	/* Modify... */
7908eb6488eSEric Joyner 	mrqc    &= ~IXGBE_MRQC_MRQE_MASK;
7918eb6488eSEric Joyner 	mtqc     =  IXGBE_MTQC_VT_ENA;      /* No initial MTQC read needed */
7928eb6488eSEric Joyner 	gcr_ext |=  IXGBE_GCR_EXT_MSIX_EN;
7938eb6488eSEric Joyner 	gcr_ext &= ~IXGBE_GCR_EXT_VT_MODE_MASK;
7948eb6488eSEric Joyner 	gpie    &= ~IXGBE_GPIE_VTMODE_MASK;
7958eb6488eSEric Joyner 	switch (adapter->iov_mode) {
7968eb6488eSEric Joyner 	case IXGBE_64_VM:
7978eb6488eSEric Joyner 		mrqc    |= IXGBE_MRQC_VMDQRSS64EN;
7988eb6488eSEric Joyner 		mtqc    |= IXGBE_MTQC_64VF;
7998eb6488eSEric Joyner 		gcr_ext |= IXGBE_GCR_EXT_VT_MODE_64;
8008eb6488eSEric Joyner 		gpie    |= IXGBE_GPIE_VTMODE_64;
8018eb6488eSEric Joyner 		break;
8028eb6488eSEric Joyner 	case IXGBE_32_VM:
8038eb6488eSEric Joyner 		mrqc    |= IXGBE_MRQC_VMDQRSS32EN;
8048eb6488eSEric Joyner 		mtqc    |= IXGBE_MTQC_32VF;
8058eb6488eSEric Joyner 		gcr_ext |= IXGBE_GCR_EXT_VT_MODE_32;
8068eb6488eSEric Joyner 		gpie    |= IXGBE_GPIE_VTMODE_32;
8078eb6488eSEric Joyner 		break;
8088eb6488eSEric Joyner 	default:
8098eb6488eSEric Joyner 		panic("Unexpected SR-IOV mode %d", adapter->iov_mode);
8108eb6488eSEric Joyner 	}
8118eb6488eSEric Joyner 	/* Write... */
8128eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
8138eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_MTQC, mtqc);
8148eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr_ext);
8158eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
8168eb6488eSEric Joyner 
8178eb6488eSEric Joyner 	/* Enable rx/tx for the PF. */
8188eb6488eSEric Joyner 	vf_reg = IXGBE_VF_INDEX(adapter->pool);
8198eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), IXGBE_VF_BIT(adapter->pool));
8208eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), IXGBE_VF_BIT(adapter->pool));
8218eb6488eSEric Joyner 
8228eb6488eSEric Joyner 	/* Allow VM-to-VM communication. */
8238eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
8248eb6488eSEric Joyner 
8258eb6488eSEric Joyner 	vt_ctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN;
8268eb6488eSEric Joyner 	vt_ctl |= (adapter->pool << IXGBE_VT_CTL_POOL_SHIFT);
8278eb6488eSEric Joyner 	IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vt_ctl);
8288eb6488eSEric Joyner 
8298eb6488eSEric Joyner 	for (i = 0; i < adapter->num_vfs; i++)
8308eb6488eSEric Joyner 		ixgbe_init_vf(adapter, &adapter->vfs[i]);
8318eb6488eSEric Joyner } /* ixgbe_initialize_iov */
8328eb6488eSEric Joyner 
8338eb6488eSEric Joyner 
8348eb6488eSEric Joyner /* Check the max frame setting of all active VF's */
8358eb6488eSEric Joyner void
8368eb6488eSEric Joyner ixgbe_recalculate_max_frame(struct adapter *adapter)
8378eb6488eSEric Joyner {
8388eb6488eSEric Joyner 	struct ixgbe_vf *vf;
8398eb6488eSEric Joyner 
8408eb6488eSEric Joyner 	for (int i = 0; i < adapter->num_vfs; i++) {
8418eb6488eSEric Joyner 		vf = &adapter->vfs[i];
8428eb6488eSEric Joyner 		if (vf->flags & IXGBE_VF_ACTIVE)
843*c19c7afeSEric Joyner 			ixgbe_update_max_frame(adapter, vf->maximum_frame_size);
8448eb6488eSEric Joyner 	}
8458eb6488eSEric Joyner } /* ixgbe_recalculate_max_frame */
8468eb6488eSEric Joyner 
8478eb6488eSEric Joyner int
848*c19c7afeSEric Joyner ixgbe_if_iov_vf_add(if_ctx_t ctx, u16 vfnum, const nvlist_t *config)
8498eb6488eSEric Joyner {
8508eb6488eSEric Joyner 	struct adapter *adapter;
8518eb6488eSEric Joyner 	struct ixgbe_vf *vf;
8528eb6488eSEric Joyner 	const void *mac;
8538eb6488eSEric Joyner 
854*c19c7afeSEric Joyner 	adapter = iflib_get_softc(ctx);
8558eb6488eSEric Joyner 
8568eb6488eSEric Joyner 	KASSERT(vfnum < adapter->num_vfs, ("VF index %d is out of range %d",
8578eb6488eSEric Joyner 	    vfnum, adapter->num_vfs));
8588eb6488eSEric Joyner 
8598eb6488eSEric Joyner 	vf = &adapter->vfs[vfnum];
8608eb6488eSEric Joyner 	vf->pool= vfnum;
8618eb6488eSEric Joyner 
8628eb6488eSEric Joyner 	/* RAR[0] is used by the PF so use vfnum + 1 for VF RAR. */
8638eb6488eSEric Joyner 	vf->rar_index = vfnum + 1;
8648eb6488eSEric Joyner 	vf->default_vlan = 0;
865*c19c7afeSEric Joyner 	vf->maximum_frame_size = ETHER_MAX_LEN;
866*c19c7afeSEric Joyner 	ixgbe_update_max_frame(adapter, vf->maximum_frame_size);
8678eb6488eSEric Joyner 
8688eb6488eSEric Joyner 	if (nvlist_exists_binary(config, "mac-addr")) {
8698eb6488eSEric Joyner 		mac = nvlist_get_binary(config, "mac-addr", NULL);
8708eb6488eSEric Joyner 		bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN);
8718eb6488eSEric Joyner 		if (nvlist_get_bool(config, "allow-set-mac"))
8728eb6488eSEric Joyner 			vf->flags |= IXGBE_VF_CAP_MAC;
8738eb6488eSEric Joyner 	} else
8748eb6488eSEric Joyner 		/*
8758eb6488eSEric Joyner 		 * If the administrator has not specified a MAC address then
8768eb6488eSEric Joyner 		 * we must allow the VF to choose one.
8778eb6488eSEric Joyner 		 */
8788eb6488eSEric Joyner 		vf->flags |= IXGBE_VF_CAP_MAC;
8798eb6488eSEric Joyner 
8808eb6488eSEric Joyner 	vf->flags |= IXGBE_VF_ACTIVE;
8818eb6488eSEric Joyner 
8828eb6488eSEric Joyner 	ixgbe_init_vf(adapter, vf);
8838eb6488eSEric Joyner 
8848eb6488eSEric Joyner 	return (0);
885*c19c7afeSEric Joyner } /* ixgbe_if_iov_vf_add */
8868eb6488eSEric Joyner 
8878eb6488eSEric Joyner #else
8888eb6488eSEric Joyner 
8898eb6488eSEric Joyner void
890*c19c7afeSEric Joyner ixgbe_handle_mbx(void *context)
8918eb6488eSEric Joyner {
892*c19c7afeSEric Joyner 	UNREFERENCED_PARAMETER(context);
8938eb6488eSEric Joyner } /* ixgbe_handle_mbx */
8948eb6488eSEric Joyner 
8958eb6488eSEric Joyner #endif
896