c2_provider.c 21.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*
 * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
 * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
 *
 * This software is available to you under a choice of one of two
 * licenses.  You may choose to be licensed under the terms of the GNU
 * General Public License (GPL) Version 2, available from the file
 * COPYING in the main directory of this source tree, or the
 * OpenIB.org BSD license below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/inetdevice.h>
#include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/if_vlan.h>
#include <linux/crc32.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/if_arp.h>
52
#include <linux/vmalloc.h>
53
54
55
56
57
58

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/byteorder.h>

#include <rdma/ib_smi.h>
59
#include <rdma/ib_umem.h>
60
61
62
63
64
65
66
67
68
69
#include <rdma/ib_user_verbs.h>
#include "c2.h"
#include "c2_provider.h"
#include "c2_user.h"

static int c2_query_device(struct ib_device *ibdev,
			   struct ib_device_attr *props)
{
	struct c2_dev *c2dev = to_c2dev(ibdev);

70
	pr_debug("%s:%u\n", __func__, __LINE__);
71
72
73
74
75
76
77
78

	*props = c2dev->props;
	return 0;
}

static int c2_query_port(struct ib_device *ibdev,
			 u8 port, struct ib_port_attr *props)
{
79
	pr_debug("%s:%u\n", __func__, __LINE__);
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

	props->max_mtu = IB_MTU_4096;
	props->lid = 0;
	props->lmc = 0;
	props->sm_lid = 0;
	props->sm_sl = 0;
	props->state = IB_PORT_ACTIVE;
	props->phys_state = 0;
	props->port_cap_flags =
	    IB_PORT_CM_SUP |
	    IB_PORT_REINIT_SUP |
	    IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP;
	props->gid_tbl_len = 1;
	props->pkey_tbl_len = 1;
	props->qkey_viol_cntr = 0;
	props->active_width = 1;
	props->active_speed = 1;

	return 0;
}

static int c2_modify_port(struct ib_device *ibdev,
			  u8 port, int port_modify_mask,
			  struct ib_port_modify *props)
{
105
	pr_debug("%s:%u\n", __func__, __LINE__);
106
107
108
109
110
111
	return 0;
}

static int c2_query_pkey(struct ib_device *ibdev,
			 u8 port, u16 index, u16 * pkey)
{
112
	pr_debug("%s:%u\n", __func__, __LINE__);
113
114
115
116
117
118
119
120
121
	*pkey = 0;
	return 0;
}

static int c2_query_gid(struct ib_device *ibdev, u8 port,
			int index, union ib_gid *gid)
{
	struct c2_dev *c2dev = to_c2dev(ibdev);

122
	pr_debug("%s:%u\n", __func__, __LINE__);
123
124
125
126
127
128
129
130
131
132
133
134
135
136
	memset(&(gid->raw[0]), 0, sizeof(gid->raw));
	memcpy(&(gid->raw[0]), c2dev->pseudo_netdev->dev_addr, 6);

	return 0;
}

/* Allocate the user context data structure. This keeps track
 * of all objects associated with a particular user-mode client.
 */
static struct ib_ucontext *c2_alloc_ucontext(struct ib_device *ibdev,
					     struct ib_udata *udata)
{
	struct c2_ucontext *context;

137
	pr_debug("%s:%u\n", __func__, __LINE__);
138
139
140
141
142
143
144
145
146
	context = kmalloc(sizeof(*context), GFP_KERNEL);
	if (!context)
		return ERR_PTR(-ENOMEM);

	return &context->ibucontext;
}

static int c2_dealloc_ucontext(struct ib_ucontext *context)
{
147
	pr_debug("%s:%u\n", __func__, __LINE__);
148
149
150
151
152
153
	kfree(context);
	return 0;
}

static int c2_mmap_uar(struct ib_ucontext *context, struct vm_area_struct *vma)
{
154
	pr_debug("%s:%u\n", __func__, __LINE__);
155
156
157
158
159
160
161
162
163
164
	return -ENOSYS;
}

static struct ib_pd *c2_alloc_pd(struct ib_device *ibdev,
				 struct ib_ucontext *context,
				 struct ib_udata *udata)
{
	struct c2_pd *pd;
	int err;

165
	pr_debug("%s:%u\n", __func__, __LINE__);
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

	pd = kmalloc(sizeof(*pd), GFP_KERNEL);
	if (!pd)
		return ERR_PTR(-ENOMEM);

	err = c2_pd_alloc(to_c2dev(ibdev), !context, pd);
	if (err) {
		kfree(pd);
		return ERR_PTR(err);
	}

	if (context) {
		if (ib_copy_to_udata(udata, &pd->pd_id, sizeof(__u32))) {
			c2_pd_free(to_c2dev(ibdev), pd);
			kfree(pd);
			return ERR_PTR(-EFAULT);
		}
	}

	return &pd->ibpd;
}

static int c2_dealloc_pd(struct ib_pd *pd)
{
190
	pr_debug("%s:%u\n", __func__, __LINE__);
191
192
193
194
195
196
197
198
	c2_pd_free(to_c2dev(pd->device), to_c2pd(pd));
	kfree(pd);

	return 0;
}

static struct ib_ah *c2_ah_create(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
{
199
	pr_debug("%s:%u\n", __func__, __LINE__);
200
201
202
203
204
	return ERR_PTR(-ENOSYS);
}

static int c2_ah_destroy(struct ib_ah *ah)
{
205
	pr_debug("%s:%u\n", __func__, __LINE__);
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
	return -ENOSYS;
}

static void c2_add_ref(struct ib_qp *ibqp)
{
	struct c2_qp *qp;
	BUG_ON(!ibqp);
	qp = to_c2qp(ibqp);
	atomic_inc(&qp->refcount);
}

static void c2_rem_ref(struct ib_qp *ibqp)
{
	struct c2_qp *qp;
	BUG_ON(!ibqp);
	qp = to_c2qp(ibqp);
	if (atomic_dec_and_test(&qp->refcount))
		wake_up(&qp->wait);
}

struct ib_qp *c2_get_qp(struct ib_device *device, int qpn)
{
	struct c2_dev* c2dev = to_c2dev(device);
	struct c2_qp *qp;

	qp = c2_find_qpn(c2dev, qpn);
	pr_debug("%s Returning QP=%p for QPN=%d, device=%p, refcount=%d\n",
233
		__func__, qp, qpn, device,
234
235
236
237
238
239
240
241
242
243
244
245
		(qp?atomic_read(&qp->refcount):0));

	return (qp?&qp->ibqp:NULL);
}

static struct ib_qp *c2_create_qp(struct ib_pd *pd,
				  struct ib_qp_init_attr *init_attr,
				  struct ib_udata *udata)
{
	struct c2_qp *qp;
	int err;

246
	pr_debug("%s:%u\n", __func__, __LINE__);
247

248
249
250
	if (init_attr->create_flags)
		return ERR_PTR(-EINVAL);

251
252
253
254
	switch (init_attr->qp_type) {
	case IB_QPT_RC:
		qp = kzalloc(sizeof(*qp), GFP_KERNEL);
		if (!qp) {
255
			pr_debug("%s: Unable to allocate QP\n", __func__);
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
			return ERR_PTR(-ENOMEM);
		}
		spin_lock_init(&qp->lock);
		if (pd->uobject) {
			/* userspace specific */
		}

		err = c2_alloc_qp(to_c2dev(pd->device),
				  to_c2pd(pd), init_attr, qp);

		if (err && pd->uobject) {
			/* userspace specific */
		}

		break;
	default:
272
		pr_debug("%s: Invalid QP type: %d\n", __func__,
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
			init_attr->qp_type);
		return ERR_PTR(-EINVAL);
	}

	if (err) {
		kfree(qp);
		return ERR_PTR(err);
	}

	return &qp->ibqp;
}

static int c2_destroy_qp(struct ib_qp *ib_qp)
{
	struct c2_qp *qp = to_c2qp(ib_qp);

	pr_debug("%s:%u qp=%p,qp->state=%d\n",
290
		__func__, __LINE__, ib_qp, qp->state);
291
292
293
294
295
	c2_free_qp(to_c2dev(ib_qp->device), qp);
	kfree(qp);
	return 0;
}

296
static struct ib_cq *c2_create_cq(struct ib_device *ibdev, int entries, int vector,
297
298
299
300
301
302
303
304
				  struct ib_ucontext *context,
				  struct ib_udata *udata)
{
	struct c2_cq *cq;
	int err;

	cq = kmalloc(sizeof(*cq), GFP_KERNEL);
	if (!cq) {
305
		pr_debug("%s: Unable to allocate CQ\n", __func__);
306
307
308
309
310
		return ERR_PTR(-ENOMEM);
	}

	err = c2_init_cq(to_c2dev(ibdev), entries, NULL, cq);
	if (err) {
311
		pr_debug("%s: error initializing CQ\n", __func__);
312
313
314
315
316
317
318
319
320
321
322
		kfree(cq);
		return ERR_PTR(err);
	}

	return &cq->ibcq;
}

static int c2_destroy_cq(struct ib_cq *ib_cq)
{
	struct c2_cq *cq = to_c2cq(ib_cq);

323
	pr_debug("%s:%u\n", __func__, __LINE__);
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395

	c2_free_cq(to_c2dev(ib_cq->device), cq);
	kfree(cq);

	return 0;
}

static inline u32 c2_convert_access(int acc)
{
	return (acc & IB_ACCESS_REMOTE_WRITE ? C2_ACF_REMOTE_WRITE : 0) |
	    (acc & IB_ACCESS_REMOTE_READ ? C2_ACF_REMOTE_READ : 0) |
	    (acc & IB_ACCESS_LOCAL_WRITE ? C2_ACF_LOCAL_WRITE : 0) |
	    C2_ACF_LOCAL_READ | C2_ACF_WINDOW_BIND;
}

static struct ib_mr *c2_reg_phys_mr(struct ib_pd *ib_pd,
				    struct ib_phys_buf *buffer_list,
				    int num_phys_buf, int acc, u64 * iova_start)
{
	struct c2_mr *mr;
	u64 *page_list;
	u32 total_len;
	int err, i, j, k, page_shift, pbl_depth;

	pbl_depth = 0;
	total_len = 0;

	page_shift = PAGE_SHIFT;
	/*
	 * If there is only 1 buffer we assume this could
	 * be a map of all phy mem...use a 32k page_shift.
	 */
	if (num_phys_buf == 1)
		page_shift += 3;

	for (i = 0; i < num_phys_buf; i++) {

		if (buffer_list[i].addr & ~PAGE_MASK) {
			pr_debug("Unaligned Memory Buffer: 0x%x\n",
				(unsigned int) buffer_list[i].addr);
			return ERR_PTR(-EINVAL);
		}

		if (!buffer_list[i].size) {
			pr_debug("Invalid Buffer Size\n");
			return ERR_PTR(-EINVAL);
		}

		total_len += buffer_list[i].size;
		pbl_depth += ALIGN(buffer_list[i].size,
				   (1 << page_shift)) >> page_shift;
	}

	page_list = vmalloc(sizeof(u64) * pbl_depth);
	if (!page_list) {
		pr_debug("couldn't vmalloc page_list of size %zd\n",
			(sizeof(u64) * pbl_depth));
		return ERR_PTR(-ENOMEM);
	}

	for (i = 0, j = 0; i < num_phys_buf; i++) {

		int naddrs;

 		naddrs = ALIGN(buffer_list[i].size,
			       (1 << page_shift)) >> page_shift;
		for (k = 0; k < naddrs; k++)
			page_list[j++] = (buffer_list[i].addr +
						     (k << page_shift));
	}

	mr = kmalloc(sizeof(*mr), GFP_KERNEL);
396
397
	if (!mr) {
		vfree(page_list);
398
		return ERR_PTR(-ENOMEM);
399
	}
400
401

	mr->pd = to_c2pd(ib_pd);
402
	mr->umem = NULL;
403
404
	pr_debug("%s - page shift %d, pbl_depth %d, total_len %u, "
		"*iova_start %llx, first pa %llx, last pa %llx\n",
405
		__func__, page_shift, pbl_depth, total_len,
406
407
408
		(unsigned long long) *iova_start,
	       	(unsigned long long) page_list[0],
	       	(unsigned long long) page_list[pbl_depth-1]);
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
  	err = c2_nsmr_register_phys_kern(to_c2dev(ib_pd->device), page_list,
 					 (1 << page_shift), pbl_depth,
					 total_len, 0, iova_start,
					 c2_convert_access(acc), mr);
	vfree(page_list);
	if (err) {
		kfree(mr);
		return ERR_PTR(err);
	}

	return &mr->ibmr;
}

static struct ib_mr *c2_get_dma_mr(struct ib_pd *pd, int acc)
{
	struct ib_phys_buf bl;
	u64 kva = 0;

427
	pr_debug("%s:%u\n", __func__, __LINE__);
428
429
430
431
432
433
434

	/* AMSO1100 limit */
	bl.size = 0xffffffff;
	bl.addr = 0;
	return c2_reg_phys_mr(pd, &bl, 1, acc, &kva);
}

435
436
static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
				    u64 virt, int acc, struct ib_udata *udata)
437
438
439
440
441
442
443
444
445
446
{
	u64 *pages;
	u64 kva = 0;
	int shift, n, len;
	int i, j, k;
	int err = 0;
	struct ib_umem_chunk *chunk;
	struct c2_pd *c2pd = to_c2pd(pd);
	struct c2_mr *c2mr;

447
	pr_debug("%s:%u\n", __func__, __LINE__);
448
449
450
451
452
453

	c2mr = kmalloc(sizeof(*c2mr), GFP_KERNEL);
	if (!c2mr)
		return ERR_PTR(-ENOMEM);
	c2mr->pd = c2pd;

454
	c2mr->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0);
455
456
457
458
459
460
461
462
	if (IS_ERR(c2mr->umem)) {
		err = PTR_ERR(c2mr->umem);
		kfree(c2mr);
		return ERR_PTR(err);
	}

	shift = ffs(c2mr->umem->page_size) - 1;

463
	n = 0;
464
	list_for_each_entry(chunk, &c2mr->umem->chunk_list, list)
465
466
467
468
469
470
471
472
473
		n += chunk->nents;

	pages = kmalloc(n * sizeof(u64), GFP_KERNEL);
	if (!pages) {
		err = -ENOMEM;
		goto err;
	}

	i = 0;
474
	list_for_each_entry(chunk, &c2mr->umem->chunk_list, list) {
475
476
477
478
479
		for (j = 0; j < chunk->nmap; ++j) {
			len = sg_dma_len(&chunk->page_list[j]) >> shift;
			for (k = 0; k < len; ++k) {
				pages[i++] =
					sg_dma_address(&chunk->page_list[j]) +
480
					(c2mr->umem->page_size * k);
481
482
483
484
			}
		}
	}

485
	kva = virt;
486
487
  	err = c2_nsmr_register_phys_kern(to_c2dev(pd->device),
					 pages,
488
					 c2mr->umem->page_size,
489
					 i,
490
491
					 length,
					 c2mr->umem->offset,
492
493
494
495
					 &kva,
					 c2_convert_access(acc),
					 c2mr);
	kfree(pages);
496
497
	if (err)
		goto err;
498
499
500
	return &c2mr->ibmr;

err:
501
	ib_umem_release(c2mr->umem);
502
503
504
505
506
507
508
509
510
	kfree(c2mr);
	return ERR_PTR(err);
}

static int c2_dereg_mr(struct ib_mr *ib_mr)
{
	struct c2_mr *mr = to_c2mr(ib_mr);
	int err;

511
	pr_debug("%s:%u\n", __func__, __LINE__);
512
513
514
515

	err = c2_stag_dealloc(to_c2dev(ib_mr->device), ib_mr->lkey);
	if (err)
		pr_debug("c2_stag_dealloc failed: %d\n", err);
516
517
518
	else {
		if (mr->umem)
			ib_umem_release(mr->umem);
519
		kfree(mr);
520
	}
521
522
523
524

	return err;
}

525
526
static ssize_t show_rev(struct device *dev, struct device_attribute *attr,
			char *buf)
527
{
528
	struct c2_dev *c2dev = container_of(dev, struct c2_dev, ibdev.dev);
529
	pr_debug("%s:%u\n", __func__, __LINE__);
530
	return sprintf(buf, "%x\n", c2dev->props.hw_ver);
531
532
}

533
534
static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr,
			   char *buf)
535
{
536
	struct c2_dev *c2dev = container_of(dev, struct c2_dev, ibdev.dev);
537
	pr_debug("%s:%u\n", __func__, __LINE__);
538
	return sprintf(buf, "%x.%x.%x\n",
539
540
541
		       (int) (c2dev->props.fw_ver >> 32),
		       (int) (c2dev->props.fw_ver >> 16) & 0xffff,
		       (int) (c2dev->props.fw_ver & 0xffff));
542
543
}

544
545
static ssize_t show_hca(struct device *dev, struct device_attribute *attr,
			char *buf)
546
{
547
	pr_debug("%s:%u\n", __func__, __LINE__);
548
549
550
	return sprintf(buf, "AMSO1100\n");
}

551
552
static ssize_t show_board(struct device *dev, struct device_attribute *attr,
			  char *buf)
553
{
554
	pr_debug("%s:%u\n", __func__, __LINE__);
555
556
557
	return sprintf(buf, "%.*s\n", 32, "AMSO1100 Board ID");
}

558
559
560
561
static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
562

563
564
565
566
567
static struct device_attribute *c2_dev_attributes[] = {
	&dev_attr_hw_rev,
	&dev_attr_fw_ver,
	&dev_attr_hca_type,
	&dev_attr_board_id
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
};

static int c2_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
			int attr_mask, struct ib_udata *udata)
{
	int err;

	err =
	    c2_qp_modify(to_c2dev(ibqp->device), to_c2qp(ibqp), attr,
			 attr_mask);

	return err;
}

static int c2_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
{
584
	pr_debug("%s:%u\n", __func__, __LINE__);
585
586
587
588
589
	return -ENOSYS;
}

static int c2_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
{
590
	pr_debug("%s:%u\n", __func__, __LINE__);
591
592
593
594
595
596
597
598
599
600
	return -ENOSYS;
}

static int c2_process_mad(struct ib_device *ibdev,
			  int mad_flags,
			  u8 port_num,
			  struct ib_wc *in_wc,
			  struct ib_grh *in_grh,
			  struct ib_mad *in_mad, struct ib_mad *out_mad)
{
601
	pr_debug("%s:%u\n", __func__, __LINE__);
602
603
604
605
606
	return -ENOSYS;
}

static int c2_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
{
607
	pr_debug("%s:%u\n", __func__, __LINE__);
608
609
610
611
612
613
614

	/* Request a connection */
	return c2_llp_connect(cm_id, iw_param);
}

static int c2_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
{
615
	pr_debug("%s:%u\n", __func__, __LINE__);
616
617
618
619
620
621
622
623
624

	/* Accept the new connection */
	return c2_llp_accept(cm_id, iw_param);
}

static int c2_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
{
	int err;

625
	pr_debug("%s:%u\n", __func__, __LINE__);
626
627
628
629
630
631
632
633
634

	err = c2_llp_reject(cm_id, pdata, pdata_len);
	return err;
}

static int c2_service_create(struct iw_cm_id *cm_id, int backlog)
{
	int err;

635
	pr_debug("%s:%u\n", __func__, __LINE__);
636
637
	err = c2_llp_service_create(cm_id, backlog);
	pr_debug("%s:%u err=%d\n",
638
		__func__, __LINE__,
639
640
641
642
643
644
645
		err);
	return err;
}

static int c2_service_destroy(struct iw_cm_id *cm_id)
{
	int err;
646
	pr_debug("%s:%u\n", __func__, __LINE__);
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751

	err = c2_llp_service_destroy(cm_id);

	return err;
}

static int c2_pseudo_up(struct net_device *netdev)
{
	struct in_device *ind;
	struct c2_dev *c2dev = netdev->priv;

	ind = in_dev_get(netdev);
	if (!ind)
		return 0;

	pr_debug("adding...\n");
	for_ifa(ind) {
#ifdef DEBUG
		u8 *ip = (u8 *) & ifa->ifa_address;

		pr_debug("%s: %d.%d.%d.%d\n",
		       ifa->ifa_label, ip[0], ip[1], ip[2], ip[3]);
#endif
		c2_add_addr(c2dev, ifa->ifa_address, ifa->ifa_mask);
	}
	endfor_ifa(ind);
	in_dev_put(ind);

	return 0;
}

static int c2_pseudo_down(struct net_device *netdev)
{
	struct in_device *ind;
	struct c2_dev *c2dev = netdev->priv;

	ind = in_dev_get(netdev);
	if (!ind)
		return 0;

	pr_debug("deleting...\n");
	for_ifa(ind) {
#ifdef DEBUG
		u8 *ip = (u8 *) & ifa->ifa_address;

		pr_debug("%s: %d.%d.%d.%d\n",
		       ifa->ifa_label, ip[0], ip[1], ip[2], ip[3]);
#endif
		c2_del_addr(c2dev, ifa->ifa_address, ifa->ifa_mask);
	}
	endfor_ifa(ind);
	in_dev_put(ind);

	return 0;
}

static int c2_pseudo_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
	kfree_skb(skb);
	return NETDEV_TX_OK;
}

static int c2_pseudo_change_mtu(struct net_device *netdev, int new_mtu)
{
	int ret = 0;

	if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
		return -EINVAL;

	netdev->mtu = new_mtu;

	/* TODO: Tell rnic about new rmda interface mtu */
	return ret;
}

static void setup(struct net_device *netdev)
{
	netdev->open = c2_pseudo_up;
	netdev->stop = c2_pseudo_down;
	netdev->hard_start_xmit = c2_pseudo_xmit_frame;
	netdev->get_stats = NULL;
	netdev->tx_timeout = NULL;
	netdev->set_mac_address = NULL;
	netdev->change_mtu = c2_pseudo_change_mtu;
	netdev->watchdog_timeo = 0;
	netdev->type = ARPHRD_ETHER;
	netdev->mtu = 1500;
	netdev->hard_header_len = ETH_HLEN;
	netdev->addr_len = ETH_ALEN;
	netdev->tx_queue_len = 0;
	netdev->flags |= IFF_NOARP;
	return;
}

static struct net_device *c2_pseudo_netdev_init(struct c2_dev *c2dev)
{
	char name[IFNAMSIZ];
	struct net_device *netdev;

	/* change ethxxx to iwxxx */
	strcpy(name, "iw");
	strcat(name, &c2dev->netdev->name[3]);
	netdev = alloc_netdev(sizeof(*netdev), name, setup);
	if (!netdev) {
		printk(KERN_ERR PFX "%s -  etherdev alloc failed",
752
			__func__);
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
		return NULL;
	}

	netdev->priv = c2dev;

	SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev);

	memcpy_fromio(netdev->dev_addr, c2dev->kva + C2_REGS_RDMA_ENADDR, 6);

	/* Print out the MAC address */
	pr_debug("%s: MAC %02X:%02X:%02X:%02X:%02X:%02X\n",
		netdev->name,
		netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
		netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);

#if 0
	/* Disable network packets */
	netif_stop_queue(netdev);
#endif
	return netdev;
}

int c2_register_device(struct c2_dev *dev)
{
777
	int ret = -ENOMEM;
778
779
780
781
	int i;

	/* Register pseudo network device */
	dev->pseudo_netdev = c2_pseudo_netdev_init(dev);
782
783
784
785
786
787
	if (!dev->pseudo_netdev)
		goto out3;

	ret = register_netdev(dev->pseudo_netdev);
	if (ret)
		goto out2;
788

789
	pr_debug("%s:%u\n", __func__, __LINE__);
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
	strlcpy(dev->ibdev.name, "amso%d", IB_DEVICE_NAME_MAX);
	dev->ibdev.owner = THIS_MODULE;
	dev->ibdev.uverbs_cmd_mask =
	    (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
	    (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
	    (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
	    (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
	    (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
	    (1ull << IB_USER_VERBS_CMD_REG_MR) |
	    (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
	    (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
	    (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
	    (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
	    (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) |
	    (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
	    (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
	    (1ull << IB_USER_VERBS_CMD_POLL_CQ) |
	    (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
	    (1ull << IB_USER_VERBS_CMD_POST_SEND) |
	    (1ull << IB_USER_VERBS_CMD_POST_RECV);

	dev->ibdev.node_type = RDMA_NODE_RNIC;
	memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid));
	memcpy(&dev->ibdev.node_guid, dev->pseudo_netdev->dev_addr, 6);
	dev->ibdev.phys_port_cnt = 1;
815
	dev->ibdev.num_comp_vectors = 1;
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
	dev->ibdev.dma_device = &dev->pcidev->dev;
	dev->ibdev.query_device = c2_query_device;
	dev->ibdev.query_port = c2_query_port;
	dev->ibdev.modify_port = c2_modify_port;
	dev->ibdev.query_pkey = c2_query_pkey;
	dev->ibdev.query_gid = c2_query_gid;
	dev->ibdev.alloc_ucontext = c2_alloc_ucontext;
	dev->ibdev.dealloc_ucontext = c2_dealloc_ucontext;
	dev->ibdev.mmap = c2_mmap_uar;
	dev->ibdev.alloc_pd = c2_alloc_pd;
	dev->ibdev.dealloc_pd = c2_dealloc_pd;
	dev->ibdev.create_ah = c2_ah_create;
	dev->ibdev.destroy_ah = c2_ah_destroy;
	dev->ibdev.create_qp = c2_create_qp;
	dev->ibdev.modify_qp = c2_modify_qp;
	dev->ibdev.destroy_qp = c2_destroy_qp;
	dev->ibdev.create_cq = c2_create_cq;
	dev->ibdev.destroy_cq = c2_destroy_cq;
	dev->ibdev.poll_cq = c2_poll_cq;
	dev->ibdev.get_dma_mr = c2_get_dma_mr;
	dev->ibdev.reg_phys_mr = c2_reg_phys_mr;
	dev->ibdev.reg_user_mr = c2_reg_user_mr;
	dev->ibdev.dereg_mr = c2_dereg_mr;

	dev->ibdev.alloc_fmr = NULL;
	dev->ibdev.unmap_fmr = NULL;
	dev->ibdev.dealloc_fmr = NULL;
	dev->ibdev.map_phys_fmr = NULL;

	dev->ibdev.attach_mcast = c2_multicast_attach;
	dev->ibdev.detach_mcast = c2_multicast_detach;
	dev->ibdev.process_mad = c2_process_mad;

	dev->ibdev.req_notify_cq = c2_arm_cq;
	dev->ibdev.post_send = c2_post_send;
	dev->ibdev.post_recv = c2_post_receive;

	dev->ibdev.iwcm = kmalloc(sizeof(*dev->ibdev.iwcm), GFP_KERNEL);
	dev->ibdev.iwcm->add_ref = c2_add_ref;
	dev->ibdev.iwcm->rem_ref = c2_rem_ref;
	dev->ibdev.iwcm->get_qp = c2_get_qp;
	dev->ibdev.iwcm->connect = c2_connect;
	dev->ibdev.iwcm->accept = c2_accept;
	dev->ibdev.iwcm->reject = c2_reject;
	dev->ibdev.iwcm->create_listen = c2_service_create;
	dev->ibdev.iwcm->destroy_listen = c2_service_destroy;

	ret = ib_register_device(&dev->ibdev);
	if (ret)
865
		goto out1;
866

867
868
869
	for (i = 0; i < ARRAY_SIZE(c2_dev_attributes); ++i) {
		ret = device_create_file(&dev->ibdev.dev,
					       c2_dev_attributes[i]);
870
871
		if (ret)
			goto out0;
872
	}
873
	goto out3;
874

875
876
877
878
879
880
881
out0:
	ib_unregister_device(&dev->ibdev);
out1:
	unregister_netdev(dev->pseudo_netdev);
out2:
	free_netdev(dev->pseudo_netdev);
out3:
882
	pr_debug("%s:%u ret=%d\n", __func__, __LINE__, ret);
883
	return ret;
884
885
886
887
}

void c2_unregister_device(struct c2_dev *dev)
{
888
	pr_debug("%s:%u\n", __func__, __LINE__);
889
890
891
892
	unregister_netdev(dev->pseudo_netdev);
	free_netdev(dev->pseudo_netdev);
	ib_unregister_device(&dev->ibdev);
}