/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2010-2021. All rights reserved. * Description: common driver moudle define * Author: Hisilicon * Create: 2010-1-25 */ #include #include #include #include #include "osal_ext.h" #include "drv_base_ext.h" #include "drv_dev_ext.h" #include "drv_media_ext.h" #include "osal_comm.h" #include "drv_module.h" #include "soc_module.h" #include "drv_ioctl_module.h" #include "osal_private.h" typedef struct { unsigned int *interrupt_cpu_array; unsigned int affinity_cells; unsigned int affinity_groups; } affinity_info; static struct platform_device *g_osal_virt_dev = NULL; static affinity_info g_osal_affinity_info = {0}; /* irq: hard irq number in dts * paffinity: affinity to fill in * used by osal only * 0 on success, -x on errors */ int osal_irq_find_affinity(unsigned int irq, unsigned int *paffinity) { unsigned int affinity_cells, affinity_groups, i; if (unlikely(paffinity == NULL)) { osal_printk("paffinity is null!\n"); return -EINVAL; } if (g_osal_affinity_info.interrupt_cpu_array == NULL) { /* not exist or error */ osal_printk(KERN_DEBUG"interrupt_cpu_info was null cannot find affnity!\n"); *paffinity = OSAL_CPU_ALL; return -ENOENT; } affinity_cells = g_osal_affinity_info.affinity_cells; affinity_groups = g_osal_affinity_info.affinity_groups; for (i = 0; i < affinity_groups; i++) { /* traverse every group */ if (irq == g_osal_affinity_info.interrupt_cpu_array[i * affinity_cells]) { break; } } if (i == affinity_groups) { /* no irq in table */ osal_printk("irq:%#x was out of plan, please set affinity manually!\n", irq); *paffinity = OSAL_CPU_ALL; return -ENOENT; } *paffinity = g_osal_affinity_info.interrupt_cpu_array[i * affinity_cells + 1]; return 0; } int osal_get_irq_by_name(const char *name) { struct resource *res = NULL; if (g_osal_virt_dev == NULL) { osal_printk("%s -osal_virt_dev is not registered\n", __FUNCTION__); return -1; } if (name == NULL) { osal_printk("input module name is NULL.\n"); return -1; } res = platform_get_resource_byname(g_osal_virt_dev, IORESOURCE_IRQ, name); if (res == NULL) { osal_printk("module %s platform_get_resource_byname fail!\n", name); return -1; } return (int)res->start; } EXPORT_SYMBOL(osal_get_irq_by_name); void osal_smccc_smc(const osal_smccc_info *info, osal_smccc_res *res) { struct arm_smccc_res res_tmp = { 0 }; if (info == NULL || res == NULL) { osal_printk("osal_smccc_smc info or res null ptr\n"); return; } arm_smccc_smc(info->a0, info->a1, info->a2, info->a3, info->a4, info->a5, info->a6, info->a7, &res_tmp); res->a0 = res_tmp.a0; res->a1 = res_tmp.a1; res->a2 = res_tmp.a2; res->a3 = res_tmp.a3; } EXPORT_SYMBOL(osal_smccc_smc); static int drv_osal_virt_probe(struct platform_device *dev) { int ret; unsigned int affinity_cells; unsigned int affinity_groups; osal_printk("name:%s\n", dev->dev.of_node->name); if (strcmp(dev->dev.of_node->name, "virtdev") == 0) { g_osal_virt_dev = dev; osal_printk("virtual device initialization.1 success\n"); } else if (strcmp(dev->dev.of_node->name, "cpu_affinity") == 0) { ret = of_property_read_u32(dev->dev.of_node, "affinity-cells", &affinity_cells); if (ret != 0) { osal_printk("get affinity-cells failed\n"); return -1; } ret = of_property_read_u32(dev->dev.of_node, "affinity-size-cells", &affinity_groups); if (ret != 0) { osal_printk("get affinity-size-cells failed\n"); return -1; } g_osal_affinity_info.interrupt_cpu_array = (unsigned int *)kzalloc((affinity_cells * affinity_groups * sizeof(unsigned int)), GFP_KERNEL); if (g_osal_affinity_info.interrupt_cpu_array == NULL) { osal_printk("kzalloc interrupt cpu info failed\n"); return -1; } ret = of_property_read_u32_array(dev->dev.of_node, "interrupt_cpu", g_osal_affinity_info.interrupt_cpu_array, (affinity_cells * affinity_groups)); if (ret != 0) { osal_printk("get interrupt_cpu info failed\n"); kfree(g_osal_affinity_info.interrupt_cpu_array); g_osal_affinity_info.interrupt_cpu_array = NULL; return -1; } g_osal_affinity_info.affinity_cells = affinity_cells; g_osal_affinity_info.affinity_groups = affinity_groups; osal_printk("virtual device initialization.2 success\n"); } return 0; } static int drv_osal_virt_remove(struct platform_device *dev) { if ((strcmp(dev->dev.of_node->name, "cpu_affinity") == 0) && (g_osal_affinity_info.interrupt_cpu_array != NULL)) { kfree(g_osal_affinity_info.interrupt_cpu_array); g_osal_affinity_info.interrupt_cpu_array = NULL; } return 0; } static const struct of_device_id g_osal_virt_dev_match[] __maybe_unused = { { .compatible = "virt-device", }, { .compatible = "cpu_affinity", }, {}, }; MODULE_DEVICE_TABLE(of, g_osal_virt_dev_match); struct platform_driver g_osal_virt_platform_drv = { .probe = drv_osal_virt_probe, .remove = drv_osal_virt_remove, .driver = { .name = "virt-device", .owner = THIS_MODULE, .of_match_table = of_match_ptr(g_osal_virt_dev_match), }, }; static int ext_drv_osal_init(void) { int ret; ret = platform_driver_register(&g_osal_virt_platform_drv); if (ret != 0) { osal_printk("register driver failed\n"); return -1; } ret = drv_pm_mod_init(); if (ret != TD_SUCCESS) { osal_printk("drv_pm_mod_init failed:%#x!\n", ret); goto exit_platform; } return TD_SUCCESS; exit_platform: platform_driver_unregister(&g_osal_virt_platform_drv); return ret; } static void ext_drv_osal_exit(void) { platform_driver_unregister(&g_osal_virt_platform_drv); drv_pm_mod_exit(); return; } static int osal_drv_open(void *private_data) { osal_printk("osal open\n"); return 0; } static int osal_drv_close(void *private_data) { osal_printk("osal close\n"); return 0; } static osal_fileops g_osal_module_fops = { .open = osal_drv_open, .release = osal_drv_close, .cmd_list = NULL, .cmd_cnt = 0, }; static osal_dev g_osal_dev = { .name = SOC_DEV_OSAL_NAME, .minor = SOC_DEV_OSAL_MINOR, .fops = &g_osal_module_fops, }; static int drv_osal_dev_register(void) { int ret; ret = osal_dev_register(&g_osal_dev); if (ret != 0) { osal_printk("register device failed\n"); return -1; } return 0; } static void drv_osal_dev_unregister(void) { osal_dev_unregister(&g_osal_dev); } int drv_osal_module_init(void) { int ret; drv_module_init(); ret = ext_drv_osal_init(); if (ret != 0) { osal_printk("common init failed\n"); goto err_module_exit; } ret = drv_osal_dev_register(); if (ret != 0) { osal_printk("dev register failed\n"); goto err_osal_exit; } #ifndef SOCT_FPGA_SUPPORT ret = ext_drv_bus_clock_init(); if (ret != 0) { osal_printk("init bus clock failed\n"); goto err_osal_unregister; } #endif #ifdef MODULE osal_printk("Load osal_ext.ko success.\n"); #endif return 0; #ifndef SOCT_FPGA_SUPPORT err_osal_unregister: drv_osal_dev_unregister(); #endif err_osal_exit: ext_drv_osal_exit(); err_module_exit: drv_module_exit(); return -1; } void drv_osal_module_exit(void) { drv_osal_dev_unregister(); drv_module_exit(); ext_drv_osal_exit(); #ifndef SOCT_FPGA_SUPPORT ext_drv_bus_clock_deinit(); #endif osal_printk("remove osal_ext.ko success.\n"); return; } #ifdef MODULE module_init(drv_osal_module_init); module_exit(drv_osal_module_exit); #else soc_initcall(drv_osal_module_init); #endif MODULE_AUTHOR("HUANGLONG"); MODULE_LICENSE("GPL");