qmsi: gpio: Use locking mechanism to guard critical regions.

This will guard the driver API to be safe for concurrent
invocation from fibers or tasks.

The machanism is by default disabled. To enable it, the
following flag needs to be defined:

CONFIG_GPIO_QMSI_API_REENTRANCY

Jira: ZEP-441

Change-Id: Ia3ee738aff2f8e70e4f9a7ec76346138ff6f5031
Signed-off-by: Sergio Rodriguez <sergio.sf.rodriguez@intel.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
Signed-off-by: Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
This commit is contained in:
Sergio Rodriguez 2016-06-01 20:57:59 -07:00 committed by Inaky Perez-Gonzalez
parent 3c5af9ab5b
commit b4d87a575a
2 changed files with 60 additions and 0 deletions

View file

@ -70,4 +70,12 @@ config GPIO_QMSI_AON_IRQ_PRI
help
IRQ priority
config GPIO_QMSI_API_REENTRANCY
bool
prompt "GPIO driver API reentrancy"
depends on GPIO_QMSI
default n
help
Enable support for QMSI GPIO driver API reentrancy.
endif # GPIO_QMSI

View file

@ -37,8 +37,47 @@ struct gpio_qmsi_config {
struct gpio_qmsi_runtime {
sys_slist_t callbacks;
uint32_t pin_callbacks;
#ifdef CONFIG_GPIO_QMSI_API_REENTRANCY
struct nano_sem sem;
#endif /* CONFIG_GPIO_QMSI_API_REENTRANCY */
};
#ifdef CONFIG_GPIO_QMSI_API_REENTRANCY
#define RP_GET(dev) (&((struct gpio_qmsi_runtime *)(dev->driver_data))->sem)
static const int reentrancy_protection = 1;
#else
#define RP_GET(context) (NULL)
static const int reentrancy_protection;
#endif /* CONFIG_GPIO_QMSI_API_REENTRANCY */
static void gpio_reentrancy_init(struct device *dev)
{
if (!reentrancy_protection) {
return;
}
nano_sem_init(RP_GET(dev));
nano_sem_give(RP_GET(dev));
}
static void gpio_critical_region_start(struct device *dev)
{
if (!reentrancy_protection) {
return;
}
nano_sem_take(RP_GET(dev), TICKS_UNLIMITED);
}
static void gpio_critical_region_end(struct device *dev)
{
if (!reentrancy_protection) {
return;
}
nano_sem_give(RP_GET(dev));
}
int gpio_qmsi_init(struct device *dev);
#ifdef CONFIG_GPIO_QMSI_0
@ -162,7 +201,9 @@ static inline void qmsi_pin_config(struct device *port, uint32_t pin, int flags)
return;
}
gpio_critical_region_start(port);
qm_gpio_set_config(gpio, &cfg);
gpio_critical_region_end(port);
}
static inline void qmsi_port_config(struct device *port, int flags)
@ -198,6 +239,8 @@ static inline int gpio_qmsi_write(struct device *port,
struct gpio_qmsi_config *gpio_config = port->config->config_info;
qm_gpio_t gpio = gpio_config->gpio;
gpio_critical_region_start(port);
if (access_op == GPIO_ACCESS_BY_PIN) {
if (value) {
qm_gpio_set_pin(gpio, pin);
@ -208,6 +251,7 @@ static inline int gpio_qmsi_write(struct device *port,
qm_gpio_write_port(gpio, value);
}
gpio_critical_region_end(port);
return 0;
}
@ -244,6 +288,8 @@ static inline int gpio_qmsi_enable_callback(struct device *port,
{
struct gpio_qmsi_runtime *context = port->driver_data;
gpio_critical_region_start(port);
if (access_op == GPIO_ACCESS_BY_PIN) {
_gpio_enable_callback(port, BIT(pin));
context->pin_callbacks |= BIT(pin);
@ -252,6 +298,7 @@ static inline int gpio_qmsi_enable_callback(struct device *port,
context->pin_callbacks = 0xffffffff;
}
gpio_critical_region_end(port);
return 0;
}
@ -260,6 +307,8 @@ static inline int gpio_qmsi_disable_callback(struct device *port,
{
struct gpio_qmsi_runtime *context = port->driver_data;
gpio_critical_region_start(port);
if (access_op == GPIO_ACCESS_BY_PIN) {
_gpio_disable_callback(port, BIT(pin));
context->pin_callbacks &= ~BIT(pin);
@ -268,6 +317,7 @@ static inline int gpio_qmsi_disable_callback(struct device *port,
context->pin_callbacks = 0;
}
gpio_critical_region_end(port);
return 0;
}
@ -284,6 +334,8 @@ int gpio_qmsi_init(struct device *port)
{
struct gpio_qmsi_config *gpio_config = port->config->config_info;
gpio_reentrancy_init(port);
switch (gpio_config->gpio) {
case QM_GPIO_0:
clk_periph_enable(CLK_PERIPH_GPIO_REGISTER |