Commit dae81683 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband:
  IB/ehca: Discard double CQE for one WR
  IB/ehca: Check idr_find() return value
  IB/ehca: Repoll CQ on invalid opcode
  IB/ehca: Rename goto label in ehca_poll_cq_one()
  IB/ehca: Update qp_state on cached modify_qp()
  IPoIB/cm: Use vmalloc() to allocate rx_rings
parents ddc752a4 3a3eae0d
...@@ -156,6 +156,14 @@ struct ehca_mod_qp_parm { ...@@ -156,6 +156,14 @@ struct ehca_mod_qp_parm {
#define EHCA_MOD_QP_PARM_MAX 4 #define EHCA_MOD_QP_PARM_MAX 4
#define QMAP_IDX_MASK 0xFFFFULL
/* struct for tracking if cqes have been reported to the application */
struct ehca_qmap_entry {
u16 app_wr_id;
u16 reported;
};
struct ehca_qp { struct ehca_qp {
union { union {
struct ib_qp ib_qp; struct ib_qp ib_qp;
...@@ -165,6 +173,7 @@ struct ehca_qp { ...@@ -165,6 +173,7 @@ struct ehca_qp {
enum ehca_ext_qp_type ext_type; enum ehca_ext_qp_type ext_type;
enum ib_qp_state state; enum ib_qp_state state;
struct ipz_queue ipz_squeue; struct ipz_queue ipz_squeue;
struct ehca_qmap_entry *sq_map;
struct ipz_queue ipz_rqueue; struct ipz_queue ipz_rqueue;
struct h_galpas galpas; struct h_galpas galpas;
u32 qkey; u32 qkey;
......
...@@ -213,6 +213,7 @@ struct ehca_wqe { ...@@ -213,6 +213,7 @@ struct ehca_wqe {
#define WC_STATUS_ERROR_BIT 0x80000000 #define WC_STATUS_ERROR_BIT 0x80000000
#define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800 #define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800
#define WC_STATUS_PURGE_BIT 0x10 #define WC_STATUS_PURGE_BIT 0x10
#define WC_SEND_RECEIVE_BIT 0x80
struct ehca_cqe { struct ehca_cqe {
u64 work_request_id; u64 work_request_id;
......
...@@ -412,6 +412,7 @@ static struct ehca_qp *internal_create_qp( ...@@ -412,6 +412,7 @@ static struct ehca_qp *internal_create_qp(
struct ehca_shca *shca = container_of(pd->device, struct ehca_shca, struct ehca_shca *shca = container_of(pd->device, struct ehca_shca,
ib_device); ib_device);
struct ib_ucontext *context = NULL; struct ib_ucontext *context = NULL;
u32 nr_qes;
u64 h_ret; u64 h_ret;
int is_llqp = 0, has_srq = 0; int is_llqp = 0, has_srq = 0;
int qp_type, max_send_sge, max_recv_sge, ret; int qp_type, max_send_sge, max_recv_sge, ret;
...@@ -715,6 +716,15 @@ static struct ehca_qp *internal_create_qp( ...@@ -715,6 +716,15 @@ static struct ehca_qp *internal_create_qp(
"and pages ret=%i", ret); "and pages ret=%i", ret);
goto create_qp_exit2; goto create_qp_exit2;
} }
nr_qes = my_qp->ipz_squeue.queue_length /
my_qp->ipz_squeue.qe_size;
my_qp->sq_map = vmalloc(nr_qes *
sizeof(struct ehca_qmap_entry));
if (!my_qp->sq_map) {
ehca_err(pd->device, "Couldn't allocate squeue "
"map ret=%i", ret);
goto create_qp_exit3;
}
} }
if (HAS_RQ(my_qp)) { if (HAS_RQ(my_qp)) {
...@@ -724,7 +734,7 @@ static struct ehca_qp *internal_create_qp( ...@@ -724,7 +734,7 @@ static struct ehca_qp *internal_create_qp(
if (ret) { if (ret) {
ehca_err(pd->device, "Couldn't initialize rqueue " ehca_err(pd->device, "Couldn't initialize rqueue "
"and pages ret=%i", ret); "and pages ret=%i", ret);
goto create_qp_exit3; goto create_qp_exit4;
} }
} }
...@@ -770,7 +780,7 @@ static struct ehca_qp *internal_create_qp( ...@@ -770,7 +780,7 @@ static struct ehca_qp *internal_create_qp(
if (!my_qp->mod_qp_parm) { if (!my_qp->mod_qp_parm) {
ehca_err(pd->device, ehca_err(pd->device,
"Could not alloc mod_qp_parm"); "Could not alloc mod_qp_parm");
goto create_qp_exit4; goto create_qp_exit5;
} }
} }
} }
...@@ -780,7 +790,7 @@ static struct ehca_qp *internal_create_qp( ...@@ -780,7 +790,7 @@ static struct ehca_qp *internal_create_qp(
h_ret = ehca_define_sqp(shca, my_qp, init_attr); h_ret = ehca_define_sqp(shca, my_qp, init_attr);
if (h_ret != H_SUCCESS) { if (h_ret != H_SUCCESS) {
ret = ehca2ib_return_code(h_ret); ret = ehca2ib_return_code(h_ret);
goto create_qp_exit5; goto create_qp_exit6;
} }
} }
...@@ -789,7 +799,7 @@ static struct ehca_qp *internal_create_qp( ...@@ -789,7 +799,7 @@ static struct ehca_qp *internal_create_qp(
if (ret) { if (ret) {
ehca_err(pd->device, ehca_err(pd->device,
"Couldn't assign qp to send_cq ret=%i", ret); "Couldn't assign qp to send_cq ret=%i", ret);
goto create_qp_exit5; goto create_qp_exit6;
} }
} }
...@@ -815,22 +825,26 @@ static struct ehca_qp *internal_create_qp( ...@@ -815,22 +825,26 @@ static struct ehca_qp *internal_create_qp(
if (ib_copy_to_udata(udata, &resp, sizeof resp)) { if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
ehca_err(pd->device, "Copy to udata failed"); ehca_err(pd->device, "Copy to udata failed");
ret = -EINVAL; ret = -EINVAL;
goto create_qp_exit6; goto create_qp_exit7;
} }
} }
return my_qp; return my_qp;
create_qp_exit6: create_qp_exit7:
ehca_cq_unassign_qp(my_qp->send_cq, my_qp->real_qp_num); ehca_cq_unassign_qp(my_qp->send_cq, my_qp->real_qp_num);
create_qp_exit5: create_qp_exit6:
kfree(my_qp->mod_qp_parm); kfree(my_qp->mod_qp_parm);
create_qp_exit4: create_qp_exit5:
if (HAS_RQ(my_qp)) if (HAS_RQ(my_qp))
ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
create_qp_exit4:
if (HAS_SQ(my_qp))
vfree(my_qp->sq_map);
create_qp_exit3: create_qp_exit3:
if (HAS_SQ(my_qp)) if (HAS_SQ(my_qp))
ipz_queue_dtor(my_pd, &my_qp->ipz_squeue); ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
...@@ -1534,8 +1548,6 @@ static int internal_modify_qp(struct ib_qp *ibqp, ...@@ -1534,8 +1548,6 @@ static int internal_modify_qp(struct ib_qp *ibqp,
if (attr_mask & IB_QP_QKEY) if (attr_mask & IB_QP_QKEY)
my_qp->qkey = attr->qkey; my_qp->qkey = attr->qkey;
my_qp->state = qp_new_state;
modify_qp_exit2: modify_qp_exit2:
if (squeue_locked) { /* this means: sqe -> rts */ if (squeue_locked) { /* this means: sqe -> rts */
spin_unlock_irqrestore(&my_qp->spinlock_s, flags); spin_unlock_irqrestore(&my_qp->spinlock_s, flags);
...@@ -1551,6 +1563,8 @@ static int internal_modify_qp(struct ib_qp *ibqp, ...@@ -1551,6 +1563,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
struct ib_udata *udata) struct ib_udata *udata)
{ {
int ret = 0;
struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca, struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca,
ib_device); ib_device);
struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp); struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
...@@ -1597,12 +1611,18 @@ int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, ...@@ -1597,12 +1611,18 @@ int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
attr->qp_state, my_qp->init_attr.port_num, attr->qp_state, my_qp->init_attr.port_num,
ibqp->qp_type); ibqp->qp_type);
spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
return 0; goto out;
} }
spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
} }
return internal_modify_qp(ibqp, attr, attr_mask, 0); ret = internal_modify_qp(ibqp, attr, attr_mask, 0);
out:
if ((ret == 0) && (attr_mask & IB_QP_STATE))
my_qp->state = attr->qp_state;
return ret;
} }
void ehca_recover_sqp(struct ib_qp *sqp) void ehca_recover_sqp(struct ib_qp *sqp)
...@@ -1973,8 +1993,10 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, ...@@ -1973,8 +1993,10 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
if (HAS_RQ(my_qp)) if (HAS_RQ(my_qp))
ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
if (HAS_SQ(my_qp)) if (HAS_SQ(my_qp)) {
ipz_queue_dtor(my_pd, &my_qp->ipz_squeue); ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
vfree(my_qp->sq_map);
}
kmem_cache_free(qp_cache, my_qp); kmem_cache_free(qp_cache, my_qp);
atomic_dec(&shca->num_qps); atomic_dec(&shca->num_qps);
return 0; return 0;
......
...@@ -139,6 +139,7 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr) ...@@ -139,6 +139,7 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
static inline int ehca_write_swqe(struct ehca_qp *qp, static inline int ehca_write_swqe(struct ehca_qp *qp,
struct ehca_wqe *wqe_p, struct ehca_wqe *wqe_p,
const struct ib_send_wr *send_wr, const struct ib_send_wr *send_wr,
u32 sq_map_idx,
int hidden) int hidden)
{ {
u32 idx; u32 idx;
...@@ -157,7 +158,11 @@ static inline int ehca_write_swqe(struct ehca_qp *qp, ...@@ -157,7 +158,11 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
/* clear wqe header until sglist */ /* clear wqe header until sglist */
memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list)); memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list));
wqe_p->work_request_id = send_wr->wr_id; wqe_p->work_request_id = send_wr->wr_id & ~QMAP_IDX_MASK;
wqe_p->work_request_id |= sq_map_idx & QMAP_IDX_MASK;
qp->sq_map[sq_map_idx].app_wr_id = send_wr->wr_id & QMAP_IDX_MASK;
qp->sq_map[sq_map_idx].reported = 0;
switch (send_wr->opcode) { switch (send_wr->opcode) {
case IB_WR_SEND: case IB_WR_SEND:
...@@ -381,6 +386,7 @@ static inline int post_one_send(struct ehca_qp *my_qp, ...@@ -381,6 +386,7 @@ static inline int post_one_send(struct ehca_qp *my_qp,
{ {
struct ehca_wqe *wqe_p; struct ehca_wqe *wqe_p;
int ret; int ret;
u32 sq_map_idx;
u64 start_offset = my_qp->ipz_squeue.current_q_offset; u64 start_offset = my_qp->ipz_squeue.current_q_offset;
/* get pointer next to free WQE */ /* get pointer next to free WQE */
...@@ -393,8 +399,15 @@ static inline int post_one_send(struct ehca_qp *my_qp, ...@@ -393,8 +399,15 @@ static inline int post_one_send(struct ehca_qp *my_qp,
"qp_num=%x", my_qp->ib_qp.qp_num); "qp_num=%x", my_qp->ib_qp.qp_num);
return -ENOMEM; return -ENOMEM;
} }
/*
* Get the index of the WQE in the send queue. The same index is used
* for writing into the sq_map.
*/
sq_map_idx = start_offset / my_qp->ipz_squeue.qe_size;
/* write a SEND WQE into the QUEUE */ /* write a SEND WQE into the QUEUE */
ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr, hidden); ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr, sq_map_idx, hidden);
/* /*
* if something failed, * if something failed,
* reset the free entry pointer to the start value * reset the free entry pointer to the start value
...@@ -589,7 +602,7 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc) ...@@ -589,7 +602,7 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
struct ehca_qp *my_qp; struct ehca_qp *my_qp;
int cqe_count = 0, is_error; int cqe_count = 0, is_error;
poll_cq_one_read_cqe: repoll:
cqe = (struct ehca_cqe *) cqe = (struct ehca_cqe *)
ipz_qeit_get_inc_valid(&my_cq->ipz_queue); ipz_qeit_get_inc_valid(&my_cq->ipz_queue);
if (!cqe) { if (!cqe) {
...@@ -617,7 +630,7 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc) ...@@ -617,7 +630,7 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
ehca_dmp(cqe, 64, "cq_num=%x qp_num=%x", ehca_dmp(cqe, 64, "cq_num=%x qp_num=%x",
my_cq->cq_number, cqe->local_qp_number); my_cq->cq_number, cqe->local_qp_number);
/* ignore this purged cqe */ /* ignore this purged cqe */
goto poll_cq_one_read_cqe; goto repoll;
} }
spin_lock_irqsave(&qp->spinlock_s, flags); spin_lock_irqsave(&qp->spinlock_s, flags);
purgeflag = qp->sqerr_purgeflag; purgeflag = qp->sqerr_purgeflag;
...@@ -636,7 +649,7 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc) ...@@ -636,7 +649,7 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
* that caused sqe and turn off purge flag * that caused sqe and turn off purge flag
*/ */
qp->sqerr_purgeflag = 0; qp->sqerr_purgeflag = 0;
goto poll_cq_one_read_cqe; goto repoll;
} }
} }
...@@ -654,8 +667,34 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc) ...@@ -654,8 +667,34 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
my_cq, my_cq->cq_number); my_cq, my_cq->cq_number);
} }
/* we got a completion! */ read_lock(&ehca_qp_idr_lock);
wc->wr_id = cqe->work_request_id; my_qp = idr_find(&ehca_qp_idr, cqe->qp_token);
read_unlock(&ehca_qp_idr_lock);
if (!my_qp)
goto repoll;
wc->qp = &my_qp->ib_qp;
if (!(cqe->w_completion_flags & WC_SEND_RECEIVE_BIT)) {
struct ehca_qmap_entry *qmap_entry;
/*
* We got a send completion and need to restore the original
* wr_id.
*/
qmap_entry = &my_qp->sq_map[cqe->work_request_id &
QMAP_IDX_MASK];
if (qmap_entry->reported) {
ehca_warn(cq->device, "Double cqe on qp_num=%#x",
my_qp->real_qp_num);
/* found a double cqe, discard it and read next one */
goto repoll;
}
wc->wr_id = cqe->work_request_id & ~QMAP_IDX_MASK;
wc->wr_id |= qmap_entry->app_wr_id;
qmap_entry->reported = 1;
} else
/* We got a receive completion. */
wc->wr_id = cqe->work_request_id;
/* eval ib_wc_opcode */ /* eval ib_wc_opcode */
wc->opcode = ib_wc_opcode[cqe->optype]-1; wc->opcode = ib_wc_opcode[cqe->optype]-1;
...@@ -667,7 +706,7 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc) ...@@ -667,7 +706,7 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
ehca_dmp(cqe, 64, "ehca_cq=%p cq_num=%x", ehca_dmp(cqe, 64, "ehca_cq=%p cq_num=%x",
my_cq, my_cq->cq_number); my_cq, my_cq->cq_number);
/* update also queue adder to throw away this entry!!! */ /* update also queue adder to throw away this entry!!! */
goto poll_cq_one_exit0; goto repoll;
} }
/* eval ib_wc_status */ /* eval ib_wc_status */
...@@ -678,11 +717,6 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc) ...@@ -678,11 +717,6 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
} else } else
wc->status = IB_WC_SUCCESS; wc->status = IB_WC_SUCCESS;
read_lock(&ehca_qp_idr_lock);
my_qp = idr_find(&ehca_qp_idr, cqe->qp_token);
wc->qp = &my_qp->ib_qp;
read_unlock(&ehca_qp_idr_lock);
wc->byte_len = cqe->nr_bytes_transferred; wc->byte_len = cqe->nr_bytes_transferred;
wc->pkey_index = cqe->pkey_index; wc->pkey_index = cqe->pkey_index;
wc->slid = cqe->rlid; wc->slid = cqe->rlid;
......
...@@ -202,7 +202,7 @@ static void ipoib_cm_free_rx_ring(struct net_device *dev, ...@@ -202,7 +202,7 @@ static void ipoib_cm_free_rx_ring(struct net_device *dev,
dev_kfree_skb_any(rx_ring[i].skb); dev_kfree_skb_any(rx_ring[i].skb);
} }
kfree(rx_ring); vfree(rx_ring);
} }
static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv *priv) static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv *priv)
...@@ -352,9 +352,14 @@ static int ipoib_cm_nonsrq_init_rx(struct net_device *dev, struct ib_cm_id *cm_i ...@@ -352,9 +352,14 @@ static int ipoib_cm_nonsrq_init_rx(struct net_device *dev, struct ib_cm_id *cm_i
int ret; int ret;
int i; int i;
rx->rx_ring = kcalloc(ipoib_recvq_size, sizeof *rx->rx_ring, GFP_KERNEL); rx->rx_ring = vmalloc(ipoib_recvq_size * sizeof *rx->rx_ring);
if (!rx->rx_ring) if (!rx->rx_ring) {
printk(KERN_WARNING "%s: failed to allocate CM non-SRQ ring (%d entries)\n",
priv->ca->name, ipoib_recvq_size);
return -ENOMEM; return -ENOMEM;
}
memset(rx->rx_ring, 0, ipoib_recvq_size * sizeof *rx->rx_ring);
t = kmalloc(sizeof *t, GFP_KERNEL); t = kmalloc(sizeof *t, GFP_KERNEL);
if (!t) { if (!t) {
...@@ -1494,14 +1499,16 @@ static void ipoib_cm_create_srq(struct net_device *dev, int max_sge) ...@@ -1494,14 +1499,16 @@ static void ipoib_cm_create_srq(struct net_device *dev, int max_sge)
return; return;
} }
priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring, priv->cm.srq_ring = vmalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring);
GFP_KERNEL);
if (!priv->cm.srq_ring) { if (!priv->cm.srq_ring) {
printk(KERN_WARNING "%s: failed to allocate CM SRQ ring (%d entries)\n", printk(KERN_WARNING "%s: failed to allocate CM SRQ ring (%d entries)\n",
priv->ca->name, ipoib_recvq_size); priv->ca->name, ipoib_recvq_size);
ib_destroy_srq(priv->cm.srq); ib_destroy_srq(priv->cm.srq);
priv->cm.srq = NULL; priv->cm.srq = NULL;
return;
} }
memset(priv->cm.srq_ring, 0, ipoib_recvq_size * sizeof *priv->cm.srq_ring);
} }
int ipoib_cm_dev_init(struct net_device *dev) int ipoib_cm_dev_init(struct net_device *dev)
......
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