linux/drivers/net/ethernet/xilinx/ll_temac_main.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Driver for Xilinx TEMAC Ethernet device
 *
 * Copyright (c) 2008 Nissin Systems Co., Ltd.,  Yoshio Kashiwagi
 * Copyright (c) 2005-2008 DLA Systems,  David H. Lynch Jr. <[email protected]>
 * Copyright (c) 2008-2009 Secret Lab Technologies Ltd.
 *
 * This is a driver for the Xilinx ll_temac ipcore which is often used
 * in the Virtex and Spartan series of chips.
 *
 * Notes:
 * - The ll_temac hardware uses indirect access for many of the TEMAC
 *   registers, include the MDIO bus.  However, indirect access to MDIO
 *   registers take considerably more clock cycles than to TEMAC registers.
 *   MDIO accesses are long, so threads doing them should probably sleep
 *   rather than busywait.  However, since only one indirect access can be
 *   in progress at any given time, that means that *all* indirect accesses
 *   could end up sleeping (to wait for an MDIO access to complete).
 *   Fortunately none of the indirect accesses are on the 'hot' path for tx
 *   or rx, so this should be okay.
 *
 * TODO:
 * - Factor out locallink DMA code into separate driver
 * - Fix support for hardware checksumming.
 * - Testing.  Lots and lots of testing.
 *
 */

#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/mii.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/platform_device.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/tcp.h>      /* needed for sizeof(tcphdr) */
#include <linux/udp.h>      /* needed for sizeof(udphdr) */
#include <linux/phy.h>
#include <linux/in.h>
#include <linux/io.h>
#include <linux/ip.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/dma-mapping.h>
#include <linux/processor.h>
#include <linux/platform_data/xilinx-ll-temac.h>

#include "ll_temac.h"

/* Descriptors defines for Tx and Rx DMA */
#define TX_BD_NUM_DEFAULT
#define RX_BD_NUM_DEFAULT
#define TX_BD_NUM_MAX
#define RX_BD_NUM_MAX

/* ---------------------------------------------------------------------
 * Low level register access functions
 */

static u32 _temac_ior_be(struct temac_local *lp, int offset)
{}

static void _temac_iow_be(struct temac_local *lp, int offset, u32 value)
{}

static u32 _temac_ior_le(struct temac_local *lp, int offset)
{}

static void _temac_iow_le(struct temac_local *lp, int offset, u32 value)
{}

static bool hard_acs_rdy(struct temac_local *lp)
{}

static bool hard_acs_rdy_or_timeout(struct temac_local *lp, ktime_t timeout)
{}

/* Poll for maximum 20 ms.  This is similar to the 2 jiffies @ 100 Hz
 * that was used before, and should cover MDIO bus speed down to 3200
 * Hz.
 */
#define HARD_ACS_RDY_POLL_NS

/*
 * temac_indirect_busywait - Wait for current indirect register access
 * to complete.
 */
int temac_indirect_busywait(struct temac_local *lp)
{}

/*
 * temac_indirect_in32 - Indirect register read access.  This function
 * must be called without lp->indirect_lock being held.
 */
u32 temac_indirect_in32(struct temac_local *lp, int reg)
{}

/*
 * temac_indirect_in32_locked - Indirect register read access.  This
 * function must be called with lp->indirect_lock being held.  Use
 * this together with spin_lock_irqsave/spin_lock_irqrestore to avoid
 * repeated lock/unlock and to ensure uninterrupted access to indirect
 * registers.
 */
u32 temac_indirect_in32_locked(struct temac_local *lp, int reg)
{}

/*
 * temac_indirect_out32 - Indirect register write access.  This function
 * must be called without lp->indirect_lock being held.
 */
void temac_indirect_out32(struct temac_local *lp, int reg, u32 value)
{}

/*
 * temac_indirect_out32_locked - Indirect register write access.  This
 * function must be called with lp->indirect_lock being held.  Use
 * this together with spin_lock_irqsave/spin_lock_irqrestore to avoid
 * repeated lock/unlock and to ensure uninterrupted access to indirect
 * registers.
 */
void temac_indirect_out32_locked(struct temac_local *lp, int reg, u32 value)
{}

/*
 * temac_dma_in32_* - Memory mapped DMA read, these function expects a
 * register input that is based on DCR word addresses which are then
 * converted to memory mapped byte addresses.  To be assigned to
 * lp->dma_in32.
 */
static u32 temac_dma_in32_be(struct temac_local *lp, int reg)
{}

static u32 temac_dma_in32_le(struct temac_local *lp, int reg)
{}

/*
 * temac_dma_out32_* - Memory mapped DMA read, these function expects
 * a register input that is based on DCR word addresses which are then
 * converted to memory mapped byte addresses.  To be assigned to
 * lp->dma_out32.
 */
static void temac_dma_out32_be(struct temac_local *lp, int reg, u32 value)
{}

static void temac_dma_out32_le(struct temac_local *lp, int reg, u32 value)
{}

/* DMA register access functions can be DCR based or memory mapped.
 * The PowerPC 440 is DCR based, the PowerPC 405 and MicroBlaze are both
 * memory mapped.
 */
#ifdef CONFIG_PPC_DCR

/*
 * temac_dma_dcr_in32 - DCR based DMA read
 */
static u32 temac_dma_dcr_in(struct temac_local *lp, int reg)
{
	return dcr_read(lp->sdma_dcrs, reg);
}

/*
 * temac_dma_dcr_out32 - DCR based DMA write
 */
static void temac_dma_dcr_out(struct temac_local *lp, int reg, u32 value)
{
	dcr_write(lp->sdma_dcrs, reg, value);
}

/*
 * temac_dcr_setup - If the DMA is DCR based, then setup the address and
 * I/O  functions
 */
static int temac_dcr_setup(struct temac_local *lp, struct platform_device *op,
			   struct device_node *np)
{
	unsigned int dcrs;

	/* setup the dcr address mapping if it's in the device tree */

	dcrs = dcr_resource_start(np, 0);
	if (dcrs != 0) {
		lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0));
		lp->dma_in = temac_dma_dcr_in;
		lp->dma_out = temac_dma_dcr_out;
		dev_dbg(&op->dev, "DCR base: %x\n", dcrs);
		return 0;
	}
	/* no DCR in the device tree, indicate a failure */
	return -1;
}

#else

/*
 * temac_dcr_setup - This is a stub for when DCR is not supported,
 * such as with MicroBlaze and x86
 */
static int temac_dcr_setup(struct temac_local *lp, struct platform_device *op,
			   struct device_node *np)
{}

#endif

/*
 * temac_dma_bd_release - Release buffer descriptor rings
 */
static void temac_dma_bd_release(struct net_device *ndev)
{}

/*
 * temac_dma_bd_init - Setup buffer descriptor rings
 */
static int temac_dma_bd_init(struct net_device *ndev)
{}

/* ---------------------------------------------------------------------
 * net_device_ops
 */

static void temac_do_set_mac_address(struct net_device *ndev)
{}

static int temac_init_mac_address(struct net_device *ndev, const void *address)
{}

static int temac_set_mac_address(struct net_device *ndev, void *p)
{}

static void temac_set_multicast_list(struct net_device *ndev)
{}

static struct temac_option {} temac_options[] =;

/*
 * temac_setoptions
 */
static u32 temac_setoptions(struct net_device *ndev, u32 options)
{}

/* Initialize temac */
static void temac_device_reset(struct net_device *ndev)
{}

static void temac_adjust_link(struct net_device *ndev)
{}

#ifdef CONFIG_64BIT

static void ptr_to_txbd(void *p, struct cdmac_bd *bd)
{}

static void *ptr_from_txbd(struct cdmac_bd *bd)
{}

#else

static void ptr_to_txbd(void *p, struct cdmac_bd *bd)
{
	bd->app4 = (u32)p;
}

static void *ptr_from_txbd(struct cdmac_bd *bd)
{
	return (void *)(bd->app4);
}

#endif

static void temac_start_xmit_done(struct net_device *ndev)
{}

static inline int temac_check_tx_bd_space(struct temac_local *lp, int num_frag)
{}

static netdev_tx_t
temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{}

static int ll_temac_recv_buffers_available(struct temac_local *lp)
{}

static void ll_temac_recv(struct net_device *ndev)
{}

/* Function scheduled to ensure a restart in case of DMA halt
 * condition caused by running out of buffer descriptors.
 */
static void ll_temac_restart_work_func(struct work_struct *work)
{}

static irqreturn_t ll_temac_tx_irq(int irq, void *_ndev)
{}

static irqreturn_t ll_temac_rx_irq(int irq, void *_ndev)
{}

static int temac_open(struct net_device *ndev)
{}

static int temac_stop(struct net_device *ndev)
{}

#ifdef CONFIG_NET_POLL_CONTROLLER
static void
temac_poll_controller(struct net_device *ndev)
{}
#endif

static const struct net_device_ops temac_netdev_ops =;

/* ---------------------------------------------------------------------
 * SYSFS device attributes
 */
static ssize_t temac_show_llink_regs(struct device *dev,
				     struct device_attribute *attr, char *buf)
{}

static DEVICE_ATTR(llink_regs, 0440, temac_show_llink_regs, NULL);

static struct attribute *temac_device_attrs[] =;

static const struct attribute_group temac_attr_group =;

/* ---------------------------------------------------------------------
 * ethtool support
 */

static void
ll_temac_ethtools_get_ringparam(struct net_device *ndev,
				struct ethtool_ringparam *ering,
				struct kernel_ethtool_ringparam *kernel_ering,
				struct netlink_ext_ack *extack)
{}

static int
ll_temac_ethtools_set_ringparam(struct net_device *ndev,
				struct ethtool_ringparam *ering,
				struct kernel_ethtool_ringparam *kernel_ering,
				struct netlink_ext_ack *extack)
{}

static int
ll_temac_ethtools_get_coalesce(struct net_device *ndev,
			       struct ethtool_coalesce *ec,
			       struct kernel_ethtool_coalesce *kernel_coal,
			       struct netlink_ext_ack *extack)
{}

static int
ll_temac_ethtools_set_coalesce(struct net_device *ndev,
			       struct ethtool_coalesce *ec,
			       struct kernel_ethtool_coalesce *kernel_coal,
			       struct netlink_ext_ack *extack)
{}

static const struct ethtool_ops temac_ethtool_ops =;

static int temac_probe(struct platform_device *pdev)
{}

static void temac_remove(struct platform_device *pdev)
{}

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

static struct platform_driver temac_driver =;

module_platform_driver();

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