arm/imx/gpio: add spinlock protection
The GPIO registers need protection from concurrent access for operations that are not atomic. Cc: stable@kernel.org Cc: Juergen Beisert <j.beisert@pengutronix.de> Cc: Daniel Mack <daniel@caiaq.de> Reported-by: rpkamiak@rockwellcollins.com Signed-off-by: Baruch Siach <baruch@tkos.co.il> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
		
					parent
					
						
							
								ef93f1443c
							
						
					
				
			
			
				commit
				
					
						14cb0deb66
					
				
			
		
					 2 changed files with 9 additions and 0 deletions
				
			
		|  | @ -214,13 +214,16 @@ static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset, | ||||||
| 	struct mxc_gpio_port *port = | 	struct mxc_gpio_port *port = | ||||||
| 		container_of(chip, struct mxc_gpio_port, chip); | 		container_of(chip, struct mxc_gpio_port, chip); | ||||||
| 	u32 l; | 	u32 l; | ||||||
|  | 	unsigned long flags; | ||||||
| 
 | 
 | ||||||
|  | 	spin_lock_irqsave(&port->lock, flags); | ||||||
| 	l = __raw_readl(port->base + GPIO_GDIR); | 	l = __raw_readl(port->base + GPIO_GDIR); | ||||||
| 	if (dir) | 	if (dir) | ||||||
| 		l |= 1 << offset; | 		l |= 1 << offset; | ||||||
| 	else | 	else | ||||||
| 		l &= ~(1 << offset); | 		l &= ~(1 << offset); | ||||||
| 	__raw_writel(l, port->base + GPIO_GDIR); | 	__raw_writel(l, port->base + GPIO_GDIR); | ||||||
|  | 	spin_unlock_irqrestore(&port->lock, flags); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void mxc_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | static void mxc_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||||||
|  | @ -229,9 +232,12 @@ static void mxc_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||||||
| 		container_of(chip, struct mxc_gpio_port, chip); | 		container_of(chip, struct mxc_gpio_port, chip); | ||||||
| 	void __iomem *reg = port->base + GPIO_DR; | 	void __iomem *reg = port->base + GPIO_DR; | ||||||
| 	u32 l; | 	u32 l; | ||||||
|  | 	unsigned long flags; | ||||||
| 
 | 
 | ||||||
|  | 	spin_lock_irqsave(&port->lock, flags); | ||||||
| 	l = (__raw_readl(reg) & (~(1 << offset))) | (value << offset); | 	l = (__raw_readl(reg) & (~(1 << offset))) | (value << offset); | ||||||
| 	__raw_writel(l, reg); | 	__raw_writel(l, reg); | ||||||
|  | 	spin_unlock_irqrestore(&port->lock, flags); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset) | static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset) | ||||||
|  | @ -285,6 +291,8 @@ int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt) | ||||||
| 		port[i].chip.base = i * 32; | 		port[i].chip.base = i * 32; | ||||||
| 		port[i].chip.ngpio = 32; | 		port[i].chip.ngpio = 32; | ||||||
| 
 | 
 | ||||||
|  | 		spin_lock_init(&port[i].lock); | ||||||
|  | 
 | ||||||
| 		/* its a serious configuration bug when it fails */ | 		/* its a serious configuration bug when it fails */ | ||||||
| 		BUG_ON( gpiochip_add(&port[i].chip) < 0 ); | 		BUG_ON( gpiochip_add(&port[i].chip) < 0 ); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -37,6 +37,7 @@ struct mxc_gpio_port { | ||||||
| 	int virtual_irq_start; | 	int virtual_irq_start; | ||||||
| 	struct gpio_chip chip; | 	struct gpio_chip chip; | ||||||
| 	u32 both_edges; | 	u32 both_edges; | ||||||
|  | 	spinlock_t lock; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| int mxc_gpio_init(struct mxc_gpio_port*, int); | int mxc_gpio_init(struct mxc_gpio_port*, int); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Baruch Siach
				Baruch Siach