diff --git a/spacewire/grspwrtr/grspwrtr.c b/spacewire/grspwrtr/grspwrtr.c index 706af5a5..4dcb4220 100644 --- a/spacewire/grspwrtr/grspwrtr.c +++ b/spacewire/grspwrtr/grspwrtr.c @@ -39,8 +39,9 @@ #define LOG_ERROR(fmt, ...) fprintf(stderr, "spacewire-router: " fmt "\n", ##__VA_ARGS__) /* clang-format on */ -#define SPWRTR_PRIO 3 -#define SPWRTR_PORTS 4 +#define SPWRTR_PRIO 3 +#define SPWRTR_MAX_PHY_PORT 31 +#define SPWRTR_PORT_CNT (SPWRTR_SPW_CNT + SPWRTR_AMBA_CNT) #define R_RESERVED(start, end) uint32_t rsvd_##start##_##end[(end - start) / sizeof(uint32_t)] /* reserved address */ #define BIT(i) (1u << (i)) /* bitmask for single bit */ @@ -154,11 +155,11 @@ static struct { static int spwrtr_setPortMapping(spwrtr_dev_t *dev, uint8_t port, uint32_t enPorts) { - if (port == 0) { + if ((port == 0 || port > SPWRTR_PORT_CNT) && port <= SPWRTR_MAX_PHY_PORT) { return -EINVAL; } - if ((enPorts >> (SPWRTR_PORTS + 1)) > 0) { + if ((enPorts >> (SPWRTR_PORT_CNT + 1)) > 0) { return -EINVAL; } @@ -171,7 +172,7 @@ static int spwrtr_setPortMapping(spwrtr_dev_t *dev, uint8_t port, uint32_t enPor static int spwrtr_getPortMapping(spwrtr_dev_t *dev, uint8_t port, uint32_t *enPorts) { - if (port == 0) { + if ((port == 0 || port > SPWRTR_PORT_CNT) && port <= SPWRTR_MAX_PHY_PORT) { return -EINVAL; } @@ -194,6 +195,39 @@ static int spwrtr_resetDevice(spwrtr_dev_t *dev) } +static int spwrtr_setClockDiv(spwrtr_dev_t *dev, uint8_t port, uint8_t clkdiv) +{ + if (port == 0 || port > SPWRTR_SPW_CNT) { + return -EINVAL; + } + + uint32_t pctrl; + + pctrl = dev->mmio->rtr_pctrl[port]; + pctrl &= ~SPWRTR_PCTRL_RD_MASK; + pctrl |= (clkdiv << SPWRTR_PCTRL_RD_SHIFT) & SPWRTR_PCTRL_RD_MASK; + + dev->mmio->rtr_pctrl[port] = pctrl; + + TRACE("port: %d set clockdiv: %d", port, clkdiv); + + return 0; +} + + +static int spwrtr_getClockDiv(spwrtr_dev_t *dev, uint8_t port, uint8_t *clkdiv) +{ + if (port == 0 || port > SPWRTR_SPW_CNT) { + return -EINVAL; + } + + *clkdiv = (dev->mmio->rtr_pctrl[port] & SPWRTR_PCTRL_RD_MASK) >> SPWRTR_PCTRL_RD_SHIFT; + TRACE("port: %d clockdiv: %d", port, *clkdiv); + + return 0; +} + + /* Message handling */ @@ -212,6 +246,13 @@ static void spwrtr_handleDevCtl(msg_t *msg) err = spwrtr_getPortMapping(&spwrtr_common.dev, ictl->task.mapping.port, &octl->val); break; + case spwrtr_clkdiv_set: + err = spwrtr_setClockDiv(&spwrtr_common.dev, ictl->task.clkdiv.port, ictl->task.clkdiv.div); + break; + case spwrtr_clkdiv_get: + err = spwrtr_getClockDiv(&spwrtr_common.dev, ictl->task.clkdiv.port, (uint8_t *)&octl->val); + break; + case spwrtr_reset: err = spwrtr_resetDevice(&spwrtr_common.dev); break; diff --git a/spacewire/grspwrtr/grspwrtr.h b/spacewire/grspwrtr/grspwrtr.h index 984da32e..62e52ba0 100644 --- a/spacewire/grspwrtr/grspwrtr.h +++ b/spacewire/grspwrtr/grspwrtr.h @@ -20,13 +20,17 @@ typedef struct { /* clang-format off */ - enum { spwrtr_pmap_set = 0, spwrtr_pmap_get, spwrtr_pctrl, spwrtr_reset } type; + enum { spwrtr_pmap_set = 0, spwrtr_pmap_get, spwrtr_clkdiv_set, spwrtr_clkdiv_get, spwrtr_reset } type; /* clang-format on */ union { struct { uint8_t port; uint32_t enPorts; } mapping; + struct { + uint8_t port; + uint8_t div; + } clkdiv; } task; } spwrtr_t; diff --git a/spacewire/libgrspw/libgrspw.c b/spacewire/libgrspw/libgrspw.c index 938e589c..b7336a08 100644 --- a/spacewire/libgrspw/libgrspw.c +++ b/spacewire/libgrspw/libgrspw.c @@ -109,7 +109,9 @@ #define SPW_TX_DESC_CNT 64 /* Sensible maximum value */ -#define MAX_PACKET_LEN 1024 +#ifndef SPW_MAX_PACKET_LEN +#define SPW_MAX_PACKET_LEN 1024 +#endif /* RX descriptor ctrl bits: @@ -184,7 +186,6 @@ typedef struct { size_t lastTxDesc; size_t nextRxDesc; - bool txWaited[SPW_TX_DESC_CNT]; bool rxAcknowledged[SPW_RX_DESC_CNT]; handle_t ctrlLock; @@ -195,8 +196,8 @@ typedef struct { handle_t cond; handle_t rxAckCond; - volatile uint8_t (*txBuff)[MAX_PACKET_LEN]; - volatile uint8_t (*rxBuff)[MAX_PACKET_LEN]; + volatile uint8_t (*txBuff)[SPW_MAX_PACKET_LEN]; + volatile uint8_t (*rxBuff)[SPW_MAX_PACKET_LEN]; volatile spw_txDesc_t *txDesc; volatile spw_rxDesc_t *rxDesc; } spw_dev_t; @@ -234,12 +235,12 @@ static int spw_buffersAlloc(spw_dev_t *dev) dev->rxDesc = (void *)((addr_t)dev->txDesc + sizeof(spw_txDesc_t) * SPW_TX_DESC_CNT); - dev->rxBuff = mmap(NULL, MAX_PACKET_LEN * SPW_RX_DESC_CNT, PROT_READ | PROT_WRITE, MAP_UNCACHED | MAP_ANONYMOUS, -1, 0); + dev->rxBuff = mmap(NULL, SPW_MAX_PACKET_LEN * SPW_RX_DESC_CNT, PROT_READ | PROT_WRITE, MAP_UNCACHED | MAP_ANONYMOUS | MAP_CONTIGUOUS, -1, 0); if (dev->rxBuff == MAP_FAILED) { return -ENOMEM; } - dev->txBuff = mmap(NULL, MAX_PACKET_LEN * SPW_TX_DESC_CNT, PROT_READ | PROT_WRITE, MAP_UNCACHED | MAP_ANONYMOUS, -1, 0); + dev->txBuff = mmap(NULL, SPW_MAX_PACKET_LEN * SPW_TX_DESC_CNT, PROT_READ | PROT_WRITE, MAP_UNCACHED | MAP_ANONYMOUS | MAP_CONTIGUOUS, -1, 0); if (dev->txBuff == MAP_FAILED) { return -ENOMEM; } @@ -251,10 +252,10 @@ static int spw_buffersAlloc(spw_dev_t *dev) static void spw_buffersFree(spw_dev_t *dev) { if (dev->txBuff != MAP_FAILED) { - (void)munmap((void *)dev->txBuff, MAX_PACKET_LEN * SPW_TX_DESC_CNT); + (void)munmap((void *)dev->txBuff, SPW_MAX_PACKET_LEN * SPW_TX_DESC_CNT); } if (dev->rxBuff != MAP_FAILED) { - (void)munmap((void *)dev->rxBuff, MAX_PACKET_LEN * SPW_RX_DESC_CNT); + (void)munmap((void *)dev->rxBuff, SPW_MAX_PACKET_LEN * SPW_RX_DESC_CNT); } if (dev->txDesc != MAP_FAILED) { size_t descSz = PAGE_ALIGN(sizeof(spw_txDesc_t) * SPW_TX_DESC_CNT + sizeof(spw_rxDesc_t) * SPW_RX_DESC_CNT); @@ -317,10 +318,13 @@ __attribute__((section(".interrupt"), aligned(0x1000))) static int spw_irqHandle /* Operations on device */ -/* Blocks execution until all packets are transmitted. */ -static int spw_transmitWait(spw_dev_t *dev, const uint8_t *buf, const size_t nPackets) +static int spw_transmit(spw_dev_t *dev, const uint8_t *buf, size_t bufsz, const size_t nPackets, bool async) { - if (nPackets > SPW_TX_DESC_CNT) { + if ((buf == NULL) || (bufsz < SPW_TX_MIN_BUFSZ)) { + return -EINVAL; + } + + if (!async && (nPackets > SPW_TX_DESC_CNT)) { return -EINVAL; } @@ -335,89 +339,7 @@ static int spw_transmitWait(spw_dev_t *dev, const uint8_t *buf, const size_t nPa for (size_t cnt = 0; cnt < nPackets; cnt++) { (void)mutexLock(dev->txIrqLock); - while ((dev->txDescFree == 0) || dev->txWaited[dev->lastTxDesc]) { - /* Wait for free descriptor or for packet to be acknowledged */ - (void)condWait(dev->cond, dev->txIrqLock, 0); - } - dev->txDescFree--; - (void)mutexUnlock(dev->txIrqLock); - - volatile spw_txDesc_t *desc = &dev->txDesc[dev->lastTxDesc]; - - spw_txPacket_t packet; - buf += spw_txMsgToPacket(buf, &packet); - /* Interrupt after each packet transmitted */ - desc->ctrl = (packet.flags & TX_DESC_USR_MSK) | TX_DESC_IE; - if (dev->lastTxDesc == SPW_TX_DESC_CNT - 1) { - /* Wrap around */ - desc->ctrl |= TX_DESC_WR; - } - - /* on riscv64 pa can exceed 32 bits */ - uintptr_t pa = va2pa((void *)packet.hdr); - if ((pa & ~SPW_ADDR_MASK) != 0) { - LOG_ERROR("DMA addr 0x%" PRIxPTR "exceeds 32-bit limit", pa); - return -EINVAL; - } - desc->hdrAddr = pa; - - pa = va2pa((void *)packet.data); - if ((pa & ~SPW_ADDR_MASK) != 0) { - LOG_ERROR("DMA addr 0x%" PRIxPTR "exceeds 32-bit limit", pa); - return -EINVAL; - } - desc->dataAddr = pa; - desc->packetLen = packet.dataLen; - - /* Everything is set up, enable descriptor */ - desc->ctrl |= TX_DESC_EN; - - dev->txWaited[dev->lastTxDesc] = true; - - /* Start transmission */ - dev->vbase[DMA_CTRL] |= DMA_CTRL_TE; - - dev->lastTxDesc = (dev->lastTxDesc + 1) % SPW_TX_DESC_CNT; - } - - TRACE("Packets set up"); - - /* Wait for transmission to finish */ - while ((firstDesc <= lastDesc) || wrapped) { - if ((dev->txDesc[firstDesc].ctrl & TX_DESC_EN) == 0) { - dev->txWaited[firstDesc] = false; - size_t next = (firstDesc + 1) % SPW_TX_DESC_CNT; - if ((next == 0) && wrapped) { - wrapped = false; - } - firstDesc = next; - } - else { - (void)mutexLock(dev->txIrqLock); - (void)condWait(dev->cond, dev->txIrqLock, 0); - (void)mutexUnlock(dev->txIrqLock); - } - } - - TRACE("Packets sent"); - - (void)mutexUnlock(dev->txLock); - - return nPackets; -} - - -/* Starts transmission and returns */ -static int spw_transmitAsync(spw_dev_t *dev, const uint8_t *buf, const size_t nPackets) -{ - (void)mutexLock(dev->txLock); - - TRACE("nPackets: %zu", nPackets); - - /* Setup descriptors */ - for (size_t cnt = 0; cnt < nPackets; cnt++) { - (void)mutexLock(dev->txIrqLock); - while ((dev->txDescFree == 0) || dev->txWaited[dev->lastTxDesc]) { + while (dev->txDescFree == 0) { /* Wait for free descriptor or for packet to be acknowledged */ (void)condWait(dev->cond, dev->txIrqLock, 0); } @@ -434,7 +356,6 @@ static int spw_transmitAsync(spw_dev_t *dev, const uint8_t *buf, const size_t nP /* Wrap around */ desc->ctrl |= TX_DESC_WR; } - desc->packetLen = packet.dataLen; uint8_t hdrLen = packet.flags & TX_DESC_HDR_LEN; volatile void *txBuff = dev->txBuff[dev->lastTxDesc]; @@ -456,11 +377,11 @@ static int spw_transmitAsync(spw_dev_t *dev, const uint8_t *buf, const size_t nP return -EINVAL; } desc->dataAddr = pa; + desc->packetLen = packet.dataLen; /* Everything is set up, enable descriptor */ desc->ctrl |= TX_DESC_EN; - dev->txWaited[dev->lastTxDesc] = false; /* Start transmission */ dev->vbase[DMA_CTRL] |= DMA_CTRL_TE; @@ -468,6 +389,24 @@ static int spw_transmitAsync(spw_dev_t *dev, const uint8_t *buf, const size_t nP dev->lastTxDesc = (dev->lastTxDesc + 1) % SPW_TX_DESC_CNT; } + if (!async) { + /* Wait for transmission to finish */ + while ((firstDesc <= lastDesc) || wrapped) { + if ((dev->txDesc[firstDesc].ctrl & TX_DESC_EN) == 0) { + size_t next = (firstDesc + 1) % SPW_TX_DESC_CNT; + if ((next == 0) && wrapped) { + wrapped = false; + } + firstDesc = next; + } + else { + (void)mutexLock(dev->txIrqLock); + (void)condWait(dev->cond, dev->txIrqLock, 0); + (void)mutexUnlock(dev->txIrqLock); + } + } + } + TRACE("Packets set up"); (void)mutexUnlock(dev->txLock); @@ -476,20 +415,6 @@ static int spw_transmitAsync(spw_dev_t *dev, const uint8_t *buf, const size_t nP } -static int spw_transmit(spw_dev_t *dev, const uint8_t *buf, const size_t bufsz, const size_t nPackets, bool async) -{ - if ((buf == NULL) || (bufsz < SPW_TX_MIN_BUFSZ)) { - return -EINVAL; - } - - if (nPackets == 0) { - return 0; - } - - return async ? spw_transmitAsync(dev, buf, nPackets) : spw_transmitWait(dev, buf, nPackets); -} - - /* Configure RX DMA descriptors */ static int spw_rxConfigure(spw_dev_t *dev, size_t *firstDesc, const size_t nPackets) { @@ -544,8 +469,13 @@ static int spw_rxConfigure(spw_dev_t *dev, size_t *firstDesc, const size_t nPack /* Read from RX buffers */ -static int spw_rxRead(spw_dev_t *dev, size_t firstDesc, uint8_t *buf, size_t bufsz, const size_t nPackets) +static int spw_rxRead(spw_dev_t *dev, uint8_t *buf, size_t bufsz, size_t *readCnt, const spw_t *ictl) { + size_t firstDesc = ictl->task.rx.firstDesc; + const size_t nPackets = ictl->task.rx.nPackets; + const uint32_t timeoutUs = ictl->task.rx.timeoutUs; + int err = 0; + if ((firstDesc >= SPW_RX_DESC_CNT) || (nPackets > SPW_RX_DESC_CNT)) { return -EINVAL; } @@ -563,7 +493,8 @@ static int spw_rxRead(spw_dev_t *dev, size_t firstDesc, uint8_t *buf, size_t buf uint32_t flags = dev->rxDesc[firstDesc].ctrl & RX_DESC_USR_MSK; size_t rxLen = flags & RX_DESC_LEN; if ((rxLen + SPW_RX_MIN_BUFSZ) > bufsz) { - /* Buffer too small */ + LOG_ERROR("buffer too small: %zu < %zu", bufsz, (rxLen + SPW_RX_MIN_BUFSZ)); + err = -EINVAL; break; } /* Copy packet to user buffer */ @@ -577,16 +508,41 @@ static int spw_rxRead(spw_dev_t *dev, size_t firstDesc, uint8_t *buf, size_t buf buf += rxLen; bufsz -= rxLen; cnt++; - condSignal(dev->rxAckCond); } else { - (void)condWait(dev->cond, dev->rxLock, 0); + condSignal(dev->rxAckCond); + if (condWait(dev->cond, dev->rxLock, timeoutUs) == -ETIME) { + TRACE("packet: %zu timeout: %uus", firstDesc, timeoutUs); + + dev->vbase[DMA_CTRL] &= ~DMA_CTRL_RE; + + /* ack unused descriptors */ + while ((firstDesc < lastDesc) || wrapped) { + dev->rxAcknowledged[firstDesc] = true; + dev->rxDesc[firstDesc].ctrl = 0; + + size_t next = (firstDesc + 1) % SPW_RX_DESC_CNT; + if ((next == 0) && wrapped) { + wrapped = false; + } + firstDesc = next; + } + + /* move DMA pointer to skip timeouted descriptors */ + dev->vbase[DMA_RX_DESC] = va2pa((void *)&dev->rxDesc[lastDesc]); + dev->vbase[DMA_CTRL] |= DMA_CTRL_RE; + + err = -ETIME; + break; + } } } (void)mutexUnlock(dev->rxLock); + condSignal(dev->rxAckCond); - return cnt; + *readCnt = cnt; + return err; } @@ -628,7 +584,7 @@ static void spw_handleDevCtl(msg_t *msg, int dev) break; case spw_rx: - msg->o.err = spw_rxRead(spw, ictl->task.rx.firstDesc, msg->o.data, msg->o.size, ictl->task.rx.nPackets); + msg->o.err = spw_rxRead(spw, msg->o.data, msg->o.size, &octl->val, ictl); break; case spw_tx: @@ -718,7 +674,7 @@ static int spw_defaultConfig(spw_dev_t *dev) dev->vbase[SPW_CTRL] |= SPW_CTRL_LS; dev->vbase[DMA_CTRL] |= DMA_CTRL_RI | DMA_CTRL_TI; - dev->vbase[DMA_RX_LEN] = MAX_PACKET_LEN; + dev->vbase[DMA_RX_LEN] = SPW_MAX_PACKET_LEN; uintptr_t pa = va2pa((void *)dev->txDesc); if ((pa & ~SPW_ADDR_MASK) != 0) { diff --git a/spacewire/libgrspw/libgrspw.h b/spacewire/libgrspw/libgrspw.h index ac0e93ea..b3bfb023 100644 --- a/spacewire/libgrspw/libgrspw.h +++ b/spacewire/libgrspw/libgrspw.h @@ -96,6 +96,7 @@ typedef struct { struct { size_t firstDesc; size_t nPackets; + uint32_t timeoutUs; } rx; struct { size_t nPackets;