sis_mm.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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. #define SIS_MM_ALIGN_SHIFT 4
  39. #define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1)
  40. #if defined(CONFIG_FB_SIS)
  41. /* fb management via fb device */
  42. #define SIS_MM_ALIGN_SHIFT 0
  43. #define SIS_MM_ALIGN_MASK 0
  44. static void *sis_sman_mm_allocate(void *private, unsigned long size,
  45. unsigned alignment)
  46. {
  47. struct sis_memreq req;
  48. req.size = size;
  49. sis_malloc(&req);
  50. if (req.size == 0)
  51. return NULL;
  52. else
  53. return (void *)~req.offset;
  54. }
  55. static void sis_sman_mm_free(void *private, void *ref)
  56. {
  57. sis_free(~((unsigned long)ref));
  58. }
  59. static void sis_sman_mm_destroy(void *private)
  60. {
  61. ;
  62. }
  63. unsigned long sis_sman_mm_offset(void *private, void *ref)
  64. {
  65. return ~((unsigned long)ref);
  66. }
  67. #endif
  68. static int sis_fb_init(DRM_IOCTL_ARGS)
  69. {
  70. DRM_DEVICE;
  71. drm_sis_private_t *dev_priv = dev->dev_private;
  72. drm_sis_fb_t fb;
  73. int ret;
  74. DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t __user *) data, sizeof(fb));
  75. mutex_lock(&dev->struct_mutex);
  76. #if defined(CONFIG_FB_SIS)
  77. {
  78. drm_sman_mm_t sman_mm;
  79. sman_mm.private = (void *)0xFFFFFFFF;
  80. sman_mm.allocate = sis_sman_mm_allocate;
  81. sman_mm.free = sis_sman_mm_free;
  82. sman_mm.destroy = sis_sman_mm_destroy;
  83. sman_mm.offset = sis_sman_mm_offset;
  84. ret =
  85. drm_sman_set_manager(&dev_priv->sman, VIDEO_TYPE, &sman_mm);
  86. }
  87. #else
  88. ret = drm_sman_set_range(&dev_priv->sman, VIDEO_TYPE, 0,
  89. fb.size >> SIS_MM_ALIGN_SHIFT);
  90. #endif
  91. if (ret) {
  92. DRM_ERROR("VRAM memory manager initialisation error\n");
  93. mutex_unlock(&dev->struct_mutex);
  94. return ret;
  95. }
  96. dev_priv->vram_initialized = 1;
  97. dev_priv->vram_offset = fb.offset;
  98. mutex_unlock(&dev->struct_mutex);
  99. DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
  100. return 0;
  101. }
  102. static int sis_drm_alloc(drm_device_t * dev, drm_file_t * priv,
  103. unsigned long data, int pool)
  104. {
  105. drm_sis_private_t *dev_priv = dev->dev_private;
  106. drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *) data;
  107. drm_sis_mem_t mem;
  108. int retval = 0;
  109. drm_memblock_item_t *item;
  110. DRM_COPY_FROM_USER_IOCTL(mem, argp, sizeof(mem));
  111. mutex_lock(&dev->struct_mutex);
  112. if (0 == ((pool == 0) ? dev_priv->vram_initialized :
  113. dev_priv->agp_initialized)) {
  114. DRM_ERROR
  115. ("Attempt to allocate from uninitialized memory manager.\n");
  116. return DRM_ERR(EINVAL);
  117. }
  118. mem.size = (mem.size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT;
  119. item = drm_sman_alloc(&dev_priv->sman, pool, mem.size, 0,
  120. (unsigned long)priv);
  121. mutex_unlock(&dev->struct_mutex);
  122. if (item) {
  123. mem.offset = ((pool == 0) ?
  124. dev_priv->vram_offset : dev_priv->agp_offset) +
  125. (item->mm->
  126. offset(item->mm, item->mm_info) << SIS_MM_ALIGN_SHIFT);
  127. mem.free = item->user_hash.key;
  128. mem.size = mem.size << SIS_MM_ALIGN_SHIFT;
  129. } else {
  130. mem.offset = 0;
  131. mem.size = 0;
  132. mem.free = 0;
  133. retval = DRM_ERR(ENOMEM);
  134. }
  135. DRM_COPY_TO_USER_IOCTL(argp, mem, sizeof(mem));
  136. DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem.size,
  137. mem.offset);
  138. return retval;
  139. }
  140. static int sis_drm_free(DRM_IOCTL_ARGS)
  141. {
  142. DRM_DEVICE;
  143. drm_sis_private_t *dev_priv = dev->dev_private;
  144. drm_sis_mem_t mem;
  145. int ret;
  146. DRM_COPY_FROM_USER_IOCTL(mem, (drm_sis_mem_t __user *) data,
  147. sizeof(mem));
  148. mutex_lock(&dev->struct_mutex);
  149. ret = drm_sman_free_key(&dev_priv->sman, mem.free);
  150. mutex_unlock(&dev->struct_mutex);
  151. DRM_DEBUG("free = 0x%lx\n", mem.free);
  152. return ret;
  153. }
  154. static int sis_fb_alloc(DRM_IOCTL_ARGS)
  155. {
  156. DRM_DEVICE;
  157. return sis_drm_alloc(dev, priv, data, VIDEO_TYPE);
  158. }
  159. static int sis_ioctl_agp_init(DRM_IOCTL_ARGS)
  160. {
  161. DRM_DEVICE;
  162. drm_sis_private_t *dev_priv = dev->dev_private;
  163. drm_sis_agp_t agp;
  164. int ret;
  165. dev_priv = dev->dev_private;
  166. DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t __user *) data,
  167. sizeof(agp));
  168. mutex_lock(&dev->struct_mutex);
  169. ret = drm_sman_set_range(&dev_priv->sman, AGP_TYPE, 0,
  170. agp.size >> SIS_MM_ALIGN_SHIFT);
  171. if (ret) {
  172. DRM_ERROR("AGP memory manager initialisation error\n");
  173. mutex_unlock(&dev->struct_mutex);
  174. return ret;
  175. }
  176. dev_priv->agp_initialized = 1;
  177. dev_priv->agp_offset = agp.offset;
  178. mutex_unlock(&dev->struct_mutex);
  179. DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
  180. return 0;
  181. }
  182. static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS)
  183. {
  184. DRM_DEVICE;
  185. return sis_drm_alloc(dev, priv, data, AGP_TYPE);
  186. }
  187. static drm_local_map_t *sis_reg_init(drm_device_t *dev)
  188. {
  189. drm_map_list_t *entry;
  190. drm_local_map_t *map;
  191. list_for_each_entry(entry, &dev->maplist->head, head) {
  192. map = entry->map;
  193. if (!map)
  194. continue;
  195. if (map->type == _DRM_REGISTERS) {
  196. return map;
  197. }
  198. }
  199. return NULL;
  200. }
  201. int sis_idle(drm_device_t *dev)
  202. {
  203. drm_sis_private_t *dev_priv = dev->dev_private;
  204. uint32_t idle_reg;
  205. unsigned long end;
  206. int i;
  207. if (dev_priv->idle_fault)
  208. return 0;
  209. if (dev_priv->mmio == NULL) {
  210. dev_priv->mmio = sis_reg_init(dev);
  211. if (dev_priv->mmio == NULL) {
  212. DRM_ERROR("Could not find register map.\n");
  213. return 0;
  214. }
  215. }
  216. /*
  217. * Implement a device switch here if needed
  218. */
  219. if (dev_priv->chipset != SIS_CHIP_315)
  220. return 0;
  221. /*
  222. * Timeout after 3 seconds. We cannot use DRM_WAIT_ON here
  223. * because its polling frequency is too low.
  224. */
  225. end = jiffies + (DRM_HZ * 3);
  226. for (i=0; i<4; ++i) {
  227. do {
  228. idle_reg = SIS_READ(0x85cc);
  229. } while ( !time_after_eq(jiffies, end) &&
  230. ((idle_reg & 0x80000000) != 0x80000000));
  231. }
  232. if (time_after_eq(jiffies, end)) {
  233. DRM_ERROR("Graphics engine idle timeout. "
  234. "Disabling idle check\n");
  235. dev_priv->idle_fault = 1;
  236. }
  237. /*
  238. * The caller never sees an error code. It gets trapped
  239. * in libdrm.
  240. */
  241. return 0;
  242. }
  243. void sis_lastclose(struct drm_device *dev)
  244. {
  245. drm_sis_private_t *dev_priv = dev->dev_private;
  246. if (!dev_priv)
  247. return;
  248. mutex_lock(&dev->struct_mutex);
  249. drm_sman_cleanup(&dev_priv->sman);
  250. dev_priv->vram_initialized = 0;
  251. dev_priv->agp_initialized = 0;
  252. dev_priv->mmio = NULL;
  253. mutex_unlock(&dev->struct_mutex);
  254. }
  255. void sis_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
  256. {
  257. drm_sis_private_t *dev_priv = dev->dev_private;
  258. drm_file_t *priv = filp->private_data;
  259. mutex_lock(&dev->struct_mutex);
  260. if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
  261. mutex_unlock(&dev->struct_mutex);
  262. return;
  263. }
  264. if (dev->driver->dma_quiescent) {
  265. dev->driver->dma_quiescent(dev);
  266. }
  267. drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
  268. mutex_unlock(&dev->struct_mutex);
  269. return;
  270. }
  271. drm_ioctl_desc_t sis_ioctls[] = {
  272. [DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)] = {sis_fb_alloc, DRM_AUTH},
  273. [DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_drm_free, DRM_AUTH},
  274. [DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] =
  275. {sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY},
  276. [DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = {sis_ioctl_agp_alloc, DRM_AUTH},
  277. [DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_drm_free, DRM_AUTH},
  278. [DRM_IOCTL_NR(DRM_SIS_FB_INIT)] =
  279. {sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY}
  280. };
  281. int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);