From 03141e6041e9619bc39e74feb7c979a68aa6fb75 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 10 Jul 2014 12:29:14 +0300 Subject: [PATCH] mlx4_ib: Fix endianness in blueflame post_send. qp object field doorbell_qpn was initialized using swab() at qp creation. swab() unconditionally swaps dword endianness. Thus, on little-endian platforms the endianness of doorbell_qpn was big endian; on big-endian platforms, doorbell_qpn is little-endian. In post send blueflame, doorbell_qpn was taken as is (i.e., the driver assumed that it was in big-endian format). This was OK for little-endian hosts, but incorrect for big-endian hosts. The fix is to use cpu_to_be32 when initializing doorbell_qpn (thus guaranteeing that doorbell_qpn is in big-endian format on all host types). This also requires modifying non-bf sends to use __raw_writel (which does not do any endianness swapping) instead of writel (which does endianness swapping on big-endian hosts). The fix was developed by Shamir Rabinovitch of Oracle. Signed-off-by: Jack Morgenstein (Ported by Mellanox OFED 2.4) Signed-off-by: Mukesh Kacker --- drivers/infiniband/hw/mlx4/mlx4_ib.h | 2 +- drivers/infiniband/hw/mlx4/qp.c | 7 ++++--- drivers/net/ethernet/mellanox/mlx4_vnic/vnic_qp.c | 7 ++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 86046705d2c5..1d19744333eb 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -279,7 +279,7 @@ struct mlx4_ib_qp { struct mlx4_db db; struct mlx4_ib_wq rq; - u32 doorbell_qpn; + __be32 doorbell_qpn; __be32 sq_signal_bits; unsigned sq_next_wqe; int sq_max_wqes_per_wr; diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index a00000bcd1cf..84df3d8c9355 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -861,7 +861,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, * shifting) for send doorbell. Precompute this value to save * a little bit when posting sends. */ - qp->doorbell_qpn = swab32(qp->mqp.qpn << 8); + qp->doorbell_qpn = cpu_to_be32((u32)qp->mqp.qpn << 8); qp->mqp.event = mlx4_ib_qp_event; if (!*caller_qp) @@ -3053,7 +3053,7 @@ out: /* We set above doorbell_qpn bits to 0 as part of vlan * tag initialization, so |= should be correct. */ - *(u32 *) (&ctrl->vlan_tag) |= qp->doorbell_qpn; + *(__be32 *)(&ctrl->vlan_tag) |= qp->doorbell_qpn; /* * Make sure that descriptor is written to memory * before writing to BlueFlame page. @@ -3077,7 +3077,8 @@ out: */ wmb(); - writel(qp->doorbell_qpn, qp->bf.uar->map + MLX4_SEND_DOORBELL); + __raw_writel((__force u32)qp->doorbell_qpn, + qp->bf.uar->map + MLX4_SEND_DOORBELL); /* * Make sure doorbells don't leak out of SQ spinlock diff --git a/drivers/net/ethernet/mellanox/mlx4_vnic/vnic_qp.c b/drivers/net/ethernet/mellanox/mlx4_vnic/vnic_qp.c index b4884b8b3e47..f70000047765 100644 --- a/drivers/net/ethernet/mellanox/mlx4_vnic/vnic_qp.c +++ b/drivers/net/ethernet/mellanox/mlx4_vnic/vnic_qp.c @@ -630,7 +630,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, * shifting) for send doorbell. Precompute this value to save * a little bit when posting sends. */ - qp->doorbell_qpn = swab32(qp->mqp.qpn << 8); + qp->doorbell_qpn = cpu_to_be32((u32)qp->mqp.qpn << 8); qp->mqp.event = mlx4_ib_qp_event; @@ -1489,7 +1489,7 @@ int vnic_ib_post_send(struct ib_qp *ibqp, out: if (nreq == 1 && inl && size > 1 && size < qp->bf.buf_size / 16) { ctrl->owner_opcode |= htonl((qp->sq_next_wqe & 0xffff) << 8); - *(u32 *) (&ctrl->vlan_tag) |= qp->doorbell_qpn; + *(__be32 *)(&ctrl->vlan_tag) |= qp->doorbell_qpn; /* * Make sure that descriptor is written to memory * before writing to BlueFlame page. @@ -1513,7 +1513,8 @@ out: */ wmb(); - writel(qp->doorbell_qpn, qp->bf.uar->map + MLX4_SEND_DOORBELL); + __raw_writel((__force u32)qp->doorbell_qpn, + qp->bf.uar->map + MLX4_SEND_DOORBELL); /* * Make sure doorbells don't leak out of SQ spinlock -- 2.50.1