From b8963e75368763f8753b912541ee6bb58c2473d3 Mon Sep 17 00:00:00 2001 From: Victor Hsu Date: Sat, 9 Oct 2021 11:34:32 +0800 Subject: wcn6740: Add CNSS platform driver modules Bug: 202572584 Change-Id: I6e2e81606910c6fe9c179492be0b14f1819a119f --- cnss_genl/Kconfig | 9 +++ cnss_genl/Makefile | 6 ++ cnss_genl/cnss_nl.c | 229 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 244 insertions(+) create mode 100644 cnss_genl/Kconfig create mode 100644 cnss_genl/Makefile create mode 100644 cnss_genl/cnss_nl.c (limited to 'cnss_genl') diff --git a/cnss_genl/Kconfig b/cnss_genl/Kconfig new file mode 100644 index 0000000..5d87d8e --- /dev/null +++ b/cnss_genl/Kconfig @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config CNSS_GENL + tristate "CNSS Generic Netlink Socket Driver" + help + This module creates generic netlink family "CLD80211". This can be + used by cld driver and userspace utilities to communicate over + netlink sockets. This module creates different multicast groups to + facilitate the same. diff --git a/cnss_genl/Makefile b/cnss_genl/Makefile new file mode 100644 index 0000000..6ea0dfc --- /dev/null +++ b/cnss_genl/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ifeq ($(CONFIG_CNSS_OUT_OF_TREE),y) +ccflags-y += -I$(WLAN_PLATFORM_ROOT)/inc +endif +obj-$(CONFIG_CNSS_GENL) := cnss_nl.o diff --git a/cnss_genl/cnss_nl.c b/cnss_genl/cnss_nl.c new file mode 100644 index 0000000..0c67e43 --- /dev/null +++ b/cnss_genl/cnss_nl.c @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. */ + +#include +#include +#include +#include + +#define CLD80211_GENL_NAME "cld80211" + +#define CLD80211_MULTICAST_GROUP_SVC_MSGS "svc_msgs" +#define CLD80211_MULTICAST_GROUP_HOST_LOGS "host_logs" +#define CLD80211_MULTICAST_GROUP_FW_LOGS "fw_logs" +#define CLD80211_MULTICAST_GROUP_PER_PKT_STATS "per_pkt_stats" +#define CLD80211_MULTICAST_GROUP_DIAG_EVENTS "diag_events" +#define CLD80211_MULTICAST_GROUP_FATAL_EVENTS "fatal_events" +#define CLD80211_MULTICAST_GROUP_OEM_MSGS "oem_msgs" + +static const struct genl_multicast_group nl_mcgrps[] = { + [CLD80211_MCGRP_SVC_MSGS] = { .name = + CLD80211_MULTICAST_GROUP_SVC_MSGS}, + [CLD80211_MCGRP_HOST_LOGS] = { .name = + CLD80211_MULTICAST_GROUP_HOST_LOGS}, + [CLD80211_MCGRP_FW_LOGS] = { .name = + CLD80211_MULTICAST_GROUP_FW_LOGS}, + [CLD80211_MCGRP_PER_PKT_STATS] = { .name = + CLD80211_MULTICAST_GROUP_PER_PKT_STATS}, + [CLD80211_MCGRP_DIAG_EVENTS] = { .name = + CLD80211_MULTICAST_GROUP_DIAG_EVENTS}, + [CLD80211_MCGRP_FATAL_EVENTS] = { .name = + CLD80211_MULTICAST_GROUP_FATAL_EVENTS}, + [CLD80211_MCGRP_OEM_MSGS] = { .name = + CLD80211_MULTICAST_GROUP_OEM_MSGS}, +}; + +struct cld_ops { + cld80211_cb cb; + void *cb_ctx; +}; + +struct cld80211_nl_data { + struct cld_ops cld_ops[CLD80211_MAX_COMMANDS]; +}; + +static struct cld80211_nl_data nl_data; + +static inline struct cld80211_nl_data *get_local_ctx(void) +{ + return &nl_data; +} + +static struct genl_ops nl_ops[CLD80211_MAX_COMMANDS]; + +/* policy for the attributes */ +static const struct nla_policy cld80211_policy[CLD80211_ATTR_MAX + 1] = { + [CLD80211_ATTR_VENDOR_DATA] = { .type = NLA_NESTED }, + [CLD80211_ATTR_DATA] = { .type = NLA_BINARY, + .len = CLD80211_MAX_NL_DATA }, + [CLD80211_ATTR_META_DATA] = { .type = NLA_BINARY, + .len = CLD80211_MAX_NL_DATA }, + [CLD80211_ATTR_CMD] = { .type = NLA_U32 }, + [CLD80211_ATTR_CMD_TAG_DATA] = { .type = NLA_NESTED }, +}; + +static int cld80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + u8 cmd_id = ops->cmd; + struct cld80211_nl_data *nl = get_local_ctx(); + + if (cmd_id < 1 || cmd_id > CLD80211_MAX_COMMANDS) { + pr_err("CLD80211: Command Not supported: %u\n", cmd_id); + return -EOPNOTSUPP; + } + info->user_ptr[0] = nl->cld_ops[cmd_id - 1].cb; + info->user_ptr[1] = nl->cld_ops[cmd_id - 1].cb_ctx; + + return 0; +} + +/* The netlink family */ +static struct genl_family cld80211_fam __ro_after_init = { + .name = CLD80211_GENL_NAME, + .hdrsize = 0, /* no private header */ + .version = 1, /* no particular meaning now */ + .maxattr = CLD80211_ATTR_MAX, + .policy = cld80211_policy, + .netnsok = true, + .pre_doit = cld80211_pre_doit, + .post_doit = NULL, + .module = THIS_MODULE, + .ops = nl_ops, + .n_ops = ARRAY_SIZE(nl_ops), + .mcgrps = nl_mcgrps, + .n_mcgrps = ARRAY_SIZE(nl_mcgrps), +}; + +int register_cld_cmd_cb(u8 cmd_id, cld80211_cb func, void *cb_ctx) +{ + struct cld80211_nl_data *nl = get_local_ctx(); + + pr_debug("CLD80211: Registering command: %d\n", cmd_id); + if (!cmd_id || cmd_id > CLD80211_MAX_COMMANDS) { + pr_debug("CLD80211: invalid command: %d\n", cmd_id); + return -EINVAL; + } + + nl->cld_ops[cmd_id - 1].cb = func; + nl->cld_ops[cmd_id - 1].cb_ctx = cb_ctx; + + return 0; +} +EXPORT_SYMBOL(register_cld_cmd_cb); + +int deregister_cld_cmd_cb(u8 cmd_id) +{ + struct cld80211_nl_data *nl = get_local_ctx(); + + pr_debug("CLD80211: De-registering command: %d\n", cmd_id); + if (!cmd_id || cmd_id > CLD80211_MAX_COMMANDS) { + pr_debug("CLD80211: invalid command: %d\n", cmd_id); + return -EINVAL; + } + + nl->cld_ops[cmd_id - 1].cb = NULL; + nl->cld_ops[cmd_id - 1].cb_ctx = NULL; + + return 0; +} +EXPORT_SYMBOL(deregister_cld_cmd_cb); + +struct genl_family *cld80211_get_genl_family(void) +{ + return &cld80211_fam; +} +EXPORT_SYMBOL(cld80211_get_genl_family); + +static int cld80211_doit(struct sk_buff *skb, struct genl_info *info) +{ + cld80211_cb cld_cb; + void *cld_ctx; + + cld_cb = info->user_ptr[0]; + + if (!cld_cb) { + pr_err("CLD80211: Not supported\n"); + return -EOPNOTSUPP; + } + cld_ctx = info->user_ptr[1]; + + if (info->attrs[CLD80211_ATTR_VENDOR_DATA]) { + cld_cb(nla_data(info->attrs[CLD80211_ATTR_VENDOR_DATA]), + nla_len(info->attrs[CLD80211_ATTR_VENDOR_DATA]), + cld_ctx, info->snd_portid); + } else { + pr_err("CLD80211: No CLD80211_ATTR_VENDOR_DATA\n"); + return -EINVAL; + } + return 0; +} + +static int __cld80211_init(void) +{ + int err, i; + + memset(&nl_ops[0], 0, sizeof(nl_ops)); + + pr_info("CLD80211: Initializing\n"); + for (i = 0; i < CLD80211_MAX_COMMANDS; i++) { + nl_ops[i].cmd = i + 1; + nl_ops[i].doit = cld80211_doit; + nl_ops[i].flags = GENL_ADMIN_PERM; + } + + err = genl_register_family(&cld80211_fam); + if (err) { + pr_err("CLD80211: Failed to register cld80211 family: %d\n", + err); + } + + return err; +} + +static void __cld80211_exit(void) +{ + genl_unregister_family(&cld80211_fam); +} + +/** + * cld80211_is_valid_dt_node_found - Check if valid device tree node present + * + * Valid device tree node means a node with "qcom,wlan" property present and + * "status" property not disabled. + * + * Return: true if valid device tree node found, false if not found + */ +static bool cld80211_is_valid_dt_node_found(void) +{ + struct device_node *dn = NULL; + + for_each_node_with_property(dn, "qcom,wlan") { + if (of_device_is_available(dn)) + break; + } + + if (dn) + return true; + + return false; +} + +static int __init cld80211_init(void) +{ + if (!cld80211_is_valid_dt_node_found()) + return -ENODEV; + + return __cld80211_init(); +} + +static void __exit cld80211_exit(void) +{ + __cld80211_exit(); +} + +module_init(cld80211_init); +module_exit(cld80211_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("CNSS generic netlink module"); -- cgit v1.2.3