mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	RDMA/ocrdma: Add driver for Emulex OneConnect IBoE RDMA adapter
Signed-off-by: Parav Pandit <parav.pandit@emulex.com> Signed-off-by: Roland Dreier <roland@purestorage.com>
This commit is contained in:
		
							parent
							
								
									045508a8a3
								
							
						
					
					
						commit
						fe2caefcdf
					
				
					 14 changed files with 8393 additions and 0 deletions
				
			
		| 
						 | 
					@ -51,6 +51,7 @@ source "drivers/infiniband/hw/cxgb3/Kconfig"
 | 
				
			||||||
source "drivers/infiniband/hw/cxgb4/Kconfig"
 | 
					source "drivers/infiniband/hw/cxgb4/Kconfig"
 | 
				
			||||||
source "drivers/infiniband/hw/mlx4/Kconfig"
 | 
					source "drivers/infiniband/hw/mlx4/Kconfig"
 | 
				
			||||||
source "drivers/infiniband/hw/nes/Kconfig"
 | 
					source "drivers/infiniband/hw/nes/Kconfig"
 | 
				
			||||||
 | 
					source "drivers/infiniband/hw/ocrdma/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
source "drivers/infiniband/ulp/ipoib/Kconfig"
 | 
					source "drivers/infiniband/ulp/ipoib/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ obj-$(CONFIG_INFINIBAND_CXGB3)		+= hw/cxgb3/
 | 
				
			||||||
obj-$(CONFIG_INFINIBAND_CXGB4)		+= hw/cxgb4/
 | 
					obj-$(CONFIG_INFINIBAND_CXGB4)		+= hw/cxgb4/
 | 
				
			||||||
obj-$(CONFIG_MLX4_INFINIBAND)		+= hw/mlx4/
 | 
					obj-$(CONFIG_MLX4_INFINIBAND)		+= hw/mlx4/
 | 
				
			||||||
obj-$(CONFIG_INFINIBAND_NES)		+= hw/nes/
 | 
					obj-$(CONFIG_INFINIBAND_NES)		+= hw/nes/
 | 
				
			||||||
 | 
					obj-$(CONFIG_INFINIBAND_OCRDMA)		+= hw/ocrdma/
 | 
				
			||||||
obj-$(CONFIG_INFINIBAND_IPOIB)		+= ulp/ipoib/
 | 
					obj-$(CONFIG_INFINIBAND_IPOIB)		+= ulp/ipoib/
 | 
				
			||||||
obj-$(CONFIG_INFINIBAND_SRP)		+= ulp/srp/
 | 
					obj-$(CONFIG_INFINIBAND_SRP)		+= ulp/srp/
 | 
				
			||||||
obj-$(CONFIG_INFINIBAND_SRPT)		+= ulp/srpt/
 | 
					obj-$(CONFIG_INFINIBAND_SRPT)		+= ulp/srpt/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										8
									
								
								drivers/infiniband/hw/ocrdma/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								drivers/infiniband/hw/ocrdma/Kconfig
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,8 @@
 | 
				
			||||||
 | 
					config INFINIBAND_OCRDMA
 | 
				
			||||||
 | 
						tristate "Emulex One Connect HCA support"
 | 
				
			||||||
 | 
						depends on ETHERNET && NETDEVICES && PCI
 | 
				
			||||||
 | 
						select NET_VENDOR_EMULEX
 | 
				
			||||||
 | 
						select BE2NET
 | 
				
			||||||
 | 
						---help---
 | 
				
			||||||
 | 
						  This driver provides low-level InfiniBand over Ethernet
 | 
				
			||||||
 | 
						  support for Emulex One Connect host channel adapters (HCAs).
 | 
				
			||||||
							
								
								
									
										5
									
								
								drivers/infiniband/hw/ocrdma/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								drivers/infiniband/hw/ocrdma/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					ccflags-y := -Idrivers/net/ethernet/emulex/benet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-$(CONFIG_INFINIBAND_OCRDMA)	+= ocrdma.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ocrdma-y :=	ocrdma_main.o ocrdma_verbs.o ocrdma_hw.o ocrdma_ah.o
 | 
				
			||||||
							
								
								
									
										392
									
								
								drivers/infiniband/hw/ocrdma/ocrdma.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										392
									
								
								drivers/infiniband/hw/ocrdma/ocrdma.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,392 @@
 | 
				
			||||||
 | 
					/*******************************************************************
 | 
				
			||||||
 | 
					 * This file is part of the Emulex RoCE Device Driver for          *
 | 
				
			||||||
 | 
					 * RoCE (RDMA over Converged Ethernet) adapters.                   *
 | 
				
			||||||
 | 
					 * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
 | 
				
			||||||
 | 
					 * EMULEX and SLI are trademarks of Emulex.                        *
 | 
				
			||||||
 | 
					 * www.emulex.com                                                  *
 | 
				
			||||||
 | 
					 *                                                                 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or   *
 | 
				
			||||||
 | 
					 * modify it under the terms of version 2 of the GNU General       *
 | 
				
			||||||
 | 
					 * Public License as published by the Free Software Foundation.    *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful. *
 | 
				
			||||||
 | 
					 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
 | 
				
			||||||
 | 
					 * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
 | 
				
			||||||
 | 
					 * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
 | 
				
			||||||
 | 
					 * more details, a copy of which can be found in the file COPYING  *
 | 
				
			||||||
 | 
					 * included with this package.                                     *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contact Information:
 | 
				
			||||||
 | 
					 * linux-drivers@emulex.com
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Emulex
 | 
				
			||||||
 | 
					 * 3333 Susan Street
 | 
				
			||||||
 | 
					 * Costa Mesa, CA 92626
 | 
				
			||||||
 | 
					 *******************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __OCRDMA_H__
 | 
				
			||||||
 | 
					#define __OCRDMA_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/mutex.h>
 | 
				
			||||||
 | 
					#include <linux/list.h>
 | 
				
			||||||
 | 
					#include <linux/spinlock.h>
 | 
				
			||||||
 | 
					#include <linux/pci.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <rdma/ib_verbs.h>
 | 
				
			||||||
 | 
					#include <rdma/ib_user_verbs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <be_roce.h>
 | 
				
			||||||
 | 
					#include "ocrdma_sli.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define OCRDMA_ROCE_DEV_VERSION "1.0.0"
 | 
				
			||||||
 | 
					#define OCRDMA_NODE_DESC "Emulex OneConnect RoCE HCA"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ocrdma_err(format, arg...) printk(KERN_ERR format, ##arg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define OCRDMA_MAX_AH 512
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define OCRDMA_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_dev_attr {
 | 
				
			||||||
 | 
						u8 fw_ver[32];
 | 
				
			||||||
 | 
						u32 vendor_id;
 | 
				
			||||||
 | 
						u32 device_id;
 | 
				
			||||||
 | 
						u16 max_pd;
 | 
				
			||||||
 | 
						u16 max_cq;
 | 
				
			||||||
 | 
						u16 max_cqe;
 | 
				
			||||||
 | 
						u16 max_qp;
 | 
				
			||||||
 | 
						u16 max_wqe;
 | 
				
			||||||
 | 
						u16 max_rqe;
 | 
				
			||||||
 | 
						u32 max_inline_data;
 | 
				
			||||||
 | 
						int max_send_sge;
 | 
				
			||||||
 | 
						int max_recv_sge;
 | 
				
			||||||
 | 
						int max_mr;
 | 
				
			||||||
 | 
						u64 max_mr_size;
 | 
				
			||||||
 | 
						u32 max_num_mr_pbl;
 | 
				
			||||||
 | 
						int max_fmr;
 | 
				
			||||||
 | 
						int max_map_per_fmr;
 | 
				
			||||||
 | 
						int max_pages_per_frmr;
 | 
				
			||||||
 | 
						u16 max_ord_per_qp;
 | 
				
			||||||
 | 
						u16 max_ird_per_qp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int device_cap_flags;
 | 
				
			||||||
 | 
						u8 cq_overflow_detect;
 | 
				
			||||||
 | 
						u8 srq_supported;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u32 wqe_size;
 | 
				
			||||||
 | 
						u32 rqe_size;
 | 
				
			||||||
 | 
						u32 ird_page_size;
 | 
				
			||||||
 | 
						u8 local_ca_ack_delay;
 | 
				
			||||||
 | 
						u8 ird;
 | 
				
			||||||
 | 
						u8 num_ird_pages;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_pbl {
 | 
				
			||||||
 | 
						void *va;
 | 
				
			||||||
 | 
						dma_addr_t pa;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_queue_info {
 | 
				
			||||||
 | 
						void *va;
 | 
				
			||||||
 | 
						dma_addr_t dma;
 | 
				
			||||||
 | 
						u32 size;
 | 
				
			||||||
 | 
						u16 len;
 | 
				
			||||||
 | 
						u16 entry_size;		/* Size of an element in the queue */
 | 
				
			||||||
 | 
						u16 id;			/* qid, where to ring the doorbell. */
 | 
				
			||||||
 | 
						u16 head, tail;
 | 
				
			||||||
 | 
						bool created;
 | 
				
			||||||
 | 
						atomic_t used;		/* Number of valid elements in the queue */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_eq {
 | 
				
			||||||
 | 
						struct ocrdma_queue_info q;
 | 
				
			||||||
 | 
						u32 vector;
 | 
				
			||||||
 | 
						int cq_cnt;
 | 
				
			||||||
 | 
						struct ocrdma_dev *dev;
 | 
				
			||||||
 | 
						char irq_name[32];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_mq {
 | 
				
			||||||
 | 
						struct ocrdma_queue_info sq;
 | 
				
			||||||
 | 
						struct ocrdma_queue_info cq;
 | 
				
			||||||
 | 
						bool rearm_cq;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mqe_ctx {
 | 
				
			||||||
 | 
						struct mutex lock; /* for serializing mailbox commands on MQ */
 | 
				
			||||||
 | 
						wait_queue_head_t cmd_wait;
 | 
				
			||||||
 | 
						u32 tag;
 | 
				
			||||||
 | 
						u16 cqe_status;
 | 
				
			||||||
 | 
						u16 ext_status;
 | 
				
			||||||
 | 
						bool cmd_done;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_dev {
 | 
				
			||||||
 | 
						struct ib_device ibdev;
 | 
				
			||||||
 | 
						struct ocrdma_dev_attr attr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct mutex dev_lock; /* provides syncronise access to device data */
 | 
				
			||||||
 | 
						spinlock_t flush_q_lock ____cacheline_aligned;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct ocrdma_cq **cq_tbl;
 | 
				
			||||||
 | 
						struct ocrdma_qp **qp_tbl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct ocrdma_eq meq;
 | 
				
			||||||
 | 
						struct ocrdma_eq *qp_eq_tbl;
 | 
				
			||||||
 | 
						int eq_cnt;
 | 
				
			||||||
 | 
						u16 base_eqid;
 | 
				
			||||||
 | 
						u16 max_eq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						union ib_gid *sgid_tbl;
 | 
				
			||||||
 | 
						/* provided synchronization to sgid table for
 | 
				
			||||||
 | 
						 * updating gid entries triggered by notifier.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						spinlock_t sgid_lock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int gsi_qp_created;
 | 
				
			||||||
 | 
						struct ocrdma_cq *gsi_sqcq;
 | 
				
			||||||
 | 
						struct ocrdma_cq *gsi_rqcq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct ocrdma_av *va;
 | 
				
			||||||
 | 
							dma_addr_t pa;
 | 
				
			||||||
 | 
							u32 size;
 | 
				
			||||||
 | 
							u32 num_ah;
 | 
				
			||||||
 | 
							/* provide synchronization for av
 | 
				
			||||||
 | 
							 * entry allocations.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							spinlock_t lock;
 | 
				
			||||||
 | 
							u32 ahid;
 | 
				
			||||||
 | 
							struct ocrdma_pbl pbl;
 | 
				
			||||||
 | 
						} av_tbl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void *mbx_cmd;
 | 
				
			||||||
 | 
						struct ocrdma_mq mq;
 | 
				
			||||||
 | 
						struct mqe_ctx mqe_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct be_dev_info nic_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct list_head entry;
 | 
				
			||||||
 | 
						int id;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_cq {
 | 
				
			||||||
 | 
						struct ib_cq ibcq;
 | 
				
			||||||
 | 
						struct ocrdma_dev *dev;
 | 
				
			||||||
 | 
						struct ocrdma_cqe *va;
 | 
				
			||||||
 | 
						u32 phase;
 | 
				
			||||||
 | 
						u32 getp;	/* pointer to pending wrs to
 | 
				
			||||||
 | 
								 * return to stack, wrap arounds
 | 
				
			||||||
 | 
								 * at max_hw_cqe
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
						u32 max_hw_cqe;
 | 
				
			||||||
 | 
						bool phase_change;
 | 
				
			||||||
 | 
						bool armed, solicited;
 | 
				
			||||||
 | 
						bool arm_needed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spinlock_t cq_lock ____cacheline_aligned; /* provide synchronization
 | 
				
			||||||
 | 
											   * to cq polling
 | 
				
			||||||
 | 
											   */
 | 
				
			||||||
 | 
						/* syncronizes cq completion handler invoked from multiple context */
 | 
				
			||||||
 | 
						spinlock_t comp_handler_lock ____cacheline_aligned;
 | 
				
			||||||
 | 
						u16 id;
 | 
				
			||||||
 | 
						u16 eqn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct ocrdma_ucontext *ucontext;
 | 
				
			||||||
 | 
						dma_addr_t pa;
 | 
				
			||||||
 | 
						u32 len;
 | 
				
			||||||
 | 
						atomic_t use_cnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* head of all qp's sq and rq for which cqes need to be flushed
 | 
				
			||||||
 | 
						 * by the software.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct list_head sq_head, rq_head;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_pd {
 | 
				
			||||||
 | 
						struct ib_pd ibpd;
 | 
				
			||||||
 | 
						struct ocrdma_dev *dev;
 | 
				
			||||||
 | 
						struct ocrdma_ucontext *uctx;
 | 
				
			||||||
 | 
						atomic_t use_cnt;
 | 
				
			||||||
 | 
						u32 id;
 | 
				
			||||||
 | 
						int num_dpp_qp;
 | 
				
			||||||
 | 
						u32 dpp_page;
 | 
				
			||||||
 | 
						bool dpp_enabled;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_ah {
 | 
				
			||||||
 | 
						struct ib_ah ibah;
 | 
				
			||||||
 | 
						struct ocrdma_dev *dev;
 | 
				
			||||||
 | 
						struct ocrdma_av *av;
 | 
				
			||||||
 | 
						u16 sgid_index;
 | 
				
			||||||
 | 
						u32 id;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_qp_hwq_info {
 | 
				
			||||||
 | 
						u8 *va;			/* virtual address */
 | 
				
			||||||
 | 
						u32 max_sges;
 | 
				
			||||||
 | 
						u32 head, tail;
 | 
				
			||||||
 | 
						u32 entry_size;
 | 
				
			||||||
 | 
						u32 max_cnt;
 | 
				
			||||||
 | 
						u32 max_wqe_idx;
 | 
				
			||||||
 | 
						u32 free_delta;
 | 
				
			||||||
 | 
						u16 dbid;		/* qid, where to ring the doorbell. */
 | 
				
			||||||
 | 
						u32 len;
 | 
				
			||||||
 | 
						dma_addr_t pa;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_srq {
 | 
				
			||||||
 | 
						struct ib_srq ibsrq;
 | 
				
			||||||
 | 
						struct ocrdma_dev *dev;
 | 
				
			||||||
 | 
						u8 __iomem *db;
 | 
				
			||||||
 | 
						/* provide synchronization to multiple context(s) posting rqe */
 | 
				
			||||||
 | 
						spinlock_t q_lock ____cacheline_aligned;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct ocrdma_qp_hwq_info rq;
 | 
				
			||||||
 | 
						struct ocrdma_pd *pd;
 | 
				
			||||||
 | 
						atomic_t use_cnt;
 | 
				
			||||||
 | 
						u32 id;
 | 
				
			||||||
 | 
						u64 *rqe_wr_id_tbl;
 | 
				
			||||||
 | 
						u32 *idx_bit_fields;
 | 
				
			||||||
 | 
						u32 bit_fields_len;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_qp {
 | 
				
			||||||
 | 
						struct ib_qp ibqp;
 | 
				
			||||||
 | 
						struct ocrdma_dev *dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u8 __iomem *sq_db;
 | 
				
			||||||
 | 
						/* provide synchronization to multiple context(s) posting wqe, rqe */
 | 
				
			||||||
 | 
						spinlock_t q_lock ____cacheline_aligned;
 | 
				
			||||||
 | 
						struct ocrdma_qp_hwq_info sq;
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							uint64_t wrid;
 | 
				
			||||||
 | 
							uint16_t dpp_wqe_idx;
 | 
				
			||||||
 | 
							uint16_t dpp_wqe;
 | 
				
			||||||
 | 
							uint8_t  signaled;
 | 
				
			||||||
 | 
							uint8_t  rsvd[3];
 | 
				
			||||||
 | 
						} *wqe_wr_id_tbl;
 | 
				
			||||||
 | 
						u32 max_inline_data;
 | 
				
			||||||
 | 
						struct ocrdma_cq *sq_cq;
 | 
				
			||||||
 | 
						/* list maintained per CQ to flush SQ errors */
 | 
				
			||||||
 | 
						struct list_head sq_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u8 __iomem *rq_db;
 | 
				
			||||||
 | 
						struct ocrdma_qp_hwq_info rq;
 | 
				
			||||||
 | 
						u64 *rqe_wr_id_tbl;
 | 
				
			||||||
 | 
						struct ocrdma_cq *rq_cq;
 | 
				
			||||||
 | 
						struct ocrdma_srq *srq;
 | 
				
			||||||
 | 
						/* list maintained per CQ to flush RQ errors */
 | 
				
			||||||
 | 
						struct list_head rq_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum ocrdma_qp_state state;	/*  QP state */
 | 
				
			||||||
 | 
						int cap_flags;
 | 
				
			||||||
 | 
						u32 max_ord, max_ird;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u32 id;
 | 
				
			||||||
 | 
						struct ocrdma_pd *pd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum ib_qp_type qp_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int sgid_idx;
 | 
				
			||||||
 | 
						u32 qkey;
 | 
				
			||||||
 | 
						bool dpp_enabled;
 | 
				
			||||||
 | 
						u8 *ird_q_va;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define OCRDMA_GET_NUM_POSTED_SHIFT_VAL(qp) \
 | 
				
			||||||
 | 
						(((qp->dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) && \
 | 
				
			||||||
 | 
							(qp->id < 64)) ? 24 : 16)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_hw_mr {
 | 
				
			||||||
 | 
						struct ocrdma_dev *dev;
 | 
				
			||||||
 | 
						u32 lkey;
 | 
				
			||||||
 | 
						u8 fr_mr;
 | 
				
			||||||
 | 
						u8 remote_atomic;
 | 
				
			||||||
 | 
						u8 remote_rd;
 | 
				
			||||||
 | 
						u8 remote_wr;
 | 
				
			||||||
 | 
						u8 local_rd;
 | 
				
			||||||
 | 
						u8 local_wr;
 | 
				
			||||||
 | 
						u8 mw_bind;
 | 
				
			||||||
 | 
						u8 rsvd;
 | 
				
			||||||
 | 
						u64 len;
 | 
				
			||||||
 | 
						struct ocrdma_pbl *pbl_table;
 | 
				
			||||||
 | 
						u32 num_pbls;
 | 
				
			||||||
 | 
						u32 num_pbes;
 | 
				
			||||||
 | 
						u32 pbl_size;
 | 
				
			||||||
 | 
						u32 pbe_size;
 | 
				
			||||||
 | 
						u64 fbo;
 | 
				
			||||||
 | 
						u64 va;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_mr {
 | 
				
			||||||
 | 
						struct ib_mr ibmr;
 | 
				
			||||||
 | 
						struct ib_umem *umem;
 | 
				
			||||||
 | 
						struct ocrdma_hw_mr hwmr;
 | 
				
			||||||
 | 
						struct ocrdma_pd *pd;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_ucontext {
 | 
				
			||||||
 | 
						struct ib_ucontext ibucontext;
 | 
				
			||||||
 | 
						struct ocrdma_dev *dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct list_head mm_head;
 | 
				
			||||||
 | 
						struct mutex mm_list_lock; /* protects list entries of mm type */
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							u32 *va;
 | 
				
			||||||
 | 
							dma_addr_t pa;
 | 
				
			||||||
 | 
							u32 len;
 | 
				
			||||||
 | 
						} ah_tbl;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_mm {
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							u64 phy_addr;
 | 
				
			||||||
 | 
							unsigned long len;
 | 
				
			||||||
 | 
						} key;
 | 
				
			||||||
 | 
						struct list_head entry;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct ocrdma_dev *get_ocrdma_dev(struct ib_device *ibdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return container_of(ibdev, struct ocrdma_dev, ibdev);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct ocrdma_ucontext *get_ocrdma_ucontext(struct ib_ucontext
 | 
				
			||||||
 | 
												  *ibucontext)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return container_of(ibucontext, struct ocrdma_ucontext, ibucontext);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct ocrdma_pd *get_ocrdma_pd(struct ib_pd *ibpd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return container_of(ibpd, struct ocrdma_pd, ibpd);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct ocrdma_cq *get_ocrdma_cq(struct ib_cq *ibcq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return container_of(ibcq, struct ocrdma_cq, ibcq);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct ocrdma_qp *get_ocrdma_qp(struct ib_qp *ibqp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return container_of(ibqp, struct ocrdma_qp, ibqp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct ocrdma_mr *get_ocrdma_mr(struct ib_mr *ibmr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return container_of(ibmr, struct ocrdma_mr, ibmr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct ocrdma_ah *get_ocrdma_ah(struct ib_ah *ibah)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return container_of(ibah, struct ocrdma_ah, ibah);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct ocrdma_srq *get_ocrdma_srq(struct ib_srq *ibsrq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return container_of(ibsrq, struct ocrdma_srq, ibsrq);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										134
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_abi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_abi.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,134 @@
 | 
				
			||||||
 | 
					/*******************************************************************
 | 
				
			||||||
 | 
					 * This file is part of the Emulex RoCE Device Driver for          *
 | 
				
			||||||
 | 
					 * RoCE (RDMA over Converged Ethernet) adapters.                   *
 | 
				
			||||||
 | 
					 * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
 | 
				
			||||||
 | 
					 * EMULEX and SLI are trademarks of Emulex.                        *
 | 
				
			||||||
 | 
					 * www.emulex.com                                                  *
 | 
				
			||||||
 | 
					 *                                                                 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or   *
 | 
				
			||||||
 | 
					 * modify it under the terms of version 2 of the GNU General       *
 | 
				
			||||||
 | 
					 * Public License as published by the Free Software Foundation.    *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful. *
 | 
				
			||||||
 | 
					 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
 | 
				
			||||||
 | 
					 * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
 | 
				
			||||||
 | 
					 * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
 | 
				
			||||||
 | 
					 * more details, a copy of which can be found in the file COPYING  *
 | 
				
			||||||
 | 
					 * included with this package.                                     *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contact Information:
 | 
				
			||||||
 | 
					 * linux-drivers@emulex.com
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Emulex
 | 
				
			||||||
 | 
					 * 3333 Susan Street
 | 
				
			||||||
 | 
					 * Costa Mesa, CA 92626
 | 
				
			||||||
 | 
					 *******************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __OCRDMA_ABI_H__
 | 
				
			||||||
 | 
					#define __OCRDMA_ABI_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_alloc_ucontext_resp {
 | 
				
			||||||
 | 
						u32 dev_id;
 | 
				
			||||||
 | 
						u32 wqe_size;
 | 
				
			||||||
 | 
						u32 max_inline_data;
 | 
				
			||||||
 | 
						u32 dpp_wqe_size;
 | 
				
			||||||
 | 
						u64 ah_tbl_page;
 | 
				
			||||||
 | 
						u32 ah_tbl_len;
 | 
				
			||||||
 | 
						u32 rsvd;
 | 
				
			||||||
 | 
						u8 fw_ver[32];
 | 
				
			||||||
 | 
						u32 rqe_size;
 | 
				
			||||||
 | 
						u64 rsvd1;
 | 
				
			||||||
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* user kernel communication data structures. */
 | 
				
			||||||
 | 
					struct ocrdma_alloc_pd_ureq {
 | 
				
			||||||
 | 
						u64 rsvd1;
 | 
				
			||||||
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_alloc_pd_uresp {
 | 
				
			||||||
 | 
						u32 id;
 | 
				
			||||||
 | 
						u32 dpp_enabled;
 | 
				
			||||||
 | 
						u32 dpp_page_addr_hi;
 | 
				
			||||||
 | 
						u32 dpp_page_addr_lo;
 | 
				
			||||||
 | 
						u64 rsvd1;
 | 
				
			||||||
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_create_cq_ureq {
 | 
				
			||||||
 | 
						u32 dpp_cq;
 | 
				
			||||||
 | 
						u32 rsvd;
 | 
				
			||||||
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_CQ_PAGES 8
 | 
				
			||||||
 | 
					struct ocrdma_create_cq_uresp {
 | 
				
			||||||
 | 
						u32 cq_id;
 | 
				
			||||||
 | 
						u32 page_size;
 | 
				
			||||||
 | 
						u32 num_pages;
 | 
				
			||||||
 | 
						u32 max_hw_cqe;
 | 
				
			||||||
 | 
						u64 page_addr[MAX_CQ_PAGES];
 | 
				
			||||||
 | 
						u64 db_page_addr;
 | 
				
			||||||
 | 
						u32 db_page_size;
 | 
				
			||||||
 | 
						u32 phase_change;
 | 
				
			||||||
 | 
						u64 rsvd1;
 | 
				
			||||||
 | 
						u64 rsvd2;
 | 
				
			||||||
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_QP_PAGES 8
 | 
				
			||||||
 | 
					#define MAX_UD_AV_PAGES 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_create_qp_ureq {
 | 
				
			||||||
 | 
						u8 enable_dpp_cq;
 | 
				
			||||||
 | 
						u8 rsvd;
 | 
				
			||||||
 | 
						u16 dpp_cq_id;
 | 
				
			||||||
 | 
						u32 rsvd1;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_create_qp_uresp {
 | 
				
			||||||
 | 
						u16 qp_id;
 | 
				
			||||||
 | 
						u16 sq_dbid;
 | 
				
			||||||
 | 
						u16 rq_dbid;
 | 
				
			||||||
 | 
						u16 resv0;
 | 
				
			||||||
 | 
						u32 sq_page_size;
 | 
				
			||||||
 | 
						u32 rq_page_size;
 | 
				
			||||||
 | 
						u32 num_sq_pages;
 | 
				
			||||||
 | 
						u32 num_rq_pages;
 | 
				
			||||||
 | 
						u64 sq_page_addr[MAX_QP_PAGES];
 | 
				
			||||||
 | 
						u64 rq_page_addr[MAX_QP_PAGES];
 | 
				
			||||||
 | 
						u64 db_page_addr;
 | 
				
			||||||
 | 
						u32 db_page_size;
 | 
				
			||||||
 | 
						u32 dpp_credit;
 | 
				
			||||||
 | 
						u32 dpp_offset;
 | 
				
			||||||
 | 
						u32 rsvd1;
 | 
				
			||||||
 | 
						u32 num_wqe_allocated;
 | 
				
			||||||
 | 
						u32 num_rqe_allocated;
 | 
				
			||||||
 | 
						u32 free_wqe_delta;
 | 
				
			||||||
 | 
						u32 free_rqe_delta;
 | 
				
			||||||
 | 
						u32 db_sq_offset;
 | 
				
			||||||
 | 
						u32 db_rq_offset;
 | 
				
			||||||
 | 
						u32 db_shift;
 | 
				
			||||||
 | 
						u64 rsvd2;
 | 
				
			||||||
 | 
						u64 rsvd3;
 | 
				
			||||||
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_create_srq_uresp {
 | 
				
			||||||
 | 
						u16 rq_dbid;
 | 
				
			||||||
 | 
						u16 resv0;
 | 
				
			||||||
 | 
						u32 resv1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u32 rq_page_size;
 | 
				
			||||||
 | 
						u32 num_rq_pages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u64 rq_page_addr[MAX_QP_PAGES];
 | 
				
			||||||
 | 
						u64 db_page_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u32 db_page_size;
 | 
				
			||||||
 | 
						u32 num_rqe_allocated;
 | 
				
			||||||
 | 
						u32 db_rq_offset;
 | 
				
			||||||
 | 
						u32 db_shift;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u32 free_rqe_delta;
 | 
				
			||||||
 | 
						u32 rsvd2;
 | 
				
			||||||
 | 
						u64 rsvd3;
 | 
				
			||||||
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif				/* __OCRDMA_ABI_H__ */
 | 
				
			||||||
							
								
								
									
										172
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_ah.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_ah.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,172 @@
 | 
				
			||||||
 | 
					/*******************************************************************
 | 
				
			||||||
 | 
					 * This file is part of the Emulex RoCE Device Driver for          *
 | 
				
			||||||
 | 
					 * RoCE (RDMA over Converged Ethernet) adapters.                   *
 | 
				
			||||||
 | 
					 * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
 | 
				
			||||||
 | 
					 * EMULEX and SLI are trademarks of Emulex.                        *
 | 
				
			||||||
 | 
					 * www.emulex.com                                                  *
 | 
				
			||||||
 | 
					 *                                                                 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or   *
 | 
				
			||||||
 | 
					 * modify it under the terms of version 2 of the GNU General       *
 | 
				
			||||||
 | 
					 * Public License as published by the Free Software Foundation.    *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful. *
 | 
				
			||||||
 | 
					 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
 | 
				
			||||||
 | 
					 * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
 | 
				
			||||||
 | 
					 * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
 | 
				
			||||||
 | 
					 * more details, a copy of which can be found in the file COPYING  *
 | 
				
			||||||
 | 
					 * included with this package.                                     *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contact Information:
 | 
				
			||||||
 | 
					 * linux-drivers@emulex.com
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Emulex
 | 
				
			||||||
 | 
					 * 3333 Susan Street
 | 
				
			||||||
 | 
					 * Costa Mesa, CA 92626
 | 
				
			||||||
 | 
					 *******************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <net/neighbour.h>
 | 
				
			||||||
 | 
					#include <net/netevent.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <rdma/ib_addr.h>
 | 
				
			||||||
 | 
					#include <rdma/ib_cache.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ocrdma.h"
 | 
				
			||||||
 | 
					#include "ocrdma_verbs.h"
 | 
				
			||||||
 | 
					#include "ocrdma_ah.h"
 | 
				
			||||||
 | 
					#include "ocrdma_hw.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int set_av_attr(struct ocrdma_ah *ah,
 | 
				
			||||||
 | 
									struct ib_ah_attr *attr, int pdid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int status = 0;
 | 
				
			||||||
 | 
						u16 vlan_tag; bool vlan_enabled = false;
 | 
				
			||||||
 | 
						struct ocrdma_dev *dev = ah->dev;
 | 
				
			||||||
 | 
						struct ocrdma_eth_vlan eth;
 | 
				
			||||||
 | 
						struct ocrdma_grh grh;
 | 
				
			||||||
 | 
						int eth_sz;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(ð, 0, sizeof(eth));
 | 
				
			||||||
 | 
						memset(&grh, 0, sizeof(grh));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ah->sgid_index = attr->grh.sgid_index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vlan_tag = rdma_get_vlan_id(&attr->grh.dgid);
 | 
				
			||||||
 | 
						if (vlan_tag && (vlan_tag < 0x1000)) {
 | 
				
			||||||
 | 
							eth.eth_type = cpu_to_be16(0x8100);
 | 
				
			||||||
 | 
							eth.roce_eth_type = cpu_to_be16(OCRDMA_ROCE_ETH_TYPE);
 | 
				
			||||||
 | 
							vlan_tag |= (attr->sl & 7) << 13;
 | 
				
			||||||
 | 
							eth.vlan_tag = cpu_to_be16(vlan_tag);
 | 
				
			||||||
 | 
							eth_sz = sizeof(struct ocrdma_eth_vlan);
 | 
				
			||||||
 | 
							vlan_enabled = true;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							eth.eth_type = cpu_to_be16(OCRDMA_ROCE_ETH_TYPE);
 | 
				
			||||||
 | 
							eth_sz = sizeof(struct ocrdma_eth_basic);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						memcpy(ð.smac[0], &dev->nic_info.mac_addr[0], ETH_ALEN);
 | 
				
			||||||
 | 
						status = ocrdma_resolve_dgid(dev, &attr->grh.dgid, ð.dmac[0]);
 | 
				
			||||||
 | 
						if (status)
 | 
				
			||||||
 | 
							return status;
 | 
				
			||||||
 | 
						status = ocrdma_query_gid(&dev->ibdev, 1, attr->grh.sgid_index,
 | 
				
			||||||
 | 
								(union ib_gid *)&grh.sgid[0]);
 | 
				
			||||||
 | 
						if (status)
 | 
				
			||||||
 | 
							return status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						grh.tclass_flow = cpu_to_be32((6 << 28) |
 | 
				
			||||||
 | 
								(attr->grh.traffic_class << 24) |
 | 
				
			||||||
 | 
								attr->grh.flow_label);
 | 
				
			||||||
 | 
						/* 0x1b is next header value in GRH */
 | 
				
			||||||
 | 
						grh.pdid_hoplimit = cpu_to_be32((pdid << 16) |
 | 
				
			||||||
 | 
								(0x1b << 8) | attr->grh.hop_limit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(&grh.dgid[0], attr->grh.dgid.raw, sizeof(attr->grh.dgid.raw));
 | 
				
			||||||
 | 
						memcpy(&ah->av->eth_hdr, ð, eth_sz);
 | 
				
			||||||
 | 
						memcpy((u8 *)ah->av + eth_sz, &grh, sizeof(struct ocrdma_grh));
 | 
				
			||||||
 | 
						if (vlan_enabled)
 | 
				
			||||||
 | 
							ah->av->valid |= OCRDMA_AV_VLAN_VALID;
 | 
				
			||||||
 | 
						return status;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32 *ahid_addr;
 | 
				
			||||||
 | 
						int status;
 | 
				
			||||||
 | 
						struct ocrdma_ah *ah;
 | 
				
			||||||
 | 
						struct ocrdma_pd *pd = get_ocrdma_pd(ibpd);
 | 
				
			||||||
 | 
						struct ocrdma_dev *dev = pd->dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!(attr->ah_flags & IB_AH_GRH))
 | 
				
			||||||
 | 
							return ERR_PTR(-EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ah = kzalloc(sizeof *ah, GFP_ATOMIC);
 | 
				
			||||||
 | 
						if (!ah)
 | 
				
			||||||
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
						ah->dev = pd->dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = ocrdma_alloc_av(dev, ah);
 | 
				
			||||||
 | 
						if (status)
 | 
				
			||||||
 | 
							goto av_err;
 | 
				
			||||||
 | 
						status = set_av_attr(ah, attr, pd->id);
 | 
				
			||||||
 | 
						if (status)
 | 
				
			||||||
 | 
							goto av_conf_err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* if pd is for the user process, pass the ah_id to user space */
 | 
				
			||||||
 | 
						if ((pd->uctx) && (pd->uctx->ah_tbl.va)) {
 | 
				
			||||||
 | 
							ahid_addr = pd->uctx->ah_tbl.va + attr->dlid;
 | 
				
			||||||
 | 
							*ahid_addr = ah->id;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return &ah->ibah;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					av_conf_err:
 | 
				
			||||||
 | 
						ocrdma_free_av(dev, ah);
 | 
				
			||||||
 | 
					av_err:
 | 
				
			||||||
 | 
						kfree(ah);
 | 
				
			||||||
 | 
						return ERR_PTR(status);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_destroy_ah(struct ib_ah *ibah)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ocrdma_ah *ah = get_ocrdma_ah(ibah);
 | 
				
			||||||
 | 
						ocrdma_free_av(ah->dev, ah);
 | 
				
			||||||
 | 
						kfree(ah);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_query_ah(struct ib_ah *ibah, struct ib_ah_attr *attr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ocrdma_ah *ah = get_ocrdma_ah(ibah);
 | 
				
			||||||
 | 
						struct ocrdma_av *av = ah->av;
 | 
				
			||||||
 | 
						struct ocrdma_grh *grh;
 | 
				
			||||||
 | 
						attr->ah_flags |= IB_AH_GRH;
 | 
				
			||||||
 | 
						if (ah->av->valid & Bit(1)) {
 | 
				
			||||||
 | 
							grh = (struct ocrdma_grh *)((u8 *)ah->av +
 | 
				
			||||||
 | 
									sizeof(struct ocrdma_eth_vlan));
 | 
				
			||||||
 | 
							attr->sl = be16_to_cpu(av->eth_hdr.vlan_tag) >> 13;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							grh = (struct ocrdma_grh *)((u8 *)ah->av +
 | 
				
			||||||
 | 
										sizeof(struct ocrdma_eth_basic));
 | 
				
			||||||
 | 
							attr->sl = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						memcpy(&attr->grh.dgid.raw[0], &grh->dgid[0], sizeof(grh->dgid));
 | 
				
			||||||
 | 
						attr->grh.sgid_index = ah->sgid_index;
 | 
				
			||||||
 | 
						attr->grh.hop_limit = be32_to_cpu(grh->pdid_hoplimit) & 0xff;
 | 
				
			||||||
 | 
						attr->grh.traffic_class = be32_to_cpu(grh->tclass_flow) >> 24;
 | 
				
			||||||
 | 
						attr->grh.flow_label = be32_to_cpu(grh->tclass_flow) & 0x00ffffffff;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_modify_ah(struct ib_ah *ibah, struct ib_ah_attr *attr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* modify_ah is unsupported */
 | 
				
			||||||
 | 
						return -ENOSYS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_process_mad(struct ib_device *ibdev,
 | 
				
			||||||
 | 
							       int process_mad_flags,
 | 
				
			||||||
 | 
							       u8 port_num,
 | 
				
			||||||
 | 
							       struct ib_wc *in_wc,
 | 
				
			||||||
 | 
							       struct ib_grh *in_grh,
 | 
				
			||||||
 | 
							       struct ib_mad *in_mad, struct ib_mad *out_mad)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return IB_MAD_RESULT_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										42
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_ah.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_ah.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,42 @@
 | 
				
			||||||
 | 
					/*******************************************************************
 | 
				
			||||||
 | 
					 * This file is part of the Emulex RoCE Device Driver for          *
 | 
				
			||||||
 | 
					 * RoCE (RDMA over Converged Ethernet) adapters.                   *
 | 
				
			||||||
 | 
					 * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
 | 
				
			||||||
 | 
					 * EMULEX and SLI are trademarks of Emulex.                        *
 | 
				
			||||||
 | 
					 * www.emulex.com                                                  *
 | 
				
			||||||
 | 
					 *                                                                 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or   *
 | 
				
			||||||
 | 
					 * modify it under the terms of version 2 of the GNU General       *
 | 
				
			||||||
 | 
					 * Public License as published by the Free Software Foundation.    *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful. *
 | 
				
			||||||
 | 
					 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
 | 
				
			||||||
 | 
					 * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
 | 
				
			||||||
 | 
					 * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
 | 
				
			||||||
 | 
					 * more details, a copy of which can be found in the file COPYING  *
 | 
				
			||||||
 | 
					 * included with this package.                                     *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contact Information:
 | 
				
			||||||
 | 
					 * linux-drivers@emulex.com
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Emulex
 | 
				
			||||||
 | 
					 * 3333 Susan Street
 | 
				
			||||||
 | 
					 * Costa Mesa, CA 92626
 | 
				
			||||||
 | 
					 *******************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __OCRDMA_AH_H__
 | 
				
			||||||
 | 
					#define __OCRDMA_AH_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ib_ah *ocrdma_create_ah(struct ib_pd *, struct ib_ah_attr *);
 | 
				
			||||||
 | 
					int ocrdma_destroy_ah(struct ib_ah *);
 | 
				
			||||||
 | 
					int ocrdma_query_ah(struct ib_ah *, struct ib_ah_attr *);
 | 
				
			||||||
 | 
					int ocrdma_modify_ah(struct ib_ah *, struct ib_ah_attr *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_process_mad(struct ib_device *,
 | 
				
			||||||
 | 
							       int process_mad_flags,
 | 
				
			||||||
 | 
							       u8 port_num,
 | 
				
			||||||
 | 
							       struct ib_wc *in_wc,
 | 
				
			||||||
 | 
							       struct ib_grh *in_grh,
 | 
				
			||||||
 | 
							       struct ib_mad *in_mad, struct ib_mad *out_mad);
 | 
				
			||||||
 | 
					#endif				/* __OCRDMA_AH_H__ */
 | 
				
			||||||
							
								
								
									
										2640
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_hw.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2640
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_hw.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										132
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_hw.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_hw.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,132 @@
 | 
				
			||||||
 | 
					/*******************************************************************
 | 
				
			||||||
 | 
					 * This file is part of the Emulex RoCE Device Driver for          *
 | 
				
			||||||
 | 
					 * RoCE (RDMA over Converged Ethernet) CNA Adapters.              *
 | 
				
			||||||
 | 
					 * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
 | 
				
			||||||
 | 
					 * EMULEX and SLI are trademarks of Emulex.                        *
 | 
				
			||||||
 | 
					 * www.emulex.com                                                  *
 | 
				
			||||||
 | 
					 *                                                                 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or   *
 | 
				
			||||||
 | 
					 * modify it under the terms of version 2 of the GNU General       *
 | 
				
			||||||
 | 
					 * Public License as published by the Free Software Foundation.    *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful. *
 | 
				
			||||||
 | 
					 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
 | 
				
			||||||
 | 
					 * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
 | 
				
			||||||
 | 
					 * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
 | 
				
			||||||
 | 
					 * more details, a copy of which can be found in the file COPYING  *
 | 
				
			||||||
 | 
					 * included with this package.                                     *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contact Information:
 | 
				
			||||||
 | 
					 * linux-drivers@emulex.com
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Emulex
 | 
				
			||||||
 | 
					 * 3333 Susan Street
 | 
				
			||||||
 | 
					 * Costa Mesa, CA 92626
 | 
				
			||||||
 | 
					 *******************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __OCRDMA_HW_H__
 | 
				
			||||||
 | 
					#define __OCRDMA_HW_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ocrdma_sli.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void ocrdma_cpu_to_le32(void *dst, u32 len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef __BIG_ENDIAN
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
						u32 *src_ptr = dst;
 | 
				
			||||||
 | 
						u32 *dst_ptr = dst;
 | 
				
			||||||
 | 
						for (; i < (len / 4); i++)
 | 
				
			||||||
 | 
							*(dst_ptr + i) = cpu_to_le32p(src_ptr + i);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void ocrdma_le32_to_cpu(void *dst, u32 len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef __BIG_ENDIAN
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
						u32 *src_ptr = dst;
 | 
				
			||||||
 | 
						u32 *dst_ptr = dst;
 | 
				
			||||||
 | 
						for (; i < (len / sizeof(u32)); i++)
 | 
				
			||||||
 | 
							*(dst_ptr + i) = le32_to_cpu(*(src_ptr + i));
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void ocrdma_copy_cpu_to_le32(void *dst, void *src, u32 len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef __BIG_ENDIAN
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
						u32 *src_ptr = src;
 | 
				
			||||||
 | 
						u32 *dst_ptr = dst;
 | 
				
			||||||
 | 
						for (; i < (len / sizeof(u32)); i++)
 | 
				
			||||||
 | 
							*(dst_ptr + i) = cpu_to_le32p(src_ptr + i);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						memcpy(dst, src, len);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void ocrdma_copy_le32_to_cpu(void *dst, void *src, u32 len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef __BIG_ENDIAN
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
						u32 *src_ptr = src;
 | 
				
			||||||
 | 
						u32 *dst_ptr = dst;
 | 
				
			||||||
 | 
						for (; i < len / sizeof(u32); i++)
 | 
				
			||||||
 | 
							*(dst_ptr + i) = le32_to_cpu(*(src_ptr + i));
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						memcpy(dst, src, len);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_init_hw(struct ocrdma_dev *);
 | 
				
			||||||
 | 
					void ocrdma_cleanup_hw(struct ocrdma_dev *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum ib_qp_state get_ibqp_state(enum ocrdma_qp_state qps);
 | 
				
			||||||
 | 
					void ocrdma_ring_cq_db(struct ocrdma_dev *, u16 cq_id, bool armed,
 | 
				
			||||||
 | 
							       bool solicited, u16 cqe_popped);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* verbs specific mailbox commands */
 | 
				
			||||||
 | 
					int ocrdma_query_config(struct ocrdma_dev *,
 | 
				
			||||||
 | 
								struct ocrdma_mbx_query_config *config);
 | 
				
			||||||
 | 
					int ocrdma_resolve_dgid(struct ocrdma_dev *, union ib_gid *dgid, u8 *mac_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_mbx_alloc_pd(struct ocrdma_dev *, struct ocrdma_pd *);
 | 
				
			||||||
 | 
					int ocrdma_mbx_dealloc_pd(struct ocrdma_dev *, struct ocrdma_pd *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_mbx_alloc_lkey(struct ocrdma_dev *, struct ocrdma_hw_mr *hwmr,
 | 
				
			||||||
 | 
								  u32 pd_id, int addr_check);
 | 
				
			||||||
 | 
					int ocrdma_mbx_dealloc_lkey(struct ocrdma_dev *, int fmr, u32 lkey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_reg_mr(struct ocrdma_dev *, struct ocrdma_hw_mr *hwmr,
 | 
				
			||||||
 | 
								u32 pd_id, int acc);
 | 
				
			||||||
 | 
					int ocrdma_mbx_create_cq(struct ocrdma_dev *, struct ocrdma_cq *,
 | 
				
			||||||
 | 
									int entries, int dpp_cq);
 | 
				
			||||||
 | 
					int ocrdma_mbx_destroy_cq(struct ocrdma_dev *, struct ocrdma_cq *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_mbx_create_qp(struct ocrdma_qp *, struct ib_qp_init_attr *attrs,
 | 
				
			||||||
 | 
								 u8 enable_dpp_cq, u16 dpp_cq_id, u16 *dpp_offset,
 | 
				
			||||||
 | 
								 u16 *dpp_credit_lmt);
 | 
				
			||||||
 | 
					int ocrdma_mbx_modify_qp(struct ocrdma_dev *, struct ocrdma_qp *,
 | 
				
			||||||
 | 
								 struct ib_qp_attr *attrs, int attr_mask,
 | 
				
			||||||
 | 
								 enum ib_qp_state old_qps);
 | 
				
			||||||
 | 
					int ocrdma_mbx_query_qp(struct ocrdma_dev *, struct ocrdma_qp *,
 | 
				
			||||||
 | 
								struct ocrdma_qp_params *param);
 | 
				
			||||||
 | 
					int ocrdma_mbx_destroy_qp(struct ocrdma_dev *, struct ocrdma_qp *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_mbx_create_srq(struct ocrdma_srq *,
 | 
				
			||||||
 | 
								  struct ib_srq_init_attr *,
 | 
				
			||||||
 | 
								  struct ocrdma_pd *);
 | 
				
			||||||
 | 
					int ocrdma_mbx_modify_srq(struct ocrdma_srq *, struct ib_srq_attr *);
 | 
				
			||||||
 | 
					int ocrdma_mbx_query_srq(struct ocrdma_srq *, struct ib_srq_attr *);
 | 
				
			||||||
 | 
					int ocrdma_mbx_destroy_srq(struct ocrdma_dev *, struct ocrdma_srq *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_alloc_av(struct ocrdma_dev *, struct ocrdma_ah *);
 | 
				
			||||||
 | 
					int ocrdma_free_av(struct ocrdma_dev *, struct ocrdma_ah *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_qp_state_machine(struct ocrdma_qp *, enum ib_qp_state new_state,
 | 
				
			||||||
 | 
								    enum ib_qp_state *old_ib_state);
 | 
				
			||||||
 | 
					bool ocrdma_is_qp_in_sq_flushlist(struct ocrdma_cq *, struct ocrdma_qp *);
 | 
				
			||||||
 | 
					bool ocrdma_is_qp_in_rq_flushlist(struct ocrdma_cq *, struct ocrdma_qp *);
 | 
				
			||||||
 | 
					void ocrdma_flush_qp(struct ocrdma_qp *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif				/* __OCRDMA_HW_H__ */
 | 
				
			||||||
							
								
								
									
										558
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										558
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_main.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,558 @@
 | 
				
			||||||
 | 
					/*******************************************************************
 | 
				
			||||||
 | 
					 * This file is part of the Emulex RoCE Device Driver for          *
 | 
				
			||||||
 | 
					 * RoCE (RDMA over Converged Ethernet) adapters.                   *
 | 
				
			||||||
 | 
					 * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
 | 
				
			||||||
 | 
					 * EMULEX and SLI are trademarks of Emulex.                        *
 | 
				
			||||||
 | 
					 * www.emulex.com                                                  *
 | 
				
			||||||
 | 
					 *                                                                 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or   *
 | 
				
			||||||
 | 
					 * modify it under the terms of version 2 of the GNU General       *
 | 
				
			||||||
 | 
					 * Public License as published by the Free Software Foundation.    *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful. *
 | 
				
			||||||
 | 
					 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
 | 
				
			||||||
 | 
					 * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
 | 
				
			||||||
 | 
					 * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
 | 
				
			||||||
 | 
					 * more details, a copy of which can be found in the file COPYING  *
 | 
				
			||||||
 | 
					 * included with this package.                                     *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contact Information:
 | 
				
			||||||
 | 
					 * linux-drivers@emulex.com
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Emulex
 | 
				
			||||||
 | 
					 * 3333 Susan Street
 | 
				
			||||||
 | 
					 * Costa Mesa, CA 92626
 | 
				
			||||||
 | 
					 *******************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/version.h>
 | 
				
			||||||
 | 
					#include <linux/idr.h>
 | 
				
			||||||
 | 
					#include <rdma/ib_verbs.h>
 | 
				
			||||||
 | 
					#include <rdma/ib_user_verbs.h>
 | 
				
			||||||
 | 
					#include <rdma/ib_addr.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/netdevice.h>
 | 
				
			||||||
 | 
					#include <net/addrconf.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ocrdma.h"
 | 
				
			||||||
 | 
					#include "ocrdma_verbs.h"
 | 
				
			||||||
 | 
					#include "ocrdma_ah.h"
 | 
				
			||||||
 | 
					#include "be_roce.h"
 | 
				
			||||||
 | 
					#include "ocrdma_hw.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_VERSION(OCRDMA_ROCE_DEV_VERSION);
 | 
				
			||||||
 | 
					MODULE_DESCRIPTION("Emulex RoCE HCA Driver");
 | 
				
			||||||
 | 
					MODULE_AUTHOR("Emulex Corporation");
 | 
				
			||||||
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static LIST_HEAD(ocrdma_dev_list);
 | 
				
			||||||
 | 
					static DEFINE_MUTEX(ocrdma_devlist_lock);
 | 
				
			||||||
 | 
					static DEFINE_IDR(ocrdma_dev_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static union ib_gid ocrdma_zero_sgid;
 | 
				
			||||||
 | 
					static int ocrdma_inet6addr_event(struct notifier_block *,
 | 
				
			||||||
 | 
									  unsigned long, void *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct notifier_block ocrdma_inet6addr_notifier = {
 | 
				
			||||||
 | 
						.notifier_call = ocrdma_inet6addr_event
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_get_instance(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int instance = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Assign an unused number */
 | 
				
			||||||
 | 
						if (!idr_pre_get(&ocrdma_dev_id, GFP_KERNEL))
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						if (idr_get_new(&ocrdma_dev_id, NULL, &instance))
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						return instance;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ocrdma_get_guid(struct ocrdma_dev *dev, u8 *guid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 mac_addr[6];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(&mac_addr[0], &dev->nic_info.mac_addr[0], ETH_ALEN);
 | 
				
			||||||
 | 
						guid[0] = mac_addr[0] ^ 2;
 | 
				
			||||||
 | 
						guid[1] = mac_addr[1];
 | 
				
			||||||
 | 
						guid[2] = mac_addr[2];
 | 
				
			||||||
 | 
						guid[3] = 0xff;
 | 
				
			||||||
 | 
						guid[4] = 0xfe;
 | 
				
			||||||
 | 
						guid[5] = mac_addr[3];
 | 
				
			||||||
 | 
						guid[6] = mac_addr[4];
 | 
				
			||||||
 | 
						guid[7] = mac_addr[5];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ocrdma_build_sgid_mac(union ib_gid *sgid, unsigned char *mac_addr,
 | 
				
			||||||
 | 
									  bool is_vlan, u16 vlan_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						sgid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
 | 
				
			||||||
 | 
						sgid->raw[8] = mac_addr[0] ^ 2;
 | 
				
			||||||
 | 
						sgid->raw[9] = mac_addr[1];
 | 
				
			||||||
 | 
						sgid->raw[10] = mac_addr[2];
 | 
				
			||||||
 | 
						if (is_vlan) {
 | 
				
			||||||
 | 
							sgid->raw[11] = vlan_id >> 8;
 | 
				
			||||||
 | 
							sgid->raw[12] = vlan_id & 0xff;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							sgid->raw[11] = 0xff;
 | 
				
			||||||
 | 
							sgid->raw[12] = 0xfe;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sgid->raw[13] = mac_addr[3];
 | 
				
			||||||
 | 
						sgid->raw[14] = mac_addr[4];
 | 
				
			||||||
 | 
						sgid->raw[15] = mac_addr[5];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ocrdma_add_sgid(struct ocrdma_dev *dev, unsigned char *mac_addr,
 | 
				
			||||||
 | 
								    bool is_vlan, u16 vlan_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						bool found = false;
 | 
				
			||||||
 | 
						union ib_gid new_sgid;
 | 
				
			||||||
 | 
						int free_idx = OCRDMA_MAX_SGID;
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&ocrdma_zero_sgid, 0, sizeof(union ib_gid));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ocrdma_build_sgid_mac(&new_sgid, mac_addr, is_vlan, vlan_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irqsave(&dev->sgid_lock, flags);
 | 
				
			||||||
 | 
						for (i = 0; i < OCRDMA_MAX_SGID; i++) {
 | 
				
			||||||
 | 
							if (!memcmp(&dev->sgid_tbl[i], &ocrdma_zero_sgid,
 | 
				
			||||||
 | 
								    sizeof(union ib_gid))) {
 | 
				
			||||||
 | 
								/* found free entry */
 | 
				
			||||||
 | 
								if (!found) {
 | 
				
			||||||
 | 
									free_idx = i;
 | 
				
			||||||
 | 
									found = true;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else if (!memcmp(&dev->sgid_tbl[i], &new_sgid,
 | 
				
			||||||
 | 
									   sizeof(union ib_gid))) {
 | 
				
			||||||
 | 
								/* entry already present, no addition is required. */
 | 
				
			||||||
 | 
								spin_unlock_irqrestore(&dev->sgid_lock, flags);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						/* if entry doesn't exist and if table has some space, add entry */
 | 
				
			||||||
 | 
						if (found)
 | 
				
			||||||
 | 
							memcpy(&dev->sgid_tbl[free_idx], &new_sgid,
 | 
				
			||||||
 | 
							       sizeof(union ib_gid));
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&dev->sgid_lock, flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool ocrdma_del_sgid(struct ocrdma_dev *dev, unsigned char *mac_addr,
 | 
				
			||||||
 | 
								    bool is_vlan, u16 vlan_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int found = false;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						union ib_gid sgid;
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ocrdma_build_sgid_mac(&sgid, mac_addr, is_vlan, vlan_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irqsave(&dev->sgid_lock, flags);
 | 
				
			||||||
 | 
						/* first is default sgid, which cannot be deleted. */
 | 
				
			||||||
 | 
						for (i = 1; i < OCRDMA_MAX_SGID; i++) {
 | 
				
			||||||
 | 
							if (!memcmp(&dev->sgid_tbl[i], &sgid, sizeof(union ib_gid))) {
 | 
				
			||||||
 | 
								/* found matching entry */
 | 
				
			||||||
 | 
								memset(&dev->sgid_tbl[i], 0, sizeof(union ib_gid));
 | 
				
			||||||
 | 
								found = true;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&dev->sgid_lock, flags);
 | 
				
			||||||
 | 
						return found;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ocrdma_add_default_sgid(struct ocrdma_dev *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* GID Index 0 - Invariant manufacturer-assigned EUI-64 */
 | 
				
			||||||
 | 
						union ib_gid *sgid = &dev->sgid_tbl[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sgid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
 | 
				
			||||||
 | 
						ocrdma_get_guid(dev, &sgid->raw[8]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ocrdma_build_sgid_tbl(struct ocrdma_dev *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct net_device *netdev, *tmp;
 | 
				
			||||||
 | 
						u16 vlan_id;
 | 
				
			||||||
 | 
						bool is_vlan;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						netdev = dev->nic_info.netdev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ocrdma_add_default_sgid(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rcu_read_lock();
 | 
				
			||||||
 | 
						for_each_netdev_rcu(&init_net, tmp) {
 | 
				
			||||||
 | 
							if (netdev == tmp || vlan_dev_real_dev(tmp) == netdev) {
 | 
				
			||||||
 | 
								if (!netif_running(tmp) || !netif_oper_up(tmp))
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								if (netdev != tmp) {
 | 
				
			||||||
 | 
									vlan_id = vlan_dev_vlan_id(tmp);
 | 
				
			||||||
 | 
									is_vlan = true;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									is_vlan = false;
 | 
				
			||||||
 | 
									vlan_id = 0;
 | 
				
			||||||
 | 
									tmp = netdev;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ocrdma_add_sgid(dev, tmp->dev_addr, is_vlan, vlan_id);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ocrdma_inet6addr_event(struct notifier_block *notifier,
 | 
				
			||||||
 | 
									  unsigned long event, void *ptr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
 | 
				
			||||||
 | 
						struct net_device *event_netdev = ifa->idev->dev;
 | 
				
			||||||
 | 
						struct net_device *netdev = NULL;
 | 
				
			||||||
 | 
						struct ib_event gid_event;
 | 
				
			||||||
 | 
						struct ocrdma_dev *dev;
 | 
				
			||||||
 | 
						bool found = false;
 | 
				
			||||||
 | 
						bool is_vlan = false;
 | 
				
			||||||
 | 
						u16 vid = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						netdev = vlan_dev_real_dev(event_netdev);
 | 
				
			||||||
 | 
						if (netdev != event_netdev) {
 | 
				
			||||||
 | 
							is_vlan = true;
 | 
				
			||||||
 | 
							vid = vlan_dev_vlan_id(event_netdev);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mutex_lock(&ocrdma_devlist_lock);
 | 
				
			||||||
 | 
						list_for_each_entry(dev, &ocrdma_dev_list, entry) {
 | 
				
			||||||
 | 
							if (dev->nic_info.netdev == netdev) {
 | 
				
			||||||
 | 
								found = true;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mutex_unlock(&ocrdma_devlist_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!found)
 | 
				
			||||||
 | 
							return NOTIFY_DONE;
 | 
				
			||||||
 | 
						if (!rdma_link_local_addr((struct in6_addr *)&ifa->addr))
 | 
				
			||||||
 | 
							return NOTIFY_DONE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&dev->dev_lock);
 | 
				
			||||||
 | 
						switch (event) {
 | 
				
			||||||
 | 
						case NETDEV_UP:
 | 
				
			||||||
 | 
							ocrdma_add_sgid(dev, netdev->dev_addr, is_vlan, vid);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case NETDEV_DOWN:
 | 
				
			||||||
 | 
							found = ocrdma_del_sgid(dev, netdev->dev_addr, is_vlan, vid);
 | 
				
			||||||
 | 
							if (found) {
 | 
				
			||||||
 | 
								/* found the matching entry, notify
 | 
				
			||||||
 | 
								 * the consumers about it
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								gid_event.device = &dev->ibdev;
 | 
				
			||||||
 | 
								gid_event.element.port_num = 1;
 | 
				
			||||||
 | 
								gid_event.event = IB_EVENT_GID_CHANGE;
 | 
				
			||||||
 | 
								ib_dispatch_event(&gid_event);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mutex_unlock(&dev->dev_lock);
 | 
				
			||||||
 | 
						return NOTIFY_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static enum rdma_link_layer ocrdma_link_layer(struct ib_device *device,
 | 
				
			||||||
 | 
										      u8 port_num)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return IB_LINK_LAYER_ETHERNET;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_register_device(struct ocrdma_dev *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						strlcpy(dev->ibdev.name, "ocrdma%d", IB_DEVICE_NAME_MAX);
 | 
				
			||||||
 | 
						ocrdma_get_guid(dev, (u8 *)&dev->ibdev.node_guid);
 | 
				
			||||||
 | 
						memcpy(dev->ibdev.node_desc, OCRDMA_NODE_DESC,
 | 
				
			||||||
 | 
						       sizeof(OCRDMA_NODE_DESC));
 | 
				
			||||||
 | 
						dev->ibdev.owner = THIS_MODULE;
 | 
				
			||||||
 | 
						dev->ibdev.uverbs_cmd_mask =
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(GET_CONTEXT) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(QUERY_DEVICE) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(QUERY_PORT) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(ALLOC_PD) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(DEALLOC_PD) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(REG_MR) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(DEREG_MR) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(CREATE_COMP_CHANNEL) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(CREATE_CQ) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(RESIZE_CQ) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(DESTROY_CQ) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(REQ_NOTIFY_CQ) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(CREATE_QP) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(MODIFY_QP) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(QUERY_QP) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(DESTROY_QP) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(POLL_CQ) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(POST_SEND) |
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(POST_RECV);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev->ibdev.uverbs_cmd_mask |=
 | 
				
			||||||
 | 
						    OCRDMA_UVERBS(CREATE_AH) |
 | 
				
			||||||
 | 
						     OCRDMA_UVERBS(MODIFY_AH) |
 | 
				
			||||||
 | 
						     OCRDMA_UVERBS(QUERY_AH) |
 | 
				
			||||||
 | 
						     OCRDMA_UVERBS(DESTROY_AH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev->ibdev.node_type = RDMA_NODE_IB_CA;
 | 
				
			||||||
 | 
						dev->ibdev.phys_port_cnt = 1;
 | 
				
			||||||
 | 
						dev->ibdev.num_comp_vectors = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* mandatory verbs. */
 | 
				
			||||||
 | 
						dev->ibdev.query_device = ocrdma_query_device;
 | 
				
			||||||
 | 
						dev->ibdev.query_port = ocrdma_query_port;
 | 
				
			||||||
 | 
						dev->ibdev.modify_port = ocrdma_modify_port;
 | 
				
			||||||
 | 
						dev->ibdev.query_gid = ocrdma_query_gid;
 | 
				
			||||||
 | 
						dev->ibdev.get_link_layer = ocrdma_link_layer;
 | 
				
			||||||
 | 
						dev->ibdev.alloc_pd = ocrdma_alloc_pd;
 | 
				
			||||||
 | 
						dev->ibdev.dealloc_pd = ocrdma_dealloc_pd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev->ibdev.create_cq = ocrdma_create_cq;
 | 
				
			||||||
 | 
						dev->ibdev.destroy_cq = ocrdma_destroy_cq;
 | 
				
			||||||
 | 
						dev->ibdev.resize_cq = ocrdma_resize_cq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev->ibdev.create_qp = ocrdma_create_qp;
 | 
				
			||||||
 | 
						dev->ibdev.modify_qp = ocrdma_modify_qp;
 | 
				
			||||||
 | 
						dev->ibdev.query_qp = ocrdma_query_qp;
 | 
				
			||||||
 | 
						dev->ibdev.destroy_qp = ocrdma_destroy_qp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev->ibdev.query_pkey = ocrdma_query_pkey;
 | 
				
			||||||
 | 
						dev->ibdev.create_ah = ocrdma_create_ah;
 | 
				
			||||||
 | 
						dev->ibdev.destroy_ah = ocrdma_destroy_ah;
 | 
				
			||||||
 | 
						dev->ibdev.query_ah = ocrdma_query_ah;
 | 
				
			||||||
 | 
						dev->ibdev.modify_ah = ocrdma_modify_ah;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev->ibdev.poll_cq = ocrdma_poll_cq;
 | 
				
			||||||
 | 
						dev->ibdev.post_send = ocrdma_post_send;
 | 
				
			||||||
 | 
						dev->ibdev.post_recv = ocrdma_post_recv;
 | 
				
			||||||
 | 
						dev->ibdev.req_notify_cq = ocrdma_arm_cq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev->ibdev.get_dma_mr = ocrdma_get_dma_mr;
 | 
				
			||||||
 | 
						dev->ibdev.dereg_mr = ocrdma_dereg_mr;
 | 
				
			||||||
 | 
						dev->ibdev.reg_user_mr = ocrdma_reg_user_mr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* mandatory to support user space verbs consumer. */
 | 
				
			||||||
 | 
						dev->ibdev.alloc_ucontext = ocrdma_alloc_ucontext;
 | 
				
			||||||
 | 
						dev->ibdev.dealloc_ucontext = ocrdma_dealloc_ucontext;
 | 
				
			||||||
 | 
						dev->ibdev.mmap = ocrdma_mmap;
 | 
				
			||||||
 | 
						dev->ibdev.dma_device = &dev->nic_info.pdev->dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev->ibdev.process_mad = ocrdma_process_mad;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
 | 
				
			||||||
 | 
							dev->ibdev.uverbs_cmd_mask |=
 | 
				
			||||||
 | 
							     OCRDMA_UVERBS(CREATE_SRQ) |
 | 
				
			||||||
 | 
							     OCRDMA_UVERBS(MODIFY_SRQ) |
 | 
				
			||||||
 | 
							     OCRDMA_UVERBS(QUERY_SRQ) |
 | 
				
			||||||
 | 
							     OCRDMA_UVERBS(DESTROY_SRQ) |
 | 
				
			||||||
 | 
							     OCRDMA_UVERBS(POST_SRQ_RECV);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dev->ibdev.create_srq = ocrdma_create_srq;
 | 
				
			||||||
 | 
							dev->ibdev.modify_srq = ocrdma_modify_srq;
 | 
				
			||||||
 | 
							dev->ibdev.query_srq = ocrdma_query_srq;
 | 
				
			||||||
 | 
							dev->ibdev.destroy_srq = ocrdma_destroy_srq;
 | 
				
			||||||
 | 
							dev->ibdev.post_srq_recv = ocrdma_post_srq_recv;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ib_register_device(&dev->ibdev, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ocrdma_alloc_resources(struct ocrdma_dev *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						mutex_init(&dev->dev_lock);
 | 
				
			||||||
 | 
						dev->sgid_tbl = kzalloc(sizeof(union ib_gid) *
 | 
				
			||||||
 | 
									OCRDMA_MAX_SGID, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!dev->sgid_tbl)
 | 
				
			||||||
 | 
							goto alloc_err;
 | 
				
			||||||
 | 
						spin_lock_init(&dev->sgid_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev->cq_tbl = kzalloc(sizeof(struct ocrdma_cq *) *
 | 
				
			||||||
 | 
								      OCRDMA_MAX_CQ, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!dev->cq_tbl)
 | 
				
			||||||
 | 
							goto alloc_err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dev->attr.max_qp) {
 | 
				
			||||||
 | 
							dev->qp_tbl = kzalloc(sizeof(struct ocrdma_qp *) *
 | 
				
			||||||
 | 
									      OCRDMA_MAX_QP, GFP_KERNEL);
 | 
				
			||||||
 | 
							if (!dev->qp_tbl)
 | 
				
			||||||
 | 
								goto alloc_err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spin_lock_init(&dev->av_tbl.lock);
 | 
				
			||||||
 | 
						spin_lock_init(&dev->flush_q_lock);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					alloc_err:
 | 
				
			||||||
 | 
						ocrdma_err("%s(%d) error.\n", __func__, dev->id);
 | 
				
			||||||
 | 
						return -ENOMEM;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ocrdma_free_resources(struct ocrdma_dev *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						kfree(dev->qp_tbl);
 | 
				
			||||||
 | 
						kfree(dev->cq_tbl);
 | 
				
			||||||
 | 
						kfree(dev->sgid_tbl);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int status = 0;
 | 
				
			||||||
 | 
						struct ocrdma_dev *dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev = (struct ocrdma_dev *)ib_alloc_device(sizeof(struct ocrdma_dev));
 | 
				
			||||||
 | 
						if (!dev) {
 | 
				
			||||||
 | 
							ocrdma_err("Unable to allocate ib device\n");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						dev->mbx_cmd = kzalloc(sizeof(struct ocrdma_mqe_emb_cmd), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!dev->mbx_cmd)
 | 
				
			||||||
 | 
							goto idr_err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(&dev->nic_info, dev_info, sizeof(*dev_info));
 | 
				
			||||||
 | 
						dev->id = ocrdma_get_instance();
 | 
				
			||||||
 | 
						if (dev->id < 0)
 | 
				
			||||||
 | 
							goto idr_err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = ocrdma_init_hw(dev);
 | 
				
			||||||
 | 
						if (status)
 | 
				
			||||||
 | 
							goto init_err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = ocrdma_alloc_resources(dev);
 | 
				
			||||||
 | 
						if (status)
 | 
				
			||||||
 | 
							goto alloc_err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = ocrdma_build_sgid_tbl(dev);
 | 
				
			||||||
 | 
						if (status)
 | 
				
			||||||
 | 
							goto alloc_err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = ocrdma_register_device(dev);
 | 
				
			||||||
 | 
						if (status)
 | 
				
			||||||
 | 
							goto alloc_err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&ocrdma_devlist_lock);
 | 
				
			||||||
 | 
						list_add_tail(&dev->entry, &ocrdma_dev_list);
 | 
				
			||||||
 | 
						mutex_unlock(&ocrdma_devlist_lock);
 | 
				
			||||||
 | 
						return dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					alloc_err:
 | 
				
			||||||
 | 
						ocrdma_free_resources(dev);
 | 
				
			||||||
 | 
						ocrdma_cleanup_hw(dev);
 | 
				
			||||||
 | 
					init_err:
 | 
				
			||||||
 | 
						idr_remove(&ocrdma_dev_id, dev->id);
 | 
				
			||||||
 | 
					idr_err:
 | 
				
			||||||
 | 
						kfree(dev->mbx_cmd);
 | 
				
			||||||
 | 
						ib_dealloc_device(&dev->ibdev);
 | 
				
			||||||
 | 
						ocrdma_err("%s() leaving. ret=%d\n", __func__, status);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ocrdma_remove(struct ocrdma_dev *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* first unregister with stack to stop all the active traffic
 | 
				
			||||||
 | 
						 * of the registered clients.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						ib_unregister_device(&dev->ibdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&ocrdma_devlist_lock);
 | 
				
			||||||
 | 
						list_del(&dev->entry);
 | 
				
			||||||
 | 
						mutex_unlock(&ocrdma_devlist_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ocrdma_free_resources(dev);
 | 
				
			||||||
 | 
						ocrdma_cleanup_hw(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						idr_remove(&ocrdma_dev_id, dev->id);
 | 
				
			||||||
 | 
						kfree(dev->mbx_cmd);
 | 
				
			||||||
 | 
						ib_dealloc_device(&dev->ibdev);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ocrdma_open(struct ocrdma_dev *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ib_event port_event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						port_event.event = IB_EVENT_PORT_ACTIVE;
 | 
				
			||||||
 | 
						port_event.element.port_num = 1;
 | 
				
			||||||
 | 
						port_event.device = &dev->ibdev;
 | 
				
			||||||
 | 
						ib_dispatch_event(&port_event);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ocrdma_close(struct ocrdma_dev *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						struct ocrdma_qp *qp, **cur_qp;
 | 
				
			||||||
 | 
						struct ib_event err_event;
 | 
				
			||||||
 | 
						struct ib_qp_attr attrs;
 | 
				
			||||||
 | 
						int attr_mask = IB_QP_STATE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						attrs.qp_state = IB_QPS_ERR;
 | 
				
			||||||
 | 
						mutex_lock(&dev->dev_lock);
 | 
				
			||||||
 | 
						if (dev->qp_tbl) {
 | 
				
			||||||
 | 
							cur_qp = dev->qp_tbl;
 | 
				
			||||||
 | 
							for (i = 0; i < OCRDMA_MAX_QP; i++) {
 | 
				
			||||||
 | 
								qp = cur_qp[i];
 | 
				
			||||||
 | 
								if (qp) {
 | 
				
			||||||
 | 
									/* change the QP state to ERROR */
 | 
				
			||||||
 | 
									_ocrdma_modify_qp(&qp->ibqp, &attrs, attr_mask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									err_event.event = IB_EVENT_QP_FATAL;
 | 
				
			||||||
 | 
									err_event.element.qp = &qp->ibqp;
 | 
				
			||||||
 | 
									err_event.device = &dev->ibdev;
 | 
				
			||||||
 | 
									ib_dispatch_event(&err_event);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mutex_unlock(&dev->dev_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err_event.event = IB_EVENT_PORT_ERR;
 | 
				
			||||||
 | 
						err_event.element.port_num = 1;
 | 
				
			||||||
 | 
						err_event.device = &dev->ibdev;
 | 
				
			||||||
 | 
						ib_dispatch_event(&err_event);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* event handling via NIC driver ensures that all the NIC specific
 | 
				
			||||||
 | 
					 * initialization done before RoCE driver notifies
 | 
				
			||||||
 | 
					 * event to stack.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void ocrdma_event_handler(struct ocrdma_dev *dev, u32 event)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (event) {
 | 
				
			||||||
 | 
						case BE_DEV_UP:
 | 
				
			||||||
 | 
							ocrdma_open(dev);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case BE_DEV_DOWN:
 | 
				
			||||||
 | 
							ocrdma_close(dev);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ocrdma_driver ocrdma_drv = {
 | 
				
			||||||
 | 
						.name			= "ocrdma_driver",
 | 
				
			||||||
 | 
						.add			= ocrdma_add,
 | 
				
			||||||
 | 
						.remove			= ocrdma_remove,
 | 
				
			||||||
 | 
						.state_change_handler	= ocrdma_event_handler,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int __init ocrdma_init_module(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = register_inet6addr_notifier(&ocrdma_inet6addr_notifier);
 | 
				
			||||||
 | 
						if (status)
 | 
				
			||||||
 | 
							return status;
 | 
				
			||||||
 | 
						status = be_roce_register_driver(&ocrdma_drv);
 | 
				
			||||||
 | 
						if (status)
 | 
				
			||||||
 | 
							unregister_inet6addr_notifier(&ocrdma_inet6addr_notifier);
 | 
				
			||||||
 | 
						return status;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void __exit ocrdma_exit_module(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						be_roce_unregister_driver(&ocrdma_drv);
 | 
				
			||||||
 | 
						unregister_inet6addr_notifier(&ocrdma_inet6addr_notifier);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module_init(ocrdma_init_module);
 | 
				
			||||||
 | 
					module_exit(ocrdma_exit_module);
 | 
				
			||||||
							
								
								
									
										1672
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_sli.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1672
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_sli.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										2542
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2542
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										94
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_verbs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								drivers/infiniband/hw/ocrdma/ocrdma_verbs.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,94 @@
 | 
				
			||||||
 | 
					/*******************************************************************
 | 
				
			||||||
 | 
					 * This file is part of the Emulex RoCE Device Driver for          *
 | 
				
			||||||
 | 
					 * RoCE (RDMA over Converged Ethernet) adapters.                   *
 | 
				
			||||||
 | 
					 * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
 | 
				
			||||||
 | 
					 * EMULEX and SLI are trademarks of Emulex.                        *
 | 
				
			||||||
 | 
					 * www.emulex.com                                                  *
 | 
				
			||||||
 | 
					 *                                                                 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or   *
 | 
				
			||||||
 | 
					 * modify it under the terms of version 2 of the GNU General       *
 | 
				
			||||||
 | 
					 * Public License as published by the Free Software Foundation.    *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful. *
 | 
				
			||||||
 | 
					 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
 | 
				
			||||||
 | 
					 * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
 | 
				
			||||||
 | 
					 * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
 | 
				
			||||||
 | 
					 * more details, a copy of which can be found in the file COPYING  *
 | 
				
			||||||
 | 
					 * included with this package.                                     *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contact Information:
 | 
				
			||||||
 | 
					 * linux-drivers@emulex.com
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Emulex
 | 
				
			||||||
 | 
					 * 3333 Susan Street
 | 
				
			||||||
 | 
					 * Costa Mesa, CA 92626
 | 
				
			||||||
 | 
					 *******************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __OCRDMA_VERBS_H__
 | 
				
			||||||
 | 
					#define __OCRDMA_VERBS_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/version.h>
 | 
				
			||||||
 | 
					int ocrdma_post_send(struct ib_qp *, struct ib_send_wr *,
 | 
				
			||||||
 | 
							     struct ib_send_wr **bad_wr);
 | 
				
			||||||
 | 
					int ocrdma_post_recv(struct ib_qp *, struct ib_recv_wr *,
 | 
				
			||||||
 | 
							     struct ib_recv_wr **bad_wr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_poll_cq(struct ib_cq *, int num_entries, struct ib_wc *wc);
 | 
				
			||||||
 | 
					int ocrdma_arm_cq(struct ib_cq *, enum ib_cq_notify_flags flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_query_device(struct ib_device *, struct ib_device_attr *props);
 | 
				
			||||||
 | 
					int ocrdma_query_port(struct ib_device *, u8 port, struct ib_port_attr *props);
 | 
				
			||||||
 | 
					int ocrdma_modify_port(struct ib_device *, u8 port, int mask,
 | 
				
			||||||
 | 
							       struct ib_port_modify *props);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ocrdma_get_guid(struct ocrdma_dev *, u8 *guid);
 | 
				
			||||||
 | 
					int ocrdma_query_gid(struct ib_device *, u8 port,
 | 
				
			||||||
 | 
							     int index, union ib_gid *gid);
 | 
				
			||||||
 | 
					int ocrdma_query_pkey(struct ib_device *, u8 port, u16 index, u16 *pkey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *,
 | 
				
			||||||
 | 
										  struct ib_udata *);
 | 
				
			||||||
 | 
					int ocrdma_dealloc_ucontext(struct ib_ucontext *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_mmap(struct ib_ucontext *, struct vm_area_struct *vma);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ib_pd *ocrdma_alloc_pd(struct ib_device *,
 | 
				
			||||||
 | 
								      struct ib_ucontext *, struct ib_udata *);
 | 
				
			||||||
 | 
					int ocrdma_dealloc_pd(struct ib_pd *pd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ib_cq *ocrdma_create_cq(struct ib_device *, int entries, int vector,
 | 
				
			||||||
 | 
								       struct ib_ucontext *, struct ib_udata *);
 | 
				
			||||||
 | 
					int ocrdma_resize_cq(struct ib_cq *, int cqe, struct ib_udata *);
 | 
				
			||||||
 | 
					int ocrdma_destroy_cq(struct ib_cq *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ib_qp *ocrdma_create_qp(struct ib_pd *,
 | 
				
			||||||
 | 
								       struct ib_qp_init_attr *attrs,
 | 
				
			||||||
 | 
								       struct ib_udata *);
 | 
				
			||||||
 | 
					int _ocrdma_modify_qp(struct ib_qp *, struct ib_qp_attr *attr,
 | 
				
			||||||
 | 
							      int attr_mask);
 | 
				
			||||||
 | 
					int ocrdma_modify_qp(struct ib_qp *, struct ib_qp_attr *attr,
 | 
				
			||||||
 | 
							     int attr_mask, struct ib_udata *udata);
 | 
				
			||||||
 | 
					int ocrdma_query_qp(struct ib_qp *,
 | 
				
			||||||
 | 
							    struct ib_qp_attr *qp_attr,
 | 
				
			||||||
 | 
							    int qp_attr_mask, struct ib_qp_init_attr *);
 | 
				
			||||||
 | 
					int ocrdma_destroy_qp(struct ib_qp *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ib_srq *ocrdma_create_srq(struct ib_pd *, struct ib_srq_init_attr *,
 | 
				
			||||||
 | 
									 struct ib_udata *);
 | 
				
			||||||
 | 
					int ocrdma_modify_srq(struct ib_srq *, struct ib_srq_attr *,
 | 
				
			||||||
 | 
							      enum ib_srq_attr_mask, struct ib_udata *);
 | 
				
			||||||
 | 
					int ocrdma_query_srq(struct ib_srq *, struct ib_srq_attr *);
 | 
				
			||||||
 | 
					int ocrdma_destroy_srq(struct ib_srq *);
 | 
				
			||||||
 | 
					int ocrdma_post_srq_recv(struct ib_srq *, struct ib_recv_wr *,
 | 
				
			||||||
 | 
								 struct ib_recv_wr **bad_recv_wr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ocrdma_dereg_mr(struct ib_mr *);
 | 
				
			||||||
 | 
					struct ib_mr *ocrdma_get_dma_mr(struct ib_pd *, int acc);
 | 
				
			||||||
 | 
					struct ib_mr *ocrdma_reg_kernel_mr(struct ib_pd *,
 | 
				
			||||||
 | 
									   struct ib_phys_buf *buffer_list,
 | 
				
			||||||
 | 
									   int num_phys_buf, int acc, u64 *iova_start);
 | 
				
			||||||
 | 
					struct ib_mr *ocrdma_reg_user_mr(struct ib_pd *, u64 start, u64 length,
 | 
				
			||||||
 | 
									 u64 virt, int acc, struct ib_udata *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif				/* __OCRDMA_VERBS_H__ */
 | 
				
			||||||
		Loading…
	
		Reference in a new issue