linux/drivers/net/ethernet/cirrus/cs89x0.c

/* cs89x0.c: A Crystal Semiconductor (Now Cirrus Logic) CS89[02]0
 *           driver for linux.
 * Written 1996 by Russell Nelson, with reference to skeleton.c
 * written 1993-1994 by Donald Becker.
 *
 * This software may be used and distributed according to the terms
 * of the GNU General Public License, incorporated herein by reference.
 *
 * The author may be reached at [email protected], Crynwr
 * Software, 521 Pleasant Valley Rd., Potsdam, NY 13676
 *
 * Other contributors:
 * Mike Cruse        : [email protected]
 * Russ Nelson
 * Melody Lee        : [email protected]
 * Alan Cox
 * Andrew Morton
 * Oskar Schirmer    : [email protected]
 * Deepak Saxena     : [email protected]
 * Dmitry Pervushin  : [email protected]
 * Deepak Saxena     : [email protected]
 * Domenico Andreoli : [email protected]
 */


/*
 * Set this to zero to disable DMA code
 *
 * Note that even if DMA is turned off we still support the 'dma' and  'use_dma'
 * module options so we don't break any startup scripts.
 */
#ifndef CONFIG_ISA_DMA_API
#define ALLOW_DMA
#else
#define ALLOW_DMA
#endif

/*
 * Set this to zero to remove all the debug statements via
 * dead code elimination
 */
#define DEBUGGING

/* Sources:
 *	Crynwr packet driver epktisa.
 *	Crystal Semiconductor data sheets.
 */

#define pr_fmt(fmt)

#include <linux/module.h>
#include <linux/printk.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/jiffies.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/gfp.h>
#include <linux/io.h>

#include <net/Space.h>

#include <asm/irq.h>
#include <linux/atomic.h>
#if ALLOW_DMA
#include <asm/dma.h>
#endif

#include "cs89x0.h"

#define cs89_dbg(val, level, fmt, ...)

static char version[] __initdata =;

#define DRV_NAME

/* First, a few definitions that the brave might change.
 * A zero-terminated list of I/O addresses to be probed. Some special flags..
 * Addr & 1 = Read back the address port, look for signature and reset
 * the page window before probing
 * Addr & 3 = Reset the page window and probe
 * The CLPS eval board has the Cirrus chip at 0x80090300, in ARM IO space,
 * but it is possible that a Cirrus board could be plugged into the ISA
 * slots.
 */
/* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps
 * them to system IRQ numbers. This mapping is card specific and is set to
 * the configuration of the Cirrus Eval board for this chip.
 */
#if IS_ENABLED(CONFIG_CS89x0_ISA)
static unsigned int netcard_portlist[] __used __initdata = {
	0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240,
	0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0
};
static unsigned int cs8900_irq_map[] = {
	10, 11, 12, 5
};
#endif

#if DEBUGGING
static unsigned int net_debug =;
#else
#define net_debug
#endif

/* The number of low I/O ports used by the ethercard. */
#define NETCARD_IO_EXTENT

/* we allow the user to override various values normally set in the EEPROM */
#define FORCE_RJ45
#define FORCE_AUI
#define FORCE_BNC

#define FORCE_AUTO
#define FORCE_HALF
#define FORCE_FULL

/* Information that need to be kept for each board. */
struct net_local {};

/* Example routines you must write ;->. */
#define tx_done(dev)

/*
 * Permit 'cs89x0_dma=N' in the kernel boot environment
 */
#if !defined(MODULE)
#if ALLOW_DMA
static int g_cs89x0_dma;

static int __init dma_fn(char *str)
{}

__setup();
#endif	/* ALLOW_DMA */

static int g_cs89x0_media__force;

static int __init media_fn(char *str)
{}

__setup();
#endif

static void readwords(struct net_local *lp, int portno, void *buf, int length)
{}

static void writewords(struct net_local *lp, int portno, void *buf, int length)
{}

static u16
readreg(struct net_device *dev, u16 regno)
{}

static void
writereg(struct net_device *dev, u16 regno, u16 value)
{}

static int __init
wait_eeprom_ready(struct net_device *dev)
{}

static int __init
get_eeprom_data(struct net_device *dev, int off, int len, int *buffer)
{}

static int  __init
get_eeprom_cksum(int off, int len, int *buffer)
{}

static void
write_irq(struct net_device *dev, int chip_type, int irq)
{}

static void
count_rx_errors(int status, struct net_device *dev)
{}

/*********************************
 * This page contains DMA routines
 *********************************/

#if ALLOW_DMA

#define dma_page_eq(ptr1, ptr2)

static void
get_dma_channel(struct net_device *dev)
{}

static void
write_dma(struct net_device *dev, int chip_type, int dma)
{}

static void
set_dma_cfg(struct net_device *dev)
{}

static int
dma_bufcfg(struct net_device *dev)
{}

static int
dma_busctl(struct net_device *dev)
{}

static void
dma_rx(struct net_device *dev)
{}

static void release_dma_buff(struct net_local *lp)
{}

#endif	/* ALLOW_DMA */

static void
control_dc_dc(struct net_device *dev, int on_not_off)
{}

/* send a test packet - return true if carrier bits are ok */
static int
send_test_pkt(struct net_device *dev)
{}

#define DETECTED_NONE
#define DETECTED_RJ45H
#define DETECTED_RJ45F
#define DETECTED_AUI
#define DETECTED_BNC

static int
detect_tp(struct net_device *dev)
{}

static int
detect_bnc(struct net_device *dev)
{}

static int
detect_aui(struct net_device *dev)
{}

/* We have a good packet(s), get it/them out of the buffers. */
static void
net_rx(struct net_device *dev)
{}

/* The typical workload of the driver:
 * Handle the network interface interrupts.
 */

static irqreturn_t net_interrupt(int irq, void *dev_id)
{}

/* Open/initialize the board.  This is called (in the current kernel)
   sometime after booting when the 'ifconfig' program is run.

   This routine should set everything up anew at each open, even
   registers that "should" only need to be set once at boot, so that
   there is non-reboot way to recover if something goes wrong.
*/

/* AKPM: do we need to do any locking here? */

static int
net_open(struct net_device *dev)
{}

/* The inverse routine to net_open(). */
static int
net_close(struct net_device *dev)
{}

/* Get the current statistics.
 * This may be called with the card open or closed.
 */
static struct net_device_stats *
net_get_stats(struct net_device *dev)
{}

static void net_timeout(struct net_device *dev, unsigned int txqueue)
{}

static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev)
{}

static void set_multicast_list(struct net_device *dev)
{}

static int set_mac_address(struct net_device *dev, void *p)
{}

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

static const struct net_device_ops net_ops =;

static void __init reset_chip(struct net_device *dev)
{}

/* This is the real probe routine.
 * Linux has a history of friendly device probes on the ISA bus.
 * A good device probes avoids doing writes, and
 * verifies that the correct device exists and functions.
 * Return 0 on success.
 */
static int __init
cs89x0_probe1(struct net_device *dev, void __iomem *ioaddr, int modular)
{}

#if IS_ENABLED(CONFIG_CS89x0_ISA)
/*
 * This function converts the I/O port address used by the cs89x0_probe() and
 * init_module() functions to the I/O memory address used by the
 * cs89x0_probe1() function.
 */
static int __init
cs89x0_ioport_probe(struct net_device *dev, unsigned long ioport, int modular)
{
	struct net_local *lp = netdev_priv(dev);
	int ret;
	void __iomem *io_mem;

	if (!lp)
		return -ENOMEM;

	dev->base_addr = ioport;

	if (!request_region(ioport, NETCARD_IO_EXTENT, DRV_NAME)) {
		ret = -EBUSY;
		goto out;
	}

	io_mem = ioport_map(ioport & ~3, NETCARD_IO_EXTENT);
	if (!io_mem) {
		ret = -ENOMEM;
		goto release;
	}

	/* if they give us an odd I/O address, then do ONE write to
	 * the address port, to get it back to address zero, where we
	 * expect to find the EISA signature word. An IO with a base of 0x3
	 * will skip the test for the ADD_PORT.
	 */
	if (ioport & 1) {
		cs89_dbg(1, info, "%s: odd ioaddr 0x%lx\n", dev->name, ioport);
		if ((ioport & 2) != 2) {
			if ((ioread16(io_mem + ADD_PORT) & ADD_MASK) !=
			    ADD_SIG) {
				pr_err("%s: bad signature 0x%x\n",
				       dev->name, ioread16(io_mem + ADD_PORT));
				ret = -ENODEV;
				goto unmap;
			}
		}
	}

	ret = cs89x0_probe1(dev, io_mem, modular);
	if (!ret)
		goto out;
unmap:
	ioport_unmap(io_mem);
release:
	release_region(ioport, NETCARD_IO_EXTENT);
out:
	return ret;
}

#ifndef MODULE
/* Check for a network adaptor of this type, and return '0' iff one exists.
 * If dev->base_addr == 0, probe all likely locations.
 * If dev->base_addr == 1, always return failure.
 * If dev->base_addr == 2, allocate space for the device and return success
 * (detachable devices only).
 * Return 0 on success.
 */

struct net_device * __init cs89x0_probe(int unit)
{
	struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
	unsigned *port;
	int err = 0;
	int irq;
	int io;

	if (!dev)
		return ERR_PTR(-ENODEV);

	sprintf(dev->name, "eth%d", unit);
	netdev_boot_setup_check(dev);
	io = dev->base_addr;
	irq = dev->irq;

	cs89_dbg(0, info, "cs89x0_probe(0x%x)\n", io);

	if (io > 0x1ff)	{	/* Check a single specified location. */
		err = cs89x0_ioport_probe(dev, io, 0);
	} else if (io != 0) {	/* Don't probe at all. */
		err = -ENXIO;
	} else {
		for (port = netcard_portlist; *port; port++) {
			if (cs89x0_ioport_probe(dev, *port, 0) == 0)
				break;
			dev->irq = irq;
		}
		if (!*port)
			err = -ENODEV;
	}
	if (err)
		goto out;
	return dev;
out:
	free_netdev(dev);
	pr_warn("no cs8900 or cs8920 detected.  Be sure to disable PnP with SETUP\n");
	return ERR_PTR(err);
}
#else
static struct net_device *dev_cs89x0;

/* Support the 'debug' module parm even if we're compiled for non-debug to
 * avoid breaking someone's startup scripts
 */

static int io;
static int irq;
static int debug;
static char media[8];
static int duplex = -1;

static int use_dma;			/* These generate unused var warnings if ALLOW_DMA = 0 */
static int dma;
static int dmasize = 16;		/* or 64 */

module_param_hw(io, int, ioport, 0);
module_param_hw(irq, int, irq, 0);
module_param(debug, int, 0);
module_param_string(media, media, sizeof(media), 0);
module_param(duplex, int, 0);
module_param_hw(dma , int, dma, 0);
module_param(dmasize , int, 0);
module_param(use_dma , int, 0);
MODULE_PARM_DESC(io, "cs89x0 I/O base address");
MODULE_PARM_DESC(irq, "cs89x0 IRQ number");
#if DEBUGGING
MODULE_PARM_DESC(debug, "cs89x0 debug level (0-6)");
#else
MODULE_PARM_DESC(debug, "(ignored)");
#endif
MODULE_PARM_DESC(media, "Set cs89x0 adapter(s) media type(s) (rj45,bnc,aui)");
/* No other value than -1 for duplex seems to be currently interpreted */
MODULE_PARM_DESC(duplex, "(ignored)");
#if ALLOW_DMA
MODULE_PARM_DESC(dma , "cs89x0 ISA DMA channel; ignored if use_dma=0");
MODULE_PARM_DESC(dmasize , "cs89x0 DMA size in kB (16,64); ignored if use_dma=0");
MODULE_PARM_DESC(use_dma , "cs89x0 using DMA (0-1)");
#else
MODULE_PARM_DESC(dma , "(ignored)");
MODULE_PARM_DESC(dmasize , "(ignored)");
MODULE_PARM_DESC(use_dma , "(ignored)");
#endif

MODULE_AUTHOR("Mike Cruse, Russwll Nelson <[email protected]>, Andrew Morton");
MODULE_LICENSE("GPL");

/*
 * media=t             - specify media type
 * or media=2
 * or media=aui
 * or medai=auto
 * duplex=0            - specify forced half/full/autonegotiate duplex
 * debug=#             - debug level
 *
 * Default Chip Configuration:
 * DMA Burst = enabled
 * IOCHRDY Enabled = enabled
 * UseSA = enabled
 * CS8900 defaults to half-duplex if not specified on command-line
 * CS8920 defaults to autoneg if not specified on command-line
 * Use reset defaults for other config parameters
 *
 * Assumptions:
 * media type specified is supported (circuitry is present)
 * if memory address is > 1MB, then required mem decode hw is present
 * if 10B-2, then agent other than driver will enable DC/DC converter
 * (hw or software util)
 */

static int __init cs89x0_isa_init_module(void)
{
	struct net_device *dev;
	struct net_local *lp;
	int ret = 0;

#if DEBUGGING
	net_debug = debug;
#else
	debug = 0;
#endif
	dev = alloc_etherdev(sizeof(struct net_local));
	if (!dev)
		return -ENOMEM;

	dev->irq = irq;
	dev->base_addr = io;
	lp = netdev_priv(dev);

#if ALLOW_DMA
	if (use_dma) {
		lp->use_dma = use_dma;
		lp->dma = dma;
		lp->dmasize = dmasize;
	}
#endif

	spin_lock_init(&lp->lock);

	/* boy, they'd better get these right */
	if (!strcmp(media, "rj45"))
		lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T;
	else if (!strcmp(media, "aui"))
		lp->adapter_cnf = A_CNF_MEDIA_AUI   | A_CNF_AUI;
	else if (!strcmp(media, "bnc"))
		lp->adapter_cnf = A_CNF_MEDIA_10B_2 | A_CNF_10B_2;
	else
		lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T;

	if (duplex == -1)
		lp->auto_neg_cnf = AUTO_NEG_ENABLE;

	if (io == 0) {
		pr_err("Module autoprobing not allowed\n");
		pr_err("Append io=0xNNN\n");
		ret = -EPERM;
		goto out;
	} else if (io <= 0x1ff) {
		ret = -ENXIO;
		goto out;
	}

#if ALLOW_DMA
	if (use_dma && dmasize != 16 && dmasize != 64) {
		pr_err("dma size must be either 16K or 64K, not %dK\n",
		       dmasize);
		ret = -EPERM;
		goto out;
	}
#endif
	ret = cs89x0_ioport_probe(dev, io, 1);
	if (ret)
		goto out;

	dev_cs89x0 = dev;
	return 0;
out:
	free_netdev(dev);
	return ret;
}
module_init(cs89x0_isa_init_module);

static void __exit cs89x0_isa_cleanup_module(void)
{
	struct net_local *lp = netdev_priv(dev_cs89x0);

	unregister_netdev(dev_cs89x0);
	iowrite16(PP_ChipID, lp->virt_addr + ADD_PORT);
	ioport_unmap(lp->virt_addr);
	release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT);
	free_netdev(dev_cs89x0);
}
module_exit(cs89x0_isa_cleanup_module);
#endif /* MODULE */
#endif /* CONFIG_CS89x0_ISA */

#if IS_ENABLED(CONFIG_CS89x0_PLATFORM)
static int __init cs89x0_platform_probe(struct platform_device *pdev)
{}

static void cs89x0_platform_remove(struct platform_device *pdev)
{}

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

static struct platform_driver cs89x0_driver =;

module_platform_driver_probe();

#endif /* CONFIG_CS89x0_PLATFORM */

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