mirror of
https://github.com/qemu/qemu.git
synced 2024-11-27 22:03:35 +08:00
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);
|
||||
}
|
||||
|
||||
if (previous_active_console) {
|
||||
console_select(previous_active_console->index);
|
||||
}
|
||||
}
|
||||
|
||||
void vga_hw_text_update(console_ch_t *chardata)
|
||||
|
@ -112,6 +112,7 @@ static void spin_kick(void *data)
|
||||
|
||||
env->halted = 0;
|
||||
env->exception_index = -1;
|
||||
env->stopped = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
target_phys_addr_t rma_size,
|
||||
target_phys_addr_t initrd_base,
|
||||
@ -107,9 +145,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
|
||||
{
|
||||
void *fdt;
|
||||
CPUState *env;
|
||||
uint64_t mem_reg_property_rma[] = { 0, cpu_to_be64(rma_size) };
|
||||
uint64_t mem_reg_property_nonrma[] = { cpu_to_be64(rma_size),
|
||||
cpu_to_be64(ram_size - rma_size) };
|
||||
uint64_t mem_reg_property[2];
|
||||
uint32_t start_prop = cpu_to_be32(initrd_base);
|
||||
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
|
||||
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;
|
||||
char *modelname;
|
||||
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) \
|
||||
do { \
|
||||
@ -146,6 +189,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
|
||||
/* /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(fdt, "linux,initrd-start",
|
||||
&start_prop, sizeof(start_prop))));
|
||||
@ -164,24 +210,54 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
|
||||
_FDT((fdt_end_node(fdt)));
|
||||
|
||||
/* 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(fdt, "reg", mem_reg_property_rma,
|
||||
sizeof(mem_reg_property_rma))));
|
||||
_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)));
|
||||
|
||||
if (ram_size > rma_size) {
|
||||
char mem_name[32];
|
||||
/* RAM: Node 0 */
|
||||
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_property_string(fdt, "device_type", "memory")));
|
||||
_FDT((fdt_property(fdt, "reg", mem_reg_property_nonrma,
|
||||
sizeof(mem_reg_property_nonrma))));
|
||||
_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)));
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
_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]);
|
||||
}
|
||||
|
||||
/* This is needed during FDT finalization */
|
||||
spapr->cpu_model = g_strdup(modelname);
|
||||
|
||||
for (env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
int index = env->cpu_index;
|
||||
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,
|
||||
sizeof(hypertas_prop))));
|
||||
|
||||
_FDT((fdt_property(fdt, "ibm,associativity-reference-points",
|
||||
refpoints, sizeof(refpoints))));
|
||||
|
||||
_FDT((fdt_end_node(fdt)));
|
||||
|
||||
/* interrupt controller */
|
||||
@ -351,6 +433,16 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
|
||||
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)));
|
||||
|
||||
cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
|
||||
|
@ -21,6 +21,7 @@ typedef struct sPAPREnvironment {
|
||||
target_ulong entry_point;
|
||||
int next_irq;
|
||||
int rtc_offset;
|
||||
char *cpu_model;
|
||||
} sPAPREnvironment;
|
||||
|
||||
#define H_SUCCESS 0
|
||||
|
@ -474,16 +474,6 @@ static target_ulong h_multicast_ctrl(CPUState *env, sPAPREnvironment *spapr,
|
||||
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 = {
|
||||
.init = spapr_vlan_init,
|
||||
.devnode = spapr_vlan_devnode,
|
||||
@ -491,7 +481,6 @@ static VIOsPAPRDeviceInfo spapr_vlan = {
|
||||
.dt_type = "network",
|
||||
.dt_compatible = "IBM,l-lan",
|
||||
.signal_mask = 0x1,
|
||||
.hcalls = vlan_hcalls,
|
||||
.qdev.name = "spapr-vlan",
|
||||
.qdev.size = sizeof(VIOsPAPRVLANDevice),
|
||||
.qdev.props = (Property[]) {
|
||||
@ -504,5 +493,11 @@ static VIOsPAPRDeviceInfo spapr_vlan = {
|
||||
static void spapr_vlan_register(void)
|
||||
{
|
||||
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);
|
||||
|
127
hw/spapr_vio.c
127
hw/spapr_vio.c
@ -621,11 +621,43 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
|
||||
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)
|
||||
{
|
||||
VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
|
||||
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
|
||||
char *id;
|
||||
int ret;
|
||||
|
||||
ret = spapr_vio_check_reg(dev, info);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Don't overwrite ids assigned on the command line */
|
||||
if (!dev->qdev.id) {
|
||||
@ -684,7 +716,6 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
|
||||
VIOsPAPRBus *bus;
|
||||
BusState *qbus;
|
||||
DeviceState *dev;
|
||||
DeviceInfo *qinfo;
|
||||
|
||||
/* Create bridge device */
|
||||
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("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;
|
||||
}
|
||||
|
||||
@ -749,21 +768,95 @@ static void spapr_vio_register_devices(void)
|
||||
device_init(spapr_vio_register_devices)
|
||||
|
||||
#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)
|
||||
{
|
||||
DeviceState *qdev;
|
||||
int ret = 0;
|
||||
DeviceState *qdev, **qdevs;
|
||||
int i, num, ret = 0;
|
||||
|
||||
/* Count qdevs on the bus list */
|
||||
num = 0;
|
||||
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);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
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 */
|
||||
|
@ -75,7 +75,6 @@ typedef struct {
|
||||
const char *dt_name, *dt_type, *dt_compatible;
|
||||
target_ulong signal_mask;
|
||||
int (*init)(VIOsPAPRDevice *dev);
|
||||
void (*hcalls)(VIOsPAPRBus *bus);
|
||||
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
|
||||
} 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 void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info);
|
||||
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);
|
||||
|
||||
@ -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_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);
|
||||
void spapr_vio_quiesce(void);
|
||||
|
||||
|
@ -135,18 +135,11 @@ void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev)
|
||||
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 = {
|
||||
.init = spapr_vty_init,
|
||||
.dt_name = "vty",
|
||||
.dt_type = "serial",
|
||||
.dt_compatible = "hvterm1",
|
||||
.hcalls = vty_hcalls,
|
||||
.qdev.name = "spapr-vty",
|
||||
.qdev.size = sizeof(VIOsPAPRVTYDevice),
|
||||
.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)
|
||||
{
|
||||
VIOsPAPRDevice *sdev;
|
||||
|
||||
sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
|
||||
if (!sdev && reg == 0) {
|
||||
DeviceState *qdev;
|
||||
|
||||
/* Hack for kernel early debug, which always specifies reg==0.
|
||||
* We search all VIO devices, and grab the first available vty
|
||||
* device. This attempts to mimic existing PowerVM behaviour
|
||||
* We search all VIO devices, and grab the vty with the lowest
|
||||
* reg. This attempts to mimic existing PowerVM behaviour
|
||||
* (early debug does work there, despite having no vty with
|
||||
* reg==0. */
|
||||
QTAILQ_FOREACH(qdev, &spapr->vio_bus->bus.children, sibling) {
|
||||
if (qdev->info == &spapr_vty.qdev) {
|
||||
return DO_UPCAST(VIOsPAPRDevice, qdev, qdev);
|
||||
}
|
||||
}
|
||||
return spapr_vty_get_default(spapr->vio_bus);
|
||||
}
|
||||
|
||||
return sdev;
|
||||
@ -182,5 +204,7 @@ static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
|
||||
static void spapr_vty_register(void)
|
||||
{
|
||||
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);
|
||||
|
@ -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)
|
||||
{
|
||||
switch (env->mmu_model) {
|
||||
case POWERPC_MMU_BOOKE206:
|
||||
mmubooke206_dump_mmu(f, cpu_fprintf, env);
|
||||
break;
|
||||
#if defined(TARGET_PPC64)
|
||||
case POWERPC_MMU_64B:
|
||||
case POWERPC_MMU_2_06:
|
||||
mmubooks_dump_mmu(f, cpu_fprintf, env);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
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)
|
||||
{
|
||||
return 0;
|
||||
return env->halted;
|
||||
}
|
||||
|
||||
static int kvmppc_handle_halt(CPUState *env)
|
||||
|
@ -2,6 +2,7 @@
|
||||
* PowerPC CPU initialization for qemu.
|
||||
*
|
||||
* Copyright (c) 2003-2007 Jocelyn Mayer
|
||||
* Copyright 2011 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* 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 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)
|
||||
{
|
||||
uint32_t tlbncfg[2];
|
||||
@ -4430,15 +4458,26 @@ static void init_proc_e500 (CPUPPCState *env, int version)
|
||||
env->nb_ways = 2;
|
||||
env->id_tlbs = 0;
|
||||
switch (version) {
|
||||
case 1:
|
||||
case fsl_e500v1:
|
||||
/* e500v1 */
|
||||
tlbncfg[0] = gen_tlbncfg(2, 1, 1, 0, 256);
|
||||
tlbncfg[1] = gen_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
|
||||
env->dcache_line_size = 32;
|
||||
env->icache_line_size = 32;
|
||||
break;
|
||||
case 2:
|
||||
case fsl_e500v2:
|
||||
/* e500v2 */
|
||||
tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512);
|
||||
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;
|
||||
default:
|
||||
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
|
||||
|
||||
init_excp_e200(env);
|
||||
env->dcache_line_size = 32;
|
||||
env->icache_line_size = 32;
|
||||
/* Allocate hardware IRQ controller */
|
||||
ppce500_irq_init(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)
|
||||
{
|
||||
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 */
|
||||
@ -7070,6 +7112,7 @@ enum {
|
||||
CPU_POWERPC_e500v2_v21 = 0x80210021,
|
||||
CPU_POWERPC_e500v2_v22 = 0x80210022,
|
||||
CPU_POWERPC_e500v2_v30 = 0x80210030,
|
||||
CPU_POWERPC_e500mc = 0x80230020,
|
||||
/* MPC85xx microcontrollers */
|
||||
#define CPU_POWERPC_MPC8533 CPU_POWERPC_MPC8533_v11
|
||||
#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 e500v2 v3.0 core */
|
||||
POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2),
|
||||
POWERPC_DEF("e500mc", CPU_POWERPC_e500mc, e500mc),
|
||||
/* PowerPC e500 microcontrollers */
|
||||
/* MPC8533 */
|
||||
POWERPC_DEF_SVR("MPC8533",
|
||||
|
Loading…
Reference in New Issue
Block a user