Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1908453
  • 博文数量: 376
  • 博客积分: 2147
  • 博客等级: 大尉
  • 技术积分: 3642
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-06 10:47
文章分类

全部博文(376)

文章存档

2019年(3)

2017年(28)

2016年(15)

2015年(17)

2014年(182)

2013年(16)

2012年(115)

我的朋友

分类: 嵌入式

2013-03-22 09:40:07

//drivers/net/gianfar.c
static int register_grp_irqs(struct gfar_priv_grp *grp)
{
    struct gfar_private *priv = grp->priv;
    struct net_device *dev = priv->ndev;
    int err;
#ifdef CONFIG_GFAR_SW_PKT_STEERING
    int i, j;
    int cpus = num_online_cpus();
    struct cpumask cpumask_msg_intrs;
#endif

    /* If the device has multiple interrupts, register for
     * them.  Otherwise, only register for the one */
    if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
        /* Install our interrupt handlers for Error,
         * Transmit, and Receive */
        if ((err = request_irq(grp->interruptError, gfar_error, 0,
                grp->int_name_er,grp)) < 0) {
            if (netif_msg_intr(priv))
                printk(KERN_ERR "%s: Can't get IRQ %d\n",
                    dev->name, grp->interruptError);

                goto err_irq_fail;
        }

#ifndef CONFIG_RX_TX_BD_XNGE
        if ((err = request_irq(grp->interruptTransmit, gfar_transmit,//安装发送中断
                0, grp->int_name_tx, grp)) < 0) {
            if (netif_msg_intr(priv))
                printk(KERN_ERR "%s: Can't get IRQ %d\n",
                    dev->name, grp->interruptTransmit);
            goto tx_irq_fail;
        }
#endif

        if ((err = request_irq(grp->interruptReceive, gfar_receive, 0,
                grp->int_name_rx, grp)) < 0) {
            if (netif_msg_intr(priv))
                printk(KERN_ERR "%s: Can't get IRQ %d\n",
                    dev->name, grp->interruptReceive);
            goto rx_irq_fail;
        }
    } else {
        if ((err = request_irq(grp->interruptTransmit, gfar_interrupt, 0,
                grp->int_name_tx, grp)) < 0) {
            if (netif_msg_intr(priv))
                printk(KERN_ERR "%s: Can't get IRQ %d\n",
                    dev->name, grp->interruptTransmit);
            goto err_irq_fail;
        }
    }

#ifdef CONFIG_GFAR_SW_PKT_STEERING
    if (priv->sps) {
        for (i = 0; i < cpus; i++) {
            sprintf(grp->int_name_vtx[i], "%s_g%d_vtx%d",
                priv->ndev->name, grp->grp_id, i);
            err = request_irq(grp->msg_virtual_tx[i]->irq,
                        gfar_virtual_transmit, 0,
                        grp->int_name_vtx[i], grp);
            if (err < 0) {
                priv->sps = 0;
                printk(KERN_WARNING
                "%s: Can't request msg IRQ %d for dev %s\n",
                __func__,
                grp->msg_virtual_tx[i]->irq, dev->name);
                for (j = 0; j < i; j++) {
                    free_irq(grp->msg_virtual_tx[j]->irq,
                        grp);
                    clrbits32(grp->msg_virtual_tx[j]->mer,
                    1 << grp->msg_virtual_tx[j]->msg_num);
                }
                goto vtx_irq_fail;
            }
            cpumask_clear(&cpumask_msg_intrs);
            cpumask_set_cpu(i, &cpumask_msg_intrs);
            irq_set_affinity(grp->msg_virtual_tx[i]->irq,
                        &cpumask_msg_intrs);
            fsl_enable_msg(grp->msg_virtual_tx[i]);
        }
    }
#endif
    return 0;

#ifdef CONFIG_GFAR_SW_PKT_STEERING
vtx_irq_fail:
    free_irq(grp->interruptReceive, grp);
#endif
rx_irq_fail:
#ifndef CONFIG_RX_TX_BD_XNGE
    free_irq(grp->interruptTransmit, grp);
#endif
tx_irq_fail:
    free_irq(grp->interruptError, grp);
err_irq_fail:
    return err;

}

static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
        const char *name, void *dev)
{
    return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}

//kernel/irq/manage.c
int request_threaded_irq(unsigned int irq, irq_handler_t handler,
             irq_handler_t thread_fn, unsigned long irqflags,
             const char *devname, void *dev_id)
{
    struct irqaction *action;
    struct irq_desc *desc;
    int retval;

    /*
     * Sanity-check: shared interrupts must pass in a real dev-ID,
     * otherwise we'll have trouble later trying to figure out
     * which interrupt is which (messes up the interrupt freeing
     * logic etc).
     */
    if ((irqflags & IRQF_SHARED) && !dev_id)
        return -EINVAL;

    desc = irq_to_desc(irq);
    if (!desc)
        return -EINVAL;

    if (desc->status & IRQ_NOREQUEST)
        return -EINVAL;

    if (!handler) {
        if (!thread_fn)
            return -EINVAL;
        handler = irq_default_primary_handler;
    }

    action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);//分配action结构
    if (!action)
        return -ENOMEM;

    action->handler = handler;
    action->thread_fn = thread_fn;
    action->flags = irqflags;
    action->name = devname;
    action->dev_id = dev_id;

    chip_bus_lock(irq, desc);
    retval = __setup_irq(irq, desc, action);
    chip_bus_sync_unlock(irq, desc);

    if (retval)
        kfree(action);

#ifdef CONFIG_DEBUG_SHIRQ
    if (!retval && (irqflags & IRQF_SHARED)) {
        /*
         * It's a shared IRQ -- the driver ought to be prepared for it
         * to happen immediately, so let's make sure....
         * We disable the irq to make sure that a 'real' IRQ doesn't
         * run in parallel with our fake.
         */
        unsigned long flags;

        disable_irq(irq);
        local_irq_save(flags);

        handler(irq, dev_id);

        local_irq_restore(flags);
        enable_irq(irq);
    }
#endif
    return retval;
}


static int
__setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
{
    struct irqaction *old, **old_ptr;
    const char *old_name = NULL;
    unsigned long flags;
    int nested, shared = 0;
    int ret;

    if (!desc)
        return -EINVAL;

    if (desc->chip == &no_irq_chip)
        return -ENOSYS;
    /*
     * Some drivers like serial.c use request_irq() heavily,
     * so we have to be careful not to interfere with a
     * running system.
     */
    if (new->flags & IRQF_SAMPLE_RANDOM) {
        /*
         * This function might sleep, we want to call it first,
         * outside of the atomic block.
         * Yes, this might clear the entropy pool if the wrong
         * driver is attempted to be loaded, without actually
         * installing a new handler, but is this really a problem,
         * only the sysadmin is able to do this.
         */
        rand_initialize_irq(irq);
    }

    /* Oneshot interrupts are not allowed with shared */
    if ((new->flags & IRQF_ONESHOT) && (new->flags & IRQF_SHARED))
        return -EINVAL;

    /*
     * Check whether the interrupt nests into another interrupt
     * thread.
     */
    nested = desc->status & IRQ_NESTED_THREAD;
    if (nested) {
        if (!new->thread_fn)
            return -EINVAL;
        /*
         * Replace the primary handler which was provided from
         * the driver for non nested interrupt handling by the
         * dummy function which warns when called.
         */
        new->handler = irq_nested_primary_handler;
    }

    /*
     * Create a handler thread when a thread function is supplied
     * and the interrupt does not nest into another interrupt
     * thread.
     */
    if (new->thread_fn && !nested) {
        struct task_struct *t;

        t = kthread_create(irq_thread, new, "irq/%d-%s", irq,
                   new->name);
        if (IS_ERR(t))
            return PTR_ERR(t);
        /*
         * We keep the reference to the task struct even if
         * the thread dies to avoid that the interrupt code
         * references an already freed task_struct.
         */
        get_task_struct(t);
        new->thread = t;
    }

    /*
     * The following block of code has to be executed atomically
     */
    raw_spin_lock_irqsave(&desc->lock, flags);
    old_ptr = &desc->action;
    old = *old_ptr;
    if (old) {
        /*
         * Can't share interrupts unless both agree to and are
         * the same type (level, edge, polarity). So both flag
         * fields must have IRQF_SHARED set and the bits which
         * set the trigger type must match.
         */
        if (!((old->flags & new->flags) & IRQF_SHARED) ||
            ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) {
            old_name = old->name;
            goto mismatch;
        }

#if defined(CONFIG_IRQ_PER_CPU)
        /* All handlers must agree on per-cpuness */
        if ((old->flags & IRQF_PERCPU) !=
            (new->flags & IRQF_PERCPU))
            goto mismatch;
#endif

        /* add new interrupt at end of irq queue */
        do {
            old_ptr = &old->next;
            old = *old_ptr;
        } while (old);
        shared = 1;
    }

    if (!shared) {
        irq_chip_set_defaults(desc->chip);

        init_waitqueue_head(&desc->wait_for_threads);

        /* Setup the type (level, edge polarity) if configured: */
        if (new->flags & IRQF_TRIGGER_MASK) {
            ret = __irq_set_trigger(desc, irq,
                    new->flags & IRQF_TRIGGER_MASK);

            if (ret)
                goto out_thread;
        } else
            compat_irq_chip_set_default_handler(desc);
#if defined(CONFIG_IRQ_PER_CPU)
        if (new->flags & IRQF_PERCPU)
            desc->status |= IRQ_PER_CPU;
#endif

        desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | IRQ_ONESHOT |
                  IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);

        if (new->flags & IRQF_ONESHOT)
            desc->status |= IRQ_ONESHOT;

        if (!(desc->status & IRQ_NOAUTOEN)) {
            desc->depth = 0;
            desc->status &= ~IRQ_DISABLED;
            desc->chip->startup(irq);//调用chip的startup函数,其实就是default_startup,在default_startup中调用enable,在enable调用具体芯片的mpic_unmask_irq,这样不屏蔽该中断
        } else
            /* Undo nested disables: */
            desc->depth = 1;

        /* Exclude IRQ from balancing if requested */
        if (new->flags & IRQF_NOBALANCING)
            desc->status |= IRQ_NO_BALANCING;

        /* Set default affinity mask once everything is setup */
        setup_affinity(irq, desc);

    } else if ((new->flags & IRQF_TRIGGER_MASK)
            && (new->flags & IRQF_TRIGGER_MASK)
                != (desc->status & IRQ_TYPE_SENSE_MASK)) {
        /* hope the handler works with the actual trigger mode... */
        pr_warning("IRQ %d uses trigger mode %d; requested %d\n",
                irq, (int)(desc->status & IRQ_TYPE_SENSE_MASK),
                (int)(new->flags & IRQF_TRIGGER_MASK));
    }

    new->irq = irq;
    *old_ptr = new;

    /* Reset broken irq detection when installing new handler */
    desc->irq_count = 0;
    desc->irqs_unhandled = 0;

    /*
     * Check whether we disabled the irq via the spurious handler
     * before. Reenable it and give it another chance.
     */
    if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) {
        desc->status &= ~IRQ_SPURIOUS_DISABLED;
        __enable_irq(desc, irq, false);
    }

    raw_spin_unlock_irqrestore(&desc->lock, flags);

    /*
     * Strictly no need to wake it up, but hung_task complains
     * when no hard interrupt wakes the thread up.
     */
    if (new->thread)
        wake_up_process(new->thread);

    register_irq_proc(irq, desc);
    new->dir = NULL;
    register_handler_proc(irq, new);

    return 0;

mismatch:
#ifdef CONFIG_DEBUG_SHIRQ
    if (!(new->flags & IRQF_PROBE_SHARED)) {
        printk(KERN_ERR "IRQ handler type mismatch for IRQ %d\n", irq);
        if (old_name)
            printk(KERN_ERR "current handler: %s\n", old_name);
        dump_stack();
    }
#endif
    ret = -EBUSY;

out_thread:
    raw_spin_unlock_irqrestore(&desc->lock, flags);
    if (new->thread) {
        struct task_struct *t = new->thread;

        new->thread = NULL;
        if (likely(!test_bit(IRQTF_DIED, &new->thread_flags)))
            kthread_stop(t);
        put_task_struct(t);
    }
    return ret;
}

//arch/powerpc/sysdev/mpic.c
void mpic_unmask_irq(unsigned int irq)
{
    unsigned int loops = 100000;
    struct mpic *mpic = mpic_from_irq(irq);
    unsigned int src = mpic_irq_to_hw(irq);

    DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src);

    mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI),
               mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) &
               ~MPIC_VECPRI_MASK);
    /* make sure mask gets to controller before we return to user */
    do {
        if (!loops--) {
            printk(KERN_ERR "mpic_enable_irq timeout\n");
            break;
        }
    } while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK);
}

阅读(2090) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~