From 3da6b4349ff57aadf1202a188e880ede7a3aea81 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 16 Dec 2024 22:30:21 +0000 Subject: [PATCH] piolib: Increase data_bytes range to 32-bits In many places, the number of bytes in a data transfer is stored as a 32-bit (or greater) value, but the ioctl API to the kernel stores it in a 16-bit field, alongside which is a 16-bit gap due to the alignment requirements of the pointer that follows. Increase the size of data_bytes to a uint32_t, so that it can handle larger transfers. Since using different sizes as either end can lead to unpredictable results, a separate IOCTL is used for larger transfers, allowing the kernel support to be determined and backwards compatibility to be maintained. See: https://github.com/raspberrypi/utils/issues/107 Signed-off-by: Phil Elwell --- piolib/examples/apitest.c | 20 +++++++++++++++++++- piolib/include/rp1_pio_if.h | 13 +++++++++---- piolib/pio_rp1.c | 8 ++++++-- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/piolib/examples/apitest.c b/piolib/examples/apitest.c index 2f6597d..ba1ecb3 100644 --- a/piolib/examples/apitest.c +++ b/piolib/examples/apitest.c @@ -184,7 +184,7 @@ int main(int argc, const char **argv) { pio_panic("RX FIFO is not empty"); offset = pio_add_program(pio, &genseq_program); - pio_sm_config_xfer(pio, sm, PIO_DIR_FROM_SM, 256, 1); + pio_sm_config_xfer(pio, sm, PIO_DIR_FROM_SM, 4096, 2); pio_gpio_init(pio, gpio); pio_sm_set_consecutive_pindirs(pio, sm, gpio, 1, true); @@ -219,6 +219,24 @@ int main(int argc, const char **argv) { sleep_ms(10); } + if (!ret) + { + const uint32_t words = 0x10000; + uint32_t *bigbuf = malloc(words * sizeof(bigbuf[0])); + + pio_sm_put_blocking(pio, sm, words - 1); + ret = pio_sm_xfer_data(pio, sm, PIO_DIR_FROM_SM, words * sizeof(bigbuf[0]), bigbuf); + if (!ret) { + for (i = words - 1; i >= 0; i--) + { + int v = bigbuf[words - 1 - i]; + if (v != i) + printf(" %x: %x\n", i, v); + } + } + free(bigbuf); + } + if (ret) printf("* error %d\n", ret); return ret; diff --git a/piolib/include/rp1_pio_if.h b/piolib/include/rp1_pio_if.h index 84e749e..22f6d84 100644 --- a/piolib/include/rp1_pio_if.h +++ b/piolib/include/rp1_pio_if.h @@ -164,6 +164,14 @@ struct rp1_pio_sm_xfer_data_args { uint16_t sm; uint16_t dir; uint16_t data_bytes; + uint16_t rsvd; + void *data; +}; + +struct rp1_pio_sm_xfer_data32_args { + uint16_t sm; + uint16_t dir; + uint32_t data_bytes; void *data; }; @@ -177,10 +185,7 @@ struct rp1_access_hw_args { #define PIO_IOC_SM_CONFIG_XFER _IOW(PIO_IOC_MAGIC, 0, struct rp1_pio_sm_config_xfer_args) #define PIO_IOC_SM_XFER_DATA _IOW(PIO_IOC_MAGIC, 1, struct rp1_pio_sm_xfer_data_args) - -#ifdef CONFIG_COMPAT -//XXX #define PIO_IOC_SM_XFER_DATA32 _IOW(PIO_IOC_MAGIC, 2, struct pio_sm_xfer_data_args) -#endif +#define PIO_IOC_SM_XFER_DATA32 _IOW(PIO_IOC_MAGIC, 2, struct rp1_pio_sm_xfer_data32_args) #define PIO_IOC_READ_HW _IOW(PIO_IOC_MAGIC, 8, struct rp1_access_hw_args) #define PIO_IOC_WRITE_HW _IOW(PIO_IOC_MAGIC, 9, struct rp1_access_hw_args) diff --git a/piolib/pio_rp1.c b/piolib/pio_rp1.c index 41e1f66..a601ef0 100644 --- a/piolib/pio_rp1.c +++ b/piolib/pio_rp1.c @@ -264,10 +264,14 @@ static int rp1_pio_sm_config_xfer(PIO pio, uint sm, uint dir, uint buf_size, uin static int rp1_pio_sm_xfer_data(PIO pio, uint sm, uint dir, uint data_bytes, void *data) { - struct rp1_pio_sm_xfer_data_args args = { .sm = sm, .dir = dir, .data_bytes = data_bytes, .data = data }; + struct rp1_pio_sm_xfer_data_args args = { .sm = sm, .dir = dir, .data_bytes = data_bytes, .rsvd = 0, .data = data }; + struct rp1_pio_sm_xfer_data32_args args32 = { .sm = sm, .dir = dir, .data_bytes = data_bytes, .data = data }; int err; check_sm_param(sm); - err = rp1_ioctl(pio, PIO_IOC_SM_XFER_DATA, &args); + if (data_bytes > 0xffff) + err = rp1_ioctl(pio, PIO_IOC_SM_XFER_DATA32, &args32); + else + err = rp1_ioctl(pio, PIO_IOC_SM_XFER_DATA, &args); return (err > 0); }