ib_srpt: Make the completion vector configurable

Allow a set of completion vectors to be associated with each InfiniBand
HCA port and allocate the completion vector for each session in a
round-robin fashion from the per-port set. This helps to spread the
InfiniBand interrupt workload over multiple CPU's, at least if different
InfiniBand MSI-X vectors are associated with different CPU's.


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@5728 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Bart Van Assche
2014-08-25 12:50:19 +00:00
parent 8995f1c241
commit 7061a6ee8d
2 changed files with 123 additions and 3 deletions
+113 -3
View File
@@ -2133,12 +2133,12 @@ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch)
ch->rq_size + srpt_sq_size);
#else
ch->cq = ib_create_cq(sdev->device, srpt_completion, NULL, ch,
ch->rq_size + srpt_sq_size, 0);
ch->rq_size + srpt_sq_size, ch->comp_vector);
#endif
if (IS_ERR(ch->cq)) {
ret = PTR_ERR(ch->cq);
PRINT_ERROR("failed to create CQ cqe= %d ret= %d",
ch->rq_size + srpt_sq_size, ret);
PRINT_ERROR("failed to create CQ: cqe %d; c.v. %d; ret %d",
ch->rq_size + srpt_sq_size, ch->comp_vector, ret);
goto out;
}
@@ -2296,6 +2296,18 @@ static void __srpt_close_all_ch(struct srpt_tgt *srpt_tgt)
}
}
static struct srpt_device *srpt_convert_to_sdev(struct scst_tgt *scst_tgt)
{
struct srpt_port *sport;
if (one_target_per_port) {
sport = scst_tgt_get_tgt_priv(scst_tgt);
return sport ? sport->sdev : NULL;
} else {
return scst_tgt_get_tgt_priv(scst_tgt);
}
}
static struct srpt_tgt *srpt_convert_scst_tgt(struct scst_tgt *scst_tgt)
{
struct srpt_device *sdev;
@@ -2394,6 +2406,26 @@ static bool srpt_is_target_enabled(struct scst_tgt *scst_tgt)
}
#endif
/*
* srpt_next_comp_vector() - Next completion vector >= srpt_tgt->comp_vector
*/
static u8 srpt_next_comp_vector(struct srpt_tgt *srpt_tgt)
{
u8 comp_vector;
mutex_lock(&srpt_tgt->mutex);
comp_vector = find_next_bit(srpt_tgt->comp_v_mask, COMP_V_MASK_SIZE,
srpt_tgt->comp_vector);
if (comp_vector >= COMP_V_MASK_SIZE)
comp_vector = find_next_bit(srpt_tgt->comp_v_mask,
COMP_V_MASK_SIZE, 0);
sBUG_ON(comp_vector >= COMP_V_MASK_SIZE);
srpt_tgt->comp_vector = comp_vector + 1;
mutex_unlock(&srpt_tgt->mutex);
return comp_vector;
}
/**
* srpt_cm_req_recv() - Process the event IB_CM_REQ_RECEIVED.
*
@@ -2556,6 +2588,8 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
list_add_tail(&ch->ioctx_ring[i]->free_list, &ch->free_list);
}
ch->comp_vector = srpt_next_comp_vector(srpt_tgt);
ret = srpt_create_ch_ib(ch);
if (ret) {
rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
@@ -3782,6 +3816,57 @@ static uint16_t srpt_get_scsi_transport_version(struct scst_tgt *scst_tgt)
}
#if !defined(CONFIG_SCST_PROC)
static ssize_t show_comp_v_mask(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct scst_tgt *scst_tgt = container_of(kobj, struct scst_tgt,
tgt_kobj);
struct srpt_tgt *srpt_tgt = srpt_convert_scst_tgt(scst_tgt);
int res = -E_TGT_PRIV_NOT_YET_SET;
if (!srpt_tgt)
goto out;
res = sprintf(buf, "%#lx\n%s", srpt_tgt->comp_v_mask[0],
SCST_SYSFS_KEY_MARK "\n");
out:
return res;
}
static ssize_t store_comp_v_mask(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf,
size_t count)
{
struct scst_tgt *scst_tgt = container_of(kobj, struct scst_tgt,
tgt_kobj);
struct srpt_tgt *srpt_tgt = srpt_convert_scst_tgt(scst_tgt);
struct srpt_device *sdev = srpt_convert_to_sdev(scst_tgt);
int res = -E_TGT_PRIV_NOT_YET_SET;
unsigned long mask;
if (!srpt_tgt)
goto out;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
res = kstrtoul(buf, 16, &mask);
#else
res = strict_strtoul(buf, 16, &mask);
#endif
if (res)
goto out;
res = -EINVAL;
if (mask == 0 || mask >= (1ULL << sdev->device->num_comp_vectors))
goto out;
srpt_tgt->comp_v_mask[0] = mask;
res = count;
out:
return res;
}
static struct kobj_attribute srpt_show_comp_v_mask_attr =
__ATTR(comp_v_mask, S_IRUGO | S_IWUSR, show_comp_v_mask,
store_comp_v_mask);
static ssize_t srpt_show_device(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
@@ -3873,6 +3958,7 @@ static struct kobj_attribute srpt_show_login_info_attr =
__ATTR(login_info, S_IRUGO, show_login_info, NULL);
static const struct attribute *srpt_tgt_attrs[] = {
&srpt_show_comp_v_mask_attr.attr,
&srpt_device_attr.attr,
&srpt_show_login_info_attr.attr,
NULL
@@ -3917,17 +4003,37 @@ static ssize_t show_ch_state(struct kobject *kobj, struct kobj_attribute *attr,
return sprintf(buf, "%s\n", get_ch_state_name(ch->state));
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) || defined(RHEL_RELEASE_CODE)
static ssize_t show_comp_vector(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct scst_session *scst_sess;
struct srpt_rdma_ch *ch;
scst_sess = container_of(kobj, struct scst_session, sess_kobj);
ch = scst_sess_get_tgt_priv(scst_sess);
return ch ? sprintf(buf, "%u\n", ch->comp_vector) : -ENOENT;
}
#endif
static const struct kobj_attribute srpt_req_lim_attr =
__ATTR(req_lim, S_IRUGO, show_req_lim, NULL);
static const struct kobj_attribute srpt_req_lim_delta_attr =
__ATTR(req_lim_delta, S_IRUGO, show_req_lim_delta, NULL);
static const struct kobj_attribute srpt_ch_state_attr =
__ATTR(ch_state, S_IRUGO, show_ch_state, NULL);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) || defined(RHEL_RELEASE_CODE)
static const struct kobj_attribute srpt_comp_vector_attr =
__ATTR(comp_vector, S_IRUGO, show_comp_vector, NULL);
#endif
static const struct attribute *srpt_sess_attrs[] = {
&srpt_req_lim_attr.attr,
&srpt_req_lim_delta_attr.attr,
&srpt_ch_state_attr.attr,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) || defined(RHEL_RELEASE_CODE)
&srpt_comp_vector_attr.attr,
#endif
NULL
};
#endif
@@ -3986,9 +4092,13 @@ static struct scst_proc_data srpt_log_proc_data = {
/* Note: the caller must have zero-initialized *@srpt_tgt. */
static void srpt_init_tgt(struct srpt_tgt *srpt_tgt)
{
int i;
INIT_LIST_HEAD(&srpt_tgt->nexus_list);
init_waitqueue_head(&srpt_tgt->ch_releaseQ);
mutex_init(&srpt_tgt->mutex);
for (i = 0; i < COMP_V_MASK_SIZE; i++)
__set_bit(i, srpt_tgt->comp_v_mask);
}
/**
+10
View File
@@ -139,6 +139,8 @@ enum {
DEFAULT_MAX_RDMA_SIZE = 65536,
RDMA_COMPL_TIMEOUT_S = 80,
COMP_V_MASK_SIZE = 64,
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) && \
@@ -334,6 +336,7 @@ enum rdma_ch_state {
* list contains struct srpt_ioctx elements and is protected
* against concurrent modification by the cm_id spinlock.
* @pkey: P_Key of the IB partition for this SRP channel.
* @comp_vector: Completion vector assigned to the QP.
* @scst_sess: SCST session information associated with this SRP channel.
* @sess_name: SCST session name.
*/
@@ -368,6 +371,9 @@ struct srpt_rdma_ch {
struct list_head list;
struct list_head cmd_wait_list;
uint16_t pkey;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) || defined(RHEL_RELEASE_CODE)
u8 comp_vector;
#endif
bool using_rdma_cm;
bool processing_wait_list;
@@ -395,6 +401,8 @@ struct srpt_nexus {
* @mutex: Protects @nexus_list and srpt_nexus.ch_list.
* @nexus_list: Per-device I_T nexus list.
* @scst_tgt: SCST target information associated with this HCA.
* @comp_v_mask: Bitmask with one bit per allowed completion vector.
* @comp_vector: Completion vector from where searching will start.
* @enabled: Whether or not this SCST target is enabled.
*/
struct srpt_tgt {
@@ -402,6 +410,8 @@ struct srpt_tgt {
struct mutex mutex;
struct list_head nexus_list;
struct scst_tgt *scst_tgt;
DECLARE_BITMAP(comp_v_mask, COMP_V_MASK_SIZE);
u8 comp_vector;
bool enabled;
};