1/*
2 * Copyright 2012 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
23 */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <stdint.h>
28#include <stdbool.h>
29#include <assert.h>
30#include <errno.h>
31
32#include "libdrm_lists.h"
33
34#include "nouveau.h"
35#include "private.h"
36
37struct nouveau_bufref_priv {
38	struct nouveau_bufref base;
39	struct nouveau_bufref_priv *next;
40	struct nouveau_bufctx *bufctx;
41};
42
43struct nouveau_bufbin_priv {
44	struct nouveau_bufref_priv *list;
45	int relocs;
46};
47
48struct nouveau_bufctx_priv {
49	struct nouveau_bufctx base;
50	struct nouveau_bufref_priv *free;
51	int nr_bins;
52	struct nouveau_bufbin_priv bins[];
53};
54
55static inline struct nouveau_bufctx_priv *
56nouveau_bufctx(struct nouveau_bufctx *bctx)
57{
58	return (struct nouveau_bufctx_priv *)bctx;
59}
60
61drm_public int
62nouveau_bufctx_new(struct nouveau_client *client, int bins,
63		   struct nouveau_bufctx **pbctx)
64{
65	struct nouveau_bufctx_priv *priv;
66
67	priv = calloc(1, sizeof(*priv) + sizeof(priv->bins[0]) * bins);
68	if (priv) {
69		DRMINITLISTHEAD(&priv->base.head);
70		DRMINITLISTHEAD(&priv->base.pending);
71		DRMINITLISTHEAD(&priv->base.current);
72		priv->base.client = client;
73		priv->nr_bins = bins;
74		*pbctx = &priv->base;
75		return 0;
76	}
77
78	return -ENOMEM;
79}
80
81drm_public void
82nouveau_bufctx_del(struct nouveau_bufctx **pbctx)
83{
84	struct nouveau_bufctx_priv *pctx = nouveau_bufctx(*pbctx);
85	struct nouveau_bufref_priv *pref;
86	if (pctx) {
87		while (pctx->nr_bins--)
88			nouveau_bufctx_reset(&pctx->base, pctx->nr_bins);
89		while ((pref = pctx->free)) {
90			pctx->free = pref->next;
91			free(pref);
92		}
93		free(pctx);
94		*pbctx = NULL;
95	}
96}
97
98drm_public void
99nouveau_bufctx_reset(struct nouveau_bufctx *bctx, int bin)
100{
101	struct nouveau_bufctx_priv *pctx = nouveau_bufctx(bctx);
102	struct nouveau_bufbin_priv *pbin = &pctx->bins[bin];
103	struct nouveau_bufref_priv *pref;
104
105	while ((pref = pbin->list)) {
106		DRMLISTDELINIT(&pref->base.thead);
107		pbin->list = pref->next;
108		pref->next = pctx->free;
109		pctx->free = pref;
110	}
111
112	bctx->relocs -= pbin->relocs;
113	pbin->relocs  = 0;
114}
115
116drm_public struct nouveau_bufref *
117nouveau_bufctx_refn(struct nouveau_bufctx *bctx, int bin,
118		    struct nouveau_bo *bo, uint32_t flags)
119{
120	struct nouveau_bufctx_priv *pctx = nouveau_bufctx(bctx);
121	struct nouveau_bufbin_priv *pbin = &pctx->bins[bin];
122	struct nouveau_bufref_priv *pref = pctx->free;
123
124	if (!pref)
125		pref = malloc(sizeof(*pref));
126	else
127		pctx->free = pref->next;
128
129	if (pref) {
130		pref->base.bo = bo;
131		pref->base.flags = flags;
132		pref->base.packet = 0;
133
134		DRMLISTADDTAIL(&pref->base.thead, &bctx->pending);
135		pref->bufctx = bctx;
136		pref->next = pbin->list;
137		pbin->list = pref;
138	}
139
140	return &pref->base;
141}
142
143drm_public struct nouveau_bufref *
144nouveau_bufctx_mthd(struct nouveau_bufctx *bctx, int bin, uint32_t packet,
145		    struct nouveau_bo *bo, uint64_t data, uint32_t flags,
146		    uint32_t vor, uint32_t tor)
147{
148	struct nouveau_bufctx_priv *pctx = nouveau_bufctx(bctx);
149	struct nouveau_bufbin_priv *pbin = &pctx->bins[bin];
150	struct nouveau_bufref *bref = nouveau_bufctx_refn(bctx, bin, bo, flags);
151	if (bref) {
152		bref->packet = packet;
153		bref->data = data;
154		bref->vor = vor;
155		bref->tor = tor;
156		pbin->relocs++;
157		bctx->relocs++;
158	}
159	return bref;
160}
161