diff options
author | Jan-Bernd Themann <ossthema@de.ibm.com> | 2006-09-13 11:44:31 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-09-13 13:23:52 -0400 |
commit | 7a291083225af6e22ffaa46b3d91cfc1a1ccaab4 (patch) | |
tree | c87a93ee7d5c1c63ce98dc90a62cd0b4dfc4318f /drivers/net/ehea/ehea_qmr.c | |
parent | 7de745e56244156233e5cdd62b462e52e638d408 (diff) |
[PATCH] ehea: IBM eHEA Ethernet Device Driver
Hi Jeff,
I fixed the __iomem issue and tested the driver with sparse. Looks good so far.
Thanks for your effort.
Jan-Bernd Themann
Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
drivers/net/Kconfig | 9
drivers/net/Makefile | 1
drivers/net/ehea/Makefile | 6
drivers/net/ehea/ehea.h | 447 ++++++
drivers/net/ehea/ehea_ethtool.c | 294 ++++
drivers/net/ehea/ehea_hcall.h | 51
drivers/net/ehea/ehea_hw.h | 287 ++++
drivers/net/ehea/ehea_main.c | 2654 ++++++++++++++++++++++++++++++++++++++++
drivers/net/ehea/ehea_phyp.c | 705 ++++++++++
drivers/net/ehea/ehea_phyp.h | 455 ++++++
drivers/net/ehea/ehea_qmr.c | 582 ++++++++
drivers/net/ehea/ehea_qmr.h | 358 +++++
12 files changed, 5849 insertions(+)
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/ehea/ehea_qmr.c')
-rw-r--r-- | drivers/net/ehea/ehea_qmr.c | 582 |
1 files changed, 582 insertions, 0 deletions
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c new file mode 100644 index 000000000000..3e1862326c88 --- /dev/null +++ b/drivers/net/ehea/ehea_qmr.c | |||
@@ -0,0 +1,582 @@ | |||
1 | /* | ||
2 | * linux/drivers/net/ehea/ehea_qmr.c | ||
3 | * | ||
4 | * eHEA ethernet device driver for IBM eServer System p | ||
5 | * | ||
6 | * (C) Copyright IBM Corp. 2006 | ||
7 | * | ||
8 | * Authors: | ||
9 | * Christoph Raisch <raisch@de.ibm.com> | ||
10 | * Jan-Bernd Themann <themann@de.ibm.com> | ||
11 | * Thomas Klein <tklein@de.ibm.com> | ||
12 | * | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2, or (at your option) | ||
17 | * any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
27 | */ | ||
28 | |||
29 | #include "ehea.h" | ||
30 | #include "ehea_phyp.h" | ||
31 | #include "ehea_qmr.h" | ||
32 | |||
33 | static void *hw_qpageit_get_inc(struct hw_queue *queue) | ||
34 | { | ||
35 | void *retvalue = hw_qeit_get(queue); | ||
36 | |||
37 | queue->current_q_offset += queue->pagesize; | ||
38 | if (queue->current_q_offset > queue->queue_length) { | ||
39 | queue->current_q_offset -= queue->pagesize; | ||
40 | retvalue = NULL; | ||
41 | } else if (((u64) retvalue) & (EHEA_PAGESIZE-1)) { | ||
42 | ehea_error("not on pageboundary"); | ||
43 | retvalue = NULL; | ||
44 | } | ||
45 | return retvalue; | ||
46 | } | ||
47 | |||
48 | static int hw_queue_ctor(struct hw_queue *queue, const u32 nr_of_pages, | ||
49 | const u32 pagesize, const u32 qe_size) | ||
50 | { | ||
51 | int pages_per_kpage = PAGE_SIZE / pagesize; | ||
52 | int i, k; | ||
53 | |||
54 | if ((pagesize > PAGE_SIZE) || (!pages_per_kpage)) { | ||
55 | ehea_error("pagesize conflict! kernel pagesize=%d, " | ||
56 | "ehea pagesize=%d", (int)PAGE_SIZE, (int)pagesize); | ||
57 | return -EINVAL; | ||
58 | } | ||
59 | |||
60 | queue->queue_length = nr_of_pages * pagesize; | ||
61 | queue->queue_pages = kmalloc(nr_of_pages * sizeof(void*), GFP_KERNEL); | ||
62 | if (!queue->queue_pages) { | ||
63 | ehea_error("no mem for queue_pages"); | ||
64 | return -ENOMEM; | ||
65 | } | ||
66 | |||
67 | /* | ||
68 | * allocate pages for queue: | ||
69 | * outer loop allocates whole kernel pages (page aligned) and | ||
70 | * inner loop divides a kernel page into smaller hea queue pages | ||
71 | */ | ||
72 | i = 0; | ||
73 | while (i < nr_of_pages) { | ||
74 | u8 *kpage = (u8*)get_zeroed_page(GFP_KERNEL); | ||
75 | if (!kpage) | ||
76 | goto out_nomem; | ||
77 | for (k = 0; k < pages_per_kpage && i < nr_of_pages; k++) { | ||
78 | (queue->queue_pages)[i] = (struct ehea_page*)kpage; | ||
79 | kpage += pagesize; | ||
80 | i++; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | queue->current_q_offset = 0; | ||
85 | queue->qe_size = qe_size; | ||
86 | queue->pagesize = pagesize; | ||
87 | queue->toggle_state = 1; | ||
88 | |||
89 | return 0; | ||
90 | out_nomem: | ||
91 | for (i = 0; i < nr_of_pages; i += pages_per_kpage) { | ||
92 | if (!(queue->queue_pages)[i]) | ||
93 | break; | ||
94 | free_page((unsigned long)(queue->queue_pages)[i]); | ||
95 | } | ||
96 | return -ENOMEM; | ||
97 | } | ||
98 | |||
99 | static void hw_queue_dtor(struct hw_queue *queue) | ||
100 | { | ||
101 | int pages_per_kpage = PAGE_SIZE / queue->pagesize; | ||
102 | int i, nr_pages; | ||
103 | |||
104 | if (!queue || !queue->queue_pages) | ||
105 | return; | ||
106 | |||
107 | nr_pages = queue->queue_length / queue->pagesize; | ||
108 | |||
109 | for (i = 0; i < nr_pages; i += pages_per_kpage) | ||
110 | free_page((unsigned long)(queue->queue_pages)[i]); | ||
111 | |||
112 | kfree(queue->queue_pages); | ||
113 | } | ||
114 | |||
115 | struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter, | ||
116 | int nr_of_cqe, u64 eq_handle, u32 cq_token) | ||
117 | { | ||
118 | struct ehea_cq *cq; | ||
119 | struct h_epa epa; | ||
120 | u64 *cq_handle_ref, hret, rpage; | ||
121 | u32 act_nr_of_entries, act_pages, counter; | ||
122 | int ret; | ||
123 | void *vpage; | ||
124 | |||
125 | cq = kzalloc(sizeof(*cq), GFP_KERNEL); | ||
126 | if (!cq) { | ||
127 | ehea_error("no mem for cq"); | ||
128 | goto out_nomem; | ||
129 | } | ||
130 | |||
131 | cq->attr.max_nr_of_cqes = nr_of_cqe; | ||
132 | cq->attr.cq_token = cq_token; | ||
133 | cq->attr.eq_handle = eq_handle; | ||
134 | |||
135 | cq->adapter = adapter; | ||
136 | |||
137 | cq_handle_ref = &cq->fw_handle; | ||
138 | act_nr_of_entries = 0; | ||
139 | act_pages = 0; | ||
140 | |||
141 | hret = ehea_h_alloc_resource_cq(adapter->handle, &cq->attr, | ||
142 | &cq->fw_handle, &cq->epas); | ||
143 | if (hret != H_SUCCESS) { | ||
144 | ehea_error("alloc_resource_cq failed"); | ||
145 | goto out_freemem; | ||
146 | } | ||
147 | |||
148 | ret = hw_queue_ctor(&cq->hw_queue, cq->attr.nr_pages, | ||
149 | EHEA_PAGESIZE, sizeof(struct ehea_cqe)); | ||
150 | if (ret) | ||
151 | goto out_freeres; | ||
152 | |||
153 | for (counter = 0; counter < cq->attr.nr_pages; counter++) { | ||
154 | vpage = hw_qpageit_get_inc(&cq->hw_queue); | ||
155 | if (!vpage) { | ||
156 | ehea_error("hw_qpageit_get_inc failed"); | ||
157 | goto out_kill_hwq; | ||
158 | } | ||
159 | |||
160 | rpage = virt_to_abs(vpage); | ||
161 | hret = ehea_h_register_rpage(adapter->handle, | ||
162 | 0, EHEA_CQ_REGISTER_ORIG, | ||
163 | cq->fw_handle, rpage, 1); | ||
164 | if (hret < H_SUCCESS) { | ||
165 | ehea_error("register_rpage_cq failed ehea_cq=%p " | ||
166 | "hret=%lx counter=%i act_pages=%i", | ||
167 | cq, hret, counter, cq->attr.nr_pages); | ||
168 | goto out_kill_hwq; | ||
169 | } | ||
170 | |||
171 | if (counter == (cq->attr.nr_pages - 1)) { | ||
172 | vpage = hw_qpageit_get_inc(&cq->hw_queue); | ||
173 | |||
174 | if ((hret != H_SUCCESS) || (vpage)) { | ||
175 | ehea_error("registration of pages not " | ||
176 | "complete hret=%lx\n", hret); | ||
177 | goto out_kill_hwq; | ||
178 | } | ||
179 | } else { | ||
180 | if ((hret != H_PAGE_REGISTERED) || (!vpage)) { | ||
181 | ehea_error("CQ: registration of page failed " | ||
182 | "hret=%lx\n", hret); | ||
183 | goto out_kill_hwq; | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | |||
188 | hw_qeit_reset(&cq->hw_queue); | ||
189 | epa = cq->epas.kernel; | ||
190 | ehea_reset_cq_ep(cq); | ||
191 | ehea_reset_cq_n1(cq); | ||
192 | |||
193 | return cq; | ||
194 | |||
195 | out_kill_hwq: | ||
196 | hw_queue_dtor(&cq->hw_queue); | ||
197 | |||
198 | out_freeres: | ||
199 | ehea_h_free_resource(adapter->handle, cq->fw_handle); | ||
200 | |||
201 | out_freemem: | ||
202 | kfree(cq); | ||
203 | |||
204 | out_nomem: | ||
205 | return NULL; | ||
206 | } | ||
207 | |||
208 | int ehea_destroy_cq(struct ehea_cq *cq) | ||
209 | { | ||
210 | u64 adapter_handle, hret; | ||
211 | |||
212 | adapter_handle = cq->adapter->handle; | ||
213 | |||
214 | if (!cq) | ||
215 | return 0; | ||
216 | |||
217 | /* deregister all previous registered pages */ | ||
218 | hret = ehea_h_free_resource(adapter_handle, cq->fw_handle); | ||
219 | if (hret != H_SUCCESS) { | ||
220 | ehea_error("destroy CQ failed"); | ||
221 | return -EIO; | ||
222 | } | ||
223 | |||
224 | hw_queue_dtor(&cq->hw_queue); | ||
225 | kfree(cq); | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter, | ||
231 | const enum ehea_eq_type type, | ||
232 | const u32 max_nr_of_eqes, const u8 eqe_gen) | ||
233 | { | ||
234 | int ret, i; | ||
235 | u64 hret, rpage; | ||
236 | void *vpage; | ||
237 | struct ehea_eq *eq; | ||
238 | |||
239 | eq = kzalloc(sizeof(*eq), GFP_KERNEL); | ||
240 | if (!eq) { | ||
241 | ehea_error("no mem for eq"); | ||
242 | return NULL; | ||
243 | } | ||
244 | |||
245 | eq->adapter = adapter; | ||
246 | eq->attr.type = type; | ||
247 | eq->attr.max_nr_of_eqes = max_nr_of_eqes; | ||
248 | eq->attr.eqe_gen = eqe_gen; | ||
249 | spin_lock_init(&eq->spinlock); | ||
250 | |||
251 | hret = ehea_h_alloc_resource_eq(adapter->handle, | ||
252 | &eq->attr, &eq->fw_handle); | ||
253 | if (hret != H_SUCCESS) { | ||
254 | ehea_error("alloc_resource_eq failed"); | ||
255 | goto out_freemem; | ||
256 | } | ||
257 | |||
258 | ret = hw_queue_ctor(&eq->hw_queue, eq->attr.nr_pages, | ||
259 | EHEA_PAGESIZE, sizeof(struct ehea_eqe)); | ||
260 | if (ret) { | ||
261 | ehea_error("can't allocate eq pages"); | ||
262 | goto out_freeres; | ||
263 | } | ||
264 | |||
265 | for (i = 0; i < eq->attr.nr_pages; i++) { | ||
266 | vpage = hw_qpageit_get_inc(&eq->hw_queue); | ||
267 | if (!vpage) { | ||
268 | ehea_error("hw_qpageit_get_inc failed"); | ||
269 | hret = H_RESOURCE; | ||
270 | goto out_kill_hwq; | ||
271 | } | ||
272 | |||
273 | rpage = virt_to_abs(vpage); | ||
274 | |||
275 | hret = ehea_h_register_rpage(adapter->handle, 0, | ||
276 | EHEA_EQ_REGISTER_ORIG, | ||
277 | eq->fw_handle, rpage, 1); | ||
278 | |||
279 | if (i == (eq->attr.nr_pages - 1)) { | ||
280 | /* last page */ | ||
281 | vpage = hw_qpageit_get_inc(&eq->hw_queue); | ||
282 | if ((hret != H_SUCCESS) || (vpage)) { | ||
283 | goto out_kill_hwq; | ||
284 | } | ||
285 | } else { | ||
286 | if ((hret != H_PAGE_REGISTERED) || (!vpage)) { | ||
287 | goto out_kill_hwq; | ||
288 | } | ||
289 | } | ||
290 | } | ||
291 | |||
292 | hw_qeit_reset(&eq->hw_queue); | ||
293 | return eq; | ||
294 | |||
295 | out_kill_hwq: | ||
296 | hw_queue_dtor(&eq->hw_queue); | ||
297 | |||
298 | out_freeres: | ||
299 | ehea_h_free_resource(adapter->handle, eq->fw_handle); | ||
300 | |||
301 | out_freemem: | ||
302 | kfree(eq); | ||
303 | return NULL; | ||
304 | } | ||
305 | |||
306 | struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq) | ||
307 | { | ||
308 | struct ehea_eqe *eqe; | ||
309 | unsigned long flags; | ||
310 | |||
311 | spin_lock_irqsave(&eq->spinlock, flags); | ||
312 | eqe = (struct ehea_eqe*)hw_eqit_eq_get_inc_valid(&eq->hw_queue); | ||
313 | spin_unlock_irqrestore(&eq->spinlock, flags); | ||
314 | |||
315 | return eqe; | ||
316 | } | ||
317 | |||
318 | int ehea_destroy_eq(struct ehea_eq *eq) | ||
319 | { | ||
320 | u64 hret; | ||
321 | unsigned long flags; | ||
322 | |||
323 | if (!eq) | ||
324 | return 0; | ||
325 | |||
326 | spin_lock_irqsave(&eq->spinlock, flags); | ||
327 | |||
328 | hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle); | ||
329 | spin_unlock_irqrestore(&eq->spinlock, flags); | ||
330 | |||
331 | if (hret != H_SUCCESS) { | ||
332 | ehea_error("destroy_eq failed"); | ||
333 | return -EIO; | ||
334 | } | ||
335 | |||
336 | hw_queue_dtor(&eq->hw_queue); | ||
337 | kfree(eq); | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | /** | ||
343 | * allocates memory for a queue and registers pages in phyp | ||
344 | */ | ||
345 | int ehea_qp_alloc_register(struct ehea_qp *qp, struct hw_queue *hw_queue, | ||
346 | int nr_pages, int wqe_size, int act_nr_sges, | ||
347 | struct ehea_adapter *adapter, int h_call_q_selector) | ||
348 | { | ||
349 | u64 hret, rpage; | ||
350 | int ret, cnt; | ||
351 | void *vpage; | ||
352 | |||
353 | ret = hw_queue_ctor(hw_queue, nr_pages, EHEA_PAGESIZE, wqe_size); | ||
354 | if (ret) | ||
355 | return ret; | ||
356 | |||
357 | for (cnt = 0; cnt < nr_pages; cnt++) { | ||
358 | vpage = hw_qpageit_get_inc(hw_queue); | ||
359 | if (!vpage) { | ||
360 | ehea_error("hw_qpageit_get_inc failed"); | ||
361 | goto out_kill_hwq; | ||
362 | } | ||
363 | rpage = virt_to_abs(vpage); | ||
364 | hret = ehea_h_register_rpage(adapter->handle, | ||
365 | 0, h_call_q_selector, | ||
366 | qp->fw_handle, rpage, 1); | ||
367 | if (hret < H_SUCCESS) { | ||
368 | ehea_error("register_rpage_qp failed"); | ||
369 | goto out_kill_hwq; | ||
370 | } | ||
371 | } | ||
372 | hw_qeit_reset(hw_queue); | ||
373 | return 0; | ||
374 | |||
375 | out_kill_hwq: | ||
376 | hw_queue_dtor(hw_queue); | ||
377 | return -EIO; | ||
378 | } | ||
379 | |||
380 | static inline u32 map_wqe_size(u8 wqe_enc_size) | ||
381 | { | ||
382 | return 128 << wqe_enc_size; | ||
383 | } | ||
384 | |||
385 | struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter, | ||
386 | u32 pd, struct ehea_qp_init_attr *init_attr) | ||
387 | { | ||
388 | int ret; | ||
389 | u64 hret; | ||
390 | struct ehea_qp *qp; | ||
391 | u32 wqe_size_in_bytes_sq, wqe_size_in_bytes_rq1; | ||
392 | u32 wqe_size_in_bytes_rq2, wqe_size_in_bytes_rq3; | ||
393 | |||
394 | |||
395 | qp = kzalloc(sizeof(*qp), GFP_KERNEL); | ||
396 | if (!qp) { | ||
397 | ehea_error("no mem for qp"); | ||
398 | return NULL; | ||
399 | } | ||
400 | |||
401 | qp->adapter = adapter; | ||
402 | |||
403 | hret = ehea_h_alloc_resource_qp(adapter->handle, init_attr, pd, | ||
404 | &qp->fw_handle, &qp->epas); | ||
405 | if (hret != H_SUCCESS) { | ||
406 | ehea_error("ehea_h_alloc_resource_qp failed"); | ||
407 | goto out_freemem; | ||
408 | } | ||
409 | |||
410 | wqe_size_in_bytes_sq = map_wqe_size(init_attr->act_wqe_size_enc_sq); | ||
411 | wqe_size_in_bytes_rq1 = map_wqe_size(init_attr->act_wqe_size_enc_rq1); | ||
412 | wqe_size_in_bytes_rq2 = map_wqe_size(init_attr->act_wqe_size_enc_rq2); | ||
413 | wqe_size_in_bytes_rq3 = map_wqe_size(init_attr->act_wqe_size_enc_rq3); | ||
414 | |||
415 | ret = ehea_qp_alloc_register(qp, &qp->hw_squeue, init_attr->nr_sq_pages, | ||
416 | wqe_size_in_bytes_sq, | ||
417 | init_attr->act_wqe_size_enc_sq, adapter, | ||
418 | 0); | ||
419 | if (ret) { | ||
420 | ehea_error("can't register for sq ret=%x", ret); | ||
421 | goto out_freeres; | ||
422 | } | ||
423 | |||
424 | ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue1, | ||
425 | init_attr->nr_rq1_pages, | ||
426 | wqe_size_in_bytes_rq1, | ||
427 | init_attr->act_wqe_size_enc_rq1, | ||
428 | adapter, 1); | ||
429 | if (ret) { | ||
430 | ehea_error("can't register for rq1 ret=%x", ret); | ||
431 | goto out_kill_hwsq; | ||
432 | } | ||
433 | |||
434 | if (init_attr->rq_count > 1) { | ||
435 | ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue2, | ||
436 | init_attr->nr_rq2_pages, | ||
437 | wqe_size_in_bytes_rq2, | ||
438 | init_attr->act_wqe_size_enc_rq2, | ||
439 | adapter, 2); | ||
440 | if (ret) { | ||
441 | ehea_error("can't register for rq2 ret=%x", ret); | ||
442 | goto out_kill_hwr1q; | ||
443 | } | ||
444 | } | ||
445 | |||
446 | if (init_attr->rq_count > 2) { | ||
447 | ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue3, | ||
448 | init_attr->nr_rq3_pages, | ||
449 | wqe_size_in_bytes_rq3, | ||
450 | init_attr->act_wqe_size_enc_rq3, | ||
451 | adapter, 3); | ||
452 | if (ret) { | ||
453 | ehea_error("can't register for rq3 ret=%x", ret); | ||
454 | goto out_kill_hwr2q; | ||
455 | } | ||
456 | } | ||
457 | |||
458 | qp->init_attr = *init_attr; | ||
459 | |||
460 | return qp; | ||
461 | |||
462 | out_kill_hwr2q: | ||
463 | hw_queue_dtor(&qp->hw_rqueue2); | ||
464 | |||
465 | out_kill_hwr1q: | ||
466 | hw_queue_dtor(&qp->hw_rqueue1); | ||
467 | |||
468 | out_kill_hwsq: | ||
469 | hw_queue_dtor(&qp->hw_squeue); | ||
470 | |||
471 | out_freeres: | ||
472 | ehea_h_disable_and_get_hea(adapter->handle, qp->fw_handle); | ||
473 | ehea_h_free_resource(adapter->handle, qp->fw_handle); | ||
474 | |||
475 | out_freemem: | ||
476 | kfree(qp); | ||
477 | return NULL; | ||
478 | } | ||
479 | |||
480 | int ehea_destroy_qp(struct ehea_qp *qp) | ||
481 | { | ||
482 | u64 hret; | ||
483 | struct ehea_qp_init_attr *qp_attr = &qp->init_attr; | ||
484 | |||
485 | if (!qp) | ||
486 | return 0; | ||
487 | |||
488 | hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle); | ||
489 | if (hret != H_SUCCESS) { | ||
490 | ehea_error("destroy_qp failed"); | ||
491 | return -EIO; | ||
492 | } | ||
493 | |||
494 | hw_queue_dtor(&qp->hw_squeue); | ||
495 | hw_queue_dtor(&qp->hw_rqueue1); | ||
496 | |||
497 | if (qp_attr->rq_count > 1) | ||
498 | hw_queue_dtor(&qp->hw_rqueue2); | ||
499 | if (qp_attr->rq_count > 2) | ||
500 | hw_queue_dtor(&qp->hw_rqueue3); | ||
501 | kfree(qp); | ||
502 | |||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | int ehea_reg_mr_adapter(struct ehea_adapter *adapter) | ||
507 | { | ||
508 | int i, k, ret; | ||
509 | u64 hret, pt_abs, start, end, nr_pages; | ||
510 | u32 acc_ctrl = EHEA_MR_ACC_CTRL; | ||
511 | u64 *pt; | ||
512 | |||
513 | start = KERNELBASE; | ||
514 | end = (u64)high_memory; | ||
515 | nr_pages = (end - start) / PAGE_SIZE; | ||
516 | |||
517 | pt = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
518 | if (!pt) { | ||
519 | ehea_error("no mem"); | ||
520 | ret = -ENOMEM; | ||
521 | goto out; | ||
522 | } | ||
523 | pt_abs = virt_to_abs(pt); | ||
524 | |||
525 | hret = ehea_h_alloc_resource_mr(adapter->handle, start, end - start, | ||
526 | acc_ctrl, adapter->pd, | ||
527 | &adapter->mr.handle, &adapter->mr.lkey); | ||
528 | if (hret != H_SUCCESS) { | ||
529 | ehea_error("alloc_resource_mr failed"); | ||
530 | ret = -EIO; | ||
531 | goto out; | ||
532 | } | ||
533 | |||
534 | adapter->mr.vaddr = KERNELBASE; | ||
535 | k = 0; | ||
536 | |||
537 | while (nr_pages > 0) { | ||
538 | if (nr_pages > 1) { | ||
539 | u64 num_pages = min(nr_pages, (u64)512); | ||
540 | for (i = 0; i < num_pages; i++) | ||
541 | pt[i] = virt_to_abs((void*)(((u64)start) | ||
542 | + ((k++) * | ||
543 | PAGE_SIZE))); | ||
544 | |||
545 | hret = ehea_h_register_rpage_mr(adapter->handle, | ||
546 | adapter->mr.handle, 0, | ||
547 | 0, (u64)pt_abs, | ||
548 | num_pages); | ||
549 | nr_pages -= num_pages; | ||
550 | } else { | ||
551 | u64 abs_adr = virt_to_abs((void*)(((u64)start) | ||
552 | + (k * PAGE_SIZE))); | ||
553 | hret = ehea_h_register_rpage_mr(adapter->handle, | ||
554 | adapter->mr.handle, 0, | ||
555 | 0, abs_adr,1); | ||
556 | nr_pages--; | ||
557 | } | ||
558 | |||
559 | if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) { | ||
560 | ehea_h_free_resource(adapter->handle, | ||
561 | adapter->mr.handle); | ||
562 | ehea_error("register_rpage_mr failed: hret = %lX", | ||
563 | hret); | ||
564 | ret = -EIO; | ||
565 | goto out; | ||
566 | } | ||
567 | } | ||
568 | |||
569 | if (hret != H_SUCCESS) { | ||
570 | ehea_h_free_resource(adapter->handle, adapter->mr.handle); | ||
571 | ehea_error("register_rpage failed for last page: hret = %lX", | ||
572 | hret); | ||
573 | ret = -EIO; | ||
574 | goto out; | ||
575 | } | ||
576 | ret = 0; | ||
577 | out: | ||
578 | kfree(pt); | ||
579 | return ret; | ||
580 | } | ||
581 | |||
582 | |||