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