-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'remotes/amarkovic/tags/mips-gsoc-queue-…
…jun-27-2020' into staging MIPS + TCG Continuous Benchmarking queue for June 27th, 2020 # gpg: Signature made Sat 27 Jun 2020 20:30:48 BST # gpg: using RSA key D4972A8967F75A65 # gpg: Good signature from "Aleksandar Markovic <[email protected]>" [full] # Primary key fingerprint: 8526 FBF1 5DA3 811F 4A01 DD75 D497 2A89 67F7 5A65 * remotes/amarkovic/tags/mips-gsoc-queue-jun-27-2020: MAINTAINERS: Add 'Performance Tools and Tests' subsection scripts/performance: Add topN_callgrind.py script scripts/performance: Add topN_perf.py script MAINTAINERS: Add Loongson-3 maintainer and reviewer hw/intc: Add Loongson LIOINTC support hw/mips: Implement the kvm_type() hook in MachineClass Signed-off-by: Peter Maydell <[email protected]>
- Loading branch information
Showing
8 changed files
with
585 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1096,6 +1096,12 @@ F: hw/isa/vt82c686.c | |
F: hw/pci-host/bonito.c | ||
F: include/hw/isa/vt82c686.h | ||
|
||
Loongson-3 virtual platforms | ||
M: Huacai Chen <[email protected]> | ||
R: Jiaxun Yang <[email protected]> | ||
S: Maintained | ||
F: hw/intc/loongson_liointc.c | ||
|
||
Boston | ||
M: Paul Burton <[email protected]> | ||
R: Aleksandar Rikalo <[email protected]> | ||
|
@@ -3019,3 +3025,10 @@ M: Peter Maydell <[email protected]> | |
S: Maintained | ||
F: docs/conf.py | ||
F: docs/*/conf.py | ||
|
||
Miscellaneous | ||
------------- | ||
Performance Tools and Tests | ||
M: Ahmed Karaman <[email protected]> | ||
S: Maintained | ||
F: scripts/performance/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,3 +64,6 @@ config OMPIC | |
|
||
config RX_ICU | ||
bool | ||
|
||
config LOONGSON_LIOINTC | ||
bool |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
/* | ||
* QEMU Loongson Local I/O interrupt controler. | ||
* | ||
* Copyright (c) 2020 Jiaxun Yang <[email protected]> | ||
* | ||
* 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. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
#include "qemu/osdep.h" | ||
#include "hw/sysbus.h" | ||
#include "qemu/module.h" | ||
#include "hw/irq.h" | ||
#include "hw/qdev-properties.h" | ||
|
||
#define D(x) | ||
|
||
#define NUM_IRQS 32 | ||
|
||
#define NUM_CORES 4 | ||
#define NUM_IPS 4 | ||
#define NUM_PARENTS (NUM_CORES * NUM_IPS) | ||
#define PARENT_COREx_IPy(x, y) (NUM_IPS * x + y) | ||
|
||
#define R_MAPPER_START 0x0 | ||
#define R_MAPPER_END 0x20 | ||
#define R_ISR R_MAPPER_END | ||
#define R_IEN 0x24 | ||
#define R_IEN_SET 0x28 | ||
#define R_IEN_CLR 0x2c | ||
#define R_PERCORE_ISR(x) (0x40 + 0x8 * x) | ||
#define R_END 0x64 | ||
|
||
#define TYPE_LOONGSON_LIOINTC "loongson.liointc" | ||
#define LOONGSON_LIOINTC(obj) \ | ||
OBJECT_CHECK(struct loongson_liointc, (obj), TYPE_LOONGSON_LIOINTC) | ||
|
||
struct loongson_liointc { | ||
SysBusDevice parent_obj; | ||
|
||
MemoryRegion mmio; | ||
qemu_irq parent_irq[NUM_PARENTS]; | ||
|
||
uint8_t mapper[NUM_IRQS]; /* 0:3 for core, 4:7 for IP */ | ||
uint32_t isr; | ||
uint32_t ien; | ||
uint32_t per_core_isr[NUM_CORES]; | ||
|
||
/* state of the interrupt input pins */ | ||
uint32_t pin_state; | ||
bool parent_state[NUM_PARENTS]; | ||
}; | ||
|
||
static void update_irq(struct loongson_liointc *p) | ||
{ | ||
uint32_t irq, core, ip; | ||
uint32_t per_ip_isr[NUM_IPS] = {0}; | ||
|
||
/* level triggered interrupt */ | ||
p->isr = p->pin_state; | ||
|
||
/* Clear disabled IRQs */ | ||
p->isr &= p->ien; | ||
|
||
/* Clear per_core_isr */ | ||
for (core = 0; core < NUM_CORES; core++) { | ||
p->per_core_isr[core] = 0; | ||
} | ||
|
||
/* Update per_core_isr and per_ip_isr */ | ||
for (irq = 0; irq < NUM_IRQS; irq++) { | ||
if (!(p->isr & (1 << irq))) { | ||
continue; | ||
} | ||
|
||
for (core = 0; core < NUM_CORES; core++) { | ||
if ((p->mapper[irq] & (1 << core))) { | ||
p->per_core_isr[core] |= (1 << irq); | ||
} | ||
} | ||
|
||
for (ip = 0; ip < NUM_IPS; ip++) { | ||
if ((p->mapper[irq] & (1 << (ip + 4)))) { | ||
per_ip_isr[ip] |= (1 << irq); | ||
} | ||
} | ||
} | ||
|
||
/* Emit IRQ to parent! */ | ||
for (core = 0; core < NUM_CORES; core++) { | ||
for (ip = 0; ip < NUM_IPS; ip++) { | ||
int parent = PARENT_COREx_IPy(core, ip); | ||
if (p->parent_state[parent] != | ||
(!!p->per_core_isr[core] && !!per_ip_isr[ip])) { | ||
p->parent_state[parent] = !p->parent_state[parent]; | ||
qemu_set_irq(p->parent_irq[parent], p->parent_state[parent]); | ||
} | ||
} | ||
} | ||
} | ||
|
||
static uint64_t | ||
liointc_read(void *opaque, hwaddr addr, unsigned int size) | ||
{ | ||
struct loongson_liointc *p = opaque; | ||
uint32_t r = 0; | ||
|
||
/* Mapper is 1 byte */ | ||
if (size == 1 && addr < R_MAPPER_END) { | ||
r = p->mapper[addr]; | ||
goto out; | ||
} | ||
|
||
/* Rest is 4 byte */ | ||
if (size != 4 || (addr % 4)) { | ||
goto out; | ||
} | ||
|
||
if (addr >= R_PERCORE_ISR(0) && | ||
addr < R_PERCORE_ISR(NUM_CORES)) { | ||
int core = (addr - R_PERCORE_ISR(0)) / 4; | ||
r = p->per_core_isr[core]; | ||
goto out; | ||
} | ||
|
||
switch (addr) { | ||
case R_ISR: | ||
r = p->isr; | ||
break; | ||
case R_IEN: | ||
r = p->ien; | ||
break; | ||
default: | ||
break; | ||
} | ||
|
||
out: | ||
D(qemu_log("%s: size=%d addr=%lx val=%x\n", __func__, size, addr, r)); | ||
return r; | ||
} | ||
|
||
static void | ||
liointc_write(void *opaque, hwaddr addr, | ||
uint64_t val64, unsigned int size) | ||
{ | ||
struct loongson_liointc *p = opaque; | ||
uint32_t value = val64; | ||
|
||
D(qemu_log("%s: size=%d, addr=%lx val=%x\n", __func__, size, addr, value)); | ||
|
||
/* Mapper is 1 byte */ | ||
if (size == 1 && addr < R_MAPPER_END) { | ||
p->mapper[addr] = value; | ||
goto out; | ||
} | ||
|
||
/* Rest is 4 byte */ | ||
if (size != 4 || (addr % 4)) { | ||
goto out; | ||
} | ||
|
||
if (addr >= R_PERCORE_ISR(0) && | ||
addr < R_PERCORE_ISR(NUM_CORES)) { | ||
int core = (addr - R_PERCORE_ISR(0)) / 4; | ||
p->per_core_isr[core] = value; | ||
goto out; | ||
} | ||
|
||
switch (addr) { | ||
case R_IEN_SET: | ||
p->ien |= value; | ||
break; | ||
case R_IEN_CLR: | ||
p->ien &= ~value; | ||
break; | ||
default: | ||
break; | ||
} | ||
|
||
out: | ||
update_irq(p); | ||
} | ||
|
||
static const MemoryRegionOps pic_ops = { | ||
.read = liointc_read, | ||
.write = liointc_write, | ||
.endianness = DEVICE_NATIVE_ENDIAN, | ||
.valid = { | ||
.min_access_size = 1, | ||
.max_access_size = 4 | ||
} | ||
}; | ||
|
||
static void irq_handler(void *opaque, int irq, int level) | ||
{ | ||
struct loongson_liointc *p = opaque; | ||
|
||
p->pin_state &= ~(1 << irq); | ||
p->pin_state |= level << irq; | ||
update_irq(p); | ||
} | ||
|
||
static void loongson_liointc_init(Object *obj) | ||
{ | ||
struct loongson_liointc *p = LOONGSON_LIOINTC(obj); | ||
int i; | ||
|
||
qdev_init_gpio_in(DEVICE(obj), irq_handler, 32); | ||
|
||
for (i = 0; i < NUM_PARENTS; i++) { | ||
sysbus_init_irq(SYS_BUS_DEVICE(obj), &p->parent_irq[i]); | ||
} | ||
|
||
memory_region_init_io(&p->mmio, obj, &pic_ops, p, | ||
"loongson.liointc", R_END); | ||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &p->mmio); | ||
} | ||
|
||
static const TypeInfo loongson_liointc_info = { | ||
.name = TYPE_LOONGSON_LIOINTC, | ||
.parent = TYPE_SYS_BUS_DEVICE, | ||
.instance_size = sizeof(struct loongson_liointc), | ||
.instance_init = loongson_liointc_init, | ||
}; | ||
|
||
static void loongson_liointc_register_types(void) | ||
{ | ||
type_register_static(&loongson_liointc_info); | ||
} | ||
|
||
type_init(loongson_liointc_register_types) |
Oops, something went wrong.