linux/drivers/net/ethernet/ti/davinci_emac.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * DaVinci Ethernet Medium Access Controller
 *
 * DaVinci EMAC is based upon CPPI 3.0 TI DMA engine
 *
 * Copyright (C) 2009 Texas Instruments.
 *
 * ---------------------------------------------------------------------------
 * History:
 * 0-5 A number of folks worked on this driver in bits and pieces but the major
 *     contribution came from Suraj Iyer and Anant Gole
 * 6.0 Anant Gole - rewrote the driver as per Linux conventions
 * 6.1 Chaithrika U S - added support for Gigabit and RMII features,
 *     PHY layer usage
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/in.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <linux/highmem.h>
#include <linux/proc_fs.h>
#include <linux/ctype.h>
#include <linux/spinlock.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/semaphore.h>
#include <linux/phy.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/pm_runtime.h>
#include <linux/davinci_emac.h>
#include <linux/of.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/mfd/syscon.h>

#include <asm/irq.h>
#include <asm/page.h>

#include "cpsw.h"
#include "davinci_cpdma.h"

static int debug_level;
module_param(debug_level, int, 0);
MODULE_PARM_DESC();

/* Netif debug messages possible */
#define DAVINCI_EMAC_DEBUG

/* version info */
#define EMAC_MAJOR_VERSION
#define EMAC_MINOR_VERSION
#define EMAC_MODULE_VERSION
MODULE_VERSION();
static const char emac_version_string[] =;

/* Configuration items */
#define EMAC_DEF_PASS_CRC
#define EMAC_DEF_QOS_EN
#define EMAC_DEF_NO_BUFF_CHAIN
#define EMAC_DEF_MACCTRL_FRAME_EN
#define EMAC_DEF_SHORT_FRAME_EN
#define EMAC_DEF_ERROR_FRAME_EN
#define EMAC_DEF_PROM_EN
#define EMAC_DEF_PROM_CH
#define EMAC_DEF_BCAST_EN
#define EMAC_DEF_BCAST_CH
#define EMAC_DEF_MCAST_EN
#define EMAC_DEF_MCAST_CH

#define EMAC_DEF_TXPRIO_FIXED
#define EMAC_DEF_TXPACING_EN

#define EMAC_DEF_BUFFER_OFFSET
#define EMAC_DEF_MIN_ETHPKTSIZE
#define EMAC_DEF_MAX_FRAME_SIZE
#define EMAC_DEF_TX_CH
#define EMAC_DEF_RX_CH
#define EMAC_DEF_RX_NUM_DESC
#define EMAC_DEF_MAX_TX_CH
#define EMAC_DEF_MAX_RX_CH

/* Buffer descriptor parameters */
#define EMAC_DEF_TX_MAX_SERVICE
#define EMAC_DEF_RX_MAX_SERVICE

/* EMAC register related defines */
#define EMAC_ALL_MULTI_REG_VALUE
#define EMAC_NUM_MULTICAST_BITS
#define EMAC_TX_CONTROL_TX_ENABLE_VAL
#define EMAC_RX_CONTROL_RX_ENABLE_VAL
#define EMAC_MAC_HOST_ERR_INTMASK_VAL
#define EMAC_RX_UNICAST_CLEAR_ALL
#define EMAC_INT_MASK_CLEAR

/* RX MBP register bit positions */
#define EMAC_RXMBP_PASSCRC_MASK
#define EMAC_RXMBP_QOSEN_MASK
#define EMAC_RXMBP_NOCHAIN_MASK
#define EMAC_RXMBP_CMFEN_MASK
#define EMAC_RXMBP_CSFEN_MASK
#define EMAC_RXMBP_CEFEN_MASK
#define EMAC_RXMBP_CAFEN_MASK
#define EMAC_RXMBP_PROMCH_SHIFT
#define EMAC_RXMBP_PROMCH_MASK
#define EMAC_RXMBP_BROADEN_MASK
#define EMAC_RXMBP_BROADCH_SHIFT
#define EMAC_RXMBP_BROADCH_MASK
#define EMAC_RXMBP_MULTIEN_MASK
#define EMAC_RXMBP_MULTICH_SHIFT
#define EMAC_RXMBP_MULTICH_MASK
#define EMAC_RXMBP_CHMASK

/* EMAC register definitions/bit maps used */
#define EMAC_MBP_RXPROMISC
#define EMAC_MBP_PROMISCCH(ch)
#define EMAC_MBP_RXBCAST
#define EMAC_MBP_BCASTCHAN(ch)
#define EMAC_MBP_RXMCAST
#define EMAC_MBP_MCASTCHAN(ch)

/* EMAC mac_control register */
#define EMAC_MACCONTROL_TXPTYPE
#define EMAC_MACCONTROL_TXPACEEN
#define EMAC_MACCONTROL_GMIIEN
#define EMAC_MACCONTROL_GIGABITEN
#define EMAC_MACCONTROL_FULLDUPLEXEN
#define EMAC_MACCONTROL_RMIISPEED_MASK

/* GIGABIT MODE related bits */
#define EMAC_DM646X_MACCONTORL_GIG
#define EMAC_DM646X_MACCONTORL_GIGFORCE

/* EMAC mac_status register */
#define EMAC_MACSTATUS_TXERRCODE_MASK
#define EMAC_MACSTATUS_TXERRCODE_SHIFT
#define EMAC_MACSTATUS_TXERRCH_MASK
#define EMAC_MACSTATUS_TXERRCH_SHIFT
#define EMAC_MACSTATUS_RXERRCODE_MASK
#define EMAC_MACSTATUS_RXERRCODE_SHIFT
#define EMAC_MACSTATUS_RXERRCH_MASK
#define EMAC_MACSTATUS_RXERRCH_SHIFT

/* EMAC RX register masks */
#define EMAC_RX_MAX_LEN_MASK
#define EMAC_RX_BUFFER_OFFSET_MASK

/* MAC_IN_VECTOR (0x180) register bit fields */
#define EMAC_DM644X_MAC_IN_VECTOR_HOST_INT
#define EMAC_DM644X_MAC_IN_VECTOR_STATPEND_INT
#define EMAC_DM644X_MAC_IN_VECTOR_RX_INT_VEC
#define EMAC_DM644X_MAC_IN_VECTOR_TX_INT_VEC

/** NOTE:: For DM646x the IN_VECTOR has changed */
#define EMAC_DM646X_MAC_IN_VECTOR_RX_INT_VEC
#define EMAC_DM646X_MAC_IN_VECTOR_TX_INT_VEC
#define EMAC_DM646X_MAC_IN_VECTOR_HOST_INT
#define EMAC_DM646X_MAC_IN_VECTOR_STATPEND_INT

/* CPPI bit positions */
#define EMAC_CPPI_SOP_BIT
#define EMAC_CPPI_EOP_BIT
#define EMAC_CPPI_OWNERSHIP_BIT
#define EMAC_CPPI_EOQ_BIT
#define EMAC_CPPI_TEARDOWN_COMPLETE_BIT
#define EMAC_CPPI_PASS_CRC_BIT
#define EMAC_RX_BD_BUF_SIZE
#define EMAC_BD_LENGTH_FOR_CACHE
#define EMAC_RX_BD_PKT_LENGTH_MASK

/* Max hardware defines */
#define EMAC_MAX_TXRX_CHANNELS
#define EMAC_DEF_MAX_MULTICAST_ADDRESSES

/* EMAC Peripheral Device Register Memory Layout structure */
#define EMAC_MACINVECTOR

#define EMAC_DM646X_MACEOIVECTOR

#define EMAC_MACINTSTATRAW
#define EMAC_MACINTSTATMASKED
#define EMAC_MACINTMASKSET
#define EMAC_MACINTMASKCLEAR

#define EMAC_RXMBPENABLE
#define EMAC_RXUNICASTSET
#define EMAC_RXUNICASTCLEAR
#define EMAC_RXMAXLEN
#define EMAC_RXBUFFEROFFSET
#define EMAC_RXFILTERLOWTHRESH

#define EMAC_MACCONTROL
#define EMAC_MACSTATUS
#define EMAC_EMCONTROL
#define EMAC_FIFOCONTROL
#define EMAC_MACCONFIG
#define EMAC_SOFTRESET
#define EMAC_MACSRCADDRLO
#define EMAC_MACSRCADDRHI
#define EMAC_MACHASH1
#define EMAC_MACHASH2
#define EMAC_MACADDRLO
#define EMAC_MACADDRHI
#define EMAC_MACINDEX

/* EMAC statistics registers */
#define EMAC_RXGOODFRAMES
#define EMAC_RXBCASTFRAMES
#define EMAC_RXMCASTFRAMES
#define EMAC_RXPAUSEFRAMES
#define EMAC_RXCRCERRORS
#define EMAC_RXALIGNCODEERRORS
#define EMAC_RXOVERSIZED
#define EMAC_RXJABBER
#define EMAC_RXUNDERSIZED
#define EMAC_RXFRAGMENTS
#define EMAC_RXFILTERED
#define EMAC_RXQOSFILTERED
#define EMAC_RXOCTETS
#define EMAC_TXGOODFRAMES
#define EMAC_TXBCASTFRAMES
#define EMAC_TXMCASTFRAMES
#define EMAC_TXPAUSEFRAMES
#define EMAC_TXDEFERRED
#define EMAC_TXCOLLISION
#define EMAC_TXSINGLECOLL
#define EMAC_TXMULTICOLL
#define EMAC_TXEXCESSIVECOLL
#define EMAC_TXLATECOLL
#define EMAC_TXUNDERRUN
#define EMAC_TXCARRIERSENSE
#define EMAC_TXOCTETS
#define EMAC_NETOCTETS
#define EMAC_RXSOFOVERRUNS
#define EMAC_RXMOFOVERRUNS
#define EMAC_RXDMAOVERRUNS

/* EMAC DM644x control registers */
#define EMAC_CTRL_EWCTL
#define EMAC_CTRL_EWINTTCNT

/* EMAC DM644x control module masks */
#define EMAC_DM644X_EWINTCNT_MASK
#define EMAC_DM644X_INTMIN_INTVL
#define EMAC_DM644X_INTMAX_INTVL

/* EMAC DM646X control module registers */
#define EMAC_DM646X_CMINTCTRL
#define EMAC_DM646X_CMRXINTEN
#define EMAC_DM646X_CMTXINTEN
#define EMAC_DM646X_CMRXINTMAX
#define EMAC_DM646X_CMTXINTMAX

/* EMAC DM646X control module masks */
#define EMAC_DM646X_INTPACEEN
#define EMAC_DM646X_INTPRESCALE_MASK
#define EMAC_DM646X_CMINTMAX_CNT
#define EMAC_DM646X_CMINTMIN_CNT
#define EMAC_DM646X_CMINTMAX_INTVL
#define EMAC_DM646X_CMINTMIN_INTVL


/* EMAC EOI codes for C0 */
#define EMAC_DM646X_MAC_EOI_C0_RXEN
#define EMAC_DM646X_MAC_EOI_C0_TXEN

/* EMAC Stats Clear Mask */
#define EMAC_STATS_CLR_MASK

/* emac_priv: EMAC private data structure
 *
 * EMAC adapter private data structure
 */
struct emac_priv {};

/* EMAC TX Host Error description strings */
static char *emac_txhost_errcodes[16] =;

/* EMAC RX Host Error description strings */
static char *emac_rxhost_errcodes[16] =;

/* Helper macros */
#define emac_read(reg)
#define emac_write(reg, val)

#define emac_ctrl_read(reg)
#define emac_ctrl_write(reg, val)

/**
 * emac_get_drvinfo - Get EMAC driver information
 * @ndev: The DaVinci EMAC network adapter
 * @info: ethtool info structure containing name and version
 *
 * Returns EMAC driver information (name and version)
 *
 */
static void emac_get_drvinfo(struct net_device *ndev,
			     struct ethtool_drvinfo *info)
{}

/**
 * emac_get_coalesce - Get interrupt coalesce settings for this device
 * @ndev : The DaVinci EMAC network adapter
 * @coal : ethtool coalesce settings structure
 * @kernel_coal: ethtool CQE mode setting structure
 * @extack: extack for reporting error messages
 *
 * Fetch the current interrupt coalesce settings
 *
 */
static int emac_get_coalesce(struct net_device *ndev,
			     struct ethtool_coalesce *coal,
			     struct kernel_ethtool_coalesce *kernel_coal,
			     struct netlink_ext_ack *extack)
{}

/**
 * emac_set_coalesce - Set interrupt coalesce settings for this device
 * @ndev : The DaVinci EMAC network adapter
 * @coal : ethtool coalesce settings structure
 * @kernel_coal: ethtool CQE mode setting structure
 * @extack: extack for reporting error messages
 *
 * Set interrupt coalesce parameters
 *
 */
static int emac_set_coalesce(struct net_device *ndev,
			     struct ethtool_coalesce *coal,
			     struct kernel_ethtool_coalesce *kernel_coal,
			     struct netlink_ext_ack *extack)
{}


/* ethtool_ops: DaVinci EMAC Ethtool structure
 *
 * Ethtool support for EMAC adapter
 */
static const struct ethtool_ops ethtool_ops =;

/**
 * emac_update_phystatus - Update Phy status
 * @priv: The DaVinci EMAC private adapter structure
 *
 * Updates phy status and takes action for network queue if required
 * based upon link status
 *
 */
static void emac_update_phystatus(struct emac_priv *priv)
{}

/**
 * hash_get - Calculate hash value from mac address
 * @addr: mac address to delete from hash table
 *
 * Calculates hash value from mac address
 *
 */
static u32 hash_get(u8 *addr)
{}

/**
 * emac_hash_add - Hash function to add mac addr from hash table
 * @priv: The DaVinci EMAC private adapter structure
 * @mac_addr: mac address to delete from hash table
 *
 * Adds mac address to the internal hash table
 *
 */
static int emac_hash_add(struct emac_priv *priv, u8 *mac_addr)
{}

/**
 * emac_hash_del - Hash function to delete mac addr from hash table
 * @priv: The DaVinci EMAC private adapter structure
 * @mac_addr: mac address to delete from hash table
 *
 * Removes mac address from the internal hash table
 *
 */
static int emac_hash_del(struct emac_priv *priv, u8 *mac_addr)
{}

/* EMAC multicast operation */
#define EMAC_MULTICAST_ADD
#define EMAC_MULTICAST_DEL
#define EMAC_ALL_MULTI_SET
#define EMAC_ALL_MULTI_CLR

/**
 * emac_add_mcast - Set multicast address in the EMAC adapter (Internal)
 * @priv: The DaVinci EMAC private adapter structure
 * @action: multicast operation to perform
 * @mac_addr: mac address to set
 *
 * Set multicast addresses in EMAC adapter - internal function
 *
 */
static void emac_add_mcast(struct emac_priv *priv, u32 action, u8 *mac_addr)
{}

/**
 * emac_dev_mcast_set - Set multicast address in the EMAC adapter
 * @ndev: The DaVinci EMAC network adapter
 *
 * Set multicast addresses in EMAC adapter
 *
 */
static void emac_dev_mcast_set(struct net_device *ndev)
{}

/*************************************************************************
 *  EMAC Hardware manipulation
 *************************************************************************/

/**
 * emac_int_disable - Disable EMAC module interrupt (from adapter)
 * @priv: The DaVinci EMAC private adapter structure
 *
 * Disable EMAC interrupt on the adapter
 *
 */
static void emac_int_disable(struct emac_priv *priv)
{}

/**
 * emac_int_enable - Enable EMAC module interrupt (from adapter)
 * @priv: The DaVinci EMAC private adapter structure
 *
 * Enable EMAC interrupt on the adapter
 *
 */
static void emac_int_enable(struct emac_priv *priv)
{}

/**
 * emac_irq - EMAC interrupt handler
 * @irq: interrupt number
 * @dev_id: EMAC network adapter data structure ptr
 *
 * EMAC Interrupt handler - we only schedule NAPI and not process any packets
 * here. EVen the interrupt status is checked (TX/RX/Err) in NAPI poll function
 *
 * Returns interrupt handled condition
 */
static irqreturn_t emac_irq(int irq, void *dev_id)
{}

static struct sk_buff *emac_rx_alloc(struct emac_priv *priv)
{}

static void emac_rx_handler(void *token, int len, int status)
{}

static void emac_tx_handler(void *token, int len, int status)
{}

/**
 * emac_dev_xmit - EMAC Transmit function
 * @skb: SKB pointer
 * @ndev: The DaVinci EMAC network adapter
 *
 * Called by the system to transmit a packet  - we queue the packet in
 * EMAC hardware transmit queue
 *
 * Returns success(NETDEV_TX_OK) or error code (typically out of desc's)
 */
static netdev_tx_t emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev)
{}

/**
 * emac_dev_tx_timeout - EMAC Transmit timeout function
 * @ndev: The DaVinci EMAC network adapter
 * @txqueue: the index of the hung transmit queue
 *
 * Called when system detects that a skb timeout period has expired
 * potentially due to a fault in the adapter in not being able to send
 * it out on the wire. We teardown the TX channel assuming a hardware
 * error and re-initialize the TX channel for hardware operation
 *
 */
static void emac_dev_tx_timeout(struct net_device *ndev, unsigned int txqueue)
{}

/**
 * emac_set_type0addr - Set EMAC Type0 mac address
 * @priv: The DaVinci EMAC private adapter structure
 * @ch: RX channel number
 * @mac_addr: MAC address to set in device
 *
 * Called internally to set Type0 mac address of the adapter (Device)
 *
 * Returns success (0) or appropriate error code (none as of now)
 */
static void emac_set_type0addr(struct emac_priv *priv, u32 ch, char *mac_addr)
{}

/**
 * emac_set_type1addr - Set EMAC Type1 mac address
 * @priv: The DaVinci EMAC private adapter structure
 * @ch: RX channel number
 * @mac_addr: MAC address to set in device
 *
 * Called internally to set Type1 mac address of the adapter (Device)
 *
 * Returns success (0) or appropriate error code (none as of now)
 */
static void emac_set_type1addr(struct emac_priv *priv, u32 ch, char *mac_addr)
{}

/**
 * emac_set_type2addr - Set EMAC Type2 mac address
 * @priv: The DaVinci EMAC private adapter structure
 * @ch: RX channel number
 * @mac_addr: MAC address to set in device
 * @index: index into RX address entries
 * @match: match parameter for RX address matching logic
 *
 * Called internally to set Type2 mac address of the adapter (Device)
 *
 * Returns success (0) or appropriate error code (none as of now)
 */
static void emac_set_type2addr(struct emac_priv *priv, u32 ch,
			       char *mac_addr, int index, int match)
{}

/**
 * emac_setmac - Set mac address in the adapter (internal function)
 * @priv: The DaVinci EMAC private adapter structure
 * @ch: RX channel number
 * @mac_addr: MAC address to set in device
 *
 * Called internally to set the mac address of the adapter (Device)
 *
 * Returns success (0) or appropriate error code (none as of now)
 */
static void emac_setmac(struct emac_priv *priv, u32 ch, char *mac_addr)
{}

/**
 * emac_dev_setmac_addr - Set mac address in the adapter
 * @ndev: The DaVinci EMAC network adapter
 * @addr: MAC address to set in device
 *
 * Called by the system to set the mac address of the adapter (Device)
 *
 * Returns success (0) or appropriate error code (none as of now)
 */
static int emac_dev_setmac_addr(struct net_device *ndev, void *addr)
{}

/**
 * emac_hw_enable - Enable EMAC hardware for packet transmission/reception
 * @priv: The DaVinci EMAC private adapter structure
 *
 * Enables EMAC hardware for packet processing - enables PHY, enables RX
 * for packet reception and enables device interrupts and then NAPI
 *
 * Returns success (0) or appropriate error code (none right now)
 */
static int emac_hw_enable(struct emac_priv *priv)
{}

/**
 * emac_poll - EMAC NAPI Poll function
 * @napi: pointer to the napi_struct containing The DaVinci EMAC network adapter
 * @budget: Number of receive packets to process (as told by NAPI layer)
 *
 * NAPI Poll function implemented to process packets as per budget. We check
 * the type of interrupt on the device and accordingly call the TX or RX
 * packet processing functions. We follow the budget for RX processing and
 * also put a cap on number of TX pkts processed through config param. The
 * NAPI schedule function is called if more packets pending.
 *
 * Returns number of packets received (in most cases; else TX pkts - rarely)
 */
static int emac_poll(struct napi_struct *napi, int budget)
{}

#ifdef CONFIG_NET_POLL_CONTROLLER
/**
 * emac_poll_controller - EMAC Poll controller function
 * @ndev: The DaVinci EMAC network adapter
 *
 * Polled functionality used by netconsole and others in non interrupt mode
 *
 */
static void emac_poll_controller(struct net_device *ndev)
{}
#endif

static void emac_adjust_link(struct net_device *ndev)
{}

/*************************************************************************
 *  Linux Driver Model
 *************************************************************************/

/**
 * emac_devioctl - EMAC adapter ioctl
 * @ndev: The DaVinci EMAC network adapter
 * @ifrq: request parameter
 * @cmd: command parameter
 *
 * EMAC driver ioctl function
 *
 * Returns success(0) or appropriate error code
 */
static int emac_devioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd)
{}

static int match_first_device(struct device *dev, const void *data)
{}

/**
 * emac_dev_open - EMAC device open
 * @ndev: The DaVinci EMAC network adapter
 *
 * Called when system wants to start the interface. We init TX/RX channels
 * and enable the hardware for packet reception/transmission and start the
 * network queue.
 *
 * Returns 0 for a successful open, or appropriate error code
 */
static int emac_dev_open(struct net_device *ndev)
{}

/**
 * emac_dev_stop - EMAC device stop
 * @ndev: The DaVinci EMAC network adapter
 *
 * Called when system wants to stop or down the interface. We stop the network
 * queue, disable interrupts and cleanup TX/RX channels.
 *
 * We return the statistics in net_device_stats structure pulled from emac
 */
static int emac_dev_stop(struct net_device *ndev)
{}

/**
 * emac_dev_getnetstats - EMAC get statistics function
 * @ndev: The DaVinci EMAC network adapter
 *
 * Called when system wants to get statistics from the device.
 *
 * We return the statistics in net_device_stats structure pulled from emac
 */
static struct net_device_stats *emac_dev_getnetstats(struct net_device *ndev)
{}

static const struct net_device_ops emac_netdev_ops =;

static struct emac_platform_data *
davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv)
{}

static int davinci_emac_try_get_mac(struct platform_device *pdev,
				    int instance, u8 *mac_addr)
{}

/**
 * davinci_emac_probe - EMAC device probe
 * @pdev: The DaVinci EMAC device that we are removing
 *
 * Called when probing for emac devicesr. We get details of instances and
 * resource information from platform init and register a network device
 * and allocate resources necessary for driver to perform
 */
static int davinci_emac_probe(struct platform_device *pdev)
{}

/**
 * davinci_emac_remove - EMAC device remove
 * @pdev: The DaVinci EMAC device that we are removing
 *
 * Called when removing the device driver. We disable clock usage and release
 * the resources taken up by the driver and unregister network device
 */
static void davinci_emac_remove(struct platform_device *pdev)
{}

static int davinci_emac_suspend(struct device *dev)
{}

static int davinci_emac_resume(struct device *dev)
{}

static const struct dev_pm_ops davinci_emac_pm_ops =;

static const struct emac_platform_data am3517_emac_data =;

static const struct emac_platform_data dm816_emac_data =;

static const struct of_device_id davinci_emac_of_match[] =;
MODULE_DEVICE_TABLE(of, davinci_emac_of_match);

/* davinci_emac_driver: EMAC platform driver structure */
static struct platform_driver davinci_emac_driver =;

/**
 * davinci_emac_init - EMAC driver module init
 *
 * Called when initializing the driver. We register the driver with
 * the platform.
 */
static int __init davinci_emac_init(void)
{}
late_initcall(davinci_emac_init);

/**
 * davinci_emac_exit - EMAC driver module exit
 *
 * Called when exiting the driver completely. We unregister the driver with
 * the platform and exit
 */
static void __exit davinci_emac_exit(void)
{}
module_exit(davinci_emac_exit);

MODULE_LICENSE();
MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_DESCRIPTION();