Statistics
| Branch: | Revision:

root / hw / ppce500_spin.c @ a0f42610

History | View | Annotate | Download (5.4 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 5c145dac Alexander Graf
    CPUState *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 5c145dac Alexander Graf
static void mmubooke_create_initial_mapping(CPUState *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 5c145dac Alexander Graf
}
90 5c145dac Alexander Graf
91 5c145dac Alexander Graf
static void spin_kick(void *data)
92 5c145dac Alexander Graf
{
93 5c145dac Alexander Graf
    SpinKick *kick = data;
94 5c145dac Alexander Graf
    CPUState *env = kick->env;
95 5c145dac Alexander Graf
    SpinInfo *curspin = kick->spin;
96 5c145dac Alexander Graf
    target_phys_addr_t map_size = 64 * 1024 * 1024;
97 5c145dac Alexander Graf
    target_phys_addr_t map_start;
98 5c145dac Alexander Graf
99 5c145dac Alexander Graf
    cpu_synchronize_state(env);
100 5c145dac Alexander Graf
    stl_p(&curspin->pir, env->spr[SPR_PIR]);
101 5c145dac Alexander Graf
    env->nip = ldq_p(&curspin->addr) & (map_size - 1);
102 5c145dac Alexander Graf
    env->gpr[3] = ldq_p(&curspin->r3);
103 5c145dac Alexander Graf
    env->gpr[4] = 0;
104 5c145dac Alexander Graf
    env->gpr[5] = 0;
105 5c145dac Alexander Graf
    env->gpr[6] = 0;
106 5c145dac Alexander Graf
    env->gpr[7] = map_size;
107 5c145dac Alexander Graf
    env->gpr[8] = 0;
108 5c145dac Alexander Graf
    env->gpr[9] = 0;
109 5c145dac Alexander Graf
110 5c145dac Alexander Graf
    map_start = ldq_p(&curspin->addr) & ~(map_size - 1);
111 5c145dac Alexander Graf
    mmubooke_create_initial_mapping(env, 0, map_start, map_size);
112 5c145dac Alexander Graf
113 5c145dac Alexander Graf
    env->halted = 0;
114 5c145dac Alexander Graf
    env->exception_index = -1;
115 157feead Liu Yu-B13201
    env->stopped = 0;
116 5c145dac Alexander Graf
    qemu_cpu_kick(env);
117 5c145dac Alexander Graf
}
118 5c145dac Alexander Graf
119 5c145dac Alexander Graf
static void spin_write(void *opaque, target_phys_addr_t addr, uint64_t value,
120 5c145dac Alexander Graf
                       unsigned len)
121 5c145dac Alexander Graf
{
122 5c145dac Alexander Graf
    SpinState *s = opaque;
123 5c145dac Alexander Graf
    int env_idx = addr / sizeof(SpinInfo);
124 5c145dac Alexander Graf
    CPUState *env;
125 5c145dac Alexander Graf
    SpinInfo *curspin = &s->spin[env_idx];
126 5c145dac Alexander Graf
    uint8_t *curspin_p = (uint8_t*)curspin;
127 5c145dac Alexander Graf
128 5c145dac Alexander Graf
    for (env = first_cpu; env != NULL; env = env->next_cpu) {
129 5c145dac Alexander Graf
        if (env->cpu_index == env_idx) {
130 5c145dac Alexander Graf
            break;
131 5c145dac Alexander Graf
        }
132 5c145dac Alexander Graf
    }
133 5c145dac Alexander Graf
134 5c145dac Alexander Graf
    if (!env) {
135 5c145dac Alexander Graf
        /* Unknown CPU */
136 5c145dac Alexander Graf
        return;
137 5c145dac Alexander Graf
    }
138 5c145dac Alexander Graf
139 5c145dac Alexander Graf
    if (!env->cpu_index) {
140 5c145dac Alexander Graf
        /* primary CPU doesn't spin */
141 5c145dac Alexander Graf
        return;
142 5c145dac Alexander Graf
    }
143 5c145dac Alexander Graf
144 5c145dac Alexander Graf
    curspin_p = &curspin_p[addr % sizeof(SpinInfo)];
145 5c145dac Alexander Graf
    switch (len) {
146 5c145dac Alexander Graf
    case 1:
147 5c145dac Alexander Graf
        stb_p(curspin_p, value);
148 5c145dac Alexander Graf
        break;
149 5c145dac Alexander Graf
    case 2:
150 5c145dac Alexander Graf
        stw_p(curspin_p, value);
151 5c145dac Alexander Graf
        break;
152 5c145dac Alexander Graf
    case 4:
153 5c145dac Alexander Graf
        stl_p(curspin_p, value);
154 5c145dac Alexander Graf
        break;
155 5c145dac Alexander Graf
    }
156 5c145dac Alexander Graf
157 5c145dac Alexander Graf
    if (!(ldq_p(&curspin->addr) & 1)) {
158 5c145dac Alexander Graf
        /* run CPU */
159 5c145dac Alexander Graf
        SpinKick kick = {
160 5c145dac Alexander Graf
            .env = env,
161 5c145dac Alexander Graf
            .spin = curspin,
162 5c145dac Alexander Graf
        };
163 5c145dac Alexander Graf
164 5c145dac Alexander Graf
        run_on_cpu(env, spin_kick, &kick);
165 5c145dac Alexander Graf
    }
166 5c145dac Alexander Graf
}
167 5c145dac Alexander Graf
168 5c145dac Alexander Graf
static uint64_t spin_read(void *opaque, target_phys_addr_t addr, unsigned len)
169 5c145dac Alexander Graf
{
170 5c145dac Alexander Graf
    SpinState *s = opaque;
171 5c145dac Alexander Graf
    uint8_t *spin_p = &((uint8_t*)s->spin)[addr];
172 5c145dac Alexander Graf
173 5c145dac Alexander Graf
    switch (len) {
174 5c145dac Alexander Graf
    case 1:
175 5c145dac Alexander Graf
        return ldub_p(spin_p);
176 5c145dac Alexander Graf
    case 2:
177 5c145dac Alexander Graf
        return lduw_p(spin_p);
178 5c145dac Alexander Graf
    case 4:
179 5c145dac Alexander Graf
        return ldl_p(spin_p);
180 5c145dac Alexander Graf
    default:
181 5c145dac Alexander Graf
        assert(0);
182 5c145dac Alexander Graf
    }
183 5c145dac Alexander Graf
}
184 5c145dac Alexander Graf
185 5c145dac Alexander Graf
const MemoryRegionOps spin_rw_ops = {
186 5c145dac Alexander Graf
    .read = spin_read,
187 5c145dac Alexander Graf
    .write = spin_write,
188 5c145dac Alexander Graf
    .endianness = DEVICE_BIG_ENDIAN,
189 5c145dac Alexander Graf
};
190 5c145dac Alexander Graf
191 5c145dac Alexander Graf
static int ppce500_spin_initfn(SysBusDevice *dev)
192 5c145dac Alexander Graf
{
193 5c145dac Alexander Graf
    SpinState *s;
194 5c145dac Alexander Graf
195 5c145dac Alexander Graf
    s = FROM_SYSBUS(SpinState, sysbus_from_qdev(dev));
196 5c145dac Alexander Graf
197 5c145dac Alexander Graf
    memory_region_init_io(&s->iomem, &spin_rw_ops, s, "e500 spin pv device",
198 5c145dac Alexander Graf
                          sizeof(SpinInfo) * MAX_CPUS);
199 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->iomem);
200 5c145dac Alexander Graf
201 5c145dac Alexander Graf
    qemu_register_reset(spin_reset, s);
202 5c145dac Alexander Graf
203 5c145dac Alexander Graf
    return 0;
204 5c145dac Alexander Graf
}
205 5c145dac Alexander Graf
206 5c145dac Alexander Graf
static SysBusDeviceInfo ppce500_spin_info = {
207 5c145dac Alexander Graf
    .init         = ppce500_spin_initfn,
208 5c145dac Alexander Graf
    .qdev.name    = "e500-spin",
209 5c145dac Alexander Graf
    .qdev.size    = sizeof(SpinState),
210 5c145dac Alexander Graf
};
211 5c145dac Alexander Graf
212 5c145dac Alexander Graf
static void ppce500_spin_register(void)
213 5c145dac Alexander Graf
{
214 5c145dac Alexander Graf
    sysbus_register_withprop(&ppce500_spin_info);
215 5c145dac Alexander Graf
}
216 5c145dac Alexander Graf
device_init(ppce500_spin_register);