123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937 |
- /*
- * argos.c
- *
- * Copyright (c) 2012-2023 Samsung Electronics Co., Ltd
- * http://www.samsung.com
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
- #define pr_fmt(fmt) KBUILD_MODNAME ":%s() " fmt, __func__
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/device.h>
- #include <linux/pm_qos.h>
- #include <linux/reboot.h>
- #include <linux/of.h>
- #include <linux/gfp.h>
- #include <linux/platform_device.h>
- #include <linux/delay.h>
- #include <linux/sched.h>
- #include <linux/slab.h>
- #include <linux/list.h>
- #include <linux/cpumask.h>
- #include <linux/interrupt.h>
- #ifdef CONFIG_ARGOS_THROUGHPUT
- #include <linux/miscdevice.h>
- #include <linux/fs.h>
- #include <linux/uaccess.h>
- #endif
- #if defined(CONFIG_ARCH_LAHAINA) || defined(CONFIG_ARGOS_VOTING_DDR)
- #define ARGOS_VOTING_DDR_CLK
- #include <linux/interconnect.h>
- #endif
- #if IS_ENABLED(CONFIG_CPU_FREQ_LIMIT)
- #include <linux/cpufreq.h>
- #include <linux/cpufreq_limit.h>
- #ifndef CONFIG_CPU_FREQ_LIMIT_USERSPACE
- #define DVFS_ARGOS_ID CFLM_ARGOS
- int set_freq_limit(unsigned long id, unsigned int freq);
- #endif
- #else
- #define DVFS_ARGOS_ID 0
- int set_freq_limit(unsigned long id, unsigned int freq)
- {
- pr_err("%s is not yet implemented\n", __func__);
- return 0;
- }
- #endif
- #define ARGOS_NAME "argos"
- #define TYPE_SHIFT 4
- #define TYPE_MASK_BIT ((1 << TYPE_SHIFT) - 1)
- #define LOCK_RELEASE 0
- #define FREQ_UNLOCK -1
- #define SKIP_FREQ_UPDATE 0
- #define FREQ_UPDATE 1
- #define CPU_UNLOCK_FREQ -1
- #ifdef ARGOS_VOTING_DDR_CLK
- #define DDR_UNLOCK_FREQ 0
- #endif
- //Refer to "include/dt-bindings/interconnect/qcom,lahaina.h"
- #define MASTER_APPSS_PROC 2
- #define SLAVE_EBI1 512
- #define BUS_W 4 /* SM8350 DDR Voting('w' for DDR is 4) */
- #define MHZ_TO_KBPS(mhz, w) ((uint64_t)mhz * 1000 * w)
- static DEFINE_SPINLOCK(argos_irq_lock);
- static DEFINE_SPINLOCK(argos_task_lock);
- static DEFINE_SPINLOCK(argos_boost_list_lock);
- enum {
- THRESHOLD,
- BIG_MIN_FREQ,
- BIG_MAX_FREQ,
- LITTLE_MIN_FREQ,
- LITTLE_MAX_FREQ,
- DDR_FREQ,
- RESERVED,
- TASK_AFFINITY_EN,
- IRQ_AFFINITY_EN,
- SCHED_BOOST_EN,
- ITEM_MAX,
- };
- enum {
- BOOST_CPU,
- #ifdef ARGOS_VOTING_DDR_CLK
- BOOST_DDR,
- #endif
- BOOST_MAX
- };
- struct boost_table {
- unsigned int items[ITEM_MAX];
- };
- struct argos_task_affinity {
- struct task_struct *p;
- struct cpumask *affinity_cpu_mask;
- struct cpumask *default_cpu_mask;
- struct list_head entry;
- };
- struct argos_irq_affinity {
- unsigned int irq;
- struct cpumask *affinity_cpu_mask;
- struct cpumask *default_cpu_mask;
- struct list_head entry;
- };
- struct argos {
- const char *desc;
- struct platform_device *pdev;
- struct boost_table *tables;
- int ntables;
- int prev_level;
- struct list_head task_affinity_list;
- bool task_hotplug_disable;
- struct list_head irq_affinity_list;
- bool irq_hotplug_disable;
- bool hmpboost_enable;
- bool argos_block;
- struct blocking_notifier_head argos_notifier;
- /* protect prev_level, qos, task/irq_hotplug_disable, hmpboost_enable */
- struct mutex level_mutex;
- };
- #ifdef CONFIG_ARGOS_THROUGHPUT
- #define TPUT_MAX 16
- char argos_throughput[TPUT_MAX];
- #endif
- struct argos_platform_data {
- struct argos *devices;
- struct device *dev;
- int ndevice;
- #ifndef CONFIG_ARGOS_THROUGHPUT
- struct notifier_block pm_qos_nfb;
- #endif
- int *boost_list[BOOST_MAX];
- int boost_max[BOOST_MAX];
- };
- static struct argos_platform_data *argos_pdata;
- static int boost_unlock_freq[BOOST_MAX] = {
- CPU_UNLOCK_FREQ
- #ifdef ARGOS_VOTING_DDR_CLK
- , DDR_UNLOCK_FREQ
- #endif
- };
- #ifdef ARGOS_VOTING_DDR_CLK
- struct icc_path *path_argos_bw;
- int argos_icc_register = 0;
- #endif
- static int argos_find_index(const char *label)
- {
- int i;
- int dev_num = -1;
- if (!argos_pdata) {
- pr_err("argos not initialized\n");
- return -1;
- }
- for (i = 0; i < argos_pdata->ndevice; i++)
- if (strcmp(argos_pdata->devices[i].desc, label) == 0)
- dev_num = i;
- return dev_num;
- }
- int sec_argos_register_notifier(struct notifier_block *n, char *label)
- {
- struct blocking_notifier_head *cnotifier;
- int dev_num;
- dev_num = argos_find_index(label);
- if (dev_num < 0) {
- pr_err("No match found for label: %d", dev_num);
- return -ENODEV;
- }
- cnotifier = &argos_pdata->devices[dev_num].argos_notifier;
- if (!cnotifier) {
- pr_err("argos notifier not found(dev_num:%d)\n", dev_num);
- return -ENXIO;
- }
- pr_info("%pf(dev_num:%d)\n", n->notifier_call, dev_num);
- return blocking_notifier_chain_register(cnotifier, n);
- }
- EXPORT_SYMBOL_GPL(sec_argos_register_notifier);
- int sec_argos_unregister_notifier(struct notifier_block *n, char *label)
- {
- struct blocking_notifier_head *cnotifier;
- int dev_num;
- dev_num = argos_find_index(label);
- if (dev_num < 0) {
- pr_err("No match found for label: %d", dev_num);
- return -ENODEV;
- }
- cnotifier = &argos_pdata->devices[dev_num].argos_notifier;
- if (!cnotifier) {
- pr_err("argos notifier not found(dev_num:%d)\n", dev_num);
- return -ENXIO;
- }
- pr_info("%pf(dev_num:%d)\n", n->notifier_call, dev_num);
- return blocking_notifier_chain_unregister(cnotifier, n);
- }
- EXPORT_SYMBOL_GPL(sec_argos_unregister_notifier);
- static int argos_task_affinity_setup(struct task_struct *p, int dev_num,
- struct cpumask *affinity_cpu_mask,
- struct cpumask *default_cpu_mask)
- {
- struct argos_task_affinity *this;
- struct list_head *head;
- if (!argos_pdata) {
- pr_err("argos not initialized\n");
- return -ENXIO;
- }
- if (dev_num < 0 || dev_num >= argos_pdata->ndevice) {
- pr_err("dev_num:%d should be dev_num:0 ~ %d in boundary\n",
- dev_num, argos_pdata->ndevice - 1);
- return -EINVAL;
- }
- head = &argos_pdata->devices[dev_num].task_affinity_list;
- this = kzalloc(sizeof(*this), GFP_ATOMIC);
- if (!this)
- return -ENOMEM;
- this->p = p;
- this->affinity_cpu_mask = affinity_cpu_mask;
- this->default_cpu_mask = default_cpu_mask;
- spin_lock(&argos_task_lock);
- list_add(&this->entry, head);
- spin_unlock(&argos_task_lock);
- return 0;
- }
- int argos_task_affinity_setup_label(struct task_struct *p, const char *label,
- struct cpumask *affinity_cpu_mask,
- struct cpumask *default_cpu_mask)
- {
- int dev_num;
- dev_num = argos_find_index(label);
- return argos_task_affinity_setup(p, dev_num, affinity_cpu_mask,
- default_cpu_mask);
- }
- static int argos_irq_affinity_setup(unsigned int irq, int dev_num,
- struct cpumask *affinity_cpu_mask,
- struct cpumask *default_cpu_mask)
- {
- struct argos_irq_affinity *this;
- struct list_head *head;
- if (!argos_pdata) {
- pr_err("argos not initialized\n");
- return -ENXIO;
- }
- if (dev_num < 0 || dev_num >= argos_pdata->ndevice) {
- pr_err("dev_num:%d should be dev_num:0 ~ %d in boundary\n",
- dev_num, argos_pdata->ndevice - 1);
- return -EINVAL;
- }
- head = &argos_pdata->devices[dev_num].irq_affinity_list;
- this = kzalloc(sizeof(*this), GFP_ATOMIC);
- if (!this)
- return -ENOMEM;
- this->irq = irq;
- this->affinity_cpu_mask = affinity_cpu_mask;
- this->default_cpu_mask = default_cpu_mask;
- spin_lock(&argos_irq_lock);
- list_add(&this->entry, head);
- spin_unlock(&argos_irq_lock);
- return 0;
- }
- int argos_irq_affinity_setup_label(unsigned int irq, const char *label,
- struct cpumask *affinity_cpu_mask,
- struct cpumask *default_cpu_mask)
- {
- int dev_num;
- dev_num = argos_find_index(label);
- return argos_irq_affinity_setup(irq, dev_num, affinity_cpu_mask,
- default_cpu_mask);
- }
- int argos_task_affinity_apply(int dev_num, bool enable)
- {
- struct argos_task_affinity *this;
- struct list_head *head;
- int result = 0;
- struct cpumask *mask;
- bool *hotplug_disable;
- head = &argos_pdata->devices[dev_num].task_affinity_list;
- hotplug_disable = &argos_pdata->devices[dev_num].task_hotplug_disable;
- if (list_empty(head)) {
- pr_debug("task_affinity_list is empty\n");
- return result;
- }
- list_for_each_entry(this, head, entry) {
- if (enable) {
- if (!*hotplug_disable)
- *hotplug_disable = true;
- mask = this->affinity_cpu_mask;
- } else {
- if (*hotplug_disable)
- *hotplug_disable = false;
- mask = this->default_cpu_mask;
- }
- result = set_cpus_allowed_ptr(this->p, mask);
- pr_info("%s affinity %s to cpu_mask:0x%X\n",
- this->p->comm,
- (enable ? "enable" : "disable"),
- (int)*mask->bits);
- }
- return result;
- }
- int argos_irq_affinity_apply(int dev_num, bool enable)
- {
- struct argos_irq_affinity *this;
- struct list_head *head;
- int result = 0;
- struct cpumask *mask;
- bool *hotplug_disable;
- head = &argos_pdata->devices[dev_num].irq_affinity_list;
- hotplug_disable = &argos_pdata->devices[dev_num].irq_hotplug_disable;
- if (list_empty(head)) {
- pr_debug("irq_affinity_list is empty\n");
- return result;
- }
- list_for_each_entry(this, head, entry) {
- if (enable) {
- if (!*hotplug_disable)
- *hotplug_disable = true;
- mask = this->affinity_cpu_mask;
- } else {
- if (*hotplug_disable)
- *hotplug_disable = false;
- mask = this->default_cpu_mask;
- }
- #ifndef CONFIG_ARGOS_THROUGHPUT
- result = irq_set_affinity(this->irq, mask);
- #endif
- pr_info("irq%d affinity %s to cpu_mask:0x%X\n",
- this->irq, (enable ? "enable" : "disable"),
- (int)*mask->bits);
- }
- return result;
- }
- int argos_hmpboost_apply(int dev_num, bool enable)
- {
- bool *hmpboost_enable;
- hmpboost_enable = &argos_pdata->devices[dev_num].hmpboost_enable;
- if (enable) {
- /* disable -> enable */
- if (!*hmpboost_enable) {
- *hmpboost_enable = true;
- pr_info("hmp boost enable [%d]\n", dev_num);
- }
- } else {
- /* enable -> disable */
- if (*hmpboost_enable) {
- *hmpboost_enable = false;
- pr_info("hmp boost disable [%d]\n", dev_num);
- }
- }
- return 0;
- }
- static int find_max(int dev_type, int *freq, int ndevice){
- int i, max = boost_unlock_freq[dev_type];
- for (i = 0; i < ndevice; i++){
- if(freq[i] > max) max = freq[i];
- }
- return max;
- }
- static int check_update_freq(int boost_type, int dev_type, int target)
- {
- int ret = SKIP_FREQ_UPDATE, new_max, prev;
- spin_lock(&argos_boost_list_lock);
- prev = argos_pdata->boost_list[boost_type][dev_type];
- argos_pdata->boost_list[boost_type][dev_type] = target;
- new_max = find_max(boost_type, argos_pdata->boost_list[boost_type], \
- argos_pdata->ndevice);
- spin_unlock(&argos_boost_list_lock);
- if(new_max > argos_pdata->boost_max[boost_type] \
- || (prev == argos_pdata->boost_max[boost_type] \
- && new_max != argos_pdata->boost_max[boost_type])){
- argos_pdata->boost_max[boost_type] = new_max;
- ret = FREQ_UPDATE;
- }
- return ret;
- }
- static void argos_freq_lock(int type, int level)
- {
- unsigned int big_min_freq, little_min_freq;
- int target_freq, need_update;
- struct boost_table *t = &argos_pdata->devices[type].tables[level];
- const char *cname;
- cname = argos_pdata->devices[type].desc;
- if(level != FREQ_UNLOCK){
- t = &argos_pdata->devices[type].tables[level];
- big_min_freq = t->items[BIG_MIN_FREQ];
- little_min_freq = t->items[LITTLE_MIN_FREQ];
- }
- if(level != FREQ_UNLOCK)
- target_freq = (big_min_freq > little_min_freq) ?
- big_min_freq : little_min_freq;
- else
- target_freq = boost_unlock_freq[BOOST_CPU];
- need_update = check_update_freq(BOOST_CPU, type, target_freq);
- if(need_update != SKIP_FREQ_UPDATE){
- pr_info("update cpu freq %d\n", argos_pdata->boost_max[BOOST_CPU]);
- set_freq_limit(DVFS_ARGOS_ID, argos_pdata->boost_max[BOOST_CPU]);
- }
- #ifdef ARGOS_VOTING_DDR_CLK
- if(level != FREQ_UNLOCK)
- target_freq = t->items[DDR_FREQ];
- else
- target_freq = boost_unlock_freq[BOOST_DDR];
- need_update = check_update_freq(BOOST_DDR, type, target_freq);
- if(need_update != SKIP_FREQ_UPDATE){
- pr_info("update ddr freq %d\n", argos_pdata->boost_max[BOOST_DDR]);
- icc_set_bw(path_argos_bw, 0, MHZ_TO_KBPS(argos_pdata->boost_max[BOOST_DDR], BUS_W));
- }
- #endif
- }
- void argos_block_enable(char *req_name, bool set)
- {
- int dev_num;
- struct argos *cnode;
- dev_num = argos_find_index(req_name);
- if (dev_num < 0) {
- pr_err("No match found for label: %s", req_name);
- return;
- }
- cnode = &argos_pdata->devices[dev_num];
- if (set) {
- cnode->argos_block = true;
- mutex_lock(&cnode->level_mutex);
- argos_freq_lock(dev_num, FREQ_UNLOCK);
- argos_task_affinity_apply(dev_num, 0);
- argos_irq_affinity_apply(dev_num, 0);
- argos_hmpboost_apply(dev_num, 0);
- cnode->prev_level = -1;
- mutex_unlock(&cnode->level_mutex);
- } else {
- cnode->argos_block = false;
- }
- pr_info("req_name:%s block:%d\n",
- req_name, cnode->argos_block);
- }
- #ifndef CONFIG_ARGOS_THROUGHPUT
- static int argos_cpuidle_reboot_notifier(struct notifier_block *this,
- unsigned long event, void *_cmd)
- {
- switch (event) {
- case SYSTEM_POWER_OFF:
- case SYS_RESTART:
- pr_info("called\n");
- pm_qos_remove_notifier(PM_QOS_NETWORK_THROUGHPUT,
- &argos_pdata->pm_qos_nfb);
- break;
- }
- return NOTIFY_OK;
- }
- static struct notifier_block argos_cpuidle_reboot_nb = {
- .notifier_call = argos_cpuidle_reboot_notifier,
- };
- #endif
- #ifdef ARGOS_VOTING_DDR_CLK
- static void get_icc_path(void)
- {
- struct device *dev = argos_pdata->dev;
- int bus_ret = 0;
- path_argos_bw = icc_get(dev, MASTER_APPSS_PROC, SLAVE_EBI1);
- if (IS_ERR(path_argos_bw)) {
- bus_ret = PTR_ERR(path_argos_bw);
- dev_err(dev, "Failed to get path_argos_bw. ret=%d\n", bus_ret);
- if (bus_ret != -EPROBE_DEFER)
- dev_err(dev, "Failed to get icc path. ret=%d\n", bus_ret);
- } else {
- dev_info(dev, "Success to get path_argos_bw.\n");
- argos_icc_register = 1;
- }
- }
- #endif
- #if defined (CONFIG_ARGOS_THROUGHPUT)
- static int argos_pm_qos_notify(unsigned long speedtype)
- #else
- static int argos_pm_qos_notify(struct notifier_block *nfb,
- unsigned long speedtype, void *arg)
- #endif
- {
- int type, level, prev_level;
- unsigned long speed;
- bool argos_blocked;
- struct argos *cnode;
- type = (speedtype & TYPE_MASK_BIT) - 1;
- if (type < 0 || type > argos_pdata->ndevice) {
- pr_err("There is no type for devices type[%d], ndevice[%d]\n",
- type, argos_pdata->ndevice);
- return NOTIFY_BAD;
- }
- #ifdef ARGOS_VOTING_DDR_CLK
- if (argos_icc_register == 0){
- get_icc_path();
- }
- #endif
- speed = speedtype >> TYPE_SHIFT;
- cnode = &argos_pdata->devices[type];
- prev_level = cnode->prev_level;
- argos_blocked = cnode->argos_block;
- if (cnode->tables[0].items[THRESHOLD] == 0) {
- pr_debug("skip not used name:%s, speed:%ldMbps\n",\
- cnode->desc, speed);
- goto out;
- }
- /* Find proper level */
- for (level = 0; level < cnode->ntables; level++) {
- struct boost_table *t = &cnode->tables[level];
- if (speed < t->items[THRESHOLD]) {
- break;
- } else if (argos_pdata->devices[type].ntables == level) {
- level++;
- break;
- }
- }
- /* decrease 1 level to match proper table */
- level--;
- if (!argos_blocked) {
- if (level != prev_level) {
- if (mutex_trylock(&cnode->level_mutex) == 0) {
- /*
- * If the mutex is already locked, it means this argos
- * is being blocked or is handling another change.
- * We don't need to wait.
- */
- pr_warn("skip name:%s, speed:%ldMbps, prev level:%d, request level:%d\n",
- cnode->desc, speed, prev_level, level);
- goto out;
- }
- pr_info("name:%s, speed:%ldMbps, prev level:%d, request level:%d\n",
- cnode->desc, speed, prev_level, level);
- if (level == FREQ_UNLOCK) {
- if (cnode->argos_notifier.head) {
- pr_debug("Call argos notifier(%s lev:%d)\n",
- cnode->desc, level);
- blocking_notifier_call_chain(&cnode->argos_notifier,
- speed, NULL);
- }
- argos_freq_lock(type, FREQ_UNLOCK);
- argos_task_affinity_apply(type, 0);
- argos_irq_affinity_apply(type, 0);
- argos_hmpboost_apply(type, 0);
- } else {
- unsigned int enable_flag;
- argos_freq_lock(type, level);
- /* FIXME should control affinity and hmp boost */
- enable_flag = argos_pdata->devices[type].tables[level].items[TASK_AFFINITY_EN];
- argos_task_affinity_apply(type, enable_flag);
- enable_flag = argos_pdata->devices[type].tables[level].items[IRQ_AFFINITY_EN];
- argos_irq_affinity_apply(type, enable_flag);
- enable_flag =
- argos_pdata->devices[type].tables[level].items[SCHED_BOOST_EN];
- argos_hmpboost_apply(type, enable_flag);
- if (cnode->argos_notifier.head) {
- pr_debug("Call argos notifier(%s lev:%d)\n",
- cnode->desc, level);
- blocking_notifier_call_chain(&cnode->argos_notifier,
- speed, NULL);
- }
- }
- cnode->prev_level = level;
- mutex_unlock(&cnode->level_mutex);
- } else {
- pr_debug("same level (%d) is requested", level);
- }
- }
- out:
- return NOTIFY_OK;
- }
- #ifdef CONFIG_OF
- static int argos_parse_dt(struct device *dev)
- {
- struct argos_platform_data *pdata = dev->platform_data;
- struct argos *cnode;
- struct device_node *np, *cnp;
- int device_count = 0, num_level = 0;
- int retval = 0, i, j;
- np = dev->of_node;
- pdata->ndevice = of_get_child_count(np);
- if (!pdata->ndevice)
- return -ENODEV;
- pdata->devices = devm_kzalloc(dev, sizeof(struct argos) * pdata->ndevice, GFP_KERNEL);
- if (!pdata->devices)
- return -ENOMEM;
- for_each_child_of_node(np, cnp) {
- cnode = &pdata->devices[device_count];
- cnode->desc = of_get_property(cnp, "net_boost,label", NULL);
- if (of_property_read_u32(cnp, "net_boost,table_size", &num_level)) {
- dev_err(dev, "Failed to get table size: node not exist\n");
- retval = -EINVAL;
- goto err_out;
- }
- cnode->ntables = num_level;
- /* Allocation for freq and time table */
- if (!cnode->tables) {
- cnode->tables = devm_kzalloc(dev,
- sizeof(struct boost_table) * cnode->ntables, GFP_KERNEL);
- if (!cnode->tables) {
- retval = -ENOMEM;
- goto err_out;
- }
- }
- /* Get and add frequency and time table */
- for (i = 0; i < num_level; i++) {
- for (j = 0; j < ITEM_MAX; j++) {
- retval = of_property_read_u32_index(cnp, "net_boost,table",
- i * ITEM_MAX + j, &cnode->tables[i].items[j]);
- if (retval) {
- dev_err(dev, "Failed to get property\n");
- retval = -EINVAL;
- goto err_out;
- }
- }
- }
- INIT_LIST_HEAD(&cnode->task_affinity_list);
- INIT_LIST_HEAD(&cnode->irq_affinity_list);
- cnode->task_hotplug_disable = false;
- cnode->irq_hotplug_disable = false;
- cnode->hmpboost_enable = false;
- cnode->argos_block = false;
- cnode->prev_level = -1;
- mutex_init(&cnode->level_mutex);
- BLOCKING_INIT_NOTIFIER_HEAD(&cnode->argos_notifier);
- device_count++;
- }
- return 0;
- err_out:
- return retval;
- }
- #endif
- static int argos_probe(struct platform_device *pdev)
- {
- int i, j, ret = 0;
- struct argos_platform_data *pdata;
- pr_info("Start probe\n");
- if (pdev->dev.of_node) {
- pdata = devm_kzalloc(&pdev->dev,
- sizeof(struct argos_platform_data),
- GFP_KERNEL);
- if (!pdata) {
- dev_err(&pdev->dev, "Failed to allocate platform data\n");
- return -ENOMEM;
- }
- pdev->dev.platform_data = pdata;
- ret = argos_parse_dt(&pdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "Failed to parse dt data\n");
- return ret;
- }
- pr_info("parse dt done\n");
- for(i = 0; i < BOOST_MAX; i++){
- pdata->boost_list[i] = devm_kzalloc(&pdev->dev, sizeof(int) * pdata->ndevice, GFP_KERNEL);
- if (!pdata->boost_list[i]) {
- dev_err(&pdev->dev, "Failed to allocate boosting frequency list\n");
- return -ENOMEM;
- }
- for (j = 0; j < pdata->ndevice; j++){
- pdata->boost_list[i][j] = boost_unlock_freq[i];
- }
- pdata->boost_max[i] = boost_unlock_freq[i];
- }
- } else {
- pdata = pdev->dev.platform_data;
- }
- if (!pdata) {
- dev_err(&pdev->dev, "There are no platform data\n");
- return -EINVAL;
- }
- if (!pdata->ndevice || !pdata->devices) {
- dev_err(&pdev->dev, "There are no devices\n");
- return -EINVAL;
- }
- #ifndef CONFIG_ARGOS_THROUGHPUT
- pdata->pm_qos_nfb.notifier_call = argos_pm_qos_notify;
- pm_qos_add_notifier(PM_QOS_NETWORK_THROUGHPUT, &pdata->pm_qos_nfb);
- register_reboot_notifier(&argos_cpuidle_reboot_nb);
- #endif
- argos_pdata = pdata;
- argos_pdata->dev = &pdev->dev;
- platform_set_drvdata(pdev, pdata);
- return 0;
- }
- static int argos_remove(struct platform_device *pdev)
- {
- struct argos_platform_data *pdata = platform_get_drvdata(pdev);
- if (!pdata || !argos_pdata)
- return 0;
- #ifndef CONFIG_ARGOS_THROUGHPUT
- pm_qos_remove_notifier(PM_QOS_NETWORK_THROUGHPUT, &pdata->pm_qos_nfb);
- unregister_reboot_notifier(&argos_cpuidle_reboot_nb);
- #endif
- #ifdef ARGOS_VOTING_DDR_CLK
- if (argos_icc_register == 1)
- icc_put(path_argos_bw);
- #endif
- return 0;
- }
- #ifdef CONFIG_OF
- static const struct of_device_id argos_dt_ids[] = {
- { .compatible = "samsung,argos"},
- { }
- };
- #endif
- static struct platform_driver argos_driver = {
- .driver = {
- .name = ARGOS_NAME,
- .owner = THIS_MODULE,
- #ifdef CONFIG_OF
- .of_match_table = of_match_ptr(argos_dt_ids),
- #endif
- },
- .probe = argos_probe,
- .remove = argos_remove
- };
- #ifdef CONFIG_ARGOS_THROUGHPUT
- static ssize_t argos_tput_read(struct file *filep, char __user *buf,
- size_t count, loff_t *ppos)
- {
- int ret;
- //pr_info("argos_throughput %s\n", argos_throughput);
- ret = copy_to_user(buf, (void *)argos_throughput, TPUT_MAX);
- if (ret < 0) {
- pr_err("fail to copy argos throughput value.\n");
- return -EINVAL;
- }
- return ret;
- }
- static ssize_t argos_tput_write(struct file *filep, const char __user *buf,
- size_t count, loff_t *ppos)
- {
- int ret;
- unsigned long val;
- ret = copy_from_user(argos_throughput, buf, TPUT_MAX);
- if (ret < 0) {
- pr_err("fail to get argos throughput value.\n");
- return -EINVAL;
- }
- ret = kstrtoul(argos_throughput, 16, &val);
- if (ret < 0) {
- pr_err("fail to convertet throughput unsigned long.\n");
- return -EINVAL;
- }
- argos_pm_qos_notify(val);
- //pr_info("tput : %s\n", argos_throughput);
- return count;
- }
- static const struct file_operations argos_tput_fops = {
- .owner = THIS_MODULE,
- .open = NULL,
- .read = argos_tput_read,
- .write = argos_tput_write,
- .llseek = NULL,
- };
- static struct miscdevice argos_tput_miscdev = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "network_throughput",
- .fops = &argos_tput_fops,
- };
- #endif
- static int __init argos_init(void)
- {
- int ret;
- #ifdef CONFIG_ARGOS_THROUGHPUT
- ret = misc_register(&argos_tput_miscdev);
- if (ret) {
- pr_err("Failed to register miscdevice");
- goto err;
- }
- #endif
- ret = platform_driver_register(&argos_driver);
- if (ret) {
- pr_err("Failed to register platform driver");
- goto err;
- }
- err:
- return ret;
- }
- static void __exit argos_exit(void)
- {
- return platform_driver_unregister(&argos_driver);
- }
- late_initcall(argos_init);
- module_exit(argos_exit);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("SAMSUNG Electronics");
- MODULE_DESCRIPTION("ARGOS DEVICE");
|