Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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