linux/drivers/net/ethernet/tehuti/tehuti.c

// 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();