 9285faa1e7
			
		
	
	
	9285faa1e7
	
	
	
		
			
			Fix a place where we might dereference a NULL pointer; this fixes Coverity CID 1392. On inspection I also found a place where we could attempt to kmem_cache_free() a NULL pointer, so fix this too. Signed-off-by: Tom Tucker <tom@opengridcomputing.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
		
			
				
	
	
		
			213 lines
		
	
	
	
		
			5.5 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			213 lines
		
	
	
	
		
			5.5 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
 | |
|  * Copyright (c) 2005 Open Grid Computing, Inc. 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
 | |
|  * General Public License (GPL) Version 2, available from the file
 | |
|  * COPYING in the main directory of this source tree, or the
 | |
|  * OpenIB.org BSD license below:
 | |
|  *
 | |
|  *     Redistribution and use in source and binary forms, with or
 | |
|  *     without modification, are permitted provided that the following
 | |
|  *     conditions are met:
 | |
|  *
 | |
|  *      - Redistributions of source code must retain the above
 | |
|  *        copyright notice, this list of conditions and the following
 | |
|  *        disclaimer.
 | |
|  *
 | |
|  *      - Redistributions in binary form must reproduce the above
 | |
|  *        copyright notice, this list of conditions and the following
 | |
|  *        disclaimer in the documentation and/or other materials
 | |
|  *        provided with the distribution.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | |
|  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | |
|  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | |
|  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 | |
|  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 | |
|  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | |
|  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | |
|  * SOFTWARE.
 | |
|  */
 | |
| #include "c2.h"
 | |
| #include <rdma/iw_cm.h>
 | |
| #include "c2_vq.h"
 | |
| 
 | |
| static void handle_mq(struct c2_dev *c2dev, u32 index);
 | |
| static void handle_vq(struct c2_dev *c2dev, u32 mq_index);
 | |
| 
 | |
| /*
 | |
|  * Handle RNIC interrupts
 | |
|  */
 | |
| void c2_rnic_interrupt(struct c2_dev *c2dev)
 | |
| {
 | |
| 	unsigned int mq_index;
 | |
| 
 | |
| 	while (c2dev->hints_read != be16_to_cpu(*c2dev->hint_count)) {
 | |
| 		mq_index = readl(c2dev->regs + PCI_BAR0_HOST_HINT);
 | |
| 		if (mq_index & 0x80000000) {
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		c2dev->hints_read++;
 | |
| 		handle_mq(c2dev, mq_index);
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Top level MQ handler
 | |
|  */
 | |
| static void handle_mq(struct c2_dev *c2dev, u32 mq_index)
 | |
| {
 | |
| 	if (c2dev->qptr_array[mq_index] == NULL) {
 | |
| 		pr_debug(KERN_INFO "handle_mq: stray activity for mq_index=%d\n",
 | |
| 			mq_index);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	switch (mq_index) {
 | |
| 	case (0):
 | |
| 		/*
 | |
| 		 * An index of 0 in the activity queue
 | |
| 		 * indicates the req vq now has messages
 | |
| 		 * available...
 | |
| 		 *
 | |
| 		 * Wake up any waiters waiting on req VQ
 | |
| 		 * message availability.
 | |
| 		 */
 | |
| 		wake_up(&c2dev->req_vq_wo);
 | |
| 		break;
 | |
| 	case (1):
 | |
| 		handle_vq(c2dev, mq_index);
 | |
| 		break;
 | |
| 	case (2):
 | |
| 		/* We have to purge the VQ in case there are pending
 | |
| 		 * accept reply requests that would result in the
 | |
| 		 * generation of an ESTABLISHED event. If we don't
 | |
| 		 * generate these first, a CLOSE event could end up
 | |
| 		 * being delivered before the ESTABLISHED event.
 | |
| 		 */
 | |
| 		handle_vq(c2dev, 1);
 | |
| 
 | |
| 		c2_ae_event(c2dev, mq_index);
 | |
| 		break;
 | |
| 	default:
 | |
| 		/* There is no event synchronization between CQ events
 | |
| 		 * and AE or CM events. In fact, CQE could be
 | |
| 		 * delivered for all of the I/O up to and including the
 | |
| 		 * FLUSH for a peer disconenct prior to the ESTABLISHED
 | |
| 		 * event being delivered to the app. The reason for this
 | |
| 		 * is that CM events are delivered on a thread, while AE
 | |
| 		 * and CM events are delivered on interrupt context.
 | |
| 		 */
 | |
| 		c2_cq_event(c2dev, mq_index);
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Handles verbs WR replies.
 | |
|  */
 | |
| static void handle_vq(struct c2_dev *c2dev, u32 mq_index)
 | |
| {
 | |
| 	void *adapter_msg, *reply_msg;
 | |
| 	struct c2wr_hdr *host_msg;
 | |
| 	struct c2wr_hdr tmp;
 | |
| 	struct c2_mq *reply_vq;
 | |
| 	struct c2_vq_req *req;
 | |
| 	struct iw_cm_event cm_event;
 | |
| 	int err;
 | |
| 
 | |
| 	reply_vq = (struct c2_mq *) c2dev->qptr_array[mq_index];
 | |
| 
 | |
| 	/*
 | |
| 	 * get next msg from mq_index into adapter_msg.
 | |
| 	 * don't free it yet.
 | |
| 	 */
 | |
| 	adapter_msg = c2_mq_consume(reply_vq);
 | |
| 	if (adapter_msg == NULL) {
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	host_msg = vq_repbuf_alloc(c2dev);
 | |
| 
 | |
| 	/*
 | |
| 	 * If we can't get a host buffer, then we'll still
 | |
| 	 * wakeup the waiter, we just won't give him the msg.
 | |
| 	 * It is assumed the waiter will deal with this...
 | |
| 	 */
 | |
| 	if (!host_msg) {
 | |
| 		pr_debug("handle_vq: no repbufs!\n");
 | |
| 
 | |
| 		/*
 | |
| 		 * just copy the WR header into a local variable.
 | |
| 		 * this allows us to still demux on the context
 | |
| 		 */
 | |
| 		host_msg = &tmp;
 | |
| 		memcpy(host_msg, adapter_msg, sizeof(tmp));
 | |
| 		reply_msg = NULL;
 | |
| 	} else {
 | |
| 		memcpy(host_msg, adapter_msg, reply_vq->msg_size);
 | |
| 		reply_msg = host_msg;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * consume the msg from the MQ
 | |
| 	 */
 | |
| 	c2_mq_free(reply_vq);
 | |
| 
 | |
| 	/*
 | |
| 	 * wakeup the waiter.
 | |
| 	 */
 | |
| 	req = (struct c2_vq_req *) (unsigned long) host_msg->context;
 | |
| 	if (req == NULL) {
 | |
| 		/*
 | |
| 		 * We should never get here, as the adapter should
 | |
| 		 * never send us a reply that we're not expecting.
 | |
| 		 */
 | |
| 		vq_repbuf_free(c2dev, host_msg);
 | |
| 		pr_debug("handle_vq: UNEXPECTEDLY got NULL req\n");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	if (reply_msg)
 | |
| 		err = c2_errno(reply_msg);
 | |
| 	else
 | |
| 		err = -ENOMEM;
 | |
| 
 | |
| 	if (!err) switch (req->event) {
 | |
| 	case IW_CM_EVENT_ESTABLISHED:
 | |
| 		c2_set_qp_state(req->qp,
 | |
| 				C2_QP_STATE_RTS);
 | |
| 	case IW_CM_EVENT_CLOSE:
 | |
| 
 | |
| 		/*
 | |
| 		 * Move the QP to RTS if this is
 | |
| 		 * the established event
 | |
| 		 */
 | |
| 		cm_event.event = req->event;
 | |
| 		cm_event.status = 0;
 | |
| 		cm_event.local_addr = req->cm_id->local_addr;
 | |
| 		cm_event.remote_addr = req->cm_id->remote_addr;
 | |
| 		cm_event.private_data = NULL;
 | |
| 		cm_event.private_data_len = 0;
 | |
| 		req->cm_id->event_handler(req->cm_id, &cm_event);
 | |
| 		break;
 | |
| 	default:
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	req->reply_msg = (u64) (unsigned long) (reply_msg);
 | |
| 	atomic_set(&req->reply_ready, 1);
 | |
| 	wake_up(&req->wait_object);
 | |
| 
 | |
| 	/*
 | |
| 	 * If the request was cancelled, then this put will
 | |
| 	 * free the vq_req memory...and reply_msg!!!
 | |
| 	 */
 | |
| 	vq_req_put(c2dev, req);
 | |
| }
 |