This is an automated email from the ASF dual-hosted git repository. jerpelea pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push: new 880c8e5d266 drivers/net: add IGB network card support 880c8e5d266 is described below commit 880c8e5d26662f690432645327e3b76ebd2980b0 Author: p-szafonimateusz <p-szafonimate...@xiaomi.com> AuthorDate: Mon Jun 9 13:04:38 2025 +0200 drivers/net: add IGB network card support Add support for Intel IGB type of network cards. Signed-off-by: p-szafonimateusz <p-szafonimate...@xiaomi.com> --- .../components/drivers/special/pci/index.rst | 10 + drivers/net/CMakeLists.txt | 4 + drivers/net/Kconfig | 30 + drivers/net/Make.defs | 8 +- drivers/net/igb.c | 1492 ++++++++++++++++++++ drivers/net/igb.h | 544 +++++++ drivers/pci/pci_drivers.c | 11 + include/nuttx/net/igb.h | 59 + 8 files changed, 2156 insertions(+), 2 deletions(-) diff --git a/Documentation/components/drivers/special/pci/index.rst b/Documentation/components/drivers/special/pci/index.rst index 99160423b4e..ddd5dca7e58 100644 --- a/Documentation/components/drivers/special/pci/index.rst +++ b/Documentation/components/drivers/special/pci/index.rst @@ -50,6 +50,16 @@ Supported devices: - Intel 82574L - Intel 82574L +Intel igb +--------- + +Intel igb compatible NIC support can be found in ``drivers/net/igb.c``. + +Supported devices: + +- Intel 82576 +- Intel I211 + Intel igc --------- diff --git a/drivers/net/CMakeLists.txt b/drivers/net/CMakeLists.txt index 3d0937f7f5f..1e9613871e8 100644 --- a/drivers/net/CMakeLists.txt +++ b/drivers/net/CMakeLists.txt @@ -89,6 +89,10 @@ if(CONFIG_NET) list(APPEND SRCS e1000.c) endif() + if(CONFIG_NET_IGB) + list(APPEND SRCS igb.c) + endif() + if(CONFIG_NET_IGC) list(APPEND SRCS igc.c) endif() diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 77e6604877c..ffb561a3e47 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -815,6 +815,36 @@ config NET_E1000_RXSPARE endif # NET_E1000 +menuconfig NET_IGB + bool "Intel IGB support" + default n + depends on PCI && PCI_MSIX + ---help--- + Enable IGB PCI Ethernet driver. + +if NET_IGB + +config NET_IGB_TXDESC + int "Intel IGB TX descriptors" + default 256 + +config NET_IGB_RXDESC + int "Intel IGB RX descriptors" + default 256 + +config NET_IGB_RXSPARE + int "Intel IGB spare RX buffers" + default 8 + +config NET_IGB_INT_INTERVAL + int "Intel IGB interrupt interval" + default 100 + range 1 8191 + ---help--- + Minimum Inter-interrupt Interval in 1 us increments. + +endif # NET_IGB + menuconfig NET_IGC bool "Intel IGC support" default n diff --git a/drivers/net/Make.defs b/drivers/net/Make.defs index f341749752b..b1e781b7e00 100644 --- a/drivers/net/Make.defs +++ b/drivers/net/Make.defs @@ -103,14 +103,18 @@ ifeq ($(CONFIG_NET_E1000),y) CSRCS += e1000.c endif -ifeq ($(CONFIG_DRIVERS_WIFI_SIM),y) - CSRCS += wifi_sim.c +ifeq ($(CONFIG_NET_IGB),y) + CSRCS += igb.c endif ifeq ($(CONFIG_NET_IGC),y) CSRCS += igc.c endif +ifeq ($(CONFIG_DRIVERS_WIFI_SIM),y) + CSRCS += wifi_sim.c +endif + # Include network build support DEPPATH += --dep-path net diff --git a/drivers/net/igb.c b/drivers/net/igb.c new file mode 100644 index 00000000000..8585dd83b3e --- /dev/null +++ b/drivers/net/igb.c @@ -0,0 +1,1492 @@ +/***************************************************************************** + * drivers/net/igb.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> + +#include <assert.h> +#include <debug.h> +#include <errno.h> + +#include <nuttx/arch.h> +#include <nuttx/kmalloc.h> +#include <nuttx/wqueue.h> +#include <nuttx/addrenv.h> +#include <nuttx/spinlock.h> + +#include <nuttx/net/netdev_lowerhalf.h> +#include <nuttx/pci/pci.h> +#include <nuttx/net/igb.h> + +#include <arch/barriers.h> + +#include "igb.h" + +/***************************************************************************** + * Pre-processor Definitions + *****************************************************************************/ + +#if CONFIG_NET_IGB_TXDESC % 8 != 0 +# error CONFIG_NET_IGB_TXDESC must be multiple of 8 +#endif + +#if CONFIG_NET_IGB_RXDESC % 8 != 0 +# error CONFIG_NET_IGB_RXDESC must be multiple of 8 +#endif + +/* Packet buffer size */ + +#define IGB_PKTBUF_SIZE 2048 +#define IGB_RCTL_BSIZE IGB_RCTL_BSIZE_2048 + +/* TX and RX descriptors */ + +#define IGB_TX_DESC CONFIG_NET_IGB_TXDESC +#define IGB_RX_DESC CONFIG_NET_IGB_RXDESC + +/* After RX packet is done, we provide free netpkt to the RX descriptor ring. + * The upper-half network logic is responsible for freeing the RX packets + * so we need some additional spare netpkt buffers to assure that it's + * always possible to allocate the new RX packet in the receiver logic. + * It's hard to tell how many spare buffers is needed, for now it's set to 8. + */ + +#define IGB_TX_QUOTA IGB_TX_DESC +#define IGB_RX_QUOTA (IGB_RX_DESC + CONFIG_NET_IGB_RXSPARE) + +/* NOTE: CONFIG_IOB_ALIGNMENT must match system D-CACHE line size */ + +#if CONFIG_IOB_NBUFFERS < IGB_RX_QUOTA + IGB_TX_QUOTA +# error CONFIG_IOB_NBUFFERS must be > (IGB_RX_QUOTA + IGB_TX_QUOTA) +#endif + +#if CONFIG_IOB_BUFSIZE < IGB_PKTBUF_SIZE +# error CONFIG_IOB_BUFSIZE must be > IGB_PKTBUF_SIZE +#endif + +/* PCI BARs */ + +#define IGB_MMIO_BAR 0 +#define IGB_FLASH_BAR 1 +#define IGB_IO_BAR 2 +#define IGB_MSIX_BAR 3 + +/* For MSI-X we allocate all interrupts to MSI-X vector 0 */ + +#define IGB_GPIE_MSIX_SINGLE (IGB_GPIE_NSICR | IGB_GPIE_EIAME | \ + IGB_GPIE_PBASUPPORT) +#define IGB_MSIX_IMS (IGB_IC_TXDW | IGB_IC_LSC | \ + IGB_IC_RXMISS | IGB_IC_RXDW) +#define IGB_MSIX_EIMS (IGB_EIMS_NOMSIX_OTHER | \ + IGB_EIMS_NOMSIX_RXTX0) +#define IGB_MSIX_IVAR0 (IGB_IVAR0_RXQ0_VAL | IGB_IVAR0_TXQ0_VAL) +#define IGB_MSIX_IVARMSC (IGB_IVARMSC_OTHER_VAL) + +/***************************************************************************** + * Private Types + *****************************************************************************/ + +/* Extend default PCI devie type */ + +struct igb_type_s +{ + uint32_t desc_align; /* Descriptor alignment */ + uint32_t mta_regs; /* MTA registers */ +}; + +/* IGB private data */ + +struct igb_driver_s +{ + /* This holds the information visible to the NuttX network */ + + struct netdev_lowerhalf_s dev; + struct work_s work; + + /* Packets list */ + + FAR netpkt_t **tx_pkt; + FAR netpkt_t **rx_pkt; + + /* Descriptors */ + + FAR struct igb_tx_leg_s *tx; + FAR struct igb_rx_leg_s *rx; + + size_t tx_now; + size_t tx_done; + size_t rx_now; + + /* PCI data */ + + FAR struct pci_device_s *pcidev; + FAR const struct igb_type_s *type; + int irq; + uint64_t base; + +#ifdef CONFIG_NET_MCASTGROUP + /* MTA shadow */ + + FAR uint32_t *mta; +#endif +}; + +/***************************************************************************** + * Private Functions Definitions + *****************************************************************************/ + +/* Helpers */ + +static uint32_t igb_getreg_mem(FAR struct igb_driver_s *priv, + unsigned int offset); +static void igb_putreg_mem(FAR struct igb_driver_s *priv, + unsigned int offset, + uint32_t value); +#ifdef CONFIG_DEBUG_NET_INFO +static void igb_dump_reg(FAR struct igb_driver_s *priv, + FAR const char *msg, unsigned int offset); +static void igb_dump_mem(FAR struct igb_driver_s *priv, FAR const char *msg); +#endif + +/* Rings management */ + +static void igb_txclean(FAR struct igb_driver_s *priv); +static void igb_rxclean(FAR struct igb_driver_s *priv); + +/* Common TX logic */ + +static int igb_transmit(FAR struct netdev_lowerhalf_s *dev, + FAR netpkt_t *pkt); + +/* Interrupt handling */ + +static FAR netpkt_t *igb_receive(FAR struct netdev_lowerhalf_s *dev); +static void igb_txdone(FAR struct netdev_lowerhalf_s *dev); + +static void igb_msix_interrupt(FAR struct igb_driver_s *priv); +static int igb_interrupt(int irq, FAR void *context, FAR void *arg); + +/* NuttX callback functions */ + +static int igb_ifup(FAR struct netdev_lowerhalf_s *dev); +static int igb_ifdown(FAR struct netdev_lowerhalf_s *dev); + +#ifdef CONFIG_NET_MCASTGROUP +static uint32_t igb_hashmta(FAR struct igb_driver_s *priv, + FAR const uint8_t *mac); +static int igb_addmac(FAR struct netdev_lowerhalf_s *dev, + FAR const uint8_t *mac); +static int igb_rmmac(FAR struct netdev_lowerhalf_s *dev, + FAR const uint8_t *mac); +#endif + +/* Initialization */ + +static void igb_disable(FAR struct igb_driver_s *priv); +static void igb_enable(FAR struct igb_driver_s *priv); +static int igb_initialize(FAR struct igb_driver_s *priv); +static int igb_probe(FAR struct pci_device_s *dev); + +/***************************************************************************** + * Private Data + *****************************************************************************/ + +/* Intel 82576 (QEMU -device igb) */ + +static const struct igb_type_s g_igb_82576 = +{ + .desc_align = 128, + .mta_regs = 128 +}; + +/* Intel I211 */ + +static const struct igb_type_s g_igb_i211 = +{ + .desc_align = 128, + .mta_regs = 128 +}; + +static const struct pci_device_id_s g_igb_id_table[] = +{ + { + PCI_DEVICE(0x8086, 0x10c9), + .driver_data = (uintptr_t)&g_igb_82576 + }, + + { + PCI_DEVICE(0x8086, 0x1539), + .driver_data = (uintptr_t)&g_igb_i211 + }, + + { + PCI_DEVICE(0x8086, 0x1533), + .driver_data = (uintptr_t)&g_igb_i211 + }, + { } +}; + +static struct pci_driver_s g_pci_igb_drv = +{ + .id_table = g_igb_id_table, + .probe = igb_probe, +}; + +static const struct netdev_ops_s g_igb_ops = +{ + .ifup = igb_ifup, + .ifdown = igb_ifdown, + .transmit = igb_transmit, + .receive = igb_receive, +#ifdef CONFIG_NET_MCASTGROUP + .addmac = igb_addmac, + .rmmac = igb_rmmac, +#endif +}; + +/***************************************************************************** + * Private Functions + *****************************************************************************/ + +/***************************************************************************** + * Name: igb_getreg_mem + *****************************************************************************/ + +static uint32_t igb_getreg_mem(FAR struct igb_driver_s *priv, + unsigned int offset) +{ + uintptr_t addr = priv->base + offset; + return *((FAR volatile uint32_t *)addr); +} + +/***************************************************************************** + * Name: igb_putreg_mem + *****************************************************************************/ + +static void igb_putreg_mem(FAR struct igb_driver_s *priv, + unsigned int offset, + uint32_t value) +{ + uintptr_t addr = priv->base + offset; + *((FAR volatile uint32_t *)addr) = value; +} + +#ifdef CONFIG_DEBUG_NET_INFO +/***************************************************************************** + * Name: igb_dump_reg + *****************************************************************************/ + +static void igb_dump_reg(FAR struct igb_driver_s *priv, + FAR const char *msg, unsigned int offset) +{ + ninfo("\t%s:\t\t0x%" PRIx32 "\n", msg, igb_getreg_mem(priv, offset)); +} + +/***************************************************************************** + * Name: igb_dump_mem + *****************************************************************************/ + +static void igb_dump_mem(FAR struct igb_driver_s *priv, FAR const char *msg) +{ + ninfo("\nDump: %s\n", msg); + + ninfo("General registers:\n"); + igb_dump_reg(priv, "CTRL", IGB_CTRL); + igb_dump_reg(priv, "STATUS", IGB_STATUS); + igb_dump_reg(priv, "CTRLEXT", IGB_CTRLEXT); + igb_dump_reg(priv, "MDIC", IGB_MDIC); + igb_dump_reg(priv, "SERDESCTL", IGB_SERDESCTL); + igb_dump_reg(priv, "FCAL", IGB_FCAL); + igb_dump_reg(priv, "FCAH", IGB_FCAH); + igb_dump_reg(priv, "FCT", IGB_FCT); + igb_dump_reg(priv, "CONNSW", IGB_CONNSW); + igb_dump_reg(priv, "VET", IGB_VET); + igb_dump_reg(priv, "FCTTV", IGB_FCTTV); + + ninfo("Interrupt registers:\n"); + igb_dump_reg(priv, "ICS", IGB_ICS); + igb_dump_reg(priv, "IMS", IGB_IMS); + igb_dump_reg(priv, "IAM", IGB_IAM); + igb_dump_reg(priv, "EICS", IGB_EICS); + igb_dump_reg(priv, "EIMS", IGB_EIMS); + igb_dump_reg(priv, "EIAM", IGB_EIAM); + igb_dump_reg(priv, "EIAC", IGB_EIAC); + igb_dump_reg(priv, "IVAR0", IGB_IVAR0); + igb_dump_reg(priv, "IVARMSC", IGB_IVARMSC); + igb_dump_reg(priv, "EITR0", IGB_EITR0); + igb_dump_reg(priv, "GPIE", IGB_GPIE); + igb_dump_reg(priv, "PBACL", IGB_PBACL); + + ninfo("Receive registers:\n"); + igb_dump_reg(priv, "RCTL", IGB_RCTL); + igb_dump_reg(priv, "PSRCTL", IGB_PSRCTL); + igb_dump_reg(priv, "FCRTL0", IGB_FCRTL0); + igb_dump_reg(priv, "FCRTH0", IGB_FCRTH0); + igb_dump_reg(priv, "RXPBSIZE", IGB_RXPBSIZE); + igb_dump_reg(priv, "FCRTV", IGB_FCRTV); + igb_dump_reg(priv, "RDBAL0", IGB_RDBAL0); + igb_dump_reg(priv, "RDBAH0", IGB_RDBAH0); + igb_dump_reg(priv, "RDLEN0", IGB_RDLEN0); + igb_dump_reg(priv, "SRRCTL0", IGB_SRRCTL0); + igb_dump_reg(priv, "RDH0", IGB_RDH0); + igb_dump_reg(priv, "RDT0", IGB_RDT0); + igb_dump_reg(priv, "RXDCTL0", IGB_RXDCTL0); + igb_dump_reg(priv, "RXCTL0", IGB_RXCTL0); + igb_dump_reg(priv, "RXCSUM", IGB_RXCSUM); + igb_dump_reg(priv, "RLPML", IGB_RLPML); + igb_dump_reg(priv, "RFCTL", IGB_RFCTL); + igb_dump_reg(priv, "MTA", IGB_MTA); + igb_dump_reg(priv, "RAL", IGB_RAL); + igb_dump_reg(priv, "RAH", IGB_RAH); + + ninfo("Transmit registers:\n"); + igb_dump_reg(priv, "TXPBSIZE", IGB_TXPBSIZE); + igb_dump_reg(priv, "PBTWAC", IGB_PBTWAC); + igb_dump_reg(priv, "TCTL", IGB_TCTL); + igb_dump_reg(priv, "TCTLEXT", IGB_TCTLEXT); + igb_dump_reg(priv, "TIPG", IGB_TIPG); + igb_dump_reg(priv, "RETXCTL", IGB_RETXCTL); + igb_dump_reg(priv, "DTXCTL", IGB_DTXCTL); + igb_dump_reg(priv, "TDBAL0", IGB_TDBAL0); + igb_dump_reg(priv, "TDBAH0", IGB_TDBAH0); + igb_dump_reg(priv, "TDLEN0", IGB_TDLEN0); + igb_dump_reg(priv, "TDH0", IGB_TDH0); + igb_dump_reg(priv, "TDT0", IGB_TDT0); + igb_dump_reg(priv, "TXDCTL0", IGB_TXDCTL0); + igb_dump_reg(priv, "TXCTL0", IGB_TXCTL0); + igb_dump_reg(priv, "TDWBAL0", IGB_TDWBAL0); + igb_dump_reg(priv, "TDWBAH0", IGB_TDWBAH0); + + ninfo("Statistic registers:\n"); + igb_dump_reg(priv, "CRCERRS", IGB_CRCERRS); + igb_dump_reg(priv, "ALGNERRC", IGB_ALGNERRC); + igb_dump_reg(priv, "RXERRC", IGB_RXERRC); + igb_dump_reg(priv, "MPC", IGB_MPC); + igb_dump_reg(priv, "SCC", IGB_SCC); + igb_dump_reg(priv, "ECOL", IGB_ECOL); + igb_dump_reg(priv, "MCC", IGB_MCC); + igb_dump_reg(priv, "LATECOL", IGB_LATECOL); + igb_dump_reg(priv, "COLC", IGB_COLC); + igb_dump_reg(priv, "DC", IGB_DC); + igb_dump_reg(priv, "TNCRS", IGB_TNCRS); + igb_dump_reg(priv, "RLEC", IGB_RLEC); + igb_dump_reg(priv, "XONRXC", IGB_XONRXC); + igb_dump_reg(priv, "XONTXC", IGB_XONTXC); + igb_dump_reg(priv, "XOFFRXC", IGB_XOFFRXC); + igb_dump_reg(priv, "XOFFTXC", IGB_XOFFTXC); + igb_dump_reg(priv, "FCRUC", IGB_FCRUC); + igb_dump_reg(priv, "PRC64", IGB_PRC64); + igb_dump_reg(priv, "PRC127", IGB_PRC127); + igb_dump_reg(priv, "PRC255", IGB_PRC255); + igb_dump_reg(priv, "PRC511", IGB_PRC511); + igb_dump_reg(priv, "PRC1023", IGB_PRC1023); + igb_dump_reg(priv, "PRC1522", IGB_PRC1522); + igb_dump_reg(priv, "GPRC", IGB_GPRC); + igb_dump_reg(priv, "BPRC", IGB_BPRC); + igb_dump_reg(priv, "MPRC", IGB_MPRC); + igb_dump_reg(priv, "GPTC", IGB_GPTC); + igb_dump_reg(priv, "GORCL", IGB_GORCL); + igb_dump_reg(priv, "GORCH", IGB_GORCH); + igb_dump_reg(priv, "GOTCL", IGB_GOTCL); + igb_dump_reg(priv, "GOTCH", IGB_GOTCH); + igb_dump_reg(priv, "RNBC", IGB_RNBC); + igb_dump_reg(priv, "RUC", IGB_RUC); + igb_dump_reg(priv, "RFC", IGB_RFC); + igb_dump_reg(priv, "ROC", IGB_ROC); + igb_dump_reg(priv, "RJC", IGB_RJC); + igb_dump_reg(priv, "MNGPRC", IGB_MNGPRC); + igb_dump_reg(priv, "MPDC", IGB_MPDC); + igb_dump_reg(priv, "TORL", IGB_TORL); + igb_dump_reg(priv, "TORH", IGB_TORH); + igb_dump_reg(priv, "TPR", IGB_TPR); + igb_dump_reg(priv, "TPT", IGB_TPT); + igb_dump_reg(priv, "PTC64", IGB_PTC64); + igb_dump_reg(priv, "PTC127", IGB_PTC127); + igb_dump_reg(priv, "PTC255", IGB_PTC255); + igb_dump_reg(priv, "PTC511", IGB_PTC511); + igb_dump_reg(priv, "PTC1023", IGB_PTC1023); + igb_dump_reg(priv, "PTC1522", IGB_PTC1522); + igb_dump_reg(priv, "BPTC", IGB_BPTC); + ninfo("Diagnostic registers:\n"); + igb_dump_reg(priv, "RDFT", IGB_RDFT); + igb_dump_reg(priv, "RDFHS", IGB_RDFHS); + igb_dump_reg(priv, "RDFTS", IGB_RDFTS); + igb_dump_reg(priv, "RDFPC", IGB_RDFPC); + igb_dump_reg(priv, "RPBECCSTS", IGB_RPBECCSTS); + igb_dump_reg(priv, "TPBECCSTS", IGB_TPBECCSTS); + igb_dump_reg(priv, "FCSTS0", IGB_FCSTS0); + igb_dump_reg(priv, "RDHESTS", IGB_RDHESTS); + igb_dump_reg(priv, "TDHESTS", IGB_TDHESTS); + igb_dump_reg(priv, "TDFH", IGB_TDFH); + igb_dump_reg(priv, "TDFT", IGB_TDFT); + igb_dump_reg(priv, "TDFHS", IGB_TDFHS); + igb_dump_reg(priv, "TDFTS", IGB_TDFTS); + igb_dump_reg(priv, "TDFPC", IGB_TDFPC); + igb_dump_reg(priv, "TDHMP", IGB_TDHMP); + igb_dump_reg(priv, "CIRC", IGB_CIRC); + igb_dump_reg(priv, "TXBDC", IGB_TXBDC); + igb_dump_reg(priv, "TXIDLE", IGB_TXIDLE); + igb_dump_reg(priv, "RXBDC", IGB_RXBDC); + igb_dump_reg(priv, "RXIDLE", IGB_RXIDLE); +} +#endif + +/***************************************************************************** + * Name: igb_txclean + * + * Description: + * Clean transmission ring + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumption: + * This function can be called only after card reset and when TX is disabled + * + *****************************************************************************/ + +static void igb_txclean(FAR struct igb_driver_s *priv) +{ + FAR struct netdev_lowerhalf_s *netdev = &priv->dev; + + /* Reset ring */ + + igb_putreg_mem(priv, IGB_TDH0, 0); + igb_putreg_mem(priv, IGB_TDT0, 0); + + /* Free any pending TX */ + + while (priv->tx_now != priv->tx_done) + { + /* Free net packet */ + + netpkt_free(netdev, priv->tx_pkt[priv->tx_done], NETPKT_TX); + + /* Next descriptor */ + + priv->tx_done = (priv->tx_done + 1) % IGB_TX_DESC; + } + + priv->tx_now = 0; + priv->tx_done = 0; +} + +/***************************************************************************** + * Name: igb_rxclean + * + * Description: + * Clean receive ring + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumption: + * This function can be called only after card reset and when RX is disabled + * + *****************************************************************************/ + +static void igb_rxclean(FAR struct igb_driver_s *priv) +{ + priv->rx_now = 0; + + igb_putreg_mem(priv, IGB_RDH0, 0); + igb_putreg_mem(priv, IGB_RDT0, IGB_RX_DESC - 1); +} + +/***************************************************************************** + * Name: igb_transmit + * + * Description: + * Start hardware transmission. Called either from the txdone interrupt + * handling or from watchdog based polling. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked. + * + *****************************************************************************/ + +static int igb_transmit(FAR struct netdev_lowerhalf_s *dev, + FAR netpkt_t *pkt) +{ + FAR struct igb_driver_s *priv = (FAR struct igb_driver_s *)dev; + uint64_t pa = 0; + int desc = priv->tx_now; + size_t len = netpkt_getdatalen(dev, pkt); + size_t tx_next = (priv->tx_now + 1) % IGB_TX_DESC; + + ninfo("transmit\n"); + + /* Check the send length */ + + if (len > IGB_PKTBUF_SIZE) + { + nerr("net transmit buffer too large\n"); + return -EINVAL; + } + + if (!IFF_IS_RUNNING(dev->netdev.d_flags)) + { + return -ENETDOWN; + } + + /* Drop packet if ring full */ + + if (tx_next == priv->tx_done) + { + return -ENOMEM; + } + + /* Store TX packet reference */ + + priv->tx_pkt[priv->tx_now] = pkt; + + /* Prepare next TX descriptor */ + + priv->tx_now = tx_next; + + /* Setup TX descriptor */ + + pa = up_addrenv_va_to_pa(netpkt_getdata(dev, pkt)); + + priv->tx[desc].addr = pa; + priv->tx[desc].len = len; + priv->tx[desc].cmd = (IGB_TDESC_CMD_EOP | IGB_TDESC_CMD_IFCS | + IGB_TDESC_CMD_RS); + priv->tx[desc].cso = 0; + priv->tx[desc].status = 0; + + UP_DSB(); + + /* Update TX tail */ + + igb_putreg_mem(priv, IGB_TDT0, priv->tx_now); + + ninfodumpbuffer("Transmitted:", netpkt_getdata(dev, pkt), len); + + return OK; +} + +/***************************************************************************** + * Name: igb_receive + * + * Description: + * An interrupt was received indicating the availability of a new RX packet + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked. + * + *****************************************************************************/ + +static FAR netpkt_t *igb_receive(FAR struct netdev_lowerhalf_s *dev) +{ + FAR struct igb_driver_s *priv = (FAR struct igb_driver_s *)dev; + FAR netpkt_t *pkt = NULL; + FAR struct igb_rx_leg_s *rx = NULL; + int desc = 0; + + desc = priv->rx_now; + + /* Get RX descriptor and RX packet */ + + rx = &priv->rx[desc]; + pkt = priv->rx_pkt[desc]; + + /* Check if descriptor done */ + + if (!(rx->status & IGB_RDESC_STATUS_DD)) + { + return NULL; + } + + /* Next descriptor */ + + priv->rx_now = (priv->rx_now + 1) % IGB_RX_DESC; + + /* Allocate new rx packet */ + + priv->rx_pkt[desc] = netpkt_alloc(dev, NETPKT_RX); + if (priv->rx_pkt[desc] == NULL) + { + nerr("alloc pkt_new failed\n"); + PANIC(); + } + + /* Set packet length */ + + netpkt_setdatalen(dev, pkt, rx->len); + + /* Store new packet in RX descriptor ring */ + + rx->addr = up_addrenv_va_to_pa( + netpkt_getdata(dev, priv->rx_pkt[desc])); + rx->len = 0; + rx->status = 0; + + /* Update RX tail */ + + igb_putreg_mem(priv, IGB_RDT0, desc); + + /* Handle errors */ + + if (rx->errors) + { + nerr("RX error reported (%"PRIu8")\n", rx->errors); + NETDEV_RXERRORS(&priv->dev.netdev); + netpkt_free(dev, pkt, NETPKT_RX); + return NULL; + } + + return pkt; +} + +/***************************************************************************** + * Name: igb_txdone + * + * Description: + * An interrupt was received indicating that the last TX packet(s) is done + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked. + * + *****************************************************************************/ + +static void igb_txdone(FAR struct netdev_lowerhalf_s *dev) +{ + FAR struct igb_driver_s *priv = (FAR struct igb_driver_s *)dev; + + while (priv->tx_now != priv->tx_done) + { + if (priv->tx[priv->tx_done].status == 0) + { + break; + } + + if (!(priv->tx[priv->tx_done].status & IGB_TDESC_STATUS_DD)) + { + nerr("tx failed: 0x%" PRIx32 "\n", priv->tx[priv->tx_done].status); + NETDEV_TXERRORS(&priv->dev.netdev); + } + + /* Free net packet */ + + netpkt_free(dev, priv->tx_pkt[priv->tx_done], NETPKT_TX); + + /* Next descriptor */ + + priv->tx_done = (priv->tx_done + 1) % IGB_TX_DESC; + } + + netdev_lower_txdone(dev); +} + +/***************************************************************************** + * Name: igb_link_work + * + * Description: + * Handle link status change. + * + * Input Parameters: + * arg - Reference to the lover half driver structure (cast to void *) + * + * Returned Value: + * None + * + *****************************************************************************/ + +static void igb_link_work(FAR void *arg) +{ + FAR struct igb_driver_s *priv = arg; + uint32_t tmp; + + tmp = igb_getreg_mem(priv, IGB_STATUS); + if (tmp & IGB_STATUS_LU) + { + ninfo("Link up, status = 0x%x\n", tmp); + + netdev_lower_carrier_on(&priv->dev); + } + else + { + ninfo("Link down\n"); + + netdev_lower_carrier_off(&priv->dev); + } +} + +/***************************************************************************** + * Name: igb_misx_interrupt + * + * Description: + * Perform MSI-X interrupt work + * + * Input Parameters: + * arg - The argument passed when work_queue() was called. + * + * Returned Value: + * OK on success + * + * Assumptions: + * Runs on a worker thread. + * + *****************************************************************************/ + +static void igb_msix_interrupt(FAR struct igb_driver_s *priv) +{ + uint32_t icr = 0; + uint32_t eicr = 0; + + /* Get interrupts */ + + icr = igb_getreg_mem(priv, IGB_ICR); + eicr = igb_getreg_mem(priv, IGB_EICR); + + ninfo("eicr = 0x%" PRIx32 " icr = 0x%" PRIx32 "\n", eicr, icr); + + if (icr == 0) + { + /* Ignore spurious interrupts */ + + return; + } + + /* Receiver Descriptor Write Back */ + + if (icr & IGB_IC_RXDW) + { + netdev_lower_rxready(&priv->dev); + } + + /* Link Status Change */ + + if (icr & IGB_IC_LSC) + { + if (work_available(&priv->work)) + { + /* Schedule to work queue because netdev_lower_carrier_xxx API + * can't be used in interrupt context + */ + + work_queue(LPWORK, &priv->work, igb_link_work, priv, 0); + } + } + + /* Receiver Miss */ + + if (icr & IGB_IC_RXMISS) + { + nerr("Receiver Miss\n"); + netdev_lower_rxready(&priv->dev); + } + + /* Transmit Descriptor Written Back */ + + if (icr & IGB_IC_TXDW) + { + igb_txdone(&priv->dev); + } +} + +/***************************************************************************** + * Name: igb_interrupt + * + * Description: + * Hardware interrupt handler + * + * Input Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info (architecture-specific) + * + * Returned Value: + * OK on success + * + * Assumptions: + * Runs in the context of a the Ethernet interrupt handler. Local + * interrupts are disabled by the interrupt logic. + * + *****************************************************************************/ + +static int igb_interrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct igb_driver_s *priv = (FAR struct igb_driver_s *)arg; + + DEBUGASSERT(priv != NULL); + + ninfo("interrupt!\n"); + + /* Schedule to perform the interrupt processing on the worker thread. */ + + igb_msix_interrupt(priv); + + return OK; +} + +/***************************************************************************** + * Name: igb_ifup + * + * Description: + * NuttX Callback: Bring up the Ethernet interface when an IP address is + * provided + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked. + * + *****************************************************************************/ + +static int igb_ifup(FAR struct netdev_lowerhalf_s *dev) +{ + FAR struct igb_driver_s *priv = (FAR struct igb_driver_s *)dev; + irqstate_t flags; + +#ifdef CONFIG_NET_IPv4 + ninfo("Bringing up: %u.%u.%u.%u\n", + ip4_addr1(dev->netdev.d_ipaddr), ip4_addr2(dev->netdev.d_ipaddr), + ip4_addr3(dev->netdev.d_ipaddr), ip4_addr4(dev->netdev.d_ipaddr)); +#endif + +#ifdef CONFIG_NET_IPv6 + ninfo("Bringing up: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + dev->netdev.d_ipv6addr[0], dev->netdev.d_ipv6addr[1], + dev->netdev.d_ipv6addr[2], dev->netdev.d_ipv6addr[3], + dev->netdev.d_ipv6addr[4], dev->netdev.d_ipv6addr[5], + dev->netdev.d_ipv6addr[6], dev->netdev.d_ipv6addr[7]); +#endif + + flags = enter_critical_section(); + + /* Enable the Ethernet */ + + igb_enable(priv); + leave_critical_section(flags); + + /* Update link status in case link status interrupt is missing */ + + igb_link_work(priv); + + return OK; +} + +/***************************************************************************** + * Name: igb_ifdown + * + * Description: + * NuttX Callback: Stop the interface. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked. + * + *****************************************************************************/ + +static int igb_ifdown(FAR struct netdev_lowerhalf_s *dev) +{ + FAR struct igb_driver_s *priv = (FAR struct igb_driver_s *)dev; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Put the EMAC in its reset, non-operational state. This should be + * a known configuration that will guarantee the igb_ifup() always + * successfully brings the interface back up. + */ + + igb_disable(priv); + leave_critical_section(flags); + return OK; +} + +#ifdef CONFIG_NET_MCASTGROUP +/***************************************************************************** + * Name: igb_hashmta + * + * Note: This logic is based on freeBSD igb implementation + * + *****************************************************************************/ + +static uint32_t igb_hashmta(FAR struct igb_driver_s *priv, + FAR const uint8_t *mac) +{ + uint32_t hash_mask = 0; + uint8_t bit_shift = 0; + + /* Register count multiplied by bits per register */ + + hash_mask = (priv->type->mta_regs * 32) - 1; + +/* For a mc_filter_type of 0, bit_shift is the number of left-shifts + * where 0xFF would still fall within the hash mask. + */ + + while (hash_mask >> bit_shift != 0xff) + { + bit_shift++; + } + + /* bit_shift += 0 because we have MO set to 0 */ + + return hash_mask & ((mac[4] >> (8 - bit_shift)) | (mac[5] << bit_shift)); +} + +/***************************************************************************** + * Name: igb_addmac + * + * Description: + * NuttX Callback: Add the specified MAC address to the hardware multicast + * address filtering + * + * Parameters: + * dev - Reference to the NuttX driver state structure + * mac - The MAC address to be added + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + *****************************************************************************/ + +static int igb_addmac(FAR struct netdev_lowerhalf_s *dev, + FAR const uint8_t *mac) +{ + FAR struct igb_driver_s *priv = (FAR struct igb_driver_s *)dev; + uint16_t hash = 0; + uint8_t row = 0; + uint8_t bit = 0; + int i = 0; + + hash = igb_hashmta(priv, mac); + bit = hash & 31; + row = (hash >> 5) & (priv->type->mta_regs - 1); + + /* Bits 4:0 indicate bit in row word */ + + priv->mta[row] |= (1 << bit); + + /* Replace the entire MTA */ + + for (i = priv->type->mta_regs - 1; i >= 0; i--) + { + igb_putreg_mem(priv, IGB_MTA + (i << 2), priv->mta[i]); + } + + return OK; +} + +/***************************************************************************** + * Name: igb_rmmac + * + * Description: + * NuttX Callback: Remove the specified MAC address from the hardware + * multicast address filtering + * + * Parameters: + * dev - Reference to the NuttX driver state structure + * mac - The MAC address to be removed + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + *****************************************************************************/ + +static int igb_rmmac(FAR struct netdev_lowerhalf_s *dev, + FAR const uint8_t *mac) +{ + FAR struct igb_driver_s *priv = (FAR struct igb_driver_s *)dev; + uint16_t hash = 0; + uint8_t row = 0; + uint8_t bit = 0; + int i = 0; + + hash = igb_hashmta(priv, mac); + bit = hash & 31; + row = (hash >> 5) & (priv->type->mta_regs - 1); + + /* Bits 4:0 indicate bit in row word */ + + priv->mta[row] &= ~(1 << bit); + + /* Replace the entire MTA */ + + for (i = priv->type->mta_regs - 1; i >= 0; i--) + { + igb_putreg_mem(priv, IGB_MTA + (i << 2), priv->mta[i]); + } + + return OK; +} +#endif /* CONFIG_NET_MCASTGROUP */ + +/***************************************************************************** + * Name: igb_disable + * + * Description: + * Reset device to known state. + * + *****************************************************************************/ + +static void igb_disable(FAR struct igb_driver_s *priv) +{ + uint32_t regval; + int i = 0; + + /* Disable interrupts */ + + igb_putreg_mem(priv, IGB_EIMC, IGB_MSIX_EIMS); + igb_putreg_mem(priv, IGB_IMC, IGB_MSIX_IMS); + up_disable_irq(priv->irq); + + /* Disable Transmitter */ + + regval = igb_getreg_mem(priv, IGB_TCTL); + regval &= ~IGB_TCTL_EN; + igb_putreg_mem(priv, IGB_TCTL, regval); + + /* Disable Receiver */ + + igb_putreg_mem(priv, IGB_RCTL, 0); + + /* We have to reset device, otherwise writing to RDH and THD corrupts + * the device state. + */ + + igb_putreg_mem(priv, IGB_CTRL, IGB_CTRL_RST); + + /* Reset Tx tail */ + + igb_txclean(priv); + + /* Reset Rx tail */ + + igb_rxclean(priv); + + /* Free RX packets */ + + for (i = 0; i < IGB_RX_DESC; i += 1) + { + netpkt_free(&priv->dev, priv->rx_pkt[i], NETPKT_RX); + } +} + +/***************************************************************************** + * Name: igb_phy_reset + * + * Description: + * Reset PHY + * + *****************************************************************************/ + +static void igb_phy_reset(FAR struct igb_driver_s *priv) +{ + uint32_t regval = 0; + + regval = igb_getreg_mem(priv, IGB_CTRL); + igb_putreg_mem(priv, IGB_CTRL, regval | IGB_CTRL_PHYRST); + up_udelay(100); + igb_putreg_mem(priv, IGB_CTRL, regval); + up_udelay(100); +} + +/***************************************************************************** + * Name: igb_enable + * + * Description: + * Enable device. + * + *****************************************************************************/ + +static void igb_enable(FAR struct igb_driver_s *priv) +{ + FAR struct netdev_lowerhalf_s *dev = (FAR struct netdev_lowerhalf_s *)priv; + uint64_t pa = 0; + uint32_t regval = 0; + int i = 0; + + /* Reset PHY */ + + igb_phy_reset(priv); + + /* Reset Multicast Table Array */ + + for (i = 0; i < priv->type->mta_regs; i++) + { + igb_putreg_mem(priv, IGB_MTA + (i << 2), 0); + } + + /* Allocate RX packets */ + + for (i = 0; i < IGB_RX_DESC; i += 1) + { + priv->rx_pkt[i] = netpkt_alloc(dev, NETPKT_RX); + if (priv->rx_pkt[i] == NULL) + { + nerr("alloc rx_pkt failed\n"); + PANIC(); + } + + /* Configure RX descriptor */ + + priv->rx[i].addr = up_addrenv_va_to_pa( + netpkt_getdata(dev, priv->rx_pkt[i])); + priv->rx[i].len = 0; + priv->rx[i].status = 0; + } + + /* Setup TX descriptor */ + + /* The address passed to the NIC must be physical */ + + pa = up_addrenv_va_to_pa(priv->tx); + + regval = (uint32_t)pa; + igb_putreg_mem(priv, IGB_TDBAL0, regval); + regval = (uint32_t)(pa >> 32); + igb_putreg_mem(priv, IGB_TDBAH0, regval); + + regval = IGB_TX_DESC * sizeof(struct igb_tx_leg_s); + igb_putreg_mem(priv, IGB_TDLEN0, regval); + + /* Reset TX tail */ + + igb_txclean(priv); + + /* Setup RX descriptor */ + + /* The address passed to the NIC must be physical */ + + pa = up_addrenv_va_to_pa(priv->rx); + + regval = (uint32_t)pa; + igb_putreg_mem(priv, IGB_RDBAL0, regval); + regval = (uint32_t)(pa >> 32); + igb_putreg_mem(priv, IGB_RDBAH0, regval); + + regval = IGB_RX_DESC * sizeof(struct igb_rx_leg_s); + igb_putreg_mem(priv, IGB_RDLEN0, regval); + + /* Enable interrupts */ + + igb_putreg_mem(priv, IGB_EIMS, IGB_MSIX_EIMS); + igb_putreg_mem(priv, IGB_IMS, IGB_MSIX_IMS); + up_enable_irq(priv->irq); + + /* Set link up */ + + igb_putreg_mem(priv, IGB_CTRL, IGB_CTRL_SLU); + + /* Setup and enable Transmitter */ + + regval = igb_getreg_mem(priv, IGB_TCTL); + regval |= IGB_TCTL_EN | IGB_TCTL_PSP; + igb_putreg_mem(priv, IGB_TCTL, regval); + + /* Setup and enable Receiver */ + + regval = (IGB_RCTL_EN | IGB_RCTL_MPE | + (IGB_RCTL_BSIZE << IGB_RCTL_BSIZE_SHIFT)); +#ifdef CONFIG_NET_PROMISCUOUS + regval |= IGB_RCTL_UPE | IGB_RCTL_MPE; +#endif + igb_putreg_mem(priv, IGB_RCTL, regval); + + /* Enable TX queeu */ + + regval = igb_getreg_mem(priv, IGB_TXDCTL0); + regval |= IGB_TXDCTL_ENABLE; + igb_putreg_mem(priv, IGB_TXDCTL0, regval); + + /* Enable RX queue */ + + regval = igb_getreg_mem(priv, IGB_RXDCTL0); + regval |= IGB_RXDCTL_ENABLE; + igb_putreg_mem(priv, IGB_RXDCTL0, regval); + + /* Reset RX tail - after queue is enabled */ + + igb_rxclean(priv); + +#ifdef CONFIG_DEBUG_NET_INFO + /* Dump memory */ + + igb_dump_mem(priv, "enabled"); +#endif +} + +/***************************************************************************** + * Name: igb_initialize + * + * Description: + * Initialize device + * + *****************************************************************************/ + +static int igb_initialize(FAR struct igb_driver_s *priv) +{ + uint32_t regval = 0; + uint64_t mac = 0; + int ret = OK; + + /* Allocate MSI */ + + ret = pci_alloc_irq(priv->pcidev, &priv->irq, 1); + if (ret != 1) + { + nerr("Failed to allocate MSI %d\n", ret); + return ret; + } + + /* Attach IRQ */ + + irq_attach(priv->irq, igb_interrupt, priv); + + /* Connect MSI */ + + ret = pci_connect_irq(priv->pcidev, &priv->irq, 1); + if (ret != OK) + { + nerr("Failed to connect MSI %d\n", ret); + pci_release_irq(priv->pcidev, &priv->irq, 1); + + return -ENOTSUP; + } + + /* Clear previous Extended Interrupt Mask */ + + igb_putreg_mem(priv, IGB_EIMC, 0xffffffff); + igb_putreg_mem(priv, IGB_IMC, 0xffffffff); + + /* Configure MSI-X */ + + igb_putreg_mem(priv, IGB_IVAR0, IGB_MSIX_IVAR0); + igb_putreg_mem(priv, IGB_IVARMSC, IGB_MSIX_IVARMSC); + + /* Enable MSI-X Single Vector */ + + igb_putreg_mem(priv, IGB_GPIE, IGB_GPIE_MSIX_SINGLE); + igb_putreg_mem(priv, IGB_EIMS, IGB_MSIX_EIMS); + + /* Configure Other causes */ + + igb_putreg_mem(priv, IGB_IMS, IGB_MSIX_IMS); + + /* Configure Interrupt Throttle */ + + igb_putreg_mem(priv, IGB_EITR0, (CONFIG_NET_IGB_INT_INTERVAL << 2)); + + /* Get MAC if valid */ + + regval = igb_getreg_mem(priv, IGB_RAH); + if (regval & IGB_RAH_AV) + { + mac = ((uint64_t)regval & IGB_RAH_RAH_MASK) << 32; + mac |= igb_getreg_mem(priv, IGB_RAL); + memcpy(&priv->dev.netdev.d_mac.ether, &mac, sizeof(struct ether_addr)); + } + else + { + nwarn("Receive Address not valid!\n"); + } + + return OK; +} + +/***************************************************************************** + * Name: igb_probe + * + * Description: + * Initialize device + * + *****************************************************************************/ + +static int igb_probe(FAR struct pci_device_s *dev) +{ + FAR const struct igb_type_s *type = NULL; + FAR struct igb_driver_s *priv = NULL; + FAR struct netdev_lowerhalf_s *netdev = NULL; + int ret = -ENOMEM; + + /* Get type data associated with this PCI device card */ + + type = (FAR const struct igb_type_s *)dev->id->driver_data; + + /* Not found private data */ + + if (type == NULL) + { + return -ENODEV; + } + + /* Allocate the interface structure */ + + priv = kmm_zalloc(sizeof(*priv)); + if (priv == NULL) + { + return ret; + } + + priv->pcidev = dev; + + /* Allocate TX descriptors */ + + priv->tx = kmm_memalign(type->desc_align, + IGB_TX_DESC * sizeof(struct igb_tx_leg_s)); + if (priv->tx == NULL) + { + nerr("alloc tx failed %d\n", errno); + goto errout; + } + + /* Allocate RX descriptors */ + + priv->rx = kmm_memalign(type->desc_align, + IGB_RX_DESC * sizeof(struct igb_rx_leg_s)); + if (priv->rx == NULL) + { + nerr("alloc rx failed %d\n", errno); + goto errout; + } + + /* Allocate TX packet pointer array */ + + priv->tx_pkt = kmm_zalloc(IGB_TX_DESC * sizeof(netpkt_t *)); + if (priv->tx_pkt == NULL) + { + nerr("alloc tx_pkt failed\n"); + goto errout; + } + + /* Allocate RX packet pointer array */ + + priv->rx_pkt = kmm_zalloc(IGB_RX_DESC * sizeof(netpkt_t *)); + if (priv->rx_pkt == NULL) + { + nerr("alloc rx_pkt failed\n"); + goto errout; + } + +#ifdef CONFIG_NET_MCASTGROUP + /* Allocate MTA shadow */ + + priv->mta = kmm_zalloc(type->mta_regs); + if (priv->mta == NULL) + { + nerr("alloc mta failed\n"); + goto errout; + } +#endif + + /* Get devices */ + + netdev = &priv->dev; + priv->type = type; + + pci_set_master(dev); + pciinfo("Enabled bus mastering\n"); + pci_enable_device(dev); + pciinfo("Enabled memory resources\n"); + + /* If the BAR is MMIO then it must be mapped */ + + priv->base = (uintptr_t)pci_map_bar(dev, IGB_MMIO_BAR); + if (!priv->base) + { + pcierr("Not found MMIO control bar\n"); + goto errout; + } + + /* Initialize PHYs, Ethernet interface, and setup up Ethernet interrupts */ + + ret = igb_initialize(priv); + if (ret != OK) + { + nerr("igb_initialize failed %d\n", ret); + return ret; + } + + /* Register the network device */ + + netdev->quota[NETPKT_TX] = IGB_TX_QUOTA; + netdev->quota[NETPKT_RX] = IGB_RX_QUOTA; + netdev->ops = &g_igb_ops; + + return netdev_lower_register(netdev, NET_LL_ETHERNET); + +errout: + kmm_free(priv->tx); + kmm_free(priv->rx); +#ifdef CONFIG_NET_MCASTGROUP + kmm_free(priv->mta); +#endif + kmm_free(priv); + return ret; +} + +/***************************************************************************** + * Public Functions + *****************************************************************************/ + +/***************************************************************************** + * Name: pci_igb_init + * + * Description: + * Register a pci driver + * + *****************************************************************************/ + +int pci_igb_init(void) +{ + return pci_register_driver(&g_pci_igb_drv); +} diff --git a/drivers/net/igb.h b/drivers/net/igb.h new file mode 100644 index 00000000000..e281fd5ad3c --- /dev/null +++ b/drivers/net/igb.h @@ -0,0 +1,544 @@ +/***************************************************************************** + * drivers/net/igb.h + * + * 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. + * + *****************************************************************************/ + +#ifndef __DRIVERS_NET_IGB_H +#define __DRIVERS_NET_IGB_H + +/***************************************************************************** + * Included Files + *****************************************************************************/ + +#include <stdint.h> + +/***************************************************************************** + * Pre-processor Definitions + *****************************************************************************/ + +/* General registers */ + +#define IGB_CTRL (0x0000) /* Device Control Register */ +#define IGB_STATUS (0x0008) /* Device Status Register */ +#define IGB_CTRLEXT (0x0018) /* Extended Device Control Register */ +#define IGB_MDIC (0x0020) /* MDI Control Register */ +#define IGB_SERDESCTL (0x0024) /* Serdes_ana */ +#define IGB_FCAL (0x0028) /* Flow Control Address Low */ +#define IGB_FCAH (0x002c) /* Flow Control Address High */ +#define IGB_FCT (0x0030) /* Flow Control Type */ +#define IGB_CONNSW (0x0034) /* Copper/Fiber Switch Control */ +#define IGB_VET (0x0038) /* VLAN Ether Type */ +#define IGB_FCTTV (0x0170) /* Flow Control Transmit Timer Value */ +#define IGB_LEDCTL (0x0e00) /* LED Control */ +#define IGB_I2CCM (0x1028) /* SFP I2C Command */ +#define IGB_I2CPARAMS (0x102c) /* SFP I2C Parameter */ +#define IGB_WDSTP (0x1040) /* Watchdog Setup Register */ +#define IGB_WDSWSTS (0x1044) /* Watchdog Software */ +#define IGB_FRTIMER (0x1048) /* Free Running Timer */ +#define IGB_TCPTIMER (0x104c) /* TCP Timer */ +#define IGB_DCAID (0x5b70) /* DCA Requester ID Information Register */ +#define IGB_SWSM (0x5b50) /* Software Semaphore Register */ +#define IGB_FWSM (0x5b54) /* Firmware Semaphore Register */ +#define IGB_SWFWSYNC (0x5b5c) /* Software-Firmware Synchronization */ + +/* Flash/EEPROM Registers */ + +#define IGB_EEC (0x00010) /* EEPROM/FLASH Control Register */ +#define IGB_EERD (0x00014) /* EEPROM Read Register */ +#define IGB_FLA (0x0001c) /* Flash Access Register */ +#define IGB_EEMNGCTL (0x01010) /* MNG EEPROM Control Register */ +#define IGB_EEMNGDATA (0x01014) /* MNG EEPROM Read/Write data */ +#define IGB_FLMNGCTL (0x01018) /* MNG Flash Control Register */ +#define IGB_FLMNGDATA (0x0101c) /* MNG Flash Read data */ +#define IGB_FLMNGCNT (0x01020) /* MNG Flash Read Counter */ +#define IGB_EEARBC (0x01024) /* EEPROM Auto Read Bus Control */ +#define IGB_FLASHOP (0x0103c) /* Flash Opcode Register */ +#define IGB_EEDIAG (0x01038) /* EEPROM Diagnostic */ +#define IGB_VPDDIAG (0x01060) /* VPD Diagnostic */ + +/* Interrupt registers */ + +#define IGB_ICR (0x1500) /* Interrupt Cause Read */ +#define IGB_ICS (0x1504) /* Interrupt Cause Set */ +#define IGB_IMS (0x1508) /* Interrupt Mask Set */ +#define IGB_IMC (0x150c) /* Interrupt Mask Clear */ +#define IGB_IAM (0x1510) /* Interrupt Acknowledge Auto–Mask */ +#define IGB_EICS (0x1520) /* Extended Interrupt Cause Set */ +#define IGB_EIMS (0x1524) /* Extended Interrupt Mask Set/Read */ +#define IGB_EIMC (0x1528) /* Extended Interrupt Mask Clear */ +#define IGB_EIAC (0x152c) /* Extended Interrupt Auto Clear */ +#define IGB_EIAM (0x1530) /* Extended Interrupt Auto Mask */ +#define IGB_EICR (0x1580) /* Extended Interrupt Cause Read */ +#define IGB_IVAR0 (0x1700) /* Interrupt Vector Allocation Registers */ +#define IGB_IVARMSC (0x1740) /* Interrupt Vector Allocation Registers - MISC */ +#define IGB_EITR0 (0x1680) /* Extended Interrupt Throttling Rate 0 - 24 */ +#define IGB_GPIE (0x1514) /* General Purpose Interrupt Enable */ +#define IGB_PBACL (0x5b68) /* MSI-X PBA Clear */ + +/* Receive registers */ + +#define IGB_RCTL (0x0100) /* Receive Control */ +#define IGB_FCRTL0 (0x2160) /* Flow Control Receive Threshold Low */ +#define IGB_PSRCTL (0x2170) /* Packet Split Receive Control Register */ +#define IGB_FCRTH0 (0x2168) /* Flow Control Receive Threshold High */ +#define IGB_RXPBSIZE (0x2404) /* Rx Packet Buffer Size */ +#define IGB_PBRWAC (0x24e8) /* Rx Packet Buffer wrap around counter */ +#define IGB_FCRTV (0x2460) /* Flow Control Refresh Threshold Value */ +#define IGB_DRXMXOD (0x2540) /* DMA RX Max Total Allow Size Requests */ +#define IGB_RDBAL0 (0xc000) /* Tx Descriptor Base Address Low */ +#define IGB_RDBAH0 (0xc004) /* Rx Descriptor Base Address High */ +#define IGB_RDLEN0 (0xc008) /* Rx Descriptor Length */ +#define IGB_SRRCTL0 (0xc00c) /* Split and Replication Receive Control Register Queue */ +#define IGB_RDH0 (0xc010) /* Rx Descriptor Head */ +#define IGB_RDT0 (0xc018) /* Rx Descriptor Tail */ +#define IGB_RXDCTL0 (0xc028) /* Receive Descriptor Control Queue */ +#define IGB_RXCTL0 (0xc014) /* Receive Queue DCA CTRL Register */ +#define IGB_RXCSUM (0x5000) /* Receive Checksum Control */ +#define IGB_RLPML (0x5004) /* Receive Long packet maximal length */ +#define IGB_RFCTL (0x5008) /* Receive Filter Control Register */ +#define IGB_MTA (0x5200) /* Multicast Table Array (n) */ +#define IGB_RAL (0x5400) /* Receive Address Low */ +#define IGB_RAH (0x5404) /* Receive Address Low */ +#define IGB_PSRTYPE0 (0x5480) /* Packet Split Receive type (n) */ +#define IGB_RPLPSRTYPE (0x54c0) /* Replicated Packet Split Receive type */ +#define IGB_VTCTL (0x5818) /* Next Generation VMDq Control register */ +#define IGB_VFTA0 (0x5600) /* VLAN Filter Table Array (n) */ +#define IGB_MRQC (0x5818) /* Multiple Receive Queues Command */ +#define IGB_RETA (0x5c00) /* Redirection Table */ +#define IGB_RSSRK (0x5c80) /* RSS Random Key Register */ + +/* Transmit registers */ + +#define IGB_TXPBSIZE (0x3404) /* Transmit Packet Buffer Size */ +#define IGB_PBTWAC (0x34e8) /* Tx Packet Buffer wrap around counter */ +#define IGB_TCTL (0x0400) /* Transmit Control */ +#define IGB_TCTLEXT (0x0404) /* Transmit Control Extended */ +#define IGB_TIPG (0x0410) /* Transmit IPG Register */ +#define IGB_RETXCTL (0x041c) /* Retry Buffer Control */ +#define IGB_DTXCTL (0x3590) /* DMA Tx Control */ +#define IGB_DTXTCPFLGL (0x359c) /* DMA Tx TCP Flags Control Low */ +#define IGB_DTXTCPFLGH (0x35a0) /* DMA Tx TCP Flags Control High */ +#define IGB_DTXMXSZRQ (0x3540) /* DMA Tx Max Total Allow Size Requests */ +#define IGB_DTXMXPKTSZ (0x355c) /* DMA Tx Max Allowable Packet Size */ +#define IGB_TDBAL0 (0xe000) /* Tx Descriptor Base Low */ +#define IGB_TDBAH0 (0xe004) /* Tx Descriptor Base High*/ +#define IGB_TDLEN0 (0xe008) /* Tx Descriptor Ring Length */ +#define IGB_TDH0 (0xe010) /* Tx Descriptor Head */ +#define IGB_TDT0 (0xe018) /* Tx Descriptor Tail */ +#define IGB_TXDCTL0 (0xe028) /* Transmit Descriptor Control Queue */ +#define IGB_TXCTL0 (0xe014) /* Tx DCA CTRL Register Queue */ +#define IGB_TDWBAL0 (0xe038) /* Transmit Descriptor WB Address Low Queue */ +#define IGB_TDWBAH0 (0xe03c) /* Transmit Descriptor WB Address High Queue */ + +/* TODO: Filters */ + +#define IGB_ETQF0 (0x5cb0) /* EType Queue Filter */ +#define IGB_IMIR0 (0x5a80) /* Immediate Interrupt Rx */ +#define IGB_IMIREXT0 (0x5aa9) /* Immediate Interrupt Rx Extended */ +#define IGB_IMIRVP (0x5ac0) /* Immediate Interrupt Rx VLAN Priority */ +#define IGB_SAQF0 (0x5980) /* Source Address Queue Filter */ +#define IGB_DAQF0 (0x59a0) /* Destination Address Queue Filter */ +#define IGB_SPQF0 (0x59c0) /* Source Port Queue Filter */ +#define IGB_FTQF0 (0x59e0) /* Five-Tuple Queue Filter */ +#define IGB_SYNQF (0x55fc) /* SYN Packet Queue Filter */ + +/* TODO: Virtualization */ + +/* Statistic registers */ + +#define IGB_CRCERRS (0x04000) /* CRC Error Count */ +#define IGB_ALGNERRC (0x04004) /* Alignment Error Count */ +#define IGB_SYMERRS (0x04008) /* Symbol Error Count */ +#define IGB_RXERRC (0x0400c) /* RX Error Count */ +#define IGB_MPC (0x04010) /* Missed Packets Count */ +#define IGB_SCC (0x04014) /* Single Collision Count */ +#define IGB_ECOL (0x04018) /* Excessive Collisions Count */ +#define IGB_MCC (0x0401c) /* Multiple Collision Count */ +#define IGB_LATECOL (0x04020) /* Late Collisions Count */ +#define IGB_COLC (0x04028) /* Collision Count */ +#define IGB_DC (0x04030) /* Defer Count */ +#define IGB_TNCRS (0x04034) /* Transmit with No CRS */ +#define IGB_HTDPMC (0x0403c) /* Host Transmit Discarded Packets by MAC Count */ +#define IGB_RLEC (0x04040) /* Receive Length Error Count */ +#define IGB_CBRDPC (0x04044) /* Circuit Breaker Rx dropped packet */ +#define IGB_XONRXC (0x04048) /* XON Received Count */ +#define IGB_XONTXC (0x0404c) /* XON Transmitted Count */ +#define IGB_XOFFRXC (0x04050) /* XOFF Received Count */ +#define IGB_XOFFTXC (0x04054) /* XOFF Transmitted Count */ +#define IGB_FCRUC (0x04058) /* FC Received Unsupported Count */ +#define IGB_PRC64 (0x0405c) /* Packets Received [64 Bytes] Count */ +#define IGB_PRC127 (0x04060) /* Packets Received [65–127 Bytes] Count */ +#define IGB_PRC255 (0x04064) /* Packets Received [128–255 Bytes] */ +#define IGB_PRC511 (0x04068) /* Packets Received [256–511 Bytes] */ +#define IGB_PRC1023 (0x0406c) /* Packets Received [512–1023 Bytes] */ +#define IGB_PRC1522 (0x04070) /* Packets Received [1024 to Max Bytes] */ +#define IGB_GPRC (0x04074) /* Good Packets Received Count */ +#define IGB_BPRC (0x04078) /* Broadcast Packets Received Count */ +#define IGB_MPRC (0x0407c) /* Multicast Packets Received Count */ +#define IGB_GPTC (0x04080) /* Good Packets Transmitted Count */ +#define IGB_GORCL (0x04088) /* Good Octets Received Count Low */ +#define IGB_GORCH (0x0408c) /* Good Octets Received Count High */ +#define IGB_GOTCL (0x04090) /* Good Octets Transmitted Count Low */ +#define IGB_GOTCH (0x04094) /* Good Octets Transmitted Count High */ +#define IGB_RNBC (0x040a0) /* Receive No Buffers Count */ +#define IGB_RUC (0x040a4) /* Receive Undersize Count */ +#define IGB_RFC (0x040a8) /* Receive Fragment Count */ +#define IGB_ROC (0x040ac) /* Receive Oversize Count */ +#define IGB_RJC (0x040b0) /* Receive Jabber Count */ +#define IGB_MNGPRC (0x040b4) /* Management Packets Received Count */ +#define IGB_MPDC (0x040b8) /* Management Packets Dropped Count */ +#define IGB_MNGPTC (0x040bc) /* Management Packets Transmitted Count */ +#define IGB_BMNGPRC (0x0414c) /* BMC Management Packets Receive Count */ +#define IGB_BMPDC (0x04140) /* BMC Management Packets Dropped Count */ +#define IGB_BMNGPTC (0x04144) /* BMC Management Packets Transmitted Count */ +#define IGB_TORL (0x040c0) /* Total Octets Received */ +#define IGB_TORH (0x040c4) /* Total Octets Received */ +#define IGB_TOTL (0x040c8) /* Total Octets Transmitted */ +#define IGB_TOTH (0x040cc) /* Total Octets Transmitted */ +#define IGB_TPR (0x040d0) /* Total Packets Received */ +#define IGB_TPT (0x040d4) /* Total Packets Transmitted */ +#define IGB_PTC64 (0x040d8) /* Packets Transmitted [64 Bytes] Count */ +#define IGB_PTC127 (0x040dc) /* Packets Transmitted [65–127 Bytes] Count */ +#define IGB_PTC255 (0x040e0) /* Packets Transmitted [128–255 Bytes] Count */ +#define IGB_PTC511 (0x040e4) /* Packets Transmitted [256–511 Bytes] Count */ +#define IGB_PTC1023 (0x040e8) /* Packets Transmitted [512–1023 Bytes] Count */ +#define IGB_PTC1522 (0x040ec) /* Packets Transmitted [Greater than 1024 Bytes] Count */ +#define IGB_MCPTC (0x040f0) /* Multicast Packets Transmitted Count */ +#define IGB_BPTC (0x040f4) /* Broadcast Packets Transmitted Count */ + /* ... missing registers */ + +/* Wake Up and Proxying */ + +#define IGB_WUC (0x5800) /* Wake Up Control Register */ +#define IGB_WUFC (0x5808) /* Wake Up Filter Control Register */ +#define IGB_WUS (0x5810) /* Wake Up Status Register */ +#define IGB_WUPL (0x5900) /* Wake Up Packet Length */ +#define IGB_WUPM (0x5a00) /* Wake Up Packet Memory */ +#define IGB_FHFT (0x9000) /* Flexible Host Filter Table registers */ +#define IGB_FHFTEXT (0x9a00) /* Flexible Host Filter Table registers extended */ + +/* TODO: Management Register */ + +/* TODO: PCIe */ + +/* Diagnostic */ + +#define IGB_RDFH (0x2410) /* RX Data FIFO Head */ +#define IGB_RDFT (0x2418) /* RX Data FIFO Tail */ +#define IGB_RDFHS (0x2420) /* RX Data FIFO Head Saved */ +#define IGB_RDFTS (0x2428) /* RX Data FIFO Tail Saved */ +#define IGB_RDFPC (0x2430) /* Receive Data FIFO Packet Count */ +#define IGB_RPBECCSTS (0x245c) /* Receive Packet buffer ECC control */ +#define IGB_TPBECCSTS (0x345C) /* Transmit Packet buffer ECC control */ +#define IGB_FCSTS0 (0x2464) /* Flow Control Status */ +#define IGB_RDHESTS (0x25c0) /* Rx Descriptor Handler ECC status */ +#define IGB_TDHESTS (0x35c0) /* Tx Descriptor Handler ECC status */ +#define IGB_TDFH (0x3410) /* TX Data FIFO Head */ +#define IGB_TDFT (0x3418) /* TX Data FIFO Tail */ +#define IGB_TDFHS (0x3420) /* TX Data FIFO Head Saved */ +#define IGB_TDFTS (0x3428) /* TX Data FIFO Tail Saved */ +#define IGB_TDFPC (0x3430) /* Transmit Data FIFO Packet Count */ +#define IGB_TDHMP (0x35fc) /* Tx Descriptor Handler Memory Page Number */ +#define IGB_CIRC (0x0f00) /* Circuits Control */ +#define IGB_TXBDC (0x35e0) /* Tx DMA Performance Burst and Descriptor Count */ +#define IGB_TXIDLE (0x35e4) /* Tx DMA Performance Idle Count */ +#define IGB_RXBDC (0x25e0) /* Tx DMA Performance Burst and Descriptor Count */ +#define IGB_RXIDLE (0x25E4) /* Tx DMA Performance Idle Count */ + +/* TODO: PCS */ + +/* TODO: Time Sync */ + +/* TODO: MACSec */ + +/* TODO: IPSec */ + +/* Device Control Register */ + +#define IGB_CTRL_FD (1 << 0) /* Bit 0: Full-Duplex */ + /* Bit 1: Reserved */ +#define IGB_CTRL_GIOMDIS (1 << 2) /* Bit 2: GIO Master Enable Status */ +#define IGB_CTRL_LRST (1 << 3) /* Bit 3: Link Reset */ + /* Bits 4-5: Reserved */ +#define IGB_CTRL_SLU (1 << 6) /* Bit 6: Set Link Up */ +#define IGB_CTRL_ILOS (1 << 7) /* Bit 7: Invert Loss-of-Signal */ +#define IGB_CTRL_SPEED_SHIFT (8) /* Bits 8-9: Speed selection */ +#define IGB_CTRL_SPEED_MASK (3 << IGB_CTRL_SPEED_SHIFT) +# define IGB_CTRL_SPEED_10MBS (0 << IGB_CTRL_SPEED_SHIFT) +# define IGB_CTRL_SPEED_100MBS (1 << IGB_CTRL_SPEED_SHIFT) +# define IGB_CTRL_SPEED_1000MBS (2 << IGB_CTRL_SPEED_SHIFT) + + /* Bit 10: Reserved */ +#define IGB_CTRL_FRCSPD (1 << 11) /* Bit 11: Force Speed */ +#define IGB_CTRL_FRCDPLX (1 << 12) /* Bit 12: Force Duplex */ + /* Bits 13-15: Reserved */ +#define IGB_CTRL_SDP0_GPIEN (1 << 16) /* Bit 16: GPI Detection Enable for SDP0 */ +#define IGB_CTRL_SDP1_GPIEN (1 << 17) /* Bit 17: GPI Detection Enable for SDP1 */ +#define IGB_CTRL_SDP0_DATA (1 << 18) /* Bit 18: SDP0 Data Value */ +#define IGB_CTRL_SDP1_DATA (1 << 19) /* Bit 19: SDP1 Data Value */ +#define IGB_CTRL_ADVD3WUC (1 << 20) /* Bit 20: D3Cold Wakeup Capability Advertisement Enable */ +#define IGB_CTRL_SDP0_WDE (1 << 21) /* Bit 21: SDP0 Used for Watchdog Indication */ +#define IGB_CTRL_SDP0_IODIR (1 << 22) /* Bit 22: SDP0 Pin Directionality */ +#define IGB_CTRL_SDP1_IODIR (1 << 23) /* Bit 23: SDP1 Pin Directionality */ + /* Bits 24-25: Reserved */ +#define IGB_CTRL_RST (1 << 26) /* Bit 26: Device Reset */ +#define IGB_CTRL_RFCE (1 << 27) /* Bit 27: Receive Flow Control Enable */ +#define IGB_CTRL_TFCE (1 << 28) /* Bit 28: Transmit Flow Control Enable */ + /* Bit 29: Reserved */ +#define IGB_CTRL_VME (1 << 30) /* Bit 30: VLAN Mode Enable */ +#define IGB_CTRL_PHYRST (1 << 31) /* Bit 31: PHY Reset */ + +/* Device Status Regiuster */ + +#define IGB_STATUS_FD (1 << 0) /* Bit 0: Full Duplex */ +#define IGB_STATUS_LU (1 << 1) /* Bit 1: Link Up */ +#define IGB_STATUS_LANID_SHIFT (2) /* Bit 2-3: LAN ID*/ +#define IGB_STATUS_TXOFF (1 << 4) /* Bit 4: Transmission Paused */ + /* Bit 5: Reserved */ +#define IGB_STATUS_SPEED_SHFIT (6) /* Bits 6-7: Link speed setting */ +#define IGB_STATUS_ASDV_SHFIT (8) /* Bits 8-9: Auto-Speed Detection Value. */ +#define IGB_STATUS_PHYRA (10) /* Bit 10: PHY Reset Asserted */ + /* Bits 11-13: Reserved */ +#define IGB_STATUS_NVFS_SHFIT (14) /* Bits 14-17: Num VFs in the IOV capability */ +#define IGB_STATUS_IOVMODE (18) /* Bit 18: VF enable (VFE) bit in the IOV */ +#define IGB_STATUS_GIOM (19) /* Bit 19: GIO Master Disable bit state */ + /* Bits 20-30: Reserved */ +#define IGB_STATUS_DMACGE (31) /* Bit 31: DMA clock gating Enable bit */ + +/* Receive Address High */ + +#define IGB_RAH_RAH_MASK (0xffff) /* Bits 0-15: Receive address High */ +#define IGB_RAH_ASEL (16) /* Bits 16-17 Address Select */ +#define IGB_RAH_POOLSEL (18) /* Bits 18-25 Pool Select */ + /* Bits 26-30: Reserved */ +#define IGB_RAH_AV (1 << 31) /* Bit 31: Address Valid */ + +/* Transmit Control */ + + /* Bit 0: Reserved */ +#define IGB_TCTL_EN (1 << 1) /* Bit 1: Transmit Enable */ + /* Bit 2: Reserved */ +#define IGB_TCTL_PSP (1 << 3) /* Bit 3: Pad Short Packets */ +#define IGB_TCTL_CT_SHIFT (4) /* Bits 4-11: Collision Threshold */ +#define IGB_TCTL_COLD_SHIFT (12) /* Bits 12-21: Collision Distance (BST) */ +#define IGB_TCTL_SWXOFF (1 << 22) /* Bit 22: Software XOFF Transmission */ + /* Bit 23: Reserved */ +#define IGB_TCTL_RTLC (1 << 24) /* Bit 24: Re-transmit on Late Collision */ + /* Bits 25-32: Reserved */ + +/* Transmit Descriptor Control */ + +#define IGB_TXDCTL_PTHRESH_SHIFT (0) /* Bits 0-4: Prefetch Threshold */ + /* Bits 5-7: Reserved */ +#define IGB_TXDCTL_HTHRESH_SHIFT (8) /* Bits 8-12: Host Threshold */ + /* Bits 13-15: Reserved */ +#define IGB_TXDCTL_WTHRESH_SHIFT (16) /* Bits 16-20: Write-Back Threshold */ + /* Bits 21-24: Reserved */ +#define IGB_TXDCTL_ENABLE (1 << 25) /* Bit 25: Transmit Queue Enable */ + /* Bits 27-31: Reserved */ + +/* Tx Descriptor Ring Length */ + +/* Receive Control */ + + /* Bit 0: Reserved */ +#define IGB_RCTL_EN (1 << 1) /* Bit 1: Receiver Enable */ +#define IGB_RCTL_SBP (1 << 2) /* Bit 2: Store Bad Packets */ +#define IGB_RCTL_UPE (1 << 3) /* Bit 3: Unicast Promiscuous Enabled */ +#define IGB_RCTL_MPE (1 << 4) /* Bit 4: Multicast Promiscuous Enabled */ +#define IGB_RCTL_LPE (1 << 5) /* Bit 5: Long Packet Reception Enable */ +#define IGB_RCTL_LBM_SHIFT (6) /* Bits 6-7: Loopback mode */ + /* Bits 8-11: Reserved */ +#define IGB_RCTL_MO_SHIFT (12) /* Bits 12-13: Multicast Offset */ + /* Bit 14: Reserved */ +#define IGB_RCTL_BAM (1 << 15) /* Bit 15: Broadcast Accept Mode */ +#define IGB_RCTL_BSIZE_SHIFT (16) /* Bits 16-17: Receive Buffer Size */ +# define IGB_RCTL_BSIZE_2048 (0 << 16) /* 00b: 2048 bytes */ +# define IGB_RCTL_BSIZE_1024 (1 << 16) /* 01b: 1024 bytes */ +# define IGB_RCTL_BSIZE_512 (2 << 16) /* 10b: 512 bytes */ +# define IGB_RCTL_BSIZE_256 (3 << 16) /* 11b: 256 bytes */ +#define IGB_RCTL_VFE (1 << 18) /* Bit 18: VLAN Filter Enable */ +#define IGB_RCTL_CFIEN (1 << 18) /* Bit 19: Canonical Form Indicator Enable */ +#define IGB_RCTL_CFI (1 << 20) /* Bit 20: Canonical Form Indicator bit value */ +#define IGB_RCTL_PSP (1 << 21) /* Bit 21: Pad Small Receive Packets */ +#define IGB_RCTL_DPF (1 << 22) /* Bit 22: Discard Pause Frames */ +#define IGB_RCTL_PMCF (1 << 23) /* Bit 23: Pass MAC Control Frames */ + /* Bits 24-25: Reserved */ +#define IGB_RCTL_SECRC (1 << 26) /* Bit 26: Strip Ethernet CRC from incoming packet */ + /* Bits 27-31: Reserved */ + +/* Receive Descriptor Control */ + +#define IGB_RXDCTL_PTHRESH_SHIFT (0) /* Bits 0-4: Prefetch Threshold */ + /* Bits 5-7: Reserved */ +#define IGB_RXDCTL_HTHRESH_SHIFT (8) /* Bits 8-12: Host Threshold */ + /* Bits 13-15: Reserved */ +#define IGB_RXDCTL_WTHRESH_SHIFT (16) /* Bits 16-20: Write-Back Threshold */ + /* Bits 21-24: Reserved */ +#define IGB_RXDCTL_ENABLE (1 << 25) /* Bit 25: Receive Queue Enable */ +#define IGB_RXDCTL_SWFLUSH (1 << 26) /* Bit 26: Receive Software Flush */ + /* Bits 27-31: Reserved */ + +/* Interrupt Cause */ + +#define IGB_IC_TXDW (1 << 0) /* Bit 0: Transmit Descriptor Written Back */ + /* Bit 1: Reserved */ +#define IGB_IC_LSC (1 << 2) /* Bit 2: Link Status Change */ + /* Bit 3: Reserved */ +#define IGB_IC_RXDMT0 (1 << 4) /* Bit 4: Receive Descriptor Minimum Threshold Reached */ +#define IGB_IC_MACSEC (1 << 5) /* Bit 5: Sets the MACSec interrupt */ +#define IGB_IC_RXMISS (1 << 6) /* Bit 6: Receiver Miss Interrupt */ +#define IGB_IC_RXDW (1 << 7) /* Bit 7: Receiver Descriptor Write Back interrupt */ +#define IGB_IC_VMMB (1 << 8) /* Bit 8: Sets the VM mailbox interrupt. */ + /* Bits 9-10: Reserved */ + /* Bits 11-14: General Purpose Interrupts */ +#define IGB_IC_PTRAP (1 << 15) /* Bit 15: Probe trap interrupt */ + /* Bits 16-17: Reserved */ +#define IGB_IC_MNG (1 << 18) /* Bit 18: Management Event interrupt */ + /* Bit 19: Reserved */ +#define IGB_IC_OMED (1 << 20) /* Bit 20: Sets the Other Media Energy Detected Interrupt */ + /* Bit 21: Reserved */ +#define IGB_IC_FER (1 << 22) /* Bit 22: Fatal Error interrupt */ +#define IGB_IC_NFER (1 << 23) /* Bit 23: Sets the Non Fatal Error Interrupt */ +#define IGB_IC_CSRTO (1 << 24) /* Bit 24: Sets the CSR access time out indication interrupt */ +#define IGB_IC_SCE (1 << 25) /* Bit 25: Set the Storm Control Event Interrupt */ +#define IGB_IC_SWD (1 << 26) /* Bit 26: Software Watchdog interrupt */ + /* Bit 27: Reserved */ +#define IGB_IC_DOUTSYNC (1 << 28) /* Bit 28: Sets the DMA Tx Out of Sync Interrupt. */ + /* Bit 29: Reserved */ +#define IGB_IC_TCPTIM (1 << 30) /* Bit 30: Sets the TCP timer interrupt */ + /* Bit 31: Reserved */ + +/* Extended Interrupt Mask for Non-MSI-X Mode */ + +#define IGB_EIMS_NOMSIX_RXTX0 (1 << 0) +#define IGB_EIMS_NOMSIX_RXTX1 (1 << 1) +#define IGB_EIMS_NOMSIX_RXTX2 (1 << 2) +#define IGB_EIMS_NOMSIX_RXTX3 (1 << 3) +#define IGB_EIMS_NOMSIX_TCPTIM (1 << 30) +#define IGB_EIMS_NOMSIX_OTHER (1 << 31) + +/* Extended Interrupt Mask for MSI-X Mode */ + +#define IGB_EIMS_MSIX_0 (1 << 0) +#define IGB_EIMS_MSIX_1 (1 << 1) +#define IGB_EIMS_MSIX_2 (1 << 2) +#define IGB_EIMS_MSIX_3 (1 << 3) +#define IGB_EIMS_MSIX_4 (1 << 4) + +/* Interrupt Vector Allocation Registers */ + +#define IGB_IVAR0_RXQ0_SHIFT (0) /* Bits 0-4: MSI-X vector assigned to RxQ0 */ +#define IGB_IVAR0_RXQ0_VAL (1 << 7) /* Bit 7: Valid bit for RxQ0 */ +#define IGB_IVAR0_TXQ0_SHIFT (8) /* Bits 8-12: MSI-X vector assigned to TxQ0 */ +#define IGB_IVAR0_TXQ0_VAL (1 << 7) /* Bit 7: Valid bit for TxQ0 */ + +/* Interrupt Vector Allocation Registers - Misc */ + +#define IGB_IVARMSC_TCPTIM (0) /* Bits 0-5: MSI-X vectorassigned to TCP timer interrupt */ + /* Bits 5-6: Reserved */ +#define IGB_IVARMSC_TCPTIM_VAL (1 << 7) /* Bit 7: Enable bit for TCP timer interrupt */ +#define IGB_IVARMSC_OTHER_SHIFT (8) /* Bits 8-12: MSI-X vector assigned to Other Cause */ + /* Bits 13-14: Reserved */ +#define IGB_IVARMSC_OTHER_VAL (1 << 15) /* Bit 15: Enable bit for Other Cause */ + /* Bits 20-30: Reserved */ + +/* General Purpose Interrupt Enable */ + +#define IGB_GPIE_NSICR (1 << 0) /* Bit 0: Non Selective Interrupt Clear on Read */ + /* Bits 1-3: Reserved */ +#define IGB_GPIE_MSIX (1 << 4) /* Bit 4: MSI-X mode */ + /* Bits 5-6: Reserved */ +#define IGB_GPIE_LLINTERVAL_SHIFT (7) /* Bits 7-11: Low Latency Credits Increment Rate */ + /* Bits 12-29: Reserved */ +#define IGB_GPIE_EIAME (1 << 30) /* Bit 30: Extended Interrupt Auto Mask Enable */ +#define IGB_GPIE_PBASUPPORT (1 << 31) /* Bit 31: PBA Support */ + +/* Transmit Descriptor Command Field */ + +#define IGB_TDESC_CMD_EOP (1 << 0) /* Bit 0: End Of Packet */ +#define IGB_TDESC_CMD_IFCS (1 << 1) /* Bit 1: Insert FCS */ +#define IGB_TDESC_CMD_IC (1 << 2) /* Bit 2: Insert Checksum */ +#define IGB_TDESC_CMD_RS (1 << 3) /* Bit 3: Report Status */ +#define IGB_TDESC_CMD_DEXT (1 << 5) /* Bit 5: Extension (0b for legacy mode) */ +#define IGB_TDESC_CMD_VLE (1 << 6) /* Bit 6: VLAN Packet Enable */ + +/* Transmit Descriptor Status Field */ + +#define IGB_TDESC_STATUS_DD (1 << 0) /* Bit 0: Descriptor Done */ + +/* Transmit Descriptor Special Field */ + +#define IGB_TDESC_SPEC_VLAN_SHIFT (0) /* Bits 0-11: VLAN Identifier */ +#define IGB_TDESC_SPEC_CFI (1 << 12) /* Bit 12: Canonical Form Indicator */ +#define IGB_TDESC_SPEC_PRI_SHIFT (13) /* Bits 13-15: User Priority */ + +/* Receive Descriptor Status Field */ + +#define IGB_RDESC_STATUS_DD (1 << 0) /* Bit 0: Descriptor Done */ +#define IGB_RDESC_STATUS_EOP (1 << 1) /* Bit 1: End of Packet */ +#define IGB_RDESC_STATUS_VP (1 << 3) /* Bit 3: Packet is 802.1Q (matched VET) */ +#define IGB_RDESC_STATUS_UDPCS (1 << 4) /* Bit 4: UDP checksum or IP payload checksum calculated on packet */ +#define IGB_RDESC_STATUS_L4CS (1 << 5) /* Bit 5: L4 (UDP or TCP) checksum calculated on packet */ +#define IGB_RDESC_STATUS_IPCS (1 << 6) /* Bit 6: IP Checksum Calculated on Packet */ +#define IGB_RDESC_STATUS_PIF (1 << 7) /* Bit 7: Passed in-exact filter */ + +/* Receive Descriptor Errors Field */ + +#define IGB_RDESC_ERRORS_L4E (1 << 5) /* Bit 5: TCP/UDP Checksum Error */ +#define IGB_RDESC_ERRORS_IPE (1 << 6) /* Bit 6: IP Checksum Error */ +#define IGB_RDESC_ERRORS_RXE (1 << 7) /* Bit 7: RX Data Error */ + +/* Receive Descriptor Special Field */ + +#define IGB_RDESC_SPEC_VLAN_SHIFT (0) /* Bits 0-11: VLAN Identifier */ +#define IGB_RDESC_SPEC_CFI (1 << 12) /* Bit 12: Canonical Form Indicator */ +#define IGB_RDESC_SPEC_PRI_SHIFT (13) /* Bits 13-15: User Priority */ + +/***************************************************************************** + * Public Types + *****************************************************************************/ + +/* Legacy TX descriptor */ + +begin_packed_struct struct igb_tx_leg_s +{ + uint64_t addr; + uint16_t len; + uint8_t cso; + uint8_t cmd; + uint8_t status; + uint8_t css; + uint16_t special; +} end_packed_struct; + +/* Legacy RX descriptor */ + +begin_packed_struct struct igb_rx_leg_s +{ + uint64_t addr; + uint16_t len; + uint16_t checksum; + uint8_t status; + uint8_t errors; + uint16_t special; +} end_packed_struct; + +#endif /* __DRIVERS_NET_IGB!_H */ diff --git a/drivers/pci/pci_drivers.c b/drivers/pci/pci_drivers.c index 5a0301c8dfd..c2204bd1239 100644 --- a/drivers/pci/pci_drivers.c +++ b/drivers/pci/pci_drivers.c @@ -32,6 +32,7 @@ #include <nuttx/virtio/virtio-pci.h> #include <nuttx/net/e1000.h> #include <nuttx/net/igc.h> +#include <nuttx/net/igb.h> #include <nuttx/can/kvaser_pci.h> #include <nuttx/can/ctucanfd_pci.h> #include <nuttx/usb/xhci_pci.h> @@ -163,6 +164,16 @@ int pci_register_drivers(void) } #endif + /* Initialization igb driver */ + +#ifdef CONFIG_NET_IGB + ret = pci_igb_init(); + if (ret < 0) + { + pcierr("pci_igb_init failed, ret=%d\n", ret); + } +#endif + /* Initialzie Kvaser pci driver */ #ifdef CONFIG_CAN_KVASER diff --git a/include/nuttx/net/igb.h b/include/nuttx/net/igb.h new file mode 100644 index 00000000000..1377959a984 --- /dev/null +++ b/include/nuttx/net/igb.h @@ -0,0 +1,59 @@ +/**************************************************************************** + * include/nuttx/net/igb.h + * + * 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. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_NET_IGB_H +#define __INCLUDE_NUTTX_NET_IGB_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: pci_igb_init + * + * Description: + * Register a pci driver + * + ****************************************************************************/ + +int pci_igb_init(void); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_NET_IGB_H */