#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_sriov.c,v 1.18 2023/10/06 14:37:04 msaitoh Exp $");
#include "ixgbe.h"
#include "ixgbe_sriov.h"
#ifdef PCI_IOV
MALLOC_DEFINE(M_IXGBE_SRIOV, "ix_sriov", "ix SR-IOV allocations");
int
ixgbe_pci_iov_detach(device_t dev)
{
return pci_iov_detach(dev);
}
void
ixgbe_define_iov_schemas(device_t dev, int *error)
{
nvlist_t *pf_schema, *vf_schema;
pf_schema = pci_iov_schema_alloc_node();
vf_schema = pci_iov_schema_alloc_node();
pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof",
IOV_SCHEMA_HASDEFAULT, TRUE);
pci_iov_schema_add_bool(vf_schema, "allow-set-mac",
IOV_SCHEMA_HASDEFAULT, FALSE);
pci_iov_schema_add_bool(vf_schema, "allow-promisc",
IOV_SCHEMA_HASDEFAULT, FALSE);
*error = pci_iov_attach(dev, pf_schema, vf_schema);
if (*error != 0) {
device_printf(dev,
"Error %d setting up SR-IOV\n", *error);
}
}
inline void
ixgbe_align_all_queue_indices(struct ixgbe_softc *sc)
{
int i;
int index;
for (i = 0; i < sc->num_queues; i++) {
index = ixgbe_vf_que_index(sc->iov_mode, sc->pool, i);
sc->rx_rings[i].me = index;
sc->tx_rings[i].me = index;
}
}
static inline void
ixgbe_send_vf_msg(struct ixgbe_hw *hw, struct ixgbe_vf *vf, u32 msg)
{
if (vf->flags & IXGBE_VF_CTS)
msg |= IXGBE_VT_MSGTYPE_CTS;
hw->mbx.ops[vf->pool].write(hw, &msg, 1, vf->pool);
}
static inline void
ixgbe_send_vf_ack(struct ixgbe_softc *sc, struct ixgbe_vf *vf, u32 msg)
{
msg &= IXGBE_VT_MSG_MASK;
ixgbe_send_vf_msg(&sc->hw, vf, msg | IXGBE_VT_MSGTYPE_SUCCESS);
}
static inline void
ixgbe_send_vf_nack(struct ixgbe_softc *sc, struct ixgbe_vf *vf, u32 msg)
{
msg &= IXGBE_VT_MSG_MASK;
ixgbe_send_vf_msg(&sc->hw, vf, msg | IXGBE_VT_MSGTYPE_FAILURE);
}
static inline void
ixgbe_process_vf_ack(struct ixgbe_softc *sc, struct ixgbe_vf *vf)
{
if (!(vf->flags & IXGBE_VF_CTS))
ixgbe_send_vf_nack(sc, vf, 0);
}
static inline bool
ixgbe_vf_mac_changed(struct ixgbe_vf *vf, const uint8_t *mac)
{
return (bcmp(mac, vf->ether_addr, ETHER_ADDR_LEN) != 0);
}
static inline int
ixgbe_vf_queues(int mode)
{
switch (mode) {
case IXGBE_64_VM:
return (2);
case IXGBE_32_VM:
return (4);
case IXGBE_NO_VM:
default:
return (0);
}
}
inline int
ixgbe_vf_que_index(int mode, int vfnum, int num)
{
return ((vfnum * ixgbe_vf_queues(mode)) + num);
}
static inline void
ixgbe_update_max_frame(struct ixgbe_softc * sc, int max_frame)
{
if (sc->max_frame_size < max_frame)
sc->max_frame_size = max_frame;
}
inline u32
ixgbe_get_mrqc(int iov_mode)
{
u32 mrqc;
switch (iov_mode) {
case IXGBE_64_VM:
mrqc = IXGBE_MRQC_VMDQRSS64EN;
break;
case IXGBE_32_VM:
mrqc = IXGBE_MRQC_VMDQRSS32EN;
break;
case IXGBE_NO_VM:
mrqc = 0;
break;
default:
panic("Unexpected SR-IOV mode %d", iov_mode);
}
return mrqc;
}
inline u32
ixgbe_get_mtqc(int iov_mode)
{
uint32_t mtqc;
switch (iov_mode) {
case IXGBE_64_VM:
mtqc = IXGBE_MTQC_64VF | IXGBE_MTQC_VT_ENA;
break;
case IXGBE_32_VM:
mtqc = IXGBE_MTQC_32VF | IXGBE_MTQC_VT_ENA;
break;
case IXGBE_NO_VM:
mtqc = IXGBE_MTQC_64Q_1PB;
break;
default:
panic("Unexpected SR-IOV mode %d", iov_mode);
}
return mtqc;
}
void
ixgbe_ping_all_vfs(struct ixgbe_softc *sc)
{
struct ixgbe_vf *vf;
for (int i = 0; i < sc->num_vfs; i++) {
vf = &sc->vfs[i];
if (vf->flags & IXGBE_VF_ACTIVE)
ixgbe_send_vf_msg(&sc->hw, vf, IXGBE_PF_CONTROL_MSG);
}
}
static void
ixgbe_vf_set_default_vlan(struct ixgbe_softc *sc, struct ixgbe_vf *vf,
uint16_t tag)
{
struct ixgbe_hw *hw;
uint32_t vmolr, vmvir;
hw = &sc->hw;
vf->vlan_tag = tag;
vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf->pool));
vmolr &= ~(IXGBE_VMOLR_ROMPE | IXGBE_VMOLR_ROPE);
vmolr &= ~IXGBE_VMOLR_MPE;
vmolr |= IXGBE_VMOLR_BAM;
if (tag == 0) {
vmolr |= IXGBE_VMOLR_AUPE;
vmvir = 0;
} else {
vmolr &= ~IXGBE_VMOLR_AUPE;
vmvir = (tag | IXGBE_VMVIR_VLANA_DEFAULT);
}
IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf->pool), vmolr);
IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf->pool), vmvir);
}
static void
ixgbe_clear_vfmbmem(struct ixgbe_softc *sc, struct ixgbe_vf *vf)
{
struct ixgbe_hw *hw = &sc->hw;
uint32_t vf_index = IXGBE_VF_INDEX(vf->pool);
uint16_t mbx_size = hw->mbx.size;
uint16_t i;
IXGBE_CORE_LOCK_ASSERT(sc);
for (i = 0; i < mbx_size; ++i)
IXGBE_WRITE_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_index), i, 0x0);
}
static bool
ixgbe_vf_frame_size_compatible(struct ixgbe_softc *sc, struct ixgbe_vf *vf)
{
if (sc->hw.mac.type != ixgbe_mac_82599EB)
return (TRUE);
switch (vf->api_ver) {
case IXGBE_API_VER_1_0:
case IXGBE_API_VER_UNKNOWN:
if (sc->max_frame_size > ETHER_MAX_LEN ||
vf->max_frame_size > ETHER_MAX_LEN)
return (FALSE);
return (TRUE);
break;
case IXGBE_API_VER_1_1:
default:
if (vf->max_frame_size <= ETHER_MAX_LEN)
return (TRUE);
if (sc->max_frame_size <= ETHER_MAX_LEN)
return (TRUE);
return (FALSE);
}
}
static void
ixgbe_process_vf_reset(struct ixgbe_softc *sc, struct ixgbe_vf *vf)
{
ixgbe_vf_set_default_vlan(sc, vf, vf->default_vlan);
ixgbe_clear_rar(&sc->hw, vf->rar_index);
ixgbe_clear_vfmbmem(sc, vf);
ixgbe_toggle_txdctl(&sc->hw, IXGBE_VF_INDEX(vf->pool));
vf->api_ver = IXGBE_API_VER_UNKNOWN;
}
static void
ixgbe_vf_enable_transmit(struct ixgbe_softc *sc, struct ixgbe_vf *vf)
{
struct ixgbe_hw *hw;
uint32_t vf_index, vfte;
hw = &sc->hw;
vf_index = IXGBE_VF_INDEX(vf->pool);
vfte = IXGBE_READ_REG(hw, IXGBE_VFTE(vf_index));
vfte |= IXGBE_VF_BIT(vf->pool);
IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_index), vfte);
}
static void
ixgbe_vf_enable_receive(struct ixgbe_softc *sc, struct ixgbe_vf *vf)
{
struct ixgbe_hw *hw;
uint32_t vf_index, vfre;
hw = &sc->hw;
vf_index = IXGBE_VF_INDEX(vf->pool);
vfre = IXGBE_READ_REG(hw, IXGBE_VFRE(vf_index));
if (ixgbe_vf_frame_size_compatible(sc, vf))
vfre |= IXGBE_VF_BIT(vf->pool);
else
vfre &= ~IXGBE_VF_BIT(vf->pool);
IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_index), vfre);
}
static void
ixgbe_vf_reset_msg(struct ixgbe_softc *sc, struct ixgbe_vf *vf, uint32_t *msg)
{
struct ixgbe_hw *hw;
uint32_t ack;
uint32_t resp[IXGBE_VF_PERMADDR_MSG_LEN];
hw = &sc->hw;
ixgbe_process_vf_reset(sc, vf);
if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) {
ixgbe_set_rar(&sc->hw, vf->rar_index, vf->ether_addr,
vf->pool, TRUE);
ack = IXGBE_VT_MSGTYPE_SUCCESS;
} else
ack = IXGBE_VT_MSGTYPE_FAILURE;
ixgbe_vf_enable_transmit(sc, vf);
ixgbe_vf_enable_receive(sc, vf);
vf->flags |= IXGBE_VF_CTS;
resp[0] = IXGBE_VF_RESET | ack;
bcopy(vf->ether_addr, &resp[1], ETHER_ADDR_LEN);
resp[3] = hw->mac.mc_filter_type;
hw->mbx.ops.write(hw, resp, IXGBE_VF_PERMADDR_MSG_LEN, vf->pool);
}
static void
ixgbe_vf_set_mac(struct ixgbe_softc *sc, struct ixgbe_vf *vf, uint32_t *msg)
{
uint8_t *mac;
mac = (uint8_t*)&msg[1];
if (!(vf->flags & IXGBE_VF_CAP_MAC) && ixgbe_vf_mac_changed(vf, mac)) {
ixgbe_send_vf_nack(sc, vf, msg[0]);
return;
}
if (ixgbe_validate_mac_addr(mac) != 0) {
ixgbe_send_vf_nack(sc, vf, msg[0]);
return;
}
bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN);
ixgbe_set_rar(&sc->hw, vf->rar_index, vf->ether_addr, vf->pool,
TRUE);
ixgbe_send_vf_ack(sc, vf, msg[0]);
}
static void
ixgbe_vf_set_mc_addr(struct ixgbe_softc *sc, struct ixgbe_vf *vf, u32 *msg)
{
u16 *list = (u16*)&msg[1];
int entries;
u32 vmolr, vec_bit, vec_reg, mta_reg;
entries = (msg[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT;
entries = uimin(entries, IXGBE_MAX_VF_MC);
vmolr = IXGBE_READ_REG(&sc->hw, IXGBE_VMOLR(vf->pool));
vf->num_mc_hashes = entries;
for (int i = 0; i < entries; i++) {
vf->mc_hash[i] = list[i];
vec_reg = (vf->mc_hash[i] >> 5) & 0x7F;
vec_bit = vf->mc_hash[i] & 0x1F;
mta_reg = IXGBE_READ_REG(&sc->hw, IXGBE_MTA(vec_reg));
mta_reg |= (1 << vec_bit);
IXGBE_WRITE_REG(&sc->hw, IXGBE_MTA(vec_reg), mta_reg);
}
vmolr |= IXGBE_VMOLR_ROMPE;
IXGBE_WRITE_REG(&sc->hw, IXGBE_VMOLR(vf->pool), vmolr);
ixgbe_send_vf_ack(sc, vf, msg[0]);
}
static void
ixgbe_vf_set_vlan(struct ixgbe_softc *sc, struct ixgbe_vf *vf, uint32_t *msg)
{
struct ixgbe_hw *hw;
int enable;
uint16_t tag;
hw = &sc->hw;
enable = IXGBE_VT_MSGINFO(msg[0]);
tag = msg[1] & IXGBE_VLVF_VLANID_MASK;
if (!(vf->flags & IXGBE_VF_CAP_VLAN)) {
ixgbe_send_vf_nack(sc, vf, msg[0]);
return;
}
if (tag == 0 && enable != 0) {
ixgbe_send_vf_nack(sc, vf, msg[0]);
return;
}
ixgbe_set_vfta(hw, tag, vf->pool, enable, false);
ixgbe_send_vf_ack(sc, vf, msg[0]);
}
static void
ixgbe_vf_set_lpe(struct ixgbe_softc *sc, struct ixgbe_vf *vf, uint32_t *msg)
{
struct ixgbe_hw *hw;
uint32_t vf_max_size, pf_max_size, mhadd;
hw = &sc->hw;
vf_max_size = msg[1];
if (vf_max_size < ETHER_CRC_LEN) {
ixgbe_send_vf_ack(sc, vf, msg[0]);
return;
}
vf_max_size -= ETHER_CRC_LEN;
if (vf_max_size > IXGBE_MAX_FRAME_SIZE) {
ixgbe_send_vf_ack(sc, vf, msg[0]);
return;
}
vf->max_frame_size = vf_max_size;
ixgbe_update_max_frame(sc, vf->max_frame_size);
ixgbe_vf_enable_receive(sc, vf);
mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
pf_max_size = (mhadd & IXGBE_MHADD_MFS_MASK) >> IXGBE_MHADD_MFS_SHIFT;
if (pf_max_size < sc->max_frame_size) {
mhadd &= ~IXGBE_MHADD_MFS_MASK;
mhadd |= sc->max_frame_size << IXGBE_MHADD_MFS_SHIFT;
IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd);
}
ixgbe_send_vf_ack(sc, vf, msg[0]);
}
static void
ixgbe_vf_set_macvlan(struct ixgbe_softc *sc, struct ixgbe_vf *vf,
uint32_t *msg)
{
ixgbe_send_vf_nack(sc, vf, msg[0]);
}
static void
ixgbe_vf_api_negotiate(struct ixgbe_softc *sc, struct ixgbe_vf *vf,
uint32_t *msg)
{
switch (msg[1]) {
case IXGBE_API_VER_1_0:
case IXGBE_API_VER_1_1:
vf->api_ver = msg[1];
ixgbe_send_vf_ack(sc, vf, msg[0]);
break;
default:
vf->api_ver = IXGBE_API_VER_UNKNOWN;
ixgbe_send_vf_nack(sc, vf, msg[0]);
break;
}
}
static void
ixgbe_vf_get_queues(struct ixgbe_softc *sc, struct ixgbe_vf *vf, uint32_t *msg)
{
struct ixgbe_hw *hw;
uint32_t resp[IXGBE_VF_GET_QUEUES_RESP_LEN];
int num_queues;
hw = &sc->hw;
switch (msg[0]) {
case IXGBE_API_VER_1_0:
case IXGBE_API_VER_UNKNOWN:
ixgbe_send_vf_nack(sc, vf, msg[0]);
return;
}
resp[0] = IXGBE_VF_GET_QUEUES | IXGBE_VT_MSGTYPE_SUCCESS |
IXGBE_VT_MSGTYPE_CTS;
num_queues = ixgbe_vf_queues(sc->iov_mode);
resp[IXGBE_VF_TX_QUEUES] = num_queues;
resp[IXGBE_VF_RX_QUEUES] = num_queues;
resp[IXGBE_VF_TRANS_VLAN] = (vf->default_vlan != 0);
resp[IXGBE_VF_DEF_QUEUE] = 0;
hw->mbx.ops.write(hw, resp, IXGBE_VF_GET_QUEUES_RESP_LEN, vf->pool);
}
static void
ixgbe_process_vf_msg(struct ixgbe_softc *sc, struct ixgbe_vf *vf)
{
struct ixgbe_hw *hw;
uint32_t msg[IXGBE_VFMAILBOX_SIZE];
int error;
hw = &sc->hw;
error = hw->mbx.ops[vf->pool].read(hw, msg, IXGBE_VFMAILBOX_SIZE,
vf->pool);
if (error != 0)
return;
CTR3(KTR_MALLOC, "%s: received msg %x from %d",
sc->ifp->if_xname, msg[0], vf->pool);
if (msg[0] == IXGBE_VF_RESET) {
ixgbe_vf_reset_msg(sc, vf, msg);
return;
}
if (!(vf->flags & IXGBE_VF_CTS)) {
ixgbe_send_vf_nack(sc, vf, msg[0]);
return;
}
switch (msg[0] & IXGBE_VT_MSG_MASK) {
case IXGBE_VF_SET_MAC_ADDR:
ixgbe_vf_set_mac(sc, vf, msg);
break;
case IXGBE_VF_SET_MULTICAST:
ixgbe_vf_set_mc_addr(sc, vf, msg);
break;
case IXGBE_VF_SET_VLAN:
ixgbe_vf_set_vlan(sc, vf, msg);
break;
case IXGBE_VF_SET_LPE:
ixgbe_vf_set_lpe(sc, vf, msg);
break;
case IXGBE_VF_SET_MACVLAN:
ixgbe_vf_set_macvlan(sc, vf, msg);
break;
case IXGBE_VF_API_NEGOTIATE:
ixgbe_vf_api_negotiate(sc, vf, msg);
break;
case IXGBE_VF_GET_QUEUES:
ixgbe_vf_get_queues(sc, vf, msg);
break;
default:
ixgbe_send_vf_nack(sc, vf, msg[0]);
}
}
void
ixgbe_handle_mbx(void *context)
{
struct ixgbe_softc *sc = context;
struct ixgbe_hw *hw;
struct ixgbe_vf *vf;
int i;
KASSERT(mutex_owned(&sc->core_mtx));
hw = &sc->hw;
for (i = 0; i < sc->num_vfs; i++) {
vf = &sc->vfs[i];
if ((vf->flags & IXGBE_VF_ACTIVE) == 0)
continue;
if (hw->mbx.ops[vf->pool].check_for_rst(hw, vf->pool) == 0)
ixgbe_process_vf_reset(sc, vf);
if (hw->mbx.ops[vf->pool].check_for_msg(hw, vf->pool) == 0)
ixgbe_process_vf_msg(sc, vf);
if (hw->mbx.ops[vf->pool].check_for_ack(hw, vf->pool) == 0)
ixgbe_process_vf_ack(sc, vf);
}
}
int
ixgbe_init_iov(device_t dev, u16 num_vfs, const nvlist_t *config)
{
struct ixgbe_softc *sc;
int retval = 0;
sc = device_get_softc(dev);
sc->iov_mode = IXGBE_NO_VM;
if (num_vfs == 0) {
retval = EINVAL;
goto err_init_iov;
}
if (num_vfs >= IXGBE_32_VM)
sc->iov_mode = IXGBE_64_VM;
else
sc->iov_mode = IXGBE_32_VM;
sc->pool = sc->iov_mode - 1;
if ((num_vfs > sc->pool) || (num_vfs >= IXGBE_64_VM)) {
retval = ENOSPC;
goto err_init_iov;
}
IXGBE_CORE_LOCK(sc);
sc->vfs = malloc(sizeof(*sc->vfs) * num_vfs, M_IXGBE_SRIOV,
M_NOWAIT | M_ZERO);
if (sc->vfs == NULL) {
retval = ENOMEM;
IXGBE_CORE_UNLOCK(sc);
goto err_init_iov;
}
sc->num_vfs = num_vfs;
ixgbe_init_mbx_params_pf(&sc->hw);
sc->feat_en |= IXGBE_FEATURE_SRIOV;
sc->init_locked(sc);
IXGBE_CORE_UNLOCK(sc);
return retval;
err_init_iov:
sc->num_vfs = 0;
sc->pool = 0;
sc->iov_mode = IXGBE_NO_VM;
return retval;
}
void
ixgbe_uninit_iov(device_t dev)
{
struct ixgbe_hw *hw;
struct ixgbe_softc *sc;
uint32_t pf_reg, vf_reg;
sc = device_get_softc(dev);
hw = &sc->hw;
IXGBE_CORE_LOCK(sc);
pf_reg = IXGBE_VF_INDEX(sc->pool);
IXGBE_WRITE_REG(hw, IXGBE_VFRE(pf_reg), IXGBE_VF_BIT(sc->pool));
IXGBE_WRITE_REG(hw, IXGBE_VFTE(pf_reg), IXGBE_VF_BIT(sc->pool));
if (pf_reg == 0)
vf_reg = 1;
else
vf_reg = 0;
IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), 0);
IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), 0);
IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, 0);
free(sc->vfs, M_IXGBE_SRIOV);
sc->vfs = NULL;
sc->num_vfs = 0;
sc->feat_en &= ~IXGBE_FEATURE_SRIOV;
IXGBE_CORE_UNLOCK(sc);
}
static void
ixgbe_init_vf(struct ixgbe_softc *sc, struct ixgbe_vf *vf)
{
struct ixgbe_hw *hw;
uint32_t vf_index, pfmbimr;
IXGBE_CORE_LOCK_ASSERT(sc);
hw = &sc->hw;
if (!(vf->flags & IXGBE_VF_ACTIVE))
return;
vf_index = IXGBE_VF_INDEX(vf->pool);
pfmbimr = IXGBE_READ_REG(hw, IXGBE_PFMBIMR(vf_index));
pfmbimr |= IXGBE_VF_BIT(vf->pool);
IXGBE_WRITE_REG(hw, IXGBE_PFMBIMR(vf_index), pfmbimr);
ixgbe_vf_set_default_vlan(sc, vf, vf->vlan_tag);
if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) {
ixgbe_set_rar(&sc->hw, vf->rar_index,
vf->ether_addr, vf->pool, TRUE);
}
ixgbe_vf_enable_transmit(sc, vf);
ixgbe_vf_enable_receive(sc, vf);
ixgbe_send_vf_msg(&sc->hw, vf, IXGBE_PF_CONTROL_MSG);
}
void
ixgbe_initialize_iov(struct ixgbe_softc *sc)
{
struct ixgbe_hw *hw = &sc->hw;
uint32_t mrqc, mtqc, vt_ctl, vf_reg, gcr_ext, gpie;
int i;
if (sc->iov_mode == IXGBE_NO_VM)
return;
IXGBE_CORE_LOCK_ASSERT(sc);
mrqc = IXGBE_READ_REG(hw, IXGBE_MRQC);
gcr_ext = IXGBE_READ_REG(hw, IXGBE_GCR_EXT);
gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
mrqc &= ~IXGBE_MRQC_MRQE_MASK;
mtqc = IXGBE_MTQC_VT_ENA;
gcr_ext |= IXGBE_GCR_EXT_MSIX_EN;
gcr_ext &= ~IXGBE_GCR_EXT_VT_MODE_MASK;
gpie &= ~IXGBE_GPIE_VTMODE_MASK;
switch (sc->iov_mode) {
case IXGBE_64_VM:
mrqc |= IXGBE_MRQC_VMDQRSS64EN;
mtqc |= IXGBE_MTQC_64VF;
gcr_ext |= IXGBE_GCR_EXT_VT_MODE_64;
gpie |= IXGBE_GPIE_VTMODE_64;
break;
case IXGBE_32_VM:
mrqc |= IXGBE_MRQC_VMDQRSS32EN;
mtqc |= IXGBE_MTQC_32VF;
gcr_ext |= IXGBE_GCR_EXT_VT_MODE_32;
gpie |= IXGBE_GPIE_VTMODE_32;
break;
default:
panic("Unexpected SR-IOV mode %d", sc->iov_mode);
}
IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
IXGBE_WRITE_REG(hw, IXGBE_MTQC, mtqc);
IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr_ext);
IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
vf_reg = IXGBE_VF_INDEX(sc->pool);
IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), IXGBE_VF_BIT(sc->pool));
IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), IXGBE_VF_BIT(sc->pool));
IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
vt_ctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN;
vt_ctl |= (sc->pool << IXGBE_VT_CTL_POOL_SHIFT);
IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vt_ctl);
for (i = 0; i < sc->num_vfs; i++)
ixgbe_init_vf(sc, &sc->vfs[i]);
}
void
ixgbe_recalculate_max_frame(struct ixgbe_softc *sc)
{
struct ixgbe_vf *vf;
IXGBE_CORE_LOCK_ASSERT(sc);
for (int i = 0; i < sc->num_vfs; i++) {
vf = &sc->vfs[i];
if (vf->flags & IXGBE_VF_ACTIVE)
ixgbe_update_max_frame(sc, vf->max_frame_size);
}
}
int
ixgbe_add_vf(device_t dev, u16 vfnum, const nvlist_t *config)
{
struct ixgbe_softc *sc;
struct ixgbe_vf *vf;
const void *mac;
sc = device_get_softc(dev);
KASSERT(vfnum < sc->num_vfs, ("VF index %d is out of range %d",
vfnum, sc->num_vfs));
IXGBE_CORE_LOCK(sc);
vf = &sc->vfs[vfnum];
vf->pool= vfnum;
vf->rar_index = vfnum + 1;
vf->default_vlan = 0;
vf->max_frame_size = ETHER_MAX_LEN;
ixgbe_update_max_frame(sc, vf->max_frame_size);
if (nvlist_exists_binary(config, "mac-addr")) {
mac = nvlist_get_binary(config, "mac-addr", NULL);
bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN);
if (nvlist_get_bool(config, "allow-set-mac"))
vf->flags |= IXGBE_VF_CAP_MAC;
} else
vf->flags |= IXGBE_VF_CAP_MAC;
vf->flags |= IXGBE_VF_ACTIVE;
ixgbe_init_vf(sc, vf);
IXGBE_CORE_UNLOCK(sc);
return (0);
}
#else
void
ixgbe_handle_mbx(void *context)
{
UNREFERENCED_1PARAMETER(context);
}
inline int
ixgbe_vf_que_index(int mode, int vfnum, int num)
{
UNREFERENCED_2PARAMETER(mode, vfnum);
return num;
}
#endif