sis_mm.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /**************************************************************************
  2. *
  3. * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
  4. * All Rights Reserved.
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a
  7. * copy of this software and associated documentation files (the
  8. * "Software"), to deal in the Software without restriction, including
  9. * without limitation the rights to use, copy, modify, merge, publish,
  10. * distribute, sub license, and/or sell copies of the Software, and to
  11. * permit persons to whom the Software is furnished to do so, subject to
  12. * the following conditions:
  13. *
  14. * The above copyright notice and this permission notice (including the
  15. * next paragraph) shall be included in all copies or substantial portions
  16. * of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  21. * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  22. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  23. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  24. * USE OR OTHER DEALINGS IN THE SOFTWARE.
  25. *
  26. *
  27. **************************************************************************/
  28. /*
  29. * Authors:
  30. * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
  31. */
  32. #include "drmP.h"
  33. #include "sis_drm.h"
  34. #include "sis_drv.h"
  35. #include <video/sisfb.h>
  36. #define VIDEO_TYPE 0
  37. #define AGP_TYPE 1
  38. #if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
  39. /* fb management via fb device */
  40. #define SIS_MM_ALIGN_SHIFT 0
  41. #define SIS_MM_ALIGN_MASK 0
  42. static void *sis_sman_mm_allocate(void *private, unsigned long size,
  43. unsigned alignment)
  44. {
  45. struct sis_memreq req;
  46. req.size = size;
  47. sis_malloc(&req);
  48. if (req.size == 0)
  49. return NULL;
  50. else
  51. return (void *)(unsigned long)~req.offset;
  52. }
  53. static void sis_sman_mm_free(void *private, void *ref)
  54. {
  55. sis_free(~((unsigned long)ref));
  56. }
  57. static void sis_sman_mm_destroy(void *private)
  58. {
  59. ;
  60. }
  61. static unsigned long sis_sman_mm_offset(void *private, void *ref)
  62. {
  63. return ~((unsigned long)ref);
  64. }
  65. #else /* CONFIG_FB_SIS[_MODULE] */
  66. #define SIS_MM_ALIGN_SHIFT 4
  67. #define SIS_MM_ALIGN_MASK ((1 << SIS_MM_ALIGN_SHIFT) - 1)
  68. #endif /* CONFIG_FB_SIS[_MODULE] */
  69. static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
  70. {
  71. drm_sis_private_t *dev_priv = dev->dev_private;
  72. drm_sis_fb_t *fb = data;
  73. int ret;
  74. mutex_lock(&dev->struct_mutex);
  75. #if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
  76. {
  77. struct drm_sman_mm sman_mm;
  78. sman_mm.private = (void *)0xFFFFFFFF;
  79. sman_mm.allocate = sis_sman_mm_allocate;
  80. sman_mm.free = sis_sman_mm_free;
  81. sman_mm.destroy = sis_sman_mm_destroy;
  82. sman_mm.offset = sis_sman_mm_offset;
  83. ret =
  84. drm_sman_set_manager(&dev_priv->sman, VIDEO_TYPE, &sman_mm);
  85. }
  86. #else
  87. ret = drm_sman_set_range(&dev_priv->sman, VIDEO_TYPE, 0,
  88. fb->size >> SIS_MM_ALIGN_SHIFT);
  89. #endif
  90. if (ret) {
  91. DRM_ERROR("VRAM memory manager initialisation error\n");
  92. mutex_unlock(&dev->struct_mutex);
  93. return ret;
  94. }
  95. dev_priv->vram_initialized = 1;
  96. dev_priv->vram_offset = fb->offset;
  97. mutex_unlock(&dev->struct_mutex);
  98. DRM_DEBUG("offset = %u, size = %u\n", fb->offset, fb->size);
  99. return 0;
  100. }
  101. static int sis_drm_alloc(struct drm_device *dev, struct drm_file *file_priv,
  102. void *data, int pool)
  103. {
  104. drm_sis_private_t *dev_priv = dev->dev_private;
  105. drm_sis_mem_t *mem = data;
  106. int retval = 0;
  107. struct drm_memblock_item *item;
  108. mutex_lock(&dev->struct_mutex);
  109. if (0 == ((pool == 0) ? dev_priv->vram_initialized :
  110. dev_priv->agp_initialized)) {
  111. DRM_ERROR
  112. ("Attempt to allocate from uninitialized memory manager.\n");
  113. mutex_unlock(&dev->struct_mutex);
  114. return -EINVAL;
  115. }
  116. mem->size = (mem->size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT;
  117. item = drm_sman_alloc(&dev_priv->sman, pool, mem->size, 0,
  118. (unsigned long)file_priv);
  119. mutex_unlock(&dev->struct_mutex);
  120. if (item) {
  121. mem->offset = ((pool == 0) ?
  122. dev_priv->vram_offset : dev_priv->agp_offset) +
  123. (item->mm->
  124. offset(item->mm, item->mm_info) << SIS_MM_ALIGN_SHIFT);
  125. mem->free = item->user_hash.key;
  126. mem->size = mem->size << SIS_MM_ALIGN_SHIFT;
  127. } else {
  128. mem->offset = 0;
  129. mem->size = 0;
  130. mem->free = 0;
  131. retval = -ENOMEM;
  132. }
  133. DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem->size,
  134. mem->offset);
  135. return retval;
  136. }
  137. static int sis_drm_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
  138. {
  139. drm_sis_private_t *dev_priv = dev->dev_private;
  140. drm_sis_mem_t *mem = data;
  141. int ret;
  142. mutex_lock(&dev->struct_mutex);
  143. ret = drm_sman_free_key(&dev_priv->sman, mem->free);
  144. mutex_unlock(&dev->struct_mutex);
  145. DRM_DEBUG("free = 0x%lx\n", mem->free);
  146. return ret;
  147. }
  148. static int sis_fb_alloc(struct drm_device *dev, void *data,
  149. struct drm_file *file_priv)
  150. {
  151. return sis_drm_alloc(dev, file_priv, data, VIDEO_TYPE);
  152. }
  153. static int sis_ioctl_agp_init(struct drm_device *dev, void *data,
  154. struct drm_file *file_priv)
  155. {
  156. drm_sis_private_t *dev_priv = dev->dev_private;
  157. drm_sis_agp_t *agp = data;
  158. int ret;
  159. dev_priv = dev->dev_private;
  160. mutex_lock(&dev->struct_mutex);
  161. ret = drm_sman_set_range(&dev_priv->sman, AGP_TYPE, 0,
  162. agp->size >> SIS_MM_ALIGN_SHIFT);
  163. if (ret) {
  164. DRM_ERROR("AGP memory manager initialisation error\n");
  165. mutex_unlock(&dev->struct_mutex);
  166. return ret;
  167. }
  168. dev_priv->agp_initialized = 1;
  169. dev_priv->agp_offset = agp->offset;
  170. mutex_unlock(&dev->struct_mutex);
  171. DRM_DEBUG("offset = %u, size = %u\n", agp->offset, agp->size);
  172. return 0;
  173. }
  174. static int sis_ioctl_agp_alloc(struct drm_device *dev, void *data,
  175. struct drm_file *file_priv)
  176. {
  177. return sis_drm_alloc(dev, file_priv, data, AGP_TYPE);
  178. }
  179. static drm_local_map_t *sis_reg_init(struct drm_device *dev)
  180. {
  181. struct drm_map_list *entry;
  182. drm_local_map_t *map;
  183. list_for_each_entry(entry, &dev->maplist, head) {
  184. map = entry->map;
  185. if (!map)
  186. continue;
  187. if (map->type == _DRM_REGISTERS)
  188. return map;
  189. }
  190. return NULL;
  191. }
  192. int sis_idle(struct drm_device *dev)
  193. {
  194. drm_sis_private_t *dev_priv = dev->dev_private;
  195. uint32_t idle_reg;
  196. unsigned long end;
  197. int i;
  198. if (dev_priv->idle_fault)
  199. return 0;
  200. if (dev_priv->mmio == NULL) {
  201. dev_priv->mmio = sis_reg_init(dev);
  202. if (dev_priv->mmio == NULL) {
  203. DRM_ERROR("Could not find register map.\n");
  204. return 0;
  205. }
  206. }
  207. /*
  208. * Implement a device switch here if needed
  209. */
  210. if (dev_priv->chipset != SIS_CHIP_315)
  211. return 0;
  212. /*
  213. * Timeout after 3 seconds. We cannot use DRM_WAIT_ON here
  214. * because its polling frequency is too low.
  215. */
  216. end = jiffies + (DRM_HZ * 3);
  217. for (i = 0; i < 4; ++i) {
  218. do {
  219. idle_reg = SIS_READ(0x85cc);
  220. } while (!time_after_eq(jiffies, end) &&
  221. ((idle_reg & 0x80000000) != 0x80000000));
  222. }
  223. if (time_after_eq(jiffies, end)) {
  224. DRM_ERROR("Graphics engine idle timeout. "
  225. "Disabling idle check\n");
  226. dev_priv->idle_fault = 1;
  227. }
  228. /*
  229. * The caller never sees an error code. It gets trapped
  230. * in libdrm.
  231. */
  232. return 0;
  233. }
  234. void sis_lastclose(struct drm_device *dev)
  235. {
  236. drm_sis_private_t *dev_priv = dev->dev_private;
  237. if (!dev_priv)
  238. return;
  239. mutex_lock(&dev->struct_mutex);
  240. drm_sman_cleanup(&dev_priv->sman);
  241. dev_priv->vram_initialized = 0;
  242. dev_priv->agp_initialized = 0;
  243. dev_priv->mmio = NULL;
  244. mutex_unlock(&dev->struct_mutex);
  245. }
  246. void sis_reclaim_buffers_locked(struct drm_device *dev,
  247. struct drm_file *file_priv)
  248. {
  249. drm_sis_private_t *dev_priv = dev->dev_private;
  250. mutex_lock(&dev->struct_mutex);
  251. if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)file_priv)) {
  252. mutex_unlock(&dev->struct_mutex);
  253. return;
  254. }
  255. if (dev->driver->dma_quiescent)
  256. dev->driver->dma_quiescent(dev);
  257. drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)file_priv);
  258. mutex_unlock(&dev->struct_mutex);
  259. return;
  260. }
  261. struct drm_ioctl_desc sis_ioctls[] = {
  262. DRM_IOCTL_DEF_DRV(SIS_FB_ALLOC, sis_fb_alloc, DRM_AUTH),
  263. DRM_IOCTL_DEF_DRV(SIS_FB_FREE, sis_drm_free, DRM_AUTH),
  264. DRM_IOCTL_DEF_DRV(SIS_AGP_INIT, sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY),
  265. DRM_IOCTL_DEF_DRV(SIS_AGP_ALLOC, sis_ioctl_agp_alloc, DRM_AUTH),
  266. DRM_IOCTL_DEF_DRV(SIS_AGP_FREE, sis_drm_free, DRM_AUTH),
  267. DRM_IOCTL_DEF_DRV(SIS_FB_INIT, sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY),
  268. };
  269. int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);