1/*************************************************************************** 2 * Copyright (c) 2005-2009, Broadcom Corporation. 3 * 4 * Name: crystalhd_misc . c 5 * 6 * Description: 7 * BCM70012 Linux driver misc routines. 8 * 9 * HISTORY: 10 * 11 ********************************************************************** 12 * This file is part of the crystalhd device driver. 13 * 14 * This driver 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, version 2 of the License. 17 * 18 * This driver is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this driver. If not, see <http://www.gnu.org/licenses/>. 25 **********************************************************************/ 26 27#include <linux/slab.h> 28 29#include "crystalhd_misc.h" 30#include "crystalhd_lnx.h" 31 32uint32_t g_linklog_level; 33 34static inline uint32_t crystalhd_dram_rd(struct crystalhd_adp *adp, uint32_t mem_off) 35{ 36 crystalhd_reg_wr(adp, DCI_DRAM_BASE_ADDR, (mem_off >> 19)); 37 return bc_dec_reg_rd(adp, (0x00380000 | (mem_off & 0x0007FFFF))); 38} 39 40static inline void crystalhd_dram_wr(struct crystalhd_adp *adp, uint32_t mem_off, uint32_t val) 41{ 42 crystalhd_reg_wr(adp, DCI_DRAM_BASE_ADDR, (mem_off >> 19)); 43 bc_dec_reg_wr(adp, (0x00380000 | (mem_off & 0x0007FFFF)), val); 44} 45 46static inline enum BC_STATUS bc_chk_dram_range(struct crystalhd_adp *adp, uint32_t start_off, uint32_t cnt) 47{ 48 return BC_STS_SUCCESS; 49} 50 51static struct crystalhd_dio_req *crystalhd_alloc_dio(struct crystalhd_adp *adp) 52{ 53 unsigned long flags = 0; 54 struct crystalhd_dio_req *temp = NULL; 55 56 if (!adp) { 57 BCMLOG_ERR("Invalid Arg!!\n"); 58 return temp; 59 } 60 61 spin_lock_irqsave(&adp->lock, flags); 62 temp = adp->ua_map_free_head; 63 if (temp) 64 adp->ua_map_free_head = adp->ua_map_free_head->next; 65 spin_unlock_irqrestore(&adp->lock, flags); 66 67 return temp; 68} 69 70static void crystalhd_free_dio(struct crystalhd_adp *adp, struct crystalhd_dio_req *dio) 71{ 72 unsigned long flags = 0; 73 74 if (!adp || !dio) 75 return; 76 spin_lock_irqsave(&adp->lock, flags); 77 dio->sig = crystalhd_dio_inv; 78 dio->page_cnt = 0; 79 dio->fb_size = 0; 80 memset(&dio->uinfo, 0, sizeof(dio->uinfo)); 81 dio->next = adp->ua_map_free_head; 82 adp->ua_map_free_head = dio; 83 spin_unlock_irqrestore(&adp->lock, flags); 84} 85 86static struct crystalhd_elem *crystalhd_alloc_elem(struct crystalhd_adp *adp) 87{ 88 unsigned long flags = 0; 89 struct crystalhd_elem *temp = NULL; 90 91 if (!adp) 92 return temp; 93 spin_lock_irqsave(&adp->lock, flags); 94 temp = adp->elem_pool_head; 95 if (temp) { 96 adp->elem_pool_head = adp->elem_pool_head->flink; 97 memset(temp, 0, sizeof(*temp)); 98 } 99 spin_unlock_irqrestore(&adp->lock, flags); 100 101 return temp; 102} 103static void crystalhd_free_elem(struct crystalhd_adp *adp, struct crystalhd_elem *elem) 104{ 105 unsigned long flags = 0; 106 107 if (!adp || !elem) 108 return; 109 spin_lock_irqsave(&adp->lock, flags); 110 elem->flink = adp->elem_pool_head; 111 adp->elem_pool_head = elem; 112 spin_unlock_irqrestore(&adp->lock, flags); 113} 114 115static inline void crystalhd_set_sg(struct scatterlist *sg, struct page *page, 116 unsigned int len, unsigned int offset) 117{ 118 sg_set_page(sg, page, len, offset); 119#ifdef CONFIG_X86_64 120 sg->dma_length = len; 121#endif 122} 123 124static inline void crystalhd_init_sg(struct scatterlist *sg, unsigned int entries) 125{ 126 /* http://lkml.org/lkml/2007/11/27/68 */ 127 sg_init_table(sg, entries); 128} 129 130/*========================== Extern ========================================*/ 131/** 132 * bc_dec_reg_rd - Read 7412's device register. 133 * @adp: Adapter instance 134 * @reg_off: Register offset. 135 * 136 * Return: 137 * 32bit value read 138 * 139 * 7412's device register read routine. This interface use 140 * 7412's device access range mapped from BAR-2 (4M) of PCIe 141 * configuration space. 142 */ 143uint32_t bc_dec_reg_rd(struct crystalhd_adp *adp, uint32_t reg_off) 144{ 145 if (!adp || (reg_off > adp->pci_mem_len)) { 146 BCMLOG_ERR("dec_rd_reg_off outof range: 0x%08x\n", reg_off); 147 return 0; 148 } 149 150 return readl(adp->addr + reg_off); 151} 152 153/** 154 * bc_dec_reg_wr - Write 7412's device register 155 * @adp: Adapter instance 156 * @reg_off: Register offset. 157 * @val: Dword value to be written. 158 * 159 * Return: 160 * none. 161 * 162 * 7412's device register write routine. This interface use 163 * 7412's device access range mapped from BAR-2 (4M) of PCIe 164 * configuration space. 165 */ 166void bc_dec_reg_wr(struct crystalhd_adp *adp, uint32_t reg_off, uint32_t val) 167{ 168 if (!adp || (reg_off > adp->pci_mem_len)) { 169 BCMLOG_ERR("dec_wr_reg_off outof range: 0x%08x\n", reg_off); 170 return; 171 } 172 writel(val, adp->addr + reg_off); 173 udelay(8); 174} 175 176/** 177 * crystalhd_reg_rd - Read Link's device register. 178 * @adp: Adapter instance 179 * @reg_off: Register offset. 180 * 181 * Return: 182 * 32bit value read 183 * 184 * Link device register read routine. This interface use 185 * Link's device access range mapped from BAR-1 (64K) of PCIe 186 * configuration space. 187 * 188 */ 189uint32_t crystalhd_reg_rd(struct crystalhd_adp *adp, uint32_t reg_off) 190{ 191 if (!adp || (reg_off > adp->pci_i2o_len)) { 192 BCMLOG_ERR("link_rd_reg_off outof range: 0x%08x\n", reg_off); 193 return 0; 194 } 195 return readl(adp->i2o_addr + reg_off); 196} 197 198/** 199 * crystalhd_reg_wr - Write Link's device register 200 * @adp: Adapter instance 201 * @reg_off: Register offset. 202 * @val: Dword value to be written. 203 * 204 * Return: 205 * none. 206 * 207 * Link device register write routine. This interface use 208 * Link's device access range mapped from BAR-1 (64K) of PCIe 209 * configuration space. 210 * 211 */ 212void crystalhd_reg_wr(struct crystalhd_adp *adp, uint32_t reg_off, uint32_t val) 213{ 214 if (!adp || (reg_off > adp->pci_i2o_len)) { 215 BCMLOG_ERR("link_wr_reg_off outof range: 0x%08x\n", reg_off); 216 return; 217 } 218 writel(val, adp->i2o_addr + reg_off); 219} 220 221/** 222 * crystalhd_mem_rd - Read data from 7412's DRAM area. 223 * @adp: Adapter instance 224 * @start_off: Start offset. 225 * @dw_cnt: Count in dwords. 226 * @rd_buff: Buffer to copy the data from dram. 227 * 228 * Return: 229 * Status. 230 * 231 * 7412's Dram read routine. 232 */ 233enum BC_STATUS crystalhd_mem_rd(struct crystalhd_adp *adp, uint32_t start_off, 234 uint32_t dw_cnt, uint32_t *rd_buff) 235{ 236 uint32_t ix = 0; 237 238 if (!adp || !rd_buff || 239 (bc_chk_dram_range(adp, start_off, dw_cnt) != BC_STS_SUCCESS)) { 240 BCMLOG_ERR("Invalid arg\n"); 241 return BC_STS_INV_ARG; 242 } 243 for (ix = 0; ix < dw_cnt; ix++) 244 rd_buff[ix] = crystalhd_dram_rd(adp, (start_off + (ix * 4))); 245 246 return BC_STS_SUCCESS; 247} 248 249/** 250 * crystalhd_mem_wr - Write data to 7412's DRAM area. 251 * @adp: Adapter instance 252 * @start_off: Start offset. 253 * @dw_cnt: Count in dwords. 254 * @wr_buff: Data Buffer to be written. 255 * 256 * Return: 257 * Status. 258 * 259 * 7412's Dram write routine. 260 */ 261enum BC_STATUS crystalhd_mem_wr(struct crystalhd_adp *adp, uint32_t start_off, 262 uint32_t dw_cnt, uint32_t *wr_buff) 263{ 264 uint32_t ix = 0; 265 266 if (!adp || !wr_buff || 267 (bc_chk_dram_range(adp, start_off, dw_cnt) != BC_STS_SUCCESS)) { 268 BCMLOG_ERR("Invalid arg\n"); 269 return BC_STS_INV_ARG; 270 } 271 272 for (ix = 0; ix < dw_cnt; ix++) 273 crystalhd_dram_wr(adp, (start_off + (ix * 4)), wr_buff[ix]); 274 275 return BC_STS_SUCCESS; 276} 277/** 278 * crystalhd_pci_cfg_rd - PCIe config read 279 * @adp: Adapter instance 280 * @off: PCI config space offset. 281 * @len: Size -- Byte, Word & dword. 282 * @val: Value read 283 * 284 * Return: 285 * Status. 286 * 287 * Get value from Link's PCIe config space. 288 */ 289enum BC_STATUS crystalhd_pci_cfg_rd(struct crystalhd_adp *adp, uint32_t off, 290 uint32_t len, uint32_t *val) 291{ 292 enum BC_STATUS sts = BC_STS_SUCCESS; 293 int rc = 0; 294 295 if (!adp || !val) { 296 BCMLOG_ERR("Invalid arg\n"); 297 return BC_STS_INV_ARG; 298 } 299 300 switch (len) { 301 case 1: 302 rc = pci_read_config_byte(adp->pdev, off, (u8 *)val); 303 break; 304 case 2: 305 rc = pci_read_config_word(adp->pdev, off, (u16 *)val); 306 break; 307 case 4: 308 rc = pci_read_config_dword(adp->pdev, off, (u32 *)val); 309 break; 310 default: 311 rc = -EINVAL; 312 sts = BC_STS_INV_ARG; 313 BCMLOG_ERR("Invalid len:%d\n", len); 314 }; 315 316 if (rc && (sts == BC_STS_SUCCESS)) 317 sts = BC_STS_ERROR; 318 319 return sts; 320} 321 322/** 323 * crystalhd_pci_cfg_wr - PCIe config write 324 * @adp: Adapter instance 325 * @off: PCI config space offset. 326 * @len: Size -- Byte, Word & dword. 327 * @val: Value to be written 328 * 329 * Return: 330 * Status. 331 * 332 * Set value to Link's PCIe config space. 333 */ 334enum BC_STATUS crystalhd_pci_cfg_wr(struct crystalhd_adp *adp, uint32_t off, 335 uint32_t len, uint32_t val) 336{ 337 enum BC_STATUS sts = BC_STS_SUCCESS; 338 int rc = 0; 339 340 if (!adp || !val) { 341 BCMLOG_ERR("Invalid arg\n"); 342 return BC_STS_INV_ARG; 343 } 344 345 switch (len) { 346 case 1: 347 rc = pci_write_config_byte(adp->pdev, off, (u8)val); 348 break; 349 case 2: 350 rc = pci_write_config_word(adp->pdev, off, (u16)val); 351 break; 352 case 4: 353 rc = pci_write_config_dword(adp->pdev, off, val); 354 break; 355 default: 356 rc = -EINVAL; 357 sts = BC_STS_INV_ARG; 358 BCMLOG_ERR("Invalid len:%d\n", len); 359 }; 360 361 if (rc && (sts == BC_STS_SUCCESS)) 362 sts = BC_STS_ERROR; 363 364 return sts; 365} 366 367/** 368 * bc_kern_dma_alloc - Allocate memory for Dma rings 369 * @adp: Adapter instance 370 * @sz: Size of the memory to allocate. 371 * @phy_addr: Physical address of the memory allocated. 372 * Typedef to system's dma_addr_t (u64) 373 * 374 * Return: 375 * Pointer to allocated memory.. 376 * 377 * Wrapper to Linux kernel interface. 378 * 379 */ 380void *bc_kern_dma_alloc(struct crystalhd_adp *adp, uint32_t sz, 381 dma_addr_t *phy_addr) 382{ 383 void *temp = NULL; 384 385 if (!adp || !sz || !phy_addr) { 386 BCMLOG_ERR("Invalide Arg..\n"); 387 return temp; 388 } 389 390 temp = pci_alloc_consistent(adp->pdev, sz, phy_addr); 391 if (temp) 392 memset(temp, 0, sz); 393 394 return temp; 395} 396 397/** 398 * bc_kern_dma_free - Release Dma ring memory. 399 * @adp: Adapter instance 400 * @sz: Size of the memory to allocate. 401 * @ka: Kernel virtual address returned during _dio_alloc() 402 * @phy_addr: Physical address of the memory allocated. 403 * Typedef to system's dma_addr_t (u64) 404 * 405 * Return: 406 * none. 407 */ 408void bc_kern_dma_free(struct crystalhd_adp *adp, uint32_t sz, void *ka, 409 dma_addr_t phy_addr) 410{ 411 if (!adp || !ka || !sz || !phy_addr) { 412 BCMLOG_ERR("Invalide Arg..\n"); 413 return; 414 } 415 416 pci_free_consistent(adp->pdev, sz, ka, phy_addr); 417} 418 419/** 420 * crystalhd_create_dioq - Create Generic DIO queue 421 * @adp: Adapter instance 422 * @dioq_hnd: Handle to the dio queue created 423 * @cb : Optional - Call back To free the element. 424 * @cbctx: Context to pass to callback. 425 * 426 * Return: 427 * status 428 * 429 * Initialize Generic DIO queue to hold any data. Callback 430 * will be used to free elements while deleting the queue. 431 */ 432enum BC_STATUS crystalhd_create_dioq(struct crystalhd_adp *adp, 433 struct crystalhd_dioq **dioq_hnd, 434 crystalhd_data_free_cb cb, void *cbctx) 435{ 436 struct crystalhd_dioq *dioq = NULL; 437 438 if (!adp || !dioq_hnd) { 439 BCMLOG_ERR("Invalid arg!!\n"); 440 return BC_STS_INV_ARG; 441 } 442 443 dioq = kzalloc(sizeof(*dioq), GFP_KERNEL); 444 if (!dioq) 445 return BC_STS_INSUFF_RES; 446 447 spin_lock_init(&dioq->lock); 448 dioq->sig = BC_LINK_DIOQ_SIG; 449 dioq->head = (struct crystalhd_elem *)&dioq->head; 450 dioq->tail = (struct crystalhd_elem *)&dioq->head; 451 crystalhd_create_event(&dioq->event); 452 dioq->adp = adp; 453 dioq->data_rel_cb = cb; 454 dioq->cb_context = cbctx; 455 *dioq_hnd = dioq; 456 457 return BC_STS_SUCCESS; 458} 459 460/** 461 * crystalhd_delete_dioq - Delete Generic DIO queue 462 * @adp: Adapter instance 463 * @dioq: DIOQ instance.. 464 * 465 * Return: 466 * None. 467 * 468 * Release Generic DIO queue. This function will remove 469 * all the entries from the Queue and will release data 470 * by calling the call back provided during creation. 471 * 472 */ 473void crystalhd_delete_dioq(struct crystalhd_adp *adp, struct crystalhd_dioq *dioq) 474{ 475 void *temp; 476 477 if (!dioq || (dioq->sig != BC_LINK_DIOQ_SIG)) 478 return; 479 480 do { 481 temp = crystalhd_dioq_fetch(dioq); 482 if (temp && dioq->data_rel_cb) 483 dioq->data_rel_cb(dioq->cb_context, temp); 484 } while (temp); 485 dioq->sig = 0; 486 kfree(dioq); 487} 488 489/** 490 * crystalhd_dioq_add - Add new DIO request element. 491 * @ioq: DIO queue instance 492 * @t: DIO request to be added. 493 * @wake: True - Wake up suspended process. 494 * @tag: Special tag to assign - For search and get. 495 * 496 * Return: 497 * Status. 498 * 499 * Insert new element to Q tail. 500 */ 501enum BC_STATUS crystalhd_dioq_add(struct crystalhd_dioq *ioq, void *data, 502 bool wake, uint32_t tag) 503{ 504 unsigned long flags = 0; 505 struct crystalhd_elem *tmp; 506 507 if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG) || !data) { 508 BCMLOG_ERR("Invalid arg!!\n"); 509 return BC_STS_INV_ARG; 510 } 511 512 tmp = crystalhd_alloc_elem(ioq->adp); 513 if (!tmp) { 514 BCMLOG_ERR("No free elements.\n"); 515 return BC_STS_INSUFF_RES; 516 } 517 518 tmp->data = data; 519 tmp->tag = tag; 520 spin_lock_irqsave(&ioq->lock, flags); 521 tmp->flink = (struct crystalhd_elem *)&ioq->head; 522 tmp->blink = ioq->tail; 523 tmp->flink->blink = tmp; 524 tmp->blink->flink = tmp; 525 ioq->count++; 526 spin_unlock_irqrestore(&ioq->lock, flags); 527 528 if (wake) 529 crystalhd_set_event(&ioq->event); 530 531 return BC_STS_SUCCESS; 532} 533 534/** 535 * crystalhd_dioq_fetch - Fetch element from head. 536 * @ioq: DIO queue instance 537 * 538 * Return: 539 * data element from the head.. 540 * 541 * Remove an element from Queue. 542 */ 543void *crystalhd_dioq_fetch(struct crystalhd_dioq *ioq) 544{ 545 unsigned long flags = 0; 546 struct crystalhd_elem *tmp; 547 struct crystalhd_elem *ret = NULL; 548 void *data = NULL; 549 550 if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG)) { 551 BCMLOG_ERR("Invalid arg!!\n"); 552 return data; 553 } 554 555 spin_lock_irqsave(&ioq->lock, flags); 556 tmp = ioq->head; 557 if (tmp != (struct crystalhd_elem *)&ioq->head) { 558 ret = tmp; 559 tmp->flink->blink = tmp->blink; 560 tmp->blink->flink = tmp->flink; 561 ioq->count--; 562 } 563 spin_unlock_irqrestore(&ioq->lock, flags); 564 if (ret) { 565 data = ret->data; 566 crystalhd_free_elem(ioq->adp, ret); 567 } 568 569 return data; 570} 571/** 572 * crystalhd_dioq_find_and_fetch - Search the tag and Fetch element 573 * @ioq: DIO queue instance 574 * @tag: Tag to search for. 575 * 576 * Return: 577 * element from the head.. 578 * 579 * Search TAG and remove the element. 580 */ 581void *crystalhd_dioq_find_and_fetch(struct crystalhd_dioq *ioq, uint32_t tag) 582{ 583 unsigned long flags = 0; 584 struct crystalhd_elem *tmp; 585 struct crystalhd_elem *ret = NULL; 586 void *data = NULL; 587 588 if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG)) { 589 BCMLOG_ERR("Invalid arg!!\n"); 590 return data; 591 } 592 593 spin_lock_irqsave(&ioq->lock, flags); 594 tmp = ioq->head; 595 while (tmp != (struct crystalhd_elem *)&ioq->head) { 596 if (tmp->tag == tag) { 597 ret = tmp; 598 tmp->flink->blink = tmp->blink; 599 tmp->blink->flink = tmp->flink; 600 ioq->count--; 601 break; 602 } 603 tmp = tmp->flink; 604 } 605 spin_unlock_irqrestore(&ioq->lock, flags); 606 607 if (ret) { 608 data = ret->data; 609 crystalhd_free_elem(ioq->adp, ret); 610 } 611 612 return data; 613} 614 615/** 616 * crystalhd_dioq_fetch_wait - Fetch element from Head. 617 * @ioq: DIO queue instance 618 * @to_secs: Wait timeout in seconds.. 619 * 620 * Return: 621 * element from the head.. 622 * 623 * Return element from head if Q is not empty. Wait for new element 624 * if Q is empty for Timeout seconds. 625 */ 626void *crystalhd_dioq_fetch_wait(struct crystalhd_dioq *ioq, uint32_t to_secs, 627 uint32_t *sig_pend) 628{ 629 unsigned long flags = 0; 630 int rc = 0, count; 631 void *tmp = NULL; 632 633 if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG) || !to_secs || !sig_pend) { 634 BCMLOG_ERR("Invalid arg!!\n"); 635 return tmp; 636 } 637 638 count = to_secs; 639 spin_lock_irqsave(&ioq->lock, flags); 640 while ((ioq->count == 0) && count) { 641 spin_unlock_irqrestore(&ioq->lock, flags); 642 643 crystalhd_wait_on_event(&ioq->event, (ioq->count > 0), 1000, rc, 0); 644 if (rc == 0) { 645 goto out; 646 } else if (rc == -EINTR) { 647 BCMLOG(BCMLOG_INFO, "Cancelling fetch wait\n"); 648 *sig_pend = 1; 649 return tmp; 650 } 651 spin_lock_irqsave(&ioq->lock, flags); 652 count--; 653 } 654 spin_unlock_irqrestore(&ioq->lock, flags); 655 656out: 657 return crystalhd_dioq_fetch(ioq); 658} 659 660/** 661 * crystalhd_map_dio - Map user address for DMA 662 * @adp: Adapter instance 663 * @ubuff: User buffer to map. 664 * @ubuff_sz: User buffer size. 665 * @uv_offset: UV buffer offset. 666 * @en_422mode: TRUE:422 FALSE:420 Capture mode. 667 * @dir_tx: TRUE for Tx (To device from host) 668 * @dio_hnd: Handle to mapped DIO request. 669 * 670 * Return: 671 * Status. 672 * 673 * This routine maps user address and lock pages for DMA. 674 * 675 */ 676enum BC_STATUS crystalhd_map_dio(struct crystalhd_adp *adp, void *ubuff, 677 uint32_t ubuff_sz, uint32_t uv_offset, 678 bool en_422mode, bool dir_tx, 679 struct crystalhd_dio_req **dio_hnd) 680{ 681 struct crystalhd_dio_req *dio; 682 unsigned long start = 0, end = 0, uaddr = 0, count = 0; 683 unsigned long spsz = 0, uv_start = 0; 684 int i = 0, rw = 0, res = 0, nr_pages = 0, skip_fb_sg = 0; 685 686 if (!adp || !ubuff || !ubuff_sz || !dio_hnd) { 687 BCMLOG_ERR("Invalid arg\n"); 688 return BC_STS_INV_ARG; 689 } 690 /* Compute pages */ 691 uaddr = (unsigned long)ubuff; 692 count = (unsigned long)ubuff_sz; 693 end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT; 694 start = uaddr >> PAGE_SHIFT; 695 nr_pages = end - start; 696 697 if (!count || ((uaddr + count) < uaddr)) { 698 BCMLOG_ERR("User addr overflow!!\n"); 699 return BC_STS_INV_ARG; 700 } 701 702 dio = crystalhd_alloc_dio(adp); 703 if (!dio) { 704 BCMLOG_ERR("dio pool empty..\n"); 705 return BC_STS_INSUFF_RES; 706 } 707 708 if (dir_tx) { 709 rw = WRITE; 710 dio->direction = DMA_TO_DEVICE; 711 } else { 712 rw = READ; 713 dio->direction = DMA_FROM_DEVICE; 714 } 715 716 if (nr_pages > dio->max_pages) { 717 BCMLOG_ERR("max_pages(%d) exceeded(%d)!!\n", 718 dio->max_pages, nr_pages); 719 crystalhd_unmap_dio(adp, dio); 720 return BC_STS_INSUFF_RES; 721 } 722 723 if (uv_offset) { 724 uv_start = (uaddr + (unsigned long)uv_offset) >> PAGE_SHIFT; 725 dio->uinfo.uv_sg_ix = uv_start - start; 726 dio->uinfo.uv_sg_off = ((uaddr + (unsigned long)uv_offset) & ~PAGE_MASK); 727 } 728 729 dio->fb_size = ubuff_sz & 0x03; 730 if (dio->fb_size) { 731 res = copy_from_user(dio->fb_va, 732 (void *)(uaddr + count - dio->fb_size), 733 dio->fb_size); 734 if (res) { 735 BCMLOG_ERR("failed %d to copy %u fill bytes from %p\n", 736 res, dio->fb_size, 737 (void *)(uaddr + count-dio->fb_size)); 738 crystalhd_unmap_dio(adp, dio); 739 return BC_STS_INSUFF_RES; 740 } 741 } 742 743 down_read(¤t->mm->mmap_sem); 744 res = get_user_pages(current, current->mm, uaddr, nr_pages, rw == READ, 745 0, dio->pages, NULL); 746 up_read(¤t->mm->mmap_sem); 747 748 /* Save for release..*/ 749 dio->sig = crystalhd_dio_locked; 750 if (res < nr_pages) { 751 BCMLOG_ERR("get pages failed: %d-%d\n", nr_pages, res); 752 dio->page_cnt = res; 753 crystalhd_unmap_dio(adp, dio); 754 return BC_STS_ERROR; 755 } 756 757 dio->page_cnt = nr_pages; 758 /* Get scatter/gather */ 759 crystalhd_init_sg(dio->sg, dio->page_cnt); 760 crystalhd_set_sg(&dio->sg[0], dio->pages[0], 0, uaddr & ~PAGE_MASK); 761 if (nr_pages > 1) { 762 dio->sg[0].length = PAGE_SIZE - dio->sg[0].offset; 763 764#ifdef CONFIG_X86_64 765 dio->sg[0].dma_length = dio->sg[0].length; 766#endif 767 count -= dio->sg[0].length; 768 for (i = 1; i < nr_pages; i++) { 769 if (count < 4) { 770 spsz = count; 771 skip_fb_sg = 1; 772 } else { 773 spsz = (count < PAGE_SIZE) ? 774 (count & ~0x03) : PAGE_SIZE; 775 } 776 crystalhd_set_sg(&dio->sg[i], dio->pages[i], spsz, 0); 777 count -= spsz; 778 } 779 } else { 780 if (count < 4) { 781 dio->sg[0].length = count; 782 skip_fb_sg = 1; 783 } else { 784 dio->sg[0].length = count - dio->fb_size; 785 } 786#ifdef CONFIG_X86_64 787 dio->sg[0].dma_length = dio->sg[0].length; 788#endif 789 } 790 dio->sg_cnt = pci_map_sg(adp->pdev, dio->sg, 791 dio->page_cnt, dio->direction); 792 if (dio->sg_cnt <= 0) { 793 BCMLOG_ERR("sg map %d-%d\n", dio->sg_cnt, dio->page_cnt); 794 crystalhd_unmap_dio(adp, dio); 795 return BC_STS_ERROR; 796 } 797 if (dio->sg_cnt && skip_fb_sg) 798 dio->sg_cnt -= 1; 799 dio->sig = crystalhd_dio_sg_mapped; 800 /* Fill in User info.. */ 801 dio->uinfo.xfr_len = ubuff_sz; 802 dio->uinfo.xfr_buff = ubuff; 803 dio->uinfo.uv_offset = uv_offset; 804 dio->uinfo.b422mode = en_422mode; 805 dio->uinfo.dir_tx = dir_tx; 806 807 *dio_hnd = dio; 808 809 return BC_STS_SUCCESS; 810} 811 812/** 813 * crystalhd_unmap_sgl - Release mapped resources 814 * @adp: Adapter instance 815 * @dio: DIO request instance 816 * 817 * Return: 818 * Status. 819 * 820 * This routine is to unmap the user buffer pages. 821 */ 822enum BC_STATUS crystalhd_unmap_dio(struct crystalhd_adp *adp, struct crystalhd_dio_req *dio) 823{ 824 struct page *page = NULL; 825 int j = 0; 826 827 if (!adp || !dio) { 828 BCMLOG_ERR("Invalid arg\n"); 829 return BC_STS_INV_ARG; 830 } 831 832 if ((dio->page_cnt > 0) && (dio->sig != crystalhd_dio_inv)) { 833 for (j = 0; j < dio->page_cnt; j++) { 834 page = dio->pages[j]; 835 if (page) { 836 if (!PageReserved(page) && 837 (dio->direction == DMA_FROM_DEVICE)) 838 SetPageDirty(page); 839 page_cache_release(page); 840 } 841 } 842 } 843 if (dio->sig == crystalhd_dio_sg_mapped) 844 pci_unmap_sg(adp->pdev, dio->sg, dio->page_cnt, dio->direction); 845 846 crystalhd_free_dio(adp, dio); 847 848 return BC_STS_SUCCESS; 849} 850 851/** 852 * crystalhd_create_dio_pool - Allocate mem pool for DIO management. 853 * @adp: Adapter instance 854 * @max_pages: Max pages for size calculation. 855 * 856 * Return: 857 * system error. 858 * 859 * This routine creates a memory pool to hold dio context for 860 * for HW Direct IO operation. 861 */ 862int crystalhd_create_dio_pool(struct crystalhd_adp *adp, uint32_t max_pages) 863{ 864 uint32_t asz = 0, i = 0; 865 uint8_t *temp; 866 struct crystalhd_dio_req *dio; 867 868 if (!adp || !max_pages) { 869 BCMLOG_ERR("Invalid Arg!!\n"); 870 return -EINVAL; 871 } 872 873 /* Get dma memory for fill byte handling..*/ 874 adp->fill_byte_pool = pci_pool_create("crystalhd_fbyte", 875 adp->pdev, 8, 8, 0); 876 if (!adp->fill_byte_pool) { 877 BCMLOG_ERR("failed to create fill byte pool\n"); 878 return -ENOMEM; 879 } 880 881 /* Get the max size from user based on 420/422 modes */ 882 asz = (sizeof(*dio->pages) * max_pages) + 883 (sizeof(*dio->sg) * max_pages) + sizeof(*dio); 884 885 BCMLOG(BCMLOG_DBG, "Initializing Dio pool %d %d %x %p\n", 886 BC_LINK_SG_POOL_SZ, max_pages, asz, adp->fill_byte_pool); 887 888 for (i = 0; i < BC_LINK_SG_POOL_SZ; i++) { 889 temp = kzalloc(asz, GFP_KERNEL); 890 if ((temp) == NULL) { 891 BCMLOG_ERR("Failed to alloc %d mem\n", asz); 892 return -ENOMEM; 893 } 894 895 dio = (struct crystalhd_dio_req *)temp; 896 temp += sizeof(*dio); 897 dio->pages = (struct page **)temp; 898 temp += (sizeof(*dio->pages) * max_pages); 899 dio->sg = (struct scatterlist *)temp; 900 dio->max_pages = max_pages; 901 dio->fb_va = pci_pool_alloc(adp->fill_byte_pool, GFP_KERNEL, 902 &dio->fb_pa); 903 if (!dio->fb_va) { 904 BCMLOG_ERR("fill byte alloc failed.\n"); 905 return -ENOMEM; 906 } 907 908 crystalhd_free_dio(adp, dio); 909 } 910 911 return 0; 912} 913 914/** 915 * crystalhd_destroy_dio_pool - Release DIO mem pool. 916 * @adp: Adapter instance 917 * 918 * Return: 919 * none. 920 * 921 * This routine releases dio memory pool during close. 922 */ 923void crystalhd_destroy_dio_pool(struct crystalhd_adp *adp) 924{ 925 struct crystalhd_dio_req *dio; 926 int count = 0; 927 928 if (!adp) { 929 BCMLOG_ERR("Invalid Arg!!\n"); 930 return; 931 } 932 933 do { 934 dio = crystalhd_alloc_dio(adp); 935 if (dio) { 936 if (dio->fb_va) 937 pci_pool_free(adp->fill_byte_pool, 938 dio->fb_va, dio->fb_pa); 939 count++; 940 kfree(dio); 941 } 942 } while (dio); 943 944 if (adp->fill_byte_pool) { 945 pci_pool_destroy(adp->fill_byte_pool); 946 adp->fill_byte_pool = NULL; 947 } 948 949 BCMLOG(BCMLOG_DBG, "Released dio pool %d\n", count); 950} 951 952/** 953 * crystalhd_create_elem_pool - List element pool creation. 954 * @adp: Adapter instance 955 * @pool_size: Number of elements in the pool. 956 * 957 * Return: 958 * 0 - success, <0 error 959 * 960 * Create general purpose list element pool to hold pending, 961 * and active requests. 962 */ 963int __devinit crystalhd_create_elem_pool(struct crystalhd_adp *adp, 964 uint32_t pool_size) 965{ 966 uint32_t i; 967 struct crystalhd_elem *temp; 968 969 if (!adp || !pool_size) 970 return -EINVAL; 971 972 for (i = 0; i < pool_size; i++) { 973 temp = kzalloc(sizeof(*temp), GFP_KERNEL); 974 if (!temp) { 975 BCMLOG_ERR("kalloc failed\n"); 976 return -ENOMEM; 977 } 978 crystalhd_free_elem(adp, temp); 979 } 980 BCMLOG(BCMLOG_DBG, "allocated %d elem\n", pool_size); 981 return 0; 982} 983 984/** 985 * crystalhd_delete_elem_pool - List element pool deletion. 986 * @adp: Adapter instance 987 * 988 * Return: 989 * none 990 * 991 * Delete general purpose list element pool. 992 */ 993void crystalhd_delete_elem_pool(struct crystalhd_adp *adp) 994{ 995 struct crystalhd_elem *temp; 996 int dbg_cnt = 0; 997 998 if (!adp) 999 return; 1000 1001 do { 1002 temp = crystalhd_alloc_elem(adp); 1003 if (temp) { 1004 kfree(temp); 1005 dbg_cnt++; 1006 } 1007 } while (temp); 1008 1009 BCMLOG(BCMLOG_DBG, "released %d elem\n", dbg_cnt); 1010} 1011 1012/*================ Debug support routines.. ================================*/ 1013void crystalhd_show_buffer(uint32_t off, uint8_t *buff, uint32_t dwcount) 1014{ 1015 uint32_t i, k = 1; 1016 1017 for (i = 0; i < dwcount; i++) { 1018 if (k == 1) 1019 BCMLOG(BCMLOG_DATA, "0x%08X : ", off); 1020 1021 BCMLOG(BCMLOG_DATA, " 0x%08X ", *((uint32_t *)buff)); 1022 1023 buff += sizeof(uint32_t); 1024 off += sizeof(uint32_t); 1025 k++; 1026 if ((i == dwcount - 1) || (k > 4)) { 1027 BCMLOG(BCMLOG_DATA, "\n"); 1028 k = 1; 1029 } 1030 } 1031} 1032