/* * Copyright (c) 2012, ARM Limited. All rights reserved. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the * following conditions are met: * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the * above copyright notice, this list of conditions and * the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of ARM nor the names of its * contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. */ #include "virtualisor.h" #include "gic_registers.h" #include "misc.h" #include "virt_helpers.h" #include "vgiclib.h" #include "int_master.h" /* * Whether A15 or A7, the distributor accesses are virtualised in * exactly the same manner. */ void handle_vgic_distif_abort(unsigned pa, unsigned *data, unsigned write) { unsigned value = 0, reg_offset = pa & 0xfff; switch (reg_offset >> 7) { /* Access to Processor Target registers */ case (GICD_CPUS >> 7): if (write) { unsigned icdiptr_orig = read32(pa); unsigned icdiptr_curr = 0; /* * OS is trying to reprogram the processor targets register. * Find out the cpu interface mask for this cluster and use * that instead to program the register. */ value = get_cpuif_mask(*data); write32(pa, value); icdiptr_curr = value; /* * Virtual irq migration needs communication with another cpu in * HYP mode. A cluster switch while doing this can cause a deadlock * and there is no easy way around this. So the assumption is that * the OS will prevent a switch while an irq migration operation is * in progress. */ if (FALSE == async_switchover) start_virq_migration(icdiptr_orig, icdiptr_curr, reg_offset - GICD_CPUS); } else { value = read32(pa); *data = get_cpu_mask(value); } break; /* Access to Software generated interrupt register */ case (GICD_SW >> 7): if (write) { /* Get the updated cpu interface mask */ value = get_cpuif_mask((*data >> 16) & 0xff) << 16; value |= *data & ~(0xff << 16); /* * Clear the old cpu interface mask & update * value with new cpu interface mask */ write32(pa, value); } else { /* Cannot possibly have a read from SGI generation register */ } break; default: if (write) { write32(pa, *data); } else { *data = read32(pa); } } return; }