nouveau_ramht.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*
  2. * Copyright 2010 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. #include "drmP.h"
  25. #include "nouveau_drv.h"
  26. #include "nouveau_ramht.h"
  27. static uint32_t
  28. nouveau_ramht_hash_handle(struct drm_device *dev, int channel, uint32_t handle)
  29. {
  30. struct drm_nouveau_private *dev_priv = dev->dev_private;
  31. uint32_t hash = 0;
  32. int i;
  33. NV_DEBUG(dev, "ch%d handle=0x%08x\n", channel, handle);
  34. for (i = 32; i > 0; i -= dev_priv->ramht_bits) {
  35. hash ^= (handle & ((1 << dev_priv->ramht_bits) - 1));
  36. handle >>= dev_priv->ramht_bits;
  37. }
  38. if (dev_priv->card_type < NV_50)
  39. hash ^= channel << (dev_priv->ramht_bits - 4);
  40. hash <<= 3;
  41. NV_DEBUG(dev, "hash=0x%08x\n", hash);
  42. return hash;
  43. }
  44. static int
  45. nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht,
  46. uint32_t offset)
  47. {
  48. struct drm_nouveau_private *dev_priv = dev->dev_private;
  49. uint32_t ctx = nv_ro32(ramht, offset + 4);
  50. if (dev_priv->card_type < NV_40)
  51. return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0);
  52. return (ctx != 0);
  53. }
  54. int
  55. nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
  56. struct nouveau_gpuobj *gpuobj)
  57. {
  58. struct drm_device *dev = chan->dev;
  59. struct drm_nouveau_private *dev_priv = dev->dev_private;
  60. struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
  61. struct nouveau_ramht_entry *entry;
  62. struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
  63. uint32_t ctx, co, ho;
  64. if (nouveau_ramht_find(chan, handle))
  65. return -EEXIST;
  66. entry = kmalloc(sizeof(*entry), GFP_KERNEL);
  67. if (!entry)
  68. return -ENOMEM;
  69. entry->channel = chan;
  70. entry->gpuobj = NULL;
  71. entry->handle = handle;
  72. list_add(&entry->head, &chan->ramht->entries);
  73. nouveau_gpuobj_ref(gpuobj, &entry->gpuobj);
  74. if (dev_priv->card_type < NV_40) {
  75. ctx = NV_RAMHT_CONTEXT_VALID | (gpuobj->cinst >> 4) |
  76. (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) |
  77. (gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT);
  78. } else
  79. if (dev_priv->card_type < NV_50) {
  80. ctx = (gpuobj->cinst >> 4) |
  81. (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) |
  82. (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
  83. } else {
  84. if (gpuobj->engine == NVOBJ_ENGINE_DISPLAY) {
  85. ctx = (gpuobj->cinst << 10) | 2;
  86. } else {
  87. ctx = (gpuobj->cinst >> 4) |
  88. ((gpuobj->engine <<
  89. NV40_RAMHT_CONTEXT_ENGINE_SHIFT));
  90. }
  91. }
  92. co = ho = nouveau_ramht_hash_handle(dev, chan->id, handle);
  93. do {
  94. if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
  95. NV_DEBUG(dev,
  96. "insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
  97. chan->id, co, handle, ctx);
  98. nv_wo32(ramht, co + 0, handle);
  99. nv_wo32(ramht, co + 4, ctx);
  100. instmem->flush(dev);
  101. return 0;
  102. }
  103. NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n",
  104. chan->id, co, nv_ro32(ramht, co));
  105. co += 8;
  106. if (co >= dev_priv->ramht_size)
  107. co = 0;
  108. } while (co != ho);
  109. NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id);
  110. list_del(&entry->head);
  111. kfree(entry);
  112. return -ENOMEM;
  113. }
  114. void
  115. nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle)
  116. {
  117. struct drm_device *dev = chan->dev;
  118. struct drm_nouveau_private *dev_priv = dev->dev_private;
  119. struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
  120. struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
  121. struct nouveau_ramht_entry *entry, *tmp;
  122. u32 co, ho;
  123. list_for_each_entry_safe(entry, tmp, &chan->ramht->entries, head) {
  124. if (entry->channel != chan || entry->handle != handle)
  125. continue;
  126. nouveau_gpuobj_ref(NULL, &entry->gpuobj);
  127. list_del(&entry->head);
  128. kfree(entry);
  129. break;
  130. }
  131. co = ho = nouveau_ramht_hash_handle(dev, chan->id, handle);
  132. do {
  133. if (nouveau_ramht_entry_valid(dev, ramht, co) &&
  134. (handle == nv_ro32(ramht, co))) {
  135. NV_DEBUG(dev,
  136. "remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
  137. chan->id, co, handle, nv_ro32(ramht, co + 4));
  138. nv_wo32(ramht, co + 0, 0x00000000);
  139. nv_wo32(ramht, co + 4, 0x00000000);
  140. instmem->flush(dev);
  141. return;
  142. }
  143. co += 8;
  144. if (co >= dev_priv->ramht_size)
  145. co = 0;
  146. } while (co != ho);
  147. NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
  148. chan->id, handle);
  149. }
  150. struct nouveau_gpuobj *
  151. nouveau_ramht_find(struct nouveau_channel *chan, u32 handle)
  152. {
  153. struct nouveau_ramht_entry *entry;
  154. list_for_each_entry(entry, &chan->ramht->entries, head) {
  155. if (entry->channel == chan && entry->handle == handle)
  156. return entry->gpuobj;
  157. }
  158. return NULL;
  159. }
  160. int
  161. nouveau_ramht_new(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
  162. struct nouveau_ramht **pramht)
  163. {
  164. struct nouveau_ramht *ramht;
  165. ramht = kzalloc(sizeof(*ramht), GFP_KERNEL);
  166. if (!ramht)
  167. return -ENOMEM;
  168. ramht->dev = dev;
  169. ramht->refcount = 1;
  170. INIT_LIST_HEAD(&ramht->entries);
  171. nouveau_gpuobj_ref(gpuobj, &ramht->gpuobj);
  172. *pramht = ramht;
  173. return 0;
  174. }
  175. void
  176. nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr,
  177. struct nouveau_channel *chan)
  178. {
  179. struct nouveau_ramht_entry *entry, *tmp;
  180. struct nouveau_ramht *ramht;
  181. if (ref)
  182. ref->refcount++;
  183. ramht = *ptr;
  184. if (ramht) {
  185. list_for_each_entry_safe(entry, tmp, &ramht->entries, head) {
  186. if (entry->channel == chan)
  187. nouveau_ramht_remove(chan, entry->handle);
  188. }
  189. if (--ramht->refcount == 0) {
  190. nouveau_gpuobj_ref(NULL, &ramht->gpuobj);
  191. kfree(ramht);
  192. }
  193. }
  194. *ptr = ref;
  195. }