/*
* Copyright (C) 2013 Martin Peres <martin.peres@free.fr>
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/* Usage: gcc -g sw_mth_test.c `pkg-config --libs --cflags libdrm_nouveau`&& ./a.out */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <assert.h>
#include "nouveau_local.h"
#include <sched.h>
#define SUBC_SW(m) 7, (m)
#define NV01_SUBCHAN_OBJECT 0x00000000
#define NV50_MAX_COUNTERS 12
#define RING_SIZE 9
#define TIMEOUT 1e6
int main()
{
struct nouveau_device *dev;
struct nouveau_client *client;
struct nouveau_object *channel;
struct nouveau_pushbuf *push;
struct nouveau_object *query;
struct nouveau_object *nvsw;
struct nouveau_bo *notify;
struct nv04_fifo *fifo;
struct nv04_fifo nv04_data = { .vram = 0xbeef0201, .gart = 0xbeef0202 };
uint32_t *nvsw_map;
int ret, fd, i, e, offset;
uint64_t cnt;
fd = open("/dev/dri/renderD129", O_RDWR);
assert(fd > 0);
assert(!nouveau_device_wrap(fd, 0, &dev));
assert(!nouveau_client_new(dev, &client));
assert(!nouveau_object_new(&dev->object, 0, NOUVEAU_FIFO_CHANNEL_CLASS,
&nv04_data, sizeof(nv04_data), &channel));
assert(!nouveau_pushbuf_new(client, channel, 1, 4000, 1, &push));
assert(!nouveau_object_new(channel, 0xD8000100, NOUVEAU_NOTIFIER_CLASS,
&(struct nv04_notify){ .length = 1300 },
sizeof(struct nv04_notify), &query));
assert(!nouveau_object_new(channel, 0xbeef506e, 0x506e, NULL, 0, &nvsw));
fifo = channel->data;
assert(!nouveau_bo_wrap(dev, fifo->notify, ¬ify));
assert(!nouveau_bo_map(notify, 0, client));
nvsw_map = notify->map + ((struct nv04_notify*)query->data)->offset;
nvsw_map[0] = 0x42;
BEGIN_NV04(push, SUBC_SW(NV01_SUBCHAN_OBJECT), 1);
PUSH_DATA (push, nvsw->handle);
BEGIN_NV04(push, SUBC_SW(0x0600), 1);
PUSH_DATA (push, query->handle);
BEGIN_NV04(push, SUBC_SW(0x0604), 1);
PUSH_DATA (push, RING_SIZE);
BEGIN_NV04(push, SUBC_SW(0x0608), 1);
PUSH_DATA (push, 0xa);
BEGIN_NV04(push, SUBC_SW(0x060c), 1);
PUSH_DATA (push, 0);
//BEGIN_NV04(push, SUBC_SW(0x0610), 1);
//PUSH_DATA (push, 0);
PUSH_KICK (push);
#if 1
for (i = 0; i < 1000 * RING_SIZE; i++) {
/*
BEGIN_NV04(push, SUBC_SW(0x060c), 1);
PUSH_DATA (push, 0);
PUSH_KICK (push);
*/
BEGIN_NV04(push, SUBC_SW(0x0608), 1);
PUSH_DATA (push, i);
PUSH_KICK (push);
cnt = 0;
offset = (1 + (i % RING_SIZE) * NV50_MAX_COUNTERS * 3);
printf("seq %u: ", i);
while (nvsw_map[0] != i && cnt < TIMEOUT) {
cnt++;
sched_yield();
}
uint32_t read_seq = nvsw_map[offset];
if (cnt < TIMEOUT && read_seq == i)
printf("OK\n");
else if (cnt < TIMEOUT) {
printf("NOK (nvsw_map[offset = %u] == %u)\n", offset * 4, read_seq);
return 1;
} else {
printf("TIMEOUT");
return 1;
}
}
#endif
#if 0
/* stress test */
for (e = 0; e < 1000; e++) {
uint32_t size = 1;
assert(PUSH_SPACE(push, size * 2));
assert(PUSH_AVAIL(push) >= size * 2);
for (i = 0; i < size; i++) {
BEGIN_NV04(push, SUBC_SW(0x0608), 1);
PUSH_DATA (push, e * 100 + i);
}
PUSH_KICK (push);
}
#endif
return 0;
}