Thanks for the detailed review
Laura Abbott писал 30.06.2015 20:56:
On 06/30/2015 08:34 AM, Andrew Andrianov wrote:
if (!idev)
+ return -ENOMEM;
+ }
Yeah this is a bit messy as your comments note. Since there can only be
one Ion
device in the system, it seems like it would make more sense to have a
top level
DT node and then have the heaps be subnodes to avoid this 'guess when
to create
the device' bit.
I'm afraid this is not a very good idea, if the heaps represent some
_physical_
address ranges, e.g. a SRAM memory (read below for our weird use case).
In this case, the way I understand DT philosophy, it should be a subnode
of the
respective axi/apb/whatever node where it's connected. Correct me if I'm
wrong.
+
+ ipdev = kzalloc(sizeof(*ipdev), GFP_KERNEL);
+ if (!ipdev)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ipdev);
+
+ /* Read out name first for the sake of sane error-reporting */
+ ret = of_property_read_string(pdev->dev.of_node, "ion-heap-name",
+ &ion_heap_name);
+ if (ret != 0)
+ goto errfreeipdev;
+
+ ret = of_property_read_u32(pdev->dev.of_node, "ion-heap-id",
+ &ion_heap_id);
+ if (ret != 0)
+ goto errfreeipdev;
+
+ /* Check id to be sane first */
+ if ((ion_heap_id < 0) || (ion_heap_id >= ION_NUM_HEAP_IDS)) {
+ dev_err(&pdev->dev, "bad heap id specified: %d\n",
+ ion_heap_id);
+ goto errfreeipdev;
+ }
+
+ if ((1 << ion_heap_id) & claimed_heap_ids) {
+ dev_err(&pdev->dev, "heap id %d is already claimed\n",
+ ion_heap_id);
+ goto errfreeipdev;
+ }
I thought the core Ion framework was already checking this but
apparently not. This is so fundamental it should really be moved into
the core framework and not at the client level.
I tried to mess as little as possible (e.g. not mess at all) with the
guts of
ION, so ended up with an extra check. If you want, I can hack into the
ion itself,
and send the patch for the next respin.
+
+ ret = of_property_read_u32(pdev->dev.of_node, "ion-heap-type",
+ &ion_heap_type);
+ if (ret != 0)
+ goto errfreeipdev;
+
+ ret = of_property_read_u32(pdev->dev.of_node, "ion-heap-align",
+ &ion_heap_align);
+ if (ret != 0)
+ goto errfreeipdev;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory");
+ /* Not always needed, throw no error if missing */
+ if (res) {
+ /* Fill in some defaults */
+ addr = res->start;
+ size = resource_size(res);
+ }
+
+ switch (ion_heap_type) {
+ case ION_HEAP_TYPE_DMA:
+ if (res) {
+ ret = dma_declare_coherent_memory(&pdev->dev,
+ res->start,
+ res->start,
+ resource_size(res),
+ DMA_MEMORY_MAP |
+ DMA_MEMORY_EXCLUSIVE);
+ if (ret == 0) {
+ ret = -ENODEV;
+ goto errfreeipdev;
+ }
+ }
The name is ION_HEAP_TYPE_DMA but the real point of the heap was to
be able to use CMA memory. Calling dma_declare_coherent_memory defeats
the point since we won't use CMA memory. The coherent memory pool is
closer
to a carveout anyway so I'd argue if you want the effects of a coherent
memory pool you should be using carveout memory anyway.
In our weird use case we use ION to share buffers between NeuroMatrix
DSP
cores, video decoder, video output device and a userspace application
that
orchestrates the whole process. The system has several dedicated SRAM
banks,
that should represented as dedicated ION heaps. Those are differently
wired in
the system (e.g. ARM core can't even execute code from some of them) and
to
achieve maximum performance certain buffers should be only allocated
from
certain banks for the thing to work fast.
(Yes, it's just as scary as it sounds)
In other words - we need several coherent pools, and
dma_declare_coherent
looked like the only existing way to tell ION:
"hey, we want a heap out of this very physical region!"
In reality that's mostly our only use case, all the rest heap types look
like mostly
useful for testing rather than in production, as a smarter replacement
of ion-dummy
driver which I used as a reference while writing this one.
+ /*
+ * If no memory region declared in dt we assume that
+ * the user is okay with plain dma_alloc_coherent.
+ */
+ break;
+ case ION_HEAP_TYPE_CARVEOUT:
+ case ION_HEAP_TYPE_CHUNK:
+ if (size == 0) {
+ ret = -EIO;
+ goto errfreeipdev;
+ }
+ ipdev->freepage_ptr = alloc_pages_exact(size, GFP_KERNEL);
+ if (ipdev->freepage_ptr) {
+ addr = virt_to_phys(ipdev->freepage_ptr);
+ } else {
+ ret = -ENOMEM;
+ goto errfreeipdev;
+ }
+ break;
+ }
+
This won't work if the carveout region is larger than the buddy
allocator
allows. That's why ion_reserve used the memblock APIs, to avoid being
limited by buddy allocator sizes.
I guess it's okay for testing purposes. Unless I'm missing by the end of
the workday a simple way to do it properly.
+ ipdev->data.id = ion_heap_id;
+ ipdev->data.type = ion_heap_type;
+ ipdev->data.name = ion_heap_name;
+ ipdev->data.align = ion_heap_align;
+ ipdev->data.base = addr;
+ ipdev->data.size = size;
+
+ /* This one make dma_declare_coherent_memory actually work */
+ ipdev->data.priv = &pdev->dev;
+
+ ipdev->heap = ion_heap_create(&ipdev->data);
+ if (!ipdev->heap)
+ goto errfreeipdev;
+
+ /* If it's needed - take care enable clocks */
+ ipdev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(ipdev->clk))
+ ipdev->clk = NULL;
+ else
+ clk_prepare_enable(ipdev->clk);
+
Probe deferal for the clocks here?
Oops, missed that one. Since I couldn't test clock gating (sram clock's
not gated on my hw),
I just settled for the same way they do it in drivers/misc/sram.c (And
they don't handle
deferral at all there!)
+ ion_device_add_heap(idev, ipdev->heap);
+ claimed_heap_ids |= (1 << ion_heap_id);
+ ipdev->heap_id = ion_heap_id;
+
+ dev_dbg(&pdev->dev, "heap %s id %d type %d align 0x%x at phys 0x%lx
len %lu KiB\n",
+ ion_heap_name, ion_heap_id, ion_heap_type, ion_heap_align,
+ (unsigned long int)addr, ((unsigned long int)(size / 1024)));
+ return 0;
+
+errfreeipdev:
+ kfree(ipdev);
+ dev_err(&pdev->dev, "Failed to register heap: %s\n",
+ ion_heap_name);
+ return -ENOMEM;
+}
+
+static int ion_physmem_remove(struct platform_device *pdev)
+{
+ struct physmem_ion_dev *ipdev = platform_get_drvdata(pdev);
+
+ ion_heap_destroy(ipdev->heap);
+ claimed_heap_ids &= ~(1 << ipdev->heap_id);
+ if (ipdev->need_free_coherent)
+ dma_release_declared_memory(&pdev->dev);
+ if (ipdev->freepage_ptr)
+ free_pages_exact(ipdev->freepage_ptr, ipdev->data.size);
+ kfree(ipdev->heap);
+ if (ipdev->clk)
+ clk_disable_unprepare(ipdev->clk);
+ kfree(ipdev);
+
+ /* We only remove heaps and disable clocks here.
+ * There's no point in nuking the device itself, since:
+ * a). ION driver modules can't be unloaded (yet?)
+ * b). ion_device_destroy() looks like a stub and doesn't
+ * take care to free heaps/clients.
+ * c). I can't think of a scenario where it will be required
+ */
+
+ return 0;
+}
+
+static struct platform_driver ion_physmem_driver = {
+ .probe = ion_physmem_probe,
+ .remove = ion_physmem_remove,
+ .driver = {
+ .name = "ion-physmem",
+ .of_match_table = of_match_ptr(of_match_table),
+ },
+};
+
+static int __init ion_physmem_init(void)
+{
+ return platform_driver_register(&ion_physmem_driver);
+}
+device_initcall(ion_physmem_init);
diff --git a/include/dt-bindings/ion,physmem.h
b/include/dt-bindings/ion,physmem.h
new file mode 100644
index 0000000..6b24362
--- /dev/null
+++ b/include/dt-bindings/ion,physmem.h
@@ -0,0 +1,16 @@
+/*
+ * This header provides constants for ION physmem driver.
+ *
+ */
+
+#ifndef __DT_BINDINGS_ION_PHYSMEM_H
+#define __DT_BINDINGS_ION_PHYSMEM_H
+
+#define ION_HEAP_TYPE_SYSTEM 0
+#define ION_HEAP_TYPE_SYSTEM_CONTIG 1
+#define ION_HEAP_TYPE_CARVEOUT 2
+#define ION_HEAP_TYPE_CHUNK 3
+#define ION_HEAP_TYPE_DMA 4
+#define ION_HEAP_TYPE_CUSTOM 5
+
+#endif /* __DT_BINDINGS_ION_PHYSMEM_H */
These are the same as the heap types in ion.h. If they actually need to
be
the same, they should be sharing definitions. If they don't need to be
the same,
please changes the name to avoid name space collisions.
Got it, I'll make ion.h #include <dt-bindings/ion,physmem.h> then.
Thanks,
Laura
--
Regards,
Andrew
RC Module :: http://module.ru
_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel