Path: blob/master/drivers/infiniband/hw/amso1100/c2_intr.c
15112 views
/*1* Copyright (c) 2005 Ammasso, Inc. All rights reserved.2* Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.3*4* This software is available to you under a choice of one of two5* licenses. You may choose to be licensed under the terms of the GNU6* General Public License (GPL) Version 2, available from the file7* COPYING in the main directory of this source tree, or the8* OpenIB.org BSD license below:9*10* Redistribution and use in source and binary forms, with or11* without modification, are permitted provided that the following12* conditions are met:13*14* - Redistributions of source code must retain the above15* copyright notice, this list of conditions and the following16* disclaimer.17*18* - Redistributions in binary form must reproduce the above19* copyright notice, this list of conditions and the following20* disclaimer in the documentation and/or other materials21* provided with the distribution.22*23* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,24* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF25* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30* SOFTWARE.31*/32#include "c2.h"33#include <rdma/iw_cm.h>34#include "c2_vq.h"3536static void handle_mq(struct c2_dev *c2dev, u32 index);37static void handle_vq(struct c2_dev *c2dev, u32 mq_index);3839/*40* Handle RNIC interrupts41*/42void c2_rnic_interrupt(struct c2_dev *c2dev)43{44unsigned int mq_index;4546while (c2dev->hints_read != be16_to_cpu(*c2dev->hint_count)) {47mq_index = readl(c2dev->regs + PCI_BAR0_HOST_HINT);48if (mq_index & 0x80000000) {49break;50}5152c2dev->hints_read++;53handle_mq(c2dev, mq_index);54}5556}5758/*59* Top level MQ handler60*/61static void handle_mq(struct c2_dev *c2dev, u32 mq_index)62{63if (c2dev->qptr_array[mq_index] == NULL) {64pr_debug("handle_mq: stray activity for mq_index=%d\n",65mq_index);66return;67}6869switch (mq_index) {70case (0):71/*72* An index of 0 in the activity queue73* indicates the req vq now has messages74* available...75*76* Wake up any waiters waiting on req VQ77* message availability.78*/79wake_up(&c2dev->req_vq_wo);80break;81case (1):82handle_vq(c2dev, mq_index);83break;84case (2):85/* We have to purge the VQ in case there are pending86* accept reply requests that would result in the87* generation of an ESTABLISHED event. If we don't88* generate these first, a CLOSE event could end up89* being delivered before the ESTABLISHED event.90*/91handle_vq(c2dev, 1);9293c2_ae_event(c2dev, mq_index);94break;95default:96/* There is no event synchronization between CQ events97* and AE or CM events. In fact, CQE could be98* delivered for all of the I/O up to and including the99* FLUSH for a peer disconenct prior to the ESTABLISHED100* event being delivered to the app. The reason for this101* is that CM events are delivered on a thread, while AE102* and CM events are delivered on interrupt context.103*/104c2_cq_event(c2dev, mq_index);105break;106}107108return;109}110111/*112* Handles verbs WR replies.113*/114static void handle_vq(struct c2_dev *c2dev, u32 mq_index)115{116void *adapter_msg, *reply_msg;117struct c2wr_hdr *host_msg;118struct c2wr_hdr tmp;119struct c2_mq *reply_vq;120struct c2_vq_req *req;121struct iw_cm_event cm_event;122int err;123124reply_vq = (struct c2_mq *) c2dev->qptr_array[mq_index];125126/*127* get next msg from mq_index into adapter_msg.128* don't free it yet.129*/130adapter_msg = c2_mq_consume(reply_vq);131if (adapter_msg == NULL) {132return;133}134135host_msg = vq_repbuf_alloc(c2dev);136137/*138* If we can't get a host buffer, then we'll still139* wakeup the waiter, we just won't give him the msg.140* It is assumed the waiter will deal with this...141*/142if (!host_msg) {143pr_debug("handle_vq: no repbufs!\n");144145/*146* just copy the WR header into a local variable.147* this allows us to still demux on the context148*/149host_msg = &tmp;150memcpy(host_msg, adapter_msg, sizeof(tmp));151reply_msg = NULL;152} else {153memcpy(host_msg, adapter_msg, reply_vq->msg_size);154reply_msg = host_msg;155}156157/*158* consume the msg from the MQ159*/160c2_mq_free(reply_vq);161162/*163* wakeup the waiter.164*/165req = (struct c2_vq_req *) (unsigned long) host_msg->context;166if (req == NULL) {167/*168* We should never get here, as the adapter should169* never send us a reply that we're not expecting.170*/171vq_repbuf_free(c2dev, host_msg);172pr_debug("handle_vq: UNEXPECTEDLY got NULL req\n");173return;174}175176if (reply_msg)177err = c2_errno(reply_msg);178else179err = -ENOMEM;180181if (!err) switch (req->event) {182case IW_CM_EVENT_ESTABLISHED:183c2_set_qp_state(req->qp,184C2_QP_STATE_RTS);185case IW_CM_EVENT_CLOSE:186187/*188* Move the QP to RTS if this is189* the established event190*/191cm_event.event = req->event;192cm_event.status = 0;193cm_event.local_addr = req->cm_id->local_addr;194cm_event.remote_addr = req->cm_id->remote_addr;195cm_event.private_data = NULL;196cm_event.private_data_len = 0;197req->cm_id->event_handler(req->cm_id, &cm_event);198break;199default:200break;201}202203req->reply_msg = (u64) (unsigned long) (reply_msg);204atomic_set(&req->reply_ready, 1);205wake_up(&req->wait_object);206207/*208* If the request was cancelled, then this put will209* free the vq_req memory...and reply_msg!!!210*/211vq_req_put(c2dev, req);212}213214215