1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004 Topspin Communications. All rights reserved. 3219820Sjeff * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 4219820Sjeff * 5219820Sjeff * This software is available to you under a choice of one of two 6219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 7219820Sjeff * General Public License (GPL) Version 2, available from the file 8219820Sjeff * COPYING in the main directory of this source tree, or the 9219820Sjeff * OpenIB.org BSD license below: 10219820Sjeff * 11219820Sjeff * Redistribution and use in source and binary forms, with or 12219820Sjeff * without modification, are permitted provided that the following 13219820Sjeff * conditions are met: 14219820Sjeff * 15219820Sjeff * - Redistributions of source code must retain the above 16219820Sjeff * copyright notice, this list of conditions and the following 17219820Sjeff * disclaimer. 18219820Sjeff * 19219820Sjeff * - Redistributions in binary form must reproduce the above 20219820Sjeff * copyright notice, this list of conditions and the following 21219820Sjeff * disclaimer in the documentation and/or other materials 22219820Sjeff * provided with the distribution. 23219820Sjeff * 24219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31219820Sjeff * SOFTWARE. 32219820Sjeff */ 33219820Sjeff 34219820Sjeff#include <linux/string.h> 35219820Sjeff#include <linux/slab.h> 36219820Sjeff 37219820Sjeff#include <rdma/ib_verbs.h> 38219820Sjeff#include <rdma/ib_cache.h> 39219820Sjeff 40219820Sjeff#include "mthca_dev.h" 41219820Sjeff 42219820Sjeffenum { 43219820Sjeff MTHCA_RATE_TAVOR_FULL = 0, 44219820Sjeff MTHCA_RATE_TAVOR_1X = 1, 45219820Sjeff MTHCA_RATE_TAVOR_4X = 2, 46219820Sjeff MTHCA_RATE_TAVOR_1X_DDR = 3 47219820Sjeff}; 48219820Sjeff 49219820Sjeffenum { 50219820Sjeff MTHCA_RATE_MEMFREE_FULL = 0, 51219820Sjeff MTHCA_RATE_MEMFREE_QUARTER = 1, 52219820Sjeff MTHCA_RATE_MEMFREE_EIGHTH = 2, 53219820Sjeff MTHCA_RATE_MEMFREE_HALF = 3 54219820Sjeff}; 55219820Sjeff 56219820Sjeffstruct mthca_av { 57219820Sjeff __be32 port_pd; 58219820Sjeff u8 reserved1; 59219820Sjeff u8 g_slid; 60219820Sjeff __be16 dlid; 61219820Sjeff u8 reserved2; 62219820Sjeff u8 gid_index; 63219820Sjeff u8 msg_sr; 64219820Sjeff u8 hop_limit; 65219820Sjeff __be32 sl_tclass_flowlabel; 66219820Sjeff __be32 dgid[4]; 67219820Sjeff}; 68219820Sjeff 69219820Sjeffstatic enum ib_rate memfree_rate_to_ib(u8 mthca_rate, u8 port_rate) 70219820Sjeff{ 71219820Sjeff switch (mthca_rate) { 72219820Sjeff case MTHCA_RATE_MEMFREE_EIGHTH: 73219820Sjeff return mult_to_ib_rate(port_rate >> 3); 74219820Sjeff case MTHCA_RATE_MEMFREE_QUARTER: 75219820Sjeff return mult_to_ib_rate(port_rate >> 2); 76219820Sjeff case MTHCA_RATE_MEMFREE_HALF: 77219820Sjeff return mult_to_ib_rate(port_rate >> 1); 78219820Sjeff case MTHCA_RATE_MEMFREE_FULL: 79219820Sjeff default: 80219820Sjeff return mult_to_ib_rate(port_rate); 81219820Sjeff } 82219820Sjeff} 83219820Sjeff 84219820Sjeffstatic enum ib_rate tavor_rate_to_ib(u8 mthca_rate, u8 port_rate) 85219820Sjeff{ 86219820Sjeff switch (mthca_rate) { 87219820Sjeff case MTHCA_RATE_TAVOR_1X: return IB_RATE_2_5_GBPS; 88219820Sjeff case MTHCA_RATE_TAVOR_1X_DDR: return IB_RATE_5_GBPS; 89219820Sjeff case MTHCA_RATE_TAVOR_4X: return IB_RATE_10_GBPS; 90219820Sjeff default: return mult_to_ib_rate(port_rate); 91219820Sjeff } 92219820Sjeff} 93219820Sjeff 94219820Sjeffenum ib_rate mthca_rate_to_ib(struct mthca_dev *dev, u8 mthca_rate, u8 port) 95219820Sjeff{ 96219820Sjeff if (mthca_is_memfree(dev)) { 97219820Sjeff /* Handle old Arbel FW */ 98219820Sjeff if (dev->limits.stat_rate_support == 0x3 && mthca_rate) 99219820Sjeff return IB_RATE_2_5_GBPS; 100219820Sjeff 101219820Sjeff return memfree_rate_to_ib(mthca_rate, dev->rate[port - 1]); 102219820Sjeff } else 103219820Sjeff return tavor_rate_to_ib(mthca_rate, dev->rate[port - 1]); 104219820Sjeff} 105219820Sjeff 106219820Sjeffstatic u8 ib_rate_to_memfree(u8 req_rate, u8 cur_rate) 107219820Sjeff{ 108219820Sjeff if (cur_rate <= req_rate) 109219820Sjeff return 0; 110219820Sjeff 111219820Sjeff /* 112219820Sjeff * Inter-packet delay (IPD) to get from rate X down to a rate 113219820Sjeff * no more than Y is (X - 1) / Y. 114219820Sjeff */ 115219820Sjeff switch ((cur_rate - 1) / req_rate) { 116219820Sjeff case 0: return MTHCA_RATE_MEMFREE_FULL; 117219820Sjeff case 1: return MTHCA_RATE_MEMFREE_HALF; 118219820Sjeff case 2: /* fall through */ 119219820Sjeff case 3: return MTHCA_RATE_MEMFREE_QUARTER; 120219820Sjeff default: return MTHCA_RATE_MEMFREE_EIGHTH; 121219820Sjeff } 122219820Sjeff} 123219820Sjeff 124219820Sjeffstatic u8 ib_rate_to_tavor(u8 static_rate) 125219820Sjeff{ 126219820Sjeff switch (static_rate) { 127219820Sjeff case IB_RATE_2_5_GBPS: return MTHCA_RATE_TAVOR_1X; 128219820Sjeff case IB_RATE_5_GBPS: return MTHCA_RATE_TAVOR_1X_DDR; 129219820Sjeff case IB_RATE_10_GBPS: return MTHCA_RATE_TAVOR_4X; 130219820Sjeff default: return MTHCA_RATE_TAVOR_FULL; 131219820Sjeff } 132219820Sjeff} 133219820Sjeff 134219820Sjeffu8 mthca_get_rate(struct mthca_dev *dev, int static_rate, u8 port) 135219820Sjeff{ 136219820Sjeff u8 rate; 137219820Sjeff 138219820Sjeff if (!static_rate || ib_rate_to_mult(static_rate) >= dev->rate[port - 1]) 139219820Sjeff return 0; 140219820Sjeff 141219820Sjeff if (mthca_is_memfree(dev)) 142219820Sjeff rate = ib_rate_to_memfree(ib_rate_to_mult(static_rate), 143219820Sjeff dev->rate[port - 1]); 144219820Sjeff else 145219820Sjeff rate = ib_rate_to_tavor(static_rate); 146219820Sjeff 147219820Sjeff if (!(dev->limits.stat_rate_support & (1 << rate))) 148219820Sjeff rate = 1; 149219820Sjeff 150219820Sjeff return rate; 151219820Sjeff} 152219820Sjeff 153219820Sjeffint mthca_create_ah(struct mthca_dev *dev, 154219820Sjeff struct mthca_pd *pd, 155219820Sjeff struct ib_ah_attr *ah_attr, 156219820Sjeff struct mthca_ah *ah) 157219820Sjeff{ 158219820Sjeff u32 index = -1; 159219820Sjeff struct mthca_av *av = NULL; 160219820Sjeff 161219820Sjeff ah->type = MTHCA_AH_PCI_POOL; 162219820Sjeff 163219820Sjeff if (mthca_is_memfree(dev)) { 164219820Sjeff ah->av = kmalloc(sizeof *ah->av, GFP_ATOMIC); 165219820Sjeff if (!ah->av) 166219820Sjeff return -ENOMEM; 167219820Sjeff 168219820Sjeff ah->type = MTHCA_AH_KMALLOC; 169219820Sjeff av = ah->av; 170219820Sjeff } else if (!atomic_read(&pd->sqp_count) && 171219820Sjeff !(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) { 172219820Sjeff index = mthca_alloc(&dev->av_table.alloc); 173219820Sjeff 174219820Sjeff /* fall back to allocate in host memory */ 175219820Sjeff if (index == -1) 176219820Sjeff goto on_hca_fail; 177219820Sjeff 178219820Sjeff av = kmalloc(sizeof *av, GFP_ATOMIC); 179219820Sjeff if (!av) 180219820Sjeff goto on_hca_fail; 181219820Sjeff 182219820Sjeff ah->type = MTHCA_AH_ON_HCA; 183219820Sjeff ah->avdma = dev->av_table.ddr_av_base + 184219820Sjeff index * MTHCA_AV_SIZE; 185219820Sjeff } 186219820Sjeff 187219820Sjeffon_hca_fail: 188219820Sjeff if (ah->type == MTHCA_AH_PCI_POOL) { 189219820Sjeff ah->av = pci_pool_alloc(dev->av_table.pool, 190219820Sjeff GFP_ATOMIC, &ah->avdma); 191219820Sjeff if (!ah->av) 192219820Sjeff return -ENOMEM; 193219820Sjeff 194219820Sjeff av = ah->av; 195219820Sjeff } 196219820Sjeff 197219820Sjeff ah->key = pd->ntmr.ibmr.lkey; 198219820Sjeff 199219820Sjeff memset(av, 0, MTHCA_AV_SIZE); 200219820Sjeff 201219820Sjeff av->port_pd = cpu_to_be32(pd->pd_num | (ah_attr->port_num << 24)); 202219820Sjeff av->g_slid = ah_attr->src_path_bits; 203219820Sjeff av->dlid = cpu_to_be16(ah_attr->dlid); 204219820Sjeff av->msg_sr = (3 << 4) | /* 2K message */ 205219820Sjeff mthca_get_rate(dev, ah_attr->static_rate, ah_attr->port_num); 206219820Sjeff av->sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); 207219820Sjeff if (ah_attr->ah_flags & IB_AH_GRH) { 208219820Sjeff av->g_slid |= 0x80; 209219820Sjeff av->gid_index = (ah_attr->port_num - 1) * dev->limits.gid_table_len + 210219820Sjeff ah_attr->grh.sgid_index; 211219820Sjeff av->hop_limit = ah_attr->grh.hop_limit; 212219820Sjeff av->sl_tclass_flowlabel |= 213219820Sjeff cpu_to_be32((ah_attr->grh.traffic_class << 20) | 214219820Sjeff ah_attr->grh.flow_label); 215219820Sjeff memcpy(av->dgid, ah_attr->grh.dgid.raw, 16); 216219820Sjeff } else { 217219820Sjeff /* Arbel workaround -- low byte of GID must be 2 */ 218219820Sjeff av->dgid[3] = cpu_to_be32(2); 219219820Sjeff } 220219820Sjeff 221219820Sjeff if (0) { 222219820Sjeff int j; 223219820Sjeff 224219820Sjeff mthca_dbg(dev, "Created UDAV at %p/%08lx:\n", 225219820Sjeff av, (unsigned long) ah->avdma); 226219820Sjeff for (j = 0; j < 8; ++j) 227219820Sjeff printk(KERN_DEBUG " [%2x] %08x\n", 228219820Sjeff j * 4, be32_to_cpu(((__be32 *) av)[j])); 229219820Sjeff } 230219820Sjeff 231219820Sjeff if (ah->type == MTHCA_AH_ON_HCA) { 232219820Sjeff memcpy_toio(dev->av_table.av_map + index * MTHCA_AV_SIZE, 233219820Sjeff av, MTHCA_AV_SIZE); 234219820Sjeff kfree(av); 235219820Sjeff } 236219820Sjeff 237219820Sjeff return 0; 238219820Sjeff} 239219820Sjeff 240219820Sjeffint mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah) 241219820Sjeff{ 242219820Sjeff switch (ah->type) { 243219820Sjeff case MTHCA_AH_ON_HCA: 244219820Sjeff mthca_free(&dev->av_table.alloc, 245219820Sjeff (ah->avdma - dev->av_table.ddr_av_base) / 246219820Sjeff MTHCA_AV_SIZE); 247219820Sjeff break; 248219820Sjeff 249219820Sjeff case MTHCA_AH_PCI_POOL: 250219820Sjeff pci_pool_free(dev->av_table.pool, ah->av, ah->avdma); 251219820Sjeff break; 252219820Sjeff 253219820Sjeff case MTHCA_AH_KMALLOC: 254219820Sjeff kfree(ah->av); 255219820Sjeff break; 256219820Sjeff } 257219820Sjeff 258219820Sjeff return 0; 259219820Sjeff} 260219820Sjeff 261219820Sjeffint mthca_ah_grh_present(struct mthca_ah *ah) 262219820Sjeff{ 263219820Sjeff return !!(ah->av->g_slid & 0x80); 264219820Sjeff} 265219820Sjeff 266219820Sjeffint mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah, 267219820Sjeff struct ib_ud_header *header) 268219820Sjeff{ 269219820Sjeff if (ah->type == MTHCA_AH_ON_HCA) 270219820Sjeff return -EINVAL; 271219820Sjeff 272219820Sjeff header->lrh.service_level = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28; 273219820Sjeff header->lrh.destination_lid = ah->av->dlid; 274219820Sjeff header->lrh.source_lid = cpu_to_be16(ah->av->g_slid & 0x7f); 275219820Sjeff if (mthca_ah_grh_present(ah)) { 276219820Sjeff header->grh.traffic_class = 277219820Sjeff (be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20) & 0xff; 278219820Sjeff header->grh.flow_label = 279219820Sjeff ah->av->sl_tclass_flowlabel & cpu_to_be32(0xfffff); 280219820Sjeff header->grh.hop_limit = ah->av->hop_limit; 281219820Sjeff ib_get_cached_gid(&dev->ib_dev, 282219820Sjeff be32_to_cpu(ah->av->port_pd) >> 24, 283219820Sjeff ah->av->gid_index % dev->limits.gid_table_len, 284219820Sjeff &header->grh.source_gid); 285219820Sjeff memcpy(header->grh.destination_gid.raw, 286219820Sjeff ah->av->dgid, 16); 287219820Sjeff } 288219820Sjeff 289219820Sjeff return 0; 290219820Sjeff} 291219820Sjeff 292219820Sjeffint mthca_ah_query(struct ib_ah *ibah, struct ib_ah_attr *attr) 293219820Sjeff{ 294219820Sjeff struct mthca_ah *ah = to_mah(ibah); 295219820Sjeff struct mthca_dev *dev = to_mdev(ibah->device); 296219820Sjeff 297219820Sjeff /* Only implement for MAD and memfree ah for now. */ 298219820Sjeff if (ah->type == MTHCA_AH_ON_HCA) 299219820Sjeff return -ENOSYS; 300219820Sjeff 301219820Sjeff memset(attr, 0, sizeof *attr); 302219820Sjeff attr->dlid = be16_to_cpu(ah->av->dlid); 303219820Sjeff attr->sl = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28; 304219820Sjeff attr->port_num = be32_to_cpu(ah->av->port_pd) >> 24; 305219820Sjeff attr->static_rate = mthca_rate_to_ib(dev, ah->av->msg_sr & 0x7, 306219820Sjeff attr->port_num); 307219820Sjeff attr->src_path_bits = ah->av->g_slid & 0x7F; 308219820Sjeff attr->ah_flags = mthca_ah_grh_present(ah) ? IB_AH_GRH : 0; 309219820Sjeff 310219820Sjeff if (attr->ah_flags) { 311219820Sjeff attr->grh.traffic_class = 312219820Sjeff be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20; 313219820Sjeff attr->grh.flow_label = 314219820Sjeff be32_to_cpu(ah->av->sl_tclass_flowlabel) & 0xfffff; 315219820Sjeff attr->grh.hop_limit = ah->av->hop_limit; 316219820Sjeff attr->grh.sgid_index = ah->av->gid_index & 317219820Sjeff (dev->limits.gid_table_len - 1); 318219820Sjeff memcpy(attr->grh.dgid.raw, ah->av->dgid, 16); 319219820Sjeff } 320219820Sjeff 321219820Sjeff return 0; 322219820Sjeff} 323219820Sjeff 324219820Sjeffint mthca_init_av_table(struct mthca_dev *dev) 325219820Sjeff{ 326219820Sjeff int err; 327219820Sjeff 328219820Sjeff if (mthca_is_memfree(dev)) 329219820Sjeff return 0; 330219820Sjeff 331219820Sjeff err = mthca_alloc_init(&dev->av_table.alloc, 332219820Sjeff dev->av_table.num_ddr_avs, 333219820Sjeff dev->av_table.num_ddr_avs - 1, 334219820Sjeff 0); 335219820Sjeff if (err) 336219820Sjeff return err; 337219820Sjeff 338219820Sjeff dev->av_table.pool = pci_pool_create("mthca_av", dev->pdev, 339219820Sjeff MTHCA_AV_SIZE, 340219820Sjeff MTHCA_AV_SIZE, 0); 341219820Sjeff if (!dev->av_table.pool) 342219820Sjeff goto out_free_alloc; 343219820Sjeff 344219820Sjeff if (!(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) { 345219820Sjeff dev->av_table.av_map = ioremap(pci_resource_start(dev->pdev, 4) + 346219820Sjeff dev->av_table.ddr_av_base - 347219820Sjeff dev->ddr_start, 348219820Sjeff dev->av_table.num_ddr_avs * 349219820Sjeff MTHCA_AV_SIZE); 350219820Sjeff if (!dev->av_table.av_map) 351219820Sjeff goto out_free_pool; 352219820Sjeff } else 353219820Sjeff dev->av_table.av_map = NULL; 354219820Sjeff 355219820Sjeff return 0; 356219820Sjeff 357219820Sjeff out_free_pool: 358219820Sjeff pci_pool_destroy(dev->av_table.pool); 359219820Sjeff 360219820Sjeff out_free_alloc: 361219820Sjeff mthca_alloc_cleanup(&dev->av_table.alloc); 362219820Sjeff return -ENOMEM; 363219820Sjeff} 364219820Sjeff 365219820Sjeffvoid mthca_cleanup_av_table(struct mthca_dev *dev) 366219820Sjeff{ 367219820Sjeff if (mthca_is_memfree(dev)) 368219820Sjeff return; 369219820Sjeff 370219820Sjeff if (dev->av_table.av_map) 371219820Sjeff iounmap(dev->av_table.av_map); 372219820Sjeff pci_pool_destroy(dev->av_table.pool); 373219820Sjeff mthca_alloc_cleanup(&dev->av_table.alloc); 374219820Sjeff} 375