Statistics
| Branch: | Revision:

root / hw / ppce500_spin.c @ 37952117

History | View | Annotate | Download (5.7 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 5c145dac Alexander Graf
#include "sysemu.h"
32 5c145dac Alexander Graf
#include "sysbus.h"
33 5c145dac Alexander Graf
#include "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 5c145dac Alexander Graf
} __attribute__ ((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 e2684c0b Andreas Färber
    CPUPPCState *env;
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 5c145dac Alexander Graf
static inline target_phys_addr_t 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 5c145dac Alexander Graf
                                     target_phys_addr_t pa,
79 5c145dac Alexander Graf
                                     target_phys_addr_t len)
80 5c145dac Alexander Graf
{
81 5c145dac Alexander Graf
    ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1);
82 5c145dac Alexander Graf
    target_phys_addr_t 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 e2684c0b Andreas Färber
    CPUPPCState *env = kick->env;
96 5c145dac Alexander Graf
    SpinInfo *curspin = kick->spin;
97 5c145dac Alexander Graf
    target_phys_addr_t map_size = 64 * 1024 * 1024;
98 5c145dac Alexander Graf
    target_phys_addr_t map_start;
99 5c145dac Alexander Graf
100 5c145dac Alexander Graf
    cpu_synchronize_state(env);
101 5c145dac Alexander Graf
    stl_p(&curspin->pir, env->spr[SPR_PIR]);
102 5c145dac Alexander Graf
    env->nip = ldq_p(&curspin->addr) & (map_size - 1);
103 5c145dac Alexander Graf
    env->gpr[3] = ldq_p(&curspin->r3);
104 5c145dac Alexander Graf
    env->gpr[4] = 0;
105 5c145dac Alexander Graf
    env->gpr[5] = 0;
106 5c145dac Alexander Graf
    env->gpr[6] = 0;
107 5c145dac Alexander Graf
    env->gpr[7] = map_size;
108 5c145dac Alexander Graf
    env->gpr[8] = 0;
109 5c145dac Alexander Graf
    env->gpr[9] = 0;
110 5c145dac Alexander Graf
111 5c145dac Alexander Graf
    map_start = ldq_p(&curspin->addr) & ~(map_size - 1);
112 5c145dac Alexander Graf
    mmubooke_create_initial_mapping(env, 0, map_start, map_size);
113 5c145dac Alexander Graf
114 5c145dac Alexander Graf
    env->halted = 0;
115 5c145dac Alexander Graf
    env->exception_index = -1;
116 157feead Liu Yu-B13201
    env->stopped = 0;
117 5c145dac Alexander Graf
    qemu_cpu_kick(env);
118 5c145dac Alexander Graf
}
119 5c145dac Alexander Graf
120 5c145dac Alexander Graf
static void spin_write(void *opaque, target_phys_addr_t addr, uint64_t value,
121 5c145dac Alexander Graf
                       unsigned len)
122 5c145dac Alexander Graf
{
123 5c145dac Alexander Graf
    SpinState *s = opaque;
124 5c145dac Alexander Graf
    int env_idx = addr / sizeof(SpinInfo);
125 e2684c0b Andreas Färber
    CPUPPCState *env;
126 5c145dac Alexander Graf
    SpinInfo *curspin = &s->spin[env_idx];
127 5c145dac Alexander Graf
    uint8_t *curspin_p = (uint8_t*)curspin;
128 5c145dac Alexander Graf
129 5c145dac Alexander Graf
    for (env = first_cpu; env != NULL; env = env->next_cpu) {
130 5c145dac Alexander Graf
        if (env->cpu_index == env_idx) {
131 5c145dac Alexander Graf
            break;
132 5c145dac Alexander Graf
        }
133 5c145dac Alexander Graf
    }
134 5c145dac Alexander Graf
135 5c145dac Alexander Graf
    if (!env) {
136 5c145dac Alexander Graf
        /* Unknown CPU */
137 5c145dac Alexander Graf
        return;
138 5c145dac Alexander Graf
    }
139 5c145dac Alexander Graf
140 5c145dac Alexander Graf
    if (!env->cpu_index) {
141 5c145dac Alexander Graf
        /* primary CPU doesn't spin */
142 5c145dac Alexander Graf
        return;
143 5c145dac Alexander Graf
    }
144 5c145dac Alexander Graf
145 5c145dac Alexander Graf
    curspin_p = &curspin_p[addr % sizeof(SpinInfo)];
146 5c145dac Alexander Graf
    switch (len) {
147 5c145dac Alexander Graf
    case 1:
148 5c145dac Alexander Graf
        stb_p(curspin_p, value);
149 5c145dac Alexander Graf
        break;
150 5c145dac Alexander Graf
    case 2:
151 5c145dac Alexander Graf
        stw_p(curspin_p, value);
152 5c145dac Alexander Graf
        break;
153 5c145dac Alexander Graf
    case 4:
154 5c145dac Alexander Graf
        stl_p(curspin_p, value);
155 5c145dac Alexander Graf
        break;
156 5c145dac Alexander Graf
    }
157 5c145dac Alexander Graf
158 5c145dac Alexander Graf
    if (!(ldq_p(&curspin->addr) & 1)) {
159 5c145dac Alexander Graf
        /* run CPU */
160 5c145dac Alexander Graf
        SpinKick kick = {
161 5c145dac Alexander Graf
            .env = env,
162 5c145dac Alexander Graf
            .spin = curspin,
163 5c145dac Alexander Graf
        };
164 5c145dac Alexander Graf
165 5c145dac Alexander Graf
        run_on_cpu(env, spin_kick, &kick);
166 5c145dac Alexander Graf
    }
167 5c145dac Alexander Graf
}
168 5c145dac Alexander Graf
169 5c145dac Alexander Graf
static uint64_t spin_read(void *opaque, target_phys_addr_t addr, unsigned len)
170 5c145dac Alexander Graf
{
171 5c145dac Alexander Graf
    SpinState *s = opaque;
172 5c145dac Alexander Graf
    uint8_t *spin_p = &((uint8_t*)s->spin)[addr];
173 5c145dac Alexander Graf
174 5c145dac Alexander Graf
    switch (len) {
175 5c145dac Alexander Graf
    case 1:
176 5c145dac Alexander Graf
        return ldub_p(spin_p);
177 5c145dac Alexander Graf
    case 2:
178 5c145dac Alexander Graf
        return lduw_p(spin_p);
179 5c145dac Alexander Graf
    case 4:
180 5c145dac Alexander Graf
        return ldl_p(spin_p);
181 5c145dac Alexander Graf
    default:
182 5f2c23e6 Stefan Weil
        hw_error("ppce500: unexpected %s with len = %u", __func__, len);
183 5c145dac Alexander Graf
    }
184 5c145dac Alexander Graf
}
185 5c145dac Alexander Graf
186 b7c28f02 Stefan Weil
static const MemoryRegionOps spin_rw_ops = {
187 5c145dac Alexander Graf
    .read = spin_read,
188 5c145dac Alexander Graf
    .write = spin_write,
189 5c145dac Alexander Graf
    .endianness = DEVICE_BIG_ENDIAN,
190 5c145dac Alexander Graf
};
191 5c145dac Alexander Graf
192 5c145dac Alexander Graf
static int ppce500_spin_initfn(SysBusDevice *dev)
193 5c145dac Alexander Graf
{
194 5c145dac Alexander Graf
    SpinState *s;
195 5c145dac Alexander Graf
196 5c145dac Alexander Graf
    s = FROM_SYSBUS(SpinState, sysbus_from_qdev(dev));
197 5c145dac Alexander Graf
198 5c145dac Alexander Graf
    memory_region_init_io(&s->iomem, &spin_rw_ops, s, "e500 spin pv device",
199 5c145dac Alexander Graf
                          sizeof(SpinInfo) * MAX_CPUS);
200 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->iomem);
201 5c145dac Alexander Graf
202 5c145dac Alexander Graf
    qemu_register_reset(spin_reset, s);
203 5c145dac Alexander Graf
204 5c145dac Alexander Graf
    return 0;
205 5c145dac Alexander Graf
}
206 5c145dac Alexander Graf
207 999e12bb Anthony Liguori
static void ppce500_spin_class_init(ObjectClass *klass, void *data)
208 999e12bb Anthony Liguori
{
209 999e12bb Anthony Liguori
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
210 999e12bb Anthony Liguori
211 999e12bb Anthony Liguori
    k->init = ppce500_spin_initfn;
212 999e12bb Anthony Liguori
}
213 999e12bb Anthony Liguori
214 39bffca2 Anthony Liguori
static TypeInfo ppce500_spin_info = {
215 39bffca2 Anthony Liguori
    .name          = "e500-spin",
216 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
217 39bffca2 Anthony Liguori
    .instance_size = sizeof(SpinState),
218 39bffca2 Anthony Liguori
    .class_init    = ppce500_spin_class_init,
219 5c145dac Alexander Graf
};
220 5c145dac Alexander Graf
221 83f7d43a Andreas Färber
static void ppce500_spin_register_types(void)
222 5c145dac Alexander Graf
{
223 39bffca2 Anthony Liguori
    type_register_static(&ppce500_spin_info);
224 5c145dac Alexander Graf
}
225 83f7d43a Andreas Färber
226 83f7d43a Andreas Färber
type_init(ppce500_spin_register_types)