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

Commit 6beec7d4 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm_bam_rmnet: Use Probe Method for Enumerating BAM"

parents 84d73ecf 0f002ea3
Loading
Loading
Loading
Loading
+95 −314
Original line number Original line Diff line number Diff line
@@ -31,10 +31,6 @@
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <net/pkt_sched.h>
#include <net/pkt_sched.h>


#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif

#include <soc/qcom/bam_dmux.h>
#include <soc/qcom/bam_dmux.h>


/* Debug message support */
/* Debug message support */
@@ -59,9 +55,6 @@ MODULE_PARM_DESC(msm_rmnet_bam_headroom_check_failure,
#define DBG1(x...) DBG(DEBUG_MASK_LVL1, x)
#define DBG1(x...) DBG(DEBUG_MASK_LVL1, x)
#define DBG2(x...) DBG(DEBUG_MASK_LVL2, x)
#define DBG2(x...) DBG(DEBUG_MASK_LVL2, x)


/* Configure device instances */
#define RMNET_DEVICE_COUNT  9

/* allow larger frames */
/* allow larger frames */
#define RMNET_DATA_LEN 2000
#define RMNET_DATA_LEN 2000


@@ -91,70 +84,11 @@ struct rmnet_private {
	u32 operation_mode; /* IOCTL specified mode (protocol, QoS header) */
	u32 operation_mode; /* IOCTL specified mode (protocol, QoS header) */
	uint8_t device_up;
	uint8_t device_up;
	uint8_t in_reset;
	uint8_t in_reset;
	struct platform_driver *bam_pdev;
};
};


#ifdef CONFIG_MSM_RMNET_DEBUG
#ifdef CONFIG_MSM_RMNET_DEBUG
static unsigned long timeout_us;
static unsigned long timeout_us;


#ifdef CONFIG_HAS_EARLYSUSPEND
/*
 * If early suspend is enabled then we specify two timeout values,
 * screen on (default), and screen is off.
 */
static unsigned long timeout_suspend_us;
static struct device *rmnet0;

/* Set timeout in us when the screen is off. */
static ssize_t timeout_suspend_store(struct device *d,
				     struct device_attribute *attr,
				     const char *buf, size_t n)
{
	timeout_suspend_us = strict_strtoul(buf, NULL, 10);
	return n;
}

static ssize_t timeout_suspend_show(struct device *d,
				    struct device_attribute *attr,
				    char *buf)
{
	return snprintf(buf, PAGE_SIZE, "%lu\n",
			(unsigned long) timeout_suspend_us);
}

static DEVICE_ATTR(timeout_suspend, 0664, timeout_suspend_show,
		   timeout_suspend_store);

static void rmnet_early_suspend(struct early_suspend *handler)
{
	if (rmnet0) {
		struct rmnet_private *p = netdev_priv(to_net_dev(rmnet0));
		p->timeout_us = timeout_suspend_us;
	}
}

static void rmnet_late_resume(struct early_suspend *handler)
{
	if (rmnet0) {
		struct rmnet_private *p = netdev_priv(to_net_dev(rmnet0));
		p->timeout_us = timeout_us;
	}
}

static struct early_suspend rmnet_power_suspend = {
	.suspend = rmnet_early_suspend,
	.resume = rmnet_late_resume,
};

static int __init rmnet_late_init(void)
{
	register_early_suspend(&rmnet_power_suspend);
	return 0;
}

late_initcall(rmnet_late_init);
#endif

/* Returns 1 if packet caused rmnet to wakeup, 0 otherwise. */
/* Returns 1 if packet caused rmnet to wakeup, 0 otherwise. */
static int rmnet_cause_wakeup(struct rmnet_private *p)
static int rmnet_cause_wakeup(struct rmnet_private *p)
{
{
@@ -196,13 +130,8 @@ DEVICE_ATTR(wakeups_rcv, 0444, wakeups_rcv_show, NULL);
static ssize_t timeout_store(struct device *d, struct device_attribute *attr,
static ssize_t timeout_store(struct device *d, struct device_attribute *attr,
			     const char *buf, size_t n)
			     const char *buf, size_t n)
{
{
#ifndef CONFIG_HAS_EARLYSUSPEND
	struct rmnet_private *p = netdev_priv(to_net_dev(d));
	struct rmnet_private *p = netdev_priv(to_net_dev(d));
	p->timeout_us = timeout_us = strict_strtoul(buf, NULL, 10);
	p->timeout_us = timeout_us = strict_strtoul(buf, NULL, 10);
#else
/* If using early suspend/resume hooks do not write the value on store. */
	timeout_us = strict_strtoul(buf, NULL, 10);
#endif
	return n;
	return n;
}
}


@@ -220,6 +149,7 @@ DEVICE_ATTR(timeout, 0664, timeout_show, timeout_store);


/* Forward declaration */
/* Forward declaration */
static int rmnet_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static int rmnet_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static struct platform_driver bam_rmnet_drivers[BAM_DMUX_NUM_CHANNELS];


static __be16 rmnet_ip_type_trans(struct sk_buff *skb, struct net_device *dev)
static __be16 rmnet_ip_type_trans(struct sk_buff *skb, struct net_device *dev)
{
{
@@ -426,20 +356,11 @@ static int __rmnet_open(struct net_device *dev)


	if (p->device_up == DEVICE_UNINITIALIZED) {
	if (p->device_up == DEVICE_UNINITIALIZED) {
		r = msm_bam_dmux_open(p->ch_id, dev, bam_notify);
		r = msm_bam_dmux_open(p->ch_id, dev, bam_notify);

		if (r < 0) {
		if (r < 0) {
			DBG0("%s: ch=%d failed with rc %d\n",
			DBG0("%s: ch=%d failed with rc %d\n",
					__func__, p->ch_id, r);
					__func__, p->ch_id, r);
			return -ENODEV;
			return -ENODEV;
		}
		}

		r = platform_driver_register(p->bam_pdev);
		if (r) {
			pr_err("%s: bam pdev registration failed n=%d rc=%d\n",
					__func__, p->ch_id, r);
			msm_bam_dmux_close(p->ch_id);
			return r;
		}
	}
	}


	p->device_up = DEVICE_ACTIVE;
	p->device_up = DEVICE_ACTIVE;
@@ -739,7 +660,7 @@ static int rmnet_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
	return rc;
	return rc;
}
}


static void __init rmnet_setup(struct net_device *dev)
static void rmnet_setup(struct net_device *dev)
{
{
	/* Using Ethernet mode by default */
	/* Using Ethernet mode by default */
	dev->netdev_ops = &rmnet_ops_ether;
	dev->netdev_ops = &rmnet_ops_ether;
@@ -754,307 +675,167 @@ static void __init rmnet_setup(struct net_device *dev)
	dev->watchdog_timeo = 1000; /* 10 seconds? */
	dev->watchdog_timeo = 1000; /* 10 seconds? */
}
}


static struct net_device *netdevs[RMNET_DEVICE_COUNT];
static struct net_device *netdevs[BAM_DMUX_NUM_CHANNELS];
static struct platform_driver bam_rmnet_drivers[RMNET_DEVICE_COUNT];


static int bam_rmnet_probe(struct platform_device *pdev)
#ifdef CONFIG_MSM_RMNET_DEBUG
static int rmnet_debug_init(struct net_device *dev)
{
{
	int i;
	char name[BAM_DMUX_CH_NAME_MAX_LEN];
	struct rmnet_private *p;

	for (i = 0; i < RMNET_DEVICE_COUNT; ++i) {
		scnprintf(name, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d", i);
		if (!strncmp(pdev->name, name, BAM_DMUX_CH_NAME_MAX_LEN))
			break;
	}


	if (i >= RMNET_DEVICE_COUNT) {
	struct device *d;
		pr_err("%s: wrong netdev %s\n", __func__, pdev->name);
	struct rmnet_private *p;
		return -ENODEV;
	int err = 0;
	}
	d = &(dev->dev);

	p = netdev_priv(dev);
	p = netdev_priv(netdevs[i]);
	p->timeout_us = 0;
	if (p->in_reset) {
	p->wakeups_xmit = p->wakeups_rcv = 0;
		p->in_reset = 0;
	err = device_create_file(d, &dev_attr_timeout);
		msm_bam_dmux_open(p->ch_id, netdevs[i], bam_notify);
	if (err)
		netif_carrier_on(netdevs[i]);
		return err;
		netif_start_queue(netdevs[i]);
	err = device_create_file(d, &dev_attr_wakeups_xmit);
	if (err)
		return err;
	err = device_create_file(d, &dev_attr_wakeups_rcv);
	return err;
}
}

#else
static int rmnet_debug_init(struct net_device *dev)
{
	return 0;
	return 0;
}
}
#endif


static int bam_rmnet_remove(struct platform_device *pdev)
static int bam_rmnet_probe(struct platform_device *pdev)
{
{
	int i;
	int i, ret;
	char name[BAM_DMUX_CH_NAME_MAX_LEN];
	struct rmnet_private *p;
	struct rmnet_private *p;
	struct device *d;
	char name[BAM_DMUX_CH_NAME_MAX_LEN];
	struct net_device *dev;
	const char *dev_name;


	for (i = 0; i < RMNET_DEVICE_COUNT; ++i) {
	for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
		scnprintf(name, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d", i);
		scnprintf(name, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d", i);
		if (!strncmp(pdev->name, name, BAM_DMUX_CH_NAME_MAX_LEN))
		if (!strcmp(pdev->name, name))
			break;
			break;
	}
	}


	p = netdev_priv(netdevs[i]);
	if (((i > BAM_DMUX_DATA_RMNET_7) && (i < BAM_DMUX_DATA_REV_RMNET_0)) ||
	p->in_reset = 1;
	    (i >= BAM_DMUX_NUM_CHANNELS)) {
	if (p->waiting_for_ul_skb != NULL) {
		pr_err("%s: wrong netdev %s\n", __func__, pdev->name);
		dev_kfree_skb_any(p->waiting_for_ul_skb);
		return -ENODEV;
		p->waiting_for_ul_skb = NULL;
	}
	msm_bam_dmux_close(p->ch_id);
	netif_carrier_off(netdevs[i]);
	netif_stop_queue(netdevs[i]);
	return 0;
	}
	}


/* support for 9 new rmnet ports */
	if (i <= BAM_DMUX_DATA_RMNET_7)
#define RMNET_REV_DEVICE_COUNT (9)
		dev_name = "rmnet%d";
static struct net_device *netdevs_rev[RMNET_REV_DEVICE_COUNT];
	else
static struct platform_driver bam_rmnet_rev_drivers[RMNET_REV_DEVICE_COUNT];
		dev_name = "rev_rmnet%d";


static int bam_rmnet_rev_probe(struct platform_device *pdev)
	dev = alloc_netdev(sizeof(*p), dev_name, rmnet_setup);
{
	if (!dev) {
	int i;
		pr_err("%s: no memory for netdev %d\n", __func__, i);
	char name[BAM_DMUX_CH_NAME_MAX_LEN];
		return -ENOMEM;
	struct rmnet_private *p;

	for (i = 0; i < RMNET_REV_DEVICE_COUNT; ++i) {
		scnprintf(name, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
					(i+BAM_DMUX_DATA_REV_RMNET_0));
		if (!strncmp(pdev->name, name, BAM_DMUX_CH_NAME_MAX_LEN))
			break;
	}
	}


	if (i >= RMNET_REV_DEVICE_COUNT) {
	netdevs[i] = dev;
		pr_err("%s: wrong netdev %s\n", __func__, pdev->name);
	d = &(dev->dev);
		return -ENODEV;
	p = netdev_priv(dev);
	}
	/* Initial config uses Ethernet */
	p->operation_mode = RMNET_MODE_LLP_ETH;
	p->ch_id = i;
	p->waiting_for_ul_skb = NULL;
	p->device_up = DEVICE_UNINITIALIZED;
	spin_lock_init(&p->lock);
	spin_lock_init(&p->tx_queue_lock);


	p = netdev_priv(netdevs_rev[i]);
	ret = register_netdev(dev);
	if (p->in_reset) {
	if (ret) {
		p->in_reset = 0;
		pr_err("%s: unable to register netdev %d rc=%d\n",
		msm_bam_dmux_open(p->ch_id, netdevs_rev[i], bam_notify);
			__func__, i, ret);
		netif_carrier_on(netdevs_rev[i]);
		netdevs[i] = NULL;
		netif_start_queue(netdevs_rev[i]);
		free_netdev(dev);
		return ret;
	}
	}


	rmnet_debug_init(dev);

	return 0;
	return 0;
}
}


static int bam_rmnet_rev_remove(struct platform_device *pdev)
static int bam_rmnet_remove(struct platform_device *pdev)
{
{
	int i;
	int i;
	char name[BAM_DMUX_CH_NAME_MAX_LEN];
	struct rmnet_private *p;
	struct rmnet_private *p;
	char name[BAM_DMUX_CH_NAME_MAX_LEN];


	for (i = 0; i < RMNET_REV_DEVICE_COUNT; ++i) {
	for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
		scnprintf(name, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
		scnprintf(name, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d", i);
				(i+BAM_DMUX_DATA_REV_RMNET_0));
		if (!strcmp(pdev->name, name))
		if (!strncmp(pdev->name, name, BAM_DMUX_CH_NAME_MAX_LEN))
			break;
			break;
	}
	}


	if (i >= RMNET_REV_DEVICE_COUNT) {
	if (((i > BAM_DMUX_DATA_RMNET_7) && (i < BAM_DMUX_DATA_REV_RMNET_0)) ||
	    (i >= BAM_DMUX_NUM_CHANNELS)) {
		pr_err("%s: wrong netdev %s\n", __func__, pdev->name);
		pr_err("%s: wrong netdev %s\n", __func__, pdev->name);
		return 0;
		return -ENODEV;
	}
	}


	p = netdev_priv(netdevs_rev[i]);
	p = netdev_priv(netdevs[i]);
	p->in_reset = 1;
	if (p->waiting_for_ul_skb != NULL) {
	if (p->waiting_for_ul_skb != NULL) {
		dev_kfree_skb_any(p->waiting_for_ul_skb);
		dev_kfree_skb_any(p->waiting_for_ul_skb);
		p->waiting_for_ul_skb = NULL;
		p->waiting_for_ul_skb = NULL;
	}
	}
	msm_bam_dmux_close(p->ch_id);
	msm_bam_dmux_close(p->ch_id);
	netif_carrier_off(netdevs_rev[i]);
	netif_carrier_off(netdevs[i]);
	netif_stop_queue(netdevs_rev[i]);
	netif_stop_queue(netdevs[i]);

	unregister_netdev(netdevs[i]);
	free_netdev(netdevs[i]);

	return 0;
	return 0;
}
}


#ifdef CONFIG_MSM_RMNET_DEBUG
#ifdef CONFIG_MSM_RMNET_DEBUG
#ifdef CONFIG_HAS_EARLYSUSPEND
static void rmnet_clear_timeout_us(void)
static int rmnet_debug_init_timeout_suspend(struct net_device *dev)
{
{
	struct device *d;
	timeout_us = 0;
	d = &(dev->dev);
	return device_create_file(d, &dev_attr_timeout_suspend);
}
}
#else
#else
static int rmnet_debug_init_timeout_suspend(struct net_device *dev)
static void rmnet_clear_timeout_us(void)
{
{
	return 0;
	return;
}
}
#endif
#endif /* CONFIG_MSM_RMNET_DEBUG */
static int rmnet_debug_init(struct net_device *dev)
{


	struct device *d;
	struct rmnet_private *p;
	int err = 0;
	d = &(dev->dev);
	p = netdev_priv(dev);
	p->timeout_us = 0;
	p->wakeups_xmit = p->wakeups_rcv = 0;
	err = device_create_file(d, &dev_attr_timeout);
	if (err)
		return err;
	err = device_create_file(d, &dev_attr_wakeups_xmit);
	if (err)
		return err;
	err = device_create_file(d, &dev_attr_wakeups_rcv);
	if (err)
		return err;
	err = rmnet_debug_init_timeout_suspend(dev);
	return err;
}
#else
static int rmnet_debug_init(struct net_device *dev)
{
	return 0;
}
#endif
static int __init rmnet_init(void)
static int __init rmnet_init(void)
{
{
	int ret;
	struct device *d;
	struct net_device *dev;
	struct rmnet_private *p;
	unsigned n;
	unsigned n;
	char *tempname;
	char *tempname;


	pr_info("%s: BAM devices[%d]\n", __func__, RMNET_DEVICE_COUNT);
	rmnet_clear_timeout_us();

#ifdef CONFIG_MSM_RMNET_DEBUG
	timeout_us = 0;
#ifdef CONFIG_HAS_EARLYSUSPEND
	timeout_suspend_us = 0;
#endif
#endif

	for (n = 0; n < RMNET_DEVICE_COUNT; n++) {
		const char *dev_name = "rmnet%d";

		if (n == BAM_DMUX_USB_RMNET_0)
			dev_name = "rmnet_usb%d";


		dev = alloc_netdev(sizeof(struct rmnet_private),
	n = 0;
				   dev_name, rmnet_setup);
	while (n < BAM_DMUX_NUM_CHANNELS) {

		if ((n > BAM_DMUX_DATA_RMNET_7) &&
		if (!dev) {
		    (n < BAM_DMUX_DATA_REV_RMNET_0)) {
			pr_err("%s: no memory for netdev %d\n", __func__, n);
			n++;
			return -ENOMEM;
		}

		netdevs[n] = dev;
		d = &(dev->dev);
		p = netdev_priv(dev);
		/* Initial config uses Ethernet */
		p->operation_mode = RMNET_MODE_LLP_ETH;
		p->ch_id = n;
		p->waiting_for_ul_skb = NULL;
		p->in_reset = 0;
		p->device_up = DEVICE_UNINITIALIZED;
		spin_lock_init(&p->lock);
		spin_lock_init(&p->tx_queue_lock);
#ifdef CONFIG_MSM_RMNET_DEBUG
		p->timeout_us = timeout_us;
		p->wakeups_xmit = p->wakeups_rcv = 0;
#endif

		ret = register_netdev(dev);
		if (ret) {
			pr_err("%s: unable to register netdev"
				   " %d rc=%d\n", __func__, n, ret);
			netdevs[n] = NULL;
			free_netdev(dev);
			return ret;
		}

#ifdef CONFIG_MSM_RMNET_DEBUG
		if (device_create_file(d, &dev_attr_timeout))
			continue;
			continue;
		if (device_create_file(d, &dev_attr_wakeups_xmit))
		}
			continue;
		if (device_create_file(d, &dev_attr_wakeups_rcv))
			continue;
#ifdef CONFIG_HAS_EARLYSUSPEND
		if (device_create_file(d, &dev_attr_timeout_suspend))
			continue;

		/* Only care about rmnet0 for suspend/resume tiemout hooks. */
		if (n == 0)
			rmnet0 = d;
#endif
#endif
		bam_rmnet_drivers[n].probe = bam_rmnet_probe;
		bam_rmnet_drivers[n].probe = bam_rmnet_probe;
		bam_rmnet_drivers[n].remove = bam_rmnet_remove;
		bam_rmnet_drivers[n].remove = bam_rmnet_remove;
		tempname = kmalloc(BAM_DMUX_CH_NAME_MAX_LEN, GFP_KERNEL);
		tempname = kmalloc(BAM_DMUX_CH_NAME_MAX_LEN, GFP_KERNEL);
		if (tempname == NULL) {
		if (tempname == NULL) {
			netdevs[n] = NULL;
			netdevs[n] = NULL;
			ret = -ENOMEM;
			return -ENOMEM;
			goto error;
		}
		}
		scnprintf(tempname, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
		scnprintf(tempname, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
			  n);
			  n);
		bam_rmnet_drivers[n].driver.name = tempname;
		bam_rmnet_drivers[n].driver.name = tempname;
		bam_rmnet_drivers[n].driver.owner = THIS_MODULE;
		bam_rmnet_drivers[n].driver.owner = THIS_MODULE;
		p->bam_pdev = &bam_rmnet_drivers[n];
		platform_driver_register(&bam_rmnet_drivers[n]);
		n++;
	}
	}
	/*Support for new rmnet ports */
	for (n = 0; n < RMNET_REV_DEVICE_COUNT; n++) {
		dev = alloc_netdev(sizeof(struct rmnet_private),
				   "rev_rmnet%d", rmnet_setup);

		if (!dev) {
			pr_err("%s: no memory for rev netdev %d\n",
							__func__, n);
			return -ENOMEM;
		}

		netdevs_rev[n] = dev;
		d = &(dev->dev);
		p = netdev_priv(dev);
		/* Initial config uses Ethernet */
		p->operation_mode = RMNET_MODE_LLP_ETH;
		p->ch_id = n+BAM_DMUX_DATA_REV_RMNET_0;
		p->waiting_for_ul_skb = NULL;
		p->in_reset = 0;
		p->device_up = DEVICE_UNINITIALIZED;
		spin_lock_init(&p->lock);
		spin_lock_init(&p->tx_queue_lock);


		ret = register_netdev(dev);
		if (ret) {
			pr_err("%s: unable to register rev netdev %d rc=%d\n",
							__func__, n, ret);
			netdevs_rev[n] = NULL;
			free_netdev(dev);
			return ret;
		}
		if (rmnet_debug_init(dev))
			continue;
		bam_rmnet_rev_drivers[n].probe = bam_rmnet_rev_probe;
		bam_rmnet_rev_drivers[n].remove = bam_rmnet_rev_remove;
		tempname = kmalloc(BAM_DMUX_CH_NAME_MAX_LEN, GFP_KERNEL);
		if (tempname == NULL) {
			netdevs_rev[n] = NULL;
			ret = -ENOMEM;
			goto error;
		}
		scnprintf(tempname, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
					(n+BAM_DMUX_DATA_REV_RMNET_0));
		bam_rmnet_rev_drivers[n].driver.name = tempname;
		bam_rmnet_rev_drivers[n].driver.owner = THIS_MODULE;
		p->bam_pdev = &bam_rmnet_rev_drivers[n];
	}
	return 0;
	return 0;

error:
	unregister_netdev(dev);
	free_netdev(dev);
	return ret;
}
}


module_init(rmnet_init);
module_init(rmnet_init);