Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dmaengine: qcom_hidma: add support for object hierarchy

In order to create a relationship model between the channels and the
management object, we are adding support for object hierarchy to the
drivers. This patch simplifies the userspace application development.
We will not have to traverse different firmware paths based on device
tree or ACPI based kernels.

No matter what flavor of kernel is used, objects will be represented as
platform devices.

The new layout is as follows:

hidmam_10: hidma-mgmt@0x5A000000 {
compatible = "qcom,hidma-mgmt-1.0";
...

hidma_10: hidma@0x5a010000 {
compatible = "qcom,hidma-1.0";
...
}
}

The hidma_mgmt_init detects each instance of the hidma-mgmt-1.0 objects
in device tree and calls into the channel driver to create platform devices
for each child of the management object.

Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>

authored by

Sinan Kaya and committed by
Vinod Koul
42d236f8 570d0176

+156 -5
+9
Documentation/ABI/testing/sysfs-platform-hidma
··· 1 + What: /sys/devices/platform/hidma-*/chid 2 + /sys/devices/platform/QCOM8061:*/chid 3 + Date: Dec 2015 4 + KernelVersion: 4.4 5 + Contact: "Sinan Kaya <okaya@cudeaurora.org>" 6 + Description: 7 + Contains the ID of the channel within the HIDMA instance. 8 + It is used to associate a given HIDMA channel with the 9 + priority and weight calls in the management interface.
+38 -1
drivers/dma/qcom/hidma.c
··· 530 530 return hidma_ll_inthandler(chirq, lldev); 531 531 } 532 532 533 + static ssize_t hidma_show_values(struct device *dev, 534 + struct device_attribute *attr, char *buf) 535 + { 536 + struct platform_device *pdev = to_platform_device(dev); 537 + struct hidma_dev *mdev = platform_get_drvdata(pdev); 538 + 539 + buf[0] = 0; 540 + 541 + if (strcmp(attr->attr.name, "chid") == 0) 542 + sprintf(buf, "%d\n", mdev->chidx); 543 + 544 + return strlen(buf); 545 + } 546 + 547 + static int hidma_create_sysfs_entry(struct hidma_dev *dev, char *name, 548 + int mode) 549 + { 550 + struct device_attribute *attrs; 551 + char *name_copy; 552 + 553 + attrs = devm_kmalloc(dev->ddev.dev, sizeof(struct device_attribute), 554 + GFP_KERNEL); 555 + if (!attrs) 556 + return -ENOMEM; 557 + 558 + name_copy = devm_kstrdup(dev->ddev.dev, name, GFP_KERNEL); 559 + if (!name_copy) 560 + return -ENOMEM; 561 + 562 + attrs->attr.name = name_copy; 563 + attrs->attr.mode = mode; 564 + attrs->show = hidma_show_values; 565 + sysfs_attr_init(&attrs->attr); 566 + 567 + return device_create_file(dev->ddev.dev, attrs); 568 + } 569 + 533 570 static int hidma_probe(struct platform_device *pdev) 534 571 { 535 572 struct hidma_dev *dmadev; ··· 682 645 dmadev->irq = chirq; 683 646 tasklet_init(&dmadev->task, hidma_issue_task, (unsigned long)dmadev); 684 647 hidma_debug_init(dmadev); 648 + hidma_create_sysfs_entry(dmadev, "chid", S_IRUGO); 685 649 dev_info(&pdev->dev, "HI-DMA engine driver registration complete\n"); 686 650 platform_set_drvdata(pdev, dmadev); 687 651 pm_runtime_mark_last_busy(dmadev->ddev.dev); ··· 730 692 {.compatible = "qcom,hidma-1.0",}, 731 693 {}, 732 694 }; 733 - 734 695 MODULE_DEVICE_TABLE(of, hidma_match); 735 696 736 697 static struct platform_driver hidma_driver = {
+109 -4
drivers/dma/qcom/hidma_mgmt.c
··· 1 1 /* 2 2 * Qualcomm Technologies HIDMA DMA engine Management interface 3 3 * 4 - * Copyright (c) 2015, The Linux Foundation. All rights reserved. 4 + * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. 5 5 * 6 6 * This program is free software; you can redistribute it and/or modify 7 7 * it under the terms of the GNU General Public License version 2 and ··· 17 17 #include <linux/acpi.h> 18 18 #include <linux/of.h> 19 19 #include <linux/property.h> 20 - #include <linux/interrupt.h> 21 - #include <linux/platform_device.h> 20 + #include <linux/of_irq.h> 21 + #include <linux/of_platform.h> 22 22 #include <linux/module.h> 23 23 #include <linux/uaccess.h> 24 24 #include <linux/slab.h> 25 25 #include <linux/pm_runtime.h> 26 26 #include <linux/bitops.h> 27 + #include <linux/dma-mapping.h> 27 28 28 29 #include "hidma_mgmt.h" 29 30 ··· 299 298 }, 300 299 }; 301 300 302 - module_platform_driver(hidma_mgmt_driver); 301 + #if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) 302 + static int object_counter; 303 + 304 + static int __init hidma_mgmt_of_populate_channels(struct device_node *np) 305 + { 306 + struct platform_device *pdev_parent = of_find_device_by_node(np); 307 + struct platform_device_info pdevinfo; 308 + struct of_phandle_args out_irq; 309 + struct device_node *child; 310 + struct resource *res; 311 + const __be32 *cell; 312 + int ret = 0, size, i, num; 313 + u64 addr, addr_size; 314 + 315 + for_each_available_child_of_node(np, child) { 316 + struct resource *res_iter; 317 + struct platform_device *new_pdev; 318 + 319 + cell = of_get_property(child, "reg", &size); 320 + if (!cell) { 321 + ret = -EINVAL; 322 + goto out; 323 + } 324 + 325 + size /= sizeof(*cell); 326 + num = size / 327 + (of_n_addr_cells(child) + of_n_size_cells(child)) + 1; 328 + 329 + /* allocate a resource array */ 330 + res = kcalloc(num, sizeof(*res), GFP_KERNEL); 331 + if (!res) { 332 + ret = -ENOMEM; 333 + goto out; 334 + } 335 + 336 + /* read each reg value */ 337 + i = 0; 338 + res_iter = res; 339 + while (i < size) { 340 + addr = of_read_number(&cell[i], 341 + of_n_addr_cells(child)); 342 + i += of_n_addr_cells(child); 343 + 344 + addr_size = of_read_number(&cell[i], 345 + of_n_size_cells(child)); 346 + i += of_n_size_cells(child); 347 + 348 + res_iter->start = addr; 349 + res_iter->end = res_iter->start + addr_size - 1; 350 + res_iter->flags = IORESOURCE_MEM; 351 + res_iter++; 352 + } 353 + 354 + ret = of_irq_parse_one(child, 0, &out_irq); 355 + if (ret) 356 + goto out; 357 + 358 + res_iter->start = irq_create_of_mapping(&out_irq); 359 + res_iter->name = "hidma event irq"; 360 + res_iter->flags = IORESOURCE_IRQ; 361 + 362 + memset(&pdevinfo, 0, sizeof(pdevinfo)); 363 + pdevinfo.fwnode = &child->fwnode; 364 + pdevinfo.parent = pdev_parent ? &pdev_parent->dev : NULL; 365 + pdevinfo.name = child->name; 366 + pdevinfo.id = object_counter++; 367 + pdevinfo.res = res; 368 + pdevinfo.num_res = num; 369 + pdevinfo.data = NULL; 370 + pdevinfo.size_data = 0; 371 + pdevinfo.dma_mask = DMA_BIT_MASK(64); 372 + new_pdev = platform_device_register_full(&pdevinfo); 373 + if (!new_pdev) { 374 + ret = -ENODEV; 375 + goto out; 376 + } 377 + of_dma_configure(&new_pdev->dev, child); 378 + 379 + kfree(res); 380 + res = NULL; 381 + } 382 + out: 383 + kfree(res); 384 + 385 + return ret; 386 + } 387 + #endif 388 + 389 + static int __init hidma_mgmt_init(void) 390 + { 391 + #if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) 392 + struct device_node *child; 393 + 394 + for (child = of_find_matching_node(NULL, hidma_mgmt_match); child; 395 + child = of_find_matching_node(child, hidma_mgmt_match)) { 396 + /* device tree based firmware here */ 397 + hidma_mgmt_of_populate_channels(child); 398 + of_node_put(child); 399 + } 400 + #endif 401 + platform_driver_register(&hidma_mgmt_driver); 402 + 403 + return 0; 404 + } 405 + module_init(hidma_mgmt_init); 303 406 MODULE_LICENSE("GPL v2");