soc: qcom: irq_helper: Add irq helper module
This module provides two APIs which are used to control a boolean sysfs entry deploy. The irq balancer's blacklist in user space will be controlled by this sysfs entry. CRs-Fixed: 1013201 Change-Id: Ie6ec7211c64f3c4f53b9f590e5bcf5fa1937d594 Signed-off-by: Runmin Wang <runminw@codeaurora.org>
This commit is contained in:
parent
2566204c8d
commit
2f5179d09a
3 changed files with 189 additions and 0 deletions
|
@ -374,6 +374,15 @@ config QCOM_WATCHDOG_V2
|
||||||
deadlocks. It does not run during the bootup process, so it will
|
deadlocks. It does not run during the bootup process, so it will
|
||||||
not catch any early lockups.
|
not catch any early lockups.
|
||||||
|
|
||||||
|
config QCOM_IRQ_HELPER
|
||||||
|
bool "QCOM Irq Helper"
|
||||||
|
help
|
||||||
|
This enables the irq helper module. It exposes two APIs
|
||||||
|
int irq_blacklist_on(void) and int irq_blacklist_off(void)
|
||||||
|
to other kernel module.
|
||||||
|
These two apis will be used to control the black list used
|
||||||
|
by the irq balancer.
|
||||||
|
|
||||||
config QCOM_MEMORY_DUMP
|
config QCOM_MEMORY_DUMP
|
||||||
bool "Qualcomm Memory Dump Support"
|
bool "Qualcomm Memory Dump Support"
|
||||||
help
|
help
|
||||||
|
|
|
@ -67,6 +67,7 @@ obj-$(CONFIG_QCOM_MEMORY_DUMP_V2) += memory_dump_v2.o
|
||||||
obj-$(CONFIG_QCOM_DCC) += dcc.o
|
obj-$(CONFIG_QCOM_DCC) += dcc.o
|
||||||
obj-$(CONFIG_QCOM_WATCHDOG_V2) += watchdog_v2.o
|
obj-$(CONFIG_QCOM_WATCHDOG_V2) += watchdog_v2.o
|
||||||
obj-$(CONFIG_QCOM_COMMON_LOG) += common_log.o
|
obj-$(CONFIG_QCOM_COMMON_LOG) += common_log.o
|
||||||
|
obj-$(CONFIG_QCOM_IRQ_HELPER) += irq-helper.o
|
||||||
obj-$(CONFIG_TRACER_PKT) += tracer_pkt.o
|
obj-$(CONFIG_TRACER_PKT) += tracer_pkt.o
|
||||||
obj-$(CONFIG_ICNSS) += icnss.o wlan_firmware_service_v01.o
|
obj-$(CONFIG_ICNSS) += icnss.o wlan_firmware_service_v01.o
|
||||||
obj-$(CONFIG_SOC_BUS) += socinfo.o
|
obj-$(CONFIG_SOC_BUS) += socinfo.o
|
||||||
|
|
179
drivers/soc/qcom/irq-helper.c
Normal file
179
drivers/soc/qcom/irq-helper.c
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
|
* only version 2 as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/cpu.h>
|
||||||
|
#include <linux/sysfs.h>
|
||||||
|
#include <linux/kobject.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
struct irq_helper {
|
||||||
|
bool enable;
|
||||||
|
bool deploy;
|
||||||
|
uint32_t count;
|
||||||
|
struct kobject kobj;
|
||||||
|
/* spinlock to protect reference count variable 'count' */
|
||||||
|
spinlock_t lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct irq_helper_attr {
|
||||||
|
struct attribute attr;
|
||||||
|
ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
|
||||||
|
char *buf);
|
||||||
|
size_t (*store)(struct kobject *kobj, struct attribute *attr,
|
||||||
|
const char *buf, size_t count);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IRQ_HELPER_ATTR(_name, _mode, _show, _store) \
|
||||||
|
struct irq_helper_attr irq_helper_##_name = \
|
||||||
|
__ATTR(_name, _mode, _show, _store)
|
||||||
|
|
||||||
|
#define to_irq_helper(kobj) \
|
||||||
|
container_of(kobj, struct irq_helper, kobj)
|
||||||
|
|
||||||
|
#define to_irq_helper_attr(_attr) \
|
||||||
|
container_of(_attr, struct irq_helper_attr, attr)
|
||||||
|
|
||||||
|
static ssize_t attr_show(struct kobject *kobj, struct attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct irq_helper_attr *irq_attr = to_irq_helper_attr(attr);
|
||||||
|
ssize_t ret = -EIO;
|
||||||
|
|
||||||
|
if (irq_attr->show)
|
||||||
|
ret = irq_attr->show(kobj, attr, buf);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sysfs_ops irq_helper_sysfs_ops = {
|
||||||
|
.show = attr_show,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct kobj_type irq_helper_ktype = {
|
||||||
|
.sysfs_ops = &irq_helper_sysfs_ops,
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t show_deploy(struct kobject *kobj, struct attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct irq_helper *irq = to_irq_helper(kobj);
|
||||||
|
|
||||||
|
return snprintf(buf, sizeof(irq->deploy), "%u\n", irq->deploy);
|
||||||
|
}
|
||||||
|
IRQ_HELPER_ATTR(irq_blacklist_on, 0444, show_deploy, NULL);
|
||||||
|
|
||||||
|
static struct irq_helper *irq_h;
|
||||||
|
|
||||||
|
int irq_blacklist_on(void)
|
||||||
|
{
|
||||||
|
bool flag = false;
|
||||||
|
|
||||||
|
if (!irq_h) {
|
||||||
|
pr_err("%s: init function is not called", __func__);
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
if (!irq_h->enable) {
|
||||||
|
pr_err("%s: enable bit is not set up", __func__);
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
spin_lock(&irq_h->lock);
|
||||||
|
irq_h->count++;
|
||||||
|
if (!irq_h->deploy) {
|
||||||
|
irq_h->deploy = true;
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
spin_unlock(&irq_h->lock);
|
||||||
|
if (flag)
|
||||||
|
sysfs_notify(&irq_h->kobj, NULL, "irq_blacklist_on");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(irq_blacklist_on);
|
||||||
|
|
||||||
|
int irq_blacklist_off(void)
|
||||||
|
{
|
||||||
|
bool flag = false;
|
||||||
|
|
||||||
|
if (!irq_h) {
|
||||||
|
pr_err("%s: init function is not called", __func__);
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
if (!irq_h->enable) {
|
||||||
|
pr_err("%s: enable bit is not set up", __func__);
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
spin_lock(&irq_h->lock);
|
||||||
|
if (irq_h->count == 0) {
|
||||||
|
pr_err("%s: ref-count is 0, cannot call irq blacklist off.",
|
||||||
|
__func__);
|
||||||
|
spin_unlock(&irq_h->lock);
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
irq_h->count--;
|
||||||
|
if (irq_h->count == 0) {
|
||||||
|
irq_h->deploy = false;
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
spin_unlock(&irq_h->lock);
|
||||||
|
|
||||||
|
if (flag)
|
||||||
|
sysfs_notify(&irq_h->kobj, NULL, "irq_blacklist_on");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(irq_blacklist_off);
|
||||||
|
|
||||||
|
static int __init irq_helper_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
irq_h = kzalloc(sizeof(struct irq_helper), GFP_KERNEL);
|
||||||
|
if (!irq_h)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = kobject_init_and_add(&irq_h->kobj, &irq_helper_ktype,
|
||||||
|
kernel_kobj, "%s", "irq_helper");
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s:Error in creation kobject_add\n", __func__);
|
||||||
|
goto out_free_irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sysfs_create_file(&irq_h->kobj,
|
||||||
|
&irq_helper_irq_blacklist_on.attr);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s:Error in sysfs_create_file\n", __func__);
|
||||||
|
goto out_put_kobj;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock_init(&irq_h->lock);
|
||||||
|
irq_h->count = 0;
|
||||||
|
irq_h->enable = true;
|
||||||
|
return 0;
|
||||||
|
out_put_kobj:
|
||||||
|
koject_put(&irq_h->kobj);
|
||||||
|
out_free_irq:
|
||||||
|
kfree(irq_h);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
module_init(irq_helper_init);
|
||||||
|
|
||||||
|
static void __exit irq_helper_exit(void)
|
||||||
|
{
|
||||||
|
sysfs_remove_file(&irq_h->kobj, &irq_helper_irq_blacklist_on.attr);
|
||||||
|
kobject_del(&irq_h->kobj);
|
||||||
|
kobject_put(&irq_h->kobj);
|
||||||
|
kfree(irq_h);
|
||||||
|
}
|
||||||
|
module_exit(irq_helper_exit);
|
||||||
|
MODULE_DESCRIPTION("IRQ Helper APIs");
|
Loading…
Add table
Reference in a new issue