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));
...@@ -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 (HAS_RQ(my_qp))
ehca_add_to_err_list(my_qp, 0);
my_qp->rq_map.left_to_poll = 0;
}
qmap_tail_idx = get_app_wr_id(cqe->work_request_id);
if (!(cqe->w_completion_flags & WC_SEND_RECEIVE_BIT))
/* We got a send completion. */
qmap = &my_qp->sq_map;
else
/* We got a receive completion. */
qmap = &my_qp->rq_map;
qmap_entry = &qmap->map[qmap_tail_idx];
if (qmap_entry->reported) { if (qmap_entry->reported) {
ehca_warn(cq->device, "Double cqe on qp_num=%#x", ehca_warn(cq->device, "Double cqe on qp_num=%#x",
my_qp->real_qp_num); my_qp->real_qp_num);
/* found a double cqe, discard it and read next one */ /* found a double cqe, discard it and read next one */
goto repoll; goto repoll;
} }
wc->wr_id = cqe->work_request_id & ~QMAP_IDX_MASK;
wc->wr_id |= qmap_entry->app_wr_id; wc->wr_id = replace_wr_id(cqe->work_request_id, qmap_entry->app_wr_id);
qmap_entry->reported = 1; qmap_entry->reported = 1;
} else
/* We got a receive completion. */ /* this is a proper completion, we need to advance the tail pointer */
wc->wr_id = cqe->work_request_id; 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);
}
if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID)))
neigh_event_send(rt->u.dst.neighbour, NULL); neigh_event_send(rt->u.dst.neighbour, NULL);
ip_rt_put(rt); ip_rt_put(rt);
return rc;
} }
...@@ -1107,11 +1127,13 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core, ...@@ -1107,11 +1127,13 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
cm_node->loopbackpartner = NULL; cm_node->loopbackpartner = NULL;
/* 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) {
arpindex = nes_addr_resolve_neigh(nesvnic, cm_info->rem_addr);
if (arpindex < 0) { if (arpindex < 0) {
kfree(cm_node); kfree(cm_node);
nes_addr_send_arp(cm_info->rem_addr);
return NULL; return NULL;
} }
}
/* copy the mac addr to node context */ /* copy the mac addr to node context */
memcpy(cm_node->rem_mac, nesadapter->arp_table[arpindex].mac_addr, ETH_ALEN); memcpy(cm_node->rem_mac, nesadapter->arp_table[arpindex].mac_addr, ETH_ALEN);
...@@ -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;
} }
......
...@@ -55,18 +55,19 @@ u32 int_mod_cq_depth_24; ...@@ -55,18 +55,19 @@ u32 int_mod_cq_depth_24;
u32 int_mod_cq_depth_16; u32 int_mod_cq_depth_16;
u32 int_mod_cq_depth_4; u32 int_mod_cq_depth_4;
u32 int_mod_cq_depth_1; u32 int_mod_cq_depth_1;
static const u8 nes_max_critical_error_count = 100;
#include "nes_cm.h" #include "nes_cm.h"
static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq); static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq);
static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_count); static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_count);
static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count, static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
u8 OneG_Mode); struct nes_adapter *nesadapter, u8 OneG_Mode);
static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq); static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq);
static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq); static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq);
static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq); static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq);
static void nes_process_iwarp_aeqe(struct nes_device *nesdev, static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
struct nes_hw_aeqe *aeqe); struct nes_hw_aeqe *aeqe);
static void process_critical_error(struct nes_device *nesdev);
static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number); static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number);
static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode); static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode);
...@@ -222,11 +223,10 @@ static void nes_nic_tune_timer(struct nes_device *nesdev) ...@@ -222,11 +223,10 @@ static void nes_nic_tune_timer(struct nes_device *nesdev)
} }
/* boundary checking */ /* boundary checking */
if (shared_timer->timer_in_use > NES_NIC_FAST_TIMER_HIGH) if (shared_timer->timer_in_use > shared_timer->threshold_high)
shared_timer->timer_in_use = NES_NIC_FAST_TIMER_HIGH; shared_timer->timer_in_use = shared_timer->threshold_high;
else if (shared_timer->timer_in_use < NES_NIC_FAST_TIMER_LOW) { else if (shared_timer->timer_in_use < shared_timer->threshold_low)
shared_timer->timer_in_use = NES_NIC_FAST_TIMER_LOW; shared_timer->timer_in_use = shared_timer->threshold_low;
}
nesdev->currcq_count = 0; nesdev->currcq_count = 0;
...@@ -292,9 +292,6 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) { ...@@ -292,9 +292,6 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
if ((port_count = nes_reset_adapter_ne020(nesdev, &OneG_Mode)) == 0) if ((port_count = nes_reset_adapter_ne020(nesdev, &OneG_Mode)) == 0)
return NULL; return NULL;
if (nes_init_serdes(nesdev, hw_rev, port_count, OneG_Mode))
return NULL;
nes_init_csr_ne020(nesdev, hw_rev, port_count);
max_qp = nes_read_indexed(nesdev, NES_IDX_QP_CTX_SIZE); max_qp = nes_read_indexed(nesdev, NES_IDX_QP_CTX_SIZE);
nes_debug(NES_DBG_INIT, "QP_CTX_SIZE=%u\n", max_qp); nes_debug(NES_DBG_INIT, "QP_CTX_SIZE=%u\n", max_qp);
...@@ -353,6 +350,22 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) { ...@@ -353,6 +350,22 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
nes_debug(NES_DBG_INIT, "Allocating new nesadapter @ %p, size = %u (actual size = %u).\n", nes_debug(NES_DBG_INIT, "Allocating new nesadapter @ %p, size = %u (actual size = %u).\n",
nesadapter, (u32)sizeof(struct nes_adapter), adapter_size); nesadapter, (u32)sizeof(struct nes_adapter), adapter_size);
if (nes_read_eeprom_values(nesdev, nesadapter)) {
printk(KERN_ERR PFX "Unable to read EEPROM data.\n");
kfree(nesadapter);
return NULL;
}
if (nes_init_serdes(nesdev, hw_rev, port_count, nesadapter,
OneG_Mode)) {
kfree(nesadapter);
return NULL;
}
nes_init_csr_ne020(nesdev, hw_rev, port_count);
memset(nesadapter->pft_mcast_map, 255,
sizeof nesadapter->pft_mcast_map);
/* populate the new nesadapter */ /* populate the new nesadapter */
nesadapter->devfn = nesdev->pcidev->devfn; nesadapter->devfn = nesdev->pcidev->devfn;
nesadapter->bus_number = nesdev->pcidev->bus->number; nesadapter->bus_number = nesdev->pcidev->bus->number;
...@@ -468,20 +481,25 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) { ...@@ -468,20 +481,25 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
/* setup port configuration */ /* setup port configuration */
if (nesadapter->port_count == 1) { if (nesadapter->port_count == 1) {
u32temp = 0x00000000; nesadapter->log_port = 0x00000000;
if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT) if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT)
nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000002); nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000002);
else else
nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003); nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
} else {
if (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) {
nesadapter->log_port = 0x000000D8;
} else { } else {
if (nesadapter->port_count == 2) if (nesadapter->port_count == 2)
u32temp = 0x00000044; nesadapter->log_port = 0x00000044;
else else
u32temp = 0x000000e4; nesadapter->log_port = 0x000000e4;
}
nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003); nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
} }
nes_write_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT, u32temp); nes_write_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT,
nesadapter->log_port);
nes_debug(NES_DBG_INIT, "Probe time, LOG2PHY=%u\n", nes_debug(NES_DBG_INIT, "Probe time, LOG2PHY=%u\n",
nes_read_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT)); nes_read_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT));
...@@ -706,23 +724,43 @@ static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_ ...@@ -706,23 +724,43 @@ static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_
* nes_init_serdes * nes_init_serdes
*/ */
static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count, static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
u8 OneG_Mode) struct nes_adapter *nesadapter, u8 OneG_Mode)
{ {
int i; int i;
u32 u32temp; u32 u32temp;
u32 serdes_common_control;
if (hw_rev != NE020_REV) { if (hw_rev != NE020_REV) {
/* init serdes 0 */ /* init serdes 0 */
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF); nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
if (!OneG_Mode) if (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) {
serdes_common_control = nes_read_indexed(nesdev,
NES_IDX_ETH_SERDES_COMMON_CONTROL0);
serdes_common_control |= 0x000000100;
nes_write_indexed(nesdev,
NES_IDX_ETH_SERDES_COMMON_CONTROL0,
serdes_common_control);
} else if (!OneG_Mode) {
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE0, 0x11110000); nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE0, 0x11110000);
if (port_count > 1) { }
if (((port_count > 1) &&
(nesadapter->phy_type[0] != NES_PHY_TYPE_PUMA_1G)) ||
((port_count > 2) &&
(nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G))) {
/* init serdes 1 */ /* init serdes 1 */
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000FF); nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000FF);
if (!OneG_Mode) if (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) {
serdes_common_control = nes_read_indexed(nesdev,
NES_IDX_ETH_SERDES_COMMON_CONTROL1);
serdes_common_control |= 0x000000100;
nes_write_indexed(nesdev,
NES_IDX_ETH_SERDES_COMMON_CONTROL1,
serdes_common_control);
} else if (!OneG_Mode) {
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE1, 0x11110000); nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE1, 0x11110000);
} }
}
} else { } else {
/* init serdes 0 */ /* init serdes 0 */
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, 0x00000008); nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, 0x00000008);
...@@ -826,7 +864,8 @@ static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_cou ...@@ -826,7 +864,8 @@ static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_cou
nes_write_indexed(nesdev, 0x00005000, 0x00018000); nes_write_indexed(nesdev, 0x00005000, 0x00018000);
/* nes_write_indexed(nesdev, 0x00005000, 0x00010000); */ /* nes_write_indexed(nesdev, 0x00005000, 0x00010000); */
nes_write_indexed(nesdev, 0x00005004, 0x00020001); nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG1, (wqm_quanta << 1) |
0x00000001);
nes_write_indexed(nesdev, 0x00005008, 0x1F1F1F1F); nes_write_indexed(nesdev, 0x00005008, 0x1F1F1F1F);
nes_write_indexed(nesdev, 0x00005010, 0x1F1F1F1F); nes_write_indexed(nesdev, 0x00005010, 0x1F1F1F1F);
nes_write_indexed(nesdev, 0x00005018, 0x1F1F1F1F); nes_write_indexed(nesdev, 0x00005018, 0x1F1F1F1F);
...@@ -1226,6 +1265,7 @@ int nes_init_phy(struct nes_device *nesdev) ...@@ -1226,6 +1265,7 @@ int nes_init_phy(struct nes_device *nesdev)
if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_1G) { if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_1G) {
printk(PFX "%s: Programming mdc config for 1G\n", __func__); printk(PFX "%s: Programming mdc config for 1G\n", __func__);
tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG); tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
tx_config &= 0xFFFFFFE3;
tx_config |= 0x04; tx_config |= 0x04;
nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config); nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
} }
...@@ -1291,7 +1331,8 @@ int nes_init_phy(struct nes_device *nesdev) ...@@ -1291,7 +1331,8 @@ int nes_init_phy(struct nes_device *nesdev)
(nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) { (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) {
/* setup 10G MDIO operation */ /* setup 10G MDIO operation */
tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG); tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
tx_config |= 0x14; tx_config &= 0xFFFFFFE3;
tx_config |= 0x15;
nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config); nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
} }
if ((nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) { if ((nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) {
...@@ -1315,7 +1356,7 @@ int nes_init_phy(struct nes_device *nesdev) ...@@ -1315,7 +1356,7 @@ int nes_init_phy(struct nes_device *nesdev)
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc319, 0x0008); nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc319, 0x0008);
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc31a, 0x0098); nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc31a, 0x0098);
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0026, 0x0E00); nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0026, 0x0E00);
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0027, 0x0000); nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0027, 0x0001);
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0028, 0xA528); nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0028, 0xA528);
/* /*
...@@ -1759,9 +1800,14 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev) ...@@ -1759,9 +1800,14 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev)
*/ */
void nes_destroy_nic_qp(struct nes_vnic *nesvnic) void nes_destroy_nic_qp(struct nes_vnic *nesvnic)
{ {
u64 u64temp;
dma_addr_t bus_address;
struct nes_device *nesdev = nesvnic->nesdev; struct nes_device *nesdev = nesvnic->nesdev;
struct nes_hw_cqp_wqe *cqp_wqe; struct nes_hw_cqp_wqe *cqp_wqe;
struct nes_hw_nic_sq_wqe *nic_sqe;
struct nes_hw_nic_rq_wqe *nic_rqe; struct nes_hw_nic_rq_wqe *nic_rqe;
__le16 *wqe_fragment_length;
u16 wqe_fragment_index;
u64 wqe_frag; u64 wqe_frag;
u32 cqp_head; u32 cqp_head;
unsigned long flags; unsigned long flags;
...@@ -1770,14 +1816,69 @@ void nes_destroy_nic_qp(struct nes_vnic *nesvnic) ...@@ -1770,14 +1816,69 @@ void nes_destroy_nic_qp(struct nes_vnic *nesvnic)
/* Free remaining NIC receive buffers */ /* Free remaining NIC receive buffers */
while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) { while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) {
nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail]; nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail];
wqe_frag = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]); wqe_frag = (u64)le32_to_cpu(
wqe_frag |= ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32; nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
wqe_frag |= ((u64)le32_to_cpu(
nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX]))<<32;
pci_unmap_single(nesdev->pcidev, (dma_addr_t)wqe_frag, pci_unmap_single(nesdev->pcidev, (dma_addr_t)wqe_frag,
nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
dev_kfree_skb(nesvnic->nic.rx_skb[nesvnic->nic.rq_tail++]); dev_kfree_skb(nesvnic->nic.rx_skb[nesvnic->nic.rq_tail++]);
nesvnic->nic.rq_tail &= (nesvnic->nic.rq_size - 1); nesvnic->nic.rq_tail &= (nesvnic->nic.rq_size - 1);
} }
/* Free remaining NIC transmit buffers */
while (nesvnic->nic.sq_head != nesvnic->nic.sq_tail) {
nic_sqe = &nesvnic->nic.sq_vbase[nesvnic->nic.sq_tail];
wqe_fragment_index = 1;
wqe_fragment_length = (__le16 *)
&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
/* bump past the vlan tag */
wqe_fragment_length++;
if (le16_to_cpu(wqe_fragment_length[wqe_fragment_index]) != 0) {
u64temp = (u64)le32_to_cpu(
nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+
wqe_fragment_index*2]);
u64temp += ((u64)le32_to_cpu(
nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX
+ wqe_fragment_index*2]))<<32;
bus_address = (dma_addr_t)u64temp;
if (test_and_clear_bit(nesvnic->nic.sq_tail,
nesvnic->nic.first_frag_overflow)) {
pci_unmap_single(nesdev->pcidev,
bus_address,
le16_to_cpu(wqe_fragment_length[
wqe_fragment_index++]),
PCI_DMA_TODEVICE);
}
for (; wqe_fragment_index < 5; wqe_fragment_index++) {
if (wqe_fragment_length[wqe_fragment_index]) {
u64temp = le32_to_cpu(
nic_sqe->wqe_words[
NES_NIC_SQ_WQE_FRAG0_LOW_IDX+
wqe_fragment_index*2]);
u64temp += ((u64)le32_to_cpu(
nic_sqe->wqe_words[
NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+
wqe_fragment_index*2]))<<32;
bus_address = (dma_addr_t)u64temp;
pci_unmap_page(nesdev->pcidev,
bus_address,
le16_to_cpu(
wqe_fragment_length[
wqe_fragment_index]),
PCI_DMA_TODEVICE);
} else
break;
}
}
if (nesvnic->nic.tx_skb[nesvnic->nic.sq_tail])
dev_kfree_skb(
nesvnic->nic.tx_skb[nesvnic->nic.sq_tail]);
nesvnic->nic.sq_tail = (++nesvnic->nic.sq_tail)
& (nesvnic->nic.sq_size - 1);
}
spin_lock_irqsave(&nesdev->cqp.lock, flags); spin_lock_irqsave(&nesdev->cqp.lock, flags);
/* Destroy NIC QP */ /* Destroy NIC QP */
...@@ -1894,7 +1995,30 @@ int nes_napi_isr(struct nes_device *nesdev) ...@@ -1894,7 +1995,30 @@ int nes_napi_isr(struct nes_device *nesdev)
} }
} }
static void process_critical_error(struct nes_device *nesdev)
{
u32 debug_error;
u32 nes_idx_debug_error_masks0 = 0;
u16 error_module = 0;
debug_error = nes_read_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS);
printk(KERN_ERR PFX "Critical Error reported by device!!! 0x%02X\n",
(u16)debug_error);
nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS,
0x01010000 | (debug_error & 0x0000ffff));
if (crit_err_count++ > 10)
nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS1, 1 << 0x17);
error_module = (u16) (debug_error & 0x1F00) >> 8;
if (++nesdev->nesadapter->crit_error_count[error_module-1] >=
nes_max_critical_error_count) {
printk(KERN_ERR PFX "Masking off critical error for module "
"0x%02X\n", (u16)error_module);
nes_idx_debug_error_masks0 = nes_read_indexed(nesdev,
NES_IDX_DEBUG_ERROR_MASKS0);
nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS0,
nes_idx_debug_error_masks0 | (1 << error_module));
}
}
/** /**
* nes_dpc * nes_dpc
*/ */
...@@ -1909,7 +2033,6 @@ void nes_dpc(unsigned long param) ...@@ -1909,7 +2033,6 @@ void nes_dpc(unsigned long param)
u32 timer_stat; u32 timer_stat;
u32 temp_int_stat; u32 temp_int_stat;
u32 intf_int_stat; u32 intf_int_stat;
u32 debug_error;
u32 processed_intf_int = 0; u32 processed_intf_int = 0;
u16 processed_timer_int = 0; u16 processed_timer_int = 0;
u16 completion_ints = 0; u16 completion_ints = 0;
...@@ -1987,14 +2110,7 @@ void nes_dpc(unsigned long param) ...@@ -1987,14 +2110,7 @@ void nes_dpc(unsigned long param)
intf_int_stat = nes_read32(nesdev->regs+NES_INTF_INT_STAT); intf_int_stat = nes_read32(nesdev->regs+NES_INTF_INT_STAT);
intf_int_stat &= nesdev->intf_int_req; intf_int_stat &= nesdev->intf_int_req;
if (NES_INTF_INT_CRITERR & intf_int_stat) { if (NES_INTF_INT_CRITERR & intf_int_stat) {
debug_error = nes_read_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS); process_critical_error(nesdev);
printk(KERN_ERR PFX "Critical Error reported by device!!! 0x%02X\n",
(u16)debug_error);
nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS,
0x01010000 | (debug_error & 0x0000ffff));
/* BUG(); */
if (crit_err_count++ > 10)
nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS1, 1 << 0x17);
} }
if (NES_INTF_INT_PCIERR & intf_int_stat) { if (NES_INTF_INT_PCIERR & intf_int_stat) {
printk(KERN_ERR PFX "PCI Error reported by device!!!\n"); printk(KERN_ERR PFX "PCI Error reported by device!!!\n");
...@@ -2258,7 +2374,8 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) ...@@ -2258,7 +2374,8 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
spin_unlock_irqrestore(&nesadapter->phy_lock, flags); spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
} }
/* read the PHY interrupt status register */ /* read the PHY interrupt status register */
if (nesadapter->OneG_Mode) { if ((nesadapter->OneG_Mode) &&
(nesadapter->phy_type[mac_index] != NES_PHY_TYPE_PUMA_1G)) {
do { do {
nes_read_1G_phy_reg(nesdev, 0x1a, nes_read_1G_phy_reg(nesdev, 0x1a,
nesadapter->phy_index[mac_index], &phy_data); nesadapter->phy_index[mac_index], &phy_data);
...@@ -3077,6 +3194,22 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, ...@@ -3077,6 +3194,22 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
nes_cm_disconn(nesqp); nes_cm_disconn(nesqp);
break; break;
/* TODO: additional AEs need to be here */ /* TODO: additional AEs need to be here */
case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION:
nesqp = *((struct nes_qp **)&context);
spin_lock_irqsave(&nesqp->lock, flags);
nesqp->hw_iwarp_state = iwarp_state;
nesqp->hw_tcp_state = tcp_state;
nesqp->last_aeq = async_event_id;
spin_unlock_irqrestore(&nesqp->lock, flags);
if (nesqp->ibqp.event_handler) {
ibevent.device = nesqp->ibqp.device;
ibevent.element.qp = &nesqp->ibqp;
ibevent.event = IB_EVENT_QP_ACCESS_ERR;
nesqp->ibqp.event_handler(&ibevent,
nesqp->ibqp.qp_context);
}
nes_cm_disconn(nesqp);
break;
default: default:
nes_debug(NES_DBG_AEQ, "Processing an iWARP related AE for QP, misc = 0x%04X\n", nes_debug(NES_DBG_AEQ, "Processing an iWARP related AE for QP, misc = 0x%04X\n",
async_event_id); async_event_id);
......
...@@ -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 {
......
...@@ -91,6 +91,7 @@ static struct nic_qp_map *nic_qp_mapping_per_function[] = { ...@@ -91,6 +91,7 @@ static struct nic_qp_map *nic_qp_mapping_per_function[] = {
static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
| NETIF_MSG_IFUP | NETIF_MSG_IFDOWN; | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
static int debug = -1; static int debug = -1;
static int nics_per_function = 1;
/** /**
* nes_netdev_poll * nes_netdev_poll
...@@ -201,7 +202,8 @@ static int nes_netdev_open(struct net_device *netdev) ...@@ -201,7 +202,8 @@ static int nes_netdev_open(struct net_device *netdev)
nes_debug(NES_DBG_NETDEV, "i=%d, perfect filter table index= %d, PERF FILTER LOW" nes_debug(NES_DBG_NETDEV, "i=%d, perfect filter table index= %d, PERF FILTER LOW"
" (Addr:%08X) = %08X, HIGH = %08X.\n", " (Addr:%08X) = %08X, HIGH = %08X.\n",
i, nesvnic->qp_nic_index[i], i, nesvnic->qp_nic_index[i],
NES_IDX_PERFECT_FILTER_LOW+((nesvnic->perfect_filter_index + i) * 8), NES_IDX_PERFECT_FILTER_LOW+
(nesvnic->qp_nic_index[i] * 8),
macaddr_low, macaddr_low,
(u32)macaddr_high | NES_MAC_ADDR_VALID | (u32)macaddr_high | NES_MAC_ADDR_VALID |
((((u32)nesvnic->nic_index) << 16))); ((((u32)nesvnic->nic_index) << 16)));
...@@ -272,14 +274,18 @@ static int nes_netdev_stop(struct net_device *netdev) ...@@ -272,14 +274,18 @@ static int nes_netdev_stop(struct net_device *netdev)
break; break;
} }
if (first_nesvnic->netdev_open == 0) if ((first_nesvnic->netdev_open == 1) && (first_nesvnic != nesvnic) &&
nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK+(0x200*nesdev->mac_index), 0xffffffff); (PCI_FUNC(first_nesvnic->nesdev->pcidev->devfn) !=
else if ((first_nesvnic != nesvnic) && PCI_FUNC(nesvnic->nesdev->pcidev->devfn))) {
(PCI_FUNC(first_nesvnic->nesdev->pcidev->devfn) != PCI_FUNC(nesvnic->nesdev->pcidev->devfn))) { nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK+
nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK + (0x200 * nesdev->mac_index), 0xffffffff); (0x200*nesdev->mac_index), 0xffffffff);
nes_write_indexed(first_nesvnic->nesdev, NES_IDX_MAC_INT_MASK + (0x200 * first_nesvnic->nesdev->mac_index), nes_write_indexed(first_nesvnic->nesdev,
NES_IDX_MAC_INT_MASK+
(0x200*first_nesvnic->nesdev->mac_index),
~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT | ~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT |
NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR)); NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR));
} else {
nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK+(0x200*nesdev->mac_index), 0xffffffff);
} }
nic_active_mask = ~((u32)(1 << nesvnic->nic_index)); nic_active_mask = ~((u32)(1 << nesvnic->nic_index));
...@@ -437,7 +443,7 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev) ...@@ -437,7 +443,7 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev)
struct nes_hw_nic_sq_wqe *nic_sqe; struct nes_hw_nic_sq_wqe *nic_sqe;
struct tcphdr *tcph; struct tcphdr *tcph;
/* struct udphdr *udph; */ /* struct udphdr *udph; */
#define NES_MAX_TSO_FRAGS 18 #define NES_MAX_TSO_FRAGS MAX_SKB_FRAGS
/* 64K segment plus overflow on each side */ /* 64K segment plus overflow on each side */
dma_addr_t tso_bus_address[NES_MAX_TSO_FRAGS]; dma_addr_t tso_bus_address[NES_MAX_TSO_FRAGS];
dma_addr_t bus_address; dma_addr_t bus_address;
...@@ -605,6 +611,8 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev) ...@@ -605,6 +611,8 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev)
wqe_fragment_length[wqe_fragment_index] = 0; wqe_fragment_length[wqe_fragment_index] = 0;
set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG1_LOW_IDX, set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG1_LOW_IDX,
bus_address); bus_address);
tso_wqe_length += skb_headlen(skb) -
original_first_length;
} }
while (wqe_fragment_index < 5) { while (wqe_fragment_index < 5) {
wqe_fragment_length[wqe_fragment_index] = wqe_fragment_length[wqe_fragment_index] =
...@@ -827,6 +835,7 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) ...@@ -827,6 +835,7 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
{ {
struct nes_vnic *nesvnic = netdev_priv(netdev); struct nes_vnic *nesvnic = netdev_priv(netdev);
struct nes_device *nesdev = nesvnic->nesdev; struct nes_device *nesdev = nesvnic->nesdev;
struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;
struct dev_mc_list *multicast_addr; struct dev_mc_list *multicast_addr;
u32 nic_active_bit; u32 nic_active_bit;
u32 nic_active; u32 nic_active;
...@@ -836,7 +845,12 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) ...@@ -836,7 +845,12 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
u8 mc_all_on = 0; u8 mc_all_on = 0;
u8 mc_index; u8 mc_index;
int mc_nic_index = -1; int mc_nic_index = -1;
u8 pft_entries_preallocated = max(nesadapter->adapter_fcn_count *
nics_per_function, 4);
u8 max_pft_entries_avaiable = NES_PFT_SIZE - pft_entries_preallocated;
unsigned long flags;
spin_lock_irqsave(&nesadapter->resource_lock, flags);
nic_active_bit = 1 << nesvnic->nic_index; nic_active_bit = 1 << nesvnic->nic_index;
if (netdev->flags & IFF_PROMISC) { if (netdev->flags & IFF_PROMISC) {
...@@ -847,7 +861,7 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) ...@@ -847,7 +861,7 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
nic_active |= nic_active_bit; nic_active |= nic_active_bit;
nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active); nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
mc_all_on = 1; mc_all_on = 1;
} else if ((netdev->flags & IFF_ALLMULTI) || (netdev->mc_count > NES_MULTICAST_PF_MAX) || } else if ((netdev->flags & IFF_ALLMULTI) ||
(nesvnic->nic_index > 3)) { (nesvnic->nic_index > 3)) {
nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL); nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
nic_active |= nic_active_bit; nic_active |= nic_active_bit;
...@@ -866,17 +880,34 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) ...@@ -866,17 +880,34 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
} }
nes_debug(NES_DBG_NIC_RX, "Number of MC entries = %d, Promiscous = %d, All Multicast = %d.\n", nes_debug(NES_DBG_NIC_RX, "Number of MC entries = %d, Promiscous = %d, All Multicast = %d.\n",
netdev->mc_count, (netdev->flags & IFF_PROMISC)?1:0, netdev->mc_count, !!(netdev->flags & IFF_PROMISC),
(netdev->flags & IFF_ALLMULTI)?1:0); !!(netdev->flags & IFF_ALLMULTI));
if (!mc_all_on) { if (!mc_all_on) {
multicast_addr = netdev->mc_list; multicast_addr = netdev->mc_list;
perfect_filter_register_address = NES_IDX_PERFECT_FILTER_LOW + 0x80; perfect_filter_register_address = NES_IDX_PERFECT_FILTER_LOW +
perfect_filter_register_address += nesvnic->nic_index*0x40; pft_entries_preallocated * 0x8;
for (mc_index=0; mc_index < NES_MULTICAST_PF_MAX; mc_index++) { for (mc_index = 0; mc_index < max_pft_entries_avaiable;
while (multicast_addr && nesvnic->mcrq_mcast_filter && ((mc_nic_index = nesvnic->mcrq_mcast_filter(nesvnic, multicast_addr->dmi_addr)) == 0)) mc_index++) {
while (multicast_addr && nesvnic->mcrq_mcast_filter &&
((mc_nic_index = nesvnic->mcrq_mcast_filter(nesvnic,
multicast_addr->dmi_addr)) == 0)) {
multicast_addr = multicast_addr->next; multicast_addr = multicast_addr->next;
}
if (mc_nic_index < 0) if (mc_nic_index < 0)
mc_nic_index = nesvnic->nic_index; mc_nic_index = nesvnic->nic_index;
while (nesadapter->pft_mcast_map[mc_index] < 16 &&
nesadapter->pft_mcast_map[mc_index] !=
nesvnic->nic_index &&
mc_index < max_pft_entries_avaiable) {
nes_debug(NES_DBG_NIC_RX,
"mc_index=%d skipping nic_index=%d,\
used for=%d \n", mc_index,
nesvnic->nic_index,
nesadapter->pft_mcast_map[mc_index]);
mc_index++;
}
if (mc_index >= max_pft_entries_avaiable)
break;
if (multicast_addr) { if (multicast_addr) {
DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac);
nes_debug(NES_DBG_NIC_RX, "Assigning MC Address %s to register 0x%04X nic_idx=%d\n", nes_debug(NES_DBG_NIC_RX, "Assigning MC Address %s to register 0x%04X nic_idx=%d\n",
...@@ -897,15 +928,33 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) ...@@ -897,15 +928,33 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
(u32)macaddr_high | NES_MAC_ADDR_VALID | (u32)macaddr_high | NES_MAC_ADDR_VALID |
((((u32)(1<<mc_nic_index)) << 16))); ((((u32)(1<<mc_nic_index)) << 16)));
multicast_addr = multicast_addr->next; multicast_addr = multicast_addr->next;
nesadapter->pft_mcast_map[mc_index] =
nesvnic->nic_index;
} else { } else {
nes_debug(NES_DBG_NIC_RX, "Clearing MC Address at register 0x%04X\n", nes_debug(NES_DBG_NIC_RX, "Clearing MC Address at register 0x%04X\n",
perfect_filter_register_address+(mc_index * 8)); perfect_filter_register_address+(mc_index * 8));
nes_write_indexed(nesdev, nes_write_indexed(nesdev,
perfect_filter_register_address+4+(mc_index * 8), perfect_filter_register_address+4+(mc_index * 8),
0); 0);
nesadapter->pft_mcast_map[mc_index] = 255;
} }
} }
/* PFT is not large enough */
if (multicast_addr && multicast_addr->next) {
nic_active = nes_read_indexed(nesdev,
NES_IDX_NIC_MULTICAST_ALL);
nic_active |= nic_active_bit;
nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL,
nic_active);
nic_active = nes_read_indexed(nesdev,
NES_IDX_NIC_UNICAST_ALL);
nic_active &= ~nic_active_bit;
nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL,
nic_active);
} }
}
spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
} }
...@@ -918,6 +967,10 @@ static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu) ...@@ -918,6 +967,10 @@ static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu)
struct nes_device *nesdev = nesvnic->nesdev; struct nes_device *nesdev = nesvnic->nesdev;
int ret = 0; int ret = 0;
u8 jumbomode = 0; u8 jumbomode = 0;
u32 nic_active;
u32 nic_active_bit;
u32 uc_all_active;
u32 mc_all_active;
if ((new_mtu < ETH_ZLEN) || (new_mtu > max_mtu)) if ((new_mtu < ETH_ZLEN) || (new_mtu > max_mtu))
return -EINVAL; return -EINVAL;
...@@ -931,8 +984,24 @@ static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu) ...@@ -931,8 +984,24 @@ static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu)
nes_nic_init_timer_defaults(nesdev, jumbomode); nes_nic_init_timer_defaults(nesdev, jumbomode);
if (netif_running(netdev)) { if (netif_running(netdev)) {
nic_active_bit = 1 << nesvnic->nic_index;
mc_all_active = nes_read_indexed(nesdev,
NES_IDX_NIC_MULTICAST_ALL) & nic_active_bit;
uc_all_active = nes_read_indexed(nesdev,
NES_IDX_NIC_UNICAST_ALL) & nic_active_bit;
nes_netdev_stop(netdev); nes_netdev_stop(netdev);
nes_netdev_open(netdev); nes_netdev_open(netdev);
nic_active = nes_read_indexed(nesdev,
NES_IDX_NIC_MULTICAST_ALL);
nic_active |= mc_all_active;
nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL,
nic_active);
nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
nic_active |= uc_all_active;
nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
} }
return ret; return ret;
...@@ -1208,10 +1277,12 @@ static void nes_netdev_get_drvinfo(struct net_device *netdev, ...@@ -1208,10 +1277,12 @@ static void nes_netdev_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo) struct ethtool_drvinfo *drvinfo)
{ {
struct nes_vnic *nesvnic = netdev_priv(netdev); struct nes_vnic *nesvnic = netdev_priv(netdev);
struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;
strcpy(drvinfo->driver, DRV_NAME); strcpy(drvinfo->driver, DRV_NAME);
strcpy(drvinfo->bus_info, pci_name(nesvnic->nesdev->pcidev)); strcpy(drvinfo->bus_info, pci_name(nesvnic->nesdev->pcidev));
strcpy(drvinfo->fw_version, "TBD"); sprintf(drvinfo->fw_version, "%u.%u", nesadapter->firmware_version>>16,
nesadapter->firmware_version & 0x000000ff);
strcpy(drvinfo->version, DRV_VERSION); strcpy(drvinfo->version, DRV_VERSION);
drvinfo->n_stats = nes_netdev_get_stats_count(netdev); drvinfo->n_stats = nes_netdev_get_stats_count(netdev);
drvinfo->testinfo_len = 0; drvinfo->testinfo_len = 0;
...@@ -1587,7 +1658,9 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, ...@@ -1587,7 +1658,9 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
nesvnic, (unsigned long)netdev->features, nesvnic->nic.qp_id, nesvnic, (unsigned long)netdev->features, nesvnic->nic.qp_id,
nesvnic->nic_index, nesvnic->logical_port, nesdev->mac_index); nesvnic->nic_index, nesvnic->logical_port, nesdev->mac_index);
if (nesvnic->nesdev->nesadapter->port_count == 1) { if (nesvnic->nesdev->nesadapter->port_count == 1 &&
nesvnic->nesdev->nesadapter->adapter_fcn_count == 1) {
nesvnic->qp_nic_index[0] = nesvnic->nic_index; nesvnic->qp_nic_index[0] = nesvnic->nic_index;
nesvnic->qp_nic_index[1] = nesvnic->nic_index + 1; nesvnic->qp_nic_index[1] = nesvnic->nic_index + 1;
if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT) { if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT) {
...@@ -1598,9 +1671,12 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, ...@@ -1598,9 +1671,12 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
nesvnic->qp_nic_index[3] = nesvnic->nic_index + 3; nesvnic->qp_nic_index[3] = nesvnic->nic_index + 3;
} }
} else { } else {
if (nesvnic->nesdev->nesadapter->port_count == 2) { if (nesvnic->nesdev->nesadapter->port_count == 2 ||
(nesvnic->nesdev->nesadapter->port_count == 1 &&
nesvnic->nesdev->nesadapter->adapter_fcn_count == 2)) {
nesvnic->qp_nic_index[0] = nesvnic->nic_index; nesvnic->qp_nic_index[0] = nesvnic->nic_index;
nesvnic->qp_nic_index[1] = nesvnic->nic_index + 2; nesvnic->qp_nic_index[1] = nesvnic->nic_index
+ 2;
nesvnic->qp_nic_index[2] = 0xf; nesvnic->qp_nic_index[2] = 0xf;
nesvnic->qp_nic_index[3] = 0xf; nesvnic->qp_nic_index[3] = 0xf;
} else { } else {
......
...@@ -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