Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=87c3019d7b1acb7704a257d78c482112e9b0c227
Commit:     87c3019d7b1acb7704a257d78c482112e9b0c227
Parent:     32a1db42480dc972e8e92be68d9e604f6aff5381
Author:     Jon Burgess <[EMAIL PROTECTED]>
AuthorDate: Thu May 3 12:23:44 2007 -0300
Committer:  Mauro Carvalho Chehab <[EMAIL PROTECTED]>
CommitDate: Wed May 9 10:12:42 2007 -0300

    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 <[EMAIL PROTECTED]>
    Signed-off-by: Oliver Endriss <[EMAIL PROTECTED]>
    Signed-off-by: Mauro Carvalho Chehab <[EMAIL PROTECTED]>
---
 drivers/media/common/saa7146_core.c   |   54 +++++++++++++++++++++-----------
 drivers/media/dvb/ttpci/av7110.c      |    9 ++++--
 drivers/media/dvb/ttpci/budget-core.c |   37 ++++++++++++----------
 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 86cbdbc..ef3e54c 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
        char *mem = vmalloc_32(length);
        int slen = 0;
 
-       if (NULL == mem) {
-               return NULL;
-       }
+       if (NULL == mem)
+               goto err_null;
 
-       if (!(pt->slist = vmalloc_to_sg(mem, pages))) {
-               vfree(mem);
-               return NULL;
-       }
+       if (!(pt->slist = vmalloc_to_sg(mem, pages)))
+               goto err_free_mem;
 
-       if (saa7146_pgtable_alloc(pci, pt)) {
-               kfree(pt->slist);
-               pt->slist = NULL;
-               vfree(mem);
-               return NULL;
-       }
+       if (saa7146_pgtable_alloc(pci, pt))
+               goto err_free_slist;
 
-       slen = pci_map_sg(pci,pt->slist,pages,PCI_DMA_FROMDEVICE);
-       if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen)) {
-               return NULL;
-       }
+       pt->nents = pages;
+       slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE);
+       if (0 == slen)
+               goto err_free_pgtable;
+
+       if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen))
+               goto err_unmap_sg;
 
        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)
@@ -166,8 +183,6 @@ void saa7146_pgtable_free(struct pci_dev *pci, struct 
saa7146_pgtable *pt)
                return;
        pci_free_consistent(pci, pt->size, pt->cpu, pt->dma);
        pt->cpu = NULL;
-       kfree(pt->slist);
-       pt->slist = NULL;
 }
 
 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_build_single);
 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_setgpio);
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 67becdd..ef1108c 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)
        if (!budget->feeding1 || (newdma == olddma))
                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
        /* track rps1 activity */
        printk("vpeirq: %02x Event Counter 1 0x%04x\n",
@@ -2679,8 +2682,8 @@ err_iobuf_vfree_6:
 err_pci_free_5:
        pci_free_consistent(pdev, 8192, av7110->debi_virt, av7110->debi_bus);
 err_saa71466_vfree_4:
-       if (!av7110->grabbing)
-               saa7146_pgtable_free(pdev, &av7110->pt);
+       if (av7110->grabbing)
+               saa7146_vfree_destroy_pgtable(pdev, av7110->grabbing, 
&av7110->pt);
 err_i2c_del_3:
        i2c_del_adapter(&av7110->i2c_adap);
 err_dvb_unregister_adapter_2:
@@ -2710,7 +2713,7 @@ static int __devexit av7110_detach(struct saa7146_dev* 
saa)
                SAA7146_ISR_CLEAR(saa, MASK_10);
                msleep(50);
                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);
 
diff --git a/drivers/media/dvb/ttpci/budget-core.c 
b/drivers/media/dvb/ttpci/budget-core.c
index 6b97dc1..2557ac9 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)
        u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
        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 */
        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);
 
        if (i2c_add_adapter(&budget->i2c_adap) < 0) {
-               dvb_unregister_adapter(&budget->dvb_adapter);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto err_dvb_unregister;
        }
 
        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;
-               goto err;
+               goto err_del_i2c;
        }
 
        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)
                saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
 
-       if (budget_register(budget) == 0) {
-               return 0;
-       }
-err:
-       i2c_del_adapter(&budget->i2c_adap);
+       if (budget_register(budget) == 0)
+               return 0; /* Everything OK */
+
+       /* An error occurred, cleanup resources */
+       saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt);
 
-       vfree(budget->grabbing);
+err_del_i2c:
+       i2c_del_adapter(&budget->i2c_adap);
 
+err_dvb_unregister:
        dvb_unregister_adapter(&budget->dvb_adapter);
 
        return ret;
@@ -555,15 +560,13 @@ int ttpci_budget_deinit(struct budget *budget)
 
        budget_unregister(budget);
 
-       i2c_del_adapter(&budget->i2c_adap);
-
-       dvb_unregister_adapter(&budget->dvb_adapter);
-
        tasklet_kill(&budget->vpe_tasklet);
 
-       saa7146_pgtable_free(dev->pci, &budget->pt);
+       saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt);
 
-       vfree(budget->grabbing);
+       i2c_del_adapter(&budget->i2c_adap);
+
+       dvb_unregister_adapter(&budget->dvb_adapter);
 
        return 0;
 }
diff --git a/include/media/saa7146.h b/include/media/saa7146.h
index 796bcf1..d3f4f5a 100644
--- a/include/media/saa7146.h
+++ b/include/media/saa7146.h
@@ -58,6 +58,7 @@ struct saa7146_pgtable {
        unsigned long   offset;
        /* used for custom pagetables (used for example by budget dvb cards) */
        struct scatterlist *slist;
+       int             nents;
 };
 
 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);
 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);
+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);
 int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop);
 
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to