[svn-commits] rmeyerriecks: linux/trunk r9998 - in /linux/trunk/drivers/dahdi: voicebus/ wc...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Jun 28 17:29:04 CDT 2011


Author: rmeyerriecks
Date: Tue Jun 28 17:29:00 2011
New Revision: 9998

URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=9998
Log:
wcte12xp, wctdm24xxp: Load VPMOCT032 firmware in background.

The firmware load has been moved into a workqueue to prevent the module load
from blocking for the duration of the firmware upload. This could be up to 40
seconds. Driver prevents configuration until firmware load is finished and
is_initialized() returns true.

Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>
Signed-off-by: Shaun Ruffell <sruffell at digium.com>

Modified:
    linux/trunk/drivers/dahdi/voicebus/vpmoct.c
    linux/trunk/drivers/dahdi/voicebus/vpmoct.h
    linux/trunk/drivers/dahdi/wctdm24xxp/base.c
    linux/trunk/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
    linux/trunk/drivers/dahdi/wctdm24xxp/xhfc.c
    linux/trunk/drivers/dahdi/wcte12xp/base.c
    linux/trunk/drivers/dahdi/wcte12xp/wcte12xp.h

Modified: linux/trunk/drivers/dahdi/voicebus/vpmoct.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/voicebus/vpmoct.c?view=diff&rev=9998&r1=9997&r2=9998
==============================================================================
--- linux/trunk/drivers/dahdi/voicebus/vpmoct.c (original)
+++ linux/trunk/drivers/dahdi/voicebus/vpmoct.c Tue Jun 28 17:29:00 2011
@@ -23,6 +23,7 @@
  */
 
 #include <linux/jiffies.h>
+#include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/crc32.h>
 
@@ -291,9 +292,36 @@
 	return -1;
 }
 
+/**
+ * vpmoct_get_mode - Return the current operating mode of the VPMOCT032.
+ * @vpm:	The vpm to query.
+ *
+ * Will be either BOOTLOADER, APPLICATION, or UNKNOWN.
+ *
+ */
+static enum vpmoct_mode vpmoct_get_mode(struct vpmoct *vpm)
+{
+	int i;
+	enum vpmoct_mode ret = UNKNOWN;
+	char identifier[11] = {0};
+
+	for (i = 0; i < ARRAY_SIZE(identifier) - 1; i++)
+		identifier[i] = vpmoct_read_byte(vpm, VPMOCT_IDENT+i);
+
+	if (!memcmp(identifier, "bootloader", sizeof(identifier) - 1))
+		ret = BOOTLOADER;
+	else if (!memcmp(identifier, "VPMOCT032\0", sizeof(identifier) - 1))
+		ret = APPLICATION;
+
+	dev_dbg(vpm->dev, "vpmoct identifier: %s\n", identifier);
+	return ret;
+}
+
+
 static inline short
 vpmoct_check_firmware_crc(struct vpmoct *vpm, size_t size, u8 major, u8 minor)
 {
+	short ret = 0;
 	u8 status;
 
 	/* Load firmware size */
@@ -311,15 +339,29 @@
 		dev_info(vpm->dev,
 			 "vpmoct firmware CRC check failed: %x\n", status);
 		/* TODO: Try the load again */
-		return -1;
+		ret = -1;
 	} else {
-		dev_info(vpm->dev, "vpmoct firmware uploaded successfully\n");
+
 		/* Switch to application code */
 		vpmoct_write_dword(vpm, VPMOCT_BOOT_ADDRESS2, 0xDEADBEEF);
-		/* Soft reset the processor */
 		vpmoct_write_byte(vpm, VPMOCT_BOOT_CMD, VPMOCT_BOOT_REBOOT);
-		return 0;
-	}
+
+		msleep(250);
+		status = vpmoct_resync(vpm);
+
+		if (APPLICATION != vpmoct_get_mode(vpm)) {
+			dev_info(vpm->dev,
+				 "vpmoct firmware failed to switch to "
+				 "application. (%x)\n", status);
+			ret = -1;
+		} else {
+			vpm->mode = APPLICATION;
+			dev_info(vpm->dev,
+				 "vpmoct firmware uploaded successfully\n");
+		}
+	}
+
+	return ret;
 }
 
 static inline short vpmoct_switch_to_boot(struct vpmoct *vpm)
@@ -330,8 +372,60 @@
 		dev_info(vpm->dev, "Failed to switch to bootloader\n");
 		return -1;
 	}
-	vpm->mode = VPMOCT_MODE_BOOTLOADER;
+	vpm->mode = BOOTLOADER;
 	return 0;
+}
+
+struct vpmoct_load_work {
+	struct vpmoct *vpm;
+	struct work_struct work;
+	struct workqueue_struct *wq;
+	load_complete_func_t load_complete;
+	bool operational;
+};
+
+/**
+ * vpmoct_load_complete_fn -
+ *
+ * This function should run in the context of one of the system workqueues so
+ * that it can destroy any workqueues that may have been created to setup a
+ * long running firmware load.
+ *
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void vpmoct_load_complete_fn(void *data)
+{
+	struct vpmoct_load_work *work = data;
+#else
+static void vpmoct_load_complete_fn(struct work_struct *data)
+{
+	struct vpmoct_load_work *work =
+			container_of(data, struct vpmoct_load_work, work);
+#endif
+	/* Do not touch work->vpm after calling load complete. It may have
+	 * been freed in the function by the board driver. */
+	work->load_complete(work->vpm->dev, work->operational);
+	destroy_workqueue(work->wq);
+	kfree(work);
+}
+
+/**
+ * vpmoct_load_complete - Call the load_complete function in a system workqueue.
+ * @work:
+ * @operational:	Whether the VPM is functioning or not.
+ *
+ */
+static void
+vpmoct_load_complete(struct vpmoct_load_work *work, bool operational)
+{
+	work->operational = operational;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+	INIT_WORK(&work->work, vpmoct_load_complete_fn, work);
+#else
+	INIT_WORK(&work->work, vpmoct_load_complete_fn);
+#endif
+	schedule_work(&work->work);
 }
 
 static bool is_valid_vpmoct_firmware(const struct firmware *fw)
@@ -353,38 +447,38 @@
  * vpmoct_load_flash - Check the current flash version and possibly load.
  * @vpm:  The VPMOCT032 module to check / load.
  *
- * Returns 0 on success, otherwise an error message.
- *
- * Must be called in process context.
- *
  */
-static int vpmoct_load_flash(struct vpmoct *vpm)
-{
-	int firm;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void vpmoct_load_flash(void *data)
+{
+	struct vpmoct_load_work *work = data;
+#else
+static void vpmoct_load_flash(struct work_struct *data)
+{
+	struct vpmoct_load_work *work =
+			container_of(data, struct vpmoct_load_work, work);
+#endif
+	int res;
+	struct vpmoct *const vpm = work->vpm;
 	const struct firmware *fw;
 	const struct vpmoct_header *header;
 	char serial[VPMOCT_SERIAL_SIZE+1];
 	const char *const FIRMWARE_NAME = "dahdi-fw-vpmoct032.bin";
 	int i;
 
-	/* Load the firmware */
-	firm = request_firmware(&fw, FIRMWARE_NAME, vpm->dev);
-	if (firm) {
-		dev_info(vpm->dev, "vpmoct: Failed to load firmware from"\
-				" userspace!, %d\n", firm);
-		return -ENOMEM;
-	}
-
-	if (!is_valid_vpmoct_firmware(fw)) {
+	res = request_firmware(&fw, FIRMWARE_NAME, vpm->dev);
+	if (res) {
 		dev_warn(vpm->dev,
-			 "%s is invalid. Please reinstall.\n", FIRMWARE_NAME);
-		release_firmware(fw);
-		return -EINVAL;
-	}
-
-	header = (const struct vpmoct_header *)fw->data;
-
-	if (vpm->mode == VPMOCT_MODE_APPLICATION) {
+			 "vpmoct: Failed to load firmware from userspace! %d\n",
+			 res);
+		header = NULL;
+		fw = NULL;
+	} else {
+		header = (const struct vpmoct_header *)fw->data;
+	}
+
+	if (vpm->mode == APPLICATION) {
+
 		/* Check the running application firmware
 		 * for the proper version */
 		vpm->major = vpmoct_read_byte(vpm, VPMOCT_MAJOR);
@@ -393,16 +487,37 @@
 			serial[i] = vpmoct_read_byte(vpm, VPMOCT_SERIAL+i);
 		serial[VPMOCT_SERIAL_SIZE] = '\0';
 
-		dev_info(vpm->dev, "vpmoct: Detected firmware v%d.%d\n",
-				vpm->major, vpm->minor);
-		dev_info(vpm->dev, "vpmoct: Serial %s\n", serial);
+		dev_info(vpm->dev,
+			 "vpmoct: Detected firmware v%d.%d Serial: %s\n",
+			 vpm->major, vpm->minor,
+			 (serial[0] != -1) ? serial : "(None)");
+
+		if (!fw) {
+			/* Again, we'll use the existing loaded firmware. */
+			vpmoct_set_defaults(vpm);
+			vpmoct_load_complete(work, true);
+			return;
+		}
+
+		if (!is_valid_vpmoct_firmware(fw)) {
+			dev_warn(vpm->dev,
+				 "%s is invalid. Please reinstall.\n",
+				 FIRMWARE_NAME);
+
+			/* Just use the old version of the fimware. */
+			release_firmware(fw);
+			vpmoct_set_defaults(vpm);
+			vpmoct_load_complete(work, true);
+			return;
+		}
 
 		if (vpm->minor == header->minor &&
 		    vpm->major == header->major) {
 			/* Proper version is running */
 			release_firmware(fw);
 			vpmoct_set_defaults(vpm);
-			return 0;
+			vpmoct_load_complete(work, true);
+			return;
 		} else {
 
 			/* Incorrect version of application code is
@@ -410,6 +525,15 @@
 			if (vpmoct_switch_to_boot(vpm))
 				goto error;
 		}
+	}
+
+	if (!fw) {
+		vpmoct_load_complete(work, false);
+		return;
+	} else if (!is_valid_vpmoct_firmware(fw)) {
+		dev_warn(vpm->dev,
+			 "%s is invalid. Please reinstall.\n", FIRMWARE_NAME);
+		goto error;
 	}
 
 	dev_info(vpm->dev, "vpmoct: Uploading firmware, v%d.%d. This can "\
@@ -426,12 +550,15 @@
 		goto error;
 	release_firmware(fw);
 	vpmoct_set_defaults(vpm);
-	return 0;
+	vpmoct_load_complete(work, true);
+	return;
 
 error:
 	dev_info(vpm->dev, "Unable to load firmware\n");
 	release_firmware(fw);
-	return -1;
+	/* TODO: Should we disable module if the firmware doesn't load? */
+	vpmoct_load_complete(work, false);
+	return;
 }
 
 struct vpmoct *vpmoct_alloc(void)
@@ -452,44 +579,82 @@
 
 void vpmoct_free(struct vpmoct *vpm)
 {
+	unsigned long flags;
+	struct vpmoct_cmd *cmd;
+	LIST_HEAD(list);
+
+	if (!vpm)
+		return;
+
+	spin_lock_irqsave(&vpm->list_lock, flags);
+	list_splice(&vpm->active_list, &list);
+	list_splice(&vpm->pending_list, &list);
+	spin_unlock_irqrestore(&vpm->list_lock, flags);
+
+	while (!list_empty(&list)) {
+		cmd = list_entry(list.next, struct vpmoct_cmd, node);
+		list_del(&cmd->node);
+		kfree(cmd);
+	}
+
 	kfree(vpm);
 }
 EXPORT_SYMBOL(vpmoct_free);
 
 /**
  * vpmoct_init - Check for / initialize VPMOCT032 module.
- * @vpm:	struct vpmoct allocated with vpmoct_alloc
- *
- * Returns 0 on success or an error code.
+ * @vpm:		struct vpmoct allocated with vpmoct_alloc
+ * @load_complete_fn:	Function to call when the load is complete.
+ *
+ * Check to see if there is a VPMOCT module installed. If there appears to be
+ * one return 0 and perform any necessary setup in the background. The
+ * load_complete function will be called in a system global workqueue when the
+ * initialization is complete.
  *
  * Must be called in process context.
  */
-int vpmoct_init(struct vpmoct *vpm)
-{
-	unsigned int i;
-	char identifier[10];
-
-	if (vpmoct_resync(vpm))
+int vpmoct_init(struct vpmoct *vpm, load_complete_func_t load_complete)
+{
+	struct vpmoct_load_work *work;
+
+	if (!vpm || !vpm->dev || !load_complete)
+		return -EINVAL;
+
+	if (vpmoct_resync(vpm)) {
+		load_complete(vpm->dev, false);
 		return -ENODEV;
-
-	/* Probe for vpmoct ident string */
-	for (i = 0; i < ARRAY_SIZE(identifier); i++)
-		identifier[i] = vpmoct_read_byte(vpm, VPMOCT_IDENT+i);
-
-	if (!memcmp(identifier, "bootloader", sizeof(identifier))) {
-		/* vpmoct is in bootloader mode */
-		dev_info(vpm->dev, "Detected vpmoct bootloader, attempting "\
-				"to load firmware\n");
-		vpm->mode = VPMOCT_MODE_BOOTLOADER;
-		return vpmoct_load_flash(vpm);
-	} else if (!memcmp(identifier, "VPMOCT032\0", sizeof(identifier))) {
-		/* vpmoct is in application mode */
-		vpm->mode = VPMOCT_MODE_APPLICATION;
-		return vpmoct_load_flash(vpm);
-	} else {
-		/* No vpmoct is installed */
+	}
+
+	vpm->mode = vpmoct_get_mode(vpm);
+
+	if (UNKNOWN == vpm->mode) {
+		load_complete(vpm->dev, false);
 		return -ENODEV;
 	}
+
+	work = kzalloc(sizeof(*work), GFP_KERNEL);
+	if (!work) {
+		load_complete(vpm->dev, false);
+		return -ENOMEM;
+	}
+
+	work->wq = create_singlethread_workqueue("vpmoct");
+	if (!work->wq) {
+		kfree(work);
+		load_complete(vpm->dev, false);
+		return -ENOMEM;
+	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+	INIT_WORK(&work->work, vpmoct_load_flash, work);
+#else
+	INIT_WORK(&work->work, vpmoct_load_flash);
+#endif
+
+	work->vpm = vpm;
+	work->load_complete = load_complete;
+	queue_work(work->wq, &work->work);
+	return 0;
 }
 EXPORT_SYMBOL(vpmoct_init);
 

Modified: linux/trunk/drivers/dahdi/voicebus/vpmoct.h
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/voicebus/vpmoct.h?view=diff&rev=9998&r1=9997&r2=9998
==============================================================================
--- linux/trunk/drivers/dahdi/voicebus/vpmoct.h (original)
+++ linux/trunk/drivers/dahdi/voicebus/vpmoct.h Tue Jun 28 17:29:00 2011
@@ -61,15 +61,14 @@
 #define VPMOCT_BOOT_ADDRESS2 0x1c
 #define VPMOCT_BOOT_RAM 0x20
 
-#define VPMOCT_MODE_BOOTLOADER  0
-#define VPMOCT_MODE_APPLICATION 1
+enum vpmoct_mode { UNKNOWN = 0, APPLICATION, BOOTLOADER };
 
 struct vpmoct {
 	struct list_head pending_list;
 	struct list_head active_list;
 	spinlock_t list_lock;
 	struct mutex mutex;
-	unsigned short int mode;
+	enum vpmoct_mode mode;
 	struct device *dev;
 	u32 companding;
 	u32 echo;
@@ -99,7 +98,8 @@
 
 struct vpmoct *vpmoct_alloc(void);
 void vpmoct_free(struct vpmoct *vpm);
-int vpmoct_init(struct vpmoct *vpm);
+typedef void (*load_complete_func_t)(struct device *dev, bool operational);
+int vpmoct_init(struct vpmoct *vpm, load_complete_func_t load_complete);
 int vpmoct_echocan_create(struct vpmoct *vpm,
 			   int channo,
 			   int companding);

Modified: linux/trunk/drivers/dahdi/wctdm24xxp/base.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/wctdm24xxp/base.c?view=diff&rev=9998&r1=9997&r2=9998
==============================================================================
--- linux/trunk/drivers/dahdi/wctdm24xxp/base.c (original)
+++ linux/trunk/drivers/dahdi/wctdm24xxp/base.c Tue Jun 28 17:29:00 2011
@@ -307,12 +307,6 @@
 static inline __attribute_const__ int VPM_CMD_BYTE(int timeslot, int bit)
 {
 	return ((((timeslot) & 0x3) * 3 + (bit)) * 7) + ((timeslot) >> 2);
-}
-
-static inline bool is_initialized(struct wctdm *wc)
-{
-	WARN_ON(wc->initialized < 0);
-	return (wc->initialized == 0);
 }
 
 static void
@@ -2131,6 +2125,7 @@
 		return vpmadt032_name;
 	else if (wc->vpmoct)
 		return vpmoct_name;
+
 	return NULL;
 }
 
@@ -4374,12 +4369,37 @@
 	return 0;
 }
 
+static void wctdm_vpm_load_complete(struct device *dev, bool operational)
+{
+	unsigned long flags;
+	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+	struct wctdm *wc = pci_get_drvdata(pdev);
+	struct vpmoct *vpm = NULL;
+
+	WARN_ON(!wc || !wc->not_ready);
+	if (!wc || !wc->not_ready)
+		return;
+
+	spin_lock_irqsave(&wc->reglock, flags);
+	wc->not_ready--;
+	if (operational) {
+		wc->ctlreg |= 0x10;
+	} else {
+		vpm = wc->vpmoct;
+		wc->vpmoct = NULL;
+	}
+	spin_unlock_irqrestore(&wc->reglock, flags);
+
+	if (vpm)
+		vpmoct_free(vpm);
+}
+
 static void wctdm_initialize_vpm(struct wctdm *wc)
 {
 	int res = 0;
 
 	if (!vpmsupport)
-		goto cleanup;
+		return;
 
 	res = wctdm_initialize_vpmadt032(wc);
 	if (!res) {
@@ -4393,29 +4413,26 @@
 		if (!vpm) {
 			dev_info(&wc->vb.pdev->dev,
 			    "Unable to allocate memory for struct vpmoct\n");
-			goto cleanup;
+			return;
 		}
 
 		vpm->dev = &wc->vb.pdev->dev;
 
 		spin_lock_irqsave(&wc->reglock, flags);
 		wc->vpmoct = vpm;
+		wc->not_ready++;
 		spin_unlock_irqrestore(&wc->reglock, flags);
 
-		if (!vpmoct_init(vpm)) {
-			wc->ctlreg |= 0x10;
-			return;
-		} else {
+		res = vpmoct_init(vpm, wctdm_vpm_load_complete);
+		if (-EINVAL == res) {
 			spin_lock_irqsave(&wc->reglock, flags);
 			wc->vpmoct = NULL;
+			wc->not_ready--;
 			spin_unlock_irqrestore(&wc->reglock, flags);
 			vpmoct_free(vpm);
-			goto cleanup;
-		}
-	}
-
-cleanup:
-	dev_info(&wc->vb.pdev->dev, "VPM: Support Disabled\n");
+		}
+	}
+	return;
 }
 
 static void wctdm_identify_modules(struct wctdm *wc)
@@ -5214,7 +5231,7 @@
 	if (!wc)
 		return -ENOMEM;
 
-	wc->initialized = 1;
+	wc->not_ready = 1;
 
 	down(&ifacelock);
 	/* \todo this is a candidate for removal... */
@@ -5460,7 +5477,7 @@
 		}
 	}
 
-	wc->initialized--;
+	wc->not_ready--;
 
 	dev_info(&wc->vb.pdev->dev,
 		 "Found a %s: %s (%d BRI spans, %d analog %s)\n",
@@ -5531,38 +5548,51 @@
 
 static void __devexit wctdm_remove_one(struct pci_dev *pdev)
 {
+	int i;
+	unsigned long flags;
 	struct wctdm *wc = pci_get_drvdata(pdev);
-	struct vpmadt032 *vpm = wc->vpmadt032;
-	int i;
-
-
-	if (wc) {
-
-		remove_sysfs_files(wc);
-
-		if (vpm) {
-			clear_bit(VPM150M_ACTIVE, &vpm->control);
-			flush_scheduled_work();
-		}
-
-		/* shut down any BRI modules */
-		for (i = 0; i < wc->mods_per_board; i += 4) {
-			if (wc->mods[i].type == BRI)
-				wctdm_unload_b400m(wc, i);
-		}
-
-		voicebus_stop(&wc->vb);
-
-		if (vpm) {
-			vpmadt032_free(wc->vpmadt032);
-			wc->vpmadt032 = NULL;
-		}
-
-		dev_info(&wc->vb.pdev->dev, "Freed a %s\n",
-				(is_hx8(wc)) ? "Hybrid card" : "Wildcard");
-		/* Release span */
-		wctdm_release(wc);
-	}
+	struct vpmadt032 *vpmadt032;
+	struct vpmoct	 *vpmoct;
+
+	if (!wc)
+		return;
+
+	vpmadt032 = wc->vpmadt032;
+	vpmoct = wc->vpmoct;
+
+	remove_sysfs_files(wc);
+
+	if (vpmadt032) {
+		clear_bit(VPM150M_ACTIVE, &vpmadt032->control);
+		flush_scheduled_work();
+	} else if (vpmoct) {
+		while (wctdm_wait_for_ready(wc))
+			schedule();
+	}
+
+	/* shut down any BRI modules */
+	for (i = 0; i < wc->mods_per_board; i += 4) {
+		if (wc->mods[i].type == BRI)
+			wctdm_unload_b400m(wc, i);
+	}
+
+	voicebus_stop(&wc->vb);
+
+	if (vpmadt032) {
+		vpmadt032_free(vpmadt032);
+		wc->vpmadt032 = NULL;
+	} else if (vpmoct) {
+		spin_lock_irqsave(&wc->reglock, flags);
+		wc->vpmoct = NULL;
+		spin_unlock_irqrestore(&wc->reglock, flags);
+		vpmoct_free(vpmoct);
+	}
+
+	dev_info(&wc->vb.pdev->dev, "Freed a %s\n",
+			(is_hx8(wc)) ? "Hybrid card" : "Wildcard");
+
+	/* Release span */
+	wctdm_release(wc);
 }
 
 static DEFINE_PCI_DEVICE_TABLE(wctdm_pci_tbl) = {

Modified: linux/trunk/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/wctdm24xxp/wctdm24xxp.h?view=diff&rev=9998&r1=9997&r2=9998
==============================================================================
--- linux/trunk/drivers/dahdi/wctdm24xxp/wctdm24xxp.h (original)
+++ linux/trunk/drivers/dahdi/wctdm24xxp/wctdm24xxp.h Tue Jun 28 17:29:00 2011
@@ -273,10 +273,16 @@
 	struct semaphore syncsem;
 	int oldsync;
 
-	int initialized;	 /* 0 when the entire card is ready to go */
+	int not_ready;		 /* 0 when the entire card is ready to go */
 	unsigned long checkflag; /* Internal state flags and task bits */
 	int companding;
 };
+
+static inline bool is_initialized(struct wctdm *wc)
+{
+	WARN_ON(wc->not_ready < 0);
+	return (wc->not_ready == 0);
+}
 
 /* Atomic flag bits for checkflag field */
 #define WCTDM_CHECK_TIMING	0

Modified: linux/trunk/drivers/dahdi/wctdm24xxp/xhfc.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/wctdm24xxp/xhfc.c?view=diff&rev=9998&r1=9997&r2=9998
==============================================================================
--- linux/trunk/drivers/dahdi/wctdm24xxp/xhfc.c (original)
+++ linux/trunk/drivers/dahdi/wctdm24xxp/xhfc.c Tue Jun 28 17:29:00 2011
@@ -1160,7 +1160,7 @@
 	}
 
 	for (j = 0; j < WC_MAX_IFACES && ifaces[j]; j++) {
-		if (!ifaces[j]->initialized) {
+		if (is_initialized(ifaces[j])) {
 			set_bit(WCTDM_CHECK_TIMING, &wc->checkflag);
 			osrc = -2;
 			goto out;
@@ -2194,7 +2194,7 @@
 	b4 = bspan->parent;
 	wc = b4->wc;
 
-	if ((file->f_flags & O_NONBLOCK) && !wc->initialized)
+	if ((file->f_flags & O_NONBLOCK) && !is_initialized(wc))
 		return -EAGAIN;
 
 	res = wctdm_wait_for_ready(wc);
@@ -2271,7 +2271,7 @@
 	struct b400m *b4 = bspan->parent;
 	int res;
 
-	if ((file->f_flags & O_NONBLOCK) && !b4->wc->initialized)
+	if ((file->f_flags & O_NONBLOCK) && !is_initialized(b4->wc))
 		return -EAGAIN;
 
 	res = wctdm_wait_for_ready(b4->wc);
@@ -2395,7 +2395,7 @@
 	int i, j, k, fifo;
 	unsigned char b, b2;
 
-	if (b4->shutdown || !b4->wc->initialized)
+	if (b4->shutdown || !is_initialized(b4->wc))
 		return;
 
 	b4->irq_oview = b400m_getreg(b4, R_IRQ_OVIEW);
@@ -2518,7 +2518,7 @@
 		return;
 
 	/* DEFINITELY don't do anything if our structures aren't ready! */
-	if (!wc->initialized || !b4 || !b4->inited)
+	if (!is_initialized(wc) || !b4 || !b4->inited)
 		return;
 
 	if (offset == 0) {

Modified: linux/trunk/drivers/dahdi/wcte12xp/base.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/wcte12xp/base.c?view=diff&rev=9998&r1=9997&r2=9998
==============================================================================
--- linux/trunk/drivers/dahdi/wcte12xp/base.c (original)
+++ linux/trunk/drivers/dahdi/wcte12xp/base.c Tue Jun 28 17:29:00 2011
@@ -1054,8 +1054,24 @@
 
 static inline bool is_initialized(struct t1 *wc)
 {
-	WARN_ON(wc->initialized < 0);
-	return (wc->initialized == 0);
+	WARN_ON(wc->not_ready < 0);
+	return (wc->not_ready == 0);
+}
+
+/**
+ * t1_wait_for_ready
+ *
+ * Check if the board has finished any setup and is ready to start processing
+ * calls.
+ */
+static int t1_wait_for_ready(struct t1 *wc)
+{
+	while (!is_initialized(wc)) {
+		if (fatal_signal_pending(current))
+			return -EIO;
+		msleep_interruptible(250);
+	}
+	return 0;
 }
 
 static int t1xxp_chanconfig(struct file *file,
@@ -1066,11 +1082,7 @@
 	if (file->f_flags & O_NONBLOCK && !is_initialized(wc)) {
 			return -EAGAIN;
 	} else {
-		while (!is_initialized(wc)) {
-			if (fatal_signal_pending(current))
-				return -EIO;
-			msleep_interruptible(250);
-		}
+		t1_wait_for_ready(wc);
 	}
 
 	if (test_bit(DAHDI_FLAGBIT_RUNNING, &chan->span->flags) &&
@@ -1539,7 +1551,7 @@
 		set_bit(0, &wc->ctlreg);
 	}
 
-	wc->initialized--;
+	wc->not_ready--;
 	kfree(w);
 }
 
@@ -1561,26 +1573,42 @@
 	return 0;
 }
 
-static int check_and_load_vpm(struct t1 *wc)
-{
-	int res;
+static void t1_vpm_load_complete(struct device *dev, bool operational)
+{
+	unsigned long flags;
+	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+	struct t1 *wc = pci_get_drvdata(pdev);
+	struct vpmoct *vpm = NULL;
+
+	if (!wc || is_initialized(wc)) {
+		WARN_ON(!wc);
+		return;
+	}
+
+	spin_lock_irqsave(&wc->reglock, flags);
+	wc->not_ready--;
+	if (operational) {
+		set_bit(VPM150M_ACTIVE, &wc->ctlreg);
+	} else {
+		clear_bit(VPM150M_ACTIVE, &wc->ctlreg);
+		vpm = wc->vpmoct;
+		wc->vpmoct = NULL;
+	}
+	spin_unlock_irqrestore(&wc->reglock, flags);
+
+	if (vpm)
+		vpmoct_free(vpm);
+}
+
+static void check_and_load_vpm(struct t1 *wc)
+{
 	unsigned long flags;
 	struct vpmadt032_options options;
-	struct vpmadt032 *vpm = NULL;
+	struct vpmadt032 *vpmadt = NULL;
 
 	if (!vpmsupport) {
-		t1_info(wc, "VPM Support Disabled\n");
-		vpmadt032_free(wc->vpmadt032);
-		wc->vpmadt032 = NULL;
-		return 0;
-	}
-
-	/* The firmware may already be loaded. */
-	if (wc->vpmadt032) {
-		u16 version;
-		res = gpakPingDsp(wc->vpmadt032->dspid, &version);
-		if (!res)
-			return 0;
+		t1_info(wc, "VPM Support Disabled via module parameter\n");
+		return;
 	}
 
 	memset(&options, 0, sizeof(options));
@@ -1594,69 +1622,49 @@
 	 * done setting it up here, an hour should cover it... */
 	wc->vpm_check = jiffies + HZ*3600;
 
-	vpm = vpmadt032_alloc(&options);
-	if (!vpm)
-		return -ENOMEM;
-
-	vpm->setchanconfig_from_state = setchanconfig_from_state;
+	vpmadt = vpmadt032_alloc(&options);
+	if (!vpmadt)
+		return;
+
+	vpmadt->setchanconfig_from_state = setchanconfig_from_state;
 
 	spin_lock_irqsave(&wc->reglock, flags);
-	wc->vpmadt032 = vpm;
+	wc->vpmadt032 = vpmadt;
 	spin_unlock_irqrestore(&wc->reglock, flags);
 
-	res = vpmadt032_test(vpm, &wc->vb);
-	if (-ENODEV == res) {
-		struct vpmoct *vpmoct;
-
+	/* Probe for and attempt to load a vpmadt032 module */
+	if (vpmadt032_test(vpmadt, &wc->vb) || vpm_start_load(wc)) {
 		/* There does not appear to be a VPMADT032 installed. */
 		clear_bit(VPM150M_ACTIVE, &wc->ctlreg);
 		spin_lock_irqsave(&wc->reglock, flags);
 		wc->vpmadt032 = NULL;
 		spin_unlock_irqrestore(&wc->reglock, flags);
-		vpmadt032_free(vpm);
+		vpmadt032_free(vpmadt);
+	}
+
+	/* Probe for and attempt to load a vpmoct032 module */
+	if (NULL == wc->vpmadt032) {
+		struct vpmoct *vpmoct;
 
 		/* Check for vpmoct */
 		vpmoct = vpmoct_alloc();
 		if (!vpmoct)
-			return -ENOMEM;
+			return;
 
 		vpmoct->dev = &wc->vb.pdev->dev;
 
 		spin_lock_irqsave(&wc->reglock, flags);
 		wc->vpmoct = vpmoct;
+		wc->not_ready++;
 		spin_unlock_irqrestore(&wc->reglock, flags);
 
-		res = vpmoct_init(wc->vpmoct);
-		if (res) {
-			dev_info(&wc->vb.pdev->dev,
-				"Unable to initialize vpmoct module\n");
-			spin_lock_irqsave(&wc->reglock, flags);
-			wc->vpmoct = NULL;
-			spin_unlock_irqrestore(&wc->reglock, flags);
-			vpmoct_free(vpmoct);
-		} else {
-			set_bit(VPM150M_ACTIVE, &wc->ctlreg);
-		}
-
-		return res;
-	}
-
-	res = vpm_start_load(wc);
-	if (res) {
-		/* There does not appear to be a VPMADT032 installed. */
-		clear_bit(VPM150M_ACTIVE, &wc->ctlreg);
-		spin_lock_irqsave(&wc->reglock, flags);
-		wc->vpmadt032 = NULL;
-		spin_unlock_irqrestore(&wc->reglock, flags);
-		vpmadt032_free(vpm);
-		return res;
-	}
-	return res;
+		vpmoct_init(vpmoct, t1_vpm_load_complete);
+	}
 }
 #else
-static inline int check_and_load_vpm(const struct t1 *wc)
-{
-	return 0;
+static inline void check_and_load_vpm(const struct t1 *wc)
+{
+	return;
 }
 #endif
 
@@ -1706,11 +1714,7 @@
 		if (!is_initialized(wc))
 			return -EAGAIN;
 	} else {
-		while (!is_initialized(wc)) {
-			if (fatal_signal_pending(current))
-				return -EIO;
-			msleep_interruptible(250);
-		}
+		t1_wait_for_ready(wc);
 	}
 
 	/* Do we want to SYNC on receive or not */
@@ -2340,7 +2344,7 @@
 	/* If there is a failed VPM module, do not block dahdi_cfg
 	 * indefinitely. */
 	if (++wc->vpm_check_count > MAX_CHECKS) {
-		wc->initialized--;
+		wc->not_ready--;
 		wc->vpm_check = MAX_JIFFY_OFFSET;
 		t1_info(wc, "Disabling VPMADT032 Checking.\n");
 		return;
@@ -2395,7 +2399,7 @@
 	set_bit(VPM150M_ACTIVE, &wc->ctlreg);
 	t1_info(wc, "VPMADT032 is reenabled.\n");
 	wc->vpm_check = jiffies + HZ*5;
-	wc->initialized--;
+	wc->not_ready--;
 	return;
 }
 
@@ -2544,7 +2548,7 @@
 	if (!wc)
 		return -ENOMEM;
 
-	wc->initialized = 1;
+	wc->not_ready = 1;
 
 	ifaces[index] = wc;
 
@@ -2659,11 +2663,10 @@
 	t1_info(wc, "Found a %s\n", wc->variety);
 	voicebus_unlock_latency(&wc->vb);
 
-	/* If there is VPMADT032 or VPMOCT032 module attached to this device,
-	 * it will signal ready after the channels are configured and ready
-	 * for use. */
-	if (!wc->vpmadt032 && !wc->vpmoct)
-		wc->initialized--;
+	/* If there is VPMADT032 module attached to this device, it will
+	 * signal ready after the channels are configured and ready for use. */
+	if (!wc->vpmadt032)
+		wc->not_ready--;
 	return 0;
 }
 
@@ -2671,7 +2674,9 @@
 {
 	struct t1 *wc = pci_get_drvdata(pdev);
 #ifdef VPM_SUPPORT
-	struct vpmadt032 *vpm = wc->vpmadt032;
+	unsigned long flags;
+	struct vpmadt032 *vpmadt = wc->vpmadt032;
+	struct vpmoct	 *vpmoct = wc->vpmoct;
 #endif
 	if (!wc)
 		return;
@@ -2685,20 +2690,30 @@
 	del_timer_sync(&wc->timer);
 	flush_workqueue(wc->wq);
 #ifdef VPM_SUPPORT
-	if (vpm)
-		flush_workqueue(vpm->wq);
+	if (vpmadt) {
+		clear_bit(VPM150M_ACTIVE, &vpmadt->control);
+		flush_workqueue(vpmadt->wq);
+	} else if (vpmoct) {
+		while (t1_wait_for_ready(wc))
+			schedule();
+	}
 #endif
 	del_timer_sync(&wc->timer);
 
 	voicebus_release(&wc->vb);
 
 #ifdef VPM_SUPPORT
-	if(vpm) {
+	if (vpmadt) {
+		spin_lock_irqsave(&wc->reglock, flags);
 		wc->vpmadt032 = NULL;
-		clear_bit(VPM150M_ACTIVE, &vpm->control);
-		vpmadt032_free(vpm);
-	}
-
+		spin_unlock_irqrestore(&wc->reglock, flags);
+		vpmadt032_free(vpmadt);
+	} else if (vpmoct) {
+		spin_lock_irqsave(&wc->reglock, flags);
+		wc->vpmoct = NULL;
+		spin_unlock_irqrestore(&wc->reglock, flags);
+		vpmoct_free(vpmoct);
+	}
 #endif
 
 	t1_info(wc, "Freed a Wildcard TE12xP.\n");

Modified: linux/trunk/drivers/dahdi/wcte12xp/wcte12xp.h
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/wcte12xp/wcte12xp.h?view=diff&rev=9998&r1=9997&r2=9998
==============================================================================
--- linux/trunk/drivers/dahdi/wcte12xp/wcte12xp.h (original)
+++ linux/trunk/drivers/dahdi/wcte12xp/wcte12xp.h Tue Jun 28 17:29:00 2011
@@ -139,7 +139,7 @@
 	struct timer_list timer;
 	struct work_struct timer_work;
 	struct workqueue_struct *wq;
-	bool initialized;	/* 0 when entire card is ready to go */
+	unsigned int not_ready;	/* 0 when entire card is ready to go */
 };
 
 #define t1_info(t1, format, arg...)         \




More information about the svn-commits mailing list