mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-05 08:43:55 -06:00
pull-loongarch-20250514
-----BEGIN PGP SIGNATURE----- iLMEAAEKAB0WIQS4/x2g0v3LLaCcbCxAov/yOSY+3wUCaCRNgwAKCRBAov/yOSY+ 343NBACeXLcXkNfPDRsuYC/Z0iYrMO8HuQ6VAcN1f4H+qP6Uo7ywb13GpJTLmewD iYmD93qVZBAglSUWhaVzBZbAjGFzZSDLcO0bmfsMvmUaIJfIZkJqRG01shk9iMMR zDLEax9udJdhJxBPCINNonXHds4vYKasjUureKd1SJidiBKG4w== =wdkQ -----END PGP SIGNATURE----- Merge tag 'pull-loongarch-20250514' of https://github.com/gaosong715/qemu into staging pull-loongarch-20250514 # -----BEGIN PGP SIGNATURE----- # # iLMEAAEKAB0WIQS4/x2g0v3LLaCcbCxAov/yOSY+3wUCaCRNgwAKCRBAov/yOSY+ # 343NBACeXLcXkNfPDRsuYC/Z0iYrMO8HuQ6VAcN1f4H+qP6Uo7ywb13GpJTLmewD # iYmD93qVZBAglSUWhaVzBZbAjGFzZSDLcO0bmfsMvmUaIJfIZkJqRG01shk9iMMR # zDLEax9udJdhJxBPCINNonXHds4vYKasjUureKd1SJidiBKG4w== # =wdkQ # -----END PGP SIGNATURE----- # gpg: Signature made Wed 14 May 2025 04:00:03 EDT # gpg: using RSA key B8FF1DA0D2FDCB2DA09C6C2C40A2FFF239263EDF # gpg: Good signature from "Song Gao <m17746591750@163.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: B8FF 1DA0 D2FD CB2D A09C 6C2C 40A2 FFF2 3926 3EDF * tag 'pull-loongarch-20250514' of https://github.com/gaosong715/qemu: hw/loongarch/boot: Adjust the loading position of the initrd hw/intc/loongarch_pch: Merge three memory region into one hw/intc/loongarch_pch: Set flexible memory access size with iomem region hw/intc/loongarch_pch: Rename memory region iomem32_low with iomem hw/intc/loongarch_pch: Use unified trace event for memory region ops hw/intc/loongarch_pch: Use generic write callback for iomem8 region hw/intc/loongarch_pch: Use generic write callback for iomem32_high region hw/intc/loongarch_pch: Use generic write callback for iomem32_low region hw/intc/loongarch_pch: Use generic read callback for iomem8 region hw/intc/loongarch_pch: Use generic read callback for iomem32_high region hw/intc/loongarch_pch: Use generic read callback for iomem32_low region hw/intc/loongarch_pch: Discard write operation with ISR register hw/intc/loongarch_pch: Use relative address in MemoryRegionOps hw/intc/loongarch_pch: Set version information at initial stage hw/intc/loongarch_pch: Remove some duplicate macro hw/intc/loongarch_pch: Modify register name PCH_PIC_xxx_OFFSET with PCH_PIC_xxx hw/intc/loongarch_pch: Modify name of some registers Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
8648138789
6 changed files with 196 additions and 273 deletions
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qemu/bitops.h"
|
#include "qemu/bitops.h"
|
||||||
|
#include "qemu/log.h"
|
||||||
#include "hw/irq.h"
|
#include "hw/irq.h"
|
||||||
#include "hw/intc/loongarch_pch_pic.h"
|
#include "hw/intc/loongarch_pch_pic.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
@ -71,285 +72,181 @@ static void pch_pic_irq_handler(void *opaque, int irq, int level)
|
||||||
pch_pic_update_irq(s, mask, level);
|
pch_pic_update_irq(s, mask, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr,
|
static uint64_t pch_pic_read(void *opaque, hwaddr addr, uint64_t field_mask)
|
||||||
unsigned size)
|
|
||||||
{
|
{
|
||||||
LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
|
LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
|
||||||
uint64_t val = 0;
|
uint64_t val = 0;
|
||||||
uint32_t offset = addr & 0xfff;
|
uint32_t offset;
|
||||||
|
|
||||||
switch (offset) {
|
offset = addr & 7;
|
||||||
case PCH_PIC_INT_ID_LO:
|
addr -= offset;
|
||||||
val = PCH_PIC_INT_ID_VAL;
|
switch (addr) {
|
||||||
|
case PCH_PIC_INT_ID:
|
||||||
|
val = s->id.data;
|
||||||
break;
|
break;
|
||||||
case PCH_PIC_INT_ID_HI:
|
case PCH_PIC_INT_MASK:
|
||||||
/*
|
val = s->int_mask;
|
||||||
* With 7A1000 manual
|
|
||||||
* bit 0-15 pch irqchip version
|
|
||||||
* bit 16-31 irq number supported with pch irqchip
|
|
||||||
*/
|
|
||||||
val = deposit32(PCH_PIC_INT_ID_VER, 16, 16, s->irq_num - 1);
|
|
||||||
break;
|
break;
|
||||||
case PCH_PIC_INT_MASK_LO:
|
case PCH_PIC_INT_EDGE:
|
||||||
val = (uint32_t)s->int_mask;
|
val = s->intedge;
|
||||||
break;
|
break;
|
||||||
case PCH_PIC_INT_MASK_HI:
|
case PCH_PIC_HTMSI_EN:
|
||||||
val = s->int_mask >> 32;
|
val = s->htmsi_en;
|
||||||
break;
|
break;
|
||||||
case PCH_PIC_INT_EDGE_LO:
|
case PCH_PIC_AUTO_CTRL0:
|
||||||
val = (uint32_t)s->intedge;
|
case PCH_PIC_AUTO_CTRL1:
|
||||||
|
/* PCH PIC connect to EXTIOI always, discard auto_ctrl access */
|
||||||
break;
|
break;
|
||||||
case PCH_PIC_INT_EDGE_HI:
|
case PCH_PIC_INT_STATUS:
|
||||||
val = s->intedge >> 32;
|
val = s->intisr & (~s->int_mask);
|
||||||
break;
|
break;
|
||||||
case PCH_PIC_HTMSI_EN_LO:
|
case PCH_PIC_INT_POL:
|
||||||
val = (uint32_t)s->htmsi_en;
|
val = s->int_polarity;
|
||||||
break;
|
break;
|
||||||
case PCH_PIC_HTMSI_EN_HI:
|
case PCH_PIC_HTMSI_VEC ... PCH_PIC_HTMSI_VEC_END:
|
||||||
val = s->htmsi_en >> 32;
|
val = *(uint64_t *)(s->htmsi_vector + addr - PCH_PIC_HTMSI_VEC);
|
||||||
break;
|
break;
|
||||||
case PCH_PIC_AUTO_CTRL0_LO:
|
case PCH_PIC_ROUTE_ENTRY ... PCH_PIC_ROUTE_ENTRY_END:
|
||||||
case PCH_PIC_AUTO_CTRL0_HI:
|
val = *(uint64_t *)(s->route_entry + addr - PCH_PIC_ROUTE_ENTRY);
|
||||||
case PCH_PIC_AUTO_CTRL1_LO:
|
|
||||||
case PCH_PIC_AUTO_CTRL1_HI:
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"pch_pic_read: Bad address 0x%"PRIx64"\n", addr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
trace_loongarch_pch_pic_low_readw(size, addr, val);
|
return (val >> (offset * 8)) & field_mask;
|
||||||
return val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t get_writew_val(uint64_t value, uint32_t target, bool hi)
|
static void pch_pic_write(void *opaque, hwaddr addr, uint64_t value,
|
||||||
{
|
uint64_t field_mask)
|
||||||
uint64_t mask = 0xffffffff00000000;
|
|
||||||
uint64_t data = target;
|
|
||||||
|
|
||||||
return hi ? (value & ~mask) | (data << 32) : (value & mask) | data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr,
|
|
||||||
uint64_t value, unsigned size)
|
|
||||||
{
|
{
|
||||||
LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
|
LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
|
||||||
uint32_t offset, old_valid, data = (uint32_t)value;
|
uint32_t offset;
|
||||||
uint64_t old, int_mask;
|
uint64_t old, mask, data, *ptemp;
|
||||||
offset = addr & 0xfff;
|
|
||||||
|
|
||||||
trace_loongarch_pch_pic_low_writew(size, addr, data);
|
offset = addr & 7;
|
||||||
|
addr -= offset;
|
||||||
|
mask = field_mask << (offset * 8);
|
||||||
|
data = (value & field_mask) << (offset * 8);
|
||||||
|
switch (addr) {
|
||||||
|
case PCH_PIC_INT_MASK:
|
||||||
|
old = s->int_mask;
|
||||||
|
s->int_mask = (old & ~mask) | data;
|
||||||
|
if (old & ~data) {
|
||||||
|
pch_pic_update_irq(s, old & ~data, 1);
|
||||||
|
}
|
||||||
|
|
||||||
switch (offset) {
|
if (~old & data) {
|
||||||
case PCH_PIC_INT_MASK_LO:
|
pch_pic_update_irq(s, ~old & data, 0);
|
||||||
old = s->int_mask;
|
|
||||||
s->int_mask = get_writew_val(old, data, 0);
|
|
||||||
old_valid = (uint32_t)old;
|
|
||||||
if (old_valid & ~data) {
|
|
||||||
pch_pic_update_irq(s, (old_valid & ~data), 1);
|
|
||||||
}
|
|
||||||
if (~old_valid & data) {
|
|
||||||
pch_pic_update_irq(s, (~old_valid & data), 0);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PCH_PIC_INT_MASK_HI:
|
case PCH_PIC_INT_EDGE:
|
||||||
old = s->int_mask;
|
s->intedge = (s->intedge & ~mask) | data;
|
||||||
s->int_mask = get_writew_val(old, data, 1);
|
|
||||||
old_valid = (uint32_t)(old >> 32);
|
|
||||||
int_mask = old_valid & ~data;
|
|
||||||
if (int_mask) {
|
|
||||||
pch_pic_update_irq(s, int_mask << 32, 1);
|
|
||||||
}
|
|
||||||
int_mask = ~old_valid & data;
|
|
||||||
if (int_mask) {
|
|
||||||
pch_pic_update_irq(s, int_mask << 32, 0);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case PCH_PIC_INT_EDGE_LO:
|
case PCH_PIC_INT_CLEAR:
|
||||||
s->intedge = get_writew_val(s->intedge, data, 0);
|
|
||||||
break;
|
|
||||||
case PCH_PIC_INT_EDGE_HI:
|
|
||||||
s->intedge = get_writew_val(s->intedge, data, 1);
|
|
||||||
break;
|
|
||||||
case PCH_PIC_INT_CLEAR_LO:
|
|
||||||
if (s->intedge & data) {
|
if (s->intedge & data) {
|
||||||
s->intirr &= (~data);
|
s->intirr &= ~data;
|
||||||
pch_pic_update_irq(s, data, 0);
|
pch_pic_update_irq(s, data, 0);
|
||||||
s->intisr &= (~data);
|
s->intisr &= ~data;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PCH_PIC_INT_CLEAR_HI:
|
case PCH_PIC_HTMSI_EN:
|
||||||
value <<= 32;
|
s->htmsi_en = (s->htmsi_en & ~mask) | data;
|
||||||
if (s->intedge & value) {
|
|
||||||
s->intirr &= (~value);
|
|
||||||
pch_pic_update_irq(s, value, 0);
|
|
||||||
s->intisr &= (~value);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case PCH_PIC_HTMSI_EN_LO:
|
case PCH_PIC_AUTO_CTRL0:
|
||||||
s->htmsi_en = get_writew_val(s->htmsi_en, data, 0);
|
case PCH_PIC_AUTO_CTRL1:
|
||||||
|
/* Discard auto_ctrl access */
|
||||||
break;
|
break;
|
||||||
case PCH_PIC_HTMSI_EN_HI:
|
case PCH_PIC_INT_POL:
|
||||||
s->htmsi_en = get_writew_val(s->htmsi_en, data, 1);
|
s->int_polarity = (s->int_polarity & ~mask) | data;
|
||||||
break;
|
break;
|
||||||
case PCH_PIC_AUTO_CTRL0_LO:
|
case PCH_PIC_HTMSI_VEC ... PCH_PIC_HTMSI_VEC_END:
|
||||||
case PCH_PIC_AUTO_CTRL0_HI:
|
ptemp = (uint64_t *)(s->htmsi_vector + addr - PCH_PIC_HTMSI_VEC);
|
||||||
case PCH_PIC_AUTO_CTRL1_LO:
|
*ptemp = (*ptemp & ~mask) | data;
|
||||||
case PCH_PIC_AUTO_CTRL1_HI:
|
break;
|
||||||
|
case PCH_PIC_ROUTE_ENTRY ... PCH_PIC_ROUTE_ENTRY_END:
|
||||||
|
ptemp = (uint64_t *)(s->route_entry + addr - PCH_PIC_ROUTE_ENTRY);
|
||||||
|
*ptemp = (*ptemp & ~mask) | data;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"pch_pic_write: Bad address 0x%"PRIx64"\n", addr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr,
|
static uint64_t loongarch_pch_pic_read(void *opaque, hwaddr addr,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
|
|
||||||
uint64_t val = 0;
|
uint64_t val = 0;
|
||||||
uint32_t offset = addr & 0xfff;
|
|
||||||
|
|
||||||
switch (offset) {
|
switch (size) {
|
||||||
case STATUS_LO_START:
|
case 1:
|
||||||
val = (uint32_t)(s->intisr & (~s->int_mask));
|
val = pch_pic_read(opaque, addr, UCHAR_MAX);
|
||||||
break;
|
break;
|
||||||
case STATUS_HI_START:
|
case 2:
|
||||||
val = (s->intisr & (~s->int_mask)) >> 32;
|
val = pch_pic_read(opaque, addr, USHRT_MAX);
|
||||||
break;
|
break;
|
||||||
case POL_LO_START:
|
case 4:
|
||||||
val = (uint32_t)s->int_polarity;
|
val = pch_pic_read(opaque, addr, UINT_MAX);
|
||||||
break;
|
break;
|
||||||
case POL_HI_START:
|
case 8:
|
||||||
val = s->int_polarity >> 32;
|
val = pch_pic_read(opaque, addr, UINT64_MAX);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"loongarch_pch_pic_read: Bad size %d\n", size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
trace_loongarch_pch_pic_high_readw(size, addr, val);
|
trace_loongarch_pch_pic_read(size, addr, val);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr,
|
static void loongarch_pch_pic_write(void *opaque, hwaddr addr,
|
||||||
uint64_t value, unsigned size)
|
uint64_t value, unsigned size)
|
||||||
{
|
{
|
||||||
LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
|
trace_loongarch_pch_pic_write(size, addr, value);
|
||||||
uint32_t offset, data = (uint32_t)value;
|
|
||||||
offset = addr & 0xfff;
|
|
||||||
|
|
||||||
trace_loongarch_pch_pic_high_writew(size, addr, data);
|
switch (size) {
|
||||||
|
case 1:
|
||||||
switch (offset) {
|
pch_pic_write(opaque, addr, value, UCHAR_MAX);
|
||||||
case STATUS_LO_START:
|
|
||||||
s->intisr = get_writew_val(s->intisr, data, 0);
|
|
||||||
break;
|
break;
|
||||||
case STATUS_HI_START:
|
case 2:
|
||||||
s->intisr = get_writew_val(s->intisr, data, 1);
|
pch_pic_write(opaque, addr, value, USHRT_MAX);
|
||||||
break;
|
break;
|
||||||
case POL_LO_START:
|
|
||||||
s->int_polarity = get_writew_val(s->int_polarity, data, 0);
|
|
||||||
break;
|
break;
|
||||||
case POL_HI_START:
|
case 4:
|
||||||
s->int_polarity = get_writew_val(s->int_polarity, data, 1);
|
pch_pic_write(opaque, addr, value, UINT_MAX);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
pch_pic_write(opaque, addr, value, UINT64_MAX);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"loongarch_pch_pic_write: Bad size %d\n", size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr,
|
static const MemoryRegionOps loongarch_pch_pic_ops = {
|
||||||
unsigned size)
|
.read = loongarch_pch_pic_read,
|
||||||
{
|
.write = loongarch_pch_pic_write,
|
||||||
LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
|
|
||||||
uint64_t val = 0;
|
|
||||||
uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
|
|
||||||
int64_t offset_tmp;
|
|
||||||
|
|
||||||
switch (offset) {
|
|
||||||
case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END:
|
|
||||||
offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
|
|
||||||
if (offset_tmp >= 0 && offset_tmp < 64) {
|
|
||||||
val = s->htmsi_vector[offset_tmp];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END:
|
|
||||||
offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
|
|
||||||
if (offset_tmp >= 0 && offset_tmp < 64) {
|
|
||||||
val = s->route_entry[offset_tmp];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
trace_loongarch_pch_pic_readb(size, addr, val);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr,
|
|
||||||
uint64_t data, unsigned size)
|
|
||||||
{
|
|
||||||
LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
|
|
||||||
int32_t offset_tmp;
|
|
||||||
uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
|
|
||||||
|
|
||||||
trace_loongarch_pch_pic_writeb(size, addr, data);
|
|
||||||
|
|
||||||
switch (offset) {
|
|
||||||
case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END:
|
|
||||||
offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
|
|
||||||
if (offset_tmp >= 0 && offset_tmp < 64) {
|
|
||||||
s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END:
|
|
||||||
offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
|
|
||||||
if (offset_tmp >= 0 && offset_tmp < 64) {
|
|
||||||
s->route_entry[offset_tmp] = (uint8_t)(data & 0xff);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const MemoryRegionOps loongarch_pch_pic_reg32_low_ops = {
|
|
||||||
.read = loongarch_pch_pic_low_readw,
|
|
||||||
.write = loongarch_pch_pic_low_writew,
|
|
||||||
.valid = {
|
|
||||||
.min_access_size = 4,
|
|
||||||
.max_access_size = 8,
|
|
||||||
},
|
|
||||||
.impl = {
|
|
||||||
.min_access_size = 4,
|
|
||||||
.max_access_size = 4,
|
|
||||||
},
|
|
||||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const MemoryRegionOps loongarch_pch_pic_reg32_high_ops = {
|
|
||||||
.read = loongarch_pch_pic_high_readw,
|
|
||||||
.write = loongarch_pch_pic_high_writew,
|
|
||||||
.valid = {
|
|
||||||
.min_access_size = 4,
|
|
||||||
.max_access_size = 8,
|
|
||||||
},
|
|
||||||
.impl = {
|
|
||||||
.min_access_size = 4,
|
|
||||||
.max_access_size = 4,
|
|
||||||
},
|
|
||||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const MemoryRegionOps loongarch_pch_pic_reg8_ops = {
|
|
||||||
.read = loongarch_pch_pic_readb,
|
|
||||||
.write = loongarch_pch_pic_writeb,
|
|
||||||
.valid = {
|
.valid = {
|
||||||
.min_access_size = 1,
|
.min_access_size = 1,
|
||||||
.max_access_size = 1,
|
.max_access_size = 8,
|
||||||
|
/*
|
||||||
|
* PCH PIC device would not work correctly if the guest was doing
|
||||||
|
* unaligned access. This might not be a limitation on the real
|
||||||
|
* device but in practice there is no reason for a guest to access
|
||||||
|
* this device unaligned.
|
||||||
|
*/
|
||||||
|
.unaligned = false,
|
||||||
},
|
},
|
||||||
.impl = {
|
.impl = {
|
||||||
.min_access_size = 1,
|
.min_access_size = 1,
|
||||||
.max_access_size = 1,
|
.max_access_size = 8,
|
||||||
},
|
},
|
||||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
@ -378,18 +275,10 @@ static void loongarch_pic_realize(DeviceState *dev, Error **errp)
|
||||||
|
|
||||||
qdev_init_gpio_out(dev, s->parent_irq, s->irq_num);
|
qdev_init_gpio_out(dev, s->parent_irq, s->irq_num);
|
||||||
qdev_init_gpio_in(dev, pch_pic_irq_handler, s->irq_num);
|
qdev_init_gpio_in(dev, pch_pic_irq_handler, s->irq_num);
|
||||||
memory_region_init_io(&s->iomem32_low, OBJECT(dev),
|
memory_region_init_io(&s->iomem, OBJECT(dev),
|
||||||
&loongarch_pch_pic_reg32_low_ops,
|
&loongarch_pch_pic_ops,
|
||||||
s, PCH_PIC_NAME(.reg32_part1), 0x100);
|
s, TYPE_LOONGARCH_PIC, VIRT_PCH_REG_SIZE);
|
||||||
memory_region_init_io(&s->iomem8, OBJECT(dev), &loongarch_pch_pic_reg8_ops,
|
sysbus_init_mmio(sbd, &s->iomem);
|
||||||
s, PCH_PIC_NAME(.reg8), 0x2a0);
|
|
||||||
memory_region_init_io(&s->iomem32_high, OBJECT(dev),
|
|
||||||
&loongarch_pch_pic_reg32_high_ops,
|
|
||||||
s, PCH_PIC_NAME(.reg32_part2), 0xc60);
|
|
||||||
sysbus_init_mmio(sbd, &s->iomem32_low);
|
|
||||||
sysbus_init_mmio(sbd, &s->iomem8);
|
|
||||||
sysbus_init_mmio(sbd, &s->iomem32_high);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loongarch_pic_class_init(ObjectClass *klass, const void *data)
|
static void loongarch_pic_class_init(ObjectClass *klass, const void *data)
|
||||||
|
|
|
@ -49,6 +49,19 @@ static void loongarch_pic_common_reset_hold(Object *obj, ResetType type)
|
||||||
LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(obj);
|
LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(obj);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With Loongson 7A1000 user manual
|
||||||
|
* Chapter 5.2 "Description of Interrupt-related Registers"
|
||||||
|
*
|
||||||
|
* Interrupt controller identification register 1
|
||||||
|
* Bit 24-31 Interrupt Controller ID
|
||||||
|
* Interrupt controller identification register 2
|
||||||
|
* Bit 0-7 Interrupt Controller version number
|
||||||
|
* Bit 16-23 The number of interrupt sources supported
|
||||||
|
*/
|
||||||
|
s->id.desc.id = PCH_PIC_INT_ID_VAL;
|
||||||
|
s->id.desc.version = PCH_PIC_INT_ID_VER;
|
||||||
|
s->id.desc.irq_num = s->irq_num - 1;
|
||||||
s->int_mask = UINT64_MAX;
|
s->int_mask = UINT64_MAX;
|
||||||
s->htmsi_en = 0x0;
|
s->htmsi_en = 0x0;
|
||||||
s->intedge = 0x0;
|
s->intedge = 0x0;
|
||||||
|
|
|
@ -314,12 +314,8 @@ loongson_ipi_read(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x
|
||||||
loongson_ipi_write(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
|
loongson_ipi_write(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
|
||||||
# loongarch_pch_pic.c
|
# loongarch_pch_pic.c
|
||||||
loongarch_pch_pic_irq_handler(int irq, int level) "irq %d level %d"
|
loongarch_pch_pic_irq_handler(int irq, int level) "irq %d level %d"
|
||||||
loongarch_pch_pic_low_readw(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
loongarch_pch_pic_read(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
||||||
loongarch_pch_pic_low_writew(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
loongarch_pch_pic_write(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
||||||
loongarch_pch_pic_high_readw(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
|
||||||
loongarch_pch_pic_high_writew(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
|
||||||
loongarch_pch_pic_readb(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
|
||||||
loongarch_pch_pic_writeb(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
|
||||||
|
|
||||||
# loongarch_pch_msi.c
|
# loongarch_pch_msi.c
|
||||||
loongarch_msi_set_irq(int irq_num) "set msi irq %d"
|
loongarch_msi_set_irq(int irq_num) "set msi irq %d"
|
||||||
|
|
|
@ -235,6 +235,45 @@ static int64_t load_loongarch_linux_image(const char *filename,
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ram_addr_t alloc_initrd_memory(struct loongarch_boot_info *info,
|
||||||
|
uint64_t advice_start, ssize_t rd_size)
|
||||||
|
{
|
||||||
|
hwaddr base, ram_size, gap, low_end;
|
||||||
|
ram_addr_t initrd_end, initrd_start;
|
||||||
|
|
||||||
|
base = VIRT_LOWMEM_BASE;
|
||||||
|
gap = VIRT_LOWMEM_SIZE;
|
||||||
|
initrd_start = advice_start;
|
||||||
|
initrd_end = initrd_start + rd_size;
|
||||||
|
|
||||||
|
ram_size = info->ram_size;
|
||||||
|
low_end = base + MIN(ram_size, gap);
|
||||||
|
if (initrd_end <= low_end) {
|
||||||
|
return initrd_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ram_size <= gap) {
|
||||||
|
error_report("The low memory too small for initial ram disk '%s',"
|
||||||
|
"You need to expand the ram",
|
||||||
|
info->initrd_filename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to load initrd in the high memory
|
||||||
|
*/
|
||||||
|
ram_size -= gap;
|
||||||
|
initrd_start = VIRT_HIGHMEM_BASE;
|
||||||
|
if (rd_size <= ram_size) {
|
||||||
|
return initrd_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_report("The high memory too small for initial ram disk '%s',"
|
||||||
|
"You need to expand the ram",
|
||||||
|
info->initrd_filename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
static int64_t load_kernel_info(struct loongarch_boot_info *info)
|
static int64_t load_kernel_info(struct loongarch_boot_info *info)
|
||||||
{
|
{
|
||||||
uint64_t kernel_entry, kernel_low, kernel_high;
|
uint64_t kernel_entry, kernel_low, kernel_high;
|
||||||
|
@ -263,15 +302,10 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info)
|
||||||
initrd_size = get_image_size(info->initrd_filename);
|
initrd_size = get_image_size(info->initrd_filename);
|
||||||
if (initrd_size > 0) {
|
if (initrd_size > 0) {
|
||||||
initrd_offset = ROUND_UP(kernel_high + 4 * kernel_size, 64 * KiB);
|
initrd_offset = ROUND_UP(kernel_high + 4 * kernel_size, 64 * KiB);
|
||||||
|
initrd_offset = alloc_initrd_memory(info, initrd_offset,
|
||||||
if (initrd_offset + initrd_size > info->ram_size) {
|
initrd_size);
|
||||||
error_report("memory too small for initial ram disk '%s'",
|
initrd_size = load_image_targphys(info->initrd_filename,
|
||||||
info->initrd_filename);
|
initrd_offset, initrd_size);
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
initrd_size = load_image_targphys(info->initrd_filename, initrd_offset,
|
|
||||||
info->ram_size - initrd_offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initrd_size == (target_ulong)-1) {
|
if (initrd_size == (target_ulong)-1) {
|
||||||
|
|
|
@ -429,12 +429,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
|
||||||
sysbus_realize_and_unref(d, &error_fatal);
|
sysbus_realize_and_unref(d, &error_fatal);
|
||||||
memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE,
|
memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE,
|
||||||
sysbus_mmio_get_region(d, 0));
|
sysbus_mmio_get_region(d, 0));
|
||||||
memory_region_add_subregion(get_system_memory(),
|
|
||||||
VIRT_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET,
|
|
||||||
sysbus_mmio_get_region(d, 1));
|
|
||||||
memory_region_add_subregion(get_system_memory(),
|
|
||||||
VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO,
|
|
||||||
sysbus_mmio_get_region(d, 2));
|
|
||||||
|
|
||||||
/* Connect pch_pic irqs to extioi */
|
/* Connect pch_pic irqs to extioi */
|
||||||
for (i = 0; i < num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
|
|
|
@ -10,44 +10,43 @@
|
||||||
#include "hw/pci-host/ls7a.h"
|
#include "hw/pci-host/ls7a.h"
|
||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
|
|
||||||
#define PCH_PIC_INT_ID_VAL 0x7000000UL
|
#define PCH_PIC_INT_ID 0x00
|
||||||
#define PCH_PIC_INT_ID_VER 0x1UL
|
#define PCH_PIC_INT_ID_VAL 0x7
|
||||||
#define PCH_PIC_INT_ID_LO 0x00
|
#define PCH_PIC_INT_ID_VER 0x1
|
||||||
#define PCH_PIC_INT_ID_HI 0x04
|
#define PCH_PIC_INT_MASK 0x20
|
||||||
#define PCH_PIC_INT_MASK_LO 0x20
|
#define PCH_PIC_HTMSI_EN 0x40
|
||||||
#define PCH_PIC_INT_MASK_HI 0x24
|
#define PCH_PIC_INT_EDGE 0x60
|
||||||
#define PCH_PIC_HTMSI_EN_LO 0x40
|
#define PCH_PIC_INT_CLEAR 0x80
|
||||||
#define PCH_PIC_HTMSI_EN_HI 0x44
|
#define PCH_PIC_AUTO_CTRL0 0xc0
|
||||||
#define PCH_PIC_INT_EDGE_LO 0x60
|
#define PCH_PIC_AUTO_CTRL1 0xe0
|
||||||
#define PCH_PIC_INT_EDGE_HI 0x64
|
#define PCH_PIC_ROUTE_ENTRY 0x100
|
||||||
#define PCH_PIC_INT_CLEAR_LO 0x80
|
|
||||||
#define PCH_PIC_INT_CLEAR_HI 0x84
|
|
||||||
#define PCH_PIC_AUTO_CTRL0_LO 0xc0
|
|
||||||
#define PCH_PIC_AUTO_CTRL0_HI 0xc4
|
|
||||||
#define PCH_PIC_AUTO_CTRL1_LO 0xe0
|
|
||||||
#define PCH_PIC_AUTO_CTRL1_HI 0xe4
|
|
||||||
#define PCH_PIC_ROUTE_ENTRY_OFFSET 0x100
|
|
||||||
#define PCH_PIC_ROUTE_ENTRY_END 0x13f
|
#define PCH_PIC_ROUTE_ENTRY_END 0x13f
|
||||||
#define PCH_PIC_HTMSI_VEC_OFFSET 0x200
|
#define PCH_PIC_HTMSI_VEC 0x200
|
||||||
#define PCH_PIC_HTMSI_VEC_END 0x23f
|
#define PCH_PIC_HTMSI_VEC_END 0x23f
|
||||||
#define PCH_PIC_INT_STATUS_LO 0x3a0
|
#define PCH_PIC_INT_STATUS 0x3a0
|
||||||
#define PCH_PIC_INT_STATUS_HI 0x3a4
|
#define PCH_PIC_INT_POL 0x3e0
|
||||||
#define PCH_PIC_INT_POL_LO 0x3e0
|
|
||||||
#define PCH_PIC_INT_POL_HI 0x3e4
|
|
||||||
|
|
||||||
#define STATUS_LO_START 0
|
|
||||||
#define STATUS_HI_START 0x4
|
|
||||||
#define POL_LO_START 0x40
|
|
||||||
#define POL_HI_START 0x44
|
|
||||||
|
|
||||||
#define TYPE_LOONGARCH_PIC_COMMON "loongarch_pic_common"
|
#define TYPE_LOONGARCH_PIC_COMMON "loongarch_pic_common"
|
||||||
OBJECT_DECLARE_TYPE(LoongArchPICCommonState,
|
OBJECT_DECLARE_TYPE(LoongArchPICCommonState,
|
||||||
LoongArchPICCommonClass, LOONGARCH_PIC_COMMON)
|
LoongArchPICCommonClass, LOONGARCH_PIC_COMMON)
|
||||||
|
|
||||||
|
union LoongArchPIC_ID {
|
||||||
|
struct {
|
||||||
|
uint8_t _reserved_0[3];
|
||||||
|
uint8_t id;
|
||||||
|
uint8_t version;
|
||||||
|
uint8_t _reserved_1;
|
||||||
|
uint8_t irq_num;
|
||||||
|
uint8_t _reserved_2;
|
||||||
|
} QEMU_PACKED desc;
|
||||||
|
uint64_t data;
|
||||||
|
};
|
||||||
|
|
||||||
struct LoongArchPICCommonState {
|
struct LoongArchPICCommonState {
|
||||||
SysBusDevice parent_obj;
|
SysBusDevice parent_obj;
|
||||||
|
|
||||||
qemu_irq parent_irq[64];
|
qemu_irq parent_irq[64];
|
||||||
|
union LoongArchPIC_ID id; /* 0x00 interrupt ID register */
|
||||||
uint64_t int_mask; /* 0x020 interrupt mask register */
|
uint64_t int_mask; /* 0x020 interrupt mask register */
|
||||||
uint64_t htmsi_en; /* 0x040 1=msi */
|
uint64_t htmsi_en; /* 0x040 1=msi */
|
||||||
uint64_t intedge; /* 0x060 edge=1 level=0 */
|
uint64_t intedge; /* 0x060 edge=1 level=0 */
|
||||||
|
@ -66,9 +65,7 @@ struct LoongArchPICCommonState {
|
||||||
uint8_t route_entry[64]; /* 0x100 - 0x138 */
|
uint8_t route_entry[64]; /* 0x100 - 0x138 */
|
||||||
uint8_t htmsi_vector[64]; /* 0x200 - 0x238 */
|
uint8_t htmsi_vector[64]; /* 0x200 - 0x238 */
|
||||||
|
|
||||||
MemoryRegion iomem32_low;
|
MemoryRegion iomem;
|
||||||
MemoryRegion iomem32_high;
|
|
||||||
MemoryRegion iomem8;
|
|
||||||
unsigned int irq_num;
|
unsigned int irq_num;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue