Path: blob/master/drivers/infiniband/hw/ehca/ehca_av.c
15112 views
/*1* IBM eServer eHCA Infiniband device driver for Linux on POWER2*3* address vector functions4*5* Authors: Hoang-Nam Nguyen <[email protected]>6* Khadija Souissi <[email protected]>7* Reinhard Ernst <[email protected]>8* Christoph Raisch <[email protected]>9*10* Copyright (c) 2005 IBM Corporation11*12* All rights reserved.13*14* This source code is distributed under a dual license of GPL v2.0 and OpenIB15* BSD.16*17* OpenIB BSD License18*19* Redistribution and use in source and binary forms, with or without20* modification, are permitted provided that the following conditions are met:21*22* Redistributions of source code must retain the above copyright notice, this23* list of conditions and the following disclaimer.24*25* Redistributions in binary form must reproduce the above copyright notice,26* this list of conditions and the following disclaimer in the documentation27* and/or other materials28* provided with the distribution.29*30* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"31* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE32* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE33* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE34* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR35* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF36* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR37* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER38* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)39* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE40* POSSIBILITY OF SUCH DAMAGE.41*/4243#include <linux/slab.h>4445#include "ehca_tools.h"46#include "ehca_iverbs.h"47#include "hcp_if.h"4849static struct kmem_cache *av_cache;5051int ehca_calc_ipd(struct ehca_shca *shca, int port,52enum ib_rate path_rate, u32 *ipd)53{54int path = ib_rate_to_mult(path_rate);55int link, ret;56struct ib_port_attr pa;5758if (path_rate == IB_RATE_PORT_CURRENT) {59*ipd = 0;60return 0;61}6263if (unlikely(path < 0)) {64ehca_err(&shca->ib_device, "Invalid static rate! path_rate=%x",65path_rate);66return -EINVAL;67}6869ret = ehca_query_port(&shca->ib_device, port, &pa);70if (unlikely(ret < 0)) {71ehca_err(&shca->ib_device, "Failed to query port ret=%i", ret);72return ret;73}7475link = ib_width_enum_to_int(pa.active_width) * pa.active_speed;7677if (path >= link)78/* no need to throttle if path faster than link */79*ipd = 0;80else81/* IPD = round((link / path) - 1) */82*ipd = ((link + (path >> 1)) / path) - 1;8384return 0;85}8687struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)88{89int ret;90struct ehca_av *av;91struct ehca_shca *shca = container_of(pd->device, struct ehca_shca,92ib_device);9394av = kmem_cache_alloc(av_cache, GFP_KERNEL);95if (!av) {96ehca_err(pd->device, "Out of memory pd=%p ah_attr=%p",97pd, ah_attr);98return ERR_PTR(-ENOMEM);99}100101av->av.sl = ah_attr->sl;102av->av.dlid = ah_attr->dlid;103av->av.slid_path_bits = ah_attr->src_path_bits;104105if (ehca_static_rate < 0) {106u32 ipd;107if (ehca_calc_ipd(shca, ah_attr->port_num,108ah_attr->static_rate, &ipd)) {109ret = -EINVAL;110goto create_ah_exit1;111}112av->av.ipd = ipd;113} else114av->av.ipd = ehca_static_rate;115116av->av.lnh = ah_attr->ah_flags;117av->av.grh.word_0 = EHCA_BMASK_SET(GRH_IPVERSION_MASK, 6);118av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_TCLASS_MASK,119ah_attr->grh.traffic_class);120av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_FLOWLABEL_MASK,121ah_attr->grh.flow_label);122av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_HOPLIMIT_MASK,123ah_attr->grh.hop_limit);124av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_NEXTHEADER_MASK, 0x1B);125/* set sgid in grh.word_1 */126if (ah_attr->ah_flags & IB_AH_GRH) {127int rc;128struct ib_port_attr port_attr;129union ib_gid gid;130memset(&port_attr, 0, sizeof(port_attr));131rc = ehca_query_port(pd->device, ah_attr->port_num,132&port_attr);133if (rc) { /* invalid port number */134ret = -EINVAL;135ehca_err(pd->device, "Invalid port number "136"ehca_query_port() returned %x "137"pd=%p ah_attr=%p", rc, pd, ah_attr);138goto create_ah_exit1;139}140memset(&gid, 0, sizeof(gid));141rc = ehca_query_gid(pd->device,142ah_attr->port_num,143ah_attr->grh.sgid_index, &gid);144if (rc) {145ret = -EINVAL;146ehca_err(pd->device, "Failed to retrieve sgid "147"ehca_query_gid() returned %x "148"pd=%p ah_attr=%p", rc, pd, ah_attr);149goto create_ah_exit1;150}151memcpy(&av->av.grh.word_1, &gid, sizeof(gid));152}153av->av.pmtu = shca->max_mtu;154155/* dgid comes in grh.word_3 */156memcpy(&av->av.grh.word_3, &ah_attr->grh.dgid,157sizeof(ah_attr->grh.dgid));158159return &av->ib_ah;160161create_ah_exit1:162kmem_cache_free(av_cache, av);163164return ERR_PTR(ret);165}166167int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)168{169struct ehca_av *av;170struct ehca_ud_av new_ehca_av;171struct ehca_shca *shca = container_of(ah->pd->device, struct ehca_shca,172ib_device);173174memset(&new_ehca_av, 0, sizeof(new_ehca_av));175new_ehca_av.sl = ah_attr->sl;176new_ehca_av.dlid = ah_attr->dlid;177new_ehca_av.slid_path_bits = ah_attr->src_path_bits;178new_ehca_av.ipd = ah_attr->static_rate;179new_ehca_av.lnh = EHCA_BMASK_SET(GRH_FLAG_MASK,180(ah_attr->ah_flags & IB_AH_GRH) > 0);181new_ehca_av.grh.word_0 = EHCA_BMASK_SET(GRH_TCLASS_MASK,182ah_attr->grh.traffic_class);183new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_FLOWLABEL_MASK,184ah_attr->grh.flow_label);185new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_HOPLIMIT_MASK,186ah_attr->grh.hop_limit);187new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_NEXTHEADER_MASK, 0x1b);188189/* set sgid in grh.word_1 */190if (ah_attr->ah_flags & IB_AH_GRH) {191int rc;192struct ib_port_attr port_attr;193union ib_gid gid;194memset(&port_attr, 0, sizeof(port_attr));195rc = ehca_query_port(ah->device, ah_attr->port_num,196&port_attr);197if (rc) { /* invalid port number */198ehca_err(ah->device, "Invalid port number "199"ehca_query_port() returned %x "200"ah=%p ah_attr=%p port_num=%x",201rc, ah, ah_attr, ah_attr->port_num);202return -EINVAL;203}204memset(&gid, 0, sizeof(gid));205rc = ehca_query_gid(ah->device,206ah_attr->port_num,207ah_attr->grh.sgid_index, &gid);208if (rc) {209ehca_err(ah->device, "Failed to retrieve sgid "210"ehca_query_gid() returned %x "211"ah=%p ah_attr=%p port_num=%x "212"sgid_index=%x",213rc, ah, ah_attr, ah_attr->port_num,214ah_attr->grh.sgid_index);215return -EINVAL;216}217memcpy(&new_ehca_av.grh.word_1, &gid, sizeof(gid));218}219220new_ehca_av.pmtu = shca->max_mtu;221222memcpy(&new_ehca_av.grh.word_3, &ah_attr->grh.dgid,223sizeof(ah_attr->grh.dgid));224225av = container_of(ah, struct ehca_av, ib_ah);226av->av = new_ehca_av;227228return 0;229}230231int ehca_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)232{233struct ehca_av *av = container_of(ah, struct ehca_av, ib_ah);234235memcpy(&ah_attr->grh.dgid, &av->av.grh.word_3,236sizeof(ah_attr->grh.dgid));237ah_attr->sl = av->av.sl;238239ah_attr->dlid = av->av.dlid;240241ah_attr->src_path_bits = av->av.slid_path_bits;242ah_attr->static_rate = av->av.ipd;243ah_attr->ah_flags = EHCA_BMASK_GET(GRH_FLAG_MASK, av->av.lnh);244ah_attr->grh.traffic_class = EHCA_BMASK_GET(GRH_TCLASS_MASK,245av->av.grh.word_0);246ah_attr->grh.hop_limit = EHCA_BMASK_GET(GRH_HOPLIMIT_MASK,247av->av.grh.word_0);248ah_attr->grh.flow_label = EHCA_BMASK_GET(GRH_FLOWLABEL_MASK,249av->av.grh.word_0);250251return 0;252}253254int ehca_destroy_ah(struct ib_ah *ah)255{256kmem_cache_free(av_cache, container_of(ah, struct ehca_av, ib_ah));257258return 0;259}260261int ehca_init_av_cache(void)262{263av_cache = kmem_cache_create("ehca_cache_av",264sizeof(struct ehca_av), 0,265SLAB_HWCACHE_ALIGN,266NULL);267if (!av_cache)268return -ENOMEM;269return 0;270}271272void ehca_cleanup_av_cache(void)273{274if (av_cache)275kmem_cache_destroy(av_cache);276}277278279