From 492088b3fa1b81ce64aaf2d6095e6f783a64286a Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 30 Mar 2020 17:07:11 +0300 Subject: [PATCH] net: ppp: Convert PPP driver to use normal UART APIs This is needed so that we can support GSM 07.10 muxing protocol. Signed-off-by: Jukka Rissanen --- drivers/console/gsm_mux.h | 6 ++ drivers/modem/Kconfig.gsm | 6 ++ drivers/modem/gsm_ppp.c | 89 +++----------------- drivers/net/Kconfig | 18 ++++- drivers/net/ppp.c | 165 +++++++++++++++++++++++++++++++++++--- 5 files changed, 192 insertions(+), 92 deletions(-) diff --git a/drivers/console/gsm_mux.h b/drivers/console/gsm_mux.h index 179cb23f590..afe169119d3 100644 --- a/drivers/console/gsm_mux.h +++ b/drivers/console/gsm_mux.h @@ -5,8 +5,14 @@ */ #define DLCI_CONTROL 0 + +#if IS_ENABLED(CONFIG_GSM_MUX) #define DLCI_AT CONFIG_GSM_MUX_DLCI_AT #define DLCI_PPP CONFIG_GSM_MUX_DLCI_PPP +#else +#define DLCI_AT -1 +#define DLCI_PPP -1 +#endif struct gsm_mux; struct gsm_dlci; diff --git a/drivers/modem/Kconfig.gsm b/drivers/modem/Kconfig.gsm index 1cd6748486a..e4ced9ab8f3 100644 --- a/drivers/modem/Kconfig.gsm +++ b/drivers/modem/Kconfig.gsm @@ -32,6 +32,12 @@ endchoice config MODEM_GSM_UART_NAME string "UART device name the modem is connected to" +config MODEM_GSM_RX_STACK_SIZE + int "Size of the stack allocated for receiving data from modem" + default 512 + help + Sets the stack size which will be used by the GSM RX thread. + config MODEM_GSM_INIT_PRIORITY int "Init priority for the GSM modem driver" default 42 diff --git a/drivers/modem/gsm_ppp.c b/drivers/modem/gsm_ppp.c index 8919287b5c9..c1f8fde938b 100644 --- a/drivers/modem/gsm_ppp.c +++ b/drivers/modem/gsm_ppp.c @@ -13,7 +13,6 @@ LOG_MODULE_REGISTER(modem_gsm, CONFIG_MODEM_LOG_LEVEL); #include #include #include -#include #include #include "modem_context.h" @@ -24,7 +23,7 @@ LOG_MODULE_REGISTER(modem_gsm, CONFIG_MODEM_LOG_LEVEL); #define GSM_CMD_READ_BUF 128 #define GSM_CMD_AT_TIMEOUT K_SECONDS(2) #define GSM_CMD_SETUP_TIMEOUT K_SECONDS(6) -#define GSM_RX_STACK_SIZE 1024 +#define GSM_RX_STACK_SIZE CONFIG_MODEM_GSM_RX_STACK_SIZE #define GSM_RECV_MAX_BUF 30 #define GSM_RECV_BUF_SIZE 128 #define GSM_BUF_ALLOC_TIMEOUT K_SECONDS(1) @@ -56,8 +55,6 @@ static struct gsm_modem { u8_t *ppp_recv_buf; size_t ppp_recv_buf_len; - uart_pipe_recv_cb ppp_recv_cb; - struct k_sem ppp_send_sem; enum setup_state state; struct device *ppp_dev; @@ -69,8 +66,6 @@ static struct gsm_modem { bool setup_done : 1; } gsm; -static size_t recv_buf_offset; - NET_BUF_POOL_DEFINE(gsm_recv_pool, GSM_RECV_MAX_BUF, GSM_RECV_BUF_SIZE, 0, NULL); K_THREAD_STACK_DEFINE(gsm_rx_stack, GSM_RX_STACK_SIZE); @@ -79,47 +74,14 @@ struct k_thread gsm_rx_thread; static void gsm_rx(struct gsm_modem *gsm) { - int bytes, r; - LOG_DBG("starting"); while (true) { k_sem_take(&gsm->gsm_data.rx_sem, K_FOREVER); - if (gsm->mux_enabled == false) { - if (gsm->setup_done == false) { - gsm->context.cmd_handler.process( - &gsm->context.cmd_handler, - &gsm->context.iface); - continue; - } - - if (gsm->ppp_recv_cb == NULL || - gsm->ppp_recv_buf == NULL || - gsm->ppp_recv_buf_len == 0) { - return; - } - - r = gsm->context.iface.read( - &gsm->context.iface, - &gsm->ppp_recv_buf[recv_buf_offset], - gsm->ppp_recv_buf_len - - recv_buf_offset, - &bytes); - if (r < 0 || bytes == 0) { - continue; - } - - recv_buf_offset += bytes; - - gsm->ppp_recv_buf = gsm->ppp_recv_cb(gsm->ppp_recv_buf, - &recv_buf_offset); - } else if (IS_ENABLED(CONFIG_GSM_MUX) && gsm->mux_enabled) { - /* The handler will listen AT channel */ - gsm->context.cmd_handler.process( - &gsm->context.cmd_handler, - &gsm->context.iface); - } + /* The handler will listen AT channel */ + gsm->context.cmd_handler.process(&gsm->context.cmd_handler, + &gsm->context.iface); } } @@ -282,20 +244,15 @@ static int gsm_setup_mccmno(struct gsm_modem *gsm) static void set_ppp_carrier_on(struct gsm_modem *gsm) { struct device *ppp_dev = device_get_binding(CONFIG_NET_PPP_DRV_NAME); - struct net_if *iface; + const struct ppp_api *api = + (const struct ppp_api *)ppp_dev->driver_api; if (!ppp_dev) { LOG_ERR("Cannot find PPP %s!", "device"); return; } - iface = net_if_lookup_by_dev(ppp_dev); - if (!iface) { - LOG_ERR("Cannot find PPP %s!", "network interface"); - return; - } - - net_ppp_carrier_on(iface); + api->start(ppp_dev); } static void gsm_finalize_connection(struct gsm_modem *gsm) @@ -352,11 +309,12 @@ static void gsm_finalize_connection(struct gsm_modem *gsm) gsm->setup_done = true; - /* FIXME: This will let PPP to start send data. We should actually - * change this so that the PPP L2 is initialized after the GSM modem - * is working and connection is created. TBDL. + /* If we are not muxing, the modem interface and gsm_rx() thread is not + * needed as PPP will handle the incoming traffic internally. */ - k_sem_give(&gsm->ppp_send_sem); + if (!IS_ENABLED(CONFIG_GSM_MUX)) { + k_thread_abort(&gsm_rx_thread); + } set_ppp_carrier_on(gsm); } @@ -576,8 +534,6 @@ static int gsm_init(struct device *device) LOG_DBG("Generic GSM modem (%p)", gsm); - k_sem_init(&gsm->ppp_send_sem, 0, 1); - gsm->cmd_handler_data.cmds[CMD_RESP] = response_cmds; gsm->cmd_handler_data.cmds_len[CMD_RESP] = ARRAY_SIZE(response_cmds); gsm->cmd_handler_data.read_buf = &gsm->cmd_read_buf[0]; @@ -630,6 +586,7 @@ static int gsm_init(struct device *device) K_THREAD_STACK_SIZEOF(gsm_rx_stack), (k_thread_entry_t) gsm_rx, gsm, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); + k_thread_name_set(&gsm_rx_thread, "gsm_rx"); k_delayed_work_init(&gsm->gsm_configure_work, gsm_configure); @@ -638,25 +595,5 @@ static int gsm_init(struct device *device) return 0; } -int uart_pipe_send(const u8_t *buf, int len) -{ - k_sem_take(&gsm.ppp_send_sem, K_FOREVER); - - (void)gsm.context.iface.write(&gsm.context.iface, buf, len); - - k_sem_give(&gsm.ppp_send_sem); - - return 0; -} - - -/* Setup the connection to PPP. PPP driver will call this function. */ -void uart_pipe_register(u8_t *buf, size_t len, uart_pipe_recv_cb cb) -{ - gsm.ppp_recv_buf = buf; - gsm.ppp_recv_buf_len = len; - gsm.ppp_recv_cb = cb; -} - DEVICE_INIT(gsm_ppp, "modem_gsm", gsm_init, &gsm, NULL, POST_KERNEL, CONFIG_MODEM_GSM_INIT_PRIORITY); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 916416c9aef..641551c7f1f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -8,24 +8,34 @@ menuconfig NET_PPP bool "Point-to-point (PPP) UART based driver" depends on NET_L2_PPP depends on NET_NATIVE - select UART_PIPE if ! MODEM_GSM_PPP - select UART_INTERRUPT_DRIVEN + select UART_MUX if GSM_MUX if NET_PPP +config NET_PPP_UART_NAME + string "UART device name the PPP is connected to" + depends on !MODEM_GSM_PPP + config NET_PPP_DRV_NAME string "PPP Driver name" default "ppp" help This option sets the driver name -config NET_PPP_UART_PIPE_BUF_LEN +config NET_PPP_UART_BUF_LEN int "Buffer length when reading from UART" default 8 help - This options sets the size of the UART pipe buffer where data + This options sets the size of the UART buffer where data is being read to. +config NET_PPP_RINGBUF_SIZE + int "PPP ring buffer size" + default 256 + help + PPP ring buffer size when passing data from RX ISR to worker + thread that will pass the data to IP stack. + config NET_PPP_VERIFY_FCS bool "Verify that received FCS is valid" default y diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index ddf720e494c..50a8cf9ad96 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -27,13 +27,15 @@ LOG_MODULE_REGISTER(net_ppp, LOG_LEVEL); #include #include #include -#include +#include #include +#include +#include #include "../../subsys/net/ip/net_stats.h" #include "../../subsys/net/ip/net_private.h" -#define UART_BUF_LEN CONFIG_NET_PPP_UART_PIPE_BUF_LEN +#define UART_BUF_LEN CONFIG_NET_PPP_UART_BUF_LEN enum ppp_driver_state { STATE_HDLC_FRAME_START, @@ -42,6 +44,7 @@ enum ppp_driver_state { }; struct ppp_driver_context { + struct device *dev; struct net_if *iface; /* This net_pkt contains pkt that is being read */ @@ -59,10 +62,19 @@ struct ppp_driver_context { u8_t mac_addr[6]; struct net_linkaddr ll_addr; + /* Flag that tells whether this instance is initialized or not */ + atomic_t modem_init_done; + + /* Incoming data is routed via ring buffer */ + struct ring_buf rx_ringbuf; + u8_t rx_buf[CONFIG_NET_PPP_RINGBUF_SIZE]; + + /* ISR function callback worker */ + struct k_work cb_work; + #if defined(CONFIG_NET_STATISTICS_PPP) struct net_stats_ppp stats; #endif - enum ppp_driver_state state; #if defined(CONFIG_PPP_CLIENT_CLIENTSERVER) @@ -176,7 +188,11 @@ static void ppp_change_state(struct ppp_driver_context *ctx, static int ppp_send_flush(struct ppp_driver_context *ppp, int off) { if (!IS_ENABLED(CONFIG_NET_TEST)) { - uart_pipe_send(ppp->send_buf, off); + u8_t *buf = ppp->send_buf; + + while (off--) { + uart_poll_out(ppp->dev, *buf++); + } } return 0; @@ -401,6 +417,7 @@ static void ppp_process_msg(struct ppp_driver_context *ppp) ppp->pkt = NULL; } +#if defined(CONFIG_NET_TEST) static u8_t *ppp_recv_cb(u8_t *buf, size_t *off) { struct ppp_driver_context *ppp = @@ -435,7 +452,6 @@ static u8_t *ppp_recv_cb(u8_t *buf, size_t *off) return buf; } -#if defined(CONFIG_NET_TEST) void ppp_driver_feed_data(u8_t *data, int data_len) { struct ppp_driver_context *ppp = &ppp_driver_context_data; @@ -609,12 +625,57 @@ static int ppp_send(struct device *dev, struct net_pkt *pkt) return 0; } +#if !defined(CONFIG_NET_TEST) +static void ppp_isr_cb_work(struct k_work *work) +{ + struct ppp_driver_context *ppp = + CONTAINER_OF(work, struct ppp_driver_context, cb_work); + u8_t *data; + size_t len, tmp; + int ret; + + len = ring_buf_get_claim(&ppp->rx_ringbuf, &data, + CONFIG_NET_PPP_RINGBUF_SIZE); + if (len == 0) { + LOG_DBG("Ringbuf %p is empty!", &ppp->rx_ringbuf); + return; + } + + /* This will print too much data, enable only if really needed */ + if (0) { + LOG_HEXDUMP_DBG(data, len, ppp->dev->config->name); + } + + tmp = len; + + do { + if (ppp_input_byte(ppp, *data++) == 0) { + /* Ignore empty or too short frames */ + if (ppp->pkt && net_pkt_get_len(ppp->pkt) > 3) { + ppp_process_msg(ppp); + break; + } + } + } while (--tmp); + + ret = ring_buf_get_finish(&ppp->rx_ringbuf, len); + if (ret < 0) { + LOG_DBG("Cannot flush ring buffer (%d)", ret); + } +} +#endif /* !CONFIG_NET_TEST */ + static int ppp_driver_init(struct device *dev) { struct ppp_driver_context *ppp = dev->driver_data; LOG_DBG("[%p] dev %p", ppp, dev); +#if !defined(CONFIG_NET_TEST) + ring_buf_init(&ppp->rx_ringbuf, sizeof(ppp->rx_buf), ppp->rx_buf); + k_work_init(&ppp->cb_work, ppp_isr_cb_work); +#endif + ppp->pkt = NULL; ppp_change_state(ppp, STATE_HDLC_FRAME_START); #if defined(CONFIG_PPP_CLIENT_CLIENTSERVER) @@ -674,13 +735,6 @@ use_random_mac: memset(ppp->buf, 0, sizeof(ppp->buf)); - /* We do not use uart_pipe for unit tests as the unit test has its - * own handling of UART. See tests/net/ppp/driver for details. - */ - if (!IS_ENABLED(CONFIG_NET_TEST)) { - uart_pipe_register(ppp->buf, sizeof(ppp->buf), ppp_recv_cb); - } - /* If we have a GSM modem with PPP support, then do not start the * interface automatically but only after the modem is ready. */ @@ -698,10 +752,97 @@ static struct net_stats_ppp *ppp_get_stats(struct device *dev) } #endif +#if !defined(CONFIG_NET_TEST) +static void ppp_uart_flush(struct device *dev) +{ + u8_t c; + + while (uart_fifo_read(dev, &c, 1) > 0) { + continue; + } +} + +static void ppp_uart_isr(void *user_data) +{ + struct ppp_driver_context *context = user_data; + struct device *uart = context->dev; + int rx = 0, ret; + + /* get all of the data off UART as fast as we can */ + while (uart_irq_update(uart) && uart_irq_rx_ready(uart)) { + rx = uart_fifo_read(uart, context->buf, sizeof(context->buf)); + if (rx <= 0) { + continue; + } + + ret = ring_buf_put(&context->rx_ringbuf, context->buf, rx); + if (ret < rx) { + LOG_ERR("Rx buffer doesn't have enough space. " + "Bytes pending: %d, written: %d", + rx, ret); + break; + } + + k_work_submit(&context->cb_work); + } +} +#endif /* !CONFIG_NET_TEST */ + static int ppp_start(struct device *dev) { struct ppp_driver_context *context = dev->driver_data; + /* Init the PPP UART only once. This should only be done after + * the GSM muxing is setup and enabled. GSM modem will call this + * after everything is ready to be connected. + */ +#if !defined(CONFIG_NET_TEST) + if (atomic_cas(&context->modem_init_done, false, true)) { + const char *dev_name = NULL; + + /* Now try to figure out what device to open. If GSM muxing + * is enabled, then use it. If not, then check if modem + * configuration is enabled, and use that. If none are enabled, + * then use our own config. + */ +#if IS_ENABLED(CONFIG_GSM_MUX) + struct device *mux; + + mux = uart_mux_find(CONFIG_GSM_MUX_DLCI_PPP); + if (mux == NULL) { + LOG_ERR("Cannot find GSM mux dev for DLCI %d", + CONFIG_GSM_MUX_DLCI_PPP); + return -ENOENT; + } + + dev_name = mux->config->name; +#elif IS_ENABLED(CONFIG_MODEM_GSM_PPP) + dev_name = CONFIG_MODEM_GSM_UART_NAME; +#else + dev_name = CONFIG_NET_PPP_UART_NAME; +#endif + if (dev_name == NULL || dev_name[0] == '\0') { + LOG_ERR("UART configuration is wrong!"); + return -EINVAL; + } + + LOG_DBG("Initializing PPP to use %s", dev_name); + + context->dev = device_get_binding(dev_name); + if (!context->dev) { + LOG_ERR("Cannot find dev %s", dev_name); + return -ENODEV; + } + + uart_irq_rx_disable(context->dev); + uart_irq_tx_disable(context->dev); + ppp_uart_flush(context->dev); + uart_irq_callback_user_data_set(context->dev, ppp_uart_isr, + context); + uart_irq_rx_enable(context->dev); + } +#endif /* !CONFIG_NET_TEST */ + net_ppp_carrier_on(context->iface); return 0;