linux/drivers/net/ethernet/smsc/smc91x.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * smc91x.c
 * This is a driver for SMSC's 91C9x/91C1xx single-chip Ethernet devices.
 *
 * Copyright (C) 1996 by Erik Stahlman
 * Copyright (C) 2001 Standard Microsystems Corporation
 *	Developed by Simple Network Magic Corporation
 * Copyright (C) 2003 Monta Vista Software, Inc.
 *	Unified SMC91x driver by Nicolas Pitre
 *
 * Arguments:
 * 	io	= for the base address
 *	irq	= for the IRQ
 *	nowait	= 0 for normal wait states, 1 eliminates additional wait states
 *
 * original author:
 * 	Erik Stahlman <[email protected]>
 *
 * hardware multicast code:
 *    Peter Cammaert <[email protected]>
 *
 * contributors:
 * 	Daris A Nevil <[email protected]>
 *      Nicolas Pitre <[email protected]>
 *	Russell King <[email protected]>
 *
 * History:
 *   08/20/00  Arnaldo Melo       fix kfree(skb) in smc_hardware_send_packet
 *   12/15/00  Christian Jullien  fix "Warning: kfree_skb on hard IRQ"
 *   03/16/01  Daris A Nevil      modified smc9194.c for use with LAN91C111
 *   08/22/01  Scott Anderson     merge changes from smc9194 to smc91111
 *   08/21/01  Pramod B Bhardwaj  added support for RevB of LAN91C111
 *   12/20/01  Jeff Sutherland    initial port to Xscale PXA with DMA support
 *   04/07/03  Nicolas Pitre      unified SMC91x driver, killed irq races,
 *                                more bus abstraction, big cleanup, etc.
 *   29/09/03  Russell King       - add driver model support
 *                                - ethtool support
 *                                - convert to use generic MII interface
 *                                - add link up/down notification
 *                                - don't try to handle full negotiation in
 *                                  smc_phy_configure
 *                                - clean up (and fix stack overrun) in PHY
 *                                  MII read/write functions
 *   22/09/04  Nicolas Pitre      big update (see commit log for details)
 */
static const char version[] =;

/* Debugging level */
#ifndef SMC_DEBUG
#define SMC_DEBUG
#endif


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/crc32.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/workqueue.h>
#include <linux/of.h>
#include <linux/of_device.h>

#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>

#include <asm/io.h>

#include "smc91x.h"

#if defined(CONFIG_ASSABET_NEPONSET)
#include <mach/assabet.h>
#include <mach/neponset.h>
#endif

#ifndef SMC_NOWAIT
#define SMC_NOWAIT
#endif
static int nowait =;
module_param(nowait, int, 0400);
MODULE_PARM_DESC();

/*
 * Transmit timeout, default 5 seconds.
 */
static int watchdog =;
module_param(watchdog, int, 0400);
MODULE_PARM_DESC();

MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_ALIAS();

/*
 * The internal workings of the driver.  If you are changing anything
 * here with the SMC stuff, you should have the datasheet and know
 * what you are doing.
 */
#define CARDNAME

/*
 * Use power-down feature of the chip
 */
#define POWER_DOWN

/*
 * Wait time for memory to be free.  This probably shouldn't be
 * tuned that much, as waiting for this means nothing else happens
 * in the system
 */
#define MEMORY_WAIT_TIME

/*
 * The maximum number of processing loops allowed for each call to the
 * IRQ handler.
 */
#define MAX_IRQ_LOOPS

/*
 * This selects whether TX packets are sent one by one to the SMC91x internal
 * memory and throttled until transmission completes.  This may prevent
 * RX overruns a litle by keeping much of the memory free for RX packets
 * but to the expense of reduced TX throughput and increased IRQ overhead.
 * Note this is not a cure for a too slow data bus or too high IRQ latency.
 */
#define THROTTLE_TX_PKTS

/*
 * The MII clock high/low times.  2x this number gives the MII clock period
 * in microseconds. (was 50, but this gives 6.4ms for each MII transaction!)
 */
#define MII_DELAY

#define DBG(n, dev, fmt, ...)

#define PRINTK(dev, fmt, ...)

#if SMC_DEBUG > 3
static void PRINT_PKT(u_char *buf, int length)
{
	int i;
	int remainder;
	int lines;

	lines = length / 16;
	remainder = length % 16;

	for (i = 0; i < lines ; i ++) {
		int cur;
		printk(KERN_DEBUG);
		for (cur = 0; cur < 8; cur++) {
			u_char a, b;
			a = *buf++;
			b = *buf++;
			pr_cont("%02x%02x ", a, b);
		}
		pr_cont("\n");
	}
	printk(KERN_DEBUG);
	for (i = 0; i < remainder/2 ; i++) {
		u_char a, b;
		a = *buf++;
		b = *buf++;
		pr_cont("%02x%02x ", a, b);
	}
	pr_cont("\n");
}
#else
static inline void PRINT_PKT(u_char *buf, int length) {}
#endif


/* this enables an interrupt in the interrupt mask register */
#define SMC_ENABLE_INT(lp, x)

/* this disables an interrupt from the interrupt mask register */
#define SMC_DISABLE_INT(lp, x)

/*
 * Wait while MMU is busy.  This is usually in the order of a few nanosecs
 * if at all, but let's avoid deadlocking the system if the hardware
 * decides to go south.
 */
#define SMC_WAIT_MMU_BUSY(lp)


/*
 * this does a soft reset on the device
 */
static void smc_reset(struct net_device *dev)
{}

/*
 * Enable Interrupts, Receive, and Transmit
 */
static void smc_enable(struct net_device *dev)
{}

/*
 * this puts the device in an inactive state
 */
static void smc_shutdown(struct net_device *dev)
{}

/*
 * This is the procedure to handle the receipt of a packet.
 */
static inline void  smc_rcv(struct net_device *dev)
{}

#ifdef CONFIG_SMP
/*
 * On SMP we have the following problem:
 *
 * 	A = smc_hardware_send_pkt()
 * 	B = smc_hard_start_xmit()
 * 	C = smc_interrupt()
 *
 * A and B can never be executed simultaneously.  However, at least on UP,
 * it is possible (and even desirable) for C to interrupt execution of
 * A or B in order to have better RX reliability and avoid overruns.
 * C, just like A and B, must have exclusive access to the chip and
 * each of them must lock against any other concurrent access.
 * Unfortunately this is not possible to have C suspend execution of A or
 * B taking place on another CPU. On UP this is no an issue since A and B
 * are run from softirq context and C from hard IRQ context, and there is
 * no other CPU where concurrent access can happen.
 * If ever there is a way to force at least B and C to always be executed
 * on the same CPU then we could use read/write locks to protect against
 * any other concurrent access and C would always interrupt B. But life
 * isn't that easy in a SMP world...
 */
#define smc_special_trylock(lock, flags)
#define smc_special_lock(lock, flags)
#define smc_special_unlock(lock, flags)
#else
#define smc_special_trylock
#define smc_special_lock
#define smc_special_unlock
#endif

/*
 * This is called to actually send a packet to the chip.
 */
static void smc_hardware_send_pkt(struct tasklet_struct *t)
{}

/*
 * Since I am not sure if I will have enough room in the chip's ram
 * to store the packet, I call this routine which either sends it
 * now, or set the card to generates an interrupt when ready
 * for the packet.
 */
static netdev_tx_t
smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{}

/*
 * This handles a TX interrupt, which is only called when:
 * - a TX error occurred, or
 * - CTL_AUTO_RELEASE is not set and TX of a packet completed.
 */
static void smc_tx(struct net_device *dev)
{}


/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/

static void smc_mii_out(struct net_device *dev, unsigned int val, int bits)
{}

static unsigned int smc_mii_in(struct net_device *dev, int bits)
{}

/*
 * Reads a register from the MII Management serial interface
 */
static int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg)
{}

/*
 * Writes a register to the MII Management serial interface
 */
static void smc_phy_write(struct net_device *dev, int phyaddr, int phyreg,
			  int phydata)
{}

/*
 * Finds and reports the PHY address
 */
static void smc_phy_detect(struct net_device *dev)
{}

/*
 * Sets the PHY to a configuration as determined by the user
 */
static int smc_phy_fixed(struct net_device *dev)
{}

/**
 * smc_phy_reset - reset the phy
 * @dev: net device
 * @phy: phy address
 *
 * Issue a software reset for the specified PHY and
 * wait up to 100ms for the reset to complete.  We should
 * not access the PHY for 50ms after issuing the reset.
 *
 * The time to wait appears to be dependent on the PHY.
 *
 * Must be called with lp->lock locked.
 */
static int smc_phy_reset(struct net_device *dev, int phy)
{}

/**
 * smc_phy_powerdown - powerdown phy
 * @dev: net device
 *
 * Power down the specified PHY
 */
static void smc_phy_powerdown(struct net_device *dev)
{}

/**
 * smc_phy_check_media - check the media status and adjust TCR
 * @dev: net device
 * @init: set true for initialisation
 *
 * Select duplex mode depending on negotiation state.  This
 * also updates our carrier state.
 */
static void smc_phy_check_media(struct net_device *dev, int init)
{}

/*
 * Configures the specified PHY through the MII management interface
 * using Autonegotiation.
 * Calls smc_phy_fixed() if the user has requested a certain config.
 * If RPC ANEG bit is set, the media selection is dependent purely on
 * the selection by the MII (either in the MII BMCR reg or the result
 * of autonegotiation.)  If the RPC ANEG bit is cleared, the selection
 * is controlled by the RPC SPEED and RPC DPLX bits.
 */
static void smc_phy_configure(struct work_struct *work)
{}

/*
 * smc_phy_interrupt
 *
 * Purpose:  Handle interrupts relating to PHY register 18. This is
 *  called from the "hard" interrupt handler under our private spinlock.
 */
static void smc_phy_interrupt(struct net_device *dev)
{}

/*--- END PHY CONTROL AND CONFIGURATION-------------------------------------*/

static void smc_10bt_check_media(struct net_device *dev, int init)
{}

static void smc_eph_interrupt(struct net_device *dev)
{}

/*
 * This is the main routine of the driver, to handle the device when
 * it needs some attention.
 */
static irqreturn_t smc_interrupt(int irq, void *dev_id)
{}

#ifdef CONFIG_NET_POLL_CONTROLLER
/*
 * Polling receive - used by netconsole and other diagnostic tools
 * to allow network i/o with interrupts disabled.
 */
static void smc_poll_controller(struct net_device *dev)
{}
#endif

/* Our watchdog timed out. Called by the networking layer */
static void smc_timeout(struct net_device *dev, unsigned int txqueue)
{}

/*
 * This routine will, depending on the values passed to it,
 * either make it accept multicast packets, go into
 * promiscuous mode (for TCPDUMP and cousins) or accept
 * a select set of multicast packets
 */
static void smc_set_multicast_list(struct net_device *dev)
{}


/*
 * Open and Initialize the board
 *
 * Set up everything, reset the card, etc..
 */
static int
smc_open(struct net_device *dev)
{}

/*
 * smc_close
 *
 * this makes the board clean up everything that it can
 * and not talk to the outside world.   Caused by
 * an 'ifconfig ethX down'
 */
static int smc_close(struct net_device *dev)
{}

/*
 * Ethtool support
 */
static int
smc_ethtool_get_link_ksettings(struct net_device *dev,
			       struct ethtool_link_ksettings *cmd)
{}

static int
smc_ethtool_set_link_ksettings(struct net_device *dev,
			       const struct ethtool_link_ksettings *cmd)
{}

static void
smc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{}

static int smc_ethtool_nwayreset(struct net_device *dev)
{}

static u32 smc_ethtool_getmsglevel(struct net_device *dev)
{}

static void smc_ethtool_setmsglevel(struct net_device *dev, u32 level)
{}

static int smc_write_eeprom_word(struct net_device *dev, u16 addr, u16 word)
{}

static int smc_read_eeprom_word(struct net_device *dev, u16 addr, u16 *word)
{}

static int smc_ethtool_geteeprom_len(struct net_device *dev)
{}

static int smc_ethtool_geteeprom(struct net_device *dev,
		struct ethtool_eeprom *eeprom, u8 *data)
{}

static int smc_ethtool_seteeprom(struct net_device *dev,
		struct ethtool_eeprom *eeprom, u8 *data)
{}


static const struct ethtool_ops smc_ethtool_ops =;

static const struct net_device_ops smc_netdev_ops =;

/*
 * smc_findirq
 *
 * This routine has a simple purpose -- make the SMC chip generate an
 * interrupt, so an auto-detect routine can detect it, and find the IRQ,
 */
/*
 * does this still work?
 *
 * I just deleted auto_irq.c, since it was never built...
 *   --jgarzik
 */
static int smc_findirq(struct smc_local *lp)
{}

/*
 * Function: smc_probe(unsigned long ioaddr)
 *
 * Purpose:
 *	Tests to see if a given ioaddr points to an SMC91x chip.
 *	Returns a 0 on success
 *
 * Algorithm:
 *	(1) see if the high byte of BANK_SELECT is 0x33
 * 	(2) compare the ioaddr with the base register's address
 *	(3) see if I recognize the chip ID in the appropriate register
 *
 * Here I do typical initialization tasks.
 *
 * o  Initialize the structure if needed
 * o  print out my vanity message if not done so already
 * o  print out what type of hardware is detected
 * o  print out the ethernet address
 * o  find the IRQ
 * o  set up my private data
 * o  configure the dev structure with my subroutines
 * o  actually GRAB the irq.
 * o  GRAB the region
 */
static int smc_probe(struct net_device *dev, void __iomem *ioaddr,
		     unsigned long irq_flags)
{}

static int smc_enable_device(struct platform_device *pdev)
{}

static int smc_request_attrib(struct platform_device *pdev,
			      struct net_device *ndev)
{}

static void smc_release_attrib(struct platform_device *pdev,
			       struct net_device *ndev)
{}

static inline void smc_request_datacs(struct platform_device *pdev, struct net_device *ndev)
{}

static void smc_release_datacs(struct platform_device *pdev, struct net_device *ndev)
{}

static const struct acpi_device_id smc91x_acpi_match[] =;
MODULE_DEVICE_TABLE(acpi, smc91x_acpi_match);

#if IS_BUILTIN(CONFIG_OF)
static const struct of_device_id smc91x_match[] =;
MODULE_DEVICE_TABLE(of, smc91x_match);

/**
 * try_toggle_control_gpio - configure a gpio if it exists
 * @dev: net device
 * @desc: where to store the GPIO descriptor, if it exists
 * @name: name of the GPIO in DT
 * @index: index of the GPIO in DT
 * @value: set the GPIO to this value
 * @nsdelay: delay before setting the GPIO
 */
static int try_toggle_control_gpio(struct device *dev,
				   struct gpio_desc **desc,
				   const char *name, int index,
				   int value, unsigned int nsdelay)
{}
#endif

/*
 * smc_init(void)
 *   Input parameters:
 *	dev->base_addr == 0, try to find all possible locations
 *	dev->base_addr > 0x1ff, this is the address to check
 *	dev->base_addr == <anything else>, return failure code
 *
 *   Output:
 *	0 --> there is a device
 *	anything else, error
 */
static int smc_drv_probe(struct platform_device *pdev)
{}

static void smc_drv_remove(struct platform_device *pdev)
{}

static int smc_drv_suspend(struct device *dev)
{}

static int smc_drv_resume(struct device *dev)
{}

static const struct dev_pm_ops smc_drv_pm_ops =;

static struct platform_driver smc_driver =;

module_platform_driver();