📄 pq2ads-pci-pic.c
字号:
/* * PQ2 ADS-style PCI interrupt controller * * Copyright 2007 Freescale Semiconductor, Inc. * Author: Scott Wood <scottwood@freescale.com> * * Loosely based on mpc82xx ADS support by Vitaly Bordug <vbordug@ru.mvista.com> * Copyright (c) 2006 MontaVista Software, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. */#include <linux/init.h>#include <linux/spinlock.h>#include <linux/irq.h>#include <linux/types.h>#include <linux/bootmem.h>#include <asm/io.h>#include <asm/prom.h>#include <asm/cpm2.h>#include "pq2.h"static DEFINE_SPINLOCK(pci_pic_lock);struct pq2ads_pci_pic { struct device_node *node; struct irq_host *host; struct { u32 stat; u32 mask; } __iomem *regs;};#define NUM_IRQS 32static void pq2ads_pci_mask_irq(unsigned int virq){ struct pq2ads_pci_pic *priv = get_irq_chip_data(virq); int irq = NUM_IRQS - virq_to_hw(virq) - 1; if (irq != -1) { unsigned long flags; spin_lock_irqsave(&pci_pic_lock, flags); setbits32(&priv->regs->mask, 1 << irq); mb(); spin_unlock_irqrestore(&pci_pic_lock, flags); }}static void pq2ads_pci_unmask_irq(unsigned int virq){ struct pq2ads_pci_pic *priv = get_irq_chip_data(virq); int irq = NUM_IRQS - virq_to_hw(virq) - 1; if (irq != -1) { unsigned long flags; spin_lock_irqsave(&pci_pic_lock, flags); clrbits32(&priv->regs->mask, 1 << irq); spin_unlock_irqrestore(&pci_pic_lock, flags); }}static struct irq_chip pq2ads_pci_ic = { .typename = "PQ2 ADS PCI", .name = "PQ2 ADS PCI", .end = pq2ads_pci_unmask_irq, .mask = pq2ads_pci_mask_irq, .mask_ack = pq2ads_pci_mask_irq, .ack = pq2ads_pci_mask_irq, .unmask = pq2ads_pci_unmask_irq, .enable = pq2ads_pci_unmask_irq, .disable = pq2ads_pci_mask_irq};static void pq2ads_pci_irq_demux(unsigned int irq, struct irq_desc *desc){ struct pq2ads_pci_pic *priv = desc->handler_data; u32 stat, mask, pend; int bit; for (;;) { stat = in_be32(&priv->regs->stat); mask = in_be32(&priv->regs->mask); pend = stat & ~mask; if (!pend) break; for (bit = 0; pend != 0; ++bit, pend <<= 1) { if (pend & 0x80000000) { int virq = irq_linear_revmap(priv->host, bit); generic_handle_irq(virq); } } }}static int pci_pic_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw){ get_irq_desc(virq)->status |= IRQ_LEVEL; set_irq_chip_data(virq, h->host_data); set_irq_chip(virq, &pq2ads_pci_ic); return 0;}static void pci_host_unmap(struct irq_host *h, unsigned int virq){ /* remove chip and handler */ set_irq_chip_data(virq, NULL); set_irq_chip(virq, NULL);}static struct irq_host_ops pci_pic_host_ops = { .map = pci_pic_host_map, .unmap = pci_host_unmap,};int __init pq2ads_pci_init_irq(void){ struct pq2ads_pci_pic *priv; struct irq_host *host; struct device_node *np; int ret = -ENODEV; int irq; np = of_find_compatible_node(NULL, NULL, "fsl,pq2ads-pci-pic"); if (!np) { printk(KERN_ERR "No pci pic node in device tree.\n"); of_node_put(np); goto out; } irq = irq_of_parse_and_map(np, 0); if (irq == NO_IRQ) { printk(KERN_ERR "No interrupt in pci pic node.\n"); of_node_put(np); goto out; } priv = alloc_bootmem(sizeof(struct pq2ads_pci_pic)); if (!priv) { of_node_put(np); ret = -ENOMEM; goto out_unmap_irq; } /* PCI interrupt controller registers: status and mask */ priv->regs = of_iomap(np, 0); if (!priv->regs) { printk(KERN_ERR "Cannot map PCI PIC registers.\n"); goto out_free_bootmem; } /* mask all PCI interrupts */ out_be32(&priv->regs->mask, ~0); mb(); host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, NUM_IRQS, &pci_pic_host_ops, NUM_IRQS); if (!host) { ret = -ENOMEM; goto out_unmap_regs; } host->host_data = priv; priv->host = host; host->host_data = priv; set_irq_data(irq, priv); set_irq_chained_handler(irq, pq2ads_pci_irq_demux); of_node_put(np); return 0;out_unmap_regs: iounmap(priv->regs);out_free_bootmem: free_bootmem((unsigned long)priv, sizeof(sizeof(struct pq2ads_pci_pic))); of_node_put(np);out_unmap_irq: irq_dispose_mapping(irq);out: return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -