#include "iavf_vc_common.h"
static void iavf_handle_link_event(struct iavf_sc *sc,
struct virtchnl_pf_event *vpe);
int
iavf_send_pf_msg(struct iavf_sc *sc,
enum virtchnl_ops op, u8 *msg, u16 len)
{
struct iavf_hw *hw = &sc->hw;
device_t dev = sc->dev;
enum iavf_status status;
int val_err;
val_err = virtchnl_vc_validate_vf_msg(&sc->version, op, msg, len);
if (val_err)
device_printf(dev, "Error validating msg to PF for op %d,"
" msglen %d: error %d\n", op, len, val_err);
if (!iavf_check_asq_alive(hw)) {
if (op != VIRTCHNL_OP_GET_STATS)
device_printf(dev, "Unable to send opcode %s to PF, "
"ASQ is not alive\n", iavf_vc_opcode_str(op));
return (0);
}
if (op != VIRTCHNL_OP_GET_STATS)
iavf_dbg_vc(sc,
"Sending msg (op=%s[%d]) to PF\n",
iavf_vc_opcode_str(op), op);
status = iavf_aq_send_msg_to_pf(hw, op, IAVF_SUCCESS, msg, len, NULL);
if (status && op != VIRTCHNL_OP_GET_STATS)
device_printf(dev, "Unable to send opcode %s to PF, "
"status %s, aq error %s\n",
iavf_vc_opcode_str(op),
iavf_stat_str(hw, status),
iavf_aq_str(hw, hw->aq.asq_last_status));
return (status);
}
int
iavf_send_api_ver(struct iavf_sc *sc)
{
struct virtchnl_version_info vvi;
vvi.major = VIRTCHNL_VERSION_MAJOR;
vvi.minor = VIRTCHNL_VERSION_MINOR;
return iavf_send_pf_msg(sc, VIRTCHNL_OP_VERSION,
(u8 *)&vvi, sizeof(vvi));
}
int
iavf_verify_api_ver(struct iavf_sc *sc)
{
struct virtchnl_version_info *pf_vvi;
struct iavf_hw *hw = &sc->hw;
struct iavf_arq_event_info event;
enum iavf_status status;
device_t dev = sc->dev;
int error = 0;
int retries = 0;
event.buf_len = IAVF_AQ_BUF_SZ;
event.msg_buf = (u8 *)malloc(event.buf_len, M_IAVF, M_WAITOK);
for (;;) {
if (++retries > IAVF_AQ_MAX_ERR)
goto out_alloc;
iavf_msec_pause(100);
status = iavf_clean_arq_element(hw, &event, NULL);
if (status == IAVF_ERR_ADMIN_QUEUE_NO_WORK)
continue;
else if (status) {
error = EIO;
goto out_alloc;
}
if ((enum virtchnl_ops)le32toh(event.desc.cookie_high) !=
VIRTCHNL_OP_VERSION) {
iavf_dbg_vc(sc, "%s: Received unexpected op response: %d\n",
__func__, le32toh(event.desc.cookie_high));
continue;
}
status = (enum iavf_status)le32toh(event.desc.cookie_low);
if (status) {
error = EIO;
goto out_alloc;
} else
break;
}
pf_vvi = (struct virtchnl_version_info *)event.msg_buf;
if ((pf_vvi->major > VIRTCHNL_VERSION_MAJOR) ||
((pf_vvi->major == VIRTCHNL_VERSION_MAJOR) &&
(pf_vvi->minor > VIRTCHNL_VERSION_MINOR))) {
device_printf(dev, "Critical PF/VF API version mismatch!\n");
error = EIO;
} else {
sc->version.major = pf_vvi->major;
sc->version.minor = pf_vvi->minor;
}
device_printf(dev, "PF API %d.%d / VF API %d.%d\n",
pf_vvi->major, pf_vvi->minor,
VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
out_alloc:
free(event.msg_buf, M_IAVF);
return (error);
}
int
iavf_send_vf_config_msg(struct iavf_sc *sc)
{
u32 caps;
caps = VF_BASE_MODE_OFFLOADS |
VIRTCHNL_VF_CAP_ADV_LINK_SPEED;
iavf_dbg_info(sc, "Sending offload flags: 0x%b\n",
caps, IAVF_PRINTF_VF_OFFLOAD_FLAGS);
if (sc->version.minor == VIRTCHNL_VERSION_MINOR_NO_VF_CAPS)
return iavf_send_pf_msg(sc, VIRTCHNL_OP_GET_VF_RESOURCES,
NULL, 0);
else
return iavf_send_pf_msg(sc, VIRTCHNL_OP_GET_VF_RESOURCES,
(u8 *)&caps, sizeof(caps));
}
int
iavf_get_vf_config(struct iavf_sc *sc)
{
struct iavf_hw *hw = &sc->hw;
device_t dev = sc->dev;
enum iavf_status status = IAVF_SUCCESS;
struct iavf_arq_event_info event;
u16 len;
u32 retries = 0;
int error = 0;
len = sizeof(struct virtchnl_vf_resource) +
sizeof(struct virtchnl_vsi_resource);
event.buf_len = len;
event.msg_buf = (u8 *)malloc(event.buf_len, M_IAVF, M_WAITOK);
for (;;) {
status = iavf_clean_arq_element(hw, &event, NULL);
if (status == IAVF_ERR_ADMIN_QUEUE_NO_WORK) {
if (++retries <= IAVF_AQ_MAX_ERR)
iavf_msec_pause(10);
} else if ((enum virtchnl_ops)le32toh(event.desc.cookie_high) !=
VIRTCHNL_OP_GET_VF_RESOURCES) {
iavf_dbg_vc(sc, "%s: Received a response from PF,"
" opcode %d, error %d",
__func__,
le32toh(event.desc.cookie_high),
le32toh(event.desc.cookie_low));
retries++;
continue;
} else {
status = (enum iavf_status)le32toh(event.desc.cookie_low);
if (status) {
device_printf(dev, "%s: Error returned from PF,"
" opcode %d, error %d\n", __func__,
le32toh(event.desc.cookie_high),
le32toh(event.desc.cookie_low));
error = EIO;
goto out_alloc;
}
break;
}
if (retries > IAVF_AQ_MAX_ERR) {
iavf_dbg_vc(sc,
"%s: Did not receive response after %d tries.",
__func__, retries);
error = ETIMEDOUT;
goto out_alloc;
}
}
memcpy(sc->vf_res, event.msg_buf, min(event.msg_len, len));
iavf_vf_parse_hw_config(hw, sc->vf_res);
out_alloc:
free(event.msg_buf, M_IAVF);
return (error);
}
int
iavf_enable_queues(struct iavf_sc *sc)
{
struct virtchnl_queue_select vqs;
struct iavf_vsi *vsi = &sc->vsi;
vqs.vsi_id = sc->vsi_res->vsi_id;
vqs.tx_queues = (1 << IAVF_NTXQS(vsi)) - 1;
vqs.rx_queues = vqs.tx_queues;
iavf_send_pf_msg(sc, VIRTCHNL_OP_ENABLE_QUEUES,
(u8 *)&vqs, sizeof(vqs));
return (0);
}
int
iavf_disable_queues(struct iavf_sc *sc)
{
struct virtchnl_queue_select vqs;
struct iavf_vsi *vsi = &sc->vsi;
vqs.vsi_id = sc->vsi_res->vsi_id;
vqs.tx_queues = (1 << IAVF_NTXQS(vsi)) - 1;
vqs.rx_queues = vqs.tx_queues;
iavf_send_pf_msg(sc, VIRTCHNL_OP_DISABLE_QUEUES,
(u8 *)&vqs, sizeof(vqs));
return (0);
}
int
iavf_add_vlans(struct iavf_sc *sc)
{
struct virtchnl_vlan_filter_list *v;
struct iavf_vlan_filter *f, *ftmp;
device_t dev = sc->dev;
int i = 0, cnt = 0;
u32 len;
SLIST_FOREACH(f, sc->vlan_filters, next) {
if (f->flags & IAVF_FILTER_ADD)
cnt++;
}
if (!cnt)
return (ENOENT);
len = sizeof(struct virtchnl_vlan_filter_list) +
(cnt * sizeof(u16));
if (len > IAVF_AQ_BUF_SZ) {
device_printf(dev, "%s: Exceeded Max AQ Buf size\n",
__func__);
return (EFBIG);
}
v = (struct virtchnl_vlan_filter_list *)malloc(len, M_IAVF, M_NOWAIT | M_ZERO);
if (!v) {
device_printf(dev, "%s: unable to allocate memory\n",
__func__);
return (ENOMEM);
}
v->vsi_id = sc->vsi_res->vsi_id;
v->num_elements = cnt;
SLIST_FOREACH_SAFE(f, sc->vlan_filters, next, ftmp) {
if (f->flags & IAVF_FILTER_ADD) {
bcopy(&f->vlan, &v->vlan_id[i], sizeof(u16));
f->flags = IAVF_FILTER_USED;
i++;
}
if (i == cnt)
break;
}
iavf_send_pf_msg(sc, VIRTCHNL_OP_ADD_VLAN, (u8 *)v, len);
free(v, M_IAVF);
return (0);
}
int
iavf_del_vlans(struct iavf_sc *sc)
{
struct virtchnl_vlan_filter_list *v;
struct iavf_vlan_filter *f, *ftmp;
device_t dev = sc->dev;
int i = 0, cnt = 0;
u32 len;
SLIST_FOREACH(f, sc->vlan_filters, next) {
if (f->flags & IAVF_FILTER_DEL)
cnt++;
}
if (!cnt)
return (ENOENT);
len = sizeof(struct virtchnl_vlan_filter_list) +
(cnt * sizeof(u16));
if (len > IAVF_AQ_BUF_SZ) {
device_printf(dev, "%s: Exceeded Max AQ Buf size\n",
__func__);
return (EFBIG);
}
v = (struct virtchnl_vlan_filter_list *)
malloc(len, M_IAVF, M_NOWAIT | M_ZERO);
if (!v) {
device_printf(dev, "%s: unable to allocate memory\n",
__func__);
return (ENOMEM);
}
v->vsi_id = sc->vsi_res->vsi_id;
v->num_elements = cnt;
SLIST_FOREACH_SAFE(f, sc->vlan_filters, next, ftmp) {
if (f->flags & IAVF_FILTER_DEL) {
bcopy(&f->vlan, &v->vlan_id[i], sizeof(u16));
i++;
SLIST_REMOVE(sc->vlan_filters, f, iavf_vlan_filter, next);
free(f, M_IAVF);
}
if (i == cnt)
break;
}
iavf_send_pf_msg(sc, VIRTCHNL_OP_DEL_VLAN, (u8 *)v, len);
free(v, M_IAVF);
return (0);
}
int
iavf_add_ether_filters(struct iavf_sc *sc)
{
struct virtchnl_ether_addr_list *a;
struct iavf_mac_filter *f;
device_t dev = sc->dev;
int len, j = 0, cnt = 0;
int error;
SLIST_FOREACH(f, sc->mac_filters, next) {
if (f->flags & IAVF_FILTER_ADD)
cnt++;
}
if (cnt == 0) {
iavf_dbg_vc(sc, "%s: cnt == 0, exiting...\n", __func__);
return (ENOENT);
}
len = sizeof(struct virtchnl_ether_addr_list) +
(cnt * sizeof(struct virtchnl_ether_addr));
a = (struct virtchnl_ether_addr_list *)
malloc(len, M_IAVF, M_NOWAIT | M_ZERO);
if (a == NULL) {
device_printf(dev, "%s: Failed to get memory for "
"virtchnl_ether_addr_list\n", __func__);
return (ENOMEM);
}
a->vsi_id = sc->vsi.id;
a->num_elements = cnt;
SLIST_FOREACH(f, sc->mac_filters, next) {
if (f->flags & IAVF_FILTER_ADD) {
bcopy(f->macaddr, a->list[j].addr, ETHER_ADDR_LEN);
f->flags &= ~IAVF_FILTER_ADD;
j++;
iavf_dbg_vc(sc, "%s: ADD: " MAC_FORMAT "\n",
__func__, MAC_FORMAT_ARGS(f->macaddr));
}
if (j == cnt)
break;
}
iavf_dbg_vc(sc, "%s: len %d, j %d, cnt %d\n", __func__,
len, j, cnt);
error = iavf_send_pf_msg(sc,
VIRTCHNL_OP_ADD_ETH_ADDR, (u8 *)a, len);
free(a, M_IAVF);
return (error);
}
int
iavf_del_ether_filters(struct iavf_sc *sc)
{
struct virtchnl_ether_addr_list *d;
struct iavf_mac_filter *f, *f_temp;
device_t dev = sc->dev;
int len, j = 0, cnt = 0;
SLIST_FOREACH(f, sc->mac_filters, next) {
if (f->flags & IAVF_FILTER_DEL)
cnt++;
}
if (cnt == 0) {
iavf_dbg_vc(sc, "%s: cnt == 0, exiting...\n", __func__);
return (ENOENT);
}
len = sizeof(struct virtchnl_ether_addr_list) +
(cnt * sizeof(struct virtchnl_ether_addr));
d = (struct virtchnl_ether_addr_list *)
malloc(len, M_IAVF, M_NOWAIT | M_ZERO);
if (d == NULL) {
device_printf(dev, "%s: Failed to get memory for "
"virtchnl_ether_addr_list\n", __func__);
return (ENOMEM);
}
d->vsi_id = sc->vsi.id;
d->num_elements = cnt;
SLIST_FOREACH_SAFE(f, sc->mac_filters, next, f_temp) {
if (f->flags & IAVF_FILTER_DEL) {
bcopy(f->macaddr, d->list[j].addr, ETHER_ADDR_LEN);
iavf_dbg_vc(sc, "DEL: " MAC_FORMAT "\n",
MAC_FORMAT_ARGS(f->macaddr));
j++;
SLIST_REMOVE(sc->mac_filters, f, iavf_mac_filter, next);
free(f, M_IAVF);
}
if (j == cnt)
break;
}
iavf_send_pf_msg(sc,
VIRTCHNL_OP_DEL_ETH_ADDR, (u8 *)d, len);
free(d, M_IAVF);
return (0);
}
int
iavf_request_reset(struct iavf_sc *sc)
{
wr32(&sc->hw, IAVF_VFGEN_RSTAT, VIRTCHNL_VFR_INPROGRESS);
iavf_send_pf_msg(sc, VIRTCHNL_OP_RESET_VF, NULL, 0);
return (0);
}
int
iavf_request_stats(struct iavf_sc *sc)
{
struct virtchnl_queue_select vqs;
int error = 0;
vqs.vsi_id = sc->vsi_res->vsi_id;
error = iavf_send_pf_msg(sc, VIRTCHNL_OP_GET_STATS,
(u8 *)&vqs, sizeof(vqs));
if (error)
device_printf(sc->dev, "Error sending stats request to PF: %d\n", error);
return (0);
}
void
iavf_update_stats_counters(struct iavf_sc *sc, struct iavf_eth_stats *es)
{
struct iavf_vsi *vsi = &sc->vsi;
vsi->ipackets = es->rx_unicast + es->rx_multicast + es->rx_broadcast;
vsi->opackets = es->tx_unicast + es->tx_multicast + es->tx_broadcast;
vsi->ibytes = es->rx_bytes;
vsi->obytes = es->tx_bytes;
vsi->imcasts = es->rx_multicast;
vsi->omcasts = es->tx_multicast;
vsi->oerrors = es->tx_errors;
vsi->iqdrops = es->rx_discards;
vsi->oqdrops = es->tx_discards;
vsi->noproto = es->rx_unknown_protocol;
vsi->eth_stats = *es;
}
int
iavf_config_rss_key(struct iavf_sc *sc)
{
struct virtchnl_rss_key *rss_key_msg;
int msg_len, key_length;
u8 rss_seed[IAVF_RSS_KEY_SIZE];
#ifdef RSS
rss_getkey((uint8_t *) &rss_seed);
#else
iavf_get_default_rss_key((u32 *)rss_seed);
#endif
key_length = IAVF_RSS_KEY_SIZE;
msg_len = sizeof(struct virtchnl_rss_key) + (sizeof(u8) * key_length) - 1;
rss_key_msg = (struct virtchnl_rss_key *)
malloc(msg_len, M_IAVF, M_NOWAIT | M_ZERO);
if (rss_key_msg == NULL) {
device_printf(sc->dev, "Unable to allocate msg memory for RSS key msg.\n");
return (ENOMEM);
}
rss_key_msg->vsi_id = sc->vsi_res->vsi_id;
rss_key_msg->key_len = key_length;
bcopy(rss_seed, &rss_key_msg->key[0], key_length);
iavf_dbg_vc(sc, "%s: vsi_id %d, key_len %d\n", __func__,
rss_key_msg->vsi_id, rss_key_msg->key_len);
iavf_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_RSS_KEY,
(u8 *)rss_key_msg, msg_len);
free(rss_key_msg, M_IAVF);
return (0);
}
int
iavf_set_rss_hena(struct iavf_sc *sc)
{
struct virtchnl_rss_hena hena;
struct iavf_hw *hw = &sc->hw;
if (hw->mac.type == IAVF_MAC_VF)
hena.hena = IAVF_DEFAULT_RSS_HENA_AVF;
else if (hw->mac.type == IAVF_MAC_X722_VF)
hena.hena = IAVF_DEFAULT_RSS_HENA_X722;
else
hena.hena = IAVF_DEFAULT_RSS_HENA_BASE;
iavf_send_pf_msg(sc, VIRTCHNL_OP_SET_RSS_HENA,
(u8 *)&hena, sizeof(hena));
return (0);
}
int
iavf_config_rss_lut(struct iavf_sc *sc)
{
struct virtchnl_rss_lut *rss_lut_msg;
int msg_len;
u16 lut_length;
u32 lut;
int i, que_id;
lut_length = IAVF_RSS_VSI_LUT_SIZE;
msg_len = sizeof(struct virtchnl_rss_lut) + (lut_length * sizeof(u8)) - 1;
rss_lut_msg = (struct virtchnl_rss_lut *)
malloc(msg_len, M_IAVF, M_NOWAIT | M_ZERO);
if (rss_lut_msg == NULL) {
device_printf(sc->dev, "Unable to allocate msg memory for RSS lut msg.\n");
return (ENOMEM);
}
rss_lut_msg->vsi_id = sc->vsi_res->vsi_id;
rss_lut_msg->lut_entries = lut_length;
for (i = 0; i < lut_length; i++) {
#ifdef RSS
que_id = rss_get_indirection_to_bucket(i);
que_id = que_id % sc->vsi.num_rx_queues;
#else
que_id = i % sc->vsi.num_rx_queues;
#endif
lut = que_id & IAVF_RSS_VSI_LUT_ENTRY_MASK;
rss_lut_msg->lut[i] = lut;
}
iavf_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_RSS_LUT,
(u8 *)rss_lut_msg, msg_len);
free(rss_lut_msg, M_IAVF);
return (0);
}
int
iavf_config_promisc_mode(struct iavf_sc *sc)
{
struct virtchnl_promisc_info pinfo;
pinfo.vsi_id = sc->vsi_res->vsi_id;
pinfo.flags = sc->promisc_flags;
iavf_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE,
(u8 *)&pinfo, sizeof(pinfo));
return (0);
}
int
iavf_vc_send_cmd(struct iavf_sc *sc, uint32_t request)
{
switch (request) {
case IAVF_FLAG_AQ_MAP_VECTORS:
return iavf_map_queues(sc);
case IAVF_FLAG_AQ_ADD_MAC_FILTER:
return iavf_add_ether_filters(sc);
case IAVF_FLAG_AQ_ADD_VLAN_FILTER:
return iavf_add_vlans(sc);
case IAVF_FLAG_AQ_DEL_MAC_FILTER:
return iavf_del_ether_filters(sc);
case IAVF_FLAG_AQ_DEL_VLAN_FILTER:
return iavf_del_vlans(sc);
case IAVF_FLAG_AQ_CONFIGURE_QUEUES:
return iavf_configure_queues(sc);
case IAVF_FLAG_AQ_DISABLE_QUEUES:
return iavf_disable_queues(sc);
case IAVF_FLAG_AQ_ENABLE_QUEUES:
return iavf_enable_queues(sc);
case IAVF_FLAG_AQ_CONFIG_RSS_KEY:
return iavf_config_rss_key(sc);
case IAVF_FLAG_AQ_SET_RSS_HENA:
return iavf_set_rss_hena(sc);
case IAVF_FLAG_AQ_CONFIG_RSS_LUT:
return iavf_config_rss_lut(sc);
case IAVF_FLAG_AQ_CONFIGURE_PROMISC:
return iavf_config_promisc_mode(sc);
}
return (0);
}
void *
iavf_vc_get_op_chan(struct iavf_sc *sc, uint32_t request)
{
switch (request) {
case IAVF_FLAG_AQ_ENABLE_QUEUES:
return (&sc->enable_queues_chan);
case IAVF_FLAG_AQ_DISABLE_QUEUES:
return (&sc->disable_queues_chan);
default:
return (NULL);
}
}
const char *
iavf_vc_stat_str(struct iavf_hw *hw, enum virtchnl_status_code stat_err)
{
switch (stat_err) {
case VIRTCHNL_STATUS_SUCCESS:
return "OK";
case VIRTCHNL_ERR_PARAM:
return "VIRTCHNL_ERR_PARAM";
case VIRTCHNL_STATUS_ERR_NO_MEMORY:
return "VIRTCHNL_STATUS_ERR_NO_MEMORY";
case VIRTCHNL_STATUS_ERR_OPCODE_MISMATCH:
return "VIRTCHNL_STATUS_ERR_OPCODE_MISMATCH";
case VIRTCHNL_STATUS_ERR_CQP_COMPL_ERROR:
return "VIRTCHNL_STATUS_ERR_CQP_COMPL_ERROR";
case VIRTCHNL_STATUS_ERR_INVALID_VF_ID:
return "VIRTCHNL_STATUS_ERR_INVALID_VF_ID";
case VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR:
return "VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR";
case VIRTCHNL_STATUS_NOT_SUPPORTED:
return "VIRTCHNL_STATUS_NOT_SUPPORTED";
}
snprintf(hw->err_str, sizeof(hw->err_str), "%d", stat_err);
return hw->err_str;
}
enum iavf_ext_link_speed
iavf_adv_speed_to_ext_speed(u32 adv_link_speed)
{
if (adv_link_speed >= 100000)
return IAVF_EXT_LINK_SPEED_100GB;
if (adv_link_speed >= 50000)
return IAVF_EXT_LINK_SPEED_50GB;
if (adv_link_speed >= 40000)
return IAVF_EXT_LINK_SPEED_40GB;
if (adv_link_speed >= 25000)
return IAVF_EXT_LINK_SPEED_25GB;
if (adv_link_speed >= 20000)
return IAVF_EXT_LINK_SPEED_20GB;
if (adv_link_speed >= 10000)
return IAVF_EXT_LINK_SPEED_10GB;
if (adv_link_speed >= 5000)
return IAVF_EXT_LINK_SPEED_5GB;
if (adv_link_speed >= 2500)
return IAVF_EXT_LINK_SPEED_2500MB;
if (adv_link_speed >= 1000)
return IAVF_EXT_LINK_SPEED_1000MB;
if (adv_link_speed >= 100)
return IAVF_EXT_LINK_SPEED_100MB;
if (adv_link_speed >= 10)
return IAVF_EXT_LINK_SPEED_10MB;
return IAVF_EXT_LINK_SPEED_UNKNOWN;
}
u32
iavf_ext_speed_to_ifmedia(enum iavf_ext_link_speed link_speed)
{
switch (link_speed) {
case IAVF_EXT_LINK_SPEED_100GB:
return IFM_100G_SR4;
case IAVF_EXT_LINK_SPEED_50GB:
return IFM_50G_SR2;
case IAVF_EXT_LINK_SPEED_40GB:
return IFM_40G_SR4;
case IAVF_EXT_LINK_SPEED_25GB:
return IFM_25G_SR;
case IAVF_EXT_LINK_SPEED_20GB:
return IFM_20G_KR2;
case IAVF_EXT_LINK_SPEED_10GB:
return IFM_10G_SR;
case IAVF_EXT_LINK_SPEED_5GB:
return IFM_5000_T;
case IAVF_EXT_LINK_SPEED_2500MB:
return IFM_2500_T;
case IAVF_EXT_LINK_SPEED_1000MB:
return IFM_1000_T;
case IAVF_EXT_LINK_SPEED_100MB:
return IFM_100_TX;
case IAVF_EXT_LINK_SPEED_10MB:
return IFM_10_T;
case IAVF_EXT_LINK_SPEED_UNKNOWN:
default:
return IFM_UNKNOWN;
}
}
enum iavf_ext_link_speed
iavf_vc_speed_to_ext_speed(enum virtchnl_link_speed link_speed)
{
switch (link_speed) {
case VIRTCHNL_LINK_SPEED_40GB:
return IAVF_EXT_LINK_SPEED_40GB;
case VIRTCHNL_LINK_SPEED_25GB:
return IAVF_EXT_LINK_SPEED_25GB;
case VIRTCHNL_LINK_SPEED_20GB:
return IAVF_EXT_LINK_SPEED_20GB;
case VIRTCHNL_LINK_SPEED_10GB:
return IAVF_EXT_LINK_SPEED_10GB;
case VIRTCHNL_LINK_SPEED_1GB:
return IAVF_EXT_LINK_SPEED_1000MB;
case VIRTCHNL_LINK_SPEED_100MB:
return IAVF_EXT_LINK_SPEED_100MB;
case VIRTCHNL_LINK_SPEED_UNKNOWN:
default:
return IAVF_EXT_LINK_SPEED_UNKNOWN;
}
}
const char *
iavf_vc_speed_to_string(enum virtchnl_link_speed link_speed)
{
return iavf_ext_speed_to_str(iavf_vc_speed_to_ext_speed(link_speed));
}
const char *
iavf_ext_speed_to_str(enum iavf_ext_link_speed link_speed)
{
switch (link_speed) {
case IAVF_EXT_LINK_SPEED_100GB:
return "100 Gbps";
case IAVF_EXT_LINK_SPEED_50GB:
return "50 Gbps";
case IAVF_EXT_LINK_SPEED_40GB:
return "40 Gbps";
case IAVF_EXT_LINK_SPEED_25GB:
return "25 Gbps";
case IAVF_EXT_LINK_SPEED_20GB:
return "20 Gbps";
case IAVF_EXT_LINK_SPEED_10GB:
return "10 Gbps";
case IAVF_EXT_LINK_SPEED_5GB:
return "5 Gbps";
case IAVF_EXT_LINK_SPEED_2500MB:
return "2.5 Gbps";
case IAVF_EXT_LINK_SPEED_1000MB:
return "1 Gbps";
case IAVF_EXT_LINK_SPEED_100MB:
return "100 Mbps";
case IAVF_EXT_LINK_SPEED_10MB:
return "10 Mbps";
case IAVF_EXT_LINK_SPEED_UNKNOWN:
default:
return "Unknown";
}
}
const char *
iavf_vc_opcode_str(uint16_t op)
{
switch (op) {
case VIRTCHNL_OP_VERSION:
return ("VERSION");
case VIRTCHNL_OP_RESET_VF:
return ("RESET_VF");
case VIRTCHNL_OP_GET_VF_RESOURCES:
return ("GET_VF_RESOURCES");
case VIRTCHNL_OP_CONFIG_TX_QUEUE:
return ("CONFIG_TX_QUEUE");
case VIRTCHNL_OP_CONFIG_RX_QUEUE:
return ("CONFIG_RX_QUEUE");
case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
return ("CONFIG_VSI_QUEUES");
case VIRTCHNL_OP_CONFIG_IRQ_MAP:
return ("CONFIG_IRQ_MAP");
case VIRTCHNL_OP_ENABLE_QUEUES:
return ("ENABLE_QUEUES");
case VIRTCHNL_OP_DISABLE_QUEUES:
return ("DISABLE_QUEUES");
case VIRTCHNL_OP_ADD_ETH_ADDR:
return ("ADD_ETH_ADDR");
case VIRTCHNL_OP_DEL_ETH_ADDR:
return ("DEL_ETH_ADDR");
case VIRTCHNL_OP_ADD_VLAN:
return ("ADD_VLAN");
case VIRTCHNL_OP_DEL_VLAN:
return ("DEL_VLAN");
case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
return ("CONFIG_PROMISCUOUS_MODE");
case VIRTCHNL_OP_GET_STATS:
return ("GET_STATS");
case VIRTCHNL_OP_RSVD:
return ("RSVD");
case VIRTCHNL_OP_EVENT:
return ("EVENT");
case VIRTCHNL_OP_CONFIG_RSS_KEY:
return ("CONFIG_RSS_KEY");
case VIRTCHNL_OP_CONFIG_RSS_LUT:
return ("CONFIG_RSS_LUT");
case VIRTCHNL_OP_GET_RSS_HENA_CAPS:
return ("GET_RSS_HENA_CAPS");
case VIRTCHNL_OP_SET_RSS_HENA:
return ("SET_RSS_HENA");
default:
return ("UNKNOWN");
}
}
void
iavf_vc_completion(struct iavf_sc *sc,
enum virtchnl_ops v_opcode,
enum virtchnl_status_code v_retval, u8 *msg, u16 msglen __unused)
{
device_t dev = sc->dev;
if (v_opcode != VIRTCHNL_OP_GET_STATS)
iavf_dbg_vc(sc, "%s: opcode %s\n", __func__,
iavf_vc_opcode_str(v_opcode));
if (v_opcode == VIRTCHNL_OP_EVENT) {
struct virtchnl_pf_event *vpe =
(struct virtchnl_pf_event *)msg;
switch (vpe->event) {
case VIRTCHNL_EVENT_LINK_CHANGE:
iavf_handle_link_event(sc, vpe);
break;
case VIRTCHNL_EVENT_RESET_IMPENDING:
device_printf(dev, "PF initiated reset!\n");
iavf_set_state(&sc->state, IAVF_STATE_RESET_PENDING);
break;
default:
iavf_dbg_vc(sc, "Unknown event %d from AQ\n",
vpe->event);
break;
}
return;
}
if (v_retval) {
bool print_error = true;
switch (v_opcode) {
case VIRTCHNL_OP_ADD_ETH_ADDR:
device_printf(dev, "WARNING: Error adding VF mac filter!\n");
device_printf(dev, "WARNING: Device may not receive traffic!\n");
break;
case VIRTCHNL_OP_ENABLE_QUEUES:
sc->enable_queues_chan = 1;
wakeup_one(&sc->enable_queues_chan);
break;
case VIRTCHNL_OP_DISABLE_QUEUES:
sc->disable_queues_chan = 1;
wakeup_one(&sc->disable_queues_chan);
if (!(sc->dbg_mask & IAVF_DBG_VC))
print_error = false;
break;
default:
break;
}
if (print_error)
device_printf(dev,
"%s: AQ returned error %s to our request %s!\n",
__func__, iavf_vc_stat_str(&sc->hw, v_retval),
iavf_vc_opcode_str(v_opcode));
return;
}
switch (v_opcode) {
case VIRTCHNL_OP_GET_STATS:
iavf_update_stats_counters(sc, (struct iavf_eth_stats *)msg);
break;
case VIRTCHNL_OP_ADD_ETH_ADDR:
break;
case VIRTCHNL_OP_DEL_ETH_ADDR:
break;
case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
break;
case VIRTCHNL_OP_ADD_VLAN:
break;
case VIRTCHNL_OP_DEL_VLAN:
break;
case VIRTCHNL_OP_ENABLE_QUEUES:
atomic_store_rel_32(&sc->queues_enabled, 1);
sc->enable_queues_chan = 1;
wakeup_one(&sc->enable_queues_chan);
break;
case VIRTCHNL_OP_DISABLE_QUEUES:
atomic_store_rel_32(&sc->queues_enabled, 0);
sc->disable_queues_chan = 1;
wakeup_one(&sc->disable_queues_chan);
break;
case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
break;
case VIRTCHNL_OP_CONFIG_IRQ_MAP:
break;
case VIRTCHNL_OP_CONFIG_RSS_KEY:
break;
case VIRTCHNL_OP_SET_RSS_HENA:
break;
case VIRTCHNL_OP_CONFIG_RSS_LUT:
break;
default:
iavf_dbg_vc(sc,
"Received unexpected message %s from PF.\n",
iavf_vc_opcode_str(v_opcode));
break;
}
}
static void
iavf_handle_link_event(struct iavf_sc *sc, struct virtchnl_pf_event *vpe)
{
MPASS(vpe->event == VIRTCHNL_EVENT_LINK_CHANGE);
if (sc->vf_res->vf_cap_flags & VIRTCHNL_VF_CAP_ADV_LINK_SPEED)
{
iavf_dbg_vc(sc, "Link change (adv): status %d, speed %u\n",
vpe->event_data.link_event_adv.link_status,
vpe->event_data.link_event_adv.link_speed);
sc->link_up =
vpe->event_data.link_event_adv.link_status;
sc->link_speed_adv =
vpe->event_data.link_event_adv.link_speed;
} else {
iavf_dbg_vc(sc, "Link change: status %d, speed %x\n",
vpe->event_data.link_event.link_status,
vpe->event_data.link_event.link_speed);
sc->link_up =
vpe->event_data.link_event.link_status;
sc->link_speed =
vpe->event_data.link_event.link_speed;
}
iavf_update_link_status(sc);
}