mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/agraf/tags/signed-ppc-for-upstream' into staging
Patch queue for ppc - 2014-03-05 This pull request includes: - VSX emulation support - book3s pr/hv selection - some bug fixes - qdev stable numbering - eTSEC emulation # gpg: Signature made Wed 05 Mar 2014 02:14:19 GMT using RSA key ID 03FEDC60 # gpg: Can't check signature: public key not found * remotes/agraf/tags/signed-ppc-for-upstream: (130 commits) target-ppc: spapr: e500: fix to use cpu_dt_id target-ppc: add PowerPCCPU::cpu_dt_id target-ppc: Introduce hypervisor call H_GET_TCE target-ppc: Update ppc_hash64_store_hpte to support updating in-kernel htab target-ppc: Change the hpte store API target-ppc: Fix page table lookup with kvm enabled target-ppc: Fix htab_mask calculation target-ppc: Use Additional Temporary in stqcx Case target-ppc: Fix Compiler Warnings Due to 64-Bit Constants Declared as UL PPC: sPAPR: Only use getpagesize() when we run with kvm target-ppc/translate.c: Use ULL suffix for 64 bit constants spapr-vlan: flush queue whenever can_receive can go from false to true target-ppc: Altivec 2.07: Vector Permute and Exclusive OR target-ppc: Altivec 2.07: Vector SHA Sigma Instructions target-ppc: Altivec 2.07: AES Instructions target-ppc: Altivec 2.07: Binary Coded Decimal Instructions target-ppc: Altivec 2.07: Vector Polynomial Multiply Sum target-ppc: Altivec 2.07: Vector Gather Bits by Bytes target-ppc: Altivec 2.07: Doubleword Compares target-ppc: Altivec 2.07: vbpermq Instruction ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -47,4 +47,5 @@ CONFIG_E500=y
|
||||
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
|
||||
# For PReP
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_ETSEC=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
|
||||
+24
-6
@@ -284,12 +284,30 @@ static void *load_at(int fd, int offset, int size)
|
||||
#define SZ 64
|
||||
#include "hw/elf_ops.h"
|
||||
|
||||
const char *load_elf_strerror(int error)
|
||||
{
|
||||
switch (error) {
|
||||
case 0:
|
||||
return "No error";
|
||||
case ELF_LOAD_FAILED:
|
||||
return "Failed to load ELF";
|
||||
case ELF_LOAD_NOT_ELF:
|
||||
return "The image is not ELF";
|
||||
case ELF_LOAD_WRONG_ARCH:
|
||||
return "The image is from incompatible architecture";
|
||||
case ELF_LOAD_WRONG_ENDIAN:
|
||||
return "The image has incorrect endianness";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
/* return < 0 if error, otherwise the number of bytes loaded in memory */
|
||||
int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
|
||||
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
|
||||
uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb)
|
||||
{
|
||||
int fd, data_order, target_data_order, must_swab, ret;
|
||||
int fd, data_order, target_data_order, must_swab, ret = ELF_LOAD_FAILED;
|
||||
uint8_t e_ident[EI_NIDENT];
|
||||
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
@@ -302,8 +320,10 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
|
||||
if (e_ident[0] != ELFMAG0 ||
|
||||
e_ident[1] != ELFMAG1 ||
|
||||
e_ident[2] != ELFMAG2 ||
|
||||
e_ident[3] != ELFMAG3)
|
||||
e_ident[3] != ELFMAG3) {
|
||||
ret = ELF_LOAD_NOT_ELF;
|
||||
goto fail;
|
||||
}
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
data_order = ELFDATA2MSB;
|
||||
#else
|
||||
@@ -317,6 +337,7 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
|
||||
}
|
||||
|
||||
if (target_data_order != e_ident[EI_DATA]) {
|
||||
ret = ELF_LOAD_WRONG_ENDIAN;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -329,12 +350,9 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
|
||||
pentry, lowaddr, highaddr, elf_machine, clear_lsb);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
close(fd);
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bswap_uboot_header(uboot_image_header_t *hdr)
|
||||
|
||||
+13
-7
@@ -440,27 +440,33 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
|
||||
static void qbus_realize(BusState *bus, DeviceState *parent, const char *name)
|
||||
{
|
||||
const char *typename = object_get_typename(OBJECT(bus));
|
||||
BusClass *bc;
|
||||
char *buf;
|
||||
int i,len;
|
||||
int i, len, bus_id;
|
||||
|
||||
bus->parent = parent;
|
||||
|
||||
if (name) {
|
||||
bus->name = g_strdup(name);
|
||||
} else if (bus->parent && bus->parent->id) {
|
||||
/* parent device has id -> use it for bus name */
|
||||
/* parent device has id -> use it plus parent-bus-id for bus name */
|
||||
bus_id = bus->parent->num_child_bus;
|
||||
|
||||
len = strlen(bus->parent->id) + 16;
|
||||
buf = g_malloc(len);
|
||||
snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus);
|
||||
snprintf(buf, len, "%s.%d", bus->parent->id, bus_id);
|
||||
bus->name = buf;
|
||||
} else {
|
||||
/* no id -> use lowercase bus type for bus name */
|
||||
/* no id -> use lowercase bus type plus global bus-id for bus name */
|
||||
bc = BUS_GET_CLASS(bus);
|
||||
bus_id = bc->automatic_ids++;
|
||||
|
||||
len = strlen(typename) + 16;
|
||||
buf = g_malloc(len);
|
||||
len = snprintf(buf, len, "%s.%d", typename,
|
||||
bus->parent ? bus->parent->num_child_bus : 0);
|
||||
for (i = 0; i < len; i++)
|
||||
len = snprintf(buf, len, "%s.%d", typename, bus_id);
|
||||
for (i = 0; i < len; i++) {
|
||||
buf[i] = qemu_tolower(buf[i]);
|
||||
}
|
||||
bus->name = buf;
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -221,10 +221,16 @@ static void pc_init1(QEMUMachineInitArgs *args,
|
||||
} else {
|
||||
for(i = 0; i < MAX_IDE_BUS; i++) {
|
||||
ISADevice *dev;
|
||||
char busname[] = "ide.0";
|
||||
dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i],
|
||||
ide_irq[i],
|
||||
hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
|
||||
idebus[i] = qdev_get_child_bus(DEVICE(dev), "ide.0");
|
||||
/*
|
||||
* The ide bus name is ide.0 for the first bus and ide.1 for the
|
||||
* second one.
|
||||
*/
|
||||
busname[4] = '0' + i;
|
||||
idebus[i] = qdev_get_child_bus(DEVICE(dev), busname);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
|
||||
|
||||
encap.cap = KVM_CAP_IRQ_MPIC;
|
||||
encap.args[0] = opp->fd;
|
||||
encap.args[1] = cs->cpu_index;
|
||||
encap.args[1] = kvm_arch_vcpu_id(cs);
|
||||
|
||||
return kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
|
||||
}
|
||||
|
||||
+13
-2
@@ -33,6 +33,17 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/visitor.h"
|
||||
|
||||
static int get_cpu_index_by_dt_id(int cpu_dt_id)
|
||||
{
|
||||
PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id);
|
||||
|
||||
if (cpu) {
|
||||
return cpu->parent_obj.cpu_index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
@@ -659,7 +670,7 @@ static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong server = args[0];
|
||||
target_ulong server = get_cpu_index_by_dt_id(args[0]);
|
||||
target_ulong mfrr = args[1];
|
||||
|
||||
if (server >= spapr->icp->nr_servers) {
|
||||
@@ -728,7 +739,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
}
|
||||
|
||||
nr = rtas_ld(args, 0);
|
||||
server = rtas_ld(args, 1);
|
||||
server = get_cpu_index_by_dt_id(rtas_ld(args, 1));
|
||||
priority = rtas_ld(args, 2);
|
||||
|
||||
if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
|
||||
|
||||
+5
-5
@@ -65,7 +65,7 @@ static void icp_get_kvm_state(ICPState *ss)
|
||||
ret = kvm_vcpu_ioctl(ss->cs, KVM_GET_ONE_REG, ®);
|
||||
if (ret != 0) {
|
||||
error_report("Unable to retrieve KVM interrupt controller state"
|
||||
" for CPU %d: %s", ss->cs->cpu_index, strerror(errno));
|
||||
" for CPU %ld: %s", kvm_arch_vcpu_id(ss->cs), strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ static int icp_set_kvm_state(ICPState *ss, int version_id)
|
||||
ret = kvm_vcpu_ioctl(ss->cs, KVM_SET_ONE_REG, ®);
|
||||
if (ret != 0) {
|
||||
error_report("Unable to restore KVM interrupt controller state (0x%"
|
||||
PRIx64 ") for CPU %d: %s", state, ss->cs->cpu_index,
|
||||
PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(ss->cs),
|
||||
strerror(errno));
|
||||
return ret;
|
||||
}
|
||||
@@ -325,15 +325,15 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
|
||||
struct kvm_enable_cap xics_enable_cap = {
|
||||
.cap = KVM_CAP_IRQ_XICS,
|
||||
.flags = 0,
|
||||
.args = {icpkvm->kernel_xics_fd, cs->cpu_index, 0, 0},
|
||||
.args = {icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs), 0, 0},
|
||||
};
|
||||
|
||||
ss->cs = cs;
|
||||
|
||||
ret = kvm_vcpu_ioctl(ss->cs, KVM_ENABLE_CAP, &xics_enable_cap);
|
||||
if (ret < 0) {
|
||||
error_report("Unable to connect CPU%d to kernel XICS: %s",
|
||||
cs->cpu_index, strerror(errno));
|
||||
error_report("Unable to connect CPU%ld to kernel XICS: %s",
|
||||
kvm_arch_vcpu_id(cs), strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params)
|
||||
&entry, &kernel_low, &kernel_high, 1,
|
||||
ELF_MACHINE, 0);
|
||||
|
||||
if (!kernel_size) {
|
||||
if (kernel_size <= 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
loader_params->kernel_filename);
|
||||
exit(1);
|
||||
|
||||
@@ -32,3 +32,6 @@ obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
|
||||
|
||||
obj-$(CONFIG_VIRTIO) += virtio-net.o
|
||||
obj-y += vhost_net.o
|
||||
|
||||
obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \
|
||||
fsl_etsec/rings.o fsl_etsec/miim.o
|
||||
|
||||
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
* QEMU Freescale eTSEC Emulator
|
||||
*
|
||||
* Copyright (c) 2011-2013 AdaCore
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This implementation doesn't include ring priority, TCP/IP Off-Load, QoS.
|
||||
*/
|
||||
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "trace.h"
|
||||
#include "hw/ptimer.h"
|
||||
#include "etsec.h"
|
||||
#include "registers.h"
|
||||
|
||||
/* #define HEX_DUMP */
|
||||
/* #define DEBUG_REGISTER */
|
||||
|
||||
#ifdef DEBUG_REGISTER
|
||||
static const int debug_etsec = 1;
|
||||
#else
|
||||
static const int debug_etsec;
|
||||
#endif
|
||||
|
||||
#define DPRINTF(fmt, ...) do { \
|
||||
if (debug_etsec) { \
|
||||
qemu_log(fmt , ## __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static uint64_t etsec_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
eTSEC *etsec = opaque;
|
||||
uint32_t reg_index = addr / 4;
|
||||
eTSEC_Register *reg = NULL;
|
||||
uint32_t ret = 0x0;
|
||||
|
||||
assert(reg_index < ETSEC_REG_NUMBER);
|
||||
|
||||
reg = &etsec->regs[reg_index];
|
||||
|
||||
|
||||
switch (reg->access) {
|
||||
case ACC_WO:
|
||||
ret = 0x00000000;
|
||||
break;
|
||||
|
||||
case ACC_RW:
|
||||
case ACC_W1C:
|
||||
case ACC_RO:
|
||||
default:
|
||||
ret = reg->value;
|
||||
break;
|
||||
}
|
||||
|
||||
DPRINTF("Read 0x%08x @ 0x" TARGET_FMT_plx
|
||||
" : %s (%s)\n",
|
||||
ret, addr, reg->name, reg->desc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void write_tstat(eTSEC *etsec,
|
||||
eTSEC_Register *reg,
|
||||
uint32_t reg_index,
|
||||
uint32_t value)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
/* Check THLTi flag in TSTAT */
|
||||
if (value & (1 << (31 - i))) {
|
||||
etsec_walk_tx_ring(etsec, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write 1 to clear */
|
||||
reg->value &= ~value;
|
||||
}
|
||||
|
||||
static void write_rstat(eTSEC *etsec,
|
||||
eTSEC_Register *reg,
|
||||
uint32_t reg_index,
|
||||
uint32_t value)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
/* Check QHLTi flag in RSTAT */
|
||||
if (value & (1 << (23 - i)) && !(reg->value & (1 << (23 - i)))) {
|
||||
etsec_walk_rx_ring(etsec, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write 1 to clear */
|
||||
reg->value &= ~value;
|
||||
}
|
||||
|
||||
static void write_tbasex(eTSEC *etsec,
|
||||
eTSEC_Register *reg,
|
||||
uint32_t reg_index,
|
||||
uint32_t value)
|
||||
{
|
||||
reg->value = value & ~0x7;
|
||||
|
||||
/* Copy this value in the ring's TxBD pointer */
|
||||
etsec->regs[TBPTR0 + (reg_index - TBASE0)].value = value & ~0x7;
|
||||
}
|
||||
|
||||
static void write_rbasex(eTSEC *etsec,
|
||||
eTSEC_Register *reg,
|
||||
uint32_t reg_index,
|
||||
uint32_t value)
|
||||
{
|
||||
reg->value = value & ~0x7;
|
||||
|
||||
/* Copy this value in the ring's RxBD pointer */
|
||||
etsec->regs[RBPTR0 + (reg_index - RBASE0)].value = value & ~0x7;
|
||||
}
|
||||
|
||||
static void write_ievent(eTSEC *etsec,
|
||||
eTSEC_Register *reg,
|
||||
uint32_t reg_index,
|
||||
uint32_t value)
|
||||
{
|
||||
/* Write 1 to clear */
|
||||
reg->value &= ~value;
|
||||
|
||||
if (!(reg->value & (IEVENT_TXF | IEVENT_TXF))) {
|
||||
qemu_irq_lower(etsec->tx_irq);
|
||||
}
|
||||
if (!(reg->value & (IEVENT_RXF | IEVENT_RXF))) {
|
||||
qemu_irq_lower(etsec->rx_irq);
|
||||
}
|
||||
|
||||
if (!(reg->value & (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC |
|
||||
IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC |
|
||||
IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ |
|
||||
IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE |
|
||||
IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD |
|
||||
IEVENT_MMRW))) {
|
||||
qemu_irq_lower(etsec->err_irq);
|
||||
}
|
||||
}
|
||||
|
||||
static void write_dmactrl(eTSEC *etsec,
|
||||
eTSEC_Register *reg,
|
||||
uint32_t reg_index,
|
||||
uint32_t value)
|
||||
{
|
||||
reg->value = value;
|
||||
|
||||
if (value & DMACTRL_GRS) {
|
||||
|
||||
if (etsec->rx_buffer_len != 0) {
|
||||
/* Graceful receive stop delayed until end of frame */
|
||||
} else {
|
||||
/* Graceful receive stop now */
|
||||
etsec->regs[IEVENT].value |= IEVENT_GRSC;
|
||||
if (etsec->regs[IMASK].value & IMASK_GRSCEN) {
|
||||
qemu_irq_raise(etsec->err_irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value & DMACTRL_GTS) {
|
||||
|
||||
if (etsec->tx_buffer_len != 0) {
|
||||
/* Graceful transmit stop delayed until end of frame */
|
||||
} else {
|
||||
/* Graceful transmit stop now */
|
||||
etsec->regs[IEVENT].value |= IEVENT_GTSC;
|
||||
if (etsec->regs[IMASK].value & IMASK_GTSCEN) {
|
||||
qemu_irq_raise(etsec->err_irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(value & DMACTRL_WOP)) {
|
||||
/* Start polling */
|
||||
ptimer_stop(etsec->ptimer);
|
||||
ptimer_set_count(etsec->ptimer, 1);
|
||||
ptimer_run(etsec->ptimer, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void etsec_write(void *opaque,
|
||||
hwaddr addr,
|
||||
uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
eTSEC *etsec = opaque;
|
||||
uint32_t reg_index = addr / 4;
|
||||
eTSEC_Register *reg = NULL;
|
||||
uint32_t before = 0x0;
|
||||
|
||||
assert(reg_index < ETSEC_REG_NUMBER);
|
||||
|
||||
reg = &etsec->regs[reg_index];
|
||||
before = reg->value;
|
||||
|
||||
switch (reg_index) {
|
||||
case IEVENT:
|
||||
write_ievent(etsec, reg, reg_index, value);
|
||||
break;
|
||||
|
||||
case DMACTRL:
|
||||
write_dmactrl(etsec, reg, reg_index, value);
|
||||
break;
|
||||
|
||||
case TSTAT:
|
||||
write_tstat(etsec, reg, reg_index, value);
|
||||
break;
|
||||
|
||||
case RSTAT:
|
||||
write_rstat(etsec, reg, reg_index, value);
|
||||
break;
|
||||
|
||||
case TBASE0 ... TBASE7:
|
||||
write_tbasex(etsec, reg, reg_index, value);
|
||||
break;
|
||||
|
||||
case RBASE0 ... RBASE7:
|
||||
write_rbasex(etsec, reg, reg_index, value);
|
||||
break;
|
||||
|
||||
case MIIMCFG ... MIIMIND:
|
||||
etsec_write_miim(etsec, reg, reg_index, value);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Default handling */
|
||||
switch (reg->access) {
|
||||
|
||||
case ACC_RW:
|
||||
case ACC_WO:
|
||||
reg->value = value;
|
||||
break;
|
||||
|
||||
case ACC_W1C:
|
||||
reg->value &= ~value;
|
||||
break;
|
||||
|
||||
case ACC_RO:
|
||||
default:
|
||||
/* Read Only or Unknown register */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF("Write 0x%08x @ 0x" TARGET_FMT_plx
|
||||
" val:0x%08x->0x%08x : %s (%s)\n",
|
||||
(unsigned int)value, addr, before, reg->value,
|
||||
reg->name, reg->desc);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps etsec_ops = {
|
||||
.read = etsec_read,
|
||||
.write = etsec_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void etsec_timer_hit(void *opaque)
|
||||
{
|
||||
eTSEC *etsec = opaque;
|
||||
|
||||
ptimer_stop(etsec->ptimer);
|
||||
|
||||
if (!(etsec->regs[DMACTRL].value & DMACTRL_WOP)) {
|
||||
|
||||
if (!(etsec->regs[DMACTRL].value & DMACTRL_GTS)) {
|
||||
etsec_walk_tx_ring(etsec, 0);
|
||||
}
|
||||
ptimer_set_count(etsec->ptimer, 1);
|
||||
ptimer_run(etsec->ptimer, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void etsec_reset(DeviceState *d)
|
||||
{
|
||||
eTSEC *etsec = ETSEC_COMMON(d);
|
||||
int i = 0;
|
||||
int reg_index = 0;
|
||||
|
||||
/* Default value for all registers */
|
||||
for (i = 0; i < ETSEC_REG_NUMBER; i++) {
|
||||
etsec->regs[i].name = "Reserved";
|
||||
etsec->regs[i].desc = "";
|
||||
etsec->regs[i].access = ACC_UNKNOWN;
|
||||
etsec->regs[i].value = 0x00000000;
|
||||
}
|
||||
|
||||
/* Set-up known registers */
|
||||
for (i = 0; eTSEC_registers_def[i].name != NULL; i++) {
|
||||
|
||||
reg_index = eTSEC_registers_def[i].offset / 4;
|
||||
|
||||
etsec->regs[reg_index].name = eTSEC_registers_def[i].name;
|
||||
etsec->regs[reg_index].desc = eTSEC_registers_def[i].desc;
|
||||
etsec->regs[reg_index].access = eTSEC_registers_def[i].access;
|
||||
etsec->regs[reg_index].value = eTSEC_registers_def[i].reset;
|
||||
}
|
||||
|
||||
etsec->tx_buffer = NULL;
|
||||
etsec->tx_buffer_len = 0;
|
||||
etsec->rx_buffer = NULL;
|
||||
etsec->rx_buffer_len = 0;
|
||||
|
||||
etsec->phy_status =
|
||||
MII_SR_EXTENDED_CAPS | MII_SR_LINK_STATUS | MII_SR_AUTONEG_CAPS |
|
||||
MII_SR_AUTONEG_COMPLETE | MII_SR_PREAMBLE_SUPPRESS |
|
||||
MII_SR_EXTENDED_STATUS | MII_SR_100T2_HD_CAPS | MII_SR_100T2_FD_CAPS |
|
||||
MII_SR_10T_HD_CAPS | MII_SR_10T_FD_CAPS | MII_SR_100X_HD_CAPS |
|
||||
MII_SR_100X_FD_CAPS | MII_SR_100T4_CAPS;
|
||||
}
|
||||
|
||||
static void etsec_cleanup(NetClientState *nc)
|
||||
{
|
||||
/* qemu_log("eTSEC cleanup\n"); */
|
||||
}
|
||||
|
||||
static int etsec_can_receive(NetClientState *nc)
|
||||
{
|
||||
eTSEC *etsec = qemu_get_nic_opaque(nc);
|
||||
|
||||
return etsec->rx_buffer_len == 0;
|
||||
}
|
||||
|
||||
static ssize_t etsec_receive(NetClientState *nc,
|
||||
const uint8_t *buf,
|
||||
size_t size)
|
||||
{
|
||||
eTSEC *etsec = qemu_get_nic_opaque(nc);
|
||||
|
||||
#if defined(HEX_DUMP)
|
||||
fprintf(stderr, "%s receive size:%d\n", etsec->nic->nc.name, size);
|
||||
qemu_hexdump(buf, stderr, "", size);
|
||||
#endif
|
||||
etsec_rx_ring_write(etsec, buf, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
static void etsec_set_link_status(NetClientState *nc)
|
||||
{
|
||||
eTSEC *etsec = qemu_get_nic_opaque(nc);
|
||||
|
||||
etsec_miim_link_status(etsec, nc);
|
||||
}
|
||||
|
||||
static NetClientInfo net_etsec_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = etsec_can_receive,
|
||||
.receive = etsec_receive,
|
||||
.cleanup = etsec_cleanup,
|
||||
.link_status_changed = etsec_set_link_status,
|
||||
};
|
||||
|
||||
static void etsec_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
eTSEC *etsec = ETSEC_COMMON(dev);
|
||||
|
||||
etsec->nic = qemu_new_nic(&net_etsec_info, &etsec->conf,
|
||||
object_get_typename(OBJECT(dev)), dev->id, etsec);
|
||||
qemu_format_nic_info_str(qemu_get_queue(etsec->nic), etsec->conf.macaddr.a);
|
||||
|
||||
|
||||
etsec->bh = qemu_bh_new(etsec_timer_hit, etsec);
|
||||
etsec->ptimer = ptimer_init(etsec->bh);
|
||||
ptimer_set_freq(etsec->ptimer, 100);
|
||||
}
|
||||
|
||||
static void etsec_instance_init(Object *obj)
|
||||
{
|
||||
eTSEC *etsec = ETSEC_COMMON(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&etsec->io_area, OBJECT(etsec), &etsec_ops, etsec,
|
||||
"eTSEC", 0x1000);
|
||||
sysbus_init_mmio(sbd, &etsec->io_area);
|
||||
|
||||
sysbus_init_irq(sbd, &etsec->tx_irq);
|
||||
sysbus_init_irq(sbd, &etsec->rx_irq);
|
||||
sysbus_init_irq(sbd, &etsec->err_irq);
|
||||
}
|
||||
|
||||
static Property etsec_properties[] = {
|
||||
DEFINE_NIC_PROPERTIES(eTSEC, conf),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void etsec_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = etsec_realize;
|
||||
dc->reset = etsec_reset;
|
||||
dc->props = etsec_properties;
|
||||
}
|
||||
|
||||
static TypeInfo etsec_info = {
|
||||
.name = "eTSEC",
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(eTSEC),
|
||||
.class_init = etsec_class_init,
|
||||
.instance_init = etsec_instance_init,
|
||||
};
|
||||
|
||||
static void etsec_register_types(void)
|
||||
{
|
||||
type_register_static(&etsec_info);
|
||||
}
|
||||
|
||||
type_init(etsec_register_types)
|
||||
|
||||
DeviceState *etsec_create(hwaddr base,
|
||||
MemoryRegion * mr,
|
||||
NICInfo * nd,
|
||||
qemu_irq tx_irq,
|
||||
qemu_irq rx_irq,
|
||||
qemu_irq err_irq)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_create(NULL, "eTSEC");
|
||||
qdev_set_nic_properties(dev, nd);
|
||||
|
||||
if (qdev_init(dev)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, tx_irq);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, rx_irq);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, err_irq);
|
||||
|
||||
memory_region_add_subregion(mr, base,
|
||||
SYS_BUS_DEVICE(dev)->mmio[0].memory);
|
||||
|
||||
return dev;
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* QEMU Freescale eTSEC Emulator
|
||||
*
|
||||
* Copyright (c) 2011-2013 AdaCore
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _ETSEC_H_
|
||||
#define _ETSEC_H_
|
||||
|
||||
#include "hw/qdev.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/ptimer.h"
|
||||
|
||||
/* Buffer Descriptors */
|
||||
|
||||
typedef struct eTSEC_rxtx_bd {
|
||||
uint16_t flags;
|
||||
uint16_t length;
|
||||
uint32_t bufptr;
|
||||
} eTSEC_rxtx_bd;
|
||||
|
||||
#define BD_WRAP (1 << 13)
|
||||
#define BD_INTERRUPT (1 << 12)
|
||||
#define BD_LAST (1 << 11)
|
||||
|
||||
#define BD_TX_READY (1 << 15)
|
||||
#define BD_TX_PADCRC (1 << 14)
|
||||
#define BD_TX_TC (1 << 10)
|
||||
#define BD_TX_PREDEF (1 << 9)
|
||||
#define BD_TX_HFELC (1 << 7)
|
||||
#define BD_TX_CFRL (1 << 6)
|
||||
#define BD_TX_RC_MASK 0xF
|
||||
#define BD_TX_RC_OFFSET 0x2
|
||||
#define BD_TX_TOEUN (1 << 1)
|
||||
#define BD_TX_TR (1 << 0)
|
||||
|
||||
#define BD_RX_EMPTY (1 << 15)
|
||||
#define BD_RX_RO1 (1 << 14)
|
||||
#define BD_RX_FIRST (1 << 10)
|
||||
#define BD_RX_MISS (1 << 8)
|
||||
#define BD_RX_BROADCAST (1 << 7)
|
||||
#define BD_RX_MULTICAST (1 << 6)
|
||||
#define BD_RX_LG (1 << 5)
|
||||
#define BD_RX_NO (1 << 4)
|
||||
#define BD_RX_SH (1 << 3)
|
||||
#define BD_RX_CR (1 << 2)
|
||||
#define BD_RX_OV (1 << 1)
|
||||
#define BD_RX_TR (1 << 0)
|
||||
|
||||
/* Tx FCB flags */
|
||||
#define FCB_TX_VLN (1 << 7)
|
||||
#define FCB_TX_IP (1 << 6)
|
||||
#define FCB_TX_IP6 (1 << 5)
|
||||
#define FCB_TX_TUP (1 << 4)
|
||||
#define FCB_TX_UDP (1 << 3)
|
||||
#define FCB_TX_CIP (1 << 2)
|
||||
#define FCB_TX_CTU (1 << 1)
|
||||
#define FCB_TX_NPH (1 << 0)
|
||||
|
||||
/* PHY Status Register */
|
||||
#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
|
||||
#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
|
||||
#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
|
||||
#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
|
||||
#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
|
||||
#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
|
||||
#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
|
||||
#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
|
||||
#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
|
||||
#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
|
||||
#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
|
||||
#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
|
||||
#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
|
||||
#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
|
||||
#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
|
||||
|
||||
/* eTSEC */
|
||||
|
||||
/* Number of register in the device */
|
||||
#define ETSEC_REG_NUMBER 1024
|
||||
|
||||
typedef struct eTSEC_Register {
|
||||
const char *name;
|
||||
const char *desc;
|
||||
uint32_t access;
|
||||
uint32_t value;
|
||||
} eTSEC_Register;
|
||||
|
||||
typedef struct eTSEC {
|
||||
SysBusDevice busdev;
|
||||
|
||||
MemoryRegion io_area;
|
||||
|
||||
eTSEC_Register regs[ETSEC_REG_NUMBER];
|
||||
|
||||
NICState *nic;
|
||||
NICConf conf;
|
||||
|
||||
/* Tx */
|
||||
|
||||
uint8_t *tx_buffer;
|
||||
uint32_t tx_buffer_len;
|
||||
eTSEC_rxtx_bd first_bd;
|
||||
|
||||
/* Rx */
|
||||
|
||||
uint8_t *rx_buffer;
|
||||
uint32_t rx_buffer_len;
|
||||
uint32_t rx_remaining_data;
|
||||
uint8_t rx_first_in_frame;
|
||||
uint8_t rx_fcb_size;
|
||||
eTSEC_rxtx_bd rx_first_bd;
|
||||
uint8_t rx_fcb[10];
|
||||
uint32_t rx_padding;
|
||||
|
||||
/* IRQs */
|
||||
qemu_irq tx_irq;
|
||||
qemu_irq rx_irq;
|
||||
qemu_irq err_irq;
|
||||
|
||||
|
||||
uint16_t phy_status;
|
||||
uint16_t phy_control;
|
||||
|
||||
/* Polling */
|
||||
QEMUBH *bh;
|
||||
struct ptimer_state *ptimer;
|
||||
|
||||
} eTSEC;
|
||||
|
||||
#define TYPE_ETSEC_COMMON "eTSEC"
|
||||
#define ETSEC_COMMON(obj) \
|
||||
OBJECT_CHECK(eTSEC, (obj), TYPE_ETSEC_COMMON)
|
||||
|
||||
#define eTSEC_TRANSMIT 1
|
||||
#define eTSEC_RECEIVE 2
|
||||
|
||||
DeviceState *etsec_create(hwaddr base,
|
||||
MemoryRegion *mr,
|
||||
NICInfo *nd,
|
||||
qemu_irq tx_irq,
|
||||
qemu_irq rx_irq,
|
||||
qemu_irq err_irq);
|
||||
|
||||
void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr);
|
||||
void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr);
|
||||
void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size);
|
||||
|
||||
void etsec_write_miim(eTSEC *etsec,
|
||||
eTSEC_Register *reg,
|
||||
uint32_t reg_index,
|
||||
uint32_t value);
|
||||
|
||||
void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc);
|
||||
|
||||
#endif /* ! _ETSEC_H_ */
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* QEMU Freescale eTSEC Emulator
|
||||
*
|
||||
* Copyright (c) 2011-2013 AdaCore
|
||||
*
|
||||
* 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 "etsec.h"
|
||||
#include "registers.h"
|
||||
|
||||
/* #define DEBUG_MIIM */
|
||||
|
||||
#define MIIM_CONTROL 0
|
||||
#define MIIM_STATUS 1
|
||||
#define MIIM_PHY_ID_1 2
|
||||
#define MIIM_PHY_ID_2 3
|
||||
#define MIIM_T2_STATUS 10
|
||||
#define MIIM_EXT_STATUS 15
|
||||
|
||||
static void miim_read_cycle(eTSEC *etsec)
|
||||
{
|
||||
uint8_t phy;
|
||||
uint8_t addr;
|
||||
uint16_t value;
|
||||
|
||||
phy = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
|
||||
(void)phy; /* Unreferenced */
|
||||
addr = etsec->regs[MIIMADD].value & 0x1F;
|
||||
|
||||
switch (addr) {
|
||||
case MIIM_CONTROL:
|
||||
value = etsec->phy_control;
|
||||
break;
|
||||
case MIIM_STATUS:
|
||||
value = etsec->phy_status;
|
||||
break;
|
||||
case MIIM_T2_STATUS:
|
||||
value = 0x1800; /* Local and remote receivers OK */
|
||||
break;
|
||||
default:
|
||||
value = 0x0;
|
||||
break;
|
||||
};
|
||||
|
||||
#ifdef DEBUG_MIIM
|
||||
qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
|
||||
#endif
|
||||
|
||||
etsec->regs[MIIMSTAT].value = value;
|
||||
}
|
||||
|
||||
static void miim_write_cycle(eTSEC *etsec)
|
||||
{
|
||||
uint8_t phy;
|
||||
uint8_t addr;
|
||||
uint16_t value;
|
||||
|
||||
phy = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
|
||||
(void)phy; /* Unreferenced */
|
||||
addr = etsec->regs[MIIMADD].value & 0x1F;
|
||||
value = etsec->regs[MIIMCON].value & 0xffff;
|
||||
|
||||
#ifdef DEBUG_MIIM
|
||||
qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
|
||||
#endif
|
||||
|
||||
switch (addr) {
|
||||
case MIIM_CONTROL:
|
||||
etsec->phy_control = value & ~(0x8100);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
void etsec_write_miim(eTSEC *etsec,
|
||||
eTSEC_Register *reg,
|
||||
uint32_t reg_index,
|
||||
uint32_t value)
|
||||
{
|
||||
|
||||
switch (reg_index) {
|
||||
|
||||
case MIIMCOM:
|
||||
/* Read and scan cycle */
|
||||
|
||||
if ((!(reg->value & MIIMCOM_READ)) && (value & MIIMCOM_READ)) {
|
||||
/* Read */
|
||||
miim_read_cycle(etsec);
|
||||
}
|
||||
reg->value = value;
|
||||
break;
|
||||
|
||||
case MIIMCON:
|
||||
reg->value = value & 0xffff;
|
||||
miim_write_cycle(etsec);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Default handling */
|
||||
switch (reg->access) {
|
||||
|
||||
case ACC_RW:
|
||||
case ACC_WO:
|
||||
reg->value = value;
|
||||
break;
|
||||
|
||||
case ACC_W1C:
|
||||
reg->value &= ~value;
|
||||
break;
|
||||
|
||||
case ACC_RO:
|
||||
default:
|
||||
/* Read Only or Unknown register */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc)
|
||||
{
|
||||
/* Set link status */
|
||||
if (nc->link_down) {
|
||||
etsec->phy_status &= ~MII_SR_LINK_STATUS;
|
||||
} else {
|
||||
etsec->phy_status |= MII_SR_LINK_STATUS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* QEMU Freescale eTSEC Emulator
|
||||
*
|
||||
* Copyright (c) 2011-2013 AdaCore
|
||||
*
|
||||
* 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 "registers.h"
|
||||
|
||||
const eTSEC_Register_Definition eTSEC_registers_def[] = {
|
||||
{0x000, "TSEC_ID", "Controller ID register", ACC_RO, 0x01240000},
|
||||
{0x004, "TSEC_ID2", "Controller ID register 2", ACC_RO, 0x003000F0},
|
||||
{0x010, "IEVENT", "Interrupt event register", ACC_W1C, 0x00000000},
|
||||
{0x014, "IMASK", "Interrupt mask register", ACC_RW, 0x00000000},
|
||||
{0x018, "EDIS", "Error disabled register", ACC_RW, 0x00000000},
|
||||
{0x020, "ECNTRL", "Ethernet control register", ACC_RW, 0x00000040},
|
||||
{0x028, "PTV", "Pause time value register", ACC_RW, 0x00000000},
|
||||
{0x02C, "DMACTRL", "DMA control register", ACC_RW, 0x00000000},
|
||||
{0x030, "TBIPA", "TBI PHY address register", ACC_RW, 0x00000000},
|
||||
|
||||
/* eTSEC FIFO Control and Status Registers */
|
||||
|
||||
{0x058, "FIFO_RX_ALARM", "FIFO receive alarm start threshold register", ACC_RW, 0x00000040},
|
||||
{0x05C, "FIFO_RX_ALARM_SHUTOFF", "FIFO receive alarm shut-off threshold register", ACC_RW, 0x00000080},
|
||||
{0x08C, "FIFO_TX_THR", "FIFO transmit threshold register", ACC_RW, 0x00000080},
|
||||
{0x098, "FIFO_TX_STARVE", "FIFO transmit starve register", ACC_RW, 0x00000040},
|
||||
{0x09C, "FIFO_TX_STARVE_SHUTOFF", "FIFO transmit starve shut-off register", ACC_RW, 0x00000080},
|
||||
|
||||
/* eTSEC Transmit Control and Status Registers */
|
||||
|
||||
{0x100, "TCTRL", "Transmit control register", ACC_RW, 0x00000000},
|
||||
{0x104, "TSTAT", "Transmit status register", ACC_W1C, 0x00000000},
|
||||
{0x108, "DFVLAN", "Default VLAN control word", ACC_RW, 0x81000000},
|
||||
{0x110, "TXIC", "Transmit interrupt coalescing register", ACC_RW, 0x00000000},
|
||||
{0x114, "TQUEUE", "Transmit queue control register", ACC_RW, 0x00008000},
|
||||
{0x140, "TR03WT", "TxBD Rings 0-3 round-robin weightings", ACC_RW, 0x00000000},
|
||||
{0x144, "TR47WT", "TxBD Rings 4-7 round-robin weightings", ACC_RW, 0x00000000},
|
||||
{0x180, "TBDBPH", "Tx data buffer pointer high bits", ACC_RW, 0x00000000},
|
||||
{0x184, "TBPTR0", "TxBD pointer for ring 0", ACC_RW, 0x00000000},
|
||||
{0x18C, "TBPTR1", "TxBD pointer for ring 1", ACC_RW, 0x00000000},
|
||||
{0x194, "TBPTR2", "TxBD pointer for ring 2", ACC_RW, 0x00000000},
|
||||
{0x19C, "TBPTR3", "TxBD pointer for ring 3", ACC_RW, 0x00000000},
|
||||
{0x1A4, "TBPTR4", "TxBD pointer for ring 4", ACC_RW, 0x00000000},
|
||||
{0x1AC, "TBPTR5", "TxBD pointer for ring 5", ACC_RW, 0x00000000},
|
||||
{0x1B4, "TBPTR6", "TxBD pointer for ring 6", ACC_RW, 0x00000000},
|
||||
{0x1BC, "TBPTR7", "TxBD pointer for ring 7", ACC_RW, 0x00000000},
|
||||
{0x200, "TBASEH", "TxBD base address high bits", ACC_RW, 0x00000000},
|
||||
{0x204, "TBASE0", "TxBD base address of ring 0", ACC_RW, 0x00000000},
|
||||
{0x20C, "TBASE1", "TxBD base address of ring 1", ACC_RW, 0x00000000},
|
||||
{0x214, "TBASE2", "TxBD base address of ring 2", ACC_RW, 0x00000000},
|
||||
{0x21C, "TBASE3", "TxBD base address of ring 3", ACC_RW, 0x00000000},
|
||||
{0x224, "TBASE4", "TxBD base address of ring 4", ACC_RW, 0x00000000},
|
||||
{0x22C, "TBASE5", "TxBD base address of ring 5", ACC_RW, 0x00000000},
|
||||
{0x234, "TBASE6", "TxBD base address of ring 6", ACC_RW, 0x00000000},
|
||||
{0x23C, "TBASE7", "TxBD base address of ring 7", ACC_RW, 0x00000000},
|
||||
{0x280, "TMR_TXTS1_ID", "Tx time stamp identification tag (set 1)", ACC_RO, 0x00000000},
|
||||
{0x284, "TMR_TXTS2_ID", "Tx time stamp identification tag (set 2)", ACC_RO, 0x00000000},
|
||||
{0x2C0, "TMR_TXTS1_H", "Tx time stamp high (set 1)", ACC_RO, 0x00000000},
|
||||
{0x2C4, "TMR_TXTS1_L", "Tx time stamp high (set 1)", ACC_RO, 0x00000000},
|
||||
{0x2C8, "TMR_TXTS2_H", "Tx time stamp high (set 2)", ACC_RO, 0x00000000},
|
||||
{0x2CC, "TMR_TXTS2_L", "Tx time stamp high (set 2)", ACC_RO, 0x00000000},
|
||||
|
||||
/* eTSEC Receive Control and Status Registers */
|
||||
|
||||
{0x300, "RCTRL", "Receive control register", ACC_RW, 0x00000000},
|
||||
{0x304, "RSTAT", "Receive status register", ACC_W1C, 0x00000000},
|
||||
{0x310, "RXIC", "Receive interrupt coalescing register", ACC_RW, 0x00000000},
|
||||
{0x314, "RQUEUE", "Receive queue control register.", ACC_RW, 0x00800080},
|
||||
{0x330, "RBIFX", "Receive bit field extract control register", ACC_RW, 0x00000000},
|
||||
{0x334, "RQFAR", "Receive queue filing table address register", ACC_RW, 0x00000000},
|
||||
{0x338, "RQFCR", "Receive queue filing table control register", ACC_RW, 0x00000000},
|
||||
{0x33C, "RQFPR", "Receive queue filing table property register", ACC_RW, 0x00000000},
|
||||
{0x340, "MRBLR", "Maximum receive buffer length register", ACC_RW, 0x00000000},
|
||||
{0x380, "RBDBPH", "Rx data buffer pointer high bits", ACC_RW, 0x00000000},
|
||||
{0x384, "RBPTR0", "RxBD pointer for ring 0", ACC_RW, 0x00000000},
|
||||
{0x38C, "RBPTR1", "RxBD pointer for ring 1", ACC_RW, 0x00000000},
|
||||
{0x394, "RBPTR2", "RxBD pointer for ring 2", ACC_RW, 0x00000000},
|
||||
{0x39C, "RBPTR3", "RxBD pointer for ring 3", ACC_RW, 0x00000000},
|
||||
{0x3A4, "RBPTR4", "RxBD pointer for ring 4", ACC_RW, 0x00000000},
|
||||
{0x3AC, "RBPTR5", "RxBD pointer for ring 5", ACC_RW, 0x00000000},
|
||||
{0x3B4, "RBPTR6", "RxBD pointer for ring 6", ACC_RW, 0x00000000},
|
||||
{0x3BC, "RBPTR7", "RxBD pointer for ring 7", ACC_RW, 0x00000000},
|
||||
{0x400, "RBASEH", "RxBD base address high bits", ACC_RW, 0x00000000},
|
||||
{0x404, "RBASE0", "RxBD base address of ring 0", ACC_RW, 0x00000000},
|
||||
{0x40C, "RBASE1", "RxBD base address of ring 1", ACC_RW, 0x00000000},
|
||||
{0x414, "RBASE2", "RxBD base address of ring 2", ACC_RW, 0x00000000},
|
||||
{0x41C, "RBASE3", "RxBD base address of ring 3", ACC_RW, 0x00000000},
|
||||
{0x424, "RBASE4", "RxBD base address of ring 4", ACC_RW, 0x00000000},
|
||||
{0x42C, "RBASE5", "RxBD base address of ring 5", ACC_RW, 0x00000000},
|
||||
{0x434, "RBASE6", "RxBD base address of ring 6", ACC_RW, 0x00000000},
|
||||
{0x43C, "RBASE7", "RxBD base address of ring 7", ACC_RW, 0x00000000},
|
||||
{0x4C0, "TMR_RXTS_H", "Rx timer time stamp register high", ACC_RW, 0x00000000},
|
||||
{0x4C4, "TMR_RXTS_L", "Rx timer time stamp register low", ACC_RW, 0x00000000},
|
||||
|
||||
/* eTSEC MAC Registers */
|
||||
|
||||
{0x500, "MACCFG1", "MAC configuration register 1", ACC_RW, 0x00000000},
|
||||
{0x504, "MACCFG2", "MAC configuration register 2", ACC_RW, 0x00007000},
|
||||
{0x508, "IPGIFG", "Inter-packet/inter-frame gap register", ACC_RW, 0x40605060},
|
||||
{0x50C, "HAFDUP", "Half-duplex control", ACC_RW, 0x00A1F037},
|
||||
{0x510, "MAXFRM", "Maximum frame length", ACC_RW, 0x00000600},
|
||||
{0x520, "MIIMCFG", "MII management configuration", ACC_RW, 0x00000007},
|
||||
{0x524, "MIIMCOM", "MII management command", ACC_RW, 0x00000000},
|
||||
{0x528, "MIIMADD", "MII management address", ACC_RW, 0x00000000},
|
||||
{0x52C, "MIIMCON", "MII management control", ACC_WO, 0x00000000},
|
||||
{0x530, "MIIMSTAT", "MII management status", ACC_RO, 0x00000000},
|
||||
{0x534, "MIIMIND", "MII management indicator", ACC_RO, 0x00000000},
|
||||
{0x53C, "IFSTAT", "Interface status", ACC_RO, 0x00000000},
|
||||
{0x540, "MACSTNADDR1", "MAC station address register 1", ACC_RW, 0x00000000},
|
||||
{0x544, "MACSTNADDR2", "MAC station address register 2", ACC_RW, 0x00000000},
|
||||
{0x548, "MAC01ADDR1", "MAC exact match address 1, part 1", ACC_RW, 0x00000000},
|
||||
{0x54C, "MAC01ADDR2", "MAC exact match address 1, part 2", ACC_RW, 0x00000000},
|
||||
{0x550, "MAC02ADDR1", "MAC exact match address 2, part 1", ACC_RW, 0x00000000},
|
||||
{0x554, "MAC02ADDR2", "MAC exact match address 2, part 2", ACC_RW, 0x00000000},
|
||||
{0x558, "MAC03ADDR1", "MAC exact match address 3, part 1", ACC_RW, 0x00000000},
|
||||
{0x55C, "MAC03ADDR2", "MAC exact match address 3, part 2", ACC_RW, 0x00000000},
|
||||
{0x560, "MAC04ADDR1", "MAC exact match address 4, part 1", ACC_RW, 0x00000000},
|
||||
{0x564, "MAC04ADDR2", "MAC exact match address 4, part 2", ACC_RW, 0x00000000},
|
||||
{0x568, "MAC05ADDR1", "MAC exact match address 5, part 1", ACC_RW, 0x00000000},
|
||||
{0x56C, "MAC05ADDR2", "MAC exact match address 5, part 2", ACC_RW, 0x00000000},
|
||||
{0x570, "MAC06ADDR1", "MAC exact match address 6, part 1", ACC_RW, 0x00000000},
|
||||
{0x574, "MAC06ADDR2", "MAC exact match address 6, part 2", ACC_RW, 0x00000000},
|
||||
{0x578, "MAC07ADDR1", "MAC exact match address 7, part 1", ACC_RW, 0x00000000},
|
||||
{0x57C, "MAC07ADDR2", "MAC exact match address 7, part 2", ACC_RW, 0x00000000},
|
||||
{0x580, "MAC08ADDR1", "MAC exact match address 8, part 1", ACC_RW, 0x00000000},
|
||||
{0x584, "MAC08ADDR2", "MAC exact match address 8, part 2", ACC_RW, 0x00000000},
|
||||
{0x588, "MAC09ADDR1", "MAC exact match address 9, part 1", ACC_RW, 0x00000000},
|
||||
{0x58C, "MAC09ADDR2", "MAC exact match address 9, part 2", ACC_RW, 0x00000000},
|
||||
{0x590, "MAC10ADDR1", "MAC exact match address 10, part 1", ACC_RW, 0x00000000},
|
||||
{0x594, "MAC10ADDR2", "MAC exact match address 10, part 2", ACC_RW, 0x00000000},
|
||||
{0x598, "MAC11ADDR1", "MAC exact match address 11, part 1", ACC_RW, 0x00000000},
|
||||
{0x59C, "MAC11ADDR2", "MAC exact match address 11, part 2", ACC_RW, 0x00000000},
|
||||
{0x5A0, "MAC12ADDR1", "MAC exact match address 12, part 1", ACC_RW, 0x00000000},
|
||||
{0x5A4, "MAC12ADDR2", "MAC exact match address 12, part 2", ACC_RW, 0x00000000},
|
||||
{0x5A8, "MAC13ADDR1", "MAC exact match address 13, part 1", ACC_RW, 0x00000000},
|
||||
{0x5AC, "MAC13ADDR2", "MAC exact match address 13, part 2", ACC_RW, 0x00000000},
|
||||
{0x5B0, "MAC14ADDR1", "MAC exact match address 14, part 1", ACC_RW, 0x00000000},
|
||||
{0x5B4, "MAC14ADDR2", "MAC exact match address 14, part 2", ACC_RW, 0x00000000},
|
||||
{0x5B8, "MAC15ADDR1", "MAC exact match address 15, part 1", ACC_RW, 0x00000000},
|
||||
{0x5BC, "MAC15ADDR2", "MAC exact match address 15, part 2", ACC_RW, 0x00000000},
|
||||
|
||||
/* eTSEC, "Transmit", "and", Receive, Counters */
|
||||
|
||||
{0x680, "TR64", "Transmit and receive 64-byte frame counter ", ACC_RW, 0x00000000},
|
||||
{0x684, "TR127", "Transmit and receive 65- to 127-byte frame counter", ACC_RW, 0x00000000},
|
||||
{0x688, "TR255", "Transmit and receive 128- to 255-byte frame counter", ACC_RW, 0x00000000},
|
||||
{0x68C, "TR511", "Transmit and receive 256- to 511-byte frame counter", ACC_RW, 0x00000000},
|
||||
{0x690, "TR1K", "Transmit and receive 512- to 1023-byte frame counter", ACC_RW, 0x00000000},
|
||||
{0x694, "TRMAX", "Transmit and receive 1024- to 1518-byte frame counter", ACC_RW, 0x00000000},
|
||||
{0x698, "TRMGV", "Transmit and receive 1519- to 1522-byte good VLAN frame count", ACC_RW, 0x00000000},
|
||||
|
||||
/* eTSEC Receive Counters */
|
||||
|
||||
{0x69C, "RBYT", "Receive byte counter", ACC_RW, 0x00000000},
|
||||
{0x6A0, "RPKT", "Receive packet counter", ACC_RW, 0x00000000},
|
||||
{0x6A4, "RFCS", "Receive FCS error counter", ACC_RW, 0x00000000},
|
||||
{0x6A8, "RMCA", "Receive multicast packet counter", ACC_RW, 0x00000000},
|
||||
{0x6AC, "RBCA", "Receive broadcast packet counter", ACC_RW, 0x00000000},
|
||||
{0x6B0, "RXCF", "Receive control frame packet counter ", ACC_RW, 0x00000000},
|
||||
{0x6B4, "RXPF", "Receive PAUSE frame packet counter", ACC_RW, 0x00000000},
|
||||
{0x6B8, "RXUO", "Receive unknown OP code counter ", ACC_RW, 0x00000000},
|
||||
{0x6BC, "RALN", "Receive alignment error counter ", ACC_RW, 0x00000000},
|
||||
{0x6C0, "RFLR", "Receive frame length error counter ", ACC_RW, 0x00000000},
|
||||
{0x6C4, "RCDE", "Receive code error counter ", ACC_RW, 0x00000000},
|
||||
{0x6C8, "RCSE", "Receive carrier sense error counter", ACC_RW, 0x00000000},
|
||||
{0x6CC, "RUND", "Receive undersize packet counter", ACC_RW, 0x00000000},
|
||||
{0x6D0, "ROVR", "Receive oversize packet counter ", ACC_RW, 0x00000000},
|
||||
{0x6D4, "RFRG", "Receive fragments counter", ACC_RW, 0x00000000},
|
||||
{0x6D8, "RJBR", "Receive jabber counter ", ACC_RW, 0x00000000},
|
||||
{0x6DC, "RDRP", "Receive drop counter", ACC_RW, 0x00000000},
|
||||
|
||||
/* eTSEC Transmit Counters */
|
||||
|
||||
{0x6E0, "TBYT", "Transmit byte counter", ACC_RW, 0x00000000},
|
||||
{0x6E4, "TPKT", "Transmit packet counter", ACC_RW, 0x00000000},
|
||||
{0x6E8, "TMCA", "Transmit multicast packet counter ", ACC_RW, 0x00000000},
|
||||
{0x6EC, "TBCA", "Transmit broadcast packet counter ", ACC_RW, 0x00000000},
|
||||
{0x6F0, "TXPF", "Transmit PAUSE control frame counter ", ACC_RW, 0x00000000},
|
||||
{0x6F4, "TDFR", "Transmit deferral packet counter ", ACC_RW, 0x00000000},
|
||||
{0x6F8, "TEDF", "Transmit excessive deferral packet counter ", ACC_RW, 0x00000000},
|
||||
{0x6FC, "TSCL", "Transmit single collision packet counter", ACC_RW, 0x00000000},
|
||||
{0x700, "TMCL", "Transmit multiple collision packet counter", ACC_RW, 0x00000000},
|
||||
{0x704, "TLCL", "Transmit late collision packet counter", ACC_RW, 0x00000000},
|
||||
{0x708, "TXCL", "Transmit excessive collision packet counter", ACC_RW, 0x00000000},
|
||||
{0x70C, "TNCL", "Transmit total collision counter ", ACC_RW, 0x00000000},
|
||||
{0x714, "TDRP", "Transmit drop frame counter", ACC_RW, 0x00000000},
|
||||
{0x718, "TJBR", "Transmit jabber frame counter ", ACC_RW, 0x00000000},
|
||||
{0x71C, "TFCS", "Transmit FCS error counter", ACC_RW, 0x00000000},
|
||||
{0x720, "TXCF", "Transmit control frame counter ", ACC_RW, 0x00000000},
|
||||
{0x724, "TOVR", "Transmit oversize frame counter", ACC_RW, 0x00000000},
|
||||
{0x728, "TUND", "Transmit undersize frame counter ", ACC_RW, 0x00000000},
|
||||
{0x72C, "TFRG", "Transmit fragments frame counter ", ACC_RW, 0x00000000},
|
||||
|
||||
/* eTSEC Counter Control and TOE Statistics Registers */
|
||||
|
||||
{0x730, "CAR1", "Carry register one register", ACC_W1C, 0x00000000},
|
||||
{0x734, "CAR2", "Carry register two register ", ACC_W1C, 0x00000000},
|
||||
{0x738, "CAM1", "Carry register one mask register ", ACC_RW, 0xFE03FFFF},
|
||||
{0x73C, "CAM2", "Carry register two mask register ", ACC_RW, 0x000FFFFD},
|
||||
{0x740, "RREJ", "Receive filer rejected packet counter", ACC_RW, 0x00000000},
|
||||
|
||||
/* Hash Function Registers */
|
||||
|
||||
{0x800, "IGADDR0", "Individual/group address register 0", ACC_RW, 0x00000000},
|
||||
{0x804, "IGADDR1", "Individual/group address register 1", ACC_RW, 0x00000000},
|
||||
{0x808, "IGADDR2", "Individual/group address register 2", ACC_RW, 0x00000000},
|
||||
{0x80C, "IGADDR3", "Individual/group address register 3", ACC_RW, 0x00000000},
|
||||
{0x810, "IGADDR4", "Individual/group address register 4", ACC_RW, 0x00000000},
|
||||
{0x814, "IGADDR5", "Individual/group address register 5", ACC_RW, 0x00000000},
|
||||
{0x818, "IGADDR6", "Individual/group address register 6", ACC_RW, 0x00000000},
|
||||
{0x81C, "IGADDR7", "Individual/group address register 7", ACC_RW, 0x00000000},
|
||||
{0x880, "GADDR0", "Group address register 0", ACC_RW, 0x00000000},
|
||||
{0x884, "GADDR1", "Group address register 1", ACC_RW, 0x00000000},
|
||||
{0x888, "GADDR2", "Group address register 2", ACC_RW, 0x00000000},
|
||||
{0x88C, "GADDR3", "Group address register 3", ACC_RW, 0x00000000},
|
||||
{0x890, "GADDR4", "Group address register 4", ACC_RW, 0x00000000},
|
||||
{0x894, "GADDR5", "Group address register 5", ACC_RW, 0x00000000},
|
||||
{0x898, "GADDR6", "Group address register 6", ACC_RW, 0x00000000},
|
||||
{0x89C, "GADDR7", "Group address register 7", ACC_RW, 0x00000000},
|
||||
|
||||
/* eTSEC DMA Attribute Registers */
|
||||
|
||||
{0xBF8, "ATTR", "Attribute register", ACC_RW, 0x00000000},
|
||||
{0xBFC, "ATTRELI", "Attribute extract length and extract index register", ACC_RW, 0x00000000},
|
||||
|
||||
|
||||
/* eTSEC Lossless Flow Control Registers */
|
||||
|
||||
{0xC00, "RQPRM0", "Receive Queue Parameters register 0 ", ACC_RW, 0x00000000},
|
||||
{0xC04, "RQPRM1", "Receive Queue Parameters register 1 ", ACC_RW, 0x00000000},
|
||||
{0xC08, "RQPRM2", "Receive Queue Parameters register 2 ", ACC_RW, 0x00000000},
|
||||
{0xC0C, "RQPRM3", "Receive Queue Parameters register 3 ", ACC_RW, 0x00000000},
|
||||
{0xC10, "RQPRM4", "Receive Queue Parameters register 4 ", ACC_RW, 0x00000000},
|
||||
{0xC14, "RQPRM5", "Receive Queue Parameters register 5 ", ACC_RW, 0x00000000},
|
||||
{0xC18, "RQPRM6", "Receive Queue Parameters register 6 ", ACC_RW, 0x00000000},
|
||||
{0xC1C, "RQPRM7", "Receive Queue Parameters register 7 ", ACC_RW, 0x00000000},
|
||||
{0xC44, "RFBPTR0", "Last Free RxBD pointer for ring 0", ACC_RW, 0x00000000},
|
||||
{0xC4C, "RFBPTR1", "Last Free RxBD pointer for ring 1", ACC_RW, 0x00000000},
|
||||
{0xC54, "RFBPTR2", "Last Free RxBD pointer for ring 2", ACC_RW, 0x00000000},
|
||||
{0xC5C, "RFBPTR3", "Last Free RxBD pointer for ring 3", ACC_RW, 0x00000000},
|
||||
{0xC64, "RFBPTR4", "Last Free RxBD pointer for ring 4", ACC_RW, 0x00000000},
|
||||
{0xC6C, "RFBPTR5", "Last Free RxBD pointer for ring 5", ACC_RW, 0x00000000},
|
||||
{0xC74, "RFBPTR6", "Last Free RxBD pointer for ring 6", ACC_RW, 0x00000000},
|
||||
{0xC7C, "RFBPTR7", "Last Free RxBD pointer for ring 7", ACC_RW, 0x00000000},
|
||||
|
||||
/* eTSEC Future Expansion Space */
|
||||
|
||||
/* Reserved*/
|
||||
|
||||
/* eTSEC IEEE 1588 Registers */
|
||||
|
||||
{0xE00, "TMR_CTRL", "Timer control register", ACC_RW, 0x00010001},
|
||||
{0xE04, "TMR_TEVENT", "time stamp event register", ACC_W1C, 0x00000000},
|
||||
{0xE08, "TMR_TEMASK", "Timer event mask register", ACC_RW, 0x00000000},
|
||||
{0xE0C, "TMR_PEVENT", "time stamp event register", ACC_RW, 0x00000000},
|
||||
{0xE10, "TMR_PEMASK", "Timer event mask register", ACC_RW, 0x00000000},
|
||||
{0xE14, "TMR_STAT", "time stamp status register", ACC_RW, 0x00000000},
|
||||
{0xE18, "TMR_CNT_H", "timer counter high register", ACC_RW, 0x00000000},
|
||||
{0xE1C, "TMR_CNT_L", "timer counter low register", ACC_RW, 0x00000000},
|
||||
{0xE20, "TMR_ADD", "Timer drift compensation addend register", ACC_RW, 0x00000000},
|
||||
{0xE24, "TMR_ACC", "Timer accumulator register", ACC_RW, 0x00000000},
|
||||
{0xE28, "TMR_PRSC", "Timer prescale", ACC_RW, 0x00000002},
|
||||
{0xE30, "TMROFF_H", "Timer offset high", ACC_RW, 0x00000000},
|
||||
{0xE34, "TMROFF_L", "Timer offset low", ACC_RW, 0x00000000},
|
||||
{0xE40, "TMR_ALARM1_H", "Timer alarm 1 high register", ACC_RW, 0xFFFFFFFF},
|
||||
{0xE44, "TMR_ALARM1_L", "Timer alarm 1 high register", ACC_RW, 0xFFFFFFFF},
|
||||
{0xE48, "TMR_ALARM2_H", "Timer alarm 2 high register", ACC_RW, 0xFFFFFFFF},
|
||||
{0xE4C, "TMR_ALARM2_L", "Timer alarm 2 high register", ACC_RW, 0xFFFFFFFF},
|
||||
{0xE80, "TMR_FIPER1", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
|
||||
{0xE84, "TMR_FIPER2", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
|
||||
{0xE88, "TMR_FIPER3", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
|
||||
{0xEA0, "TMR_ETTS1_H", "Time stamp of general purpose external trigger ", ACC_RW, 0x00000000},
|
||||
{0xEA4, "TMR_ETTS1_L", "Time stamp of general purpose external trigger", ACC_RW, 0x00000000},
|
||||
{0xEA8, "TMR_ETTS2_H", "Time stamp of general purpose external trigger ", ACC_RW, 0x00000000},
|
||||
{0xEAC, "TMR_ETTS2_L", "Time stamp of general purpose external trigger", ACC_RW, 0x00000000},
|
||||
|
||||
/* End Of Table */
|
||||
{0x0, 0x0, 0x0, 0x0, 0x0}
|
||||
};
|
||||
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* QEMU Freescale eTSEC Emulator
|
||||
*
|
||||
* Copyright (c) 2011-2013 AdaCore
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _ETSEC_REGISTERS_H_
|
||||
#define _ETSEC_REGISTERS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum eTSEC_Register_Access_Type {
|
||||
ACC_RW = 1, /* Read/Write */
|
||||
ACC_RO = 2, /* Read Only */
|
||||
ACC_WO = 3, /* Write Only */
|
||||
ACC_W1C = 4, /* Write 1 to clear */
|
||||
ACC_UNKNOWN = 5 /* Unknown register*/
|
||||
};
|
||||
|
||||
typedef struct eTSEC_Register_Definition {
|
||||
uint32_t offset;
|
||||
const char *name;
|
||||
const char *desc;
|
||||
enum eTSEC_Register_Access_Type access;
|
||||
uint32_t reset;
|
||||
} eTSEC_Register_Definition;
|
||||
|
||||
extern const eTSEC_Register_Definition eTSEC_registers_def[];
|
||||
|
||||
#define DMACTRL_LE (1 << 15)
|
||||
#define DMACTRL_GRS (1 << 4)
|
||||
#define DMACTRL_GTS (1 << 3)
|
||||
#define DMACTRL_WOP (1 << 0)
|
||||
|
||||
#define IEVENT_PERR (1 << 0)
|
||||
#define IEVENT_DPE (1 << 1)
|
||||
#define IEVENT_FIQ (1 << 2)
|
||||
#define IEVENT_FIR (1 << 3)
|
||||
#define IEVENT_FGPI (1 << 4)
|
||||
#define IEVENT_RXF (1 << 7)
|
||||
#define IEVENT_GRSC (1 << 8)
|
||||
#define IEVENT_MMRW (1 << 9)
|
||||
#define IEVENT_MMRD (1 << 10)
|
||||
#define IEVENT_MAG (1 << 11)
|
||||
#define IEVENT_RXB (1 << 15)
|
||||
#define IEVENT_XFUN (1 << 16)
|
||||
#define IEVENT_CRL (1 << 17)
|
||||
#define IEVENT_LC (1 << 18)
|
||||
#define IEVENT_TXF (1 << 20)
|
||||
#define IEVENT_TXB (1 << 21)
|
||||
#define IEVENT_TXE (1 << 22)
|
||||
#define IEVENT_TXC (1 << 23)
|
||||
#define IEVENT_BABT (1 << 24)
|
||||
#define IEVENT_GTSC (1 << 25)
|
||||
#define IEVENT_MSRO (1 << 26)
|
||||
#define IEVENT_EBERR (1 << 28)
|
||||
#define IEVENT_BSY (1 << 29)
|
||||
#define IEVENT_RXC (1 << 30)
|
||||
#define IEVENT_BABR (1 << 31)
|
||||
|
||||
#define IMASK_RXFEN (1 << 7)
|
||||
#define IMASK_GRSCEN (1 << 8)
|
||||
#define IMASK_RXBEN (1 << 15)
|
||||
#define IMASK_TXFEN (1 << 20)
|
||||
#define IMASK_TXBEN (1 << 21)
|
||||
#define IMASK_GTSCEN (1 << 25)
|
||||
|
||||
#define MACCFG1_TX_EN (1 << 0)
|
||||
#define MACCFG1_RX_EN (1 << 2)
|
||||
|
||||
#define MACCFG2_CRC_EN (1 << 1)
|
||||
#define MACCFG2_PADCRC (1 << 2)
|
||||
|
||||
#define MIIMCOM_READ (1 << 0)
|
||||
#define MIIMCOM_SCAN (1 << 1)
|
||||
|
||||
#define RCTRL_PRSDEP_MASK (0x3)
|
||||
#define RCTRL_PRSDEP_OFFSET (6)
|
||||
#define RCTRL_RSF (1 << 2)
|
||||
|
||||
/* Index of each register */
|
||||
|
||||
#define TSEC_ID (0x000 / 4)
|
||||
#define TSEC_ID2 (0x004 / 4)
|
||||
#define IEVENT (0x010 / 4)
|
||||
#define IMASK (0x014 / 4)
|
||||
#define EDIS (0x018 / 4)
|
||||
#define ECNTRL (0x020 / 4)
|
||||
#define PTV (0x028 / 4)
|
||||
#define DMACTRL (0x02C / 4)
|
||||
#define TBIPA (0x030 / 4)
|
||||
#define TCTRL (0x100 / 4)
|
||||
#define TSTAT (0x104 / 4)
|
||||
#define DFVLAN (0x108 / 4)
|
||||
#define TXIC (0x110 / 4)
|
||||
#define TQUEUE (0x114 / 4)
|
||||
#define TR03WT (0x140 / 4)
|
||||
#define TR47WT (0x144 / 4)
|
||||
#define TBDBPH (0x180 / 4)
|
||||
#define TBPTR0 (0x184 / 4)
|
||||
#define TBPTR1 (0x18C / 4)
|
||||
#define TBPTR2 (0x194 / 4)
|
||||
#define TBPTR3 (0x19C / 4)
|
||||
#define TBPTR4 (0x1A4 / 4)
|
||||
#define TBPTR5 (0x1AC / 4)
|
||||
#define TBPTR6 (0x1B4 / 4)
|
||||
#define TBPTR7 (0x1BC / 4)
|
||||
#define TBASEH (0x200 / 4)
|
||||
#define TBASE0 (0x204 / 4)
|
||||
#define TBASE1 (0x20C / 4)
|
||||
#define TBASE2 (0x214 / 4)
|
||||
#define TBASE3 (0x21C / 4)
|
||||
#define TBASE4 (0x224 / 4)
|
||||
#define TBASE5 (0x22C / 4)
|
||||
#define TBASE6 (0x234 / 4)
|
||||
#define TBASE7 (0x23C / 4)
|
||||
#define TMR_TXTS1_ID (0x280 / 4)
|
||||
#define TMR_TXTS2_ID (0x284 / 4)
|
||||
#define TMR_TXTS1_H (0x2C0 / 4)
|
||||
#define TMR_TXTS1_L (0x2C4 / 4)
|
||||
#define TMR_TXTS2_H (0x2C8 / 4)
|
||||
#define TMR_TXTS2_L (0x2CC / 4)
|
||||
#define RCTRL (0x300 / 4)
|
||||
#define RSTAT (0x304 / 4)
|
||||
#define RXIC (0x310 / 4)
|
||||
#define RQUEUE (0x314 / 4)
|
||||
#define RBIFX (0x330 / 4)
|
||||
#define RQFAR (0x334 / 4)
|
||||
#define RQFCR (0x338 / 4)
|
||||
#define RQFPR (0x33C / 4)
|
||||
#define MRBLR (0x340 / 4)
|
||||
#define RBDBPH (0x380 / 4)
|
||||
#define RBPTR0 (0x384 / 4)
|
||||
#define RBPTR1 (0x38C / 4)
|
||||
#define RBPTR2 (0x394 / 4)
|
||||
#define RBPTR3 (0x39C / 4)
|
||||
#define RBPTR4 (0x3A4 / 4)
|
||||
#define RBPTR5 (0x3AC / 4)
|
||||
#define RBPTR6 (0x3B4 / 4)
|
||||
#define RBPTR7 (0x3BC / 4)
|
||||
#define RBASEH (0x400 / 4)
|
||||
#define RBASE0 (0x404 / 4)
|
||||
#define RBASE1 (0x40C / 4)
|
||||
#define RBASE2 (0x414 / 4)
|
||||
#define RBASE3 (0x41C / 4)
|
||||
#define RBASE4 (0x424 / 4)
|
||||
#define RBASE5 (0x42C / 4)
|
||||
#define RBASE6 (0x434 / 4)
|
||||
#define RBASE7 (0x43C / 4)
|
||||
#define TMR_RXTS_H (0x4C0 / 4)
|
||||
#define TMR_RXTS_L (0x4C4 / 4)
|
||||
#define MACCFG1 (0x500 / 4)
|
||||
#define MACCFG2 (0x504 / 4)
|
||||
#define IPGIFG (0x508 / 4)
|
||||
#define HAFDUP (0x50C / 4)
|
||||
#define MAXFRM (0x510 / 4)
|
||||
#define MIIMCFG (0x520 / 4)
|
||||
#define MIIMCOM (0x524 / 4)
|
||||
#define MIIMADD (0x528 / 4)
|
||||
#define MIIMCON (0x52C / 4)
|
||||
#define MIIMSTAT (0x530 / 4)
|
||||
#define MIIMIND (0x534 / 4)
|
||||
#define IFSTAT (0x53C / 4)
|
||||
#define MACSTNADDR1 (0x540 / 4)
|
||||
#define MACSTNADDR2 (0x544 / 4)
|
||||
#define MAC01ADDR1 (0x548 / 4)
|
||||
#define MAC01ADDR2 (0x54C / 4)
|
||||
#define MAC02ADDR1 (0x550 / 4)
|
||||
#define MAC02ADDR2 (0x554 / 4)
|
||||
#define MAC03ADDR1 (0x558 / 4)
|
||||
#define MAC03ADDR2 (0x55C / 4)
|
||||
#define MAC04ADDR1 (0x560 / 4)
|
||||
#define MAC04ADDR2 (0x564 / 4)
|
||||
#define MAC05ADDR1 (0x568 / 4)
|
||||
#define MAC05ADDR2 (0x56C / 4)
|
||||
#define MAC06ADDR1 (0x570 / 4)
|
||||
#define MAC06ADDR2 (0x574 / 4)
|
||||
#define MAC07ADDR1 (0x578 / 4)
|
||||
#define MAC07ADDR2 (0x57C / 4)
|
||||
#define MAC08ADDR1 (0x580 / 4)
|
||||
#define MAC08ADDR2 (0x584 / 4)
|
||||
#define MAC09ADDR1 (0x588 / 4)
|
||||
#define MAC09ADDR2 (0x58C / 4)
|
||||
#define MAC10ADDR1 (0x590 / 4)
|
||||
#define MAC10ADDR2 (0x594 / 4)
|
||||
#define MAC11ADDR1 (0x598 / 4)
|
||||
#define MAC11ADDR2 (0x59C / 4)
|
||||
#define MAC12ADDR1 (0x5A0 / 4)
|
||||
#define MAC12ADDR2 (0x5A4 / 4)
|
||||
#define MAC13ADDR1 (0x5A8 / 4)
|
||||
#define MAC13ADDR2 (0x5AC / 4)
|
||||
#define MAC14ADDR1 (0x5B0 / 4)
|
||||
#define MAC14ADDR2 (0x5B4 / 4)
|
||||
#define MAC15ADDR1 (0x5B8 / 4)
|
||||
#define MAC15ADDR2 (0x5BC / 4)
|
||||
#define TR64 (0x680 / 4)
|
||||
#define TR127 (0x684 / 4)
|
||||
#define TR255 (0x688 / 4)
|
||||
#define TR511 (0x68C / 4)
|
||||
#define TR1K (0x690 / 4)
|
||||
#define TRMAX (0x694 / 4)
|
||||
#define TRMGV (0x698 / 4)
|
||||
#define RBYT (0x69C / 4)
|
||||
#define RPKT (0x6A0 / 4)
|
||||
#define RFCS (0x6A4 / 4)
|
||||
#define RMCA (0x6A8 / 4)
|
||||
#define RBCA (0x6AC / 4)
|
||||
#define RXCF (0x6B0 / 4)
|
||||
#define RXPF (0x6B4 / 4)
|
||||
#define RXUO (0x6B8 / 4)
|
||||
#define RALN (0x6BC / 4)
|
||||
#define RFLR (0x6C0 / 4)
|
||||
#define RCDE (0x6C4 / 4)
|
||||
#define RCSE (0x6C8 / 4)
|
||||
#define RUND (0x6CC / 4)
|
||||
#define ROVR (0x6D0 / 4)
|
||||
#define RFRG (0x6D4 / 4)
|
||||
#define RJBR (0x6D8 / 4)
|
||||
#define RDRP (0x6DC / 4)
|
||||
#define TBYT (0x6E0 / 4)
|
||||
#define TPKT (0x6E4 / 4)
|
||||
#define TMCA (0x6E8 / 4)
|
||||
#define TBCA (0x6EC / 4)
|
||||
#define TXPF (0x6F0 / 4)
|
||||
#define TDFR (0x6F4 / 4)
|
||||
#define TEDF (0x6F8 / 4)
|
||||
#define TSCL (0x6FC / 4)
|
||||
#define TMCL (0x700 / 4)
|
||||
#define TLCL (0x704 / 4)
|
||||
#define TXCL (0x708 / 4)
|
||||
#define TNCL (0x70C / 4)
|
||||
#define TDRP (0x714 / 4)
|
||||
#define TJBR (0x718 / 4)
|
||||
#define TFCS (0x71C / 4)
|
||||
#define TXCF (0x720 / 4)
|
||||
#define TOVR (0x724 / 4)
|
||||
#define TUND (0x728 / 4)
|
||||
#define TFRG (0x72C / 4)
|
||||
#define CAR1 (0x730 / 4)
|
||||
#define CAR2 (0x734 / 4)
|
||||
#define CAM1 (0x738 / 4)
|
||||
#define CAM2 (0x73C / 4)
|
||||
#define RREJ (0x740 / 4)
|
||||
#define IGADDR0 (0x800 / 4)
|
||||
#define IGADDR1 (0x804 / 4)
|
||||
#define IGADDR2 (0x808 / 4)
|
||||
#define IGADDR3 (0x80C / 4)
|
||||
#define IGADDR4 (0x810 / 4)
|
||||
#define IGADDR5 (0x814 / 4)
|
||||
#define IGADDR6 (0x818 / 4)
|
||||
#define IGADDR7 (0x81C / 4)
|
||||
#define GADDR0 (0x880 / 4)
|
||||
#define GADDR1 (0x884 / 4)
|
||||
#define GADDR2 (0x888 / 4)
|
||||
#define GADDR3 (0x88C / 4)
|
||||
#define GADDR4 (0x890 / 4)
|
||||
#define GADDR5 (0x894 / 4)
|
||||
#define GADDR6 (0x898 / 4)
|
||||
#define GADDR7 (0x89C / 4)
|
||||
#define ATTR (0xBF8 / 4)
|
||||
#define ATTRELI (0xBFC / 4)
|
||||
#define RQPRM0 (0xC00 / 4)
|
||||
#define RQPRM1 (0xC04 / 4)
|
||||
#define RQPRM2 (0xC08 / 4)
|
||||
#define RQPRM3 (0xC0C / 4)
|
||||
#define RQPRM4 (0xC10 / 4)
|
||||
#define RQPRM5 (0xC14 / 4)
|
||||
#define RQPRM6 (0xC18 / 4)
|
||||
#define RQPRM7 (0xC1C / 4)
|
||||
#define RFBPTR0 (0xC44 / 4)
|
||||
#define RFBPTR1 (0xC4C / 4)
|
||||
#define RFBPTR2 (0xC54 / 4)
|
||||
#define RFBPTR3 (0xC5C / 4)
|
||||
#define RFBPTR4 (0xC64 / 4)
|
||||
#define RFBPTR5 (0xC6C / 4)
|
||||
#define RFBPTR6 (0xC74 / 4)
|
||||
#define RFBPTR7 (0xC7C / 4)
|
||||
#define TMR_CTRL (0xE00 / 4)
|
||||
#define TMR_TEVENT (0xE04 / 4)
|
||||
#define TMR_TEMASK (0xE08 / 4)
|
||||
#define TMR_PEVENT (0xE0C / 4)
|
||||
#define TMR_PEMASK (0xE10 / 4)
|
||||
#define TMR_STAT (0xE14 / 4)
|
||||
#define TMR_CNT_H (0xE18 / 4)
|
||||
#define TMR_CNT_L (0xE1C / 4)
|
||||
#define TMR_ADD (0xE20 / 4)
|
||||
#define TMR_ACC (0xE24 / 4)
|
||||
#define TMR_PRSC (0xE28 / 4)
|
||||
#define TMROFF_H (0xE30 / 4)
|
||||
#define TMROFF_L (0xE34 / 4)
|
||||
#define TMR_ALARM1_H (0xE40 / 4)
|
||||
#define TMR_ALARM1_L (0xE44 / 4)
|
||||
#define TMR_ALARM2_H (0xE48 / 4)
|
||||
#define TMR_ALARM2_L (0xE4C / 4)
|
||||
#define TMR_FIPER1 (0xE80 / 4)
|
||||
#define TMR_FIPER2 (0xE84 / 4)
|
||||
#define TMR_FIPER3 (0xE88 / 4)
|
||||
#define TMR_ETTS1_H (0xEA0 / 4)
|
||||
#define TMR_ETTS1_L (0xEA4 / 4)
|
||||
#define TMR_ETTS2_H (0xEA8 / 4)
|
||||
#define TMR_ETTS2_L (0xEAC / 4)
|
||||
|
||||
#endif /* ! _ETSEC_REGISTERS_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -405,6 +405,8 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
|
||||
|
||||
dev->rx_bufs++;
|
||||
|
||||
qemu_flush_queued_packets(qemu_get_queue(dev->nic));
|
||||
|
||||
DPRINTF("h_add_logical_lan_buffer(): Added buf ptr=%d rx_bufs=%d"
|
||||
" bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
|
||||
(unsigned long long)buf);
|
||||
|
||||
+5
-2
@@ -238,6 +238,7 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
|
||||
the first node as boot node and be happy */
|
||||
for (i = smp_cpus - 1; i >= 0; i--) {
|
||||
CPUState *cpu;
|
||||
PowerPCCPU *pcpu;
|
||||
char cpu_name[128];
|
||||
uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);
|
||||
|
||||
@@ -246,14 +247,16 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
|
||||
continue;
|
||||
}
|
||||
env = cpu->env_ptr;
|
||||
pcpu = POWERPC_CPU(cpu);
|
||||
|
||||
snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x",
|
||||
cpu->cpu_index);
|
||||
ppc_get_vcpu_dt_id(pcpu));
|
||||
qemu_fdt_add_subnode(fdt, cpu_name);
|
||||
qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
|
||||
qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
|
||||
qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
|
||||
qemu_fdt_setprop_cell(fdt, cpu_name, "reg", cpu->cpu_index);
|
||||
qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
|
||||
ppc_get_vcpu_dt_id(pcpu));
|
||||
qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
|
||||
env->dcache_line_size);
|
||||
qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "hw/ppc/ppc_e500.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "hw/timer/m48t59.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/loader.h"
|
||||
@@ -1362,3 +1363,24 @@ int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* CPU device-tree ID helpers */
|
||||
int ppc_get_vcpu_dt_id(PowerPCCPU *cpu)
|
||||
{
|
||||
return cpu->cpu_dt_id;
|
||||
}
|
||||
|
||||
PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id)
|
||||
{
|
||||
CPUState *cs;
|
||||
|
||||
CPU_FOREACH(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
|
||||
if (cpu->cpu_dt_id == cpu_dt_id) {
|
||||
return cpu;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+43
-13
@@ -49,6 +49,7 @@
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/usb.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
@@ -206,19 +207,20 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(cpu);
|
||||
int index = ppc_get_vcpu_dt_id(POWERPC_CPU(cpu));
|
||||
uint32_t associativity[] = {cpu_to_be32(0x5),
|
||||
cpu_to_be32(0x0),
|
||||
cpu_to_be32(0x0),
|
||||
cpu_to_be32(0x0),
|
||||
cpu_to_be32(cpu->numa_node),
|
||||
cpu_to_be32(cpu->cpu_index)};
|
||||
cpu_to_be32(index)};
|
||||
|
||||
if ((cpu->cpu_index % smt) != 0) {
|
||||
if ((index % smt) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(cpu_model, 32, "/cpus/%s@%x", dc->fw_name,
|
||||
cpu->cpu_index);
|
||||
index);
|
||||
|
||||
offset = fdt_path_offset(fdt, cpu_model);
|
||||
if (offset < 0) {
|
||||
@@ -367,7 +369,7 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
||||
CPUPPCState *env = &cpu->env;
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
|
||||
int index = cs->cpu_index;
|
||||
int index = ppc_get_vcpu_dt_id(cpu);
|
||||
uint32_t servers_prop[smp_threads];
|
||||
uint32_t gservers_prop[smp_threads * 2];
|
||||
char *nodename;
|
||||
@@ -685,6 +687,7 @@ static void spapr_reset_htab(sPAPREnvironment *spapr)
|
||||
if (shift > 0) {
|
||||
/* Kernel handles htab, we don't need to allocate one */
|
||||
spapr->htab_shift = shift;
|
||||
kvmppc_kern_htab = true;
|
||||
} else {
|
||||
if (!spapr->htab) {
|
||||
/* Allocate an htab if we don't yet have one */
|
||||
@@ -740,8 +743,21 @@ static void spapr_cpu_reset(void *opaque)
|
||||
env->spr[SPR_HIOR] = 0;
|
||||
|
||||
env->external_htab = (uint8_t *)spapr->htab;
|
||||
if (kvm_enabled() && !env->external_htab) {
|
||||
/*
|
||||
* HV KVM, set external_htab to 1 so our ppc_hash64_load_hpte*
|
||||
* functions do the right thing.
|
||||
*/
|
||||
env->external_htab = (void *)1;
|
||||
}
|
||||
env->htab_base = -1;
|
||||
env->htab_mask = HTAB_SIZE(spapr) - 1;
|
||||
/*
|
||||
* htab_mask is the mask used to normalize hash value to PTEG index.
|
||||
* htab_shift is log2 of hash table size.
|
||||
* We have 8 hpte per group, and each hpte is 16 bytes.
|
||||
* ie have 128 bytes per hpte entry.
|
||||
*/
|
||||
env->htab_mask = (1ULL << ((spapr)->htab_shift - 7)) - 1;
|
||||
env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab |
|
||||
(spapr->htab_shift - 18);
|
||||
}
|
||||
@@ -1305,20 +1321,15 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
|
||||
|
||||
kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
|
||||
NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);
|
||||
if (kernel_size < 0) {
|
||||
if (kernel_size == ELF_LOAD_WRONG_ENDIAN) {
|
||||
kernel_size = load_elf(kernel_filename,
|
||||
translate_kernel_address, NULL,
|
||||
NULL, &lowaddr, NULL, 0, ELF_MACHINE, 0);
|
||||
kernel_le = kernel_size > 0;
|
||||
}
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_image_targphys(kernel_filename,
|
||||
KERNEL_LOAD_ADDR,
|
||||
load_limit - KERNEL_LOAD_ADDR);
|
||||
}
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
kernel_filename);
|
||||
fprintf(stderr, "qemu: error loading %s: %s\n",
|
||||
kernel_filename, load_elf_strerror(kernel_size));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -1366,6 +1377,24 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
|
||||
assert(spapr->fdt_skel != NULL);
|
||||
}
|
||||
|
||||
static int spapr_kvm_type(const char *vm_type)
|
||||
{
|
||||
if (!vm_type) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(vm_type, "HV")) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(vm_type, "PR")) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
error_report("Unknown kvm-type specified '%s'", vm_type);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static QEMUMachine spapr_machine = {
|
||||
.name = "pseries",
|
||||
.desc = "pSeries Logical Partition (PAPR compliant)",
|
||||
@@ -1376,6 +1405,7 @@ static QEMUMachine spapr_machine = {
|
||||
.max_cpus = MAX_CPUS,
|
||||
.no_parallel = 1,
|
||||
.default_boot_order = NULL,
|
||||
.kvm_type = spapr_kvm_type,
|
||||
};
|
||||
|
||||
static void spapr_machine_init(void)
|
||||
|
||||
+51
-36
@@ -40,6 +40,17 @@ static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
|
||||
return rb;
|
||||
}
|
||||
|
||||
static inline bool valid_pte_index(CPUPPCState *env, target_ulong pte_index)
|
||||
{
|
||||
/*
|
||||
* hash value/pteg group index is normalized by htab_mask
|
||||
*/
|
||||
if (((pte_index & ~7ULL) / HPTES_PER_GROUP) & ~env->htab_mask) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
@@ -50,8 +61,8 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong ptel = args[3];
|
||||
target_ulong page_shift = 12;
|
||||
target_ulong raddr;
|
||||
target_ulong i;
|
||||
hwaddr hpte;
|
||||
target_ulong index;
|
||||
uint64_t token;
|
||||
|
||||
/* only handle 4k and 16M pages for now */
|
||||
if (pteh & HPTE64_V_LARGE) {
|
||||
@@ -91,33 +102,37 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
|
||||
pteh &= ~0x60ULL;
|
||||
|
||||
if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
|
||||
if (!valid_pte_index(env, pte_index)) {
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
if (likely((flags & H_EXACT) == 0)) {
|
||||
pte_index &= ~7ULL;
|
||||
hpte = pte_index * HASH_PTE_SIZE_64;
|
||||
for (i = 0; ; ++i) {
|
||||
if (i == 8) {
|
||||
token = ppc_hash64_start_access(cpu, pte_index);
|
||||
do {
|
||||
if (index == 8) {
|
||||
ppc_hash64_stop_access(token);
|
||||
return H_PTEG_FULL;
|
||||
}
|
||||
if ((ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) == 0) {
|
||||
if ((ppc_hash64_load_hpte0(env, token, index) & HPTE64_V_VALID) == 0) {
|
||||
break;
|
||||
}
|
||||
hpte += HASH_PTE_SIZE_64;
|
||||
}
|
||||
} while (index++);
|
||||
ppc_hash64_stop_access(token);
|
||||
} else {
|
||||
i = 0;
|
||||
hpte = pte_index * HASH_PTE_SIZE_64;
|
||||
if (ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) {
|
||||
token = ppc_hash64_start_access(cpu, pte_index);
|
||||
if (ppc_hash64_load_hpte0(env, token, 0) & HPTE64_V_VALID) {
|
||||
ppc_hash64_stop_access(token);
|
||||
return H_PTEG_FULL;
|
||||
}
|
||||
ppc_hash64_stop_access(token);
|
||||
}
|
||||
ppc_hash64_store_hpte1(env, hpte, ptel);
|
||||
/* eieio(); FIXME: need some sort of barrier for smp? */
|
||||
ppc_hash64_store_hpte0(env, hpte, pteh | HPTE64_V_HPTE_DIRTY);
|
||||
|
||||
args[0] = pte_index + i;
|
||||
ppc_hash64_store_hpte(env, pte_index + index,
|
||||
pteh | HPTE64_V_HPTE_DIRTY, ptel);
|
||||
|
||||
args[0] = pte_index + index;
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -133,17 +148,17 @@ static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex,
|
||||
target_ulong flags,
|
||||
target_ulong *vp, target_ulong *rp)
|
||||
{
|
||||
hwaddr hpte;
|
||||
uint64_t token;
|
||||
target_ulong v, r, rb;
|
||||
|
||||
if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) {
|
||||
if (!valid_pte_index(env, ptex)) {
|
||||
return REMOVE_PARM;
|
||||
}
|
||||
|
||||
hpte = ptex * HASH_PTE_SIZE_64;
|
||||
|
||||
v = ppc_hash64_load_hpte0(env, hpte);
|
||||
r = ppc_hash64_load_hpte1(env, hpte);
|
||||
token = ppc_hash64_start_access(ppc_env_get_cpu(env), ptex);
|
||||
v = ppc_hash64_load_hpte0(env, token, 0);
|
||||
r = ppc_hash64_load_hpte1(env, token, 0);
|
||||
ppc_hash64_stop_access(token);
|
||||
|
||||
if ((v & HPTE64_V_VALID) == 0 ||
|
||||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
|
||||
@@ -152,7 +167,7 @@ static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex,
|
||||
}
|
||||
*vp = v;
|
||||
*rp = r;
|
||||
ppc_hash64_store_hpte0(env, hpte, HPTE64_V_HPTE_DIRTY);
|
||||
ppc_hash64_store_hpte(env, ptex, HPTE64_V_HPTE_DIRTY, 0);
|
||||
rb = compute_tlbie_rb(v, r, ptex);
|
||||
ppc_tlb_invalidate_one(env, rb);
|
||||
return REMOVE_SUCCESS;
|
||||
@@ -259,17 +274,17 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong flags = args[0];
|
||||
target_ulong pte_index = args[1];
|
||||
target_ulong avpn = args[2];
|
||||
hwaddr hpte;
|
||||
uint64_t token;
|
||||
target_ulong v, r, rb;
|
||||
|
||||
if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
|
||||
if (!valid_pte_index(env, pte_index)) {
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
hpte = pte_index * HASH_PTE_SIZE_64;
|
||||
|
||||
v = ppc_hash64_load_hpte0(env, hpte);
|
||||
r = ppc_hash64_load_hpte1(env, hpte);
|
||||
token = ppc_hash64_start_access(cpu, pte_index);
|
||||
v = ppc_hash64_load_hpte0(env, token, 0);
|
||||
r = ppc_hash64_load_hpte1(env, token, 0);
|
||||
ppc_hash64_stop_access(token);
|
||||
|
||||
if ((v & HPTE64_V_VALID) == 0 ||
|
||||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
|
||||
@@ -282,11 +297,11 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
r |= (flags << 48) & HPTE64_R_KEY_HI;
|
||||
r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
|
||||
rb = compute_tlbie_rb(v, r, pte_index);
|
||||
ppc_hash64_store_hpte0(env, hpte, (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY);
|
||||
ppc_hash64_store_hpte(env, pte_index,
|
||||
(v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
|
||||
ppc_tlb_invalidate_one(env, rb);
|
||||
ppc_hash64_store_hpte1(env, hpte, r);
|
||||
/* Don't need a memory barrier, due to qemu's global lock */
|
||||
ppc_hash64_store_hpte0(env, hpte, v | HPTE64_V_HPTE_DIRTY);
|
||||
ppc_hash64_store_hpte(env, pte_index, v | HPTE64_V_HPTE_DIRTY, r);
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -299,7 +314,7 @@ static target_ulong h_read(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
uint8_t *hpte;
|
||||
int i, ridx, n_entries = 1;
|
||||
|
||||
if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
|
||||
if (!valid_pte_index(env, pte_index)) {
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
@@ -467,13 +482,13 @@ static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong vpa = args[2];
|
||||
target_ulong ret = H_PARAMETER;
|
||||
CPUPPCState *tenv;
|
||||
CPUState *tcpu;
|
||||
PowerPCCPU *tcpu;
|
||||
|
||||
tcpu = qemu_get_cpu(procno);
|
||||
tcpu = ppc_get_vcpu_by_dt_id(procno);
|
||||
if (!tcpu) {
|
||||
return H_PARAMETER;
|
||||
}
|
||||
tenv = tcpu->env_ptr;
|
||||
tenv = &tcpu->env;
|
||||
|
||||
switch (flags) {
|
||||
case FLAGS_REGISTER_VPA:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user