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