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