mirror of https://github.com/xqemu/xqemu.git
Merge branch 'ppc-next' of git://repo.or.cz/qemu/agraf
* 'ppc-next' of git://repo.or.cz/qemu/agraf: PPC: Add description for the Freescale e500mc core. pseries: Check for duplicate addresses on the spapr-vio bus pseries: Populate "/chosen/linux,stdout-path" in the FDT pseries: Add a routine to find a stable "default" vty and use it pseries: Emit device tree nodes in reg order pseries: FDT NUMA extensions to support multi-node guests pseries: Remove hcalls callback kvm-ppc: halt secondary cpus when guest reset console: Fix segfault on screendump without VGA adapter PPC: monitor: add ability to dump SLB entries
This commit is contained in:
commit
15f43ccda1
|
@ -186,7 +186,9 @@ void vga_hw_screen_dump(const char *filename)
|
||||||
consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
|
consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
console_select(previous_active_console->index);
|
if (previous_active_console) {
|
||||||
|
console_select(previous_active_console->index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_hw_text_update(console_ch_t *chardata)
|
void vga_hw_text_update(console_ch_t *chardata)
|
||||||
|
|
|
@ -112,6 +112,7 @@ static void spin_kick(void *data)
|
||||||
|
|
||||||
env->halted = 0;
|
env->halted = 0;
|
||||||
env->exception_index = -1;
|
env->exception_index = -1;
|
||||||
|
env->stopped = 0;
|
||||||
qemu_cpu_kick(env);
|
qemu_cpu_kick(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
114
hw/spapr.c
114
hw/spapr.c
|
@ -97,6 +97,44 @@ qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num)
|
||||||
return qirq;
|
return qirq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr)
|
||||||
|
{
|
||||||
|
int ret = 0, offset;
|
||||||
|
CPUState *env;
|
||||||
|
char cpu_model[32];
|
||||||
|
int smt = kvmppc_smt_threads();
|
||||||
|
|
||||||
|
assert(spapr->cpu_model);
|
||||||
|
|
||||||
|
for (env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||||
|
uint32_t associativity[] = {cpu_to_be32(0x5),
|
||||||
|
cpu_to_be32(0x0),
|
||||||
|
cpu_to_be32(0x0),
|
||||||
|
cpu_to_be32(0x0),
|
||||||
|
cpu_to_be32(env->numa_node),
|
||||||
|
cpu_to_be32(env->cpu_index)};
|
||||||
|
|
||||||
|
if ((env->cpu_index % smt) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(cpu_model, 32, "/cpus/%s@%x", spapr->cpu_model,
|
||||||
|
env->cpu_index);
|
||||||
|
|
||||||
|
offset = fdt_path_offset(fdt, cpu_model);
|
||||||
|
if (offset < 0) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity,
|
||||||
|
sizeof(associativity));
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void *spapr_create_fdt_skel(const char *cpu_model,
|
static void *spapr_create_fdt_skel(const char *cpu_model,
|
||||||
target_phys_addr_t rma_size,
|
target_phys_addr_t rma_size,
|
||||||
target_phys_addr_t initrd_base,
|
target_phys_addr_t initrd_base,
|
||||||
|
@ -107,9 +145,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
|
||||||
{
|
{
|
||||||
void *fdt;
|
void *fdt;
|
||||||
CPUState *env;
|
CPUState *env;
|
||||||
uint64_t mem_reg_property_rma[] = { 0, cpu_to_be64(rma_size) };
|
uint64_t mem_reg_property[2];
|
||||||
uint64_t mem_reg_property_nonrma[] = { cpu_to_be64(rma_size),
|
|
||||||
cpu_to_be64(ram_size - rma_size) };
|
|
||||||
uint32_t start_prop = cpu_to_be32(initrd_base);
|
uint32_t start_prop = cpu_to_be32(initrd_base);
|
||||||
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
|
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
|
||||||
uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
|
uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
|
||||||
|
@ -119,6 +155,13 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
|
||||||
int i;
|
int i;
|
||||||
char *modelname;
|
char *modelname;
|
||||||
int smt = kvmppc_smt_threads();
|
int smt = kvmppc_smt_threads();
|
||||||
|
unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80};
|
||||||
|
uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
|
||||||
|
uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0),
|
||||||
|
cpu_to_be32(0x0), cpu_to_be32(0x0),
|
||||||
|
cpu_to_be32(0x0)};
|
||||||
|
char mem_name[32];
|
||||||
|
target_phys_addr_t node0_size, mem_start;
|
||||||
|
|
||||||
#define _FDT(exp) \
|
#define _FDT(exp) \
|
||||||
do { \
|
do { \
|
||||||
|
@ -146,6 +189,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
|
||||||
/* /chosen */
|
/* /chosen */
|
||||||
_FDT((fdt_begin_node(fdt, "chosen")));
|
_FDT((fdt_begin_node(fdt, "chosen")));
|
||||||
|
|
||||||
|
/* Set Form1_affinity */
|
||||||
|
_FDT((fdt_property(fdt, "ibm,architecture-vec-5", vec5, sizeof(vec5))));
|
||||||
|
|
||||||
_FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline)));
|
_FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline)));
|
||||||
_FDT((fdt_property(fdt, "linux,initrd-start",
|
_FDT((fdt_property(fdt, "linux,initrd-start",
|
||||||
&start_prop, sizeof(start_prop))));
|
&start_prop, sizeof(start_prop))));
|
||||||
|
@ -164,24 +210,54 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
|
||||||
_FDT((fdt_end_node(fdt)));
|
_FDT((fdt_end_node(fdt)));
|
||||||
|
|
||||||
/* memory node(s) */
|
/* memory node(s) */
|
||||||
_FDT((fdt_begin_node(fdt, "memory@0")));
|
node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size;
|
||||||
|
if (rma_size > node0_size) {
|
||||||
|
rma_size = node0_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RMA */
|
||||||
|
mem_reg_property[0] = 0;
|
||||||
|
mem_reg_property[1] = cpu_to_be64(rma_size);
|
||||||
|
_FDT((fdt_begin_node(fdt, "memory@0")));
|
||||||
_FDT((fdt_property_string(fdt, "device_type", "memory")));
|
_FDT((fdt_property_string(fdt, "device_type", "memory")));
|
||||||
_FDT((fdt_property(fdt, "reg", mem_reg_property_rma,
|
_FDT((fdt_property(fdt, "reg", mem_reg_property,
|
||||||
sizeof(mem_reg_property_rma))));
|
sizeof(mem_reg_property))));
|
||||||
|
_FDT((fdt_property(fdt, "ibm,associativity", associativity,
|
||||||
|
sizeof(associativity))));
|
||||||
_FDT((fdt_end_node(fdt)));
|
_FDT((fdt_end_node(fdt)));
|
||||||
|
|
||||||
if (ram_size > rma_size) {
|
/* RAM: Node 0 */
|
||||||
char mem_name[32];
|
if (node0_size > rma_size) {
|
||||||
|
mem_reg_property[0] = cpu_to_be64(rma_size);
|
||||||
|
mem_reg_property[1] = cpu_to_be64(node0_size - rma_size);
|
||||||
|
|
||||||
sprintf(mem_name, "memory@%" PRIx64, (uint64_t)rma_size);
|
sprintf(mem_name, "memory@" TARGET_FMT_lx, rma_size);
|
||||||
_FDT((fdt_begin_node(fdt, mem_name)));
|
_FDT((fdt_begin_node(fdt, mem_name)));
|
||||||
_FDT((fdt_property_string(fdt, "device_type", "memory")));
|
_FDT((fdt_property_string(fdt, "device_type", "memory")));
|
||||||
_FDT((fdt_property(fdt, "reg", mem_reg_property_nonrma,
|
_FDT((fdt_property(fdt, "reg", mem_reg_property,
|
||||||
sizeof(mem_reg_property_nonrma))));
|
sizeof(mem_reg_property))));
|
||||||
|
_FDT((fdt_property(fdt, "ibm,associativity", associativity,
|
||||||
|
sizeof(associativity))));
|
||||||
_FDT((fdt_end_node(fdt)));
|
_FDT((fdt_end_node(fdt)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* RAM: Node 1 and beyond */
|
||||||
|
mem_start = node0_size;
|
||||||
|
for (i = 1; i < nb_numa_nodes; i++) {
|
||||||
|
mem_reg_property[0] = cpu_to_be64(mem_start);
|
||||||
|
mem_reg_property[1] = cpu_to_be64(node_mem[i]);
|
||||||
|
associativity[3] = associativity[4] = cpu_to_be32(i);
|
||||||
|
sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start);
|
||||||
|
_FDT((fdt_begin_node(fdt, mem_name)));
|
||||||
|
_FDT((fdt_property_string(fdt, "device_type", "memory")));
|
||||||
|
_FDT((fdt_property(fdt, "reg", mem_reg_property,
|
||||||
|
sizeof(mem_reg_property))));
|
||||||
|
_FDT((fdt_property(fdt, "ibm,associativity", associativity,
|
||||||
|
sizeof(associativity))));
|
||||||
|
_FDT((fdt_end_node(fdt)));
|
||||||
|
mem_start += node_mem[i];
|
||||||
|
}
|
||||||
|
|
||||||
/* cpus */
|
/* cpus */
|
||||||
_FDT((fdt_begin_node(fdt, "cpus")));
|
_FDT((fdt_begin_node(fdt, "cpus")));
|
||||||
|
|
||||||
|
@ -194,6 +270,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
|
||||||
modelname[i] = toupper(modelname[i]);
|
modelname[i] = toupper(modelname[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This is needed during FDT finalization */
|
||||||
|
spapr->cpu_model = g_strdup(modelname);
|
||||||
|
|
||||||
for (env = first_cpu; env != NULL; env = env->next_cpu) {
|
for (env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||||
int index = env->cpu_index;
|
int index = env->cpu_index;
|
||||||
uint32_t servers_prop[smp_threads];
|
uint32_t servers_prop[smp_threads];
|
||||||
|
@ -280,6 +359,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
|
||||||
_FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop,
|
_FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop,
|
||||||
sizeof(hypertas_prop))));
|
sizeof(hypertas_prop))));
|
||||||
|
|
||||||
|
_FDT((fdt_property(fdt, "ibm,associativity-reference-points",
|
||||||
|
refpoints, sizeof(refpoints))));
|
||||||
|
|
||||||
_FDT((fdt_end_node(fdt)));
|
_FDT((fdt_end_node(fdt)));
|
||||||
|
|
||||||
/* interrupt controller */
|
/* interrupt controller */
|
||||||
|
@ -351,6 +433,16 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
|
||||||
fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
|
fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Advertise NUMA via ibm,associativity */
|
||||||
|
if (nb_numa_nodes > 1) {
|
||||||
|
ret = spapr_set_associativity(fdt, spapr);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Couldn't set up NUMA device tree properties\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
|
||||||
|
|
||||||
_FDT((fdt_pack(fdt)));
|
_FDT((fdt_pack(fdt)));
|
||||||
|
|
||||||
cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
|
cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
|
||||||
|
|
|
@ -21,6 +21,7 @@ typedef struct sPAPREnvironment {
|
||||||
target_ulong entry_point;
|
target_ulong entry_point;
|
||||||
int next_irq;
|
int next_irq;
|
||||||
int rtc_offset;
|
int rtc_offset;
|
||||||
|
char *cpu_model;
|
||||||
} sPAPREnvironment;
|
} sPAPREnvironment;
|
||||||
|
|
||||||
#define H_SUCCESS 0
|
#define H_SUCCESS 0
|
||||||
|
|
|
@ -474,16 +474,6 @@ static target_ulong h_multicast_ctrl(CPUState *env, sPAPREnvironment *spapr,
|
||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vlan_hcalls(VIOsPAPRBus *bus)
|
|
||||||
{
|
|
||||||
spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
|
|
||||||
spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
|
|
||||||
spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
|
|
||||||
spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
|
|
||||||
h_add_logical_lan_buffer);
|
|
||||||
spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
static VIOsPAPRDeviceInfo spapr_vlan = {
|
static VIOsPAPRDeviceInfo spapr_vlan = {
|
||||||
.init = spapr_vlan_init,
|
.init = spapr_vlan_init,
|
||||||
.devnode = spapr_vlan_devnode,
|
.devnode = spapr_vlan_devnode,
|
||||||
|
@ -491,7 +481,6 @@ static VIOsPAPRDeviceInfo spapr_vlan = {
|
||||||
.dt_type = "network",
|
.dt_type = "network",
|
||||||
.dt_compatible = "IBM,l-lan",
|
.dt_compatible = "IBM,l-lan",
|
||||||
.signal_mask = 0x1,
|
.signal_mask = 0x1,
|
||||||
.hcalls = vlan_hcalls,
|
|
||||||
.qdev.name = "spapr-vlan",
|
.qdev.name = "spapr-vlan",
|
||||||
.qdev.size = sizeof(VIOsPAPRVLANDevice),
|
.qdev.size = sizeof(VIOsPAPRVLANDevice),
|
||||||
.qdev.props = (Property[]) {
|
.qdev.props = (Property[]) {
|
||||||
|
@ -504,5 +493,11 @@ static VIOsPAPRDeviceInfo spapr_vlan = {
|
||||||
static void spapr_vlan_register(void)
|
static void spapr_vlan_register(void)
|
||||||
{
|
{
|
||||||
spapr_vio_bus_register_withprop(&spapr_vlan);
|
spapr_vio_bus_register_withprop(&spapr_vlan);
|
||||||
|
spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
|
||||||
|
spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
|
||||||
|
spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
|
||||||
|
spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
|
||||||
|
h_add_logical_lan_buffer);
|
||||||
|
spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
|
||||||
}
|
}
|
||||||
device_init(spapr_vlan_register);
|
device_init(spapr_vlan_register);
|
||||||
|
|
129
hw/spapr_vio.c
129
hw/spapr_vio.c
|
@ -621,11 +621,43 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
|
||||||
rtas_st(rets, 0, 0);
|
rtas_st(rets, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int spapr_vio_check_reg(VIOsPAPRDevice *sdev, VIOsPAPRDeviceInfo *info)
|
||||||
|
{
|
||||||
|
VIOsPAPRDevice *other_sdev;
|
||||||
|
DeviceState *qdev;
|
||||||
|
VIOsPAPRBus *sbus;
|
||||||
|
|
||||||
|
sbus = DO_UPCAST(VIOsPAPRBus, bus, sdev->qdev.parent_bus);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check two device aren't given clashing addresses by the user (or some
|
||||||
|
* other mechanism). We have to open code this because we have to check
|
||||||
|
* for matches with devices other than us.
|
||||||
|
*/
|
||||||
|
QTAILQ_FOREACH(qdev, &sbus->bus.children, sibling) {
|
||||||
|
other_sdev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev);
|
||||||
|
|
||||||
|
if (other_sdev != sdev && other_sdev->reg == sdev->reg) {
|
||||||
|
fprintf(stderr, "vio: %s and %s devices conflict at address %#x\n",
|
||||||
|
info->qdev.name, other_sdev->qdev.info->name, sdev->reg);
|
||||||
|
return -EEXIST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
|
static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
|
||||||
{
|
{
|
||||||
VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
|
VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
|
||||||
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
|
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
|
||||||
char *id;
|
char *id;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = spapr_vio_check_reg(dev, info);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Don't overwrite ids assigned on the command line */
|
/* Don't overwrite ids assigned on the command line */
|
||||||
if (!dev->qdev.id) {
|
if (!dev->qdev.id) {
|
||||||
|
@ -684,7 +716,6 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
|
||||||
VIOsPAPRBus *bus;
|
VIOsPAPRBus *bus;
|
||||||
BusState *qbus;
|
BusState *qbus;
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
DeviceInfo *qinfo;
|
|
||||||
|
|
||||||
/* Create bridge device */
|
/* Create bridge device */
|
||||||
dev = qdev_create(NULL, "spapr-vio-bridge");
|
dev = qdev_create(NULL, "spapr-vio-bridge");
|
||||||
|
@ -711,18 +742,6 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
|
||||||
spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass);
|
spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass);
|
||||||
spapr_rtas_register("quiesce", rtas_quiesce);
|
spapr_rtas_register("quiesce", rtas_quiesce);
|
||||||
|
|
||||||
for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) {
|
|
||||||
VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
|
|
||||||
|
|
||||||
if (qinfo->bus_info != &spapr_vio_bus_info) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->hcalls) {
|
|
||||||
info->hcalls(bus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bus;
|
return bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -749,21 +768,95 @@ static void spapr_vio_register_devices(void)
|
||||||
device_init(spapr_vio_register_devices)
|
device_init(spapr_vio_register_devices)
|
||||||
|
|
||||||
#ifdef CONFIG_FDT
|
#ifdef CONFIG_FDT
|
||||||
|
static int compare_reg(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
VIOsPAPRDevice const *dev1, *dev2;
|
||||||
|
|
||||||
|
dev1 = (VIOsPAPRDevice *)*(DeviceState **)p1;
|
||||||
|
dev2 = (VIOsPAPRDevice *)*(DeviceState **)p2;
|
||||||
|
|
||||||
|
if (dev1->reg < dev2->reg) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (dev1->reg == dev2->reg) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* dev1->reg > dev2->reg */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
|
int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
|
||||||
{
|
{
|
||||||
DeviceState *qdev;
|
DeviceState *qdev, **qdevs;
|
||||||
int ret = 0;
|
int i, num, ret = 0;
|
||||||
|
|
||||||
|
/* Count qdevs on the bus list */
|
||||||
|
num = 0;
|
||||||
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
|
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
|
||||||
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
|
num++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy out into an array of pointers */
|
||||||
|
qdevs = g_malloc(sizeof(qdev) * num);
|
||||||
|
num = 0;
|
||||||
|
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
|
||||||
|
qdevs[num++] = qdev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sort the array */
|
||||||
|
qsort(qdevs, num, sizeof(qdev), compare_reg);
|
||||||
|
|
||||||
|
/* Hack alert. Give the devices to libfdt in reverse order, we happen
|
||||||
|
* to know that will mean they are in forward order in the tree. */
|
||||||
|
for (i = num - 1; i >= 0; i--) {
|
||||||
|
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)(qdevs[i]);
|
||||||
|
|
||||||
ret = vio_make_devnode(dev, fdt);
|
ret = vio_make_devnode(dev, fdt);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
ret = 0;
|
||||||
|
out:
|
||||||
|
free(qdevs);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus)
|
||||||
|
{
|
||||||
|
VIOsPAPRDevice *dev;
|
||||||
|
char *name, *path;
|
||||||
|
int ret, offset;
|
||||||
|
|
||||||
|
dev = spapr_vty_get_default(bus);
|
||||||
|
if (!dev)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
offset = fdt_path_offset(fdt, "/chosen");
|
||||||
|
if (offset < 0) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = vio_format_dev_name(dev);
|
||||||
|
if (!name) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asprintf(&path, "/vdevice/%s", name) < 0) {
|
||||||
|
path = NULL;
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path);
|
||||||
|
out:
|
||||||
|
free(name);
|
||||||
|
free(path);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_FDT */
|
#endif /* CONFIG_FDT */
|
||||||
|
|
|
@ -75,7 +75,6 @@ typedef struct {
|
||||||
const char *dt_name, *dt_type, *dt_compatible;
|
const char *dt_name, *dt_type, *dt_compatible;
|
||||||
target_ulong signal_mask;
|
target_ulong signal_mask;
|
||||||
int (*init)(VIOsPAPRDevice *dev);
|
int (*init)(VIOsPAPRDevice *dev);
|
||||||
void (*hcalls)(VIOsPAPRBus *bus);
|
|
||||||
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
|
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
|
||||||
} VIOsPAPRDeviceInfo;
|
} VIOsPAPRDeviceInfo;
|
||||||
|
|
||||||
|
@ -83,6 +82,7 @@ extern VIOsPAPRBus *spapr_vio_bus_init(void);
|
||||||
extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
|
extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
|
||||||
extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info);
|
extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info);
|
||||||
extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
|
extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
|
||||||
|
extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus);
|
||||||
|
|
||||||
extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
|
extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
|
||||||
|
|
||||||
|
@ -108,6 +108,8 @@ void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev);
|
||||||
void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd);
|
void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd);
|
||||||
void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg);
|
void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg);
|
||||||
|
|
||||||
|
VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus);
|
||||||
|
|
||||||
int spapr_tce_set_bypass(uint32_t unit, uint32_t enable);
|
int spapr_tce_set_bypass(uint32_t unit, uint32_t enable);
|
||||||
void spapr_vio_quiesce(void);
|
void spapr_vio_quiesce(void);
|
||||||
|
|
||||||
|
|
|
@ -135,18 +135,11 @@ void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev)
|
||||||
qdev_init_nofail(dev);
|
qdev_init_nofail(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vty_hcalls(VIOsPAPRBus *bus)
|
|
||||||
{
|
|
||||||
spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
|
|
||||||
spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
|
|
||||||
}
|
|
||||||
|
|
||||||
static VIOsPAPRDeviceInfo spapr_vty = {
|
static VIOsPAPRDeviceInfo spapr_vty = {
|
||||||
.init = spapr_vty_init,
|
.init = spapr_vty_init,
|
||||||
.dt_name = "vty",
|
.dt_name = "vty",
|
||||||
.dt_type = "serial",
|
.dt_type = "serial",
|
||||||
.dt_compatible = "hvterm1",
|
.dt_compatible = "hvterm1",
|
||||||
.hcalls = vty_hcalls,
|
|
||||||
.qdev.name = "spapr-vty",
|
.qdev.name = "spapr-vty",
|
||||||
.qdev.size = sizeof(VIOsPAPRVTYDevice),
|
.qdev.size = sizeof(VIOsPAPRVTYDevice),
|
||||||
.qdev.props = (Property[]) {
|
.qdev.props = (Property[]) {
|
||||||
|
@ -156,24 +149,53 @@ static VIOsPAPRDeviceInfo spapr_vty = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
|
||||||
|
{
|
||||||
|
VIOsPAPRDevice *sdev, *selected;
|
||||||
|
DeviceState *iter;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To avoid the console bouncing around we want one VTY to be
|
||||||
|
* the "default". We haven't really got anything to go on, so
|
||||||
|
* arbitrarily choose the one with the lowest reg value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
selected = NULL;
|
||||||
|
QTAILQ_FOREACH(iter, &bus->bus.children, sibling) {
|
||||||
|
/* Only look at VTY devices */
|
||||||
|
if (iter->info != &spapr_vty.qdev) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter);
|
||||||
|
|
||||||
|
/* First VTY we've found, so it is selected for now */
|
||||||
|
if (!selected) {
|
||||||
|
selected = sdev;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Choose VTY with lowest reg value */
|
||||||
|
if (sdev->reg < selected->reg) {
|
||||||
|
selected = sdev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
|
static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
|
||||||
{
|
{
|
||||||
VIOsPAPRDevice *sdev;
|
VIOsPAPRDevice *sdev;
|
||||||
|
|
||||||
sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
|
sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
|
||||||
if (!sdev && reg == 0) {
|
if (!sdev && reg == 0) {
|
||||||
DeviceState *qdev;
|
|
||||||
|
|
||||||
/* Hack for kernel early debug, which always specifies reg==0.
|
/* Hack for kernel early debug, which always specifies reg==0.
|
||||||
* We search all VIO devices, and grab the first available vty
|
* We search all VIO devices, and grab the vty with the lowest
|
||||||
* device. This attempts to mimic existing PowerVM behaviour
|
* reg. This attempts to mimic existing PowerVM behaviour
|
||||||
* (early debug does work there, despite having no vty with
|
* (early debug does work there, despite having no vty with
|
||||||
* reg==0. */
|
* reg==0. */
|
||||||
QTAILQ_FOREACH(qdev, &spapr->vio_bus->bus.children, sibling) {
|
return spapr_vty_get_default(spapr->vio_bus);
|
||||||
if (qdev->info == &spapr_vty.qdev) {
|
|
||||||
return DO_UPCAST(VIOsPAPRDevice, qdev, qdev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sdev;
|
return sdev;
|
||||||
|
@ -182,5 +204,7 @@ static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
|
||||||
static void spapr_vty_register(void)
|
static void spapr_vty_register(void)
|
||||||
{
|
{
|
||||||
spapr_vio_bus_register_withprop(&spapr_vty);
|
spapr_vio_bus_register_withprop(&spapr_vty);
|
||||||
|
spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
|
||||||
|
spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
|
||||||
}
|
}
|
||||||
device_init(spapr_vty_register);
|
device_init(spapr_vty_register);
|
||||||
|
|
|
@ -1545,12 +1545,40 @@ static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(TARGET_PPC64)
|
||||||
|
static void mmubooks_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
|
||||||
|
CPUState *env)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint64_t slbe, slbv;
|
||||||
|
|
||||||
|
cpu_synchronize_state(env);
|
||||||
|
|
||||||
|
cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n");
|
||||||
|
for (i = 0; i < env->slb_nr; i++) {
|
||||||
|
slbe = env->slb[i].esid;
|
||||||
|
slbv = env->slb[i].vsid;
|
||||||
|
if (slbe == 0 && slbv == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n",
|
||||||
|
i, slbe, slbv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
|
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
|
||||||
{
|
{
|
||||||
switch (env->mmu_model) {
|
switch (env->mmu_model) {
|
||||||
case POWERPC_MMU_BOOKE206:
|
case POWERPC_MMU_BOOKE206:
|
||||||
mmubooke206_dump_mmu(f, cpu_fprintf, env);
|
mmubooke206_dump_mmu(f, cpu_fprintf, env);
|
||||||
break;
|
break;
|
||||||
|
#if defined(TARGET_PPC64)
|
||||||
|
case POWERPC_MMU_64B:
|
||||||
|
case POWERPC_MMU_2_06:
|
||||||
|
mmubooks_dump_mmu(f, cpu_fprintf, env);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
cpu_fprintf(f, "%s: unimplemented\n", __func__);
|
cpu_fprintf(f, "%s: unimplemented\n", __func__);
|
||||||
}
|
}
|
||||||
|
|
|
@ -504,7 +504,7 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run)
|
||||||
|
|
||||||
int kvm_arch_process_async_events(CPUState *env)
|
int kvm_arch_process_async_events(CPUState *env)
|
||||||
{
|
{
|
||||||
return 0;
|
return env->halted;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kvmppc_handle_halt(CPUState *env)
|
static int kvmppc_handle_halt(CPUState *env)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* PowerPC CPU initialization for qemu.
|
* PowerPC CPU initialization for qemu.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2003-2007 Jocelyn Mayer
|
* Copyright (c) 2003-2007 Jocelyn Mayer
|
||||||
|
* Copyright 2011 Freescale Semiconductor, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -4399,6 +4400,33 @@ static void init_proc_e300 (CPUPPCState *env)
|
||||||
#define check_pow_e500v2 check_pow_hid0
|
#define check_pow_e500v2 check_pow_hid0
|
||||||
#define init_proc_e500v2 init_proc_e500v2
|
#define init_proc_e500v2 init_proc_e500v2
|
||||||
|
|
||||||
|
/* e500mc core */
|
||||||
|
#define POWERPC_INSNS_e500mc (PPC_INSNS_BASE | PPC_ISEL | \
|
||||||
|
PPC_WRTEE | PPC_RFDI | PPC_RFMCI | \
|
||||||
|
PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
|
||||||
|
PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \
|
||||||
|
PPC_FLOAT | PPC_FLOAT_FRES | \
|
||||||
|
PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | \
|
||||||
|
PPC_FLOAT_STFIWX | PPC_WAIT | \
|
||||||
|
PPC_MEM_TLBSYNC | PPC_TLBIVAX)
|
||||||
|
#define POWERPC_INSNS2_e500mc (PPC2_BOOKE206)
|
||||||
|
#define POWERPC_MSRM_e500mc (0x000000001402FB36ULL)
|
||||||
|
#define POWERPC_MMU_e500mc (POWERPC_MMU_BOOKE206)
|
||||||
|
#define POWERPC_EXCP_e500mc (POWERPC_EXCP_BOOKE)
|
||||||
|
#define POWERPC_INPUT_e500mc (PPC_FLAGS_INPUT_BookE)
|
||||||
|
/* Fixme: figure out the correct flag for e500mc */
|
||||||
|
#define POWERPC_BFDM_e500mc (bfd_mach_ppc_e500)
|
||||||
|
#define POWERPC_FLAG_e500mc (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \
|
||||||
|
POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK)
|
||||||
|
#define check_pow_e500mc check_pow_none
|
||||||
|
#define init_proc_e500mc init_proc_e500mc
|
||||||
|
|
||||||
|
enum fsl_e500_version {
|
||||||
|
fsl_e500v1,
|
||||||
|
fsl_e500v2,
|
||||||
|
fsl_e500mc,
|
||||||
|
};
|
||||||
|
|
||||||
static void init_proc_e500 (CPUPPCState *env, int version)
|
static void init_proc_e500 (CPUPPCState *env, int version)
|
||||||
{
|
{
|
||||||
uint32_t tlbncfg[2];
|
uint32_t tlbncfg[2];
|
||||||
|
@ -4430,15 +4458,26 @@ static void init_proc_e500 (CPUPPCState *env, int version)
|
||||||
env->nb_ways = 2;
|
env->nb_ways = 2;
|
||||||
env->id_tlbs = 0;
|
env->id_tlbs = 0;
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case 1:
|
case fsl_e500v1:
|
||||||
/* e500v1 */
|
/* e500v1 */
|
||||||
tlbncfg[0] = gen_tlbncfg(2, 1, 1, 0, 256);
|
tlbncfg[0] = gen_tlbncfg(2, 1, 1, 0, 256);
|
||||||
tlbncfg[1] = gen_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
|
tlbncfg[1] = gen_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
|
||||||
|
env->dcache_line_size = 32;
|
||||||
|
env->icache_line_size = 32;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case fsl_e500v2:
|
||||||
/* e500v2 */
|
/* e500v2 */
|
||||||
tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512);
|
tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512);
|
||||||
tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
|
tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
|
||||||
|
env->dcache_line_size = 32;
|
||||||
|
env->icache_line_size = 32;
|
||||||
|
break;
|
||||||
|
case fsl_e500mc:
|
||||||
|
/* e500mc */
|
||||||
|
tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512);
|
||||||
|
tlbncfg[1] = gen_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64);
|
||||||
|
env->dcache_line_size = 64;
|
||||||
|
env->icache_line_size = 64;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]);
|
cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]);
|
||||||
|
@ -4522,20 +4561,23 @@ static void init_proc_e500 (CPUPPCState *env, int version)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
init_excp_e200(env);
|
init_excp_e200(env);
|
||||||
env->dcache_line_size = 32;
|
|
||||||
env->icache_line_size = 32;
|
|
||||||
/* Allocate hardware IRQ controller */
|
/* Allocate hardware IRQ controller */
|
||||||
ppce500_irq_init(env);
|
ppce500_irq_init(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_proc_e500v1(CPUPPCState *env)
|
static void init_proc_e500v1(CPUPPCState *env)
|
||||||
{
|
{
|
||||||
init_proc_e500(env, 1);
|
init_proc_e500(env, fsl_e500v1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_proc_e500v2(CPUPPCState *env)
|
static void init_proc_e500v2(CPUPPCState *env)
|
||||||
{
|
{
|
||||||
init_proc_e500(env, 2);
|
init_proc_e500(env, fsl_e500v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_proc_e500mc(CPUPPCState *env)
|
||||||
|
{
|
||||||
|
init_proc_e500(env, fsl_e500mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Non-embedded PowerPC */
|
/* Non-embedded PowerPC */
|
||||||
|
@ -7070,6 +7112,7 @@ enum {
|
||||||
CPU_POWERPC_e500v2_v21 = 0x80210021,
|
CPU_POWERPC_e500v2_v21 = 0x80210021,
|
||||||
CPU_POWERPC_e500v2_v22 = 0x80210022,
|
CPU_POWERPC_e500v2_v22 = 0x80210022,
|
||||||
CPU_POWERPC_e500v2_v30 = 0x80210030,
|
CPU_POWERPC_e500v2_v30 = 0x80210030,
|
||||||
|
CPU_POWERPC_e500mc = 0x80230020,
|
||||||
/* MPC85xx microcontrollers */
|
/* MPC85xx microcontrollers */
|
||||||
#define CPU_POWERPC_MPC8533 CPU_POWERPC_MPC8533_v11
|
#define CPU_POWERPC_MPC8533 CPU_POWERPC_MPC8533_v11
|
||||||
#define CPU_POWERPC_MPC8533_v10 CPU_POWERPC_e500v2_v21
|
#define CPU_POWERPC_MPC8533_v10 CPU_POWERPC_e500v2_v21
|
||||||
|
@ -8471,6 +8514,7 @@ static const ppc_def_t ppc_defs[] = {
|
||||||
POWERPC_DEF("e500v2_v22", CPU_POWERPC_e500v2_v22, e500v2),
|
POWERPC_DEF("e500v2_v22", CPU_POWERPC_e500v2_v22, e500v2),
|
||||||
/* PowerPC e500v2 v3.0 core */
|
/* PowerPC e500v2 v3.0 core */
|
||||||
POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2),
|
POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2),
|
||||||
|
POWERPC_DEF("e500mc", CPU_POWERPC_e500mc, e500mc),
|
||||||
/* PowerPC e500 microcontrollers */
|
/* PowerPC e500 microcontrollers */
|
||||||
/* MPC8533 */
|
/* MPC8533 */
|
||||||
POWERPC_DEF_SVR("MPC8533",
|
POWERPC_DEF_SVR("MPC8533",
|
||||||
|
|
Loading…
Reference in New Issue