Skip to content

Commit 2e96110

Browse files
ChiHuaLfabiobaltieri
authored andcommitted
driver: Port80: npcx: defer Port80 code sending to workqueue thread
If the host sends Port80 postcodes frequently while EC is busy handling other tasks, the Port80 FIFO (16-byte depth) might overflow easily, especially when the host sends the postcode with the 4-byte format. This change defers the handling and sending (to the upper layer) postcodes to the system workqueue thread. It can reduce a lot of (but not all) the overflow case. Also in practice, we usually care about the latest postcodes. The older codes are not significant to the developer. This commit also lowers the printing of the overflow warning to LOG_DEBUG. Signed-off-by: Jun Lin <[email protected]>
1 parent 4562358 commit 2e96110

File tree

2 files changed

+94
-55
lines changed

2 files changed

+94
-55
lines changed

drivers/espi/Kconfig.npcx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ config ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_MULTI_BYTE
4848
EC can accept 1/2/4 bytes of Port 80 data written from the Host in an
4949
eSPI transaction.
5050

51+
config ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_RING_BUF_SIZE
52+
int "Debug Port80 ring buffer size"
53+
depends on ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_MULTI_BYTE
54+
default 256
55+
help
56+
The size of the ring buffer in byte used by the Port80 ISR to store
57+
Postcodes from Host.
58+
5159
# The default value 'y' for the existing options if ESPI_NPCX is selected.
5260
if ESPI_NPCX
5361

drivers/espi/host_subs_npcx.c

Lines changed: 86 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@
118118
#include <zephyr/drivers/clock_control.h>
119119
#include <zephyr/drivers/pinctrl.h>
120120
#include <zephyr/kernel.h>
121+
#include <zephyr/sys/ring_buffer.h>
121122
#include <soc.h>
122123
#include "espi_utils.h"
123124
#include "soc_host.h"
@@ -148,6 +149,18 @@ struct host_sub_npcx_data {
148149
uint8_t plt_rst_asserted; /* current PLT_RST# status */
149150
uint8_t espi_rst_asserted; /* current ESPI_RST# status */
150151
const struct device *host_bus_dev; /* device for eSPI/LPC bus */
152+
#ifdef CONFIG_ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_MULTI_BYTE
153+
struct ring_buf port80_ring_buf;
154+
uint8_t port80_data[CONFIG_ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_RING_BUF_SIZE];
155+
struct k_work work;
156+
#endif
157+
};
158+
159+
struct npcx_dp80_buf {
160+
union {
161+
uint16_t offset_code_16;
162+
uint8_t offset_code[2];
163+
};
151164
};
152165

153166
static const struct npcx_clk_cfg host_dev_clk_cfg[] =
@@ -474,77 +487,90 @@ static void host_pmch_ibf_isr(const void *arg)
474487

475488
/* Host port80 sub-device local functions */
476489
#if defined(CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80)
477-
static void host_port80_isr(const void *arg)
490+
#if defined(CONFIG_ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_MULTI_BYTE)
491+
static void host_port80_work_handler(struct k_work *item)
478492
{
479-
ARG_UNUSED(arg);
480-
struct shm_reg *const inst_shm = host_sub_cfg.inst_shm;
481-
struct espi_event evt = { ESPI_BUS_PERIPHERAL_NOTIFICATION,
482-
(ESPI_PERIPHERAL_INDEX_0 << 16) | ESPI_PERIPHERAL_DEBUG_PORT80,
483-
ESPI_PERIPHERAL_NODATA
484-
};
485-
uint8_t status = inst_shm->DP80STS;
486-
487-
if (!IS_ENABLED(CONFIG_ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_MULTI_BYTE)) {
488-
LOG_DBG("%s: p80 status 0x%02X", __func__, status);
489-
490-
/* Read out port80 data continuously if FIFO is not empty */
491-
while (IS_BIT_SET(inst_shm->DP80STS, NPCX_DP80STS_FNE)) {
492-
LOG_DBG("p80: %04x", inst_shm->DP80BUF);
493-
evt.evt_data = inst_shm->DP80BUF;
493+
uint32_t code = 0;
494+
struct host_sub_npcx_data *data = CONTAINER_OF(item, struct host_sub_npcx_data, work);
495+
struct ring_buf *rbuf = &data->port80_ring_buf;
496+
struct espi_event evt = {ESPI_BUS_PERIPHERAL_NOTIFICATION,
497+
(ESPI_PERIPHERAL_INDEX_0 << 16) | ESPI_PERIPHERAL_DEBUG_PORT80,
498+
ESPI_PERIPHERAL_NODATA};
499+
500+
while (!ring_buf_is_empty(rbuf)) {
501+
struct npcx_dp80_buf dp80_buf;
502+
uint8_t offset;
503+
504+
ring_buf_get(rbuf, &dp80_buf.offset_code[0], sizeof(dp80_buf.offset_code));
505+
offset = dp80_buf.offset_code[1];
506+
code |= dp80_buf.offset_code[0] << (8 * offset);
507+
if (ring_buf_is_empty(rbuf)) {
508+
evt.evt_data = code;
494509
espi_send_callbacks(host_sub_data.callbacks, host_sub_data.host_bus_dev,
495510
evt);
511+
break;
496512
}
497-
498-
} else {
499-
uint16_t port80_buf[16];
500-
uint8_t count = 0;
501-
uint32_t code = 0;
502-
503-
while (IS_BIT_SET(inst_shm->DP80STS, NPCX_DP80STS_FNE) &&
504-
count < ARRAY_SIZE(port80_buf)) {
505-
port80_buf[count++] = inst_shm->DP80BUF;
513+
/* peek the offset of the next byte */
514+
ring_buf_peek(rbuf, &dp80_buf.offset_code[0], sizeof(dp80_buf.offset_code));
515+
offset = dp80_buf.offset_code[1];
516+
/*
517+
* If the peeked next byte's offset is 0, it is the start of the new code.
518+
* Pass the current code to the application layer to handle the Port80 code.
519+
*/
520+
if (offset == 0) {
521+
evt.evt_data = code;
522+
espi_send_callbacks(host_sub_data.callbacks, host_sub_data.host_bus_dev,
523+
evt);
524+
code = 0;
506525
}
526+
}
527+
}
528+
#endif
507529

508-
for (uint8_t i = 0; i < count; i++) {
509-
uint8_t offset;
510-
uint32_t buf_data;
530+
static void host_port80_isr(const void *arg)
531+
{
532+
ARG_UNUSED(arg);
533+
struct shm_reg *const inst_shm = host_sub_cfg.inst_shm;
534+
uint8_t status = inst_shm->DP80STS;
511535

512-
buf_data = port80_buf[i];
513-
offset = GET_FIELD(buf_data, NPCX_DP80BUF_OFFS_FIELD);
514-
code |= (buf_data & 0xFF) << (8 * offset);
536+
#ifdef CONFIG_ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_MULTI_BYTE
537+
struct ring_buf *rbuf = &host_sub_data.port80_ring_buf;
515538

516-
if (i == count - 1) {
517-
evt.evt_data = code;
518-
espi_send_callbacks(host_sub_data.callbacks,
519-
host_sub_data.host_bus_dev, evt);
520-
break;
521-
}
539+
while (IS_BIT_SET(inst_shm->DP80STS, NPCX_DP80STS_FNE)) {
540+
struct npcx_dp80_buf dp80_buf;
522541

523-
/* peek the offset of the next byte */
524-
buf_data = port80_buf[i + 1];
525-
offset = GET_FIELD(buf_data, NPCX_DP80BUF_OFFS_FIELD);
526-
/*
527-
* If the peeked next byte's offset is 0 means it is the start
528-
* of the new code. Pass the current code to Port80
529-
* common layer.
530-
*/
531-
if (offset == 0) {
532-
evt.evt_data = code;
533-
espi_send_callbacks(host_sub_data.callbacks,
534-
host_sub_data.host_bus_dev, evt);
535-
code = 0;
536-
}
537-
}
542+
dp80_buf.offset_code_16 = inst_shm->DP80BUF;
543+
ring_buf_put(rbuf, &dp80_buf.offset_code[0], sizeof(dp80_buf.offset_code));
544+
}
545+
k_work_submit(&host_sub_data.work);
546+
#else
547+
struct espi_event evt = {ESPI_BUS_PERIPHERAL_NOTIFICATION,
548+
(ESPI_PERIPHERAL_INDEX_0 << 16) | ESPI_PERIPHERAL_DEBUG_PORT80,
549+
ESPI_PERIPHERAL_NODATA};
550+
551+
/* Read out port80 data continuously if FIFO is not empty */
552+
while (IS_BIT_SET(inst_shm->DP80STS, NPCX_DP80STS_FNE)) {
553+
LOG_DBG("p80: %04x", inst_shm->DP80BUF);
554+
evt.evt_data = inst_shm->DP80BUF;
555+
espi_send_callbacks(host_sub_data.callbacks, host_sub_data.host_bus_dev, evt);
538556
}
557+
#endif
558+
LOG_DBG("%s: p80 status 0x%02X", __func__, status);
539559

540560
/* If FIFO is overflow, show error msg */
541561
if (IS_BIT_SET(status, NPCX_DP80STS_FOR)) {
542562
inst_shm->DP80STS |= BIT(NPCX_DP80STS_FOR);
543-
LOG_ERR("Port80 FIFO Overflow!");
563+
LOG_DBG("Port80 FIFO Overflow!");
544564
}
545565

546-
/* Clear all pending bit indicates that FIFO was written by host */
547-
inst_shm->DP80STS |= BIT(NPCX_DP80STS_FWR);
566+
/* If there are pending post codes remains in FIFO after processing and sending previous
567+
* post codes, do not clear the FNE bit. This allows this handler to be called again
568+
* immediately after it exists.
569+
*/
570+
if (!IS_BIT_SET(inst_shm->DP80STS, NPCX_DP80STS_FNE)) {
571+
/* Clear all pending bit indicates that FIFO was written by host */
572+
inst_shm->DP80STS |= BIT(NPCX_DP80STS_FWR);
573+
}
548574
}
549575

550576
static void host_port80_init(void)
@@ -1101,6 +1127,11 @@ int npcx_host_init_subs_core_domain(const struct device *host_bus_dev,
11011127
#endif
11021128
#if defined(CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80)
11031129
host_port80_init();
1130+
#if defined(CONFIG_ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_MULTI_BYTE)
1131+
ring_buf_init(&host_sub_data.port80_ring_buf, sizeof(host_sub_data.port80_data),
1132+
host_sub_data.port80_data);
1133+
k_work_init(&host_sub_data.work, host_port80_work_handler);
1134+
#endif
11041135
#endif
11051136
#if defined(CONFIG_ESPI_PERIPHERAL_UART)
11061137
host_uart_init();

0 commit comments

Comments
 (0)