1b2b1885dfcb3a206623e926704057b448d06781dRob Clark/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
2b2b1885dfcb3a206623e926704057b448d06781dRob Clark
3b2b1885dfcb3a206623e926704057b448d06781dRob Clark/*
4b2b1885dfcb3a206623e926704057b448d06781dRob Clark * Copyright (C) 2013 Rob Clark <robclark@freedesktop.org>
5b2b1885dfcb3a206623e926704057b448d06781dRob Clark *
6b2b1885dfcb3a206623e926704057b448d06781dRob Clark * Permission is hereby granted, free of charge, to any person obtaining a
7b2b1885dfcb3a206623e926704057b448d06781dRob Clark * copy of this software and associated documentation files (the "Software"),
8b2b1885dfcb3a206623e926704057b448d06781dRob Clark * to deal in the Software without restriction, including without limitation
9b2b1885dfcb3a206623e926704057b448d06781dRob Clark * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10b2b1885dfcb3a206623e926704057b448d06781dRob Clark * and/or sell copies of the Software, and to permit persons to whom the
11b2b1885dfcb3a206623e926704057b448d06781dRob Clark * Software is furnished to do so, subject to the following conditions:
12b2b1885dfcb3a206623e926704057b448d06781dRob Clark *
13b2b1885dfcb3a206623e926704057b448d06781dRob Clark * The above copyright notice and this permission notice (including the next
14b2b1885dfcb3a206623e926704057b448d06781dRob Clark * paragraph) shall be included in all copies or substantial portions of the
15b2b1885dfcb3a206623e926704057b448d06781dRob Clark * Software.
16b2b1885dfcb3a206623e926704057b448d06781dRob Clark *
17b2b1885dfcb3a206623e926704057b448d06781dRob Clark * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18b2b1885dfcb3a206623e926704057b448d06781dRob Clark * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19b2b1885dfcb3a206623e926704057b448d06781dRob Clark * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20b2b1885dfcb3a206623e926704057b448d06781dRob Clark * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21b2b1885dfcb3a206623e926704057b448d06781dRob Clark * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22b2b1885dfcb3a206623e926704057b448d06781dRob Clark * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23b2b1885dfcb3a206623e926704057b448d06781dRob Clark * SOFTWARE.
24b2b1885dfcb3a206623e926704057b448d06781dRob Clark *
25b2b1885dfcb3a206623e926704057b448d06781dRob Clark * Authors:
26b2b1885dfcb3a206623e926704057b448d06781dRob Clark *    Rob Clark <robclark@freedesktop.org>
27b2b1885dfcb3a206623e926704057b448d06781dRob Clark */
28b2b1885dfcb3a206623e926704057b448d06781dRob Clark
29c09dcbc736afb2e6a05d4cfc5c3d878ace43e2baRob Clark#ifdef HAVE_CONFIG_H
30c09dcbc736afb2e6a05d4cfc5c3d878ace43e2baRob Clark# include <config.h>
31c09dcbc736afb2e6a05d4cfc5c3d878ace43e2baRob Clark#endif
32c09dcbc736afb2e6a05d4cfc5c3d878ace43e2baRob Clark
33b2b1885dfcb3a206623e926704057b448d06781dRob Clark#include <assert.h>
34b2b1885dfcb3a206623e926704057b448d06781dRob Clark
35b2b1885dfcb3a206623e926704057b448d06781dRob Clark#include "freedreno_ringbuffer.h"
36b2b1885dfcb3a206623e926704057b448d06781dRob Clark#include "kgsl_priv.h"
37b2b1885dfcb3a206623e926704057b448d06781dRob Clark
38b2b1885dfcb3a206623e926704057b448d06781dRob Clark
39b2b1885dfcb3a206623e926704057b448d06781dRob Clark/* because kgsl tries to validate the gpuaddr on kernel side in ISSUEIBCMDS,
40b2b1885dfcb3a206623e926704057b448d06781dRob Clark * we can't use normal gem bo's for ringbuffer..  someday the kernel part
41b2b1885dfcb3a206623e926704057b448d06781dRob Clark * needs to be reworked into a single sane drm driver :-/
42b2b1885dfcb3a206623e926704057b448d06781dRob Clark */
43b2b1885dfcb3a206623e926704057b448d06781dRob Clarkstruct kgsl_rb_bo {
44b2b1885dfcb3a206623e926704057b448d06781dRob Clark	struct kgsl_pipe *pipe;
45b2b1885dfcb3a206623e926704057b448d06781dRob Clark	void    *hostptr;
46b2b1885dfcb3a206623e926704057b448d06781dRob Clark	uint32_t gpuaddr;
47b2b1885dfcb3a206623e926704057b448d06781dRob Clark	uint32_t size;
48b2b1885dfcb3a206623e926704057b448d06781dRob Clark};
49b2b1885dfcb3a206623e926704057b448d06781dRob Clark
50b2b1885dfcb3a206623e926704057b448d06781dRob Clarkstruct kgsl_ringbuffer {
51b2b1885dfcb3a206623e926704057b448d06781dRob Clark	struct fd_ringbuffer base;
52b2b1885dfcb3a206623e926704057b448d06781dRob Clark	struct kgsl_rb_bo *bo;
53b2b1885dfcb3a206623e926704057b448d06781dRob Clark};
54b2b1885dfcb3a206623e926704057b448d06781dRob Clark
55b2b1885dfcb3a206623e926704057b448d06781dRob Clarkstatic inline struct kgsl_ringbuffer * to_kgsl_ringbuffer(struct fd_ringbuffer *x)
56b2b1885dfcb3a206623e926704057b448d06781dRob Clark{
57b2b1885dfcb3a206623e926704057b448d06781dRob Clark	return (struct kgsl_ringbuffer *)x;
58b2b1885dfcb3a206623e926704057b448d06781dRob Clark}
59b2b1885dfcb3a206623e926704057b448d06781dRob Clark
60b2b1885dfcb3a206623e926704057b448d06781dRob Clarkstatic void kgsl_rb_bo_del(struct kgsl_rb_bo *bo)
61b2b1885dfcb3a206623e926704057b448d06781dRob Clark{
62b2b1885dfcb3a206623e926704057b448d06781dRob Clark	struct kgsl_sharedmem_free req = {
63b2b1885dfcb3a206623e926704057b448d06781dRob Clark			.gpuaddr = bo->gpuaddr,
64b2b1885dfcb3a206623e926704057b448d06781dRob Clark	};
65b2b1885dfcb3a206623e926704057b448d06781dRob Clark	int ret;
66b2b1885dfcb3a206623e926704057b448d06781dRob Clark
6784badffe5e1995eae6739267bdc3fd9ef7a55f32Emil Velikov	drm_munmap(bo->hostptr, bo->size);
68b2b1885dfcb3a206623e926704057b448d06781dRob Clark
69b2b1885dfcb3a206623e926704057b448d06781dRob Clark	ret = ioctl(bo->pipe->fd, IOCTL_KGSL_SHAREDMEM_FREE, &req);
70b2b1885dfcb3a206623e926704057b448d06781dRob Clark	if (ret) {
71b2b1885dfcb3a206623e926704057b448d06781dRob Clark		ERROR_MSG("sharedmem free failed: %s", strerror(errno));
72b2b1885dfcb3a206623e926704057b448d06781dRob Clark	}
73b2b1885dfcb3a206623e926704057b448d06781dRob Clark
74b2b1885dfcb3a206623e926704057b448d06781dRob Clark	free(bo);
75b2b1885dfcb3a206623e926704057b448d06781dRob Clark}
76b2b1885dfcb3a206623e926704057b448d06781dRob Clark
77b2b1885dfcb3a206623e926704057b448d06781dRob Clarkstatic struct kgsl_rb_bo * kgsl_rb_bo_new(struct kgsl_pipe *pipe, uint32_t size)
78b2b1885dfcb3a206623e926704057b448d06781dRob Clark{
79b2b1885dfcb3a206623e926704057b448d06781dRob Clark	struct kgsl_rb_bo *bo;
80b2b1885dfcb3a206623e926704057b448d06781dRob Clark	struct kgsl_gpumem_alloc req = {
81b2b1885dfcb3a206623e926704057b448d06781dRob Clark			.size = ALIGN(size, 4096),
82b2b1885dfcb3a206623e926704057b448d06781dRob Clark			.flags = KGSL_MEMFLAGS_GPUREADONLY,
83b2b1885dfcb3a206623e926704057b448d06781dRob Clark	};
84b2b1885dfcb3a206623e926704057b448d06781dRob Clark	int ret;
85b2b1885dfcb3a206623e926704057b448d06781dRob Clark
86b2b1885dfcb3a206623e926704057b448d06781dRob Clark	bo = calloc(1, sizeof(*bo));
87b2b1885dfcb3a206623e926704057b448d06781dRob Clark	if (!bo) {
88b2b1885dfcb3a206623e926704057b448d06781dRob Clark		ERROR_MSG("allocation failed");
89b2b1885dfcb3a206623e926704057b448d06781dRob Clark		return NULL;
90b2b1885dfcb3a206623e926704057b448d06781dRob Clark	}
91b2b1885dfcb3a206623e926704057b448d06781dRob Clark	ret = ioctl(pipe->fd, IOCTL_KGSL_GPUMEM_ALLOC, &req);
92b2b1885dfcb3a206623e926704057b448d06781dRob Clark	if (ret) {
93b2b1885dfcb3a206623e926704057b448d06781dRob Clark		ERROR_MSG("gpumem allocation failed: %s", strerror(errno));
94b2b1885dfcb3a206623e926704057b448d06781dRob Clark		goto fail;
95b2b1885dfcb3a206623e926704057b448d06781dRob Clark	}
96b2b1885dfcb3a206623e926704057b448d06781dRob Clark
97b2b1885dfcb3a206623e926704057b448d06781dRob Clark	bo->pipe = pipe;
98b2b1885dfcb3a206623e926704057b448d06781dRob Clark	bo->gpuaddr = req.gpuaddr;
99b2b1885dfcb3a206623e926704057b448d06781dRob Clark	bo->size = size;
10084badffe5e1995eae6739267bdc3fd9ef7a55f32Emil Velikov	bo->hostptr = drm_mmap(NULL, size, PROT_WRITE|PROT_READ,
101b2b1885dfcb3a206623e926704057b448d06781dRob Clark				MAP_SHARED, pipe->fd, req.gpuaddr);
102b2b1885dfcb3a206623e926704057b448d06781dRob Clark
103b2b1885dfcb3a206623e926704057b448d06781dRob Clark	return bo;
104b2b1885dfcb3a206623e926704057b448d06781dRob Clarkfail:
105b2b1885dfcb3a206623e926704057b448d06781dRob Clark	if (bo)
106b2b1885dfcb3a206623e926704057b448d06781dRob Clark		kgsl_rb_bo_del(bo);
107b2b1885dfcb3a206623e926704057b448d06781dRob Clark	return NULL;
108b2b1885dfcb3a206623e926704057b448d06781dRob Clark}
109b2b1885dfcb3a206623e926704057b448d06781dRob Clark
110b2b1885dfcb3a206623e926704057b448d06781dRob Clarkstatic void * kgsl_ringbuffer_hostptr(struct fd_ringbuffer *ring)
111b2b1885dfcb3a206623e926704057b448d06781dRob Clark{
112b2b1885dfcb3a206623e926704057b448d06781dRob Clark	struct kgsl_ringbuffer *kgsl_ring = to_kgsl_ringbuffer(ring);
113b2b1885dfcb3a206623e926704057b448d06781dRob Clark	return kgsl_ring->bo->hostptr;
114b2b1885dfcb3a206623e926704057b448d06781dRob Clark}
115b2b1885dfcb3a206623e926704057b448d06781dRob Clark
116b2b1885dfcb3a206623e926704057b448d06781dRob Clarkstatic int kgsl_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_start)
117b2b1885dfcb3a206623e926704057b448d06781dRob Clark{
118b2b1885dfcb3a206623e926704057b448d06781dRob Clark	struct kgsl_ringbuffer *kgsl_ring = to_kgsl_ringbuffer(ring);
119b2b1885dfcb3a206623e926704057b448d06781dRob Clark	struct kgsl_pipe *kgsl_pipe = to_kgsl_pipe(ring->pipe);
120b2b1885dfcb3a206623e926704057b448d06781dRob Clark	uint32_t offset = (uint8_t *)last_start - (uint8_t *)ring->start;
121b2b1885dfcb3a206623e926704057b448d06781dRob Clark	struct kgsl_ibdesc ibdesc = {
122b2b1885dfcb3a206623e926704057b448d06781dRob Clark			.gpuaddr     = kgsl_ring->bo->gpuaddr + offset,
123b2b1885dfcb3a206623e926704057b448d06781dRob Clark			.hostptr     = last_start,
124b2b1885dfcb3a206623e926704057b448d06781dRob Clark			.sizedwords  = ring->cur - last_start,
125b2b1885dfcb3a206623e926704057b448d06781dRob Clark	};
126b2b1885dfcb3a206623e926704057b448d06781dRob Clark	struct kgsl_ringbuffer_issueibcmds req = {
127b2b1885dfcb3a206623e926704057b448d06781dRob Clark			.drawctxt_id = kgsl_pipe->drawctxt_id,
128b2b1885dfcb3a206623e926704057b448d06781dRob Clark			.ibdesc_addr = (unsigned long)&ibdesc,
129b2b1885dfcb3a206623e926704057b448d06781dRob Clark			.numibs      = 1,
130b2b1885dfcb3a206623e926704057b448d06781dRob Clark			.flags       = KGSL_CONTEXT_SUBMIT_IB_LIST,
131b2b1885dfcb3a206623e926704057b448d06781dRob Clark	};
132b2b1885dfcb3a206623e926704057b448d06781dRob Clark	int ret;
133b2b1885dfcb3a206623e926704057b448d06781dRob Clark
134b2b1885dfcb3a206623e926704057b448d06781dRob Clark	kgsl_pipe_pre_submit(kgsl_pipe);
135b2b1885dfcb3a206623e926704057b448d06781dRob Clark
136b2b1885dfcb3a206623e926704057b448d06781dRob Clark	/* z180_cmdstream_issueibcmds() is made of fail: */
137b2b1885dfcb3a206623e926704057b448d06781dRob Clark	if (ring->pipe->id == FD_PIPE_2D) {
138b2b1885dfcb3a206623e926704057b448d06781dRob Clark		/* fix up size field in last cmd packet */
139b2b1885dfcb3a206623e926704057b448d06781dRob Clark		uint32_t last_size = (uint32_t)(ring->cur - last_start);
140b2b1885dfcb3a206623e926704057b448d06781dRob Clark		/* 5 is length of first packet, 2 for the two 7f000000's */
141b2b1885dfcb3a206623e926704057b448d06781dRob Clark		last_start[2] = last_size - (5 + 2);
142b2b1885dfcb3a206623e926704057b448d06781dRob Clark		ibdesc.gpuaddr = kgsl_ring->bo->gpuaddr;
143b2b1885dfcb3a206623e926704057b448d06781dRob Clark		ibdesc.hostptr = kgsl_ring->bo->hostptr;
144b2b1885dfcb3a206623e926704057b448d06781dRob Clark		ibdesc.sizedwords = 0x145;
145b2b1885dfcb3a206623e926704057b448d06781dRob Clark		req.timestamp = (uint32_t)kgsl_ring->bo->hostptr;
146b2b1885dfcb3a206623e926704057b448d06781dRob Clark	}
147b2b1885dfcb3a206623e926704057b448d06781dRob Clark
148b2b1885dfcb3a206623e926704057b448d06781dRob Clark	do {
149b2b1885dfcb3a206623e926704057b448d06781dRob Clark		ret = ioctl(kgsl_pipe->fd, IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS, &req);
150b2b1885dfcb3a206623e926704057b448d06781dRob Clark	} while ((ret == -1) && ((errno == EINTR) || (errno == EAGAIN)));
151b2b1885dfcb3a206623e926704057b448d06781dRob Clark	if (ret)
152b2b1885dfcb3a206623e926704057b448d06781dRob Clark		ERROR_MSG("issueibcmds failed!  %d (%s)", ret, strerror(errno));
153b2b1885dfcb3a206623e926704057b448d06781dRob Clark
154b2b1885dfcb3a206623e926704057b448d06781dRob Clark	ring->last_timestamp = req.timestamp;
155b2b1885dfcb3a206623e926704057b448d06781dRob Clark	ring->last_start = ring->cur;
156b2b1885dfcb3a206623e926704057b448d06781dRob Clark
157b2b1885dfcb3a206623e926704057b448d06781dRob Clark	kgsl_pipe_post_submit(kgsl_pipe, req.timestamp);
158b2b1885dfcb3a206623e926704057b448d06781dRob Clark
159b2b1885dfcb3a206623e926704057b448d06781dRob Clark	return ret;
160b2b1885dfcb3a206623e926704057b448d06781dRob Clark}
161b2b1885dfcb3a206623e926704057b448d06781dRob Clark
162b2b1885dfcb3a206623e926704057b448d06781dRob Clarkstatic void kgsl_ringbuffer_emit_reloc(struct fd_ringbuffer *ring,
163b2b1885dfcb3a206623e926704057b448d06781dRob Clark		const struct fd_reloc *r)
164b2b1885dfcb3a206623e926704057b448d06781dRob Clark{
165b2b1885dfcb3a206623e926704057b448d06781dRob Clark	struct kgsl_bo *kgsl_bo = to_kgsl_bo(r->bo);
166b2b1885dfcb3a206623e926704057b448d06781dRob Clark	uint32_t addr = kgsl_bo_gpuaddr(kgsl_bo, r->offset);
167b2b1885dfcb3a206623e926704057b448d06781dRob Clark	assert(addr);
168b2b1885dfcb3a206623e926704057b448d06781dRob Clark	if (r->shift < 0)
169b2b1885dfcb3a206623e926704057b448d06781dRob Clark		addr >>= -r->shift;
170b2b1885dfcb3a206623e926704057b448d06781dRob Clark	else
171b2b1885dfcb3a206623e926704057b448d06781dRob Clark		addr <<= r->shift;
172b2b1885dfcb3a206623e926704057b448d06781dRob Clark	(*ring->cur++) = addr | r->or;
173b2b1885dfcb3a206623e926704057b448d06781dRob Clark	kgsl_pipe_add_submit(to_kgsl_pipe(ring->pipe), kgsl_bo);
174b2b1885dfcb3a206623e926704057b448d06781dRob Clark}
175b2b1885dfcb3a206623e926704057b448d06781dRob Clark
176b2b1885dfcb3a206623e926704057b448d06781dRob Clarkstatic void kgsl_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
177b2b1885dfcb3a206623e926704057b448d06781dRob Clark		struct fd_ringmarker *target, struct fd_ringmarker *end)
178b2b1885dfcb3a206623e926704057b448d06781dRob Clark{
179b2b1885dfcb3a206623e926704057b448d06781dRob Clark	struct kgsl_ringbuffer *target_ring = to_kgsl_ringbuffer(target->ring);
180b2b1885dfcb3a206623e926704057b448d06781dRob Clark	(*ring->cur++) = target_ring->bo->gpuaddr +
181b2b1885dfcb3a206623e926704057b448d06781dRob Clark			(uint8_t *)target->cur - (uint8_t *)target->ring->start;
182b2b1885dfcb3a206623e926704057b448d06781dRob Clark}
183b2b1885dfcb3a206623e926704057b448d06781dRob Clark
184b2b1885dfcb3a206623e926704057b448d06781dRob Clarkstatic void kgsl_ringbuffer_destroy(struct fd_ringbuffer *ring)
185b2b1885dfcb3a206623e926704057b448d06781dRob Clark{
186b2b1885dfcb3a206623e926704057b448d06781dRob Clark	struct kgsl_ringbuffer *kgsl_ring = to_kgsl_ringbuffer(ring);
187b2b1885dfcb3a206623e926704057b448d06781dRob Clark	if (ring->last_timestamp)
188b2b1885dfcb3a206623e926704057b448d06781dRob Clark		fd_pipe_wait(ring->pipe, ring->last_timestamp);
189b2b1885dfcb3a206623e926704057b448d06781dRob Clark	if (kgsl_ring->bo)
190b2b1885dfcb3a206623e926704057b448d06781dRob Clark		kgsl_rb_bo_del(kgsl_ring->bo);
191b2b1885dfcb3a206623e926704057b448d06781dRob Clark	free(kgsl_ring);
192b2b1885dfcb3a206623e926704057b448d06781dRob Clark}
193b2b1885dfcb3a206623e926704057b448d06781dRob Clark
1946a6d668fad9833350deaddc61e917de3dcb38262Emil Velikovstatic const struct fd_ringbuffer_funcs funcs = {
195b2b1885dfcb3a206623e926704057b448d06781dRob Clark		.hostptr = kgsl_ringbuffer_hostptr,
196b2b1885dfcb3a206623e926704057b448d06781dRob Clark		.flush = kgsl_ringbuffer_flush,
197b2b1885dfcb3a206623e926704057b448d06781dRob Clark		.emit_reloc = kgsl_ringbuffer_emit_reloc,
198b2b1885dfcb3a206623e926704057b448d06781dRob Clark		.emit_reloc_ring = kgsl_ringbuffer_emit_reloc_ring,
199b2b1885dfcb3a206623e926704057b448d06781dRob Clark		.destroy = kgsl_ringbuffer_destroy,
200b2b1885dfcb3a206623e926704057b448d06781dRob Clark};
201b2b1885dfcb3a206623e926704057b448d06781dRob Clark
20244e9a0258a4cab4a22fc44d1440ea882e3ad0334Emil Velikovdrm_private struct fd_ringbuffer * kgsl_ringbuffer_new(struct fd_pipe *pipe,
203b2b1885dfcb3a206623e926704057b448d06781dRob Clark		uint32_t size)
204b2b1885dfcb3a206623e926704057b448d06781dRob Clark{
205b2b1885dfcb3a206623e926704057b448d06781dRob Clark	struct kgsl_ringbuffer *kgsl_ring;
206b2b1885dfcb3a206623e926704057b448d06781dRob Clark	struct fd_ringbuffer *ring = NULL;
207b2b1885dfcb3a206623e926704057b448d06781dRob Clark
208b2b1885dfcb3a206623e926704057b448d06781dRob Clark	kgsl_ring = calloc(1, sizeof(*kgsl_ring));
209b2b1885dfcb3a206623e926704057b448d06781dRob Clark	if (!kgsl_ring) {
210b2b1885dfcb3a206623e926704057b448d06781dRob Clark		ERROR_MSG("allocation failed");
211b2b1885dfcb3a206623e926704057b448d06781dRob Clark		goto fail;
212b2b1885dfcb3a206623e926704057b448d06781dRob Clark	}
213b2b1885dfcb3a206623e926704057b448d06781dRob Clark
214b2b1885dfcb3a206623e926704057b448d06781dRob Clark	ring = &kgsl_ring->base;
215b2b1885dfcb3a206623e926704057b448d06781dRob Clark	ring->funcs = &funcs;
216b2b1885dfcb3a206623e926704057b448d06781dRob Clark
217b2b1885dfcb3a206623e926704057b448d06781dRob Clark	kgsl_ring->bo = kgsl_rb_bo_new(to_kgsl_pipe(pipe), size);
218b2b1885dfcb3a206623e926704057b448d06781dRob Clark	if (!kgsl_ring->bo) {
219b2b1885dfcb3a206623e926704057b448d06781dRob Clark		ERROR_MSG("ringbuffer allocation failed");
220b2b1885dfcb3a206623e926704057b448d06781dRob Clark		goto fail;
221b2b1885dfcb3a206623e926704057b448d06781dRob Clark	}
222b2b1885dfcb3a206623e926704057b448d06781dRob Clark
223b2b1885dfcb3a206623e926704057b448d06781dRob Clark	return ring;
224b2b1885dfcb3a206623e926704057b448d06781dRob Clarkfail:
225b2b1885dfcb3a206623e926704057b448d06781dRob Clark	if (ring)
226b2b1885dfcb3a206623e926704057b448d06781dRob Clark		fd_ringbuffer_del(ring);
227b2b1885dfcb3a206623e926704057b448d06781dRob Clark	return NULL;
228b2b1885dfcb3a206623e926704057b448d06781dRob Clark}
229