The following bug happens when insmoding hp_sdc_mlc.ko:
HP SDC MLC: Registering the System Domain Controller's HIL MLC.
BUG: rwlock recursion on CPU#0, hotplug/1814,
00854734
Backtrace:
[<
10267560>] _raw_write_lock+0x50/0x88
[<
10104008>] _write_lock_irqsave+0x14/0x24
[<
008537d4>] hp_sdc_mlc_out+0x38/0x25c [hp_sdc_mlc]
[<
0084ebd8>] hilse_donode+0x308/0x470 [hil_mlc]
[<
0084ed80>] hil_mlcs_process+0x40/0x6c [hil_mlc]
[<
10130f80>] tasklet_action+0x78/0xb8
[<
10130cec>] __do_softirq+0x60/0xcc
[<
1010428c>] __lock_text_end+0x38/0x48
[<
10108348>] do_cpu_irq_mask+0xf0/0x11c
[<
1010b068>] intr_return+0x0/0xc
Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
break;
case HILSE_CTS:
+ write_lock_irqsave(&mlc->lock, flags);
nextidx = mlc->cts(mlc) ? node->bad : node->good;
+ write_unlock_irqrestore(&mlc->lock, flags);
break;
default:
EXPORT_SYMBOL(hp_sdc_release_hil_irq);
EXPORT_SYMBOL(hp_sdc_release_cooked_irq);
+EXPORT_SYMBOL(__hp_sdc_enqueue_transaction);
EXPORT_SYMBOL(hp_sdc_enqueue_transaction);
EXPORT_SYMBOL(hp_sdc_dequeue_transaction);
}
/******* Functions called in either user or kernel context ****/
-int hp_sdc_enqueue_transaction(hp_sdc_transaction *this)
+int __hp_sdc_enqueue_transaction(hp_sdc_transaction *this)
{
- unsigned long flags;
int i;
if (this == NULL) {
- tasklet_schedule(&hp_sdc.task);
+ BUG();
return -EINVAL;
}
- write_lock_irqsave(&hp_sdc.lock, flags);
-
/* Can't have same transaction on queue twice */
for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
if (hp_sdc.tq[i] == this)
for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
if (hp_sdc.tq[i] == NULL) {
hp_sdc.tq[i] = this;
- write_unlock_irqrestore(&hp_sdc.lock, flags);
tasklet_schedule(&hp_sdc.task);
return 0;
}
- write_unlock_irqrestore(&hp_sdc.lock, flags);
printk(KERN_WARNING PREFIX "No free slot to add transaction.\n");
return -EBUSY;
fail:
- write_unlock_irqrestore(&hp_sdc.lock,flags);
printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n");
return -EINVAL;
}
+int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) {
+ unsigned long flags;
+ int ret;
+
+ write_lock_irqsave(&hp_sdc.lock, flags);
+ ret = __hp_sdc_enqueue_transaction(this);
+ write_unlock_irqrestore(&hp_sdc.lock,flags);
+
+ return ret;
+}
+
int hp_sdc_dequeue_transaction(hp_sdc_transaction *this)
{
unsigned long flags;
static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout)
{
- unsigned long flags;
struct hp_sdc_mlc_priv_s *priv;
int rc = 2;
priv = mlc->priv;
- write_lock_irqsave(&mlc->lock, flags);
-
/* Try to down the semaphore */
if (down_trylock(&mlc->isem)) {
struct timeval tv;
wasup:
up(&mlc->isem);
rc = 0;
- goto done;
done:
- write_unlock_irqrestore(&mlc->lock, flags);
return rc;
}
static int hp_sdc_mlc_cts(hil_mlc *mlc)
{
struct hp_sdc_mlc_priv_s *priv;
- unsigned long flags;
priv = mlc->priv;
- write_lock_irqsave(&mlc->lock, flags);
-
/* Try to down the semaphores -- they should be up. */
BUG_ON(down_trylock(&mlc->isem));
BUG_ON(down_trylock(&mlc->osem));
priv->tseq[2] = 1;
priv->tseq[3] = 0;
priv->tseq[4] = 0;
- hp_sdc_enqueue_transaction(&priv->trans);
+ __hp_sdc_enqueue_transaction(&priv->trans);
busy:
- write_unlock_irqrestore(&mlc->lock, flags);
return 1;
done:
priv->trans.act.semaphore = &mlc->osem;
up(&mlc->csem);
- write_unlock_irqrestore(&mlc->lock, flags);
return 0;
}
static void hp_sdc_mlc_out(hil_mlc *mlc)
{
struct hp_sdc_mlc_priv_s *priv;
- unsigned long flags;
priv = mlc->priv;
- write_lock_irqsave(&mlc->lock, flags);
-
/* Try to down the semaphore -- it should be up. */
BUG_ON(down_trylock(&mlc->osem));
do_data:
if (priv->emtestmode) {
up(&mlc->osem);
- goto done;
+ return;
}
/* Shouldn't be sending commands when loop may be busy */
BUG_ON(down_trylock(&mlc->csem));
}
enqueue:
hp_sdc_enqueue_transaction(&priv->trans);
- done:
- write_unlock_irqrestore(&mlc->lock, flags);
}
static int __init hp_sdc_mlc_init(void)
struct semaphore *semaphore; /* Semaphore to sleep on. */
} act;
} hp_sdc_transaction;
+int __hp_sdc_enqueue_transaction(hp_sdc_transaction *this);
int hp_sdc_enqueue_transaction(hp_sdc_transaction *this);
int hp_sdc_dequeue_transaction(hp_sdc_transaction *this);