Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
crystalhd_misc.c
Go to the documentation of this file.
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 "crystalhd.h"
28 
29 #include <linux/slab.h>
30 
32 
33 static inline uint32_t crystalhd_dram_rd(struct crystalhd_adp *adp, uint32_t mem_off)
34 {
35  crystalhd_reg_wr(adp, DCI_DRAM_BASE_ADDR, (mem_off >> 19));
36  return bc_dec_reg_rd(adp, (0x00380000 | (mem_off & 0x0007FFFF)));
37 }
38 
39 static inline void crystalhd_dram_wr(struct crystalhd_adp *adp, uint32_t mem_off, uint32_t val)
40 {
41  crystalhd_reg_wr(adp, DCI_DRAM_BASE_ADDR, (mem_off >> 19));
42  bc_dec_reg_wr(adp, (0x00380000 | (mem_off & 0x0007FFFF)), val);
43 }
44 
45 static inline enum BC_STATUS bc_chk_dram_range(struct crystalhd_adp *adp, uint32_t start_off, uint32_t cnt)
46 {
47  return BC_STS_SUCCESS;
48 }
49 
50 static struct crystalhd_dio_req *crystalhd_alloc_dio(struct crystalhd_adp *adp)
51 {
52  unsigned long flags = 0;
53  struct crystalhd_dio_req *temp = NULL;
54 
55  if (!adp) {
56  BCMLOG_ERR("Invalid Arg!!\n");
57  return temp;
58  }
59 
60  spin_lock_irqsave(&adp->lock, flags);
61  temp = adp->ua_map_free_head;
62  if (temp)
63  adp->ua_map_free_head = adp->ua_map_free_head->next;
64  spin_unlock_irqrestore(&adp->lock, flags);
65 
66  return temp;
67 }
68 
69 static void crystalhd_free_dio(struct crystalhd_adp *adp, struct crystalhd_dio_req *dio)
70 {
71  unsigned long flags = 0;
72 
73  if (!adp || !dio)
74  return;
75  spin_lock_irqsave(&adp->lock, flags);
76  dio->sig = crystalhd_dio_inv;
77  dio->page_cnt = 0;
78  dio->fb_size = 0;
79  memset(&dio->uinfo, 0, sizeof(dio->uinfo));
80  dio->next = adp->ua_map_free_head;
81  adp->ua_map_free_head = dio;
82  spin_unlock_irqrestore(&adp->lock, flags);
83 }
84 
85 static struct crystalhd_elem *crystalhd_alloc_elem(struct crystalhd_adp *adp)
86 {
87  unsigned long flags = 0;
88  struct crystalhd_elem *temp = NULL;
89 
90  if (!adp)
91  return temp;
92  spin_lock_irqsave(&adp->lock, flags);
93  temp = adp->elem_pool_head;
94  if (temp) {
95  adp->elem_pool_head = adp->elem_pool_head->flink;
96  memset(temp, 0, sizeof(*temp));
97  }
98  spin_unlock_irqrestore(&adp->lock, flags);
99 
100  return temp;
101 }
102 static void crystalhd_free_elem(struct crystalhd_adp *adp, struct crystalhd_elem *elem)
103 {
104  unsigned long flags = 0;
105 
106  if (!adp || !elem)
107  return;
108  spin_lock_irqsave(&adp->lock, flags);
109  elem->flink = adp->elem_pool_head;
110  adp->elem_pool_head = elem;
111  spin_unlock_irqrestore(&adp->lock, flags);
112 }
113 
114 static inline void crystalhd_set_sg(struct scatterlist *sg, struct page *page,
115  unsigned int len, unsigned int offset)
116 {
117  sg_set_page(sg, page, len, offset);
118 #ifdef CONFIG_X86_64
119  sg->dma_length = len;
120 #endif
121 }
122 
123 static inline void crystalhd_init_sg(struct scatterlist *sg, unsigned int entries)
124 {
125  /* http://lkml.org/lkml/2007/11/27/68 */
126  sg_init_table(sg, entries);
127 }
128 
129 /*========================== Extern ========================================*/
143 {
144  if (!adp || (reg_off > adp->pci_mem_len)) {
145  BCMLOG_ERR("dec_rd_reg_off outof range: 0x%08x\n", reg_off);
146  return 0;
147  }
148 
149  return readl(adp->addr + reg_off);
150 }
151 
165 void bc_dec_reg_wr(struct crystalhd_adp *adp, uint32_t reg_off, uint32_t val)
166 {
167  if (!adp || (reg_off > adp->pci_mem_len)) {
168  BCMLOG_ERR("dec_wr_reg_off outof range: 0x%08x\n", reg_off);
169  return;
170  }
171  writel(val, adp->addr + reg_off);
172  udelay(8);
173 }
174 
189 {
190  if (!adp || (reg_off > adp->pci_i2o_len)) {
191  BCMLOG_ERR("link_rd_reg_off outof range: 0x%08x\n", reg_off);
192  return 0;
193  }
194  return readl(adp->i2o_addr + reg_off);
195 }
196 
211 void crystalhd_reg_wr(struct crystalhd_adp *adp, uint32_t reg_off, uint32_t val)
212 {
213  if (!adp || (reg_off > adp->pci_i2o_len)) {
214  BCMLOG_ERR("link_wr_reg_off outof range: 0x%08x\n", reg_off);
215  return;
216  }
217  writel(val, adp->i2o_addr + reg_off);
218 }
219 
232 enum BC_STATUS crystalhd_mem_rd(struct crystalhd_adp *adp, uint32_t start_off,
233  uint32_t dw_cnt, uint32_t *rd_buff)
234 {
235  uint32_t ix = 0;
236 
237  if (!adp || !rd_buff ||
238  (bc_chk_dram_range(adp, start_off, dw_cnt) != BC_STS_SUCCESS)) {
239  BCMLOG_ERR("Invalid arg\n");
240  return BC_STS_INV_ARG;
241  }
242  for (ix = 0; ix < dw_cnt; ix++)
243  rd_buff[ix] = crystalhd_dram_rd(adp, (start_off + (ix * 4)));
244 
245  return BC_STS_SUCCESS;
246 }
247 
260 enum BC_STATUS crystalhd_mem_wr(struct crystalhd_adp *adp, uint32_t start_off,
261  uint32_t dw_cnt, uint32_t *wr_buff)
262 {
263  uint32_t ix = 0;
264 
265  if (!adp || !wr_buff ||
266  (bc_chk_dram_range(adp, start_off, dw_cnt) != BC_STS_SUCCESS)) {
267  BCMLOG_ERR("Invalid arg\n");
268  return BC_STS_INV_ARG;
269  }
270 
271  for (ix = 0; ix < dw_cnt; ix++)
272  crystalhd_dram_wr(adp, (start_off + (ix * 4)), wr_buff[ix]);
273 
274  return BC_STS_SUCCESS;
275 }
289  uint32_t len, uint32_t *val)
290 {
292  int rc = 0;
293 
294  if (!adp || !val) {
295  BCMLOG_ERR("Invalid arg\n");
296  return BC_STS_INV_ARG;
297  }
298 
299  switch (len) {
300  case 1:
301  rc = pci_read_config_byte(adp->pdev, off, (u8 *)val);
302  break;
303  case 2:
304  rc = pci_read_config_word(adp->pdev, off, (u16 *)val);
305  break;
306  case 4:
307  rc = pci_read_config_dword(adp->pdev, off, (u32 *)val);
308  break;
309  default:
310  rc = -EINVAL;
311  sts = BC_STS_INV_ARG;
312  BCMLOG_ERR("Invalid len:%d\n", len);
313  }
314 
315  if (rc && (sts == BC_STS_SUCCESS))
316  sts = BC_STS_ERROR;
317 
318  return sts;
319 }
320 
334  uint32_t len, uint32_t val)
335 {
337  int rc = 0;
338 
339  if (!adp || !val) {
340  BCMLOG_ERR("Invalid arg\n");
341  return BC_STS_INV_ARG;
342  }
343 
344  switch (len) {
345  case 1:
346  rc = pci_write_config_byte(adp->pdev, off, (u8)val);
347  break;
348  case 2:
349  rc = pci_write_config_word(adp->pdev, off, (u16)val);
350  break;
351  case 4:
352  rc = pci_write_config_dword(adp->pdev, off, val);
353  break;
354  default:
355  rc = -EINVAL;
356  sts = BC_STS_INV_ARG;
357  BCMLOG_ERR("Invalid len:%d\n", len);
358  }
359 
360  if (rc && (sts == BC_STS_SUCCESS))
361  sts = BC_STS_ERROR;
362 
363  return sts;
364 }
365 
380  dma_addr_t *phy_addr)
381 {
382  void *temp = NULL;
383 
384  if (!adp || !sz || !phy_addr) {
385  BCMLOG_ERR("Invalide Arg..\n");
386  return temp;
387  }
388 
389  temp = pci_alloc_consistent(adp->pdev, sz, phy_addr);
390  if (temp)
391  memset(temp, 0, sz);
392 
393  return temp;
394 }
395 
407 void bc_kern_dma_free(struct crystalhd_adp *adp, uint32_t sz, void *ka,
408  dma_addr_t phy_addr)
409 {
410  if (!adp || !ka || !sz || !phy_addr) {
411  BCMLOG_ERR("Invalide Arg..\n");
412  return;
413  }
414 
415  pci_free_consistent(adp->pdev, sz, ka, phy_addr);
416 }
417 
432  struct crystalhd_dioq **dioq_hnd,
433  crystalhd_data_free_cb cb, void *cbctx)
434 {
435  struct crystalhd_dioq *dioq = NULL;
436 
437  if (!adp || !dioq_hnd) {
438  BCMLOG_ERR("Invalid arg!!\n");
439  return BC_STS_INV_ARG;
440  }
441 
442  dioq = kzalloc(sizeof(*dioq), GFP_KERNEL);
443  if (!dioq)
444  return BC_STS_INSUFF_RES;
445 
446  spin_lock_init(&dioq->lock);
447  dioq->sig = BC_LINK_DIOQ_SIG;
448  dioq->head = (struct crystalhd_elem *)&dioq->head;
449  dioq->tail = (struct crystalhd_elem *)&dioq->head;
451  dioq->adp = adp;
452  dioq->data_rel_cb = cb;
453  dioq->cb_context = cbctx;
454  *dioq_hnd = dioq;
455 
456  return BC_STS_SUCCESS;
457 }
458 
472 void crystalhd_delete_dioq(struct crystalhd_adp *adp, struct crystalhd_dioq *dioq)
473 {
474  void *temp;
475 
476  if (!dioq || (dioq->sig != BC_LINK_DIOQ_SIG))
477  return;
478 
479  do {
480  temp = crystalhd_dioq_fetch(dioq);
481  if (temp && dioq->data_rel_cb)
482  dioq->data_rel_cb(dioq->cb_context, temp);
483  } while (temp);
484  dioq->sig = 0;
485  kfree(dioq);
486 }
487 
501  bool wake, uint32_t tag)
502 {
503  unsigned long flags = 0;
504  struct crystalhd_elem *tmp;
505 
506  if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG) || !data) {
507  BCMLOG_ERR("Invalid arg!!\n");
508  return BC_STS_INV_ARG;
509  }
510 
511  tmp = crystalhd_alloc_elem(ioq->adp);
512  if (!tmp) {
513  BCMLOG_ERR("No free elements.\n");
514  return BC_STS_INSUFF_RES;
515  }
516 
517  tmp->data = data;
518  tmp->tag = tag;
519  spin_lock_irqsave(&ioq->lock, flags);
520  tmp->flink = (struct crystalhd_elem *)&ioq->head;
521  tmp->blink = ioq->tail;
522  tmp->flink->blink = tmp;
523  tmp->blink->flink = tmp;
524  ioq->count++;
525  spin_unlock_irqrestore(&ioq->lock, flags);
526 
527  if (wake)
528  crystalhd_set_event(&ioq->event);
529 
530  return BC_STS_SUCCESS;
531 }
532 
543 {
544  unsigned long flags = 0;
545  struct crystalhd_elem *tmp;
546  struct crystalhd_elem *ret = NULL;
547  void *data = NULL;
548 
549  if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG)) {
550  BCMLOG_ERR("Invalid arg!!\n");
551  return data;
552  }
553 
554  spin_lock_irqsave(&ioq->lock, flags);
555  tmp = ioq->head;
556  if (tmp != (struct crystalhd_elem *)&ioq->head) {
557  ret = tmp;
558  tmp->flink->blink = tmp->blink;
559  tmp->blink->flink = tmp->flink;
560  ioq->count--;
561  }
562  spin_unlock_irqrestore(&ioq->lock, flags);
563  if (ret) {
564  data = ret->data;
565  crystalhd_free_elem(ioq->adp, ret);
566  }
567 
568  return data;
569 }
581 {
582  unsigned long flags = 0;
583  struct crystalhd_elem *tmp;
584  struct crystalhd_elem *ret = NULL;
585  void *data = NULL;
586 
587  if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG)) {
588  BCMLOG_ERR("Invalid arg!!\n");
589  return data;
590  }
591 
592  spin_lock_irqsave(&ioq->lock, flags);
593  tmp = ioq->head;
594  while (tmp != (struct crystalhd_elem *)&ioq->head) {
595  if (tmp->tag == tag) {
596  ret = tmp;
597  tmp->flink->blink = tmp->blink;
598  tmp->blink->flink = tmp->flink;
599  ioq->count--;
600  break;
601  }
602  tmp = tmp->flink;
603  }
604  spin_unlock_irqrestore(&ioq->lock, flags);
605 
606  if (ret) {
607  data = ret->data;
608  crystalhd_free_elem(ioq->adp, ret);
609  }
610 
611  return data;
612 }
613 
626  uint32_t *sig_pend)
627 {
628  unsigned long flags = 0;
629  int rc = 0, count;
630  void *tmp = NULL;
631 
632  if (!ioq || (ioq->sig != BC_LINK_DIOQ_SIG) || !to_secs || !sig_pend) {
633  BCMLOG_ERR("Invalid arg!!\n");
634  return tmp;
635  }
636 
637  count = to_secs;
638  spin_lock_irqsave(&ioq->lock, flags);
639  while ((ioq->count == 0) && count) {
640  spin_unlock_irqrestore(&ioq->lock, flags);
641 
642  crystalhd_wait_on_event(&ioq->event, (ioq->count > 0), 1000, rc, 0);
643  if (rc == 0) {
644  goto out;
645  } else if (rc == -EINTR) {
646  BCMLOG(BCMLOG_INFO, "Cancelling fetch wait\n");
647  *sig_pend = 1;
648  return tmp;
649  }
650  spin_lock_irqsave(&ioq->lock, flags);
651  count--;
652  }
653  spin_unlock_irqrestore(&ioq->lock, flags);
654 
655 out:
656  return crystalhd_dioq_fetch(ioq);
657 }
658 
675 enum BC_STATUS crystalhd_map_dio(struct crystalhd_adp *adp, void *ubuff,
676  uint32_t ubuff_sz, uint32_t uv_offset,
677  bool en_422mode, bool dir_tx,
678  struct crystalhd_dio_req **dio_hnd)
679 {
680  struct crystalhd_dio_req *dio;
681  /* FIXME: jarod: should some of these unsigned longs be uint32_t or uintptr_t? */
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(&current->mm->mmap_sem);
744  res = get_user_pages(current, current->mm, uaddr, nr_pages, rw == READ,
745  0, dio->pages, NULL);
746  up_read(&current->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;
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 
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 
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 
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 
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 
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.. ================================*/
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 }