lkml.org 
[lkml]   [2010]   [Dec]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC/PATCH 2/3] mfd: twl4030-irq: drop the workqueue hackery
    Date
    Finally that workqueue isn't needed anymore.
    Drop that hackery and move the spinlock_t to
    a mutex so we can issue I2C operations with
    a lock held.

    Signed-off-by: Felipe Balbi <balbi@ti.com>
    ---
    drivers/mfd/twl4030-irq.c | 226 +++++++++++++++++++--------------------------
    1 files changed, 96 insertions(+), 130 deletions(-)

    diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
    index 91331a7..298956d 100644
    --- a/drivers/mfd/twl4030-irq.c
    +++ b/drivers/mfd/twl4030-irq.c
    @@ -31,6 +31,7 @@
    #include <linux/interrupt.h>
    #include <linux/irq.h>
    #include <linux/slab.h>
    +#include <linux/mutex.h>

    #include <linux/i2c/twl.h>

    @@ -434,46 +435,36 @@ static inline void activate_irq(int irq)

    /*----------------------------------------------------------------------*/

    -static DEFINE_SPINLOCK(sih_agent_lock);
    -
    -static struct workqueue_struct *wq;
    -
    struct sih_agent {
    int irq_base;
    const struct sih *sih;

    u32 imr;
    - bool imr_change_pending;
    - struct work_struct mask_work;
    -
    u32 edge_change;
    - struct work_struct edge_work;
    +
    + struct mutex irq_lock;
    };

    -static void twl4030_sih_do_mask(struct work_struct *work)
    +/*----------------------------------------------------------------------*/
    +
    +static void twl4030_sih_mask(unsigned irq)
    {
    - struct sih_agent *agent;
    - const struct sih *sih;
    + struct sih_agent *agent = get_irq_chip_data(irq);
    + const struct sih *sih = agent->sih;
    +
    union {
    u8 bytes[4];
    u32 word;
    } imr;
    +
    int status;

    - agent = container_of(work, struct sih_agent, mask_work);
    -
    - /* see what work we have */
    - spin_lock_irq(&sih_agent_lock);
    - if (agent->imr_change_pending) {
    - sih = agent->sih;
    - /* byte[0] gets overwritten as we write ... */
    - imr.word = cpu_to_le32(agent->imr << 8);
    - agent->imr_change_pending = false;
    - } else
    - sih = NULL;
    - spin_unlock_irq(&sih_agent_lock);
    - if (!sih)
    - return;
    + agent->imr |= BIT(irq - agent->irq_base);
    +
    + mutex_lock(&agent->irq_lock);
    +
    + /* byte[0] gets overwritten as we write ... */
    + imr.word = cpu_to_le32(agent->imr << 8);

    /* write the whole mask ... simpler than subsetting it */
    status = twl_i2c_write(sih->module, imr.bytes,
    @@ -481,111 +472,42 @@ static void twl4030_sih_do_mask(struct work_struct *work)
    if (status)
    pr_err("twl4030: %s, %s --> %d\n", __func__,
    "write", status);
    + mutex_unlock(&agent->irq_lock);
    }

    -static void twl4030_sih_do_edge(struct work_struct *work)
    +static void twl4030_sih_unmask(unsigned irq)
    {
    - struct sih_agent *agent;
    - const struct sih *sih;
    - u8 bytes[6];
    - u32 edge_change;
    - int status;
    -
    - agent = container_of(work, struct sih_agent, edge_work);
    -
    - /* see what work we have */
    - spin_lock_irq(&sih_agent_lock);
    - edge_change = agent->edge_change;
    - agent->edge_change = 0;
    - sih = edge_change ? agent->sih : NULL;
    - spin_unlock_irq(&sih_agent_lock);
    - if (!sih)
    - return;
    -
    - /* Read, reserving first byte for write scratch. Yes, this
    - * could be cached for some speedup ... but be careful about
    - * any processor on the other IRQ line, EDR registers are
    - * shared.
    - */
    - status = twl_i2c_read(sih->module, bytes + 1,
    - sih->edr_offset, sih->bytes_edr);
    - if (status) {
    - pr_err("twl4030: %s, %s --> %d\n", __func__,
    - "read", status);
    - return;
    - }
    + struct sih_agent *agent = get_irq_chip_data(irq);
    + const struct sih *sih = agent->sih;

    - /* Modify only the bits we know must change */
    - while (edge_change) {
    - int i = fls(edge_change) - 1;
    - struct irq_desc *d = irq_to_desc(i + agent->irq_base);
    - int byte = 1 + (i >> 2);
    - int off = (i & 0x3) * 2;
    -
    - if (!d) {
    - pr_err("twl4030: Invalid IRQ: %d\n",
    - i + agent->irq_base);
    - return;
    - }
    + union {
    + u8 bytes[4];
    + u32 word;
    + } imr;

    - bytes[byte] &= ~(0x03 << off);
    + int status;

    - raw_spin_lock_irq(&d->lock);
    - if (d->status & IRQ_TYPE_EDGE_RISING)
    - bytes[byte] |= BIT(off + 1);
    - if (d->status & IRQ_TYPE_EDGE_FALLING)
    - bytes[byte] |= BIT(off + 0);
    - raw_spin_unlock_irq(&d->lock);
    + mutex_lock(&agent->irq_lock);
    + agent->imr &= ~BIT(irq - agent->irq_base);

    - edge_change &= ~BIT(i);
    - }
    + /* byte[0] gets overwritten as we write ... */
    + imr.word = cpu_to_le32(agent->imr << 8);

    - /* Write */
    - status = twl_i2c_write(sih->module, bytes,
    - sih->edr_offset, sih->bytes_edr);
    + /* write the whole mask ... simpler than subsetting it */
    + status = twl_i2c_write(sih->module, imr.bytes,
    + sih->mask[irq_line].imr_offset, sih->bytes_ixr);
    if (status)
    pr_err("twl4030: %s, %s --> %d\n", __func__,
    "write", status);
    -}
    -
    -/*----------------------------------------------------------------------*/
    -
    -/*
    - * All irq_chip methods get issued from code holding irq_desc[irq].lock,
    - * which can't perform the underlying I2C operations (because they sleep).
    - * So we must hand them off to a thread (workqueue) and cope with asynch
    - * completion, potentially including some re-ordering, of these requests.
    - */
    -
    -static void twl4030_sih_mask(unsigned irq)
    -{
    - struct sih_agent *sih = get_irq_chip_data(irq);
    - unsigned long flags;
    -
    - spin_lock_irqsave(&sih_agent_lock, flags);
    - sih->imr |= BIT(irq - sih->irq_base);
    - sih->imr_change_pending = true;
    - queue_work(wq, &sih->mask_work);
    - spin_unlock_irqrestore(&sih_agent_lock, flags);
    -}
    -
    -static void twl4030_sih_unmask(unsigned irq)
    -{
    - struct sih_agent *sih = get_irq_chip_data(irq);
    - unsigned long flags;
    -
    - spin_lock_irqsave(&sih_agent_lock, flags);
    - sih->imr &= ~BIT(irq - sih->irq_base);
    - sih->imr_change_pending = true;
    - queue_work(wq, &sih->mask_work);
    - spin_unlock_irqrestore(&sih_agent_lock, flags);
    + mutex_unlock(&agent->irq_lock);
    }

    static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
    {
    - struct sih_agent *sih = get_irq_chip_data(irq);
    - struct irq_desc *desc = irq_to_desc(irq);
    - unsigned long flags;
    + struct sih_agent *agent = get_irq_chip_data(irq);
    + const struct sih *sih = agent->sih;
    + struct irq_desc *desc = irq_to_desc(irq);
    + int status = 0;

    if (!desc) {
    pr_err("twl4030: Invalid IRQ: %d\n", irq);
    @@ -595,15 +517,67 @@ static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
    if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
    return -EINVAL;

    - spin_lock_irqsave(&sih_agent_lock, flags);
    + mutex_lock(&agent->irq_lock);
    if ((desc->status & IRQ_TYPE_SENSE_MASK) != trigger) {
    + u8 bytes[6];
    + u32 edge_change;
    +
    desc->status &= ~IRQ_TYPE_SENSE_MASK;
    desc->status |= trigger;
    - sih->edge_change |= BIT(irq - sih->irq_base);
    - queue_work(wq, &sih->edge_work);
    + agent->edge_change |= BIT(irq - agent->irq_base);
    + edge_change = agent->edge_change;
    +
    + /* Read, reserving first byte for write scratch. Yes, this
    + * could be cached for some speedup ... but be careful about
    + * any processor on the other IRQ line, EDR registers are
    + * shared.
    + */
    + status = twl_i2c_read(sih->module, bytes + 1,
    + sih->edr_offset, sih->bytes_edr);
    + if (status) {
    + pr_err("twl4030: %s, %s --> %d\n", __func__,
    + "read", status);
    + goto out;
    + }
    +
    + /* Modify only the bits we know must change */
    + while (edge_change) {
    + int i = fls(edge_change) - 1;
    + struct irq_desc *d = irq_to_desc(i + agent->irq_base);
    + int byte = 1 + (i >> 2);
    + int off = (i & 0x3) * 2;
    +
    + if (!d) {
    + pr_err("twl4030: Invalid IRQ: %d\n",
    + i + agent->irq_base);
    + status = -ENODEV;
    + goto out;
    + }
    +
    + bytes[byte] &= ~(0x03 << off);
    +
    + raw_spin_lock_irq(&d->lock);
    + if (d->status & IRQ_TYPE_EDGE_RISING)
    + bytes[byte] |= BIT(off + 1);
    + if (d->status & IRQ_TYPE_EDGE_FALLING)
    + bytes[byte] |= BIT(off + 0);
    + raw_spin_unlock_irq(&d->lock);
    +
    + edge_change &= ~BIT(i);
    + }
    +
    + /* Write */
    + status = twl_i2c_write(sih->module, bytes,
    + sih->edr_offset, sih->bytes_edr);
    + if (status)
    + pr_err("twl4030: %s, %s --> %d\n", __func__,
    + "write", status);
    }
    - spin_unlock_irqrestore(&sih_agent_lock, flags);
    - return 0;
    +
    +out:
    + mutex_unlock(&agent->irq_lock);
    +
    + return status;
    }

    static struct irq_chip twl4030_sih_irq_chip = {
    @@ -706,8 +680,7 @@ int twl4030_sih_setup(int module)
    agent->irq_base = irq_base;
    agent->sih = sih;
    agent->imr = ~0;
    - INIT_WORK(&agent->mask_work, twl4030_sih_do_mask);
    - INIT_WORK(&agent->edge_work, twl4030_sih_do_edge);
    + mutex_init(&agent->irq_lock);

    for (i = 0; i < sih->bits; i++) {
    irq = irq_base + i;
    @@ -755,12 +728,6 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
    if (status < 0)
    return status;

    - wq = create_singlethread_workqueue("twl4030-irqchip");
    - if (!wq) {
    - pr_err("twl4030: workqueue FAIL\n");
    - return -ESRCH;
    - }
    -
    twl4030_irq_base = irq_base;

    /* install an irq handler for each of the SIH modules;
    @@ -802,8 +769,7 @@ fail_rqirq:
    fail:
    for (i = irq_base; i < irq_end; i++)
    set_irq_chip_and_handler(i, NULL, NULL);
    - destroy_workqueue(wq);
    - wq = NULL;
    +
    return status;
    }

    --
    1.7.3.4.598.g85356


    \
     
     \ /
      Last update: 2010-12-28 18:21    [W:0.067 / U:0.320 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site