michallenc commented on code in PR #16623: URL: https://github.com/apache/nuttx/pull/16623#discussion_r2166748447
########## drivers/net/ncv7410.c: ########## @@ -0,0 +1,1703 @@ +/**************************************************************************** + * drivers/net/ncv7410.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#if defined(CONFIG_NET) && defined(CONFIG_NCV7410) Review Comment: `#if defined(CONFIG_NET)` should not be needed as you shouldn't be able to select `CONFIG_NCV7410` without it. ########## drivers/net/ncv7410.c: ########## @@ -0,0 +1,1703 @@ +/**************************************************************************** + * drivers/net/ncv7410.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#if defined(CONFIG_NET) && defined(CONFIG_NCV7410) + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <assert.h> +#include <debug.h> +#include <errno.h> + +#include <nuttx/spi/spi.h> +#include <sys/endian.h> + +#include <nuttx/irq.h> +#include <nuttx/kmalloc.h> +#include <nuttx/wqueue.h> +#include <nuttx/signal.h> +#include <nuttx/mutex.h> +#include <nuttx/net/ncv7410.h> +#include <nuttx/net/netdev_lowerhalf.h> + +#include "ncv7410.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NCVWORK LPWORK + +#define NCV_RESET_TRIES 5 + +/* Maximum frame size = (MTU + LL heaader size) + FCS size */ + +#define NCV_MAX_FRAME_SIZE(p) (p->dev.netdev.d_pktsize + 4) + +/* Packet Memory ************************************************************/ + +/* Maximum number of allocated tx and rx packets */ + +#define NCV7410_TX_QUOTA 1 +#define NCV7410_RX_QUOTA 2 + +#if CONFIG_IOB_NBUFFERS < (NCV7410_TX_QUOTA + NCV7410_RX_QUOTA) +# error "CONFIG_IOB_NBUFFERS must be > (NCV7410_TX_QUOTA + NCV7410_RX_QUOTA)" +#endif + +#ifndef CONFIG_SCHED_LPWORK +# error "CONFIG_SCHED_LPWORK is needed by NCV7410 driver" +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The ncv7410_driver_s encapsulates all state information for a single + * hardware interface + */ + +enum ncv_ifstate_e +{ + NCV_RESET, + NCV_INIT_DOWN, + NCV_INIT_UP +}; + +struct ncv7410_driver_s +{ + /* This holds the information visible to the NuttX network + * (must be placed first) + */ + + struct netdev_lowerhalf_s dev; + + mutex_t mutex; + + /* This is the contained SPI driver instance */ + + FAR struct spi_dev_s *spi; + + /* irq number of the interrupt signal pin */ + + int irqnum; + + /* Work instances for work_queue handling */ + + struct work_s interrupt_work; + struct work_s io_work; + + /* Driver state, one of ncv_ifstate_e values */ + + uint8_t ifstate; + + /* MAC-PHY internal buffer status */ + + int txc; + int rca; + + /* Packet buffer management */ + + FAR netpkt_t *tx_pkt; + FAR netpkt_t *rx_pkt; + int tx_pkt_idx; + int rx_pkt_idx; + int tx_pkt_len; + bool rx_pkt_ready; +}; Review Comment: Use ```C struct ncv7410_driver_s { struct netdev_lowerhalf_s dev; /* .... */ mutex_t mutex; /* .... */ .... } ``` style of comments for structure. Just be careful with long lines. ########## drivers/net/ncv7410.c: ########## @@ -0,0 +1,1703 @@ +/**************************************************************************** + * drivers/net/ncv7410.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#if defined(CONFIG_NET) && defined(CONFIG_NCV7410) + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <assert.h> +#include <debug.h> +#include <errno.h> + +#include <nuttx/spi/spi.h> +#include <sys/endian.h> + +#include <nuttx/irq.h> +#include <nuttx/kmalloc.h> +#include <nuttx/wqueue.h> +#include <nuttx/signal.h> +#include <nuttx/mutex.h> +#include <nuttx/net/ncv7410.h> +#include <nuttx/net/netdev_lowerhalf.h> + +#include "ncv7410.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NCVWORK LPWORK + +#define NCV_RESET_TRIES 5 + +/* Maximum frame size = (MTU + LL heaader size) + FCS size */ + +#define NCV_MAX_FRAME_SIZE(p) (p->dev.netdev.d_pktsize + 4) + +/* Packet Memory ************************************************************/ + +/* Maximum number of allocated tx and rx packets */ + +#define NCV7410_TX_QUOTA 1 +#define NCV7410_RX_QUOTA 2 + +#if CONFIG_IOB_NBUFFERS < (NCV7410_TX_QUOTA + NCV7410_RX_QUOTA) +# error "CONFIG_IOB_NBUFFERS must be > (NCV7410_TX_QUOTA + NCV7410_RX_QUOTA)" +#endif + +#ifndef CONFIG_SCHED_LPWORK +# error "CONFIG_SCHED_LPWORK is needed by NCV7410 driver" +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The ncv7410_driver_s encapsulates all state information for a single + * hardware interface + */ + +enum ncv_ifstate_e +{ + NCV_RESET, + NCV_INIT_DOWN, + NCV_INIT_UP +}; + +struct ncv7410_driver_s +{ + /* This holds the information visible to the NuttX network + * (must be placed first) + */ + + struct netdev_lowerhalf_s dev; + + mutex_t mutex; + + /* This is the contained SPI driver instance */ + + FAR struct spi_dev_s *spi; + + /* irq number of the interrupt signal pin */ + + int irqnum; + + /* Work instances for work_queue handling */ + + struct work_s interrupt_work; + struct work_s io_work; + + /* Driver state, one of ncv_ifstate_e values */ + + uint8_t ifstate; + + /* MAC-PHY internal buffer status */ + + int txc; + int rca; + + /* Packet buffer management */ + + FAR netpkt_t *tx_pkt; + FAR netpkt_t *rx_pkt; + int tx_pkt_idx; + int rx_pkt_idx; + int tx_pkt_len; + bool rx_pkt_ready; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Bit calculations */ + +static int ncv_get_parity(uint32_t w); +uint8_t ncv_bitrev8(uint8_t b); + +/* SPI transfers */ + +static int ncv_write_reg(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, uint32_t word); + +static int ncv_read_reg(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, FAR uint32_t *word); + +static int ncv_set_clear_bits(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, + uint32_t setbits, uint32_t clearbits); + +static int ncv_poll_footer(FAR struct ncv7410_driver_s *priv, + FAR uint32_t *footer); + +static int ncv_exchange_chunk(FAR struct ncv7410_driver_s *priv, + FAR uint8_t *txbuf, FAR uint8_t *rxbuf, + uint32_t header, uint32_t *footer); + +/* Interrupt handling */ + +static int ncv_interrupt(int irq, FAR void *context, FAR void *arg); +static void ncv_interrupt_work(FAR void *arg); + +/* Data Transaction Protocol logic */ + +static void ncv_io_work(FAR void *arg); +static uint32_t ncv_prepare_chunk_exchange(FAR struct ncv7410_driver_s *priv, + FAR uint8_t *txbuf); +static bool ncv_can_rx(FAR struct ncv7410_driver_s *priv); +static void ncv_try_finish_tx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_handle_rx_chunk(FAR struct ncv7410_driver_s *priv, + uint32_t footer, FAR uint8_t *rxbuf); +static void ncv_finalize_rx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_release_tx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_release_rx_packet(FAR struct ncv7410_driver_s *priv); + +/* SPI inline utility functions */ + +static inline void ncv_lock_spi(FAR struct ncv7410_driver_s *priv); +static inline void ncv_unlock_spi(FAR struct ncv7410_driver_s *priv); + +static inline void ncv_config_spi(FAR struct ncv7410_driver_s *priv); + +static inline void ncv_select_spi(FAR struct ncv7410_driver_s *priv); +static inline void ncv_deselect_spi(FAR struct ncv7410_driver_s *priv); + +/* ncv7410 reset and configuration */ + +static int ncv_reset(FAR struct ncv7410_driver_s *priv); +static int ncv_config(FAR struct ncv7410_driver_s *priv); +static int ncv_enable(FAR struct ncv7410_driver_s *priv); +static int ncv_disable(FAR struct ncv7410_driver_s *priv); +static int ncv_init_mac_addr(FAR struct ncv7410_driver_s *priv); + +/* Driver buffer manipulation */ + +static void ncv_reset_driver_buffers(FAR struct ncv7410_driver_s *priv); + +/* NuttX callback functions */ + +static int ncv7410_ifup(FAR struct netdev_lowerhalf_s *dev); +static int ncv7410_ifdown(FAR struct netdev_lowerhalf_s *dev); +static int ncv7410_transmit(FAR struct netdev_lowerhalf_s *dev, + FAR netpkt_t *pkt); +static FAR netpkt_t *ncv7410_receive(FAR struct netdev_lowerhalf_s *dev); + +/* Debug */ + +static void ncv_print_footer(uint32_t footer); + +/* Initialization */ + +int ncv7410_initialize(FAR struct spi_dev_s *spi, int irq); Review Comment: Remove, this is already declared in [include/nuttx/net/ncv7410.h](https://github.com/apache/nuttx/pull/16623/files#diff-c75bb3e9911c1f8728c9bfe46aa02088c160e4d18b01233e658f355d48476ac6) ########## drivers/net/ncv7410.c: ########## @@ -0,0 +1,1703 @@ +/**************************************************************************** + * drivers/net/ncv7410.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#if defined(CONFIG_NET) && defined(CONFIG_NCV7410) + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <assert.h> +#include <debug.h> +#include <errno.h> + +#include <nuttx/spi/spi.h> +#include <sys/endian.h> + +#include <nuttx/irq.h> +#include <nuttx/kmalloc.h> +#include <nuttx/wqueue.h> +#include <nuttx/signal.h> +#include <nuttx/mutex.h> +#include <nuttx/net/ncv7410.h> +#include <nuttx/net/netdev_lowerhalf.h> + +#include "ncv7410.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NCVWORK LPWORK + +#define NCV_RESET_TRIES 5 + +/* Maximum frame size = (MTU + LL heaader size) + FCS size */ + +#define NCV_MAX_FRAME_SIZE(p) (p->dev.netdev.d_pktsize + 4) + +/* Packet Memory ************************************************************/ + +/* Maximum number of allocated tx and rx packets */ + +#define NCV7410_TX_QUOTA 1 +#define NCV7410_RX_QUOTA 2 + +#if CONFIG_IOB_NBUFFERS < (NCV7410_TX_QUOTA + NCV7410_RX_QUOTA) +# error "CONFIG_IOB_NBUFFERS must be > (NCV7410_TX_QUOTA + NCV7410_RX_QUOTA)" +#endif + +#ifndef CONFIG_SCHED_LPWORK +# error "CONFIG_SCHED_LPWORK is needed by NCV7410 driver" +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The ncv7410_driver_s encapsulates all state information for a single + * hardware interface + */ + +enum ncv_ifstate_e +{ + NCV_RESET, + NCV_INIT_DOWN, + NCV_INIT_UP +}; + +struct ncv7410_driver_s +{ + /* This holds the information visible to the NuttX network + * (must be placed first) + */ + + struct netdev_lowerhalf_s dev; + + mutex_t mutex; + + /* This is the contained SPI driver instance */ + + FAR struct spi_dev_s *spi; + + /* irq number of the interrupt signal pin */ + + int irqnum; + + /* Work instances for work_queue handling */ + + struct work_s interrupt_work; + struct work_s io_work; + + /* Driver state, one of ncv_ifstate_e values */ + + uint8_t ifstate; + + /* MAC-PHY internal buffer status */ + + int txc; + int rca; + + /* Packet buffer management */ + + FAR netpkt_t *tx_pkt; + FAR netpkt_t *rx_pkt; + int tx_pkt_idx; + int rx_pkt_idx; + int tx_pkt_len; + bool rx_pkt_ready; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Bit calculations */ + +static int ncv_get_parity(uint32_t w); +uint8_t ncv_bitrev8(uint8_t b); + +/* SPI transfers */ + +static int ncv_write_reg(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, uint32_t word); + +static int ncv_read_reg(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, FAR uint32_t *word); + +static int ncv_set_clear_bits(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, + uint32_t setbits, uint32_t clearbits); + +static int ncv_poll_footer(FAR struct ncv7410_driver_s *priv, + FAR uint32_t *footer); + +static int ncv_exchange_chunk(FAR struct ncv7410_driver_s *priv, + FAR uint8_t *txbuf, FAR uint8_t *rxbuf, + uint32_t header, uint32_t *footer); + +/* Interrupt handling */ + +static int ncv_interrupt(int irq, FAR void *context, FAR void *arg); +static void ncv_interrupt_work(FAR void *arg); + +/* Data Transaction Protocol logic */ + +static void ncv_io_work(FAR void *arg); +static uint32_t ncv_prepare_chunk_exchange(FAR struct ncv7410_driver_s *priv, + FAR uint8_t *txbuf); +static bool ncv_can_rx(FAR struct ncv7410_driver_s *priv); +static void ncv_try_finish_tx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_handle_rx_chunk(FAR struct ncv7410_driver_s *priv, + uint32_t footer, FAR uint8_t *rxbuf); +static void ncv_finalize_rx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_release_tx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_release_rx_packet(FAR struct ncv7410_driver_s *priv); + +/* SPI inline utility functions */ + +static inline void ncv_lock_spi(FAR struct ncv7410_driver_s *priv); +static inline void ncv_unlock_spi(FAR struct ncv7410_driver_s *priv); + +static inline void ncv_config_spi(FAR struct ncv7410_driver_s *priv); + +static inline void ncv_select_spi(FAR struct ncv7410_driver_s *priv); +static inline void ncv_deselect_spi(FAR struct ncv7410_driver_s *priv); + +/* ncv7410 reset and configuration */ + +static int ncv_reset(FAR struct ncv7410_driver_s *priv); +static int ncv_config(FAR struct ncv7410_driver_s *priv); +static int ncv_enable(FAR struct ncv7410_driver_s *priv); +static int ncv_disable(FAR struct ncv7410_driver_s *priv); +static int ncv_init_mac_addr(FAR struct ncv7410_driver_s *priv); + +/* Driver buffer manipulation */ + +static void ncv_reset_driver_buffers(FAR struct ncv7410_driver_s *priv); + +/* NuttX callback functions */ + +static int ncv7410_ifup(FAR struct netdev_lowerhalf_s *dev); +static int ncv7410_ifdown(FAR struct netdev_lowerhalf_s *dev); +static int ncv7410_transmit(FAR struct netdev_lowerhalf_s *dev, + FAR netpkt_t *pkt); +static FAR netpkt_t *ncv7410_receive(FAR struct netdev_lowerhalf_s *dev); + +/* Debug */ + +static void ncv_print_footer(uint32_t footer); + +/* Initialization */ + +int ncv7410_initialize(FAR struct spi_dev_s *spi, int irq); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ncv_interrupt + * + * Description: + * Schedule interrupt work when the interrupt signal from MAC-PHY is + * received. + * + * Input Parameters: + * irq - not used + * context - not used + * arg - ncv7410_driver_s priv structure to be passed to the interrupt + * worker + * + * Returned Value: + * OK is always returned. + * + ****************************************************************************/ + +static int ncv_interrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct ncv7410_driver_s *priv = (FAR struct ncv7410_driver_s *) arg; Review Comment: ```suggestion FAR struct ncv7410_driver_s *priv = (FAR struct ncv7410_driver_s *)arg; ``` Multiple occurrences. ########## drivers/net/ncv7410.c: ########## @@ -0,0 +1,1703 @@ +/**************************************************************************** + * drivers/net/ncv7410.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#if defined(CONFIG_NET) && defined(CONFIG_NCV7410) + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <assert.h> +#include <debug.h> +#include <errno.h> + +#include <nuttx/spi/spi.h> +#include <sys/endian.h> + +#include <nuttx/irq.h> +#include <nuttx/kmalloc.h> +#include <nuttx/wqueue.h> +#include <nuttx/signal.h> +#include <nuttx/mutex.h> +#include <nuttx/net/ncv7410.h> +#include <nuttx/net/netdev_lowerhalf.h> + +#include "ncv7410.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NCVWORK LPWORK + +#define NCV_RESET_TRIES 5 + +/* Maximum frame size = (MTU + LL heaader size) + FCS size */ + +#define NCV_MAX_FRAME_SIZE(p) (p->dev.netdev.d_pktsize + 4) + +/* Packet Memory ************************************************************/ + +/* Maximum number of allocated tx and rx packets */ + +#define NCV7410_TX_QUOTA 1 +#define NCV7410_RX_QUOTA 2 + +#if CONFIG_IOB_NBUFFERS < (NCV7410_TX_QUOTA + NCV7410_RX_QUOTA) +# error "CONFIG_IOB_NBUFFERS must be > (NCV7410_TX_QUOTA + NCV7410_RX_QUOTA)" +#endif + +#ifndef CONFIG_SCHED_LPWORK +# error "CONFIG_SCHED_LPWORK is needed by NCV7410 driver" +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The ncv7410_driver_s encapsulates all state information for a single + * hardware interface + */ + +enum ncv_ifstate_e +{ + NCV_RESET, + NCV_INIT_DOWN, + NCV_INIT_UP +}; + +struct ncv7410_driver_s +{ + /* This holds the information visible to the NuttX network + * (must be placed first) + */ + + struct netdev_lowerhalf_s dev; + + mutex_t mutex; + + /* This is the contained SPI driver instance */ + + FAR struct spi_dev_s *spi; + + /* irq number of the interrupt signal pin */ + + int irqnum; + + /* Work instances for work_queue handling */ + + struct work_s interrupt_work; + struct work_s io_work; + + /* Driver state, one of ncv_ifstate_e values */ + + uint8_t ifstate; + + /* MAC-PHY internal buffer status */ + + int txc; + int rca; + + /* Packet buffer management */ + + FAR netpkt_t *tx_pkt; + FAR netpkt_t *rx_pkt; + int tx_pkt_idx; + int rx_pkt_idx; + int tx_pkt_len; + bool rx_pkt_ready; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Bit calculations */ + +static int ncv_get_parity(uint32_t w); +uint8_t ncv_bitrev8(uint8_t b); + +/* SPI transfers */ + +static int ncv_write_reg(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, uint32_t word); + +static int ncv_read_reg(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, FAR uint32_t *word); + +static int ncv_set_clear_bits(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, + uint32_t setbits, uint32_t clearbits); + +static int ncv_poll_footer(FAR struct ncv7410_driver_s *priv, + FAR uint32_t *footer); + +static int ncv_exchange_chunk(FAR struct ncv7410_driver_s *priv, + FAR uint8_t *txbuf, FAR uint8_t *rxbuf, + uint32_t header, uint32_t *footer); + +/* Interrupt handling */ + +static int ncv_interrupt(int irq, FAR void *context, FAR void *arg); +static void ncv_interrupt_work(FAR void *arg); + +/* Data Transaction Protocol logic */ + +static void ncv_io_work(FAR void *arg); +static uint32_t ncv_prepare_chunk_exchange(FAR struct ncv7410_driver_s *priv, + FAR uint8_t *txbuf); +static bool ncv_can_rx(FAR struct ncv7410_driver_s *priv); +static void ncv_try_finish_tx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_handle_rx_chunk(FAR struct ncv7410_driver_s *priv, + uint32_t footer, FAR uint8_t *rxbuf); +static void ncv_finalize_rx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_release_tx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_release_rx_packet(FAR struct ncv7410_driver_s *priv); + +/* SPI inline utility functions */ + +static inline void ncv_lock_spi(FAR struct ncv7410_driver_s *priv); +static inline void ncv_unlock_spi(FAR struct ncv7410_driver_s *priv); + +static inline void ncv_config_spi(FAR struct ncv7410_driver_s *priv); + +static inline void ncv_select_spi(FAR struct ncv7410_driver_s *priv); +static inline void ncv_deselect_spi(FAR struct ncv7410_driver_s *priv); + +/* ncv7410 reset and configuration */ + +static int ncv_reset(FAR struct ncv7410_driver_s *priv); +static int ncv_config(FAR struct ncv7410_driver_s *priv); +static int ncv_enable(FAR struct ncv7410_driver_s *priv); +static int ncv_disable(FAR struct ncv7410_driver_s *priv); +static int ncv_init_mac_addr(FAR struct ncv7410_driver_s *priv); + +/* Driver buffer manipulation */ + +static void ncv_reset_driver_buffers(FAR struct ncv7410_driver_s *priv); + +/* NuttX callback functions */ + +static int ncv7410_ifup(FAR struct netdev_lowerhalf_s *dev); +static int ncv7410_ifdown(FAR struct netdev_lowerhalf_s *dev); +static int ncv7410_transmit(FAR struct netdev_lowerhalf_s *dev, + FAR netpkt_t *pkt); +static FAR netpkt_t *ncv7410_receive(FAR struct netdev_lowerhalf_s *dev); + +/* Debug */ + +static void ncv_print_footer(uint32_t footer); + +/* Initialization */ + +int ncv7410_initialize(FAR struct spi_dev_s *spi, int irq); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ncv_interrupt + * + * Description: + * Schedule interrupt work when the interrupt signal from MAC-PHY is + * received. + * + * Input Parameters: + * irq - not used + * context - not used + * arg - ncv7410_driver_s priv structure to be passed to the interrupt + * worker + * + * Returned Value: + * OK is always returned. + * + ****************************************************************************/ + +static int ncv_interrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct ncv7410_driver_s *priv = (FAR struct ncv7410_driver_s *) arg; + + ninfo("ncv7410 interrupt!\n"); + + /* schedule interrupt work */ + + work_queue(NCVWORK, &priv->interrupt_work, ncv_interrupt_work, priv, 0); + return OK; +} + +/**************************************************************************** + * Name: ncv_interrupt_work + * + * Description: + * Identify the interrupt source and perform necessary work. + * + * Input Parameters: + * arg - pointer to driver private data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_interrupt_work(FAR void *arg) +{ + FAR struct ncv7410_driver_s *priv = (FAR struct ncv7410_driver_s *) arg; + uint32_t footer; + + nxmutex_lock(&priv->mutex); + + if (priv->ifstate != NCV_INIT_UP) + { + nxmutex_unlock(&priv->mutex); + return; + } + + ninfo("ncv7410 interrupt worker invoked!\n"); + + /* poll the data chunk footer */ + + if (ncv_poll_footer(priv, &footer)) + { + nerr("polling footer unsuccessful\n"); + + /* TODO: don't */ + + PANIC(); + } + + ncv_print_footer(footer); + + /* if EXST in the footer, check enabled sources + * STATUS0, link-status in clause 22 phy registers + * (not yet implemented) + */ + + /* update MAC-PHY buffer status */ + + priv->txc = oa_tx_credits(footer); + priv->rca = oa_rx_available(footer); + + if ((priv->tx_pkt && priv->txc) || priv->rca) + { + /* schedule IO work */ + + work_queue(NCVWORK, &priv->io_work, ncv_io_work, priv, 0); + } + + nxmutex_unlock(&priv->mutex); +} + +/**************************************************************************** + * Name: ncv_io_work + * + * Description: + * Exchange data chunk with the MAC-PHY. + * + * Input Parameters: + * arg - pointer to driver private data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_io_work(FAR void *arg) +{ + FAR struct ncv7410_driver_s *priv = (FAR struct ncv7410_driver_s *) arg; + + uint8_t txbuf[NCV_CHUNK_DEFAULT_PAYLOAD_SIZE]; + uint8_t rxbuf[NCV_CHUNK_DEFAULT_PAYLOAD_SIZE]; + + uint32_t header; + uint32_t footer; + + nxmutex_lock(&priv->mutex); + + if (priv->ifstate != NCV_INIT_UP) + { + nxmutex_unlock(&priv->mutex); + return; + } + + header = ncv_prepare_chunk_exchange(priv, txbuf); + + /* perform the SPI exchange */ + + if (ncv_exchange_chunk(priv, txbuf, rxbuf, header, &footer)) + { + nerr("Error during chunk exchange\n"); + + /* TODO: do not panic, the best is probably to report the error + * and reset MAC to some defined state and reset driver + */ + + PANIC(); + } + + ncv_try_finish_tx_packet(priv); + + ncv_handle_rx_chunk(priv, footer, rxbuf); + + /* schedule further work if needed */ + + if ((priv->tx_pkt && priv->txc) || priv->rca) + { + work_queue(NCVWORK, &priv->io_work, ncv_io_work, priv, 0); + } + + nxmutex_unlock(&priv->mutex); +} + +/**************************************************************************** + * Name: ncv_prepare_chunk_exchange + * + * Description: + * Determine whether there is data to transmit or receive. + * Set the appropriate header bitfields and fill the txbuf accordingly. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * txbuf - pointer to the transmit chunk buffer + * + * Returned Value: + * Returns the prepared chunk header + * + ****************************************************************************/ + +static uint32_t ncv_prepare_chunk_exchange(FAR struct ncv7410_driver_s *priv, + FAR uint8_t *txbuf) +{ + uint32_t header = 0; + int txlen; + + if (priv->tx_pkt && priv->txc) + { + header |= (1 << OA_DV_POS); /* Data Valid */ + + if (priv->tx_pkt_idx == 0) + { + header |= (1 << OA_SV_POS) /* Start Valid */ + | (0 << OA_SWO_POS); /* Start Word Offset = 0 */ + } + + txlen = priv->tx_pkt_len - priv->tx_pkt_idx; + + if (txlen <= NCV_CHUNK_DEFAULT_PAYLOAD_SIZE) + { + header |= (1 << OA_EV_POS) /* End Valid */ + | ((txlen - 1) << OA_EBO_POS); /* End Byte Offset */ + } + else + { + txlen = NCV_CHUNK_DEFAULT_PAYLOAD_SIZE; + } + + /* copy data from network to txbuf */ + + netpkt_copyout(&priv->dev, txbuf, priv->tx_pkt, + txlen, priv->tx_pkt_idx); + priv->tx_pkt_idx += txlen; + } + + if (ncv_can_rx(priv) == false) + { + header |= (1 << OA_NORX_POS); /* no rx */ + } + + return header; +} + +/**************************************************************************** + * Name: ncv_can_rx + * + * Description: + * Determine whether rx data is available and whether it can be received. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * If it is possible to receive an rx chunk, true is returned, + * otherwise false is returned. + * + ****************************************************************************/ + +static bool ncv_can_rx(FAR struct ncv7410_driver_s *priv) +{ + if (!priv->rca) + { + return false; + } + + if (priv->rx_pkt_ready) + { + return false; + } + + if (priv->rx_pkt) + { + return true; + } + + /* no RX packet, try to alloc */ + + priv->rx_pkt = netpkt_alloc(&priv->dev, NETPKT_RX); + if (priv->rx_pkt) + { + return true; + } + + ninfo("info: Failed to alloc rx netpkt\n"); + + /* there is no buffer for rx data */ + + return false; +} + +/**************************************************************************** + * Name: ncv_try_finish_tx_packet + * + * Description: + * Check whether the entire packet has been transmitted. + * If so, free the tx netpkt and notify the upperhalf. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_try_finish_tx_packet(FAR struct ncv7410_driver_s *priv) +{ + if (priv->tx_pkt && (priv->tx_pkt_idx == priv->tx_pkt_len)) + { + ncv_release_tx_packet(priv); + netdev_lower_txdone(&priv->dev); + } +} + +/**************************************************************************** + * Name: ncv_handle_rx_chunk + * + * Description: + * Parse the received footer, update buffer status and handle data + * in the rxbuf. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * footer - the received footer + * rxbuf - pointer to the received data buffer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_handle_rx_chunk(FAR struct ncv7410_driver_s *priv, + uint32_t footer, FAR uint8_t *rxbuf) +{ + int rxlen; + int newlen; + + /* update buffer status */ + + priv->txc = oa_tx_credits(footer); + priv->rca = oa_rx_available(footer); + + /* check rx_pkt && !rx_pkt_ready, + * oa_data_valid flag might have been set due to an SPI error + */ + + if (oa_data_valid(footer) && priv->rx_pkt && !priv->rx_pkt_ready) + { + if (oa_start_valid(footer)) + { + priv->rx_pkt_idx = 0; + } + + if (oa_end_valid(footer)) + { + if (oa_frame_drop(footer)) + { + ncv_release_rx_packet(priv); + return; + } + + rxlen = oa_end_byte_offset(footer) + 1; + } + else + { + rxlen = NCV_CHUNK_DEFAULT_PAYLOAD_SIZE; + } + + newlen = priv->rx_pkt_idx + rxlen; + + if (newlen > NCV_MAX_FRAME_SIZE(priv)) + { + nwarn("Dropping chunk of a packet that is too long"); + + /* set index so that a subsequent chunk with + * smaller payload won't pass + */ + + priv->rx_pkt_idx = NCV_MAX_FRAME_SIZE(priv) + 1; + return; + } + + netpkt_copyin(&priv->dev, priv->rx_pkt, rxbuf, + rxlen, priv->rx_pkt_idx); + priv->rx_pkt_idx = newlen; + + if (oa_end_valid(footer)) + { + /* finalize packet and notify the upper */ + + ncv_finalize_rx_packet(priv); + netdev_lower_rxready(&priv->dev); + } + } +} + +/**************************************************************************** + * Name: ncv_finalize_rx_packet + * + * Description: + * Strip down last 4 bytes (FCS) from the rx packet and mark it ready. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_finalize_rx_packet(FAR struct ncv7410_driver_s *priv) +{ + netpkt_setdatalen(&priv->dev, priv->rx_pkt, + netpkt_getdatalen(&priv->dev, priv->rx_pkt) - 4); + priv->rx_pkt_ready = true; +} + +/**************************************************************************** + * Name: ncv_release_tx_packet + * + * Description: + * Release the tx packet. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_release_tx_packet(FAR struct ncv7410_driver_s *priv) +{ + netpkt_free(&priv->dev, priv->tx_pkt, NETPKT_TX); + priv->tx_pkt = NULL; +} + +/**************************************************************************** + * Name: ncv_release_rx_packet + * + * Description: + * Release the rx packet. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_release_rx_packet(FAR struct ncv7410_driver_s *priv) +{ + netpkt_free(&priv->dev, priv->rx_pkt, NETPKT_RX); + priv->rx_pkt = NULL; +} + +/**************************************************************************** + * Name: ncv_get_parity + * + * Description: + * Obtain parity of a 32-bit word. + * + * Input Parameters: + * w - 32-bit word, subject to the parity calculation + * + * Returned Value: + * If the parity of the word is even, zero is returned. + * Otherwise one is returned. + * + ****************************************************************************/ + +static int ncv_get_parity(uint32_t w) +{ + /* www-graphics.stanford.edu/~seander/bithacks.html */ + + w ^= w >> 1; + w ^= w >> 2; + w = (w & 0x11111111u) * 0x11111111u; + return (w >> 28) & 1; +} + +/**************************************************************************** + * Name: ncv_bitrev8 + * + * Description: + * Perform a bit reverse of a byte. + * + * Input Parameters: + * b - byte to be reversed + * + * Returned Value: + * Byte with reversed bits is returned. + * + ****************************************************************************/ + +uint8_t ncv_bitrev8(uint8_t b) +{ + /* https://stackoverflow.com/a/2602885 */ + + b = (b & 0xf0) >> 4 | (b & 0x0f) << 4; + b = (b & 0xcc) >> 2 | (b & 0x33) << 2; + b = (b & 0xaa) >> 1 | (b & 0x55) << 1; + return b; +} + +/**************************************************************************** + * Name: ncv_(lock/unlock/config/select/deselect)_spi + * + * Description: + * Helper functions to setup SPI hardware. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void ncv_lock_spi(FAR struct ncv7410_driver_s *priv) +{ + SPI_LOCK(priv->spi, true); +} + +static inline void ncv_unlock_spi(FAR struct ncv7410_driver_s *priv) +{ + SPI_LOCK(priv->spi, false); +} + +static inline void ncv_config_spi(FAR struct ncv7410_driver_s *priv) +{ + SPI_SETMODE(priv->spi, OA_SPI_MODE); + SPI_SETBITS(priv->spi, OA_SPI_NBITS); + SPI_HWFEATURES(priv->spi, 0); /* disable HW features */ + SPI_SETFREQUENCY(priv->spi, CONFIG_NCV7410_FREQUENCY); +} + +static inline void ncv_select_spi(FAR struct ncv7410_driver_s *priv) +{ + SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), true); Review Comment: ```suggestion SPI_SELECT(priv->spi, SPIDEV_ETHERNET(priv->id), true); ``` The id can be passed as an argument of `ncv7410_initialize` so the board level logic can decide it. Either pass it as an integer or add `struct ncv7410_config` and add it to it. The latter option is better if future configuration based on board level logic will be required. You can take a look at `drivers/ioexpander/icxj.c` for example. ########## drivers/net/ncv7410.c: ########## @@ -0,0 +1,1703 @@ +/**************************************************************************** + * drivers/net/ncv7410.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#if defined(CONFIG_NET) && defined(CONFIG_NCV7410) + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <assert.h> +#include <debug.h> +#include <errno.h> + +#include <nuttx/spi/spi.h> +#include <sys/endian.h> + +#include <nuttx/irq.h> +#include <nuttx/kmalloc.h> +#include <nuttx/wqueue.h> +#include <nuttx/signal.h> +#include <nuttx/mutex.h> +#include <nuttx/net/ncv7410.h> +#include <nuttx/net/netdev_lowerhalf.h> + +#include "ncv7410.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NCVWORK LPWORK + +#define NCV_RESET_TRIES 5 + +/* Maximum frame size = (MTU + LL heaader size) + FCS size */ + +#define NCV_MAX_FRAME_SIZE(p) (p->dev.netdev.d_pktsize + 4) + +/* Packet Memory ************************************************************/ + +/* Maximum number of allocated tx and rx packets */ + +#define NCV7410_TX_QUOTA 1 +#define NCV7410_RX_QUOTA 2 + +#if CONFIG_IOB_NBUFFERS < (NCV7410_TX_QUOTA + NCV7410_RX_QUOTA) +# error "CONFIG_IOB_NBUFFERS must be > (NCV7410_TX_QUOTA + NCV7410_RX_QUOTA)" +#endif + +#ifndef CONFIG_SCHED_LPWORK +# error "CONFIG_SCHED_LPWORK is needed by NCV7410 driver" +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The ncv7410_driver_s encapsulates all state information for a single + * hardware interface + */ + +enum ncv_ifstate_e +{ + NCV_RESET, + NCV_INIT_DOWN, + NCV_INIT_UP +}; + +struct ncv7410_driver_s +{ + /* This holds the information visible to the NuttX network + * (must be placed first) + */ + + struct netdev_lowerhalf_s dev; + + mutex_t mutex; + + /* This is the contained SPI driver instance */ + + FAR struct spi_dev_s *spi; + + /* irq number of the interrupt signal pin */ + + int irqnum; + + /* Work instances for work_queue handling */ + + struct work_s interrupt_work; + struct work_s io_work; + + /* Driver state, one of ncv_ifstate_e values */ + + uint8_t ifstate; + + /* MAC-PHY internal buffer status */ + + int txc; + int rca; + + /* Packet buffer management */ + + FAR netpkt_t *tx_pkt; + FAR netpkt_t *rx_pkt; + int tx_pkt_idx; + int rx_pkt_idx; + int tx_pkt_len; + bool rx_pkt_ready; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Bit calculations */ + +static int ncv_get_parity(uint32_t w); +uint8_t ncv_bitrev8(uint8_t b); + +/* SPI transfers */ + +static int ncv_write_reg(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, uint32_t word); + +static int ncv_read_reg(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, FAR uint32_t *word); + +static int ncv_set_clear_bits(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, + uint32_t setbits, uint32_t clearbits); + +static int ncv_poll_footer(FAR struct ncv7410_driver_s *priv, + FAR uint32_t *footer); + +static int ncv_exchange_chunk(FAR struct ncv7410_driver_s *priv, + FAR uint8_t *txbuf, FAR uint8_t *rxbuf, + uint32_t header, uint32_t *footer); + +/* Interrupt handling */ + +static int ncv_interrupt(int irq, FAR void *context, FAR void *arg); +static void ncv_interrupt_work(FAR void *arg); + +/* Data Transaction Protocol logic */ + +static void ncv_io_work(FAR void *arg); +static uint32_t ncv_prepare_chunk_exchange(FAR struct ncv7410_driver_s *priv, + FAR uint8_t *txbuf); +static bool ncv_can_rx(FAR struct ncv7410_driver_s *priv); +static void ncv_try_finish_tx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_handle_rx_chunk(FAR struct ncv7410_driver_s *priv, + uint32_t footer, FAR uint8_t *rxbuf); +static void ncv_finalize_rx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_release_tx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_release_rx_packet(FAR struct ncv7410_driver_s *priv); + +/* SPI inline utility functions */ + +static inline void ncv_lock_spi(FAR struct ncv7410_driver_s *priv); +static inline void ncv_unlock_spi(FAR struct ncv7410_driver_s *priv); + +static inline void ncv_config_spi(FAR struct ncv7410_driver_s *priv); + +static inline void ncv_select_spi(FAR struct ncv7410_driver_s *priv); +static inline void ncv_deselect_spi(FAR struct ncv7410_driver_s *priv); + +/* ncv7410 reset and configuration */ + +static int ncv_reset(FAR struct ncv7410_driver_s *priv); +static int ncv_config(FAR struct ncv7410_driver_s *priv); +static int ncv_enable(FAR struct ncv7410_driver_s *priv); +static int ncv_disable(FAR struct ncv7410_driver_s *priv); +static int ncv_init_mac_addr(FAR struct ncv7410_driver_s *priv); + +/* Driver buffer manipulation */ + +static void ncv_reset_driver_buffers(FAR struct ncv7410_driver_s *priv); + +/* NuttX callback functions */ + +static int ncv7410_ifup(FAR struct netdev_lowerhalf_s *dev); +static int ncv7410_ifdown(FAR struct netdev_lowerhalf_s *dev); +static int ncv7410_transmit(FAR struct netdev_lowerhalf_s *dev, + FAR netpkt_t *pkt); +static FAR netpkt_t *ncv7410_receive(FAR struct netdev_lowerhalf_s *dev); + +/* Debug */ + +static void ncv_print_footer(uint32_t footer); + +/* Initialization */ + +int ncv7410_initialize(FAR struct spi_dev_s *spi, int irq); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ncv_interrupt + * + * Description: + * Schedule interrupt work when the interrupt signal from MAC-PHY is + * received. + * + * Input Parameters: + * irq - not used + * context - not used + * arg - ncv7410_driver_s priv structure to be passed to the interrupt + * worker + * + * Returned Value: + * OK is always returned. + * + ****************************************************************************/ + +static int ncv_interrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct ncv7410_driver_s *priv = (FAR struct ncv7410_driver_s *) arg; + + ninfo("ncv7410 interrupt!\n"); + + /* schedule interrupt work */ + + work_queue(NCVWORK, &priv->interrupt_work, ncv_interrupt_work, priv, 0); + return OK; +} + +/**************************************************************************** + * Name: ncv_interrupt_work + * + * Description: + * Identify the interrupt source and perform necessary work. + * + * Input Parameters: + * arg - pointer to driver private data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_interrupt_work(FAR void *arg) +{ + FAR struct ncv7410_driver_s *priv = (FAR struct ncv7410_driver_s *) arg; + uint32_t footer; + + nxmutex_lock(&priv->mutex); + + if (priv->ifstate != NCV_INIT_UP) + { + nxmutex_unlock(&priv->mutex); + return; + } + + ninfo("ncv7410 interrupt worker invoked!\n"); + + /* poll the data chunk footer */ + + if (ncv_poll_footer(priv, &footer)) + { + nerr("polling footer unsuccessful\n"); + + /* TODO: don't */ + + PANIC(); + } + + ncv_print_footer(footer); + + /* if EXST in the footer, check enabled sources + * STATUS0, link-status in clause 22 phy registers + * (not yet implemented) + */ + + /* update MAC-PHY buffer status */ + + priv->txc = oa_tx_credits(footer); + priv->rca = oa_rx_available(footer); + + if ((priv->tx_pkt && priv->txc) || priv->rca) + { + /* schedule IO work */ + + work_queue(NCVWORK, &priv->io_work, ncv_io_work, priv, 0); + } + + nxmutex_unlock(&priv->mutex); +} + +/**************************************************************************** + * Name: ncv_io_work + * + * Description: + * Exchange data chunk with the MAC-PHY. + * + * Input Parameters: + * arg - pointer to driver private data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_io_work(FAR void *arg) +{ + FAR struct ncv7410_driver_s *priv = (FAR struct ncv7410_driver_s *) arg; + + uint8_t txbuf[NCV_CHUNK_DEFAULT_PAYLOAD_SIZE]; + uint8_t rxbuf[NCV_CHUNK_DEFAULT_PAYLOAD_SIZE]; + + uint32_t header; + uint32_t footer; + + nxmutex_lock(&priv->mutex); + + if (priv->ifstate != NCV_INIT_UP) + { + nxmutex_unlock(&priv->mutex); + return; + } + + header = ncv_prepare_chunk_exchange(priv, txbuf); + + /* perform the SPI exchange */ + + if (ncv_exchange_chunk(priv, txbuf, rxbuf, header, &footer)) + { + nerr("Error during chunk exchange\n"); + + /* TODO: do not panic, the best is probably to report the error + * and reset MAC to some defined state and reset driver + */ + + PANIC(); + } + + ncv_try_finish_tx_packet(priv); + + ncv_handle_rx_chunk(priv, footer, rxbuf); + + /* schedule further work if needed */ + + if ((priv->tx_pkt && priv->txc) || priv->rca) + { + work_queue(NCVWORK, &priv->io_work, ncv_io_work, priv, 0); + } + + nxmutex_unlock(&priv->mutex); +} + +/**************************************************************************** + * Name: ncv_prepare_chunk_exchange + * + * Description: + * Determine whether there is data to transmit or receive. + * Set the appropriate header bitfields and fill the txbuf accordingly. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * txbuf - pointer to the transmit chunk buffer + * + * Returned Value: + * Returns the prepared chunk header + * + ****************************************************************************/ + +static uint32_t ncv_prepare_chunk_exchange(FAR struct ncv7410_driver_s *priv, + FAR uint8_t *txbuf) +{ + uint32_t header = 0; + int txlen; + + if (priv->tx_pkt && priv->txc) + { + header |= (1 << OA_DV_POS); /* Data Valid */ + + if (priv->tx_pkt_idx == 0) + { + header |= (1 << OA_SV_POS) /* Start Valid */ + | (0 << OA_SWO_POS); /* Start Word Offset = 0 */ + } + + txlen = priv->tx_pkt_len - priv->tx_pkt_idx; + + if (txlen <= NCV_CHUNK_DEFAULT_PAYLOAD_SIZE) + { + header |= (1 << OA_EV_POS) /* End Valid */ + | ((txlen - 1) << OA_EBO_POS); /* End Byte Offset */ + } + else + { + txlen = NCV_CHUNK_DEFAULT_PAYLOAD_SIZE; + } + + /* copy data from network to txbuf */ + + netpkt_copyout(&priv->dev, txbuf, priv->tx_pkt, + txlen, priv->tx_pkt_idx); + priv->tx_pkt_idx += txlen; + } + + if (ncv_can_rx(priv) == false) + { + header |= (1 << OA_NORX_POS); /* no rx */ + } + + return header; +} + +/**************************************************************************** + * Name: ncv_can_rx + * + * Description: + * Determine whether rx data is available and whether it can be received. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * If it is possible to receive an rx chunk, true is returned, + * otherwise false is returned. + * + ****************************************************************************/ + +static bool ncv_can_rx(FAR struct ncv7410_driver_s *priv) +{ + if (!priv->rca) + { + return false; + } + + if (priv->rx_pkt_ready) + { + return false; + } + + if (priv->rx_pkt) + { + return true; + } + + /* no RX packet, try to alloc */ + + priv->rx_pkt = netpkt_alloc(&priv->dev, NETPKT_RX); + if (priv->rx_pkt) + { + return true; + } + + ninfo("info: Failed to alloc rx netpkt\n"); + + /* there is no buffer for rx data */ + + return false; +} + +/**************************************************************************** + * Name: ncv_try_finish_tx_packet + * + * Description: + * Check whether the entire packet has been transmitted. + * If so, free the tx netpkt and notify the upperhalf. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_try_finish_tx_packet(FAR struct ncv7410_driver_s *priv) +{ + if (priv->tx_pkt && (priv->tx_pkt_idx == priv->tx_pkt_len)) + { + ncv_release_tx_packet(priv); + netdev_lower_txdone(&priv->dev); + } +} + +/**************************************************************************** + * Name: ncv_handle_rx_chunk + * + * Description: + * Parse the received footer, update buffer status and handle data + * in the rxbuf. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * footer - the received footer + * rxbuf - pointer to the received data buffer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_handle_rx_chunk(FAR struct ncv7410_driver_s *priv, + uint32_t footer, FAR uint8_t *rxbuf) +{ + int rxlen; + int newlen; + + /* update buffer status */ + + priv->txc = oa_tx_credits(footer); + priv->rca = oa_rx_available(footer); + + /* check rx_pkt && !rx_pkt_ready, + * oa_data_valid flag might have been set due to an SPI error + */ + + if (oa_data_valid(footer) && priv->rx_pkt && !priv->rx_pkt_ready) + { + if (oa_start_valid(footer)) + { + priv->rx_pkt_idx = 0; + } + + if (oa_end_valid(footer)) + { + if (oa_frame_drop(footer)) + { + ncv_release_rx_packet(priv); + return; + } + + rxlen = oa_end_byte_offset(footer) + 1; + } + else + { + rxlen = NCV_CHUNK_DEFAULT_PAYLOAD_SIZE; + } + + newlen = priv->rx_pkt_idx + rxlen; + + if (newlen > NCV_MAX_FRAME_SIZE(priv)) + { + nwarn("Dropping chunk of a packet that is too long"); + + /* set index so that a subsequent chunk with + * smaller payload won't pass + */ + + priv->rx_pkt_idx = NCV_MAX_FRAME_SIZE(priv) + 1; + return; + } + + netpkt_copyin(&priv->dev, priv->rx_pkt, rxbuf, + rxlen, priv->rx_pkt_idx); + priv->rx_pkt_idx = newlen; + + if (oa_end_valid(footer)) + { + /* finalize packet and notify the upper */ + + ncv_finalize_rx_packet(priv); + netdev_lower_rxready(&priv->dev); + } + } +} + +/**************************************************************************** + * Name: ncv_finalize_rx_packet + * + * Description: + * Strip down last 4 bytes (FCS) from the rx packet and mark it ready. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_finalize_rx_packet(FAR struct ncv7410_driver_s *priv) +{ + netpkt_setdatalen(&priv->dev, priv->rx_pkt, + netpkt_getdatalen(&priv->dev, priv->rx_pkt) - 4); + priv->rx_pkt_ready = true; +} + +/**************************************************************************** + * Name: ncv_release_tx_packet + * + * Description: + * Release the tx packet. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_release_tx_packet(FAR struct ncv7410_driver_s *priv) +{ + netpkt_free(&priv->dev, priv->tx_pkt, NETPKT_TX); + priv->tx_pkt = NULL; +} + +/**************************************************************************** + * Name: ncv_release_rx_packet + * + * Description: + * Release the rx packet. + * + * Input Parameters: + * priv - pointer to the driver-specific state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void ncv_release_rx_packet(FAR struct ncv7410_driver_s *priv) +{ + netpkt_free(&priv->dev, priv->rx_pkt, NETPKT_RX); + priv->rx_pkt = NULL; +} + +/**************************************************************************** + * Name: ncv_get_parity + * + * Description: + * Obtain parity of a 32-bit word. + * + * Input Parameters: + * w - 32-bit word, subject to the parity calculation + * + * Returned Value: + * If the parity of the word is even, zero is returned. + * Otherwise one is returned. + * + ****************************************************************************/ + +static int ncv_get_parity(uint32_t w) +{ + /* www-graphics.stanford.edu/~seander/bithacks.html */ + + w ^= w >> 1; + w ^= w >> 2; + w = (w & 0x11111111u) * 0x11111111u; + return (w >> 28) & 1; +} + +/**************************************************************************** + * Name: ncv_bitrev8 + * + * Description: + * Perform a bit reverse of a byte. + * + * Input Parameters: + * b - byte to be reversed + * + * Returned Value: + * Byte with reversed bits is returned. + * + ****************************************************************************/ + +uint8_t ncv_bitrev8(uint8_t b) +{ + /* https://stackoverflow.com/a/2602885 */ + + b = (b & 0xf0) >> 4 | (b & 0x0f) << 4; + b = (b & 0xcc) >> 2 | (b & 0x33) << 2; + b = (b & 0xaa) >> 1 | (b & 0x55) << 1; + return b; +} + +/**************************************************************************** Review Comment: Is there a reason to have lock, config and select as three separate functions? You use them in the same order together anyway. I would just call `ncv_select_spi` that would lock, config and select and `ncv_deselect_spi` that would deselect and unlock ########## drivers/net/ncv7410.c: ########## @@ -0,0 +1,1703 @@ +/**************************************************************************** + * drivers/net/ncv7410.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#if defined(CONFIG_NET) && defined(CONFIG_NCV7410) + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <assert.h> +#include <debug.h> +#include <errno.h> + +#include <nuttx/spi/spi.h> +#include <sys/endian.h> + +#include <nuttx/irq.h> +#include <nuttx/kmalloc.h> +#include <nuttx/wqueue.h> +#include <nuttx/signal.h> +#include <nuttx/mutex.h> +#include <nuttx/net/ncv7410.h> +#include <nuttx/net/netdev_lowerhalf.h> + +#include "ncv7410.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NCVWORK LPWORK + +#define NCV_RESET_TRIES 5 + +/* Maximum frame size = (MTU + LL heaader size) + FCS size */ + +#define NCV_MAX_FRAME_SIZE(p) (p->dev.netdev.d_pktsize + 4) + +/* Packet Memory ************************************************************/ + +/* Maximum number of allocated tx and rx packets */ + +#define NCV7410_TX_QUOTA 1 +#define NCV7410_RX_QUOTA 2 + +#if CONFIG_IOB_NBUFFERS < (NCV7410_TX_QUOTA + NCV7410_RX_QUOTA) +# error "CONFIG_IOB_NBUFFERS must be > (NCV7410_TX_QUOTA + NCV7410_RX_QUOTA)" +#endif + +#ifndef CONFIG_SCHED_LPWORK +# error "CONFIG_SCHED_LPWORK is needed by NCV7410 driver" +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The ncv7410_driver_s encapsulates all state information for a single + * hardware interface + */ + +enum ncv_ifstate_e +{ + NCV_RESET, + NCV_INIT_DOWN, + NCV_INIT_UP +}; + +struct ncv7410_driver_s +{ + /* This holds the information visible to the NuttX network + * (must be placed first) + */ + + struct netdev_lowerhalf_s dev; + + mutex_t mutex; + + /* This is the contained SPI driver instance */ + + FAR struct spi_dev_s *spi; + + /* irq number of the interrupt signal pin */ + + int irqnum; + + /* Work instances for work_queue handling */ + + struct work_s interrupt_work; + struct work_s io_work; + + /* Driver state, one of ncv_ifstate_e values */ + + uint8_t ifstate; + + /* MAC-PHY internal buffer status */ + + int txc; + int rca; + + /* Packet buffer management */ + + FAR netpkt_t *tx_pkt; + FAR netpkt_t *rx_pkt; + int tx_pkt_idx; + int rx_pkt_idx; + int tx_pkt_len; + bool rx_pkt_ready; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Bit calculations */ + +static int ncv_get_parity(uint32_t w); +uint8_t ncv_bitrev8(uint8_t b); + +/* SPI transfers */ + +static int ncv_write_reg(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, uint32_t word); + +static int ncv_read_reg(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, FAR uint32_t *word); + +static int ncv_set_clear_bits(FAR struct ncv7410_driver_s *priv, + oa_regid_t regid, + uint32_t setbits, uint32_t clearbits); + +static int ncv_poll_footer(FAR struct ncv7410_driver_s *priv, + FAR uint32_t *footer); + +static int ncv_exchange_chunk(FAR struct ncv7410_driver_s *priv, + FAR uint8_t *txbuf, FAR uint8_t *rxbuf, + uint32_t header, uint32_t *footer); + +/* Interrupt handling */ + +static int ncv_interrupt(int irq, FAR void *context, FAR void *arg); +static void ncv_interrupt_work(FAR void *arg); + +/* Data Transaction Protocol logic */ + +static void ncv_io_work(FAR void *arg); +static uint32_t ncv_prepare_chunk_exchange(FAR struct ncv7410_driver_s *priv, + FAR uint8_t *txbuf); +static bool ncv_can_rx(FAR struct ncv7410_driver_s *priv); +static void ncv_try_finish_tx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_handle_rx_chunk(FAR struct ncv7410_driver_s *priv, + uint32_t footer, FAR uint8_t *rxbuf); +static void ncv_finalize_rx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_release_tx_packet(FAR struct ncv7410_driver_s *priv); +static void ncv_release_rx_packet(FAR struct ncv7410_driver_s *priv); + +/* SPI inline utility functions */ + +static inline void ncv_lock_spi(FAR struct ncv7410_driver_s *priv); +static inline void ncv_unlock_spi(FAR struct ncv7410_driver_s *priv); + +static inline void ncv_config_spi(FAR struct ncv7410_driver_s *priv); + +static inline void ncv_select_spi(FAR struct ncv7410_driver_s *priv); +static inline void ncv_deselect_spi(FAR struct ncv7410_driver_s *priv); + +/* ncv7410 reset and configuration */ + +static int ncv_reset(FAR struct ncv7410_driver_s *priv); +static int ncv_config(FAR struct ncv7410_driver_s *priv); +static int ncv_enable(FAR struct ncv7410_driver_s *priv); +static int ncv_disable(FAR struct ncv7410_driver_s *priv); +static int ncv_init_mac_addr(FAR struct ncv7410_driver_s *priv); + +/* Driver buffer manipulation */ + +static void ncv_reset_driver_buffers(FAR struct ncv7410_driver_s *priv); + +/* NuttX callback functions */ + +static int ncv7410_ifup(FAR struct netdev_lowerhalf_s *dev); +static int ncv7410_ifdown(FAR struct netdev_lowerhalf_s *dev); +static int ncv7410_transmit(FAR struct netdev_lowerhalf_s *dev, + FAR netpkt_t *pkt); +static FAR netpkt_t *ncv7410_receive(FAR struct netdev_lowerhalf_s *dev); + +/* Debug */ + +static void ncv_print_footer(uint32_t footer); Review Comment: I would place the deifinition, declaration and calls to this under `#ifdef CONFIG_DEBUG_NET_INFO` to reduce code size and useless function call. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org