cregit-Linux how code gets into the kernel

Release 4.14 arch/powerpc/kvm/mpic.c

Directory: arch/powerpc/kvm
/*
 * OpenPIC emulation
 *
 * Copyright (c) 2004 Jocelyn Mayer
 *               2011 Alexander Graf
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/kvm_host.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/anon_inodes.h>
#include <linux/uaccess.h>
#include <asm/mpic.h>
#include <asm/kvm_para.h>
#include <asm/kvm_host.h>
#include <asm/kvm_ppc.h>
#include <kvm/iodev.h>


#define MAX_CPU     32

#define MAX_SRC     256

#define MAX_TMR     4

#define MAX_IPI     4

#define MAX_MSI     8

#define MAX_IRQ     (MAX_SRC + MAX_IPI + MAX_TMR)

#define VID         0x03	
/* MPIC version ID */

/* OpenPIC capability flags */

#define OPENPIC_FLAG_IDR_CRIT     (1 << 0)

#define OPENPIC_FLAG_ILR          (2 << 0)

/* OpenPIC address map */

#define OPENPIC_REG_SIZE             0x40000

#define OPENPIC_GLB_REG_START        0x0

#define OPENPIC_GLB_REG_SIZE         0x10F0

#define OPENPIC_TMR_REG_START        0x10F0

#define OPENPIC_TMR_REG_SIZE         0x220

#define OPENPIC_MSI_REG_START        0x1600

#define OPENPIC_MSI_REG_SIZE         0x200

#define OPENPIC_SUMMARY_REG_START    0x3800

#define OPENPIC_SUMMARY_REG_SIZE     0x800

#define OPENPIC_SRC_REG_START        0x10000

#define OPENPIC_SRC_REG_SIZE         (MAX_SRC * 0x20)

#define OPENPIC_CPU_REG_START        0x20000

#define OPENPIC_CPU_REG_SIZE         (0x100 + ((MAX_CPU - 1) * 0x1000))


struct fsl_mpic_info {
	
int max_ext;
};


static struct fsl_mpic_info fsl_mpic_20 = {
	.max_ext = 12,
};


static struct fsl_mpic_info fsl_mpic_42 = {
	.max_ext = 12,
};


#define FRR_NIRQ_SHIFT    16

#define FRR_NCPU_SHIFT     8

#define FRR_VID_SHIFT      0


#define VID_REVISION_1_2   2

#define VID_REVISION_1_3   3


#define VIR_GENERIC      0x00000000	
/* Generic Vendor ID */


#define GCR_RESET        0x80000000

#define GCR_MODE_PASS    0x00000000

#define GCR_MODE_MIXED   0x20000000

#define GCR_MODE_PROXY   0x60000000


#define TBCR_CI           0x80000000	
/* count inhibit */

#define TCCR_TOG          0x80000000	
/* toggles when decrement to zero */


#define IDR_EP_SHIFT      31

#define IDR_EP_MASK       (1 << IDR_EP_SHIFT)

#define IDR_CI0_SHIFT     30

#define IDR_CI1_SHIFT     29

#define IDR_P1_SHIFT      1

#define IDR_P0_SHIFT      0


#define ILR_INTTGT_MASK   0x000000ff

#define ILR_INTTGT_INT    0x00

#define ILR_INTTGT_CINT   0x01	
/* critical */

#define ILR_INTTGT_MCP    0x02	
/* machine check */

#define NUM_OUTPUTS       3


#define MSIIR_OFFSET       0x140

#define MSIIR_SRS_SHIFT    29

#define MSIIR_SRS_MASK     (0x7 << MSIIR_SRS_SHIFT)

#define MSIIR_IBS_SHIFT    24

#define MSIIR_IBS_MASK     (0x1f << MSIIR_IBS_SHIFT)


static int get_current_cpu(void) { #if defined(CONFIG_KVM) && defined(CONFIG_BOOKE) struct kvm_vcpu *vcpu = current->thread.kvm_vcpu; return vcpu ? vcpu->arch.irq_cpu_id : -1; #else /* XXX */ return -1; #endif }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood51100.00%4100.00%
Total51100.00%4100.00%

static int openpic_cpu_write_internal(void *opaque, gpa_t addr, u32 val, int idx); static int openpic_cpu_read_internal(void *opaque, gpa_t addr, u32 *ptr, int idx); static inline void write_IRQreg_idr(struct openpic *opp, int n_IRQ, uint32_t val); enum irq_type { IRQ_TYPE_NORMAL = 0, IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */ IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */ }; struct irq_queue { /* Round up to the nearest 64 IRQs so that the queue length * won't change when moving between 32 and 64 bit hosts. */ unsigned long queue[BITS_TO_LONGS((MAX_IRQ + 63) & ~63)]; int next; int priority; }; struct irq_source { uint32_t ivpr; /* IRQ vector/priority register */ uint32_t idr; /* IRQ destination register */ uint32_t destmask; /* bitmap of CPU destinations */ int last_cpu; int output; /* IRQ level, e.g. ILR_INTTGT_INT */ int pending; /* TRUE if IRQ is pending */ enum irq_type type; bool level:1; /* level-triggered */ bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */ }; #define IVPR_MASK_SHIFT 31 #define IVPR_MASK_MASK (1 << IVPR_MASK_SHIFT) #define IVPR_ACTIVITY_SHIFT 30 #define IVPR_ACTIVITY_MASK (1 << IVPR_ACTIVITY_SHIFT) #define IVPR_MODE_SHIFT 29 #define IVPR_MODE_MASK (1 << IVPR_MODE_SHIFT) #define IVPR_POLARITY_SHIFT 23 #define IVPR_POLARITY_MASK (1 << IVPR_POLARITY_SHIFT) #define IVPR_SENSE_SHIFT 22 #define IVPR_SENSE_MASK (1 << IVPR_SENSE_SHIFT) #define IVPR_PRIORITY_MASK (0xF << 16) #define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16)) #define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask) /* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */ #define IDR_EP 0x80000000 /* external pin */ #define IDR_CI 0x40000000 /* critical interrupt */ struct irq_dest { struct kvm_vcpu *vcpu; int32_t ctpr; /* CPU current task priority */ struct irq_queue raised; struct irq_queue servicing; /* Count of IRQ sources asserting on non-INT outputs */ uint32_t outputs_active[NUM_OUTPUTS]; }; #define MAX_MMIO_REGIONS 10 struct openpic { struct kvm *kvm; struct kvm_device *dev; struct kvm_io_device mmio; const struct mem_reg *mmio_regions[MAX_MMIO_REGIONS]; int num_mmio_regions; gpa_t reg_base; spinlock_t lock; /* Behavior control */ struct fsl_mpic_info *fsl; uint32_t model; uint32_t flags; uint32_t nb_irqs; uint32_t vid; uint32_t vir; /* Vendor identification register */ uint32_t vector_mask; uint32_t tfrr_reset; uint32_t ivpr_reset; uint32_t idr_reset; uint32_t brr1; uint32_t mpic_mode_mask; /* Global registers */ uint32_t frr; /* Feature reporting register */ uint32_t gcr; /* Global configuration register */ uint32_t pir; /* Processor initialization register */ uint32_t spve; /* Spurious vector register */ uint32_t tfrr; /* Timer frequency reporting register */ /* Source registers */ struct irq_source src[MAX_IRQ]; /* Local registers per output pin */ struct irq_dest dst[MAX_CPU]; uint32_t nb_cpus; /* Timer registers */ struct { uint32_t tccr; /* Global timer current count register */ uint32_t tbcr; /* Global timer base count register */ } timers[MAX_TMR]; /* Shared MSI registers */ struct { uint32_t msir; /* Shared Message Signaled Interrupt Register */ } msi[MAX_MSI]; uint32_t max_irq; uint32_t irq_ipi0; uint32_t irq_tim0; uint32_t irq_msi; };
static void mpic_irq_raise(struct openpic *opp, struct irq_dest *dst, int output) { struct kvm_interrupt irq = { .irq = KVM_INTERRUPT_SET_LEVEL, }; if (!dst->vcpu) { pr_debug("%s: destination cpu %d does not exist\n", __func__, (int)(dst - &opp->dst[0])); return; } pr_debug("%s: cpu %d output %d\n", __func__, dst->vcpu->arch.irq_cpu_id, output); if (output != ILR_INTTGT_INT) /* TODO */ return; kvm_vcpu_ioctl_interrupt(dst->vcpu, &irq); }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood97100.00%2100.00%
Total97100.00%2100.00%


static void mpic_irq_lower(struct openpic *opp, struct irq_dest *dst, int output) { if (!dst->vcpu) { pr_debug("%s: destination cpu %d does not exist\n", __func__, (int)(dst - &opp->dst[0])); return; } pr_debug("%s: cpu %d output %d\n", __func__, dst->vcpu->arch.irq_cpu_id, output); if (output != ILR_INTTGT_INT) /* TODO */ return; kvmppc_core_dequeue_external(dst->vcpu); }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood83100.00%2100.00%
Total83100.00%2100.00%


static inline void IRQ_setbit(struct irq_queue *q, int n_IRQ) { set_bit(n_IRQ, q->queue); }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood24100.00%2100.00%
Total24100.00%2100.00%


static inline void IRQ_resetbit(struct irq_queue *q, int n_IRQ) { clear_bit(n_IRQ, q->queue); }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood24100.00%2100.00%
Total24100.00%2100.00%


static void IRQ_check(struct openpic *opp, struct irq_queue *q) { int irq = -1; int next = -1; int priority = -1; for (;;) { irq = find_next_bit(q->queue, opp->max_irq, irq + 1); if (irq == opp->max_irq) break; pr_debug("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n", irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority); if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) { next = irq; priority = IVPR_PRIORITY(opp->src[irq].ivpr); } } q->next = next; q->priority = priority; }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood136100.00%2100.00%
Total136100.00%2100.00%


static int IRQ_get_next(struct openpic *opp, struct irq_queue *q) { /* XXX: optimize */ IRQ_check(opp, q); return q->next; }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood29100.00%2100.00%
Total29100.00%2100.00%


static void IRQ_local_pipe(struct openpic *opp, int n_CPU, int n_IRQ, bool active, bool was_active) { struct irq_dest *dst; struct irq_source *src; int priority; dst = &opp->dst[n_CPU]; src = &opp->src[n_IRQ]; pr_debug("%s: IRQ %d active %d was %d\n", __func__, n_IRQ, active, was_active); if (src->output != ILR_INTTGT_INT) { pr_debug("%s: output %d irq %d active %d was %d count %d\n", __func__, src->output, n_IRQ, active, was_active, dst->outputs_active[src->output]); /* On Freescale MPIC, critical interrupts ignore priority, * IACK, EOI, etc. Before MPIC v4.1 they also ignore * masking. */ if (active) { if (!was_active && dst->outputs_active[src->output]++ == 0) { pr_debug("%s: Raise OpenPIC output %d cpu %d irq %d\n", __func__, src->output, n_CPU, n_IRQ); mpic_irq_raise(opp, dst, src->output); } } else { if (was_active && --dst->outputs_active[src->output] == 0) { pr_debug("%s: Lower OpenPIC output %d cpu %d irq %d\n", __func__, src->output, n_CPU, n_IRQ); mpic_irq_lower(opp, dst, src->output); } } return; } priority = IVPR_PRIORITY(src->ivpr); /* Even if the interrupt doesn't have enough priority, * it is still raised, in case ctpr is lowered later. */ if (active) IRQ_setbit(&dst->raised, n_IRQ); else IRQ_resetbit(&dst->raised, n_IRQ); IRQ_check(opp, &dst->raised); if (active && priority <= dst->ctpr) { pr_debug("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n", __func__, n_IRQ, priority, dst->ctpr, n_CPU); active = 0; } if (active) { if (IRQ_get_next(opp, &dst->servicing) >= 0 && priority <= dst->servicing.priority) { pr_debug("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", __func__, n_IRQ, dst->servicing.next, n_CPU); } else { pr_debug("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n", __func__, n_CPU, n_IRQ, dst->raised.next); mpic_irq_raise(opp, dst, ILR_INTTGT_INT); } } else { IRQ_get_next(opp, &dst->servicing); if (dst->raised.priority > dst->ctpr && dst->raised.priority > dst->servicing.priority) { pr_debug("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n", __func__, n_IRQ, dst->raised.next, dst->raised.priority, dst->ctpr, dst->servicing.priority, n_CPU); /* IRQ line stays asserted */ } else { pr_debug("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n", __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU); mpic_irq_lower(opp, dst, ILR_INTTGT_INT); } } }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood465100.00%3100.00%
Total465100.00%3100.00%

/* update pic state because registers for n_IRQ have changed value */
static void openpic_update_irq(struct openpic *opp, int n_IRQ) { struct irq_source *src; bool active, was_active; int i; src = &opp->src[n_IRQ]; active = src->pending; if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) { /* Interrupt source is disabled */ pr_debug("%s: IRQ %d is disabled\n", __func__, n_IRQ); active = false; } was_active = !!(src->ivpr & IVPR_ACTIVITY_MASK); /* * We don't have a similar check for already-active because * ctpr may have changed and we need to withdraw the interrupt. */ if (!active && !was_active) { pr_debug("%s: IRQ %d is already inactive\n", __func__, n_IRQ); return; } if (active) src->ivpr |= IVPR_ACTIVITY_MASK; else src->ivpr &= ~IVPR_ACTIVITY_MASK; if (src->destmask == 0) { /* No target */ pr_debug("%s: IRQ %d has no target\n", __func__, n_IRQ); return; } if (src->destmask == (1 << src->last_cpu)) { /* Only one CPU is allowed to receive this IRQ */ IRQ_local_pipe(opp, src->last_cpu, n_IRQ, active, was_active); } else if (!(src->ivpr & IVPR_MODE_MASK)) { /* Directed delivery mode */ for (i = 0; i < opp->nb_cpus; i++) { if (src->destmask & (1 << i)) { IRQ_local_pipe(opp, i, n_IRQ, active, was_active); } } } else { /* Distributed delivery mode */ for (i = src->last_cpu + 1; i != src->last_cpu; i++) { if (i == opp->nb_cpus) i = 0; if (src->destmask & (1 << i)) { IRQ_local_pipe(opp, i, n_IRQ, active, was_active); src->last_cpu = i; break; } } } }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood308100.00%2100.00%
Total308100.00%2100.00%


static void openpic_set_irq(void *opaque, int n_IRQ, int level) { struct openpic *opp = opaque; struct irq_source *src; if (n_IRQ >= MAX_IRQ) { WARN_ONCE(1, "%s: IRQ %d out of range\n", __func__, n_IRQ); return; } src = &opp->src[n_IRQ]; pr_debug("openpic: set irq %d = %d ivpr=0x%08x\n", n_IRQ, level, src->ivpr); if (src->level) { /* level-sensitive irq */ src->pending = level; openpic_update_irq(opp, n_IRQ); } else { /* edge-sensitive irq */ if (level) { src->pending = 1; openpic_update_irq(opp, n_IRQ); } if (src->output != ILR_INTTGT_INT) { /* Edge-triggered interrupts shouldn't be used * with non-INT delivery, but just in case, * try to make it do something sane rather than * cause an interrupt storm. This is close to * what you'd probably see happen in real hardware. */ src->pending = 0; openpic_update_irq(opp, n_IRQ); } } }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood140100.00%3100.00%
Total140100.00%3100.00%


static void openpic_reset(struct openpic *opp) { int i; opp->gcr = GCR_RESET; /* Initialise controller registers */ opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) | (opp->vid << FRR_VID_SHIFT); opp->pir = 0; opp->spve = -1 & opp->vector_mask; opp->tfrr = opp->tfrr_reset; /* Initialise IRQ sources */ for (i = 0; i < opp->max_irq; i++) { opp->src[i].ivpr = opp->ivpr_reset; switch (opp->src[i].type) { case IRQ_TYPE_NORMAL: opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK); break; case IRQ_TYPE_FSLINT: opp->src[i].ivpr |= IVPR_POLARITY_MASK; break; case IRQ_TYPE_FSLSPECIAL: break; } write_IRQreg_idr(opp, i, opp->idr_reset); } /* Initialise IRQ destinations */ for (i = 0; i < MAX_CPU; i++) { opp->dst[i].ctpr = 15; memset(&opp->dst[i].raised, 0, sizeof(struct irq_queue)); opp->dst[i].raised.next = -1; memset(&opp->dst[i].servicing, 0, sizeof(struct irq_queue)); opp->dst[i].servicing.next = -1; } /* Initialise timers */ for (i = 0; i < MAX_TMR; i++) { opp->timers[i].tccr = 0; opp->timers[i].tbcr = TBCR_CI; } /* Go out of RESET state */ opp->gcr = 0; }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood29896.44%375.00%
Alexander Graf113.56%125.00%
Total309100.00%4100.00%


static inline uint32_t read_IRQreg_idr(struct openpic *opp, int n_IRQ) { return opp->src[n_IRQ].idr; }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood25100.00%2100.00%
Total25100.00%2100.00%


static inline uint32_t read_IRQreg_ilr(struct openpic *opp, int n_IRQ) { if (opp->flags & OPENPIC_FLAG_ILR) return opp->src[n_IRQ].output; return 0xffffffff; }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood36100.00%2100.00%
Total36100.00%2100.00%


static inline uint32_t read_IRQreg_ivpr(struct openpic *opp, int n_IRQ) { return opp->src[n_IRQ].ivpr; }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood25100.00%2100.00%
Total25100.00%2100.00%


static inline void write_IRQreg_idr(struct openpic *opp, int n_IRQ, uint32_t val) { struct irq_source *src = &opp->src[n_IRQ]; uint32_t normal_mask = (1UL << opp->nb_cpus) - 1; uint32_t crit_mask = 0; uint32_t mask = normal_mask; int crit_shift = IDR_EP_SHIFT - opp->nb_cpus; int i; if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { crit_mask = mask << crit_shift; mask |= crit_mask | IDR_EP; } src->idr = val & mask; pr_debug("Set IDR %d to 0x%08x\n", n_IRQ, src->idr); if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { if (src->idr & crit_mask) { if (src->idr & normal_mask) { pr_debug("%s: IRQ configured for multiple output types, using critical\n", __func__); } src->output = ILR_INTTGT_CINT; src->nomask = true; src->destmask = 0; for (i = 0; i < opp->nb_cpus; i++) { int n_ci = IDR_CI0_SHIFT - i; if (src->idr & (1UL << n_ci)) src->destmask |= 1UL << i; } } else { src->output = ILR_INTTGT_INT; src->nomask = false; src->destmask = src->idr & normal_mask; } } else { src->destmask = src->idr; } }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood242100.00%3100.00%
Total242100.00%3100.00%


static inline void write_IRQreg_ilr(struct openpic *opp, int n_IRQ, uint32_t val) { if (opp->flags & OPENPIC_FLAG_ILR) { struct irq_source *src = &opp->src[n_IRQ]; src->output = val & ILR_INTTGT_MASK; pr_debug("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr, src->output); /* TODO: on MPIC v4.0 only, set nomask for non-INT */ } }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood65100.00%2100.00%
Total65100.00%2100.00%


static inline void write_IRQreg_ivpr(struct openpic *opp, int n_IRQ, uint32_t val) { uint32_t mask; /* NOTE when implementing newer FSL MPIC models: starting with v4.0, * the polarity bit is read-only on internal interrupts. */ mask = IVPR_MASK_MASK | IVPR_PRIORITY_MASK | IVPR_SENSE_MASK | IVPR_POLARITY_MASK | opp->vector_mask; /* ACTIVITY bit is read-only */ opp->src[n_IRQ].ivpr = (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | (val & mask); /* For FSL internal interrupts, The sense bit is reserved and zero, * and the interrupt is always level-triggered. Timers and IPIs * have no sense or polarity bits, and are edge-triggered. */ switch (opp->src[n_IRQ].type) { case IRQ_TYPE_NORMAL: opp->src[n_IRQ].level = !!(opp->src[n_IRQ].ivpr & IVPR_SENSE_MASK); break; case IRQ_TYPE_FSLINT: opp->src[n_IRQ].ivpr &= ~IVPR_SENSE_MASK; break; case IRQ_TYPE_FSLSPECIAL: opp->src[n_IRQ].ivpr &= ~(IVPR_POLARITY_MASK | IVPR_SENSE_MASK); break; } openpic_update_irq(opp, n_IRQ); pr_debug("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val, opp->src[n_IRQ].ivpr); }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood168100.00%2100.00%
Total168100.00%2100.00%


static void openpic_gcr_write(struct openpic *opp, uint64_t val) { if (val & GCR_RESET) { openpic_reset(opp); return; } opp->gcr &= ~opp->mpic_mode_mask; opp->gcr |= val & opp->mpic_mode_mask; }

Contributors

PersonTokensPropCommitsCommitProp
Scott Wood47100.00%2100.00%
Total47100.00%2100.00%


static int openpic_gbl_write(void *opaque, gpa_t addr, u32 val) { struct openpic *opp = opaque; int err = 0; pr_debug("%s: addr %#llx <= %08x\n", __func__, addr, val); if (addr &