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

ssb: add locking around gpio register accesses

The GPIOs are access through some registers in the chip common core or
over extif. We need locking around these GPIO accesses, all GPIOs are
accessed through the same registers and parallel writes will cause
problems.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Patchwork: http://patchwork.linux-mips.org/patch/4590
Acked-by: Florian Fainelli <florian@openwrt.org>

authored by

Hauke Mehrtens and committed by
John Crispin
394bc7e3 da22f22e

+109 -11
+59 -7
drivers/ssb/driver_chipcommon.c
··· 284 284 { 285 285 if (!cc->dev) 286 286 return; /* We don't have a ChipCommon */ 287 + 288 + spin_lock_init(&cc->gpio_lock); 289 + 287 290 if (cc->dev->id.revision >= 11) 288 291 cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT); 289 292 ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status); ··· 421 418 422 419 u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) 423 420 { 424 - return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); 421 + unsigned long flags; 422 + u32 res = 0; 423 + 424 + spin_lock_irqsave(&cc->gpio_lock, flags); 425 + res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); 426 + spin_unlock_irqrestore(&cc->gpio_lock, flags); 427 + 428 + return res; 425 429 } 426 430 427 431 u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) 428 432 { 429 - return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); 433 + unsigned long flags; 434 + u32 res = 0; 435 + 436 + spin_lock_irqsave(&cc->gpio_lock, flags); 437 + res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); 438 + spin_unlock_irqrestore(&cc->gpio_lock, flags); 439 + 440 + return res; 430 441 } 431 442 432 443 u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value) 433 444 { 434 - return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); 445 + unsigned long flags; 446 + u32 res = 0; 447 + 448 + spin_lock_irqsave(&cc->gpio_lock, flags); 449 + res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); 450 + spin_unlock_irqrestore(&cc->gpio_lock, flags); 451 + 452 + return res; 435 453 } 436 454 EXPORT_SYMBOL(ssb_chipco_gpio_control); 437 455 438 456 u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value) 439 457 { 440 - return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value); 458 + unsigned long flags; 459 + u32 res = 0; 460 + 461 + spin_lock_irqsave(&cc->gpio_lock, flags); 462 + res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value); 463 + spin_unlock_irqrestore(&cc->gpio_lock, flags); 464 + 465 + return res; 441 466 } 442 467 443 468 u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value) 444 469 { 445 - return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value); 470 + unsigned long flags; 471 + u32 res = 0; 472 + 473 + spin_lock_irqsave(&cc->gpio_lock, flags); 474 + res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value); 475 + spin_unlock_irqrestore(&cc->gpio_lock, flags); 476 + 477 + return res; 446 478 } 447 479 448 480 u32 ssb_chipco_gpio_pullup(struct ssb_chipcommon *cc, u32 mask, u32 value) 449 481 { 482 + unsigned long flags; 483 + u32 res = 0; 484 + 450 485 if (cc->dev->id.revision < 20) 451 486 return 0xffffffff; 452 487 453 - return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLUP, mask, value); 488 + spin_lock_irqsave(&cc->gpio_lock, flags); 489 + res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLUP, mask, value); 490 + spin_unlock_irqrestore(&cc->gpio_lock, flags); 491 + 492 + return res; 454 493 } 455 494 456 495 u32 ssb_chipco_gpio_pulldown(struct ssb_chipcommon *cc, u32 mask, u32 value) 457 496 { 497 + unsigned long flags; 498 + u32 res = 0; 499 + 458 500 if (cc->dev->id.revision < 20) 459 501 return 0xffffffff; 460 502 461 - return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLDOWN, mask, value); 503 + spin_lock_irqsave(&cc->gpio_lock, flags); 504 + res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLDOWN, mask, value); 505 + spin_unlock_irqrestore(&cc->gpio_lock, flags); 506 + 507 + return res; 462 508 } 463 509 464 510 #ifdef CONFIG_SSB_SERIAL
+39 -4
drivers/ssb/driver_extif.c
··· 118 118 extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks); 119 119 } 120 120 121 + void ssb_extif_init(struct ssb_extif *extif) 122 + { 123 + if (!extif->dev) 124 + return; /* We don't have a Extif core */ 125 + spin_lock_init(&extif->gpio_lock); 126 + } 127 + 121 128 u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) 122 129 { 123 130 return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask; ··· 132 125 133 126 u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value) 134 127 { 135 - return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0), 128 + unsigned long flags; 129 + u32 res = 0; 130 + 131 + spin_lock_irqsave(&extif->gpio_lock, flags); 132 + res = extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0), 136 133 mask, value); 134 + spin_unlock_irqrestore(&extif->gpio_lock, flags); 135 + 136 + return res; 137 137 } 138 138 139 139 u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value) 140 140 { 141 - return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0), 141 + unsigned long flags; 142 + u32 res = 0; 143 + 144 + spin_lock_irqsave(&extif->gpio_lock, flags); 145 + res = extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0), 142 146 mask, value); 147 + spin_unlock_irqrestore(&extif->gpio_lock, flags); 148 + 149 + return res; 143 150 } 144 151 145 152 u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value) 146 153 { 147 - return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value); 154 + unsigned long flags; 155 + u32 res = 0; 156 + 157 + spin_lock_irqsave(&extif->gpio_lock, flags); 158 + res = extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value); 159 + spin_unlock_irqrestore(&extif->gpio_lock, flags); 160 + 161 + return res; 148 162 } 149 163 150 164 u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value) 151 165 { 152 - return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value); 166 + unsigned long flags; 167 + u32 res = 0; 168 + 169 + spin_lock_irqsave(&extif->gpio_lock, flags); 170 + res = extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value); 171 + spin_unlock_irqrestore(&extif->gpio_lock, flags); 172 + 173 + return res; 153 174 }
+1
drivers/ssb/main.c
··· 796 796 if (err) 797 797 goto err_pcmcia_exit; 798 798 ssb_chipcommon_init(&bus->chipco); 799 + ssb_extif_init(&bus->extif); 799 800 ssb_mipscore_init(&bus->mipscore); 800 801 err = ssb_fetch_invariants(bus, get_invariants); 801 802 if (err) {
+8
drivers/ssb/ssb_private.h
··· 211 211 extern u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc); 212 212 extern u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc); 213 213 214 + #ifdef CONFIG_SSB_DRIVER_EXTIF 215 + extern void ssb_extif_init(struct ssb_extif *extif); 216 + #else 217 + static inline void ssb_extif_init(struct ssb_extif *extif) 218 + { 219 + } 220 + #endif 221 + 214 222 #endif /* LINUX_SSB_PRIVATE_H_ */
+1
include/linux/ssb/ssb_driver_chipcommon.h
··· 590 590 u32 status; 591 591 /* Fast Powerup Delay constant */ 592 592 u16 fast_pwrup_delay; 593 + spinlock_t gpio_lock; 593 594 struct ssb_chipcommon_pmu pmu; 594 595 }; 595 596
+1
include/linux/ssb/ssb_driver_extif.h
··· 158 158 159 159 struct ssb_extif { 160 160 struct ssb_device *dev; 161 + spinlock_t gpio_lock; 161 162 }; 162 163 163 164 static inline bool ssb_extif_available(struct ssb_extif *extif)