staging: comedi: comedi_isadma: Use a non-NULL device for DMA API
authorIan Abbott <abbotti@mev.co.uk>
Fri, 26 Apr 2019 13:54:13 +0000 (14:54 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 27 Apr 2019 13:00:35 +0000 (15:00 +0200)
The "comedi_isadma" module calls `dma_alloc_coherent()` and
`dma_free_coherent()` with a NULL device pointer which is no longer
allowed.  If the `hw_dev` member of the `struct comedi_device` has been
set to a valid device, that can be used instead.  Unfortunately, all the
current users of the "comedi_isadma" module leave the `hw_dev` member
set to NULL.  In that case, fall back to using the comedi "class" device
pointed to by the `class_dev` member if that is non-NULL.  In that case,
make it "DMA-capable" with a coherent DMA mask set to the ISA bus limit
of 16MB (24 bits).

Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/comedi/drivers/comedi_isadma.c
drivers/staging/comedi/drivers/comedi_isadma.h

index b77dc8d5d3ffdf0dc8f72975bc6722c89f226201..c729094298c2f08d46072c2586ccf57b5c46f721 100644 (file)
@@ -172,6 +172,19 @@ struct comedi_isadma *comedi_isadma_alloc(struct comedi_device *dev,
                goto no_dma;
        dma->desc = desc;
        dma->n_desc = n_desc;
+       if (dev->hw_dev) {
+               dma->dev = dev->hw_dev;
+       } else {
+               /* Fall back to using the "class" device. */
+               if (!dev->class_dev)
+                       goto no_dma;
+               /* Need 24-bit mask for ISA DMA. */
+               if (dma_coerce_mask_and_coherent(dev->class_dev,
+                                                DMA_BIT_MASK(24))) {
+                       goto no_dma;
+               }
+               dma->dev = dev->class_dev;
+       }
 
        dma_chans[0] = dma_chan1;
        if (dma_chan2 == 0 || dma_chan2 == dma_chan1)
@@ -192,7 +205,7 @@ struct comedi_isadma *comedi_isadma_alloc(struct comedi_device *dev,
                desc = &dma->desc[i];
                desc->chan = dma_chans[i];
                desc->maxsize = maxsize;
-               desc->virt_addr = dma_alloc_coherent(NULL, desc->maxsize,
+               desc->virt_addr = dma_alloc_coherent(dma->dev, desc->maxsize,
                                                     &desc->hw_addr,
                                                     GFP_KERNEL);
                if (!desc->virt_addr)
@@ -224,7 +237,7 @@ void comedi_isadma_free(struct comedi_isadma *dma)
                for (i = 0; i < dma->n_desc; i++) {
                        desc = &dma->desc[i];
                        if (desc->virt_addr)
-                               dma_free_coherent(NULL, desc->maxsize,
+                               dma_free_coherent(dma->dev, desc->maxsize,
                                                  desc->virt_addr,
                                                  desc->hw_addr);
                }
index 2bd1329d727f978320c4d952671aebc5bc2f4578..9d2b12db7e6e3f5bb8100fe88b2c3177244a87da 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/types.h>
 
 struct comedi_device;
+struct device;
 
 /*
  * These are used to avoid issues when <asm/dma.h> and the DMA_MODE_
@@ -38,6 +39,7 @@ struct comedi_isadma_desc {
 
 /**
  * struct comedi_isadma - ISA DMA data
+ * @dev:       device to allocate non-coherent memory for
  * @desc:      cookie for each DMA buffer
  * @n_desc:    the number of cookies
  * @cur_dma:   the current cookie in use
@@ -45,6 +47,7 @@ struct comedi_isadma_desc {
  * @chan2:     the second DMA channel requested
  */
 struct comedi_isadma {
+       struct device *dev;
        struct comedi_isadma_desc *desc;
        int n_desc;
        int cur_dma;