Statistics
| Branch: | Revision:

root / hw / ppce500_spin.c @ 26ca8c06

History | View | Annotate | Download (5.6 kB)

1 5c145dac Alexander Graf
/*
2 5c145dac Alexander Graf
 * QEMU PowerPC e500v2 ePAPR spinning code
3 5c145dac Alexander Graf
 *
4 5c145dac Alexander Graf
 * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
5 5c145dac Alexander Graf
 *
6 5c145dac Alexander Graf
 * Author: Alexander Graf, <agraf@suse.de>
7 5c145dac Alexander Graf
 *
8 5c145dac Alexander Graf
 * This library is free software; you can redistribute it and/or
9 5c145dac Alexander Graf
 * modify it under the terms of the GNU Lesser General Public
10 5c145dac Alexander Graf
 * License as published by the Free Software Foundation; either
11 5c145dac Alexander Graf
 * version 2 of the License, or (at your option) any later version.
12 5c145dac Alexander Graf
 *
13 5c145dac Alexander Graf
 * This library is distributed in the hope that it will be useful,
14 5c145dac Alexander Graf
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 5c145dac Alexander Graf
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 5c145dac Alexander Graf
 * Lesser General Public License for more details.
17 5c145dac Alexander Graf
 *
18 5c145dac Alexander Graf
 * You should have received a copy of the GNU Lesser General Public
19 5c145dac Alexander Graf
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 5c145dac Alexander Graf
 *
21 5c145dac Alexander Graf
 * This code is not really a device, but models an interface that usually
22 5c145dac Alexander Graf
 * firmware takes care of. It's used when QEMU plays the role of firmware.
23 5c145dac Alexander Graf
 *
24 5c145dac Alexander Graf
 * Specification:
25 5c145dac Alexander Graf
 *
26 5c145dac Alexander Graf
 * https://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.1.pdf
27 5c145dac Alexander Graf
 *
28 5c145dac Alexander Graf
 */
29 5c145dac Alexander Graf
30 5c145dac Alexander Graf
#include "hw.h"
31 9c17d615 Paolo Bonzini
#include "sysemu/sysemu.h"
32 5c145dac Alexander Graf
#include "sysbus.h"
33 9c17d615 Paolo Bonzini
#include "sysemu/kvm.h"
34 5c145dac Alexander Graf
35 5c145dac Alexander Graf
#define MAX_CPUS 32
36 5c145dac Alexander Graf
37 5c145dac Alexander Graf
typedef struct spin_info {
38 5c145dac Alexander Graf
    uint64_t addr;
39 5c145dac Alexander Graf
    uint64_t r3;
40 5c145dac Alexander Graf
    uint32_t resv;
41 5c145dac Alexander Graf
    uint32_t pir;
42 5c145dac Alexander Graf
    uint64_t reserved;
43 7c7bb022 Stefan Weil
} QEMU_PACKED SpinInfo;
44 5c145dac Alexander Graf
45 5c145dac Alexander Graf
typedef struct spin_state {
46 5c145dac Alexander Graf
    SysBusDevice busdev;
47 5c145dac Alexander Graf
    MemoryRegion iomem;
48 5c145dac Alexander Graf
    SpinInfo spin[MAX_CPUS];
49 5c145dac Alexander Graf
} SpinState;
50 5c145dac Alexander Graf
51 5c145dac Alexander Graf
typedef struct spin_kick {
52 b6444a42 Andreas Färber
    PowerPCCPU *cpu;
53 5c145dac Alexander Graf
    SpinInfo *spin;
54 5c145dac Alexander Graf
} SpinKick;
55 5c145dac Alexander Graf
56 5c145dac Alexander Graf
static void spin_reset(void *opaque)
57 5c145dac Alexander Graf
{
58 5c145dac Alexander Graf
    SpinState *s = opaque;
59 5c145dac Alexander Graf
    int i;
60 5c145dac Alexander Graf
61 5c145dac Alexander Graf
    for (i = 0; i < MAX_CPUS; i++) {
62 5c145dac Alexander Graf
        SpinInfo *info = &s->spin[i];
63 5c145dac Alexander Graf
64 5c145dac Alexander Graf
        info->pir = i;
65 5c145dac Alexander Graf
        info->r3 = i;
66 5c145dac Alexander Graf
        info->addr = 1;
67 5c145dac Alexander Graf
    }
68 5c145dac Alexander Graf
}
69 5c145dac Alexander Graf
70 5c145dac Alexander Graf
/* Create -kernel TLB entries for BookE, linearly spanning 256MB.  */
71 a8170e5e Avi Kivity
static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
72 5c145dac Alexander Graf
{
73 5c145dac Alexander Graf
    return (ffs(size >> 10) - 1) >> 1;
74 5c145dac Alexander Graf
}
75 5c145dac Alexander Graf
76 e2684c0b Andreas Färber
static void mmubooke_create_initial_mapping(CPUPPCState *env,
77 5c145dac Alexander Graf
                                     target_ulong va,
78 a8170e5e Avi Kivity
                                     hwaddr pa,
79 a8170e5e Avi Kivity
                                     hwaddr len)
80 5c145dac Alexander Graf
{
81 5c145dac Alexander Graf
    ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1);
82 a8170e5e Avi Kivity
    hwaddr size;
83 5c145dac Alexander Graf
84 5c145dac Alexander Graf
    size = (booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT);
85 5c145dac Alexander Graf
    tlb->mas1 = MAS1_VALID | size;
86 5c145dac Alexander Graf
    tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M;
87 5c145dac Alexander Graf
    tlb->mas7_3 = pa & TARGET_PAGE_MASK;
88 5c145dac Alexander Graf
    tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
89 58f90f21 Bharat Bhushan
    env->tlb_dirty = true;
90 5c145dac Alexander Graf
}
91 5c145dac Alexander Graf
92 5c145dac Alexander Graf
static void spin_kick(void *data)
93 5c145dac Alexander Graf
{
94 5c145dac Alexander Graf
    SpinKick *kick = data;
95 f324e766 Andreas Färber
    CPUState *cpu = CPU(kick->cpu);
96 b6444a42 Andreas Färber
    CPUPPCState *env = &kick->cpu->env;
97 5c145dac Alexander Graf
    SpinInfo *curspin = kick->spin;
98 a8170e5e Avi Kivity
    hwaddr map_size = 64 * 1024 * 1024;
99 a8170e5e Avi Kivity
    hwaddr map_start;
100 5c145dac Alexander Graf
101 5c145dac Alexander Graf
    cpu_synchronize_state(env);
102 5c145dac Alexander Graf
    stl_p(&curspin->pir, env->spr[SPR_PIR]);
103 5c145dac Alexander Graf
    env->nip = ldq_p(&curspin->addr) & (map_size - 1);
104 5c145dac Alexander Graf
    env->gpr[3] = ldq_p(&curspin->r3);
105 5c145dac Alexander Graf
    env->gpr[4] = 0;
106 5c145dac Alexander Graf
    env->gpr[5] = 0;
107 5c145dac Alexander Graf
    env->gpr[6] = 0;
108 5c145dac Alexander Graf
    env->gpr[7] = map_size;
109 5c145dac Alexander Graf
    env->gpr[8] = 0;
110 5c145dac Alexander Graf
    env->gpr[9] = 0;
111 5c145dac Alexander Graf
112 5c145dac Alexander Graf
    map_start = ldq_p(&curspin->addr) & ~(map_size - 1);
113 5c145dac Alexander Graf
    mmubooke_create_initial_mapping(env, 0, map_start, map_size);
114 5c145dac Alexander Graf
115 5c145dac Alexander Graf
    env->halted = 0;
116 5c145dac Alexander Graf
    env->exception_index = -1;
117 f324e766 Andreas Färber
    cpu->stopped = false;
118 c08d7424 Andreas Färber
    qemu_cpu_kick(cpu);
119 5c145dac Alexander Graf
}
120 5c145dac Alexander Graf
121 a8170e5e Avi Kivity
static void spin_write(void *opaque, hwaddr addr, uint64_t value,
122 5c145dac Alexander Graf
                       unsigned len)
123 5c145dac Alexander Graf
{
124 5c145dac Alexander Graf
    SpinState *s = opaque;
125 5c145dac Alexander Graf
    int env_idx = addr / sizeof(SpinInfo);
126 e2684c0b Andreas Färber
    CPUPPCState *env;
127 5c145dac Alexander Graf
    SpinInfo *curspin = &s->spin[env_idx];
128 5c145dac Alexander Graf
    uint8_t *curspin_p = (uint8_t*)curspin;
129 5c145dac Alexander Graf
130 5c145dac Alexander Graf
    for (env = first_cpu; env != NULL; env = env->next_cpu) {
131 5c145dac Alexander Graf
        if (env->cpu_index == env_idx) {
132 5c145dac Alexander Graf
            break;
133 5c145dac Alexander Graf
        }
134 5c145dac Alexander Graf
    }
135 5c145dac Alexander Graf
136 5c145dac Alexander Graf
    if (!env) {
137 5c145dac Alexander Graf
        /* Unknown CPU */
138 5c145dac Alexander Graf
        return;
139 5c145dac Alexander Graf
    }
140 5c145dac Alexander Graf
141 5c145dac Alexander Graf
    if (!env->cpu_index) {
142 5c145dac Alexander Graf
        /* primary CPU doesn't spin */
143 5c145dac Alexander Graf
        return;
144 5c145dac Alexander Graf
    }
145 5c145dac Alexander Graf
146 5c145dac Alexander Graf
    curspin_p = &curspin_p[addr % sizeof(SpinInfo)];
147 5c145dac Alexander Graf
    switch (len) {
148 5c145dac Alexander Graf
    case 1:
149 5c145dac Alexander Graf
        stb_p(curspin_p, value);
150 5c145dac Alexander Graf
        break;
151 5c145dac Alexander Graf
    case 2:
152 5c145dac Alexander Graf
        stw_p(curspin_p, value);
153 5c145dac Alexander Graf
        break;
154 5c145dac Alexander Graf
    case 4:
155 5c145dac Alexander Graf
        stl_p(curspin_p, value);
156 5c145dac Alexander Graf
        break;
157 5c145dac Alexander Graf
    }
158 5c145dac Alexander Graf
159 5c145dac Alexander Graf
    if (!(ldq_p(&curspin->addr) & 1)) {
160 5c145dac Alexander Graf
        /* run CPU */
161 5c145dac Alexander Graf
        SpinKick kick = {
162 b6444a42 Andreas Färber
            .cpu = ppc_env_get_cpu(env),
163 5c145dac Alexander Graf
            .spin = curspin,
164 5c145dac Alexander Graf
        };
165 5c145dac Alexander Graf
166 f100f0b3 Andreas Färber
        run_on_cpu(CPU(kick.cpu), spin_kick, &kick);
167 5c145dac Alexander Graf
    }
168 5c145dac Alexander Graf
}
169 5c145dac Alexander Graf
170 a8170e5e Avi Kivity
static uint64_t spin_read(void *opaque, hwaddr addr, unsigned len)
171 5c145dac Alexander Graf
{
172 5c145dac Alexander Graf
    SpinState *s = opaque;
173 5c145dac Alexander Graf
    uint8_t *spin_p = &((uint8_t*)s->spin)[addr];
174 5c145dac Alexander Graf
175 5c145dac Alexander Graf
    switch (len) {
176 5c145dac Alexander Graf
    case 1:
177 5c145dac Alexander Graf
        return ldub_p(spin_p);
178 5c145dac Alexander Graf
    case 2:
179 5c145dac Alexander Graf
        return lduw_p(spin_p);
180 5c145dac Alexander Graf
    case 4:
181 5c145dac Alexander Graf
        return ldl_p(spin_p);
182 5c145dac Alexander Graf
    default:
183 5f2c23e6 Stefan Weil
        hw_error("ppce500: unexpected %s with len = %u", __func__, len);
184 5c145dac Alexander Graf
    }
185 5c145dac Alexander Graf
}
186 5c145dac Alexander Graf
187 b7c28f02 Stefan Weil
static const MemoryRegionOps spin_rw_ops = {
188 5c145dac Alexander Graf
    .read = spin_read,
189 5c145dac Alexander Graf
    .write = spin_write,
190 5c145dac Alexander Graf
    .endianness = DEVICE_BIG_ENDIAN,
191 5c145dac Alexander Graf
};
192 5c145dac Alexander Graf
193 5c145dac Alexander Graf
static int ppce500_spin_initfn(SysBusDevice *dev)
194 5c145dac Alexander Graf
{
195 5c145dac Alexander Graf
    SpinState *s;
196 5c145dac Alexander Graf
197 5c145dac Alexander Graf
    s = FROM_SYSBUS(SpinState, sysbus_from_qdev(dev));
198 5c145dac Alexander Graf
199 5c145dac Alexander Graf
    memory_region_init_io(&s->iomem, &spin_rw_ops, s, "e500 spin pv device",
200 5c145dac Alexander Graf
                          sizeof(SpinInfo) * MAX_CPUS);
201 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->iomem);
202 5c145dac Alexander Graf
203 5c145dac Alexander Graf
    qemu_register_reset(spin_reset, s);
204 5c145dac Alexander Graf
205 5c145dac Alexander Graf
    return 0;
206 5c145dac Alexander Graf
}
207 5c145dac Alexander Graf
208 999e12bb Anthony Liguori
static void ppce500_spin_class_init(ObjectClass *klass, void *data)
209 999e12bb Anthony Liguori
{
210 999e12bb Anthony Liguori
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
211 999e12bb Anthony Liguori
212 999e12bb Anthony Liguori
    k->init = ppce500_spin_initfn;
213 999e12bb Anthony Liguori
}
214 999e12bb Anthony Liguori
215 8c43a6f0 Andreas Färber
static const TypeInfo ppce500_spin_info = {
216 39bffca2 Anthony Liguori
    .name          = "e500-spin",
217 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
218 39bffca2 Anthony Liguori
    .instance_size = sizeof(SpinState),
219 39bffca2 Anthony Liguori
    .class_init    = ppce500_spin_class_init,
220 5c145dac Alexander Graf
};
221 5c145dac Alexander Graf
222 83f7d43a Andreas Färber
static void ppce500_spin_register_types(void)
223 5c145dac Alexander Graf
{
224 39bffca2 Anthony Liguori
    type_register_static(&ppce500_spin_info);
225 5c145dac Alexander Graf
}
226 83f7d43a Andreas Färber
227 83f7d43a Andreas Färber
type_init(ppce500_spin_register_types)