1/*
2 * Copyright 2014 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs <bskeggs@redhat.com>
23 */
24
25#include "nouveau_copy.h"
26
27void
28nouveau_copy_fini(ScreenPtr pScreen)
29{
30	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
31	NVPtr pNv = NVPTR(pScrn);
32	nouveau_object_del(&pNv->NvCopy);
33	nouveau_pushbuf_del(&pNv->ce_pushbuf);
34	nouveau_object_del(&pNv->ce_channel);
35}
36
37Bool
38nouveau_copy_init(ScreenPtr pScreen)
39{
40	static const struct {
41		CARD32 oclass;
42		int engine;
43		Bool (*init)(NVPtr);
44	} methods[] = {
45		{ 0xc1b5, 0, nouveau_copya0b5_init },
46		{ 0xc0b5, 0, nouveau_copya0b5_init },
47		{ 0xb0b5, 0, nouveau_copya0b5_init },
48		{ 0xa0b5, 0, nouveau_copya0b5_init },
49		{ 0x90b8, 5, nouveau_copy90b5_init },
50		{ 0x90b5, 4, nouveau_copy90b5_init },
51		{ 0x85b5, 0, nouveau_copy85b5_init },
52		{}
53	}, *method = methods;
54	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
55	NVPtr pNv = NVPTR(pScrn);
56	int ret;
57
58	if (pNv->AccelMethod == NONE) {
59		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
60			   "[COPY] acceleration disabled\n");
61		return FALSE;
62	}
63
64	switch (pNv->Architecture) {
65	case NV_TESLA:
66		if (pNv->dev->chipset < 0xa3 ||
67		    pNv->dev->chipset == 0xaa ||
68		    pNv->dev->chipset == 0xac)
69			return FALSE;
70
71		ret = nouveau_object_new(&pNv->dev->object, 0,
72					 NOUVEAU_FIFO_CHANNEL_CLASS,
73					 &(struct nv04_fifo) {
74						.vram = NvDmaFB,
75						.gart = NvDmaTT,
76					 }, sizeof(struct nv04_fifo),
77					 &pNv->ce_channel);
78		break;
79	case NV_FERMI:
80		ret = nouveau_object_new(&pNv->dev->object, 0,
81					 NOUVEAU_FIFO_CHANNEL_CLASS,
82					 &(struct nvc0_fifo) {
83					 }, sizeof(struct nvc0_fifo),
84					 &pNv->ce_channel);
85		break;
86	case NV_KEPLER:
87	case NV_MAXWELL:
88	case NV_PASCAL:
89		ret = nouveau_object_new(&pNv->dev->object, 0,
90					 NOUVEAU_FIFO_CHANNEL_CLASS,
91					 &(struct nve0_fifo) {
92						.engine = NVE0_FIFO_ENGINE_CE0 |
93							  NVE0_FIFO_ENGINE_CE1,
94					 }, sizeof(struct nve0_fifo),
95					 &pNv->ce_channel);
96		break;
97	default:
98		return FALSE;
99	}
100
101	if (ret) {
102		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
103			   "[COPY] error allocating channel: %d\n", ret);
104		return FALSE;
105	}
106
107	ret = nouveau_pushbuf_new(pNv->client, pNv->ce_channel, 4,
108				  32 * 1024, true, &pNv->ce_pushbuf);
109	if (ret) {
110		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
111			   "[COPY] error allocating pushbuf: %d\n", ret);
112		nouveau_copy_fini(pScreen);
113		return FALSE;
114	}
115
116	while (method->init) {
117		ret = nouveau_object_new(pNv->ce_channel,
118					 method->engine << 16 | method->oclass,
119					 method->oclass, NULL, 0,
120					 &pNv->NvCopy);
121		if (ret == 0) {
122			if (!method->init(pNv)) {
123				xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
124					   "[COPY] failed to initialise.\n");
125				nouveau_copy_fini(pScreen);
126				return FALSE;
127			}
128			break;
129		}
130		method++;
131	}
132
133	if (ret) {
134		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
135			   "[COPY] failed to allocate class.\n");
136		nouveau_copy_fini(pScreen);
137		return FALSE;
138	}
139
140	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[COPY] async initialised.\n");
141	return TRUE;
142}
143