linux/drivers/net/ethernet/natsemi/ns83820.c

// SPDX-License-Identifier: GPL-2.0-or-later
#define VERSION
/* ns83820.c by Benjamin LaHaise with contributions.
 *
 * Questions/comments/discussion to [email protected].
 *
 * $Revision: 1.34.2.23 $
 *
 * Copyright 2001 Benjamin LaHaise.
 * Copyright 2001, 2002 Red Hat.
 *
 * Mmmm, chocolate vanilla mocha...
 *
 * ChangeLog
 * =========
 *	20010414	0.1 - created
 *	20010622	0.2 - basic rx and tx.
 *	20010711	0.3 - added duplex and link state detection support.
 *	20010713	0.4 - zero copy, no hangs.
 *			0.5 - 64 bit dma support (davem will hate me for this)
 *			    - disable jumbo frames to avoid tx hangs
 *			    - work around tx deadlocks on my 1.02 card via
 *			      fiddling with TXCFG
 *	20010810	0.6 - use pci dma api for ringbuffers, work on ia64
 *	20010816	0.7 - misc cleanups
 *	20010826	0.8 - fix critical zero copy bugs
 *			0.9 - internal experiment
 *	20010827	0.10 - fix ia64 unaligned access.
 *	20010906	0.11 - accept all packets with checksum errors as
 *			       otherwise fragments get lost
 *			     - fix >> 32 bugs
 *			0.12 - add statistics counters
 *			     - add allmulti/promisc support
 *	20011009	0.13 - hotplug support, other smaller pci api cleanups
 *	20011204	0.13a - optical transceiver support added
 *				by Michael Clark <[email protected]>
 *	20011205	0.13b - call register_netdev earlier in initialization
 *				suppress duplicate link status messages
 *	20011117 	0.14 - ethtool GDRVINFO, GLINK support from jgarzik
 *	20011204 	0.15	get ppc (big endian) working
 *	20011218	0.16	various cleanups
 *	20020310	0.17	speedups
 *	20020610	0.18 -	actually use the pci dma api for highmem
 *			     -	remove pci latency register fiddling
 *			0.19 -	better bist support
 *			     -	add ihr and reset_phy parameters
 *			     -	gmii bus probing
 *			     -	fix missed txok introduced during performance
 *				tuning
 *			0.20 -	fix stupid RFEN thinko.  i am such a smurf.
 *	20040828	0.21 -	add hardware vlan accleration
 *				by Neil Horman <[email protected]>
 *	20050406	0.22 -	improved DAC ifdefs from Andi Kleen
 *			     -	removal of dead code from Adrian Bunk
 *			     -	fix half duplex collision behaviour
 * Driver Overview
 * ===============
 *
 * This driver was originally written for the National Semiconductor
 * 83820 chip, a 10/100/1000 Mbps 64 bit PCI ethernet NIC.  Hopefully
 * this code will turn out to be a) clean, b) correct, and c) fast.
 * With that in mind, I'm aiming to split the code up as much as
 * reasonably possible.  At present there are X major sections that
 * break down into a) packet receive, b) packet transmit, c) link
 * management, d) initialization and configuration.  Where possible,
 * these code paths are designed to run in parallel.
 *
 * This driver has been tested and found to work with the following
 * cards (in no particular order):
 *
 *	Cameo		SOHO-GA2000T	SOHO-GA2500T
 *	D-Link		DGE-500T
 *	PureData	PDP8023Z-TG
 *	SMC		SMC9452TX	SMC9462TX
 *	Netgear		GA621
 *
 * Special thanks to SMC for providing hardware to test this driver on.
 *
 * Reports of success or failure would be greatly appreciated.
 */
//#define dprintk		printk
#define dprintk(x...)

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/ip.h>	/* for iph */
#include <linux/in.h>	/* for IPPROTO_... */
#include <linux/compiler.h>
#include <linux/prefetch.h>
#include <linux/ethtool.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/if_vlan.h>
#include <linux/rtnetlink.h>
#include <linux/jiffies.h>
#include <linux/slab.h>

#include <asm/io.h>
#include <linux/uaccess.h>

#define DRV_NAME

/* Global parameters.  See module_param near the bottom. */
static int ihr =;
static int reset_phy =;
static int lnksts =;		/* CFG_LNKSTS bit polarity */

/* Dprintk is used for more interesting debug events */
#undef Dprintk
#define Dprintk

/* tunables */
#define RX_BUF_SIZE
#if IS_ENABLED(CONFIG_VLAN_8021Q)
#define NS83820_VLAN_ACCEL_SUPPORT
#endif

/* Must not exceed ~65000. */
#define NR_RX_DESC
#define NR_TX_DESC

/* not tunable */
#define REAL_RX_BUF_SIZE

#define MIN_TX_DESC_FREE

/* register defines */
#define CFGCS

#define CR_TXE
#define CR_TXD
/* Ramit : Here's a tip, don't do a RXD immediately followed by an RXE
 * The Receive engine skips one descriptor and moves
 * onto the next one!! */
#define CR_RXE
#define CR_RXD
#define CR_TXR
#define CR_RXR
#define CR_SWI
#define CR_RST

#define PTSCR_EEBIST_FAIL
#define PTSCR_EEBIST_EN
#define PTSCR_EELOAD_EN
#define PTSCR_RBIST_FAIL
#define PTSCR_RBIST_DONE
#define PTSCR_RBIST_EN
#define PTSCR_RBIST_RST

#define MEAR_EEDI
#define MEAR_EEDO
#define MEAR_EECLK
#define MEAR_EESEL
#define MEAR_MDIO
#define MEAR_MDDIR
#define MEAR_MDC

#define ISR_TXDESC3
#define ISR_TXDESC2
#define ISR_TXDESC1
#define ISR_TXDESC0
#define ISR_RXDESC3
#define ISR_RXDESC2
#define ISR_RXDESC1
#define ISR_RXDESC0
#define ISR_TXRCMP
#define ISR_RXRCMP
#define ISR_DPERR
#define ISR_SSERR
#define ISR_RMABT
#define ISR_RTABT
#define ISR_RXSOVR
#define ISR_HIBINT
#define ISR_PHY
#define ISR_PME
#define ISR_SWI
#define ISR_MIB
#define ISR_TXURN
#define ISR_TXIDLE
#define ISR_TXERR
#define ISR_TXDESC
#define ISR_TXOK
#define ISR_RXORN
#define ISR_RXIDLE
#define ISR_RXEARLY
#define ISR_RXERR
#define ISR_RXDESC
#define ISR_RXOK

#define TXCFG_CSI
#define TXCFG_HBI
#define TXCFG_MLB
#define TXCFG_ATP
#define TXCFG_ECRETRY
#define TXCFG_BRST_DIS
#define TXCFG_MXDMA1024
#define TXCFG_MXDMA512
#define TXCFG_MXDMA256
#define TXCFG_MXDMA128
#define TXCFG_MXDMA64
#define TXCFG_MXDMA32
#define TXCFG_MXDMA16
#define TXCFG_MXDMA8

#define CFG_LNKSTS
#define CFG_SPDSTS
#define CFG_SPDSTS1
#define CFG_SPDSTS0
#define CFG_DUPSTS
#define CFG_TBI_EN
#define CFG_MODE_1000
/* Ramit : Dont' ever use AUTO_1000, it never works and is buggy.
 * Read the Phy response and then configure the MAC accordingly */
#define CFG_AUTO_1000
#define CFG_PINT_CTL
#define CFG_PINT_DUPSTS
#define CFG_PINT_LNKSTS
#define CFG_PINT_SPDSTS
#define CFG_TMRTEST
#define CFG_MRM_DIS
#define CFG_MWI_DIS
#define CFG_T64ADDR
#define CFG_PCI64_DET
#define CFG_DATA64_EN
#define CFG_M64ADDR
#define CFG_PHY_RST
#define CFG_PHY_DIS
#define CFG_EXTSTS_EN
#define CFG_REQALG
#define CFG_SB
#define CFG_POW
#define CFG_EXD
#define CFG_PESEL
#define CFG_BROM_DIS
#define CFG_EXT_125
#define CFG_BEM

#define EXTSTS_UDPPKT
#define EXTSTS_TCPPKT
#define EXTSTS_IPPKT
#define EXTSTS_VPKT
#define EXTSTS_VTG_MASK

#define SPDSTS_POLARITY

#define MIBC_MIBS
#define MIBC_ACLR
#define MIBC_FRZ
#define MIBC_WRN

#define PCR_PSEN
#define PCR_PS_MCAST
#define PCR_PS_DA
#define PCR_STHI_8
#define PCR_STLO_4
#define PCR_FFHI_8K
#define PCR_FFLO_4K
#define PCR_PAUSE_CNT

#define RXCFG_AEP
#define RXCFG_ARP
#define RXCFG_STRIPCRC
#define RXCFG_RX_FD
#define RXCFG_ALP
#define RXCFG_AIRL
#define RXCFG_MXDMA512
#define RXCFG_DRTH
#define RXCFG_DRTH0

#define RFCR_RFEN
#define RFCR_AAB
#define RFCR_AAM
#define RFCR_AAU
#define RFCR_APM
#define RFCR_APAT
#define RFCR_APAT3
#define RFCR_APAT2
#define RFCR_APAT1
#define RFCR_APAT0
#define RFCR_AARP
#define RFCR_MHEN
#define RFCR_UHEN
#define RFCR_ULM

#define VRCR_RUDPE
#define VRCR_RTCPE
#define VRCR_RIPE
#define VRCR_IPEN
#define VRCR_DUTF
#define VRCR_DVTF
#define VRCR_VTREN
#define VRCR_VTDEN

#define VTCR_PPCHK
#define VTCR_GCHK
#define VTCR_VPPTI
#define VTCR_VGTI

#define CR
#define CFG
#define MEAR
#define PTSCR
#define ISR
#define IMR
#define IER
#define IHR
#define TXDP
#define TXDP_HI
#define TXCFG
#define GPIOR
#define RXDP
#define RXDP_HI
#define RXCFG
#define PQCR
#define WCSR
#define PCR
#define RFCR
#define RFDR

#define SRR

#define VRCR
#define VTCR
#define VDR
#define CCSR

#define TBICR
#define TBISR
#define TANAR
#define TANLPAR
#define TANER
#define TESR

#define TBICR_MR_AN_ENABLE
#define TBICR_MR_RESTART_AN

#define TBISR_MR_LINK_STATUS
#define TBISR_MR_AN_COMPLETE

#define TANAR_PS2
#define TANAR_PS1
#define TANAR_HALF_DUP
#define TANAR_FULL_DUP

#define GPIOR_GP5_OE
#define GPIOR_GP4_OE
#define GPIOR_GP3_OE
#define GPIOR_GP2_OE
#define GPIOR_GP1_OE
#define GPIOR_GP3_OUT
#define GPIOR_GP1_OUT

#define LINK_AUTONEGOTIATE
#define LINK_DOWN
#define LINK_UP

#define HW_ADDR_LEN
#define desc_addr_set(desc, addr)
#define desc_addr_get(desc)

#define DESC_LINK
#define DESC_BUFPTR
#define DESC_CMDSTS
#define DESC_EXTSTS

#define CMDSTS_OWN
#define CMDSTS_MORE
#define CMDSTS_INTR
#define CMDSTS_ERR
#define CMDSTS_OK
#define CMDSTS_RUNT
#define CMDSTS_LEN_MASK

#define CMDSTS_DEST_MASK
#define CMDSTS_DEST_SELF
#define CMDSTS_DEST_MULTI

#define DESC_SIZE

struct rx_info {};


struct ns83820 {};

static inline struct ns83820 *PRIV(struct net_device *dev)
{}

#define __kick_rx(dev)

static inline void kick_rx(struct net_device *ndev)
{}

//free = (tx_done_idx + NR_TX_DESC-2 - free_idx) % NR_TX_DESC
#define start_tx_okay(dev)

/* Packet Receiver
 *
 * The hardware supports linked lists of receive descriptors for
 * which ownership is transferred back and forth by means of an
 * ownership bit.  While the hardware does support the use of a
 * ring for receive descriptors, we only make use of a chain in
 * an attempt to reduce bus traffic under heavy load scenarios.
 * This will also make bugs a bit more obvious.  The current code
 * only makes use of a single rx chain; I hope to implement
 * priority based rx for version 1.0.  Goal: even under overload
 * conditions, still route realtime traffic with as low jitter as
 * possible.
 */
static inline void build_rx_desc(struct ns83820 *dev, __le32 *desc, dma_addr_t link, dma_addr_t buf, u32 cmdsts, u32 extsts)
{}

#define nr_rx_empty(dev)
static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb)
{}

static inline int rx_refill(struct net_device *ndev, gfp_t gfp)
{}

static void rx_refill_atomic(struct net_device *ndev)
{}

/* REFILL */
static inline void queue_refill(struct work_struct *work)
{}

static inline void clear_rx_desc(struct ns83820 *dev, unsigned i)
{}

static void phy_intr(struct net_device *ndev)
{}

static int ns83820_setup_rx(struct net_device *ndev)
{}

static void ns83820_cleanup_rx(struct ns83820 *dev)
{}

static void ns83820_rx_kick(struct net_device *ndev)
{}

/* rx_irq
 *
 */
static void rx_irq(struct net_device *ndev)
{}

static void rx_action(struct tasklet_struct *t)
{}

/* Packet Transmit code
 */
static inline void kick_tx(struct ns83820 *dev)
{}

/* No spinlock needed on the transmit irq path as the interrupt handler is
 * serialized.
 */
static void do_tx_done(struct net_device *ndev)
{}

static void ns83820_cleanup_tx(struct ns83820 *dev)
{}

/* transmit routine.  This code relies on the network layer serializing
 * its calls in, but will run happily in parallel with the interrupt
 * handler.  This code currently has provisions for fragmenting tx buffers
 * while trying to track down a bug in either the zero copy code or
 * the tx fifo (hence the MAX_FRAG_LEN).
 */
static netdev_tx_t ns83820_hard_start_xmit(struct sk_buff *skb,
					   struct net_device *ndev)
{}

static void ns83820_update_stats(struct ns83820 *dev)
{}

static struct net_device_stats *ns83820_get_stats(struct net_device *ndev)
{}

/* Let ethtool retrieve info */
static int ns83820_get_link_ksettings(struct net_device *ndev,
				      struct ethtool_link_ksettings *cmd)
{}

/* Let ethool change settings*/
static int ns83820_set_link_ksettings(struct net_device *ndev,
				      const struct ethtool_link_ksettings *cmd)
{}
/* end ethtool get/set support -df */

static void ns83820_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
{}

static u32 ns83820_get_link(struct net_device *ndev)
{}

static const struct ethtool_ops ops =;

static inline void ns83820_disable_interrupts(struct ns83820 *dev)
{}

/* this function is called in irq context from the ISR */
static void ns83820_mib_isr(struct ns83820 *dev)
{}

static void ns83820_do_isr(struct net_device *ndev, u32 isr);
static irqreturn_t ns83820_irq(int foo, void *data)
{}

static void ns83820_do_isr(struct net_device *ndev, u32 isr)
{}

static void ns83820_do_reset(struct ns83820 *dev, u32 which)
{}

static int ns83820_stop(struct net_device *ndev)
{}

static void ns83820_tx_timeout(struct net_device *ndev, unsigned int txqueue)
{}

static void ns83820_tx_watch(struct timer_list *t)
{}

static int ns83820_open(struct net_device *ndev)
{}

static void ns83820_getmac(struct ns83820 *dev, struct net_device *ndev)
{}

static void ns83820_set_multicast(struct net_device *ndev)
{}

static void ns83820_run_bist(struct net_device *ndev, const char *name, u32 enable, u32 done, u32 fail)
{}

#ifdef PHY_CODE_IS_FINISHED
static void ns83820_mii_write_bit(struct ns83820 *dev, int bit)
{
	/* drive MDC low */
	dev->MEAR_cache &= ~MEAR_MDC;
	writel(dev->MEAR_cache, dev->base + MEAR);
	readl(dev->base + MEAR);

	/* enable output, set bit */
	dev->MEAR_cache |= MEAR_MDDIR;
	if (bit)
		dev->MEAR_cache |= MEAR_MDIO;
	else
		dev->MEAR_cache &= ~MEAR_MDIO;

	/* set the output bit */
	writel(dev->MEAR_cache, dev->base + MEAR);
	readl(dev->base + MEAR);

	/* Wait.  Max clock rate is 2.5MHz, this way we come in under 1MHz */
	udelay(1);

	/* drive MDC high causing the data bit to be latched */
	dev->MEAR_cache |= MEAR_MDC;
	writel(dev->MEAR_cache, dev->base + MEAR);
	readl(dev->base + MEAR);

	/* Wait again... */
	udelay(1);
}

static int ns83820_mii_read_bit(struct ns83820 *dev)
{
	int bit;

	/* drive MDC low, disable output */
	dev->MEAR_cache &= ~MEAR_MDC;
	dev->MEAR_cache &= ~MEAR_MDDIR;
	writel(dev->MEAR_cache, dev->base + MEAR);
	readl(dev->base + MEAR);

	/* Wait.  Max clock rate is 2.5MHz, this way we come in under 1MHz */
	udelay(1);

	/* drive MDC high causing the data bit to be latched */
	bit = (readl(dev->base + MEAR) & MEAR_MDIO) ? 1 : 0;
	dev->MEAR_cache |= MEAR_MDC;
	writel(dev->MEAR_cache, dev->base + MEAR);

	/* Wait again... */
	udelay(1);

	return bit;
}

static unsigned ns83820_mii_read_reg(struct ns83820 *dev, unsigned phy, unsigned reg)
{
	unsigned data = 0;
	int i;

	/* read some garbage so that we eventually sync up */
	for (i=0; i<64; i++)
		ns83820_mii_read_bit(dev);

	ns83820_mii_write_bit(dev, 0);	/* start */
	ns83820_mii_write_bit(dev, 1);
	ns83820_mii_write_bit(dev, 1);	/* opcode read */
	ns83820_mii_write_bit(dev, 0);

	/* write out the phy address: 5 bits, msb first */
	for (i=0; i<5; i++)
		ns83820_mii_write_bit(dev, phy & (0x10 >> i));

	/* write out the register address, 5 bits, msb first */
	for (i=0; i<5; i++)
		ns83820_mii_write_bit(dev, reg & (0x10 >> i));

	ns83820_mii_read_bit(dev);	/* turn around cycles */
	ns83820_mii_read_bit(dev);

	/* read in the register data, 16 bits msb first */
	for (i=0; i<16; i++) {
		data <<= 1;
		data |= ns83820_mii_read_bit(dev);
	}

	return data;
}

static unsigned ns83820_mii_write_reg(struct ns83820 *dev, unsigned phy, unsigned reg, unsigned data)
{
	int i;

	/* read some garbage so that we eventually sync up */
	for (i=0; i<64; i++)
		ns83820_mii_read_bit(dev);

	ns83820_mii_write_bit(dev, 0);	/* start */
	ns83820_mii_write_bit(dev, 1);
	ns83820_mii_write_bit(dev, 0);	/* opcode read */
	ns83820_mii_write_bit(dev, 1);

	/* write out the phy address: 5 bits, msb first */
	for (i=0; i<5; i++)
		ns83820_mii_write_bit(dev, phy & (0x10 >> i));

	/* write out the register address, 5 bits, msb first */
	for (i=0; i<5; i++)
		ns83820_mii_write_bit(dev, reg & (0x10 >> i));

	ns83820_mii_read_bit(dev);	/* turn around cycles */
	ns83820_mii_read_bit(dev);

	/* read in the register data, 16 bits msb first */
	for (i=0; i<16; i++)
		ns83820_mii_write_bit(dev, (data >> (15 - i)) & 1);

	return data;
}

static void ns83820_probe_phy(struct net_device *ndev)
{
	struct ns83820 *dev = PRIV(ndev);
	int j;
	unsigned a, b;

	for (j = 0; j < 0x16; j += 4) {
		dprintk("%s: [0x%02x] %04x %04x %04x %04x\n",
			ndev->name, j,
			ns83820_mii_read_reg(dev, 1, 0 + j),
			ns83820_mii_read_reg(dev, 1, 1 + j),
			ns83820_mii_read_reg(dev, 1, 2 + j),
			ns83820_mii_read_reg(dev, 1, 3 + j)
			);
	}

	/* read firmware version: memory addr is 0x8402 and 0x8403 */
	ns83820_mii_write_reg(dev, 1, 0x16, 0x000d);
	ns83820_mii_write_reg(dev, 1, 0x1e, 0x810e);
	a = ns83820_mii_read_reg(dev, 1, 0x1d);

	ns83820_mii_write_reg(dev, 1, 0x16, 0x000d);
	ns83820_mii_write_reg(dev, 1, 0x1e, 0x810e);
	b = ns83820_mii_read_reg(dev, 1, 0x1d);
	dprintk("version: 0x%04x 0x%04x\n", a, b);
}
#endif

static const struct net_device_ops netdev_ops =;

static int ns83820_init_one(struct pci_dev *pci_dev,
			    const struct pci_device_id *id)
{}

static void ns83820_remove_one(struct pci_dev *pci_dev)
{}

static const struct pci_device_id ns83820_pci_tbl[] =;

static struct pci_driver driver =;


static int __init ns83820_init(void)
{}

static void __exit ns83820_exit(void)
{}

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

MODULE_DEVICE_TABLE(pci, ns83820_pci_tbl);

module_param(lnksts, int, 0);
MODULE_PARM_DESC();

module_param(ihr, int, 0);
MODULE_PARM_DESC();

module_param(reset_phy, int, 0);
MODULE_PARM_DESC();

module_init();
module_exit(ns83820_exit);