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.19-rc2 582 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 "ehea.h" 30#include "ehea_phyp.h" 31#include "ehea_qmr.h" 32 33static 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 48static 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; 90out_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 99static 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 115struct 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 195out_kill_hwq: 196 hw_queue_dtor(&cq->hw_queue); 197 198out_freeres: 199 ehea_h_free_resource(adapter->handle, cq->fw_handle); 200 201out_freemem: 202 kfree(cq); 203 204out_nomem: 205 return NULL; 206} 207 208int 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 230struct 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 295out_kill_hwq: 296 hw_queue_dtor(&eq->hw_queue); 297 298out_freeres: 299 ehea_h_free_resource(adapter->handle, eq->fw_handle); 300 301out_freemem: 302 kfree(eq); 303 return NULL; 304} 305 306struct 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 318int 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 */ 345int 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 375out_kill_hwq: 376 hw_queue_dtor(hw_queue); 377 return -EIO; 378} 379 380static inline u32 map_wqe_size(u8 wqe_enc_size) 381{ 382 return 128 << wqe_enc_size; 383} 384 385struct 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 462out_kill_hwr2q: 463 hw_queue_dtor(&qp->hw_rqueue2); 464 465out_kill_hwr1q: 466 hw_queue_dtor(&qp->hw_rqueue1); 467 468out_kill_hwsq: 469 hw_queue_dtor(&qp->hw_squeue); 470 471out_freeres: 472 ehea_h_disable_and_get_hea(adapter->handle, qp->fw_handle); 473 ehea_h_free_resource(adapter->handle, qp->fw_handle); 474 475out_freemem: 476 kfree(qp); 477 return NULL; 478} 479 480int 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 506int 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; 577out: 578 kfree(pt); 579 return ret; 580} 581 582