Commit 3af73d39 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: (29 commits)
  RDMA/nes: Fix slab corruption
  IB/mlx4: Set RLKEY bit for kernel QPs
  RDMA/nes: Correct error_module bit mask
  RDMA/nes: Fix routed RDMA connections
  RDMA/nes: Enhanced PFT management scheme
  RDMA/nes: Handle AE bounds violation
  RDMA/nes: Limit critical error interrupts
  RDMA/nes: Stop spurious MAC interrupts
  RDMA/nes: Correct tso_wqe_length
  RDMA/nes: Fill in firmware version for ethtool
  RDMA/nes: Use ethtool timer value
  RDMA/nes: Correct MAX TSO frags value
  RDMA/nes: Enable MC/UC after changing MTU
  RDMA/nes: Free NIC TX buffers when destroying NIC QP
  RDMA/nes: Fix MDC setting
  RDMA/nes: Add wqm_quanta module option
  RDMA/nes: Module parameter permissions
  RDMA/cxgb3: Set active_mtu in ib_port_attr
  RDMA/nes: Add support for 4-port 1G HP blade card
  RDMA/nes: Make mini_cm_connect() static
  ...
parents 13dd7f87 eedd5d0a
...@@ -3748,6 +3748,7 @@ static void cm_add_one(struct ib_device *ib_device) ...@@ -3748,6 +3748,7 @@ static void cm_add_one(struct ib_device *ib_device)
cm_remove_port_fs(port); cm_remove_port_fs(port);
} }
device_unregister(cm_dev->device); device_unregister(cm_dev->device);
kfree(cm_dev);
} }
static void cm_remove_one(struct ib_device *ib_device) static void cm_remove_one(struct ib_device *ib_device)
...@@ -3776,6 +3777,7 @@ static void cm_remove_one(struct ib_device *ib_device) ...@@ -3776,6 +3777,7 @@ static void cm_remove_one(struct ib_device *ib_device)
cm_remove_port_fs(port); cm_remove_port_fs(port);
} }
device_unregister(cm_dev->device); device_unregister(cm_dev->device);
kfree(cm_dev);
} }
static int __init ib_cm_init(void) static int __init ib_cm_init(void)
......
...@@ -1697,9 +1697,8 @@ static inline int rcv_has_same_gid(struct ib_mad_agent_private *mad_agent_priv, ...@@ -1697,9 +1697,8 @@ static inline int rcv_has_same_gid(struct ib_mad_agent_private *mad_agent_priv,
u8 port_num = mad_agent_priv->agent.port_num; u8 port_num = mad_agent_priv->agent.port_num;
u8 lmc; u8 lmc;
send_resp = ((struct ib_mad *)(wr->send_buf.mad))-> send_resp = ib_response_mad((struct ib_mad *)wr->send_buf.mad);
mad_hdr.method & IB_MGMT_METHOD_RESP; rcv_resp = ib_response_mad(rwc->recv_buf.mad);
rcv_resp = rwc->recv_buf.mad->mad_hdr.method & IB_MGMT_METHOD_RESP;
if (send_resp == rcv_resp) if (send_resp == rcv_resp)
/* both requests, or both responses. GIDs different */ /* both requests, or both responses. GIDs different */
......
...@@ -272,7 +272,6 @@ static struct ib_qp *c2_create_qp(struct ib_pd *pd, ...@@ -272,7 +272,6 @@ static struct ib_qp *c2_create_qp(struct ib_pd *pd,
pr_debug("%s: Invalid QP type: %d\n", __func__, pr_debug("%s: Invalid QP type: %d\n", __func__,
init_attr->qp_type); init_attr->qp_type);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
break;
} }
if (err) { if (err) {
......
...@@ -1155,13 +1155,11 @@ static int iwch_query_port(struct ib_device *ibdev, ...@@ -1155,13 +1155,11 @@ static int iwch_query_port(struct ib_device *ibdev,
u8 port, struct ib_port_attr *props) u8 port, struct ib_port_attr *props)
{ {
PDBG("%s ibdev %p\n", __func__, ibdev); PDBG("%s ibdev %p\n", __func__, ibdev);
memset(props, 0, sizeof(struct ib_port_attr));
props->max_mtu = IB_MTU_4096; props->max_mtu = IB_MTU_4096;
props->lid = 0; props->active_mtu = IB_MTU_2048;
props->lmc = 0;
props->sm_lid = 0;
props->sm_sl = 0;
props->state = IB_PORT_ACTIVE; props->state = IB_PORT_ACTIVE;
props->phys_state = 0;
props->port_cap_flags = props->port_cap_flags =
IB_PORT_CM_SUP | IB_PORT_CM_SUP |
IB_PORT_SNMP_TUNNEL_SUP | IB_PORT_SNMP_TUNNEL_SUP |
...@@ -1170,7 +1168,6 @@ static int iwch_query_port(struct ib_device *ibdev, ...@@ -1170,7 +1168,6 @@ static int iwch_query_port(struct ib_device *ibdev,
IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP; IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP;
props->gid_tbl_len = 1; props->gid_tbl_len = 1;
props->pkey_tbl_len = 1; props->pkey_tbl_len = 1;
props->qkey_viol_cntr = 0;
props->active_width = 2; props->active_width = 2;
props->active_speed = 2; props->active_speed = 2;
props->max_msg_sz = -1; props->max_msg_sz = -1;
......
...@@ -164,6 +164,13 @@ struct ehca_qmap_entry { ...@@ -164,6 +164,13 @@ struct ehca_qmap_entry {
u16 reported; u16 reported;
}; };
struct ehca_queue_map {
struct ehca_qmap_entry *map;
unsigned int entries;
unsigned int tail;
unsigned int left_to_poll;
};
struct ehca_qp { struct ehca_qp {
union { union {
struct ib_qp ib_qp; struct ib_qp ib_qp;
...@@ -173,8 +180,9 @@ struct ehca_qp { ...@@ -173,8 +180,9 @@ 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 ehca_queue_map sq_map;
struct ipz_queue ipz_rqueue; struct ipz_queue ipz_rqueue;
struct ehca_queue_map rq_map;
struct h_galpas galpas; struct h_galpas galpas;
u32 qkey; u32 qkey;
u32 real_qp_num; u32 real_qp_num;
...@@ -204,6 +212,8 @@ struct ehca_qp { ...@@ -204,6 +212,8 @@ struct ehca_qp {
atomic_t nr_events; /* events seen */ atomic_t nr_events; /* events seen */
wait_queue_head_t wait_completion; wait_queue_head_t wait_completion;
int mig_armed; int mig_armed;
struct list_head sq_err_node;
struct list_head rq_err_node;
}; };
#define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ) #define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ)
...@@ -233,6 +243,8 @@ struct ehca_cq { ...@@ -233,6 +243,8 @@ struct ehca_cq {
/* mmap counter for resources mapped into user space */ /* mmap counter for resources mapped into user space */
u32 mm_count_queue; u32 mm_count_queue;
u32 mm_count_galpa; u32 mm_count_galpa;
struct list_head sqp_err_list;
struct list_head rqp_err_list;
}; };
enum ehca_mr_flag { enum ehca_mr_flag {
......
...@@ -276,6 +276,9 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, ...@@ -276,6 +276,9 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
for (i = 0; i < QP_HASHTAB_LEN; i++) for (i = 0; i < QP_HASHTAB_LEN; i++)
INIT_HLIST_HEAD(&my_cq->qp_hashtab[i]); INIT_HLIST_HEAD(&my_cq->qp_hashtab[i]);
INIT_LIST_HEAD(&my_cq->sqp_err_list);
INIT_LIST_HEAD(&my_cq->rqp_err_list);
if (context) { if (context) {
struct ipz_queue *ipz_queue = &my_cq->ipz_queue; struct ipz_queue *ipz_queue = &my_cq->ipz_queue;
struct ehca_create_cq_resp resp; struct ehca_create_cq_resp resp;
......
...@@ -197,6 +197,8 @@ void ehca_poll_eqs(unsigned long data); ...@@ -197,6 +197,8 @@ void ehca_poll_eqs(unsigned long data);
int ehca_calc_ipd(struct ehca_shca *shca, int port, int ehca_calc_ipd(struct ehca_shca *shca, int port,
enum ib_rate path_rate, u32 *ipd); enum ib_rate path_rate, u32 *ipd);
void ehca_add_to_err_list(struct ehca_qp *qp, int on_sq);
#ifdef CONFIG_PPC_64K_PAGES #ifdef CONFIG_PPC_64K_PAGES
void *ehca_alloc_fw_ctrlblock(gfp_t flags); void *ehca_alloc_fw_ctrlblock(gfp_t flags);
void ehca_free_fw_ctrlblock(void *ptr); void ehca_free_fw_ctrlblock(void *ptr);
......
...@@ -396,6 +396,50 @@ static void ehca_determine_small_queue(struct ehca_alloc_queue_parms *queue, ...@@ -396,6 +396,50 @@ static void ehca_determine_small_queue(struct ehca_alloc_queue_parms *queue,
queue->is_small = (queue->page_size != 0); queue->is_small = (queue->page_size != 0);
} }
/* needs to be called with cq->spinlock held */
void ehca_add_to_err_list(struct ehca_qp *qp, int on_sq)
{
struct list_head *list, *node;
/* TODO: support low latency QPs */
if (qp->ext_type == EQPT_LLQP)
return;
if (on_sq) {
list = &qp->send_cq->sqp_err_list;
node = &qp->sq_err_node;
} else {
list = &qp->recv_cq->rqp_err_list;
node = &qp->rq_err_node;
}
if (list_empty(node))
list_add_tail(node, list);
return;
}
static void del_from_err_list(struct ehca_cq *cq, struct list_head *node)
{
unsigned long flags;
spin_lock_irqsave(&cq->spinlock, flags);
if (!list_empty(node))
list_del_init(node);
spin_unlock_irqrestore(&cq->spinlock, flags);
}
static void reset_queue_map(struct ehca_queue_map *qmap)
{
int i;
qmap->tail = 0;
for (i = 0; i < qmap->entries; i++)
qmap->map[i].reported = 1;
}
/* /*
* Create an ib_qp struct that is either a QP or an SRQ, depending on * Create an ib_qp struct that is either a QP or an SRQ, depending on
* the value of the is_srq parameter. If init_attr and srq_init_attr share * the value of the is_srq parameter. If init_attr and srq_init_attr share
...@@ -407,12 +451,11 @@ static struct ehca_qp *internal_create_qp( ...@@ -407,12 +451,11 @@ static struct ehca_qp *internal_create_qp(
struct ib_srq_init_attr *srq_init_attr, struct ib_srq_init_attr *srq_init_attr,
struct ib_udata *udata, int is_srq) struct ib_udata *udata, int is_srq)
{ {
struct ehca_qp *my_qp; struct ehca_qp *my_qp, *my_srq = NULL;
struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd); struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
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;
...@@ -457,8 +500,7 @@ static struct ehca_qp *internal_create_qp( ...@@ -457,8 +500,7 @@ static struct ehca_qp *internal_create_qp(
/* handle SRQ base QPs */ /* handle SRQ base QPs */
if (init_attr->srq) { if (init_attr->srq) {
struct ehca_qp *my_srq = my_srq = container_of(init_attr->srq, struct ehca_qp, ib_srq);
container_of(init_attr->srq, struct ehca_qp, ib_srq);
has_srq = 1; has_srq = 1;
parms.ext_type = EQPT_SRQBASE; parms.ext_type = EQPT_SRQBASE;
...@@ -716,15 +758,19 @@ static struct ehca_qp *internal_create_qp( ...@@ -716,15 +758,19 @@ 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->sq_map.entries = my_qp->ipz_squeue.queue_length /
my_qp->ipz_squeue.qe_size; my_qp->ipz_squeue.qe_size;
my_qp->sq_map = vmalloc(nr_qes * my_qp->sq_map.map = vmalloc(my_qp->sq_map.entries *
sizeof(struct ehca_qmap_entry)); sizeof(struct ehca_qmap_entry));
if (!my_qp->sq_map) { if (!my_qp->sq_map.map) {
ehca_err(pd->device, "Couldn't allocate squeue " ehca_err(pd->device, "Couldn't allocate squeue "
"map ret=%i", ret); "map ret=%i", ret);
goto create_qp_exit3; goto create_qp_exit3;
} }
INIT_LIST_HEAD(&my_qp->sq_err_node);
/* to avoid the generation of bogus flush CQEs */
reset_queue_map(&my_qp->sq_map);
} }
if (HAS_RQ(my_qp)) { if (HAS_RQ(my_qp)) {
...@@ -736,6 +782,25 @@ static struct ehca_qp *internal_create_qp( ...@@ -736,6 +782,25 @@ static struct ehca_qp *internal_create_qp(
"and pages ret=%i", ret); "and pages ret=%i", ret);
goto create_qp_exit4; goto create_qp_exit4;
} }
my_qp->rq_map.entries = my_qp->ipz_rqueue.queue_length /
my_qp->ipz_rqueue.qe_size;
my_qp->rq_map.map = vmalloc(my_qp->rq_map.entries *
sizeof(struct ehca_qmap_entry));
if (!my_qp->rq_map.map) {
ehca_err(pd->device, "Couldn't allocate squeue "
"map ret=%i", ret);
goto create_qp_exit5;
}
INIT_LIST_HEAD(&my_qp->rq_err_node);
/* to avoid the generation of bogus flush CQEs */
reset_queue_map(&my_qp->rq_map);
} else if (init_attr->srq) {
/* this is a base QP, use the queue map of the SRQ */
my_qp->rq_map = my_srq->rq_map;
INIT_LIST_HEAD(&my_qp->rq_err_node);
my_qp->ipz_rqueue = my_srq->ipz_rqueue;
} }
if (is_srq) { if (is_srq) {
...@@ -799,7 +864,7 @@ static struct ehca_qp *internal_create_qp( ...@@ -799,7 +864,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_exit6; goto create_qp_exit7;
} }
} }
...@@ -825,25 +890,29 @@ static struct ehca_qp *internal_create_qp( ...@@ -825,25 +890,29 @@ 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_exit7; goto create_qp_exit8;
} }
} }
return my_qp; return my_qp;
create_qp_exit7: create_qp_exit8:
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_exit6: create_qp_exit7:
kfree(my_qp->mod_qp_parm); kfree(my_qp->mod_qp_parm);
create_qp_exit6:
if (HAS_RQ(my_qp))
vfree(my_qp->rq_map.map);
create_qp_exit5: 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: create_qp_exit4:
if (HAS_SQ(my_qp)) if (HAS_SQ(my_qp))
vfree(my_qp->sq_map); vfree(my_qp->sq_map.map);
create_qp_exit3: create_qp_exit3:
if (HAS_SQ(my_qp)) if (HAS_SQ(my_qp))
...@@ -1035,6 +1104,101 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca, ...@@ -1035,6 +1104,101 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
return 0; return 0;
} }
static int calc_left_cqes(u64 wqe_p, struct ipz_queue *ipz_queue,
struct ehca_queue_map *qmap)
{
void *wqe_v;
u64 q_ofs;
u32 wqe_idx;
/* convert real to abs address */
wqe_p = wqe_p & (~(1UL << 63));
wqe_v = abs_to_virt(wqe_p);
if (ipz_queue_abs_to_offset(ipz_queue, wqe_p, &q_ofs)) {
ehca_gen_err("Invalid offset for calculating left cqes "
"wqe_p=%#lx wqe_v=%p\n", wqe_p, wqe_v);
return -EFAULT;
}
wqe_idx = q_ofs / ipz_queue->qe_size;
if (wqe_idx < qmap->tail)
qmap->left_to_poll = (qmap->entries - qmap->tail) + wqe_idx;
else
qmap->left_to_poll = wqe_idx - qmap->tail;
return 0;
}
static int check_for_left_cqes(struct ehca_qp *my_qp, struct ehca_shca *shca)
{
u64 h_ret;
void *send_wqe_p, *recv_wqe_p;
int ret;
unsigned long flags;
int qp_num = my_qp->ib_qp.qp_num;
/* this hcall is not supported on base QPs */
if (my_qp->ext_type != EQPT_SRQBASE) {
/* get send and receive wqe pointer */
h_ret = hipz_h_disable_and_get_wqe(shca->ipz_hca_handle,
my_qp->ipz_qp_handle, &my_qp->pf,
&send_wqe_p, &recv_wqe_p, 4);
if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "disable_and_get_wqe() "
"failed ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, qp_num, h_ret);
return ehca2ib_return_code(h_ret);
}
/*
* acquire lock to ensure that nobody is polling the cq which
* could mean that the qmap->tail pointer is in an
* inconsistent state.
*/
spin_lock_irqsave(&my_qp->send_cq->spinlock, flags);
ret = calc_left_cqes((u64)send_wqe_p, &my_qp->ipz_squeue,
&my_qp->sq_map);
spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags);
if (ret)
return ret;
spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags);
ret = calc_left_cqes((u64)recv_wqe_p, &my_qp->ipz_rqueue,
&my_qp->rq_map);
spin_unlock_irqrestore(&my_qp->recv_cq->spinlock, flags);
if (ret)
return ret;
} else {
spin_lock_irqsave(&my_qp->send_cq->spinlock, flags);
my_qp->sq_map.left_to_poll = 0;
spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags);
spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags);
my_qp->rq_map.left_to_poll = 0;
spin_unlock_irqrestore(&my_qp->recv_cq->spinlock, flags);
}
/* this assures flush cqes being generated only for pending wqes */
if ((my_qp->sq_map.left_to_poll == 0) &&
(my_qp->rq_map.left_to_poll == 0)) {
spin_lock_irqsave(&my_qp->send_cq->spinlock, flags);
ehca_add_to_err_list(my_qp, 1);
spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags);
if (HAS_RQ(my_qp)) {
spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags);
ehca_add_to_err_list(my_qp, 0);
spin_unlock_irqrestore(&my_qp->recv_cq->spinlock,
flags);
}
}
return 0;
}
/* /*
* internal_modify_qp with circumvention to handle aqp0 properly * internal_modify_qp with circumvention to handle aqp0 properly
* smi_reset2init indicates if this is an internal reset-to-init-call for * smi_reset2init indicates if this is an internal reset-to-init-call for
...@@ -1539,10 +1703,27 @@ static int internal_modify_qp(struct ib_qp *ibqp, ...@@ -1539,10 +1703,27 @@ static int internal_modify_qp(struct ib_qp *ibqp,
goto modify_qp_exit2; goto modify_qp_exit2;
} }
} }
if ((qp_new_state == IB_QPS_ERR) && (qp_cur_state != IB_QPS_ERR)) {
ret = check_for_left_cqes(my_qp, shca);
if (ret)
goto modify_qp_exit2;
}
if (statetrans == IB_QPST_ANY2RESET) { if (statetrans == IB_QPST_ANY2RESET) {
ipz_qeit_reset(&my_qp->ipz_rqueue); ipz_qeit_reset(&my_qp->ipz_rqueue);
ipz_qeit_reset(&my_qp->ipz_squeue); ipz_qeit_reset(&my_qp->ipz_squeue);
if (qp_cur_state == IB_QPS_ERR) {
del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node);
if (HAS_RQ(my_qp))
del_from_err_list(my_qp->recv_cq,
&my_qp->rq_err_node);
}
reset_queue_map(&my_qp->sq_map);
if (HAS_RQ(my_qp))
reset_queue_map(&my_qp->rq_map);
} }
if (attr_mask & IB_QP_QKEY) if (attr_mask & IB_QP_QKEY)
...@@ -1958,6 +2139,16 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, ...@@ -1958,6 +2139,16 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
idr_remove(&ehca_qp_idr, my_qp->token); idr_remove(&ehca_qp_idr, my_qp->token);
write_unlock_irqrestore(&ehca_qp_idr_lock, flags); write_unlock_irqrestore(&ehca_qp_idr_lock, flags);
/*
* SRQs will never get into an error list and do not have a recv_cq,
* so we need to skip them here.
*/
if (HAS_RQ(my_qp) && !IS_SRQ(my_qp))
del_from_err_list(my_qp->recv_cq, &my_qp->rq_err_node);
if (HAS_SQ(my_qp))
del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node);
/* now wait until all pending events have completed */ /* now wait until all pending events have completed */
wait_event(my_qp->wait_completion, !atomic_read(&my_qp->nr_events)); wait_event(my_qp->wait_completion, !atomic_read(&my_qp->nr_events));
...@@ -1983,7 +2174,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, ...@@ -1983,7 +2174,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
if (qp_type == IB_QPT_GSI) { if (qp_type == IB_QPT_GSI) {
struct ib_event event; struct ib_event event;
ehca_info(dev, "device %s: port %x is inactive.", ehca_info(dev, "device %s: port %x is inactive.",
shca->ib_device.name, port_num); shca->ib_device.name, port_num);
event.device = &shca->ib_device; event.device = &shca->ib_device;
event.event = IB_EVENT_PORT_ERR; event.event = IB_EVENT_PORT_ERR;
event.element.port_num = port_num; event.element.port_num = port_num;
...@@ -1991,11 +2182,15 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, ...@@ -1991,11 +2182,15 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
ib_dispatch_event(&event); ib_dispatch_event(&event);
} }
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);
vfree(my_qp->rq_map.map);
}
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);
vfree(my_qp->sq_map.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);
......
...@@ -53,9 +53,25 @@ ...@@ -53,9 +53,25 @@
/* in RC traffic, insert an empty RDMA READ every this many packets */ /* in RC traffic, insert an empty RDMA READ every this many packets */
#define ACK_CIRC_THRESHOLD 2000000 #define ACK_CIRC_THRESHOLD 2000000
static u64 replace_wr_id(u64 wr_id, u16 idx)
{
u64 ret;
ret = wr_id & ~QMAP_IDX_MASK;
ret |= idx & QMAP_IDX_MASK;
return ret;
}
static u16 get_app_wr_id(u64 wr_id)
{
return wr_id & QMAP_IDX_MASK;
}
static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue, static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
struct ehca_wqe *wqe_p, struct ehca_wqe *wqe_p,
struct ib_recv_wr *recv_wr) struct ib_recv_wr *recv_wr,
u32 rq_map_idx)
{ {
u8 cnt_ds; u8 cnt_ds;
if (unlikely((recv_wr->num_sge < 0) || if (unlikely((recv_wr->num_sge < 0) ||
...@@ -69,7 +85,7 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue, ...@@ -69,7 +85,7 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
/* 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 = recv_wr->wr_id; wqe_p->work_request_id = replace_wr_id(recv_wr->wr_id, rq_map_idx);
wqe_p->nr_of_data_seg = recv_wr->num_sge; wqe_p->nr_of_data_seg = recv_wr->num_sge;
for (cnt_ds = 0; cnt_ds < recv_wr->num_sge; cnt_ds++) { for (cnt_ds = 0; cnt_ds < recv_wr->num_sge; cnt_ds++) {
...@@ -146,6 +162,7 @@ static inline int ehca_write_swqe(struct ehca_qp *qp, ...@@ -146,6 +162,7 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
u64 dma_length; u64 dma_length;
struct ehca_av *my_av; struct ehca_av *my_av;
u32 remote_qkey = send_wr->wr.ud.remote_qkey; u32 remote_qkey = send_wr->wr.ud.remote_qkey;
struct ehca_qmap_entry *qmap_entry = &qp->sq_map.map[sq_map_idx];
if (unlikely((send_wr->num_sge < 0) || if (unlikely((send_wr->num_sge < 0) ||
(send_wr->num_sge > qp->ipz_squeue.act_nr_of_sg))) { (send_wr->num_sge > qp->ipz_squeue.act_nr_of_sg))) {
...@@ -158,11 +175,10 @@ static inline int ehca_write_swqe(struct ehca_qp *qp, ...@@ -158,11 +175,10 @@ 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 & ~QMAP_IDX_MASK; wqe_p->work_request_id = replace_wr_id(send_wr->wr_id, sq_map_idx);
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; qmap_entry->app_wr_id = get_app_wr_id(send_wr->wr_id);
qp->sq_map[sq_map_idx].reported = 0; qmap_entry->reported = 0;
switch (send_wr->opcode) { switch (send_wr->opcode) {
case IB_WR_SEND: case IB_WR_SEND:
...@@ -496,7 +512,9 @@ static int internal_post_recv(struct ehca_qp *my_qp, ...@@ -496,7 +512,9 @@ static int internal_post_recv(struct ehca_qp *my_qp,
struct ehca_wqe *wqe_p; struct ehca_wqe *wqe_p;
int wqe_cnt = 0; int wqe_cnt = 0;
int ret = 0; int ret = 0;
u32 rq_map_idx;
unsigned long flags; unsigned long flags;
struct ehca_qmap_entry *qmap_entry;
if (unlikely(!HAS_RQ(my_qp))) { if (unlikely(!HAS_RQ(my_qp))) {
ehca_err(dev, "QP has no RQ ehca_qp=%p qp_num=%x ext_type=%d", ehca_err(dev, "QP has no RQ ehca_qp=%p qp_num=%x ext_type=%d",
...@@ -524,8 +542,15 @@ static int internal_post_recv(struct ehca_qp *my_qp, ...@@ -524,8 +542,15 @@ static int internal_post_recv(struct ehca_qp *my_qp,
} }
goto post_recv_exit0; goto post_recv_exit0;
} }
/*
* Get the index of the WQE in the recv queue. The same index
* is used for writing into the rq_map.
*/
rq_map_idx = start_offset / my_qp->ipz_rqueue.qe_size;
/* write a RECV WQE into the QUEUE */ /* write a RECV WQE into the QUEUE */
ret = ehca_write_rwqe(&my_qp->ipz_rqueue, wqe_p, cur_recv_wr); ret = ehca_write_rwqe(&my_qp->ipz_rqueue, wqe_p, cur_recv_wr,
rq_map_idx);
/* /*
* if something failed, * if something failed,
* reset the free entry pointer to the start value * reset the free entry pointer to the start value
...@@ -540,6 +565,11 @@ static int internal_post_recv(struct ehca_qp *my_qp, ...@@ -540,6 +565,11 @@ static int internal_post_recv(struct ehca_qp *my_qp,
} }
goto post_recv_exit0; goto post_recv_exit0;
} }
qmap_entry = &my_qp->rq_map.map[rq_map_idx];
qmap_entry->app_wr_id = get_app_wr_id(cur_recv_wr->wr_id);
qmap_entry->reported = 0;
wqe_cnt++; wqe_cnt++;
} /* eof for cur_recv_wr */ } /* eof for cur_recv_wr */
...@@ -596,10 +626,12 @@ static const u8 ib_wc_opcode[255] = { ...@@ -596,10 +626,12 @@ static const u8 ib_wc_opcode[255] = {
/* internal function to poll one entry of cq */ /* internal function to poll one entry of cq */
static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc) static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
{ {
int ret = 0; int ret = 0, qmap_tail_idx;
struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
struct ehca_cqe *cqe; struct ehca_cqe *cqe;
struct ehca_qp *my_qp; struct ehca_qp *my_qp;
struct ehca_qmap_entry *qmap_entry;
struct ehca_queue_map *qmap;
int cqe_count = 0, is_error; int cqe_count = 0, is_error;
repoll: repoll:
...@@ -674,27 +706,52 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc) ...@@ -674,27 +706,52 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
goto repoll; goto repoll;
wc->qp = &my_qp->ib_qp; wc->qp = &my_qp->ib_qp;
if (!(cqe->w_completion_flags & WC_SEND_RECEIVE_BIT)) { if (is_error) {
struct ehca_qmap_entry *qmap_entry;
/* /*
* We got a send completion and need to restore the original * set left_to_poll to 0 because in error state, we will not
* wr_id. * get any additional CQEs
*/ */
qmap_entry = &my_qp->sq_map[cqe->work_request_id & ehca_add_to_err_list(my_qp, 1);
QMAP_IDX_MASK]; my_qp->sq_map.left_to_poll = 0;
if (qmap_entry->reported) { if (HAS_RQ(my_qp))
ehca_warn(cq->device, "Double cqe on qp_num=%#x", ehca_add_to_err_list(my_qp, 0);
my_qp->real_qp_num); my_qp->rq_map.left_to_poll = 0;
/* found a double cqe, discard it and read next one */ }
goto repoll;
} qmap_tail_idx = get_app_wr_id(cqe->work_request_id);
wc->wr_id = cqe->work_request_id & ~QMAP_IDX_MASK; if (!(cqe->w_completion_flags & WC_SEND_RECEIVE_BIT))
wc->wr_id |= qmap_entry->app_wr_id; /* We got a send completion. */
qmap_entry->reported = 1; qmap = &my_qp->sq_map;
} else else
/* We got a receive completion. */ /* We got a receive completion. */
wc->wr_id = cqe->work_request_id; qmap = &my_qp->rq_map;
qmap_entry = &qmap->map[qmap_tail_idx];
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 = replace_wr_id(cqe->work_request_id, qmap_entry->app_wr_id);
qmap_entry->reported = 1;
/* this is a proper completion, we need to advance the tail pointer */
if (++qmap->tail == qmap->entries)
qmap->tail = 0;
/* if left_to_poll is decremented to 0, add the QP to the error list */
if (qmap->left_to_poll > 0) {
qmap->left_to_poll--;
if ((my_qp->sq_map.left_to_poll == 0) &&
(my_qp->rq_map.left_to_poll == 0)) {
ehca_add_to_err_list(my_qp, 1);
if (HAS_RQ(my_qp))
ehca_add_to_err_list(my_qp, 0);
}
}
/* eval ib_wc_opcode */ /* eval ib_wc_opcode */
wc->opcode = ib_wc_opcode[cqe->optype]-1; wc->opcode = ib_wc_opcode[cqe->optype]-1;
...@@ -733,13 +790,88 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc) ...@@ -733,13 +790,88 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
return ret; return ret;
} }
static int generate_flush_cqes(struct ehca_qp *my_qp, struct ib_cq *cq,
struct ib_wc *wc, int num_entries,
struct ipz_queue *ipz_queue, int on_sq)
{
int nr = 0;
struct ehca_wqe *wqe;
u64 offset;
struct ehca_queue_map *qmap;
struct ehca_qmap_entry *qmap_entry;
if (on_sq)
qmap = &my_qp->sq_map;
else
qmap = &my_qp->rq_map;
qmap_entry = &qmap->map[qmap->tail];
while ((nr < num_entries) && (qmap_entry->reported == 0)) {
/* generate flush CQE */
memset(wc, 0, sizeof(*wc));
offset = qmap->tail * ipz_queue->qe_size;
wqe = (struct ehca_wqe *)ipz_qeit_calc(ipz_queue, offset);
if (!wqe) {
ehca_err(cq->device, "Invalid wqe offset=%#lx on "
"qp_num=%#x", offset, my_qp->real_qp_num);
return nr;
}
wc->wr_id = replace_wr_id(wqe->work_request_id,
qmap_entry->app_wr_id);
if (on_sq) {
switch (wqe->optype) {
case WQE_OPTYPE_SEND:
wc->opcode = IB_WC_SEND;
break;
case WQE_OPTYPE_RDMAWRITE:
wc->opcode = IB_WC_RDMA_WRITE;
break;
case WQE_OPTYPE_RDMAREAD:
wc->opcode = IB_WC_RDMA_READ;
break;
default:
ehca_err(cq->device, "Invalid optype=%x",
wqe->optype);
return nr;
}
} else
wc->opcode = IB_WC_RECV;
if (wqe->wr_flag & WQE_WRFLAG_IMM_DATA_PRESENT) {
wc->ex.imm_data = wqe->immediate_data;
wc->wc_flags |= IB_WC_WITH_IMM;
}
wc->status = IB_WC_WR_FLUSH_ERR;
wc->qp = &my_qp->ib_qp;
/* mark as reported and advance tail pointer */
qmap_entry->reported = 1;
if (++qmap->tail == qmap->entries)
qmap->tail = 0;
qmap_entry = &qmap->map[qmap->tail];
wc++; nr++;
}
return nr;
}
int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc) int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc)
{ {
struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
int nr; int nr;
struct ehca_qp *err_qp;
struct ib_wc *current_wc = wc; struct ib_wc *current_wc = wc;
int ret = 0; int ret = 0;
unsigned long flags; unsigned long flags;
int entries_left = num_entries;
if (num_entries < 1) { if (num_entries < 1) {
ehca_err(cq->device, "Invalid num_entries=%d ehca_cq=%p " ehca_err(cq->device, "Invalid num_entries=%d ehca_cq=%p "
...@@ -749,15 +881,40 @@ int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc) ...@@ -749,15 +881,40 @@ int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc)
} }
spin_lock_irqsave(&my_cq->spinlock, flags); spin_lock_irqsave(&my_cq->spinlock, flags);
for (nr = 0; nr < num_entries; nr++) {
/* generate flush cqes for send queues */
list_for_each_entry(err_qp, &my_cq->sqp_err_list, sq_err_node) {
nr = generate_flush_cqes(err_qp, cq, current_wc, entries_left,
&err_qp->ipz_squeue, 1);
entries_left -= nr;
current_wc += nr;
if (entries_left == 0)
break;
}
/* generate flush cqes for receive queues */
list_for_each_entry(err_qp, &my_cq->rqp_err_list, rq_err_node) {
nr = generate_flush_cqes(err_qp, cq, current_wc, entries_left,
&err_qp->ipz_rqueue, 0);
entries_left -= nr;
current_wc += nr;
if (entries_left == 0)
break;
}
for (nr = 0; nr < entries_left; nr++) {
ret = ehca_poll_cq_one(cq, current_wc); ret = ehca_poll_cq_one(cq, current_wc);
if (ret) if (ret)
break; break;
current_wc++; current_wc++;
} /* eof for nr */ } /* eof for nr */
entries_left -= nr;
spin_unlock_irqrestore(&my_cq->spinlock, flags); spin_unlock_irqrestore(&my_cq->spinlock, flags);
if (ret == -EAGAIN || !ret) if (ret == -EAGAIN || !ret)
ret = nr; ret = num_entries - entries_left;
poll_cq_exit0: poll_cq_exit0:
return ret; return ret;
......
...@@ -675,7 +675,8 @@ static void send_rc_ack(struct ipath_qp *qp) ...@@ -675,7 +675,8 @@ static void send_rc_ack(struct ipath_qp *qp)
hdr.lrh[0] = cpu_to_be16(lrh0); hdr.lrh[0] = cpu_to_be16(lrh0);
hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid); hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
hdr.lrh[2] = cpu_to_be16(hwords + SIZE_OF_CRC); hdr.lrh[2] = cpu_to_be16(hwords + SIZE_OF_CRC);
hdr.lrh[3] = cpu_to_be16(dd->ipath_lid); hdr.lrh[3] = cpu_to_be16(dd->ipath_lid |
qp->remote_ah_attr.src_path_bits);
ohdr->bth[0] = cpu_to_be32(bth0); ohdr->bth[0] = cpu_to_be32(bth0);
ohdr->bth[1] = cpu_to_be32(qp->remote_qpn); ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
ohdr->bth[2] = cpu_to_be32(qp->r_ack_psn & IPATH_PSN_MASK); ohdr->bth[2] = cpu_to_be32(qp->r_ack_psn & IPATH_PSN_MASK);
......
...@@ -618,7 +618,8 @@ void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp, ...@@ -618,7 +618,8 @@ void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp,
qp->s_hdr.lrh[0] = cpu_to_be16(lrh0); qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid); qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC); qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);
qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid); qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid |
qp->remote_ah_attr.src_path_bits);
bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index); bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index);
bth0 |= extra_bytes << 20; bth0 |= extra_bytes << 20;
ohdr->bth[0] = cpu_to_be32(bth0 | (1 << 22)); ohdr->bth[0] = cpu_to_be32(bth0 | (1 << 22));
......
...@@ -340,9 +340,16 @@ static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr) ...@@ -340,9 +340,16 @@ static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr)
int acc; int acc;
int ret; int ret;
unsigned long flags; unsigned long flags;
struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd;
spin_lock_irqsave(&qp->s_lock, flags); spin_lock_irqsave(&qp->s_lock, flags);
if (qp->ibqp.qp_type != IB_QPT_SMI &&
!(dd->ipath_flags & IPATH_LINKACTIVE)) {
ret = -ENETDOWN;
goto bail;
}
/* Check that state is OK to post send. */ /* Check that state is OK to post send. */
if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK))) if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)))
goto bail_inval; goto bail_inval;
......
...@@ -1058,6 +1058,9 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, ...@@ -1058,6 +1058,9 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
else else
sqd_event = 0; sqd_event = 0;
if (!ibqp->uobject && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
context->rlkey |= (1 << 4);
/* /*
* Before passing a kernel QP to the HW, make sure that the * Before passing a kernel QP to the HW, make sure that the
* ownership bits of the send queue are set and the SQ * ownership bits of the send queue are set and the SQ
......
...@@ -149,18 +149,10 @@ void mthca_start_catas_poll(struct mthca_dev *dev) ...@@ -149,18 +149,10 @@ void mthca_start_catas_poll(struct mthca_dev *dev)
((pci_resource_len(dev->pdev, 0) - 1) & ((pci_resource_len(dev->pdev, 0) - 1) &
dev->catas_err.addr); dev->catas_err.addr);
if (!request_mem_region(addr, dev->catas_err.size * 4,
DRV_NAME)) {
mthca_warn(dev, "couldn't request catastrophic error region "
"at 0x%lx/0x%x\n", addr, dev->catas_err.size * 4);
return;
}
dev->catas_err.map = ioremap(addr, dev->catas_err.size * 4); dev->catas_err.map = ioremap(addr, dev->catas_err.size * 4);
if (!dev->catas_err.map) { if (!dev->catas_err.map) {
mthca_warn(dev, "couldn't map catastrophic error region " mthca_warn(dev, "couldn't map catastrophic error region "
"at 0x%lx/0x%x\n", addr, dev->catas_err.size * 4); "at 0x%lx/0x%x\n", addr, dev->catas_err.size * 4);
release_mem_region(addr, dev->catas_err.size * 4);
return; return;
} }
...@@ -175,13 +167,8 @@ void mthca_stop_catas_poll(struct mthca_dev *dev) ...@@ -175,13 +167,8 @@ void mthca_stop_catas_poll(struct mthca_dev *dev)
{ {
del_timer_sync(&dev->catas_err.timer); del_timer_sync(&dev->catas_err.timer);
if (dev->catas_err.map) { if (dev->catas_err.map)
iounmap(dev->catas_err.map); iounmap(dev->catas_err.map);
release_mem_region(pci_resource_start(dev->pdev, 0) +
((pci_resource_len(dev->pdev, 0) - 1) &
dev->catas_err.addr),
dev->catas_err.size * 4);
}
spin_lock_irq(&catas_lock); spin_lock_irq(&catas_lock);
list_del(&dev->catas_err.list); list_del(&dev->catas_err.list);
......
...@@ -652,27 +652,13 @@ static int mthca_map_reg(struct mthca_dev *dev, ...@@ -652,27 +652,13 @@ static int mthca_map_reg(struct mthca_dev *dev,
{ {
unsigned long base = pci_resource_start(dev->pdev, 0); unsigned long base = pci_resource_start(dev->pdev, 0);
if (!request_mem_region(base + offset, size, DRV_NAME))
return -EBUSY;
*map = ioremap(base + offset, size); *map = ioremap(base + offset, size);
if (!*map) { if (!*map)
release_mem_region(base + offset, size);
return -ENOMEM; return -ENOMEM;
}
return 0; return 0;
} }
static void mthca_unmap_reg(struct mthca_dev *dev, unsigned long offset,
unsigned long size, void __iomem *map)
{
unsigned long base = pci_resource_start(dev->pdev, 0);
release_mem_region(base + offset, size);
iounmap(map);
}
static int mthca_map_eq_regs(struct mthca_dev *dev) static int mthca_map_eq_regs(struct mthca_dev *dev)
{ {
if (mthca_is_memfree(dev)) { if (mthca_is_memfree(dev)) {
...@@ -699,9 +685,7 @@ static int mthca_map_eq_regs(struct mthca_dev *dev) ...@@ -699,9 +685,7 @@ static int mthca_map_eq_regs(struct mthca_dev *dev)
dev->fw.arbel.eq_arm_base) + 4, 4, dev->fw.arbel.eq_arm_base) + 4, 4,
&dev->eq_regs.arbel.eq_arm)) { &dev->eq_regs.arbel.eq_arm)) {
mthca_err(dev, "Couldn't map EQ arm register, aborting.\n"); mthca_err(dev, "Couldn't map EQ arm register, aborting.\n");
mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) & iounmap(dev->clr_base);
dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
dev->clr_base);
return -ENOMEM; return -ENOMEM;
} }
...@@ -710,12 +694,8 @@ static int mthca_map_eq_regs(struct mthca_dev *dev) ...@@ -710,12 +694,8 @@ static int mthca_map_eq_regs(struct mthca_dev *dev)
MTHCA_EQ_SET_CI_SIZE, MTHCA_EQ_SET_CI_SIZE,
&dev->eq_regs.arbel.eq_set_ci_base)) { &dev->eq_regs.arbel.eq_set_ci_base)) {
mthca_err(dev, "Couldn't map EQ CI register, aborting.\n"); mthca_err(dev, "Couldn't map EQ CI register, aborting.\n");
mthca_unmap_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) & iounmap(dev->eq_regs.arbel.eq_arm);
dev->fw.arbel.eq_arm_base) + 4, 4, iounmap(dev->clr_base);
dev->eq_regs.arbel.eq_arm);
mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
dev->clr_base);
return -ENOMEM; return -ENOMEM;
} }
} else { } else {
...@@ -731,8 +711,7 @@ static int mthca_map_eq_regs(struct mthca_dev *dev) ...@@ -731,8 +711,7 @@ static int mthca_map_eq_regs(struct mthca_dev *dev)
&dev->eq_regs.tavor.ecr_base)) { &dev->eq_regs.tavor.ecr_base)) {
mthca_err(dev, "Couldn't map ecr register, " mthca_err(dev, "Couldn't map ecr register, "
"aborting.\n"); "aborting.\n");
mthca_unmap_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE, iounmap(dev->clr_base);
dev->clr_base);
return -ENOMEM; return -ENOMEM;
} }
} }
...@@ -744,22 +723,12 @@ static int mthca_map_eq_regs(struct mthca_dev *dev) ...@@ -744,22 +723,12 @@ static int mthca_map_eq_regs(struct mthca_dev *dev)
static void mthca_unmap_eq_regs(struct mthca_dev *dev) static void mthca_unmap_eq_regs(struct mthca_dev *dev)
{ {
if (mthca_is_memfree(dev)) { if (mthca_is_memfree(dev)) {
mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) & iounmap(dev->eq_regs.arbel.eq_set_ci_base);
dev->fw.arbel.eq_set_ci_base, iounmap(dev->eq_regs.arbel.eq_arm);
MTHCA_EQ_SET_CI_SIZE, iounmap(dev->clr_base);
dev->eq_regs.arbel.eq_set_ci_base);
mthca_unmap_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
dev->fw.arbel.eq_arm_base) + 4, 4,
dev->eq_regs.arbel.eq_arm);
mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
dev->clr_base);
} else { } else {
mthca_unmap_reg(dev, MTHCA_ECR_BASE, iounmap(dev->eq_regs.tavor.ecr_base);
MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE, iounmap(dev->clr_base);
dev->eq_regs.tavor.ecr_base);
mthca_unmap_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE,
dev->clr_base);
} }
} }
......
...@@ -921,58 +921,6 @@ static int mthca_setup_hca(struct mthca_dev *dev) ...@@ -921,58 +921,6 @@ static int mthca_setup_hca(struct mthca_dev *dev)
return err; return err;
} }
static int mthca_request_regions(struct pci_dev *pdev, int ddr_hidden)
{
int err;
/*
* We can't just use pci_request_regions() because the MSI-X
* table is right in the middle of the first BAR. If we did
* pci_request_region and grab all of the first BAR, then
* setting up MSI-X would fail, since the PCI core wants to do
* request_mem_region on the MSI-X vector table.
*
* So just request what we need right now, and request any
* other regions we need when setting up EQs.
*/
if (!request_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE,
MTHCA_HCR_SIZE, DRV_NAME))
return -EBUSY;
err = pci_request_region(pdev, 2, DRV_NAME);
if (err)
goto err_bar2_failed;
if (!ddr_hidden) {
err = pci_request_region(pdev, 4, DRV_NAME);
if (err)
goto err_bar4_failed;
}
return 0;
err_bar4_failed:
pci_release_region(pdev, 2);
err_bar2_failed:
release_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE,
MTHCA_HCR_SIZE);
return err;
}
static void mthca_release_regions(struct pci_dev *pdev,
int ddr_hidden)
{
if (!ddr_hidden)
pci_release_region(pdev, 4);
pci_release_region(pdev, 2);
release_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE,
MTHCA_HCR_SIZE);
}
static int mthca_enable_msi_x(struct mthca_dev *mdev) static int mthca_enable_msi_x(struct mthca_dev *mdev)
{ {
struct msix_entry entries[3]; struct msix_entry entries[3];
...@@ -1059,7 +1007,7 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) ...@@ -1059,7 +1007,7 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
if (!(pci_resource_flags(pdev, 4) & IORESOURCE_MEM)) if (!(pci_resource_flags(pdev, 4) & IORESOURCE_MEM))
ddr_hidden = 1; ddr_hidden = 1;
err = mthca_request_regions(pdev, ddr_hidden); err = pci_request_regions(pdev, DRV_NAME);
if (err) { if (err) {
dev_err(&pdev->dev, "Cannot obtain PCI resources, " dev_err(&pdev->dev, "Cannot obtain PCI resources, "
"aborting.\n"); "aborting.\n");
...@@ -1196,7 +1144,7 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) ...@@ -1196,7 +1144,7 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
ib_dealloc_device(&mdev->ib_dev); ib_dealloc_device(&mdev->ib_dev);
err_free_res: err_free_res:
mthca_release_regions(pdev, ddr_hidden); pci_release_regions(pdev);
err_disable_pdev: err_disable_pdev:
pci_disable_device(pdev); pci_disable_device(pdev);
...@@ -1240,8 +1188,7 @@ static void __mthca_remove_one(struct pci_dev *pdev) ...@@ -1240,8 +1188,7 @@ static void __mthca_remove_one(struct pci_dev *pdev)
pci_disable_msix(pdev); pci_disable_msix(pdev);
ib_dealloc_device(&mdev->ib_dev); ib_dealloc_device(&mdev->ib_dev);
mthca_release_regions(pdev, mdev->mthca_flags & pci_release_regions(pdev);
MTHCA_FLAG_DDR_HIDDEN);
pci_disable_device(pdev); pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
} }
......
...@@ -70,27 +70,31 @@ int interrupt_mod_interval = 0; ...@@ -70,27 +70,31 @@ int interrupt_mod_interval = 0;
/* Interoperability */ /* Interoperability */
int mpa_version = 1; int mpa_version = 1;
module_param(mpa_version, int, 0); module_param(mpa_version, int, 0644);
MODULE_PARM_DESC(mpa_version, "MPA version to be used int MPA Req/Resp (0 or 1)"); MODULE_PARM_DESC(mpa_version, "MPA version to be used int MPA Req/Resp (0 or 1)");
/* Interoperability */ /* Interoperability */
int disable_mpa_crc = 0; int disable_mpa_crc = 0;
module_param(disable_mpa_crc, int, 0); module_param(disable_mpa_crc, int, 0644);
MODULE_PARM_DESC(disable_mpa_crc, "Disable checking of MPA CRC"); MODULE_PARM_DESC(disable_mpa_crc, "Disable checking of MPA CRC");
unsigned int send_first = 0; unsigned int send_first = 0;
module_param(send_first, int, 0); module_param(send_first, int, 0644);
MODULE_PARM_DESC(send_first, "Send RDMA Message First on Active Connection"); MODULE_PARM_DESC(send_first, "Send RDMA Message First on Active Connection");
unsigned int nes_drv_opt = 0; unsigned int nes_drv_opt = 0;
module_param(nes_drv_opt, int, 0); module_param(nes_drv_opt, int, 0644);
MODULE_PARM_DESC(nes_drv_opt, "Driver option parameters"); MODULE_PARM_DESC(nes_drv_opt, "Driver option parameters");
unsigned int nes_debug_level = 0; unsigned int nes_debug_level = 0;
module_param_named(debug_level, nes_debug_level, uint, 0644); module_param_named(debug_level, nes_debug_level, uint, 0644);
MODULE_PARM_DESC(debug_level, "Enable debug output level"); MODULE_PARM_DESC(debug_level, "Enable debug output level");
unsigned int wqm_quanta = 0x10000;
module_param(wqm_quanta, int, 0644);
MODULE_PARM_DESC(wqm_quanta, "WQM quanta");
LIST_HEAD(nes_adapter_list); LIST_HEAD(nes_adapter_list);
static LIST_HEAD(nes_dev_list); static LIST_HEAD(nes_dev_list);
...@@ -557,12 +561,32 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i ...@@ -557,12 +561,32 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i
goto bail5; goto bail5;
} }
nesdev->nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval; nesdev->nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
nesdev->nesadapter->wqm_quanta = wqm_quanta;
/* nesdev->base_doorbell_index = /* nesdev->base_doorbell_index =
nesdev->nesadapter->pd_config_base[PCI_FUNC(nesdev->pcidev->devfn)]; */ nesdev->nesadapter->pd_config_base[PCI_FUNC(nesdev->pcidev->devfn)]; */
nesdev->base_doorbell_index = 1; nesdev->base_doorbell_index = 1;
nesdev->doorbell_start = nesdev->nesadapter->doorbell_start; nesdev->doorbell_start = nesdev->nesadapter->doorbell_start;
nesdev->mac_index = PCI_FUNC(nesdev->pcidev->devfn) % nesdev->nesadapter->port_count; if (nesdev->nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) {
switch (PCI_FUNC(nesdev->pcidev->devfn) %
nesdev->nesadapter->port_count) {
case 1:
nesdev->mac_index = 2;
break;
case 2:
nesdev->mac_index = 1;
break;
case 3:
nesdev->mac_index = 3;
break;
case 0:
default:
nesdev->mac_index = 0;
}
} else {
nesdev->mac_index = PCI_FUNC(nesdev->pcidev->devfn) %
nesdev->nesadapter->port_count;
}
tasklet_init(&nesdev->dpc_tasklet, nes_dpc, (unsigned long)nesdev); tasklet_init(&nesdev->dpc_tasklet, nes_dpc, (unsigned long)nesdev);
...@@ -581,7 +605,7 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i ...@@ -581,7 +605,7 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i
nesdev->int_req = (0x101 << PCI_FUNC(nesdev->pcidev->devfn)) | nesdev->int_req = (0x101 << PCI_FUNC(nesdev->pcidev->devfn)) |
(1 << (PCI_FUNC(nesdev->pcidev->devfn)+16)); (1 << (PCI_FUNC(nesdev->pcidev->devfn)+16));
if (PCI_FUNC(nesdev->pcidev->devfn) < 4) { if (PCI_FUNC(nesdev->pcidev->devfn) < 4) {
nesdev->int_req |= (1 << (PCI_FUNC(nesdev->pcidev->devfn)+24)); nesdev->int_req |= (1 << (PCI_FUNC(nesdev->mac_index)+24));
} }
/* TODO: This really should be the first driver to load, not function 0 */ /* TODO: This really should be the first driver to load, not function 0 */
...@@ -772,14 +796,14 @@ static ssize_t nes_show_adapter(struct device_driver *ddp, char *buf) ...@@ -772,14 +796,14 @@ static ssize_t nes_show_adapter(struct device_driver *ddp, char *buf)
list_for_each_entry(nesdev, &nes_dev_list, list) { list_for_each_entry(nesdev, &nes_dev_list, list) {
if (i == ee_flsh_adapter) { if (i == ee_flsh_adapter) {
devfn = nesdev->nesadapter->devfn; devfn = nesdev->pcidev->devfn;
bus_number = nesdev->nesadapter->bus_number; bus_number = nesdev->pcidev->bus->number;
break; break;
} }
i++; i++;
} }
return snprintf(buf, PAGE_SIZE, "%x:%x", bus_number, devfn); return snprintf(buf, PAGE_SIZE, "%x:%x\n", bus_number, devfn);
} }
static ssize_t nes_store_adapter(struct device_driver *ddp, static ssize_t nes_store_adapter(struct device_driver *ddp,
...@@ -1050,6 +1074,55 @@ static ssize_t nes_store_idx_data(struct device_driver *ddp, ...@@ -1050,6 +1074,55 @@ static ssize_t nes_store_idx_data(struct device_driver *ddp,
return strnlen(buf, count); return strnlen(buf, count);
} }
/**
* nes_show_wqm_quanta
*/
static ssize_t nes_show_wqm_quanta(struct device_driver *ddp, char *buf)
{
u32 wqm_quanta_value = 0xdead;
u32 i = 0;
struct nes_device *nesdev;
list_for_each_entry(nesdev, &nes_dev_list, list) {
if (i == ee_flsh_adapter) {
wqm_quanta_value = nesdev->nesadapter->wqm_quanta;
break;
}
i++;
}
return snprintf(buf, PAGE_SIZE, "0x%X\n", wqm_quanta);
}
/**
* nes_store_wqm_quanta
*/
static ssize_t nes_store_wqm_quanta(struct device_driver *ddp,
const char *buf, size_t count)
{
unsigned long wqm_quanta_value;
u32 wqm_config1;
u32 i = 0;
struct nes_device *nesdev;
strict_strtoul(buf, 0, &wqm_quanta_value);
list_for_each_entry(nesdev, &nes_dev_list, list) {
if (i == ee_flsh_adapter) {
nesdev->nesadapter->wqm_quanta = wqm_quanta_value;
wqm_config1 = nes_read_indexed(nesdev,
NES_IDX_WQM_CONFIG1);
nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG1,
((wqm_quanta_value << 1) |
(wqm_config1 & 0x00000001)));
break;
}
i++;
}
return strnlen(buf, count);
}
static DRIVER_ATTR(adapter, S_IRUSR | S_IWUSR, static DRIVER_ATTR(adapter, S_IRUSR | S_IWUSR,
nes_show_adapter, nes_store_adapter); nes_show_adapter, nes_store_adapter);
static DRIVER_ATTR(eeprom_cmd, S_IRUSR | S_IWUSR, static DRIVER_ATTR(eeprom_cmd, S_IRUSR | S_IWUSR,
...@@ -1068,6 +1141,8 @@ static DRIVER_ATTR(idx_addr, S_IRUSR | S_IWUSR, ...@@ -1068,6 +1141,8 @@ static DRIVER_ATTR(idx_addr, S_IRUSR | S_IWUSR,
nes_show_idx_addr, nes_store_idx_addr); nes_show_idx_addr, nes_store_idx_addr);
static DRIVER_ATTR(idx_data, S_IRUSR | S_IWUSR, static DRIVER_ATTR(idx_data, S_IRUSR | S_IWUSR,
nes_show_idx_data, nes_store_idx_data); nes_show_idx_data, nes_store_idx_data);
static DRIVER_ATTR(wqm_quanta, S_IRUSR | S_IWUSR,
nes_show_wqm_quanta, nes_store_wqm_quanta);
static int nes_create_driver_sysfs(struct pci_driver *drv) static int nes_create_driver_sysfs(struct pci_driver *drv)
{ {
...@@ -1081,6 +1156,7 @@ static int nes_create_driver_sysfs(struct pci_driver *drv) ...@@ -1081,6 +1156,7 @@ static int nes_create_driver_sysfs(struct pci_driver *drv)
error |= driver_create_file(&drv->driver, &driver_attr_nonidx_data); error |= driver_create_file(&drv->driver, &driver_attr_nonidx_data);
error |= driver_create_file(&drv->driver, &driver_attr_idx_addr); error |= driver_create_file(&drv->driver, &driver_attr_idx_addr);
error |= driver_create_file(&drv->driver, &driver_attr_idx_data); error |= driver_create_file(&drv->driver, &driver_attr_idx_data);
error |= driver_create_file(&drv->driver, &driver_attr_wqm_quanta);
return error; return error;
} }
...@@ -1095,6 +1171,7 @@ static void nes_remove_driver_sysfs(struct pci_driver *drv) ...@@ -1095,6 +1171,7 @@ static void nes_remove_driver_sysfs(struct pci_driver *drv)
driver_remove_file(&drv->driver, &driver_attr_nonidx_data); driver_remove_file(&drv->driver, &driver_attr_nonidx_data);
driver_remove_file(&drv->driver, &driver_attr_idx_addr); driver_remove_file(&drv->driver, &driver_attr_idx_addr);
driver_remove_file(&drv->driver, &driver_attr_idx_data); driver_remove_file(&drv->driver, &driver_attr_idx_data);
driver_remove_file(&drv->driver, &driver_attr_wqm_quanta);
} }
/** /**
......
...@@ -169,7 +169,7 @@ extern int disable_mpa_crc; ...@@ -169,7 +169,7 @@ extern int disable_mpa_crc;
extern unsigned int send_first; extern unsigned int send_first;
extern unsigned int nes_drv_opt; extern unsigned int nes_drv_opt;
extern unsigned int nes_debug_level; extern unsigned int nes_debug_level;
extern unsigned int wqm_quanta;
extern struct list_head nes_adapter_list; extern struct list_head nes_adapter_list;
extern atomic_t cm_connects; extern atomic_t cm_connects;
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
#include <linux/random.h> #include <linux/random.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/threads.h> #include <linux/threads.h>
#include <net/arp.h>
#include <net/neighbour.h> #include <net/neighbour.h>
#include <net/route.h> #include <net/route.h>
#include <net/ip_fib.h> #include <net/ip_fib.h>
...@@ -1019,23 +1019,43 @@ static inline int mini_cm_accelerated(struct nes_cm_core *cm_core, ...@@ -1019,23 +1019,43 @@ static inline int mini_cm_accelerated(struct nes_cm_core *cm_core,
/** /**
* nes_addr_send_arp * nes_addr_resolve_neigh
*/ */
static void nes_addr_send_arp(u32 dst_ip) static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip)
{ {
struct rtable *rt; struct rtable *rt;
struct flowi fl; struct flowi fl;
struct neighbour *neigh;
int rc = -1;
DECLARE_MAC_BUF(mac);
memset(&fl, 0, sizeof fl); memset(&fl, 0, sizeof fl);
fl.nl_u.ip4_u.daddr = htonl(dst_ip); fl.nl_u.ip4_u.daddr = htonl(dst_ip);
if (ip_route_output_key(&init_net, &rt, &fl)) { if (ip_route_output_key(&init_net, &rt, &fl)) {
printk("%s: ip_route_output_key failed for 0x%08X\n", printk("%s: ip_route_output_key failed for 0x%08X\n",
__func__, dst_ip); __func__, dst_ip);
return; return rc;
}
neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, nesvnic->netdev);
if (neigh) {
if (neigh->nud_state & NUD_VALID) {
nes_debug(NES_DBG_CM, "Neighbor MAC address for 0x%08X"
" is %s, Gateway is 0x%08X \n", dst_ip,
print_mac(mac, neigh->ha), ntohl(rt->rt_gateway));
nes_manage_arp_cache(nesvnic->netdev, neigh->ha,
dst_ip, NES_ARP_ADD);
rc = nes_arp_table(nesvnic->nesdev, dst_ip, NULL,
NES_ARP_RESOLVE);
}
neigh_release(neigh);
} }
neigh_event_send(rt->u.dst.neighbour, NULL); if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID)))
neigh_event_send(rt->u.dst.neighbour, NULL);
ip_rt_put(rt); ip_rt_put(rt);
return rc;
} }
...@@ -1108,9 +1128,11 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core, ...@@ -1108,9 +1128,11 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
/* get the mac addr for the remote node */ /* get the mac addr for the remote node */
arpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE); arpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE);
if (arpindex < 0) { if (arpindex < 0) {
kfree(cm_node); arpindex = nes_addr_resolve_neigh(nesvnic, cm_info->rem_addr);
nes_addr_send_arp(cm_info->rem_addr); if (arpindex < 0) {
return NULL; kfree(cm_node);
return NULL;
}
} }
/* copy the mac addr to node context */ /* copy the mac addr to node context */
...@@ -1826,7 +1848,7 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core, ...@@ -1826,7 +1848,7 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
/** /**
* mini_cm_connect - make a connection node with params * mini_cm_connect - make a connection node with params
*/ */
struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
struct nes_vnic *nesvnic, u16 private_data_len, struct nes_vnic *nesvnic, u16 private_data_len,
void *private_data, struct nes_cm_info *cm_info) void *private_data, struct nes_cm_info *cm_info)
{ {
...@@ -2007,7 +2029,6 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod ...@@ -2007,7 +2029,6 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod
ret = rem_ref_cm_node(cm_core, cm_node); ret = rem_ref_cm_node(cm_core, cm_node);
break; break;
} }
cm_node->cm_id = NULL;
return ret; return ret;
} }
......
This diff is collapsed.
...@@ -156,6 +156,7 @@ enum indexed_regs { ...@@ -156,6 +156,7 @@ enum indexed_regs {
NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI = 0x7004, NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI = 0x7004,
NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO = 0x7008, NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO = 0x7008,
NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI = 0x700c, NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI = 0x700c,
NES_IDX_WQM_CONFIG1 = 0x5004,
NES_IDX_CM_CONFIG = 0x5100, NES_IDX_CM_CONFIG = 0x5100,
NES_IDX_NIC_LOGPORT_TO_PHYPORT = 0x6000, NES_IDX_NIC_LOGPORT_TO_PHYPORT = 0x6000,
NES_IDX_NIC_PHYPORT_TO_USW = 0x6008, NES_IDX_NIC_PHYPORT_TO_USW = 0x6008,
...@@ -967,6 +968,7 @@ struct nes_arp_entry { ...@@ -967,6 +968,7 @@ struct nes_arp_entry {
#define DEFAULT_JUMBO_NES_QL_TARGET 40 #define DEFAULT_JUMBO_NES_QL_TARGET 40
#define DEFAULT_JUMBO_NES_QL_HIGH 128 #define DEFAULT_JUMBO_NES_QL_HIGH 128
#define NES_NIC_CQ_DOWNWARD_TREND 16 #define NES_NIC_CQ_DOWNWARD_TREND 16
#define NES_PFT_SIZE 48
struct nes_hw_tune_timer { struct nes_hw_tune_timer {
/* u16 cq_count; */ /* u16 cq_count; */
...@@ -1079,6 +1081,7 @@ struct nes_adapter { ...@@ -1079,6 +1081,7 @@ struct nes_adapter {
u32 et_rx_max_coalesced_frames_high; u32 et_rx_max_coalesced_frames_high;
u32 et_rate_sample_interval; u32 et_rate_sample_interval;
u32 timer_int_limit; u32 timer_int_limit;
u32 wqm_quanta;
/* Adapter base MAC address */ /* Adapter base MAC address */
u32 mac_addr_low; u32 mac_addr_low;
...@@ -1094,12 +1097,14 @@ struct nes_adapter { ...@@ -1094,12 +1097,14 @@ struct nes_adapter {
u16 pd_config_base[4]; u16 pd_config_base[4];
u16 link_interrupt_count[4]; u16 link_interrupt_count[4];
u8 crit_error_count[32];
/* the phy index for each port */ /* the phy index for each port */
u8 phy_index[4]; u8 phy_index[4];
u8 mac_sw_state[4]; u8 mac_sw_state[4];
u8 mac_link_down[4]; u8 mac_link_down[4];
u8 phy_type[4]; u8 phy_type[4];
u8 log_port;
/* PCI information */ /* PCI information */
unsigned int devfn; unsigned int devfn;
...@@ -1113,6 +1118,7 @@ struct nes_adapter { ...@@ -1113,6 +1118,7 @@ struct nes_adapter {
u8 virtwq; u8 virtwq;
u8 et_use_adaptive_rx_coalesce; u8 et_use_adaptive_rx_coalesce;
u8 adapter_fcn_count; u8 adapter_fcn_count;
u8 pft_mcast_map[NES_PFT_SIZE];
}; };
struct nes_pbl { struct nes_pbl {
......
This diff is collapsed.
...@@ -1467,7 +1467,6 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd, ...@@ -1467,7 +1467,6 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
default: default:
nes_debug(NES_DBG_QP, "Invalid QP type: %d\n", init_attr->qp_type); nes_debug(NES_DBG_QP, "Invalid QP type: %d\n", init_attr->qp_type);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
break;
} }
/* update the QP table */ /* update the QP table */
...@@ -2498,7 +2497,6 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, ...@@ -2498,7 +2497,6 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
nes_debug(NES_DBG_MR, "Leaving, ibmr=%p", ibmr); nes_debug(NES_DBG_MR, "Leaving, ibmr=%p", ibmr);
return ibmr; return ibmr;
break;
case IWNES_MEMREG_TYPE_QP: case IWNES_MEMREG_TYPE_QP:
case IWNES_MEMREG_TYPE_CQ: case IWNES_MEMREG_TYPE_CQ:
nespbl = kzalloc(sizeof(*nespbl), GFP_KERNEL); nespbl = kzalloc(sizeof(*nespbl), GFP_KERNEL);
...@@ -2572,7 +2570,6 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, ...@@ -2572,7 +2570,6 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
nesmr->ibmr.lkey = -1; nesmr->ibmr.lkey = -1;
nesmr->mode = req.reg_type; nesmr->mode = req.reg_type;
return &nesmr->ibmr; return &nesmr->ibmr;
break;
} }
return ERR_PTR(-ENOSYS); return ERR_PTR(-ENOSYS);
......
...@@ -268,10 +268,9 @@ struct ipoib_lro { ...@@ -268,10 +268,9 @@ struct ipoib_lro {
}; };
/* /*
* Device private locking: tx_lock protects members used in TX fast * Device private locking: network stack tx_lock protects members used
* path (and we use LLTX so upper layers don't do extra locking). * in TX fast path, lock protects everything else. lock nests inside
* lock protects everything else. lock nests inside of tx_lock (ie * of tx_lock (ie tx_lock must be acquired first if needed).
* tx_lock must be acquired first if needed).
*/ */
struct ipoib_dev_priv { struct ipoib_dev_priv {
spinlock_t lock; spinlock_t lock;
...@@ -320,7 +319,6 @@ struct ipoib_dev_priv { ...@@ -320,7 +319,6 @@ struct ipoib_dev_priv {
struct ipoib_rx_buf *rx_ring; struct ipoib_rx_buf *rx_ring;
spinlock_t tx_lock;
struct ipoib_tx_buf *tx_ring; struct ipoib_tx_buf *tx_ring;
unsigned tx_head; unsigned tx_head;
unsigned tx_tail; unsigned tx_tail;
......
...@@ -786,7 +786,8 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) ...@@ -786,7 +786,8 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
dev_kfree_skb_any(tx_req->skb); dev_kfree_skb_any(tx_req->skb);
spin_lock_irqsave(&priv->tx_lock, flags); netif_tx_lock(dev);
++tx->tx_tail; ++tx->tx_tail;
if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) && if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) &&
netif_queue_stopped(dev) && netif_queue_stopped(dev) &&
...@@ -801,7 +802,7 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) ...@@ -801,7 +802,7 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
"(status=%d, wrid=%d vend_err %x)\n", "(status=%d, wrid=%d vend_err %x)\n",
wc->status, wr_id, wc->vendor_err); wc->status, wr_id, wc->vendor_err);
spin_lock(&priv->lock); spin_lock_irqsave(&priv->lock, flags);
neigh = tx->neigh; neigh = tx->neigh;
if (neigh) { if (neigh) {
...@@ -821,10 +822,10 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) ...@@ -821,10 +822,10 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
clear_bit(IPOIB_FLAG_OPER_UP, &tx->flags); clear_bit(IPOIB_FLAG_OPER_UP, &tx->flags);
spin_unlock(&priv->lock); spin_unlock_irqrestore(&priv->lock, flags);
} }
spin_unlock_irqrestore(&priv->tx_lock, flags); netif_tx_unlock(dev);
} }
int ipoib_cm_dev_open(struct net_device *dev) int ipoib_cm_dev_open(struct net_device *dev)
...@@ -1149,7 +1150,6 @@ static void ipoib_cm_tx_destroy(struct ipoib_cm_tx *p) ...@@ -1149,7 +1150,6 @@ static void ipoib_cm_tx_destroy(struct ipoib_cm_tx *p)
{ {
struct ipoib_dev_priv *priv = netdev_priv(p->dev); struct ipoib_dev_priv *priv = netdev_priv(p->dev);
struct ipoib_cm_tx_buf *tx_req; struct ipoib_cm_tx_buf *tx_req;
unsigned long flags;
unsigned long begin; unsigned long begin;
ipoib_dbg(priv, "Destroy active connection 0x%x head 0x%x tail 0x%x\n", ipoib_dbg(priv, "Destroy active connection 0x%x head 0x%x tail 0x%x\n",
...@@ -1180,12 +1180,12 @@ static void ipoib_cm_tx_destroy(struct ipoib_cm_tx *p) ...@@ -1180,12 +1180,12 @@ static void ipoib_cm_tx_destroy(struct ipoib_cm_tx *p)
DMA_TO_DEVICE); DMA_TO_DEVICE);
dev_kfree_skb_any(tx_req->skb); dev_kfree_skb_any(tx_req->skb);
++p->tx_tail; ++p->tx_tail;
spin_lock_irqsave(&priv->tx_lock, flags); netif_tx_lock_bh(p->dev);
if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) && if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) &&
netif_queue_stopped(p->dev) && netif_queue_stopped(p->dev) &&
test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
netif_wake_queue(p->dev); netif_wake_queue(p->dev);
spin_unlock_irqrestore(&priv->tx_lock, flags); netif_tx_unlock_bh(p->dev);
} }
if (p->qp) if (p->qp)
...@@ -1202,6 +1202,7 @@ static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id, ...@@ -1202,6 +1202,7 @@ static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id,
struct ipoib_dev_priv *priv = netdev_priv(tx->dev); struct ipoib_dev_priv *priv = netdev_priv(tx->dev);
struct net_device *dev = priv->dev; struct net_device *dev = priv->dev;
struct ipoib_neigh *neigh; struct ipoib_neigh *neigh;
unsigned long flags;
int ret; int ret;
switch (event->event) { switch (event->event) {
...@@ -1220,8 +1221,8 @@ static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id, ...@@ -1220,8 +1221,8 @@ static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id,
case IB_CM_REJ_RECEIVED: case IB_CM_REJ_RECEIVED:
case IB_CM_TIMEWAIT_EXIT: case IB_CM_TIMEWAIT_EXIT:
ipoib_dbg(priv, "CM error %d.\n", event->event); ipoib_dbg(priv, "CM error %d.\n", event->event);
spin_lock_irq(&priv->tx_lock); netif_tx_lock_bh(dev);
spin_lock(&priv->lock); spin_lock_irqsave(&priv->lock, flags);
neigh = tx->neigh; neigh = tx->neigh;
if (neigh) { if (neigh) {
...@@ -1239,8 +1240,8 @@ static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id, ...@@ -1239,8 +1240,8 @@ static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id,
queue_work(ipoib_workqueue, &priv->cm.reap_task); queue_work(ipoib_workqueue, &priv->cm.reap_task);
} }
spin_unlock(&priv->lock); spin_unlock_irqrestore(&priv->lock, flags);
spin_unlock_irq(&priv->tx_lock); netif_tx_unlock_bh(dev);
break; break;
default: default:
break; break;
...@@ -1294,19 +1295,24 @@ static void ipoib_cm_tx_start(struct work_struct *work) ...@@ -1294,19 +1295,24 @@ static void ipoib_cm_tx_start(struct work_struct *work)
struct ib_sa_path_rec pathrec; struct ib_sa_path_rec pathrec;
u32 qpn; u32 qpn;
spin_lock_irqsave(&priv->tx_lock, flags); netif_tx_lock_bh(dev);
spin_lock(&priv->lock); spin_lock_irqsave(&priv->lock, flags);
while (!list_empty(&priv->cm.start_list)) { while (!list_empty(&priv->cm.start_list)) {
p = list_entry(priv->cm.start_list.next, typeof(*p), list); p = list_entry(priv->cm.start_list.next, typeof(*p), list);
list_del_init(&p->list); list_del_init(&p->list);
neigh = p->neigh; neigh = p->neigh;
qpn = IPOIB_QPN(neigh->neighbour->ha); qpn = IPOIB_QPN(neigh->neighbour->ha);
memcpy(&pathrec, &p->path->pathrec, sizeof pathrec); memcpy(&pathrec, &p->path->pathrec, sizeof pathrec);
spin_unlock(&priv->lock);
spin_unlock_irqrestore(&priv->tx_lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
netif_tx_unlock_bh(dev);
ret = ipoib_cm_tx_init(p, qpn, &pathrec); ret = ipoib_cm_tx_init(p, qpn, &pathrec);
spin_lock_irqsave(&priv->tx_lock, flags);
spin_lock(&priv->lock); netif_tx_lock_bh(dev);
spin_lock_irqsave(&priv->lock, flags);
if (ret) { if (ret) {
neigh = p->neigh; neigh = p->neigh;
if (neigh) { if (neigh) {
...@@ -1320,44 +1326,52 @@ static void ipoib_cm_tx_start(struct work_struct *work) ...@@ -1320,44 +1326,52 @@ static void ipoib_cm_tx_start(struct work_struct *work)
kfree(p); kfree(p);
} }
} }
spin_unlock(&priv->lock);
spin_unlock_irqrestore(&priv->tx_lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
netif_tx_unlock_bh(dev);
} }
static void ipoib_cm_tx_reap(struct work_struct *work) static void ipoib_cm_tx_reap(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.reap_task); cm.reap_task);
struct net_device *dev = priv->dev;
struct ipoib_cm_tx *p; struct ipoib_cm_tx *p;
unsigned long flags;
netif_tx_lock_bh(dev);
spin_lock_irqsave(&priv->lock, flags);
spin_lock_irq(&priv->tx_lock);
spin_lock(&priv->lock);
while (!list_empty(&priv->cm.reap_list)) { while (!list_empty(&priv->cm.reap_list)) {
p = list_entry(priv->cm.reap_list.next, typeof(*p), list); p = list_entry(priv->cm.reap_list.next, typeof(*p), list);
list_del(&p->list); list_del(&p->list);
spin_unlock(&priv->lock); spin_unlock_irqrestore(&priv->lock, flags);
spin_unlock_irq(&priv->tx_lock); netif_tx_unlock_bh(dev);
ipoib_cm_tx_destroy(p); ipoib_cm_tx_destroy(p);
spin_lock_irq(&priv->tx_lock); netif_tx_lock_bh(dev);
spin_lock(&priv->lock); spin_lock_irqsave(&priv->lock, flags);
} }
spin_unlock(&priv->lock);
spin_unlock_irq(&priv->tx_lock); spin_unlock_irqrestore(&priv->lock, flags);
netif_tx_unlock_bh(dev);
} }
static void ipoib_cm_skb_reap(struct work_struct *work) static void ipoib_cm_skb_reap(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.skb_task); cm.skb_task);
struct net_device *dev = priv->dev;
struct sk_buff *skb; struct sk_buff *skb;
unsigned long flags;
unsigned mtu = priv->mcast_mtu; unsigned mtu = priv->mcast_mtu;
spin_lock_irq(&priv->tx_lock); netif_tx_lock_bh(dev);
spin_lock(&priv->lock); spin_lock_irqsave(&priv->lock, flags);
while ((skb = skb_dequeue(&priv->cm.skb_queue))) { while ((skb = skb_dequeue(&priv->cm.skb_queue))) {
spin_unlock(&priv->lock); spin_unlock_irqrestore(&priv->lock, flags);
spin_unlock_irq(&priv->tx_lock); netif_tx_unlock_bh(dev);
if (skb->protocol == htons(ETH_P_IP)) if (skb->protocol == htons(ETH_P_IP))
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
...@@ -1365,11 +1379,13 @@ static void ipoib_cm_skb_reap(struct work_struct *work) ...@@ -1365,11 +1379,13 @@ static void ipoib_cm_skb_reap(struct work_struct *work)
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, priv->dev); icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, priv->dev);
#endif #endif
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
spin_lock_irq(&priv->tx_lock);
spin_lock(&priv->lock); netif_tx_lock_bh(dev);
spin_lock_irqsave(&priv->lock, flags);
} }
spin_unlock(&priv->lock);
spin_unlock_irq(&priv->tx_lock); spin_unlock_irqrestore(&priv->lock, flags);
netif_tx_unlock_bh(dev);
} }
void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb, void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
......
...@@ -468,21 +468,22 @@ void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr) ...@@ -468,21 +468,22 @@ void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr)
static void drain_tx_cq(struct net_device *dev) static void drain_tx_cq(struct net_device *dev)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
unsigned long flags;
spin_lock_irqsave(&priv->tx_lock, flags); netif_tx_lock(dev);
while (poll_tx(priv)) while (poll_tx(priv))
; /* nothing */ ; /* nothing */
if (netif_queue_stopped(dev)) if (netif_queue_stopped(dev))
mod_timer(&priv->poll_timer, jiffies + 1); mod_timer(&priv->poll_timer, jiffies + 1);
spin_unlock_irqrestore(&priv->tx_lock, flags); netif_tx_unlock(dev);
} }
void ipoib_send_comp_handler(struct ib_cq *cq, void *dev_ptr) void ipoib_send_comp_handler(struct ib_cq *cq, void *dev_ptr)
{ {
drain_tx_cq((struct net_device *)dev_ptr); struct ipoib_dev_priv *priv = netdev_priv(dev_ptr);
mod_timer(&priv->poll_timer, jiffies);
} }
static inline int post_send(struct ipoib_dev_priv *priv, static inline int post_send(struct ipoib_dev_priv *priv,
...@@ -614,17 +615,20 @@ static void __ipoib_reap_ah(struct net_device *dev) ...@@ -614,17 +615,20 @@ static void __ipoib_reap_ah(struct net_device *dev)
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_ah *ah, *tah; struct ipoib_ah *ah, *tah;
LIST_HEAD(remove_list); LIST_HEAD(remove_list);
unsigned long flags;
netif_tx_lock_bh(dev);
spin_lock_irqsave(&priv->lock, flags);
spin_lock_irq(&priv->tx_lock);
spin_lock(&priv->lock);
list_for_each_entry_safe(ah, tah, &priv->dead_ahs, list) list_for_each_entry_safe(ah, tah, &priv->dead_ahs, list)
if ((int) priv->tx_tail - (int) ah->last_send >= 0) { if ((int) priv->tx_tail - (int) ah->last_send >= 0) {
list_del(&ah->list); list_del(&ah->list);
ib_destroy_ah(ah->ah); ib_destroy_ah(ah->ah);
kfree(ah); kfree(ah);
} }
spin_unlock(&priv->lock);
spin_unlock_irq(&priv->tx_lock); spin_unlock_irqrestore(&priv->lock, flags);
netif_tx_unlock_bh(dev);
} }
void ipoib_reap_ah(struct work_struct *work) void ipoib_reap_ah(struct work_struct *work)
...@@ -761,6 +765,14 @@ void ipoib_drain_cq(struct net_device *dev) ...@@ -761,6 +765,14 @@ void ipoib_drain_cq(struct net_device *dev)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
int i, n; int i, n;
/*
* We call completion handling routines that expect to be
* called from the BH-disabled NAPI poll context, so disable
* BHs here too.
*/
local_bh_disable();
do { do {
n = ib_poll_cq(priv->recv_cq, IPOIB_NUM_WC, priv->ibwc); n = ib_poll_cq(priv->recv_cq, IPOIB_NUM_WC, priv->ibwc);
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
...@@ -784,6 +796,8 @@ void ipoib_drain_cq(struct net_device *dev) ...@@ -784,6 +796,8 @@ void ipoib_drain_cq(struct net_device *dev)
while (poll_tx(priv)) while (poll_tx(priv))
; /* nothing */ ; /* nothing */
local_bh_enable();
} }
int ipoib_ib_dev_stop(struct net_device *dev, int flush) int ipoib_ib_dev_stop(struct net_device *dev, int flush)
......
...@@ -373,9 +373,10 @@ void ipoib_flush_paths(struct net_device *dev) ...@@ -373,9 +373,10 @@ void ipoib_flush_paths(struct net_device *dev)
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_path *path, *tp; struct ipoib_path *path, *tp;
LIST_HEAD(remove_list); LIST_HEAD(remove_list);
unsigned long flags;
spin_lock_irq(&priv->tx_lock); netif_tx_lock_bh(dev);
spin_lock(&priv->lock); spin_lock_irqsave(&priv->lock, flags);
list_splice_init(&priv->path_list, &remove_list); list_splice_init(&priv->path_list, &remove_list);
...@@ -385,15 +386,16 @@ void ipoib_flush_paths(struct net_device *dev) ...@@ -385,15 +386,16 @@ void ipoib_flush_paths(struct net_device *dev)
list_for_each_entry_safe(path, tp, &remove_list, list) { list_for_each_entry_safe(path, tp, &remove_list, list) {
if (path->query) if (path->query)
ib_sa_cancel_query(path->query_id, path->query); ib_sa_cancel_query(path->query_id, path->query);
spin_unlock(&priv->lock); spin_unlock_irqrestore(&priv->lock, flags);
spin_unlock_irq(&priv->tx_lock); netif_tx_unlock_bh(dev);
wait_for_completion(&path->done); wait_for_completion(&path->done);
path_free(dev, path); path_free(dev, path);
spin_lock_irq(&priv->tx_lock); netif_tx_lock_bh(dev);
spin_lock(&priv->lock); spin_lock_irqsave(&priv->lock, flags);
} }
spin_unlock(&priv->lock);
spin_unlock_irq(&priv->tx_lock); spin_unlock_irqrestore(&priv->lock, flags);
netif_tx_unlock_bh(dev);
} }
static void path_rec_completion(int status, static void path_rec_completion(int status,
...@@ -555,6 +557,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) ...@@ -555,6 +557,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_path *path; struct ipoib_path *path;
struct ipoib_neigh *neigh; struct ipoib_neigh *neigh;
unsigned long flags;
neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev); neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev);
if (!neigh) { if (!neigh) {
...@@ -563,11 +566,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) ...@@ -563,11 +566,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
return; return;
} }
/* spin_lock_irqsave(&priv->lock, flags);
* We can only be called from ipoib_start_xmit, so we're
* inside tx_lock -- no need to save/restore flags.
*/
spin_lock(&priv->lock);
path = __path_find(dev, skb->dst->neighbour->ha + 4); path = __path_find(dev, skb->dst->neighbour->ha + 4);
if (!path) { if (!path) {
...@@ -614,7 +613,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) ...@@ -614,7 +613,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
__skb_queue_tail(&neigh->queue, skb); __skb_queue_tail(&neigh->queue, skb);
} }
spin_unlock(&priv->lock); spin_unlock_irqrestore(&priv->lock, flags);
return; return;
err_list: err_list:
...@@ -626,7 +625,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) ...@@ -626,7 +625,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
++dev->stats.tx_dropped; ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
spin_unlock(&priv->lock); spin_unlock_irqrestore(&priv->lock, flags);
} }
static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev) static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev)
...@@ -650,12 +649,9 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, ...@@ -650,12 +649,9 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_path *path; struct ipoib_path *path;
unsigned long flags;
/* spin_lock_irqsave(&priv->lock, flags);
* We can only be called from ipoib_start_xmit, so we're
* inside tx_lock -- no need to save/restore flags.
*/
spin_lock(&priv->lock);
path = __path_find(dev, phdr->hwaddr + 4); path = __path_find(dev, phdr->hwaddr + 4);
if (!path || !path->valid) { if (!path || !path->valid) {
...@@ -667,7 +663,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, ...@@ -667,7 +663,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
__skb_queue_tail(&path->queue, skb); __skb_queue_tail(&path->queue, skb);
if (path_rec_start(dev, path)) { if (path_rec_start(dev, path)) {
spin_unlock(&priv->lock); spin_unlock_irqrestore(&priv->lock, flags);
path_free(dev, path); path_free(dev, path);
return; return;
} else } else
...@@ -677,7 +673,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, ...@@ -677,7 +673,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
spin_unlock(&priv->lock); spin_unlock_irqrestore(&priv->lock, flags);
return; return;
} }
...@@ -696,7 +692,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, ...@@ -696,7 +692,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
spin_unlock(&priv->lock); spin_unlock_irqrestore(&priv->lock, flags);
} }
static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
...@@ -705,13 +701,10 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -705,13 +701,10 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct ipoib_neigh *neigh; struct ipoib_neigh *neigh;
unsigned long flags; unsigned long flags;
if (unlikely(!spin_trylock_irqsave(&priv->tx_lock, flags)))
return NETDEV_TX_LOCKED;
if (likely(skb->dst && skb->dst->neighbour)) { if (likely(skb->dst && skb->dst->neighbour)) {
if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) { if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) {
ipoib_path_lookup(skb, dev); ipoib_path_lookup(skb, dev);
goto out; return NETDEV_TX_OK;
} }
neigh = *to_ipoib_neigh(skb->dst->neighbour); neigh = *to_ipoib_neigh(skb->dst->neighbour);
...@@ -721,7 +714,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -721,7 +714,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb->dst->neighbour->ha + 4, skb->dst->neighbour->ha + 4,
sizeof(union ib_gid))) || sizeof(union ib_gid))) ||
(neigh->dev != dev))) { (neigh->dev != dev))) {
spin_lock(&priv->lock); spin_lock_irqsave(&priv->lock, flags);
/* /*
* It's safe to call ipoib_put_ah() inside * It's safe to call ipoib_put_ah() inside
* priv->lock here, because we know that * priv->lock here, because we know that
...@@ -732,25 +725,25 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -732,25 +725,25 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
ipoib_put_ah(neigh->ah); ipoib_put_ah(neigh->ah);
list_del(&neigh->list); list_del(&neigh->list);
ipoib_neigh_free(dev, neigh); ipoib_neigh_free(dev, neigh);
spin_unlock(&priv->lock); spin_unlock_irqrestore(&priv->lock, flags);
ipoib_path_lookup(skb, dev); ipoib_path_lookup(skb, dev);
goto out; return NETDEV_TX_OK;
} }
if (ipoib_cm_get(neigh)) { if (ipoib_cm_get(neigh)) {
if (ipoib_cm_up(neigh)) { if (ipoib_cm_up(neigh)) {
ipoib_cm_send(dev, skb, ipoib_cm_get(neigh)); ipoib_cm_send(dev, skb, ipoib_cm_get(neigh));
goto out; return NETDEV_TX_OK;
} }
} else if (neigh->ah) { } else if (neigh->ah) {
ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb->dst->neighbour->ha)); ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb->dst->neighbour->ha));
goto out; return NETDEV_TX_OK;
} }
if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
spin_lock(&priv->lock); spin_lock_irqsave(&priv->lock, flags);
__skb_queue_tail(&neigh->queue, skb); __skb_queue_tail(&neigh->queue, skb);
spin_unlock(&priv->lock); spin_unlock_irqrestore(&priv->lock, flags);
} else { } else {
++dev->stats.tx_dropped; ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
...@@ -779,16 +772,13 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -779,16 +772,13 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
IPOIB_GID_RAW_ARG(phdr->hwaddr + 4)); IPOIB_GID_RAW_ARG(phdr->hwaddr + 4));
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
++dev->stats.tx_dropped; ++dev->stats.tx_dropped;
goto out; return NETDEV_TX_OK;
} }
unicast_arp_send(skb, dev, phdr); unicast_arp_send(skb, dev, phdr);
} }
} }
out:
spin_unlock_irqrestore(&priv->tx_lock, flags);
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
...@@ -1052,7 +1042,6 @@ static void ipoib_setup(struct net_device *dev) ...@@ -1052,7 +1042,6 @@ static void ipoib_setup(struct net_device *dev)
dev->type = ARPHRD_INFINIBAND; dev->type = ARPHRD_INFINIBAND;
dev->tx_queue_len = ipoib_sendq_size * 2; dev->tx_queue_len = ipoib_sendq_size * 2;
dev->features = (NETIF_F_VLAN_CHALLENGED | dev->features = (NETIF_F_VLAN_CHALLENGED |
NETIF_F_LLTX |
NETIF_F_HIGHDMA); NETIF_F_HIGHDMA);
memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN); memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN);
...@@ -1064,7 +1053,6 @@ static void ipoib_setup(struct net_device *dev) ...@@ -1064,7 +1053,6 @@ static void ipoib_setup(struct net_device *dev)
ipoib_lro_setup(priv); ipoib_lro_setup(priv);
spin_lock_init(&priv->lock); spin_lock_init(&priv->lock);
spin_lock_init(&priv->tx_lock);
mutex_init(&priv->vlan_mutex); mutex_init(&priv->vlan_mutex);
......
...@@ -69,14 +69,13 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast) ...@@ -69,14 +69,13 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
struct net_device *dev = mcast->dev; struct net_device *dev = mcast->dev;
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_neigh *neigh, *tmp; struct ipoib_neigh *neigh, *tmp;
unsigned long flags;
int tx_dropped = 0; int tx_dropped = 0;
ipoib_dbg_mcast(netdev_priv(dev), ipoib_dbg_mcast(netdev_priv(dev),
"deleting multicast group " IPOIB_GID_FMT "\n", "deleting multicast group " IPOIB_GID_FMT "\n",
IPOIB_GID_ARG(mcast->mcmember.mgid)); IPOIB_GID_ARG(mcast->mcmember.mgid));
spin_lock_irqsave(&priv->lock, flags); spin_lock_irq(&priv->lock);
list_for_each_entry_safe(neigh, tmp, &mcast->neigh_list, list) { list_for_each_entry_safe(neigh, tmp, &mcast->neigh_list, list) {
/* /*
...@@ -90,7 +89,7 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast) ...@@ -90,7 +89,7 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
ipoib_neigh_free(dev, neigh); ipoib_neigh_free(dev, neigh);
} }
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irq(&priv->lock);
if (mcast->ah) if (mcast->ah)
ipoib_put_ah(mcast->ah); ipoib_put_ah(mcast->ah);
...@@ -100,9 +99,9 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast) ...@@ -100,9 +99,9 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue)); dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
} }
spin_lock_irqsave(&priv->tx_lock, flags); netif_tx_lock_bh(dev);
dev->stats.tx_dropped += tx_dropped; dev->stats.tx_dropped += tx_dropped;
spin_unlock_irqrestore(&priv->tx_lock, flags); netif_tx_unlock_bh(dev);
kfree(mcast); kfree(mcast);
} }
...@@ -259,10 +258,10 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, ...@@ -259,10 +258,10 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
} }
/* actually send any queued packets */ /* actually send any queued packets */
spin_lock_irq(&priv->tx_lock); netif_tx_lock_bh(dev);
while (!skb_queue_empty(&mcast->pkt_queue)) { while (!skb_queue_empty(&mcast->pkt_queue)) {
struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue); struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue);
spin_unlock_irq(&priv->tx_lock); netif_tx_unlock_bh(dev);
skb->dev = dev; skb->dev = dev;
...@@ -273,9 +272,9 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, ...@@ -273,9 +272,9 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
if (dev_queue_xmit(skb)) if (dev_queue_xmit(skb))
ipoib_warn(priv, "dev_queue_xmit failed to requeue packet\n"); ipoib_warn(priv, "dev_queue_xmit failed to requeue packet\n");
spin_lock_irq(&priv->tx_lock); netif_tx_lock_bh(dev);
} }
spin_unlock_irq(&priv->tx_lock); netif_tx_unlock_bh(dev);
return 0; return 0;
} }
...@@ -286,7 +285,6 @@ ipoib_mcast_sendonly_join_complete(int status, ...@@ -286,7 +285,6 @@ ipoib_mcast_sendonly_join_complete(int status,
{ {
struct ipoib_mcast *mcast = multicast->context; struct ipoib_mcast *mcast = multicast->context;
struct net_device *dev = mcast->dev; struct net_device *dev = mcast->dev;
struct ipoib_dev_priv *priv = netdev_priv(dev);
/* We trap for port events ourselves. */ /* We trap for port events ourselves. */
if (status == -ENETRESET) if (status == -ENETRESET)
...@@ -302,12 +300,12 @@ ipoib_mcast_sendonly_join_complete(int status, ...@@ -302,12 +300,12 @@ ipoib_mcast_sendonly_join_complete(int status,
IPOIB_GID_ARG(mcast->mcmember.mgid), status); IPOIB_GID_ARG(mcast->mcmember.mgid), status);
/* Flush out any queued packets */ /* Flush out any queued packets */
spin_lock_irq(&priv->tx_lock); netif_tx_lock_bh(dev);
while (!skb_queue_empty(&mcast->pkt_queue)) { while (!skb_queue_empty(&mcast->pkt_queue)) {
++dev->stats.tx_dropped; ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue)); dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
} }
spin_unlock_irq(&priv->tx_lock); netif_tx_unlock_bh(dev);
/* Clear the busy flag so we try again */ /* Clear the busy flag so we try again */
status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY,
...@@ -662,12 +660,9 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) ...@@ -662,12 +660,9 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_mcast *mcast; struct ipoib_mcast *mcast;
unsigned long flags;
/* spin_lock_irqsave(&priv->lock, flags);
* We can only be called from ipoib_start_xmit, so we're
* inside tx_lock -- no need to save/restore flags.
*/
spin_lock(&priv->lock);
if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags) || if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags) ||
!priv->broadcast || !priv->broadcast ||
...@@ -738,7 +733,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) ...@@ -738,7 +733,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
} }
unlock: unlock:
spin_unlock(&priv->lock); spin_unlock_irqrestore(&priv->lock, flags);
} }
void ipoib_mcast_dev_flush(struct net_device *dev) void ipoib_mcast_dev_flush(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