Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/radeon: protect concurrent smc register access with a spinlock

smc registers are access indirectly via the main mmio aperture, so
there may be problems with concurrent access. This adds a spinlock
to protect access to this register space.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

+91 -47
+26 -13
drivers/gpu/drm/radeon/ci_smc.c
··· 47 47 u32 smc_start_address, 48 48 const u8 *src, u32 byte_count, u32 limit) 49 49 { 50 + unsigned long flags; 50 51 u32 data, original_data; 51 52 u32 addr; 52 53 u32 extra_shift; 53 - int ret; 54 + int ret = 0; 54 55 55 56 if (smc_start_address & 3) 56 57 return -EINVAL; ··· 60 59 61 60 addr = smc_start_address; 62 61 62 + spin_lock_irqsave(&rdev->smc_idx_lock, flags); 63 63 while (byte_count >= 4) { 64 64 /* SMC address space is BE */ 65 65 data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; 66 66 67 67 ret = ci_set_smc_sram_address(rdev, addr, limit); 68 68 if (ret) 69 - return ret; 69 + goto done; 70 70 71 71 WREG32(SMC_IND_DATA_0, data); 72 72 ··· 82 80 83 81 ret = ci_set_smc_sram_address(rdev, addr, limit); 84 82 if (ret) 85 - return ret; 83 + goto done; 86 84 87 85 original_data = RREG32(SMC_IND_DATA_0); 88 86 ··· 99 97 100 98 ret = ci_set_smc_sram_address(rdev, addr, limit); 101 99 if (ret) 102 - return ret; 100 + goto done; 103 101 104 102 WREG32(SMC_IND_DATA_0, data); 105 103 } 106 - return 0; 104 + 105 + done: 106 + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 107 + 108 + return ret; 107 109 } 108 110 109 111 void ci_start_smc(struct radeon_device *rdev) ··· 203 197 204 198 int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit) 205 199 { 200 + unsigned long flags; 206 201 u32 ucode_start_address; 207 202 u32 ucode_size; 208 203 const u8 *src; ··· 226 219 return -EINVAL; 227 220 228 221 src = (const u8 *)rdev->smc_fw->data; 222 + spin_lock_irqsave(&rdev->smc_idx_lock, flags); 229 223 WREG32(SMC_IND_INDEX_0, ucode_start_address); 230 224 WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0); 231 225 while (ucode_size >= 4) { ··· 239 231 ucode_size -= 4; 240 232 } 241 233 WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0); 234 + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 242 235 243 236 return 0; 244 237 } ··· 247 238 int ci_read_smc_sram_dword(struct radeon_device *rdev, 248 239 u32 smc_address, u32 *value, u32 limit) 249 240 { 241 + unsigned long flags; 250 242 int ret; 251 243 244 + spin_lock_irqsave(&rdev->smc_idx_lock, flags); 252 245 ret = ci_set_smc_sram_address(rdev, smc_address, limit); 253 - if (ret) 254 - return ret; 246 + if (ret == 0) 247 + *value = RREG32(SMC_IND_DATA_0); 248 + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 255 249 256 - *value = RREG32(SMC_IND_DATA_0); 257 - return 0; 250 + return ret; 258 251 } 259 252 260 253 int ci_write_smc_sram_dword(struct radeon_device *rdev, 261 254 u32 smc_address, u32 value, u32 limit) 262 255 { 256 + unsigned long flags; 263 257 int ret; 264 258 259 + spin_lock_irqsave(&rdev->smc_idx_lock, flags); 265 260 ret = ci_set_smc_sram_address(rdev, smc_address, limit); 266 - if (ret) 267 - return ret; 261 + if (ret == 0) 262 + WREG32(SMC_IND_DATA_0, value); 263 + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 268 264 269 - WREG32(SMC_IND_DATA_0, value); 270 - return 0; 265 + return ret; 271 266 }
+9
drivers/gpu/drm/radeon/radeon.h
··· 2110 2110 resource_size_t rmmio_size; 2111 2111 /* protects concurrent MM_INDEX/DATA based register access */ 2112 2112 spinlock_t mmio_idx_lock; 2113 + /* protects concurrent SMC based register access */ 2114 + spinlock_t smc_idx_lock; 2113 2115 void __iomem *rmmio; 2114 2116 radeon_rreg_t mc_rreg; 2115 2117 radeon_wreg_t mc_wreg; ··· 2294 2292 2295 2293 static inline u32 tn_smc_rreg(struct radeon_device *rdev, u32 reg) 2296 2294 { 2295 + unsigned long flags; 2297 2296 u32 r; 2298 2297 2298 + spin_lock_irqsave(&rdev->smc_idx_lock, flags); 2299 2299 WREG32(TN_SMC_IND_INDEX_0, (reg)); 2300 2300 r = RREG32(TN_SMC_IND_DATA_0); 2301 + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 2301 2302 return r; 2302 2303 } 2303 2304 2304 2305 static inline void tn_smc_wreg(struct radeon_device *rdev, u32 reg, u32 v) 2305 2306 { 2307 + unsigned long flags; 2308 + 2309 + spin_lock_irqsave(&rdev->smc_idx_lock, flags); 2306 2310 WREG32(TN_SMC_IND_INDEX_0, (reg)); 2307 2311 WREG32(TN_SMC_IND_DATA_0, (v)); 2312 + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 2308 2313 } 2309 2314 2310 2315 static inline u32 r600_rcu_rreg(struct radeon_device *rdev, u32 reg)
+1
drivers/gpu/drm/radeon/radeon_device.c
··· 1249 1249 /* Registers mapping */ 1250 1250 /* TODO: block userspace mapping of io register */ 1251 1251 spin_lock_init(&rdev->mmio_idx_lock); 1252 + spin_lock_init(&rdev->smc_idx_lock); 1252 1253 if (rdev->family >= CHIP_BONAIRE) { 1253 1254 rdev->rmmio_base = pci_resource_start(rdev->pdev, 5); 1254 1255 rdev->rmmio_size = pci_resource_len(rdev->pdev, 5);
+27 -17
drivers/gpu/drm/radeon/rv770_smc.c
··· 274 274 0x08, 0x72, 0x08, 0x72 275 275 }; 276 276 277 - int rv770_set_smc_sram_address(struct radeon_device *rdev, 278 - u16 smc_address, u16 limit) 277 + static int rv770_set_smc_sram_address(struct radeon_device *rdev, 278 + u16 smc_address, u16 limit) 279 279 { 280 280 u32 addr; 281 281 ··· 296 296 u16 smc_start_address, const u8 *src, 297 297 u16 byte_count, u16 limit) 298 298 { 299 + unsigned long flags; 299 300 u32 data, original_data, extra_shift; 300 301 u16 addr; 301 - int ret; 302 + int ret = 0; 302 303 303 304 if (smc_start_address & 3) 304 305 return -EINVAL; ··· 308 307 309 308 addr = smc_start_address; 310 309 310 + spin_lock_irqsave(&rdev->smc_idx_lock, flags); 311 311 while (byte_count >= 4) { 312 312 /* SMC address space is BE */ 313 313 data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; 314 314 315 315 ret = rv770_set_smc_sram_address(rdev, addr, limit); 316 316 if (ret) 317 - return ret; 317 + goto done; 318 318 319 319 WREG32(SMC_SRAM_DATA, data); 320 320 ··· 330 328 331 329 ret = rv770_set_smc_sram_address(rdev, addr, limit); 332 330 if (ret) 333 - return ret; 331 + goto done; 334 332 335 333 original_data = RREG32(SMC_SRAM_DATA); 336 334 ··· 348 346 349 347 ret = rv770_set_smc_sram_address(rdev, addr, limit); 350 348 if (ret) 351 - return ret; 349 + goto done; 352 350 353 351 WREG32(SMC_SRAM_DATA, data); 354 352 } 355 353 356 - return 0; 354 + done: 355 + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 356 + 357 + return ret; 357 358 } 358 359 359 360 static int rv770_program_interrupt_vectors(struct radeon_device *rdev, ··· 466 461 467 462 static void rv770_clear_smc_sram(struct radeon_device *rdev, u16 limit) 468 463 { 464 + unsigned long flags; 469 465 u16 i; 470 466 467 + spin_lock_irqsave(&rdev->smc_idx_lock, flags); 471 468 for (i = 0; i < limit; i += 4) { 472 469 rv770_set_smc_sram_address(rdev, i, limit); 473 470 WREG32(SMC_SRAM_DATA, 0); 474 471 } 472 + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 475 473 } 476 474 477 475 int rv770_load_smc_ucode(struct radeon_device *rdev, ··· 603 595 int rv770_read_smc_sram_dword(struct radeon_device *rdev, 604 596 u16 smc_address, u32 *value, u16 limit) 605 597 { 598 + unsigned long flags; 606 599 int ret; 607 600 601 + spin_lock_irqsave(&rdev->smc_idx_lock, flags); 608 602 ret = rv770_set_smc_sram_address(rdev, smc_address, limit); 609 - if (ret) 610 - return ret; 603 + if (ret == 0) 604 + *value = RREG32(SMC_SRAM_DATA); 605 + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 611 606 612 - *value = RREG32(SMC_SRAM_DATA); 613 - 614 - return 0; 607 + return ret; 615 608 } 616 609 617 610 int rv770_write_smc_sram_dword(struct radeon_device *rdev, 618 611 u16 smc_address, u32 value, u16 limit) 619 612 { 613 + unsigned long flags; 620 614 int ret; 621 615 616 + spin_lock_irqsave(&rdev->smc_idx_lock, flags); 622 617 ret = rv770_set_smc_sram_address(rdev, smc_address, limit); 623 - if (ret) 624 - return ret; 618 + if (ret == 0) 619 + WREG32(SMC_SRAM_DATA, value); 620 + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 625 621 626 - WREG32(SMC_SRAM_DATA, value); 627 - 628 - return 0; 622 + return ret; 629 623 }
-2
drivers/gpu/drm/radeon/rv770_smc.h
··· 187 187 #define RV770_SMC_SOFT_REGISTER_uvd_enabled 0x9C 188 188 #define RV770_SMC_SOFT_REGISTER_is_asic_lombok 0xA0 189 189 190 - int rv770_set_smc_sram_address(struct radeon_device *rdev, 191 - u16 smc_address, u16 limit); 192 190 int rv770_copy_bytes_to_smc(struct radeon_device *rdev, 193 191 u16 smc_start_address, const u8 *src, 194 192 u16 byte_count, u16 limit);
+28 -15
drivers/gpu/drm/radeon/si_smc.c
··· 29 29 #include "ppsmc.h" 30 30 #include "radeon_ucode.h" 31 31 32 - int si_set_smc_sram_address(struct radeon_device *rdev, 33 - u32 smc_address, u32 limit) 32 + static int si_set_smc_sram_address(struct radeon_device *rdev, 33 + u32 smc_address, u32 limit) 34 34 { 35 35 if (smc_address & 3) 36 36 return -EINVAL; ··· 47 47 u32 smc_start_address, 48 48 const u8 *src, u32 byte_count, u32 limit) 49 49 { 50 - int ret; 50 + unsigned long flags; 51 + int ret = 0; 51 52 u32 data, original_data, addr, extra_shift; 52 53 53 54 if (smc_start_address & 3) ··· 58 57 59 58 addr = smc_start_address; 60 59 60 + spin_lock_irqsave(&rdev->smc_idx_lock, flags); 61 61 while (byte_count >= 4) { 62 62 /* SMC address space is BE */ 63 63 data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; 64 64 65 65 ret = si_set_smc_sram_address(rdev, addr, limit); 66 66 if (ret) 67 - return ret; 67 + goto done; 68 68 69 69 WREG32(SMC_IND_DATA_0, data); 70 70 ··· 80 78 81 79 ret = si_set_smc_sram_address(rdev, addr, limit); 82 80 if (ret) 83 - return ret; 81 + goto done; 84 82 85 83 original_data = RREG32(SMC_IND_DATA_0); 86 84 ··· 98 96 99 97 ret = si_set_smc_sram_address(rdev, addr, limit); 100 98 if (ret) 101 - return ret; 99 + goto done; 102 100 103 101 WREG32(SMC_IND_DATA_0, data); 104 102 } 105 - return 0; 103 + 104 + done: 105 + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 106 + 107 + return ret; 106 108 } 107 109 108 110 void si_start_smc(struct radeon_device *rdev) ··· 209 203 210 204 int si_load_smc_ucode(struct radeon_device *rdev, u32 limit) 211 205 { 206 + unsigned long flags; 212 207 u32 ucode_start_address; 213 208 u32 ucode_size; 214 209 const u8 *src; ··· 248 241 return -EINVAL; 249 242 250 243 src = (const u8 *)rdev->smc_fw->data; 244 + spin_lock_irqsave(&rdev->smc_idx_lock, flags); 251 245 WREG32(SMC_IND_INDEX_0, ucode_start_address); 252 246 WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0); 253 247 while (ucode_size >= 4) { ··· 261 253 ucode_size -= 4; 262 254 } 263 255 WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0); 256 + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 264 257 265 258 return 0; 266 259 } ··· 269 260 int si_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address, 270 261 u32 *value, u32 limit) 271 262 { 263 + unsigned long flags; 272 264 int ret; 273 265 266 + spin_lock_irqsave(&rdev->smc_idx_lock, flags); 274 267 ret = si_set_smc_sram_address(rdev, smc_address, limit); 275 - if (ret) 276 - return ret; 268 + if (ret == 0) 269 + *value = RREG32(SMC_IND_DATA_0); 270 + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 277 271 278 - *value = RREG32(SMC_IND_DATA_0); 279 - return 0; 272 + return ret; 280 273 } 281 274 282 275 int si_write_smc_sram_dword(struct radeon_device *rdev, u32 smc_address, 283 276 u32 value, u32 limit) 284 277 { 278 + unsigned long flags; 285 279 int ret; 286 280 281 + spin_lock_irqsave(&rdev->smc_idx_lock, flags); 287 282 ret = si_set_smc_sram_address(rdev, smc_address, limit); 288 - if (ret) 289 - return ret; 283 + if (ret == 0) 284 + WREG32(SMC_IND_DATA_0, value); 285 + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 290 286 291 - WREG32(SMC_IND_DATA_0, value); 292 - return 0; 287 + return ret; 293 288 }