Path: blob/master/drivers/infiniband/hw/ehca/ehca_main.c
15112 views
/*1* IBM eServer eHCA Infiniband device driver for Linux on POWER2*3* module start stop, hca detection4*5* Authors: Heiko J Schick <[email protected]>6* Hoang-Nam Nguyen <[email protected]>7* Joachim Fenkes <[email protected]>8*9* Copyright (c) 2005 IBM Corporation10*11* All rights reserved.12*13* This source code is distributed under a dual license of GPL v2.0 and OpenIB14* BSD.15*16* OpenIB BSD License17*18* Redistribution and use in source and binary forms, with or without19* modification, are permitted provided that the following conditions are met:20*21* Redistributions of source code must retain the above copyright notice, this22* list of conditions and the following disclaimer.23*24* Redistributions in binary form must reproduce the above copyright notice,25* this list of conditions and the following disclaimer in the documentation26* and/or other materials27* provided with the distribution.28*29* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"30* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE31* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE32* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE33* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR34* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF35* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR36* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER37* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)38* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE39* POSSIBILITY OF SUCH DAMAGE.40*/4142#ifdef CONFIG_PPC_64K_PAGES43#include <linux/slab.h>44#endif4546#include <linux/notifier.h>47#include <linux/memory.h>48#include "ehca_classes.h"49#include "ehca_iverbs.h"50#include "ehca_mrmw.h"51#include "ehca_tools.h"52#include "hcp_if.h"5354#define HCAD_VERSION "0029"5556MODULE_LICENSE("Dual BSD/GPL");57MODULE_AUTHOR("Christoph Raisch <[email protected]>");58MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");59MODULE_VERSION(HCAD_VERSION);6061static int ehca_open_aqp1 = 0;62static int ehca_hw_level = 0;63static int ehca_poll_all_eqs = 1;6465int ehca_debug_level = 0;66int ehca_nr_ports = -1;67int ehca_use_hp_mr = 0;68int ehca_port_act_time = 30;69int ehca_static_rate = -1;70int ehca_scaling_code = 0;71int ehca_lock_hcalls = -1;72int ehca_max_cq = -1;73int ehca_max_qp = -1;7475module_param_named(open_aqp1, ehca_open_aqp1, bool, S_IRUGO);76module_param_named(debug_level, ehca_debug_level, int, S_IRUGO);77module_param_named(hw_level, ehca_hw_level, int, S_IRUGO);78module_param_named(nr_ports, ehca_nr_ports, int, S_IRUGO);79module_param_named(use_hp_mr, ehca_use_hp_mr, bool, S_IRUGO);80module_param_named(port_act_time, ehca_port_act_time, int, S_IRUGO);81module_param_named(poll_all_eqs, ehca_poll_all_eqs, bool, S_IRUGO);82module_param_named(static_rate, ehca_static_rate, int, S_IRUGO);83module_param_named(scaling_code, ehca_scaling_code, bool, S_IRUGO);84module_param_named(lock_hcalls, ehca_lock_hcalls, bool, S_IRUGO);85module_param_named(number_of_cqs, ehca_max_cq, int, S_IRUGO);86module_param_named(number_of_qps, ehca_max_qp, int, S_IRUGO);8788MODULE_PARM_DESC(open_aqp1,89"Open AQP1 on startup (default: no)");90MODULE_PARM_DESC(debug_level,91"Amount of debug output (0: none (default), 1: traces, "92"2: some dumps, 3: lots)");93MODULE_PARM_DESC(hw_level,94"Hardware level (0: autosensing (default), "95"0x10..0x14: eHCA, 0x20..0x23: eHCA2)");96MODULE_PARM_DESC(nr_ports,97"number of connected ports (-1: autodetect (default), "98"1: port one only, 2: two ports)");99MODULE_PARM_DESC(use_hp_mr,100"Use high performance MRs (default: no)");101MODULE_PARM_DESC(port_act_time,102"Time to wait for port activation (default: 30 sec)");103MODULE_PARM_DESC(poll_all_eqs,104"Poll all event queues periodically (default: yes)");105MODULE_PARM_DESC(static_rate,106"Set permanent static rate (default: no static rate)");107MODULE_PARM_DESC(scaling_code,108"Enable scaling code (default: no)");109MODULE_PARM_DESC(lock_hcalls,110"Serialize all hCalls made by the driver "111"(default: autodetect)");112MODULE_PARM_DESC(number_of_cqs,113"Max number of CQs which can be allocated "114"(default: autodetect)");115MODULE_PARM_DESC(number_of_qps,116"Max number of QPs which can be allocated "117"(default: autodetect)");118119DEFINE_RWLOCK(ehca_qp_idr_lock);120DEFINE_RWLOCK(ehca_cq_idr_lock);121DEFINE_IDR(ehca_qp_idr);122DEFINE_IDR(ehca_cq_idr);123124static LIST_HEAD(shca_list); /* list of all registered ehcas */125DEFINE_SPINLOCK(shca_list_lock);126127static struct timer_list poll_eqs_timer;128129#ifdef CONFIG_PPC_64K_PAGES130static struct kmem_cache *ctblk_cache;131132void *ehca_alloc_fw_ctrlblock(gfp_t flags)133{134void *ret = kmem_cache_zalloc(ctblk_cache, flags);135if (!ret)136ehca_gen_err("Out of memory for ctblk");137return ret;138}139140void ehca_free_fw_ctrlblock(void *ptr)141{142if (ptr)143kmem_cache_free(ctblk_cache, ptr);144145}146#endif147148int ehca2ib_return_code(u64 ehca_rc)149{150switch (ehca_rc) {151case H_SUCCESS:152return 0;153case H_RESOURCE: /* Resource in use */154case H_BUSY:155return -EBUSY;156case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */157case H_CONSTRAINED: /* resource constraint */158case H_NO_MEM:159return -ENOMEM;160default:161return -EINVAL;162}163}164165static int ehca_create_slab_caches(void)166{167int ret;168169ret = ehca_init_pd_cache();170if (ret) {171ehca_gen_err("Cannot create PD SLAB cache.");172return ret;173}174175ret = ehca_init_cq_cache();176if (ret) {177ehca_gen_err("Cannot create CQ SLAB cache.");178goto create_slab_caches2;179}180181ret = ehca_init_qp_cache();182if (ret) {183ehca_gen_err("Cannot create QP SLAB cache.");184goto create_slab_caches3;185}186187ret = ehca_init_av_cache();188if (ret) {189ehca_gen_err("Cannot create AV SLAB cache.");190goto create_slab_caches4;191}192193ret = ehca_init_mrmw_cache();194if (ret) {195ehca_gen_err("Cannot create MR&MW SLAB cache.");196goto create_slab_caches5;197}198199ret = ehca_init_small_qp_cache();200if (ret) {201ehca_gen_err("Cannot create small queue SLAB cache.");202goto create_slab_caches6;203}204205#ifdef CONFIG_PPC_64K_PAGES206ctblk_cache = kmem_cache_create("ehca_cache_ctblk",207EHCA_PAGESIZE, H_CB_ALIGNMENT,208SLAB_HWCACHE_ALIGN,209NULL);210if (!ctblk_cache) {211ehca_gen_err("Cannot create ctblk SLAB cache.");212ehca_cleanup_small_qp_cache();213goto create_slab_caches6;214}215#endif216return 0;217218create_slab_caches6:219ehca_cleanup_mrmw_cache();220221create_slab_caches5:222ehca_cleanup_av_cache();223224create_slab_caches4:225ehca_cleanup_qp_cache();226227create_slab_caches3:228ehca_cleanup_cq_cache();229230create_slab_caches2:231ehca_cleanup_pd_cache();232233return ret;234}235236static void ehca_destroy_slab_caches(void)237{238ehca_cleanup_small_qp_cache();239ehca_cleanup_mrmw_cache();240ehca_cleanup_av_cache();241ehca_cleanup_qp_cache();242ehca_cleanup_cq_cache();243ehca_cleanup_pd_cache();244#ifdef CONFIG_PPC_64K_PAGES245if (ctblk_cache)246kmem_cache_destroy(ctblk_cache);247#endif248}249250#define EHCA_HCAAVER EHCA_BMASK_IBM(32, 39)251#define EHCA_REVID EHCA_BMASK_IBM(40, 63)252253static struct cap_descr {254u64 mask;255char *descr;256} hca_cap_descr[] = {257{ HCA_CAP_AH_PORT_NR_CHECK, "HCA_CAP_AH_PORT_NR_CHECK" },258{ HCA_CAP_ATOMIC, "HCA_CAP_ATOMIC" },259{ HCA_CAP_AUTO_PATH_MIG, "HCA_CAP_AUTO_PATH_MIG" },260{ HCA_CAP_BAD_P_KEY_CTR, "HCA_CAP_BAD_P_KEY_CTR" },261{ HCA_CAP_SQD_RTS_PORT_CHANGE, "HCA_CAP_SQD_RTS_PORT_CHANGE" },262{ HCA_CAP_CUR_QP_STATE_MOD, "HCA_CAP_CUR_QP_STATE_MOD" },263{ HCA_CAP_INIT_TYPE, "HCA_CAP_INIT_TYPE" },264{ HCA_CAP_PORT_ACTIVE_EVENT, "HCA_CAP_PORT_ACTIVE_EVENT" },265{ HCA_CAP_Q_KEY_VIOL_CTR, "HCA_CAP_Q_KEY_VIOL_CTR" },266{ HCA_CAP_WQE_RESIZE, "HCA_CAP_WQE_RESIZE" },267{ HCA_CAP_RAW_PACKET_MCAST, "HCA_CAP_RAW_PACKET_MCAST" },268{ HCA_CAP_SHUTDOWN_PORT, "HCA_CAP_SHUTDOWN_PORT" },269{ HCA_CAP_RC_LL_QP, "HCA_CAP_RC_LL_QP" },270{ HCA_CAP_SRQ, "HCA_CAP_SRQ" },271{ HCA_CAP_UD_LL_QP, "HCA_CAP_UD_LL_QP" },272{ HCA_CAP_RESIZE_MR, "HCA_CAP_RESIZE_MR" },273{ HCA_CAP_MINI_QP, "HCA_CAP_MINI_QP" },274{ HCA_CAP_H_ALLOC_RES_SYNC, "HCA_CAP_H_ALLOC_RES_SYNC" },275};276277static int ehca_sense_attributes(struct ehca_shca *shca)278{279int i, ret = 0;280u64 h_ret;281struct hipz_query_hca *rblock;282struct hipz_query_port *port;283const char *loc_code;284285static const u32 pgsize_map[] = {286HCA_CAP_MR_PGSIZE_4K, 0x1000,287HCA_CAP_MR_PGSIZE_64K, 0x10000,288HCA_CAP_MR_PGSIZE_1M, 0x100000,289HCA_CAP_MR_PGSIZE_16M, 0x1000000,290};291292ehca_gen_dbg("Probing adapter %s...",293shca->ofdev->dev.of_node->full_name);294loc_code = of_get_property(shca->ofdev->dev.of_node, "ibm,loc-code",295NULL);296if (loc_code)297ehca_gen_dbg(" ... location lode=%s", loc_code);298299rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);300if (!rblock) {301ehca_gen_err("Cannot allocate rblock memory.");302return -ENOMEM;303}304305h_ret = hipz_h_query_hca(shca->ipz_hca_handle, rblock);306if (h_ret != H_SUCCESS) {307ehca_gen_err("Cannot query device properties. h_ret=%lli",308h_ret);309ret = -EPERM;310goto sense_attributes1;311}312313if (ehca_nr_ports == 1)314shca->num_ports = 1;315else316shca->num_ports = (u8)rblock->num_ports;317318ehca_gen_dbg(" ... found %x ports", rblock->num_ports);319320if (ehca_hw_level == 0) {321u32 hcaaver;322u32 revid;323324hcaaver = EHCA_BMASK_GET(EHCA_HCAAVER, rblock->hw_ver);325revid = EHCA_BMASK_GET(EHCA_REVID, rblock->hw_ver);326327ehca_gen_dbg(" ... hardware version=%x:%x", hcaaver, revid);328329if (hcaaver == 1) {330if (revid <= 3)331shca->hw_level = 0x10 | (revid + 1);332else333shca->hw_level = 0x14;334} else if (hcaaver == 2) {335if (revid == 0)336shca->hw_level = 0x21;337else if (revid == 0x10)338shca->hw_level = 0x22;339else if (revid == 0x20 || revid == 0x21)340shca->hw_level = 0x23;341}342343if (!shca->hw_level) {344ehca_gen_warn("unknown hardware version"345" - assuming default level");346shca->hw_level = 0x22;347}348} else349shca->hw_level = ehca_hw_level;350ehca_gen_dbg(" ... hardware level=%x", shca->hw_level);351352shca->hca_cap = rblock->hca_cap_indicators;353ehca_gen_dbg(" ... HCA capabilities:");354for (i = 0; i < ARRAY_SIZE(hca_cap_descr); i++)355if (EHCA_BMASK_GET(hca_cap_descr[i].mask, shca->hca_cap))356ehca_gen_dbg(" %s", hca_cap_descr[i].descr);357358/* Autodetect hCall locking -- the "H_ALLOC_RESOURCE synced" flag is359* a firmware property, so it's valid across all adapters360*/361if (ehca_lock_hcalls == -1)362ehca_lock_hcalls = !EHCA_BMASK_GET(HCA_CAP_H_ALLOC_RES_SYNC,363shca->hca_cap);364365/* translate supported MR page sizes; always support 4K */366shca->hca_cap_mr_pgsize = EHCA_PAGESIZE;367for (i = 0; i < ARRAY_SIZE(pgsize_map); i += 2)368if (rblock->memory_page_size_supported & pgsize_map[i])369shca->hca_cap_mr_pgsize |= pgsize_map[i + 1];370371/* Set maximum number of CQs and QPs to calculate EQ size */372if (shca->max_num_qps == -1)373shca->max_num_qps = min_t(int, rblock->max_qp,374EHCA_MAX_NUM_QUEUES);375else if (shca->max_num_qps < 1 || shca->max_num_qps > rblock->max_qp) {376ehca_gen_warn("The requested number of QPs is out of range "377"(1 - %i) specified by HW. Value is set to %i",378rblock->max_qp, rblock->max_qp);379shca->max_num_qps = rblock->max_qp;380}381382if (shca->max_num_cqs == -1)383shca->max_num_cqs = min_t(int, rblock->max_cq,384EHCA_MAX_NUM_QUEUES);385else if (shca->max_num_cqs < 1 || shca->max_num_cqs > rblock->max_cq) {386ehca_gen_warn("The requested number of CQs is out of range "387"(1 - %i) specified by HW. Value is set to %i",388rblock->max_cq, rblock->max_cq);389}390391/* query max MTU from first port -- it's the same for all ports */392port = (struct hipz_query_port *)rblock;393h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port);394if (h_ret != H_SUCCESS) {395ehca_gen_err("Cannot query port properties. h_ret=%lli",396h_ret);397ret = -EPERM;398goto sense_attributes1;399}400401shca->max_mtu = port->max_mtu;402403sense_attributes1:404ehca_free_fw_ctrlblock(rblock);405return ret;406}407408static int init_node_guid(struct ehca_shca *shca)409{410int ret = 0;411struct hipz_query_hca *rblock;412413rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);414if (!rblock) {415ehca_err(&shca->ib_device, "Can't allocate rblock memory.");416return -ENOMEM;417}418419if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) {420ehca_err(&shca->ib_device, "Can't query device properties");421ret = -EINVAL;422goto init_node_guid1;423}424425memcpy(&shca->ib_device.node_guid, &rblock->node_guid, sizeof(u64));426427init_node_guid1:428ehca_free_fw_ctrlblock(rblock);429return ret;430}431432static int ehca_init_device(struct ehca_shca *shca)433{434int ret;435436ret = init_node_guid(shca);437if (ret)438return ret;439440strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX);441shca->ib_device.owner = THIS_MODULE;442443shca->ib_device.uverbs_abi_ver = 8;444shca->ib_device.uverbs_cmd_mask =445(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |446(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |447(1ull << IB_USER_VERBS_CMD_QUERY_PORT) |448(1ull << IB_USER_VERBS_CMD_ALLOC_PD) |449(1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |450(1ull << IB_USER_VERBS_CMD_REG_MR) |451(1ull << IB_USER_VERBS_CMD_DEREG_MR) |452(1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |453(1ull << IB_USER_VERBS_CMD_CREATE_CQ) |454(1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |455(1ull << IB_USER_VERBS_CMD_CREATE_QP) |456(1ull << IB_USER_VERBS_CMD_MODIFY_QP) |457(1ull << IB_USER_VERBS_CMD_QUERY_QP) |458(1ull << IB_USER_VERBS_CMD_DESTROY_QP) |459(1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) |460(1ull << IB_USER_VERBS_CMD_DETACH_MCAST);461462shca->ib_device.node_type = RDMA_NODE_IB_CA;463shca->ib_device.phys_port_cnt = shca->num_ports;464shca->ib_device.num_comp_vectors = 1;465shca->ib_device.dma_device = &shca->ofdev->dev;466shca->ib_device.query_device = ehca_query_device;467shca->ib_device.query_port = ehca_query_port;468shca->ib_device.query_gid = ehca_query_gid;469shca->ib_device.query_pkey = ehca_query_pkey;470/* shca->in_device.modify_device = ehca_modify_device */471shca->ib_device.modify_port = ehca_modify_port;472shca->ib_device.alloc_ucontext = ehca_alloc_ucontext;473shca->ib_device.dealloc_ucontext = ehca_dealloc_ucontext;474shca->ib_device.alloc_pd = ehca_alloc_pd;475shca->ib_device.dealloc_pd = ehca_dealloc_pd;476shca->ib_device.create_ah = ehca_create_ah;477/* shca->ib_device.modify_ah = ehca_modify_ah; */478shca->ib_device.query_ah = ehca_query_ah;479shca->ib_device.destroy_ah = ehca_destroy_ah;480shca->ib_device.create_qp = ehca_create_qp;481shca->ib_device.modify_qp = ehca_modify_qp;482shca->ib_device.query_qp = ehca_query_qp;483shca->ib_device.destroy_qp = ehca_destroy_qp;484shca->ib_device.post_send = ehca_post_send;485shca->ib_device.post_recv = ehca_post_recv;486shca->ib_device.create_cq = ehca_create_cq;487shca->ib_device.destroy_cq = ehca_destroy_cq;488shca->ib_device.resize_cq = ehca_resize_cq;489shca->ib_device.poll_cq = ehca_poll_cq;490/* shca->ib_device.peek_cq = ehca_peek_cq; */491shca->ib_device.req_notify_cq = ehca_req_notify_cq;492/* shca->ib_device.req_ncomp_notif = ehca_req_ncomp_notif; */493shca->ib_device.get_dma_mr = ehca_get_dma_mr;494shca->ib_device.reg_phys_mr = ehca_reg_phys_mr;495shca->ib_device.reg_user_mr = ehca_reg_user_mr;496shca->ib_device.query_mr = ehca_query_mr;497shca->ib_device.dereg_mr = ehca_dereg_mr;498shca->ib_device.rereg_phys_mr = ehca_rereg_phys_mr;499shca->ib_device.alloc_mw = ehca_alloc_mw;500shca->ib_device.bind_mw = ehca_bind_mw;501shca->ib_device.dealloc_mw = ehca_dealloc_mw;502shca->ib_device.alloc_fmr = ehca_alloc_fmr;503shca->ib_device.map_phys_fmr = ehca_map_phys_fmr;504shca->ib_device.unmap_fmr = ehca_unmap_fmr;505shca->ib_device.dealloc_fmr = ehca_dealloc_fmr;506shca->ib_device.attach_mcast = ehca_attach_mcast;507shca->ib_device.detach_mcast = ehca_detach_mcast;508shca->ib_device.process_mad = ehca_process_mad;509shca->ib_device.mmap = ehca_mmap;510shca->ib_device.dma_ops = &ehca_dma_mapping_ops;511512if (EHCA_BMASK_GET(HCA_CAP_SRQ, shca->hca_cap)) {513shca->ib_device.uverbs_cmd_mask |=514(1ull << IB_USER_VERBS_CMD_CREATE_SRQ) |515(1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) |516(1ull << IB_USER_VERBS_CMD_QUERY_SRQ) |517(1ull << IB_USER_VERBS_CMD_DESTROY_SRQ);518519shca->ib_device.create_srq = ehca_create_srq;520shca->ib_device.modify_srq = ehca_modify_srq;521shca->ib_device.query_srq = ehca_query_srq;522shca->ib_device.destroy_srq = ehca_destroy_srq;523shca->ib_device.post_srq_recv = ehca_post_srq_recv;524}525526return ret;527}528529static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)530{531struct ehca_sport *sport = &shca->sport[port - 1];532struct ib_cq *ibcq;533struct ib_qp *ibqp;534struct ib_qp_init_attr qp_init_attr;535int ret;536537if (sport->ibcq_aqp1) {538ehca_err(&shca->ib_device, "AQP1 CQ is already created.");539return -EPERM;540}541542ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void *)(-1), 10, 0);543if (IS_ERR(ibcq)) {544ehca_err(&shca->ib_device, "Cannot create AQP1 CQ.");545return PTR_ERR(ibcq);546}547sport->ibcq_aqp1 = ibcq;548549if (sport->ibqp_sqp[IB_QPT_GSI]) {550ehca_err(&shca->ib_device, "AQP1 QP is already created.");551ret = -EPERM;552goto create_aqp1;553}554555memset(&qp_init_attr, 0, sizeof(struct ib_qp_init_attr));556qp_init_attr.send_cq = ibcq;557qp_init_attr.recv_cq = ibcq;558qp_init_attr.sq_sig_type = IB_SIGNAL_ALL_WR;559qp_init_attr.cap.max_send_wr = 100;560qp_init_attr.cap.max_recv_wr = 100;561qp_init_attr.cap.max_send_sge = 2;562qp_init_attr.cap.max_recv_sge = 1;563qp_init_attr.qp_type = IB_QPT_GSI;564qp_init_attr.port_num = port;565qp_init_attr.qp_context = NULL;566qp_init_attr.event_handler = NULL;567qp_init_attr.srq = NULL;568569ibqp = ib_create_qp(&shca->pd->ib_pd, &qp_init_attr);570if (IS_ERR(ibqp)) {571ehca_err(&shca->ib_device, "Cannot create AQP1 QP.");572ret = PTR_ERR(ibqp);573goto create_aqp1;574}575sport->ibqp_sqp[IB_QPT_GSI] = ibqp;576577return 0;578579create_aqp1:580ib_destroy_cq(sport->ibcq_aqp1);581return ret;582}583584static int ehca_destroy_aqp1(struct ehca_sport *sport)585{586int ret;587588ret = ib_destroy_qp(sport->ibqp_sqp[IB_QPT_GSI]);589if (ret) {590ehca_gen_err("Cannot destroy AQP1 QP. ret=%i", ret);591return ret;592}593594ret = ib_destroy_cq(sport->ibcq_aqp1);595if (ret)596ehca_gen_err("Cannot destroy AQP1 CQ. ret=%i", ret);597598return ret;599}600601static ssize_t ehca_show_debug_level(struct device_driver *ddp, char *buf)602{603return snprintf(buf, PAGE_SIZE, "%d\n", ehca_debug_level);604}605606static ssize_t ehca_store_debug_level(struct device_driver *ddp,607const char *buf, size_t count)608{609int value = (*buf) - '0';610if (value >= 0 && value <= 9)611ehca_debug_level = value;612return 1;613}614615static DRIVER_ATTR(debug_level, S_IRUSR | S_IWUSR,616ehca_show_debug_level, ehca_store_debug_level);617618static struct attribute *ehca_drv_attrs[] = {619&driver_attr_debug_level.attr,620NULL621};622623static struct attribute_group ehca_drv_attr_grp = {624.attrs = ehca_drv_attrs625};626627static const struct attribute_group *ehca_drv_attr_groups[] = {628&ehca_drv_attr_grp,629NULL,630};631632#define EHCA_RESOURCE_ATTR(name) \633static ssize_t ehca_show_##name(struct device *dev, \634struct device_attribute *attr, \635char *buf) \636{ \637struct ehca_shca *shca; \638struct hipz_query_hca *rblock; \639int data; \640\641shca = dev_get_drvdata(dev); \642\643rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL); \644if (!rblock) { \645dev_err(dev, "Can't allocate rblock memory.\n"); \646return 0; \647} \648\649if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) { \650dev_err(dev, "Can't query device properties\n"); \651ehca_free_fw_ctrlblock(rblock); \652return 0; \653} \654\655data = rblock->name; \656ehca_free_fw_ctrlblock(rblock); \657\658if ((strcmp(#name, "num_ports") == 0) && (ehca_nr_ports == 1)) \659return snprintf(buf, 256, "1\n"); \660else \661return snprintf(buf, 256, "%d\n", data); \662\663} \664static DEVICE_ATTR(name, S_IRUGO, ehca_show_##name, NULL);665666EHCA_RESOURCE_ATTR(num_ports);667EHCA_RESOURCE_ATTR(hw_ver);668EHCA_RESOURCE_ATTR(max_eq);669EHCA_RESOURCE_ATTR(cur_eq);670EHCA_RESOURCE_ATTR(max_cq);671EHCA_RESOURCE_ATTR(cur_cq);672EHCA_RESOURCE_ATTR(max_qp);673EHCA_RESOURCE_ATTR(cur_qp);674EHCA_RESOURCE_ATTR(max_mr);675EHCA_RESOURCE_ATTR(cur_mr);676EHCA_RESOURCE_ATTR(max_mw);677EHCA_RESOURCE_ATTR(cur_mw);678EHCA_RESOURCE_ATTR(max_pd);679EHCA_RESOURCE_ATTR(max_ah);680681static ssize_t ehca_show_adapter_handle(struct device *dev,682struct device_attribute *attr,683char *buf)684{685struct ehca_shca *shca = dev_get_drvdata(dev);686687return sprintf(buf, "%llx\n", shca->ipz_hca_handle.handle);688689}690static DEVICE_ATTR(adapter_handle, S_IRUGO, ehca_show_adapter_handle, NULL);691692static struct attribute *ehca_dev_attrs[] = {693&dev_attr_adapter_handle.attr,694&dev_attr_num_ports.attr,695&dev_attr_hw_ver.attr,696&dev_attr_max_eq.attr,697&dev_attr_cur_eq.attr,698&dev_attr_max_cq.attr,699&dev_attr_cur_cq.attr,700&dev_attr_max_qp.attr,701&dev_attr_cur_qp.attr,702&dev_attr_max_mr.attr,703&dev_attr_cur_mr.attr,704&dev_attr_max_mw.attr,705&dev_attr_cur_mw.attr,706&dev_attr_max_pd.attr,707&dev_attr_max_ah.attr,708NULL709};710711static struct attribute_group ehca_dev_attr_grp = {712.attrs = ehca_dev_attrs713};714715static int __devinit ehca_probe(struct platform_device *dev,716const struct of_device_id *id)717{718struct ehca_shca *shca;719const u64 *handle;720struct ib_pd *ibpd;721int ret, i, eq_size;722unsigned long flags;723724handle = of_get_property(dev->dev.of_node, "ibm,hca-handle", NULL);725if (!handle) {726ehca_gen_err("Cannot get eHCA handle for adapter: %s.",727dev->dev.of_node->full_name);728return -ENODEV;729}730731if (!(*handle)) {732ehca_gen_err("Wrong eHCA handle for adapter: %s.",733dev->dev.of_node->full_name);734return -ENODEV;735}736737shca = (struct ehca_shca *)ib_alloc_device(sizeof(*shca));738if (!shca) {739ehca_gen_err("Cannot allocate shca memory.");740return -ENOMEM;741}742743mutex_init(&shca->modify_mutex);744atomic_set(&shca->num_cqs, 0);745atomic_set(&shca->num_qps, 0);746shca->max_num_qps = ehca_max_qp;747shca->max_num_cqs = ehca_max_cq;748749for (i = 0; i < ARRAY_SIZE(shca->sport); i++)750spin_lock_init(&shca->sport[i].mod_sqp_lock);751752shca->ofdev = dev;753shca->ipz_hca_handle.handle = *handle;754dev_set_drvdata(&dev->dev, shca);755756ret = ehca_sense_attributes(shca);757if (ret < 0) {758ehca_gen_err("Cannot sense eHCA attributes.");759goto probe1;760}761762ret = ehca_init_device(shca);763if (ret) {764ehca_gen_err("Cannot init ehca device struct");765goto probe1;766}767768eq_size = 2 * shca->max_num_cqs + 4 * shca->max_num_qps;769/* create event queues */770ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, eq_size);771if (ret) {772ehca_err(&shca->ib_device, "Cannot create EQ.");773goto probe1;774}775776ret = ehca_create_eq(shca, &shca->neq, EHCA_NEQ, 513);777if (ret) {778ehca_err(&shca->ib_device, "Cannot create NEQ.");779goto probe3;780}781782/* create internal protection domain */783ibpd = ehca_alloc_pd(&shca->ib_device, (void *)(-1), NULL);784if (IS_ERR(ibpd)) {785ehca_err(&shca->ib_device, "Cannot create internal PD.");786ret = PTR_ERR(ibpd);787goto probe4;788}789790shca->pd = container_of(ibpd, struct ehca_pd, ib_pd);791shca->pd->ib_pd.device = &shca->ib_device;792793/* create internal max MR */794ret = ehca_reg_internal_maxmr(shca, shca->pd, &shca->maxmr);795796if (ret) {797ehca_err(&shca->ib_device, "Cannot create internal MR ret=%i",798ret);799goto probe5;800}801802ret = ib_register_device(&shca->ib_device, NULL);803if (ret) {804ehca_err(&shca->ib_device,805"ib_register_device() failed ret=%i", ret);806goto probe6;807}808809/* create AQP1 for port 1 */810if (ehca_open_aqp1 == 1) {811shca->sport[0].port_state = IB_PORT_DOWN;812ret = ehca_create_aqp1(shca, 1);813if (ret) {814ehca_err(&shca->ib_device,815"Cannot create AQP1 for port 1.");816goto probe7;817}818}819820/* create AQP1 for port 2 */821if ((ehca_open_aqp1 == 1) && (shca->num_ports == 2)) {822shca->sport[1].port_state = IB_PORT_DOWN;823ret = ehca_create_aqp1(shca, 2);824if (ret) {825ehca_err(&shca->ib_device,826"Cannot create AQP1 for port 2.");827goto probe8;828}829}830831ret = sysfs_create_group(&dev->dev.kobj, &ehca_dev_attr_grp);832if (ret) /* only complain; we can live without attributes */833ehca_err(&shca->ib_device,834"Cannot create device attributes ret=%d", ret);835836spin_lock_irqsave(&shca_list_lock, flags);837list_add(&shca->shca_list, &shca_list);838spin_unlock_irqrestore(&shca_list_lock, flags);839840return 0;841842probe8:843ret = ehca_destroy_aqp1(&shca->sport[0]);844if (ret)845ehca_err(&shca->ib_device,846"Cannot destroy AQP1 for port 1. ret=%i", ret);847848probe7:849ib_unregister_device(&shca->ib_device);850851probe6:852ret = ehca_dereg_internal_maxmr(shca);853if (ret)854ehca_err(&shca->ib_device,855"Cannot destroy internal MR. ret=%x", ret);856857probe5:858ret = ehca_dealloc_pd(&shca->pd->ib_pd);859if (ret)860ehca_err(&shca->ib_device,861"Cannot destroy internal PD. ret=%x", ret);862863probe4:864ret = ehca_destroy_eq(shca, &shca->neq);865if (ret)866ehca_err(&shca->ib_device,867"Cannot destroy NEQ. ret=%x", ret);868869probe3:870ret = ehca_destroy_eq(shca, &shca->eq);871if (ret)872ehca_err(&shca->ib_device,873"Cannot destroy EQ. ret=%x", ret);874875probe1:876ib_dealloc_device(&shca->ib_device);877878return -EINVAL;879}880881static int __devexit ehca_remove(struct platform_device *dev)882{883struct ehca_shca *shca = dev_get_drvdata(&dev->dev);884unsigned long flags;885int ret;886887sysfs_remove_group(&dev->dev.kobj, &ehca_dev_attr_grp);888889if (ehca_open_aqp1 == 1) {890int i;891for (i = 0; i < shca->num_ports; i++) {892ret = ehca_destroy_aqp1(&shca->sport[i]);893if (ret)894ehca_err(&shca->ib_device,895"Cannot destroy AQP1 for port %x "896"ret=%i", ret, i);897}898}899900ib_unregister_device(&shca->ib_device);901902ret = ehca_dereg_internal_maxmr(shca);903if (ret)904ehca_err(&shca->ib_device,905"Cannot destroy internal MR. ret=%i", ret);906907ret = ehca_dealloc_pd(&shca->pd->ib_pd);908if (ret)909ehca_err(&shca->ib_device,910"Cannot destroy internal PD. ret=%i", ret);911912ret = ehca_destroy_eq(shca, &shca->eq);913if (ret)914ehca_err(&shca->ib_device, "Cannot destroy EQ. ret=%i", ret);915916ret = ehca_destroy_eq(shca, &shca->neq);917if (ret)918ehca_err(&shca->ib_device, "Canot destroy NEQ. ret=%i", ret);919920ib_dealloc_device(&shca->ib_device);921922spin_lock_irqsave(&shca_list_lock, flags);923list_del(&shca->shca_list);924spin_unlock_irqrestore(&shca_list_lock, flags);925926return ret;927}928929static struct of_device_id ehca_device_table[] =930{931{932.name = "lhca",933.compatible = "IBM,lhca",934},935{},936};937MODULE_DEVICE_TABLE(of, ehca_device_table);938939static struct of_platform_driver ehca_driver = {940.probe = ehca_probe,941.remove = ehca_remove,942.driver = {943.name = "ehca",944.owner = THIS_MODULE,945.groups = ehca_drv_attr_groups,946.of_match_table = ehca_device_table,947},948};949950void ehca_poll_eqs(unsigned long data)951{952struct ehca_shca *shca;953954spin_lock(&shca_list_lock);955list_for_each_entry(shca, &shca_list, shca_list) {956if (shca->eq.is_initialized) {957/* call deadman proc only if eq ptr does not change */958struct ehca_eq *eq = &shca->eq;959int max = 3;960volatile u64 q_ofs, q_ofs2;961unsigned long flags;962spin_lock_irqsave(&eq->spinlock, flags);963q_ofs = eq->ipz_queue.current_q_offset;964spin_unlock_irqrestore(&eq->spinlock, flags);965do {966spin_lock_irqsave(&eq->spinlock, flags);967q_ofs2 = eq->ipz_queue.current_q_offset;968spin_unlock_irqrestore(&eq->spinlock, flags);969max--;970} while (q_ofs == q_ofs2 && max > 0);971if (q_ofs == q_ofs2)972ehca_process_eq(shca, 0);973}974}975mod_timer(&poll_eqs_timer, round_jiffies(jiffies + HZ));976spin_unlock(&shca_list_lock);977}978979static int ehca_mem_notifier(struct notifier_block *nb,980unsigned long action, void *data)981{982static unsigned long ehca_dmem_warn_time;983unsigned long flags;984985switch (action) {986case MEM_CANCEL_OFFLINE:987case MEM_CANCEL_ONLINE:988case MEM_ONLINE:989case MEM_OFFLINE:990return NOTIFY_OK;991case MEM_GOING_ONLINE:992case MEM_GOING_OFFLINE:993/* only ok if no hca is attached to the lpar */994spin_lock_irqsave(&shca_list_lock, flags);995if (list_empty(&shca_list)) {996spin_unlock_irqrestore(&shca_list_lock, flags);997return NOTIFY_OK;998} else {999spin_unlock_irqrestore(&shca_list_lock, flags);1000if (printk_timed_ratelimit(&ehca_dmem_warn_time,100130 * 1000))1002ehca_gen_err("DMEM operations are not allowed"1003"in conjunction with eHCA");1004return NOTIFY_BAD;1005}1006}1007return NOTIFY_OK;1008}10091010static struct notifier_block ehca_mem_nb = {1011.notifier_call = ehca_mem_notifier,1012};10131014static int __init ehca_module_init(void)1015{1016int ret;10171018printk(KERN_INFO "eHCA Infiniband Device Driver "1019"(Version " HCAD_VERSION ")\n");10201021ret = ehca_create_comp_pool();1022if (ret) {1023ehca_gen_err("Cannot create comp pool.");1024return ret;1025}10261027ret = ehca_create_slab_caches();1028if (ret) {1029ehca_gen_err("Cannot create SLAB caches");1030ret = -ENOMEM;1031goto module_init1;1032}10331034ret = ehca_create_busmap();1035if (ret) {1036ehca_gen_err("Cannot create busmap.");1037goto module_init2;1038}10391040ret = ibmebus_register_driver(&ehca_driver);1041if (ret) {1042ehca_gen_err("Cannot register eHCA device driver");1043ret = -EINVAL;1044goto module_init3;1045}10461047ret = register_memory_notifier(&ehca_mem_nb);1048if (ret) {1049ehca_gen_err("Failed registering memory add/remove notifier");1050goto module_init4;1051}10521053if (ehca_poll_all_eqs != 1) {1054ehca_gen_err("WARNING!!!");1055ehca_gen_err("It is possible to lose interrupts.");1056} else {1057init_timer(&poll_eqs_timer);1058poll_eqs_timer.function = ehca_poll_eqs;1059poll_eqs_timer.expires = jiffies + HZ;1060add_timer(&poll_eqs_timer);1061}10621063return 0;10641065module_init4:1066ibmebus_unregister_driver(&ehca_driver);10671068module_init3:1069ehca_destroy_busmap();10701071module_init2:1072ehca_destroy_slab_caches();10731074module_init1:1075ehca_destroy_comp_pool();1076return ret;1077};10781079static void __exit ehca_module_exit(void)1080{1081if (ehca_poll_all_eqs == 1)1082del_timer_sync(&poll_eqs_timer);10831084ibmebus_unregister_driver(&ehca_driver);10851086unregister_memory_notifier(&ehca_mem_nb);10871088ehca_destroy_busmap();10891090ehca_destroy_slab_caches();10911092ehca_destroy_comp_pool();10931094idr_destroy(&ehca_cq_idr);1095idr_destroy(&ehca_qp_idr);1096};10971098module_init(ehca_module_init);1099module_exit(ehca_module_exit);110011011102