summaryrefslogtreecommitdiff
path: root/drivers/dahdi/wctdm24xxp
diff options
context:
space:
mode:
authorRuss Meyerriecks <rmeyerreicks@digium.com>2011-06-28 22:29:00 +0000
committerRuss Meyerriecks <rmeyerreicks@digium.com>2011-06-28 22:29:00 +0000
commit608d6c66bc79ab57d2acf067ec7ed5d40b7d7749 (patch)
tree7e436a730202eb527cc319abfa2befecf1df40de /drivers/dahdi/wctdm24xxp
parentc7a4ca9241ab1774ef45e027afeb59573ee117c0 (diff)
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@digium.com> Signed-off-by: Shaun Ruffell <sruffell@digium.com> git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@9998 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'drivers/dahdi/wctdm24xxp')
-rw-r--r--drivers/dahdi/wctdm24xxp/base.c112
-rw-r--r--drivers/dahdi/wctdm24xxp/wctdm24xxp.h8
-rw-r--r--drivers/dahdi/wctdm24xxp/xhfc.c10
3 files changed, 83 insertions, 47 deletions
diff --git a/drivers/dahdi/wctdm24xxp/base.c b/drivers/dahdi/wctdm24xxp/base.c
index 73bcae6..98c0f0e 100644
--- a/drivers/dahdi/wctdm24xxp/base.c
+++ b/drivers/dahdi/wctdm24xxp/base.c
@@ -309,12 +309,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
setchanconfig_from_state(struct vpmadt032 *vpm, int channel,
GpakChannelConfig_t *chanconfig)
@@ -2131,6 +2125,7 @@ static const char *wctdm_echocan_name(const struct dahdi_chan *chan)
return vpmadt032_name;
else if (wc->vpmoct)
return vpmoct_name;
+
return NULL;
}
@@ -4374,12 +4369,37 @@ static int wctdm_initialize_vpmadt032(struct wctdm *wc)
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 @@ static void wctdm_initialize_vpm(struct wctdm *wc)
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 @@ __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!wc)
return -ENOMEM;
- wc->initialized = 1;
+ wc->not_ready = 1;
down(&ifacelock);
/* \todo this is a candidate for removal... */
@@ -5460,7 +5477,7 @@ __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
- 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 wctdm_release(struct wctdm *wc)
static void __devexit wctdm_remove_one(struct pci_dev *pdev)
{
- struct wctdm *wc = pci_get_drvdata(pdev);
- struct vpmadt032 *vpm = wc->vpmadt032;
int i;
+ unsigned long flags;
+ struct wctdm *wc = pci_get_drvdata(pdev);
+ struct vpmadt032 *vpmadt032;
+ struct vpmoct *vpmoct;
+ if (!wc)
+ return;
- if (wc) {
-
- remove_sysfs_files(wc);
+ vpmadt032 = wc->vpmadt032;
+ vpmoct = wc->vpmoct;
- if (vpm) {
- clear_bit(VPM150M_ACTIVE, &vpm->control);
- flush_scheduled_work();
- }
+ remove_sysfs_files(wc);
- /* 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);
- }
+ if (vpmadt032) {
+ clear_bit(VPM150M_ACTIVE, &vpmadt032->control);
+ flush_scheduled_work();
+ } else if (vpmoct) {
+ while (wctdm_wait_for_ready(wc))
+ schedule();
+ }
- voicebus_stop(&wc->vb);
+ /* 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);
+ }
- if (vpm) {
- vpmadt032_free(wc->vpmadt032);
- wc->vpmadt032 = NULL;
- }
+ voicebus_stop(&wc->vb);
- dev_info(&wc->vb.pdev->dev, "Freed a %s\n",
- (is_hx8(wc)) ? "Hybrid card" : "Wildcard");
- /* Release span */
- wctdm_release(wc);
+ 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) = {
diff --git a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
index 0f497aa..4ab313d 100644
--- a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
+++ b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
@@ -273,11 +273,17 @@ struct wctdm {
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
diff --git a/drivers/dahdi/wctdm24xxp/xhfc.c b/drivers/dahdi/wctdm24xxp/xhfc.c
index de6ad89..c5eb5a6 100644
--- a/drivers/dahdi/wctdm24xxp/xhfc.c
+++ b/drivers/dahdi/wctdm24xxp/xhfc.c
@@ -1160,7 +1160,7 @@ static int xhfc_find_sync_with_timingcable(struct b400m *b4)
}
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 @@ int b400m_spanconfig(struct file *file, struct dahdi_span *span,
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 @@ int b400m_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype)
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 @@ static void xhfc_work(struct work_struct *work)
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 @@ void wctdm_bri_checkisr(struct wctdm *wc, struct wctdm_module *const mod,
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) {