These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / dma / of-dma.c
index cbd4a8a..1e1f298 100644 (file)
@@ -44,6 +44,50 @@ static struct of_dma *of_dma_find_controller(struct of_phandle_args *dma_spec)
        return NULL;
 }
 
+/**
+ * of_dma_router_xlate - translation function for router devices
+ * @dma_spec:  pointer to DMA specifier as found in the device tree
+ * @of_dma:    pointer to DMA controller data (router information)
+ *
+ * The function creates new dma_spec to be passed to the router driver's
+ * of_dma_route_allocate() function to prepare a dma_spec which will be used
+ * to request channel from the real DMA controller.
+ */
+static struct dma_chan *of_dma_router_xlate(struct of_phandle_args *dma_spec,
+                                           struct of_dma *ofdma)
+{
+       struct dma_chan         *chan;
+       struct of_dma           *ofdma_target;
+       struct of_phandle_args  dma_spec_target;
+       void                    *route_data;
+
+       /* translate the request for the real DMA controller */
+       memcpy(&dma_spec_target, dma_spec, sizeof(dma_spec_target));
+       route_data = ofdma->of_dma_route_allocate(&dma_spec_target, ofdma);
+       if (IS_ERR(route_data))
+               return NULL;
+
+       ofdma_target = of_dma_find_controller(&dma_spec_target);
+       if (!ofdma_target)
+               return NULL;
+
+       chan = ofdma_target->of_dma_xlate(&dma_spec_target, ofdma_target);
+       if (chan) {
+               chan->router = ofdma->dma_router;
+               chan->route_data = route_data;
+       } else {
+               ofdma->dma_router->route_free(ofdma->dma_router->dev,
+                                             route_data);
+       }
+
+       /*
+        * Need to put the node back since the ofdma->of_dma_route_allocate
+        * has taken it for generating the new, translated dma_spec
+        */
+       of_node_put(dma_spec_target.np);
+       return chan;
+}
+
 /**
  * of_dma_controller_register - Register a DMA controller to DT DMA helpers
  * @np:                        device node of DMA controller
@@ -109,6 +153,51 @@ void of_dma_controller_free(struct device_node *np)
 }
 EXPORT_SYMBOL_GPL(of_dma_controller_free);
 
+/**
+ * of_dma_router_register - Register a DMA router to DT DMA helpers as a
+ *                         controller
+ * @np:                                device node of DMA router
+ * @of_dma_route_allocate:     setup function for the router which need to
+ *                             modify the dma_spec for the DMA controller to
+ *                             use and to set up the requested route.
+ * @dma_router:                        pointer to dma_router structure to be used when
+ *                             the route need to be free up.
+ *
+ * Returns 0 on success or appropriate errno value on error.
+ *
+ * Allocated memory should be freed with appropriate of_dma_controller_free()
+ * call.
+ */
+int of_dma_router_register(struct device_node *np,
+                          void *(*of_dma_route_allocate)
+                          (struct of_phandle_args *, struct of_dma *),
+                          struct dma_router *dma_router)
+{
+       struct of_dma   *ofdma;
+
+       if (!np || !of_dma_route_allocate || !dma_router) {
+               pr_err("%s: not enough information provided\n", __func__);
+               return -EINVAL;
+       }
+
+       ofdma = kzalloc(sizeof(*ofdma), GFP_KERNEL);
+       if (!ofdma)
+               return -ENOMEM;
+
+       ofdma->of_node = np;
+       ofdma->of_dma_xlate = of_dma_router_xlate;
+       ofdma->of_dma_route_allocate = of_dma_route_allocate;
+       ofdma->dma_router = dma_router;
+
+       /* Now queue of_dma controller structure in list */
+       mutex_lock(&of_dma_lock);
+       list_add_tail(&ofdma->of_dma_controllers, &of_dma_list);
+       mutex_unlock(&of_dma_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(of_dma_router_register);
+
 /**
  * of_dma_match_channel - Check if a DMA specifier matches name
  * @np:                device node to look for DMA channels