diff options
author | Jon Burgess <jburgess777@googlemail.com> | 2007-05-03 11:23:44 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-05-09 09:12:42 -0400 |
commit | 87c3019d7b1acb7704a257d78c482112e9b0c227 (patch) | |
tree | 312478a0bed426b3ca89bf4fae1880fed9986bd2 | |
parent | 32a1db42480dc972e8e92be68d9e604f6aff5381 (diff) |
V4L/DVB (5592): DMA: Correctly free resources on error, sync PCI streamed data
I added saa7146_vmalloc_destroy_pgtable() which frees the resources
allocated by saa7146_vmalloc_build_pgtable() and updated the callers in
budget-core.c and av7110.c. I have also been through the updated
functions and updated the error paths to ensure they free all allocated
resources on error.
I also realised that there are other callers to saa7146_pgtable_free()
which did not have any sg DMA mapped so it seems wrong to add the
pci_unmap_sg() into that function. Instead I created
saa7146_vmalloc_destroy_pgtable() to do this.
Also included in this patch are the previous fixes for pci_unmap_sg()
and syncing the PCI streamed data to work with a SWIOTLB and match the
requirements documented in DMA-API.txt.
Signed-off-by: Jon Burgess <jburgess777@googlemail.com>
Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r-- | drivers/media/common/saa7146_core.c | 54 | ||||
-rw-r--r-- | drivers/media/dvb/ttpci/av7110.c | 9 | ||||
-rw-r--r-- | drivers/media/dvb/ttpci/budget-core.c | 37 | ||||
-rw-r--r-- | include/media/saa7146.h | 2 |
4 files changed, 63 insertions, 39 deletions
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index 86cbdbcf9d7d..ef3e54cd9407 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c | |||
@@ -136,28 +136,45 @@ char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa | |||
136 | char *mem = vmalloc_32(length); | 136 | char *mem = vmalloc_32(length); |
137 | int slen = 0; | 137 | int slen = 0; |
138 | 138 | ||
139 | if (NULL == mem) { | 139 | if (NULL == mem) |
140 | return NULL; | 140 | goto err_null; |
141 | } | ||
142 | 141 | ||
143 | if (!(pt->slist = vmalloc_to_sg(mem, pages))) { | 142 | if (!(pt->slist = vmalloc_to_sg(mem, pages))) |
144 | vfree(mem); | 143 | goto err_free_mem; |
145 | return NULL; | ||
146 | } | ||
147 | 144 | ||
148 | if (saa7146_pgtable_alloc(pci, pt)) { | 145 | if (saa7146_pgtable_alloc(pci, pt)) |
149 | kfree(pt->slist); | 146 | goto err_free_slist; |
150 | pt->slist = NULL; | ||
151 | vfree(mem); | ||
152 | return NULL; | ||
153 | } | ||
154 | 147 | ||
155 | slen = pci_map_sg(pci,pt->slist,pages,PCI_DMA_FROMDEVICE); | 148 | pt->nents = pages; |
156 | if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen)) { | 149 | slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE); |
157 | return NULL; | 150 | if (0 == slen) |
158 | } | 151 | goto err_free_pgtable; |
152 | |||
153 | if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen)) | ||
154 | goto err_unmap_sg; | ||
159 | 155 | ||
160 | return mem; | 156 | return mem; |
157 | |||
158 | err_unmap_sg: | ||
159 | pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE); | ||
160 | err_free_pgtable: | ||
161 | saa7146_pgtable_free(pci, pt); | ||
162 | err_free_slist: | ||
163 | kfree(pt->slist); | ||
164 | pt->slist = NULL; | ||
165 | err_free_mem: | ||
166 | vfree(mem); | ||
167 | err_null: | ||
168 | return NULL; | ||
169 | } | ||
170 | |||
171 | void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, char *mem, struct saa7146_pgtable *pt) | ||
172 | { | ||
173 | pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE); | ||
174 | saa7146_pgtable_free(pci, pt); | ||
175 | kfree(pt->slist); | ||
176 | pt->slist = NULL; | ||
177 | vfree(mem); | ||
161 | } | 178 | } |
162 | 179 | ||
163 | void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt) | 180 | void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt) |
@@ -166,8 +183,6 @@ void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt) | |||
166 | return; | 183 | return; |
167 | pci_free_consistent(pci, pt->size, pt->cpu, pt->dma); | 184 | pci_free_consistent(pci, pt->size, pt->cpu, pt->dma); |
168 | pt->cpu = NULL; | 185 | pt->cpu = NULL; |
169 | kfree(pt->slist); | ||
170 | pt->slist = NULL; | ||
171 | } | 186 | } |
172 | 187 | ||
173 | int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) | 188 | int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) |
@@ -528,6 +543,7 @@ EXPORT_SYMBOL_GPL(saa7146_pgtable_alloc); | |||
528 | EXPORT_SYMBOL_GPL(saa7146_pgtable_free); | 543 | EXPORT_SYMBOL_GPL(saa7146_pgtable_free); |
529 | EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single); | 544 | EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single); |
530 | EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable); | 545 | EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable); |
546 | EXPORT_SYMBOL_GPL(saa7146_vfree_destroy_pgtable); | ||
531 | EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done); | 547 | EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done); |
532 | 548 | ||
533 | EXPORT_SYMBOL_GPL(saa7146_setgpio); | 549 | EXPORT_SYMBOL_GPL(saa7146_setgpio); |
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 67becdd4db60..ef1108c0bf11 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c | |||
@@ -1246,6 +1246,9 @@ static void vpeirq(unsigned long data) | |||
1246 | if (!budget->feeding1 || (newdma == olddma)) | 1246 | if (!budget->feeding1 || (newdma == olddma)) |
1247 | return; | 1247 | return; |
1248 | 1248 | ||
1249 | /* Ensure streamed PCI data is synced to CPU */ | ||
1250 | pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE); | ||
1251 | |||
1249 | #if 0 | 1252 | #if 0 |
1250 | /* track rps1 activity */ | 1253 | /* track rps1 activity */ |
1251 | printk("vpeirq: %02x Event Counter 1 0x%04x\n", | 1254 | printk("vpeirq: %02x Event Counter 1 0x%04x\n", |
@@ -2679,8 +2682,8 @@ err_iobuf_vfree_6: | |||
2679 | err_pci_free_5: | 2682 | err_pci_free_5: |
2680 | pci_free_consistent(pdev, 8192, av7110->debi_virt, av7110->debi_bus); | 2683 | pci_free_consistent(pdev, 8192, av7110->debi_virt, av7110->debi_bus); |
2681 | err_saa71466_vfree_4: | 2684 | err_saa71466_vfree_4: |
2682 | if (!av7110->grabbing) | 2685 | if (av7110->grabbing) |
2683 | saa7146_pgtable_free(pdev, &av7110->pt); | 2686 | saa7146_vfree_destroy_pgtable(pdev, av7110->grabbing, &av7110->pt); |
2684 | err_i2c_del_3: | 2687 | err_i2c_del_3: |
2685 | i2c_del_adapter(&av7110->i2c_adap); | 2688 | i2c_del_adapter(&av7110->i2c_adap); |
2686 | err_dvb_unregister_adapter_2: | 2689 | err_dvb_unregister_adapter_2: |
@@ -2710,7 +2713,7 @@ static int __devexit av7110_detach(struct saa7146_dev* saa) | |||
2710 | SAA7146_ISR_CLEAR(saa, MASK_10); | 2713 | SAA7146_ISR_CLEAR(saa, MASK_10); |
2711 | msleep(50); | 2714 | msleep(50); |
2712 | tasklet_kill(&av7110->vpe_tasklet); | 2715 | tasklet_kill(&av7110->vpe_tasklet); |
2713 | saa7146_pgtable_free(saa->pci, &av7110->pt); | 2716 | saa7146_vfree_destroy_pgtable(saa->pci, av7110->grabbing, &av7110->pt); |
2714 | } | 2717 | } |
2715 | av7110_exit_v4l(av7110); | 2718 | av7110_exit_v4l(av7110); |
2716 | 2719 | ||
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index 6b97dc1e6b65..2557ac9620d0 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c | |||
@@ -195,6 +195,9 @@ static void vpeirq(unsigned long data) | |||
195 | u32 newdma = saa7146_read(budget->dev, PCI_VDP3); | 195 | u32 newdma = saa7146_read(budget->dev, PCI_VDP3); |
196 | u32 count; | 196 | u32 count; |
197 | 197 | ||
198 | /* Ensure streamed PCI data is synced to CPU */ | ||
199 | pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE); | ||
200 | |||
198 | /* nearest lower position divisible by 188 */ | 201 | /* nearest lower position divisible by 188 */ |
199 | newdma -= newdma % 188; | 202 | newdma -= newdma % 188; |
200 | 203 | ||
@@ -504,16 +507,16 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, | |||
504 | strcpy(budget->i2c_adap.name, budget->card->name); | 507 | strcpy(budget->i2c_adap.name, budget->card->name); |
505 | 508 | ||
506 | if (i2c_add_adapter(&budget->i2c_adap) < 0) { | 509 | if (i2c_add_adapter(&budget->i2c_adap) < 0) { |
507 | dvb_unregister_adapter(&budget->dvb_adapter); | 510 | ret = -ENOMEM; |
508 | return -ENOMEM; | 511 | goto err_dvb_unregister; |
509 | } | 512 | } |
510 | 513 | ||
511 | ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac); | 514 | ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac); |
512 | 515 | ||
513 | if (NULL == | 516 | budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, budget->buffer_size, &budget->pt); |
514 | (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, budget->buffer_size, &budget->pt))) { | 517 | if (NULL == budget->grabbing) { |
515 | ret = -ENOMEM; | 518 | ret = -ENOMEM; |
516 | goto err; | 519 | goto err_del_i2c; |
517 | } | 520 | } |
518 | 521 | ||
519 | saa7146_write(dev, PCI_BT_V1, 0x001c0000); | 522 | saa7146_write(dev, PCI_BT_V1, 0x001c0000); |
@@ -526,14 +529,16 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, | |||
526 | if (bi->type != BUDGET_FS_ACTIVY) | 529 | if (bi->type != BUDGET_FS_ACTIVY) |
527 | saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); | 530 | saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); |
528 | 531 | ||
529 | if (budget_register(budget) == 0) { | 532 | if (budget_register(budget) == 0) |
530 | return 0; | 533 | return 0; /* Everything OK */ |
531 | } | 534 | |
532 | err: | 535 | /* An error occurred, cleanup resources */ |
533 | i2c_del_adapter(&budget->i2c_adap); | 536 | saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt); |
534 | 537 | ||
535 | vfree(budget->grabbing); | 538 | err_del_i2c: |
539 | i2c_del_adapter(&budget->i2c_adap); | ||
536 | 540 | ||
541 | err_dvb_unregister: | ||
537 | dvb_unregister_adapter(&budget->dvb_adapter); | 542 | dvb_unregister_adapter(&budget->dvb_adapter); |
538 | 543 | ||
539 | return ret; | 544 | return ret; |
@@ -555,15 +560,13 @@ int ttpci_budget_deinit(struct budget *budget) | |||
555 | 560 | ||
556 | budget_unregister(budget); | 561 | budget_unregister(budget); |
557 | 562 | ||
558 | i2c_del_adapter(&budget->i2c_adap); | ||
559 | |||
560 | dvb_unregister_adapter(&budget->dvb_adapter); | ||
561 | |||
562 | tasklet_kill(&budget->vpe_tasklet); | 563 | tasklet_kill(&budget->vpe_tasklet); |
563 | 564 | ||
564 | saa7146_pgtable_free(dev->pci, &budget->pt); | 565 | saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt); |
565 | 566 | ||
566 | vfree(budget->grabbing); | 567 | i2c_del_adapter(&budget->i2c_adap); |
568 | |||
569 | dvb_unregister_adapter(&budget->dvb_adapter); | ||
567 | 570 | ||
568 | return 0; | 571 | return 0; |
569 | } | 572 | } |
diff --git a/include/media/saa7146.h b/include/media/saa7146.h index 796bcf151a3a..d3f4f5a38214 100644 --- a/include/media/saa7146.h +++ b/include/media/saa7146.h | |||
@@ -58,6 +58,7 @@ struct saa7146_pgtable { | |||
58 | unsigned long offset; | 58 | unsigned long offset; |
59 | /* used for custom pagetables (used for example by budget dvb cards) */ | 59 | /* used for custom pagetables (used for example by budget dvb cards) */ |
60 | struct scatterlist *slist; | 60 | struct scatterlist *slist; |
61 | int nents; | ||
61 | }; | 62 | }; |
62 | 63 | ||
63 | struct saa7146_pci_extension_data { | 64 | struct saa7146_pci_extension_data { |
@@ -157,6 +158,7 @@ int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt); | |||
157 | void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt); | 158 | void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt); |
158 | int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length ); | 159 | int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length ); |
159 | char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt); | 160 | char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt); |
161 | void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, char *mem, struct saa7146_pgtable *pt); | ||
160 | void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data); | 162 | void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data); |
161 | int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop); | 163 | int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop); |
162 | 164 | ||