Commit 02cbfba1 authored by Alan Brady's avatar Alan Brady Committed by Tony Nguyen

idpf: add ethtool callbacks

Initialize all the ethtool ops that are supported by the driver and
add the necessary support for the ethtool callbacks. Also add
asynchronous link notification virtchnl support where the device
Control Plane sends the link status and link speed as an
asynchronous event message. Driver report the link speed on
ethtool .idpf_get_link_ksettings query.

Introduce soft reset function which is used by some of the ethtool
callbacks such as .set_channels, .set_ringparam etc. to change the
existing queue configuration. It deletes the existing queues by sending
delete queues virtchnl message to the CP and calls the 'vport_stop' flow
which disables the queues, vport etc. New set of queues are requested to
the CP and reconfigure the queue context by calling the 'vport_open'
flow. Soft reset flow also adjusts the number of vectors associated to a
vport if .set_channels is called.
Signed-off-by: default avatarAlan Brady <alan.brady@intel.com>
Co-developed-by: default avatarAlice Michael <alice.michael@intel.com>
Signed-off-by: default avatarAlice Michael <alice.michael@intel.com>
Co-developed-by: default avatarJoshua Hay <joshua.a.hay@intel.com>
Signed-off-by: default avatarJoshua Hay <joshua.a.hay@intel.com>
Co-developed-by: default avatarPhani Burra <phani.r.burra@intel.com>
Signed-off-by: default avatarPhani Burra <phani.r.burra@intel.com>
Reviewed-by: default avatarSridhar Samudrala <sridhar.samudrala@intel.com>
Reviewed-by: default avatarWillem de Bruijn <willemb@google.com>
Co-developed-by: default avatarPavan Kumar Linga <pavan.kumar.linga@intel.com>
Signed-off-by: default avatarPavan Kumar Linga <pavan.kumar.linga@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent a5ab9ee0
......@@ -9,6 +9,7 @@ idpf-y := \
idpf_controlq.o \
idpf_controlq_setup.o \
idpf_dev.o \
idpf_ethtool.o \
idpf_lib.o \
idpf_main.o \
idpf_singleq_txrx.o \
......
......@@ -15,6 +15,7 @@ struct idpf_vport_max_q;
#include <linux/pci.h>
#include <linux/bitfield.h>
#include <linux/sctp.h>
#include <linux/ethtool.h>
#include <net/gro.h>
#include <linux/dim.h>
......@@ -230,6 +231,10 @@ struct idpf_dev_ops {
STATE(IDPF_VC_MAP_IRQ_ERR) \
STATE(IDPF_VC_UNMAP_IRQ) \
STATE(IDPF_VC_UNMAP_IRQ_ERR) \
STATE(IDPF_VC_ADD_QUEUES) \
STATE(IDPF_VC_ADD_QUEUES_ERR) \
STATE(IDPF_VC_DEL_QUEUES) \
STATE(IDPF_VC_DEL_QUEUES_ERR) \
STATE(IDPF_VC_ALLOC_VECTORS) \
STATE(IDPF_VC_ALLOC_VECTORS_ERR) \
STATE(IDPF_VC_DEALLOC_VECTORS) \
......@@ -259,17 +264,42 @@ enum idpf_vport_vc_state {
extern const char * const idpf_vport_vc_state_str[];
/**
* enum idpf_vport_reset_cause - Vport soft reset causes
* @IDPF_SR_Q_CHANGE: Soft reset queue change
* @IDPF_SR_Q_DESC_CHANGE: Soft reset descriptor change
*/
enum idpf_vport_reset_cause {
IDPF_SR_Q_CHANGE,
IDPF_SR_Q_DESC_CHANGE,
};
/**
* enum idpf_vport_flags - Vport flags
* @IDPF_VPORT_DEL_QUEUES: To send delete queues message
* @IDPF_VPORT_SW_MARKER: Indicate TX pipe drain software marker packets
* processing is done
* @IDPF_VPORT_FLAGS_NBITS: Must be last
*/
enum idpf_vport_flags {
IDPF_VPORT_DEL_QUEUES,
IDPF_VPORT_SW_MARKER,
IDPF_VPORT_FLAGS_NBITS,
};
struct idpf_port_stats {
struct u64_stats_sync stats_sync;
u64_stats_t rx_hw_csum_err;
u64_stats_t rx_hsplit;
u64_stats_t rx_hsplit_hbo;
u64_stats_t rx_bad_descs;
u64_stats_t tx_linearize;
u64_stats_t tx_busy;
u64_stats_t tx_drops;
u64_stats_t tx_dma_map_errs;
struct virtchnl2_vport_stats vport_stats;
};
/**
* struct idpf_vport - Handle for netdevices and queue resources
* @num_txq: Number of allocated TX queues
......@@ -311,7 +341,9 @@ enum idpf_vport_flags {
* @default_mac_addr: device will give a default MAC to use
* @rx_itr_profile: RX profiles for Dynamic Interrupt Moderation
* @tx_itr_profile: TX profiles for Dynamic Interrupt Moderation
* @port_stats: per port csum, header split, and other offload stats
* @link_up: True if link is up
* @link_speed_mbps: Link speed in mbps
* @vc_msg: Virtchnl message buffer
* @vc_state: Virtchnl message state
* @vchnl_wq: Wait queue for virtchnl messages
......@@ -357,8 +389,10 @@ struct idpf_vport {
u8 default_mac_addr[ETH_ALEN];
u16 rx_itr_profile[IDPF_DIM_PROFILE_SLOTS];
u16 tx_itr_profile[IDPF_DIM_PROFILE_SLOTS];
struct idpf_port_stats port_stats;
bool link_up;
u32 link_speed_mbps;
char vc_msg[IDPF_CTLQ_MAX_BUF_LEN];
DECLARE_BITMAP(vc_state, IDPF_VC_NBITS);
......@@ -767,6 +801,17 @@ static inline struct idpf_vport *idpf_netdev_to_vport(struct net_device *netdev)
return np->vport;
}
/**
* idpf_netdev_to_adapter - Get adapter handle from a netdev
* @netdev: Network interface device structure
*/
static inline struct idpf_adapter *idpf_netdev_to_adapter(struct net_device *netdev)
{
struct idpf_netdev_priv *np = netdev_priv(netdev);
return np->adapter;
}
/**
* idpf_is_feature_ena - Determine if a particular feature is enabled
* @vport: Vport to check
......@@ -811,6 +856,7 @@ void idpf_mbx_task(struct work_struct *work);
void idpf_vc_event_task(struct work_struct *work);
void idpf_dev_ops_init(struct idpf_adapter *adapter);
void idpf_vf_dev_ops_init(struct idpf_adapter *adapter);
int idpf_vport_adjust_qs(struct idpf_vport *vport);
int idpf_init_dflt_mbx(struct idpf_adapter *adapter);
void idpf_deinit_dflt_mbx(struct idpf_adapter *adapter);
int idpf_vc_core_init(struct idpf_adapter *adapter);
......@@ -819,6 +865,11 @@ int idpf_intr_req(struct idpf_adapter *adapter);
void idpf_intr_rel(struct idpf_adapter *adapter);
int idpf_get_reg_intr_vecs(struct idpf_vport *vport,
struct idpf_vec_regs *reg_vals);
int idpf_send_delete_queues_msg(struct idpf_vport *vport);
int idpf_send_add_queues_msg(const struct idpf_vport *vport, u16 num_tx_q,
u16 num_complq, u16 num_rx_q, u16 num_rx_bufq);
int idpf_initiate_soft_reset(struct idpf_vport *vport,
enum idpf_vport_reset_cause reset_cause);
int idpf_send_enable_vport_msg(struct idpf_vport *vport);
int idpf_send_disable_vport_msg(struct idpf_vport *vport);
int idpf_send_destroy_vport_msg(struct idpf_vport *vport);
......@@ -831,6 +882,7 @@ void idpf_deinit_task(struct idpf_adapter *adapter);
int idpf_req_rel_vector_indexes(struct idpf_adapter *adapter,
u16 *q_vector_idxs,
struct idpf_vector_info *vec_info);
int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport);
int idpf_get_vec_ids(struct idpf_adapter *adapter,
u16 *vecids, int num_vecids,
struct virtchnl2_vector_chunks *chunks);
......@@ -838,6 +890,7 @@ int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op,
void *msg, int msg_size);
int idpf_send_mb_msg(struct idpf_adapter *adapter, u32 op,
u16 msg_size, u8 *msg);
void idpf_set_ethtool_ops(struct net_device *netdev);
int idpf_vport_alloc_max_qs(struct idpf_adapter *adapter,
struct idpf_vport_max_q *max_q);
void idpf_vport_dealloc_max_qs(struct idpf_adapter *adapter,
......@@ -855,6 +908,8 @@ int idpf_send_enable_queues_msg(struct idpf_vport *vport);
int idpf_send_create_vport_msg(struct idpf_adapter *adapter,
struct idpf_vport_max_q *max_q);
int idpf_check_supported_desc_ids(struct idpf_vport *vport);
void idpf_vport_intr_write_itr(struct idpf_q_vector *q_vector,
u16 itr, bool tx);
int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map);
int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs);
int idpf_sriov_configure(struct pci_dev *pdev, int num_vfs);
......
This diff is collapsed.
......@@ -702,6 +702,7 @@ static int idpf_cfg_netdev(struct idpf_vport *vport)
netdev->features |= dflt_features;
netdev->hw_features |= dflt_features | offloads;
netdev->hw_enc_features |= dflt_features | offloads;
idpf_set_ethtool_ops(netdev);
SET_NETDEV_DEV(netdev, &adapter->pdev->dev);
/* carrier off on init to avoid Tx hangs */
......@@ -751,6 +752,12 @@ static void idpf_vport_stop(struct idpf_vport *vport)
idpf_send_disable_vport_msg(vport);
idpf_send_disable_queues_msg(vport);
idpf_send_map_unmap_queue_vector_msg(vport, false);
/* Normally we ask for queues in create_vport, but if we're changing
* number of requested queues we do a delete then add instead of
* deleting and reallocating the vport.
*/
if (test_and_clear_bit(IDPF_VPORT_DEL_QUEUES, vport->flags))
idpf_send_delete_queues_msg(vport);
vport->link_up = false;
idpf_vport_intr_deinit(vport);
......@@ -1012,6 +1019,23 @@ void idpf_service_task(struct work_struct *work)
msecs_to_jiffies(300));
}
/**
* idpf_set_real_num_queues - set number of queues for netdev
* @vport: virtual port structure
*
* Returns 0 on success, negative on failure.
*/
static int idpf_set_real_num_queues(struct idpf_vport *vport)
{
int err;
err = netif_set_real_num_rx_queues(vport->netdev, vport->num_rxq);
if (err)
return err;
return netif_set_real_num_tx_queues(vport->netdev, vport->num_txq);
}
/**
* idpf_up_complete - Complete interface up sequence
* @vport: virtual port structure
......@@ -1495,6 +1519,154 @@ void idpf_vc_event_task(struct work_struct *work)
}
}
/**
* idpf_initiate_soft_reset - Initiate a software reset
* @vport: virtual port data struct
* @reset_cause: reason for the soft reset
*
* Soft reset only reallocs vport queue resources. Returns 0 on success,
* negative on failure.
*/
int idpf_initiate_soft_reset(struct idpf_vport *vport,
enum idpf_vport_reset_cause reset_cause)
{
struct idpf_netdev_priv *np = netdev_priv(vport->netdev);
enum idpf_vport_state current_state = np->state;
struct idpf_adapter *adapter = vport->adapter;
struct idpf_vport *new_vport;
int err, i;
/* If the system is low on memory, we can end up in bad state if we
* free all the memory for queue resources and try to allocate them
* again. Instead, we can pre-allocate the new resources before doing
* anything and bailing if the alloc fails.
*
* Make a clone of the existing vport to mimic its current
* configuration, then modify the new structure with any requested
* changes. Once the allocation of the new resources is done, stop the
* existing vport and copy the configuration to the main vport. If an
* error occurred, the existing vport will be untouched.
*
*/
new_vport = kzalloc(sizeof(*vport), GFP_KERNEL);
if (!new_vport)
return -ENOMEM;
/* This purposely avoids copying the end of the struct because it
* contains wait_queues and mutexes and other stuff we don't want to
* mess with. Nothing below should use those variables from new_vport
* and should instead always refer to them in vport if they need to.
*/
memcpy(new_vport, vport, offsetof(struct idpf_vport, vc_state));
/* Adjust resource parameters prior to reallocating resources */
switch (reset_cause) {
case IDPF_SR_Q_CHANGE:
err = idpf_vport_adjust_qs(new_vport);
if (err)
goto free_vport;
break;
case IDPF_SR_Q_DESC_CHANGE:
/* Update queue parameters before allocating resources */
idpf_vport_calc_num_q_desc(new_vport);
break;
default:
dev_err(&adapter->pdev->dev, "Unhandled soft reset cause\n");
err = -EINVAL;
goto free_vport;
}
err = idpf_vport_queues_alloc(new_vport);
if (err)
goto free_vport;
if (current_state <= __IDPF_VPORT_DOWN) {
idpf_send_delete_queues_msg(vport);
} else {
set_bit(IDPF_VPORT_DEL_QUEUES, vport->flags);
idpf_vport_stop(vport);
}
idpf_deinit_rss(vport);
/* We're passing in vport here because we need its wait_queue
* to send a message and it should be getting all the vport
* config data out of the adapter but we need to be careful not
* to add code to add_queues to change the vport config within
* vport itself as it will be wiped with a memcpy later.
*/
err = idpf_send_add_queues_msg(vport, new_vport->num_txq,
new_vport->num_complq,
new_vport->num_rxq,
new_vport->num_bufq);
if (err)
goto err_reset;
/* Same comment as above regarding avoiding copying the wait_queues and
* mutexes applies here. We do not want to mess with those if possible.
*/
memcpy(vport, new_vport, offsetof(struct idpf_vport, vc_state));
/* Since idpf_vport_queues_alloc was called with new_port, the queue
* back pointers are currently pointing to the local new_vport. Reset
* the backpointers to the original vport here
*/
for (i = 0; i < vport->num_txq_grp; i++) {
struct idpf_txq_group *tx_qgrp = &vport->txq_grps[i];
int j;
tx_qgrp->vport = vport;
for (j = 0; j < tx_qgrp->num_txq; j++)
tx_qgrp->txqs[j]->vport = vport;
if (idpf_is_queue_model_split(vport->txq_model))
tx_qgrp->complq->vport = vport;
}
for (i = 0; i < vport->num_rxq_grp; i++) {
struct idpf_rxq_group *rx_qgrp = &vport->rxq_grps[i];
struct idpf_queue *q;
u16 num_rxq;
int j;
rx_qgrp->vport = vport;
for (j = 0; j < vport->num_bufqs_per_qgrp; j++)
rx_qgrp->splitq.bufq_sets[j].bufq.vport = vport;
if (idpf_is_queue_model_split(vport->rxq_model))
num_rxq = rx_qgrp->splitq.num_rxq_sets;
else
num_rxq = rx_qgrp->singleq.num_rxq;
for (j = 0; j < num_rxq; j++) {
if (idpf_is_queue_model_split(vport->rxq_model))
q = &rx_qgrp->splitq.rxq_sets[j]->rxq;
else
q = rx_qgrp->singleq.rxqs[j];
q->vport = vport;
}
}
if (reset_cause == IDPF_SR_Q_CHANGE)
idpf_vport_alloc_vec_indexes(vport);
err = idpf_set_real_num_queues(vport);
if (err)
goto err_reset;
if (current_state == __IDPF_VPORT_UP)
err = idpf_vport_open(vport, false);
kfree(new_vport);
return err;
err_reset:
idpf_vport_queues_rel(new_vport);
free_vport:
kfree(new_vport);
return err;
}
/**
* idpf_open - Called when a network interface becomes active
* @netdev: network interface device structure
......
......@@ -3669,8 +3669,7 @@ static int idpf_vport_intr_req_irq(struct idpf_vport *vport, char *basename)
* @itr: Interrupt throttling rate
* @tx: Tx or Rx ITR
*/
static void idpf_vport_intr_write_itr(struct idpf_q_vector *q_vector,
u16 itr, bool tx)
void idpf_vport_intr_write_itr(struct idpf_q_vector *q_vector, u16 itr, bool tx)
{
struct idpf_intr_reg *intr_reg;
......
......@@ -11,13 +11,26 @@
#define IDPF_LARGE_MAX_Q 256
#define IDPF_MAX_Q 16
#define IDPF_MIN_Q 2
/* Mailbox Queue */
#define IDPF_MAX_MBXQ 1
#define IDPF_MIN_TXQ_DESC 64
#define IDPF_MIN_RXQ_DESC 64
#define IDPF_MIN_TXQ_COMPLQ_DESC 256
#define IDPF_MAX_QIDS 256
/* Number of descriptors in a queue should be a multiple of 32. RX queue
* descriptors alone should be a multiple of IDPF_REQ_RXQ_DESC_MULTIPLE
* to achieve BufQ descriptors aligned to 32
*/
#define IDPF_REQ_DESC_MULTIPLE 32
#define IDPF_REQ_RXQ_DESC_MULTIPLE (IDPF_MAX_BUFQS_PER_RXQ_GRP * 32)
#define IDPF_MIN_TX_DESC_NEEDED (MAX_SKB_FRAGS + 6)
#define IDPF_TX_WAKE_THRESH ((u16)IDPF_MIN_TX_DESC_NEEDED * 2)
#define IDPF_MAX_DESCS 8160
#define IDPF_MAX_TXQ_DESC ALIGN_DOWN(IDPF_MAX_DESCS, IDPF_REQ_DESC_MULTIPLE)
#define IDPF_MAX_RXQ_DESC ALIGN_DOWN(IDPF_MAX_DESCS, IDPF_REQ_RXQ_DESC_MULTIPLE)
#define MIN_SUPPORT_TXDID (\
VIRTCHNL2_TXDID_FLEX_FLOW_SCHED |\
VIRTCHNL2_TXDID_FLEX_TSO_CTX)
......@@ -573,6 +586,7 @@ union idpf_queue_stats {
};
#define IDPF_ITR_DYNAMIC 1
#define IDPF_ITR_MAX 0x1FE0
#define IDPF_ITR_20K 0x0032
#define IDPF_ITR_GRAN_S 1 /* Assume ITR granularity is 2us */
#define IDPF_ITR_MASK 0x1FFE /* ITR register value alignment mask */
......
......@@ -3,6 +3,50 @@
#include "idpf.h"
/**
* idpf_recv_event_msg - Receive virtchnl event message
* @vport: virtual port structure
* @ctlq_msg: message to copy from
*
* Receive virtchnl event message
*/
static void idpf_recv_event_msg(struct idpf_vport *vport,
struct idpf_ctlq_msg *ctlq_msg)
{
struct idpf_netdev_priv *np = netdev_priv(vport->netdev);
struct virtchnl2_event *v2e;
bool link_status;
u32 event;
v2e = (struct virtchnl2_event *)ctlq_msg->ctx.indirect.payload->va;
event = le32_to_cpu(v2e->event);
switch (event) {
case VIRTCHNL2_EVENT_LINK_CHANGE:
vport->link_speed_mbps = le32_to_cpu(v2e->link_speed);
link_status = v2e->link_status;
if (vport->link_up == link_status)
break;
vport->link_up = link_status;
if (np->state == __IDPF_VPORT_UP) {
if (vport->link_up) {
netif_carrier_on(vport->netdev);
netif_tx_start_all_queues(vport->netdev);
} else {
netif_tx_stop_all_queues(vport->netdev);
netif_carrier_off(vport->netdev);
}
}
break;
default:
dev_err(&vport->adapter->pdev->dev,
"Unknown event %d from PF\n", event);
break;
}
}
/**
* idpf_mb_clean - Reclaim the send mailbox queue entries
* @adapter: Driver specific private structure
......@@ -173,8 +217,12 @@ static int idpf_find_vport(struct idpf_adapter *adapter,
break;
case VIRTCHNL2_OP_ENABLE_QUEUES:
case VIRTCHNL2_OP_DISABLE_QUEUES:
case VIRTCHNL2_OP_DEL_QUEUES:
v_id = le32_to_cpu(((struct virtchnl2_del_ena_dis_queues *)vc_msg)->vport_id);
break;
case VIRTCHNL2_OP_ADD_QUEUES:
v_id = le32_to_cpu(((struct virtchnl2_add_queues *)vc_msg)->vport_id);
break;
case VIRTCHNL2_OP_MAP_QUEUE_VECTOR:
case VIRTCHNL2_OP_UNMAP_QUEUE_VECTOR:
v_id = le32_to_cpu(((struct virtchnl2_queue_vector_maps *)vc_msg)->vport_id);
......@@ -187,6 +235,9 @@ static int idpf_find_vport(struct idpf_adapter *adapter,
case VIRTCHNL2_OP_SET_RSS_KEY:
v_id = le32_to_cpu(((struct virtchnl2_rss_key *)vc_msg)->vport_id);
break;
case VIRTCHNL2_OP_EVENT:
v_id = le32_to_cpu(((struct virtchnl2_event *)vc_msg)->vport_id);
break;
case VIRTCHNL2_OP_ADD_MAC_ADDR:
case VIRTCHNL2_OP_DEL_MAC_ADDR:
v_id = le32_to_cpu(((struct virtchnl2_mac_addr_list *)vc_msg)->vport_id);
......@@ -420,6 +471,16 @@ int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op,
IDPF_VC_DIS_QUEUES,
IDPF_VC_DIS_QUEUES_ERR);
break;
case VIRTCHNL2_OP_ADD_QUEUES:
idpf_recv_vchnl_op(adapter, vport, &ctlq_msg,
IDPF_VC_ADD_QUEUES,
IDPF_VC_ADD_QUEUES_ERR);
break;
case VIRTCHNL2_OP_DEL_QUEUES:
idpf_recv_vchnl_op(adapter, vport, &ctlq_msg,
IDPF_VC_DEL_QUEUES,
IDPF_VC_DEL_QUEUES_ERR);
break;
case VIRTCHNL2_OP_MAP_QUEUE_VECTOR:
idpf_recv_vchnl_op(adapter, vport, &ctlq_msg,
IDPF_VC_MAP_IRQ,
......@@ -507,6 +568,9 @@ int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op,
IDPF_VC_DEL_MAC_ADDR,
IDPF_VC_DEL_MAC_ADDR_ERR);
break;
case VIRTCHNL2_OP_EVENT:
idpf_recv_event_msg(vport, &ctlq_msg);
break;
default:
dev_warn(&adapter->pdev->dev,
"Unhandled virtchnl response %d\n",
......@@ -1985,6 +2049,84 @@ int idpf_send_disable_queues_msg(struct idpf_vport *vport)
return idpf_wait_for_marker_event(vport);
}
/**
* idpf_convert_reg_to_queue_chunks - Copy queue chunk information to the right
* structure
* @dchunks: Destination chunks to store data to
* @schunks: Source chunks to copy data from
* @num_chunks: number of chunks to copy
*/
static void idpf_convert_reg_to_queue_chunks(struct virtchnl2_queue_chunk *dchunks,
struct virtchnl2_queue_reg_chunk *schunks,
u16 num_chunks)
{
u16 i;
for (i = 0; i < num_chunks; i++) {
dchunks[i].type = schunks[i].type;
dchunks[i].start_queue_id = schunks[i].start_queue_id;
dchunks[i].num_queues = schunks[i].num_queues;
}
}
/**
* idpf_send_delete_queues_msg - send delete queues virtchnl message
* @vport: Virtual port private data structure
*
* Will send delete queues virtchnl message. Return 0 on success, negative on
* failure.
*/
int idpf_send_delete_queues_msg(struct idpf_vport *vport)
{
struct idpf_adapter *adapter = vport->adapter;
struct virtchnl2_create_vport *vport_params;
struct virtchnl2_queue_reg_chunks *chunks;
struct virtchnl2_del_ena_dis_queues *eq;
struct idpf_vport_config *vport_config;
u16 vport_idx = vport->idx;
int buf_size, err;
u16 num_chunks;
vport_config = adapter->vport_config[vport_idx];
if (vport_config->req_qs_chunks) {
struct virtchnl2_add_queues *vc_aq =
(struct virtchnl2_add_queues *)vport_config->req_qs_chunks;
chunks = &vc_aq->chunks;
} else {
vport_params = adapter->vport_params_recvd[vport_idx];
chunks = &vport_params->chunks;
}
num_chunks = le16_to_cpu(chunks->num_chunks);
buf_size = struct_size(eq, chunks.chunks, num_chunks);
eq = kzalloc(buf_size, GFP_KERNEL);
if (!eq)
return -ENOMEM;
eq->vport_id = cpu_to_le32(vport->vport_id);
eq->chunks.num_chunks = cpu_to_le16(num_chunks);
idpf_convert_reg_to_queue_chunks(eq->chunks.chunks, chunks->chunks,
num_chunks);
mutex_lock(&vport->vc_buf_lock);
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DEL_QUEUES,
buf_size, (u8 *)eq);
if (err)
goto rel_lock;
err = idpf_min_wait_for_event(adapter, vport, IDPF_VC_DEL_QUEUES,
IDPF_VC_DEL_QUEUES_ERR);
rel_lock:
mutex_unlock(&vport->vc_buf_lock);
kfree(eq);
return err;
}
/**
* idpf_send_config_queues_msg - Send config queues virtchnl message
* @vport: Virtual port private data structure
......@@ -2003,6 +2145,78 @@ int idpf_send_config_queues_msg(struct idpf_vport *vport)
return idpf_send_config_rx_queues_msg(vport);
}
/**
* idpf_send_add_queues_msg - Send virtchnl add queues message
* @vport: Virtual port private data structure
* @num_tx_q: number of transmit queues
* @num_complq: number of transmit completion queues
* @num_rx_q: number of receive queues
* @num_rx_bufq: number of receive buffer queues
*
* Returns 0 on success, negative on failure. vport _MUST_ be const here as
* we should not change any fields within vport itself in this function.
*/
int idpf_send_add_queues_msg(const struct idpf_vport *vport, u16 num_tx_q,
u16 num_complq, u16 num_rx_q, u16 num_rx_bufq)
{
struct idpf_adapter *adapter = vport->adapter;
struct idpf_vport_config *vport_config;
struct virtchnl2_add_queues aq = { };
struct virtchnl2_add_queues *vc_msg;
u16 vport_idx = vport->idx;
int size, err;
vport_config = adapter->vport_config[vport_idx];
aq.vport_id = cpu_to_le32(vport->vport_id);
aq.num_tx_q = cpu_to_le16(num_tx_q);
aq.num_tx_complq = cpu_to_le16(num_complq);
aq.num_rx_q = cpu_to_le16(num_rx_q);
aq.num_rx_bufq = cpu_to_le16(num_rx_bufq);
mutex_lock(&((struct idpf_vport *)vport)->vc_buf_lock);
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_ADD_QUEUES,
sizeof(struct virtchnl2_add_queues), (u8 *)&aq);
if (err)
goto rel_lock;
/* We want vport to be const to prevent incidental code changes making
* changes to the vport config. We're making a special exception here
* to discard const to use the virtchnl.
*/
err = idpf_wait_for_event(adapter, (struct idpf_vport *)vport,
IDPF_VC_ADD_QUEUES, IDPF_VC_ADD_QUEUES_ERR);
if (err)
goto rel_lock;
kfree(vport_config->req_qs_chunks);
vport_config->req_qs_chunks = NULL;
vc_msg = (struct virtchnl2_add_queues *)vport->vc_msg;
/* compare vc_msg num queues with vport num queues */
if (le16_to_cpu(vc_msg->num_tx_q) != num_tx_q ||
le16_to_cpu(vc_msg->num_rx_q) != num_rx_q ||
le16_to_cpu(vc_msg->num_tx_complq) != num_complq ||
le16_to_cpu(vc_msg->num_rx_bufq) != num_rx_bufq) {
err = -EINVAL;
goto rel_lock;
}
size = struct_size(vc_msg, chunks.chunks,
le16_to_cpu(vc_msg->chunks.num_chunks));
vport_config->req_qs_chunks = kmemdup(vc_msg, size, GFP_KERNEL);
if (!vport_config->req_qs_chunks) {
err = -ENOMEM;
goto rel_lock;
}
rel_lock:
mutex_unlock(&((struct idpf_vport *)vport)->vc_buf_lock);
return err;
}
/**
* idpf_send_alloc_vectors_msg - Send virtchnl alloc vectors message
* @adapter: Driver specific private structure
......@@ -2823,7 +3037,7 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter)
*
* Return 0 on success, error on failure
*/
static int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport)
int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport)
{
struct idpf_vector_info vec_info;
int num_alloc_vecs;
......@@ -3155,6 +3369,30 @@ int idpf_vport_queue_ids_init(struct idpf_vport *vport)
return err;
}
/**
* idpf_vport_adjust_qs - Adjust to new requested queues
* @vport: virtual port data struct
*
* Renegotiate queues. Returns 0 on success, negative on failure.
*/
int idpf_vport_adjust_qs(struct idpf_vport *vport)
{
struct virtchnl2_create_vport vport_msg;
int err;
vport_msg.txq_model = cpu_to_le16(vport->txq_model);
vport_msg.rxq_model = cpu_to_le16(vport->rxq_model);
err = idpf_vport_calc_total_qs(vport->adapter, vport->idx, &vport_msg,
NULL);
if (err)
return err;
idpf_vport_init_num_qs(vport, &vport_msg);
idpf_vport_calc_num_q_groups(vport);
return 0;
}
/**
* idpf_is_capability_ena - Default implementation of capability checking
* @adapter: Private data struct
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment