msm: rmnet_bam: add subsystem restart support to rmnet over bam

Change-Id: Ie56f057de7400d91c6b3e1a7563a7df0c14e3942
Signed-off-by: Jeffrey Hugo <jhugo@codeaurora.org>
diff --git a/drivers/net/msm_rmnet_bam.c b/drivers/net/msm_rmnet_bam.c
index 8a3e427..aeb85dc 100644
--- a/drivers/net/msm_rmnet_bam.c
+++ b/drivers/net/msm_rmnet_bam.c
@@ -28,6 +28,7 @@
 #include <linux/wakelock.h>
 #include <linux/if_arp.h>
 #include <linux/msm_rmnet.h>
+#include <linux/platform_device.h>
 
 #ifdef CONFIG_HAS_EARLYSUSPEND
 #include <linux/earlysuspend.h>
@@ -82,6 +83,7 @@
 	u32 operation_mode; /* IOCTL specified mode (protocol, QoS header) */
 	uint8_t device_up;
 	uint8_t waiting_for_ul;
+	uint8_t in_reset;
 };
 
 static uint8_t ul_is_connected;
@@ -618,6 +620,51 @@
 	dev->watchdog_timeo = 1000; /* 10 seconds? */
 }
 
+static struct net_device *netdevs[RMNET_DEVICE_COUNT];
+static struct platform_driver bam_rmnet_drivers[RMNET_DEVICE_COUNT];
+
+static int bam_rmnet_probe(struct platform_device *pdev)
+{
+	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;
+	}
+
+	p = netdev_priv(netdevs[i]);
+	if (p->in_reset) {
+		p->in_reset = 0;
+		msm_bam_dmux_open(p->ch_id, netdevs[i], bam_notify);
+		netif_carrier_on(netdevs[i]);
+		netif_start_queue(netdevs[i]);
+	}
+
+	return 0;
+}
+
+static int bam_rmnet_remove(struct platform_device *pdev)
+{
+	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;
+	}
+
+	p = netdev_priv(netdevs[i]);
+	p->in_reset = 1;
+	msm_bam_dmux_close(p->ch_id);
+	netif_carrier_off(netdevs[i]);
+	netif_stop_queue(netdevs[i]);
+	return 0;
+}
 
 static int __init rmnet_init(void)
 {
@@ -626,6 +673,7 @@
 	struct net_device *dev;
 	struct rmnet_private *p;
 	unsigned n;
+	char *tempname;
 
 	pr_info("%s: BAM devices[%d]\n", __func__, RMNET_DEVICE_COUNT);
 
@@ -643,12 +691,14 @@
 		if (!dev)
 			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 = 0;
+		p->in_reset = 0;
 		spin_lock_init(&p->lock);
 #ifdef CONFIG_MSM_RMNET_DEBUG
 		p->timeout_us = timeout_us;
@@ -677,6 +727,18 @@
 			rmnet0 = d;
 #endif
 #endif
+		bam_rmnet_drivers[n].probe = bam_rmnet_probe;
+		bam_rmnet_drivers[n].remove = bam_rmnet_remove;
+		tempname = kmalloc(BAM_DMUX_CH_NAME_MAX_LEN, GFP_KERNEL);
+		if (tempname == NULL)
+			return -ENOMEM;
+		scnprintf(tempname, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
+									n);
+		bam_rmnet_drivers[n].driver.name = tempname;
+		bam_rmnet_drivers[n].driver.owner = THIS_MODULE;
+		ret = platform_driver_register(&bam_rmnet_drivers[n]);
+		if (!ret)
+			return ret;
 	}
 	return 0;
 }