1
0
Files
kernel-49/drivers/net/ethernet/amd/sun3lance.c
Greg Kroah-Hartman e9f033e359 Merge 4.9.203 into android-4.9-q
Changes in 4.9.203
	ax88172a: fix information leak on short answers
	slip: Fix memory leak in slip_open error path
	ALSA: usb-audio: Fix missing error check at mixer resolution test
	ALSA: usb-audio: not submit urb for stopped endpoint
	Input: ff-memless - kill timer in destroy()
	Input: synaptics-rmi4 - fix video buffer size
	Input: synaptics-rmi4 - clear IRQ enables for F54
	Input: synaptics-rmi4 - destroy F54 poller workqueue when removing
	IB/hfi1: Ensure full Gen3 speed in a Gen4 system
	ecryptfs_lookup_interpose(): lower_dentry->d_inode is not stable
	ecryptfs_lookup_interpose(): lower_dentry->d_parent is not stable either
	iommu/vt-d: Fix QI_DEV_IOTLB_PFSID and QI_DEV_EIOTLB_PFSID macros
	mm: memcg: switch to css_tryget() in get_mem_cgroup_from_mm()
	mm: hugetlb: switch to css_tryget() in hugetlb_cgroup_charge_cgroup()
	mmc: sdhci-of-at91: fix quirk2 overwrite
	ath10k: fix kernel panic by moving pci flush after napi_disable
	iio: dac: mcp4922: fix error handling in mcp4922_write_raw
	ALSA: pcm: signedness bug in snd_pcm_plug_alloc()
	arm64: dts: tegra210-p2180: Correct sdmmc4 vqmmc-supply
	ARM: dts: at91/trivial: Fix USART1 definition for at91sam9g45
	cfg80211: Avoid regulatory restore when COUNTRY_IE_IGNORE is set
	ALSA: seq: Do error checks at creating system ports
	ath9k: fix tx99 with monitor mode interface
	gfs2: Don't set GFS2_RDF_UPTODATE when the lvb is updated
	ASoC: dpcm: Properly initialise hw->rate_max
	MIPS: BCM47XX: Enable USB power on Netgear WNDR3400v3
	ARM: dts: exynos: Fix sound in Snow-rev5 Chromebook
	ARM: dts: exynos: Fix regulators configuration on Peach Pi/Pit Chromebooks
	i40e: use correct length for strncpy
	i40e: hold the rtnl lock on clearing interrupt scheme
	i40e: Prevent deleting MAC address from VF when set by PF
	IB/rxe: fixes for rdma read retry
	iwlwifi: mvm: avoid sending too many BARs
	ARM: dts: pxa: fix power i2c base address
	rtl8187: Fix warning generated when strncpy() destination length matches the sixe argument
	net: lan78xx: Bail out if lan78xx_get_endpoints fails
	ASoC: sgtl5000: avoid division by zero if lo_vag is zero
	ARM: dts: exynos: Disable pull control for S5M8767 PMIC
	ath10k: wmi: disable softirq's while calling ieee80211_rx
	mips: txx9: fix iounmap related issue
	ASoC: Intel: hdac_hdmi: Limit sampling rates at dai creation
	of: make PowerMac cache node search conditional on CONFIG_PPC_PMAC
	ARM: dts: omap3-gta04: give spi_lcd node a label so that we can overwrite in other DTS files
	ARM: dts: omap3-gta04: fixes for tvout / venc
	ARM: dts: omap3-gta04: tvout: enable as display1 alias
	ARM: dts: omap3-gta04: fix touchscreen tsc2007
	ARM: dts: omap3-gta04: make NAND partitions compatible with recent U-Boot
	ARM: dts: omap3-gta04: keep vpll2 always on
	dmaengine: dma-jz4780: Don't depend on MACH_JZ4780
	dmaengine: dma-jz4780: Further residue status fix
	ath9k: add back support for using active monitor interfaces for tx99
	signal: Always ignore SIGKILL and SIGSTOP sent to the global init
	signal: Properly deliver SIGILL from uprobes
	signal: Properly deliver SIGSEGV from x86 uprobes
	f2fs: fix memory leak of percpu counter in fill_super()
	scsi: sym53c8xx: fix NULL pointer dereference panic in sym_int_sir()
	ARM: imx6: register pm_power_off handler if "fsl,pmic-stby-poweroff" is set
	scsi: pm80xx: Corrected dma_unmap_sg() parameter
	scsi: pm80xx: Fixed system hang issue during kexec boot
	kprobes: Don't call BUG_ON() if there is a kprobe in use on free list
	nvmem: core: return error code instead of NULL from nvmem_device_get
	media: fix: media: pci: meye: validate offset to avoid arbitrary access
	media: dvb: fix compat ioctl translation
	ALSA: intel8x0m: Register irq handler after register initializations
	pinctrl: at91-pio4: fix has_config check in atmel_pctl_dt_subnode_to_map()
	llc: avoid blocking in llc_sap_close()
	ARM: dts: qcom: ipq4019: fix cpu0's qcom,saw2 reg value
	powerpc/vdso: Correct call frame information
	ARM: dts: socfpga: Fix I2C bus unit-address error
	pinctrl: at91: don't use the same irqchip with multiple gpiochips
	cxgb4: Fix endianness issue in t4_fwcache()
	power: supply: ab8500_fg: silence uninitialized variable warnings
	power: reset: at91-poweroff: do not procede if at91_shdwc is allocated
	power: supply: max8998-charger: Fix platform data retrieval
	component: fix loop condition to call unbind() if bind() fails
	kernfs: Fix range checks in kernfs_get_target_path
	ip_gre: fix parsing gre header in ipgre_err
	ARM: dts: rockchip: Fix erroneous SPI bus dtc warnings on rk3036
	ath9k: Fix a locking bug in ath9k_add_interface()
	s390/qeth: invoke softirqs after napi_schedule()
	PCI/ACPI: Correct error message for ASPM disabling
	serial: mxs-auart: Fix potential infinite loop
	powerpc/iommu: Avoid derefence before pointer check
	powerpc/64s/hash: Fix stab_rr off by one initialization
	powerpc/pseries: Disable CPU hotplug across migrations
	RDMA/i40iw: Fix incorrect iterator type
	libfdt: Ensure INT_MAX is defined in libfdt_env.h
	power: supply: twl4030_charger: fix charging current out-of-bounds
	power: supply: twl4030_charger: disable eoc interrupt on linear charge
	net: toshiba: fix return type of ndo_start_xmit function
	net: xilinx: fix return type of ndo_start_xmit function
	net: broadcom: fix return type of ndo_start_xmit function
	net: amd: fix return type of ndo_start_xmit function
	usb: chipidea: imx: enable OTG overcurrent in case USB subsystem is already started
	usb: chipidea: Fix otg event handler
	mlxsw: spectrum: Init shaper for TCs 8..15
	ARM: dts: am335x-evm: fix number of cpsw
	f2fs: fix to recover inode's uid/gid during POR
	ARM: dts: ux500: Correct SCU unit address
	ARM: dts: ux500: Fix LCDA clock line muxing
	ARM: dts: ste: Fix SPI controller node names
	spi: pic32: Use proper enum in dmaengine_prep_slave_rg
	cpufeature: avoid warning when compiling with clang
	ARM: dts: marvell: Fix SPI and I2C bus warnings
	bnx2x: Ignore bandwidth attention in single function mode
	net: micrel: fix return type of ndo_start_xmit function
	x86/CPU: Use correct macros for Cyrix calls
	MIPS: kexec: Relax memory restriction
	media: pci: ivtv: Fix a sleep-in-atomic-context bug in ivtv_yuv_init()
	media: au0828: Fix incorrect error messages
	media: davinci: Fix implicit enum conversion warning
	usb: gadget: uvc: configfs: Drop leaked references to config items
	usb: gadget: uvc: configfs: Prevent format changes after linking header
	phy: phy-twl4030-usb: fix denied runtime access
	usb: gadget: uvc: Factor out video USB request queueing
	usb: gadget: uvc: Only halt video streaming endpoint in bulk mode
	coresight: Fix handling of sinks
	coresight: etm4x: Configure EL2 exception level when kernel is running in HYP
	coresight: tmc: Fix byte-address alignment for RRP
	misc: kgdbts: Fix restrict error
	misc: genwqe: should return proper error value.
	vfio/pci: Fix potential memory leak in vfio_msi_cap_len
	vfio/pci: Mask buggy SR-IOV VF INTx support
	scsi: libsas: always unregister the old device if going to discover new
	ARM: dts: tegra30: fix xcvr-setup-use-fuses
	ARM: tegra: apalis_t30: fix mmc1 cmd pull-up
	ARM: dts: paz00: fix wakeup gpio keycode
	net: smsc: fix return type of ndo_start_xmit function
	EDAC: Raise the maximum number of memory controllers
	ARM: dts: realview: Fix SPI controller node names
	Bluetooth: L2CAP: Detect if remote is not able to use the whole MPS
	crypto: s5p-sss: Fix Fix argument list alignment
	crypto: fix a memory leak in rsa-kcs1pad's encryption mode
	scsi: NCR5380: Clear all unissued commands on host reset
	scsi: NCR5380: Use DRIVER_SENSE to indicate valid sense data
	scsi: NCR5380: Check for invalid reselection target
	scsi: NCR5380: Don't clear busy flag when abort fails
	scsi: NCR5380: Don't call dsprintk() following reselection interrupt
	scsi: NCR5380: Handle BUS FREE during reselection
	arm64: dts: amd: Fix SPI bus warnings
	arm64: dts: lg: Fix SPI controller node names
	ARM: dts: lpc32xx: Fix SPI controller node names
	usb: xhci-mtk: fix ISOC error when interval is zero
	fuse: use READ_ONCE on congestion_threshold and max_background
	IB/iser: Fix possible NULL deref at iser_inv_desc()
	memfd: Use radix_tree_deref_slot_protected to avoid the warning.
	slcan: Fix memory leak in error path
	net: cdc_ncm: Signedness bug in cdc_ncm_set_dgram_size()
	x86/atomic: Fix smp_mb__{before,after}_atomic()
	kprobes/x86: Prohibit probing on exception masking instructions
	uprobes/x86: Prohibit probing on MOV SS instruction
	fbdev: Ditch fb_edid_add_monspecs
	block: introduce blk_rq_is_passthrough
	libata: have ata_scsi_rw_xlat() fail invalid passthrough requests
	net: ovs: fix return type of ndo_start_xmit function
	net: xen-netback: fix return type of ndo_start_xmit function
	ARM: dts: omap5: enable OTG role for DWC3 controller
	f2fs: return correct errno in f2fs_gc
	SUNRPC: Fix priority queue fairness
	kvm: arm/arm64: Fix stage2_flush_memslot for 4 level page table
	arm64/numa: Report correct memblock range for the dummy node
	ath10k: fix vdev-start timeout on error
	ata: ahci_brcm: Allow using driver or DSL SoCs
	ath9k: fix reporting calculated new FFT upper max
	usb: gadget: udc: fotg210-udc: Fix a sleep-in-atomic-context bug in fotg210_get_status()
	nl80211: Fix a GET_KEY reply attribute
	dmaengine: ep93xx: Return proper enum in ep93xx_dma_chan_direction
	dmaengine: timb_dma: Use proper enum in td_prep_slave_sg
	mei: samples: fix a signedness bug in amt_host_if_call()
	cxgb4: Use proper enum in cxgb4_dcb_handle_fw_update
	cxgb4: Use proper enum in IEEE_FAUX_SYNC
	powerpc/pseries: Fix DTL buffer registration
	powerpc/pseries: Fix how we iterate over the DTL entries
	mtd: rawnand: sh_flctl: Use proper enum for flctl_dma_fifo0_transfer
	ixgbe: Fix crash with VFs and flow director on interface flap
	IB/mthca: Fix error return code in __mthca_init_one()
	IB/mlx4: Avoid implicit enumerated type conversion
	ACPICA: Never run _REG on system_memory and system_IO
	ata: ep93xx: Use proper enums for directions
	media: pxa_camera: Fix check for pdev->dev.of_node
	ALSA: hda/sigmatel - Disable automute for Elo VuPoint
	KVM: PPC: Book3S PR: Exiting split hack mode needs to fixup both PC and LR
	USB: serial: cypress_m8: fix interrupt-out transfer length
	mtd: physmap_of: Release resources on error
	cpu/SMT: State SMT is disabled even with nosmt and without "=force"
	brcmfmac: reduce timeout for action frame scan
	brcmfmac: fix full timeout waiting for action frame on-channel tx
	clk: samsung: Use clk_hw API for calling clk framework from clk notifiers
	i2c: brcmstb: Allow enabling the driver on DSL SoCs
	NFSv4.x: fix lock recovery during delegation recall
	dmaengine: ioat: fix prototype of ioat_enumerate_channels
	Input: st1232 - set INPUT_PROP_DIRECT property
	Input: silead - try firmware reload after unsuccessful resume
	x86/olpc: Fix build error with CONFIG_MFD_CS5535=m
	crypto: mxs-dcp - Fix SHA null hashes and output length
	crypto: mxs-dcp - Fix AES issues
	ACPI / SBS: Fix rare oops when removing modules
	iwlwifi: mvm: don't send keys when entering D3
	fbdev: sbuslib: use checked version of put_user()
	fbdev: sbuslib: integer overflow in sbusfb_ioctl_helper()
	reset: Fix potential use-after-free in __of_reset_control_get()
	bcache: recal cached_dev_sectors on detach
	s390/kasan: avoid vdso instrumentation
	proc/vmcore: Fix i386 build error of missing copy_oldmem_page_encrypted()
	backlight: lm3639: Unconditionally call led_classdev_unregister
	mfd: ti_am335x_tscadc: Keep ADC interface on if child is wakeup capable
	printk: Give error on attempt to set log buffer length to over 2G
	media: isif: fix a NULL pointer dereference bug
	GFS2: Flush the GFS2 delete workqueue before stopping the kernel threads
	media: cx231xx: fix potential sign-extension overflow on large shift
	x86/kexec: Correct KEXEC_BACKUP_SRC_END off-by-one error
	gpio: syscon: Fix possible NULL ptr usage
	spi: spidev: Fix OF tree warning logic
	ARM: 8802/1: Call syscall_trace_exit even when system call skipped
	orangefs: rate limit the client not running info message
	hwmon: (pwm-fan) Silence error on probe deferral
	hwmon: (ina3221) Fix INA3221_CONFIG_MODE macros
	misc: cxl: Fix possible null pointer dereference
	mac80211: minstrel: fix CCK rate group streams value
	spi: rockchip: initialize dma_slave_config properly
	ARM: dts: omap5: Fix dual-role mode on Super-Speed port
	arm64: uaccess: Ensure PAN is re-enabled after unhandled uaccess fault
	Linux 4.9.203

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
2019-11-27 18:47:50 +03:00

959 lines
26 KiB
C

/* sun3lance.c: Ethernet driver for SUN3 Lance chip */
/*
Sun3 Lance ethernet driver, by Sam Creasey (sammy@users.qual.net).
This driver is a part of the linux kernel, and is thus distributed
under the GNU General Public License.
The values used in LANCE_OBIO and LANCE_IRQ seem to be empirically
true for the correct IRQ and address of the lance registers. They
have not been widely tested, however. What we probably need is a
"proper" way to search for a device in the sun3's prom, but, alas,
linux has no such thing.
This driver is largely based on atarilance.c, by Roman Hodek. Other
sources of inspiration were the NetBSD sun3 am7990 driver, and the
linux sparc lance driver (sunlance.c).
There are more assumptions made throughout this driver, it almost
certainly still needs work, but it does work at least for RARP/BOOTP and
mounting the root NFS filesystem.
*/
static char *version = "sun3lance.c: v1.2 1/12/2001 Sam Creasey (sammy@sammy.net)\n";
#include <linux/module.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
#include <asm/cacheflush.h>
#include <asm/setup.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/dvma.h>
#include <asm/idprom.h>
#include <asm/machines.h>
#ifdef CONFIG_SUN3
#include <asm/sun3mmu.h>
#else
#include <asm/sun3xprom.h>
#endif
/* sun3/60 addr/irq for the lance chip. If your sun is different,
change this. */
#define LANCE_OBIO 0x120000
#define LANCE_IRQ IRQ_AUTO_3
/* Debug level:
* 0 = silent, print only serious errors
* 1 = normal, print error messages
* 2 = debug, print debug infos
* 3 = debug, print even more debug infos (packet data)
*/
#define LANCE_DEBUG 0
#ifdef LANCE_DEBUG
static int lance_debug = LANCE_DEBUG;
#else
static int lance_debug = 1;
#endif
module_param(lance_debug, int, 0);
MODULE_PARM_DESC(lance_debug, "SUN3 Lance debug level (0-3)");
MODULE_LICENSE("GPL");
#define DPRINTK(n,a) \
do { \
if (lance_debug >= n) \
printk a; \
} while( 0 )
/* we're only using 32k of memory, so we use 4 TX
buffers and 16 RX buffers. These values are expressed as log2. */
#define TX_LOG_RING_SIZE 3
#define RX_LOG_RING_SIZE 5
/* These are the derived values */
#define TX_RING_SIZE (1 << TX_LOG_RING_SIZE)
#define TX_RING_LEN_BITS (TX_LOG_RING_SIZE << 5)
#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
#define RX_RING_SIZE (1 << RX_LOG_RING_SIZE)
#define RX_RING_LEN_BITS (RX_LOG_RING_SIZE << 5)
#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
/* Definitions for packet buffer access: */
#define PKT_BUF_SZ 1544
/* Get the address of a packet buffer corresponding to a given buffer head */
#define PKTBUF_ADDR(head) (void *)((unsigned long)(MEM) | (head)->base)
/* The LANCE Rx and Tx ring descriptors. */
struct lance_rx_head {
unsigned short base; /* Low word of base addr */
volatile unsigned char flag;
unsigned char base_hi; /* High word of base addr (unused) */
short buf_length; /* This length is 2s complement! */
volatile short msg_length; /* This length is "normal". */
};
struct lance_tx_head {
unsigned short base; /* Low word of base addr */
volatile unsigned char flag;
unsigned char base_hi; /* High word of base addr (unused) */
short length; /* Length is 2s complement! */
volatile short misc;
};
/* The LANCE initialization block, described in databook. */
struct lance_init_block {
unsigned short mode; /* Pre-set mode */
unsigned char hwaddr[6]; /* Physical ethernet address */
unsigned int filter[2]; /* Multicast filter (unused). */
/* Receive and transmit ring base, along with length bits. */
unsigned short rdra;
unsigned short rlen;
unsigned short tdra;
unsigned short tlen;
unsigned short pad[4]; /* is thie needed? */
};
/* The whole layout of the Lance shared memory */
struct lance_memory {
struct lance_init_block init;
struct lance_tx_head tx_head[TX_RING_SIZE];
struct lance_rx_head rx_head[RX_RING_SIZE];
char rx_data[RX_RING_SIZE][PKT_BUF_SZ];
char tx_data[TX_RING_SIZE][PKT_BUF_SZ];
};
/* The driver's private device structure */
struct lance_private {
volatile unsigned short *iobase;
struct lance_memory *mem;
int new_rx, new_tx; /* The next free ring entry */
int old_tx, old_rx; /* ring entry to be processed */
/* These two must be longs for set_bit() */
long tx_full;
long lock;
};
/* I/O register access macros */
#define MEM lp->mem
#define DREG lp->iobase[0]
#define AREG lp->iobase[1]
#define REGA(a) (*( AREG = (a), &DREG ))
/* Definitions for the Lance */
/* tx_head flags */
#define TMD1_ENP 0x01 /* end of packet */
#define TMD1_STP 0x02 /* start of packet */
#define TMD1_DEF 0x04 /* deferred */
#define TMD1_ONE 0x08 /* one retry needed */
#define TMD1_MORE 0x10 /* more than one retry needed */
#define TMD1_ERR 0x40 /* error summary */
#define TMD1_OWN 0x80 /* ownership (set: chip owns) */
#define TMD1_OWN_CHIP TMD1_OWN
#define TMD1_OWN_HOST 0
/* tx_head misc field */
#define TMD3_TDR 0x03FF /* Time Domain Reflectometry counter */
#define TMD3_RTRY 0x0400 /* failed after 16 retries */
#define TMD3_LCAR 0x0800 /* carrier lost */
#define TMD3_LCOL 0x1000 /* late collision */
#define TMD3_UFLO 0x4000 /* underflow (late memory) */
#define TMD3_BUFF 0x8000 /* buffering error (no ENP) */
/* rx_head flags */
#define RMD1_ENP 0x01 /* end of packet */
#define RMD1_STP 0x02 /* start of packet */
#define RMD1_BUFF 0x04 /* buffer error */
#define RMD1_CRC 0x08 /* CRC error */
#define RMD1_OFLO 0x10 /* overflow */
#define RMD1_FRAM 0x20 /* framing error */
#define RMD1_ERR 0x40 /* error summary */
#define RMD1_OWN 0x80 /* ownership (set: ship owns) */
#define RMD1_OWN_CHIP RMD1_OWN
#define RMD1_OWN_HOST 0
/* register names */
#define CSR0 0 /* mode/status */
#define CSR1 1 /* init block addr (low) */
#define CSR2 2 /* init block addr (high) */
#define CSR3 3 /* misc */
#define CSR8 8 /* address filter */
#define CSR15 15 /* promiscuous mode */
/* CSR0 */
/* (R=readable, W=writeable, S=set on write, C=clear on write) */
#define CSR0_INIT 0x0001 /* initialize (RS) */
#define CSR0_STRT 0x0002 /* start (RS) */
#define CSR0_STOP 0x0004 /* stop (RS) */
#define CSR0_TDMD 0x0008 /* transmit demand (RS) */
#define CSR0_TXON 0x0010 /* transmitter on (R) */
#define CSR0_RXON 0x0020 /* receiver on (R) */
#define CSR0_INEA 0x0040 /* interrupt enable (RW) */
#define CSR0_INTR 0x0080 /* interrupt active (R) */
#define CSR0_IDON 0x0100 /* initialization done (RC) */
#define CSR0_TINT 0x0200 /* transmitter interrupt (RC) */
#define CSR0_RINT 0x0400 /* receiver interrupt (RC) */
#define CSR0_MERR 0x0800 /* memory error (RC) */
#define CSR0_MISS 0x1000 /* missed frame (RC) */
#define CSR0_CERR 0x2000 /* carrier error (no heartbeat :-) (RC) */
#define CSR0_BABL 0x4000 /* babble: tx-ed too many bits (RC) */
#define CSR0_ERR 0x8000 /* error (RC) */
/* CSR3 */
#define CSR3_BCON 0x0001 /* byte control */
#define CSR3_ACON 0x0002 /* ALE control */
#define CSR3_BSWP 0x0004 /* byte swap (1=big endian) */
/***************************** Prototypes *****************************/
static int lance_probe( struct net_device *dev);
static int lance_open( struct net_device *dev );
static void lance_init_ring( struct net_device *dev );
static netdev_tx_t lance_start_xmit(struct sk_buff *skb,
struct net_device *dev);
static irqreturn_t lance_interrupt( int irq, void *dev_id);
static int lance_rx( struct net_device *dev );
static int lance_close( struct net_device *dev );
static void set_multicast_list( struct net_device *dev );
/************************* End of Prototypes **************************/
struct net_device * __init sun3lance_probe(int unit)
{
struct net_device *dev;
static int found;
int err = -ENODEV;
if (!MACH_IS_SUN3 && !MACH_IS_SUN3X)
return ERR_PTR(-ENODEV);
/* check that this machine has an onboard lance */
switch(idprom->id_machtype) {
case SM_SUN3|SM_3_50:
case SM_SUN3|SM_3_60:
case SM_SUN3X|SM_3_80:
/* these machines have lance */
break;
default:
return ERR_PTR(-ENODEV);
}
if (found)
return ERR_PTR(-ENODEV);
dev = alloc_etherdev(sizeof(struct lance_private));
if (!dev)
return ERR_PTR(-ENOMEM);
if (unit >= 0) {
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
}
if (!lance_probe(dev))
goto out;
err = register_netdev(dev);
if (err)
goto out1;
found = 1;
return dev;
out1:
#ifdef CONFIG_SUN3
iounmap((void __iomem *)dev->base_addr);
#endif
out:
free_netdev(dev);
return ERR_PTR(err);
}
static const struct net_device_ops lance_netdev_ops = {
.ndo_open = lance_open,
.ndo_stop = lance_close,
.ndo_start_xmit = lance_start_xmit,
.ndo_set_rx_mode = set_multicast_list,
.ndo_set_mac_address = NULL,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
};
static int __init lance_probe( struct net_device *dev)
{
unsigned long ioaddr;
struct lance_private *lp;
int i;
static int did_version;
volatile unsigned short *ioaddr_probe;
unsigned short tmp1, tmp2;
#ifdef CONFIG_SUN3
ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE);
if (!ioaddr)
return 0;
#else
ioaddr = SUN3X_LANCE;
#endif
/* test to see if there's really a lance here */
/* (CSRO_INIT shouldn't be readable) */
ioaddr_probe = (volatile unsigned short *)ioaddr;
tmp1 = ioaddr_probe[0];
tmp2 = ioaddr_probe[1];
ioaddr_probe[1] = CSR0;
ioaddr_probe[0] = CSR0_INIT | CSR0_STOP;
if(ioaddr_probe[0] != CSR0_STOP) {
ioaddr_probe[0] = tmp1;
ioaddr_probe[1] = tmp2;
#ifdef CONFIG_SUN3
iounmap((void __iomem *)ioaddr);
#endif
return 0;
}
lp = netdev_priv(dev);
/* XXX - leak? */
MEM = dvma_malloc_align(sizeof(struct lance_memory), 0x10000);
if (MEM == NULL) {
#ifdef CONFIG_SUN3
iounmap((void __iomem *)ioaddr);
#endif
printk(KERN_WARNING "SUN3 Lance couldn't allocate DVMA memory\n");
return 0;
}
lp->iobase = (volatile unsigned short *)ioaddr;
dev->base_addr = (unsigned long)ioaddr; /* informational only */
REGA(CSR0) = CSR0_STOP;
if (request_irq(LANCE_IRQ, lance_interrupt, 0, "SUN3 Lance", dev) < 0) {
#ifdef CONFIG_SUN3
iounmap((void __iomem *)ioaddr);
#endif
dvma_free((void *)MEM);
printk(KERN_WARNING "SUN3 Lance unable to allocate IRQ\n");
return 0;
}
dev->irq = (unsigned short)LANCE_IRQ;
printk("%s: SUN3 Lance at io %#lx, mem %#lx, irq %d, hwaddr ",
dev->name,
(unsigned long)ioaddr,
(unsigned long)MEM,
dev->irq);
/* copy in the ethernet address from the prom */
for(i = 0; i < 6 ; i++)
dev->dev_addr[i] = idprom->id_ethaddr[i];
/* tell the card it's ether address, bytes swapped */
MEM->init.hwaddr[0] = dev->dev_addr[1];
MEM->init.hwaddr[1] = dev->dev_addr[0];
MEM->init.hwaddr[2] = dev->dev_addr[3];
MEM->init.hwaddr[3] = dev->dev_addr[2];
MEM->init.hwaddr[4] = dev->dev_addr[5];
MEM->init.hwaddr[5] = dev->dev_addr[4];
printk("%pM\n", dev->dev_addr);
MEM->init.mode = 0x0000;
MEM->init.filter[0] = 0x00000000;
MEM->init.filter[1] = 0x00000000;
MEM->init.rdra = dvma_vtob(MEM->rx_head);
MEM->init.rlen = (RX_LOG_RING_SIZE << 13) |
(dvma_vtob(MEM->rx_head) >> 16);
MEM->init.tdra = dvma_vtob(MEM->tx_head);
MEM->init.tlen = (TX_LOG_RING_SIZE << 13) |
(dvma_vtob(MEM->tx_head) >> 16);
DPRINTK(2, ("initaddr: %08lx rx_ring: %08lx tx_ring: %08lx\n",
dvma_vtob(&(MEM->init)), dvma_vtob(MEM->rx_head),
(dvma_vtob(MEM->tx_head))));
if (did_version++ == 0)
printk( version );
dev->netdev_ops = &lance_netdev_ops;
// KLUDGE -- REMOVE ME
set_bit(__LINK_STATE_PRESENT, &dev->state);
return 1;
}
static int lance_open( struct net_device *dev )
{
struct lance_private *lp = netdev_priv(dev);
int i;
DPRINTK( 2, ( "%s: lance_open()\n", dev->name ));
REGA(CSR0) = CSR0_STOP;
lance_init_ring(dev);
/* From now on, AREG is kept to point to CSR0 */
REGA(CSR0) = CSR0_INIT;
i = 1000000;
while (--i > 0)
if (DREG & CSR0_IDON)
break;
if (i <= 0 || (DREG & CSR0_ERR)) {
DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n",
dev->name, i, DREG ));
DREG = CSR0_STOP;
return -EIO;
}
DREG = CSR0_IDON | CSR0_STRT | CSR0_INEA;
netif_start_queue(dev);
DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG ));
return 0;
}
/* Initialize the LANCE Rx and Tx rings. */
static void lance_init_ring( struct net_device *dev )
{
struct lance_private *lp = netdev_priv(dev);
int i;
lp->lock = 0;
lp->tx_full = 0;
lp->new_rx = lp->new_tx = 0;
lp->old_rx = lp->old_tx = 0;
for( i = 0; i < TX_RING_SIZE; i++ ) {
MEM->tx_head[i].base = dvma_vtob(MEM->tx_data[i]);
MEM->tx_head[i].flag = 0;
MEM->tx_head[i].base_hi =
(dvma_vtob(MEM->tx_data[i])) >>16;
MEM->tx_head[i].length = 0;
MEM->tx_head[i].misc = 0;
}
for( i = 0; i < RX_RING_SIZE; i++ ) {
MEM->rx_head[i].base = dvma_vtob(MEM->rx_data[i]);
MEM->rx_head[i].flag = RMD1_OWN_CHIP;
MEM->rx_head[i].base_hi =
(dvma_vtob(MEM->rx_data[i])) >> 16;
MEM->rx_head[i].buf_length = -PKT_BUF_SZ | 0xf000;
MEM->rx_head[i].msg_length = 0;
}
/* tell the card it's ether address, bytes swapped */
MEM->init.hwaddr[0] = dev->dev_addr[1];
MEM->init.hwaddr[1] = dev->dev_addr[0];
MEM->init.hwaddr[2] = dev->dev_addr[3];
MEM->init.hwaddr[3] = dev->dev_addr[2];
MEM->init.hwaddr[4] = dev->dev_addr[5];
MEM->init.hwaddr[5] = dev->dev_addr[4];
MEM->init.mode = 0x0000;
MEM->init.filter[0] = 0x00000000;
MEM->init.filter[1] = 0x00000000;
MEM->init.rdra = dvma_vtob(MEM->rx_head);
MEM->init.rlen = (RX_LOG_RING_SIZE << 13) |
(dvma_vtob(MEM->rx_head) >> 16);
MEM->init.tdra = dvma_vtob(MEM->tx_head);
MEM->init.tlen = (TX_LOG_RING_SIZE << 13) |
(dvma_vtob(MEM->tx_head) >> 16);
/* tell the lance the address of its init block */
REGA(CSR1) = dvma_vtob(&(MEM->init));
REGA(CSR2) = dvma_vtob(&(MEM->init)) >> 16;
#ifdef CONFIG_SUN3X
REGA(CSR3) = CSR3_BSWP | CSR3_ACON | CSR3_BCON;
#else
REGA(CSR3) = CSR3_BSWP;
#endif
}
static netdev_tx_t
lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
int entry, len;
struct lance_tx_head *head;
unsigned long flags;
DPRINTK( 1, ( "%s: transmit start.\n",
dev->name));
/* Transmitter timeout, serious problems. */
if (netif_queue_stopped(dev)) {
int tickssofar = jiffies - dev_trans_start(dev);
if (tickssofar < HZ/5)
return NETDEV_TX_BUSY;
DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n",
dev->name, DREG ));
DREG = CSR0_STOP;
/*
* Always set BSWP after a STOP as STOP puts it back into
* little endian mode.
*/
REGA(CSR3) = CSR3_BSWP;
dev->stats.tx_errors++;
if(lance_debug >= 2) {
int i;
printk("Ring data: old_tx %d new_tx %d%s new_rx %d\n",
lp->old_tx, lp->new_tx,
lp->tx_full ? " (full)" : "",
lp->new_rx );
for( i = 0 ; i < RX_RING_SIZE; i++ )
printk( "rx #%d: base=%04x blen=%04x mlen=%04x\n",
i, MEM->rx_head[i].base,
-MEM->rx_head[i].buf_length,
MEM->rx_head[i].msg_length);
for( i = 0 ; i < TX_RING_SIZE; i++ )
printk("tx #%d: base=%04x len=%04x misc=%04x\n",
i, MEM->tx_head[i].base,
-MEM->tx_head[i].length,
MEM->tx_head[i].misc );
}
lance_init_ring(dev);
REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT;
netif_start_queue(dev);
return NETDEV_TX_OK;
}
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
/* Block a timer-based transmit from overlapping with us by
stopping the queue for a bit... */
netif_stop_queue(dev);
if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) {
printk( "%s: tx queue lock!.\n", dev->name);
/* don't clear dev->tbusy flag. */
return NETDEV_TX_BUSY;
}
AREG = CSR0;
DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
dev->name, DREG ));
#ifdef CONFIG_SUN3X
/* this weirdness doesn't appear on sun3... */
if(!(DREG & CSR0_INIT)) {
DPRINTK( 1, ("INIT not set, reinitializing...\n"));
REGA( CSR0 ) = CSR0_STOP;
lance_init_ring(dev);
REGA( CSR0 ) = CSR0_INIT | CSR0_STRT;
}
#endif
/* Fill in a Tx ring entry */
#if 0
if (lance_debug >= 2) {
printk( "%s: TX pkt %d type 0x%04x"
" from %s to %s"
" data at 0x%08x len %d\n",
dev->name, lp->new_tx, ((u_short *)skb->data)[6],
DEV_ADDR(&skb->data[6]), DEV_ADDR(skb->data),
(int)skb->data, (int)skb->len );
}
#endif
/* We're not prepared for the int until the last flags are set/reset.
* And the int may happen already after setting the OWN_CHIP... */
local_irq_save(flags);
/* Mask to ring buffer boundary. */
entry = lp->new_tx;
head = &(MEM->tx_head[entry]);
/* Caution: the write order is important here, set the "ownership" bits
* last.
*/
/* the sun3's lance needs it's buffer padded to the minimum
size */
len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
// head->length = -len;
head->length = (-len) | 0xf000;
head->misc = 0;
skb_copy_from_linear_data(skb, PKTBUF_ADDR(head), skb->len);
if (len != skb->len)
memset(PKTBUF_ADDR(head) + skb->len, 0, len-skb->len);
head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
lp->new_tx = (lp->new_tx + 1) & TX_RING_MOD_MASK;
dev->stats.tx_bytes += skb->len;
/* Trigger an immediate send poll. */
REGA(CSR0) = CSR0_INEA | CSR0_TDMD | CSR0_STRT;
AREG = CSR0;
DPRINTK( 2, ( "%s: lance_start_xmit() exiting, csr0 %4.4x.\n",
dev->name, DREG ));
dev_kfree_skb(skb);
lp->lock = 0;
if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) ==
TMD1_OWN_HOST)
netif_start_queue(dev);
local_irq_restore(flags);
return NETDEV_TX_OK;
}
/* The LANCE interrupt handler. */
static irqreturn_t lance_interrupt( int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct lance_private *lp = netdev_priv(dev);
int csr0;
static int in_interrupt;
if (dev == NULL) {
DPRINTK( 1, ( "lance_interrupt(): invalid dev_id\n" ));
return IRQ_NONE;
}
if (in_interrupt)
DPRINTK( 2, ( "%s: Re-entering the interrupt handler.\n", dev->name ));
in_interrupt = 1;
still_more:
flush_cache_all();
AREG = CSR0;
csr0 = DREG;
/* ack interrupts */
DREG = csr0 & (CSR0_TINT | CSR0_RINT | CSR0_IDON);
/* clear errors */
if(csr0 & CSR0_ERR)
DREG = CSR0_BABL | CSR0_MERR | CSR0_CERR | CSR0_MISS;
DPRINTK( 2, ( "%s: interrupt csr0=%04x new csr=%04x.\n",
dev->name, csr0, DREG ));
if (csr0 & CSR0_TINT) { /* Tx-done interrupt */
int old_tx = lp->old_tx;
// if(lance_debug >= 3) {
// int i;
//
// printk("%s: tx int\n", dev->name);
//
// for(i = 0; i < TX_RING_SIZE; i++)
// printk("ring %d flag=%04x\n", i,
// MEM->tx_head[i].flag);
// }
while( old_tx != lp->new_tx) {
struct lance_tx_head *head = &(MEM->tx_head[old_tx]);
DPRINTK(3, ("on tx_ring %d\n", old_tx));
if (head->flag & TMD1_OWN_CHIP)
break; /* It still hasn't been Txed */
if (head->flag & TMD1_ERR) {
int status = head->misc;
dev->stats.tx_errors++;
if (status & TMD3_RTRY) dev->stats.tx_aborted_errors++;
if (status & TMD3_LCAR) dev->stats.tx_carrier_errors++;
if (status & TMD3_LCOL) dev->stats.tx_window_errors++;
if (status & (TMD3_UFLO | TMD3_BUFF)) {
dev->stats.tx_fifo_errors++;
printk("%s: Tx FIFO error\n",
dev->name);
REGA(CSR0) = CSR0_STOP;
REGA(CSR3) = CSR3_BSWP;
lance_init_ring(dev);
REGA(CSR0) = CSR0_STRT | CSR0_INEA;
return IRQ_HANDLED;
}
} else if(head->flag & (TMD1_ENP | TMD1_STP)) {
head->flag &= ~(TMD1_ENP | TMD1_STP);
if(head->flag & (TMD1_ONE | TMD1_MORE))
dev->stats.collisions++;
dev->stats.tx_packets++;
DPRINTK(3, ("cleared tx ring %d\n", old_tx));
}
old_tx = (old_tx +1) & TX_RING_MOD_MASK;
}
lp->old_tx = old_tx;
}
if (netif_queue_stopped(dev)) {
/* The ring is no longer full, clear tbusy. */
netif_start_queue(dev);
netif_wake_queue(dev);
}
if (csr0 & CSR0_RINT) /* Rx interrupt */
lance_rx( dev );
/* Log misc errors. */
if (csr0 & CSR0_BABL) dev->stats.tx_errors++; /* Tx babble. */
if (csr0 & CSR0_MISS) dev->stats.rx_errors++; /* Missed a Rx frame. */
if (csr0 & CSR0_MERR) {
DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), "
"status %04x.\n", dev->name, csr0 ));
/* Restart the chip. */
REGA(CSR0) = CSR0_STOP;
REGA(CSR3) = CSR3_BSWP;
lance_init_ring(dev);
REGA(CSR0) = CSR0_STRT | CSR0_INEA;
}
/* Clear any other interrupt, and set interrupt enable. */
// DREG = CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR |
// CSR0_IDON | CSR0_INEA;
REGA(CSR0) = CSR0_INEA;
if(DREG & (CSR0_RINT | CSR0_TINT)) {
DPRINTK(2, ("restarting interrupt, csr0=%#04x\n", DREG));
goto still_more;
}
DPRINTK( 2, ( "%s: exiting interrupt, csr0=%#04x.\n",
dev->name, DREG ));
in_interrupt = 0;
return IRQ_HANDLED;
}
/* get packet, toss into skbuff */
static int lance_rx( struct net_device *dev )
{
struct lance_private *lp = netdev_priv(dev);
int entry = lp->new_rx;
/* If we own the next entry, it's a new packet. Send it up. */
while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) {
struct lance_rx_head *head = &(MEM->rx_head[entry]);
int status = head->flag;
if (status != (RMD1_ENP|RMD1_STP)) { /* There was an error. */
/* There is a tricky error noted by John Murphy,
<murf@perftech.com> to Russ Nelson: Even with
full-sized buffers it's possible for a jabber packet to use two
buffers, with only the last correctly noting the error. */
if (status & RMD1_ENP) /* Only count a general error at the */
dev->stats.rx_errors++; /* end of a packet.*/
if (status & RMD1_FRAM) dev->stats.rx_frame_errors++;
if (status & RMD1_OFLO) dev->stats.rx_over_errors++;
if (status & RMD1_CRC) dev->stats.rx_crc_errors++;
if (status & RMD1_BUFF) dev->stats.rx_fifo_errors++;
head->flag &= (RMD1_ENP|RMD1_STP);
} else {
/* Malloc up new buffer, compatible with net-3. */
// short pkt_len = head->msg_length;// & 0xfff;
short pkt_len = (head->msg_length & 0xfff) - 4;
struct sk_buff *skb;
if (pkt_len < 60) {
printk( "%s: Runt packet!\n", dev->name );
dev->stats.rx_errors++;
}
else {
skb = netdev_alloc_skb(dev, pkt_len + 2);
if (skb == NULL) {
dev->stats.rx_dropped++;
head->msg_length = 0;
head->flag |= RMD1_OWN_CHIP;
lp->new_rx = (lp->new_rx+1) &
RX_RING_MOD_MASK;
}
#if 0
if (lance_debug >= 3) {
u_char *data = PKTBUF_ADDR(head);
printk("%s: RX pkt %d type 0x%04x"
" from %pM to %pM",
dev->name, lp->new_tx, ((u_short *)data)[6],
&data[6], data);
printk(" data %02x %02x %02x %02x %02x %02x %02x %02x "
"len %d at %08x\n",
data[15], data[16], data[17], data[18],
data[19], data[20], data[21], data[22],
pkt_len, data);
}
#endif
if (lance_debug >= 3) {
u_char *data = PKTBUF_ADDR(head);
printk( "%s: RX pkt %d type 0x%04x len %d\n ", dev->name, entry, ((u_short *)data)[6], pkt_len);
}
skb_reserve( skb, 2 ); /* 16 byte align */
skb_put( skb, pkt_len ); /* Make room */
skb_copy_to_linear_data(skb,
PKTBUF_ADDR(head),
pkt_len);
skb->protocol = eth_type_trans( skb, dev );
netif_rx( skb );
dev->stats.rx_packets++;
dev->stats.rx_bytes += pkt_len;
}
}
// head->buf_length = -PKT_BUF_SZ | 0xf000;
head->msg_length = 0;
head->flag = RMD1_OWN_CHIP;
entry = lp->new_rx = (lp->new_rx +1) & RX_RING_MOD_MASK;
}
/* From lance.c (Donald Becker): */
/* We should check that at least two ring entries are free.
If not, we should free one and mark stats->rx_dropped++. */
return 0;
}
static int lance_close( struct net_device *dev )
{
struct lance_private *lp = netdev_priv(dev);
netif_stop_queue(dev);
AREG = CSR0;
DPRINTK( 2, ( "%s: Shutting down ethercard, status was %2.2x.\n",
dev->name, DREG ));
/* We stop the LANCE here -- it occasionally polls
memory if we don't. */
DREG = CSR0_STOP;
return 0;
}
/* Set or clear the multicast filter for this adaptor.
num_addrs == -1 Promiscuous mode, receive all packets
num_addrs == 0 Normal mode, clear multicast list
num_addrs > 0 Multicast mode, receive normal and MC packets, and do
best-effort filtering.
*/
/* completely untested on a sun3 */
static void set_multicast_list( struct net_device *dev )
{
struct lance_private *lp = netdev_priv(dev);
if(netif_queue_stopped(dev))
/* Only possible if board is already started */
return;
/* We take the simple way out and always enable promiscuous mode. */
DREG = CSR0_STOP; /* Temporarily stop the lance. */
if (dev->flags & IFF_PROMISC) {
/* Log any net taps. */
DPRINTK( 3, ( "%s: Promiscuous mode enabled.\n", dev->name ));
REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
} else {
short multicast_table[4];
int num_addrs = netdev_mc_count(dev);
int i;
/* We don't use the multicast table, but rely on upper-layer
* filtering. */
memset( multicast_table, (num_addrs == 0) ? 0 : -1,
sizeof(multicast_table) );
for( i = 0; i < 4; i++ )
REGA( CSR8+i ) = multicast_table[i];
REGA( CSR15 ) = 0; /* Unset promiscuous mode */
}
/*
* Always set BSWP after a STOP as STOP puts it back into
* little endian mode.
*/
REGA( CSR3 ) = CSR3_BSWP;
/* Resume normal operation and reset AREG to CSR0 */
REGA( CSR0 ) = CSR0_IDON | CSR0_INEA | CSR0_STRT;
}
#ifdef MODULE
static struct net_device *sun3lance_dev;
int __init init_module(void)
{
sun3lance_dev = sun3lance_probe(-1);
return PTR_ERR_OR_ZERO(sun3lance_dev);
}
void __exit cleanup_module(void)
{
unregister_netdev(sun3lance_dev);
#ifdef CONFIG_SUN3
iounmap((void __iomem *)sun3lance_dev->base_addr);
#endif
free_netdev(sun3lance_dev);
}
#endif /* MODULE */