cregit-Linux how code gets into the kernel

Release 4.14 arch/powerpc/sysdev/ipic.c

/*
 * arch/powerpc/sysdev/ipic.c
 *
 * IPIC routines implementations.
 *
 * Copyright 2005 Freescale Semiconductor, Inc.
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/reboot.h>
#include <linux/slab.h>
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/syscore_ops.h>
#include <linux/device.h>
#include <linux/spinlock.h>
#include <linux/fsl_devices.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/ipic.h>

#include "ipic.h"


static struct ipic * primary_ipic;


static struct irq_chip ipic_level_irq_chip, ipic_edge_irq_chip;
static DEFINE_RAW_SPINLOCK(ipic_lock);


static struct ipic_info ipic_info[] = {
	[1] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_C,
		.force	= IPIC_SIFCR_H,
		.bit	= 16,
		.prio_mask = 0,
        },
	[2] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_C,
		.force	= IPIC_SIFCR_H,
		.bit	= 17,
		.prio_mask = 1,
        },
	[3] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_C,
		.force	= IPIC_SIFCR_H,
		.bit	= 18,
		.prio_mask = 2,
        },
	[4] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_C,
		.force	= IPIC_SIFCR_H,
		.bit	= 19,
		.prio_mask = 3,
        },
	[5] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_C,
		.force	= IPIC_SIFCR_H,
		.bit	= 20,
		.prio_mask = 4,
        },
	[6] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_C,
		.force	= IPIC_SIFCR_H,
		.bit	= 21,
		.prio_mask = 5,
        },
	[7] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_C,
		.force	= IPIC_SIFCR_H,
		.bit	= 22,
		.prio_mask = 6,
        },
	[8] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_C,
		.force	= IPIC_SIFCR_H,
		.bit	= 23,
		.prio_mask = 7,
        },
	[9] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_D,
		.force	= IPIC_SIFCR_H,
		.bit	= 24,
		.prio_mask = 0,
        },
	[10] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_D,
		.force	= IPIC_SIFCR_H,
		.bit	= 25,
		.prio_mask = 1,
        },
	[11] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_D,
		.force	= IPIC_SIFCR_H,
		.bit	= 26,
		.prio_mask = 2,
        },
	[12] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_D,
		.force	= IPIC_SIFCR_H,
		.bit	= 27,
		.prio_mask = 3,
        },
	[13] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_D,
		.force	= IPIC_SIFCR_H,
		.bit	= 28,
		.prio_mask = 4,
        },
	[14] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_D,
		.force	= IPIC_SIFCR_H,
		.bit	= 29,
		.prio_mask = 5,
        },
	[15] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_D,
		.force	= IPIC_SIFCR_H,
		.bit	= 30,
		.prio_mask = 6,
        },
	[16] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_D,
		.force	= IPIC_SIFCR_H,
		.bit	= 31,
		.prio_mask = 7,
        },
	[17] = {
		.ack	= IPIC_SEPNR,
		.mask	= IPIC_SEMSR,
		.prio	= IPIC_SMPRR_A,
		.force	= IPIC_SEFCR,
		.bit	= 1,
		.prio_mask = 5,
        },
	[18] = {
		.ack	= IPIC_SEPNR,
		.mask	= IPIC_SEMSR,
		.prio	= IPIC_SMPRR_A,
		.force	= IPIC_SEFCR,
		.bit	= 2,
		.prio_mask = 6,
        },
	[19] = {
		.ack	= IPIC_SEPNR,
		.mask	= IPIC_SEMSR,
		.prio	= IPIC_SMPRR_A,
		.force	= IPIC_SEFCR,
		.bit	= 3,
		.prio_mask = 7,
        },
	[20] = {
		.ack	= IPIC_SEPNR,
		.mask	= IPIC_SEMSR,
		.prio	= IPIC_SMPRR_B,
		.force	= IPIC_SEFCR,
		.bit	= 4,
		.prio_mask = 4,
        },
	[21] = {
		.ack	= IPIC_SEPNR,
		.mask	= IPIC_SEMSR,
		.prio	= IPIC_SMPRR_B,
		.force	= IPIC_SEFCR,
		.bit	= 5,
		.prio_mask = 5,
        },
	[22] = {
		.ack	= IPIC_SEPNR,
		.mask	= IPIC_SEMSR,
		.prio	= IPIC_SMPRR_B,
		.force	= IPIC_SEFCR,
		.bit	= 6,
		.prio_mask = 6,
        },
	[23] = {
		.ack	= IPIC_SEPNR,
		.mask	= IPIC_SEMSR,
		.prio	= IPIC_SMPRR_B,
		.force	= IPIC_SEFCR,
		.bit	= 7,
		.prio_mask = 7,
        },
	[32] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_A,
		.force	= IPIC_SIFCR_H,
		.bit	= 0,
		.prio_mask = 0,
        },
	[33] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_A,
		.force	= IPIC_SIFCR_H,
		.bit	= 1,
		.prio_mask = 1,
        },
	[34] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_A,
		.force	= IPIC_SIFCR_H,
		.bit	= 2,
		.prio_mask = 2,
        },
	[35] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_A,
		.force	= IPIC_SIFCR_H,
		.bit	= 3,
		.prio_mask = 3,
        },
	[36] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_A,
		.force	= IPIC_SIFCR_H,
		.bit	= 4,
		.prio_mask = 4,
        },
	[37] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_A,
		.force	= IPIC_SIFCR_H,
		.bit	= 5,
		.prio_mask = 5,
        },
	[38] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_A,
		.force	= IPIC_SIFCR_H,
		.bit	= 6,
		.prio_mask = 6,
        },
	[39] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_A,
		.force	= IPIC_SIFCR_H,
		.bit	= 7,
		.prio_mask = 7,
        },
	[40] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_B,
		.force	= IPIC_SIFCR_H,
		.bit	= 8,
		.prio_mask = 0,
        },
	[41] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_B,
		.force	= IPIC_SIFCR_H,
		.bit	= 9,
		.prio_mask = 1,
        },
	[42] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_B,
		.force	= IPIC_SIFCR_H,
		.bit	= 10,
		.prio_mask = 2,
        },
	[43] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_B,
		.force	= IPIC_SIFCR_H,
		.bit	= 11,
		.prio_mask = 3,
        },
	[44] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_B,
		.force	= IPIC_SIFCR_H,
		.bit	= 12,
		.prio_mask = 4,
        },
	[45] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_B,
		.force	= IPIC_SIFCR_H,
		.bit	= 13,
		.prio_mask = 5,
        },
	[46] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_B,
		.force	= IPIC_SIFCR_H,
		.bit	= 14,
		.prio_mask = 6,
        },
	[47] = {
		.mask	= IPIC_SIMSR_H,
		.prio	= IPIC_SIPRR_B,
		.force	= IPIC_SIFCR_H,
		.bit	= 15,
		.prio_mask = 7,
        },
	[48] = {
		.ack	= IPIC_SEPNR,
		.mask	= IPIC_SEMSR,
		.prio	= IPIC_SMPRR_A,
		.force	= IPIC_SEFCR,
		.bit	= 0,
		.prio_mask = 4,
        },
	[64] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= IPIC_SMPRR_A,
		.force	= IPIC_SIFCR_L,
		.bit	= 0,
		.prio_mask = 0,
        },
	[65] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= IPIC_SMPRR_A,
		.force	= IPIC_SIFCR_L,
		.bit	= 1,
		.prio_mask = 1,
        },
	[66] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= IPIC_SMPRR_A,
		.force	= IPIC_SIFCR_L,
		.bit	= 2,
		.prio_mask = 2,
        },
	[67] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= IPIC_SMPRR_A,
		.force	= IPIC_SIFCR_L,
		.bit	= 3,
		.prio_mask = 3,
        },
	[68] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= IPIC_SMPRR_B,
		.force	= IPIC_SIFCR_L,
		.bit	= 4,
		.prio_mask = 0,
        },
	[69] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= IPIC_SMPRR_B,
		.force	= IPIC_SIFCR_L,
		.bit	= 5,
		.prio_mask = 1,
        },
	[70] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= IPIC_SMPRR_B,
		.force	= IPIC_SIFCR_L,
		.bit	= 6,
		.prio_mask = 2,
        },
	[71] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= IPIC_SMPRR_B,
		.force	= IPIC_SIFCR_L,
		.bit	= 7,
		.prio_mask = 3,
        },
	[72] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 8,
        },
	[73] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 9,
        },
	[74] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 10,
        },
	[75] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 11,
        },
	[76] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 12,
        },
	[77] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 13,
        },
	[78] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 14,
        },
	[79] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 15,
        },
	[80] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 16,
        },
	[81] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 17,
        },
	[82] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 18,
        },
	[83] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 19,
        },
	[84] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 20,
        },
	[85] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 21,
        },
	[86] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 22,
        },
	[87] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 23,
        },
	[88] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 24,
        },
	[89] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 25,
        },
	[90] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 26,
        },
	[91] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 27,
        },
	[94] = {
		.mask	= IPIC_SIMSR_L,
		.prio	= 0,
		.force	= IPIC_SIFCR_L,
		.bit	= 30,
        },
};


static inline u32 ipic_read(volatile u32 __iomem *base, unsigned int reg) { return in_be32(base + (reg >> 2)); }

Contributors

PersonTokensPropCommitsCommitProp
Kumar Gala29100.00%1100.00%
Total29100.00%1100.00%


static inline void ipic_write(volatile u32 __iomem *base, unsigned int reg, u32 value) { out_be32(base + (reg >> 2), value); }

Contributors

PersonTokensPropCommitsCommitProp
Kumar Gala33100.00%1100.00%
Total33100.00%1100.00%


static inline struct ipic * ipic_from_irq(unsigned int virq) { return primary_ipic; }

Contributors

PersonTokensPropCommitsCommitProp
Kumar Gala1593.75%150.00%
Kim Phillips16.25%150.00%
Total16100.00%2100.00%


static void ipic_unmask_irq(struct irq_data *d) { struct ipic *ipic = ipic_from_irq(d->irq); unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 temp; raw_spin_lock_irqsave(&ipic_lock, flags); temp = ipic_read(ipic->regs, ipic_info[src].mask); temp |= (1 << (31 - ipic_info[src].bit)); ipic_write(ipic->regs, ipic_info[src].mask, temp); raw_spin_unlock_irqrestore(&ipic_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Kumar Gala7269.23%120.00%
Kim Phillips2120.19%120.00%
Lennert Buytenhek87.69%120.00%
Thomas Gleixner21.92%120.00%
Grant C. Likely10.96%120.00%
Total104100.00%5100.00%


static void ipic_mask_irq(struct irq_data *d) { struct ipic *ipic = ipic_from_irq(d->irq); unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 temp; raw_spin_lock_irqsave(&ipic_lock, flags); temp = ipic_read(ipic->regs, ipic_info[src].mask); temp &= ~(1 << (31 - ipic_info[src].bit)); ipic_write(ipic->regs, ipic_info[src].mask, temp); /* mb() can't guarantee that masking is finished. But it does finish * for nearly all cases. */ mb(); raw_spin_unlock_irqrestore(&ipic_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Kumar Gala7366.97%116.67%
Kim Phillips2119.27%116.67%
Lennert Buytenhek87.34%116.67%
Li Yang43.67%116.67%
Thomas Gleixner21.83%116.67%
Grant C. Likely10.92%116.67%
Total109100.00%6100.00%


static void ipic_ack_irq(struct irq_data *d) { struct ipic *ipic = ipic_from_irq(d->irq); unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 temp; raw_spin_lock_irqsave(&ipic_lock, flags); temp = 1 << (31 - ipic_info[src].bit); ipic_write(ipic->regs, ipic_info[src].ack, temp); /* mb() can't guarantee that ack is finished. But it does finish * for nearly all cases. */ mb(); raw_spin_unlock_irqrestore(&ipic_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Kumar Gala5662.22%116.67%
Kim Phillips1820.00%116.67%
Lennert Buytenhek88.89%116.67%
Li Yang55.56%116.67%
Thomas Gleixner22.22%116.67%
Grant C. Likely11.11%116.67%
Total90100.00%6100.00%


static void ipic_mask_irq_and_ack(struct irq_data *d) { struct ipic *ipic = ipic_from_irq(d->irq); unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 temp; raw_spin_lock_irqsave(&ipic_lock, flags); temp = ipic_read(ipic->regs, ipic_info[src].mask); temp &= ~(1 << (31 - ipic_info[src].bit)); ipic_write(ipic->regs, ipic_info[src].mask, temp); temp = 1 << (31 - ipic_info[src].bit); ipic_write(ipic->regs, ipic_info[src].ack, temp); /* mb() can't guarantee that ack is finished. But it does finish * for nearly all cases. */ mb(); raw_spin_unlock_irqrestore(&ipic_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Kim Phillips9265.71%116.67%
Kumar Gala3222.86%116.67%
Lennert Buytenhek85.71%116.67%
Li Yang53.57%116.67%
Thomas Gleixner21.43%116.67%
Grant C. Likely10.71%116.67%
Total140100.00%6100.00%


static int ipic_set_irq_type(struct irq_data *d, unsigned int flow_type) { struct ipic *ipic = ipic_from_irq(d->irq); unsigned int src = irqd_to_hwirq(d); unsigned int vold, vnew, edibit; if (flow_type == IRQ_TYPE_NONE) flow_type = IRQ_TYPE_LEVEL_LOW; /* ipic supports only low assertion and high-to-low change senses */ if (!(flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))) { printk(KERN_ERR "ipic: sense type 0x%x not supported\n", flow_type); return -EINVAL; } /* ipic supports only edge mode on external interrupts */ if ((flow_type & IRQ_TYPE_EDGE_FALLING) && !ipic_info[src].ack) { printk(KERN_ERR "ipic: edge sense not supported on internal " "interrupts\n"); return -EINVAL; } irqd_set_trigger_type(d, flow_type); if (flow_type & IRQ_TYPE_LEVEL_LOW) { irq_set_handler_locked(d, handle_level_irq); d->chip = &ipic_level_irq_chip; } else { irq_set_handler_locked(d, handle_edge_irq); d->chip = &ipic_edge_irq_chip; } /* only EXT IRQ senses are programmable on ipic * internal IRQ senses are LEVEL_LOW */ if (src == IPIC_IRQ_EXT0) edibit = 15; else if (src >= IPIC_IRQ_EXT1 && src <= IPIC_IRQ_EXT7) edibit = (14 - (src - IPIC_IRQ_EXT1)); else return (flow_type & IRQ_TYPE_LEVEL_LOW) ? 0 : -EINVAL; vold = ipic_read(ipic->regs, IPIC_SECNR); if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING) { vnew = vold | (1 << edibit); } else { vnew = vold & ~(1 << edibit); } if (vold != vnew) ipic_write(ipic->regs, IPIC_SECNR, vnew); return IRQ_SET_MASK_OK_NOCOPY; }

Contributors

PersonTokensPropCommitsCommitProp
Kim Phillips20374.63%116.67%
Li Yang4215.44%116.67%
Thomas Gleixner186.62%233.33%
Lennert Buytenhek82.94%116.67%
Grant C. Likely10.37%116.67%
Total272100.00%6100.00%

/* level interrupts and edge interrupts have different ack operations */ static struct irq_chip ipic_level_irq_chip = { .name = "IPIC", .irq_unmask = ipic_unmask_irq, .irq_mask = ipic_mask_irq, .irq_mask_ack = ipic_mask_irq, .irq_set_type = ipic_set_irq_type, }; static struct irq_chip ipic_edge_irq_chip = { .name = "IPIC", .irq_unmask = ipic_unmask_irq, .irq_mask