提交 99f1c97d 编写于 作者: L 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: (81 commits)
  RDMA/cxgb3: Fix the T3A workaround checks
  IB/ipath: Remove unnecessary cast
  IPoIB: Constify seq_operations function pointer tables
  RDMA/cxgb3: Mark QP as privileged based on user capabilities
  RDMA/cxgb3: Fix page shift calculation in build_phys_page_list()
  RDMA/cxgb3: Flush the receive queue when closing
  IB/ipath: Trivial simplification of ipath_make_ud_req()
  IB/mthca: Update latest "native Arbel" firmware revision
  IPoIB: Remove redundant check of netif_queue_stopped() in xmit handler
  IB/ipath: Add mappings from HW register to PortInfo port physical state
  IB/ipath: Changes to support PIO bandwidth check on IBA7220
  IB/ipath: Minor cleanup of unused fields and chip-specific errors
  IB/ipath: New sysfs entries to control 7220 features
  IB/ipath: Add new chip-specific functions to older chips, consistent init
  IB/ipath: Remove unused MDIO interface code
  IB/ehca: Prevent RDMA-related connection failures on some eHCA2 hardware
  IB/ehca: Add "port connection autodetect mode"
  IB/ehca: Define array to store SMI/GSI QPs
  IB/ehca: Remove CQ-QP-link before destroying QP in error path of create_qp()
  IB/iser: Add change_queue_depth method
  ...
......@@ -295,16 +295,6 @@ Who: linuxppc-dev@ozlabs.org
---------------------------
What: mthca driver's MSI support
When: January 2008
Files: drivers/infiniband/hw/mthca/*.[ch]
Why: All mthca hardware also supports MSI-X, which provides
strictly more functionality than MSI. So there is no point in
having both MSI-X and MSI support in the driver.
Who: Roland Dreier <rolandd@cisco.com>
---------------------------
What: sk98lin network driver
When: Feburary 2008
Why: In kernel tree version of driver is unmaintained. Sk98lin driver
......
/*
* Copyright (c) 2004-2006 Intel Corporation. All rights reserved.
* Copyright (c) 2004-2007 Intel Corporation. All rights reserved.
* Copyright (c) 2004 Topspin Corporation. All rights reserved.
* Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved.
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
......@@ -37,12 +37,14 @@
#include <linux/completion.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/idr.h>
#include <linux/interrupt.h>
#include <linux/random.h>
#include <linux/rbtree.h>
#include <linux/spinlock.h>
#include <linux/sysfs.h>
#include <linux/workqueue.h>
#include <rdma/ib_cache.h>
......@@ -78,17 +80,94 @@ static struct ib_cm {
struct workqueue_struct *wq;
} cm;
/* Counter indexes ordered by attribute ID */
enum {
CM_REQ_COUNTER,
CM_MRA_COUNTER,
CM_REJ_COUNTER,
CM_REP_COUNTER,
CM_RTU_COUNTER,
CM_DREQ_COUNTER,
CM_DREP_COUNTER,
CM_SIDR_REQ_COUNTER,
CM_SIDR_REP_COUNTER,
CM_LAP_COUNTER,
CM_APR_COUNTER,
CM_ATTR_COUNT,
CM_ATTR_ID_OFFSET = 0x0010,
};
enum {
CM_XMIT,
CM_XMIT_RETRIES,
CM_RECV,
CM_RECV_DUPLICATES,
CM_COUNTER_GROUPS
};
static char const counter_group_names[CM_COUNTER_GROUPS]
[sizeof("cm_rx_duplicates")] = {
"cm_tx_msgs", "cm_tx_retries",
"cm_rx_msgs", "cm_rx_duplicates"
};
struct cm_counter_group {
struct kobject obj;
atomic_long_t counter[CM_ATTR_COUNT];
};
struct cm_counter_attribute {
struct attribute attr;
int index;
};
#define CM_COUNTER_ATTR(_name, _index) \
struct cm_counter_attribute cm_##_name##_counter_attr = { \
.attr = { .name = __stringify(_name), .mode = 0444, .owner = THIS_MODULE }, \
.index = _index \
}
static CM_COUNTER_ATTR(req, CM_REQ_COUNTER);
static CM_COUNTER_ATTR(mra, CM_MRA_COUNTER);
static CM_COUNTER_ATTR(rej, CM_REJ_COUNTER);
static CM_COUNTER_ATTR(rep, CM_REP_COUNTER);
static CM_COUNTER_ATTR(rtu, CM_RTU_COUNTER);
static CM_COUNTER_ATTR(dreq, CM_DREQ_COUNTER);
static CM_COUNTER_ATTR(drep, CM_DREP_COUNTER);
static CM_COUNTER_ATTR(sidr_req, CM_SIDR_REQ_COUNTER);
static CM_COUNTER_ATTR(sidr_rep, CM_SIDR_REP_COUNTER);
static CM_COUNTER_ATTR(lap, CM_LAP_COUNTER);
static CM_COUNTER_ATTR(apr, CM_APR_COUNTER);
static struct attribute *cm_counter_default_attrs[] = {
&cm_req_counter_attr.attr,
&cm_mra_counter_attr.attr,
&cm_rej_counter_attr.attr,
&cm_rep_counter_attr.attr,
&cm_rtu_counter_attr.attr,
&cm_dreq_counter_attr.attr,
&cm_drep_counter_attr.attr,
&cm_sidr_req_counter_attr.attr,
&cm_sidr_rep_counter_attr.attr,
&cm_lap_counter_attr.attr,
&cm_apr_counter_attr.attr,
NULL
};
struct cm_port {
struct cm_device *cm_dev;
struct ib_mad_agent *mad_agent;
struct kobject port_obj;
u8 port_num;
struct cm_counter_group counter_group[CM_COUNTER_GROUPS];
};
struct cm_device {
struct list_head list;
struct ib_device *device;
struct kobject dev_obj;
u8 ack_delay;
struct cm_port port[0];
struct cm_port *port[0];
};
struct cm_av {
......@@ -278,7 +357,7 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
list_for_each_entry(cm_dev, &cm.device_list, list) {
if (!ib_find_cached_gid(cm_dev->device, &path->sgid,
&p, NULL)) {
port = &cm_dev->port[p-1];
port = cm_dev->port[p-1];
break;
}
}
......@@ -1270,6 +1349,9 @@ static void cm_dup_req_handler(struct cm_work *work,
struct ib_mad_send_buf *msg = NULL;
int ret;
atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
counter[CM_REQ_COUNTER]);
/* Quick state check to discard duplicate REQs. */
if (cm_id_priv->id.state == IB_CM_REQ_RCVD)
return;
......@@ -1616,6 +1698,8 @@ static void cm_dup_rep_handler(struct cm_work *work)
if (!cm_id_priv)
return;
atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
counter[CM_REP_COUNTER]);
ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg);
if (ret)
goto deref;
......@@ -1781,6 +1865,8 @@ static int cm_rtu_handler(struct cm_work *work)
if (cm_id_priv->id.state != IB_CM_REP_SENT &&
cm_id_priv->id.state != IB_CM_MRA_REP_RCVD) {
spin_unlock_irq(&cm_id_priv->lock);
atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
counter[CM_RTU_COUNTER]);
goto out;
}
cm_id_priv->id.state = IB_CM_ESTABLISHED;
......@@ -1958,6 +2044,8 @@ static int cm_dreq_handler(struct cm_work *work)
cm_id_priv = cm_acquire_id(dreq_msg->remote_comm_id,
dreq_msg->local_comm_id);
if (!cm_id_priv) {
atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
counter[CM_DREQ_COUNTER]);
cm_issue_drep(work->port, work->mad_recv_wc);
return -EINVAL;
}
......@@ -1977,6 +2065,8 @@ static int cm_dreq_handler(struct cm_work *work)
case IB_CM_MRA_REP_RCVD:
break;
case IB_CM_TIMEWAIT:
atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
counter[CM_DREQ_COUNTER]);
if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg))
goto unlock;
......@@ -1988,6 +2078,10 @@ static int cm_dreq_handler(struct cm_work *work)
if (ib_post_send_mad(msg, NULL))
cm_free_msg(msg);
goto deref;
case IB_CM_DREQ_RCVD:
atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
counter[CM_DREQ_COUNTER]);
goto unlock;
default:
goto unlock;
}
......@@ -2339,10 +2433,20 @@ static int cm_mra_handler(struct cm_work *work)
if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_OTHER ||
cm_id_priv->id.lap_state != IB_CM_LAP_SENT ||
ib_modify_mad(cm_id_priv->av.port->mad_agent,
cm_id_priv->msg, timeout))
cm_id_priv->msg, timeout)) {
if (cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD)
atomic_long_inc(&work->port->
counter_group[CM_RECV_DUPLICATES].
counter[CM_MRA_COUNTER]);
goto out;
}
cm_id_priv->id.lap_state = IB_CM_MRA_LAP_RCVD;
break;
case IB_CM_MRA_REQ_RCVD:
case IB_CM_MRA_REP_RCVD:
atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
counter[CM_MRA_COUNTER]);
/* fall through */
default:
goto out;
}
......@@ -2502,6 +2606,8 @@ static int cm_lap_handler(struct cm_work *work)
case IB_CM_LAP_IDLE:
break;
case IB_CM_MRA_LAP_SENT:
atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
counter[CM_LAP_COUNTER]);
if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg))
goto unlock;
......@@ -2515,6 +2621,10 @@ static int cm_lap_handler(struct cm_work *work)
if (ib_post_send_mad(msg, NULL))
cm_free_msg(msg);
goto deref;
case IB_CM_LAP_RCVD:
atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
counter[CM_LAP_COUNTER]);
goto unlock;
default:
goto unlock;
}
......@@ -2796,6 +2906,8 @@ static int cm_sidr_req_handler(struct cm_work *work)
cur_cm_id_priv = cm_insert_remote_sidr(cm_id_priv);
if (cur_cm_id_priv) {
spin_unlock_irq(&cm.lock);
atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
counter[CM_SIDR_REQ_COUNTER]);
goto out; /* Duplicate message. */
}
cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD;
......@@ -2990,6 +3102,27 @@ static void cm_send_handler(struct ib_mad_agent *mad_agent,
struct ib_mad_send_wc *mad_send_wc)
{
struct ib_mad_send_buf *msg = mad_send_wc->send_buf;
struct cm_port *port;
u16 attr_index;
port = mad_agent->context;
attr_index = be16_to_cpu(((struct ib_mad_hdr *)
msg->mad)->attr_id) - CM_ATTR_ID_OFFSET;
/*
* If the send was in response to a received message (context[0] is not
* set to a cm_id), and is not a REJ, then it is a send that was
* manually retried.
*/
if (!msg->context[0] && (attr_index != CM_REJ_COUNTER))
msg->retries = 1;
atomic_long_add(1 + msg->retries,
&port->counter_group[CM_XMIT].counter[attr_index]);
if (msg->retries)
atomic_long_add(msg->retries,
&port->counter_group[CM_XMIT_RETRIES].
counter[attr_index]);
switch (mad_send_wc->status) {
case IB_WC_SUCCESS:
......@@ -3148,8 +3281,10 @@ EXPORT_SYMBOL(ib_cm_notify);
static void cm_recv_handler(struct ib_mad_agent *mad_agent,
struct ib_mad_recv_wc *mad_recv_wc)
{
struct cm_port *port = mad_agent->context;
struct cm_work *work;
enum ib_cm_event_type event;
u16 attr_id;
int paths = 0;
switch (mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) {
......@@ -3194,6 +3329,10 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent,
return;
}
attr_id = be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id);
atomic_long_inc(&port->counter_group[CM_RECV].
counter[attr_id - CM_ATTR_ID_OFFSET]);
work = kmalloc(sizeof *work + sizeof(struct ib_sa_path_rec) * paths,
GFP_KERNEL);
if (!work) {
......@@ -3204,7 +3343,7 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent,
INIT_DELAYED_WORK(&work->work, cm_work_handler);
work->cm_event.event = event;
work->mad_recv_wc = mad_recv_wc;
work->port = (struct cm_port *)mad_agent->context;
work->port = port;
queue_delayed_work(cm.wq, &work->work, 0);
}
......@@ -3379,6 +3518,108 @@ static void cm_get_ack_delay(struct cm_device *cm_dev)
cm_dev->ack_delay = attr.local_ca_ack_delay;
}
static ssize_t cm_show_counter(struct kobject *obj, struct attribute *attr,
char *buf)
{
struct cm_counter_group *group;
struct cm_counter_attribute *cm_attr;
group = container_of(obj, struct cm_counter_group, obj);
cm_attr = container_of(attr, struct cm_counter_attribute, attr);
return sprintf(buf, "%ld\n",
atomic_long_read(&group->counter[cm_attr->index]));
}
static struct sysfs_ops cm_counter_ops = {
.show = cm_show_counter
};
static struct kobj_type cm_counter_obj_type = {
.sysfs_ops = &cm_counter_ops,
.default_attrs = cm_counter_default_attrs
};
static void cm_release_port_obj(struct kobject *obj)
{
struct cm_port *cm_port;
printk(KERN_ERR "free cm port\n");
cm_port = container_of(obj, struct cm_port, port_obj);
kfree(cm_port);
}
static struct kobj_type cm_port_obj_type = {
.release = cm_release_port_obj
};
static void cm_release_dev_obj(struct kobject *obj)
{
struct cm_device *cm_dev;
printk(KERN_ERR "free cm dev\n");
cm_dev = container_of(obj, struct cm_device, dev_obj);
kfree(cm_dev);
}
static struct kobj_type cm_dev_obj_type = {
.release = cm_release_dev_obj
};
struct class cm_class = {
.name = "infiniband_cm",
};
EXPORT_SYMBOL(cm_class);
static void cm_remove_fs_obj(struct kobject *obj)
{
kobject_put(obj->parent);
kobject_put(obj);
}
static int cm_create_port_fs(struct cm_port *port)
{
int i, ret;
ret = kobject_init_and_add(&port->port_obj, &cm_port_obj_type,
kobject_get(&port->cm_dev->dev_obj),
"%d", port->port_num);
if (ret) {
kfree(port);
return ret;
}
for (i = 0; i < CM_COUNTER_GROUPS; i++) {
ret = kobject_init_and_add(&port->counter_group[i].obj,
&cm_counter_obj_type,
kobject_get(&port->port_obj),
"%s", counter_group_names[i]);
if (ret)
goto error;
}
return 0;
error:
while (i--)
cm_remove_fs_obj(&port->counter_group[i].obj);
cm_remove_fs_obj(&port->port_obj);
return ret;
}
static void cm_remove_port_fs(struct cm_port *port)
{
int i;
for (i = 0; i < CM_COUNTER_GROUPS; i++)
cm_remove_fs_obj(&port->counter_group[i].obj);
cm_remove_fs_obj(&port->port_obj);
}
static void cm_add_one(struct ib_device *device)
{
struct cm_device *cm_dev;
......@@ -3397,7 +3638,7 @@ static void cm_add_one(struct ib_device *device)
if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
return;
cm_dev = kmalloc(sizeof(*cm_dev) + sizeof(*port) *
cm_dev = kzalloc(sizeof(*cm_dev) + sizeof(*port) *
device->phys_port_cnt, GFP_KERNEL);
if (!cm_dev)
return;
......@@ -3405,11 +3646,27 @@ static void cm_add_one(struct ib_device *device)
cm_dev->device = device;
cm_get_ack_delay(cm_dev);
ret = kobject_init_and_add(&cm_dev->dev_obj, &cm_dev_obj_type,
&cm_class.subsys.kobj, "%s", device->name);
if (ret) {
kfree(cm_dev);
return;
}
set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
for (i = 1; i <= device->phys_port_cnt; i++) {
port = &cm_dev->port[i-1];
port = kzalloc(sizeof *port, GFP_KERNEL);
if (!port)
goto error1;
cm_dev->port[i-1] = port;
port->cm_dev = cm_dev;
port->port_num = i;
ret = cm_create_port_fs(port);
if (ret)
goto error1;
port->mad_agent = ib_register_mad_agent(device, i,
IB_QPT_GSI,
&reg_req,
......@@ -3418,11 +3675,11 @@ static void cm_add_one(struct ib_device *device)
cm_recv_handler,
port);
if (IS_ERR(port->mad_agent))
goto error1;
goto error2;
ret = ib_modify_port(device, i, 0, &port_modify);
if (ret)
goto error2;
goto error3;
}
ib_set_client_data(device, &cm_client, cm_dev);
......@@ -3431,17 +3688,20 @@ static void cm_add_one(struct ib_device *device)
write_unlock_irqrestore(&cm.device_lock, flags);
return;
error2:
error3:
ib_unregister_mad_agent(port->mad_agent);
error2:
cm_remove_port_fs(port);
error1:
port_modify.set_port_cap_mask = 0;
port_modify.clr_port_cap_mask = IB_PORT_CM_SUP;
while (--i) {
port = &cm_dev->port[i-1];
port = cm_dev->port[i-1];
ib_modify_port(device, port->port_num, 0, &port_modify);
ib_unregister_mad_agent(port->mad_agent);
cm_remove_port_fs(port);
}
kfree(cm_dev);
cm_remove_fs_obj(&cm_dev->dev_obj);
}
static void cm_remove_one(struct ib_device *device)
......@@ -3463,11 +3723,12 @@ static void cm_remove_one(struct ib_device *device)
write_unlock_irqrestore(&cm.device_lock, flags);
for (i = 1; i <= device->phys_port_cnt; i++) {
port = &cm_dev->port[i-1];
port = cm_dev->port[i-1];
ib_modify_port(device, port->port_num, 0, &port_modify);
ib_unregister_mad_agent(port->mad_agent);
cm_remove_port_fs(port);
}
kfree(cm_dev);
cm_remove_fs_obj(&cm_dev->dev_obj);
}
static int __init ib_cm_init(void)
......@@ -3488,17 +3749,25 @@ static int __init ib_cm_init(void)
idr_pre_get(&cm.local_id_table, GFP_KERNEL);
INIT_LIST_HEAD(&cm.timewait_list);
cm.wq = create_workqueue("ib_cm");
if (!cm.wq)
ret = class_register(&cm_class);
if (ret)
return -ENOMEM;
cm.wq = create_workqueue("ib_cm");
if (!cm.wq) {
ret = -ENOMEM;
goto error1;
}
ret = ib_register_client(&cm_client);
if (ret)
goto error;
goto error2;
return 0;
error:
error2:
destroy_workqueue(cm.wq);
error1:
class_unregister(&cm_class);
return ret;
}
......@@ -3519,6 +3788,7 @@ static void __exit ib_cm_cleanup(void)
}
ib_unregister_client(&cm_client);
class_unregister(&cm_class);
idr_destroy(&cm.local_id_table);
}
......
......@@ -488,7 +488,8 @@ void rdma_destroy_qp(struct rdma_cm_id *id)
}
EXPORT_SYMBOL(rdma_destroy_qp);
static int cma_modify_qp_rtr(struct rdma_id_private *id_priv)
static int cma_modify_qp_rtr(struct rdma_id_private *id_priv,
struct rdma_conn_param *conn_param)
{
struct ib_qp_attr qp_attr;
int qp_attr_mask, ret;
......@@ -514,13 +515,16 @@ static int cma_modify_qp_rtr(struct rdma_id_private *id_priv)
if (ret)
goto out;
if (conn_param)
qp_attr.max_dest_rd_atomic = conn_param->responder_resources;
ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
out:
mutex_unlock(&id_priv->qp_mutex);
return ret;
}
static int cma_modify_qp_rts(struct rdma_id_private *id_priv)
static int cma_modify_qp_rts(struct rdma_id_private *id_priv,
struct rdma_conn_param *conn_param)
{
struct ib_qp_attr qp_attr;
int qp_attr_mask, ret;
......@@ -536,6 +540,8 @@ static int cma_modify_qp_rts(struct rdma_id_private *id_priv)
if (ret)
goto out;
if (conn_param)
qp_attr.max_rd_atomic = conn_param->initiator_depth;
ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
out:
mutex_unlock(&id_priv->qp_mutex);
......@@ -866,11 +872,11 @@ static int cma_rep_recv(struct rdma_id_private *id_priv)
{
int ret;
ret = cma_modify_qp_rtr(id_priv);
ret = cma_modify_qp_rtr(id_priv, NULL);
if (ret)
goto reject;
ret = cma_modify_qp_rts(id_priv);
ret = cma_modify_qp_rts(id_priv, NULL);
if (ret)
goto reject;
......@@ -1122,8 +1128,10 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
cm_id->cm_handler = cma_ib_handler;
ret = conn_id->id.event_handler(&conn_id->id, &event);
if (!ret)
if (!ret) {
cma_enable_remove(conn_id);
goto out;
}
/* Destroy the CM ID by returning a non-zero value. */
conn_id->cm_id.ib = NULL;
......@@ -1262,6 +1270,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
struct net_device *dev = NULL;
struct rdma_cm_event event;
int ret;
struct ib_device_attr attr;
listen_id = cm_id->context;
if (cma_disable_remove(listen_id, CMA_LISTEN))
......@@ -1311,10 +1320,19 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr;
*sin = iw_event->remote_addr;
ret = ib_query_device(conn_id->id.device, &attr);
if (ret) {
cma_enable_remove(conn_id);
rdma_destroy_id(new_cm_id);
goto out;
}
memset(&event, 0, sizeof event);
event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
event.param.conn.private_data = iw_event->private_data;
event.param.conn.private_data_len = iw_event->private_data_len;
event.param.conn.initiator_depth = attr.max_qp_init_rd_atom;
event.param.conn.responder_resources = attr.max_qp_rd_atom;
ret = conn_id->id.event_handler(&conn_id->id, &event);
if (ret) {
/* User wants to destroy the CM ID */
......@@ -2272,7 +2290,7 @@ static int cma_connect_iw(struct rdma_id_private *id_priv,
sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr;
cm_id->remote_addr = *sin;
ret = cma_modify_qp_rtr(id_priv);
ret = cma_modify_qp_rtr(id_priv, conn_param);
if (ret)
goto out;
......@@ -2335,25 +2353,15 @@ static int cma_accept_ib(struct rdma_id_private *id_priv,
struct rdma_conn_param *conn_param)
{
struct ib_cm_rep_param rep;
struct ib_qp_attr qp_attr;
int qp_attr_mask, ret;
if (id_priv->id.qp) {
ret = cma_modify_qp_rtr(id_priv);
if (ret)
goto out;
int ret;
qp_attr.qp_state = IB_QPS_RTS;
ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, &qp_attr,
&qp_attr_mask);
if (ret)
goto out;
ret = cma_modify_qp_rtr(id_priv, conn_param);
if (ret)
goto out;
qp_attr.max_rd_atomic = conn_param->initiator_depth;
ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
if (ret)
goto out;
}
ret = cma_modify_qp_rts(id_priv, conn_param);
if (ret)
goto out;
memset(&rep, 0, sizeof rep);
rep.qp_num = id_priv->qp_num;
......@@ -2378,7 +2386,7 @@ static int cma_accept_iw(struct rdma_id_private *id_priv,
struct iw_cm_conn_param iw_param;
int ret;
ret = cma_modify_qp_rtr(id_priv);
ret = cma_modify_qp_rtr(id_priv, conn_param);
if (ret)
return ret;
......@@ -2598,11 +2606,9 @@ static void cma_set_mgid(struct rdma_id_private *id_priv,
/* IPv6 address is an SA assigned MGID. */
memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
} else {
ip_ib_mc_map(sin->sin_addr.s_addr, mc_map);
ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map);
if (id_priv->id.ps == RDMA_PS_UDP)
mc_map[7] = 0x01; /* Use RDMA CM signature */
mc_map[8] = ib_addr_get_pkey(dev_addr) >> 8;
mc_map[9] = (unsigned char) ib_addr_get_pkey(dev_addr);
*mgid = *(union ib_gid *) (mc_map + 4);
}
}
......
......@@ -139,7 +139,7 @@ static inline struct ib_pool_fmr *ib_fmr_cache_lookup(struct ib_fmr_pool *pool,
static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
{
int ret;
struct ib_pool_fmr *fmr;
struct ib_pool_fmr *fmr, *next;
LIST_HEAD(unmap_list);
LIST_HEAD(fmr_list);
......@@ -158,6 +158,20 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
#endif
}
/*
* The free_list may hold FMRs that have been put there
* because they haven't reached the max_remap count.
* Invalidate their mapping as well.
*/
list_for_each_entry_safe(fmr, next, &pool->free_list, list) {
if (fmr->remap_count == 0)
continue;
hlist_del_init(&fmr->cache_node);
fmr->remap_count = 0;
list_add_tail(&fmr->fmr->list, &fmr_list);
list_move(&fmr->list, &unmap_list);
}
list_splice(&pool->dirty_list, &unmap_list);
INIT_LIST_HEAD(&pool->dirty_list);
pool->dirty_len = 0;
......@@ -182,8 +196,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr)
struct ib_fmr_pool *pool = pool_ptr;
do {
if (pool->dirty_len >= pool->dirty_watermark ||
atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) {
if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) {
ib_fmr_batch_release(pool);
atomic_inc(&pool->flush_ser);
......@@ -194,8 +207,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr)
}
set_current_state(TASK_INTERRUPTIBLE);
if (pool->dirty_len < pool->dirty_watermark &&
atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 &&
if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 &&
!kthread_should_stop())
schedule();
__set_current_state(TASK_RUNNING);
......@@ -369,11 +381,6 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool)
i = 0;
list_for_each_entry_safe(fmr, tmp, &pool->free_list, list) {
if (fmr->remap_count) {
INIT_LIST_HEAD(&fmr_list);
list_add_tail(&fmr->fmr->list, &fmr_list);
ib_unmap_fmr(&fmr_list);
}
ib_dealloc_fmr(fmr->fmr);
list_del(&fmr->list);
kfree(fmr);
......@@ -511,8 +518,10 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr)
list_add_tail(&fmr->list, &pool->free_list);
} else {
list_add_tail(&fmr->list, &pool->dirty_list);
++pool->dirty_len;
wake_up_process(pool->thread);
if (++pool->dirty_len >= pool->dirty_watermark) {
atomic_inc(&pool->req_ser);
wake_up_process(pool->thread);
}
}
}
......
......@@ -701,7 +701,8 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
}
/* Check to post send on QP or process locally */
if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD)
if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD &&
smi_check_local_returning_smp(smp, device) == IB_SMI_DISCARD)
goto out;
local = kmalloc(sizeof *local, GFP_ATOMIC);
......@@ -752,8 +753,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
port_priv = ib_get_mad_port(mad_agent_priv->agent.device,
mad_agent_priv->agent.port_num);
if (port_priv) {
mad_priv->mad.mad.mad_hdr.tid =
((struct ib_mad *)smp)->mad_hdr.tid;
memcpy(&mad_priv->mad.mad, smp, sizeof(struct ib_mad));
recv_mad_agent = find_mad_agent(port_priv,
&mad_priv->mad.mad);
}
......@@ -1100,7 +1100,9 @@ int ib_post_send_mad(struct ib_mad_send_buf *send_buf,
mad_send_wr->tid = ((struct ib_mad_hdr *) send_buf->mad)->tid;
/* Timeout will be updated after send completes */
mad_send_wr->timeout = msecs_to_jiffies(send_buf->timeout_ms);
mad_send_wr->retries = send_buf->retries;
mad_send_wr->max_retries = send_buf->retries;
mad_send_wr->retries_left = send_buf->retries;
send_buf->retries = 0;
/* Reference for work request to QP + response */
mad_send_wr->refcount = 1 + (mad_send_wr->timeout > 0);
mad_send_wr->status = IB_WC_SUCCESS;
......@@ -1931,15 +1933,6 @@ static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv,
if (port_priv->device->process_mad) {
int ret;
if (!response) {
printk(KERN_ERR PFX "No memory for response MAD\n");
/*
* Is it better to assume that
* it wouldn't be processed ?
*/
goto out;
}
ret = port_priv->device->process_mad(port_priv->device, 0,
port_priv->port_num,
wc, &recv->grh,
......@@ -2282,8 +2275,6 @@ static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv)
/* Empty wait list to prevent receives from finding a request */
list_splice_init(&mad_agent_priv->wait_list, &cancel_list);
/* Empty local completion list as well */
list_splice_init(&mad_agent_priv->local_list, &cancel_list);
spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
/* Report all cancelled requests */
......@@ -2445,9 +2436,12 @@ static int retry_send(struct ib_mad_send_wr_private *mad_send_wr)
{
int ret;
if (!mad_send_wr->retries--)
if (!mad_send_wr->retries_left)
return -ETIMEDOUT;
mad_send_wr->retries_left--;
mad_send_wr->send_buf.retries++;
mad_send_wr->timeout = msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms);
if (mad_send_wr->mad_agent_priv->agent.rmpp_version) {
......
......@@ -131,7 +131,8 @@ struct ib_mad_send_wr_private {
struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG];
__be64 tid;
unsigned long timeout;
int retries;
int max_retries;
int retries_left;
int retry;
int refcount;
enum ib_wc_status status;
......
......@@ -684,7 +684,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
if (seg_num > mad_send_wr->last_ack) {
adjust_last_ack(mad_send_wr, seg_num);
mad_send_wr->retries = mad_send_wr->send_buf.retries;
mad_send_wr->retries_left = mad_send_wr->max_retries;
}
mad_send_wr->newwin = newwin;
if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) {
......
......@@ -73,11 +73,20 @@ struct mcast_device {
};
enum mcast_state {
MCAST_IDLE,
MCAST_JOINING,
MCAST_MEMBER,
MCAST_ERROR,
};
enum mcast_group_state {
MCAST_IDLE,
MCAST_BUSY,
MCAST_ERROR
MCAST_GROUP_ERROR,
MCAST_PKEY_EVENT
};
enum {
MCAST_INVALID_PKEY_INDEX = 0xFFFF
};
struct mcast_member;
......@@ -93,9 +102,10 @@ struct mcast_group {
struct mcast_member *last_join;
int members[3];
atomic_t refcount;
enum mcast_state state;
enum mcast_group_state state;
struct ib_sa_query *query;
int query_id;
u16 pkey_index;
};
struct mcast_member {
......@@ -378,9 +388,19 @@ static int fail_join(struct mcast_group *group, struct mcast_member *member,
static void process_group_error(struct mcast_group *group)
{
struct mcast_member *member;
int ret;
int ret = 0;
u16 pkey_index;
if (group->state == MCAST_PKEY_EVENT)
ret = ib_find_pkey(group->port->dev->device,
group->port->port_num,
be16_to_cpu(group->rec.pkey), &pkey_index);
spin_lock_irq(&group->lock);
if (group->state == MCAST_PKEY_EVENT && !ret &&
group->pkey_index == pkey_index)
goto out;
while (!list_empty(&group->active_list)) {
member = list_entry(group->active_list.next,
struct mcast_member, list);
......@@ -399,6 +419,7 @@ static void process_group_error(struct mcast_group *group)
}
group->rec.join_state = 0;
out:
group->state = MCAST_BUSY;
spin_unlock_irq(&group->lock);
}
......@@ -415,9 +436,9 @@ static void mcast_work_handler(struct work_struct *work)
retest:
spin_lock_irq(&group->lock);
while (!list_empty(&group->pending_list) ||
(group->state == MCAST_ERROR)) {
(group->state != MCAST_BUSY)) {
if (group->state == MCAST_ERROR) {
if (group->state != MCAST_BUSY) {
spin_unlock_irq(&group->lock);
process_group_error(group);
goto retest;
......@@ -494,12 +515,19 @@ static void join_handler(int status, struct ib_sa_mcmember_rec *rec,
void *context)
{
struct mcast_group *group = context;
u16 pkey_index = MCAST_INVALID_PKEY_INDEX;
if (status)
process_join_error(group, status);
else {
ib_find_pkey(group->port->dev->device, group->port->port_num,
be16_to_cpu(rec->pkey), &pkey_index);
spin_lock_irq(&group->port->lock);
group->rec = *rec;
if (group->state == MCAST_BUSY &&
group->pkey_index == MCAST_INVALID_PKEY_INDEX)
group->pkey_index = pkey_index;
if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) {
rb_erase(&group->node, &group->port->table);
mcast_insert(group->port, group, 1);
......@@ -539,6 +567,7 @@ static struct mcast_group *acquire_group(struct mcast_port *port,
group->port = port;
group->rec.mgid = *mgid;
group->pkey_index = MCAST_INVALID_PKEY_INDEX;
INIT_LIST_HEAD(&group->pending_list);
INIT_LIST_HEAD(&group->active_list);
INIT_WORK(&group->work, mcast_work_handler);
......@@ -707,7 +736,8 @@ int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num,
}
EXPORT_SYMBOL(ib_init_ah_from_mcmember);
static void mcast_groups_lost(struct mcast_port *port)
static void mcast_groups_event(struct mcast_port *port,
enum mcast_group_state state)
{
struct mcast_group *group;
struct rb_node *node;
......@@ -721,7 +751,8 @@ static void mcast_groups_lost(struct mcast_port *port)
atomic_inc(&group->refcount);
queue_work(mcast_wq, &group->work);
}
group->state = MCAST_ERROR;
if (group->state != MCAST_GROUP_ERROR)
group->state = state;
spin_unlock(&group->lock);
}
spin_unlock_irqrestore(&port->lock, flags);
......@@ -731,16 +762,20 @@ static void mcast_event_handler(struct ib_event_handler *handler,
struct ib_event *event)
{
struct mcast_device *dev;
int index;
dev = container_of(handler, struct mcast_device, event_handler);
index = event->element.port_num - dev->start_port;
switch (event->event) {
case IB_EVENT_PORT_ERR:
case IB_EVENT_LID_CHANGE:
case IB_EVENT_SM_CHANGE:
case IB_EVENT_CLIENT_REREGISTER:
mcast_groups_lost(&dev->port[event->element.port_num -
dev->start_port]);
mcast_groups_event(&dev->port[index], MCAST_GROUP_ERROR);
break;
case IB_EVENT_PKEY_CHANGE:
mcast_groups_event(&dev->port[index], MCAST_PKEY_EVENT);
break;
default:
break;
......
......@@ -59,7 +59,8 @@ extern enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp,
u8 node_type, int port_num);
/*
* Return 1 if the SMP should be handled by the local SMA/SM via process_mad
* Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM
* via process_mad
*/
static inline enum smi_action smi_check_local_smp(struct ib_smp *smp,
struct ib_device *device)
......@@ -71,4 +72,19 @@ static inline enum smi_action smi_check_local_smp(struct ib_smp *smp,
(smp->hop_ptr == smp->hop_cnt + 1)) ?
IB_SMI_HANDLE : IB_SMI_DISCARD);
}
/*
* Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM
* via process_mad
*/
static inline enum smi_action smi_check_local_returning_smp(struct ib_smp *smp,
struct ib_device *device)
{
/* C14-13:3 -- We're at the end of the DR segment of path */
/* C14-13:4 -- Hop Pointer == 0 -> give to SM */
return ((device->process_mad &&
ib_get_smp_direction(smp) &&
!smp->hop_ptr) ? IB_SMI_HANDLE : IB_SMI_DISCARD);
}
#endif /* __SMI_H_ */
......@@ -106,6 +106,9 @@ enum {
IB_UCM_MAX_DEVICES = 32
};
/* ib_cm and ib_user_cm modules share /sys/class/infiniband_cm */
extern struct class cm_class;
#define IB_UCM_BASE_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_BASE_MINOR)
static void ib_ucm_add_one(struct ib_device *device);
......@@ -1199,7 +1202,7 @@ static int ib_ucm_close(struct inode *inode, struct file *filp)
return 0;
}
static void ib_ucm_release_class_dev(struct class_device *class_dev)
static void ucm_release_class_dev(struct class_device *class_dev)
{
struct ib_ucm_device *dev;
......@@ -1217,11 +1220,6 @@ static const struct file_operations ucm_fops = {
.poll = ib_ucm_poll,
};
static struct class ucm_class = {
.name = "infiniband_cm",
.release = ib_ucm_release_class_dev
};
static ssize_t show_ibdev(struct class_device *class_dev, char *buf)
{
struct ib_ucm_device *dev;
......@@ -1257,9 +1255,10 @@ static void ib_ucm_add_one(struct ib_device *device)
if (cdev_add(&ucm_dev->dev, IB_UCM_BASE_DEV + ucm_dev->devnum, 1))
goto err;
ucm_dev->class_dev.class = &ucm_class;
ucm_dev->class_dev.class = &cm_class;
ucm_dev->class_dev.dev = device->dma_device;
ucm_dev->class_dev.devt = ucm_dev->dev.dev;
ucm_dev->class_dev.release = ucm_release_class_dev;
snprintf(ucm_dev->class_dev.class_id, BUS_ID_SIZE, "ucm%d",
ucm_dev->devnum);
if (class_device_register(&ucm_dev->class_dev))
......@@ -1306,40 +1305,34 @@ static int __init ib_ucm_init(void)
"infiniband_cm");
if (ret) {
printk(KERN_ERR "ucm: couldn't register device number\n");
goto err;
goto error1;
}
ret = class_register(&ucm_class);
if (ret) {
printk(KERN_ERR "ucm: couldn't create class infiniband_cm\n");
goto err_chrdev;
}
ret = class_create_file(&ucm_class, &class_attr_abi_version);
ret = class_create_file(&cm_class, &class_attr_abi_version);
if (ret) {
printk(KERN_ERR "ucm: couldn't create abi_version attribute\n");
goto err_class;
goto error2;
}
ret = ib_register_client(&ucm_client);
if (ret) {
printk(KERN_ERR "ucm: couldn't register client\n");
goto err_class;
goto error3;
}
return 0;
err_class:
class_unregister(&ucm_class);
err_chrdev:
error3:
class_remove_file(&cm_class, &class_attr_abi_version);
error2:
unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES);
err:
error1:
return ret;
}
static void __exit ib_ucm_cleanup(void)
{
ib_unregister_client(&ucm_client);
class_unregister(&ucm_class);
class_remove_file(&cm_class, &class_attr_abi_version);
unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES);
idr_destroy(&ctx_id_table);
}
......
......@@ -31,6 +31,7 @@
*/
#include <linux/completion.h>
#include <linux/file.h>
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/idr.h>
......@@ -991,6 +992,96 @@ static ssize_t ucma_leave_multicast(struct ucma_file *file,
return ret;
}
static void ucma_lock_files(struct ucma_file *file1, struct ucma_file *file2)
{
/* Acquire mutex's based on pointer comparison to prevent deadlock. */
if (file1 < file2) {
mutex_lock(&file1->mut);
mutex_lock(&file2->mut);
} else {
mutex_lock(&file2->mut);
mutex_lock(&file1->mut);
}
}
static void ucma_unlock_files(struct ucma_file *file1, struct ucma_file *file2)
{
if (file1 < file2) {
mutex_unlock(&file2->mut);
mutex_unlock(&file1->mut);
} else {
mutex_unlock(&file1->mut);
mutex_unlock(&file2->mut);
}
}
static void ucma_move_events(struct ucma_context *ctx, struct ucma_file *file)
{
struct ucma_event *uevent, *tmp;
list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list)
if (uevent->ctx == ctx)
list_move_tail(&uevent->list, &file->event_list);
}
static ssize_t ucma_migrate_id(struct ucma_file *new_file,
const char __user *inbuf,
int in_len, int out_len)
{
struct rdma_ucm_migrate_id cmd;
struct rdma_ucm_migrate_resp resp;
struct ucma_context *ctx;
struct file *filp;
struct ucma_file *cur_file;
int ret = 0;
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT;
/* Get current fd to protect against it being closed */
filp = fget(cmd.fd);
if (!filp)
return -ENOENT;
/* Validate current fd and prevent destruction of id. */
ctx = ucma_get_ctx(filp->private_data, cmd.id);
if (IS_ERR(ctx)) {
ret = PTR_ERR(ctx);
goto file_put;
}
cur_file = ctx->file;
if (cur_file == new_file) {
resp.events_reported = ctx->events_reported;
goto response;
}
/*
* Migrate events between fd's, maintaining order, and avoiding new
* events being added before existing events.
*/
ucma_lock_files(cur_file, new_file);
mutex_lock(&mut);
list_move_tail(&ctx->list, &new_file->ctx_list);
ucma_move_events(ctx, new_file);
ctx->file = new_file;
resp.events_reported = ctx->events_reported;
mutex_unlock(&mut);
ucma_unlock_files(cur_file, new_file);
response:
if (copy_to_user((void __user *)(unsigned long)cmd.response,
&resp, sizeof(resp)))
ret = -EFAULT;
ucma_put_ctx(ctx);
file_put:
fput(filp);
return ret;
}
static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
const char __user *inbuf,
int in_len, int out_len) = {
......@@ -1012,6 +1103,7 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
[RDMA_USER_CM_CMD_NOTIFY] = ucma_notify,
[RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast,
[RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast,
[RDMA_USER_CM_CMD_MIGRATE_ID] = ucma_migrate_id
};
static ssize_t ucma_write(struct file *filp, const char __user *buf,
......
......@@ -2,6 +2,7 @@
* Copyright (c) 2004 Topspin Communications. All rights reserved.
* Copyright (c) 2005 Voltaire, Inc. All rights reserved.
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) 2008 Cisco. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
......@@ -42,7 +43,7 @@
#include <linux/cdev.h>
#include <linux/dma-mapping.h>
#include <linux/poll.h>
#include <linux/rwsem.h>
#include <linux/mutex.h>
#include <linux/kref.h>
#include <linux/compat.h>
......@@ -94,7 +95,7 @@ struct ib_umad_port {
struct class_device *sm_class_dev;
struct semaphore sm_sem;
struct rw_semaphore mutex;
struct mutex file_mutex;
struct list_head file_list;
struct ib_device *ib_dev;
......@@ -110,11 +111,11 @@ struct ib_umad_device {
};
struct ib_umad_file {
struct mutex mutex;
struct ib_umad_port *port;
struct list_head recv_list;
struct list_head send_list;
struct list_head port_list;
spinlock_t recv_lock;
spinlock_t send_lock;
wait_queue_head_t recv_wait;
struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS];
......@@ -156,7 +157,7 @@ static int hdr_size(struct ib_umad_file *file)
sizeof (struct ib_user_mad_hdr_old);
}
/* caller must hold port->mutex at least for reading */
/* caller must hold file->mutex */
static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id)
{
return file->agents_dead ? NULL : file->agent[id];
......@@ -168,32 +169,30 @@ static int queue_packet(struct ib_umad_file *file,
{
int ret = 1;
down_read(&file->port->mutex);
mutex_lock(&file->mutex);
for (packet->mad.hdr.id = 0;
packet->mad.hdr.id < IB_UMAD_MAX_AGENTS;
packet->mad.hdr.id++)
if (agent == __get_agent(file, packet->mad.hdr.id)) {
spin_lock_irq(&file->recv_lock);
list_add_tail(&packet->list, &file->recv_list);
spin_unlock_irq(&file->recv_lock);
wake_up_interruptible(&file->recv_wait);
ret = 0;
break;
}
up_read(&file->port->mutex);
mutex_unlock(&file->mutex);
return ret;
}
static void dequeue_send(struct ib_umad_file *file,
struct ib_umad_packet *packet)
{
{
spin_lock_irq(&file->send_lock);
list_del(&packet->list);
spin_unlock_irq(&file->send_lock);
}
}
static void send_handler(struct ib_mad_agent *agent,
struct ib_mad_send_wc *send_wc)
......@@ -341,10 +340,10 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
if (count < hdr_size(file))
return -EINVAL;
spin_lock_irq(&file->recv_lock);
mutex_lock(&file->mutex);
while (list_empty(&file->recv_list)) {
spin_unlock_irq(&file->recv_lock);
mutex_unlock(&file->mutex);
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
......@@ -353,13 +352,13 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
!list_empty(&file->recv_list)))
return -ERESTARTSYS;
spin_lock_irq(&file->recv_lock);
mutex_lock(&file->mutex);
}
packet = list_entry(file->recv_list.next, struct ib_umad_packet, list);
list_del(&packet->list);
spin_unlock_irq(&file->recv_lock);
mutex_unlock(&file->mutex);
if (packet->recv_wc)
ret = copy_recv_mad(file, buf, packet, count);
......@@ -368,9 +367,9 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
if (ret < 0) {
/* Requeue packet */
spin_lock_irq(&file->recv_lock);
mutex_lock(&file->mutex);
list_add(&packet->list, &file->recv_list);
spin_unlock_irq(&file->recv_lock);
mutex_unlock(&file->mutex);
} else {
if (packet->recv_wc)
ib_free_recv_mad(packet->recv_wc);
......@@ -481,7 +480,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
goto err;
}
down_read(&file->port->mutex);
mutex_lock(&file->mutex);
agent = __get_agent(file, packet->mad.hdr.id);
if (!agent) {
......@@ -577,7 +576,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
if (ret)
goto err_send;
up_read(&file->port->mutex);
mutex_unlock(&file->mutex);
return count;
err_send:
......@@ -587,7 +586,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
err_ah:
ib_destroy_ah(ah);
err_up:
up_read(&file->port->mutex);
mutex_unlock(&file->mutex);
err:
kfree(packet);
return ret;
......@@ -613,11 +612,12 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
{
struct ib_user_mad_reg_req ureq;
struct ib_mad_reg_req req;
struct ib_mad_agent *agent;
struct ib_mad_agent *agent = NULL;
int agent_id;
int ret;
down_write(&file->port->mutex);
mutex_lock(&file->port->file_mutex);
mutex_lock(&file->mutex);
if (!file->port->ib_dev) {
ret = -EPIPE;
......@@ -666,13 +666,13 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
send_handler, recv_handler, file);
if (IS_ERR(agent)) {
ret = PTR_ERR(agent);
agent = NULL;
goto out;
}
if (put_user(agent_id,
(u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) {
ret = -EFAULT;
ib_unregister_mad_agent(agent);
goto out;
}
......@@ -690,7 +690,13 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
ret = 0;
out:
up_write(&file->port->mutex);
mutex_unlock(&file->mutex);
if (ret && agent)
ib_unregister_mad_agent(agent);
mutex_unlock(&file->port->file_mutex);
return ret;
}
......@@ -703,7 +709,8 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
if (get_user(id, arg))
return -EFAULT;
down_write(&file->port->mutex);
mutex_lock(&file->port->file_mutex);
mutex_lock(&file->mutex);
if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) {
ret = -EINVAL;
......@@ -714,11 +721,13 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
file->agent[id] = NULL;
out:
up_write(&file->port->mutex);
mutex_unlock(&file->mutex);
if (agent)
ib_unregister_mad_agent(agent);
mutex_unlock(&file->port->file_mutex);
return ret;
}
......@@ -726,12 +735,12 @@ static long ib_umad_enable_pkey(struct ib_umad_file *file)
{
int ret = 0;
down_write(&file->port->mutex);
mutex_lock(&file->mutex);
if (file->already_used)
ret = -EINVAL;
else
file->use_pkey_index = 1;
up_write(&file->port->mutex);
mutex_unlock(&file->mutex);
return ret;
}
......@@ -783,7 +792,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
if (!port)
return -ENXIO;
down_write(&port->mutex);
mutex_lock(&port->file_mutex);
if (!port->ib_dev) {
ret = -ENXIO;
......@@ -797,7 +806,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
goto out;
}
spin_lock_init(&file->recv_lock);
mutex_init(&file->mutex);
spin_lock_init(&file->send_lock);
INIT_LIST_HEAD(&file->recv_list);
INIT_LIST_HEAD(&file->send_list);
......@@ -809,7 +818,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
list_add_tail(&file->port_list, &port->file_list);
out:
up_write(&port->mutex);
mutex_unlock(&port->file_mutex);
return ret;
}
......@@ -821,7 +830,8 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
int already_dead;
int i;
down_write(&file->port->mutex);
mutex_lock(&file->port->file_mutex);
mutex_lock(&file->mutex);
already_dead = file->agents_dead;
file->agents_dead = 1;
......@@ -834,14 +844,14 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
list_del(&file->port_list);
downgrade_write(&file->port->mutex);
mutex_unlock(&file->mutex);
if (!already_dead)
for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i)
if (file->agent[i])
ib_unregister_mad_agent(file->agent[i]);
up_read(&file->port->mutex);
mutex_unlock(&file->port->file_mutex);
kfree(file);
kref_put(&dev->ref, ib_umad_release_dev);
......@@ -914,10 +924,10 @@ static int ib_umad_sm_close(struct inode *inode, struct file *filp)
};
int ret = 0;
down_write(&port->mutex);
mutex_lock(&port->file_mutex);
if (port->ib_dev)
ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props);
up_write(&port->mutex);
mutex_unlock(&port->file_mutex);
up(&port->sm_sem);
......@@ -981,7 +991,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
port->ib_dev = device;
port->port_num = port_num;
init_MUTEX(&port->sm_sem);
init_rwsem(&port->mutex);
mutex_init(&port->file_mutex);
INIT_LIST_HEAD(&port->file_list);
port->dev = cdev_alloc();
......@@ -1052,6 +1062,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
static void ib_umad_kill_port(struct ib_umad_port *port)
{
struct ib_umad_file *file;
int already_dead;
int id;
class_set_devdata(port->class_dev, NULL);
......@@ -1067,42 +1078,22 @@ static void ib_umad_kill_port(struct ib_umad_port *port)
umad_port[port->dev_num] = NULL;
spin_unlock(&port_lock);
down_write(&port->mutex);
mutex_lock(&port->file_mutex);
port->ib_dev = NULL;
/*
* Now go through the list of files attached to this port and
* unregister all of their MAD agents. We need to hold
* port->mutex while doing this to avoid racing with
* ib_umad_close(), but we can't hold the mutex for writing
* while calling ib_unregister_mad_agent(), since that might
* deadlock by calling back into queue_packet(). So we
* downgrade our lock to a read lock, and then drop and
* reacquire the write lock for the next iteration.
*
* We do list_del_init() on the file's list_head so that the
* list_del in ib_umad_close() is still OK, even after the
* file is removed from the list.
*/
while (!list_empty(&port->file_list)) {
file = list_entry(port->file_list.next, struct ib_umad_file,
port_list);
list_for_each_entry(file, &port->file_list, port_list) {
mutex_lock(&file->mutex);
already_dead = file->agents_dead;
file->agents_dead = 1;
list_del_init(&file->port_list);
downgrade_write(&port->mutex);
mutex_unlock(&file->mutex);
for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id)
if (file->agent[id])
ib_unregister_mad_agent(file->agent[id]);
up_read(&port->mutex);
down_write(&port->mutex);
}
up_write(&port->mutex);
mutex_unlock(&port->file_mutex);
clear_bit(port->dev_num, dev_map);
}
......
......@@ -179,7 +179,7 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq)
setup.size = 1UL << cq->size_log2;
setup.credits = 65535;
setup.credit_thres = 1;
if (rdev_p->t3cdev_p->type == T3B)
if (rdev_p->t3cdev_p->type != T3A)
setup.ovfl_mode = 0;
else
setup.ovfl_mode = 1;
......@@ -584,7 +584,7 @@ static int cxio_hal_ctrl_qp_write_mem(struct cxio_rdev *rdev_p, u32 addr,
{
u32 i, nr_wqe, copy_len;
u8 *copy_data;
u8 wr_len, utx_len; /* lenght in 8 byte flit */
u8 wr_len, utx_len; /* length in 8 byte flit */
enum t3_wr_flags flag;
__be64 *wqe;
u64 utx_cmd;
......
......@@ -315,7 +315,7 @@ struct t3_rdma_init_wr {
__be32 ird;
__be64 qp_dma_addr; /* 7 */
__be32 qp_dma_size; /* 8 */
u32 irs;
__be32 irs;
};
struct t3_genbit {
......@@ -324,7 +324,8 @@ struct t3_genbit {
};
enum rdma_init_wr_flags {
RECVS_POSTED = 1,
RECVS_POSTED = (1<<0),
PRIV_QP = (1<<1),
};
union t3_wr {
......
......@@ -1118,7 +1118,7 @@ static int act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
status2errno(rpl->status));
connect_reply_upcall(ep, status2errno(rpl->status));
state_set(&ep->com, DEAD);
if (ep->com.tdev->type == T3B && act_open_has_tid(rpl->status))
if (ep->com.tdev->type != T3A && act_open_has_tid(rpl->status))
release_tid(ep->com.tdev, GET_TID(rpl), NULL);
cxgb3_free_atid(ep->com.tdev, ep->atid);
dst_release(ep->dst);
......@@ -1249,7 +1249,7 @@ static void reject_cr(struct t3cdev *tdev, u32 hwtid, __be32 peer_ip,
skb_trim(skb, sizeof(struct cpl_tid_release));
skb_get(skb);
if (tdev->type == T3B)
if (tdev->type != T3A)
release_tid(tdev, hwtid, skb);
else {
struct cpl_pass_accept_rpl *rpl;
......
......@@ -122,6 +122,13 @@ int build_phys_page_list(struct ib_phys_buf *buffer_list,
*total_size += buffer_list[i].size;
if (i > 0)
mask |= buffer_list[i].addr;
else
mask |= buffer_list[i].addr & PAGE_MASK;
if (i != num_phys_buf - 1)
mask |= buffer_list[i].addr + buffer_list[i].size;
else
mask |= (buffer_list[i].addr + buffer_list[i].size +
PAGE_SIZE - 1) & PAGE_MASK;
}
if (*total_size > 0xFFFFFFFFULL)
......
......@@ -39,6 +39,7 @@
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/rtnetlink.h>
#include <asm/io.h>
#include <asm/irq.h>
......@@ -645,7 +646,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
if (err)
goto err;
if (udata && t3b_device(rhp)) {
if (udata && !t3a_device(rhp)) {
uresp.pbl_addr = (mhp->attr.pbl_addr -
rhp->rdev.rnic_info.pbl_base) >> 3;
PDBG("%s user resp pbl_addr 0x%x\n", __FUNCTION__,
......@@ -1053,7 +1054,9 @@ static ssize_t show_fw_ver(struct class_device *cdev, char *buf)
struct net_device *lldev = dev->rdev.t3cdev_p->lldev;
PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev);
rtnl_lock();
lldev->ethtool_ops->get_drvinfo(lldev, &info);
rtnl_unlock();
return sprintf(buf, "%s\n", info.fw_version);
}
......@@ -1065,7 +1068,9 @@ static ssize_t show_hca(struct class_device *cdev, char *buf)
struct net_device *lldev = dev->rdev.t3cdev_p->lldev;
PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev);
rtnl_lock();
lldev->ethtool_ops->get_drvinfo(lldev, &info);
rtnl_unlock();
return sprintf(buf, "%s\n", info.driver);
}
......
......@@ -208,36 +208,19 @@ static int iwch_sgl2pbl_map(struct iwch_dev *rhp, struct ib_sge *sg_list,
static int iwch_build_rdma_recv(struct iwch_dev *rhp, union t3_wr *wqe,
struct ib_recv_wr *wr)
{
int i, err = 0;
u32 pbl_addr[4];
u8 page_size[4];
int i;
if (wr->num_sge > T3_MAX_SGE)
return -EINVAL;
err = iwch_sgl2pbl_map(rhp, wr->sg_list, wr->num_sge, pbl_addr,
page_size);
if (err)
return err;
wqe->recv.pagesz[0] = page_size[0];
wqe->recv.pagesz[1] = page_size[1];
wqe->recv.pagesz[2] = page_size[2];
wqe->recv.pagesz[3] = page_size[3];
wqe->recv.num_sgle = cpu_to_be32(wr->num_sge);
for (i = 0; i < wr->num_sge; i++) {
wqe->recv.sgl[i].stag = cpu_to_be32(wr->sg_list[i].lkey);
wqe->recv.sgl[i].len = cpu_to_be32(wr->sg_list[i].length);
/* to in the WQE == the offset into the page */
wqe->recv.sgl[i].to = cpu_to_be64(((u32) wr->sg_list[i].addr) %
(1UL << (12 + page_size[i])));
/* pbl_addr is the adapters address in the PBL */
wqe->recv.pbl_addr[i] = cpu_to_be32(pbl_addr[i]);
wqe->recv.sgl[i].to = cpu_to_be64(wr->sg_list[i].addr);
}
for (; i < T3_MAX_SGE; i++) {
wqe->recv.sgl[i].stag = 0;
wqe->recv.sgl[i].len = 0;
wqe->recv.sgl[i].to = 0;
wqe->recv.pbl_addr[i] = 0;
}
return 0;
}
......@@ -659,6 +642,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
cxio_flush_rq(&qhp->wq, &rchp->cq, count);
spin_unlock(&qhp->lock);
spin_unlock_irqrestore(&rchp->lock, *flag);
(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
/* locking heirarchy: cq lock first, then qp lock. */
spin_lock_irqsave(&schp->lock, *flag);
......@@ -668,6 +652,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
cxio_flush_sq(&qhp->wq, &schp->cq, count);
spin_unlock(&qhp->lock);
spin_unlock_irqrestore(&schp->lock, *flag);
(*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
/* deref */
if (atomic_dec_and_test(&qhp->refcnt))
......@@ -678,7 +663,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
static void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
{
if (t3b_device(qhp->rhp))
if (qhp->ibqp.uobject)
cxio_set_wq_in_error(&qhp->wq);
else
__flush_qp(qhp, flag);
......@@ -732,6 +717,7 @@ static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp,
init_attr.qp_dma_addr = qhp->wq.dma_addr;
init_attr.qp_dma_size = (1UL << qhp->wq.size_log2);
init_attr.flags = rqes_posted(qhp) ? RECVS_POSTED : 0;
init_attr.flags |= capable(CAP_NET_BIND_SERVICE) ? PRIV_QP : 0;
init_attr.irs = qhp->ep->rcv_seq;
PDBG("%s init_attr.rq_addr 0x%x init_attr.rq_size = %d "
"flags 0x%x qpcaps 0x%x\n", __FUNCTION__,
......@@ -847,10 +833,11 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp,
disconnect = 1;
ep = qhp->ep;
}
flush_qp(qhp, &flag);
break;
case IWCH_QP_STATE_TERMINATE:
qhp->attr.state = IWCH_QP_STATE_TERMINATE;
if (t3b_device(qhp->rhp))
if (qhp->ibqp.uobject)
cxio_set_wq_in_error(&qhp->wq);
if (!internal)
terminate = 1;
......
/*
* IBM eServer eHCA Infiniband device driver for Linux on POWER
*
* adress vector functions
* address vector functions
*
* Authors: Hoang-Nam Nguyen <hnguyen@de.ibm.com>
* Khadija Souissi <souissik@de.ibm.com>
......
......@@ -94,7 +94,11 @@ struct ehca_sma_attr {
struct ehca_sport {
struct ib_cq *ibcq_aqp1;
struct ib_qp *ibqp_aqp1;
struct ib_qp *ibqp_sqp[2];
/* lock to serialze modify_qp() calls for sqp in normal
* and irq path (when event PORT_ACTIVE is received first time)
*/
spinlock_t mod_sqp_lock;
enum ib_port_state port_state;
struct ehca_sma_attr saved_attr;
};
......@@ -141,6 +145,14 @@ enum ehca_ext_qp_type {
EQPT_SRQ = 3,
};
/* struct to cache modify_qp()'s parms for GSI/SMI qp */
struct ehca_mod_qp_parm {
int mask;
struct ib_qp_attr attr;
};
#define EHCA_MOD_QP_PARM_MAX 4
struct ehca_qp {
union {
struct ib_qp ib_qp;
......@@ -164,10 +176,18 @@ struct ehca_qp {
struct ehca_cq *recv_cq;
unsigned int sqerr_purgeflag;
struct hlist_node list_entries;
/* array to cache modify_qp()'s parms for GSI/SMI qp */
struct ehca_mod_qp_parm *mod_qp_parm;
int mod_qp_parm_idx;
/* mmap counter for resources mapped into user space */
u32 mm_count_squeue;
u32 mm_count_rqueue;
u32 mm_count_galpa;
/* unsolicited ack circumvention */
int unsol_ack_circ;
int mtu_shift;
u32 message_count;
u32 packet_count;
};
#define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ)
......@@ -323,6 +343,7 @@ extern int ehca_port_act_time;
extern int ehca_use_hp_mr;
extern int ehca_scaling_code;
extern int ehca_lock_hcalls;
extern int ehca_nr_ports;
struct ipzu_queue_resp {
u32 qe_size; /* queue entry size */
......
......@@ -246,7 +246,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
} else {
if (h_ret != H_PAGE_REGISTERED) {
ehca_err(device, "Registration of page failed "
"ehca_cq=%p cq_num=%x h_ret=%li"
"ehca_cq=%p cq_num=%x h_ret=%li "
"counter=%i act_pages=%i",
my_cq, my_cq->cq_number,
h_ret, counter, param.act_pages);
......
......@@ -62,6 +62,7 @@
#define NEQE_PORT_NUMBER EHCA_BMASK_IBM( 8, 15)
#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16, 16)
#define NEQE_DISRUPTIVE EHCA_BMASK_IBM(16, 16)
#define NEQE_SPECIFIC_EVENT EHCA_BMASK_IBM(16, 23)
#define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52, 63)
#define ERROR_DATA_TYPE EHCA_BMASK_IBM( 0, 7)
......@@ -354,17 +355,34 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
{
u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe);
u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe);
u8 spec_event;
struct ehca_sport *sport = &shca->sport[port - 1];
unsigned long flags;
switch (ec) {
case 0x30: /* port availability change */
if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) {
shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
int suppress_event;
/* replay modify_qp for sqps */
spin_lock_irqsave(&sport->mod_sqp_lock, flags);
suppress_event = !sport->ibqp_sqp[IB_QPT_GSI];
if (sport->ibqp_sqp[IB_QPT_SMI])
ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_SMI]);
if (!suppress_event)
ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_GSI]);
spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
/* AQP1 was destroyed, ignore this event */
if (suppress_event)
break;
sport->port_state = IB_PORT_ACTIVE;
dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
"is active");
ehca_query_sma_attr(shca, port,
&shca->sport[port - 1].saved_attr);
&sport->saved_attr);
} else {
shca->sport[port - 1].port_state = IB_PORT_DOWN;
sport->port_state = IB_PORT_DOWN;
dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
"is inactive");
}
......@@ -378,11 +396,11 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
ehca_warn(&shca->ib_device, "disruptive port "
"%d configuration change", port);
shca->sport[port - 1].port_state = IB_PORT_DOWN;
sport->port_state = IB_PORT_DOWN;
dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
"is inactive");
shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
sport->port_state = IB_PORT_ACTIVE;
dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
"is active");
} else
......@@ -394,6 +412,16 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
case 0x33: /* trace stopped */
ehca_err(&shca->ib_device, "Traced stopped.");
break;
case 0x34: /* util async event */
spec_event = EHCA_BMASK_GET(NEQE_SPECIFIC_EVENT, eqe);
if (spec_event == 0x80) /* client reregister required */
dispatch_port_event(shca, port,
IB_EVENT_CLIENT_REREGISTER,
"client reregister req.");
else
ehca_warn(&shca->ib_device, "Unknown util async "
"event %x on port %x", spec_event, port);
break;
default:
ehca_err(&shca->ib_device, "Unknown event code: %x on %s.",
ec, shca->ib_device.name);
......
......@@ -200,4 +200,6 @@ void ehca_free_fw_ctrlblock(void *ptr);
#define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr))
#endif
void ehca_recover_sqp(struct ib_qp *sqp);
#endif
......@@ -90,7 +90,8 @@ MODULE_PARM_DESC(hw_level,
"hardware level"
" (0: autosensing (default), 1: v. 0.20, 2: v. 0.21)");
MODULE_PARM_DESC(nr_ports,
"number of connected ports (default: 2)");
"number of connected ports (-1: autodetect, 1: port one only, "
"2: two ports (default)");
MODULE_PARM_DESC(use_hp_mr,
"high performance MRs (0: no (default), 1: yes)");
MODULE_PARM_DESC(port_act_time,
......@@ -511,7 +512,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
}
sport->ibcq_aqp1 = ibcq;
if (sport->ibqp_aqp1) {
if (sport->ibqp_sqp[IB_QPT_GSI]) {
ehca_err(&shca->ib_device, "AQP1 QP is already created.");
ret = -EPERM;
goto create_aqp1;
......@@ -537,7 +538,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
ret = PTR_ERR(ibqp);
goto create_aqp1;
}
sport->ibqp_aqp1 = ibqp;
sport->ibqp_sqp[IB_QPT_GSI] = ibqp;
return 0;
......@@ -550,7 +551,7 @@ static int ehca_destroy_aqp1(struct ehca_sport *sport)
{
int ret;
ret = ib_destroy_qp(sport->ibqp_aqp1);
ret = ib_destroy_qp(sport->ibqp_sqp[IB_QPT_GSI]);
if (ret) {
ehca_gen_err("Cannot destroy AQP1 QP. ret=%i", ret);
return ret;
......@@ -693,7 +694,7 @@ static int __devinit ehca_probe(struct of_device *dev,
struct ehca_shca *shca;
const u64 *handle;
struct ib_pd *ibpd;
int ret;
int ret, i;
handle = of_get_property(dev->node, "ibm,hca-handle", NULL);
if (!handle) {
......@@ -714,6 +715,8 @@ static int __devinit ehca_probe(struct of_device *dev,
return -ENOMEM;
}
mutex_init(&shca->modify_mutex);
for (i = 0; i < ARRAY_SIZE(shca->sport); i++)
spin_lock_init(&shca->sport[i].mod_sqp_lock);
shca->ofdev = dev;
shca->ipz_hca_handle.handle = *handle;
......@@ -934,7 +937,7 @@ void ehca_poll_eqs(unsigned long data)
ehca_process_eq(shca, 0);
}
}
mod_timer(&poll_eqs_timer, jiffies + HZ);
mod_timer(&poll_eqs_timer, round_jiffies(jiffies + HZ));
spin_unlock(&shca_list_lock);
}
......
......@@ -592,10 +592,8 @@ static struct ehca_qp *internal_create_qp(
goto create_qp_exit1;
}
if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
parms.sigtype = HCALL_SIGT_EVERY;
else
parms.sigtype = HCALL_SIGT_BY_WQE;
/* Always signal by WQE so we can hide circ. WQEs */
parms.sigtype = HCALL_SIGT_BY_WQE;
/* UD_AV CIRCUMVENTION */
max_send_sge = init_attr->cap.max_send_sge;
......@@ -618,6 +616,10 @@ static struct ehca_qp *internal_create_qp(
parms.squeue.max_sge = max_send_sge;
parms.rqueue.max_sge = max_recv_sge;
/* RC QPs need one more SWQE for unsolicited ack circumvention */
if (qp_type == IB_QPT_RC)
parms.squeue.max_wr++;
if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)) {
if (HAS_SQ(my_qp))
ehca_determine_small_queue(
......@@ -650,6 +652,8 @@ static struct ehca_qp *internal_create_qp(
parms.squeue.act_nr_sges = 1;
parms.rqueue.act_nr_sges = 1;
}
/* hide the extra WQE */
parms.squeue.act_nr_wqes--;
break;
case IB_QPT_UD:
case IB_QPT_GSI:
......@@ -729,12 +733,31 @@ static struct ehca_qp *internal_create_qp(
init_attr->cap.max_send_wr = parms.squeue.act_nr_wqes;
my_qp->init_attr = *init_attr;
if (qp_type == IB_QPT_SMI || qp_type == IB_QPT_GSI) {
shca->sport[init_attr->port_num - 1].ibqp_sqp[qp_type] =
&my_qp->ib_qp;
if (ehca_nr_ports < 0) {
/* alloc array to cache subsequent modify qp parms
* for autodetect mode
*/
my_qp->mod_qp_parm =
kzalloc(EHCA_MOD_QP_PARM_MAX *
sizeof(*my_qp->mod_qp_parm),
GFP_KERNEL);
if (!my_qp->mod_qp_parm) {
ehca_err(pd->device,
"Could not alloc mod_qp_parm");
goto create_qp_exit4;
}
}
}
/* NOTE: define_apq0() not supported yet */
if (qp_type == IB_QPT_GSI) {
h_ret = ehca_define_sqp(shca, my_qp, init_attr);
if (h_ret != H_SUCCESS) {
ret = ehca2ib_return_code(h_ret);
goto create_qp_exit4;
goto create_qp_exit5;
}
}
......@@ -743,7 +766,7 @@ static struct ehca_qp *internal_create_qp(
if (ret) {
ehca_err(pd->device,
"Couldn't assign qp to send_cq ret=%i", ret);
goto create_qp_exit4;
goto create_qp_exit5;
}
}
......@@ -769,12 +792,18 @@ static struct ehca_qp *internal_create_qp(
if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
ehca_err(pd->device, "Copy to udata failed");
ret = -EINVAL;
goto create_qp_exit4;
goto create_qp_exit6;
}
}
return my_qp;
create_qp_exit6:
ehca_cq_unassign_qp(my_qp->send_cq, my_qp->real_qp_num);
create_qp_exit5:
kfree(my_qp->mod_qp_parm);
create_qp_exit4:
if (HAS_RQ(my_qp))
ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
......@@ -858,7 +887,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
update_mask,
mqpcb, my_qp->galpas.kernel);
if (hret != H_SUCCESS) {
ehca_err(pd->device, "Could not modify SRQ to INIT"
ehca_err(pd->device, "Could not modify SRQ to INIT "
"ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, my_qp->real_qp_num, hret);
goto create_srq2;
......@@ -872,7 +901,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
update_mask,
mqpcb, my_qp->galpas.kernel);
if (hret != H_SUCCESS) {
ehca_err(pd->device, "Could not enable SRQ"
ehca_err(pd->device, "Could not enable SRQ "
"ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, my_qp->real_qp_num, hret);
goto create_srq2;
......@@ -886,7 +915,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
update_mask,
mqpcb, my_qp->galpas.kernel);
if (hret != H_SUCCESS) {
ehca_err(pd->device, "Could not modify SRQ to RTR"
ehca_err(pd->device, "Could not modify SRQ to RTR "
"ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, my_qp->real_qp_num, hret);
goto create_srq2;
......@@ -992,7 +1021,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
unsigned long flags = 0;
/* do query_qp to obtain current attr values */
mqpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
mqpcb = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
if (!mqpcb) {
ehca_err(ibqp->device, "Could not get zeroed page for mqpcb "
"ehca_qp=%p qp_num=%x ", my_qp, ibqp->qp_num);
......@@ -1180,6 +1209,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1);
}
if (attr_mask & IB_QP_PORT) {
struct ehca_sport *sport;
struct ehca_qp *aqp1;
if (attr->port_num < 1 || attr->port_num > shca->num_ports) {
ret = -EINVAL;
ehca_err(ibqp->device, "Invalid port=%x. "
......@@ -1188,6 +1219,29 @@ static int internal_modify_qp(struct ib_qp *ibqp,
shca->num_ports);
goto modify_qp_exit2;
}
sport = &shca->sport[attr->port_num - 1];
if (!sport->ibqp_sqp[IB_QPT_GSI]) {
/* should not occur */
ret = -EFAULT;
ehca_err(ibqp->device, "AQP1 was not created for "
"port=%x", attr->port_num);
goto modify_qp_exit2;
}
aqp1 = container_of(sport->ibqp_sqp[IB_QPT_GSI],
struct ehca_qp, ib_qp);
if (ibqp->qp_type != IB_QPT_GSI &&
ibqp->qp_type != IB_QPT_SMI &&
aqp1->mod_qp_parm) {
/*
* firmware will reject this modify_qp() because
* port is not activated/initialized fully
*/
ret = -EFAULT;
ehca_warn(ibqp->device, "Couldn't modify qp port=%x: "
"either port is being activated (try again) "
"or cabling issue", attr->port_num);
goto modify_qp_exit2;
}
mqpcb->prim_phys_port = attr->port_num;
update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_PHYS_PORT, 1);
}
......@@ -1244,6 +1298,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
}
if (attr_mask & IB_QP_PATH_MTU) {
/* store ld(MTU) */
my_qp->mtu_shift = attr->path_mtu + 7;
mqpcb->path_mtu = attr->path_mtu;
update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PATH_MTU, 1);
}
......@@ -1467,6 +1523,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
struct ib_udata *udata)
{
struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca,
ib_device);
struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
ib_pd);
......@@ -1479,9 +1537,100 @@ int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
return -EINVAL;
}
/* The if-block below caches qp_attr to be modified for GSI and SMI
* qps during the initialization by ib_mad. When the respective port
* is activated, ie we got an event PORT_ACTIVE, we'll replay the
* cached modify calls sequence, see ehca_recover_sqs() below.
* Why that is required:
* 1) If one port is connected, older code requires that port one
* to be connected and module option nr_ports=1 to be given by
* user, which is very inconvenient for end user.
* 2) Firmware accepts modify_qp() only if respective port has become
* active. Older code had a wait loop of 30sec create_qp()/
* define_aqp1(), which is not appropriate in practice. This
* code now removes that wait loop, see define_aqp1(), and always
* reports all ports to ib_mad resp. users. Only activated ports
* will then usable for the users.
*/
if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI) {
int port = my_qp->init_attr.port_num;
struct ehca_sport *sport = &shca->sport[port - 1];
unsigned long flags;
spin_lock_irqsave(&sport->mod_sqp_lock, flags);
/* cache qp_attr only during init */
if (my_qp->mod_qp_parm) {
struct ehca_mod_qp_parm *p;
if (my_qp->mod_qp_parm_idx >= EHCA_MOD_QP_PARM_MAX) {
ehca_err(&shca->ib_device,
"mod_qp_parm overflow state=%x port=%x"
" type=%x", attr->qp_state,
my_qp->init_attr.port_num,
ibqp->qp_type);
spin_unlock_irqrestore(&sport->mod_sqp_lock,
flags);
return -EINVAL;
}
p = &my_qp->mod_qp_parm[my_qp->mod_qp_parm_idx];
p->mask = attr_mask;
p->attr = *attr;
my_qp->mod_qp_parm_idx++;
ehca_dbg(&shca->ib_device,
"Saved qp_attr for state=%x port=%x type=%x",
attr->qp_state, my_qp->init_attr.port_num,
ibqp->qp_type);
spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
return 0;
}
spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
}
return internal_modify_qp(ibqp, attr, attr_mask, 0);
}
void ehca_recover_sqp(struct ib_qp *sqp)
{
struct ehca_qp *my_sqp = container_of(sqp, struct ehca_qp, ib_qp);
int port = my_sqp->init_attr.port_num;
struct ib_qp_attr attr;
struct ehca_mod_qp_parm *qp_parm;
int i, qp_parm_idx, ret;
unsigned long flags, wr_cnt;
if (!my_sqp->mod_qp_parm)
return;
ehca_dbg(sqp->device, "SQP port=%x qp_num=%x", port, sqp->qp_num);
qp_parm = my_sqp->mod_qp_parm;
qp_parm_idx = my_sqp->mod_qp_parm_idx;
for (i = 0; i < qp_parm_idx; i++) {
attr = qp_parm[i].attr;
ret = internal_modify_qp(sqp, &attr, qp_parm[i].mask, 0);
if (ret) {
ehca_err(sqp->device, "Could not modify SQP port=%x "
"qp_num=%x ret=%x", port, sqp->qp_num, ret);
goto free_qp_parm;
}
ehca_dbg(sqp->device, "SQP port=%x qp_num=%x in state=%x",
port, sqp->qp_num, attr.qp_state);
}
/* re-trigger posted recv wrs */
wr_cnt = my_sqp->ipz_rqueue.current_q_offset /
my_sqp->ipz_rqueue.qe_size;
if (wr_cnt) {
spin_lock_irqsave(&my_sqp->spinlock_r, flags);
hipz_update_rqa(my_sqp, wr_cnt);
spin_unlock_irqrestore(&my_sqp->spinlock_r, flags);
ehca_dbg(sqp->device, "doorbell port=%x qp_num=%x wr_cnt=%lx",
port, sqp->qp_num, wr_cnt);
}
free_qp_parm:
kfree(qp_parm);
/* this prevents subsequent calls to modify_qp() to cache qp_attr */
my_sqp->mod_qp_parm = NULL;
}
int ehca_query_qp(struct ib_qp *qp,
struct ib_qp_attr *qp_attr,
int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
......@@ -1769,6 +1918,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
struct ehca_shca *shca = container_of(dev, struct ehca_shca, ib_device);
struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
ib_pd);
struct ehca_sport *sport = &shca->sport[my_qp->init_attr.port_num - 1];
u32 cur_pid = current->tgid;
u32 qp_num = my_qp->real_qp_num;
int ret;
......@@ -1815,6 +1965,14 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
port_num = my_qp->init_attr.port_num;
qp_type = my_qp->init_attr.qp_type;
if (qp_type == IB_QPT_SMI || qp_type == IB_QPT_GSI) {
spin_lock_irqsave(&sport->mod_sqp_lock, flags);
kfree(my_qp->mod_qp_parm);
my_qp->mod_qp_parm = NULL;
shca->sport[port_num - 1].ibqp_sqp[qp_type] = NULL;
spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
}
/* no support for IB_QPT_SMI yet */
if (qp_type == IB_QPT_GSI) {
struct ib_event event;
......
......@@ -50,6 +50,9 @@
#include "hcp_if.h"
#include "hipz_fns.h"
/* in RC traffic, insert an empty RDMA READ every this many packets */
#define ACK_CIRC_THRESHOLD 2000000
static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
struct ehca_wqe *wqe_p,
struct ib_recv_wr *recv_wr)
......@@ -81,7 +84,7 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
if (ehca_debug_level) {
ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p",
ipz_rqueue);
ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
ehca_dmp(wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
}
return 0;
......@@ -135,7 +138,8 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
static inline int ehca_write_swqe(struct ehca_qp *qp,
struct ehca_wqe *wqe_p,
const struct ib_send_wr *send_wr)
const struct ib_send_wr *send_wr,
int hidden)
{
u32 idx;
u64 dma_length;
......@@ -176,7 +180,9 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
wqe_p->wr_flag = 0;
if (send_wr->send_flags & IB_SEND_SIGNALED)
if ((send_wr->send_flags & IB_SEND_SIGNALED ||
qp->init_attr.sq_sig_type == IB_SIGNAL_ALL_WR)
&& !hidden)
wqe_p->wr_flag |= WQE_WRFLAG_REQ_SIGNAL_COM;
if (send_wr->opcode == IB_WR_SEND_WITH_IMM ||
......@@ -199,7 +205,7 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
wqe_p->destination_qp_number = send_wr->wr.ud.remote_qpn << 8;
wqe_p->local_ee_context_qkey = remote_qkey;
if (!send_wr->wr.ud.ah) {
if (unlikely(!send_wr->wr.ud.ah)) {
ehca_gen_err("wr.ud.ah is NULL. qp=%p", qp);
return -EINVAL;
}
......@@ -255,6 +261,15 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
} /* eof idx */
wqe_p->u.nud.atomic_1st_op_dma_len = dma_length;
/* unsolicited ack circumvention */
if (send_wr->opcode == IB_WR_RDMA_READ) {
/* on RDMA read, switch on and reset counters */
qp->message_count = qp->packet_count = 0;
qp->unsol_ack_circ = 1;
} else
/* else estimate #packets */
qp->packet_count += (dma_length >> qp->mtu_shift) + 1;
break;
default:
......@@ -355,13 +370,49 @@ static inline void map_ib_wc_status(u32 cqe_status,
*wc_status = IB_WC_SUCCESS;
}
static inline int post_one_send(struct ehca_qp *my_qp,
struct ib_send_wr *cur_send_wr,
struct ib_send_wr **bad_send_wr,
int hidden)
{
struct ehca_wqe *wqe_p;
int ret;
u64 start_offset = my_qp->ipz_squeue.current_q_offset;
/* get pointer next to free WQE */
wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue);
if (unlikely(!wqe_p)) {
/* too many posted work requests: queue overflow */
if (bad_send_wr)
*bad_send_wr = cur_send_wr;
ehca_err(my_qp->ib_qp.device, "Too many posted WQEs "
"qp_num=%x", my_qp->ib_qp.qp_num);
return -ENOMEM;
}
/* write a SEND WQE into the QUEUE */
ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr, hidden);
/*
* if something failed,
* reset the free entry pointer to the start value
*/
if (unlikely(ret)) {
my_qp->ipz_squeue.current_q_offset = start_offset;
if (bad_send_wr)
*bad_send_wr = cur_send_wr;
ehca_err(my_qp->ib_qp.device, "Could not write WQE "
"qp_num=%x", my_qp->ib_qp.qp_num);
return -EINVAL;
}
return 0;
}
int ehca_post_send(struct ib_qp *qp,
struct ib_send_wr *send_wr,
struct ib_send_wr **bad_send_wr)
{
struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp);
struct ib_send_wr *cur_send_wr;
struct ehca_wqe *wqe_p;
int wqe_cnt = 0;
int ret = 0;
unsigned long flags;
......@@ -369,37 +420,33 @@ int ehca_post_send(struct ib_qp *qp,
/* LOCK the QUEUE */
spin_lock_irqsave(&my_qp->spinlock_s, flags);
/* Send an empty extra RDMA read if:
* 1) there has been an RDMA read on this connection before
* 2) no RDMA read occurred for ACK_CIRC_THRESHOLD link packets
* 3) we can be sure that any previous extra RDMA read has been
* processed so we don't overflow the SQ
*/
if (unlikely(my_qp->unsol_ack_circ &&
my_qp->packet_count > ACK_CIRC_THRESHOLD &&
my_qp->message_count > my_qp->init_attr.cap.max_send_wr)) {
/* insert an empty RDMA READ to fix up the remote QP state */
struct ib_send_wr circ_wr;
memset(&circ_wr, 0, sizeof(circ_wr));
circ_wr.opcode = IB_WR_RDMA_READ;
post_one_send(my_qp, &circ_wr, NULL, 1); /* ignore retcode */
wqe_cnt++;
ehca_dbg(qp->device, "posted circ wr qp_num=%x", qp->qp_num);
my_qp->message_count = my_qp->packet_count = 0;
}
/* loop processes list of send reqs */
for (cur_send_wr = send_wr; cur_send_wr != NULL;
cur_send_wr = cur_send_wr->next) {
u64 start_offset = my_qp->ipz_squeue.current_q_offset;
/* get pointer next to free WQE */
wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue);
if (unlikely(!wqe_p)) {
/* too many posted work requests: queue overflow */
if (bad_send_wr)
*bad_send_wr = cur_send_wr;
if (wqe_cnt == 0) {
ret = -ENOMEM;
ehca_err(qp->device, "Too many posted WQEs "
"qp_num=%x", qp->qp_num);
}
goto post_send_exit0;
}
/* write a SEND WQE into the QUEUE */
ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr);
/*
* if something failed,
* reset the free entry pointer to the start value
*/
ret = post_one_send(my_qp, cur_send_wr, bad_send_wr, 0);
if (unlikely(ret)) {
my_qp->ipz_squeue.current_q_offset = start_offset;
*bad_send_wr = cur_send_wr;
if (wqe_cnt == 0) {
ret = -EINVAL;
ehca_err(qp->device, "Could not write WQE "
"qp_num=%x", qp->qp_num);
}
/* if one or more WQEs were successful, don't fail */
if (wqe_cnt)
ret = 0;
goto post_send_exit0;
}
wqe_cnt++;
......@@ -410,6 +457,7 @@ int ehca_post_send(struct ib_qp *qp,
post_send_exit0:
iosync(); /* serialize GAL register access */
hipz_update_sqa(my_qp, wqe_cnt);
my_qp->message_count += wqe_cnt;
spin_unlock_irqrestore(&my_qp->spinlock_s, flags);
return ret;
}
......
......@@ -40,11 +40,8 @@
*/
#include <linux/module.h>
#include <linux/err.h>
#include "ehca_classes.h"
#include "ehca_tools.h"
#include "ehca_qes.h"
#include "ehca_iverbs.h"
#include "hcp_if.h"
......@@ -93,6 +90,9 @@ u64 ehca_define_sqp(struct ehca_shca *shca,
return H_PARAMETER;
}
if (ehca_nr_ports < 0) /* autodetect mode */
return H_SUCCESS;
for (counter = 0;
shca->sport[port - 1].port_state != IB_PORT_ACTIVE &&
counter < ehca_port_act_time;
......
......@@ -81,6 +81,16 @@
#define IPATH_IB_LINK_LOOPBACK 6 /* enable local loopback */
#define IPATH_IB_LINK_EXTERNAL 7 /* normal, disable local loopback */
/*
* These 3 values (SDR and DDR may be ORed for auto-speed
* negotiation) are used for the 3rd argument to path_f_set_ib_cfg
* with cmd IPATH_IB_CFG_SPD_ENB, by direct calls or via sysfs. They
* are also the the possible values for ipath_link_speed_enabled and active
* The values were chosen to match values used within the IB spec.
*/
#define IPATH_IB_SDR 1
#define IPATH_IB_DDR 2
/*
* stats maintained by the driver. For now, at least, this is global
* to all minor devices.
......@@ -433,8 +443,9 @@ struct ipath_user_info {
#define IPATH_CMD_UNUSED_2 26
#define IPATH_CMD_PIOAVAILUPD 27 /* force an update of PIOAvail reg */
#define IPATH_CMD_POLL_TYPE 28 /* set the kind of polling we want */
#define IPATH_CMD_ARMLAUNCH_CTRL 29 /* armlaunch detection control */
#define IPATH_CMD_MAX 28
#define IPATH_CMD_MAX 29
/*
* Poll types
......@@ -477,6 +488,8 @@ struct ipath_cmd {
__u64 port_info;
/* enable/disable receipt of packets */
__u32 recv_ctrl;
/* enable/disable armlaunch errors (non-zero to enable) */
__u32 armlaunch_ctrl;
/* partition key to set */
__u16 part_key;
/* user address of __u32 bitmask of active slaves */
......@@ -579,7 +592,7 @@ struct ipath_flash {
struct infinipath_counters {
__u64 LBIntCnt;
__u64 LBFlowStallCnt;
__u64 Reserved1;
__u64 TxSDmaDescCnt; /* was Reserved1 */
__u64 TxUnsupVLErrCnt;
__u64 TxDataPktCnt;
__u64 TxFlowPktCnt;
......@@ -615,12 +628,26 @@ struct infinipath_counters {
__u64 RxP6HdrEgrOvflCnt;
__u64 RxP7HdrEgrOvflCnt;
__u64 RxP8HdrEgrOvflCnt;
__u64 Reserved6;
__u64 Reserved7;
__u64 RxP9HdrEgrOvflCnt; /* was Reserved6 */
__u64 RxP10HdrEgrOvflCnt; /* was Reserved7 */
__u64 RxP11HdrEgrOvflCnt; /* new for IBA7220 */
__u64 RxP12HdrEgrOvflCnt; /* new for IBA7220 */
__u64 RxP13HdrEgrOvflCnt; /* new for IBA7220 */
__u64 RxP14HdrEgrOvflCnt; /* new for IBA7220 */
__u64 RxP15HdrEgrOvflCnt; /* new for IBA7220 */
__u64 RxP16HdrEgrOvflCnt; /* new for IBA7220 */
__u64 IBStatusChangeCnt;
__u64 IBLinkErrRecoveryCnt;
__u64 IBLinkDownedCnt;
__u64 IBSymbolErrCnt;
/* The following are new for IBA7220 */
__u64 RxVL15DroppedPktCnt;
__u64 RxOtherLocalPhyErrCnt;
__u64 PcieRetryBufDiagQwordCnt;
__u64 ExcessBufferOvflCnt;
__u64 LocalLinkIntegrityErrCnt;
__u64 RxVlErrCnt;
__u64 RxDlidFltrCnt;
};
/*
......
......@@ -421,7 +421,7 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
else
n = head - tail;
if (unlikely((u32)cqe < n)) {
ret = -EOVERFLOW;
ret = -EINVAL;
goto bail_unlock;
}
for (n = 0; tail != head; n++) {
......
......@@ -55,7 +55,7 @@
#define __IPATH_PKTDBG 0x80 /* print packet data */
/* print process startup (init)/exit messages */
#define __IPATH_PROCDBG 0x100
/* print mmap/nopage stuff, not using VDBG any more */
/* print mmap/fault stuff, not using VDBG any more */
#define __IPATH_MMDBG 0x200
#define __IPATH_ERRPKTDBG 0x400
#define __IPATH_USER_SEND 0x1000 /* use user mode send */
......@@ -81,7 +81,7 @@
#define __IPATH_VERBDBG 0x0 /* very verbose debug */
#define __IPATH_PKTDBG 0x0 /* print packet data */
#define __IPATH_PROCDBG 0x0 /* process startup (init)/exit messages */
/* print mmap/nopage stuff, not using VDBG any more */
/* print mmap/fault stuff, not using VDBG any more */
#define __IPATH_MMDBG 0x0
#define __IPATH_EPKTDBG 0x0 /* print ethernet packet data */
#define __IPATH_IPATHDBG 0x0 /* Ethernet (IPATH) table dump on */
......
......@@ -334,6 +334,8 @@ static void ipath_verify_pioperf(struct ipath_devdata *dd)
udelay(1);
}
ipath_disable_armlaunch(dd);
writeq(0, piobuf); /* length 0, no dwords actually sent */
ipath_flush_wc();
......@@ -365,6 +367,7 @@ static void ipath_verify_pioperf(struct ipath_devdata *dd)
done:
/* disarm piobuf, so it's available again */
ipath_disarm_piobufs(dd, pbnum, 1);
ipath_enable_armlaunch(dd);
}
static int __devinit ipath_init_one(struct pci_dev *pdev,
......@@ -803,31 +806,37 @@ void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first,
unsigned cnt)
{
unsigned i, last = first + cnt;
u64 sendctrl, sendorig;
unsigned long flags;
ipath_cdbg(PKT, "disarm %u PIObufs first=%u\n", cnt, first);
sendorig = dd->ipath_sendctrl;
for (i = first; i < last; i++) {
sendctrl = sendorig | INFINIPATH_S_DISARM |
(i << INFINIPATH_S_DISARMPIOBUF_SHIFT);
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
/*
* The disarm-related bits are write-only, so it
* is ok to OR them in with our copy of sendctrl
* while we hold the lock.
*/
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
sendctrl);
dd->ipath_sendctrl | INFINIPATH_S_DISARM |
(i << INFINIPATH_S_DISARMPIOBUF_SHIFT));
/* can't disarm bufs back-to-back per iba7220 spec */
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
}
/*
* Write it again with current value, in case ipath_sendctrl changed
* while we were looping; no critical bits that would require
* locking.
*
* disable PIOAVAILUPD, then re-enable, reading scratch in
* Disable PIOAVAILUPD, then re-enable, reading scratch in
* between. This seems to avoid a chip timing race that causes
* pioavail updates to memory to stop.
* pioavail updates to memory to stop. We xor as we don't
* know the state of the bit when we're called.
*/
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
sendorig & ~INFINIPATH_S_PIOBUFAVAILUPD);
sendorig = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
dd->ipath_sendctrl ^ INFINIPATH_S_PIOBUFAVAILUPD);
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
}
/**
......@@ -1003,12 +1012,10 @@ static void get_rhf_errstring(u32 err, char *msg, size_t len)
* ipath_get_egrbuf - get an eager buffer
* @dd: the infinipath device
* @bufnum: the eager buffer to get
* @err: unused
*
* must only be called if ipath_pd[port] is known to be allocated
*/
static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum,
int err)
static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum)
{
return dd->ipath_port0_skbinfo ?
(void *) dd->ipath_port0_skbinfo[bufnum].skb->data : NULL;
......@@ -1100,13 +1107,14 @@ static void ipath_rcv_hdrerr(struct ipath_devdata *dd,
/*
* ipath_kreceive - receive a packet
* @dd: the infinipath device
* @pd: the infinipath port
*
* called from interrupt handler for errors or receive interrupt
*/
void ipath_kreceive(struct ipath_devdata *dd)
void ipath_kreceive(struct ipath_portdata *pd)
{
u64 *rc;
struct ipath_devdata *dd = pd->port_dd;
void *ebuf;
const u32 rsize = dd->ipath_rcvhdrentsize; /* words */
const u32 maxcnt = dd->ipath_rcvhdrcnt * rsize; /* words */
......@@ -1121,8 +1129,8 @@ void ipath_kreceive(struct ipath_devdata *dd)
goto bail;
}
l = dd->ipath_port0head;
hdrqtail = (u32) le64_to_cpu(*dd->ipath_hdrqtailptr);
l = pd->port_head;
hdrqtail = ipath_get_rcvhdrtail(pd);
if (l == hdrqtail)
goto bail;
......@@ -1131,7 +1139,7 @@ void ipath_kreceive(struct ipath_devdata *dd)
u32 qp;
u8 *bthbytes;
rc = (u64 *) (dd->ipath_pd[0]->port_rcvhdrq + (l << 2));
rc = (u64 *) (pd->port_rcvhdrq + (l << 2));
hdr = (struct ipath_message_header *)&rc[1];
/*
* could make a network order version of IPATH_KD_QP, and
......@@ -1156,7 +1164,7 @@ void ipath_kreceive(struct ipath_devdata *dd)
etail = ipath_hdrget_index((__le32 *) rc);
if (tlen > sizeof(*hdr) ||
etype == RCVHQ_RCV_TYPE_NON_KD)
ebuf = ipath_get_egrbuf(dd, etail, 0);
ebuf = ipath_get_egrbuf(dd, etail);
}
/*
......@@ -1191,7 +1199,7 @@ void ipath_kreceive(struct ipath_devdata *dd)
be32_to_cpu(hdr->bth[0]) & 0xff);
else {
/*
* error packet, type of error unknown.
* error packet, type of error unknown.
* Probably type 3, but we don't know, so don't
* even try to print the opcode, etc.
*/
......@@ -1241,7 +1249,7 @@ void ipath_kreceive(struct ipath_devdata *dd)
* earlier packets, we "almost" guarantee we have covered
* that case.
*/
u32 hqtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr);
u32 hqtail = ipath_get_rcvhdrtail(pd);
if (hqtail != hdrqtail) {
hdrqtail = hqtail;
reloop = 1; /* loop 1 extra time at most */
......@@ -1251,7 +1259,7 @@ void ipath_kreceive(struct ipath_devdata *dd)
pkttot += i;
dd->ipath_port0head = l;
pd->port_head = l;
if (pkttot > ipath_stats.sps_maxpkts_call)
ipath_stats.sps_maxpkts_call = pkttot;
......@@ -1335,14 +1343,9 @@ static void ipath_update_pio_bufs(struct ipath_devdata *dd)
/*
* Chip Errata: bug 6641; even and odd qwords>3 are swapped
*/
if (i > 3) {
if (i & 1)
piov = le64_to_cpu(
dd->ipath_pioavailregs_dma[i - 1]);
else
piov = le64_to_cpu(
dd->ipath_pioavailregs_dma[i + 1]);
} else
if (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS))
piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i ^ 1]);
else
piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i]);
pchg = _IPATH_ALL_CHECKBITS &
~(dd->ipath_pioavailshadow[i] ^ piov);
......@@ -1601,7 +1604,8 @@ int ipath_create_rcvhdrq(struct ipath_devdata *dd,
/* clear for security and sanity on each use */
memset(pd->port_rcvhdrq, 0, pd->port_rcvhdrq_size);
memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE);
if (pd->port_rcvhdrtail_kvaddr)
memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE);
/*
* tell chip each time we init it, even if we are re-using previous
......@@ -1617,77 +1621,6 @@ int ipath_create_rcvhdrq(struct ipath_devdata *dd,
return ret;
}
int ipath_waitfor_complete(struct ipath_devdata *dd, ipath_kreg reg_id,
u64 bits_to_wait_for, u64 * valp)
{
unsigned long timeout;
u64 lastval, val;
int ret;
lastval = ipath_read_kreg64(dd, reg_id);
/* wait a ridiculously long time */
timeout = jiffies + msecs_to_jiffies(5);
do {
val = ipath_read_kreg64(dd, reg_id);
/* set so they have something, even on failures. */
*valp = val;
if ((val & bits_to_wait_for) == bits_to_wait_for) {
ret = 0;
break;
}
if (val != lastval)
ipath_cdbg(VERBOSE, "Changed from %llx to %llx, "
"waiting for %llx bits\n",
(unsigned long long) lastval,
(unsigned long long) val,
(unsigned long long) bits_to_wait_for);
cond_resched();
if (time_after(jiffies, timeout)) {
ipath_dbg("Didn't get bits %llx in register 0x%x, "
"got %llx\n",
(unsigned long long) bits_to_wait_for,
reg_id, (unsigned long long) *valp);
ret = -ENODEV;
break;
}
} while (1);
return ret;
}
/**
* ipath_waitfor_mdio_cmdready - wait for last command to complete
* @dd: the infinipath device
*
* Like ipath_waitfor_complete(), but we wait for the CMDVALID bit to go
* away indicating the last command has completed. It doesn't return data
*/
int ipath_waitfor_mdio_cmdready(struct ipath_devdata *dd)
{
unsigned long timeout;
u64 val;
int ret;
/* wait a ridiculously long time */
timeout = jiffies + msecs_to_jiffies(5);
do {
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_mdio);
if (!(val & IPATH_MDIO_CMDVALID)) {
ret = 0;
break;
}
cond_resched();
if (time_after(jiffies, timeout)) {
ipath_dbg("CMDVALID stuck in mdio reg? (%llx)\n",
(unsigned long long) val);
ret = -ENODEV;
break;
}
} while (1);
return ret;
}
/*
* Flush all sends that might be in the ready to send state, as well as any
......@@ -2056,6 +1989,8 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val)
*/
void ipath_shutdown_device(struct ipath_devdata *dd)
{
unsigned long flags;
ipath_dbg("Shutting down the device\n");
dd->ipath_flags |= IPATH_LINKUNK;
......@@ -2076,9 +2011,13 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
* gracefully stop all sends allowing any in progress to trickle out
* first.
*/
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0ULL);
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
dd->ipath_sendctrl = 0;
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
/* flush it */
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
/*
* enough for anything that's going to trickle out to have actually
* done so.
......@@ -2335,5 +2274,34 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv)
}
return 0;
}
/*
* Disable and enable the armlaunch error. Used for PIO bandwidth testing on
* the 7220, which is count-based, rather than trigger-based. Safe for the
* driver check, since it's at init. Not completely safe when used for
* user-mode checking, since some error checking can be lost, but not
* particularly risky, and only has problematic side-effects in the face of
* very buggy user code. There is no reference counting, but that's also
* fine, given the intended use.
*/
void ipath_enable_armlaunch(struct ipath_devdata *dd)
{
dd->ipath_lasterror &= ~INFINIPATH_E_SPIOARMLAUNCH;
ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear,
INFINIPATH_E_SPIOARMLAUNCH);
dd->ipath_errormask |= INFINIPATH_E_SPIOARMLAUNCH;
ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
dd->ipath_errormask);
}
void ipath_disable_armlaunch(struct ipath_devdata *dd)
{
/* so don't re-enable if already set */
dd->ipath_maskederrs &= ~INFINIPATH_E_SPIOARMLAUNCH;
dd->ipath_errormask &= ~INFINIPATH_E_SPIOARMLAUNCH;
ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
dd->ipath_errormask);
}
module_init(infinipath_init);
module_exit(infinipath_cleanup);
......@@ -510,10 +510,10 @@ int ipath_eeprom_read(struct ipath_devdata *dd, u8 eeprom_offset,
{
int ret;
ret = down_interruptible(&dd->ipath_eep_sem);
ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
if (!ret) {
ret = ipath_eeprom_internal_read(dd, eeprom_offset, buff, len);
up(&dd->ipath_eep_sem);
mutex_unlock(&dd->ipath_eep_lock);
}
return ret;
......@@ -524,10 +524,10 @@ int ipath_eeprom_write(struct ipath_devdata *dd, u8 eeprom_offset,
{
int ret;
ret = down_interruptible(&dd->ipath_eep_sem);
ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
if (!ret) {
ret = ipath_eeprom_internal_write(dd, eeprom_offset, buff, len);
up(&dd->ipath_eep_sem);
mutex_unlock(&dd->ipath_eep_lock);
}
return ret;
......@@ -574,7 +574,7 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
struct ipath_devdata *dd0 = ipath_lookup(0);
if (t && dd0->ipath_nguid > 1 && t <= dd0->ipath_nguid) {
u8 *bguid, oguid;
u8 oguid;
dd->ipath_guid = dd0->ipath_guid;
bguid = (u8 *) & dd->ipath_guid;
......@@ -616,9 +616,9 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
goto bail;
}
down(&dd->ipath_eep_sem);
mutex_lock(&dd->ipath_eep_lock);
eep_stat = ipath_eeprom_internal_read(dd, 0, buf, len);
up(&dd->ipath_eep_sem);
mutex_unlock(&dd->ipath_eep_lock);
if (eep_stat) {
ipath_dev_err(dd, "Failed reading GUID from eeprom\n");
......@@ -674,7 +674,6 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
* elsewhere for backward-compatibility.
*/
char *snp = dd->ipath_serial;
int len;
memcpy(snp, ifp->if_sprefix, sizeof ifp->if_sprefix);
snp[sizeof ifp->if_sprefix] = '\0';
len = strlen(snp);
......@@ -764,14 +763,14 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
/* Grab semaphore and read current EEPROM. If we get an
* error, let go, but if not, keep it until we finish write.
*/
ret = down_interruptible(&dd->ipath_eep_sem);
ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
if (ret) {
ipath_dev_err(dd, "Unable to acquire EEPROM for logging\n");
goto free_bail;
}
ret = ipath_eeprom_internal_read(dd, 0, buf, len);
if (ret) {
up(&dd->ipath_eep_sem);
mutex_unlock(&dd->ipath_eep_lock);
ipath_dev_err(dd, "Unable read EEPROM for logging\n");
goto free_bail;
}
......@@ -779,7 +778,7 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
csum = flash_csum(ifp, 0);
if (csum != ifp->if_csum) {
up(&dd->ipath_eep_sem);
mutex_unlock(&dd->ipath_eep_lock);
ipath_dev_err(dd, "EEPROM cks err (0x%02X, S/B 0x%02X)\n",
csum, ifp->if_csum);
ret = 1;
......@@ -849,7 +848,7 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
csum = flash_csum(ifp, 1);
ret = ipath_eeprom_internal_write(dd, 0, buf, hi_water + 1);
}
up(&dd->ipath_eep_sem);
mutex_unlock(&dd->ipath_eep_lock);
if (ret)
ipath_dev_err(dd, "Failed updating EEPROM\n");
......
......@@ -169,7 +169,7 @@ static int ipath_get_base_info(struct file *fp,
kinfo->spi_piocnt = dd->ipath_pbufsport;
kinfo->spi_piobufbase = (u64) pd->port_piobufs;
kinfo->__spi_uregbase = (u64) dd->ipath_uregbase +
dd->ipath_palign * pd->port_port;
dd->ipath_ureg_align * pd->port_port;
} else if (master) {
kinfo->spi_piocnt = (dd->ipath_pbufsport / subport_cnt) +
(dd->ipath_pbufsport % subport_cnt);
......@@ -186,7 +186,7 @@ static int ipath_get_base_info(struct file *fp,
}
if (shared) {
kinfo->spi_port_uregbase = (u64) dd->ipath_uregbase +
dd->ipath_palign * pd->port_port;
dd->ipath_ureg_align * pd->port_port;
kinfo->spi_port_rcvegrbuf = kinfo->spi_rcv_egrbufs;
kinfo->spi_port_rcvhdr_base = kinfo->spi_rcvhdr_base;
kinfo->spi_port_rcvhdr_tailaddr = kinfo->spi_rcvhdr_tailaddr;
......@@ -742,11 +742,12 @@ static int ipath_manage_rcvq(struct ipath_portdata *pd, unsigned subport,
* updated and correct itself, even in the face of software
* bugs.
*/
*(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0;
set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
if (pd->port_rcvhdrtail_kvaddr)
ipath_clear_rcvhdrtail(pd);
set_bit(dd->ipath_r_portenable_shift + pd->port_port,
&dd->ipath_rcvctrl);
} else
clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
clear_bit(dd->ipath_r_portenable_shift + pd->port_port,
&dd->ipath_rcvctrl);
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
dd->ipath_rcvctrl);
......@@ -881,7 +882,7 @@ static int ipath_create_user_egr(struct ipath_portdata *pd)
egrcnt = dd->ipath_rcvegrcnt;
/* TID number offset for this port */
egroff = pd->port_port * egrcnt;
egroff = (pd->port_port - 1) * egrcnt + dd->ipath_p0_rcvegrcnt;
egrsize = dd->ipath_rcvegrbufsize;
ipath_cdbg(VERBOSE, "Allocating %d egr buffers, at egrtid "
"offset %x, egrsize %u\n", egrcnt, egroff, egrsize);
......@@ -1049,11 +1050,6 @@ static int mmap_piobufs(struct vm_area_struct *vma,
phys = dd->ipath_physaddr + piobufs;
/*
* Don't mark this as non-cached, or we don't get the
* write combining behavior we want on the PIO buffers!
*/
#if defined(__powerpc__)
/* There isn't a generic way to specify writethrough mappings */
pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
......@@ -1120,33 +1116,24 @@ static int mmap_rcvegrbufs(struct vm_area_struct *vma,
}
/*
* ipath_file_vma_nopage - handle a VMA page fault.
* ipath_file_vma_fault - handle a VMA page fault.
*/
static struct page *ipath_file_vma_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
static int ipath_file_vma_fault(struct vm_area_struct *vma,
struct vm_fault *vmf)
{
unsigned long offset = address - vma->vm_start;
struct page *page = NOPAGE_SIGBUS;
void *pageptr;
struct page *page;
/*
* Convert the vmalloc address into a struct page.
*/
pageptr = (void *)(offset + (vma->vm_pgoff << PAGE_SHIFT));
page = vmalloc_to_page(pageptr);
page = vmalloc_to_page((void *)(vmf->pgoff << PAGE_SHIFT));
if (!page)
goto out;
/* Increment the reference count. */
return VM_FAULT_SIGBUS;
get_page(page);
if (type)
*type = VM_FAULT_MINOR;
out:
return page;
vmf->page = page;
return 0;
}
static struct vm_operations_struct ipath_file_vm_ops = {
.nopage = ipath_file_vma_nopage,
.fault = ipath_file_vma_fault,
};
static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr,
......@@ -1284,7 +1271,7 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma)
goto bail;
}
ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
ureg = dd->ipath_uregbase + dd->ipath_ureg_align * pd->port_port;
if (!pd->port_subport_cnt) {
/* port is not shared */
piocnt = dd->ipath_pbufsport;
......@@ -1400,7 +1387,10 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd,
pollflag = ipath_poll_hdrqfull(pd);
head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port);
tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr;
if (pd->port_rcvhdrtail_kvaddr)
tail = ipath_get_rcvhdrtail(pd);
else
tail = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port);
if (head != tail)
pollflag |= POLLIN | POLLRDNORM;
......@@ -1410,7 +1400,7 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd,
/* flush waiting flag so we don't miss an event */
wmb();
set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
set_bit(pd->port_port + dd->ipath_r_intravail_shift,
&dd->ipath_rcvctrl);
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
......@@ -1790,6 +1780,7 @@ static int find_shared_port(struct file *fp,
}
port_fp(fp) = pd;
subport_fp(fp) = pd->port_cnt++;
pd->port_subpid[subport_fp(fp)] = current->pid;
tidcursor_fp(fp) = 0;
pd->active_slaves |= 1 << subport_fp(fp);
ipath_cdbg(PROC,
......@@ -1920,8 +1911,7 @@ static int ipath_do_user_init(struct file *fp,
*/
head32 = ipath_read_ureg32(dd, ur_rcvegrindextail, pd->port_port);
ipath_write_ureg(dd, ur_rcvegrindexhead, head32, pd->port_port);
dd->ipath_lastegrheads[pd->port_port] = -1;
dd->ipath_lastrcvhdrqtails[pd->port_port] = -1;
pd->port_lastrcvhdrqtail = -1;
ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n",
pd->port_port, head32);
pd->port_tidcursor = 0; /* start at beginning after open */
......@@ -1941,11 +1931,13 @@ static int ipath_do_user_init(struct file *fp,
* We explictly set the in-memory copy to 0 beforehand, so we don't
* have to wait to be sure the DMA update has happened.
*/
*(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0ULL;
set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
if (pd->port_rcvhdrtail_kvaddr)
ipath_clear_rcvhdrtail(pd);
set_bit(dd->ipath_r_portenable_shift + pd->port_port,
&dd->ipath_rcvctrl);
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
dd->ipath_rcvctrl & ~INFINIPATH_R_TAILUPD);
dd->ipath_rcvctrl &
~(1ULL << dd->ipath_r_tailupd_shift));
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
dd->ipath_rcvctrl);
/* Notify any waiting slaves */
......@@ -2022,6 +2014,7 @@ static int ipath_close(struct inode *in, struct file *fp)
* the slave(s) don't wait for receive data forever.
*/
pd->active_slaves &= ~(1 << fd->subport);
pd->port_subpid[fd->subport] = 0;
mutex_unlock(&ipath_mutex);
goto bail;
}
......@@ -2054,9 +2047,9 @@ static int ipath_close(struct inode *in, struct file *fp)
if (dd->ipath_kregbase) {
int i;
/* atomically clear receive enable port and intr avail. */
clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port,
clear_bit(dd->ipath_r_portenable_shift + port,
&dd->ipath_rcvctrl);
clear_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
clear_bit(pd->port_port + dd->ipath_r_intravail_shift,
&dd->ipath_rcvctrl);
ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl,
dd->ipath_rcvctrl);
......@@ -2149,11 +2142,15 @@ static int ipath_get_slave_info(struct ipath_portdata *pd,
static int ipath_force_pio_avail_update(struct ipath_devdata *dd)
{
u64 reg = dd->ipath_sendctrl;
unsigned long flags;
clear_bit(IPATH_S_PIOBUFAVAILUPD, &reg);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, reg);
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD);
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
return 0;
}
......@@ -2227,6 +2224,11 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
dest = &cmd.cmd.poll_type;
src = &ucmd->cmd.poll_type;
break;
case IPATH_CMD_ARMLAUNCH_CTRL:
copy = sizeof(cmd.cmd.armlaunch_ctrl);
dest = &cmd.cmd.armlaunch_ctrl;
src = &ucmd->cmd.armlaunch_ctrl;
break;
default:
ret = -EINVAL;
goto bail;
......@@ -2302,6 +2304,12 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
case IPATH_CMD_POLL_TYPE:
pd->poll_type = cmd.cmd.poll_type;
break;
case IPATH_CMD_ARMLAUNCH_CTRL:
if (cmd.cmd.armlaunch_ctrl)
ipath_enable_armlaunch(pd->port_dd);
else
ipath_disable_armlaunch(pd->port_dd);
break;
}
if (ret >= 0)
......
......@@ -108,21 +108,16 @@ static const struct file_operations atomic_stats_ops = {
.read = atomic_stats_read,
};
#define NUM_COUNTERS sizeof(struct infinipath_counters) / sizeof(u64)
static ssize_t atomic_counters_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
u64 counters[NUM_COUNTERS];
u16 i;
struct infinipath_counters counters;
struct ipath_devdata *dd;
dd = file->f_path.dentry->d_inode->i_private;
dd->ipath_f_read_counters(dd, &counters);
for (i = 0; i < NUM_COUNTERS; i++)
counters[i] = ipath_snap_cntr(dd, i);
return simple_read_from_buffer(buf, count, ppos, counters,
return simple_read_from_buffer(buf, count, ppos, &counters,
sizeof counters);
}
......@@ -243,8 +238,7 @@ static int create_device_files(struct super_block *sb,
snprintf(unit, sizeof unit, "%02d", dd->ipath_unit);
ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir,
(struct file_operations *) &simple_dir_operations,
dd);
&simple_dir_operations, dd);
if (ret) {
printk(KERN_ERR "create_file(%s) failed: %d\n", unit, ret);
goto bail;
......
......@@ -148,10 +148,57 @@ struct _infinipath_do_not_use_kernel_regs {
unsigned long long ReservedSW2[4];
};
#define IPATH_KREG_OFFSET(field) (offsetof(struct \
_infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
struct _infinipath_do_not_use_counters {
__u64 LBIntCnt;
__u64 LBFlowStallCnt;
__u64 Reserved1;
__u64 TxUnsupVLErrCnt;
__u64 TxDataPktCnt;
__u64 TxFlowPktCnt;
__u64 TxDwordCnt;
__u64 TxLenErrCnt;
__u64 TxMaxMinLenErrCnt;
__u64 TxUnderrunCnt;
__u64 TxFlowStallCnt;
__u64 TxDroppedPktCnt;
__u64 RxDroppedPktCnt;
__u64 RxDataPktCnt;
__u64 RxFlowPktCnt;
__u64 RxDwordCnt;
__u64 RxLenErrCnt;
__u64 RxMaxMinLenErrCnt;
__u64 RxICRCErrCnt;
__u64 RxVCRCErrCnt;
__u64 RxFlowCtrlErrCnt;
__u64 RxBadFormatCnt;
__u64 RxLinkProblemCnt;
__u64 RxEBPCnt;
__u64 RxLPCRCErrCnt;
__u64 RxBufOvflCnt;
__u64 RxTIDFullErrCnt;
__u64 RxTIDValidErrCnt;
__u64 RxPKeyMismatchCnt;
__u64 RxP0HdrEgrOvflCnt;
__u64 RxP1HdrEgrOvflCnt;
__u64 RxP2HdrEgrOvflCnt;
__u64 RxP3HdrEgrOvflCnt;
__u64 RxP4HdrEgrOvflCnt;
__u64 RxP5HdrEgrOvflCnt;
__u64 RxP6HdrEgrOvflCnt;
__u64 RxP7HdrEgrOvflCnt;
__u64 RxP8HdrEgrOvflCnt;
__u64 Reserved6;
__u64 Reserved7;
__u64 IBStatusChangeCnt;
__u64 IBLinkErrRecoveryCnt;
__u64 IBLinkDownedCnt;
__u64 IBSymbolErrCnt;
};
#define IPATH_KREG_OFFSET(field) (offsetof( \
struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
#define IPATH_CREG_OFFSET(field) (offsetof( \
struct infinipath_counters, field) / sizeof(u64))
struct _infinipath_do_not_use_counters, field) / sizeof(u64))
static const struct ipath_kregs ipath_ht_kregs = {
.kr_control = IPATH_KREG_OFFSET(Control),
......@@ -282,6 +329,9 @@ static const struct ipath_cregs ipath_ht_cregs = {
#define INFINIPATH_HWE_HTAPLL_RFSLIP 0x1000000000000000ULL
#define INFINIPATH_HWE_SERDESPLLFAILED 0x2000000000000000ULL
#define IBA6110_IBCS_LINKTRAININGSTATE_MASK 0xf
#define IBA6110_IBCS_LINKSTATE_SHIFT 4
/* kr_extstatus bits */
#define INFINIPATH_EXTS_FREQSEL 0x2
#define INFINIPATH_EXTS_SERDESSEL 0x4
......@@ -296,6 +346,12 @@ static const struct ipath_cregs ipath_ht_cregs = {
#define INFINIPATH_RT_BUFSIZE_MASK 0x3FFFULL
#define INFINIPATH_RT_BUFSIZE_SHIFT 48
#define INFINIPATH_R_INTRAVAIL_SHIFT 16
#define INFINIPATH_R_TAILUPD_SHIFT 31
/* kr_xgxsconfig bits */
#define INFINIPATH_XGXS_RESET 0x7ULL
/*
* masks and bits that are different in different chips, or present only
* in one
......@@ -652,7 +708,6 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
"with ID %u\n", boardrev);
snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u",
boardrev);
ret = 1;
break;
}
if (n)
......@@ -686,6 +741,13 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
dd->ipath_htspeed);
ret = 0;
/*
* set here, not in ipath_init_*_funcs because we have to do
* it after we can read chip registers.
*/
dd->ipath_ureg_align =
ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign);
bail:
return ret;
}
......@@ -969,7 +1031,8 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd,
do {
u8 cap_type;
/* the HT capability type byte is 3 bytes after the
/*
* The HT capability type byte is 3 bytes after the
* capability byte.
*/
if (pci_read_config_byte(pdev, pos + 3, &cap_type)) {
......@@ -982,6 +1045,8 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd,
} while ((pos = pci_find_next_capability(pdev, pos,
PCI_CAP_ID_HT)));
dd->ipath_flags |= IPATH_SWAP_PIOBUFS;
bail:
return ret;
}
......@@ -1074,11 +1139,55 @@ static void ipath_setup_ht_setextled(struct ipath_devdata *dd,
static void ipath_init_ht_variables(struct ipath_devdata *dd)
{
/*
* setup the register offsets, since they are different for each
* chip
*/
dd->ipath_kregs = &ipath_ht_kregs;
dd->ipath_cregs = &ipath_ht_cregs;
dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
dd->ipath_gpio_sda = IPATH_GPIO_SDA;
dd->ipath_gpio_scl = IPATH_GPIO_SCL;
/*
* Fill in data for field-values that change in newer chips.
* We dynamically specify only the mask for LINKTRAININGSTATE
* and only the shift for LINKSTATE, as they are the only ones
* that change. Also precalculate the 3 link states of interest
* and the combined mask.
*/
dd->ibcs_ls_shift = IBA6110_IBCS_LINKSTATE_SHIFT;
dd->ibcs_lts_mask = IBA6110_IBCS_LINKTRAININGSTATE_MASK;
dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK <<
dd->ibcs_ls_shift) | dd->ibcs_lts_mask;
dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
(INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift);
dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
(INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift);
dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
(INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift);
/*
* Fill in data for ibcc field-values that change in newer chips.
* We dynamically specify only the mask for LINKINITCMD
* and only the shift for LINKCMD and MAXPKTLEN, as they are
* the only ones that change.
*/
dd->ibcc_lic_mask = INFINIPATH_IBCC_LINKINITCMD_MASK;
dd->ibcc_lc_shift = INFINIPATH_IBCC_LINKCMD_SHIFT;
dd->ibcc_mpl_shift = INFINIPATH_IBCC_MAXPKTLEN_SHIFT;
/* Fill in shifts for RcvCtrl. */
dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT;
dd->ipath_r_intravail_shift = INFINIPATH_R_INTRAVAIL_SHIFT;
dd->ipath_r_tailupd_shift = INFINIPATH_R_TAILUPD_SHIFT;
dd->ipath_r_portcfg_shift = 0; /* Not on IBA6110 */
dd->ipath_i_bitsextant =
(INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
(INFINIPATH_I_RCVAVAIL_MASK <<
......@@ -1135,6 +1244,8 @@ static void ipath_init_ht_variables(struct ipath_devdata *dd)
dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT;
dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT;
/*
* EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
......@@ -1148,9 +1259,17 @@ static void ipath_init_ht_variables(struct ipath_devdata *dd)
INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT;
dd->ipath_eep_st_masks[2].errs_to_log =
INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET;
dd->ipath_eep_st_masks[2].errs_to_log = INFINIPATH_E_RESET;
dd->delay_mult = 2; /* SDR, 4X, can't change */
dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
dd->ipath_link_speed_supported = IPATH_IB_SDR;
dd->ipath_link_width_enabled = IB_WIDTH_4X;
dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported;
/* these can't change for this chip, so set once */
dd->ipath_link_width_active = dd->ipath_link_width_enabled;
dd->ipath_link_speed_active = dd->ipath_link_speed_enabled;
}
/**
......@@ -1205,14 +1324,16 @@ static void ipath_ht_init_hwerrors(struct ipath_devdata *dd)
val &= ~INFINIPATH_HWE_HTCMISCERR4;
/*
* PLL ignored because MDIO interface has a logic problem
* for reads, on Comstock and Ponderosa. BRINGUP
* PLL ignored because unused MDIO interface has a logic problem
*/
if (dd->ipath_boardrev == 4 || dd->ipath_boardrev == 9)
val &= ~INFINIPATH_HWE_SERDESPLLFAILED;
dd->ipath_hwerrmask = val;
}
/**
* ipath_ht_bringup_serdes - bring up the serdes
* @dd: the infinipath device
......@@ -1284,16 +1405,6 @@ static int ipath_ht_bringup_serdes(struct ipath_devdata *dd)
}
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
val &= ~(INFINIPATH_XGXS_MDIOADDR_MASK <<
INFINIPATH_XGXS_MDIOADDR_SHIFT);
/*
* we use address 3
*/
val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
change = 1;
}
if (val & INFINIPATH_XGXS_RESET) {
/* normally true after boot */
val &= ~INFINIPATH_XGXS_RESET;
......@@ -1329,21 +1440,6 @@ static int ipath_ht_bringup_serdes(struct ipath_devdata *dd)
(unsigned long long)
ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
if (!ipath_waitfor_mdio_cmdready(dd)) {
ipath_write_kreg(dd, dd->ipath_kregs->kr_mdio,
ipath_mdio_req(IPATH_MDIO_CMD_READ, 31,
IPATH_MDIO_CTRL_XGXS_REG_8,
0));
if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio,
IPATH_MDIO_DATAVALID, &val))
ipath_dbg("Never got MDIO data for XGXS status "
"read\n");
else
ipath_cdbg(VERBOSE, "MDIO Read reg8, "
"'bank' 31 %x\n", (u32) val);
} else
ipath_dbg("Never got MDIO cmdready for XGXS status read\n");
return ret; /* for now, say we always succeeded */
}
......@@ -1396,6 +1492,7 @@ static void ipath_ht_put_tid(struct ipath_devdata *dd,
pa |= lenvalid | INFINIPATH_RT_VALID;
}
}
writeq(pa, tidptr);
}
......@@ -1526,8 +1623,7 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
}
ipath_get_eeprom_info(dd);
if (dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' &&
dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') {
if (dd->ipath_boardrev == 5) {
/*
* Later production QHT7040 has same changes as QHT7140, so
* can use GPIO interrupts. They have serial #'s starting
......@@ -1602,6 +1698,210 @@ static void ipath_ht_free_irq(struct ipath_devdata *dd)
dd->ipath_intconfig = 0;
}
static struct ipath_message_header *
ipath_ht_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr)
{
return (struct ipath_message_header *)
&rhf_addr[sizeof(u64) / sizeof(u32)];
}
static void ipath_ht_config_ports(struct ipath_devdata *dd, ushort cfgports)
{
dd->ipath_portcnt =
ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
dd->ipath_p0_rcvegrcnt =
ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt);
}
static void ipath_ht_read_counters(struct ipath_devdata *dd,
struct infinipath_counters *cntrs)
{
cntrs->LBIntCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBIntCnt));
cntrs->LBFlowStallCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBFlowStallCnt));
cntrs->TxSDmaDescCnt = 0;
cntrs->TxUnsupVLErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnsupVLErrCnt));
cntrs->TxDataPktCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDataPktCnt));
cntrs->TxFlowPktCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowPktCnt));
cntrs->TxDwordCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDwordCnt));
cntrs->TxLenErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxLenErrCnt));
cntrs->TxMaxMinLenErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxMaxMinLenErrCnt));
cntrs->TxUnderrunCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnderrunCnt));
cntrs->TxFlowStallCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowStallCnt));
cntrs->TxDroppedPktCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDroppedPktCnt));
cntrs->RxDroppedPktCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDroppedPktCnt));
cntrs->RxDataPktCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDataPktCnt));
cntrs->RxFlowPktCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowPktCnt));
cntrs->RxDwordCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDwordCnt));
cntrs->RxLenErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLenErrCnt));
cntrs->RxMaxMinLenErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxMaxMinLenErrCnt));
cntrs->RxICRCErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxICRCErrCnt));
cntrs->RxVCRCErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxVCRCErrCnt));
cntrs->RxFlowCtrlErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowCtrlErrCnt));
cntrs->RxBadFormatCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBadFormatCnt));
cntrs->RxLinkProblemCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLinkProblemCnt));
cntrs->RxEBPCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxEBPCnt));
cntrs->RxLPCRCErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLPCRCErrCnt));
cntrs->RxBufOvflCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBufOvflCnt));
cntrs->RxTIDFullErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDFullErrCnt));
cntrs->RxTIDValidErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDValidErrCnt));
cntrs->RxPKeyMismatchCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxPKeyMismatchCnt));
cntrs->RxP0HdrEgrOvflCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt));
cntrs->RxP1HdrEgrOvflCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt));
cntrs->RxP2HdrEgrOvflCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt));
cntrs->RxP3HdrEgrOvflCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt));
cntrs->RxP4HdrEgrOvflCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt));
cntrs->RxP5HdrEgrOvflCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP5HdrEgrOvflCnt));
cntrs->RxP6HdrEgrOvflCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP6HdrEgrOvflCnt));
cntrs->RxP7HdrEgrOvflCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP7HdrEgrOvflCnt));
cntrs->RxP8HdrEgrOvflCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP8HdrEgrOvflCnt));
cntrs->RxP9HdrEgrOvflCnt = 0;
cntrs->RxP10HdrEgrOvflCnt = 0;
cntrs->RxP11HdrEgrOvflCnt = 0;
cntrs->RxP12HdrEgrOvflCnt = 0;
cntrs->RxP13HdrEgrOvflCnt = 0;
cntrs->RxP14HdrEgrOvflCnt = 0;
cntrs->RxP15HdrEgrOvflCnt = 0;
cntrs->RxP16HdrEgrOvflCnt = 0;
cntrs->IBStatusChangeCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBStatusChangeCnt));
cntrs->IBLinkErrRecoveryCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt));
cntrs->IBLinkDownedCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkDownedCnt));
cntrs->IBSymbolErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBSymbolErrCnt));
cntrs->RxVL15DroppedPktCnt = 0;
cntrs->RxOtherLocalPhyErrCnt = 0;
cntrs->PcieRetryBufDiagQwordCnt = 0;
cntrs->ExcessBufferOvflCnt = dd->ipath_overrun_thresh_errs;
cntrs->LocalLinkIntegrityErrCnt =
(dd->ipath_flags & IPATH_GPIO_ERRINTRS) ?
dd->ipath_lli_errs : dd->ipath_lli_errors;
cntrs->RxVlErrCnt = 0;
cntrs->RxDlidFltrCnt = 0;
}
/* no interrupt fallback for these chips */
static int ipath_ht_nointr_fallback(struct ipath_devdata *dd)
{
return 0;
}
/*
* reset the XGXS (between serdes and IBC). Slightly less intrusive
* than resetting the IBC or external link state, and useful in some
* cases to cause some retraining. To do this right, we reset IBC
* as well.
*/
static void ipath_ht_xgxs_reset(struct ipath_devdata *dd)
{
u64 val, prev_val;
prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
val = prev_val | INFINIPATH_XGXS_RESET;
prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */
ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
dd->ipath_control & ~INFINIPATH_C_LINKENABLE);
ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val);
ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
dd->ipath_control);
}
static int ipath_ht_get_ib_cfg(struct ipath_devdata *dd, int which)
{
int ret;
switch (which) {
case IPATH_IB_CFG_LWID:
ret = dd->ipath_link_width_active;
break;
case IPATH_IB_CFG_SPD:
ret = dd->ipath_link_speed_active;
break;
case IPATH_IB_CFG_LWID_ENB:
ret = dd->ipath_link_width_enabled;
break;
case IPATH_IB_CFG_SPD_ENB:
ret = dd->ipath_link_speed_enabled;
break;
default:
ret = -ENOTSUPP;
break;
}
return ret;
}
/* we assume range checking is already done, if needed */
static int ipath_ht_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val)
{
int ret = 0;
if (which == IPATH_IB_CFG_LWID_ENB)
dd->ipath_link_width_enabled = val;
else if (which == IPATH_IB_CFG_SPD_ENB)
dd->ipath_link_speed_enabled = val;
else
ret = -ENOTSUPP;
return ret;
}
static void ipath_ht_config_jint(struct ipath_devdata *dd, u16 a, u16 b)
{
}
static int ipath_ht_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
{
ipath_setup_ht_setextled(dd, ipath_ib_linkstate(dd, ibcs),
ipath_ib_linktrstate(dd, ibcs));
return 0;
}
/**
* ipath_init_iba6110_funcs - set up the chip-specific function pointers
* @dd: the infinipath device
......@@ -1626,22 +1926,19 @@ void ipath_init_iba6110_funcs(struct ipath_devdata *dd)
dd->ipath_f_setextled = ipath_setup_ht_setextled;
dd->ipath_f_get_base_info = ipath_ht_get_base_info;
dd->ipath_f_free_irq = ipath_ht_free_irq;
/*
* initialize chip-specific variables
*/
dd->ipath_f_tidtemplate = ipath_ht_tidtemplate;
dd->ipath_f_intr_fallback = ipath_ht_nointr_fallback;
dd->ipath_f_get_msgheader = ipath_ht_get_msgheader;
dd->ipath_f_config_ports = ipath_ht_config_ports;
dd->ipath_f_read_counters = ipath_ht_read_counters;
dd->ipath_f_xgxs_reset = ipath_ht_xgxs_reset;
dd->ipath_f_get_ib_cfg = ipath_ht_get_ib_cfg;
dd->ipath_f_set_ib_cfg = ipath_ht_set_ib_cfg;
dd->ipath_f_config_jint = ipath_ht_config_jint;
dd->ipath_f_ib_updown = ipath_ht_ib_updown;
/*
* setup the register offsets, since they are different for each
* chip
*/
dd->ipath_kregs = &ipath_ht_kregs;
dd->ipath_cregs = &ipath_ht_cregs;
/*
* do very early init that is needed before ipath_f_bus is
* called
* initialize chip-specific variables
*/
ipath_init_ht_variables(dd);
}
......@@ -145,10 +145,57 @@ struct _infinipath_do_not_use_kernel_regs {
unsigned long long Reserved12;
};
#define IPATH_KREG_OFFSET(field) (offsetof(struct \
_infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
struct _infinipath_do_not_use_counters {
__u64 LBIntCnt;
__u64 LBFlowStallCnt;
__u64 Reserved1;
__u64 TxUnsupVLErrCnt;
__u64 TxDataPktCnt;
__u64 TxFlowPktCnt;
__u64 TxDwordCnt;
__u64 TxLenErrCnt;
__u64 TxMaxMinLenErrCnt;
__u64 TxUnderrunCnt;
__u64 TxFlowStallCnt;
__u64 TxDroppedPktCnt;
__u64 RxDroppedPktCnt;
__u64 RxDataPktCnt;
__u64 RxFlowPktCnt;
__u64 RxDwordCnt;
__u64 RxLenErrCnt;
__u64 RxMaxMinLenErrCnt;
__u64 RxICRCErrCnt;
__u64 RxVCRCErrCnt;
__u64 RxFlowCtrlErrCnt;
__u64 RxBadFormatCnt;
__u64 RxLinkProblemCnt;
__u64 RxEBPCnt;
__u64 RxLPCRCErrCnt;
__u64 RxBufOvflCnt;
__u64 RxTIDFullErrCnt;
__u64 RxTIDValidErrCnt;
__u64 RxPKeyMismatchCnt;
__u64 RxP0HdrEgrOvflCnt;
__u64 RxP1HdrEgrOvflCnt;
__u64 RxP2HdrEgrOvflCnt;
__u64 RxP3HdrEgrOvflCnt;
__u64 RxP4HdrEgrOvflCnt;
__u64 RxP5HdrEgrOvflCnt;
__u64 RxP6HdrEgrOvflCnt;
__u64 RxP7HdrEgrOvflCnt;
__u64 RxP8HdrEgrOvflCnt;
__u64 Reserved6;
__u64 Reserved7;
__u64 IBStatusChangeCnt;
__u64 IBLinkErrRecoveryCnt;
__u64 IBLinkDownedCnt;
__u64 IBSymbolErrCnt;
};
#define IPATH_KREG_OFFSET(field) (offsetof( \
struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
#define IPATH_CREG_OFFSET(field) (offsetof( \
struct infinipath_counters, field) / sizeof(u64))
struct _infinipath_do_not_use_counters, field) / sizeof(u64))
static const struct ipath_kregs ipath_pe_kregs = {
.kr_control = IPATH_KREG_OFFSET(Control),
......@@ -282,6 +329,9 @@ static const struct ipath_cregs ipath_pe_cregs = {
#define INFINIPATH_HWE_PCIE0PLLFAILED 0x0800000000000000ULL
#define INFINIPATH_HWE_SERDESPLLFAILED 0x1000000000000000ULL
#define IBA6120_IBCS_LINKTRAININGSTATE_MASK 0xf
#define IBA6120_IBCS_LINKSTATE_SHIFT 4
/* kr_extstatus bits */
#define INFINIPATH_EXTS_FREQSEL 0x2
#define INFINIPATH_EXTS_SERDESSEL 0x4
......@@ -296,6 +346,9 @@ static const struct ipath_cregs ipath_pe_cregs = {
#define IPATH_GPIO_SCL (1ULL << \
(_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
#define INFINIPATH_R_INTRAVAIL_SHIFT 16
#define INFINIPATH_R_TAILUPD_SHIFT 31
/* 6120 specific hardware errors... */
static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
INFINIPATH_HWE_MSG(PCIEPOISONEDTLP, "PCIe Poisoned TLP"),
......@@ -320,10 +373,28 @@ static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \
<< INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)
static int ipath_pe_txe_recover(struct ipath_devdata *);
static void ipath_pe_put_tid_2(struct ipath_devdata *, u64 __iomem *,
u32, unsigned long);
/*
* On platforms using this chip, and not having ordered WC stores, we
* can get TXE parity errors due to speculative reads to the PIO buffers,
* and this, due to a chip bug can result in (many) false parity error
* reports. So it's a debug print on those, and an info print on systems
* where the speculative reads don't occur.
*/
static void ipath_pe_txe_recover(struct ipath_devdata *dd)
{
if (ipath_unordered_wc())
ipath_dbg("Recovering from TXE PIO parity error\n");
else {
++ipath_stats.sps_txeparity;
dev_info(&dd->pcidev->dev,
"Recovering from TXE PIO parity error\n");
}
}
/**
* ipath_pe_handle_hwerrors - display hardware errors.
* @dd: the infinipath device
......@@ -403,35 +474,11 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
* occur if a processor speculative read is done to the PIO
* buffer while we are sending a packet, for example.
*/
if ((hwerrs & TXE_PIO_PARITY) && ipath_pe_txe_recover(dd))
if (hwerrs & TXE_PIO_PARITY) {
ipath_pe_txe_recover(dd);
hwerrs &= ~TXE_PIO_PARITY;
if (hwerrs) {
/*
* if any set that we aren't ignoring only make the
* complaint once, in case it's stuck or recurring,
* and we get here multiple times
* Force link down, so switch knows, and
* LEDs are turned off
*/
if (dd->ipath_flags & IPATH_INITTED) {
ipath_set_linkstate(dd, IPATH_IB_LINKDOWN);
ipath_setup_pe_setextled(dd,
INFINIPATH_IBCS_L_STATE_DOWN,
INFINIPATH_IBCS_LT_STATE_DISABLED);
ipath_dev_err(dd, "Fatal Hardware Error (freeze "
"mode), no longer usable, SN %.16s\n",
dd->ipath_serial);
isfatal = 1;
}
/*
* Mark as having had an error for driver, and also
* for /sys and status word mapped to user programs.
* This marks unit as not usable, until reset
*/
*dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
*dd->ipath_statusp |= IPATH_STATUS_HWERROR;
dd->ipath_flags &= ~IPATH_INITTED;
} else {
}
if (!hwerrs) {
static u32 freeze_cnt;
freeze_cnt++;
......@@ -485,7 +532,7 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) {
/*
* If it occurs, it is left masked since the eternal
* If it occurs, it is left masked since the external
* interface is unused
*/
dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED;
......@@ -563,6 +610,14 @@ static int ipath_pe_boardname(struct ipath_devdata *dd, char *name,
dd->ipath_f_put_tid = ipath_pe_put_tid_2;
}
/*
* set here, not in ipath_init_*_funcs because we have to do
* it after we can read chip registers.
*/
dd->ipath_ureg_align =
ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign);
return ret;
}
......@@ -667,17 +722,8 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
prev_val = val;
if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
val &=
~(INFINIPATH_XGXS_MDIOADDR_MASK <<
INFINIPATH_XGXS_MDIOADDR_SHIFT);
/* MDIO address 3 */
val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
}
if (val & INFINIPATH_XGXS_RESET) {
if (val & INFINIPATH_XGXS_RESET)
val &= ~INFINIPATH_XGXS_RESET;
}
if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) &
INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) {
/* need to compensate for Tx inversion in partner */
......@@ -707,21 +753,6 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
(unsigned long long)
ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
if (!ipath_waitfor_mdio_cmdready(dd)) {
ipath_write_kreg(
dd, dd->ipath_kregs->kr_mdio,
ipath_mdio_req(IPATH_MDIO_CMD_READ, 31,
IPATH_MDIO_CTRL_XGXS_REG_8, 0));
if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio,
IPATH_MDIO_DATAVALID, &val))
ipath_dbg("Never got MDIO data for XGXS "
"status read\n");
else
ipath_cdbg(VERBOSE, "MDIO Read reg8, "
"'bank' 31 %x\n", (u32) val);
} else
ipath_dbg("Never got MDIO cmdready for XGXS status read\n");
return ret;
}
......@@ -902,11 +933,26 @@ static int ipath_setup_pe_config(struct ipath_devdata *dd,
else
ipath_dev_err(dd, "Can't find PCI Express "
"capability!\n");
dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
dd->ipath_link_speed_supported = IPATH_IB_SDR;
dd->ipath_link_width_enabled = IB_WIDTH_4X;
dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported;
/* these can't change for this chip, so set once */
dd->ipath_link_width_active = dd->ipath_link_width_enabled;
dd->ipath_link_speed_active = dd->ipath_link_speed_enabled;
return 0;
}
static void ipath_init_pe_variables(struct ipath_devdata *dd)
{
/*
* setup the register offsets, since they are different for each
* chip
*/
dd->ipath_kregs = &ipath_pe_kregs;
dd->ipath_cregs = &ipath_pe_cregs;
/*
* bits for selecting i2c direction and values,
* used for I2C serial flash
......@@ -916,6 +962,43 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd)
dd->ipath_gpio_sda = IPATH_GPIO_SDA;
dd->ipath_gpio_scl = IPATH_GPIO_SCL;
/*
* Fill in data for field-values that change in newer chips.
* We dynamically specify only the mask for LINKTRAININGSTATE
* and only the shift for LINKSTATE, as they are the only ones
* that change. Also precalculate the 3 link states of interest
* and the combined mask.
*/
dd->ibcs_ls_shift = IBA6120_IBCS_LINKSTATE_SHIFT;
dd->ibcs_lts_mask = IBA6120_IBCS_LINKTRAININGSTATE_MASK;
dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK <<
dd->ibcs_ls_shift) | dd->ibcs_lts_mask;
dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
(INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift);
dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
(INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift);
dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
(INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift);
/*
* Fill in data for ibcc field-values that change in newer chips.
* We dynamically specify only the mask for LINKINITCMD
* and only the shift for LINKCMD and MAXPKTLEN, as they are
* the only ones that change.
*/
dd->ibcc_lic_mask = INFINIPATH_IBCC_LINKINITCMD_MASK;
dd->ibcc_lc_shift = INFINIPATH_IBCC_LINKCMD_SHIFT;
dd->ibcc_mpl_shift = INFINIPATH_IBCC_MAXPKTLEN_SHIFT;
/* Fill in shifts for RcvCtrl. */
dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT;
dd->ipath_r_intravail_shift = INFINIPATH_R_INTRAVAIL_SHIFT;
dd->ipath_r_tailupd_shift = INFINIPATH_R_TAILUPD_SHIFT;
dd->ipath_r_portcfg_shift = 0; /* Not on IBA6120 */
/* variables for sanity checking interrupt and errors */
dd->ipath_hwe_bitsextant =
(INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
......@@ -963,6 +1046,8 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd)
dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT;
dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT;
/*
* EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
......@@ -984,6 +1069,7 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd)
INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET;
dd->delay_mult = 2; /* SDR, 4X, can't change */
}
/* setup the MSI stuff again after a reset. I'd like to just call
......@@ -1289,6 +1375,9 @@ static int ipath_pe_early_init(struct ipath_devdata *dd)
*/
dd->ipath_rcvhdrentsize = 24;
dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE;
dd->ipath_rhf_offset = 0;
dd->ipath_egrtidbase = (u64 __iomem *)
((char __iomem *) dd->ipath_kregbase + dd->ipath_rcvegrbase);
/*
* To truly support a 4KB MTU (for usermode), we need to
......@@ -1359,34 +1448,204 @@ static void ipath_pe_free_irq(struct ipath_devdata *dd)
dd->ipath_irq = 0;
}
static struct ipath_message_header *
ipath_pe_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr)
{
return (struct ipath_message_header *)
&rhf_addr[sizeof(u64) / sizeof(u32)];
}
static void ipath_pe_config_ports(struct ipath_devdata *dd, ushort cfgports)
{
dd->ipath_portcnt =
ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
dd->ipath_p0_rcvegrcnt =
ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt);
}
static void ipath_pe_read_counters(struct ipath_devdata *dd,
struct infinipath_counters *cntrs)
{
cntrs->LBIntCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBIntCnt));
cntrs->LBFlowStallCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBFlowStallCnt));
cntrs->TxSDmaDescCnt = 0;
cntrs->TxUnsupVLErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnsupVLErrCnt));
cntrs->TxDataPktCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDataPktCnt));
cntrs->TxFlowPktCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowPktCnt));
cntrs->TxDwordCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDwordCnt));
cntrs->TxLenErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxLenErrCnt));
cntrs->TxMaxMinLenErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxMaxMinLenErrCnt));
cntrs->TxUnderrunCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnderrunCnt));
cntrs->TxFlowStallCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowStallCnt));
cntrs->TxDroppedPktCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDroppedPktCnt));
cntrs->RxDroppedPktCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDroppedPktCnt));
cntrs->RxDataPktCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDataPktCnt));
cntrs->RxFlowPktCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowPktCnt));
cntrs->RxDwordCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDwordCnt));
cntrs->RxLenErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLenErrCnt));
cntrs->RxMaxMinLenErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxMaxMinLenErrCnt));
cntrs->RxICRCErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxICRCErrCnt));
cntrs->RxVCRCErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxVCRCErrCnt));
cntrs->RxFlowCtrlErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowCtrlErrCnt));
cntrs->RxBadFormatCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBadFormatCnt));
cntrs->RxLinkProblemCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLinkProblemCnt));
cntrs->RxEBPCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxEBPCnt));
cntrs->RxLPCRCErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLPCRCErrCnt));
cntrs->RxBufOvflCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBufOvflCnt));
cntrs->RxTIDFullErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDFullErrCnt));
cntrs->RxTIDValidErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDValidErrCnt));
cntrs->RxPKeyMismatchCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxPKeyMismatchCnt));
cntrs->RxP0HdrEgrOvflCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt));
cntrs->RxP1HdrEgrOvflCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt));
cntrs->RxP2HdrEgrOvflCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt));
cntrs->RxP3HdrEgrOvflCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt));
cntrs->RxP4HdrEgrOvflCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt));
cntrs->RxP5HdrEgrOvflCnt = 0;
cntrs->RxP6HdrEgrOvflCnt = 0;
cntrs->RxP7HdrEgrOvflCnt = 0;
cntrs->RxP8HdrEgrOvflCnt = 0;
cntrs->RxP9HdrEgrOvflCnt = 0;
cntrs->RxP10HdrEgrOvflCnt = 0;
cntrs->RxP11HdrEgrOvflCnt = 0;
cntrs->RxP12HdrEgrOvflCnt = 0;
cntrs->RxP13HdrEgrOvflCnt = 0;
cntrs->RxP14HdrEgrOvflCnt = 0;
cntrs->RxP15HdrEgrOvflCnt = 0;
cntrs->RxP16HdrEgrOvflCnt = 0;
cntrs->IBStatusChangeCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBStatusChangeCnt));
cntrs->IBLinkErrRecoveryCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt));
cntrs->IBLinkDownedCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkDownedCnt));
cntrs->IBSymbolErrCnt =
ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBSymbolErrCnt));
cntrs->RxVL15DroppedPktCnt = 0;
cntrs->RxOtherLocalPhyErrCnt = 0;
cntrs->PcieRetryBufDiagQwordCnt = 0;
cntrs->ExcessBufferOvflCnt = dd->ipath_overrun_thresh_errs;
cntrs->LocalLinkIntegrityErrCnt = dd->ipath_lli_errs;
cntrs->RxVlErrCnt = 0;
cntrs->RxDlidFltrCnt = 0;
}
/* no interrupt fallback for these chips */
static int ipath_pe_nointr_fallback(struct ipath_devdata *dd)
{
return 0;
}
/*
* On platforms using this chip, and not having ordered WC stores, we
* can get TXE parity errors due to speculative reads to the PIO buffers,
* and this, due to a chip bug can result in (many) false parity error
* reports. So it's a debug print on those, and an info print on systems
* where the speculative reads don't occur.
* Because we can get lots of false errors, we have no upper limit
* on recovery attempts on those platforms.
* reset the XGXS (between serdes and IBC). Slightly less intrusive
* than resetting the IBC or external link state, and useful in some
* cases to cause some retraining. To do this right, we reset IBC
* as well.
*/
static int ipath_pe_txe_recover(struct ipath_devdata *dd)
static void ipath_pe_xgxs_reset(struct ipath_devdata *dd)
{
if (ipath_unordered_wc())
ipath_dbg("Recovering from TXE PIO parity error\n");
else {
int cnt = ++ipath_stats.sps_txeparity;
if (cnt >= IPATH_MAX_PARITY_ATTEMPTS) {
if (cnt == IPATH_MAX_PARITY_ATTEMPTS)
ipath_dev_err(dd,
"Too many attempts to recover from "
"TXE parity, giving up\n");
return 0;
}
dev_info(&dd->pcidev->dev,
"Recovering from TXE PIO parity error\n");
u64 val, prev_val;
prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
val = prev_val | INFINIPATH_XGXS_RESET;
prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */
ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
dd->ipath_control & ~INFINIPATH_C_LINKENABLE);
ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val);
ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
dd->ipath_control);
}
static int ipath_pe_get_ib_cfg(struct ipath_devdata *dd, int which)
{
int ret;
switch (which) {
case IPATH_IB_CFG_LWID:
ret = dd->ipath_link_width_active;
break;
case IPATH_IB_CFG_SPD:
ret = dd->ipath_link_speed_active;
break;
case IPATH_IB_CFG_LWID_ENB:
ret = dd->ipath_link_width_enabled;
break;
case IPATH_IB_CFG_SPD_ENB:
ret = dd->ipath_link_speed_enabled;
break;
default:
ret = -ENOTSUPP;
break;
}
return 1;
return ret;
}
/* we assume range checking is already done, if needed */
static int ipath_pe_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val)
{
int ret = 0;
if (which == IPATH_IB_CFG_LWID_ENB)
dd->ipath_link_width_enabled = val;
else if (which == IPATH_IB_CFG_SPD_ENB)
dd->ipath_link_speed_enabled = val;
else
ret = -ENOTSUPP;
return ret;
}
static void ipath_pe_config_jint(struct ipath_devdata *dd, u16 a, u16 b)
{
}
static int ipath_pe_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
{
ipath_setup_pe_setextled(dd, ipath_ib_linkstate(dd, ibcs),
ipath_ib_linktrstate(dd, ibcs));
return 0;
}
/**
* ipath_init_iba6120_funcs - set up the chip-specific function pointers
* @dd: the infinipath device
......@@ -1407,7 +1666,7 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd)
dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes;
dd->ipath_f_clear_tids = ipath_pe_clear_tids;
/*
* this may get changed after we read the chip revision,
* _f_put_tid may get changed after we read the chip revision,
* but we start with the safe version for all revs
*/
dd->ipath_f_put_tid = ipath_pe_put_tid;
......@@ -1415,17 +1674,19 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd)
dd->ipath_f_setextled = ipath_setup_pe_setextled;
dd->ipath_f_get_base_info = ipath_pe_get_base_info;
dd->ipath_f_free_irq = ipath_pe_free_irq;
/* initialize chip-specific variables */
dd->ipath_f_tidtemplate = ipath_pe_tidtemplate;
dd->ipath_f_intr_fallback = ipath_pe_nointr_fallback;
dd->ipath_f_xgxs_reset = ipath_pe_xgxs_reset;
dd->ipath_f_get_msgheader = ipath_pe_get_msgheader;
dd->ipath_f_config_ports = ipath_pe_config_ports;
dd->ipath_f_read_counters = ipath_pe_read_counters;
dd->ipath_f_get_ib_cfg = ipath_pe_get_ib_cfg;
dd->ipath_f_set_ib_cfg = ipath_pe_set_ib_cfg;
dd->ipath_f_config_jint = ipath_pe_config_jint;
dd->ipath_f_ib_updown = ipath_pe_ib_updown;
/*
* setup the register offsets, since they are different for each
* chip
*/
dd->ipath_kregs = &ipath_pe_kregs;
dd->ipath_cregs = &ipath_pe_cregs;
/* initialize chip-specific variables */
ipath_init_pe_variables(dd);
}
......@@ -91,7 +91,7 @@ static int create_port0_egr(struct ipath_devdata *dd)
struct ipath_skbinfo *skbinfo;
int ret;
egrcnt = dd->ipath_rcvegrcnt;
egrcnt = dd->ipath_p0_rcvegrcnt;
skbinfo = vmalloc(sizeof(*dd->ipath_port0_skbinfo) * egrcnt);
if (skbinfo == NULL) {
......@@ -244,8 +244,7 @@ static int init_chip_first(struct ipath_devdata *dd,
* cfgports. We do still check and report a difference, if
* not same (should be impossible).
*/
dd->ipath_portcnt =
ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
dd->ipath_f_config_ports(dd, ipath_cfgports);
if (!ipath_cfgports)
dd->ipath_cfgports = dd->ipath_portcnt;
else if (ipath_cfgports <= dd->ipath_portcnt) {
......@@ -272,22 +271,7 @@ static int init_chip_first(struct ipath_devdata *dd,
goto done;
}
dd->ipath_lastegrheads = kzalloc(sizeof(*dd->ipath_lastegrheads)
* dd->ipath_cfgports,
GFP_KERNEL);
dd->ipath_lastrcvhdrqtails =
kzalloc(sizeof(*dd->ipath_lastrcvhdrqtails)
* dd->ipath_cfgports, GFP_KERNEL);
if (!dd->ipath_lastegrheads || !dd->ipath_lastrcvhdrqtails) {
ipath_dev_err(dd, "Unable to allocate head arrays, "
"failing\n");
ret = -ENOMEM;
goto done;
}
pd = create_portdata0(dd);
if (!pd) {
ipath_dev_err(dd, "Unable to allocate portdata for port "
"0, failing\n");
......@@ -345,10 +329,10 @@ static int init_chip_first(struct ipath_devdata *dd,
dd->ipath_piobcnt2k, dd->ipath_pio2kbase);
spin_lock_init(&dd->ipath_tid_lock);
spin_lock_init(&dd->ipath_sendctrl_lock);
spin_lock_init(&dd->ipath_gpio_lock);
spin_lock_init(&dd->ipath_eep_st_lock);
sema_init(&dd->ipath_eep_sem, 1);
mutex_init(&dd->ipath_eep_lock);
done:
*pdp = pd;
......@@ -372,9 +356,9 @@ static int init_chip_reset(struct ipath_devdata *dd,
*pdp = dd->ipath_pd[0];
/* ensure chip does no sends or receives while we re-initialize */
dd->ipath_control = dd->ipath_sendctrl = dd->ipath_rcvctrl = 0U;
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, 0);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0);
ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0);
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
ipath_write_kreg(dd, dd->ipath_kregs->kr_control, dd->ipath_control);
rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
if (dd->ipath_portcnt != rtmp)
......@@ -487,6 +471,7 @@ static void enable_chip(struct ipath_devdata *dd,
struct ipath_portdata *pd, int reinit)
{
u32 val;
unsigned long flags;
int i;
if (!reinit)
......@@ -495,19 +480,21 @@ static void enable_chip(struct ipath_devdata *dd,
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
dd->ipath_rcvctrl);
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
/* Enable PIO send, and update of PIOavail regs to memory. */
dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE |
INFINIPATH_S_PIOBUFAVAILUPD;
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
/*
* enable port 0 receive, and receive interrupt. other ports
* done as user opens and inits them.
*/
dd->ipath_rcvctrl = INFINIPATH_R_TAILUPD |
(1ULL << INFINIPATH_R_PORTENABLE_SHIFT) |
(1ULL << INFINIPATH_R_INTRAVAIL_SHIFT);
dd->ipath_rcvctrl = (1ULL << dd->ipath_r_tailupd_shift) |
(1ULL << dd->ipath_r_portenable_shift) |
(1ULL << dd->ipath_r_intravail_shift);
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
dd->ipath_rcvctrl);
......@@ -523,12 +510,11 @@ static void enable_chip(struct ipath_devdata *dd,
*/
val = ipath_read_ureg32(dd, ur_rcvegrindextail, 0);
(void)ipath_write_ureg(dd, ur_rcvegrindexhead, val, 0);
dd->ipath_port0head = ipath_read_ureg32(dd, ur_rcvhdrtail, 0);
/* Initialize so we interrupt on next packet received */
(void)ipath_write_ureg(dd, ur_rcvhdrhead,
dd->ipath_rhdrhead_intr_off |
dd->ipath_port0head, 0);
dd->ipath_pd[0]->port_head, 0);
/*
* by now pioavail updates to memory should have occurred, so
......@@ -542,12 +528,8 @@ static void enable_chip(struct ipath_devdata *dd,
/*
* Chip Errata bug 6641; even and odd qwords>3 are swapped.
*/
if (i > 3) {
if (i & 1)
val = dd->ipath_pioavailregs_dma[i - 1];
else
val = dd->ipath_pioavailregs_dma[i + 1];
}
if (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS))
val = dd->ipath_pioavailregs_dma[i ^ 1];
else
val = dd->ipath_pioavailregs_dma[i];
dd->ipath_pioavailshadow[i] = le64_to_cpu(val);
......@@ -690,12 +672,13 @@ static int init_housekeeping(struct ipath_devdata *dd,
*/
int ipath_init_chip(struct ipath_devdata *dd, int reinit)
{
int ret = 0, i;
int ret = 0;
u32 val32, kpiobufs;
u32 piobufs, uports;
u64 val;
struct ipath_portdata *pd = NULL; /* keep gcc4 happy */
gfp_t gfp_flags = GFP_USER | __GFP_COMP;
unsigned long flags;
ret = init_housekeeping(dd, &pd, reinit);
if (ret)
......@@ -746,7 +729,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
kpiobufs = ipath_kpiobufs;
if (kpiobufs + (uports * IPATH_MIN_USER_PORT_BUFCNT) > piobufs) {
i = (int) piobufs -
int i = (int) piobufs -
(int) (uports * IPATH_MIN_USER_PORT_BUFCNT);
if (i < 0)
i = 0;
......@@ -827,8 +810,12 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
~0ULL&~INFINIPATH_HWE_MEMBISTFAILED);
ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0ULL);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
INFINIPATH_S_PIOENABLE);
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE;
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
/*
* before error clears, since we expect serdes pll errors during
......
......@@ -683,7 +683,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
for (i = 0; i < dd->ipath_cfgports; i++) {
struct ipath_portdata *pd = dd->ipath_pd[i];
if (i == 0) {
hd = dd->ipath_port0head;
hd = pd->port_head;
tl = (u32) le64_to_cpu(
*dd->ipath_hdrqtailptr);
} else if (pd && pd->port_cnt &&
......@@ -693,7 +693,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
* except kernel
*/
tl = *(u64 *) pd->port_rcvhdrtail_kvaddr;
if (tl == dd->ipath_lastrcvhdrqtails[i])
if (tl == pd->port_lastrcvhdrqtail)
continue;
hd = ipath_read_ureg32(dd, ur_rcvhdrhead,
i);
......@@ -703,7 +703,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
(!hd && tl == dd->ipath_hdrqlast)) {
if (i == 0)
chkerrpkts = 1;
dd->ipath_lastrcvhdrqtails[i] = tl;
pd->port_lastrcvhdrqtail = tl;
pd->port_hdrqfull++;
/* flush hdrqfull so that poll() sees it */
wmb();
......@@ -712,6 +712,8 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
}
}
if (errs & INFINIPATH_E_RRCVEGRFULL) {
struct ipath_portdata *pd = dd->ipath_pd[0];
/*
* since this is of less importance and not likely to
* happen without also getting hdrfull, only count
......@@ -719,7 +721,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
* vs user)
*/
ipath_stats.sps_etidfull++;
if (dd->ipath_port0head !=
if (pd->port_head !=
(u32) le64_to_cpu(*dd->ipath_hdrqtailptr))
chkerrpkts = 1;
}
......@@ -795,6 +797,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
{
int i, im;
__le64 val;
unsigned long flags;
/* disable error interrupts, to avoid confusion */
ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL);
......@@ -813,11 +816,14 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
dd->ipath_control);
/* ensure pio avail updates continue */
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD);
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl);
dd->ipath_sendctrl);
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
/*
* We just enabled pioavailupdate, so dma copy is almost certainly
......@@ -825,8 +831,8 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
*/
for (i = 0; i < dd->ipath_pioavregs; i++) {
/* deal with 6110 chip bug */
im = i > 3 ? ((i&1) ? i-1 : i+1) : i;
val = ipath_read_kreg64(dd, (0x1000/sizeof(u64))+im);
im = i > 3 ? i ^ 1 : i;
val = ipath_read_kreg64(dd, (0x1000 / sizeof(u64)) + im);
dd->ipath_pioavailregs_dma[i] = dd->ipath_pioavailshadow[i]
= le64_to_cpu(val);
}
......@@ -849,7 +855,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
/* this is separate to allow for better optimization of ipath_intr() */
static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
static noinline void ipath_bad_intr(struct ipath_devdata *dd, u32 *unexpectp)
{
/*
* sometimes happen during driver init and unload, don't want
......@@ -877,7 +883,7 @@ static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
dd->ipath_f_free_irq(dd);
}
}
if (ipath_read_kreg32(dd, dd->ipath_kregs->kr_intmask)) {
if (ipath_read_ireg(dd, dd->ipath_kregs->kr_intmask)) {
ipath_dev_err(dd, "%u unexpected interrupts, "
"disabling interrupts completely\n",
*unexpectp);
......@@ -892,7 +898,7 @@ static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
"ignoring\n");
}
static void ipath_bad_regread(struct ipath_devdata *dd)
static noinline void ipath_bad_regread(struct ipath_devdata *dd)
{
static int allbits;
......@@ -920,31 +926,9 @@ static void ipath_bad_regread(struct ipath_devdata *dd)
}
}
static void handle_port_pioavail(struct ipath_devdata *dd)
{
u32 i;
/*
* start from port 1, since for now port 0 is never using
* wait_event for PIO
*/
for (i = 1; dd->ipath_portpiowait && i < dd->ipath_cfgports; i++) {
struct ipath_portdata *pd = dd->ipath_pd[i];
if (pd && pd->port_cnt &&
dd->ipath_portpiowait & (1U << i)) {
clear_bit(i, &dd->ipath_portpiowait);
if (test_bit(IPATH_PORT_WAITING_PIO,
&pd->port_flag)) {
clear_bit(IPATH_PORT_WAITING_PIO,
&pd->port_flag);
wake_up_interruptible(&pd->port_wait);
}
}
}
}
static void handle_layer_pioavail(struct ipath_devdata *dd)
{
unsigned long flags;
int ret;
ret = ipath_ib_piobufavail(dd->verbs_dev);
......@@ -953,9 +937,12 @@ static void handle_layer_pioavail(struct ipath_devdata *dd)
return;
set:
set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL;
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl);
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
}
/*
......@@ -969,7 +956,15 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
int i;
int rcvdint = 0;
/* test_bit below needs this... */
/*
* test_and_clear_bit(IPATH_PORT_WAITING_RCV) and
* test_and_clear_bit(IPATH_PORT_WAITING_URG) below
* would both like timely updates of the bits so that
* we don't pass them by unnecessarily. the rmb()
* here ensures that we see them promptly -- the
* corresponding wmb()'s are in ipath_poll_urgent()
* and ipath_poll_next()...
*/
rmb();
portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) &
dd->ipath_i_rcvavail_mask)
......@@ -980,7 +975,7 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
if (portr & (1 << i) && pd && pd->port_cnt) {
if (test_and_clear_bit(IPATH_PORT_WAITING_RCV,
&pd->port_flag)) {
clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT,
clear_bit(i + dd->ipath_r_intravail_shift,
&dd->ipath_rcvctrl);
wake_up_interruptible(&pd->port_wait);
rcvdint = 1;
......@@ -1039,7 +1034,7 @@ irqreturn_t ipath_intr(int irq, void *data)
goto bail;
}
istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus);
istat = ipath_read_ireg(dd, dd->ipath_kregs->kr_intstatus);
if (unlikely(!istat)) {
ipath_stats.sps_nullintr++;
......@@ -1180,7 +1175,7 @@ irqreturn_t ipath_intr(int irq, void *data)
* for receive are at the bottom.
*/
if (chk0rcv) {
ipath_kreceive(dd);
ipath_kreceive(dd->ipath_pd[0]);
istat &= ~port0rbits;
}
......@@ -1191,12 +1186,14 @@ irqreturn_t ipath_intr(int irq, void *data)
handle_urcv(dd, istat);
if (istat & INFINIPATH_I_SPIOBUFAVAIL) {
clear_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
unsigned long flags;
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
dd->ipath_sendctrl &= ~INFINIPATH_S_PIOINTBUFAVAIL;
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl);
if (dd->ipath_portpiowait)
handle_port_pioavail(dd);
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
handle_layer_pioavail(dd);
}
......
......@@ -41,6 +41,7 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/mutex.h>
#include <asm/io.h>
#include <rdma/ib_verbs.h>
......@@ -140,6 +141,11 @@ struct ipath_portdata {
u32 port_pionowait;
/* total number of rcvhdrqfull errors */
u32 port_hdrqfull;
/*
* Used to suppress multiple instances of same
* port staying stuck at same point.
*/
u32 port_lastrcvhdrqtail;
/* saved total number of rcvhdrqfull errors for poll edge trigger */
u32 port_hdrqfull_poll;
/* total number of polled urgent packets */
......@@ -148,6 +154,7 @@ struct ipath_portdata {
u32 port_urgent_poll;
/* pid of process using this port */
pid_t port_pid;
pid_t port_subpid[INFINIPATH_MAX_SUBPORT];
/* same size as task_struct .comm[] */
char port_comm[16];
/* pkeys set by this use of this port */
......@@ -166,6 +173,8 @@ struct ipath_portdata {
u32 active_slaves;
/* Type of packets or conditions we want to poll for */
u16 poll_type;
/* port rcvhdrq head offset */
u32 port_head;
};
struct sk_buff;
......@@ -182,6 +191,22 @@ struct ipath_skbinfo {
dma_addr_t phys;
};
/*
* Possible IB config parameters for ipath_f_get/set_ib_cfg()
*/
#define IPATH_IB_CFG_LIDLMC 0 /* Get/set LID (LS16b) and Mask (MS16b) */
#define IPATH_IB_CFG_HRTBT 1 /* Get/set Heartbeat off/enable/auto */
#define IPATH_IB_HRTBT_ON 3 /* Heartbeat enabled, sent every 100msec */
#define IPATH_IB_HRTBT_OFF 0 /* Heartbeat off */
#define IPATH_IB_CFG_LWID_ENB 2 /* Get/set allowed Link-width */
#define IPATH_IB_CFG_LWID 3 /* Get currently active Link-width */
#define IPATH_IB_CFG_SPD_ENB 4 /* Get/set allowed Link speeds */
#define IPATH_IB_CFG_SPD 5 /* Get current Link spd */
#define IPATH_IB_CFG_RXPOL_ENB 6 /* Get/set Auto-RX-polarity enable */
#define IPATH_IB_CFG_LREV_ENB 7 /* Get/set Auto-Lane-reversal enable */
#define IPATH_IB_CFG_LINKLATENCY 8 /* Get Auto-Lane-reversal enable */
struct ipath_devdata {
struct list_head ipath_list;
......@@ -222,6 +247,8 @@ struct ipath_devdata {
struct _ipath_layer ipath_layer;
/* setup intr */
int (*ipath_f_intrsetup)(struct ipath_devdata *);
/* fallback to alternate interrupt type if possible */
int (*ipath_f_intr_fallback)(struct ipath_devdata *);
/* setup on-chip bus config */
int (*ipath_f_bus)(struct ipath_devdata *, struct pci_dev *);
/* hard reset chip */
......@@ -244,6 +271,18 @@ struct ipath_devdata {
int (*ipath_f_get_base_info)(struct ipath_portdata *, void *);
/* free irq */
void (*ipath_f_free_irq)(struct ipath_devdata *);
struct ipath_message_header *(*ipath_f_get_msgheader)
(struct ipath_devdata *, __le32 *);
void (*ipath_f_config_ports)(struct ipath_devdata *, ushort);
int (*ipath_f_get_ib_cfg)(struct ipath_devdata *, int);
int (*ipath_f_set_ib_cfg)(struct ipath_devdata *, int, u32);
void (*ipath_f_config_jint)(struct ipath_devdata *, u16 , u16);
void (*ipath_f_read_counters)(struct ipath_devdata *,
struct infinipath_counters *);
void (*ipath_f_xgxs_reset)(struct ipath_devdata *);
/* per chip actions needed for IB Link up/down changes */
int (*ipath_f_ib_updown)(struct ipath_devdata *, int, u64);
struct ipath_ibdev *verbs_dev;
struct timer_list verbs_timer;
/* total dwords sent (summed from counter) */
......@@ -313,21 +352,11 @@ struct ipath_devdata {
* supports, less gives more pio bufs/port, etc.
*/
u32 ipath_cfgports;
/* port0 rcvhdrq head offset */
u32 ipath_port0head;
/* count of port 0 hdrqfull errors */
u32 ipath_p0_hdrqfull;
/* port 0 number of receive eager buffers */
u32 ipath_p0_rcvegrcnt;
/*
* (*cfgports) used to suppress multiple instances of same
* port staying stuck at same point
*/
u32 *ipath_lastrcvhdrqtails;
/*
* (*cfgports) used to suppress multiple instances of same
* port staying stuck at same point
*/
u32 *ipath_lastegrheads;
/*
* index of last piobuffer we used. Speeds up searching, by
* starting at this point. Doesn't matter if multiple cpu's use and
......@@ -367,14 +396,15 @@ struct ipath_devdata {
unsigned long ipath_wc_len;
/* ref count for each pkey */
atomic_t ipath_pkeyrefs[4];
/* shadow copy of all exptids physaddr; used only by funcsim */
u64 *ipath_tidsimshadow;
/* shadow copy of struct page *'s for exp tid pages */
struct page **ipath_pageshadow;
/* shadow copy of dma handles for exp tid pages */
dma_addr_t *ipath_physshadow;
/* lock to workaround chip bug 9437 */
u64 __iomem *ipath_egrtidbase;
/* lock to workaround chip bug 9437 and others */
spinlock_t ipath_kernel_tid_lock;
spinlock_t ipath_tid_lock;
spinlock_t ipath_sendctrl_lock;
/*
* IPATH_STATUS_*,
......@@ -395,6 +425,8 @@ struct ipath_devdata {
void *ipath_dummy_hdrq; /* used after port close */
dma_addr_t ipath_dummy_hdrq_phys;
unsigned long ipath_ureg_align; /* user register alignment */
/*
* Shadow copies of registers; size indicates read access size.
* Most of them are readonly, but some are write-only register,
......@@ -456,8 +488,6 @@ struct ipath_devdata {
unsigned long ipath_rcvctrl;
/* shadow kr_sendctrl */
unsigned long ipath_sendctrl;
/* ports waiting for PIOavail intr */
unsigned long ipath_portpiowait;
unsigned long ipath_lastcancel; /* to not count armlaunch after cancel */
/* value we put in kr_rcvhdrcnt */
......@@ -550,12 +580,26 @@ struct ipath_devdata {
u8 ipath_minrev;
/* board rev, from ipath_revision */
u8 ipath_boardrev;
u8 ipath_r_portenable_shift;
u8 ipath_r_intravail_shift;
u8 ipath_r_tailupd_shift;
u8 ipath_r_portcfg_shift;
/* unit # of this chip, if present */
int ipath_unit;
/* saved for restore after reset */
u8 ipath_pci_cacheline;
/* LID mask control */
u8 ipath_lmc;
/* link width supported */
u8 ipath_link_width_supported;
/* link speed supported */
u8 ipath_link_speed_supported;
u8 ipath_link_width_enabled;
u8 ipath_link_speed_enabled;
u8 ipath_link_width_active;
u8 ipath_link_speed_active;
/* Rx Polarity inversion (compensate for ~tx on partner) */
u8 ipath_rx_pol_inv;
......@@ -590,6 +634,8 @@ struct ipath_devdata {
*/
u32 ipath_i_rcvavail_mask;
u32 ipath_i_rcvurg_mask;
u16 ipath_i_rcvurg_shift;
u16 ipath_i_rcvavail_shift;
/*
* Register bits for selecting i2c direction and values, used for
......@@ -603,6 +649,29 @@ struct ipath_devdata {
/* lock for doing RMW of shadows/regs for ExtCtrl and GPIO */
spinlock_t ipath_gpio_lock;
/*
* IB link and linktraining states and masks that vary per chip in
* some way. Set at init, to avoid each IB status change interrupt
*/
u8 ibcs_ls_shift;
u8 ibcs_lts_mask;
u32 ibcs_mask;
u32 ib_init;
u32 ib_arm;
u32 ib_active;
u16 ipath_rhf_offset; /* offset of RHF within receive header entry */
/*
* shift/mask for linkcmd, linkinitcmd, maxpktlen in ibccontol
* reg. Changes for IBA7220
*/
u8 ibcc_lic_mask; /* LinkInitCmd */
u8 ibcc_lc_shift; /* LinkCmd */
u8 ibcc_mpl_shift; /* Maxpktlen */
u8 delay_mult;
/* used to override LED behavior */
u8 ipath_led_override; /* Substituted for normal value, if non-zero */
u16 ipath_led_override_timeoff; /* delta to next timer event */
......@@ -616,7 +685,7 @@ struct ipath_devdata {
/* control access to actual counters, timer */
spinlock_t ipath_eep_st_lock;
/* control high-level access to EEPROM */
struct semaphore ipath_eep_sem;
struct mutex ipath_eep_lock;
/* Below inc'd by ipath_snap_cntrs(), locked by ipath_eep_st_lock */
uint64_t ipath_traffic_wds;
/* active time is kept in seconds, but logged in hours */
......@@ -630,6 +699,10 @@ struct ipath_devdata {
* each of the counters to increment.
*/
struct ipath_eep_log_mask ipath_eep_st_masks[IPATH_EEP_LOG_CNT];
/* interrupt mitigation reload register info */
u16 ipath_jint_idle_ticks; /* idle clock ticks */
u16 ipath_jint_max_packets; /* max packets across all ports */
};
/* Private data for file operations */
......@@ -690,7 +763,7 @@ void ipath_free_pddata(struct ipath_devdata *, struct ipath_portdata *);
int ipath_parse_ushort(const char *str, unsigned short *valp);
void ipath_kreceive(struct ipath_devdata *);
void ipath_kreceive(struct ipath_portdata *);
int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned);
int ipath_reset_device(int);
void ipath_get_faststats(unsigned long);
......@@ -698,6 +771,8 @@ int ipath_set_linkstate(struct ipath_devdata *, u8);
int ipath_set_mtu(struct ipath_devdata *, u16);
int ipath_set_lid(struct ipath_devdata *, u32, u8);
int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
void ipath_enable_armlaunch(struct ipath_devdata *);
void ipath_disable_armlaunch(struct ipath_devdata *);
/* for use in system calls, where we want to know device type, etc. */
#define port_fp(fp) ((struct ipath_filedata *)(fp)->private_data)->pd
......@@ -744,9 +819,15 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
* are 64bit */
#define IPATH_32BITCOUNTERS 0x20000
/* can miss port0 rx interrupts */
/* Interrupt register is 64 bits */
#define IPATH_INTREG_64 0x40000
#define IPATH_DISABLED 0x80000 /* administratively disabled */
/* Use GPIO interrupts for new counters */
#define IPATH_GPIO_ERRINTRS 0x100000
#define IPATH_SWAP_PIOBUFS 0x200000
/* Suppress heartbeat, even if turning off loopback */
#define IPATH_NO_HRTBT 0x1000000
#define IPATH_HAS_MULT_IB_SPEED 0x8000000
/* Bits in GPIO for the added interrupts */
#define IPATH_GPIO_PORT0_BIT 2
......@@ -758,8 +839,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
/* portdata flag bit offsets */
/* waiting for a packet to arrive */
#define IPATH_PORT_WAITING_RCV 2
/* waiting for a PIO buffer to be available */
#define IPATH_PORT_WAITING_PIO 3
/* master has not finished initializing */
#define IPATH_PORT_MASTER_UNINIT 4
/* waiting for an urgent packet to arrive */
......@@ -767,8 +846,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
/* free up any allocated data at closes */
void ipath_free_data(struct ipath_portdata *dd);
int ipath_waitfor_mdio_cmdready(struct ipath_devdata *);
int ipath_waitfor_complete(struct ipath_devdata *, ipath_kreg, u64, u64 *);
u32 __iomem *ipath_getpiobuf(struct ipath_devdata *, u32 *);
void ipath_init_iba6120_funcs(struct ipath_devdata *);
void ipath_init_iba6110_funcs(struct ipath_devdata *);
......@@ -792,33 +869,6 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val);
*/
#define IPATH_DFLT_RCVHDRSIZE 9
#define IPATH_MDIO_CMD_WRITE 1
#define IPATH_MDIO_CMD_READ 2
#define IPATH_MDIO_CLD_DIV 25 /* to get 2.5 Mhz mdio clock */
#define IPATH_MDIO_CMDVALID 0x40000000 /* bit 30 */
#define IPATH_MDIO_DATAVALID 0x80000000 /* bit 31 */
#define IPATH_MDIO_CTRL_STD 0x0
static inline u64 ipath_mdio_req(int cmd, int dev, int reg, int data)
{
return (((u64) IPATH_MDIO_CLD_DIV) << 32) |
(cmd << 26) |
(dev << 21) |
(reg << 16) |
(data & 0xFFFF);
}
/* signal and fifo status, in bank 31 */
#define IPATH_MDIO_CTRL_XGXS_REG_8 0x8
/* controls loopback, redundancy */
#define IPATH_MDIO_CTRL_8355_REG_1 0x10
/* premph, encdec, etc. */
#define IPATH_MDIO_CTRL_8355_REG_2 0x11
/* Kchars, etc. */
#define IPATH_MDIO_CTRL_8355_REG_6 0x15
#define IPATH_MDIO_CTRL_8355_REG_9 0x18
#define IPATH_MDIO_CTRL_8355_REG_10 0x1D
int ipath_get_user_pages(unsigned long, size_t, struct page **);
void ipath_release_user_pages(struct page **, size_t);
void ipath_release_user_pages_on_close(struct page **, size_t);
......@@ -863,7 +913,7 @@ static inline u32 ipath_read_ureg32(const struct ipath_devdata *dd,
return readl(regno + (u64 __iomem *)
(dd->ipath_uregbase +
(char __iomem *)dd->ipath_kregbase +
dd->ipath_palign * port));
dd->ipath_ureg_align * port));
}
/**
......@@ -880,7 +930,7 @@ static inline void ipath_write_ureg(const struct ipath_devdata *dd,
{
u64 __iomem *ubase = (u64 __iomem *)
(dd->ipath_uregbase + (char __iomem *) dd->ipath_kregbase +
dd->ipath_palign * port);
dd->ipath_ureg_align * port);
if (dd->ipath_kregbase)
writeq(value, &ubase[regno]);
}
......@@ -930,6 +980,53 @@ static inline u32 ipath_read_creg32(const struct ipath_devdata *dd,
(char __iomem *)dd->ipath_kregbase));
}
static inline void ipath_write_creg(const struct ipath_devdata *dd,
ipath_creg regno, u64 value)
{
if (dd->ipath_kregbase)
writeq(value, regno + (u64 __iomem *)
(dd->ipath_cregbase +
(char __iomem *)dd->ipath_kregbase));
}
static inline void ipath_clear_rcvhdrtail(const struct ipath_portdata *pd)
{
*((u64 *) pd->port_rcvhdrtail_kvaddr) = 0ULL;
}
static inline u32 ipath_get_rcvhdrtail(const struct ipath_portdata *pd)
{
return (u32) le64_to_cpu(*((volatile __le64 *)
pd->port_rcvhdrtail_kvaddr));
}
static inline u64 ipath_read_ireg(const struct ipath_devdata *dd, ipath_kreg r)
{
return (dd->ipath_flags & IPATH_INTREG_64) ?
ipath_read_kreg64(dd, r) : ipath_read_kreg32(dd, r);
}
/*
* from contents of IBCStatus (or a saved copy), return linkstate
* Report ACTIVE_DEFER as ACTIVE, because we treat them the same
* everywhere, anyway (and should be, for almost all purposes).
*/
static inline u32 ipath_ib_linkstate(struct ipath_devdata *dd, u64 ibcs)
{
u32 state = (u32)(ibcs >> dd->ibcs_ls_shift) &
INFINIPATH_IBCS_LINKSTATE_MASK;
if (state == INFINIPATH_IBCS_L_STATE_ACT_DEFER)
state = INFINIPATH_IBCS_L_STATE_ACTIVE;
return state;
}
/* from contents of IBCStatus (or a saved copy), return linktrainingstate */
static inline u32 ipath_ib_linktrstate(struct ipath_devdata *dd, u64 ibcs)
{
return (u32)(ibcs >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
dd->ibcs_lts_mask;
}
/*
* sysfs interface.
*/
......
......@@ -128,9 +128,8 @@ int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge,
int ret;
/*
* We use LKEY == zero to mean a physical kmalloc() address.
* This is a bit of a hack since we rely on dma_map_single()
* being reversible by calling bus_to_virt().
* We use LKEY == zero for kernel virtual addresses
* (see ipath_get_dma_mr and ipath_dma.c).
*/
if (sge->lkey == 0) {
struct ipath_pd *pd = to_ipd(qp->ibqp.pd);
......
......@@ -387,8 +387,8 @@ int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
struct ib_wc wc;
int ret = 0;
ipath_dbg("QP%d/%d in error state\n",
qp->ibqp.qp_num, qp->remote_qpn);
ipath_dbg("QP%d/%d in error state (%d)\n",
qp->ibqp.qp_num, qp->remote_qpn, err);
spin_lock(&dev->pending_lock);
/* XXX What if its already removed by the timeout code? */
......@@ -855,8 +855,6 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
* See ipath_mmap() for details.
*/
if (udata && udata->outlen >= sizeof(__u64)) {
int err;
if (!qp->r_rq.wq) {
__u64 offset = 0;
......
......@@ -647,6 +647,7 @@ static void send_rc_ack(struct ipath_qp *qp)
queue_ack:
spin_lock_irqsave(&qp->s_lock, flags);
dev->n_rc_qacks++;
qp->s_flags |= IPATH_S_ACK_PENDING;
qp->s_nak_state = qp->r_nak_state;
qp->s_ack_psn = qp->r_ack_psn;
......@@ -798,11 +799,13 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
static inline void update_last_psn(struct ipath_qp *qp, u32 psn)
{
if (qp->s_wait_credit) {
qp->s_wait_credit = 0;
tasklet_hi_schedule(&qp->s_task);
if (qp->s_last_psn != psn) {
qp->s_last_psn = psn;
if (qp->s_wait_credit) {
qp->s_wait_credit = 0;
tasklet_hi_schedule(&qp->s_task);
}
}
qp->s_last_psn = psn;
}
/**
......@@ -1653,13 +1656,6 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
case OP(SEND_FIRST):
if (!ipath_get_rwqe(qp, 0)) {
rnr_nak:
/*
* A RNR NAK will ACK earlier sends and RDMA writes.
* Don't queue the NAK if a RDMA read or atomic
* is pending though.
*/
if (qp->r_nak_state)
goto done;
qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer;
qp->r_ack_psn = qp->r_psn;
goto send_ack;
......
......@@ -94,8 +94,8 @@ int ipath_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
/**
* ipath_create_srq - create a shared receive queue
* @ibpd: the protection domain of the SRQ to create
* @attr: the attributes of the SRQ
* @udata: not used by the InfiniPath verbs driver
* @srq_init_attr: the attributes of the SRQ
* @udata: data from libipathverbs when creating a user SRQ
*/
struct ib_srq *ipath_create_srq(struct ib_pd *ibpd,
struct ib_srq_init_attr *srq_init_attr,
......
此差异已折叠。
......@@ -8,5 +8,5 @@ config INFINIBAND_ISER
that speak iSCSI over iSER over InfiniBand.
The iSER protocol is defined by IETF.
See <http://www.ietf.org/internet-drafts/draft-ietf-ips-iser-05.txt>
and <http://www.infinibandta.org/members/spec/iser_annex_060418.pdf>
See <http://www.ietf.org/rfc/rfc5046.txt>
and <http://www.infinibandta.org/members/spec/Annex_iSER.PDF>
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册