Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit da179ff9 authored by Sarada Prasanna Garnayak's avatar Sarada Prasanna Garnayak Committed by Gerrit - the friendly Code Review server
Browse files

cnss: register callback for the cnss bus specific export symbol



For devices with no SDIO connected, it is useless to compile/load
the cnss SDIO platform driver, same for the cnss PCIe platform driver
compile/load for the device with non PCIe interfaced wlan module.
To resolve the above issue compile the cnss SDIO/PCIe platform driver
with cnss bus specific Kconfig flag and register callback for the bus
specific API for the cnss common export symbol.

Instead of directly calling the bus specific APIs, register callback for
the bus specific API and encapsulate the callbacks in device platform_data.
Direct calling of bus specific APIs for the cnss common export symbol
is forcing to compile & load both SDIO and PCIe platform driver even the
wlan module is not interfaced with that bus.

This also helps to reduce the attack surface of kernel.

CRs-Fixed: 1104069
Change-Id: I2d95d083a968d5bd47d4c24438183d22e2ae0c1b
Signed-off-by: default avatarSarada Prasanna Garnayak <sgarna@codeaurora.org>
parent 02f0c5a1
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
# Makefile for CNSS platform driver

obj-$(CONFIG_CNSS)	+= cnss_pci.o
obj-$(CONFIG_CNSS)	+= cnss_sdio.o
obj-$(CONFIG_CNSS_LOGGER)	+= logger/

obj-$(CONFIG_CNSS_PCI)	+= cnss_pci.o
obj-$(CONFIG_CNSS_SDIO)	+= cnss_sdio.o
obj-$(CONFIG_CNSS)	+= cnss_common.o
obj-$(CONFIG_CNSS_LOGGER)	+= logger/
+46 −127
Original line number Diff line number Diff line
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2017, 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
@@ -263,186 +263,105 @@ void cnss_dump_stack(struct task_struct *task)
}
EXPORT_SYMBOL(cnss_dump_stack);

enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev)
struct cnss_dev_platform_ops *cnss_get_platform_ops(struct device *dev)
{
	if (!dev)
		return CNSS_BUS_NONE;

	if (!dev->bus)
		return CNSS_BUS_NONE;

	if (memcmp(dev->bus->name, "sdio", 4) == 0)
		return CNSS_BUS_SDIO;
	else if (memcmp(dev->bus->name, "pci", 3) == 0)
		return CNSS_BUS_PCI;
		return NULL;
	else
		return CNSS_BUS_NONE;
		return dev->platform_data;
}

int cnss_common_request_bus_bandwidth(struct device *dev, int bandwidth)
{
	int ret;

	switch (cnss_get_dev_bus_type(dev)) {
	case CNSS_BUS_SDIO:
		ret = cnss_sdio_request_bus_bandwidth(bandwidth);
		break;
	case CNSS_BUS_PCI:
		ret = cnss_pci_request_bus_bandwidth(bandwidth);
		break;
	default:
		pr_debug("%s: Invalid device type\n", __func__);
		ret = -EINVAL;
		break;
	}
	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);

	return ret;
	if (pf_ops && pf_ops->request_bus_bandwidth)
		return pf_ops->request_bus_bandwidth(bandwidth);
	else
		return -EINVAL;
}
EXPORT_SYMBOL(cnss_common_request_bus_bandwidth);

void *cnss_common_get_virt_ramdump_mem(struct device *dev, unsigned long *size)
{
	switch (cnss_get_dev_bus_type(dev)) {
	case CNSS_BUS_SDIO:
		return cnss_sdio_get_virt_ramdump_mem(size);
	case CNSS_BUS_PCI:
		return cnss_pci_get_virt_ramdump_mem(size);
	default:
		pr_debug("%s: Invalid device type\n", __func__);
	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);

	if (pf_ops && pf_ops->get_virt_ramdump_mem)
		return pf_ops->get_virt_ramdump_mem(size);
	else
		return NULL;
}
}
EXPORT_SYMBOL(cnss_common_get_virt_ramdump_mem);

void cnss_common_device_self_recovery(struct device *dev)
{
	switch (cnss_get_dev_bus_type(dev)) {
	case CNSS_BUS_SDIO:
		cnss_sdio_device_self_recovery();
		break;
	case CNSS_BUS_PCI:
		cnss_pci_device_self_recovery();
		break;
	default:
		pr_debug("%s: Invalid device type\n", __func__);
		break;
	}
	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);

	if (pf_ops && pf_ops->device_self_recovery)
		pf_ops->device_self_recovery();
}
EXPORT_SYMBOL(cnss_common_device_self_recovery);

void cnss_common_schedule_recovery_work(struct device *dev)
{
	switch (cnss_get_dev_bus_type(dev)) {
	case CNSS_BUS_SDIO:
		cnss_sdio_schedule_recovery_work();
		break;
	case CNSS_BUS_PCI:
		cnss_pci_schedule_recovery_work();
		break;
	default:
		pr_debug("%s: Invalid device type\n", __func__);
		break;
	}
	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);

	if (pf_ops && pf_ops->schedule_recovery_work)
		pf_ops->schedule_recovery_work();
}
EXPORT_SYMBOL(cnss_common_schedule_recovery_work);

void cnss_common_device_crashed(struct device *dev)
{
	switch (cnss_get_dev_bus_type(dev)) {
	case CNSS_BUS_SDIO:
		cnss_sdio_device_crashed();
		break;
	case CNSS_BUS_PCI:
		cnss_pci_device_crashed();
		break;
	default:
		pr_debug("%s: Invalid device type\n", __func__);
		break;
	}
	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);

	if (pf_ops && pf_ops->device_crashed)
		pf_ops->device_crashed();
}
EXPORT_SYMBOL(cnss_common_device_crashed);

u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num)
{
	u8 *ret;
	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);

	switch (cnss_get_dev_bus_type(dev)) {
	case CNSS_BUS_SDIO:
		ret = cnss_sdio_get_wlan_mac_address(num);
		break;
	case CNSS_BUS_PCI:
		ret = cnss_pci_get_wlan_mac_address(num);
		break;
	default:
		pr_debug("%s: Invalid device type\n", __func__);
		ret = NULL;
		break;
	}
	return ret;
	if (pf_ops && pf_ops->get_wlan_mac_address)
		return pf_ops->get_wlan_mac_address(num);
	else
		return NULL;
}
EXPORT_SYMBOL(cnss_common_get_wlan_mac_address);

int cnss_common_set_wlan_mac_address(
		struct device *dev, const u8 *in, uint32_t len)
{
	int ret;
	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);

	switch (cnss_get_dev_bus_type(dev)) {
	case CNSS_BUS_SDIO:
		ret = cnss_sdio_set_wlan_mac_address(in, len);
		break;
	case CNSS_BUS_PCI:
		ret = cnss_pcie_set_wlan_mac_address(in, len);
		break;
	default:
		pr_debug("%s: Invalid device type\n", __func__);
		ret = -EINVAL;
		break;
	}

	return ret;
	if (pf_ops && pf_ops->set_wlan_mac_address)
		return pf_ops->set_wlan_mac_address(in, len);
	else
		return -EINVAL;
}
EXPORT_SYMBOL(cnss_common_set_wlan_mac_address);

int cnss_power_up(struct device *dev)
{
	int ret;
	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);

	switch (cnss_get_dev_bus_type(dev)) {
	case CNSS_BUS_PCI:
		ret = cnss_pcie_power_up(dev);
		break;
	case CNSS_BUS_SDIO:
		ret = cnss_sdio_power_up(dev);
		break;
	default:
		pr_err("%s: Invalid Bus Type\n", __func__);
		ret = -EINVAL;
		break;
	}

	return ret;
	if (pf_ops && pf_ops->power_up)
		return pf_ops->power_up(dev);
	else
		return -EINVAL;
}
EXPORT_SYMBOL(cnss_power_up);

int cnss_power_down(struct device *dev)
{
	int ret;
	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);

	switch (cnss_get_dev_bus_type(dev)) {
	case CNSS_BUS_PCI:
		ret = cnss_pcie_power_down(dev);
		break;
	case CNSS_BUS_SDIO:
		ret = cnss_sdio_power_down(dev);
		break;
	default:
		pr_err("%s: Invalid Bus Type\n", __func__);
		ret = -EINVAL;
		break;
	}

	return ret;
	if (pf_ops && pf_ops->power_down)
		return pf_ops->power_down(dev);
	else
		return -EINVAL;
}
EXPORT_SYMBOL(cnss_power_down);

+13 −1
Original line number Diff line number Diff line
/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2017, 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
@@ -16,6 +16,18 @@
/* max 20mhz channel count */
#define CNSS_MAX_CH_NUM		45

struct cnss_dev_platform_ops {
	int (*request_bus_bandwidth)(int bandwidth);
	void* (*get_virt_ramdump_mem)(unsigned long *size);
	void (*device_self_recovery)(void);
	void (*schedule_recovery_work)(void);
	void (*device_crashed)(void);
	u8 * (*get_wlan_mac_address)(uint32_t *num);
	int (*set_wlan_mac_address)(const u8 *in, uint32_t len);
	int (*power_up)(struct device *dev);
	int (*power_down)(struct device *dev);
};

int cnss_pci_request_bus_bandwidth(int bandwidth);
int cnss_sdio_request_bus_bandwidth(int bandwidth);

+30 −1
Original line number Diff line number Diff line
/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2017, 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
@@ -288,6 +288,7 @@ static struct cnss_data {
	atomic_t auto_suspended;
	bool monitor_wake_intr;
	struct cnss_dual_wifi dual_wifi_info;
	struct cnss_dev_platform_ops platform_ops;
} *penv;

static unsigned int pcie_link_down_panic;
@@ -1608,6 +1609,31 @@ int cnss_msm_pcie_enumerate(u32 rc_idx)
}
#endif

static void cnss_pcie_set_platform_ops(struct device *dev)
{
	struct cnss_dev_platform_ops *pf_ops = &penv->platform_ops;

	pf_ops->request_bus_bandwidth = cnss_pci_request_bus_bandwidth;
	pf_ops->get_virt_ramdump_mem = cnss_pci_get_virt_ramdump_mem;
	pf_ops->device_self_recovery = cnss_pci_device_self_recovery;
	pf_ops->schedule_recovery_work = cnss_pci_schedule_recovery_work;
	pf_ops->device_crashed = cnss_pci_device_crashed;
	pf_ops->get_wlan_mac_address = cnss_pci_get_wlan_mac_address;
	pf_ops->set_wlan_mac_address = cnss_pcie_set_wlan_mac_address;
	pf_ops->power_up = cnss_pcie_power_up;
	pf_ops->power_down = cnss_pcie_power_down;

	dev->platform_data = pf_ops;
}

static void cnss_pcie_reset_platform_ops(struct device *dev)
{
	struct cnss_dev_platform_ops *pf_ops = &penv->platform_ops;

	memset(pf_ops, 0, sizeof(struct cnss_dev_platform_ops));
	dev->platform_data = NULL;
}

static int cnss_wlan_pci_probe(struct pci_dev *pdev,
			       const struct pci_device_id *id)
{
@@ -1618,6 +1644,7 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev,
	struct codeswap_codeseg_info *cnss_seg_info = NULL;
	struct device *dev = &pdev->dev;

	cnss_pcie_set_platform_ops(dev);
	penv->pdev = pdev;
	penv->id = id;
	penv->fw_available = false;
@@ -1726,6 +1753,7 @@ end_dma_alloc:
err_unknown:
err_pcie_suspend:
smmu_init_fail:
	cnss_pcie_reset_platform_ops(dev);
	return ret;
}

@@ -1737,6 +1765,7 @@ static void cnss_wlan_pci_remove(struct pci_dev *pdev)
		return;

	dev = &penv->pldev->dev;
	cnss_pcie_reset_platform_ops(dev);
	device_remove_file(dev, &dev_attr_wlan_setup);

	if (penv->smmu_mapping)
+35 −3
Original line number Diff line number Diff line
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2017, 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
@@ -112,6 +112,7 @@ static struct cnss_sdio_data {
	struct pm_qos_request qos_request;
	struct cnss_wlan_pinctrl_info pinctrl_info;
	struct cnss_sdio_bus_bandwidth bus_bandwidth;
	struct cnss_dev_platform_ops platform_ops;
} *cnss_pdata;

#define WLAN_RECOVERY_DELAY 1
@@ -685,6 +686,23 @@ int cnss_get_restart_level(void)
}
EXPORT_SYMBOL(cnss_get_restart_level);

static void cnss_sdio_set_platform_ops(struct device *dev)
{
	struct cnss_dev_platform_ops *pf_ops = &cnss_pdata->platform_ops;

	pf_ops->power_up = cnss_sdio_power_up;
	pf_ops->power_down = cnss_sdio_power_down;
	pf_ops->device_crashed = cnss_sdio_device_crashed;
	pf_ops->get_virt_ramdump_mem = cnss_sdio_get_virt_ramdump_mem;
	pf_ops->device_self_recovery = cnss_sdio_device_self_recovery;
	pf_ops->get_wlan_mac_address = cnss_sdio_get_wlan_mac_address;
	pf_ops->set_wlan_mac_address = cnss_sdio_set_wlan_mac_address;
	pf_ops->schedule_recovery_work = cnss_sdio_schedule_recovery_work;
	pf_ops->request_bus_bandwidth = cnss_sdio_request_bus_bandwidth;

	dev->platform_data = pf_ops;
}

static int cnss_sdio_wlan_inserted(struct sdio_func *func,
				   const struct sdio_device_id *id)
{
@@ -700,6 +718,7 @@ static int cnss_sdio_wlan_inserted(struct sdio_func *func,
	info->host = func->card->host;
	info->id = id;
	info->dev = &func->dev;
	cnss_sdio_set_platform_ops(info->dev);

	cnss_put_hw_resources(cnss_pdata->cnss_sdio_info.dev);

@@ -993,15 +1012,27 @@ int cnss_wlan_unregister_oob_irq_handler(void *pm_oob)
}
EXPORT_SYMBOL(cnss_wlan_unregister_oob_irq_handler);

static void cnss_sdio_reset_platform_ops(void)
{
	struct cnss_dev_platform_ops *pf_ops = &cnss_pdata->platform_ops;
	struct cnss_sdio_info *sdio_info = &cnss_pdata->cnss_sdio_info;

	memset(pf_ops, 0, sizeof(struct cnss_dev_platform_ops));
	if (sdio_info->dev)
		sdio_info->dev->platform_data = NULL;
}

static int cnss_sdio_wlan_init(void)
{
	int error = 0;

	error = sdio_register_driver(&cnss_ar6k_driver);
	if (error)
	if (error) {
		cnss_sdio_reset_platform_ops();
		pr_err("registered fail error=%d\n", error);
	else
	} else {
		pr_debug("registered success\n");
	}

	return error;
}
@@ -1011,6 +1042,7 @@ static void cnss_sdio_wlan_exit(void)
	if (!cnss_pdata)
		return;

	cnss_sdio_reset_platform_ops();
	sdio_unregister_driver(&cnss_ar6k_driver);
}