Commit dbc614ee authored by Mulin Chao's avatar Mulin Chao Committed by Fabio Baltieri
Browse files

driver: uart: npcx: avoid concurrency writing UFTCTL register



In order to avoid concurrency situation during writing UFTCTL register,
this CL adds critical sections to prevent the unexpected result if the
driver wants to set/clear bits of this register.

Signed-off-by: default avatarMulin Chao <mlchao@nuvoton.com>
Signed-off-by: default avatarJun Lin <CHLin56@nuvoton.com>
parent 85b4143e
Loading
Loading
Loading
Loading
+20 −9
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ struct uart_npcx_data {
	/* Baud rate */
	uint32_t baud_rate;
	struct miwu_dev_callback uart_rx_cb;
	struct k_spinlock lock;
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
	uart_irq_callback_user_data_t user_cb;
	void *user_data;
@@ -144,21 +145,21 @@ static int uart_npcx_fifo_fill(const struct device *dev, const uint8_t *tx_data,
{
	const struct uart_npcx_config *const config = dev->config;
	struct uart_reg *const inst = config->inst;
	struct uart_npcx_data *data = dev->data;
	uint8_t tx_bytes = 0U;
	k_spinlock_key_t key = k_spin_lock(&data->lock);

	/* If Tx FIFO is still ready to send */
	while ((size - tx_bytes > 0) && uart_npcx_tx_fifo_ready(dev)) {
		/* Put a character into Tx FIFO */
		inst->UTBUF = tx_data[tx_bytes++];
	}
#ifdef CONFIG_PM
		struct uart_npcx_data *data = dev->data;

	uart_npcx_pm_policy_state_lock_get(data, UART_PM_POLICY_STATE_TX_FLAG);
		inst->UTBUF = tx_data[tx_bytes++];
	/* Enable NXMIP interrupt in case ec enters deep sleep early */
	inst->UFTCTL |= BIT(NPCX_UFTCTL_NXMIP_EN);
#else
		inst->UTBUF = tx_data[tx_bytes++];
#endif /* CONFIG_PM */
	}
	k_spin_unlock(&data->lock, key);

	return tx_bytes;
}
@@ -182,16 +183,22 @@ static void uart_npcx_irq_tx_enable(const struct device *dev)
{
	const struct uart_npcx_config *const config = dev->config;
	struct uart_reg *const inst = config->inst;
	struct uart_npcx_data *data = dev->data;
	k_spinlock_key_t key = k_spin_lock(&data->lock);

	inst->UFTCTL |= BIT(NPCX_UFTCTL_TEMPTY_EN);
	k_spin_unlock(&data->lock, key);
}

static void uart_npcx_irq_tx_disable(const struct device *dev)
{
	const struct uart_npcx_config *const config = dev->config;
	struct uart_reg *const inst = config->inst;
	struct uart_npcx_data *data = dev->data;
	k_spinlock_key_t key = k_spin_lock(&data->lock);

	inst->UFTCTL &= ~(BIT(NPCX_UFTCTL_TEMPTY_EN));
	k_spin_unlock(&data->lock, key);
}

static int uart_npcx_irq_tx_ready(const struct device *dev)
@@ -292,8 +299,12 @@ static void uart_npcx_isr(const struct device *dev)

	if (IS_BIT_SET(inst->UFTCTL, NPCX_UFTCTL_NXMIP_EN) &&
	    IS_BIT_SET(inst->UFTSTS, NPCX_UFTSTS_NXMIP)) {
		uart_npcx_pm_policy_state_lock_put(data, UART_PM_POLICY_STATE_TX_FLAG);
		k_spinlock_key_t key = k_spin_lock(&data->lock);

		/* Disable NXMIP interrupt */
		inst->UFTCTL &= ~BIT(NPCX_UFTCTL_NXMIP_EN);
		k_spin_unlock(&data->lock, key);
		uart_npcx_pm_policy_state_lock_put(data, UART_PM_POLICY_STATE_TX_FLAG);
	}
#endif /* CONFIG_PM */
}