* [Qemu-devel] [PATCH v5 1/7] arm: add missing scu registers
2011-12-29 16:19 [Qemu-devel] [PATCH v5 0/7] various ARM fixes for Calxeda Highbank Mark Langsdorf
@ 2011-12-29 16:19 ` Mark Langsdorf
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 2/7] arm: Set frequencies for arm_timer Mark Langsdorf
` (5 subsequent siblings)
6 siblings, 0 replies; 26+ messages in thread
From: Mark Langsdorf @ 2011-12-29 16:19 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell, Mark Langsdorf, afaerber, rob.herring
From: Rob Herring <rob.herring@calxeda.com>
Add power control register to a9mpcore
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
Changes from v3, v4
None
Changes from v2:
Better handling of byte and halfword writes to the power register
Correct handling of VMState versions
Improved commit message
Changes from v1:
Added VMState support
Checked alignment of writes to the power control register
hw/a9mpcore.c | 36 +++++++++++++++++++++++++++++++++---
1 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index cd2985f..3ef0e13 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -29,6 +29,7 @@ gic_get_current_cpu(void)
typedef struct a9mp_priv_state {
gic_state gic;
uint32_t scu_control;
+ uint32_t scu_status;
uint32_t old_timer_status[8];
uint32_t num_cpu;
qemu_irq *timer_irq;
@@ -48,7 +49,13 @@ static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset,
case 0x04: /* Configuration */
return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1);
case 0x08: /* CPU Power Status */
- return 0;
+ return s->scu_status;
+ case 0x09: /* CPU status. */
+ return s->scu_status >> 8;
+ case 0x0a: /* CPU status. */
+ return s->scu_status >> 16;
+ case 0x0b: /* CPU status. */
+ return s->scu_status >> 24;
case 0x0c: /* Invalidate All Registers In Secure State */
return 0;
case 0x40: /* Filtering Start Address Register */
@@ -67,12 +74,35 @@ static void a9_scu_write(void *opaque, target_phys_addr_t offset,
uint64_t value, unsigned size)
{
a9mp_priv_state *s = (a9mp_priv_state *)opaque;
+ uint32_t mask;
+ uint32_t shift;
+ switch (size) {
+ case 1:
+ mask = 0xff;
+ break;
+ case 2:
+ mask = 0xffff;
+ break;
+ case 4:
+ mask = 0xffffffff;
+ break;
+ default:
+ fprintf(stderr, "Invalid size %u in write to a9 scu register %x\n",
+ size, offset);
+ return;
+ }
+
switch (offset) {
case 0x00: /* Control */
s->scu_control = value & 1;
break;
case 0x4: /* Configuration: RO */
break;
+ case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */
+ shift = (offset - 0x8) * 8;
+ s->scu_status &= ~(mask << shift);
+ s->scu_status |= ((value & mask) << shift);
+ break;
case 0x0c: /* Invalidate All Registers In Secure State */
/* no-op as we do not implement caches */
break;
@@ -80,7 +110,6 @@ static void a9_scu_write(void *opaque, target_phys_addr_t offset,
case 0x44: /* Filtering End Address Register */
/* RAZ/WI, like an implementation with only one AXI master */
break;
- case 0x8: /* CPU Power Status */
case 0x50: /* SCU Access Control Register */
case 0x54: /* SCU Non-secure Access Control Register */
/* unimplemented, fall through */
@@ -169,11 +198,12 @@ static int a9mp_priv_init(SysBusDevice *dev)
static const VMStateDescription vmstate_a9mp_priv = {
.name = "a9mpcore_priv",
- .version_id = 1,
+ .version_id = 2,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(scu_control, a9mp_priv_state),
VMSTATE_UINT32_ARRAY(old_timer_status, a9mp_priv_state, 8),
+ VMSTATE_UINT32_V(scu_status, a9mp_priv_state, 2),
VMSTATE_END_OF_LIST()
}
};
--
1.7.5.4
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PATCH v5 2/7] arm: Set frequencies for arm_timer
2011-12-29 16:19 [Qemu-devel] [PATCH v5 0/7] various ARM fixes for Calxeda Highbank Mark Langsdorf
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 1/7] arm: add missing scu registers Mark Langsdorf
@ 2011-12-29 16:19 ` Mark Langsdorf
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 3/7] arm: add dummy v7 cp15 config_base_register Mark Langsdorf
` (4 subsequent siblings)
6 siblings, 0 replies; 26+ messages in thread
From: Mark Langsdorf @ 2011-12-29 16:19 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell, Mark Langsdorf, afaerber, rob.herring
Use qdev properties to allow board modelers to set the frequencies
for the sp804 timer. Each of the sp804's timers can have an
individual frequency. The timers default to 1MHz.
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Andreas Färber <afaerber@suse.de>
---
Changes from v3, v4
None
Changes from v2
Comment correctly describes behavior of properties
freqX variables are defined as uint32_t, not int
Changes from v1
Simplified multiple timer frequency handling
Removed the shared default
hw/arm_timer.c | 24 +++++++++++++++++++-----
1 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 0a5b9d2..60e1c63 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -9,6 +9,8 @@
#include "sysbus.h"
#include "qemu-timer.h"
+#include "qemu-common.h"
+#include "qdev.h"
/* Common timer implementation. */
@@ -178,6 +180,7 @@ typedef struct {
SysBusDevice busdev;
MemoryRegion iomem;
arm_timer_state *timer[2];
+ uint32_t freq0, freq1;
int level[2];
qemu_irq irq;
} sp804_state;
@@ -269,10 +272,11 @@ static int sp804_init(SysBusDevice *dev)
qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
sysbus_init_irq(dev, &s->irq);
- /* ??? The timers are actually configurable between 32kHz and 1MHz, but
- we don't implement that. */
- s->timer[0] = arm_timer_init(1000000);
- s->timer[1] = arm_timer_init(1000000);
+ /* The timers are configurable between 32kHz and 1MHz
+ * defaulting to 1MHz but overrideable as individual properties */
+ s->timer[0] = arm_timer_init(s->freq0);
+ s->timer[1] = arm_timer_init(s->freq1);
+
s->timer[0]->irq = qi[0];
s->timer[1]->irq = qi[1];
memory_region_init_io(&s->iomem, &sp804_ops, s, "sp804", 0x1000);
@@ -281,6 +285,16 @@ static int sp804_init(SysBusDevice *dev)
return 0;
}
+static SysBusDeviceInfo sp804_info = {
+ .init = sp804_init,
+ .qdev.name = "sp804",
+ .qdev.size = sizeof(sp804_state),
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("freq0", sp804_state, freq0, 1000000),
+ DEFINE_PROP_UINT32("freq1", sp804_state, freq1, 1000000),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
/* Integrator/CP timer module. */
@@ -349,7 +363,7 @@ static int icp_pit_init(SysBusDevice *dev)
static void arm_timer_register_devices(void)
{
sysbus_register_dev("integrator_pit", sizeof(icp_pit_state), icp_pit_init);
- sysbus_register_dev("sp804", sizeof(sp804_state), sp804_init);
+ sysbus_register_withprop(&sp804_info);
}
device_init(arm_timer_register_devices)
--
1.7.5.4
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PATCH v5 3/7] arm: add dummy v7 cp15 config_base_register
2011-12-29 16:19 [Qemu-devel] [PATCH v5 0/7] various ARM fixes for Calxeda Highbank Mark Langsdorf
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 1/7] arm: add missing scu registers Mark Langsdorf
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 2/7] arm: Set frequencies for arm_timer Mark Langsdorf
@ 2011-12-29 16:19 ` Mark Langsdorf
2012-01-04 14:32 ` Peter Maydell
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 4/7] arm: add dummy gic security registers Mark Langsdorf
` (3 subsequent siblings)
6 siblings, 1 reply; 26+ messages in thread
From: Mark Langsdorf @ 2011-12-29 16:19 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell, Mark Langsdorf, afaerber, rob.herring
Add a cp15 config_base_register that currently defaults to 0.
After the QOM CPU support is added, the value will be properly
set to the periphal base value.
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
Changes from v3, v4
None
Changes from v2
Added test against op2
Changes from v1
renamed the register
added comments about how it will change when QOM CPUs are added
target-arm/cpu.h | 1 +
target-arm/helper.c | 14 ++++++++++++++
2 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c4d742f..449e620 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -149,6 +149,7 @@ typedef struct CPUARMState {
uint32_t c15_i_max; /* Maximum D-cache dirty line index. */
uint32_t c15_i_min; /* Minimum D-cache dirty line index. */
uint32_t c15_threadid; /* TI debugger thread-ID. */
+ uint32_t c15_config_base_address; /* SCU base address. */
} cp15;
struct {
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 65f4fbf..b235fed 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2111,6 +2111,20 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
* 0x200 << ($rn & 0xfff), when MMU is off. */
goto bad_reg;
}
+ if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) {
+ switch (crm) {
+ case 0:
+ /* The config_base_address should hold the value of
+ * the peripheral base. ARM should get this from a CPU
+ * object property, but that support isn't available in
+ * December 2011. Default to 0 for now and board models
+ * that care can set it by a private hook */
+ if ((op1 == 4) && (op2 == 0)) {
+ return env->cp15.c15_config_base_address;
+ }
+ }
+ goto bad_reg;
+ }
return 0;
}
bad_reg:
--
1.7.5.4
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [Qemu-devel] [PATCH v5 3/7] arm: add dummy v7 cp15 config_base_register
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 3/7] arm: add dummy v7 cp15 config_base_register Mark Langsdorf
@ 2012-01-04 14:32 ` Peter Maydell
2012-01-04 16:32 ` Mark Langsdorf
0 siblings, 1 reply; 26+ messages in thread
From: Peter Maydell @ 2012-01-04 14:32 UTC (permalink / raw)
To: Mark Langsdorf; +Cc: qemu-devel, rob.herring, afaerber
On 29 December 2011 16:19, Mark Langsdorf <mark.langsdorf@calxeda.com> wrote:
> Add a cp15 config_base_register that currently defaults to 0.
> After the QOM CPU support is added, the value will be properly
> set to the periphal base value.
>
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
I need to revoke this Reviewed-by: because...
> @@ -2111,6 +2111,20 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
> * 0x200 << ($rn & 0xfff), when MMU is off. */
> goto bad_reg;
> }
> + if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) {
> + switch (crm) {
> + case 0:
> + /* The config_base_address should hold the value of
> + * the peripheral base. ARM should get this from a CPU
> + * object property, but that support isn't available in
> + * December 2011. Default to 0 for now and board models
> + * that care can set it by a private hook */
> + if ((op1 == 4) && (op2 == 0)) {
> + return env->cp15.c15_config_base_address;
> + }
> + }
> + goto bad_reg;
> + }
> return 0;
this breaks booting on vexpress, which complains
qemu: fatal: Unimplemented cp15 register read (c15, c0, {0, 1})
because we're now barfing on all the other c15 registers which we
used to read as zero.
The simplest fix is to drop that 'goto bad_reg;'.
More complicatedly we could decode the c15 range properly for A9
(as per the TRM).
-- PMM
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [Qemu-devel] [PATCH v5 3/7] arm: add dummy v7 cp15 config_base_register
2012-01-04 14:32 ` Peter Maydell
@ 2012-01-04 16:32 ` Mark Langsdorf
2012-01-04 16:47 ` Peter Maydell
0 siblings, 1 reply; 26+ messages in thread
From: Mark Langsdorf @ 2012-01-04 16:32 UTC (permalink / raw)
To: Peter Maydell; +Cc: qemu-devel@nongnu.org, Rob Herring, afaerber@suse.de
On 01/04/2012 08:32 AM, Peter Maydell wrote:
> On 29 December 2011 16:19, Mark Langsdorf <mark.langsdorf@calxeda.com> wrote:
>> Add a cp15 config_base_register that currently defaults to 0.
>> After the QOM CPU support is added, the value will be properly
>> set to the periphal base value.
>>
>> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
>> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
>
> I need to revoke this Reviewed-by: because...
>
>> @@ -2111,6 +2111,20 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
>> * 0x200 << ($rn & 0xfff), when MMU is off. */
>> goto bad_reg;
>> }
>> + if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) {
>> + switch (crm) {
>> + case 0:
>> + /* The config_base_address should hold the value of
>> + * the peripheral base. ARM should get this from a CPU
>> + * object property, but that support isn't available in
>> + * December 2011. Default to 0 for now and board models
>> + * that care can set it by a private hook */
>> + if ((op1 == 4) && (op2 == 0)) {
>> + return env->cp15.c15_config_base_address;
>> + }
>> + }
>> + goto bad_reg;
>> + }
>> return 0;
>
> this breaks booting on vexpress, which complains
> qemu: fatal: Unimplemented cp15 register read (c15, c0, {0, 1})
> because we're now barfing on all the other c15 registers which we
> used to read as zero.
Fair enough. Can I just resubmit this one patch or do you want
the entire series?
--Mark Langsdorf
Calxeda, Inc.
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [Qemu-devel] [PATCH v5 3/7] arm: add dummy v7 cp15 config_base_register
2012-01-04 16:32 ` Mark Langsdorf
@ 2012-01-04 16:47 ` Peter Maydell
2012-01-04 16:53 ` [Qemu-devel] [PATCH v6 1/1] arm: add dummy v7 cp15 registers Mark Langsdorf
0 siblings, 1 reply; 26+ messages in thread
From: Peter Maydell @ 2012-01-04 16:47 UTC (permalink / raw)
To: Mark Langsdorf; +Cc: qemu-devel@nongnu.org, Rob Herring, afaerber@suse.de
On 4 January 2012 16:32, Mark Langsdorf <mark.langsdorf@calxeda.com> wrote:
> On 01/04/2012 08:32 AM, Peter Maydell wrote:
>> On 29 December 2011 16:19, Mark Langsdorf <mark.langsdorf@calxeda.com> wrote:
>>> Add a cp15 config_base_register that currently defaults to 0.
>>> After the QOM CPU support is added, the value will be properly
>>> set to the periphal base value.
>>>
>>> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
>>> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
>>
>> I need to revoke this Reviewed-by: because...
>>
>>> @@ -2111,6 +2111,20 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
>>> * 0x200 << ($rn & 0xfff), when MMU is off. */
>>> goto bad_reg;
>>> }
>>> + if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) {
>>> + switch (crm) {
>>> + case 0:
>>> + /* The config_base_address should hold the value of
>>> + * the peripheral base. ARM should get this from a CPU
>>> + * object property, but that support isn't available in
>>> + * December 2011. Default to 0 for now and board models
>>> + * that care can set it by a private hook */
>>> + if ((op1 == 4) && (op2 == 0)) {
>>> + return env->cp15.c15_config_base_address;
>>> + }
>>> + }
>>> + goto bad_reg;
>>> + }
>>> return 0;
>>
>> this breaks booting on vexpress, which complains
>> qemu: fatal: Unimplemented cp15 register read (c15, c0, {0, 1})
>> because we're now barfing on all the other c15 registers which we
>> used to read as zero.
>
> Fair enough. Can I just resubmit this one patch or do you want
> the entire series?
Just resubmit this one as a single patch -- it has to go through my target-arm
tree rather than arm-devs anyway so if you resent the series I'd just have
to break it apart. (As you may have noticed I've put some of the other
patches into an arm-devs pullreq.)
-- PMM
^ permalink raw reply [flat|nested] 26+ messages in thread
* [Qemu-devel] [PATCH v6 1/1] arm: add dummy v7 cp15 registers
2012-01-04 16:47 ` Peter Maydell
@ 2012-01-04 16:53 ` Mark Langsdorf
2012-01-04 17:50 ` Peter Maydell
0 siblings, 1 reply; 26+ messages in thread
From: Mark Langsdorf @ 2012-01-04 16:53 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell, afaerber, Mark Langsdorf
Add dummy register support for the cp15, CRn=c15 registers.
config_base_register and power_control_register currently
default to 0, but may have improved support after the QOM
CPU patches are finished.
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v5
Added handling for all c15 registers
Changes from v3, v4
None
Changes from v2
Added test against op2
Changes from v1
renamed the register
added comments about how it will change when QOM CPUs are added
target-arm/cpu.h | 2 ++
target-arm/helper.c | 30 ++++++++++++++++++++++++++++++
2 files changed, 32 insertions(+), 0 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c4d742f..f8fb558 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -149,6 +149,8 @@ typedef struct CPUARMState {
uint32_t c15_i_max; /* Maximum D-cache dirty line index. */
uint32_t c15_i_min; /* Minimum D-cache dirty line index. */
uint32_t c15_threadid; /* TI debugger thread-ID. */
+ uint32_t c15_config_base_address; /* SCU base address. */
+ uint32_t c15_power_control; /* power control */
} cp15;
struct {
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 65f4fbf..f39bcf3 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2111,6 +2111,36 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
* 0x200 << ($rn & 0xfff), when MMU is off. */
goto bad_reg;
}
+ if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) {
+ switch (crm) {
+ case 0:
+ if ((op1 == 4) && (op2 == 0)) {
+ /* The config_base_address should hold the value of
+ * the peripheral base. ARM should get this from a CPU
+ * object property, but that support isn't available in
+ * December 2011. Default to 0 for now and board models
+ * that care can set it by a private hook */
+ return env->cp15.c15_config_base_address;
+ } else if ((op1 == 0) && (op2 == 0)) {
+ /* power_control should be set to maximum latency. Again,
+ default to 0 and set by private hook */
+ return env->cp15.c15_power_control;
+ }
+ break;
+ case 1: /* NEON Busy */
+ return 0;
+ case 5: /* tlb lockdown */
+ case 6:
+ case 7:
+ if ((op1 == 5) && (op2 == 2)) {
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+ goto bad_reg;
+ }
return 0;
}
bad_reg:
--
1.7.5.4
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [Qemu-devel] [PATCH v6 1/1] arm: add dummy v7 cp15 registers
2012-01-04 16:53 ` [Qemu-devel] [PATCH v6 1/1] arm: add dummy v7 cp15 registers Mark Langsdorf
@ 2012-01-04 17:50 ` Peter Maydell
2012-01-04 18:23 ` Mark Langsdorf
2012-01-04 19:07 ` [Qemu-devel] [PATCH v7] " Mark Langsdorf
0 siblings, 2 replies; 26+ messages in thread
From: Peter Maydell @ 2012-01-04 17:50 UTC (permalink / raw)
To: Mark Langsdorf; +Cc: qemu-devel, afaerber
On 4 January 2012 16:53, Mark Langsdorf <mark.langsdorf@calxeda.com> wrote:
> + if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) {
> + switch (crm) {
> + case 0:
> + if ((op1 == 4) && (op2 == 0)) {
> + /* The config_base_address should hold the value of
> + * the peripheral base. ARM should get this from a CPU
> + * object property, but that support isn't available in
> + * December 2011. Default to 0 for now and board models
> + * that care can set it by a private hook */
> + return env->cp15.c15_config_base_address;
> + } else if ((op1 == 0) && (op2 == 0)) {
> + /* power_control should be set to maximum latency. Again,
> + default to 0 and set by private hook */
> + return env->cp15.c15_power_control;
> + }
This one's read-write, which means it needs (a) support in set_cp15
(b) save/load
support.
> + break;
> + case 1: /* NEON Busy */
> + return 0;
> + case 5: /* tlb lockdown */
> + case 6:
> + case 7:
> + if ((op1 == 5) && (op2 == 2)) {
> + return 0;
> + }
> + break;
> + default:
> + break;
> + }
> + goto bad_reg;
> + }
You also need to implement the diagnostic register c15,c0,0,1
otherwise Linux won't boot when it tries to run this code:
http://lxr.linux.no/#linux+v3.1.7/arch/arm/mm/proc-v7.S#L345
I suggest that should be implemented as reads-as-written. (Again, will
need save/load
support.) Ditto for the power diagnostic control register c15,c0,0,2, as used in
this patch: http://www.spinics.net/lists/arm-kernel/msg115817.html
-- PMM
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [Qemu-devel] [PATCH v6 1/1] arm: add dummy v7 cp15 registers
2012-01-04 17:50 ` Peter Maydell
@ 2012-01-04 18:23 ` Mark Langsdorf
2012-01-04 19:07 ` [Qemu-devel] [PATCH v7] " Mark Langsdorf
1 sibling, 0 replies; 26+ messages in thread
From: Mark Langsdorf @ 2012-01-04 18:23 UTC (permalink / raw)
To: qemu-devel
On 01/04/2012 11:50 AM, Peter Maydell wrote:
> On 4 January 2012 16:53, Mark Langsdorf <mark.langsdorf@calxeda.com> wrote:
>> + } else if ((op1 == 0) && (op2 == 0)) {
>> + /* power_control should be set to maximum latency. Again,
>> + default to 0 and set by private hook */
>> + return env->cp15.c15_power_control;
>> + }
>
> This one's read-write, which means it needs (a) support in set_cp15
> (b) save/load support.
Okay.
> You also need to implement the diagnostic register c15,c0,0,1
> otherwise Linux won't boot when it tries to run this code:
> http://lxr.linux.no/#linux+v3.1.7/arch/arm/mm/proc-v7.S#L345
> I suggest that should be implemented as reads-as-written. (Again, will
> need save/load
> support.) Ditto for the power diagnostic control register c15,c0,0,2, as used in
> this patch: http://www.spinics.net/lists/arm-kernel/msg115817.html
I'm handling all the c15 registers listed on p 4-11 of the Cortex-A9
r3p0 TRM. Would you please give me a reference for these other two
registers? I'm not seeing them. Thanks.
--Mark
^ permalink raw reply [flat|nested] 26+ messages in thread
* [Qemu-devel] [PATCH v7] arm: add dummy v7 cp15 registers
2012-01-04 17:50 ` Peter Maydell
2012-01-04 18:23 ` Mark Langsdorf
@ 2012-01-04 19:07 ` Mark Langsdorf
2012-01-04 23:50 ` Peter Maydell
1 sibling, 1 reply; 26+ messages in thread
From: Mark Langsdorf @ 2012-01-04 19:07 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell, afaerber, Mark Langsdorf
Add dummy register support for the cp15, CRn=c15 registers.
config_base_register and power_control_register currently
default to 0, but may have improved support after the QOM
CPU patches are finished.
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v6
Added the diagnostic registers
Added save/load support
Changes from v5
Added handling for all c15 registers
Changes from v3, v4
None
Changes from v2
Added test against op2
Changes from v1
renamed the config_base_register
added comments about how it will change when QOM CPUs are added
target-arm/cpu.h | 4 ++++
target-arm/helper.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
target-arm/machine.c | 7 +++++++
3 files changed, 59 insertions(+), 0 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c4d742f..3bc90e6 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -149,6 +149,10 @@ typedef struct CPUARMState {
uint32_t c15_i_max; /* Maximum D-cache dirty line index. */
uint32_t c15_i_min; /* Minimum D-cache dirty line index. */
uint32_t c15_threadid; /* TI debugger thread-ID. */
+ uint32_t c15_config_base_address; /* SCU base address. */
+ uint32_t c15_diagnostic; /* diagnostic register */
+ uint32_t c15_power_diagnostic;
+ uint32_t c15_power_control; /* power control */
} cp15;
struct {
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 65f4fbf..62028e5 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1768,6 +1768,20 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
goto bad_reg;
}
}
+ if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) {
+ switch (crm) {
+ case 0:
+ if ((op1 == 0) && (op2 == 0)) {
+ env->cp15.c15_power_control = val;
+ } else if ((op1 == 0) && (op2 == 1)) {
+ env->cp15.c15_diagnostic = val;
+ } else if ((op1 == 0) && (op2 == 2)) {
+ env->cp15.c15_power_diagnostic = val;
+ }
+ default:
+ break;
+ }
+ }
break;
}
return;
@@ -2111,6 +2125,40 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
* 0x200 << ($rn & 0xfff), when MMU is off. */
goto bad_reg;
}
+ if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) {
+ switch (crm) {
+ case 0:
+ if ((op1 == 4) && (op2 == 0)) {
+ /* The config_base_address should hold the value of
+ * the peripheral base. ARM should get this from a CPU
+ * object property, but that support isn't available in
+ * December 2011. Default to 0 for now and board models
+ * that care can set it by a private hook */
+ return env->cp15.c15_config_base_address;
+ } else if ((op1 == 0) && (op2 == 0)) {
+ /* power_control should be set to maximum latency. Again,
+ default to 0 and set by private hook */
+ return env->cp15.c15_power_control;
+ } else if ((op1 == 0) && (op2 == 1)) {
+ return env->cp15.c15_diagnostic;
+ } else if ((op1 == 0) && (op2 == 2)) {
+ return env->cp15.c15_power_diagnostic;
+ }
+ break;
+ case 1: /* NEON Busy */
+ return 0;
+ case 5: /* tlb lockdown */
+ case 6:
+ case 7:
+ if ((op1 == 5) && (op2 == 2)) {
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+ goto bad_reg;
+ }
return 0;
}
bad_reg:
diff --git a/target-arm/machine.c b/target-arm/machine.c
index aaee9b9..7f25b0f 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -56,6 +56,9 @@ void cpu_save(QEMUFile *f, void *opaque)
qemu_put_be32(f, env->cp15.c13_tls2);
qemu_put_be32(f, env->cp15.c13_tls3);
qemu_put_be32(f, env->cp15.c15_cpar);
+ qemu_put_be32(f, env->cp15.c15_power_control);
+ qemu_put_be32(f, env->cp15.c15_diagnostic);
+ qemu_put_be32(f, env->cp15.c15_power_diagnostic);
qemu_put_be32(f, env->features);
@@ -170,6 +173,10 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
env->cp15.c13_tls2 = qemu_get_be32(f);
env->cp15.c13_tls3 = qemu_get_be32(f);
env->cp15.c15_cpar = qemu_get_be32(f);
+ env->cp15.c15_power_control = qemu_get_be32(f);
+ env->cp15.c15_diagnostic = qemu_get_be32(f);
+ env->cp15.c15_power_diagnostic = qemu_get_be32(f);
+
env->features = qemu_get_be32(f);
--
1.7.5.4
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [Qemu-devel] [PATCH v7] arm: add dummy v7 cp15 registers
2012-01-04 19:07 ` [Qemu-devel] [PATCH v7] " Mark Langsdorf
@ 2012-01-04 23:50 ` Peter Maydell
2012-01-05 0:14 ` [Qemu-devel] [PATCH v8] " Mark Langsdorf
0 siblings, 1 reply; 26+ messages in thread
From: Peter Maydell @ 2012-01-04 23:50 UTC (permalink / raw)
To: Mark Langsdorf; +Cc: qemu-devel, afaerber
On 4 January 2012 19:07, Mark Langsdorf <mark.langsdorf@calxeda.com> wrote:
> Add dummy register support for the cp15, CRn=c15 registers.
> config_base_register and power_control_register currently
> default to 0, but may have improved support after the QOM
> CPU patches are finished.
>
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> ---
> Changes from v6
> Added the diagnostic registers
> Added save/load support
> Changes from v5
> Added handling for all c15 registers
> Changes from v3, v4
> None
> Changes from v2
> Added test against op2
> Changes from v1
> renamed the config_base_register
> added comments about how it will change when QOM CPUs are added
>
> target-arm/cpu.h | 4 ++++
> target-arm/helper.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
> target-arm/machine.c | 7 +++++++
> 3 files changed, 59 insertions(+), 0 deletions(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index c4d742f..3bc90e6 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -149,6 +149,10 @@ typedef struct CPUARMState {
> uint32_t c15_i_max; /* Maximum D-cache dirty line index. */
> uint32_t c15_i_min; /* Minimum D-cache dirty line index. */
> uint32_t c15_threadid; /* TI debugger thread-ID. */
> + uint32_t c15_config_base_address; /* SCU base address. */
> + uint32_t c15_diagnostic; /* diagnostic register */
> + uint32_t c15_power_diagnostic;
> + uint32_t c15_power_control; /* power control */
> } cp15;
>
> struct {
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 65f4fbf..62028e5 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1768,6 +1768,20 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
> goto bad_reg;
> }
> }
> + if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) {
> + switch (crm) {
> + case 0:
> + if ((op1 == 0) && (op2 == 0)) {
> + env->cp15.c15_power_control = val;
> + } else if ((op1 == 0) && (op2 == 1)) {
> + env->cp15.c15_diagnostic = val;
> + } else if ((op1 == 0) && (op2 == 2)) {
> + env->cp15.c15_power_diagnostic = val;
> + }
> + default:
> + break;
> + }
> + }
> break;
> }
> return;
> @@ -2111,6 +2125,40 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
> * 0x200 << ($rn & 0xfff), when MMU is off. */
> goto bad_reg;
> }
> + if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) {
> + switch (crm) {
> + case 0:
> + if ((op1 == 4) && (op2 == 0)) {
> + /* The config_base_address should hold the value of
The indentation's wrong here and below (checkpatch complains).
> + * the peripheral base. ARM should get this from a CPU
> + * object property, but that support isn't available in
> + * December 2011. Default to 0 for now and board models
> + * that care can set it by a private hook */
> + return env->cp15.c15_config_base_address;
> + } else if ((op1 == 0) && (op2 == 0)) {
> + /* power_control should be set to maximum latency. Again,
> + default to 0 and set by private hook */
> + return env->cp15.c15_power_control;
> + } else if ((op1 == 0) && (op2 == 1)) {
> + return env->cp15.c15_diagnostic;
> + } else if ((op1 == 0) && (op2 == 2)) {
> + return env->cp15.c15_power_diagnostic;
> + }
> + break;
> + case 1: /* NEON Busy */
> + return 0;
> + case 5: /* tlb lockdown */
> + case 6:
> + case 7:
> + if ((op1 == 5) && (op2 == 2)) {
> + return 0;
> + }
> + break;
> + default:
> + break;
> + }
> + goto bad_reg;
> + }
> return 0;
> }
> bad_reg:
> diff --git a/target-arm/machine.c b/target-arm/machine.c
> index aaee9b9..7f25b0f 100644
> --- a/target-arm/machine.c
> +++ b/target-arm/machine.c
> @@ -56,6 +56,9 @@ void cpu_save(QEMUFile *f, void *opaque)
> qemu_put_be32(f, env->cp15.c13_tls2);
> qemu_put_be32(f, env->cp15.c13_tls3);
> qemu_put_be32(f, env->cp15.c15_cpar);
> + qemu_put_be32(f, env->cp15.c15_power_control);
> + qemu_put_be32(f, env->cp15.c15_diagnostic);
> + qemu_put_be32(f, env->cp15.c15_power_diagnostic);
>
> qemu_put_be32(f, env->features);
>
> @@ -170,6 +173,10 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
> env->cp15.c13_tls2 = qemu_get_be32(f);
> env->cp15.c13_tls3 = qemu_get_be32(f);
> env->cp15.c15_cpar = qemu_get_be32(f);
> + env->cp15.c15_power_control = qemu_get_be32(f);
> + env->cp15.c15_diagnostic = qemu_get_be32(f);
> + env->cp15.c15_power_diagnostic = qemu_get_be32(f);
> +
Stray blank line.
Adding fields to the cpu_load/cpu_save functions means you have
to bump CPU_SAVE_VERSION in target-arm/cpu.h.
> env->features = qemu_get_be32(f);
Thanks for your efforts revising this patch; I think we're nearly there...
-- PMM
^ permalink raw reply [flat|nested] 26+ messages in thread
* [Qemu-devel] [PATCH v8] arm: add dummy v7 cp15 registers
2012-01-04 23:50 ` Peter Maydell
@ 2012-01-05 0:14 ` Mark Langsdorf
2012-01-05 0:22 ` Peter Maydell
0 siblings, 1 reply; 26+ messages in thread
From: Mark Langsdorf @ 2012-01-05 0:14 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell, afaerber, Mark Langsdorf
Add dummy register support for the cp15, CRn=c15 registers and
for c1 SCR.
config_base_register and power_control_register currently
default to 0, but may have improved support after the QOM
CPU patches are finished.
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v7
Formatted improved
c1_scr added
CPU_SAVE_VERSION increased
Changes from v6
Added the diagnostic registers
Added save/load support
Changes from v5
Added handling for all c15 registers
Changes from v3, v4
None
Changes from v2
Added test against op2
Changes from v1
renamed the register
added comments about how it will change when QOM CPUs are added
target-arm/cpu.h | 7 +++++-
target-arm/helper.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++
target-arm/machine.c | 8 +++++++
3 files changed, 71 insertions(+), 1 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c4d742f..cfc2063 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -116,6 +116,7 @@ typedef struct CPUARMState {
uint32_t c1_sys; /* System control register. */
uint32_t c1_coproc; /* Coprocessor access register. */
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
+ uint32_t c1_scr; /* secure config register. */
uint32_t c2_base0; /* MMU translation table base 0. */
uint32_t c2_base1; /* MMU translation table base 1. */
uint32_t c2_control; /* MMU translation table base control. */
@@ -149,6 +150,10 @@ typedef struct CPUARMState {
uint32_t c15_i_max; /* Maximum D-cache dirty line index. */
uint32_t c15_i_min; /* Minimum D-cache dirty line index. */
uint32_t c15_threadid; /* TI debugger thread-ID. */
+ uint32_t c15_config_base_address; /* SCU base address. */
+ uint32_t c15_diagnostic; /* diagnostic register */
+ uint32_t c15_power_diagnostic;
+ uint32_t c15_power_control; /* power control */
} cp15;
struct {
@@ -448,7 +453,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
#define cpu_signal_handler cpu_arm_signal_handler
#define cpu_list arm_cpu_list
-#define CPU_SAVE_VERSION 4
+#define CPU_SAVE_VERSION 5
/* MMU modes definitions */
#define MMU_MODE0_SUFFIX _kernel
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 65f4fbf..acefd37 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1412,6 +1412,11 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
}
goto bad_reg;
case 1: /* System configuration. */
+ if (arm_feature(env, ARM_FEATURE_V7)
+ && op1 == 0 && crm == 1 && op2 == 0) {
+ env->cp15.c1_scr = val;
+ break;
+ }
if (arm_feature(env, ARM_FEATURE_OMAPCP))
op2 = 0;
switch (op2) {
@@ -1768,6 +1773,20 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
goto bad_reg;
}
}
+ if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) {
+ switch (crm) {
+ case 0:
+ if ((op1 == 0) && (op2 == 0)) {
+ env->cp15.c15_power_control = val;
+ } else if ((op1 == 0) && (op2 == 1)) {
+ env->cp15.c15_diagnostic = val;
+ } else if ((op1 == 0) && (op2 == 2)) {
+ env->cp15.c15_power_diagnostic = val;
+ }
+ default:
+ break;
+ }
+ }
break;
}
return;
@@ -1866,6 +1885,10 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
goto bad_reg;
}
case 1: /* System configuration. */
+ if (arm_feature(env, ARM_FEATURE_V7)
+ && op1 == 0 && crm == 1 && op2 == 0) {
+ return env->cp15.c1_scr;
+ }
if (arm_feature(env, ARM_FEATURE_OMAPCP))
op2 = 0;
switch (op2) {
@@ -2111,6 +2134,40 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
* 0x200 << ($rn & 0xfff), when MMU is off. */
goto bad_reg;
}
+ if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) {
+ switch (crm) {
+ case 0:
+ if ((op1 == 4) && (op2 == 0)) {
+ /* The config_base_address should hold the value of
+ * the peripheral base. ARM should get this from a CPU
+ * object property, but that support isn't available in
+ * December 2011. Default to 0 for now and board models
+ * that care can set it by a private hook */
+ return env->cp15.c15_config_base_address;
+ } else if ((op1 == 0) && (op2 == 0)) {
+ /* power_control should be set to maximum latency. Again,
+ default to 0 and set by private hook */
+ return env->cp15.c15_power_control;
+ } else if ((op1 == 0) && (op2 == 1)) {
+ return env->cp15.c15_diagnostic;
+ } else if ((op1 == 0) && (op2 == 2)) {
+ return env->cp15.c15_power_diagnostic;
+ }
+ break;
+ case 1: /* NEON Busy */
+ return 0;
+ case 5: /* tlb lockdown */
+ case 6:
+ case 7:
+ if ((op1 == 5) && (op2 == 2)) {
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+ goto bad_reg;
+ }
return 0;
}
bad_reg:
diff --git a/target-arm/machine.c b/target-arm/machine.c
index aaee9b9..f66b8df 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -26,6 +26,7 @@ void cpu_save(QEMUFile *f, void *opaque)
qemu_put_be32(f, env->cp15.c1_sys);
qemu_put_be32(f, env->cp15.c1_coproc);
qemu_put_be32(f, env->cp15.c1_xscaleauxcr);
+ qemu_put_be32(f, env->cp15.c1_scr);
qemu_put_be32(f, env->cp15.c2_base0);
qemu_put_be32(f, env->cp15.c2_base1);
qemu_put_be32(f, env->cp15.c2_control);
@@ -56,6 +57,9 @@ void cpu_save(QEMUFile *f, void *opaque)
qemu_put_be32(f, env->cp15.c13_tls2);
qemu_put_be32(f, env->cp15.c13_tls3);
qemu_put_be32(f, env->cp15.c15_cpar);
+ qemu_put_be32(f, env->cp15.c15_power_control);
+ qemu_put_be32(f, env->cp15.c15_diagnostic);
+ qemu_put_be32(f, env->cp15.c15_power_diagnostic);
qemu_put_be32(f, env->features);
@@ -140,6 +144,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
env->cp15.c1_sys = qemu_get_be32(f);
env->cp15.c1_coproc = qemu_get_be32(f);
env->cp15.c1_xscaleauxcr = qemu_get_be32(f);
+ env->cp15.c1_scr = qemu_get_be32(f);
env->cp15.c2_base0 = qemu_get_be32(f);
env->cp15.c2_base1 = qemu_get_be32(f);
env->cp15.c2_control = qemu_get_be32(f);
@@ -170,6 +175,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
env->cp15.c13_tls2 = qemu_get_be32(f);
env->cp15.c13_tls3 = qemu_get_be32(f);
env->cp15.c15_cpar = qemu_get_be32(f);
+ env->cp15.c15_power_control = qemu_get_be32(f);
+ env->cp15.c15_diagnostic = qemu_get_be32(f);
+ env->cp15.c15_power_diagnostic = qemu_get_be32(f);
env->features = qemu_get_be32(f);
--
1.7.5.4
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [Qemu-devel] [PATCH v8] arm: add dummy v7 cp15 registers
2012-01-05 0:14 ` [Qemu-devel] [PATCH v8] " Mark Langsdorf
@ 2012-01-05 0:22 ` Peter Maydell
2012-01-05 0:54 ` Mark Langsdorf
0 siblings, 1 reply; 26+ messages in thread
From: Peter Maydell @ 2012-01-05 0:22 UTC (permalink / raw)
To: Mark Langsdorf; +Cc: qemu-devel, afaerber
On 5 January 2012 00:14, Mark Langsdorf <mark.langsdorf@calxeda.com> wrote:
> Add dummy register support for the cp15, CRn=c15 registers and
> for c1 SCR.
Can you drop the SCR code, please? This needs to be done properly
as part of trustzone support, which is a different and rather larger
kettle of fish.
-- PMM
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [Qemu-devel] [PATCH v8] arm: add dummy v7 cp15 registers
2012-01-05 0:22 ` Peter Maydell
@ 2012-01-05 0:54 ` Mark Langsdorf
2012-01-05 8:36 ` Peter Maydell
0 siblings, 1 reply; 26+ messages in thread
From: Mark Langsdorf @ 2012-01-05 0:54 UTC (permalink / raw)
To: Peter Maydell; +Cc: qemu-devel@nongnu.org, afaerber@suse.de
On 01/04/2012 06:22 PM, Peter Maydell wrote:
> On 5 January 2012 00:14, Mark Langsdorf <mark.langsdorf@calxeda.com> wrote:
>> Add dummy register support for the cp15, CRn=c15 registers and
>> for c1 SCR.
>
> Can you drop the SCR code, please? This needs to be done properly
> as part of trustzone support, which is a different and rather larger
> kettle of fish.
I found out that the Highbank SoC model depends on the scr code
through four days of tedious debugging. Would it possible to keep
it in as a stub?
I'm still waiting on Kevin Wolf's review of the AHCI changes and
review of the last two patches from this series. I suppose I can
resubmit without scr and delay the SoC model for another while.
--Mark Langsdorf
Calxeda, Inc.
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [Qemu-devel] [PATCH v8] arm: add dummy v7 cp15 registers
2012-01-05 0:54 ` Mark Langsdorf
@ 2012-01-05 8:36 ` Peter Maydell
2012-01-05 13:16 ` [Qemu-devel] [PATCH v9] " Mark Langsdorf
0 siblings, 1 reply; 26+ messages in thread
From: Peter Maydell @ 2012-01-05 8:36 UTC (permalink / raw)
To: Mark Langsdorf; +Cc: qemu-devel@nongnu.org, afaerber@suse.de
On 5 January 2012 00:54, Mark Langsdorf <mark.langsdorf@calxeda.com> wrote:
> On 01/04/2012 06:22 PM, Peter Maydell wrote:
>> Can you drop the SCR code, please? This needs to be done properly
>> as part of trustzone support, which is a different and rather larger
>> kettle of fish.
>
> I found out that the Highbank SoC model depends on the scr code
> through four days of tedious debugging. Would it possible to keep
> it in as a stub?
Regardless, it shouldn't be in this patch, because it's not related
to the A9-specific c15 registers.
I'll have a look at the docs and see if there's a sensible minimal
implementation of the SCR that we could implement.
> I'm still waiting on Kevin Wolf's review of the AHCI changes
You should post those as a separate 2-patch AHCI set, I think.
> and
> review of the last two patches from this series.
These are still on my todo list, I haven't forgotten them.
(However I still have a huge patchset from Samsung to review
which I should probably do first.)
-- PMM
^ permalink raw reply [flat|nested] 26+ messages in thread
* [Qemu-devel] [PATCH v9] arm: add dummy v7 cp15 registers
2012-01-05 8:36 ` Peter Maydell
@ 2012-01-05 13:16 ` Mark Langsdorf
2012-01-05 15:33 ` Peter Maydell
0 siblings, 1 reply; 26+ messages in thread
From: Mark Langsdorf @ 2012-01-05 13:16 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell, afaerber, Mark Langsdorf
Add dummy register support for the cp15, CRn=c15 registers.
config_base_register and power_control_register currently
default to 0, but may have improved support after the QOM
CPU patches are finished.
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v8
Removed c1_scr
Changes from v7
Formatted improved
c1_scr added
CPU_SAVE_VERSION increased
Changes from v6
Added the diagnostic registers
Added save/load support
Changes from v5
Added handling for all c15 registers
Changes from v3, v4
None
Changes from v2
Added test against op2
Changes from v1
renamed the register
added comments about how it will change when QOM CPUs are added
target-arm/cpu.h | 6 +++++-
target-arm/helper.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
target-arm/machine.c | 6 ++++++
3 files changed, 59 insertions(+), 1 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c4d742f..26b4981 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -149,6 +149,10 @@ typedef struct CPUARMState {
uint32_t c15_i_max; /* Maximum D-cache dirty line index. */
uint32_t c15_i_min; /* Minimum D-cache dirty line index. */
uint32_t c15_threadid; /* TI debugger thread-ID. */
+ uint32_t c15_config_base_address; /* SCU base address. */
+ uint32_t c15_diagnostic; /* diagnostic register */
+ uint32_t c15_power_diagnostic;
+ uint32_t c15_power_control; /* power control */
} cp15;
struct {
@@ -448,7 +452,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
#define cpu_signal_handler cpu_arm_signal_handler
#define cpu_list arm_cpu_list
-#define CPU_SAVE_VERSION 4
+#define CPU_SAVE_VERSION 5
/* MMU modes definitions */
#define MMU_MODE0_SUFFIX _kernel
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 65f4fbf..4cfda17 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1768,6 +1768,20 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
goto bad_reg;
}
}
+ if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) {
+ switch (crm) {
+ case 0:
+ if ((op1 == 0) && (op2 == 0)) {
+ env->cp15.c15_power_control = val;
+ } else if ((op1 == 0) && (op2 == 1)) {
+ env->cp15.c15_diagnostic = val;
+ } else if ((op1 == 0) && (op2 == 2)) {
+ env->cp15.c15_power_diagnostic = val;
+ }
+ default:
+ break;
+ }
+ }
break;
}
return;
@@ -2111,6 +2125,40 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
* 0x200 << ($rn & 0xfff), when MMU is off. */
goto bad_reg;
}
+ if (ARM_CPUID(env) == ARM_CPUID_CORTEXA9) {
+ switch (crm) {
+ case 0:
+ if ((op1 == 4) && (op2 == 0)) {
+ /* The config_base_address should hold the value of
+ * the peripheral base. ARM should get this from a CPU
+ * object property, but that support isn't available in
+ * December 2011. Default to 0 for now and board models
+ * that care can set it by a private hook */
+ return env->cp15.c15_config_base_address;
+ } else if ((op1 == 0) && (op2 == 0)) {
+ /* power_control should be set to maximum latency. Again,
+ default to 0 and set by private hook */
+ return env->cp15.c15_power_control;
+ } else if ((op1 == 0) && (op2 == 1)) {
+ return env->cp15.c15_diagnostic;
+ } else if ((op1 == 0) && (op2 == 2)) {
+ return env->cp15.c15_power_diagnostic;
+ }
+ break;
+ case 1: /* NEON Busy */
+ return 0;
+ case 5: /* tlb lockdown */
+ case 6:
+ case 7:
+ if ((op1 == 5) && (op2 == 2)) {
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+ goto bad_reg;
+ }
return 0;
}
bad_reg:
diff --git a/target-arm/machine.c b/target-arm/machine.c
index aaee9b9..8984775 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -56,6 +56,9 @@ void cpu_save(QEMUFile *f, void *opaque)
qemu_put_be32(f, env->cp15.c13_tls2);
qemu_put_be32(f, env->cp15.c13_tls3);
qemu_put_be32(f, env->cp15.c15_cpar);
+ qemu_put_be32(f, env->cp15.c15_power_control);
+ qemu_put_be32(f, env->cp15.c15_diagnostic);
+ qemu_put_be32(f, env->cp15.c15_power_diagnostic);
qemu_put_be32(f, env->features);
@@ -170,6 +173,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
env->cp15.c13_tls2 = qemu_get_be32(f);
env->cp15.c13_tls3 = qemu_get_be32(f);
env->cp15.c15_cpar = qemu_get_be32(f);
+ env->cp15.c15_power_control = qemu_get_be32(f);
+ env->cp15.c15_diagnostic = qemu_get_be32(f);
+ env->cp15.c15_power_diagnostic = qemu_get_be32(f);
env->features = qemu_get_be32(f);
--
1.7.5.4
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [Qemu-devel] [PATCH v9] arm: add dummy v7 cp15 registers
2012-01-05 13:16 ` [Qemu-devel] [PATCH v9] " Mark Langsdorf
@ 2012-01-05 15:33 ` Peter Maydell
2012-01-05 15:34 ` Mark Langsdorf
0 siblings, 1 reply; 26+ messages in thread
From: Peter Maydell @ 2012-01-05 15:33 UTC (permalink / raw)
To: Mark Langsdorf; +Cc: qemu-devel, afaerber
On 5 January 2012 13:16, Mark Langsdorf <mark.langsdorf@calxeda.com> wrote:
> Add dummy register support for the cp15, CRn=c15 registers.
>
> config_base_register and power_control_register currently
> default to 0, but may have improved support after the QOM
> CPU patches are finished.
>
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
and put into target-arm.next.
(I've taken the liberty of tweaking the patch summary -- these
are A9-specific, not v7).
-- PMM
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [Qemu-devel] [PATCH v9] arm: add dummy v7 cp15 registers
2012-01-05 15:33 ` Peter Maydell
@ 2012-01-05 15:34 ` Mark Langsdorf
0 siblings, 0 replies; 26+ messages in thread
From: Mark Langsdorf @ 2012-01-05 15:34 UTC (permalink / raw)
To: Peter Maydell; +Cc: qemu-devel@nongnu.org, afaerber@suse.de
On 01/05/2012 09:33 AM, Peter Maydell wrote:
> On 5 January 2012 13:16, Mark Langsdorf <mark.langsdorf@calxeda.com> wrote:
>> Add dummy register support for the cp15, CRn=c15 registers.
>>
>> config_base_register and power_control_register currently
>> default to 0, but may have improved support after the QOM
>> CPU patches are finished.
>>
>> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
>
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
> and put into target-arm.next.
> (I've taken the liberty of tweaking the patch summary -- these
> are A9-specific, not v7).
Ack.
--Mark Langsdorf
Calxeda, Inc.
^ permalink raw reply [flat|nested] 26+ messages in thread
* [Qemu-devel] [PATCH v5 4/7] arm: add dummy gic security registers
2011-12-29 16:19 [Qemu-devel] [PATCH v5 0/7] various ARM fixes for Calxeda Highbank Mark Langsdorf
` (2 preceding siblings ...)
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 3/7] arm: add dummy v7 cp15 config_base_register Mark Langsdorf
@ 2011-12-29 16:19 ` Mark Langsdorf
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 5/5] add L2x0/PL310 cache controller device Mark Langsdorf
` (2 subsequent siblings)
6 siblings, 0 replies; 26+ messages in thread
From: Mark Langsdorf @ 2011-12-29 16:19 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell, Mark Langsdorf, afaerber, rob.herring
From: Rob Herring <rob.herring@calxeda.com>
Implement handling for the RAZ/WI gic security registers.
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
Changes from v2, v3, v4
None
Changes from v1
Moved handling back inside the 0-0x100 block
Added more clarifying comments
hw/arm_gic.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 9b52119..0339cf5 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -282,6 +282,10 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
return ((GIC_NIRQ / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
if (offset < 0x08)
return 0;
+ if (offset >= 0x80) {
+ /* Interrupt Security , RAZ/WI */
+ return 0;
+ }
#endif
goto bad_reg;
} else if (offset < 0x200) {
@@ -413,6 +417,8 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
} else if (offset < 4) {
/* ignored. */
+ } else if (offset >= 0x80) {
+ /* Interrupt Security Registers, RAZ/WI */
} else {
goto bad_reg;
}
--
1.7.5.4
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PATCH v5 5/5] add L2x0/PL310 cache controller device
2011-12-29 16:19 [Qemu-devel] [PATCH v5 0/7] various ARM fixes for Calxeda Highbank Mark Langsdorf
` (3 preceding siblings ...)
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 4/7] arm: add dummy gic security registers Mark Langsdorf
@ 2011-12-29 16:19 ` Mark Langsdorf
2012-01-04 13:29 ` Peter Maydell
2012-06-07 13:45 ` Andreas Färber
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 6/7] Add xgmac ethernet model Mark Langsdorf
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 7/7] arm: make the number of GIC interrupts configurable Mark Langsdorf
6 siblings, 2 replies; 26+ messages in thread
From: Mark Langsdorf @ 2011-12-29 16:19 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell, Mark Langsdorf, afaerber, rob.herring
From: Rob Herring <rob.herring@calxeda.com>
This is just a dummy device for ARM L2 cache controllers, based on the
pl310. The cache type parameter can be defined by a property value
and has a meaningful default.
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v4
Handling cache_type bits tracked from aux_control in the read function,
not the write function
Changes from v3
Changed default value
Adding tracking of cache_type bits from aux_control
Changes from v2
Reformatted a couple of function definitions to be 80 lines long
Changes from v1
Corrected formatting
Clarified the copyrights
Clarified GPL revision
Clarified model version
Removed hw_error() calls
Added a reset function
Restructed everything as switch/case statements
Added a type cache property
Makefile.target | 1 +
hw/arm_l2x0.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 183 insertions(+), 0 deletions(-)
create mode 100644 hw/arm_l2x0.c
diff --git a/Makefile.target b/Makefile.target
index 3261383..db5e44c 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -336,6 +336,7 @@ obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
obj-arm-y += versatile_pci.o
obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
+obj-arm-y += arm_l2x0.o
obj-arm-y += arm_mptimer.o
obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
obj-arm-y += pl061.o
diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c
new file mode 100644
index 0000000..ba106f1
--- /dev/null
+++ b/hw/arm_l2x0.c
@@ -0,0 +1,182 @@
+/*
+ * ARM dummy L210, L220, PL310 cache controller.
+ *
+ * Copyright (c) 2010-2012 Calxeda
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or any later version, as published by the Free Software
+ * Foundation.
+ *
+ * This program is distributed in the hope 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "sysbus.h"
+
+/* L2C-310 r3p2 */
+#define CACHE_ID 0x410000c8
+
+typedef struct l2x0_state {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ uint32_t cache_type;
+ uint32_t ctrl;
+ uint32_t aux_ctrl;
+ uint32_t data_ctrl;
+ uint32_t tag_ctrl;
+ uint32_t filter_start;
+ uint32_t filter_end;
+} l2x0_state;
+
+static const VMStateDescription vmstate_l2x0 = {
+ .name = "l2x0",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(ctrl, l2x0_state),
+ VMSTATE_UINT32(aux_ctrl, l2x0_state),
+ VMSTATE_UINT32(data_ctrl, l2x0_state),
+ VMSTATE_UINT32(tag_ctrl, l2x0_state),
+ VMSTATE_UINT32(filter_start, l2x0_state),
+ VMSTATE_UINT32(filter_end, l2x0_state),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+
+static uint64_t l2x0_priv_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ uint32_t cache_data;
+ l2x0_state *s = (l2x0_state *)opaque;
+ offset &= 0xfff;
+ if (offset >= 0x730 && offset < 0x800) {
+ return 0; /* cache ops complete */
+ }
+ switch (offset) {
+ case 0:
+ return CACHE_ID;
+ case 0x4:
+ /* aux_ctrl values affect cache_type values */
+ cache_data = (s->aux_ctrl & (7 << 17)) >> 15;
+ cache_data |= (s->aux_ctrl & (1 << 16)) >> 16;
+ return s->cache_type |= (cache_data << 18) | (cache_data << 6);
+ case 0x100:
+ return s->ctrl;
+ case 0x104:
+ return s->aux_ctrl;
+ case 0x108:
+ return s->tag_ctrl;
+ case 0x10C:
+ return s->data_ctrl;
+ case 0xC00:
+ return s->filter_start;
+ case 0xC04:
+ return s->filter_end;
+ case 0xF40:
+ return 0;
+ case 0xF60:
+ return 0;
+ case 0xF80:
+ return 0;
+ default:
+ fprintf(stderr, "l2x0_priv_read: Bad offset %x\n", (int)offset);
+ break;
+ }
+ return 0;
+}
+
+static void l2x0_priv_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ l2x0_state *s = (l2x0_state *)opaque;
+ offset &= 0xfff;
+ if (offset >= 0x730 && offset < 0x800) {
+ /* ignore */
+ return;
+ }
+ switch (offset) {
+ case 0x100:
+ s->ctrl = value & 1;
+ break;
+ case 0x104:
+ s->aux_ctrl = value;
+ break;
+ case 0x108:
+ s->tag_ctrl = value;
+ break;
+ case 0x10C:
+ s->data_ctrl = value;
+ break;
+ case 0xC00:
+ s->filter_start = value;
+ break;
+ case 0xC04:
+ s->filter_end = value;
+ break;
+ case 0xF40:
+ return;
+ case 0xF60:
+ return;
+ case 0xF80:
+ return;
+ default:
+ fprintf(stderr, "l2x0_priv_write: Bad offset %x\n", (int)offset);
+ break;
+ }
+}
+
+static void l2x0_priv_reset(DeviceState *dev)
+{
+ l2x0_state *s = DO_UPCAST(l2x0_state, busdev.qdev, dev);
+
+ s->ctrl = 0;
+ s->aux_ctrl = 0x02020000;
+ s->tag_ctrl = 0;
+ s->data_ctrl = 0;
+ s->filter_start = 0;
+ s->filter_end = 0;
+}
+
+static const MemoryRegionOps l2x0_mem_ops = {
+ .read = l2x0_priv_read,
+ .write = l2x0_priv_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ };
+
+static int l2x0_priv_init(SysBusDevice *dev)
+{
+ l2x0_state *s = FROM_SYSBUS(l2x0_state, dev);
+
+ memory_region_init_io(&s->iomem, &l2x0_mem_ops, s, "l2x0_cc", 0x1000);
+ sysbus_init_mmio(dev, &s->iomem);
+ return 0;
+}
+
+static SysBusDeviceInfo l2x0_info = {
+ .init = l2x0_priv_init,
+ .qdev.name = "l2x0",
+ .qdev.size = sizeof(l2x0_state),
+ .qdev.vmsd = &vmstate_l2x0,
+ .qdev.no_user = 1,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("type", l2x0_state, cache_type, 0x1c100100),
+ DEFINE_PROP_END_OF_LIST(),
+ },
+ .qdev.reset = l2x0_priv_reset,
+};
+
+static void l2x0_register_device(void)
+{
+ sysbus_register_withprop(&l2x0_info);
+}
+
+device_init(l2x0_register_device)
+
--
1.7.5.4
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [Qemu-devel] [PATCH v5 5/5] add L2x0/PL310 cache controller device
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 5/5] add L2x0/PL310 cache controller device Mark Langsdorf
@ 2012-01-04 13:29 ` Peter Maydell
2012-06-07 13:45 ` Andreas Färber
1 sibling, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2012-01-04 13:29 UTC (permalink / raw)
To: Mark Langsdorf; +Cc: qemu-devel, rob.herring, afaerber
On 29 December 2011 16:19, Mark Langsdorf <mark.langsdorf@calxeda.com> wrote:
> From: Rob Herring <rob.herring@calxeda.com>
>
> This is just a dummy device for ARM L2 cache controllers, based on the
> pl310. The cache type parameter can be defined by a property value
> and has a meaningful default.
>
> Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
(well, it has a stray blank line at the end, but I'll just zap that when I put
it into arm-devs.next.)
I'll put together the simple patches that add the cache controller to vexpress
and realview shortly.
-- PMM
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [Qemu-devel] [PATCH v5 5/5] add L2x0/PL310 cache controller device
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 5/5] add L2x0/PL310 cache controller device Mark Langsdorf
2012-01-04 13:29 ` Peter Maydell
@ 2012-06-07 13:45 ` Andreas Färber
2012-06-07 14:21 ` Mark Langsdorf
1 sibling, 1 reply; 26+ messages in thread
From: Andreas Färber @ 2012-06-07 13:45 UTC (permalink / raw)
To: Mark Langsdorf; +Cc: peter.maydell, qemu-devel, rob.herring, Paolo Bonzini
Am 29.12.2011 17:19, schrieb Mark Langsdorf:
> From: Rob Herring <rob.herring@calxeda.com>
>
> This is just a dummy device for ARM L2 cache controllers, based on the
> pl310. The cache type parameter can be defined by a property value
> and has a meaningful default.
>
> Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c
> new file mode 100644
> index 0000000..ba106f1
> --- /dev/null
> +++ b/hw/arm_l2x0.c
[...]
> +static SysBusDeviceInfo l2x0_info = {
> + .init = l2x0_priv_init,
> + .qdev.name = "l2x0",
> + .qdev.size = sizeof(l2x0_state),
> + .qdev.vmsd = &vmstate_l2x0,
> + .qdev.no_user = 1,
> + .qdev.props = (Property[]) {
> + DEFINE_PROP_UINT32("type", l2x0_state, cache_type, 0x1c100100),
Mark, this "type" property conflicts with a QOM refactoring by Paolo.
Mind if we rename it to "cache-type"? It always has its default value in
upstream.
Thanks,
Andreas
> + DEFINE_PROP_END_OF_LIST(),
> + },
> + .qdev.reset = l2x0_priv_reset,
> +};
> +
> +static void l2x0_register_device(void)
> +{
> + sysbus_register_withprop(&l2x0_info);
> +}
> +
> +device_init(l2x0_register_device)
> +
--
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [Qemu-devel] [PATCH v5 5/5] add L2x0/PL310 cache controller device
2012-06-07 13:45 ` Andreas Färber
@ 2012-06-07 14:21 ` Mark Langsdorf
0 siblings, 0 replies; 26+ messages in thread
From: Mark Langsdorf @ 2012-06-07 14:21 UTC (permalink / raw)
To: Andreas Färber
Cc: peter.maydell@linaro.org, qemu-devel@nongnu.org, Rob Herring,
Paolo Bonzini
Yes, that's fine by me.
--Mark Langsdorf
Calxeda, Inc.
________________________________________
From: Andreas Färber [afaerber@suse.de]
Sent: Thursday, June 07, 2012 8:45 AM
To: Mark Langsdorf
Cc: qemu-devel@nongnu.org; peter.maydell@linaro.org; Rob Herring; Paolo Bonzini
Subject: Re: [Qemu-devel] [PATCH v5 5/5] add L2x0/PL310 cache controller device
Am 29.12.2011 17:19, schrieb Mark Langsdorf:
> From: Rob Herring <rob.herring@calxeda.com>
>
> This is just a dummy device for ARM L2 cache controllers, based on the
> pl310. The cache type parameter can be defined by a property value
> and has a meaningful default.
>
> Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c
> new file mode 100644
> index 0000000..ba106f1
> --- /dev/null
> +++ b/hw/arm_l2x0.c
[...]
> +static SysBusDeviceInfo l2x0_info = {
> + .init = l2x0_priv_init,
> + .qdev.name = "l2x0",
> + .qdev.size = sizeof(l2x0_state),
> + .qdev.vmsd = &vmstate_l2x0,
> + .qdev.no_user = 1,
> + .qdev.props = (Property[]) {
> + DEFINE_PROP_UINT32("type", l2x0_state, cache_type, 0x1c100100),
Mark, this "type" property conflicts with a QOM refactoring by Paolo.
Mind if we rename it to "cache-type"? It always has its default value in
upstream.
Thanks,
Andreas
> + DEFINE_PROP_END_OF_LIST(),
> + },
> + .qdev.reset = l2x0_priv_reset,
> +};
> +
> +static void l2x0_register_device(void)
> +{
> + sysbus_register_withprop(&l2x0_info);
> +}
> +
> +device_init(l2x0_register_device)
> +
--
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
^ permalink raw reply [flat|nested] 26+ messages in thread
* [Qemu-devel] [PATCH v5 6/7] Add xgmac ethernet model
2011-12-29 16:19 [Qemu-devel] [PATCH v5 0/7] various ARM fixes for Calxeda Highbank Mark Langsdorf
` (4 preceding siblings ...)
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 5/5] add L2x0/PL310 cache controller device Mark Langsdorf
@ 2011-12-29 16:19 ` Mark Langsdorf
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 7/7] arm: make the number of GIC interrupts configurable Mark Langsdorf
6 siblings, 0 replies; 26+ messages in thread
From: Mark Langsdorf @ 2011-12-29 16:19 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell, Mark Langsdorf, afaerber, rob.herring
This adds very basic support for XG-mac ethernet core from Synopsis and
others. Missing things include:
- statistics counters
- WoL support
- rx checksum offload
- chained descriptors (only linear descriptor ring)
- broadcast and multicast handling
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v4
None
Changes from v3
Added debug macro and cleaned up some debug code
Refitted all lines to fit within 80 columns
Changes from v2
None
Changes from v1
Reformated most lines to fit within 80 columns
Removed a bunch of unused variables in the state structures
Got rid of some camelcase structure names
Added vmstate support
Makefile.target | 1 +
hw/xgmac.c | 424 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 425 insertions(+), 0 deletions(-)
create mode 100644 hw/xgmac.c
diff --git a/Makefile.target b/Makefile.target
index db5e44c..94cb9ff 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -340,6 +340,7 @@ obj-arm-y += arm_l2x0.o
obj-arm-y += arm_mptimer.o
obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
obj-arm-y += pl061.o
+obj-arm-y += xgmac.o
obj-arm-y += arm-semi.o
obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
diff --git a/hw/xgmac.c b/hw/xgmac.c
new file mode 100644
index 0000000..c19fff5
--- /dev/null
+++ b/hw/xgmac.c
@@ -0,0 +1,424 @@
+/*
+ * QEMU model of XGMAC Ethernet.
+ *
+ * derived from the Xilinx AXI-Ethernet by Edgar E. Iglesias.
+ *
+ * Copyright (c) 2011 Calxeda, Inc.
+ *
+ * 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 "sysbus.h"
+#include "qemu-char.h"
+#include "qemu-log.h"
+#include "net.h"
+#include "net/checksum.h"
+
+#ifdef DEBUG_XGMAC
+#define DEBUGF_BRK(message, args...) do { \
+ fprintf(stderr, (message), ## args); \
+ } while (0)
+#else
+#define DEBUGF_BRK(message, args...) do { } while (0)
+#endif
+
+#define XGMAC_CONTROL 0x00000000 /* MAC Configuration */
+#define XGMAC_FRAME_FILTER 0x00000001 /* MAC Frame Filter */
+#define XGMAC_FLOW_CTRL 0x00000006 /* MAC Flow Control */
+#define XGMAC_VLAN_TAG 0x00000007 /* VLAN Tags */
+#define XGMAC_VERSION 0x00000008 /* Version */
+/* VLAN tag for insertion or replacement into tx frames */
+#define XGMAC_VLAN_INCL 0x00000009
+#define XGMAC_LPI_CTRL 0x0000000a /* LPI Control and Status */
+#define XGMAC_LPI_TIMER 0x0000000b /* LPI Timers Control */
+#define XGMAC_TX_PACE 0x0000000c /* Transmit Pace and Stretch */
+#define XGMAC_VLAN_HASH 0x0000000d /* VLAN Hash Table */
+#define XGMAC_DEBUG 0x0000000e /* Debug */
+#define XGMAC_INT_STATUS 0x0000000f /* Interrupt and Control */
+/* HASH table registers */
+#define XGMAC_HASH(n) ((0x00000300/4) + (n))
+#define XGMAC_NUM_HASH 16
+/* Operation Mode */
+#define XGMAC_OPMODE (0x00000400/4)
+/* Remote Wake-Up Frame Filter */
+#define XGMAC_REMOTE_WAKE (0x00000700/4)
+/* PMT Control and Status */
+#define XGMAC_PMT (0x00000704/4)
+
+#define XGMAC_ADDR_HIGH(reg) (0x00000010+((reg) * 2))
+#define XGMAC_ADDR_LOW(reg) (0x00000011+((reg) * 2))
+
+#define DMA_BUS_MODE 0x000003c0 /* Bus Mode */
+#define DMA_XMT_POLL_DEMAND 0x000003c1 /* Transmit Poll Demand */
+#define DMA_RCV_POLL_DEMAND 0x000003c2 /* Received Poll Demand */
+#define DMA_RCV_BASE_ADDR 0x000003c3 /* Receive List Base */
+#define DMA_TX_BASE_ADDR 0x000003c4 /* Transmit List Base */
+#define DMA_STATUS 0x000003c5 /* Status Register */
+#define DMA_CONTROL 0x000003c6 /* Ctrl (Operational Mode) */
+#define DMA_INTR_ENA 0x000003c7 /* Interrupt Enable */
+#define DMA_MISSED_FRAME_CTR 0x000003c8 /* Missed Frame Counter */
+/* Receive Interrupt Watchdog Timer */
+#define DMA_RI_WATCHDOG_TIMER 0x000003c9
+#define DMA_AXI_BUS 0x000003ca /* AXI Bus Mode */
+#define DMA_AXI_STATUS 0x000003cb /* AXI Status */
+#define DMA_CUR_TX_DESC_ADDR 0x000003d2 /* Current Host Tx Descriptor */
+#define DMA_CUR_RX_DESC_ADDR 0x000003d3 /* Current Host Rx Descriptor */
+#define DMA_CUR_TX_BUF_ADDR 0x000003d4 /* Current Host Tx Buffer */
+#define DMA_CUR_RX_BUF_ADDR 0x000003d5 /* Current Host Rx Buffer */
+#define DMA_HW_FEATURE 0x000003d6 /* Enabled Hardware Features */
+
+/* DMA Status register defines */
+#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */
+#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */
+#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */
+#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */
+#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */
+#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */
+#define DMA_STATUS_TS_SHIFT 20
+#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */
+#define DMA_STATUS_RS_SHIFT 17
+#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */
+#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */
+#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */
+#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */
+#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */
+#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */
+#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */
+#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */
+#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */
+#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */
+#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */
+#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */
+#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */
+#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */
+#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */
+
+/* DMA Control register defines */
+#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */
+#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */
+#define DMA_CONTROL_DFF 0x01000000 /* Disable flush of rx frames */
+
+struct desc {
+ uint32_t ctl_stat;
+ uint16_t buffer1_size;
+ uint16_t buffer2_size;
+ uint32_t buffer1_addr;
+ uint32_t buffer2_addr;
+ uint32_t ext_stat;
+ uint32_t res[3];
+};
+
+#define R_MAX 0x400
+
+typedef struct rxtx_stats {
+ uint64_t rx_bytes;
+ uint64_t tx_bytes;
+
+ uint64_t rx;
+ uint64_t rx_bcast;
+ uint64_t rx_mcast;
+} rxtx_stats;
+
+typedef struct xgmac_state {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ qemu_irq sbd_irq;
+ qemu_irq pmt_irq;
+ qemu_irq mci_irq;
+ NICState *nic;
+ NICConf conf;
+
+ uint32_t c_phyaddr;
+ struct rxtx_stats stats;
+ uint32_t regs[R_MAX];
+} xgmac_state;
+
+const VMStateDescription vmstate_rxtx_stats = {
+ .name = "xgmac_stats",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(rx_bytes, rxtx_stats),
+ VMSTATE_UINT64(tx_bytes, rxtx_stats),
+ VMSTATE_UINT64(rx, rxtx_stats),
+ VMSTATE_UINT64(rx_bcast, rxtx_stats),
+ VMSTATE_UINT64(rx_mcast, rxtx_stats),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_xgmac = {
+ .name = "xgmac",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(c_phyaddr, xgmac_state),
+ VMSTATE_STRUCT(stats, xgmac_state, 0, vmstate_rxtx_stats, rxtx_stats),
+ VMSTATE_UINT32_ARRAY(regs, xgmac_state, R_MAX),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void xgmac_read_desc(struct xgmac_state *s, struct desc *d, int rx)
+{
+ uint32_t addr = rx ? s->regs[DMA_CUR_RX_DESC_ADDR] :
+ s->regs[DMA_CUR_TX_DESC_ADDR];
+ cpu_physical_memory_read(addr, d, sizeof(*d));
+}
+
+static void xgmac_write_desc(struct xgmac_state *s, struct desc *d, int rx)
+{
+ int reg = rx ? DMA_CUR_RX_DESC_ADDR : DMA_CUR_TX_DESC_ADDR;
+ uint32_t addr = s->regs[reg];
+
+ if (!rx && (d->ctl_stat & 0x00200000)) {
+ s->regs[reg] = s->regs[DMA_TX_BASE_ADDR];
+ } else if (rx && (d->buffer1_size & 0x8000)) {
+ s->regs[reg] = s->regs[DMA_RCV_BASE_ADDR];
+ } else {
+ s->regs[reg] += sizeof(*d);
+ }
+ cpu_physical_memory_write(addr, d, sizeof(*d));
+}
+
+static void xgmac_enet_send(struct xgmac_state *s)
+{
+ struct desc bd;
+ int frame_size;
+ int len;
+ uint8_t frame[8192];
+ uint8_t *ptr;
+
+ ptr = frame;
+ frame_size = 0;
+ while (1) {
+ xgmac_read_desc(s, &bd, 0);
+ if ((bd.ctl_stat & 0x80000000) == 0) {
+ /* Run out of descriptors to transmit. */
+ break;
+ }
+ len = (bd.buffer1_size & 0xfff) + (bd.buffer2_size & 0xfff);
+
+ if ((bd.buffer1_size & 0xfff) > 2048) {
+ DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- "
+ "xgmac buffer 1 len on send > 2048 (0x%x)\n",
+ __func__, bd.buffer1_size & 0xfff);
+ }
+ if ((bd.buffer2_size & 0xfff) != 0) {
+ DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- "
+ "xgmac buffer 2 len on send != 0 (0x%x)\n",
+ __func__, bd.buffer2_size & 0xfff);
+ }
+ if (len >= sizeof(frame)) {
+ DEBUGF_BRK("qemu:%s: buffer overflow %d read into %zu "
+ "buffer\n" , __func__, len, sizeof(frame));
+ DEBUGF_BRK("qemu:%s: buffer1.size=%d; buffer2.size=%d\n",
+ __func__, bd.buffer1_size, bd.buffer2_size);
+ }
+
+ cpu_physical_memory_read(bd.buffer1_addr, ptr, len);
+ ptr += len;
+ frame_size += len;
+ if (bd.ctl_stat & 0x20000000) {
+ /* Last buffer in frame. */
+ qemu_send_packet(&s->nic->nc, frame, len);
+ ptr = frame;
+ frame_size = 0;
+ s->regs[DMA_STATUS] |= DMA_STATUS_TI | DMA_STATUS_NIS;
+ }
+ bd.ctl_stat &= ~0x80000000;
+ /* Write back the modified descriptor. */
+ xgmac_write_desc(s, &bd, 0);
+ }
+}
+
+static void enet_update_irq(struct xgmac_state *s)
+{
+ int stat = s->regs[DMA_STATUS] & s->regs[DMA_INTR_ENA];
+ qemu_set_irq(s->sbd_irq, !!stat);
+}
+
+static uint64_t enet_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+ struct xgmac_state *s = opaque;
+ uint64_t r = 0;
+ addr >>= 2;
+
+ switch (addr) {
+ case XGMAC_VERSION:
+ r = 0x1012;
+ break;
+ default:
+ if (addr < ARRAY_SIZE(s->regs)) {
+ r = s->regs[addr];
+ }
+ break;
+ }
+ return r;
+}
+
+static void enet_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned size)
+{
+ struct xgmac_state *s = opaque;
+
+ addr >>= 2;
+ switch (addr) {
+ case DMA_BUS_MODE:
+ s->regs[DMA_BUS_MODE] = value & ~0x1;
+ break;
+ case DMA_XMT_POLL_DEMAND:
+ xgmac_enet_send(s);
+ break;
+ case DMA_STATUS:
+ s->regs[DMA_STATUS] = s->regs[DMA_STATUS] & ~value;
+ break;
+ case DMA_RCV_BASE_ADDR:
+ s->regs[DMA_RCV_BASE_ADDR] = s->regs[DMA_CUR_RX_DESC_ADDR] = value;
+ break;
+ case DMA_TX_BASE_ADDR:
+ s->regs[DMA_TX_BASE_ADDR] = s->regs[DMA_CUR_TX_DESC_ADDR] = value;
+ break;
+ default:
+ if (addr < ARRAY_SIZE(s->regs)) {
+ s->regs[addr] = value;
+ }
+ break;
+ }
+ enet_update_irq(s);
+}
+
+static const MemoryRegionOps enet_mem_ops = {
+ .read = enet_read,
+ .write = enet_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int eth_can_rx(VLANClientState *nc)
+{
+ struct xgmac_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+ /* RX enabled? */
+ return s->regs[DMA_CONTROL] & DMA_CONTROL_SR;
+}
+
+static ssize_t eth_rx(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+ struct xgmac_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
+ static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff};
+ int unicast, broadcast, multicast;
+ struct desc bd;
+ ssize_t ret;
+
+ unicast = ~buf[0] & 0x1;
+ broadcast = memcmp(buf, sa_bcast, 6) == 0;
+ multicast = !unicast && !broadcast;
+ if (size < 12) {
+ s->regs[DMA_STATUS] |= DMA_STATUS_RI | DMA_STATUS_NIS;
+ ret = -1;
+ goto out;
+ }
+
+ xgmac_read_desc(s, &bd, 1);
+ if ((bd.ctl_stat & 0x80000000) == 0) {
+ s->regs[DMA_STATUS] |= DMA_STATUS_RU | DMA_STATUS_AIS;
+ ret = size;
+ goto out;
+ }
+
+ cpu_physical_memory_write(bd.buffer1_addr, buf, size);
+
+ /* Add in the 4 bytes for crc (the real hw returns length incl crc) */
+ size += 4;
+ bd.ctl_stat = (size << 16) | 0x300;
+ xgmac_write_desc(s, &bd, 1);
+
+ s->stats.rx_bytes += size;
+ s->stats.rx++;
+ if (multicast) {
+ s->stats.rx_mcast++;
+ } else if (broadcast) {
+ s->stats.rx_bcast++;
+ }
+
+ s->regs[DMA_STATUS] |= DMA_STATUS_RI | DMA_STATUS_NIS;
+ ret = size;
+
+out:
+ enet_update_irq(s);
+ return ret;
+}
+
+static void eth_cleanup(VLANClientState *nc)
+{
+ struct xgmac_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
+ s->nic = NULL;
+}
+
+static NetClientInfo net_xgmac_enet_info = {
+ .type = NET_CLIENT_TYPE_NIC,
+ .size = sizeof(NICState),
+ .can_receive = eth_can_rx,
+ .receive = eth_rx,
+ .cleanup = eth_cleanup,
+};
+
+static int xgmac_enet_init(SysBusDevice *dev)
+{
+ struct xgmac_state *s = FROM_SYSBUS(typeof(*s), dev);
+
+ memory_region_init_io(&s->iomem, &enet_mem_ops, s, "xgmac", 0x1000);
+ sysbus_init_mmio(dev, &s->iomem);
+ sysbus_init_irq(dev, &s->sbd_irq);
+ sysbus_init_irq(dev, &s->pmt_irq);
+ sysbus_init_irq(dev, &s->mci_irq);
+
+ qemu_macaddr_default_if_unset(&s->conf.macaddr);
+ s->nic = qemu_new_nic(&net_xgmac_enet_info, &s->conf,
+ dev->qdev.info->name, dev->qdev.id, s);
+ qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+
+ s->regs[XGMAC_ADDR_HIGH(0)] = (s->conf.macaddr.a[5] << 8) |
+ s->conf.macaddr.a[4];
+ s->regs[XGMAC_ADDR_LOW(0)] = (s->conf.macaddr.a[3] << 24) |
+ (s->conf.macaddr.a[2] << 16) |
+ (s->conf.macaddr.a[1] << 8) |
+ s->conf.macaddr.a[0];
+
+ return 0;
+}
+
+static SysBusDeviceInfo xgmac_enet_info = {
+ .init = xgmac_enet_init,
+ .qdev.name = "xgmac",
+ .qdev.size = sizeof(struct xgmac_state),
+ .qdev.vmsd = &vmstate_xgmac,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("phyaddr", struct xgmac_state, c_phyaddr, 7),
+ DEFINE_NIC_PROPERTIES(struct xgmac_state, conf),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+static void xgmac_enet_register(void)
+{
+ sysbus_register_withprop(&xgmac_enet_info);
+}
+
+device_init(xgmac_enet_register)
--
1.7.5.4
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PATCH v5 7/7] arm: make the number of GIC interrupts configurable
2011-12-29 16:19 [Qemu-devel] [PATCH v5 0/7] various ARM fixes for Calxeda Highbank Mark Langsdorf
` (5 preceding siblings ...)
2011-12-29 16:19 ` [Qemu-devel] [PATCH v5 6/7] Add xgmac ethernet model Mark Langsdorf
@ 2011-12-29 16:19 ` Mark Langsdorf
6 siblings, 0 replies; 26+ messages in thread
From: Mark Langsdorf @ 2011-12-29 16:19 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell, Mark Langsdorf, afaerber, rob.herring
Increase the maximum number of GIC interrupts for a9mp and a11mp to 256,
and create a configurable property for each defaulting to 96 and 64
(respectively) so that device modelers can set the value appropriately
for their SoC. Other ARM processors also set their maximum number of
used IRQs appropriately.
Set the maximum theoretically number of GIC interrupts to 1020 and
update the save/restore code to only use the appropriate number for
each SoC.
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v4
None
Changes from v3
Increase maximum number of GIC interrupts to 1020
Remove SoC/implementation specific GIC_NIRQ #defs
Added properties code to arm11mp
Changed error handling for too many interrupts
Redid save/load handling
Changes from v2
Skipped
Changes from v1
Increase the number of a9mp interrupts to 192
Add a property defaulting to 96
Add a num_irq member in the gic state structure
Use the num_irq value as appropriate
Add num_irq argument to gic_init()
Add num_irq to various CPU calls to gic_init
hw/a9mpcore.c | 7 +++--
hw/arm11mpcore.c | 14 +++++++-----
hw/arm_gic.c | 57 +++++++++++++++++++++++++++++-----------------------
hw/armv7m_nvic.c | 7 ++---
hw/realview_gic.c | 3 +-
5 files changed, 48 insertions(+), 40 deletions(-)
diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index 3ef0e13..8c8b72b 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -11,9 +11,8 @@
#include "sysbus.h"
/* Configuration for arm_gic.c:
- * number of external IRQ lines, max number of CPUs, how to ID current CPU
+ * max number of CPUs, how to ID current CPU
*/
-#define GIC_NIRQ 96
#define NCPU 4
static inline int
@@ -37,6 +36,7 @@ typedef struct a9mp_priv_state {
MemoryRegion ptimer_iomem;
MemoryRegion container;
DeviceState *mptimer;
+ uint32_t num_irq;
} a9mp_priv_state;
static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset,
@@ -153,7 +153,7 @@ static int a9mp_priv_init(SysBusDevice *dev)
hw_error("a9mp_priv_init: num-cpu may not be more than %d\n", NCPU);
}
- gic_init(&s->gic, s->num_cpu);
+ gic_init(&s->gic, s->num_cpu, s->num_irq);
s->mptimer = qdev_create(NULL, "arm_mptimer");
qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
@@ -216,6 +216,7 @@ static SysBusDeviceInfo a9mp_priv_info = {
.qdev.reset = a9mp_priv_reset,
.qdev.props = (Property[]) {
DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1),
+ DEFINE_PROP_UINT32("num-irq", a9mp_priv_state, num_irq, 256),
DEFINE_PROP_END_OF_LIST(),
}
};
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index bc0457e..e4e4bb3 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -10,11 +10,6 @@
#include "sysbus.h"
#include "qemu-timer.h"
-/* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines
- (+ 32 internal). However my test chip only exposes/reports 32.
- More importantly Linux falls over if more than 32 are present! */
-#define GIC_NIRQ 64
-
#define NCPU 4
static inline int
@@ -37,6 +32,7 @@ typedef struct mpcore_priv_state {
MemoryRegion iomem;
MemoryRegion container;
DeviceState *mptimer;
+ uint32_t num_irq;
} mpcore_priv_state;
/* Per-CPU private memory mapped IO. */
@@ -132,7 +128,7 @@ static int mpcore_priv_init(SysBusDevice *dev)
{
mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
- gic_init(&s->gic, s->num_cpu);
+ gic_init(&s->gic, s->num_cpu, GIC_NIRQ);
s->mptimer = qdev_create(NULL, "arm_mptimer");
qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
qdev_init_nofail(s->mptimer);
@@ -221,6 +217,12 @@ static SysBusDeviceInfo mpcore_priv_info = {
.qdev.size = sizeof(mpcore_priv_state),
.qdev.props = (Property[]) {
DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
+ /* The MPCore TRM says the on-chip controller has 224 external
+ * IRQ lines (+ 32 internal). Some test chips only
+ * expose/report 32. More importantly Linux falls over if more
+ * than 32 are present! Set the default to 64 and let chips
+ * with more working lines set it higher */
+ DEFINE_PROP_UINT32("num-irq", mpcore_priv_state, num_irq, 64),
DEFINE_PROP_END_OF_LIST(),
}
};
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 0339cf5..5bfb01f 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -11,6 +11,7 @@
controller, MPCore distributed interrupt controller and ARMv7-M
Nested Vectored Interrupt Controller. */
+#define GIC_NIRQ 1020
//#define DEBUG_GIC
#ifdef DEBUG_GIC
@@ -111,6 +112,7 @@ typedef struct gic_state
struct gic_state *backref[NCPU];
MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */
#endif
+ int num_irq;
} gic_state;
/* TODO: Many places that call this routine could be optimized. */
@@ -133,7 +135,7 @@ static void gic_update(gic_state *s)
}
best_prio = 0x100;
best_irq = 1023;
- for (irq = 0; irq < GIC_NIRQ; irq++) {
+ for (irq = 0; irq < s->num_irq; irq++) {
if (GIC_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) {
if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
best_prio = GIC_GET_PRIORITY(irq, cpu);
@@ -222,7 +224,7 @@ static void gic_complete_irq(gic_state * s, int cpu, int irq)
int update = 0;
int cm = 1 << cpu;
DPRINTF("EOI %d\n", irq);
- if (irq >= GIC_NIRQ) {
+ if (irq >= s->num_irq) {
/* This handles two cases:
* 1. If software writes the ID of a spurious interrupt [ie 1023]
* to the GICC_EOIR, the GIC ignores that write.
@@ -279,7 +281,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
if (offset == 0)
return s->enabled;
if (offset == 4)
- return ((GIC_NIRQ / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
+ return ((s->num_irq / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
if (offset < 0x08)
return 0;
if (offset >= 0x80) {
@@ -295,7 +297,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
else
irq = (offset - 0x180) * 8;
irq += GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
res = 0;
for (i = 0; i < 8; i++) {
@@ -310,7 +312,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
else
irq = (offset - 0x280) * 8;
irq += GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
res = 0;
mask = (irq < 32) ? cm : ALL_CPU_MASK;
@@ -322,7 +324,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
} else if (offset < 0x400) {
/* Interrupt Active. */
irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
res = 0;
mask = (irq < 32) ? cm : ALL_CPU_MASK;
@@ -334,14 +336,14 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
} else if (offset < 0x800) {
/* Interrupt Priority. */
irq = (offset - 0x400) + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
res = GIC_GET_PRIORITY(irq, cpu);
#ifndef NVIC
} else if (offset < 0xc00) {
/* Interrupt CPU Target. */
irq = (offset - 0x800) + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq >= 29 && irq <= 31) {
res = cm;
@@ -351,7 +353,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
} else if (offset < 0xf00) {
/* Interrupt Configuration. */
irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
res = 0;
for (i = 0; i < 4; i++) {
@@ -426,7 +428,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
} else if (offset < 0x180) {
/* Interrupt Set Enable. */
irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 16)
value = 0xff;
@@ -451,7 +453,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
} else if (offset < 0x200) {
/* Interrupt Clear Enable. */
irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 16)
value = 0;
@@ -468,7 +470,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
} else if (offset < 0x280) {
/* Interrupt Set Pending. */
irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 16)
irq = 0;
@@ -481,7 +483,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
} else if (offset < 0x300) {
/* Interrupt Clear Pending. */
irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
for (i = 0; i < 8; i++) {
/* ??? This currently clears the pending bit for all CPUs, even
@@ -497,7 +499,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
} else if (offset < 0x800) {
/* Interrupt Priority. */
irq = (offset - 0x400) + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 32) {
s->priority1[irq][cpu] = value;
@@ -508,7 +510,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
} else if (offset < 0xc00) {
/* Interrupt CPU Target. */
irq = (offset - 0x800) + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 29)
value = 0;
@@ -518,7 +520,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
} else if (offset < 0xf00) {
/* Interrupt Configuration. */
irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 32)
value |= 0xaa;
@@ -735,17 +737,17 @@ static void gic_save(QEMUFile *f, void *opaque)
qemu_put_be32(f, s->cpu_enabled[i]);
for (j = 0; j < 32; j++)
qemu_put_be32(f, s->priority1[j][i]);
- for (j = 0; j < GIC_NIRQ; j++)
+ for (j = 0; j < s->num_irq; j++)
qemu_put_be32(f, s->last_active[j][i]);
qemu_put_be32(f, s->priority_mask[i]);
qemu_put_be32(f, s->running_irq[i]);
qemu_put_be32(f, s->running_priority[i]);
qemu_put_be32(f, s->current_pending[i]);
}
- for (i = 0; i < GIC_NIRQ - 32; i++) {
+ for (i = 0; i < s->num_irq - 32; i++) {
qemu_put_be32(f, s->priority2[i]);
}
- for (i = 0; i < GIC_NIRQ; i++) {
+ for (i = 0; i < s->num_irq; i++) {
#ifndef NVIC
qemu_put_be32(f, s->irq_target[i]);
#endif
@@ -772,17 +774,17 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id)
s->cpu_enabled[i] = qemu_get_be32(f);
for (j = 0; j < 32; j++)
s->priority1[j][i] = qemu_get_be32(f);
- for (j = 0; j < GIC_NIRQ; j++)
+ for (j = 0; j < s->num_irq; j++)
s->last_active[j][i] = qemu_get_be32(f);
s->priority_mask[i] = qemu_get_be32(f);
s->running_irq[i] = qemu_get_be32(f);
s->running_priority[i] = qemu_get_be32(f);
s->current_pending[i] = qemu_get_be32(f);
}
- for (i = 0; i < GIC_NIRQ - 32; i++) {
+ for (i = 0; i < s->num_irq - 32; i++) {
s->priority2[i] = qemu_get_be32(f);
}
- for (i = 0; i < GIC_NIRQ; i++) {
+ for (i = 0; i < s->num_irq; i++) {
#ifndef NVIC
s->irq_target[i] = qemu_get_be32(f);
#endif
@@ -798,9 +800,9 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id)
}
#if NCPU > 1
-static void gic_init(gic_state *s, int num_cpu)
+static void gic_init(gic_state *s, int num_cpu, int num_irq)
#else
-static void gic_init(gic_state *s)
+static void gic_init(gic_state *s, int num_irq)
#endif
{
int i;
@@ -808,7 +810,12 @@ static void gic_init(gic_state *s)
#if NCPU > 1
s->num_cpu = num_cpu;
#endif
- qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
+ s->num_irq = num_irq;
+ if (s->num_irq > GIC_NIRQ) {
+ hw_error("device requested %u out of %u interrupt lines, failing\n",
+ num_irq, GIC_NIRQ);
+ }
+ qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, s->num_irq - 32);
for (i = 0; i < NUM_CPU(s); i++) {
sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
}
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index bf8c3c5..0de51f4 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -15,9 +15,6 @@
#include "arm-misc.h"
#include "exec-memory.h"
-/* 32 internal lines (16 used for system exceptions) plus 64 external
- interrupt lines. */
-#define GIC_NIRQ 96
#define NCPU 1
#define NVIC 1
@@ -384,7 +381,9 @@ static int armv7m_nvic_init(SysBusDevice *dev)
{
nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
- gic_init(&s->gic);
+ /* 32 internal lines (16 used for system exceptions) plus 64 external
+ * interrupt lines. */
+ gic_init(&s->gic, 96);
memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->gic.iomem);
s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
vmstate_register(&dev->qdev, -1, &vmstate_nvic, s);
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index 8c4d509..cd7e53d 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -9,7 +9,6 @@
#include "sysbus.h"
-#define GIC_NIRQ 96
#define NCPU 1
/* Only a single "CPU" interface is present. */
@@ -37,7 +36,7 @@ static int realview_gic_init(SysBusDevice *dev)
{
RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
- gic_init(&s->gic);
+ gic_init(&s->gic, 96);
realview_gic_map_setup(s);
sysbus_init_mmio(dev, &s->container);
return 0;
--
1.7.5.4
^ permalink raw reply related [flat|nested] 26+ messages in thread