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>
This commit is contained in:
Родитель
32a1db4248
Коммит
87c3019d7b
|
@ -136,28 +136,45 @@ char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa
|
||||||
char *mem = vmalloc_32(length);
|
char *mem = vmalloc_32(length);
|
||||||
int slen = 0;
|
int slen = 0;
|
||||||
|
|
||||||
if (NULL == mem) {
|
if (NULL == mem)
|
||||||
return NULL;
|
goto err_null;
|
||||||
}
|
|
||||||
|
|
||||||
if (!(pt->slist = vmalloc_to_sg(mem, pages))) {
|
if (!(pt->slist = vmalloc_to_sg(mem, pages)))
|
||||||
vfree(mem);
|
goto err_free_mem;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (saa7146_pgtable_alloc(pci, pt)) {
|
if (saa7146_pgtable_alloc(pci, pt))
|
||||||
kfree(pt->slist);
|
goto err_free_slist;
|
||||||
pt->slist = NULL;
|
|
||||||
vfree(mem);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
slen = pci_map_sg(pci,pt->slist,pages,PCI_DMA_FROMDEVICE);
|
pt->nents = pages;
|
||||||
if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen)) {
|
slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE);
|
||||||
return NULL;
|
if (0 == slen)
|
||||||
}
|
goto err_free_pgtable;
|
||||||
|
|
||||||
|
if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen))
|
||||||
|
goto err_unmap_sg;
|
||||||
|
|
||||||
return mem;
|
return mem;
|
||||||
|
|
||||||
|
err_unmap_sg:
|
||||||
|
pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
|
||||||
|
err_free_pgtable:
|
||||||
|
saa7146_pgtable_free(pci, pt);
|
||||||
|
err_free_slist:
|
||||||
|
kfree(pt->slist);
|
||||||
|
pt->slist = NULL;
|
||||||
|
err_free_mem:
|
||||||
|
vfree(mem);
|
||||||
|
err_null:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, char *mem, struct saa7146_pgtable *pt)
|
||||||
|
{
|
||||||
|
pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
|
||||||
|
saa7146_pgtable_free(pci, pt);
|
||||||
|
kfree(pt->slist);
|
||||||
|
pt->slist = NULL;
|
||||||
|
vfree(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt)
|
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)
|
||||||
return;
|
return;
|
||||||
pci_free_consistent(pci, pt->size, pt->cpu, pt->dma);
|
pci_free_consistent(pci, pt->size, pt->cpu, pt->dma);
|
||||||
pt->cpu = NULL;
|
pt->cpu = NULL;
|
||||||
kfree(pt->slist);
|
|
||||||
pt->slist = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
|
int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
|
||||||
|
@ -528,6 +543,7 @@ EXPORT_SYMBOL_GPL(saa7146_pgtable_alloc);
|
||||||
EXPORT_SYMBOL_GPL(saa7146_pgtable_free);
|
EXPORT_SYMBOL_GPL(saa7146_pgtable_free);
|
||||||
EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single);
|
EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single);
|
||||||
EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable);
|
EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable);
|
||||||
|
EXPORT_SYMBOL_GPL(saa7146_vfree_destroy_pgtable);
|
||||||
EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done);
|
EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done);
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(saa7146_setgpio);
|
EXPORT_SYMBOL_GPL(saa7146_setgpio);
|
||||||
|
|
|
@ -1246,6 +1246,9 @@ static void vpeirq(unsigned long data)
|
||||||
if (!budget->feeding1 || (newdma == olddma))
|
if (!budget->feeding1 || (newdma == olddma))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Ensure streamed PCI data is synced to CPU */
|
||||||
|
pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* track rps1 activity */
|
/* track rps1 activity */
|
||||||
printk("vpeirq: %02x Event Counter 1 0x%04x\n",
|
printk("vpeirq: %02x Event Counter 1 0x%04x\n",
|
||||||
|
@ -2679,8 +2682,8 @@ err_iobuf_vfree_6:
|
||||||
err_pci_free_5:
|
err_pci_free_5:
|
||||||
pci_free_consistent(pdev, 8192, av7110->debi_virt, av7110->debi_bus);
|
pci_free_consistent(pdev, 8192, av7110->debi_virt, av7110->debi_bus);
|
||||||
err_saa71466_vfree_4:
|
err_saa71466_vfree_4:
|
||||||
if (!av7110->grabbing)
|
if (av7110->grabbing)
|
||||||
saa7146_pgtable_free(pdev, &av7110->pt);
|
saa7146_vfree_destroy_pgtable(pdev, av7110->grabbing, &av7110->pt);
|
||||||
err_i2c_del_3:
|
err_i2c_del_3:
|
||||||
i2c_del_adapter(&av7110->i2c_adap);
|
i2c_del_adapter(&av7110->i2c_adap);
|
||||||
err_dvb_unregister_adapter_2:
|
err_dvb_unregister_adapter_2:
|
||||||
|
@ -2710,7 +2713,7 @@ static int __devexit av7110_detach(struct saa7146_dev* saa)
|
||||||
SAA7146_ISR_CLEAR(saa, MASK_10);
|
SAA7146_ISR_CLEAR(saa, MASK_10);
|
||||||
msleep(50);
|
msleep(50);
|
||||||
tasklet_kill(&av7110->vpe_tasklet);
|
tasklet_kill(&av7110->vpe_tasklet);
|
||||||
saa7146_pgtable_free(saa->pci, &av7110->pt);
|
saa7146_vfree_destroy_pgtable(saa->pci, av7110->grabbing, &av7110->pt);
|
||||||
}
|
}
|
||||||
av7110_exit_v4l(av7110);
|
av7110_exit_v4l(av7110);
|
||||||
|
|
||||||
|
|
|
@ -195,6 +195,9 @@ static void vpeirq(unsigned long data)
|
||||||
u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
|
u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
|
||||||
u32 count;
|
u32 count;
|
||||||
|
|
||||||
|
/* Ensure streamed PCI data is synced to CPU */
|
||||||
|
pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE);
|
||||||
|
|
||||||
/* nearest lower position divisible by 188 */
|
/* nearest lower position divisible by 188 */
|
||||||
newdma -= newdma % 188;
|
newdma -= newdma % 188;
|
||||||
|
|
||||||
|
@ -504,16 +507,16 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
|
||||||
strcpy(budget->i2c_adap.name, budget->card->name);
|
strcpy(budget->i2c_adap.name, budget->card->name);
|
||||||
|
|
||||||
if (i2c_add_adapter(&budget->i2c_adap) < 0) {
|
if (i2c_add_adapter(&budget->i2c_adap) < 0) {
|
||||||
dvb_unregister_adapter(&budget->dvb_adapter);
|
ret = -ENOMEM;
|
||||||
return -ENOMEM;
|
goto err_dvb_unregister;
|
||||||
}
|
}
|
||||||
|
|
||||||
ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac);
|
ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac);
|
||||||
|
|
||||||
if (NULL ==
|
budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, budget->buffer_size, &budget->pt);
|
||||||
(budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, budget->buffer_size, &budget->pt))) {
|
if (NULL == budget->grabbing) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err;
|
goto err_del_i2c;
|
||||||
}
|
}
|
||||||
|
|
||||||
saa7146_write(dev, PCI_BT_V1, 0x001c0000);
|
saa7146_write(dev, PCI_BT_V1, 0x001c0000);
|
||||||
|
@ -526,14 +529,16 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
|
||||||
if (bi->type != BUDGET_FS_ACTIVY)
|
if (bi->type != BUDGET_FS_ACTIVY)
|
||||||
saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
|
saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
|
||||||
|
|
||||||
if (budget_register(budget) == 0) {
|
if (budget_register(budget) == 0)
|
||||||
return 0;
|
return 0; /* Everything OK */
|
||||||
}
|
|
||||||
err:
|
/* An error occurred, cleanup resources */
|
||||||
|
saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt);
|
||||||
|
|
||||||
|
err_del_i2c:
|
||||||
i2c_del_adapter(&budget->i2c_adap);
|
i2c_del_adapter(&budget->i2c_adap);
|
||||||
|
|
||||||
vfree(budget->grabbing);
|
err_dvb_unregister:
|
||||||
|
|
||||||
dvb_unregister_adapter(&budget->dvb_adapter);
|
dvb_unregister_adapter(&budget->dvb_adapter);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -555,16 +560,14 @@ int ttpci_budget_deinit(struct budget *budget)
|
||||||
|
|
||||||
budget_unregister(budget);
|
budget_unregister(budget);
|
||||||
|
|
||||||
|
tasklet_kill(&budget->vpe_tasklet);
|
||||||
|
|
||||||
|
saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt);
|
||||||
|
|
||||||
i2c_del_adapter(&budget->i2c_adap);
|
i2c_del_adapter(&budget->i2c_adap);
|
||||||
|
|
||||||
dvb_unregister_adapter(&budget->dvb_adapter);
|
dvb_unregister_adapter(&budget->dvb_adapter);
|
||||||
|
|
||||||
tasklet_kill(&budget->vpe_tasklet);
|
|
||||||
|
|
||||||
saa7146_pgtable_free(dev->pci, &budget->pt);
|
|
||||||
|
|
||||||
vfree(budget->grabbing);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ struct saa7146_pgtable {
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
/* used for custom pagetables (used for example by budget dvb cards) */
|
/* used for custom pagetables (used for example by budget dvb cards) */
|
||||||
struct scatterlist *slist;
|
struct scatterlist *slist;
|
||||||
|
int nents;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct saa7146_pci_extension_data {
|
struct saa7146_pci_extension_data {
|
||||||
|
@ -157,6 +158,7 @@ int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt);
|
||||||
void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt);
|
void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt);
|
||||||
int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length );
|
int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length );
|
||||||
char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt);
|
char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt);
|
||||||
|
void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, char *mem, struct saa7146_pgtable *pt);
|
||||||
void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data);
|
void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data);
|
||||||
int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop);
|
int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче