Commit 8aee74c8 authored by Linus Torvalds's avatar Linus Torvalds

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

* 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband:
  IB/cm: Improve local id allocation
  IPoIB/cm: Fix SRQ WR leak
  IB/ipoib: Fix typos in error messages
  IB/mlx4: Check if SRQ is full when posting receive
  IB/mlx4: Pass send queue sizes from userspace to kernel
  IB/mlx4: Fix check of opcode in mlx4_ib_post_send()
  mlx4_core: Fix array overrun in dump_dev_cap_flags()
  IB/mlx4: Fix RESET to RESET and RESET to ERROR transitions
  IB/mthca: Fix RESET to ERROR transition
  IB/mlx4: Set GRH:HopLimit when sending globally routed MADs
  IB/mthca: Set GRH:HopLimit when building MLX headers
  IB/mlx4: Fix check of max_qp_dest_rdma in modify QP
  IB/mthca: Fix use-after-free on device restart
  IB/ehca: Return proper error code if register_mr fails
  IPoIB: Handle P_Key table reordering
  IB/core: Use start_port() and end_port()
  IB/core: Add helpers for uncached GID and P_Key searches
  IB/ipath: Fix potential deadlock with multicast spinlocks
  IB/core: Free umem when mm is already gone
parents 080e8927 9f81036c
...@@ -306,7 +306,9 @@ static int cm_alloc_id(struct cm_id_private *cm_id_priv) ...@@ -306,7 +306,9 @@ static int cm_alloc_id(struct cm_id_private *cm_id_priv)
do { do {
spin_lock_irqsave(&cm.lock, flags); spin_lock_irqsave(&cm.lock, flags);
ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, ret = idr_get_new_above(&cm.local_id_table, cm_id_priv,
next_id++, &id); next_id, &id);
if (!ret)
next_id = ((unsigned) id + 1) & MAX_ID_MASK;
spin_unlock_irqrestore(&cm.lock, flags); spin_unlock_irqrestore(&cm.lock, flags);
} while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) ); } while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) );
......
...@@ -150,6 +150,18 @@ static int alloc_name(char *name) ...@@ -150,6 +150,18 @@ static int alloc_name(char *name)
return 0; return 0;
} }
static int start_port(struct ib_device *device)
{
return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1;
}
static int end_port(struct ib_device *device)
{
return (device->node_type == RDMA_NODE_IB_SWITCH) ?
0 : device->phys_port_cnt;
}
/** /**
* ib_alloc_device - allocate an IB device struct * ib_alloc_device - allocate an IB device struct
* @size:size of structure to allocate * @size:size of structure to allocate
...@@ -209,6 +221,45 @@ static int add_client_context(struct ib_device *device, struct ib_client *client ...@@ -209,6 +221,45 @@ static int add_client_context(struct ib_device *device, struct ib_client *client
return 0; return 0;
} }
static int read_port_table_lengths(struct ib_device *device)
{
struct ib_port_attr *tprops = NULL;
int num_ports, ret = -ENOMEM;
u8 port_index;
tprops = kmalloc(sizeof *tprops, GFP_KERNEL);
if (!tprops)
goto out;
num_ports = end_port(device) - start_port(device) + 1;
device->pkey_tbl_len = kmalloc(sizeof *device->pkey_tbl_len * num_ports,
GFP_KERNEL);
device->gid_tbl_len = kmalloc(sizeof *device->gid_tbl_len * num_ports,
GFP_KERNEL);
if (!device->pkey_tbl_len || !device->gid_tbl_len)
goto err;
for (port_index = 0; port_index < num_ports; ++port_index) {
ret = ib_query_port(device, port_index + start_port(device),
tprops);
if (ret)
goto err;
device->pkey_tbl_len[port_index] = tprops->pkey_tbl_len;
device->gid_tbl_len[port_index] = tprops->gid_tbl_len;
}
ret = 0;
goto out;
err:
kfree(device->gid_tbl_len);
kfree(device->pkey_tbl_len);
out:
kfree(tprops);
return ret;
}
/** /**
* ib_register_device - Register an IB device with IB core * ib_register_device - Register an IB device with IB core
* @device:Device to register * @device:Device to register
...@@ -240,10 +291,19 @@ int ib_register_device(struct ib_device *device) ...@@ -240,10 +291,19 @@ int ib_register_device(struct ib_device *device)
spin_lock_init(&device->event_handler_lock); spin_lock_init(&device->event_handler_lock);
spin_lock_init(&device->client_data_lock); spin_lock_init(&device->client_data_lock);
ret = read_port_table_lengths(device);
if (ret) {
printk(KERN_WARNING "Couldn't create table lengths cache for device %s\n",
device->name);
goto out;
}
ret = ib_device_register_sysfs(device); ret = ib_device_register_sysfs(device);
if (ret) { if (ret) {
printk(KERN_WARNING "Couldn't register device %s with driver model\n", printk(KERN_WARNING "Couldn't register device %s with driver model\n",
device->name); device->name);
kfree(device->gid_tbl_len);
kfree(device->pkey_tbl_len);
goto out; goto out;
} }
...@@ -285,6 +345,9 @@ void ib_unregister_device(struct ib_device *device) ...@@ -285,6 +345,9 @@ void ib_unregister_device(struct ib_device *device)
list_del(&device->core_list); list_del(&device->core_list);
kfree(device->gid_tbl_len);
kfree(device->pkey_tbl_len);
mutex_unlock(&device_mutex); mutex_unlock(&device_mutex);
spin_lock_irqsave(&device->client_data_lock, flags); spin_lock_irqsave(&device->client_data_lock, flags);
...@@ -507,10 +570,7 @@ int ib_query_port(struct ib_device *device, ...@@ -507,10 +570,7 @@ int ib_query_port(struct ib_device *device,
u8 port_num, u8 port_num,
struct ib_port_attr *port_attr) struct ib_port_attr *port_attr)
{ {
if (device->node_type == RDMA_NODE_IB_SWITCH) { if (port_num < start_port(device) || port_num > end_port(device))
if (port_num)
return -EINVAL;
} else if (port_num < 1 || port_num > device->phys_port_cnt)
return -EINVAL; return -EINVAL;
return device->query_port(device, port_num, port_attr); return device->query_port(device, port_num, port_attr);
...@@ -582,10 +642,7 @@ int ib_modify_port(struct ib_device *device, ...@@ -582,10 +642,7 @@ int ib_modify_port(struct ib_device *device,
u8 port_num, int port_modify_mask, u8 port_num, int port_modify_mask,
struct ib_port_modify *port_modify) struct ib_port_modify *port_modify)
{ {
if (device->node_type == RDMA_NODE_IB_SWITCH) { if (port_num < start_port(device) || port_num > end_port(device))
if (port_num)
return -EINVAL;
} else if (port_num < 1 || port_num > device->phys_port_cnt)
return -EINVAL; return -EINVAL;
return device->modify_port(device, port_num, port_modify_mask, return device->modify_port(device, port_num, port_modify_mask,
...@@ -593,6 +650,68 @@ int ib_modify_port(struct ib_device *device, ...@@ -593,6 +650,68 @@ int ib_modify_port(struct ib_device *device,
} }
EXPORT_SYMBOL(ib_modify_port); EXPORT_SYMBOL(ib_modify_port);
/**
* ib_find_gid - Returns the port number and GID table index where
* a specified GID value occurs.
* @device: The device to query.
* @gid: The GID value to search for.
* @port_num: The port number of the device where the GID value was found.
* @index: The index into the GID table where the GID was found. This
* parameter may be NULL.
*/
int ib_find_gid(struct ib_device *device, union ib_gid *gid,
u8 *port_num, u16 *index)
{
union ib_gid tmp_gid;
int ret, port, i;
for (port = start_port(device); port <= end_port(device); ++port) {
for (i = 0; i < device->gid_tbl_len[port - start_port(device)]; ++i) {
ret = ib_query_gid(device, port, i, &tmp_gid);
if (ret)
return ret;
if (!memcmp(&tmp_gid, gid, sizeof *gid)) {
*port_num = port;
if (index)
*index = i;
return 0;
}
}
}
return -ENOENT;
}
EXPORT_SYMBOL(ib_find_gid);
/**
* ib_find_pkey - Returns the PKey table index where a specified
* PKey value occurs.
* @device: The device to query.
* @port_num: The port number of the device to search for the PKey.
* @pkey: The PKey value to search for.
* @index: The index into the PKey table where the PKey was found.
*/
int ib_find_pkey(struct ib_device *device,
u8 port_num, u16 pkey, u16 *index)
{
int ret, i;
u16 tmp_pkey;
for (i = 0; i < device->pkey_tbl_len[port_num - start_port(device)]; ++i) {
ret = ib_query_pkey(device, port_num, i, &tmp_pkey);
if (ret)
return ret;
if (pkey == tmp_pkey) {
*index = i;
return 0;
}
}
return -ENOENT;
}
EXPORT_SYMBOL(ib_find_pkey);
static int __init ib_core_init(void) static int __init ib_core_init(void)
{ {
int ret; int ret;
......
...@@ -210,8 +210,10 @@ void ib_umem_release(struct ib_umem *umem) ...@@ -210,8 +210,10 @@ void ib_umem_release(struct ib_umem *umem)
__ib_umem_release(umem->context->device, umem, 1); __ib_umem_release(umem->context->device, umem, 1);
mm = get_task_mm(current); mm = get_task_mm(current);
if (!mm) if (!mm) {
kfree(umem);
return; return;
}
diff = PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT; diff = PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT;
......
...@@ -2050,13 +2050,10 @@ int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc) ...@@ -2050,13 +2050,10 @@ int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc)
switch (hipz_rc) { switch (hipz_rc) {
case H_SUCCESS: /* successful completion */ case H_SUCCESS: /* successful completion */
return 0; return 0;
case H_ADAPTER_PARM: /* invalid adapter handle */
case H_RT_PARM: /* invalid resource type */
case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */ case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
case H_MLENGTH_PARM: /* invalid memory length */
case H_MEM_ACCESS_PARM: /* invalid access controls */
case H_CONSTRAINED: /* resource constraint */ case H_CONSTRAINED: /* resource constraint */
return -EINVAL; case H_NO_MEM:
return -ENOMEM;
case H_BUSY: /* long busy */ case H_BUSY: /* long busy */
return -EBUSY; return -EBUSY;
default: default:
......
...@@ -165,10 +165,9 @@ static int ipath_mcast_add(struct ipath_ibdev *dev, ...@@ -165,10 +165,9 @@ static int ipath_mcast_add(struct ipath_ibdev *dev,
{ {
struct rb_node **n = &mcast_tree.rb_node; struct rb_node **n = &mcast_tree.rb_node;
struct rb_node *pn = NULL; struct rb_node *pn = NULL;
unsigned long flags;
int ret; int ret;
spin_lock_irqsave(&mcast_lock, flags); spin_lock_irq(&mcast_lock);
while (*n) { while (*n) {
struct ipath_mcast *tmcast; struct ipath_mcast *tmcast;
...@@ -228,7 +227,7 @@ static int ipath_mcast_add(struct ipath_ibdev *dev, ...@@ -228,7 +227,7 @@ static int ipath_mcast_add(struct ipath_ibdev *dev,
ret = 0; ret = 0;
bail: bail:
spin_unlock_irqrestore(&mcast_lock, flags); spin_unlock_irq(&mcast_lock);
return ret; return ret;
} }
...@@ -289,17 +288,16 @@ int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) ...@@ -289,17 +288,16 @@ int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
struct ipath_mcast *mcast = NULL; struct ipath_mcast *mcast = NULL;
struct ipath_mcast_qp *p, *tmp; struct ipath_mcast_qp *p, *tmp;
struct rb_node *n; struct rb_node *n;
unsigned long flags;
int last = 0; int last = 0;
int ret; int ret;
spin_lock_irqsave(&mcast_lock, flags); spin_lock_irq(&mcast_lock);
/* Find the GID in the mcast table. */ /* Find the GID in the mcast table. */
n = mcast_tree.rb_node; n = mcast_tree.rb_node;
while (1) { while (1) {
if (n == NULL) { if (n == NULL) {
spin_unlock_irqrestore(&mcast_lock, flags); spin_unlock_irq(&mcast_lock);
ret = -EINVAL; ret = -EINVAL;
goto bail; goto bail;
} }
...@@ -334,7 +332,7 @@ int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) ...@@ -334,7 +332,7 @@ int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
break; break;
} }
spin_unlock_irqrestore(&mcast_lock, flags); spin_unlock_irq(&mcast_lock);
if (p) { if (p) {
/* /*
...@@ -348,9 +346,9 @@ int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) ...@@ -348,9 +346,9 @@ int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
atomic_dec(&mcast->refcount); atomic_dec(&mcast->refcount);
wait_event(mcast->wait, !atomic_read(&mcast->refcount)); wait_event(mcast->wait, !atomic_read(&mcast->refcount));
ipath_mcast_free(mcast); ipath_mcast_free(mcast);
spin_lock(&dev->n_mcast_grps_lock); spin_lock_irq(&dev->n_mcast_grps_lock);
dev->n_mcast_grps_allocated--; dev->n_mcast_grps_allocated--;
spin_unlock(&dev->n_mcast_grps_lock); spin_unlock_irq(&dev->n_mcast_grps_lock);
} }
ret = 0; ret = 0;
......
...@@ -188,14 +188,32 @@ static int send_wqe_overhead(enum ib_qp_type type) ...@@ -188,14 +188,32 @@ static int send_wqe_overhead(enum ib_qp_type type)
} }
} }
static int set_qp_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, static int set_rq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
struct mlx4_ib_qp *qp)
{
/* Sanity check RQ size before proceeding */
if (cap->max_recv_wr > dev->dev->caps.max_wqes ||
cap->max_recv_sge > dev->dev->caps.max_rq_sg)
return -EINVAL;
qp->rq.max = cap->max_recv_wr ? roundup_pow_of_two(cap->max_recv_wr) : 0;
qp->rq.wqe_shift = ilog2(roundup_pow_of_two(cap->max_recv_sge *
sizeof (struct mlx4_wqe_data_seg)));
qp->rq.max_gs = (1 << qp->rq.wqe_shift) / sizeof (struct mlx4_wqe_data_seg);
cap->max_recv_wr = qp->rq.max;
cap->max_recv_sge = qp->rq.max_gs;
return 0;
}
static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
enum ib_qp_type type, struct mlx4_ib_qp *qp) enum ib_qp_type type, struct mlx4_ib_qp *qp)
{ {
/* Sanity check QP size before proceeding */ /* Sanity check SQ size before proceeding */
if (cap->max_send_wr > dev->dev->caps.max_wqes || if (cap->max_send_wr > dev->dev->caps.max_wqes ||
cap->max_recv_wr > dev->dev->caps.max_wqes ||
cap->max_send_sge > dev->dev->caps.max_sq_sg || cap->max_send_sge > dev->dev->caps.max_sq_sg ||
cap->max_recv_sge > dev->dev->caps.max_rq_sg ||
cap->max_inline_data + send_wqe_overhead(type) + cap->max_inline_data + send_wqe_overhead(type) +
sizeof (struct mlx4_wqe_inline_seg) > dev->dev->caps.max_sq_desc_sz) sizeof (struct mlx4_wqe_inline_seg) > dev->dev->caps.max_sq_desc_sz)
return -EINVAL; return -EINVAL;
...@@ -208,12 +226,7 @@ static int set_qp_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, ...@@ -208,12 +226,7 @@ static int set_qp_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
cap->max_send_sge + 2 > dev->dev->caps.max_sq_sg) cap->max_send_sge + 2 > dev->dev->caps.max_sq_sg)
return -EINVAL; return -EINVAL;
qp->rq.max = cap->max_recv_wr ? roundup_pow_of_two(cap->max_recv_wr) : 0; qp->sq.max = cap->max_send_wr ? roundup_pow_of_two(cap->max_send_wr) : 1;
qp->sq.max = cap->max_send_wr ? roundup_pow_of_two(cap->max_send_wr) : 0;
qp->rq.wqe_shift = ilog2(roundup_pow_of_two(cap->max_recv_sge *
sizeof (struct mlx4_wqe_data_seg)));
qp->rq.max_gs = (1 << qp->rq.wqe_shift) / sizeof (struct mlx4_wqe_data_seg);
qp->sq.wqe_shift = ilog2(roundup_pow_of_two(max(cap->max_send_sge * qp->sq.wqe_shift = ilog2(roundup_pow_of_two(max(cap->max_send_sge *
sizeof (struct mlx4_wqe_data_seg), sizeof (struct mlx4_wqe_data_seg),
...@@ -234,15 +247,25 @@ static int set_qp_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, ...@@ -234,15 +247,25 @@ static int set_qp_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
} }
cap->max_send_wr = qp->sq.max; cap->max_send_wr = qp->sq.max;
cap->max_recv_wr = qp->rq.max;
cap->max_send_sge = qp->sq.max_gs; cap->max_send_sge = qp->sq.max_gs;
cap->max_recv_sge = qp->rq.max_gs;
cap->max_inline_data = (1 << qp->sq.wqe_shift) - send_wqe_overhead(type) - cap->max_inline_data = (1 << qp->sq.wqe_shift) - send_wqe_overhead(type) -
sizeof (struct mlx4_wqe_inline_seg); sizeof (struct mlx4_wqe_inline_seg);
return 0; return 0;
} }
static int set_user_sq_size(struct mlx4_ib_qp *qp,
struct mlx4_ib_create_qp *ucmd)
{
qp->sq.max = 1 << ucmd->log_sq_bb_count;
qp->sq.wqe_shift = ucmd->log_sq_stride;
qp->buf_size = (qp->rq.max << qp->rq.wqe_shift) +
(qp->sq.max << qp->sq.wqe_shift);
return 0;
}
static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
struct ib_qp_init_attr *init_attr, struct ib_qp_init_attr *init_attr,
struct ib_udata *udata, int sqpn, struct mlx4_ib_qp *qp) struct ib_udata *udata, int sqpn, struct mlx4_ib_qp *qp)
...@@ -264,7 +287,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, ...@@ -264,7 +287,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
qp->sq.head = 0; qp->sq.head = 0;
qp->sq.tail = 0; qp->sq.tail = 0;
err = set_qp_size(dev, &init_attr->cap, init_attr->qp_type, qp); err = set_rq_size(dev, &init_attr->cap, qp);
if (err) if (err)
goto err; goto err;
...@@ -276,6 +299,10 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, ...@@ -276,6 +299,10 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
goto err; goto err;
} }
err = set_user_sq_size(qp, &ucmd);
if (err)
goto err;
qp->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, qp->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr,
qp->buf_size, 0); qp->buf_size, 0);
if (IS_ERR(qp->umem)) { if (IS_ERR(qp->umem)) {
...@@ -297,6 +324,10 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, ...@@ -297,6 +324,10 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
if (err) if (err)
goto err_mtt; goto err_mtt;
} else { } else {
err = set_kernel_sq_size(dev, &init_attr->cap, init_attr->qp_type, qp);
if (err)
goto err;
err = mlx4_ib_db_alloc(dev, &qp->db, 0); err = mlx4_ib_db_alloc(dev, &qp->db, 0);
if (err) if (err)
goto err; goto err;
...@@ -573,7 +604,7 @@ static int to_mlx4_st(enum ib_qp_type type) ...@@ -573,7 +604,7 @@ static int to_mlx4_st(enum ib_qp_type type)
} }
} }
static __be32 to_mlx4_access_flags(struct mlx4_ib_qp *qp, struct ib_qp_attr *attr, static __be32 to_mlx4_access_flags(struct mlx4_ib_qp *qp, const struct ib_qp_attr *attr,
int attr_mask) int attr_mask)
{ {
u8 dest_rd_atomic; u8 dest_rd_atomic;
...@@ -603,7 +634,7 @@ static __be32 to_mlx4_access_flags(struct mlx4_ib_qp *qp, struct ib_qp_attr *att ...@@ -603,7 +634,7 @@ static __be32 to_mlx4_access_flags(struct mlx4_ib_qp *qp, struct ib_qp_attr *att
return cpu_to_be32(hw_access_flags); return cpu_to_be32(hw_access_flags);
} }
static void store_sqp_attrs(struct mlx4_ib_sqp *sqp, struct ib_qp_attr *attr, static void store_sqp_attrs(struct mlx4_ib_sqp *sqp, const struct ib_qp_attr *attr,
int attr_mask) int attr_mask)
{ {
if (attr_mask & IB_QP_PKEY_INDEX) if (attr_mask & IB_QP_PKEY_INDEX)
...@@ -619,7 +650,7 @@ static void mlx4_set_sched(struct mlx4_qp_path *path, u8 port) ...@@ -619,7 +650,7 @@ static void mlx4_set_sched(struct mlx4_qp_path *path, u8 port)
path->sched_queue = (path->sched_queue & 0xbf) | ((port - 1) << 6); path->sched_queue = (path->sched_queue & 0xbf) | ((port - 1) << 6);
} }
static int mlx4_set_path(struct mlx4_ib_dev *dev, struct ib_ah_attr *ah, static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah,
struct mlx4_qp_path *path, u8 port) struct mlx4_qp_path *path, u8 port)
{ {
path->grh_mylmc = ah->src_path_bits & 0x7f; path->grh_mylmc = ah->src_path_bits & 0x7f;
...@@ -655,14 +686,14 @@ static int mlx4_set_path(struct mlx4_ib_dev *dev, struct ib_ah_attr *ah, ...@@ -655,14 +686,14 @@ static int mlx4_set_path(struct mlx4_ib_dev *dev, struct ib_ah_attr *ah,
return 0; return 0;
} }
int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
int attr_mask, struct ib_udata *udata) const struct ib_qp_attr *attr, int attr_mask,
enum ib_qp_state cur_state, enum ib_qp_state new_state)
{ {
struct mlx4_ib_dev *dev = to_mdev(ibqp->device); struct mlx4_ib_dev *dev = to_mdev(ibqp->device);
struct mlx4_ib_qp *qp = to_mqp(ibqp); struct mlx4_ib_qp *qp = to_mqp(ibqp);
struct mlx4_qp_context *context; struct mlx4_qp_context *context;
enum mlx4_qp_optpar optpar = 0; enum mlx4_qp_optpar optpar = 0;
enum ib_qp_state cur_state, new_state;
int sqd_event; int sqd_event;
int err = -EINVAL; int err = -EINVAL;
...@@ -670,34 +701,6 @@ int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -670,34 +701,6 @@ int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
if (!context) if (!context)
return -ENOMEM; return -ENOMEM;
mutex_lock(&qp->mutex);
cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state;
new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask))
goto out;
if ((attr_mask & IB_QP_PKEY_INDEX) &&
attr->pkey_index >= dev->dev->caps.pkey_table_len) {
goto out;
}
if ((attr_mask & IB_QP_PORT) &&
(attr->port_num == 0 || attr->port_num > dev->dev->caps.num_ports)) {
goto out;
}
if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
attr->max_rd_atomic > dev->dev->caps.max_qp_init_rdma) {
goto out;
}
if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
attr->max_dest_rd_atomic > 1 << dev->dev->caps.max_qp_dest_rdma) {
goto out;
}
context->flags = cpu_to_be32((to_mlx4_state(new_state) << 28) | context->flags = cpu_to_be32((to_mlx4_state(new_state) << 28) |
(to_mlx4_st(ibqp->qp_type) << 16)); (to_mlx4_st(ibqp->qp_type) << 16));
context->flags |= cpu_to_be32(1 << 8); /* DE? */ context->flags |= cpu_to_be32(1 << 8); /* DE? */
...@@ -920,11 +923,84 @@ int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -920,11 +923,84 @@ int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
} }
out: out:
mutex_unlock(&qp->mutex);
kfree(context); kfree(context);
return err; return err;
} }
static const struct ib_qp_attr mlx4_ib_qp_attr = { .port_num = 1 };
static const int mlx4_ib_qp_attr_mask_table[IB_QPT_UD + 1] = {
[IB_QPT_UD] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_QKEY),
[IB_QPT_UC] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
[IB_QPT_RC] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
[IB_QPT_SMI] = (IB_QP_PKEY_INDEX |
IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_PKEY_INDEX |
IB_QP_QKEY),
};
int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int attr_mask, struct ib_udata *udata)
{
struct mlx4_ib_dev *dev = to_mdev(ibqp->device);
struct mlx4_ib_qp *qp = to_mqp(ibqp);
enum ib_qp_state cur_state, new_state;
int err = -EINVAL;
mutex_lock(&qp->mutex);
cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state;
new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask))
goto out;
if ((attr_mask & IB_QP_PKEY_INDEX) &&
attr->pkey_index >= dev->dev->caps.pkey_table_len) {
goto out;
}
if ((attr_mask & IB_QP_PORT) &&
(attr->port_num == 0 || attr->port_num > dev->dev->caps.num_ports)) {
goto out;
}
if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
attr->max_rd_atomic > dev->dev->caps.max_qp_init_rdma) {
goto out;
}
if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
attr->max_dest_rd_atomic > dev->dev->caps.max_qp_dest_rdma) {
goto out;
}
if (cur_state == new_state && cur_state == IB_QPS_RESET) {
err = 0;
goto out;
}
if (cur_state == IB_QPS_RESET && new_state == IB_QPS_ERR) {
err = __mlx4_ib_modify_qp(ibqp, &mlx4_ib_qp_attr,
mlx4_ib_qp_attr_mask_table[ibqp->qp_type],
IB_QPS_RESET, IB_QPS_INIT);
if (err)
goto out;
cur_state = IB_QPS_INIT;
}
err = __mlx4_ib_modify_qp(ibqp, attr, attr_mask, cur_state, new_state);
out:
mutex_unlock(&qp->mutex);
return err;
}
static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
void *wqe) void *wqe)
{ {
...@@ -952,6 +1028,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, ...@@ -952,6 +1028,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
(be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 20) & 0xff; (be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 20) & 0xff;
sqp->ud_header.grh.flow_label = sqp->ud_header.grh.flow_label =
ah->av.sl_tclass_flowlabel & cpu_to_be32(0xfffff); ah->av.sl_tclass_flowlabel & cpu_to_be32(0xfffff);
sqp->ud_header.grh.hop_limit = ah->av.hop_limit;
ib_get_cached_gid(ib_dev, be32_to_cpu(ah->av.port_pd) >> 24, ib_get_cached_gid(ib_dev, be32_to_cpu(ah->av.port_pd) >> 24,
ah->av.gid_index, &sqp->ud_header.grh.source_gid); ah->av.gid_index, &sqp->ud_header.grh.source_gid);
memcpy(sqp->ud_header.grh.destination_gid.raw, memcpy(sqp->ud_header.grh.destination_gid.raw,
...@@ -1192,7 +1269,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, ...@@ -1192,7 +1269,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
*/ */
wmb(); wmb();
if (wr->opcode < 0 || wr->opcode > ARRAY_SIZE(mlx4_ib_opcode)) { if (wr->opcode < 0 || wr->opcode >= ARRAY_SIZE(mlx4_ib_opcode)) {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
......
...@@ -297,6 +297,12 @@ int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, ...@@ -297,6 +297,12 @@ int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
break; break;
} }
if (unlikely(srq->head == srq->tail)) {
err = -ENOMEM;
*bad_wr = wr;
break;
}
srq->wrid[srq->head] = wr->wr_id; srq->wrid[srq->head] = wr->wr_id;
next = get_wqe(srq, srq->head); next = get_wqe(srq, srq->head);
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
* Increment this value if any changes that break userspace ABI * Increment this value if any changes that break userspace ABI
* compatibility are made. * compatibility are made.
*/ */
#define MLX4_IB_UVERBS_ABI_VERSION 1 #define MLX4_IB_UVERBS_ABI_VERSION 2
/* /*
* Make sure that all structs defined in this file remain laid out so * Make sure that all structs defined in this file remain laid out so
...@@ -87,6 +87,9 @@ struct mlx4_ib_create_srq_resp { ...@@ -87,6 +87,9 @@ struct mlx4_ib_create_srq_resp {
struct mlx4_ib_create_qp { struct mlx4_ib_create_qp {
__u64 buf_addr; __u64 buf_addr;
__u64 db_addr; __u64 db_addr;
__u8 log_sq_bb_count;
__u8 log_sq_stride;
__u8 reserved[6];
}; };
#endif /* MLX4_IB_USER_H */ #endif /* MLX4_IB_USER_H */
...@@ -279,6 +279,7 @@ int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah, ...@@ -279,6 +279,7 @@ int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
(be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20) & 0xff; (be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20) & 0xff;
header->grh.flow_label = header->grh.flow_label =
ah->av->sl_tclass_flowlabel & cpu_to_be32(0xfffff); ah->av->sl_tclass_flowlabel & cpu_to_be32(0xfffff);
header->grh.hop_limit = ah->av->hop_limit;
ib_get_cached_gid(&dev->ib_dev, ib_get_cached_gid(&dev->ib_dev,
be32_to_cpu(ah->av->port_pd) >> 24, be32_to_cpu(ah->av->port_pd) >> 24,
ah->av->gid_index % dev->limits.gid_table_len, ah->av->gid_index % dev->limits.gid_table_len,
......
...@@ -1250,12 +1250,14 @@ static void __mthca_remove_one(struct pci_dev *pdev) ...@@ -1250,12 +1250,14 @@ static void __mthca_remove_one(struct pci_dev *pdev)
int __mthca_restart_one(struct pci_dev *pdev) int __mthca_restart_one(struct pci_dev *pdev)
{ {
struct mthca_dev *mdev; struct mthca_dev *mdev;
int hca_type;
mdev = pci_get_drvdata(pdev); mdev = pci_get_drvdata(pdev);
if (!mdev) if (!mdev)
return -ENODEV; return -ENODEV;
hca_type = mdev->hca_type;
__mthca_remove_one(pdev); __mthca_remove_one(pdev);
return __mthca_init_one(pdev, mdev->hca_type); return __mthca_init_one(pdev, hca_type);
} }
static int __devinit mthca_init_one(struct pci_dev *pdev, static int __devinit mthca_init_one(struct pci_dev *pdev,
......
...@@ -296,7 +296,7 @@ static int to_mthca_st(int transport) ...@@ -296,7 +296,7 @@ static int to_mthca_st(int transport)
} }
} }
static void store_attrs(struct mthca_sqp *sqp, struct ib_qp_attr *attr, static void store_attrs(struct mthca_sqp *sqp, const struct ib_qp_attr *attr,
int attr_mask) int attr_mask)
{ {
if (attr_mask & IB_QP_PKEY_INDEX) if (attr_mask & IB_QP_PKEY_INDEX)
...@@ -328,7 +328,7 @@ static void init_port(struct mthca_dev *dev, int port) ...@@ -328,7 +328,7 @@ static void init_port(struct mthca_dev *dev, int port)
mthca_warn(dev, "INIT_IB returned status %02x.\n", status); mthca_warn(dev, "INIT_IB returned status %02x.\n", status);
} }
static __be32 get_hw_access_flags(struct mthca_qp *qp, struct ib_qp_attr *attr, static __be32 get_hw_access_flags(struct mthca_qp *qp, const struct ib_qp_attr *attr,
int attr_mask) int attr_mask)
{ {
u8 dest_rd_atomic; u8 dest_rd_atomic;
...@@ -511,7 +511,7 @@ int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_m ...@@ -511,7 +511,7 @@ int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_m
return err; return err;
} }
static int mthca_path_set(struct mthca_dev *dev, struct ib_ah_attr *ah, static int mthca_path_set(struct mthca_dev *dev, const struct ib_ah_attr *ah,
struct mthca_qp_path *path, u8 port) struct mthca_qp_path *path, u8 port)
{ {
path->g_mylmc = ah->src_path_bits & 0x7f; path->g_mylmc = ah->src_path_bits & 0x7f;
...@@ -539,12 +539,12 @@ static int mthca_path_set(struct mthca_dev *dev, struct ib_ah_attr *ah, ...@@ -539,12 +539,12 @@ static int mthca_path_set(struct mthca_dev *dev, struct ib_ah_attr *ah,
return 0; return 0;
} }
int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, static int __mthca_modify_qp(struct ib_qp *ibqp,
struct ib_udata *udata) const struct ib_qp_attr *attr, int attr_mask,
enum ib_qp_state cur_state, enum ib_qp_state new_state)
{ {
struct mthca_dev *dev = to_mdev(ibqp->device); struct mthca_dev *dev = to_mdev(ibqp->device);
struct mthca_qp *qp = to_mqp(ibqp); struct mthca_qp *qp = to_mqp(ibqp);
enum ib_qp_state cur_state, new_state;
struct mthca_mailbox *mailbox; struct mthca_mailbox *mailbox;
struct mthca_qp_param *qp_param; struct mthca_qp_param *qp_param;
struct mthca_qp_context *qp_context; struct mthca_qp_context *qp_context;
...@@ -552,60 +552,6 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, ...@@ -552,60 +552,6 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
u8 status; u8 status;
int err = -EINVAL; int err = -EINVAL;
mutex_lock(&qp->mutex);
if (attr_mask & IB_QP_CUR_STATE) {
cur_state = attr->cur_qp_state;
} else {
spin_lock_irq(&qp->sq.lock);
spin_lock(&qp->rq.lock);
cur_state = qp->state;
spin_unlock(&qp->rq.lock);
spin_unlock_irq(&qp->sq.lock);
}
new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask)) {
mthca_dbg(dev, "Bad QP transition (transport %d) "
"%d->%d with attr 0x%08x\n",
qp->transport, cur_state, new_state,
attr_mask);
goto out;
}
if (cur_state == new_state && cur_state == IB_QPS_RESET) {
err = 0;
goto out;
}
if ((attr_mask & IB_QP_PKEY_INDEX) &&
attr->pkey_index >= dev->limits.pkey_table_len) {
mthca_dbg(dev, "P_Key index (%u) too large. max is %d\n",
attr->pkey_index, dev->limits.pkey_table_len-1);
goto out;
}
if ((attr_mask & IB_QP_PORT) &&
(attr->port_num == 0 || attr->port_num > dev->limits.num_ports)) {
mthca_dbg(dev, "Port number (%u) is invalid\n", attr->port_num);
goto out;
}
if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
attr->max_rd_atomic > dev->limits.max_qp_init_rdma) {
mthca_dbg(dev, "Max rdma_atomic as initiator %u too large (max is %d)\n",
attr->max_rd_atomic, dev->limits.max_qp_init_rdma);
goto out;
}
if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
attr->max_dest_rd_atomic > 1 << dev->qp_table.rdb_shift) {
mthca_dbg(dev, "Max rdma_atomic as responder %u too large (max %d)\n",
attr->max_dest_rd_atomic, 1 << dev->qp_table.rdb_shift);
goto out;
}
mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
if (IS_ERR(mailbox)) { if (IS_ERR(mailbox)) {
err = PTR_ERR(mailbox); err = PTR_ERR(mailbox);
...@@ -892,6 +838,98 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, ...@@ -892,6 +838,98 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
out_mailbox: out_mailbox:
mthca_free_mailbox(dev, mailbox); mthca_free_mailbox(dev, mailbox);
out:
return err;
}
static const struct ib_qp_attr dummy_init_attr = { .port_num = 1 };
static const int dummy_init_attr_mask[] = {
[IB_QPT_UD] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_QKEY),
[IB_QPT_UC] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
[IB_QPT_RC] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
[IB_QPT_SMI] = (IB_QP_PKEY_INDEX |
IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_PKEY_INDEX |
IB_QP_QKEY),
};
int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
struct ib_udata *udata)
{
struct mthca_dev *dev = to_mdev(ibqp->device);
struct mthca_qp *qp = to_mqp(ibqp);
enum ib_qp_state cur_state, new_state;
int err = -EINVAL;
mutex_lock(&qp->mutex);
if (attr_mask & IB_QP_CUR_STATE) {
cur_state = attr->cur_qp_state;
} else {
spin_lock_irq(&qp->sq.lock);
spin_lock(&qp->rq.lock);
cur_state = qp->state;
spin_unlock(&qp->rq.lock);
spin_unlock_irq(&qp->sq.lock);
}
new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask)) {
mthca_dbg(dev, "Bad QP transition (transport %d) "
"%d->%d with attr 0x%08x\n",
qp->transport, cur_state, new_state,
attr_mask);
goto out;
}
if ((attr_mask & IB_QP_PKEY_INDEX) &&
attr->pkey_index >= dev->limits.pkey_table_len) {
mthca_dbg(dev, "P_Key index (%u) too large. max is %d\n",
attr->pkey_index, dev->limits.pkey_table_len-1);
goto out;
}
if ((attr_mask & IB_QP_PORT) &&
(attr->port_num == 0 || attr->port_num > dev->limits.num_ports)) {
mthca_dbg(dev, "Port number (%u) is invalid\n", attr->port_num);
goto out;
}
if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
attr->max_rd_atomic > dev->limits.max_qp_init_rdma) {
mthca_dbg(dev, "Max rdma_atomic as initiator %u too large (max is %d)\n",
attr->max_rd_atomic, dev->limits.max_qp_init_rdma);
goto out;
}
if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
attr->max_dest_rd_atomic > 1 << dev->qp_table.rdb_shift) {
mthca_dbg(dev, "Max rdma_atomic as responder %u too large (max %d)\n",
attr->max_dest_rd_atomic, 1 << dev->qp_table.rdb_shift);
goto out;
}
if (cur_state == new_state && cur_state == IB_QPS_RESET) {
err = 0;
goto out;
}
if (cur_state == IB_QPS_RESET && new_state == IB_QPS_ERR) {
err = __mthca_modify_qp(ibqp, &dummy_init_attr,
dummy_init_attr_mask[ibqp->qp_type],
IB_QPS_RESET, IB_QPS_INIT);
if (err)
goto out;
cur_state = IB_QPS_INIT;
}
err = __mthca_modify_qp(ibqp, attr, attr_mask, cur_state, new_state);
out: out:
mutex_unlock(&qp->mutex); mutex_unlock(&qp->mutex);
......
...@@ -132,12 +132,46 @@ struct ipoib_cm_data { ...@@ -132,12 +132,46 @@ struct ipoib_cm_data {
__be32 mtu; __be32 mtu;
}; };
/*
* Quoting 10.3.1 Queue Pair and EE Context States:
*
* Note, for QPs that are associated with an SRQ, the Consumer should take the
* QP through the Error State before invoking a Destroy QP or a Modify QP to the
* Reset State. The Consumer may invoke the Destroy QP without first performing
* a Modify QP to the Error State and waiting for the Affiliated Asynchronous
* Last WQE Reached Event. However, if the Consumer does not wait for the
* Affiliated Asynchronous Last WQE Reached Event, then WQE and Data Segment
* leakage may occur. Therefore, it is good programming practice to tear down a
* QP that is associated with an SRQ by using the following process:
*
* - Put the QP in the Error State
* - Wait for the Affiliated Asynchronous Last WQE Reached Event;
* - either:
* drain the CQ by invoking the Poll CQ verb and either wait for CQ
* to be empty or the number of Poll CQ operations has exceeded
* CQ capacity size;
* - or
* post another WR that completes on the same CQ and wait for this
* WR to return as a WC;
* - and then invoke a Destroy QP or Reset QP.
*
* We use the second option and wait for a completion on the
* rx_drain_qp before destroying QPs attached to our SRQ.
*/
enum ipoib_cm_state {
IPOIB_CM_RX_LIVE,
IPOIB_CM_RX_ERROR, /* Ignored by stale task */
IPOIB_CM_RX_FLUSH /* Last WQE Reached event observed */
};
struct ipoib_cm_rx { struct ipoib_cm_rx {
struct ib_cm_id *id; struct ib_cm_id *id;
struct ib_qp *qp; struct ib_qp *qp;
struct list_head list; struct list_head list;
struct net_device *dev; struct net_device *dev;
unsigned long jiffies; unsigned long jiffies;
enum ipoib_cm_state state;
}; };
struct ipoib_cm_tx { struct ipoib_cm_tx {
...@@ -165,10 +199,16 @@ struct ipoib_cm_dev_priv { ...@@ -165,10 +199,16 @@ struct ipoib_cm_dev_priv {
struct ib_srq *srq; struct ib_srq *srq;
struct ipoib_cm_rx_buf *srq_ring; struct ipoib_cm_rx_buf *srq_ring;
struct ib_cm_id *id; struct ib_cm_id *id;
struct list_head passive_ids; struct ib_qp *rx_drain_qp; /* generates WR described in 10.3.1 */
struct list_head passive_ids; /* state: LIVE */
struct list_head rx_error_list; /* state: ERROR */
struct list_head rx_flush_list; /* state: FLUSH, drain not started */
struct list_head rx_drain_list; /* state: FLUSH, drain started */
struct list_head rx_reap_list; /* state: FLUSH, drain done */
struct work_struct start_task; struct work_struct start_task;
struct work_struct reap_task; struct work_struct reap_task;
struct work_struct skb_task; struct work_struct skb_task;
struct work_struct rx_reap_task;
struct delayed_work stale_task; struct delayed_work stale_task;
struct sk_buff_head skb_queue; struct sk_buff_head skb_queue;
struct list_head start_list; struct list_head start_list;
...@@ -201,15 +241,17 @@ struct ipoib_dev_priv { ...@@ -201,15 +241,17 @@ struct ipoib_dev_priv {
struct list_head multicast_list; struct list_head multicast_list;
struct rb_root multicast_tree; struct rb_root multicast_tree;
struct delayed_work pkey_task; struct delayed_work pkey_poll_task;
struct delayed_work mcast_task; struct delayed_work mcast_task;
struct work_struct flush_task; struct work_struct flush_task;
struct work_struct restart_task; struct work_struct restart_task;
struct delayed_work ah_reap_task; struct delayed_work ah_reap_task;
struct work_struct pkey_event_task;
struct ib_device *ca; struct ib_device *ca;
u8 port; u8 port;
u16 pkey; u16 pkey;
u16 pkey_index;
struct ib_pd *pd; struct ib_pd *pd;
struct ib_mr *mr; struct ib_mr *mr;
struct ib_cq *cq; struct ib_cq *cq;
...@@ -333,12 +375,13 @@ struct ipoib_dev_priv *ipoib_intf_alloc(const char *format); ...@@ -333,12 +375,13 @@ struct ipoib_dev_priv *ipoib_intf_alloc(const char *format);
int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port); int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port);
void ipoib_ib_dev_flush(struct work_struct *work); void ipoib_ib_dev_flush(struct work_struct *work);
void ipoib_pkey_event(struct work_struct *work);
void ipoib_ib_dev_cleanup(struct net_device *dev); void ipoib_ib_dev_cleanup(struct net_device *dev);
int ipoib_ib_dev_open(struct net_device *dev); int ipoib_ib_dev_open(struct net_device *dev);
int ipoib_ib_dev_up(struct net_device *dev); int ipoib_ib_dev_up(struct net_device *dev);
int ipoib_ib_dev_down(struct net_device *dev, int flush); int ipoib_ib_dev_down(struct net_device *dev, int flush);
int ipoib_ib_dev_stop(struct net_device *dev); int ipoib_ib_dev_stop(struct net_device *dev, int flush);
int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port); int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port);
void ipoib_dev_cleanup(struct net_device *dev); void ipoib_dev_cleanup(struct net_device *dev);
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <net/dst.h> #include <net/dst.h>
#include <net/icmp.h> #include <net/icmp.h>
#include <linux/icmpv6.h> #include <linux/icmpv6.h>
#include <linux/delay.h>
#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA
static int data_debug_level; static int data_debug_level;
...@@ -62,6 +63,16 @@ struct ipoib_cm_id { ...@@ -62,6 +63,16 @@ struct ipoib_cm_id {
u32 remote_mtu; u32 remote_mtu;
}; };
static struct ib_qp_attr ipoib_cm_err_attr = {
.qp_state = IB_QPS_ERR
};
#define IPOIB_CM_RX_DRAIN_WRID 0x7fffffff
static struct ib_recv_wr ipoib_cm_rx_drain_wr = {
.wr_id = IPOIB_CM_RX_DRAIN_WRID
};
static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id, static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id,
struct ib_cm_event *event); struct ib_cm_event *event);
...@@ -150,11 +161,44 @@ static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, int ...@@ -150,11 +161,44 @@ static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, int
return NULL; return NULL;
} }
static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv* priv)
{
struct ib_recv_wr *bad_wr;
/* rx_drain_qp send queue depth is 1, so
* make sure we have at most 1 outstanding WR. */
if (list_empty(&priv->cm.rx_flush_list) ||
!list_empty(&priv->cm.rx_drain_list))
return;
if (ib_post_recv(priv->cm.rx_drain_qp, &ipoib_cm_rx_drain_wr, &bad_wr))
ipoib_warn(priv, "failed to post rx_drain wr\n");
list_splice_init(&priv->cm.rx_flush_list, &priv->cm.rx_drain_list);
}
static void ipoib_cm_rx_event_handler(struct ib_event *event, void *ctx)
{
struct ipoib_cm_rx *p = ctx;
struct ipoib_dev_priv *priv = netdev_priv(p->dev);
unsigned long flags;
if (event->event != IB_EVENT_QP_LAST_WQE_REACHED)
return;
spin_lock_irqsave(&priv->lock, flags);
list_move(&p->list, &priv->cm.rx_flush_list);
p->state = IPOIB_CM_RX_FLUSH;
ipoib_cm_start_rx_drain(priv);
spin_unlock_irqrestore(&priv->lock, flags);
}
static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev, static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev,
struct ipoib_cm_rx *p) struct ipoib_cm_rx *p)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ib_qp_init_attr attr = { struct ib_qp_init_attr attr = {
.event_handler = ipoib_cm_rx_event_handler,
.send_cq = priv->cq, /* does not matter, we never send anything */ .send_cq = priv->cq, /* does not matter, we never send anything */
.recv_cq = priv->cq, .recv_cq = priv->cq,
.srq = priv->cm.srq, .srq = priv->cm.srq,
...@@ -256,6 +300,7 @@ static int ipoib_cm_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even ...@@ -256,6 +300,7 @@ static int ipoib_cm_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even
cm_id->context = p; cm_id->context = p;
p->jiffies = jiffies; p->jiffies = jiffies;
p->state = IPOIB_CM_RX_LIVE;
spin_lock_irq(&priv->lock); spin_lock_irq(&priv->lock);
if (list_empty(&priv->cm.passive_ids)) if (list_empty(&priv->cm.passive_ids))
queue_delayed_work(ipoib_workqueue, queue_delayed_work(ipoib_workqueue,
...@@ -277,7 +322,6 @@ static int ipoib_cm_rx_handler(struct ib_cm_id *cm_id, ...@@ -277,7 +322,6 @@ static int ipoib_cm_rx_handler(struct ib_cm_id *cm_id,
{ {
struct ipoib_cm_rx *p; struct ipoib_cm_rx *p;
struct ipoib_dev_priv *priv; struct ipoib_dev_priv *priv;
int ret;
switch (event->event) { switch (event->event) {
case IB_CM_REQ_RECEIVED: case IB_CM_REQ_RECEIVED:
...@@ -289,20 +333,9 @@ static int ipoib_cm_rx_handler(struct ib_cm_id *cm_id, ...@@ -289,20 +333,9 @@ static int ipoib_cm_rx_handler(struct ib_cm_id *cm_id,
case IB_CM_REJ_RECEIVED: case IB_CM_REJ_RECEIVED:
p = cm_id->context; p = cm_id->context;
priv = netdev_priv(p->dev); priv = netdev_priv(p->dev);
spin_lock_irq(&priv->lock); if (ib_modify_qp(p->qp, &ipoib_cm_err_attr, IB_QP_STATE))
if (list_empty(&p->list)) ipoib_warn(priv, "unable to move qp to error state\n");
ret = 0; /* Connection is going away already. */ /* Fall through */
else {
list_del_init(&p->list);
ret = -ECONNRESET;
}
spin_unlock_irq(&priv->lock);
if (ret) {
ib_destroy_qp(p->qp);
kfree(p);
return ret;
}
return 0;
default: default:
return 0; return 0;
} }
...@@ -354,6 +387,13 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) ...@@ -354,6 +387,13 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
wr_id, wc->status); wr_id, wc->status);
if (unlikely(wr_id >= ipoib_recvq_size)) { if (unlikely(wr_id >= ipoib_recvq_size)) {
if (wr_id == (IPOIB_CM_RX_DRAIN_WRID & ~IPOIB_CM_OP_SRQ)) {
spin_lock_irqsave(&priv->lock, flags);
list_splice_init(&priv->cm.rx_drain_list, &priv->cm.rx_reap_list);
ipoib_cm_start_rx_drain(priv);
queue_work(ipoib_workqueue, &priv->cm.rx_reap_task);
spin_unlock_irqrestore(&priv->lock, flags);
} else
ipoib_warn(priv, "cm recv completion event with wrid %d (> %d)\n", ipoib_warn(priv, "cm recv completion event with wrid %d (> %d)\n",
wr_id, ipoib_recvq_size); wr_id, ipoib_recvq_size);
return; return;
...@@ -374,9 +414,9 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) ...@@ -374,9 +414,9 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
if (p && time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) { if (p && time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) {
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
p->jiffies = jiffies; p->jiffies = jiffies;
/* Move this entry to list head, but do /* Move this entry to list head, but do not re-add it
* not re-add it if it has been removed. */ * if it has been moved out of list. */
if (!list_empty(&p->list)) if (p->state == IPOIB_CM_RX_LIVE)
list_move(&p->list, &priv->cm.passive_ids); list_move(&p->list, &priv->cm.passive_ids);
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
} }
...@@ -583,17 +623,43 @@ static void ipoib_cm_tx_completion(struct ib_cq *cq, void *tx_ptr) ...@@ -583,17 +623,43 @@ static void ipoib_cm_tx_completion(struct ib_cq *cq, void *tx_ptr)
int ipoib_cm_dev_open(struct net_device *dev) int ipoib_cm_dev_open(struct net_device *dev)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ib_qp_init_attr qp_init_attr = {
.send_cq = priv->cq, /* does not matter, we never send anything */
.recv_cq = priv->cq,
.cap.max_send_wr = 1, /* FIXME: 0 Seems not to work */
.cap.max_send_sge = 1, /* FIXME: 0 Seems not to work */
.cap.max_recv_wr = 1,
.cap.max_recv_sge = 1, /* FIXME: 0 Seems not to work */
.sq_sig_type = IB_SIGNAL_ALL_WR,
.qp_type = IB_QPT_UC,
};
int ret; int ret;
if (!IPOIB_CM_SUPPORTED(dev->dev_addr)) if (!IPOIB_CM_SUPPORTED(dev->dev_addr))
return 0; return 0;
priv->cm.rx_drain_qp = ib_create_qp(priv->pd, &qp_init_attr);
if (IS_ERR(priv->cm.rx_drain_qp)) {
printk(KERN_WARNING "%s: failed to create CM ID\n", priv->ca->name);
ret = PTR_ERR(priv->cm.rx_drain_qp);
return ret;
}
/*
* We put the QP in error state directly. This way, a "flush
* error" WC will be immediately generated for each WR we post.
*/
ret = ib_modify_qp(priv->cm.rx_drain_qp, &ipoib_cm_err_attr, IB_QP_STATE);
if (ret) {
ipoib_warn(priv, "failed to modify drain QP to error: %d\n", ret);
goto err_qp;
}
priv->cm.id = ib_create_cm_id(priv->ca, ipoib_cm_rx_handler, dev); priv->cm.id = ib_create_cm_id(priv->ca, ipoib_cm_rx_handler, dev);
if (IS_ERR(priv->cm.id)) { if (IS_ERR(priv->cm.id)) {
printk(KERN_WARNING "%s: failed to create CM ID\n", priv->ca->name); printk(KERN_WARNING "%s: failed to create CM ID\n", priv->ca->name);
ret = PTR_ERR(priv->cm.id); ret = PTR_ERR(priv->cm.id);
priv->cm.id = NULL; goto err_cm;
return ret;
} }
ret = ib_cm_listen(priv->cm.id, cpu_to_be64(IPOIB_CM_IETF_ID | priv->qp->qp_num), ret = ib_cm_listen(priv->cm.id, cpu_to_be64(IPOIB_CM_IETF_ID | priv->qp->qp_num),
...@@ -601,35 +667,79 @@ int ipoib_cm_dev_open(struct net_device *dev) ...@@ -601,35 +667,79 @@ int ipoib_cm_dev_open(struct net_device *dev)
if (ret) { if (ret) {
printk(KERN_WARNING "%s: failed to listen on ID 0x%llx\n", priv->ca->name, printk(KERN_WARNING "%s: failed to listen on ID 0x%llx\n", priv->ca->name,
IPOIB_CM_IETF_ID | priv->qp->qp_num); IPOIB_CM_IETF_ID | priv->qp->qp_num);
goto err_listen;
}
return 0;
err_listen:
ib_destroy_cm_id(priv->cm.id); ib_destroy_cm_id(priv->cm.id);
err_cm:
priv->cm.id = NULL; priv->cm.id = NULL;
err_qp:
ib_destroy_qp(priv->cm.rx_drain_qp);
return ret; return ret;
}
return 0;
} }
void ipoib_cm_dev_stop(struct net_device *dev) void ipoib_cm_dev_stop(struct net_device *dev)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_cm_rx *p; struct ipoib_cm_rx *p, *n;
unsigned long begin;
LIST_HEAD(list);
int ret;
if (!IPOIB_CM_SUPPORTED(dev->dev_addr) || !priv->cm.id) if (!IPOIB_CM_SUPPORTED(dev->dev_addr) || !priv->cm.id)
return; return;
ib_destroy_cm_id(priv->cm.id); ib_destroy_cm_id(priv->cm.id);
priv->cm.id = NULL; priv->cm.id = NULL;
spin_lock_irq(&priv->lock); spin_lock_irq(&priv->lock);
while (!list_empty(&priv->cm.passive_ids)) { while (!list_empty(&priv->cm.passive_ids)) {
p = list_entry(priv->cm.passive_ids.next, typeof(*p), list); p = list_entry(priv->cm.passive_ids.next, typeof(*p), list);
list_del_init(&p->list); list_move(&p->list, &priv->cm.rx_error_list);
p->state = IPOIB_CM_RX_ERROR;
spin_unlock_irq(&priv->lock); spin_unlock_irq(&priv->lock);
ret = ib_modify_qp(p->qp, &ipoib_cm_err_attr, IB_QP_STATE);
if (ret)
ipoib_warn(priv, "unable to move qp to error state: %d\n", ret);
spin_lock_irq(&priv->lock);
}
/* Wait for all RX to be drained */
begin = jiffies;
while (!list_empty(&priv->cm.rx_error_list) ||
!list_empty(&priv->cm.rx_flush_list) ||
!list_empty(&priv->cm.rx_drain_list)) {
if (!time_after(jiffies, begin + 5 * HZ)) {
ipoib_warn(priv, "RX drain timing out\n");
/*
* assume the HW is wedged and just free up everything.
*/
list_splice_init(&priv->cm.rx_flush_list, &list);
list_splice_init(&priv->cm.rx_error_list, &list);
list_splice_init(&priv->cm.rx_drain_list, &list);
break;
}
spin_unlock_irq(&priv->lock);
msleep(1);
spin_lock_irq(&priv->lock);
}
list_splice_init(&priv->cm.rx_reap_list, &list);
spin_unlock_irq(&priv->lock);
list_for_each_entry_safe(p, n, &list, list) {
ib_destroy_cm_id(p->id); ib_destroy_cm_id(p->id);
ib_destroy_qp(p->qp); ib_destroy_qp(p->qp);
kfree(p); kfree(p);
spin_lock_irq(&priv->lock);
} }
spin_unlock_irq(&priv->lock);
ib_destroy_qp(priv->cm.rx_drain_qp);
cancel_delayed_work(&priv->cm.stale_task); cancel_delayed_work(&priv->cm.stale_task);
} }
...@@ -1079,24 +1189,44 @@ void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb, ...@@ -1079,24 +1189,44 @@ void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
queue_work(ipoib_workqueue, &priv->cm.skb_task); queue_work(ipoib_workqueue, &priv->cm.skb_task);
} }
static void ipoib_cm_rx_reap(struct work_struct *work)
{
struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
cm.rx_reap_task);
struct ipoib_cm_rx *p, *n;
LIST_HEAD(list);
spin_lock_irq(&priv->lock);
list_splice_init(&priv->cm.rx_reap_list, &list);
spin_unlock_irq(&priv->lock);
list_for_each_entry_safe(p, n, &list, list) {
ib_destroy_cm_id(p->id);
ib_destroy_qp(p->qp);
kfree(p);
}
}
static void ipoib_cm_stale_task(struct work_struct *work) static void ipoib_cm_stale_task(struct work_struct *work)
{ {
struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
cm.stale_task.work); cm.stale_task.work);
struct ipoib_cm_rx *p; struct ipoib_cm_rx *p;
int ret;
spin_lock_irq(&priv->lock); spin_lock_irq(&priv->lock);
while (!list_empty(&priv->cm.passive_ids)) { while (!list_empty(&priv->cm.passive_ids)) {
/* List if sorted by LRU, start from tail, /* List is sorted by LRU, start from tail,
* stop when we see a recently used entry */ * stop when we see a recently used entry */
p = list_entry(priv->cm.passive_ids.prev, typeof(*p), list); p = list_entry(priv->cm.passive_ids.prev, typeof(*p), list);
if (time_before_eq(jiffies, p->jiffies + IPOIB_CM_RX_TIMEOUT)) if (time_before_eq(jiffies, p->jiffies + IPOIB_CM_RX_TIMEOUT))
break; break;
list_del_init(&p->list); list_move(&p->list, &priv->cm.rx_error_list);
p->state = IPOIB_CM_RX_ERROR;
spin_unlock_irq(&priv->lock); spin_unlock_irq(&priv->lock);
ib_destroy_cm_id(p->id); ret = ib_modify_qp(p->qp, &ipoib_cm_err_attr, IB_QP_STATE);
ib_destroy_qp(p->qp); if (ret)
kfree(p); ipoib_warn(priv, "unable to move qp to error state: %d\n", ret);
spin_lock_irq(&priv->lock); spin_lock_irq(&priv->lock);
} }
...@@ -1164,9 +1294,14 @@ int ipoib_cm_dev_init(struct net_device *dev) ...@@ -1164,9 +1294,14 @@ int ipoib_cm_dev_init(struct net_device *dev)
INIT_LIST_HEAD(&priv->cm.passive_ids); INIT_LIST_HEAD(&priv->cm.passive_ids);
INIT_LIST_HEAD(&priv->cm.reap_list); INIT_LIST_HEAD(&priv->cm.reap_list);
INIT_LIST_HEAD(&priv->cm.start_list); INIT_LIST_HEAD(&priv->cm.start_list);
INIT_LIST_HEAD(&priv->cm.rx_error_list);
INIT_LIST_HEAD(&priv->cm.rx_flush_list);
INIT_LIST_HEAD(&priv->cm.rx_drain_list);
INIT_LIST_HEAD(&priv->cm.rx_reap_list);
INIT_WORK(&priv->cm.start_task, ipoib_cm_tx_start); INIT_WORK(&priv->cm.start_task, ipoib_cm_tx_start);
INIT_WORK(&priv->cm.reap_task, ipoib_cm_tx_reap); INIT_WORK(&priv->cm.reap_task, ipoib_cm_tx_reap);
INIT_WORK(&priv->cm.skb_task, ipoib_cm_skb_reap); INIT_WORK(&priv->cm.skb_task, ipoib_cm_skb_reap);
INIT_WORK(&priv->cm.rx_reap_task, ipoib_cm_rx_reap);
INIT_DELAYED_WORK(&priv->cm.stale_task, ipoib_cm_stale_task); INIT_DELAYED_WORK(&priv->cm.stale_task, ipoib_cm_stale_task);
skb_queue_head_init(&priv->cm.skb_queue); skb_queue_head_init(&priv->cm.skb_queue);
......
...@@ -448,6 +448,13 @@ int ipoib_ib_dev_open(struct net_device *dev) ...@@ -448,6 +448,13 @@ int ipoib_ib_dev_open(struct net_device *dev)
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
int ret; int ret;
if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &priv->pkey_index)) {
ipoib_warn(priv, "P_Key 0x%04x not found\n", priv->pkey);
clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
return -1;
}
set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
ret = ipoib_init_qp(dev); ret = ipoib_init_qp(dev);
if (ret) { if (ret) {
ipoib_warn(priv, "ipoib_init_qp returned %d\n", ret); ipoib_warn(priv, "ipoib_init_qp returned %d\n", ret);
...@@ -457,14 +464,14 @@ int ipoib_ib_dev_open(struct net_device *dev) ...@@ -457,14 +464,14 @@ int ipoib_ib_dev_open(struct net_device *dev)
ret = ipoib_ib_post_receives(dev); ret = ipoib_ib_post_receives(dev);
if (ret) { if (ret) {
ipoib_warn(priv, "ipoib_ib_post_receives returned %d\n", ret); ipoib_warn(priv, "ipoib_ib_post_receives returned %d\n", ret);
ipoib_ib_dev_stop(dev); ipoib_ib_dev_stop(dev, 1);
return -1; return -1;
} }
ret = ipoib_cm_dev_open(dev); ret = ipoib_cm_dev_open(dev);
if (ret) { if (ret) {
ipoib_warn(priv, "ipoib_ib_post_receives returned %d\n", ret); ipoib_warn(priv, "ipoib_cm_dev_open returned %d\n", ret);
ipoib_ib_dev_stop(dev); ipoib_ib_dev_stop(dev, 1);
return -1; return -1;
} }
...@@ -516,7 +523,7 @@ int ipoib_ib_dev_down(struct net_device *dev, int flush) ...@@ -516,7 +523,7 @@ int ipoib_ib_dev_down(struct net_device *dev, int flush)
if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) { if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) {
mutex_lock(&pkey_mutex); mutex_lock(&pkey_mutex);
set_bit(IPOIB_PKEY_STOP, &priv->flags); set_bit(IPOIB_PKEY_STOP, &priv->flags);
cancel_delayed_work(&priv->pkey_task); cancel_delayed_work(&priv->pkey_poll_task);
mutex_unlock(&pkey_mutex); mutex_unlock(&pkey_mutex);
if (flush) if (flush)
flush_workqueue(ipoib_workqueue); flush_workqueue(ipoib_workqueue);
...@@ -543,7 +550,7 @@ static int recvs_pending(struct net_device *dev) ...@@ -543,7 +550,7 @@ static int recvs_pending(struct net_device *dev)
return pending; return pending;
} }
int ipoib_ib_dev_stop(struct net_device *dev) int ipoib_ib_dev_stop(struct net_device *dev, int flush)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ib_qp_attr qp_attr; struct ib_qp_attr qp_attr;
...@@ -629,6 +636,7 @@ int ipoib_ib_dev_stop(struct net_device *dev) ...@@ -629,6 +636,7 @@ int ipoib_ib_dev_stop(struct net_device *dev)
/* Wait for all AHs to be reaped */ /* Wait for all AHs to be reaped */
set_bit(IPOIB_STOP_REAPER, &priv->flags); set_bit(IPOIB_STOP_REAPER, &priv->flags);
cancel_delayed_work(&priv->ah_reap_task); cancel_delayed_work(&priv->ah_reap_task);
if (flush)
flush_workqueue(ipoib_workqueue); flush_workqueue(ipoib_workqueue);
begin = jiffies; begin = jiffies;
...@@ -673,13 +681,24 @@ int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port) ...@@ -673,13 +681,24 @@ int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
return 0; return 0;
} }
void ipoib_ib_dev_flush(struct work_struct *work) static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, int pkey_event)
{ {
struct ipoib_dev_priv *cpriv, *priv = struct ipoib_dev_priv *cpriv;
container_of(work, struct ipoib_dev_priv, flush_task);
struct net_device *dev = priv->dev; struct net_device *dev = priv->dev;
u16 new_index;
mutex_lock(&priv->vlan_mutex);
if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags) ) { /*
* Flush any child interfaces too -- they might be up even if
* the parent is down.
*/
list_for_each_entry(cpriv, &priv->child_intfs, list)
__ipoib_ib_dev_flush(cpriv, pkey_event);
mutex_unlock(&priv->vlan_mutex);
if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) {
ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n"); ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n");
return; return;
} }
...@@ -689,10 +708,32 @@ void ipoib_ib_dev_flush(struct work_struct *work) ...@@ -689,10 +708,32 @@ void ipoib_ib_dev_flush(struct work_struct *work)
return; return;
} }
if (pkey_event) {
if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) {
clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
ipoib_ib_dev_down(dev, 0);
ipoib_pkey_dev_delay_open(dev);
return;
}
set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
/* restart QP only if P_Key index is changed */
if (new_index == priv->pkey_index) {
ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n");
return;
}
priv->pkey_index = new_index;
}
ipoib_dbg(priv, "flushing\n"); ipoib_dbg(priv, "flushing\n");
ipoib_ib_dev_down(dev, 0); ipoib_ib_dev_down(dev, 0);
if (pkey_event) {
ipoib_ib_dev_stop(dev, 0);
ipoib_ib_dev_open(dev);
}
/* /*
* The device could have been brought down between the start and when * The device could have been brought down between the start and when
* we get here, don't bring it back up if it's not configured up * we get here, don't bring it back up if it's not configured up
...@@ -701,14 +742,24 @@ void ipoib_ib_dev_flush(struct work_struct *work) ...@@ -701,14 +742,24 @@ void ipoib_ib_dev_flush(struct work_struct *work)
ipoib_ib_dev_up(dev); ipoib_ib_dev_up(dev);
ipoib_mcast_restart_task(&priv->restart_task); ipoib_mcast_restart_task(&priv->restart_task);
} }
}
mutex_lock(&priv->vlan_mutex); void ipoib_ib_dev_flush(struct work_struct *work)
{
struct ipoib_dev_priv *priv =
container_of(work, struct ipoib_dev_priv, flush_task);
/* Flush any child interfaces too */ ipoib_dbg(priv, "Flushing %s\n", priv->dev->name);
list_for_each_entry(cpriv, &priv->child_intfs, list) __ipoib_ib_dev_flush(priv, 0);
ipoib_ib_dev_flush(&cpriv->flush_task); }
mutex_unlock(&priv->vlan_mutex); void ipoib_pkey_event(struct work_struct *work)
{
struct ipoib_dev_priv *priv =
container_of(work, struct ipoib_dev_priv, pkey_event_task);
ipoib_dbg(priv, "Flushing %s and restarting its QP\n", priv->dev->name);
__ipoib_ib_dev_flush(priv, 1);
} }
void ipoib_ib_dev_cleanup(struct net_device *dev) void ipoib_ib_dev_cleanup(struct net_device *dev)
...@@ -736,7 +787,7 @@ void ipoib_ib_dev_cleanup(struct net_device *dev) ...@@ -736,7 +787,7 @@ void ipoib_ib_dev_cleanup(struct net_device *dev)
void ipoib_pkey_poll(struct work_struct *work) void ipoib_pkey_poll(struct work_struct *work)
{ {
struct ipoib_dev_priv *priv = struct ipoib_dev_priv *priv =
container_of(work, struct ipoib_dev_priv, pkey_task.work); container_of(work, struct ipoib_dev_priv, pkey_poll_task.work);
struct net_device *dev = priv->dev; struct net_device *dev = priv->dev;
ipoib_pkey_dev_check_presence(dev); ipoib_pkey_dev_check_presence(dev);
...@@ -747,7 +798,7 @@ void ipoib_pkey_poll(struct work_struct *work) ...@@ -747,7 +798,7 @@ void ipoib_pkey_poll(struct work_struct *work)
mutex_lock(&pkey_mutex); mutex_lock(&pkey_mutex);
if (!test_bit(IPOIB_PKEY_STOP, &priv->flags)) if (!test_bit(IPOIB_PKEY_STOP, &priv->flags))
queue_delayed_work(ipoib_workqueue, queue_delayed_work(ipoib_workqueue,
&priv->pkey_task, &priv->pkey_poll_task,
HZ); HZ);
mutex_unlock(&pkey_mutex); mutex_unlock(&pkey_mutex);
} }
...@@ -766,7 +817,7 @@ int ipoib_pkey_dev_delay_open(struct net_device *dev) ...@@ -766,7 +817,7 @@ int ipoib_pkey_dev_delay_open(struct net_device *dev)
mutex_lock(&pkey_mutex); mutex_lock(&pkey_mutex);
clear_bit(IPOIB_PKEY_STOP, &priv->flags); clear_bit(IPOIB_PKEY_STOP, &priv->flags);
queue_delayed_work(ipoib_workqueue, queue_delayed_work(ipoib_workqueue,
&priv->pkey_task, &priv->pkey_poll_task,
HZ); HZ);
mutex_unlock(&pkey_mutex); mutex_unlock(&pkey_mutex);
return 1; return 1;
......
...@@ -107,7 +107,7 @@ int ipoib_open(struct net_device *dev) ...@@ -107,7 +107,7 @@ int ipoib_open(struct net_device *dev)
return -EINVAL; return -EINVAL;
if (ipoib_ib_dev_up(dev)) { if (ipoib_ib_dev_up(dev)) {
ipoib_ib_dev_stop(dev); ipoib_ib_dev_stop(dev, 1);
return -EINVAL; return -EINVAL;
} }
...@@ -152,7 +152,7 @@ static int ipoib_stop(struct net_device *dev) ...@@ -152,7 +152,7 @@ static int ipoib_stop(struct net_device *dev)
flush_workqueue(ipoib_workqueue); flush_workqueue(ipoib_workqueue);
ipoib_ib_dev_down(dev, 1); ipoib_ib_dev_down(dev, 1);
ipoib_ib_dev_stop(dev); ipoib_ib_dev_stop(dev, 1);
if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
struct ipoib_dev_priv *cpriv; struct ipoib_dev_priv *cpriv;
...@@ -988,7 +988,8 @@ static void ipoib_setup(struct net_device *dev) ...@@ -988,7 +988,8 @@ static void ipoib_setup(struct net_device *dev)
INIT_LIST_HEAD(&priv->dead_ahs); INIT_LIST_HEAD(&priv->dead_ahs);
INIT_LIST_HEAD(&priv->multicast_list); INIT_LIST_HEAD(&priv->multicast_list);
INIT_DELAYED_WORK(&priv->pkey_task, ipoib_pkey_poll); INIT_DELAYED_WORK(&priv->pkey_poll_task, ipoib_pkey_poll);
INIT_WORK(&priv->pkey_event_task, ipoib_pkey_event);
INIT_DELAYED_WORK(&priv->mcast_task, ipoib_mcast_join_task); INIT_DELAYED_WORK(&priv->mcast_task, ipoib_mcast_join_task);
INIT_WORK(&priv->flush_task, ipoib_ib_dev_flush); INIT_WORK(&priv->flush_task, ipoib_ib_dev_flush);
INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task); INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task);
......
...@@ -524,7 +524,7 @@ void ipoib_mcast_join_task(struct work_struct *work) ...@@ -524,7 +524,7 @@ void ipoib_mcast_join_task(struct work_struct *work)
return; return;
if (ib_query_gid(priv->ca, priv->port, 0, &priv->local_gid)) if (ib_query_gid(priv->ca, priv->port, 0, &priv->local_gid))
ipoib_warn(priv, "ib_gid_entry_get() failed\n"); ipoib_warn(priv, "ib_query_gid() failed\n");
else else
memcpy(priv->dev->dev_addr + 4, priv->local_gid.raw, sizeof (union ib_gid)); memcpy(priv->dev->dev_addr + 4, priv->local_gid.raw, sizeof (union ib_gid));
......
...@@ -33,8 +33,6 @@ ...@@ -33,8 +33,6 @@
* $Id: ipoib_verbs.c 1349 2004-12-16 21:09:43Z roland $ * $Id: ipoib_verbs.c 1349 2004-12-16 21:09:43Z roland $
*/ */
#include <rdma/ib_cache.h>
#include "ipoib.h" #include "ipoib.h"
int ipoib_mcast_attach(struct net_device *dev, u16 mlid, union ib_gid *mgid) int ipoib_mcast_attach(struct net_device *dev, u16 mlid, union ib_gid *mgid)
...@@ -49,7 +47,7 @@ int ipoib_mcast_attach(struct net_device *dev, u16 mlid, union ib_gid *mgid) ...@@ -49,7 +47,7 @@ int ipoib_mcast_attach(struct net_device *dev, u16 mlid, union ib_gid *mgid)
if (!qp_attr) if (!qp_attr)
goto out; goto out;
if (ib_find_cached_pkey(priv->ca, priv->port, priv->pkey, &pkey_index)) { if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &pkey_index)) {
clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
ret = -ENXIO; ret = -ENXIO;
goto out; goto out;
...@@ -94,26 +92,16 @@ int ipoib_init_qp(struct net_device *dev) ...@@ -94,26 +92,16 @@ int ipoib_init_qp(struct net_device *dev)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
int ret; int ret;
u16 pkey_index;
struct ib_qp_attr qp_attr; struct ib_qp_attr qp_attr;
int attr_mask; int attr_mask;
/* if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags))
* Search through the port P_Key table for the requested pkey value. return -1;
* The port has to be assigned to the respective IB partition in
* advance.
*/
ret = ib_find_cached_pkey(priv->ca, priv->port, priv->pkey, &pkey_index);
if (ret) {
clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
return ret;
}
set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
qp_attr.qp_state = IB_QPS_INIT; qp_attr.qp_state = IB_QPS_INIT;
qp_attr.qkey = 0; qp_attr.qkey = 0;
qp_attr.port_num = priv->port; qp_attr.port_num = priv->port;
qp_attr.pkey_index = pkey_index; qp_attr.pkey_index = priv->pkey_index;
attr_mask = attr_mask =
IB_QP_QKEY | IB_QP_QKEY |
IB_QP_PORT | IB_QP_PORT |
...@@ -185,7 +173,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) ...@@ -185,7 +173,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
size = ipoib_sendq_size + ipoib_recvq_size + 1; size = ipoib_sendq_size + ipoib_recvq_size + 1;
ret = ipoib_cm_dev_init(dev); ret = ipoib_cm_dev_init(dev);
if (!ret) if (!ret)
size += ipoib_recvq_size; size += ipoib_recvq_size + 1 /* 1 extra for rx_drain_qp */;
priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0); priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0);
if (IS_ERR(priv->cq)) { if (IS_ERR(priv->cq)) {
...@@ -259,14 +247,18 @@ void ipoib_event(struct ib_event_handler *handler, ...@@ -259,14 +247,18 @@ void ipoib_event(struct ib_event_handler *handler,
struct ipoib_dev_priv *priv = struct ipoib_dev_priv *priv =
container_of(handler, struct ipoib_dev_priv, event_handler); container_of(handler, struct ipoib_dev_priv, event_handler);
if ((record->event == IB_EVENT_PORT_ERR || if (record->element.port_num != priv->port)
record->event == IB_EVENT_PKEY_CHANGE || return;
if (record->event == IB_EVENT_PORT_ERR ||
record->event == IB_EVENT_PORT_ACTIVE || record->event == IB_EVENT_PORT_ACTIVE ||
record->event == IB_EVENT_LID_CHANGE || record->event == IB_EVENT_LID_CHANGE ||
record->event == IB_EVENT_SM_CHANGE || record->event == IB_EVENT_SM_CHANGE ||
record->event == IB_EVENT_CLIENT_REREGISTER) && record->event == IB_EVENT_CLIENT_REREGISTER) {
record->element.port_num == priv->port) {
ipoib_dbg(priv, "Port state change event\n"); ipoib_dbg(priv, "Port state change event\n");
queue_work(ipoib_workqueue, &priv->flush_task); queue_work(ipoib_workqueue, &priv->flush_task);
} else if (record->event == IB_EVENT_PKEY_CHANGE) {
ipoib_dbg(priv, "P_Key change event on port:%d\n", priv->port);
queue_work(ipoib_workqueue, &priv->pkey_event_task);
} }
} }
...@@ -90,7 +90,7 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u32 flags) ...@@ -90,7 +90,7 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u32 flags)
int i; int i;
mlx4_dbg(dev, "DEV_CAP flags:\n"); mlx4_dbg(dev, "DEV_CAP flags:\n");
for (i = 0; i < 32; ++i) for (i = 0; i < ARRAY_SIZE(fname); ++i)
if (fname[i] && (flags & (1 << i))) if (fname[i] && (flags & (1 << i)))
mlx4_dbg(dev, " %s\n", fname[i]); mlx4_dbg(dev, " %s\n", fname[i]);
} }
......
...@@ -890,6 +890,8 @@ struct ib_device { ...@@ -890,6 +890,8 @@ struct ib_device {
spinlock_t client_data_lock; spinlock_t client_data_lock;
struct ib_cache cache; struct ib_cache cache;
int *pkey_tbl_len;
int *gid_tbl_len;
u32 flags; u32 flags;
...@@ -1118,6 +1120,12 @@ int ib_modify_port(struct ib_device *device, ...@@ -1118,6 +1120,12 @@ int ib_modify_port(struct ib_device *device,
u8 port_num, int port_modify_mask, u8 port_num, int port_modify_mask,
struct ib_port_modify *port_modify); struct ib_port_modify *port_modify);
int ib_find_gid(struct ib_device *device, union ib_gid *gid,
u8 *port_num, u16 *index);
int ib_find_pkey(struct ib_device *device,
u8 port_num, u16 pkey, u16 *index);
/** /**
* ib_alloc_pd - Allocates an unused protection domain. * ib_alloc_pd - Allocates an unused protection domain.
* @device: The device on which to allocate the protection domain. * @device: The device on which to allocate the protection domain.
......
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