// SPDX-License-Identifier: GPL-2.0-or-later /* * Tehuti Networks(R) Network Driver * ethtool interface implementation * Copyright (C) 2007 Tehuti Networks Ltd. All rights reserved */ /* * RX HW/SW interaction overview * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * There are 2 types of RX communication channels between driver and NIC. * 1) RX Free Fifo - RXF - holds descriptors of empty buffers to accept incoming * traffic. This Fifo is filled by SW and is readen by HW. Each descriptor holds * info about buffer's location, size and ID. An ID field is used to identify a * buffer when it's returned with data via RXD Fifo (see below) * 2) RX Data Fifo - RXD - holds descriptors of full buffers. This Fifo is * filled by HW and is readen by SW. Each descriptor holds status and ID. * HW pops descriptor from RXF Fifo, stores ID, fills buffer with incoming data, * via dma moves it into host memory, builds new RXD descriptor with same ID, * pushes it into RXD Fifo and raises interrupt to indicate new RX data. * * Current NIC configuration (registers + firmware) makes NIC use 2 RXF Fifos. * One holds 1.5K packets and another - 26K packets. Depending on incoming * packet size, HW desides on a RXF Fifo to pop buffer from. When packet is * filled with data, HW builds new RXD descriptor for it and push it into single * RXD Fifo. * * RX SW Data Structures * ~~~~~~~~~~~~~~~~~~~~~ * skb db - used to keep track of all skbs owned by SW and their dma addresses. * For RX case, ownership lasts from allocating new empty skb for RXF until * accepting full skb from RXD and passing it to OS. Each RXF Fifo has its own * skb db. Implemented as array with bitmask. * fifo - keeps info about fifo's size and location, relevant HW registers, * usage and skb db. Each RXD and RXF Fifo has its own fifo structure. * Implemented as simple struct. * * RX SW Execution Flow * ~~~~~~~~~~~~~~~~~~~~ * Upon initialization (ifconfig up) driver creates RX fifos and initializes * relevant registers. At the end of init phase, driver enables interrupts. * NIC sees that there is no RXF buffers and raises * RD_INTR interrupt, isr fills skbs and Rx begins. * Driver has two receive operation modes: * NAPI - interrupt-driven mixed with polling * interrupt-driven only * * Interrupt-driven only flow is following. When buffer is ready, HW raises * interrupt and isr is called. isr collects all available packets * (bdx_rx_receive), refills skbs (bdx_rx_alloc_skbs) and exit. * Rx buffer allocation note * ~~~~~~~~~~~~~~~~~~~~~~~~~ * Driver cares to feed such amount of RxF descriptors that respective amount of * RxD descriptors can not fill entire RxD fifo. The main reason is lack of * overflow check in Bordeaux for RxD fifo free/used size. * FIXME: this is NOT fully implemented, more work should be done * */ #define pr_fmt(fmt) … #include "tehuti.h" static const struct pci_device_id bdx_pci_tbl[] = …; MODULE_DEVICE_TABLE(pci, bdx_pci_tbl); /* Definitions needed by ISR or NAPI functions */ static void bdx_rx_alloc_skbs(struct bdx_priv *priv, struct rxf_fifo *f); static void bdx_tx_cleanup(struct bdx_priv *priv); static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget); /* Definitions needed by FW loading */ static void bdx_tx_push_desc_safe(struct bdx_priv *priv, void *data, int size); /* Definitions needed by hw_start */ static int bdx_tx_init(struct bdx_priv *priv); static int bdx_rx_init(struct bdx_priv *priv); /* Definitions needed by bdx_close */ static void bdx_rx_free(struct bdx_priv *priv); static void bdx_tx_free(struct bdx_priv *priv); /* Definitions needed by bdx_probe */ static void bdx_set_ethtool_ops(struct net_device *netdev); /************************************************************************* * Print Info * *************************************************************************/ static void print_hw_id(struct pci_dev *pdev) { … } static void print_fw_id(struct pci_nic *nic) { … } static void print_eth_id(struct net_device *ndev) { … } /************************************************************************* * Code * *************************************************************************/ #define bdx_enable_interrupts(priv) … #define bdx_disable_interrupts(priv) … /** * bdx_fifo_init - create TX/RX descriptor fifo for host-NIC communication. * @priv: NIC private structure * @f: fifo to initialize * @fsz_type: fifo size type: 0-4KB, 1-8KB, 2-16KB, 3-32KB * @reg_CFG0: offsets of registers relative to base address * @reg_CFG1: offsets of registers relative to base address * @reg_RPTR: offsets of registers relative to base address * @reg_WPTR: offsets of registers relative to base address * * 1K extra space is allocated at the end of the fifo to simplify * processing of descriptors that wraps around fifo's end * * Returns 0 on success, negative value on failure * */ static int bdx_fifo_init(struct bdx_priv *priv, struct fifo *f, int fsz_type, u16 reg_CFG0, u16 reg_CFG1, u16 reg_RPTR, u16 reg_WPTR) { … } /** * bdx_fifo_free - free all resources used by fifo * @priv: NIC private structure * @f: fifo to release */ static void bdx_fifo_free(struct bdx_priv *priv, struct fifo *f) { … } /** * bdx_link_changed - notifies OS about hw link state. * @priv: hw adapter structure */ static void bdx_link_changed(struct bdx_priv *priv) { … } static void bdx_isr_extra(struct bdx_priv *priv, u32 isr) { … } /** * bdx_isr_napi - Interrupt Service Routine for Bordeaux NIC * @irq: interrupt number * @dev: network device * * Return IRQ_NONE if it was not our interrupt, IRQ_HANDLED - otherwise * * It reads ISR register to know interrupt reasons, and proceed them one by one. * Reasons of interest are: * RX_DESC - new packet has arrived and RXD fifo holds its descriptor * RX_FREE - number of free Rx buffers in RXF fifo gets low * TX_FREE - packet was transmited and RXF fifo holds its descriptor */ static irqreturn_t bdx_isr_napi(int irq, void *dev) { … } static int bdx_poll(struct napi_struct *napi, int budget) { … } /** * bdx_fw_load - loads firmware to NIC * @priv: NIC private structure * * Firmware is loaded via TXD fifo, so it must be initialized first. * Firware must be loaded once per NIC not per PCI device provided by NIC (NIC * can have few of them). So all drivers use semaphore register to choose one * that will actually load FW to NIC. */ static int bdx_fw_load(struct bdx_priv *priv) { … } static void bdx_restore_mac(struct net_device *ndev, struct bdx_priv *priv) { … } /** * bdx_hw_start - inits registers and starts HW's Rx and Tx engines * @priv: NIC private structure */ static int bdx_hw_start(struct bdx_priv *priv) { … } static void bdx_hw_stop(struct bdx_priv *priv) { … } static int bdx_hw_reset_direct(void __iomem *regs) { … } static int bdx_hw_reset(struct bdx_priv *priv) { … } static int bdx_sw_reset(struct bdx_priv *priv) { … } /* bdx_reset - performs right type of reset depending on hw type */ static int bdx_reset(struct bdx_priv *priv) { … } /** * bdx_close - Disables a network interface * @ndev: network interface device structure * * Returns 0, this is not allowed to fail * * The close entry point is called when an interface is de-activated * by the OS. The hardware is still under the drivers control, but * needs to be disabled. A global MAC reset is issued to stop the * hardware, and all transmit and receive resources are freed. **/ static int bdx_close(struct net_device *ndev) { … } /** * bdx_open - Called when a network interface is made active * @ndev: network interface device structure * * Returns 0 on success, negative value on failure * * The open entry point is called when a network interface is made * active by the system (IFF_UP). At this point all resources needed * for transmit and receive operations are allocated, the interrupt * handler is registered with the OS, the watchdog timer is started, * and the stack is notified that the interface is ready. **/ static int bdx_open(struct net_device *ndev) { … } static int bdx_range_check(struct bdx_priv *priv, u32 offset) { … } static int bdx_siocdevprivate(struct net_device *ndev, struct ifreq *ifr, void __user *udata, int cmd) { … } /** * __bdx_vlan_rx_vid - private helper for adding/killing VLAN vid * @ndev: network device * @vid: VLAN vid * @enable: enable or disable vlan * * Passes VLAN filter table to hardware */ static void __bdx_vlan_rx_vid(struct net_device *ndev, uint16_t vid, int enable) { … } /** * bdx_vlan_rx_add_vid - kernel hook for adding VLAN vid to hw filtering table * @ndev: network device * @proto: unused * @vid: VLAN vid to add */ static int bdx_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid) { … } /** * bdx_vlan_rx_kill_vid - kernel hook for killing VLAN vid in hw filtering table * @ndev: network device * @proto: unused * @vid: VLAN vid to kill */ static int bdx_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid) { … } /** * bdx_change_mtu - Change the Maximum Transfer Unit * @ndev: network interface device structure * @new_mtu: new value for maximum frame size * * Returns 0 on success, negative on failure */ static int bdx_change_mtu(struct net_device *ndev, int new_mtu) { … } static void bdx_setmulti(struct net_device *ndev) { … } static int bdx_set_mac(struct net_device *ndev, void *p) { … } static int bdx_read_mac(struct bdx_priv *priv) { … } static u64 bdx_read_l2stat(struct bdx_priv *priv, int reg) { … } /*Do the statistics-update work*/ static void bdx_update_stats(struct bdx_priv *priv) { … } static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len, u16 rxd_vlan); static void print_rxfd(struct rxf_desc *rxfd); /************************************************************************* * Rx DB * *************************************************************************/ static void bdx_rxdb_destroy(struct rxdb *db) { … } static struct rxdb *bdx_rxdb_create(int nelem) { … } static inline int bdx_rxdb_alloc_elem(struct rxdb *db) { … } static inline void *bdx_rxdb_addr_elem(struct rxdb *db, int n) { … } static inline int bdx_rxdb_available(struct rxdb *db) { … } static inline void bdx_rxdb_free_elem(struct rxdb *db, int n) { … } /************************************************************************* * Rx Init * *************************************************************************/ /** * bdx_rx_init - initialize RX all related HW and SW resources * @priv: NIC private structure * * Returns 0 on success, negative value on failure * * It creates rxf and rxd fifos, update relevant HW registers, preallocate * skb for rx. It assumes that Rx is desabled in HW * funcs are grouped for better cache usage * * RxD fifo is smaller than RxF fifo by design. Upon high load, RxD will be * filled and packets will be dropped by nic without getting into host or * cousing interrupt. Anyway, in that condition, host has no chance to process * all packets, but dropping in nic is cheaper, since it takes 0 cpu cycles */ /* TBD: ensure proper packet size */ static int bdx_rx_init(struct bdx_priv *priv) { … } /** * bdx_rx_free_skbs - frees and unmaps all skbs allocated for the fifo * @priv: NIC private structure * @f: RXF fifo */ static void bdx_rx_free_skbs(struct bdx_priv *priv, struct rxf_fifo *f) { … } /** * bdx_rx_free - release all Rx resources * @priv: NIC private structure * * It assumes that Rx is desabled in HW */ static void bdx_rx_free(struct bdx_priv *priv) { … } /************************************************************************* * Rx Engine * *************************************************************************/ /** * bdx_rx_alloc_skbs - fill rxf fifo with new skbs * @priv: nic's private structure * @f: RXF fifo that needs skbs * * It allocates skbs, build rxf descs and push it (rxf descr) into rxf fifo. * skb's virtual and physical addresses are stored in skb db. * To calculate free space, func uses cached values of RPTR and WPTR * When needed, it also updates RPTR and WPTR. */ /* TBD: do not update WPTR if no desc were written */ static void bdx_rx_alloc_skbs(struct bdx_priv *priv, struct rxf_fifo *f) { … } static inline void NETIF_RX_MUX(struct bdx_priv *priv, u32 rxd_val1, u16 rxd_vlan, struct sk_buff *skb) { … } static void bdx_recycle_skb(struct bdx_priv *priv, struct rxd_desc *rxdd) { … } /** * bdx_rx_receive - receives full packets from RXD fifo and pass them to OS * NOTE: a special treatment is given to non-continuous descriptors * that start near the end, wraps around and continue at the beginning. a second * part is copied right after the first, and then descriptor is interpreted as * normal. fifo has an extra space to allow such operations * @priv: nic's private structure * @f: RXF fifo that needs skbs * @budget: maximum number of packets to receive */ /* TBD: replace memcpy func call by explicite inline asm */ static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget) { … } /************************************************************************* * Debug / Temprorary Code * *************************************************************************/ static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len, u16 rxd_vlan) { … } static void print_rxfd(struct rxf_desc *rxfd) { … } /* * TX HW/SW interaction overview * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * There are 2 types of TX communication channels between driver and NIC. * 1) TX Free Fifo - TXF - holds ack descriptors for sent packets * 2) TX Data Fifo - TXD - holds descriptors of full buffers. * * Currently NIC supports TSO, checksuming and gather DMA * UFO and IP fragmentation is on the way * * RX SW Data Structures * ~~~~~~~~~~~~~~~~~~~~~ * txdb - used to keep track of all skbs owned by SW and their dma addresses. * For TX case, ownership lasts from geting packet via hard_xmit and until HW * acknowledges sent by TXF descriptors. * Implemented as cyclic buffer. * fifo - keeps info about fifo's size and location, relevant HW registers, * usage and skb db. Each RXD and RXF Fifo has its own fifo structure. * Implemented as simple struct. * * TX SW Execution Flow * ~~~~~~~~~~~~~~~~~~~~ * OS calls driver's hard_xmit method with packet to sent. * Driver creates DMA mappings, builds TXD descriptors and kicks HW * by updating TXD WPTR. * When packet is sent, HW write us TXF descriptor and SW frees original skb. * To prevent TXD fifo overflow without reading HW registers every time, * SW deploys "tx level" technique. * Upon strart up, tx level is initialized to TXD fifo length. * For every sent packet, SW gets its TXD descriptor sizei * (from precalculated array) and substructs it from tx level. * The size is also stored in txdb. When TXF ack arrives, SW fetch size of * original TXD descriptor from txdb and adds it to tx level. * When Tx level drops under some predefined treshhold, the driver * stops the TX queue. When TX level rises above that level, * the tx queue is enabled again. * * This technique avoids eccessive reading of RPTR and WPTR registers. * As our benchmarks shows, it adds 1.5 Gbit/sec to NIS's throuput. */ /** * __bdx_tx_db_ptr_next - helper function, increment read/write pointer + wrap * @db: tx data base * @pptr: read or write pointer */ static inline void __bdx_tx_db_ptr_next(struct txdb *db, struct tx_map **pptr) { … } /** * bdx_tx_db_inc_rptr - increment read pointer * @db: tx data base */ static inline void bdx_tx_db_inc_rptr(struct txdb *db) { … } /** * bdx_tx_db_inc_wptr - increment write pointer * @db: tx data base */ static inline void bdx_tx_db_inc_wptr(struct txdb *db) { … } /** * bdx_tx_db_init - creates and initializes tx db * @d: tx data base * @sz_type: size of tx fifo * * Returns 0 on success, error code otherwise */ static int bdx_tx_db_init(struct txdb *d, int sz_type) { … } /** * bdx_tx_db_close - closes tx db and frees all memory * @d: tx data base */ static void bdx_tx_db_close(struct txdb *d) { … } /************************************************************************* * Tx Engine * *************************************************************************/ /* sizes of tx desc (including padding if needed) as function * of skb's frag number */ static struct { … } txd_sizes[MAX_SKB_FRAGS + 1]; /** * bdx_tx_map_skb - creates and stores dma mappings for skb's data blocks * @priv: NIC private structure * @skb: socket buffer to map * @txdd: TX descriptor to use * * It makes dma mappings for skb's data blocks and writes them to PBL of * new tx descriptor. It also stores them in the tx db, so they could be * unmaped after data was sent. It is reponsibility of a caller to make * sure that there is enough space in the tx db. Last element holds pointer * to skb itself and marked with zero length */ static inline void bdx_tx_map_skb(struct bdx_priv *priv, struct sk_buff *skb, struct txd_desc *txdd) { … } /* init_txd_sizes - precalculate sizes of descriptors for skbs up to 16 frags * number of frags is used as index to fetch correct descriptors size, * instead of calculating it each time */ static void __init init_txd_sizes(void) { … } /* bdx_tx_init - initialize all Tx related stuff. * Namely, TXD and TXF fifos, database etc */ static int bdx_tx_init(struct bdx_priv *priv) { … } /** * bdx_tx_space - calculates available space in TX fifo * @priv: NIC private structure * * Returns available space in TX fifo in bytes */ static inline int bdx_tx_space(struct bdx_priv *priv) { … } /** * bdx_tx_transmit - send packet to NIC * @skb: packet to send * @ndev: network device assigned to NIC * Return codes: * o NETDEV_TX_OK everything ok. * o NETDEV_TX_BUSY Cannot transmit packet, try later * Usually a bug, means queue start/stop flow control is broken in * the driver. Note: the driver must NOT put the skb in its DMA ring. */ static netdev_tx_t bdx_tx_transmit(struct sk_buff *skb, struct net_device *ndev) { … } /** * bdx_tx_cleanup - clean TXF fifo, run in the context of IRQ. * @priv: bdx adapter * * It scans TXF fifo for descriptors, frees DMA mappings and reports to OS * that those packets were sent */ static void bdx_tx_cleanup(struct bdx_priv *priv) { … } /** * bdx_tx_free_skbs - frees all skbs from TXD fifo. * @priv: NIC private structure * * It gets called when OS stops this dev, eg upon "ifconfig down" or rmmod */ static void bdx_tx_free_skbs(struct bdx_priv *priv) { … } /* bdx_tx_free - frees all Tx resources */ static void bdx_tx_free(struct bdx_priv *priv) { … } /** * bdx_tx_push_desc - push descriptor to TxD fifo * @priv: NIC private structure * @data: desc's data * @size: desc's size * * Pushes desc to TxD fifo and overlaps it if needed. * NOTE: this func does not check for available space. this is responsibility * of the caller. Neither does it check that data size is smaller than * fifo size. */ static void bdx_tx_push_desc(struct bdx_priv *priv, void *data, int size) { … } /** * bdx_tx_push_desc_safe - push descriptor to TxD fifo in a safe way * @priv: NIC private structure * @data: desc's data * @size: desc's size * * NOTE: this func does check for available space and, if necessary, waits for * NIC to read existing data before writing new one. */ static void bdx_tx_push_desc_safe(struct bdx_priv *priv, void *data, int size) { … } static const struct net_device_ops bdx_netdev_ops = …; /** * bdx_probe - Device Initialization Routine * @pdev: PCI device information struct * @ent: entry in bdx_pci_tbl * * Returns 0 on success, negative on failure * * bdx_probe initializes an adapter identified by a pci_dev structure. * The OS initialization, configuring of the adapter private structure, * and a hardware reset occur. * * functions and their order used as explained in * /usr/src/linux/Documentation/DMA-{API,mapping}.txt * */ /* TBD: netif_msg should be checked and implemented. I disable it for now */ static int bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { … } /****************** Ethtool interface *********************/ /* get strings for statistics counters */ static const char bdx_stat_names[][ETH_GSTRING_LEN] = …; /* * bdx_get_link_ksettings - get device-specific settings * @netdev * @ecmd */ static int bdx_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *ecmd) { … } /* * bdx_get_drvinfo - report driver information * @netdev * @drvinfo */ static void bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) { … } /* * bdx_get_coalesce - get interrupt coalescing parameters * @netdev * @ecoal */ static int bdx_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal, struct kernel_ethtool_coalesce *kernel_coal, struct netlink_ext_ack *extack) { … } /* * bdx_set_coalesce - set interrupt coalescing parameters * @netdev * @ecoal */ static int bdx_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal, struct kernel_ethtool_coalesce *kernel_coal, struct netlink_ext_ack *extack) { … } /* Convert RX fifo size to number of pending packets */ static inline int bdx_rx_fifo_size_to_packets(int rx_size) { … } /* Convert TX fifo size to number of pending packets */ static inline int bdx_tx_fifo_size_to_packets(int tx_size) { … } /* * bdx_get_ringparam - report ring sizes * @netdev * @ring * @kernel_ring * @extack */ static void bdx_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, struct kernel_ethtool_ringparam *kernel_ring, struct netlink_ext_ack *extack) { … } /* * bdx_set_ringparam - set ring sizes * @netdev * @ring * @kernel_ring * @extack */ static int bdx_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, struct kernel_ethtool_ringparam *kernel_ring, struct netlink_ext_ack *extack) { … } /* * bdx_get_strings - return a set of strings that describe the requested objects * @netdev * @data */ static void bdx_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { … } /* * bdx_get_sset_count - return number of statistics or tests * @netdev */ static int bdx_get_sset_count(struct net_device *netdev, int stringset) { … } /* * bdx_get_ethtool_stats - return device's hardware L2 statistics * @netdev * @stats * @data */ static void bdx_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { … } /* * bdx_set_ethtool_ops - ethtool interface implementation * @netdev */ static void bdx_set_ethtool_ops(struct net_device *netdev) { … } /** * bdx_remove - Device Removal Routine * @pdev: PCI device information struct * * bdx_remove is called by the PCI subsystem to alert the driver * that it should release a PCI device. The could be caused by a * Hot-Plug event, or because the driver is going to be removed from * memory. **/ static void bdx_remove(struct pci_dev *pdev) { … } static struct pci_driver bdx_pci_driver = …; /* * print_driver_id - print parameters of the driver build */ static void __init print_driver_id(void) { … } static int __init bdx_module_init(void) { … } module_init(…) …; static void __exit bdx_module_exit(void) { … } module_exit(bdx_module_exit); MODULE_LICENSE(…) …; MODULE_AUTHOR(…); MODULE_DESCRIPTION(…); MODULE_FIRMWARE(…) …;