diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_kms.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_kms.c | 187 |
1 files changed, 113 insertions, 74 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index c75cb2c6ba71..4f2d4f4c1dab 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c | |||
@@ -50,9 +50,13 @@ int radeon_driver_unload_kms(struct drm_device *dev) | |||
50 | 50 | ||
51 | if (rdev == NULL) | 51 | if (rdev == NULL) |
52 | return 0; | 52 | return 0; |
53 | if (rdev->rmmio == NULL) | ||
54 | goto done_free; | ||
53 | radeon_acpi_fini(rdev); | 55 | radeon_acpi_fini(rdev); |
54 | radeon_modeset_fini(rdev); | 56 | radeon_modeset_fini(rdev); |
55 | radeon_device_fini(rdev); | 57 | radeon_device_fini(rdev); |
58 | |||
59 | done_free: | ||
56 | kfree(rdev); | 60 | kfree(rdev); |
57 | dev->dev_private = NULL; | 61 | dev->dev_private = NULL; |
58 | return 0; | 62 | return 0; |
@@ -176,80 +180,65 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) | |||
176 | struct radeon_device *rdev = dev->dev_private; | 180 | struct radeon_device *rdev = dev->dev_private; |
177 | struct drm_radeon_info *info = data; | 181 | struct drm_radeon_info *info = data; |
178 | struct radeon_mode_info *minfo = &rdev->mode_info; | 182 | struct radeon_mode_info *minfo = &rdev->mode_info; |
179 | uint32_t value, *value_ptr; | 183 | uint32_t *value, value_tmp, *value_ptr, value_size; |
180 | uint64_t value64, *value_ptr64; | 184 | uint64_t value64; |
181 | struct drm_crtc *crtc; | 185 | struct drm_crtc *crtc; |
182 | int i, found; | 186 | int i, found; |
183 | 187 | ||
184 | /* TIMESTAMP is a 64-bit value, needs special handling. */ | ||
185 | if (info->request == RADEON_INFO_TIMESTAMP) { | ||
186 | if (rdev->family >= CHIP_R600) { | ||
187 | value_ptr64 = (uint64_t*)((unsigned long)info->value); | ||
188 | value64 = radeon_get_gpu_clock_counter(rdev); | ||
189 | |||
190 | if (DRM_COPY_TO_USER(value_ptr64, &value64, sizeof(value64))) { | ||
191 | DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__); | ||
192 | return -EFAULT; | ||
193 | } | ||
194 | return 0; | ||
195 | } else { | ||
196 | DRM_DEBUG_KMS("timestamp is r6xx+ only!\n"); | ||
197 | return -EINVAL; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | value_ptr = (uint32_t *)((unsigned long)info->value); | 188 | value_ptr = (uint32_t *)((unsigned long)info->value); |
202 | if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value))) { | 189 | value = &value_tmp; |
203 | DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__); | 190 | value_size = sizeof(uint32_t); |
204 | return -EFAULT; | ||
205 | } | ||
206 | 191 | ||
207 | switch (info->request) { | 192 | switch (info->request) { |
208 | case RADEON_INFO_DEVICE_ID: | 193 | case RADEON_INFO_DEVICE_ID: |
209 | value = dev->pci_device; | 194 | *value = dev->pci_device; |
210 | break; | 195 | break; |
211 | case RADEON_INFO_NUM_GB_PIPES: | 196 | case RADEON_INFO_NUM_GB_PIPES: |
212 | value = rdev->num_gb_pipes; | 197 | *value = rdev->num_gb_pipes; |
213 | break; | 198 | break; |
214 | case RADEON_INFO_NUM_Z_PIPES: | 199 | case RADEON_INFO_NUM_Z_PIPES: |
215 | value = rdev->num_z_pipes; | 200 | *value = rdev->num_z_pipes; |
216 | break; | 201 | break; |
217 | case RADEON_INFO_ACCEL_WORKING: | 202 | case RADEON_INFO_ACCEL_WORKING: |
218 | /* xf86-video-ati 6.13.0 relies on this being false for evergreen */ | 203 | /* xf86-video-ati 6.13.0 relies on this being false for evergreen */ |
219 | if ((rdev->family >= CHIP_CEDAR) && (rdev->family <= CHIP_HEMLOCK)) | 204 | if ((rdev->family >= CHIP_CEDAR) && (rdev->family <= CHIP_HEMLOCK)) |
220 | value = false; | 205 | *value = false; |
221 | else | 206 | else |
222 | value = rdev->accel_working; | 207 | *value = rdev->accel_working; |
223 | break; | 208 | break; |
224 | case RADEON_INFO_CRTC_FROM_ID: | 209 | case RADEON_INFO_CRTC_FROM_ID: |
210 | if (DRM_COPY_FROM_USER(value, value_ptr, sizeof(uint32_t))) { | ||
211 | DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__); | ||
212 | return -EFAULT; | ||
213 | } | ||
225 | for (i = 0, found = 0; i < rdev->num_crtc; i++) { | 214 | for (i = 0, found = 0; i < rdev->num_crtc; i++) { |
226 | crtc = (struct drm_crtc *)minfo->crtcs[i]; | 215 | crtc = (struct drm_crtc *)minfo->crtcs[i]; |
227 | if (crtc && crtc->base.id == value) { | 216 | if (crtc && crtc->base.id == *value) { |
228 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | 217 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
229 | value = radeon_crtc->crtc_id; | 218 | *value = radeon_crtc->crtc_id; |
230 | found = 1; | 219 | found = 1; |
231 | break; | 220 | break; |
232 | } | 221 | } |
233 | } | 222 | } |
234 | if (!found) { | 223 | if (!found) { |
235 | DRM_DEBUG_KMS("unknown crtc id %d\n", value); | 224 | DRM_DEBUG_KMS("unknown crtc id %d\n", *value); |
236 | return -EINVAL; | 225 | return -EINVAL; |
237 | } | 226 | } |
238 | break; | 227 | break; |
239 | case RADEON_INFO_ACCEL_WORKING2: | 228 | case RADEON_INFO_ACCEL_WORKING2: |
240 | value = rdev->accel_working; | 229 | *value = rdev->accel_working; |
241 | break; | 230 | break; |
242 | case RADEON_INFO_TILING_CONFIG: | 231 | case RADEON_INFO_TILING_CONFIG: |
243 | if (rdev->family >= CHIP_TAHITI) | 232 | if (rdev->family >= CHIP_TAHITI) |
244 | value = rdev->config.si.tile_config; | 233 | *value = rdev->config.si.tile_config; |
245 | else if (rdev->family >= CHIP_CAYMAN) | 234 | else if (rdev->family >= CHIP_CAYMAN) |
246 | value = rdev->config.cayman.tile_config; | 235 | *value = rdev->config.cayman.tile_config; |
247 | else if (rdev->family >= CHIP_CEDAR) | 236 | else if (rdev->family >= CHIP_CEDAR) |
248 | value = rdev->config.evergreen.tile_config; | 237 | *value = rdev->config.evergreen.tile_config; |
249 | else if (rdev->family >= CHIP_RV770) | 238 | else if (rdev->family >= CHIP_RV770) |
250 | value = rdev->config.rv770.tile_config; | 239 | *value = rdev->config.rv770.tile_config; |
251 | else if (rdev->family >= CHIP_R600) | 240 | else if (rdev->family >= CHIP_R600) |
252 | value = rdev->config.r600.tile_config; | 241 | *value = rdev->config.r600.tile_config; |
253 | else { | 242 | else { |
254 | DRM_DEBUG_KMS("tiling config is r6xx+ only!\n"); | 243 | DRM_DEBUG_KMS("tiling config is r6xx+ only!\n"); |
255 | return -EINVAL; | 244 | return -EINVAL; |
@@ -262,73 +251,81 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) | |||
262 | * | 251 | * |
263 | * When returning, the value is 1 if filp owns hyper-z access, | 252 | * When returning, the value is 1 if filp owns hyper-z access, |
264 | * 0 otherwise. */ | 253 | * 0 otherwise. */ |
265 | if (value >= 2) { | 254 | if (DRM_COPY_FROM_USER(value, value_ptr, sizeof(uint32_t))) { |
266 | DRM_DEBUG_KMS("WANT_HYPERZ: invalid value %d\n", value); | 255 | DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__); |
256 | return -EFAULT; | ||
257 | } | ||
258 | if (*value >= 2) { | ||
259 | DRM_DEBUG_KMS("WANT_HYPERZ: invalid value %d\n", *value); | ||
267 | return -EINVAL; | 260 | return -EINVAL; |
268 | } | 261 | } |
269 | radeon_set_filp_rights(dev, &rdev->hyperz_filp, filp, &value); | 262 | radeon_set_filp_rights(dev, &rdev->hyperz_filp, filp, value); |
270 | break; | 263 | break; |
271 | case RADEON_INFO_WANT_CMASK: | 264 | case RADEON_INFO_WANT_CMASK: |
272 | /* The same logic as Hyper-Z. */ | 265 | /* The same logic as Hyper-Z. */ |
273 | if (value >= 2) { | 266 | if (DRM_COPY_FROM_USER(value, value_ptr, sizeof(uint32_t))) { |
274 | DRM_DEBUG_KMS("WANT_CMASK: invalid value %d\n", value); | 267 | DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__); |
268 | return -EFAULT; | ||
269 | } | ||
270 | if (*value >= 2) { | ||
271 | DRM_DEBUG_KMS("WANT_CMASK: invalid value %d\n", *value); | ||
275 | return -EINVAL; | 272 | return -EINVAL; |
276 | } | 273 | } |
277 | radeon_set_filp_rights(dev, &rdev->cmask_filp, filp, &value); | 274 | radeon_set_filp_rights(dev, &rdev->cmask_filp, filp, value); |
278 | break; | 275 | break; |
279 | case RADEON_INFO_CLOCK_CRYSTAL_FREQ: | 276 | case RADEON_INFO_CLOCK_CRYSTAL_FREQ: |
280 | /* return clock value in KHz */ | 277 | /* return clock value in KHz */ |
281 | if (rdev->asic->get_xclk) | 278 | if (rdev->asic->get_xclk) |
282 | value = radeon_get_xclk(rdev) * 10; | 279 | *value = radeon_get_xclk(rdev) * 10; |
283 | else | 280 | else |
284 | value = rdev->clock.spll.reference_freq * 10; | 281 | *value = rdev->clock.spll.reference_freq * 10; |
285 | break; | 282 | break; |
286 | case RADEON_INFO_NUM_BACKENDS: | 283 | case RADEON_INFO_NUM_BACKENDS: |
287 | if (rdev->family >= CHIP_TAHITI) | 284 | if (rdev->family >= CHIP_TAHITI) |
288 | value = rdev->config.si.max_backends_per_se * | 285 | *value = rdev->config.si.max_backends_per_se * |
289 | rdev->config.si.max_shader_engines; | 286 | rdev->config.si.max_shader_engines; |
290 | else if (rdev->family >= CHIP_CAYMAN) | 287 | else if (rdev->family >= CHIP_CAYMAN) |
291 | value = rdev->config.cayman.max_backends_per_se * | 288 | *value = rdev->config.cayman.max_backends_per_se * |
292 | rdev->config.cayman.max_shader_engines; | 289 | rdev->config.cayman.max_shader_engines; |
293 | else if (rdev->family >= CHIP_CEDAR) | 290 | else if (rdev->family >= CHIP_CEDAR) |
294 | value = rdev->config.evergreen.max_backends; | 291 | *value = rdev->config.evergreen.max_backends; |
295 | else if (rdev->family >= CHIP_RV770) | 292 | else if (rdev->family >= CHIP_RV770) |
296 | value = rdev->config.rv770.max_backends; | 293 | *value = rdev->config.rv770.max_backends; |
297 | else if (rdev->family >= CHIP_R600) | 294 | else if (rdev->family >= CHIP_R600) |
298 | value = rdev->config.r600.max_backends; | 295 | *value = rdev->config.r600.max_backends; |
299 | else { | 296 | else { |
300 | return -EINVAL; | 297 | return -EINVAL; |
301 | } | 298 | } |
302 | break; | 299 | break; |
303 | case RADEON_INFO_NUM_TILE_PIPES: | 300 | case RADEON_INFO_NUM_TILE_PIPES: |
304 | if (rdev->family >= CHIP_TAHITI) | 301 | if (rdev->family >= CHIP_TAHITI) |
305 | value = rdev->config.si.max_tile_pipes; | 302 | *value = rdev->config.si.max_tile_pipes; |
306 | else if (rdev->family >= CHIP_CAYMAN) | 303 | else if (rdev->family >= CHIP_CAYMAN) |
307 | value = rdev->config.cayman.max_tile_pipes; | 304 | *value = rdev->config.cayman.max_tile_pipes; |
308 | else if (rdev->family >= CHIP_CEDAR) | 305 | else if (rdev->family >= CHIP_CEDAR) |
309 | value = rdev->config.evergreen.max_tile_pipes; | 306 | *value = rdev->config.evergreen.max_tile_pipes; |
310 | else if (rdev->family >= CHIP_RV770) | 307 | else if (rdev->family >= CHIP_RV770) |
311 | value = rdev->config.rv770.max_tile_pipes; | 308 | *value = rdev->config.rv770.max_tile_pipes; |
312 | else if (rdev->family >= CHIP_R600) | 309 | else if (rdev->family >= CHIP_R600) |
313 | value = rdev->config.r600.max_tile_pipes; | 310 | *value = rdev->config.r600.max_tile_pipes; |
314 | else { | 311 | else { |
315 | return -EINVAL; | 312 | return -EINVAL; |
316 | } | 313 | } |
317 | break; | 314 | break; |
318 | case RADEON_INFO_FUSION_GART_WORKING: | 315 | case RADEON_INFO_FUSION_GART_WORKING: |
319 | value = 1; | 316 | *value = 1; |
320 | break; | 317 | break; |
321 | case RADEON_INFO_BACKEND_MAP: | 318 | case RADEON_INFO_BACKEND_MAP: |
322 | if (rdev->family >= CHIP_TAHITI) | 319 | if (rdev->family >= CHIP_TAHITI) |
323 | value = rdev->config.si.backend_map; | 320 | *value = rdev->config.si.backend_map; |
324 | else if (rdev->family >= CHIP_CAYMAN) | 321 | else if (rdev->family >= CHIP_CAYMAN) |
325 | value = rdev->config.cayman.backend_map; | 322 | *value = rdev->config.cayman.backend_map; |
326 | else if (rdev->family >= CHIP_CEDAR) | 323 | else if (rdev->family >= CHIP_CEDAR) |
327 | value = rdev->config.evergreen.backend_map; | 324 | *value = rdev->config.evergreen.backend_map; |
328 | else if (rdev->family >= CHIP_RV770) | 325 | else if (rdev->family >= CHIP_RV770) |
329 | value = rdev->config.rv770.backend_map; | 326 | *value = rdev->config.rv770.backend_map; |
330 | else if (rdev->family >= CHIP_R600) | 327 | else if (rdev->family >= CHIP_R600) |
331 | value = rdev->config.r600.backend_map; | 328 | *value = rdev->config.r600.backend_map; |
332 | else { | 329 | else { |
333 | return -EINVAL; | 330 | return -EINVAL; |
334 | } | 331 | } |
@@ -337,50 +334,91 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) | |||
337 | /* this is where we report if vm is supported or not */ | 334 | /* this is where we report if vm is supported or not */ |
338 | if (rdev->family < CHIP_CAYMAN) | 335 | if (rdev->family < CHIP_CAYMAN) |
339 | return -EINVAL; | 336 | return -EINVAL; |
340 | value = RADEON_VA_RESERVED_SIZE; | 337 | *value = RADEON_VA_RESERVED_SIZE; |
341 | break; | 338 | break; |
342 | case RADEON_INFO_IB_VM_MAX_SIZE: | 339 | case RADEON_INFO_IB_VM_MAX_SIZE: |
343 | /* this is where we report if vm is supported or not */ | 340 | /* this is where we report if vm is supported or not */ |
344 | if (rdev->family < CHIP_CAYMAN) | 341 | if (rdev->family < CHIP_CAYMAN) |
345 | return -EINVAL; | 342 | return -EINVAL; |
346 | value = RADEON_IB_VM_MAX_SIZE; | 343 | *value = RADEON_IB_VM_MAX_SIZE; |
347 | break; | 344 | break; |
348 | case RADEON_INFO_MAX_PIPES: | 345 | case RADEON_INFO_MAX_PIPES: |
349 | if (rdev->family >= CHIP_TAHITI) | 346 | if (rdev->family >= CHIP_TAHITI) |
350 | value = rdev->config.si.max_cu_per_sh; | 347 | *value = rdev->config.si.max_cu_per_sh; |
351 | else if (rdev->family >= CHIP_CAYMAN) | 348 | else if (rdev->family >= CHIP_CAYMAN) |
352 | value = rdev->config.cayman.max_pipes_per_simd; | 349 | *value = rdev->config.cayman.max_pipes_per_simd; |
353 | else if (rdev->family >= CHIP_CEDAR) | 350 | else if (rdev->family >= CHIP_CEDAR) |
354 | value = rdev->config.evergreen.max_pipes; | 351 | *value = rdev->config.evergreen.max_pipes; |
355 | else if (rdev->family >= CHIP_RV770) | 352 | else if (rdev->family >= CHIP_RV770) |
356 | value = rdev->config.rv770.max_pipes; | 353 | *value = rdev->config.rv770.max_pipes; |
357 | else if (rdev->family >= CHIP_R600) | 354 | else if (rdev->family >= CHIP_R600) |
358 | value = rdev->config.r600.max_pipes; | 355 | *value = rdev->config.r600.max_pipes; |
359 | else { | 356 | else { |
360 | return -EINVAL; | 357 | return -EINVAL; |
361 | } | 358 | } |
362 | break; | 359 | break; |
360 | case RADEON_INFO_TIMESTAMP: | ||
361 | if (rdev->family < CHIP_R600) { | ||
362 | DRM_DEBUG_KMS("timestamp is r6xx+ only!\n"); | ||
363 | return -EINVAL; | ||
364 | } | ||
365 | value = (uint32_t*)&value64; | ||
366 | value_size = sizeof(uint64_t); | ||
367 | value64 = radeon_get_gpu_clock_counter(rdev); | ||
368 | break; | ||
363 | case RADEON_INFO_MAX_SE: | 369 | case RADEON_INFO_MAX_SE: |
364 | if (rdev->family >= CHIP_TAHITI) | 370 | if (rdev->family >= CHIP_TAHITI) |
365 | value = rdev->config.si.max_shader_engines; | 371 | *value = rdev->config.si.max_shader_engines; |
366 | else if (rdev->family >= CHIP_CAYMAN) | 372 | else if (rdev->family >= CHIP_CAYMAN) |
367 | value = rdev->config.cayman.max_shader_engines; | 373 | *value = rdev->config.cayman.max_shader_engines; |
368 | else if (rdev->family >= CHIP_CEDAR) | 374 | else if (rdev->family >= CHIP_CEDAR) |
369 | value = rdev->config.evergreen.num_ses; | 375 | *value = rdev->config.evergreen.num_ses; |
370 | else | 376 | else |
371 | value = 1; | 377 | *value = 1; |
372 | break; | 378 | break; |
373 | case RADEON_INFO_MAX_SH_PER_SE: | 379 | case RADEON_INFO_MAX_SH_PER_SE: |
374 | if (rdev->family >= CHIP_TAHITI) | 380 | if (rdev->family >= CHIP_TAHITI) |
375 | value = rdev->config.si.max_sh_per_se; | 381 | *value = rdev->config.si.max_sh_per_se; |
376 | else | 382 | else |
377 | return -EINVAL; | 383 | return -EINVAL; |
378 | break; | 384 | break; |
385 | case RADEON_INFO_FASTFB_WORKING: | ||
386 | *value = rdev->fastfb_working; | ||
387 | break; | ||
388 | case RADEON_INFO_RING_WORKING: | ||
389 | if (DRM_COPY_FROM_USER(value, value_ptr, sizeof(uint32_t))) { | ||
390 | DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__); | ||
391 | return -EFAULT; | ||
392 | } | ||
393 | switch (*value) { | ||
394 | case RADEON_CS_RING_GFX: | ||
395 | case RADEON_CS_RING_COMPUTE: | ||
396 | *value = rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready; | ||
397 | break; | ||
398 | case RADEON_CS_RING_DMA: | ||
399 | *value = rdev->ring[R600_RING_TYPE_DMA_INDEX].ready; | ||
400 | *value |= rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX].ready; | ||
401 | break; | ||
402 | case RADEON_CS_RING_UVD: | ||
403 | *value = rdev->ring[R600_RING_TYPE_UVD_INDEX].ready; | ||
404 | break; | ||
405 | default: | ||
406 | return -EINVAL; | ||
407 | } | ||
408 | break; | ||
409 | case RADEON_INFO_SI_TILE_MODE_ARRAY: | ||
410 | if (rdev->family < CHIP_TAHITI) { | ||
411 | DRM_DEBUG_KMS("tile mode array is si only!\n"); | ||
412 | return -EINVAL; | ||
413 | } | ||
414 | value = rdev->config.si.tile_mode_array; | ||
415 | value_size = sizeof(uint32_t)*32; | ||
416 | break; | ||
379 | default: | 417 | default: |
380 | DRM_DEBUG_KMS("Invalid request %d\n", info->request); | 418 | DRM_DEBUG_KMS("Invalid request %d\n", info->request); |
381 | return -EINVAL; | 419 | return -EINVAL; |
382 | } | 420 | } |
383 | if (DRM_COPY_TO_USER(value_ptr, &value, sizeof(uint32_t))) { | 421 | if (DRM_COPY_TO_USER(value_ptr, (char*)value, value_size)) { |
384 | DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__); | 422 | DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__); |
385 | return -EFAULT; | 423 | return -EFAULT; |
386 | } | 424 | } |
@@ -513,6 +551,7 @@ void radeon_driver_preclose_kms(struct drm_device *dev, | |||
513 | rdev->hyperz_filp = NULL; | 551 | rdev->hyperz_filp = NULL; |
514 | if (rdev->cmask_filp == file_priv) | 552 | if (rdev->cmask_filp == file_priv) |
515 | rdev->cmask_filp = NULL; | 553 | rdev->cmask_filp = NULL; |
554 | radeon_uvd_free_handles(rdev, file_priv); | ||
516 | } | 555 | } |
517 | 556 | ||
518 | /* | 557 | /* |