Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0fc2dc58 authored by Henry Orosco's avatar Henry Orosco Committed by Doug Ledford
Browse files

i40iw: Add Quality of Service support



Add support for QoS on QPs. Upon device initialization,
a map is created from user priority to queue set
handles. On QP creation, use ToS to look up the queue
set handle for use with the QP.

Signed-off-by: default avatarFaisal Latif <faisal.latif@intel.com>
Signed-off-by: default avatarShiraz Saleem <shiraz.saleem@intel.com>
Signed-off-by: default avatarHenry Orosco <henry.orosco@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent e37a79e5
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -210,6 +210,12 @@ struct i40iw_msix_vector {
	u32 ceq_id;
};

struct l2params_work {
	struct work_struct work;
	struct i40iw_device *iwdev;
	struct i40iw_l2params l2params;
};

#define I40IW_MSIX_TABLE_SIZE   65

struct virtchnl_work {
@@ -514,6 +520,9 @@ void i40iw_add_pdusecount(struct i40iw_pd *iwpd);
void i40iw_hw_modify_qp(struct i40iw_device *iwdev, struct i40iw_qp *iwqp,
			struct i40iw_modify_qp_info *info, bool wait);

void i40iw_qp_suspend_resume(struct i40iw_sc_dev *dev,
			     struct i40iw_sc_qp *qp,
			     bool suspend);
enum i40iw_status_code i40iw_manage_qhash(struct i40iw_device *iwdev,
					  struct i40iw_cm_info *cminfo,
					  enum i40iw_quad_entry_type etype,
+27 −3
Original line number Diff line number Diff line
@@ -221,6 +221,7 @@ static void i40iw_get_addr_info(struct i40iw_cm_node *cm_node,
	memcpy(cm_info->rem_addr, cm_node->rem_addr, sizeof(cm_info->rem_addr));
	cm_info->loc_port = cm_node->loc_port;
	cm_info->rem_port = cm_node->rem_port;
	cm_info->user_pri = cm_node->user_pri;
}

/**
@@ -396,6 +397,7 @@ static struct i40iw_puda_buf *i40iw_form_cm_frame(struct i40iw_cm_node *cm_node,
	u32 opts_len = 0;
	u32 pd_len = 0;
	u32 hdr_len = 0;
	u16 vtag;

	sqbuf = i40iw_puda_get_bufpool(dev->ilq);
	if (!sqbuf)
@@ -445,7 +447,8 @@ static struct i40iw_puda_buf *i40iw_form_cm_frame(struct i40iw_cm_node *cm_node,
		ether_addr_copy(ethh->h_source, cm_node->loc_mac);
		if (cm_node->vlan_id < VLAN_TAG_PRESENT) {
			((struct vlan_ethhdr *)ethh)->h_vlan_proto = htons(ETH_P_8021Q);
			((struct vlan_ethhdr *)ethh)->h_vlan_TCI = htons(cm_node->vlan_id);
			vtag = (cm_node->user_pri << VLAN_PRIO_SHIFT) | cm_node->vlan_id;
			((struct vlan_ethhdr *)ethh)->h_vlan_TCI = htons(vtag);

			((struct vlan_ethhdr *)ethh)->h_vlan_encapsulated_proto = htons(ETH_P_IP);
		} else {
@@ -474,7 +477,8 @@ static struct i40iw_puda_buf *i40iw_form_cm_frame(struct i40iw_cm_node *cm_node,
		ether_addr_copy(ethh->h_source, cm_node->loc_mac);
		if (cm_node->vlan_id < VLAN_TAG_PRESENT) {
			((struct vlan_ethhdr *)ethh)->h_vlan_proto = htons(ETH_P_8021Q);
			((struct vlan_ethhdr *)ethh)->h_vlan_TCI = htons(cm_node->vlan_id);
			vtag = (cm_node->user_pri << VLAN_PRIO_SHIFT) | cm_node->vlan_id;
			((struct vlan_ethhdr *)ethh)->h_vlan_TCI = htons(vtag);
			((struct vlan_ethhdr *)ethh)->h_vlan_encapsulated_proto = htons(ETH_P_IPV6);
		} else {
			ethh->h_proto = htons(ETH_P_IPV6);
@@ -1880,6 +1884,7 @@ static int i40iw_dec_refcnt_listen(struct i40iw_cm_core *cm_core,
			nfo.loc_port = listener->loc_port;
			nfo.ipv4 = listener->ipv4;
			nfo.vlan_id = listener->vlan_id;
			nfo.user_pri = listener->user_pri;

			if (!list_empty(&listener->child_listen_list)) {
				i40iw_del_multiple_qhash(listener->iwdev, &nfo, listener);
@@ -2138,6 +2143,11 @@ static struct i40iw_cm_node *i40iw_make_cm_node(
	/* set our node specific transport info */
	cm_node->ipv4 = cm_info->ipv4;
	cm_node->vlan_id = cm_info->vlan_id;
	if ((cm_node->vlan_id == I40IW_NO_VLAN) && iwdev->dcb)
		cm_node->vlan_id = 0;
	cm_node->user_pri = cm_info->user_pri;
	if (listener)
		cm_node->user_pri = listener->user_pri;
	memcpy(cm_node->loc_addr, cm_info->loc_addr, sizeof(cm_node->loc_addr));
	memcpy(cm_node->rem_addr, cm_info->rem_addr, sizeof(cm_node->rem_addr));
	cm_node->loc_port = cm_info->loc_port;
@@ -3055,6 +3065,7 @@ void i40iw_receive_ilq(struct i40iw_sc_dev *dev, struct i40iw_puda_buf *rbuf)
	struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev;
	struct i40iw_cm_core *cm_core = &iwdev->cm_core;
	struct vlan_ethhdr *ethh;
	u16 vtag;

	/* if vlan, then maclen = 18 else 14 */
	iph = (struct iphdr *)rbuf->iph;
@@ -3068,7 +3079,9 @@ void i40iw_receive_ilq(struct i40iw_sc_dev *dev, struct i40iw_puda_buf *rbuf)
	ethh = (struct vlan_ethhdr *)rbuf->mem.va;

	if (ethh->h_vlan_proto == htons(ETH_P_8021Q)) {
		cm_info.vlan_id = ntohs(ethh->h_vlan_TCI) & VLAN_VID_MASK;
		vtag = ntohs(ethh->h_vlan_TCI);
		cm_info.user_pri = (vtag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
		cm_info.vlan_id = vtag & VLAN_VID_MASK;
		i40iw_debug(cm_core->dev,
			    I40IW_DEBUG_CM,
			    "%s vlan_id=%d\n",
@@ -3309,6 +3322,8 @@ static void i40iw_cm_init_tsa_conn(struct i40iw_qp *iwqp,

	ctx_info->tcp_info_valid = true;
	ctx_info->iwarp_info_valid = true;
	ctx_info->add_to_qoslist = true;
	ctx_info->user_pri = cm_node->user_pri;

	i40iw_init_tcp_ctx(cm_node, &tcp_info, iwqp);
	if (cm_node->snd_mark_en) {
@@ -3326,6 +3341,7 @@ static void i40iw_cm_init_tsa_conn(struct i40iw_qp *iwqp,
	/* once tcp_info is set, no need to do it again */
	ctx_info->tcp_info_valid = false;
	ctx_info->iwarp_info_valid = false;
	ctx_info->add_to_qoslist = false;
}

/**
@@ -3759,6 +3775,9 @@ int i40iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
		i40iw_netdev_vlan_ipv6(cm_info.loc_addr, &cm_info.vlan_id, NULL);
	}
	cm_info.cm_id = cm_id;
	cm_info.user_pri = rt_tos2priority(cm_id->tos);
	i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_DCB, "%s TOS:[%d] UP:[%d]\n",
		    __func__, cm_id->tos, cm_info.user_pri);
	if ((cm_info.ipv4 && (laddr->sin_addr.s_addr != raddr->sin_addr.s_addr)) ||
	    (!cm_info.ipv4 && memcmp(laddr6->sin6_addr.in6_u.u6_addr32,
				     raddr6->sin6_addr.in6_u.u6_addr32,
@@ -3904,6 +3923,11 @@ int i40iw_create_listen(struct iw_cm_id *cm_id, int backlog)

	cm_id->provider_data = cm_listen_node;

	cm_listen_node->user_pri = rt_tos2priority(cm_id->tos);
	cm_info.user_pri = cm_listen_node->user_pri;
	i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_DCB, "%s TOS:[%d] UP:[%d]\n",
		    __func__, cm_id->tos, cm_listen_node->user_pri);

	if (!cm_listen_node->reused_node) {
		if (wildcard) {
			if (cm_info.ipv4)
+1 −1
Original line number Diff line number Diff line
@@ -368,7 +368,7 @@ struct i40iw_cm_info {
	u32 rem_addr[4];
	u16 vlan_id;
	int backlog;
	u16 user_pri;
	u8 user_pri;
	bool ipv4;
};

+146 −5
Original line number Diff line number Diff line
@@ -222,6 +222,133 @@ static enum i40iw_status_code i40iw_sc_parse_fpm_query_buf(
	return 0;
}

/**
 * i40iw_fill_qos_list - Change all unknown qs handles to available ones
 * @qs_list: list of qs_handles to be fixed with valid qs_handles
 */
static void i40iw_fill_qos_list(u16 *qs_list)
{
	u16 qshandle = qs_list[0];
	int i;

	for (i = 0; i < I40IW_MAX_USER_PRIORITY; i++) {
		if (qs_list[i] == QS_HANDLE_UNKNOWN)
			qs_list[i] = qshandle;
		else
			qshandle = qs_list[i];
	}
}

/**
 * i40iw_qp_from_entry - Given entry, get to the qp structure
 * @entry: Points to list of qp structure
 */
static struct i40iw_sc_qp *i40iw_qp_from_entry(struct list_head *entry)
{
	if (!entry)
		return NULL;

	return (struct i40iw_sc_qp *)((char *)entry - offsetof(struct i40iw_sc_qp, list));
}

/**
 * i40iw_get_qp - get the next qp from the list given current qp
 * @head: Listhead of qp's
 * @qp: current qp
 */
static struct i40iw_sc_qp *i40iw_get_qp(struct list_head *head, struct i40iw_sc_qp *qp)
{
	struct list_head *entry = NULL;
	struct list_head *lastentry;

	if (list_empty(head))
		return NULL;

	if (!qp) {
		entry = head->next;
	} else {
		lastentry = &qp->list;
		entry = (lastentry != head) ? lastentry->next : NULL;
	}

	return i40iw_qp_from_entry(entry);
}

/**
 * i40iw_change_l2params - given the new l2 parameters, change all qp
 * @dev: IWARP device pointer
 * @l2params: New paramaters from l2
 */
void i40iw_change_l2params(struct i40iw_sc_dev *dev, struct i40iw_l2params *l2params)
{
	struct i40iw_sc_qp *qp = NULL;
	bool qs_handle_change = false;
	bool mss_change = false;
	unsigned long flags;
	u16 qs_handle;
	int i;

	if (dev->mss != l2params->mss) {
		mss_change = true;
		dev->mss = l2params->mss;
	}

	i40iw_fill_qos_list(l2params->qs_handle_list);
	for (i = 0; i < I40IW_MAX_USER_PRIORITY; i++) {
		qs_handle = l2params->qs_handle_list[i];
		if (dev->qos[i].qs_handle != qs_handle)
			qs_handle_change = true;
		else if (!mss_change)
			continue;       /* no MSS nor qs handle change */
		spin_lock_irqsave(&dev->qos[i].lock, flags);
		qp = i40iw_get_qp(&dev->qos[i].qplist, qp);
		while (qp) {
			if (mss_change)
				i40iw_qp_mss_modify(dev, qp);
			if (qs_handle_change) {
				qp->qs_handle = qs_handle;
				/* issue cqp suspend command */
				i40iw_qp_suspend_resume(dev, qp, true);
			}
			qp = i40iw_get_qp(&dev->qos[i].qplist, qp);
		}
		spin_unlock_irqrestore(&dev->qos[i].lock, flags);
		dev->qos[i].qs_handle = qs_handle;
	}
}

/**
 * i40iw_qp_rem_qos - remove qp from qos lists during destroy qp
 * @dev: IWARP device pointer
 * @qp: qp to be removed from qos
 */
static void i40iw_qp_rem_qos(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp)
{
	unsigned long flags;

	if (!qp->on_qoslist)
		return;
	spin_lock_irqsave(&dev->qos[qp->user_pri].lock, flags);
	list_del(&qp->list);
	spin_unlock_irqrestore(&dev->qos[qp->user_pri].lock, flags);
}

/**
 * i40iw_qp_add_qos - called during setctx fot qp to be added to qos
 * @dev: IWARP device pointer
 * @qp: qp to be added to qos
 */
void i40iw_qp_add_qos(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp)
{
	unsigned long flags;

	spin_lock_irqsave(&dev->qos[qp->user_pri].lock, flags);
	qp->qs_handle = dev->qos[qp->user_pri].qs_handle;
	list_add(&qp->list, &dev->qos[qp->user_pri].qplist);
	qp->on_qoslist = true;
	spin_unlock_irqrestore(&dev->qos[qp->user_pri].lock, flags);
}

/**
 * i40iw_sc_pd_init - initialize sc pd struct
 * @dev: sc device struct
@@ -1082,7 +1209,7 @@ static enum i40iw_status_code i40iw_sc_manage_qhash_table_entry(
			      LS_64(info->dest_ip[2], I40IW_CQPSQ_QHASH_ADDR2) |
			      LS_64(info->dest_ip[3], I40IW_CQPSQ_QHASH_ADDR3));
	}
	qw2 = LS_64(cqp->dev->qs_handle, I40IW_CQPSQ_QHASH_QS_HANDLE);
	qw2 = LS_64(cqp->dev->qos[info->user_pri].qs_handle, I40IW_CQPSQ_QHASH_QS_HANDLE);
	if (info->vlan_valid)
		qw2 |= LS_64(info->vlan_id, I40IW_CQPSQ_QHASH_VLANID);
	set_64bit_val(wqe, 16, qw2);
@@ -2151,7 +2278,7 @@ static enum i40iw_status_code i40iw_sc_qp_init(struct i40iw_sc_qp *qp,
	qp->rq_tph_en = info->rq_tph_en;
	qp->rcv_tph_en = info->rcv_tph_en;
	qp->xmit_tph_en = info->xmit_tph_en;
	qp->qs_handle = qp->pd->dev->qs_handle;
	qp->qs_handle = qp->pd->dev->qos[qp->user_pri].qs_handle;
	qp->exception_lan_queue = qp->pd->dev->exception_lan_queue;

	return 0;
@@ -2296,6 +2423,7 @@ static enum i40iw_status_code i40iw_sc_qp_destroy(
	struct i40iw_sc_cqp *cqp;
	u64 header;

	i40iw_qp_rem_qos(qp->pd->dev, qp);
	cqp = qp->pd->dev->cqp;
	wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
	if (!wqe)
@@ -2447,6 +2575,12 @@ static enum i40iw_status_code i40iw_sc_qp_setctx(

	iw = info->iwarp_info;
	tcp = info->tcp_info;
	if (info->add_to_qoslist) {
		qp->user_pri = info->user_pri;
		i40iw_qp_add_qos(qp->pd->dev, qp);
		i40iw_debug(qp->dev, I40IW_DEBUG_DCB, "%s qp[%d] UP[%d] qset[%d]\n",
			    __func__, qp->qp_uk.qp_id, qp->user_pri, qp->qs_handle);
	}
	qw0 = LS_64(qp->qp_uk.rq_wqe_size, I40IWQPC_RQWQESIZE) |
	      LS_64(info->err_rq_idx_valid, I40IWQPC_ERR_RQ_IDX_VALID) |
	      LS_64(qp->rcv_tph_en, I40IWQPC_RCVTPHEN) |
@@ -4742,6 +4876,7 @@ enum i40iw_status_code i40iw_device_init(struct i40iw_sc_dev *dev,
	u16 hmc_fcn = 0;
	enum i40iw_status_code ret_code = 0;
	u8 db_size;
	int i;

	spin_lock_init(&dev->cqp_lock);
	INIT_LIST_HEAD(&dev->cqp_cmd_head);             /* for the cqp commands backlog. */
@@ -4757,7 +4892,13 @@ enum i40iw_status_code i40iw_device_init(struct i40iw_sc_dev *dev,
		return ret_code;
	}
	dev->hmc_fn_id = info->hmc_fn_id;
	dev->qs_handle = info->qs_handle;
	i40iw_fill_qos_list(info->l2params.qs_handle_list);
	for (i = 0; i < I40IW_MAX_USER_PRIORITY; i++) {
		dev->qos[i].qs_handle = info->l2params.qs_handle_list[i];
		i40iw_debug(dev, I40IW_DEBUG_DCB, "qset[%d]: %d\n", i, dev->qos[i].qs_handle);
		spin_lock_init(&dev->qos[i].lock);
		INIT_LIST_HEAD(&dev->qos[i].qplist);
	}
	dev->exception_lan_queue = info->exception_lan_queue;
	dev->is_pf = info->is_pf;

+2 −0
Original line number Diff line number Diff line
@@ -74,6 +74,8 @@
#define RS_32_1(val, bits)      (u32)(val >> bits)
#define I40E_HI_DWORD(x)        ((u32)((((x) >> 16) >> 16) & 0xFFFFFFFF))

#define QS_HANDLE_UNKNOWN       0xffff

#define LS_64(val, field) (((u64)val << field ## _SHIFT) & (field ## _MASK))

#define RS_64(val, field) ((u64)(val & field ## _MASK) >> field ## _SHIFT)
Loading