winsys/radeon: Query the kernel for the number of SEs and SHs per SE
[mesa.git] / src / gallium / winsys / radeon / drm / radeon_drm_winsys.c
index ebf7697ac33dfca8a0dab33fcec0bce42fc7cb06..7cda70a98d30c37be15827190c2ca3c71d5622b9 100644 (file)
 #include <sys/stat.h>
 #include <unistd.h>
 
+#ifndef RADEON_INFO_ACTIVE_CU_COUNT
+#define RADEON_INFO_ACTIVE_CU_COUNT 0x20
+#endif
+
 static struct util_hash_table *fd_tab = NULL;
 pipe_static_mutex(fd_tab_mutex);
 
@@ -276,13 +280,15 @@ static boolean do_winsys_init(struct radeon_drm_winsys *ws)
     case CHIP_KAVERI:
     case CHIP_KABINI:
     case CHIP_HAWAII:
+    case CHIP_MULLINS:
         ws->info.chip_class = CIK;
         break;
     }
 
     /* Check for dma */
     ws->info.r600_has_dma = FALSE;
-    if (ws->info.chip_class >= R700 && ws->info.drm_minor >= 27) {
+    /* DMA is disabled on R700. There is IB corruption and hangs. */
+    if (ws->info.chip_class >= EVERGREEN && ws->info.drm_minor >= 27) {
         ws->info.r600_has_dma = TRUE;
     }
 
@@ -316,6 +322,11 @@ static boolean do_winsys_init(struct radeon_drm_winsys *ws)
     ws->info.gart_size = gem_info.gart_size;
     ws->info.vram_size = gem_info.vram_size;
 
+    /* Get max clock frequency info and convert it to MHz */
+    radeon_get_drm_value(ws->fd, RADEON_INFO_MAX_SCLK, NULL,
+                         &ws->info.max_sclk);
+    ws->info.max_sclk /= 1000;
+
     ws->num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
 
     /* Generation-specific queries. */
@@ -375,6 +386,15 @@ static boolean do_winsys_init(struct radeon_drm_winsys *ws)
     radeon_get_drm_value(ws->fd, RADEON_INFO_MAX_PIPES, NULL,
                          &ws->info.r600_max_pipes);
 
+    radeon_get_drm_value(ws->fd, RADEON_INFO_ACTIVE_CU_COUNT, NULL,
+                         &ws->info.max_compute_units);
+
+    radeon_get_drm_value(ws->fd, RADEON_INFO_MAX_SE, NULL,
+                         &ws->info.max_se);
+
+    radeon_get_drm_value(ws->fd, RADEON_INFO_MAX_SH_PER_SE, NULL,
+                         &ws->info.max_sh_per_se);
+
     if (radeon_get_drm_value(ws->fd, RADEON_INFO_SI_TILE_MODE_ARRAY, NULL,
                              ws->info.si_tile_mode_array)) {
         ws->info.si_tile_mode_array_valid = TRUE;
@@ -392,12 +412,6 @@ static void radeon_winsys_destroy(struct radeon_winsys *rws)
 {
     struct radeon_drm_winsys *ws = (struct radeon_drm_winsys*)rws;
 
-    pipe_mutex_lock(fd_tab_mutex);
-    if (fd_tab) {
-        util_hash_table_remove(fd_tab, intptr_to_pointer(ws->fd));
-    }
-    pipe_mutex_unlock(fd_tab_mutex);
-
     if (ws->thread) {
         ws->kill_thread = 1;
         pipe_semaphore_signal(&ws->cs_queued);
@@ -573,7 +587,27 @@ static PIPE_THREAD_ROUTINE(radeon_drm_cs_emit_ioctl, param)
 DEBUG_GET_ONCE_BOOL_OPTION(thread, "RADEON_THREAD", TRUE)
 static PIPE_THREAD_ROUTINE(radeon_drm_cs_emit_ioctl, param);
 
-PUBLIC struct radeon_winsys *radeon_drm_winsys_create(int fd)
+static bool radeon_winsys_unref(struct radeon_winsys *ws)
+{
+    struct radeon_drm_winsys *rws = (struct radeon_drm_winsys*)ws;
+    bool destroy;
+
+    /* When the reference counter drops to zero, remove the fd from the table.
+     * This must happen while the mutex is locked, so that
+     * radeon_drm_winsys_create in another thread doesn't get the winsys
+     * from the table when the counter drops to 0. */
+    pipe_mutex_lock(fd_tab_mutex);
+
+    destroy = pipe_reference(&rws->reference, NULL);
+    if (destroy && fd_tab)
+        util_hash_table_remove(fd_tab, intptr_to_pointer(rws->fd));
+
+    pipe_mutex_unlock(fd_tab_mutex);
+    return destroy;
+}
+
+PUBLIC struct radeon_winsys *
+radeon_drm_winsys_create(int fd, radeon_screen_create_t screen_create)
 {
     struct radeon_drm_winsys *ws;
 
@@ -584,8 +618,8 @@ PUBLIC struct radeon_winsys *radeon_drm_winsys_create(int fd)
 
     ws = util_hash_table_get(fd_tab, intptr_to_pointer(fd));
     if (ws) {
+        pipe_reference(NULL, &ws->reference);
         pipe_mutex_unlock(fd_tab_mutex);
-        pipe_reference(NULL, &ws->base.reference);
         return &ws->base;
     }
 
@@ -596,7 +630,6 @@ PUBLIC struct radeon_winsys *radeon_drm_winsys_create(int fd)
     }
 
     ws->fd = fd;
-    util_hash_table_set(fd_tab, intptr_to_pointer(fd), ws);
 
     if (!do_winsys_init(ws))
         goto fail;
@@ -616,9 +649,10 @@ PUBLIC struct radeon_winsys *radeon_drm_winsys_create(int fd)
     }
 
     /* init reference */
-    pipe_reference_init(&ws->base.reference, 1);
+    pipe_reference_init(&ws->reference, 1);
 
     /* Set functions. */
+    ws->base.unref = radeon_winsys_unref;
     ws->base.destroy = radeon_winsys_destroy;
     ws->base.query_info = radeon_query_info;
     ws->base.cs_request_feature = radeon_cs_request_feature;
@@ -638,6 +672,20 @@ PUBLIC struct radeon_winsys *radeon_drm_winsys_create(int fd)
     if (ws->num_cpus > 1 && debug_get_option_thread())
         ws->thread = pipe_thread_create(radeon_drm_cs_emit_ioctl, ws);
 
+    /* Create the screen at the end. The winsys must be initialized
+     * completely.
+     *
+     * Alternatively, we could create the screen based on "ws->gen"
+     * and link all drivers into one binary blob. */
+    ws->base.screen = screen_create(&ws->base);
+    if (!ws->base.screen) {
+        radeon_winsys_destroy(&ws->base);
+        pipe_mutex_unlock(fd_tab_mutex);
+        return NULL;
+    }
+
+    util_hash_table_set(fd_tab, intptr_to_pointer(fd), ws);
+
     /* We must unlock the mutex once the winsys is fully initialized, so that
      * other threads attempting to create the winsys from the same fd will
      * get a fully initialized winsys and not just half-way initialized. */