1 /* 2 * Copyright (c) 2004 Topspin Communications. All rights reserved. 3 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 4 * 5 * This software is available to you under a choice of one of two 6 * licenses. You may choose to be licensed under the terms of the GNU 7 * General Public License (GPL) Version 2, available from the file 8 * COPYING in the main directory of this source tree, or the 9 * OpenIB.org BSD license below: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * - Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 * 33 * $Id: mthca_av.c 1349 2004-12-16 21:09:43Z roland $ 34 */ 35 36 #include <linux/init.h> 37 #include <linux/string.h> 38 #include <linux/slab.h> 39 40 #include <rdma/ib_verbs.h> 41 #include <rdma/ib_cache.h> 42 43 #include "mthca_dev.h" 44 45 struct mthca_av { 46 __be32 port_pd; 47 u8 reserved1; 48 u8 g_slid; 49 __be16 dlid; 50 u8 reserved2; 51 u8 gid_index; 52 u8 msg_sr; 53 u8 hop_limit; 54 __be32 sl_tclass_flowlabel; 55 __be32 dgid[4]; 56 }; 57 58 int mthca_create_ah(struct mthca_dev *dev, 59 struct mthca_pd *pd, 60 struct ib_ah_attr *ah_attr, 61 struct mthca_ah *ah) 62 { 63 u32 index = -1; 64 struct mthca_av *av = NULL; 65 66 ah->type = MTHCA_AH_PCI_POOL; 67 68 if (mthca_is_memfree(dev)) { 69 ah->av = kmalloc(sizeof *ah->av, GFP_ATOMIC); 70 if (!ah->av) 71 return -ENOMEM; 72 73 ah->type = MTHCA_AH_KMALLOC; 74 av = ah->av; 75 } else if (!atomic_read(&pd->sqp_count) && 76 !(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) { 77 index = mthca_alloc(&dev->av_table.alloc); 78 79 /* fall back to allocate in host memory */ 80 if (index == -1) 81 goto on_hca_fail; 82 83 av = kmalloc(sizeof *av, GFP_ATOMIC); 84 if (!av) 85 goto on_hca_fail; 86 87 ah->type = MTHCA_AH_ON_HCA; 88 ah->avdma = dev->av_table.ddr_av_base + 89 index * MTHCA_AV_SIZE; 90 } 91 92 on_hca_fail: 93 if (ah->type == MTHCA_AH_PCI_POOL) { 94 ah->av = pci_pool_alloc(dev->av_table.pool, 95 SLAB_ATOMIC, &ah->avdma); 96 if (!ah->av) 97 return -ENOMEM; 98 99 av = ah->av; 100 } 101 102 ah->key = pd->ntmr.ibmr.lkey; 103 104 memset(av, 0, MTHCA_AV_SIZE); 105 106 av->port_pd = cpu_to_be32(pd->pd_num | (ah_attr->port_num << 24)); 107 av->g_slid = ah_attr->src_path_bits; 108 av->dlid = cpu_to_be16(ah_attr->dlid); 109 av->msg_sr = (3 << 4) | /* 2K message */ 110 ah_attr->static_rate; 111 av->sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); 112 if (ah_attr->ah_flags & IB_AH_GRH) { 113 av->g_slid |= 0x80; 114 av->gid_index = (ah_attr->port_num - 1) * dev->limits.gid_table_len + 115 ah_attr->grh.sgid_index; 116 av->hop_limit = ah_attr->grh.hop_limit; 117 av->sl_tclass_flowlabel |= 118 cpu_to_be32((ah_attr->grh.traffic_class << 20) | 119 ah_attr->grh.flow_label); 120 memcpy(av->dgid, ah_attr->grh.dgid.raw, 16); 121 } else { 122 /* Arbel workaround -- low byte of GID must be 2 */ 123 av->dgid[3] = cpu_to_be32(2); 124 } 125 126 if (0) { 127 int j; 128 129 mthca_dbg(dev, "Created UDAV at %p/%08lx:\n", 130 av, (unsigned long) ah->avdma); 131 for (j = 0; j < 8; ++j) 132 printk(KERN_DEBUG " [%2x] %08x\n", 133 j * 4, be32_to_cpu(((__be32 *) av)[j])); 134 } 135 136 if (ah->type == MTHCA_AH_ON_HCA) { 137 memcpy_toio(dev->av_table.av_map + index * MTHCA_AV_SIZE, 138 av, MTHCA_AV_SIZE); 139 kfree(av); 140 } 141 142 return 0; 143 } 144 145 int mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah) 146 { 147 switch (ah->type) { 148 case MTHCA_AH_ON_HCA: 149 mthca_free(&dev->av_table.alloc, 150 (ah->avdma - dev->av_table.ddr_av_base) / 151 MTHCA_AV_SIZE); 152 break; 153 154 case MTHCA_AH_PCI_POOL: 155 pci_pool_free(dev->av_table.pool, ah->av, ah->avdma); 156 break; 157 158 case MTHCA_AH_KMALLOC: 159 kfree(ah->av); 160 break; 161 } 162 163 return 0; 164 } 165 166 int mthca_ah_grh_present(struct mthca_ah *ah) 167 { 168 return !!(ah->av->g_slid & 0x80); 169 } 170 171 int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah, 172 struct ib_ud_header *header) 173 { 174 if (ah->type == MTHCA_AH_ON_HCA) 175 return -EINVAL; 176 177 header->lrh.service_level = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28; 178 header->lrh.destination_lid = ah->av->dlid; 179 header->lrh.source_lid = cpu_to_be16(ah->av->g_slid & 0x7f); 180 if (mthca_ah_grh_present(ah)) { 181 header->grh.traffic_class = 182 (be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20) & 0xff; 183 header->grh.flow_label = 184 ah->av->sl_tclass_flowlabel & cpu_to_be32(0xfffff); 185 ib_get_cached_gid(&dev->ib_dev, 186 be32_to_cpu(ah->av->port_pd) >> 24, 187 ah->av->gid_index % dev->limits.gid_table_len, 188 &header->grh.source_gid); 189 memcpy(header->grh.destination_gid.raw, 190 ah->av->dgid, 16); 191 } 192 193 return 0; 194 } 195 196 int mthca_ah_query(struct ib_ah *ibah, struct ib_ah_attr *attr) 197 { 198 struct mthca_ah *ah = to_mah(ibah); 199 struct mthca_dev *dev = to_mdev(ibah->device); 200 201 /* Only implement for MAD and memfree ah for now. */ 202 if (ah->type == MTHCA_AH_ON_HCA) 203 return -ENOSYS; 204 205 memset(attr, 0, sizeof *attr); 206 attr->dlid = be16_to_cpu(ah->av->dlid); 207 attr->sl = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28; 208 attr->static_rate = ah->av->msg_sr & 0x7; 209 attr->src_path_bits = ah->av->g_slid & 0x7F; 210 attr->port_num = be32_to_cpu(ah->av->port_pd) >> 24; 211 attr->ah_flags = mthca_ah_grh_present(ah) ? IB_AH_GRH : 0; 212 213 if (attr->ah_flags) { 214 attr->grh.traffic_class = 215 be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20; 216 attr->grh.flow_label = 217 be32_to_cpu(ah->av->sl_tclass_flowlabel) & 0xfffff; 218 attr->grh.hop_limit = ah->av->hop_limit; 219 attr->grh.sgid_index = ah->av->gid_index & 220 (dev->limits.gid_table_len - 1); 221 memcpy(attr->grh.dgid.raw, ah->av->dgid, 16); 222 } 223 224 return 0; 225 } 226 227 int __devinit mthca_init_av_table(struct mthca_dev *dev) 228 { 229 int err; 230 231 if (mthca_is_memfree(dev)) 232 return 0; 233 234 err = mthca_alloc_init(&dev->av_table.alloc, 235 dev->av_table.num_ddr_avs, 236 dev->av_table.num_ddr_avs - 1, 237 0); 238 if (err) 239 return err; 240 241 dev->av_table.pool = pci_pool_create("mthca_av", dev->pdev, 242 MTHCA_AV_SIZE, 243 MTHCA_AV_SIZE, 0); 244 if (!dev->av_table.pool) 245 goto out_free_alloc; 246 247 if (!(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) { 248 dev->av_table.av_map = ioremap(pci_resource_start(dev->pdev, 4) + 249 dev->av_table.ddr_av_base - 250 dev->ddr_start, 251 dev->av_table.num_ddr_avs * 252 MTHCA_AV_SIZE); 253 if (!dev->av_table.av_map) 254 goto out_free_pool; 255 } else 256 dev->av_table.av_map = NULL; 257 258 return 0; 259 260 out_free_pool: 261 pci_pool_destroy(dev->av_table.pool); 262 263 out_free_alloc: 264 mthca_alloc_cleanup(&dev->av_table.alloc); 265 return -ENOMEM; 266 } 267 268 void mthca_cleanup_av_table(struct mthca_dev *dev) 269 { 270 if (mthca_is_memfree(dev)) 271 return; 272 273 if (dev->av_table.av_map) 274 iounmap(dev->av_table.av_map); 275 pci_pool_destroy(dev->av_table.pool); 276 mthca_alloc_cleanup(&dev->av_table.alloc); 277 } 278