aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHauke Mehrtens <hauke@hauke-m.de>2012-11-20 17:24:32 -0500
committerJohn Crispin <blogic@openwrt.org>2012-11-21 15:55:52 -0500
commit394bc7e38be79987ed15de203920c3cddb724cc1 (patch)
tree64cb52592aab0fb2f392560fb99d8d61caa81f4a
parentda22f22e91f0d14d996c7258101575a5a06ddf85 (diff)
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>
-rw-r--r--drivers/ssb/driver_chipcommon.c66
-rw-r--r--drivers/ssb/driver_extif.c43
-rw-r--r--drivers/ssb/main.c1
-rw-r--r--drivers/ssb/ssb_private.h8
-rw-r--r--include/linux/ssb/ssb_driver_chipcommon.h1
-rw-r--r--include/linux/ssb/ssb_driver_extif.h1
6 files changed, 109 insertions, 11 deletions
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
index 4df492665565..24e02bb2ecd8 100644
--- a/drivers/ssb/driver_chipcommon.c
+++ b/drivers/ssb/driver_chipcommon.c
@@ -284,6 +284,9 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
284{ 284{
285 if (!cc->dev) 285 if (!cc->dev)
286 return; /* We don't have a ChipCommon */ 286 return; /* We don't have a ChipCommon */
287
288 spin_lock_init(&cc->gpio_lock);
289
287 if (cc->dev->id.revision >= 11) 290 if (cc->dev->id.revision >= 11)
288 cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT); 291 cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
289 ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status); 292 ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status);
@@ -418,44 +421,93 @@ u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask)
418 421
419u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) 422u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
420{ 423{
421 return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); 424 unsigned long flags;
425 u32 res = 0;
426
427 spin_lock_irqsave(&cc->gpio_lock, flags);
428 res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
429 spin_unlock_irqrestore(&cc->gpio_lock, flags);
430
431 return res;
422} 432}
423 433
424u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) 434u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
425{ 435{
426 return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); 436 unsigned long flags;
437 u32 res = 0;
438
439 spin_lock_irqsave(&cc->gpio_lock, flags);
440 res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
441 spin_unlock_irqrestore(&cc->gpio_lock, flags);
442
443 return res;
427} 444}
428 445
429u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value) 446u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value)
430{ 447{
431 return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); 448 unsigned long flags;
449 u32 res = 0;
450
451 spin_lock_irqsave(&cc->gpio_lock, flags);
452 res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value);
453 spin_unlock_irqrestore(&cc->gpio_lock, flags);
454
455 return res;
432} 456}
433EXPORT_SYMBOL(ssb_chipco_gpio_control); 457EXPORT_SYMBOL(ssb_chipco_gpio_control);
434 458
435u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value) 459u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value)
436{ 460{
437 return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value); 461 unsigned long flags;
462 u32 res = 0;
463
464 spin_lock_irqsave(&cc->gpio_lock, flags);
465 res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value);
466 spin_unlock_irqrestore(&cc->gpio_lock, flags);
467
468 return res;
438} 469}
439 470
440u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value) 471u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value)
441{ 472{
442 return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value); 473 unsigned long flags;
474 u32 res = 0;
475
476 spin_lock_irqsave(&cc->gpio_lock, flags);
477 res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value);
478 spin_unlock_irqrestore(&cc->gpio_lock, flags);
479
480 return res;
443} 481}
444 482
445u32 ssb_chipco_gpio_pullup(struct ssb_chipcommon *cc, u32 mask, u32 value) 483u32 ssb_chipco_gpio_pullup(struct ssb_chipcommon *cc, u32 mask, u32 value)
446{ 484{
485 unsigned long flags;
486 u32 res = 0;
487
447 if (cc->dev->id.revision < 20) 488 if (cc->dev->id.revision < 20)
448 return 0xffffffff; 489 return 0xffffffff;
449 490
450 return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLUP, mask, value); 491 spin_lock_irqsave(&cc->gpio_lock, flags);
492 res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLUP, mask, value);
493 spin_unlock_irqrestore(&cc->gpio_lock, flags);
494
495 return res;
451} 496}
452 497
453u32 ssb_chipco_gpio_pulldown(struct ssb_chipcommon *cc, u32 mask, u32 value) 498u32 ssb_chipco_gpio_pulldown(struct ssb_chipcommon *cc, u32 mask, u32 value)
454{ 499{
500 unsigned long flags;
501 u32 res = 0;
502
455 if (cc->dev->id.revision < 20) 503 if (cc->dev->id.revision < 20)
456 return 0xffffffff; 504 return 0xffffffff;
457 505
458 return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLDOWN, mask, value); 506 spin_lock_irqsave(&cc->gpio_lock, flags);
507 res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLDOWN, mask, value);
508 spin_unlock_irqrestore(&cc->gpio_lock, flags);
509
510 return res;
459} 511}
460 512
461#ifdef CONFIG_SSB_SERIAL 513#ifdef CONFIG_SSB_SERIAL
diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c
index dc47f30e9cf7..e1d0bb8ad725 100644
--- a/drivers/ssb/driver_extif.c
+++ b/drivers/ssb/driver_extif.c
@@ -118,6 +118,13 @@ void ssb_extif_watchdog_timer_set(struct ssb_extif *extif,
118 extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks); 118 extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks);
119} 119}
120 120
121void 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
121u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) 128u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask)
122{ 129{
123 return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask; 130 return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask;
@@ -125,22 +132,50 @@ u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask)
125 132
126u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value) 133u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
127{ 134{
128 return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0), 135 unsigned long flags;
136 u32 res = 0;
137
138 spin_lock_irqsave(&extif->gpio_lock, flags);
139 res = extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),
129 mask, value); 140 mask, value);
141 spin_unlock_irqrestore(&extif->gpio_lock, flags);
142
143 return res;
130} 144}
131 145
132u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value) 146u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
133{ 147{
134 return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0), 148 unsigned long flags;
149 u32 res = 0;
150
151 spin_lock_irqsave(&extif->gpio_lock, flags);
152 res = extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),
135 mask, value); 153 mask, value);
154 spin_unlock_irqrestore(&extif->gpio_lock, flags);
155
156 return res;
136} 157}
137 158
138u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value) 159u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value)
139{ 160{
140 return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value); 161 unsigned long flags;
162 u32 res = 0;
163
164 spin_lock_irqsave(&extif->gpio_lock, flags);
165 res = extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value);
166 spin_unlock_irqrestore(&extif->gpio_lock, flags);
167
168 return res;
141} 169}
142 170
143u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value) 171u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value)
144{ 172{
145 return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value); 173 unsigned long flags;
174 u32 res = 0;
175
176 spin_lock_irqsave(&extif->gpio_lock, flags);
177 res = extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value);
178 spin_unlock_irqrestore(&extif->gpio_lock, flags);
179
180 return res;
146} 181}
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index df0f145c22fc..6fe2d102734a 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -796,6 +796,7 @@ static int __devinit ssb_bus_register(struct ssb_bus *bus,
796 if (err) 796 if (err)
797 goto err_pcmcia_exit; 797 goto err_pcmcia_exit;
798 ssb_chipcommon_init(&bus->chipco); 798 ssb_chipcommon_init(&bus->chipco);
799 ssb_extif_init(&bus->extif);
799 ssb_mipscore_init(&bus->mipscore); 800 ssb_mipscore_init(&bus->mipscore);
800 err = ssb_fetch_invariants(bus, get_invariants); 801 err = ssb_fetch_invariants(bus, get_invariants);
801 if (err) { 802 if (err) {
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
index a305550b4b65..d6a1ba9394d9 100644
--- a/drivers/ssb/ssb_private.h
+++ b/drivers/ssb/ssb_private.h
@@ -211,4 +211,12 @@ static inline void b43_pci_ssb_bridge_exit(void)
211extern u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc); 211extern u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc);
212extern u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc); 212extern u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc);
213 213
214#ifdef CONFIG_SSB_DRIVER_EXTIF
215extern void ssb_extif_init(struct ssb_extif *extif);
216#else
217static inline void ssb_extif_init(struct ssb_extif *extif)
218{
219}
220#endif
221
214#endif /* LINUX_SSB_PRIVATE_H_ */ 222#endif /* LINUX_SSB_PRIVATE_H_ */
diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h
index c8d07c95d76e..30b694345d47 100644
--- a/include/linux/ssb/ssb_driver_chipcommon.h
+++ b/include/linux/ssb/ssb_driver_chipcommon.h
@@ -590,6 +590,7 @@ struct ssb_chipcommon {
590 u32 status; 590 u32 status;
591 /* Fast Powerup Delay constant */ 591 /* Fast Powerup Delay constant */
592 u16 fast_pwrup_delay; 592 u16 fast_pwrup_delay;
593 spinlock_t gpio_lock;
593 struct ssb_chipcommon_pmu pmu; 594 struct ssb_chipcommon_pmu pmu;
594}; 595};
595 596
diff --git a/include/linux/ssb/ssb_driver_extif.h b/include/linux/ssb/ssb_driver_extif.h
index 91161f0aa22b..bd2306854a91 100644
--- a/include/linux/ssb/ssb_driver_extif.h
+++ b/include/linux/ssb/ssb_driver_extif.h
@@ -158,6 +158,7 @@
158 158
159struct ssb_extif { 159struct ssb_extif {
160 struct ssb_device *dev; 160 struct ssb_device *dev;
161 spinlock_t gpio_lock;
161}; 162};
162 163
163static inline bool ssb_extif_available(struct ssb_extif *extif) 164static inline bool ssb_extif_available(struct ssb_extif *extif)