Revision ee86dfee hw/spapr_vio.c

b/hw/spapr_vio.c
37 37
#endif /* CONFIG_FDT */
38 38

  
39 39
/* #define DEBUG_SPAPR */
40
/* #define DEBUG_TCE */
40 41

  
41 42
#ifdef DEBUG_SPAPR
42 43
#define dprintf(fmt, ...) \
......
115 116
        }
116 117
    }
117 118

  
119
    if (dev->rtce_window_size) {
120
        uint32_t dma_prop[] = {cpu_to_be32(dev->reg),
121
                               0, 0,
122
                               0, cpu_to_be32(dev->rtce_window_size)};
123

  
124
        ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2);
125
        if (ret < 0) {
126
            return ret;
127
        }
128

  
129
        ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2);
130
        if (ret < 0) {
131
            return ret;
132
        }
133

  
134
        ret = fdt_setprop(fdt, node_off, "ibm,my-dma-window", dma_prop,
135
                          sizeof(dma_prop));
136
        if (ret < 0) {
137
            return ret;
138
        }
139
    }
140

  
118 141
    if (info->devnode) {
119 142
        ret = (info->devnode)(dev, fdt, node_off);
120 143
        if (ret < 0) {
......
126 149
}
127 150
#endif /* CONFIG_FDT */
128 151

  
152
/*
153
 * RTCE handling
154
 */
155

  
156
static void rtce_init(VIOsPAPRDevice *dev)
157
{
158
    size_t size = (dev->rtce_window_size >> SPAPR_VIO_TCE_PAGE_SHIFT)
159
        * sizeof(VIOsPAPR_RTCE);
160

  
161
    if (size) {
162
        dev->rtce_table = qemu_mallocz(size);
163
    }
164
}
165

  
166
static target_ulong h_put_tce(CPUState *env, sPAPREnvironment *spapr,
167
                              target_ulong opcode, target_ulong *args)
168
{
169
    target_ulong liobn = args[0];
170
    target_ulong ioba = args[1];
171
    target_ulong tce = args[2];
172
    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, liobn);
173
    VIOsPAPR_RTCE *rtce;
174

  
175
    if (!dev) {
176
        hcall_dprintf("spapr_vio_put_tce on non-existent LIOBN "
177
                      TARGET_FMT_lx "\n", liobn);
178
        return H_PARAMETER;
179
    }
180

  
181
    ioba &= ~(SPAPR_VIO_TCE_PAGE_SIZE - 1);
182

  
183
#ifdef DEBUG_TCE
184
    fprintf(stderr, "spapr_vio_put_tce on %s  ioba 0x" TARGET_FMT_lx
185
            "  TCE 0x" TARGET_FMT_lx "\n", dev->qdev.id, ioba, tce);
186
#endif
187

  
188
    if (ioba >= dev->rtce_window_size) {
189
        hcall_dprintf("spapr_vio_put_tce on out-of-boards IOBA 0x"
190
                      TARGET_FMT_lx "\n", ioba);
191
        return H_PARAMETER;
192
    }
193

  
194
    rtce = dev->rtce_table + (ioba >> SPAPR_VIO_TCE_PAGE_SHIFT);
195
    rtce->tce = tce;
196

  
197
    return H_SUCCESS;
198
}
199

  
200
int spapr_vio_check_tces(VIOsPAPRDevice *dev, target_ulong ioba,
201
                         target_ulong len, enum VIOsPAPR_TCEAccess access)
202
{
203
    int start, end, i;
204

  
205
    start = ioba >> SPAPR_VIO_TCE_PAGE_SHIFT;
206
    end = (ioba + len - 1) >> SPAPR_VIO_TCE_PAGE_SHIFT;
207

  
208
    for (i = start; i <= end; i++) {
209
        if ((dev->rtce_table[i].tce & access) != access) {
210
#ifdef DEBUG_TCE
211
            fprintf(stderr, "FAIL on %d\n", i);
212
#endif
213
            return -1;
214
        }
215
    }
216

  
217
    return 0;
218
}
219

  
220
int spapr_tce_dma_write(VIOsPAPRDevice *dev, uint64_t taddr, const void *buf,
221
                        uint32_t size)
222
{
223
#ifdef DEBUG_TCE
224
    fprintf(stderr, "spapr_tce_dma_write taddr=0x%llx size=0x%x\n",
225
            (unsigned long long)taddr, size);
226
#endif
227

  
228
    while (size) {
229
        uint64_t tce;
230
        uint32_t lsize;
231
        uint64_t txaddr;
232

  
233
        /* Check if we are in bound */
234
        if (taddr >= dev->rtce_window_size) {
235
#ifdef DEBUG_TCE
236
            fprintf(stderr, "spapr_tce_dma_write out of bounds\n");
237
#endif
238
            return H_DEST_PARM;
239
        }
240
        tce = dev->rtce_table[taddr >> SPAPR_VIO_TCE_PAGE_SHIFT].tce;
241

  
242
        /* How much til end of page ? */
243
        lsize = MIN(size, ((~taddr) & SPAPR_VIO_TCE_PAGE_MASK) + 1);
244

  
245
        /* Check TCE */
246
        if (!(tce & 2)) {
247
            return H_DEST_PARM;
248
        }
249

  
250
        /* Translate */
251
        txaddr = (tce & ~SPAPR_VIO_TCE_PAGE_MASK) |
252
            (taddr & SPAPR_VIO_TCE_PAGE_MASK);
253

  
254
#ifdef DEBUG_TCE
255
        fprintf(stderr, " -> write to txaddr=0x%llx, size=0x%x\n",
256
                (unsigned long long)txaddr, lsize);
257
#endif
258

  
259
        /* Do it */
260
        cpu_physical_memory_write(txaddr, buf, lsize);
261
        buf += lsize;
262
        taddr += lsize;
263
        size -= lsize;
264
    }
265
    return 0;
266
}
267

  
268
int spapr_tce_dma_zero(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t size)
269
{
270
    /* FIXME: allocating a temp buffer is nasty, but just stepping
271
     * through writing zeroes is awkward.  This will do for now. */
272
    uint8_t zeroes[size];
273

  
274
#ifdef DEBUG_TCE
275
    fprintf(stderr, "spapr_tce_dma_zero taddr=0x%llx size=0x%x\n",
276
            (unsigned long long)taddr, size);
277
#endif
278

  
279
    memset(zeroes, 0, size);
280
    return spapr_tce_dma_write(dev, taddr, zeroes, size);
281
}
282

  
283
void stb_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint8_t val)
284
{
285
    spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
286
}
287

  
288
void sth_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint16_t val)
289
{
290
    val = tswap16(val);
291
    spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
292
}
293

  
294

  
295
void stw_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t val)
296
{
297
    val = tswap32(val);
298
    spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
299
}
300

  
301
void stq_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint64_t val)
302
{
303
    val = tswap64(val);
304
    spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
305
}
306

  
307
int spapr_tce_dma_read(VIOsPAPRDevice *dev, uint64_t taddr, void *buf,
308
                       uint32_t size)
309
{
310
#ifdef DEBUG_TCE
311
    fprintf(stderr, "spapr_tce_dma_write taddr=0x%llx size=0x%x\n",
312
            (unsigned long long)taddr, size);
313
#endif
314

  
315
    while (size) {
316
        uint64_t tce;
317
        uint32_t lsize;
318
        uint64_t txaddr;
319

  
320
        /* Check if we are in bound */
321
        if (taddr >= dev->rtce_window_size) {
322
#ifdef DEBUG_TCE
323
            fprintf(stderr, "spapr_tce_dma_read out of bounds\n");
324
#endif
325
            return H_DEST_PARM;
326
        }
327
        tce = dev->rtce_table[taddr >> SPAPR_VIO_TCE_PAGE_SHIFT].tce;
328

  
329
        /* How much til end of page ? */
330
        lsize = MIN(size, ((~taddr) & SPAPR_VIO_TCE_PAGE_MASK) + 1);
331

  
332
        /* Check TCE */
333
        if (!(tce & 1)) {
334
            return H_DEST_PARM;
335
        }
336

  
337
        /* Translate */
338
        txaddr = (tce & ~SPAPR_VIO_TCE_PAGE_MASK) |
339
            (taddr & SPAPR_VIO_TCE_PAGE_MASK);
340

  
341
#ifdef DEBUG_TCE
342
        fprintf(stderr, " -> write to txaddr=0x%llx, size=0x%x\n",
343
                (unsigned long long)txaddr, lsize);
344
#endif
345
        /* Do it */
346
        cpu_physical_memory_read(txaddr, buf, lsize);
347
        buf += lsize;
348
        taddr += lsize;
349
        size -= lsize;
350
    }
351
    return H_SUCCESS;
352
}
353

  
354
uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr)
355
{
356
    uint64_t val;
357

  
358
    spapr_tce_dma_read(dev, taddr, &val, sizeof(val));
359
    return tswap64(val);
360
}
361

  
129 362
static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
130 363
{
131 364
    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
......
138 371

  
139 372
    dev->qdev.id = id;
140 373

  
374
    rtce_init(dev);
375

  
141 376
    return info->init(dev);
142 377
}
143 378

  
......
193 428
    /* hcall-vio */
194 429
    spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
195 430

  
431
    /* hcall-tce */
432
    spapr_register_hypercall(H_PUT_TCE, h_put_tce);
433

  
196 434
    for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) {
197 435
        VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
198 436

  

Also available in: Unified diff