]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge branch 'topic/sprd' into for-linus
authorVinod Koul <vinod.koul@intel.com>
Wed, 31 Jan 2018 08:20:52 +0000 (13:50 +0530)
committerVinod Koul <vinod.koul@intel.com>
Wed, 31 Jan 2018 08:20:52 +0000 (13:50 +0530)
21 files changed:
Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt
Documentation/driver-api/dmaengine/provider.rst
drivers/acpi/bus.c
drivers/acpi/property.c
drivers/base/property.c
drivers/dma/at_hdmac.c
drivers/dma/cppi41.c
drivers/dma/dma-jz4740.c
drivers/dma/dmatest.c
drivers/dma/fsl-edma.c
drivers/dma/imx-sdma.c
drivers/dma/ioat/init.c
drivers/dma/mic_x100_dma.c
drivers/dma/qcom/hidma.c
drivers/dma/qcom/hidma_ll.c
drivers/dma/qcom/hidma_mgmt.c
drivers/dma/sh/rcar-dmac.c
drivers/of/property.c
include/linux/acpi.h
include/linux/fwnode.h
include/linux/property.h

index 55492c264d1779539ffb838f3e2f020c07e45709..5d93d6de57d962364942804c7d7f911d15aee32a 100644 (file)
@@ -47,8 +47,8 @@ When the OS is not in control of the management interface (i.e. it's a guest),
 the channel nodes appear on their own, not under a management node.
 
 Required properties:
-- compatible: must contain "qcom,hidma-1.0" for initial HW or "qcom,hidma-1.1"
-for MSI capable HW.
+- compatible: must contain "qcom,hidma-1.0" for initial HW or
+  "qcom,hidma-1.1"/"qcom,hidma-1.2" for MSI capable HW.
 - reg: Addresses for the transfer and event channel
 - interrupts: Should contain the event interrupt
 - desc-count: Number of asynchronous requests this channel can handle
index 814acb4d229475bc9c00c3ff7e47a267ea6a9dba..dfc4486b5743c127fa98d8b6dc0a9e4b9659d562 100644 (file)
@@ -111,40 +111,36 @@ The first thing you need to do in your driver is to allocate this
 structure. Any of the usual memory allocators will do, but you'll also
 need to initialize a few fields in there:
 
-- channels: should be initialized as a list using the
+- ``channels``: should be initialized as a list using the
   INIT_LIST_HEAD macro for example
 
-- src_addr_widths:
+- ``src_addr_widths``:
   should contain a bitmask of the supported source transfer width
 
-- dst_addr_widths:
+- ``dst_addr_widths``:
   should contain a bitmask of the supported destination transfer width
 
-- directions:
+- ``directions``:
   should contain a bitmask of the supported slave directions
   (i.e. excluding mem2mem transfers)
 
-- residue_granularity:
+- ``residue_granularity``:
+  granularity of the transfer residue reported to dma_set_residue.
+  This can be either:
 
-  - Granularity of the transfer residue reported to dma_set_residue.
-    This can be either:
+  - Descriptor:
+    your device doesn't support any kind of residue
+    reporting. The framework will only know that a particular
+    transaction descriptor is done.
 
-  - Descriptor
+  - Segment:
+    your device is able to report which chunks have been transferred
 
-    - Your device doesn't support any kind of residue
-      reporting. The framework will only know that a particular
-      transaction descriptor is done.
+  - Burst:
+    your device is able to report which burst have been transferred
 
-      - Segment
-
-        - Your device is able to report which chunks have been transferred
-
-      - Burst
-
-        - Your device is able to report which burst have been transferred
-
-  - dev: should hold the pointer to the ``struct device`` associated
-    to your current driver instance.
+- ``dev``: should hold the pointer to the ``struct device`` associated
+  to your current driver instance.
 
 Supported transaction types
 ---------------------------
index 4d0979e02a287d638e6f2b1765ad5fda8374f264..f87ed3be779ae3a2f2e9a354e2f55f7badc83c34 100644 (file)
@@ -785,6 +785,24 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
 }
 EXPORT_SYMBOL_GPL(acpi_match_device);
 
+void *acpi_get_match_data(const struct device *dev)
+{
+       const struct acpi_device_id *match;
+
+       if (!dev->driver)
+               return NULL;
+
+       if (!dev->driver->acpi_match_table)
+               return NULL;
+
+       match = acpi_match_device(dev->driver->acpi_match_table, dev);
+       if (!match)
+               return NULL;
+
+       return (void *)match->driver_data;
+}
+EXPORT_SYMBOL_GPL(acpi_get_match_data);
+
 int acpi_match_device_ids(struct acpi_device *device,
                          const struct acpi_device_id *ids)
 {
index e26ea209b63ef1b8f89a6112de5c983db3f4feee..466d1503aba0e31f26b297df2532561a03c12ebd 100644 (file)
@@ -1271,9 +1271,17 @@ static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
        return 0;
 }
 
+static void *
+acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
+                                 const struct device *dev)
+{
+       return acpi_get_match_data(dev);
+}
+
 #define DECLARE_ACPI_FWNODE_OPS(ops) \
        const struct fwnode_operations ops = {                          \
                .device_is_available = acpi_fwnode_device_is_available, \
+               .device_get_match_data = acpi_fwnode_device_get_match_data, \
                .property_present = acpi_fwnode_property_present,       \
                .property_read_int_array =                              \
                        acpi_fwnode_property_read_int_array,            \
index 851b1b6596a4a11a38858bb1fa67d2cb5ea0679b..09eaac9400ed6727853339113cc071ac58cdbfa1 100644 (file)
@@ -1340,3 +1340,10 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
        return fwnode_call_int_op(fwnode, graph_parse_endpoint, endpoint);
 }
 EXPORT_SYMBOL(fwnode_graph_parse_endpoint);
+
+void *device_get_match_data(struct device *dev)
+{
+       return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data,
+                                 dev);
+}
+EXPORT_SYMBOL_GPL(device_get_match_data);
index fbab271b3bf9f9506c86579c75ebe32fc3235228..a861b5b4d4437d6b3be7dcf5e9d0b3475205455d 100644 (file)
@@ -708,7 +708,7 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
                         unsigned long flags)
 {
        struct at_dma_chan      *atchan = to_at_dma_chan(chan);
-       struct data_chunk       *first = xt->sgl;
+       struct data_chunk       *first;
        struct at_desc          *desc = NULL;
        size_t                  xfer_count;
        unsigned int            dwidth;
@@ -720,6 +720,8 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
        if (unlikely(!xt || xt->numf != 1 || !xt->frame_size))
                return NULL;
 
+       first = xt->sgl;
+
        dev_info(chan2dev(chan),
                 "%s: src=%pad, dest=%pad, numf=%d, frame_size=%d, flags=0x%lx\n",
                __func__, &xt->src_start, &xt->dst_start, xt->numf,
index f7e965f632747aa4c4a5532cd010d847917bbb67..d9bee65a18a4aa16fed2d2d5bcdf68df6d799601 100644 (file)
@@ -934,7 +934,7 @@ static bool cpp41_dma_filter_fn(struct dma_chan *chan, void *param)
 
        BUILD_BUG_ON(ARRAY_SIZE(am335x_usb_queues_rx) !=
                     ARRAY_SIZE(am335x_usb_queues_tx));
-       if (WARN_ON(cchan->port_num > ARRAY_SIZE(am335x_usb_queues_rx)))
+       if (WARN_ON(cchan->port_num >= ARRAY_SIZE(am335x_usb_queues_rx)))
                return false;
 
        cchan->q_num = queues[cchan->port_num].submit;
index d50273fed715096ac625382f6c511f537da57bf4..afd5e10f8927cb0c5573bb946a48755aad58b0aa 100644 (file)
@@ -555,7 +555,7 @@ static int jz4740_dma_probe(struct platform_device *pdev)
 
        ret = dma_async_device_register(dd);
        if (ret)
-               return ret;
+               goto err_clk;
 
        irq = platform_get_irq(pdev, 0);
        ret = request_irq(irq, jz4740_dma_irq, 0, dev_name(&pdev->dev), dmadev);
@@ -568,6 +568,8 @@ static int jz4740_dma_probe(struct platform_device *pdev)
 
 err_unregister:
        dma_async_device_unregister(dd);
+err_clk:
+       clk_disable_unprepare(dmadev->clk);
        return ret;
 }
 
index 47edc7fbf91f52e5259060824c38eaab69ebdb56..80cc2be6483cb87074b4a11e205f8b15c7b715e3 100644 (file)
@@ -155,6 +155,12 @@ MODULE_PARM_DESC(run, "Run the test (default: false)");
 #define PATTERN_COUNT_MASK     0x1f
 #define PATTERN_MEMSET_IDX     0x01
 
+/* poor man's completion - we want to use wait_event_freezable() on it */
+struct dmatest_done {
+       bool                    done;
+       wait_queue_head_t       *wait;
+};
+
 struct dmatest_thread {
        struct list_head        node;
        struct dmatest_info     *info;
@@ -165,6 +171,8 @@ struct dmatest_thread {
        u8                      **dsts;
        u8                      **udsts;
        enum dma_transaction_type type;
+       wait_queue_head_t done_wait;
+       struct dmatest_done test_done;
        bool                    done;
 };
 
@@ -342,18 +350,25 @@ static unsigned int dmatest_verify(u8 **bufs, unsigned int start,
        return error_count;
 }
 
-/* poor man's completion - we want to use wait_event_freezable() on it */
-struct dmatest_done {
-       bool                    done;
-       wait_queue_head_t       *wait;
-};
 
 static void dmatest_callback(void *arg)
 {
        struct dmatest_done *done = arg;
-
-       done->done = true;
-       wake_up_all(done->wait);
+       struct dmatest_thread *thread =
+               container_of(done, struct dmatest_thread, test_done);
+       if (!thread->done) {
+               done->done = true;
+               wake_up_all(done->wait);
+       } else {
+               /*
+                * If thread->done, it means that this callback occurred
+                * after the parent thread has cleaned up. This can
+                * happen in the case that driver doesn't implement
+                * the terminate_all() functionality and a dma operation
+                * did not occur within the timeout period
+                */
+               WARN(1, "dmatest: Kernel memory may be corrupted!!\n");
+       }
 }
 
 static unsigned int min_odd(unsigned int x, unsigned int y)
@@ -424,9 +439,8 @@ static unsigned long long dmatest_KBs(s64 runtime, unsigned long long len)
  */
 static int dmatest_func(void *data)
 {
-       DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_wait);
        struct dmatest_thread   *thread = data;
-       struct dmatest_done     done = { .wait = &done_wait };
+       struct dmatest_done     *done = &thread->test_done;
        struct dmatest_info     *info;
        struct dmatest_params   *params;
        struct dma_chan         *chan;
@@ -673,9 +687,9 @@ static int dmatest_func(void *data)
                        continue;
                }
 
-               done.done = false;
+               done->done = false;
                tx->callback = dmatest_callback;
-               tx->callback_param = &done;
+               tx->callback_param = done;
                cookie = tx->tx_submit(tx);
 
                if (dma_submit_error(cookie)) {
@@ -688,21 +702,12 @@ static int dmatest_func(void *data)
                }
                dma_async_issue_pending(chan);
 
-               wait_event_freezable_timeout(done_wait, done.done,
+               wait_event_freezable_timeout(thread->done_wait, done->done,
                                             msecs_to_jiffies(params->timeout));
 
                status = dma_async_is_tx_complete(chan, cookie, NULL, NULL);
 
-               if (!done.done) {
-                       /*
-                        * We're leaving the timed out dma operation with
-                        * dangling pointer to done_wait.  To make this
-                        * correct, we'll need to allocate wait_done for
-                        * each test iteration and perform "who's gonna
-                        * free it this time?" dancing.  For now, just
-                        * leave it dangling.
-                        */
-                       WARN(1, "dmatest: Kernel stack may be corrupted!!\n");
+               if (!done->done) {
                        dmaengine_unmap_put(um);
                        result("test timed out", total_tests, src_off, dst_off,
                               len, 0);
@@ -789,7 +794,7 @@ static int dmatest_func(void *data)
                dmatest_KBs(runtime, total_len), ret);
 
        /* terminate all transfers on specified channels */
-       if (ret)
+       if (ret || failed_tests)
                dmaengine_terminate_all(chan);
 
        thread->done = true;
@@ -849,6 +854,8 @@ static int dmatest_add_threads(struct dmatest_info *info,
                thread->info = info;
                thread->chan = dtc->chan;
                thread->type = type;
+               thread->test_done.wait = &thread->done_wait;
+               init_waitqueue_head(&thread->done_wait);
                smp_wmb();
                thread->task = kthread_create(dmatest_func, thread, "%s-%s%u",
                                dma_chan_name(chan), op, i);
index 6775f2c74e25b7269417bbe001adfb03698dea97..c7568869284e17d4b63379b236a0f30391640820 100644 (file)
@@ -863,11 +863,11 @@ static void fsl_edma_irq_exit(
        }
 }
 
-static void fsl_disable_clocks(struct fsl_edma_engine *fsl_edma)
+static void fsl_disable_clocks(struct fsl_edma_engine *fsl_edma, int nr_clocks)
 {
        int i;
 
-       for (i = 0; i < DMAMUX_NR; i++)
+       for (i = 0; i < nr_clocks; i++)
                clk_disable_unprepare(fsl_edma->muxclk[i]);
 }
 
@@ -904,25 +904,25 @@ static int fsl_edma_probe(struct platform_device *pdev)
 
                res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i);
                fsl_edma->muxbase[i] = devm_ioremap_resource(&pdev->dev, res);
-               if (IS_ERR(fsl_edma->muxbase[i]))
+               if (IS_ERR(fsl_edma->muxbase[i])) {
+                       /* on error: disable all previously enabled clks */
+                       fsl_disable_clocks(fsl_edma, i);
                        return PTR_ERR(fsl_edma->muxbase[i]);
+               }
 
                sprintf(clkname, "dmamux%d", i);
                fsl_edma->muxclk[i] = devm_clk_get(&pdev->dev, clkname);
                if (IS_ERR(fsl_edma->muxclk[i])) {
                        dev_err(&pdev->dev, "Missing DMAMUX block clock.\n");
+                       /* on error: disable all previously enabled clks */
+                       fsl_disable_clocks(fsl_edma, i);
                        return PTR_ERR(fsl_edma->muxclk[i]);
                }
 
                ret = clk_prepare_enable(fsl_edma->muxclk[i]);
-               if (ret) {
-                       /* disable only clks which were enabled on error */
-                       for (; i >= 0; i--)
-                               clk_disable_unprepare(fsl_edma->muxclk[i]);
-
-                       dev_err(&pdev->dev, "DMAMUX clk block failed.\n");
-                       return ret;
-               }
+               if (ret)
+                       /* on error: disable all previously enabled clks */
+                       fsl_disable_clocks(fsl_edma, i);
 
        }
 
@@ -976,7 +976,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(&pdev->dev,
                        "Can't register Freescale eDMA engine. (%d)\n", ret);
-               fsl_disable_clocks(fsl_edma);
+               fsl_disable_clocks(fsl_edma, DMAMUX_NR);
                return ret;
        }
 
@@ -985,7 +985,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
                dev_err(&pdev->dev,
                        "Can't register Freescale eDMA of_dma. (%d)\n", ret);
                dma_async_device_unregister(&fsl_edma->dma_dev);
-               fsl_disable_clocks(fsl_edma);
+               fsl_disable_clocks(fsl_edma, DMAMUX_NR);
                return ret;
        }
 
@@ -1015,7 +1015,7 @@ static int fsl_edma_remove(struct platform_device *pdev)
        fsl_edma_cleanup_vchan(&fsl_edma->dma_dev);
        of_dma_controller_free(np);
        dma_async_device_unregister(&fsl_edma->dma_dev);
-       fsl_disable_clocks(fsl_edma);
+       fsl_disable_clocks(fsl_edma, DMAMUX_NR);
 
        return 0;
 }
index 2184881afe76be5840f9adaff908c91e0626c2db..e7db24c67030d19a0db9c88d46ae867d11e4d0dd 100644 (file)
@@ -1939,4 +1939,10 @@ module_platform_driver(sdma_driver);
 
 MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
 MODULE_DESCRIPTION("i.MX SDMA driver");
+#if IS_ENABLED(CONFIG_SOC_IMX6Q)
+MODULE_FIRMWARE("imx/sdma/sdma-imx6q.bin");
+#endif
+#if IS_ENABLED(CONFIG_SOC_IMX7D)
+MODULE_FIRMWARE("imx/sdma/sdma-imx7d.bin");
+#endif
 MODULE_LICENSE("GPL");
index 2f31d3d0caa61821aa08aea360e06709bdb25d48..7792a9186f9cf35bae71792e5e0783cf53364b05 100644 (file)
@@ -390,7 +390,7 @@ static int ioat_dma_self_test(struct ioatdma_device *ioat_dma)
        if (memcmp(src, dest, IOAT_TEST_SIZE)) {
                dev_err(dev, "Self-test copy failed compare, disabling\n");
                err = -ENODEV;
-               goto free_resources;
+               goto unmap_dma;
        }
 
 unmap_dma:
index 5ba5714d0b7c9787e87282d0b71f5f7dd06dca42..94d7bd7d2880164de11957e105a5f04a1cc8b102 100644 (file)
@@ -480,9 +480,7 @@ static int mic_dma_setup_irq(struct mic_dma_chan *ch)
                to_mbus_hw_ops(ch)->request_threaded_irq(to_mbus_device(ch),
                        mic_dma_intr_handler, mic_dma_thread_fn,
                        "mic dma_channel", ch, ch->ch_num);
-       if (IS_ERR(ch->cookie))
-               return PTR_ERR(ch->cookie);
-       return 0;
+       return PTR_ERR_OR_ZERO(ch->cookie);
 }
 
 static inline void mic_dma_free_irq(struct mic_dma_chan *ch)
index e3669850aef4ce78dbae0f97d03a87393a30c5fa..963cc5228d05a5259214f2ba825c3ea735fae49d 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/of_dma.h>
+#include <linux/of_device.h>
 #include <linux/property.h>
 #include <linux/delay.h>
 #include <linux/acpi.h>
@@ -104,6 +105,10 @@ static unsigned int nr_desc_prm;
 module_param(nr_desc_prm, uint, 0644);
 MODULE_PARM_DESC(nr_desc_prm, "number of descriptors (default: 0)");
 
+enum hidma_cap {
+       HIDMA_MSI_CAP = 1,
+       HIDMA_IDENTITY_CAP,
+};
 
 /* process completed descriptors */
 static void hidma_process_completed(struct hidma_chan *mchan)
@@ -736,25 +741,12 @@ static int hidma_request_msi(struct hidma_dev *dmadev,
 #endif
 }
 
-static bool hidma_msi_capable(struct device *dev)
+static bool hidma_test_capability(struct device *dev, enum hidma_cap test_cap)
 {
-       struct acpi_device *adev = ACPI_COMPANION(dev);
-       const char *of_compat;
-       int ret = -EINVAL;
-
-       if (!adev || acpi_disabled) {
-               ret = device_property_read_string(dev, "compatible",
-                                                 &of_compat);
-               if (ret)
-                       return false;
+       enum hidma_cap cap;
 
-               ret = strcmp(of_compat, "qcom,hidma-1.1");
-       } else {
-#ifdef CONFIG_ACPI
-               ret = strcmp(acpi_device_hid(adev), "QCOM8062");
-#endif
-       }
-       return ret == 0;
+       cap = (enum hidma_cap) device_get_match_data(dev);
+       return cap ? ((cap & test_cap) > 0) : 0;
 }
 
 static int hidma_probe(struct platform_device *pdev)
@@ -834,8 +826,7 @@ static int hidma_probe(struct platform_device *pdev)
         * Determine the MSI capability of the platform. Old HW doesn't
         * support MSI.
         */
-       msi = hidma_msi_capable(&pdev->dev);
-
+       msi = hidma_test_capability(&pdev->dev, HIDMA_MSI_CAP);
        device_property_read_u32(&pdev->dev, "desc-count",
                                 &dmadev->nr_descriptors);
 
@@ -848,7 +839,10 @@ static int hidma_probe(struct platform_device *pdev)
        if (!dmadev->nr_descriptors)
                dmadev->nr_descriptors = HIDMA_NR_DEFAULT_DESC;
 
-       dmadev->chidx = readl(dmadev->dev_trca + 0x28);
+       if (hidma_test_capability(&pdev->dev, HIDMA_IDENTITY_CAP))
+               dmadev->chidx = readl(dmadev->dev_trca + 0x40);
+       else
+               dmadev->chidx = readl(dmadev->dev_trca + 0x28);
 
        /* Set DMA mask to 64 bits. */
        rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
@@ -953,7 +947,8 @@ static int hidma_remove(struct platform_device *pdev)
 #if IS_ENABLED(CONFIG_ACPI)
 static const struct acpi_device_id hidma_acpi_ids[] = {
        {"QCOM8061"},
-       {"QCOM8062"},
+       {"QCOM8062", HIDMA_MSI_CAP},
+       {"QCOM8063", (HIDMA_MSI_CAP | HIDMA_IDENTITY_CAP)},
        {},
 };
 MODULE_DEVICE_TABLE(acpi, hidma_acpi_ids);
@@ -961,7 +956,9 @@ MODULE_DEVICE_TABLE(acpi, hidma_acpi_ids);
 
 static const struct of_device_id hidma_match[] = {
        {.compatible = "qcom,hidma-1.0",},
-       {.compatible = "qcom,hidma-1.1",},
+       {.compatible = "qcom,hidma-1.1", .data = (void *)(HIDMA_MSI_CAP),},
+       {.compatible = "qcom,hidma-1.2",
+        .data = (void *)(HIDMA_MSI_CAP | HIDMA_IDENTITY_CAP),},
        {},
 };
 MODULE_DEVICE_TABLE(of, hidma_match);
index 4999e266b2dec83ea3f98fccb28aa08e08595a9b..7c6e2ff212a2c5ad3ef7879cffe888c102945ba3 100644 (file)
@@ -393,6 +393,8 @@ static int hidma_ll_reset(struct hidma_lldev *lldev)
  */
 static void hidma_ll_int_handler_internal(struct hidma_lldev *lldev, int cause)
 {
+       unsigned long irqflags;
+
        if (cause & HIDMA_ERR_INT_MASK) {
                dev_err(lldev->dev, "error 0x%x, disabling...\n",
                                cause);
@@ -410,6 +412,10 @@ static void hidma_ll_int_handler_internal(struct hidma_lldev *lldev, int cause)
                return;
        }
 
+       spin_lock_irqsave(&lldev->lock, irqflags);
+       writel_relaxed(cause, lldev->evca + HIDMA_EVCA_IRQ_CLR_REG);
+       spin_unlock_irqrestore(&lldev->lock, irqflags);
+
        /*
         * Fine tuned for this HW...
         *
@@ -421,9 +427,6 @@ static void hidma_ll_int_handler_internal(struct hidma_lldev *lldev, int cause)
         * Try to consume as many EVREs as possible.
         */
        hidma_handle_tre_completion(lldev);
-
-       /* We consumed TREs or there are pending TREs or EVREs. */
-       writel_relaxed(cause, lldev->evca + HIDMA_EVCA_IRQ_CLR_REG);
 }
 
 irqreturn_t hidma_ll_inthandler(int chirq, void *arg)
index 7335e2eb9b72a1fffc01d51317b6eff8d9c4bee7..000c7019ca7d30db231ba6e8b6d597fbf1276fa2 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/acpi.h>
 #include <linux/of.h>
 #include <linux/property.h>
+#include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/module.h>
@@ -356,67 +357,37 @@ static int __init hidma_mgmt_of_populate_channels(struct device_node *np)
 {
        struct platform_device *pdev_parent = of_find_device_by_node(np);
        struct platform_device_info pdevinfo;
-       struct of_phandle_args out_irq;
        struct device_node *child;
-       struct resource *res = NULL;
-       const __be32 *cell;
-       int ret = 0, size, i, num;
-       u64 addr, addr_size;
+       struct resource *res;
+       int ret = 0;
+
+       /* allocate a resource array */
+       res = kcalloc(3, sizeof(*res), GFP_KERNEL);
+       if (!res)
+               return -ENOMEM;
 
        for_each_available_child_of_node(np, child) {
-               struct resource *res_iter;
                struct platform_device *new_pdev;
 
-               cell = of_get_property(child, "reg", &size);
-               if (!cell) {
-                       ret = -EINVAL;
+               ret = of_address_to_resource(child, 0, &res[0]);
+               if (!ret)
                        goto out;
-               }
-
-               size /= sizeof(*cell);
-               num = size /
-                       (of_n_addr_cells(child) + of_n_size_cells(child)) + 1;
 
-               /* allocate a resource array */
-               res = kcalloc(num, sizeof(*res), GFP_KERNEL);
-               if (!res) {
-                       ret = -ENOMEM;
+               ret = of_address_to_resource(child, 1, &res[1]);
+               if (!ret)
                        goto out;
-               }
-
-               /* read each reg value */
-               i = 0;
-               res_iter = res;
-               while (i < size) {
-                       addr = of_read_number(&cell[i],
-                                             of_n_addr_cells(child));
-                       i += of_n_addr_cells(child);
-
-                       addr_size = of_read_number(&cell[i],
-                                                  of_n_size_cells(child));
-                       i += of_n_size_cells(child);
-
-                       res_iter->start = addr;
-                       res_iter->end = res_iter->start + addr_size - 1;
-                       res_iter->flags = IORESOURCE_MEM;
-                       res_iter++;
-               }
 
-               ret = of_irq_parse_one(child, 0, &out_irq);
-               if (ret)
+               ret = of_irq_to_resource(child, 0, &res[2]);
+               if (ret <= 0)
                        goto out;
 
-               res_iter->start = irq_create_of_mapping(&out_irq);
-               res_iter->name = "hidma event irq";
-               res_iter->flags = IORESOURCE_IRQ;
-
                memset(&pdevinfo, 0, sizeof(pdevinfo));
                pdevinfo.fwnode = &child->fwnode;
                pdevinfo.parent = pdev_parent ? &pdev_parent->dev : NULL;
                pdevinfo.name = child->name;
                pdevinfo.id = object_counter++;
                pdevinfo.res = res;
-               pdevinfo.num_res = num;
+               pdevinfo.num_res = 3;
                pdevinfo.data = NULL;
                pdevinfo.size_data = 0;
                pdevinfo.dma_mask = DMA_BIT_MASK(64);
@@ -434,8 +405,6 @@ static int __init hidma_mgmt_of_populate_channels(struct device_node *np)
                 */
                of_msi_configure(&new_pdev->dev, child);
                of_node_put(child);
-               kfree(res);
-               res = NULL;
        }
 out:
        kfree(res);
index 2b2c7db3e48043fcdb1d0ed377613dde185f0a1b..3bbd11daa8521c80ee98d5e4f374c19c6c4762e6 100644 (file)
@@ -10,6 +10,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
 #include <linux/interrupt.h>
@@ -741,6 +742,41 @@ static int rcar_dmac_fill_hwdesc(struct rcar_dmac_chan *chan,
 /* -----------------------------------------------------------------------------
  * Stop and reset
  */
+static void rcar_dmac_chcr_de_barrier(struct rcar_dmac_chan *chan)
+{
+       u32 chcr;
+       unsigned int i;
+
+       /*
+        * Ensure that the setting of the DE bit is actually 0 after
+        * clearing it.
+        */
+       for (i = 0; i < 1024; i++) {
+               chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
+               if (!(chcr & RCAR_DMACHCR_DE))
+                       return;
+               udelay(1);
+       }
+
+       dev_err(chan->chan.device->dev, "CHCR DE check error\n");
+}
+
+static void rcar_dmac_sync_tcr(struct rcar_dmac_chan *chan)
+{
+       u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
+
+       if (!(chcr & RCAR_DMACHCR_DE))
+               return;
+
+       /* set DE=0 and flush remaining data */
+       rcar_dmac_chan_write(chan, RCAR_DMACHCR, (chcr & ~RCAR_DMACHCR_DE));
+
+       /* make sure all remaining data was flushed */
+       rcar_dmac_chcr_de_barrier(chan);
+
+       /* back DE */
+       rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr);
+}
 
 static void rcar_dmac_chan_halt(struct rcar_dmac_chan *chan)
 {
@@ -749,6 +785,7 @@ static void rcar_dmac_chan_halt(struct rcar_dmac_chan *chan)
        chcr &= ~(RCAR_DMACHCR_DSE | RCAR_DMACHCR_DSIE | RCAR_DMACHCR_IE |
                  RCAR_DMACHCR_TE | RCAR_DMACHCR_DE);
        rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr);
+       rcar_dmac_chcr_de_barrier(chan);
 }
 
 static void rcar_dmac_chan_reinit(struct rcar_dmac_chan *chan)
@@ -1309,8 +1346,11 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan,
                residue += chunk->size;
        }
 
+       if (desc->direction == DMA_DEV_TO_MEM)
+               rcar_dmac_sync_tcr(chan);
+
        /* Add the residue for the current chunk. */
-       residue += rcar_dmac_chan_read(chan, RCAR_DMATCR) << desc->xfer_shift;
+       residue += rcar_dmac_chan_read(chan, RCAR_DMATCRB) << desc->xfer_shift;
 
        return residue;
 }
@@ -1481,6 +1521,8 @@ static irqreturn_t rcar_dmac_isr_channel(int irq, void *dev)
        if (chcr & RCAR_DMACHCR_TE)
                mask |= RCAR_DMACHCR_DE;
        rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr & ~mask);
+       if (mask & RCAR_DMACHCR_DE)
+               rcar_dmac_chcr_de_barrier(chan);
 
        if (chcr & RCAR_DMACHCR_DSE)
                ret |= rcar_dmac_isr_desc_stage_end(chan);
index 8ad33a44a7b871fabe3695a178e7cef19f2117dc..f25d36358187ddecee74df3b2042252fbbfa4c6d 100644 (file)
@@ -981,10 +981,18 @@ static int of_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
        return 0;
 }
 
+static void *
+of_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
+                               const struct device *dev)
+{
+       return (void *)of_device_get_match_data(dev);
+}
+
 const struct fwnode_operations of_fwnode_ops = {
        .get = of_fwnode_get,
        .put = of_fwnode_put,
        .device_is_available = of_fwnode_device_is_available,
+       .device_get_match_data = of_fwnode_device_get_match_data,
        .property_present = of_fwnode_property_present,
        .property_read_int_array = of_fwnode_property_read_int_array,
        .property_read_string_array = of_fwnode_property_read_string_array,
index dc1ebfeeb5ecc10e248f57084f80c72d32c6c14a..927873751323a15dc58ac2c180cc9bc45c93a47c 100644 (file)
@@ -584,6 +584,7 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
 const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
                                               const struct device *dev);
 
+void *acpi_get_match_data(const struct device *dev);
 extern bool acpi_driver_match_device(struct device *dev,
                                     const struct device_driver *drv);
 int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
@@ -755,6 +756,11 @@ static inline const struct acpi_device_id *acpi_match_device(
        return NULL;
 }
 
+static inline void *acpi_get_match_data(const struct device *dev)
+{
+       return NULL;
+}
+
 static inline bool acpi_driver_match_device(struct device *dev,
                                            const struct device_driver *drv)
 {
index 411a84c6c400c3a91fb4ca789300901ccca7fdbc..4fa1a489efe4cd6e15d88a269044fbd37dfe054d 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 
 struct fwnode_operations;
+struct device;
 
 struct fwnode_handle {
        struct fwnode_handle *secondary;
@@ -51,6 +52,7 @@ struct fwnode_reference_args {
  * struct fwnode_operations - Operations for fwnode interface
  * @get: Get a reference to an fwnode.
  * @put: Put a reference to an fwnode.
+ * @device_get_match_data: Return the device driver match data.
  * @property_present: Return true if a property is present.
  * @property_read_integer_array: Read an array of integer properties. Return
  *                              zero on success, a negative error code
@@ -71,6 +73,8 @@ struct fwnode_operations {
        struct fwnode_handle *(*get)(struct fwnode_handle *fwnode);
        void (*put)(struct fwnode_handle *fwnode);
        bool (*device_is_available)(const struct fwnode_handle *fwnode);
+       void *(*device_get_match_data)(const struct fwnode_handle *fwnode,
+                                      const struct device *dev);
        bool (*property_present)(const struct fwnode_handle *fwnode,
                                 const char *propname);
        int (*property_read_int_array)(const struct fwnode_handle *fwnode,
index f6189a3ac63ca2f57d4a29ee49df68148a957675..6653ed4b99f9a4f910f5ded5bbfc627af2a3ee5e 100644 (file)
@@ -275,6 +275,8 @@ bool device_dma_supported(struct device *dev);
 
 enum dev_dma_attr device_get_dma_attr(struct device *dev);
 
+void *device_get_match_data(struct device *dev);
+
 int device_get_phy_mode(struct device *dev);
 
 void *device_get_mac_address(struct device *dev, char *addr, int alen);