mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 09:08:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
666
drivers/net/ethernet/amd/7990.c
Normal file
666
drivers/net/ethernet/amd/7990.c
Normal file
|
@ -0,0 +1,666 @@
|
|||
/*
|
||||
* 7990.c -- LANCE ethernet IC generic routines.
|
||||
* This is an attempt to separate out the bits of various ethernet
|
||||
* drivers that are common because they all use the AMD 7990 LANCE
|
||||
* (Local Area Network Controller for Ethernet) chip.
|
||||
*
|
||||
* Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
|
||||
*
|
||||
* Most of this stuff was obtained by looking at other LANCE drivers,
|
||||
* in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful.
|
||||
* NB: this was made easy by the fact that Jes Sorensen had cleaned up
|
||||
* most of a2025 and sunlance with the aim of merging them, so the
|
||||
* common code was pretty obvious.
|
||||
*/
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/module.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/route.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <asm/irq.h>
|
||||
/* Used for the temporal inet entries and routing */
|
||||
#include <linux/socket.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/pgtable.h>
|
||||
#ifdef CONFIG_HP300
|
||||
#include <asm/blinken.h>
|
||||
#endif
|
||||
|
||||
#include "7990.h"
|
||||
|
||||
#define WRITERAP(lp, x) out_be16(lp->base + LANCE_RAP, (x))
|
||||
#define WRITERDP(lp, x) out_be16(lp->base + LANCE_RDP, (x))
|
||||
#define READRDP(lp) in_be16(lp->base + LANCE_RDP)
|
||||
|
||||
#if defined(CONFIG_HPLANCE) || defined(CONFIG_HPLANCE_MODULE)
|
||||
#include "hplance.h"
|
||||
|
||||
#undef WRITERAP
|
||||
#undef WRITERDP
|
||||
#undef READRDP
|
||||
|
||||
#if defined(CONFIG_MVME147_NET) || defined(CONFIG_MVME147_NET_MODULE)
|
||||
|
||||
/* Lossage Factor Nine, Mr Sulu. */
|
||||
#define WRITERAP(lp, x) (lp->writerap(lp, x))
|
||||
#define WRITERDP(lp, x) (lp->writerdp(lp, x))
|
||||
#define READRDP(lp) (lp->readrdp(lp))
|
||||
|
||||
#else
|
||||
|
||||
/* These inlines can be used if only CONFIG_HPLANCE is defined */
|
||||
static inline void WRITERAP(struct lance_private *lp, __u16 value)
|
||||
{
|
||||
do {
|
||||
out_be16(lp->base + HPLANCE_REGOFF + LANCE_RAP, value);
|
||||
} while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
|
||||
}
|
||||
|
||||
static inline void WRITERDP(struct lance_private *lp, __u16 value)
|
||||
{
|
||||
do {
|
||||
out_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP, value);
|
||||
} while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
|
||||
}
|
||||
|
||||
static inline __u16 READRDP(struct lance_private *lp)
|
||||
{
|
||||
__u16 value;
|
||||
do {
|
||||
value = in_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP);
|
||||
} while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
|
||||
return value;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* CONFIG_HPLANCE || CONFIG_HPLANCE_MODULE */
|
||||
|
||||
/* debugging output macros, various flavours */
|
||||
/* #define TEST_HITS */
|
||||
#ifdef UNDEF
|
||||
#define PRINT_RINGS() \
|
||||
do { \
|
||||
int t; \
|
||||
for (t = 0; t < RX_RING_SIZE; t++) { \
|
||||
printk("R%d: @(%02X %04X) len %04X, mblen %04X, bits %02X\n", \
|
||||
t, ib->brx_ring[t].rmd1_hadr, ib->brx_ring[t].rmd0, \
|
||||
ib->brx_ring[t].length, \
|
||||
ib->brx_ring[t].mblength, ib->brx_ring[t].rmd1_bits); \
|
||||
} \
|
||||
for (t = 0; t < TX_RING_SIZE; t++) { \
|
||||
printk("T%d: @(%02X %04X) len %04X, misc %04X, bits %02X\n", \
|
||||
t, ib->btx_ring[t].tmd1_hadr, ib->btx_ring[t].tmd0, \
|
||||
ib->btx_ring[t].length, \
|
||||
ib->btx_ring[t].misc, ib->btx_ring[t].tmd1_bits); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define PRINT_RINGS()
|
||||
#endif
|
||||
|
||||
/* Load the CSR registers. The LANCE has to be STOPped when we do this! */
|
||||
static void load_csrs(struct lance_private *lp)
|
||||
{
|
||||
volatile struct lance_init_block *aib = lp->lance_init_block;
|
||||
int leptr;
|
||||
|
||||
leptr = LANCE_ADDR(aib);
|
||||
|
||||
WRITERAP(lp, LE_CSR1); /* load address of init block */
|
||||
WRITERDP(lp, leptr & 0xFFFF);
|
||||
WRITERAP(lp, LE_CSR2);
|
||||
WRITERDP(lp, leptr >> 16);
|
||||
WRITERAP(lp, LE_CSR3);
|
||||
WRITERDP(lp, lp->busmaster_regval); /* set byteswap/ALEctrl/byte ctrl */
|
||||
|
||||
/* Point back to csr0 */
|
||||
WRITERAP(lp, LE_CSR0);
|
||||
}
|
||||
|
||||
/* #define to 0 or 1 appropriately */
|
||||
#define DEBUG_IRING 0
|
||||
/* Set up the Lance Rx and Tx rings and the init block */
|
||||
static void lance_init_ring(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_init_block *ib = lp->init_block;
|
||||
volatile struct lance_init_block *aib; /* for LANCE_ADDR computations */
|
||||
int leptr;
|
||||
int i;
|
||||
|
||||
aib = lp->lance_init_block;
|
||||
|
||||
lp->rx_new = lp->tx_new = 0;
|
||||
lp->rx_old = lp->tx_old = 0;
|
||||
|
||||
ib->mode = LE_MO_PROM; /* normal, enable Tx & Rx */
|
||||
|
||||
/* Copy the ethernet address to the lance init block
|
||||
* Notice that we do a byteswap if we're big endian.
|
||||
* [I think this is the right criterion; at least, sunlance,
|
||||
* a2065 and atarilance do the byteswap and lance.c (PC) doesn't.
|
||||
* However, the datasheet says that the BSWAP bit doesn't affect
|
||||
* the init block, so surely it should be low byte first for
|
||||
* everybody? Um.]
|
||||
* We could define the ib->physaddr as three 16bit values and
|
||||
* use (addr[1] << 8) | addr[0] & co, but this is more efficient.
|
||||
*/
|
||||
#ifdef __BIG_ENDIAN
|
||||
ib->phys_addr[0] = dev->dev_addr[1];
|
||||
ib->phys_addr[1] = dev->dev_addr[0];
|
||||
ib->phys_addr[2] = dev->dev_addr[3];
|
||||
ib->phys_addr[3] = dev->dev_addr[2];
|
||||
ib->phys_addr[4] = dev->dev_addr[5];
|
||||
ib->phys_addr[5] = dev->dev_addr[4];
|
||||
#else
|
||||
for (i = 0; i < 6; i++)
|
||||
ib->phys_addr[i] = dev->dev_addr[i];
|
||||
#endif
|
||||
|
||||
if (DEBUG_IRING)
|
||||
printk("TX rings:\n");
|
||||
|
||||
lp->tx_full = 0;
|
||||
/* Setup the Tx ring entries */
|
||||
for (i = 0; i < (1 << lp->lance_log_tx_bufs); i++) {
|
||||
leptr = LANCE_ADDR(&aib->tx_buf[i][0]);
|
||||
ib->btx_ring[i].tmd0 = leptr;
|
||||
ib->btx_ring[i].tmd1_hadr = leptr >> 16;
|
||||
ib->btx_ring[i].tmd1_bits = 0;
|
||||
ib->btx_ring[i].length = 0xf000; /* The ones required by tmd2 */
|
||||
ib->btx_ring[i].misc = 0;
|
||||
if (DEBUG_IRING)
|
||||
printk("%d: 0x%8.8x\n", i, leptr);
|
||||
}
|
||||
|
||||
/* Setup the Rx ring entries */
|
||||
if (DEBUG_IRING)
|
||||
printk("RX rings:\n");
|
||||
for (i = 0; i < (1 << lp->lance_log_rx_bufs); i++) {
|
||||
leptr = LANCE_ADDR(&aib->rx_buf[i][0]);
|
||||
|
||||
ib->brx_ring[i].rmd0 = leptr;
|
||||
ib->brx_ring[i].rmd1_hadr = leptr >> 16;
|
||||
ib->brx_ring[i].rmd1_bits = LE_R1_OWN;
|
||||
/* 0xf000 == bits that must be one (reserved, presumably) */
|
||||
ib->brx_ring[i].length = -RX_BUFF_SIZE | 0xf000;
|
||||
ib->brx_ring[i].mblength = 0;
|
||||
if (DEBUG_IRING)
|
||||
printk("%d: 0x%8.8x\n", i, leptr);
|
||||
}
|
||||
|
||||
/* Setup the initialization block */
|
||||
|
||||
/* Setup rx descriptor pointer */
|
||||
leptr = LANCE_ADDR(&aib->brx_ring);
|
||||
ib->rx_len = (lp->lance_log_rx_bufs << 13) | (leptr >> 16);
|
||||
ib->rx_ptr = leptr;
|
||||
if (DEBUG_IRING)
|
||||
printk("RX ptr: %8.8x\n", leptr);
|
||||
|
||||
/* Setup tx descriptor pointer */
|
||||
leptr = LANCE_ADDR(&aib->btx_ring);
|
||||
ib->tx_len = (lp->lance_log_tx_bufs << 13) | (leptr >> 16);
|
||||
ib->tx_ptr = leptr;
|
||||
if (DEBUG_IRING)
|
||||
printk("TX ptr: %8.8x\n", leptr);
|
||||
|
||||
/* Clear the multicast filter */
|
||||
ib->filter[0] = 0;
|
||||
ib->filter[1] = 0;
|
||||
PRINT_RINGS();
|
||||
}
|
||||
|
||||
/* LANCE must be STOPped before we do this, too... */
|
||||
static int init_restart_lance(struct lance_private *lp)
|
||||
{
|
||||
int i;
|
||||
|
||||
WRITERAP(lp, LE_CSR0);
|
||||
WRITERDP(lp, LE_C0_INIT);
|
||||
|
||||
/* Need a hook here for sunlance ledma stuff */
|
||||
|
||||
/* Wait for the lance to complete initialization */
|
||||
for (i = 0; (i < 100) && !(READRDP(lp) & (LE_C0_ERR | LE_C0_IDON)); i++)
|
||||
barrier();
|
||||
if ((i == 100) || (READRDP(lp) & LE_C0_ERR)) {
|
||||
printk("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, READRDP(lp));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Clear IDON by writing a "1", enable interrupts and start lance */
|
||||
WRITERDP(lp, LE_C0_IDON);
|
||||
WRITERDP(lp, LE_C0_INEA | LE_C0_STRT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lance_reset(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
int status;
|
||||
|
||||
/* Stop the lance */
|
||||
WRITERAP(lp, LE_CSR0);
|
||||
WRITERDP(lp, LE_C0_STOP);
|
||||
|
||||
load_csrs(lp);
|
||||
lance_init_ring(dev);
|
||||
dev->trans_start = jiffies; /* prevent tx timeout */
|
||||
status = init_restart_lance(lp);
|
||||
#ifdef DEBUG_DRIVER
|
||||
printk("Lance restart=%d\n", status);
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
static int lance_rx(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_init_block *ib = lp->init_block;
|
||||
volatile struct lance_rx_desc *rd;
|
||||
unsigned char bits;
|
||||
#ifdef TEST_HITS
|
||||
int i;
|
||||
#endif
|
||||
|
||||
#ifdef TEST_HITS
|
||||
printk("[");
|
||||
for (i = 0; i < RX_RING_SIZE; i++) {
|
||||
if (i == lp->rx_new)
|
||||
printk("%s",
|
||||
ib->brx_ring[i].rmd1_bits & LE_R1_OWN ? "_" : "X");
|
||||
else
|
||||
printk("%s",
|
||||
ib->brx_ring[i].rmd1_bits & LE_R1_OWN ? "." : "1");
|
||||
}
|
||||
printk("]");
|
||||
#endif
|
||||
#ifdef CONFIG_HP300
|
||||
blinken_leds(0x40, 0);
|
||||
#endif
|
||||
WRITERDP(lp, LE_C0_RINT | LE_C0_INEA); /* ack Rx int, reenable ints */
|
||||
for (rd = &ib->brx_ring[lp->rx_new]; /* For each Rx ring we own... */
|
||||
!((bits = rd->rmd1_bits) & LE_R1_OWN);
|
||||
rd = &ib->brx_ring[lp->rx_new]) {
|
||||
|
||||
/* We got an incomplete frame? */
|
||||
if ((bits & LE_R1_POK) != LE_R1_POK) {
|
||||
dev->stats.rx_over_errors++;
|
||||
dev->stats.rx_errors++;
|
||||
continue;
|
||||
} else if (bits & LE_R1_ERR) {
|
||||
/* Count only the end frame as a rx error,
|
||||
* not the beginning
|
||||
*/
|
||||
if (bits & LE_R1_BUF)
|
||||
dev->stats.rx_fifo_errors++;
|
||||
if (bits & LE_R1_CRC)
|
||||
dev->stats.rx_crc_errors++;
|
||||
if (bits & LE_R1_OFL)
|
||||
dev->stats.rx_over_errors++;
|
||||
if (bits & LE_R1_FRA)
|
||||
dev->stats.rx_frame_errors++;
|
||||
if (bits & LE_R1_EOP)
|
||||
dev->stats.rx_errors++;
|
||||
} else {
|
||||
int len = (rd->mblength & 0xfff) - 4;
|
||||
struct sk_buff *skb = netdev_alloc_skb(dev, len + 2);
|
||||
|
||||
if (!skb) {
|
||||
dev->stats.rx_dropped++;
|
||||
rd->mblength = 0;
|
||||
rd->rmd1_bits = LE_R1_OWN;
|
||||
lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
skb_reserve(skb, 2); /* 16 byte align */
|
||||
skb_put(skb, len); /* make room */
|
||||
skb_copy_to_linear_data(skb,
|
||||
(unsigned char *)&(ib->rx_buf[lp->rx_new][0]),
|
||||
len);
|
||||
skb->protocol = eth_type_trans(skb, dev);
|
||||
netif_rx(skb);
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += len;
|
||||
}
|
||||
|
||||
/* Return the packet to the pool */
|
||||
rd->mblength = 0;
|
||||
rd->rmd1_bits = LE_R1_OWN;
|
||||
lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lance_tx(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_init_block *ib = lp->init_block;
|
||||
volatile struct lance_tx_desc *td;
|
||||
int i, j;
|
||||
int status;
|
||||
|
||||
#ifdef CONFIG_HP300
|
||||
blinken_leds(0x80, 0);
|
||||
#endif
|
||||
/* csr0 is 2f3 */
|
||||
WRITERDP(lp, LE_C0_TINT | LE_C0_INEA);
|
||||
/* csr0 is 73 */
|
||||
|
||||
j = lp->tx_old;
|
||||
for (i = j; i != lp->tx_new; i = j) {
|
||||
td = &ib->btx_ring[i];
|
||||
|
||||
/* If we hit a packet not owned by us, stop */
|
||||
if (td->tmd1_bits & LE_T1_OWN)
|
||||
break;
|
||||
|
||||
if (td->tmd1_bits & LE_T1_ERR) {
|
||||
status = td->misc;
|
||||
|
||||
dev->stats.tx_errors++;
|
||||
if (status & LE_T3_RTY)
|
||||
dev->stats.tx_aborted_errors++;
|
||||
if (status & LE_T3_LCOL)
|
||||
dev->stats.tx_window_errors++;
|
||||
|
||||
if (status & LE_T3_CLOS) {
|
||||
dev->stats.tx_carrier_errors++;
|
||||
if (lp->auto_select) {
|
||||
lp->tpe = 1 - lp->tpe;
|
||||
printk("%s: Carrier Lost, trying %s\n",
|
||||
dev->name,
|
||||
lp->tpe ? "TPE" : "AUI");
|
||||
/* Stop the lance */
|
||||
WRITERAP(lp, LE_CSR0);
|
||||
WRITERDP(lp, LE_C0_STOP);
|
||||
lance_init_ring(dev);
|
||||
load_csrs(lp);
|
||||
init_restart_lance(lp);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* buffer errors and underflows turn off the transmitter */
|
||||
/* Restart the adapter */
|
||||
if (status & (LE_T3_BUF|LE_T3_UFL)) {
|
||||
dev->stats.tx_fifo_errors++;
|
||||
|
||||
printk("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
|
||||
dev->name);
|
||||
/* Stop the lance */
|
||||
WRITERAP(lp, LE_CSR0);
|
||||
WRITERDP(lp, LE_C0_STOP);
|
||||
lance_init_ring(dev);
|
||||
load_csrs(lp);
|
||||
init_restart_lance(lp);
|
||||
return 0;
|
||||
}
|
||||
} else if ((td->tmd1_bits & LE_T1_POK) == LE_T1_POK) {
|
||||
/*
|
||||
* So we don't count the packet more than once.
|
||||
*/
|
||||
td->tmd1_bits &= ~(LE_T1_POK);
|
||||
|
||||
/* One collision before packet was sent. */
|
||||
if (td->tmd1_bits & LE_T1_EONE)
|
||||
dev->stats.collisions++;
|
||||
|
||||
/* More than one collision, be optimistic. */
|
||||
if (td->tmd1_bits & LE_T1_EMORE)
|
||||
dev->stats.collisions += 2;
|
||||
|
||||
dev->stats.tx_packets++;
|
||||
}
|
||||
|
||||
j = (j + 1) & lp->tx_ring_mod_mask;
|
||||
}
|
||||
lp->tx_old = j;
|
||||
WRITERDP(lp, LE_C0_TINT | LE_C0_INEA);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
lance_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct net_device *dev = (struct net_device *)dev_id;
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
int csr0;
|
||||
|
||||
spin_lock(&lp->devlock);
|
||||
|
||||
WRITERAP(lp, LE_CSR0); /* LANCE Controller Status */
|
||||
csr0 = READRDP(lp);
|
||||
|
||||
PRINT_RINGS();
|
||||
|
||||
if (!(csr0 & LE_C0_INTR)) { /* Check if any interrupt has */
|
||||
spin_unlock(&lp->devlock);
|
||||
return IRQ_NONE; /* been generated by the Lance. */
|
||||
}
|
||||
|
||||
/* Acknowledge all the interrupt sources ASAP */
|
||||
WRITERDP(lp, csr0 & ~(LE_C0_INEA|LE_C0_TDMD|LE_C0_STOP|LE_C0_STRT|LE_C0_INIT));
|
||||
|
||||
if ((csr0 & LE_C0_ERR)) {
|
||||
/* Clear the error condition */
|
||||
WRITERDP(lp, LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA);
|
||||
}
|
||||
|
||||
if (csr0 & LE_C0_RINT)
|
||||
lance_rx(dev);
|
||||
|
||||
if (csr0 & LE_C0_TINT)
|
||||
lance_tx(dev);
|
||||
|
||||
/* Log misc errors. */
|
||||
if (csr0 & LE_C0_BABL)
|
||||
dev->stats.tx_errors++; /* Tx babble. */
|
||||
if (csr0 & LE_C0_MISS)
|
||||
dev->stats.rx_errors++; /* Missed a Rx frame. */
|
||||
if (csr0 & LE_C0_MERR) {
|
||||
printk("%s: Bus master arbitration failure, status %4.4x.\n",
|
||||
dev->name, csr0);
|
||||
/* Restart the chip. */
|
||||
WRITERDP(lp, LE_C0_STRT);
|
||||
}
|
||||
|
||||
if (lp->tx_full && netif_queue_stopped(dev) && (TX_BUFFS_AVAIL >= 0)) {
|
||||
lp->tx_full = 0;
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
|
||||
WRITERAP(lp, LE_CSR0);
|
||||
WRITERDP(lp, LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|LE_C0_IDON|LE_C0_INEA);
|
||||
|
||||
spin_unlock(&lp->devlock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int lance_open(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
int res;
|
||||
|
||||
/* Install the Interrupt handler. Or we could shunt this out to specific drivers? */
|
||||
if (request_irq(lp->irq, lance_interrupt, IRQF_SHARED, lp->name, dev))
|
||||
return -EAGAIN;
|
||||
|
||||
res = lance_reset(dev);
|
||||
spin_lock_init(&lp->devlock);
|
||||
netif_start_queue(dev);
|
||||
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lance_open);
|
||||
|
||||
int lance_close(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
|
||||
netif_stop_queue(dev);
|
||||
|
||||
/* Stop the LANCE */
|
||||
WRITERAP(lp, LE_CSR0);
|
||||
WRITERDP(lp, LE_C0_STOP);
|
||||
|
||||
free_irq(lp->irq, dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lance_close);
|
||||
|
||||
void lance_tx_timeout(struct net_device *dev)
|
||||
{
|
||||
printk("lance_tx_timeout\n");
|
||||
lance_reset(dev);
|
||||
dev->trans_start = jiffies; /* prevent tx timeout */
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lance_tx_timeout);
|
||||
|
||||
int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_init_block *ib = lp->init_block;
|
||||
int entry, skblen, len;
|
||||
static int outs;
|
||||
unsigned long flags;
|
||||
|
||||
if (!TX_BUFFS_AVAIL)
|
||||
return NETDEV_TX_LOCKED;
|
||||
|
||||
netif_stop_queue(dev);
|
||||
|
||||
skblen = skb->len;
|
||||
|
||||
#ifdef DEBUG_DRIVER
|
||||
/* dump the packet */
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
if ((i % 16) == 0)
|
||||
printk("\n");
|
||||
printk("%2.2x ", skb->data[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
|
||||
entry = lp->tx_new & lp->tx_ring_mod_mask;
|
||||
ib->btx_ring[entry].length = (-len) | 0xf000;
|
||||
ib->btx_ring[entry].misc = 0;
|
||||
|
||||
if (skb->len < ETH_ZLEN)
|
||||
memset((void *)&ib->tx_buf[entry][0], 0, ETH_ZLEN);
|
||||
skb_copy_from_linear_data(skb, (void *)&ib->tx_buf[entry][0], skblen);
|
||||
|
||||
/* Now, give the packet to the lance */
|
||||
ib->btx_ring[entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
|
||||
lp->tx_new = (lp->tx_new + 1) & lp->tx_ring_mod_mask;
|
||||
|
||||
outs++;
|
||||
/* Kick the lance: transmit now */
|
||||
WRITERDP(lp, LE_C0_INEA | LE_C0_TDMD);
|
||||
dev_consume_skb_any(skb);
|
||||
|
||||
spin_lock_irqsave(&lp->devlock, flags);
|
||||
if (TX_BUFFS_AVAIL)
|
||||
netif_start_queue(dev);
|
||||
else
|
||||
lp->tx_full = 1;
|
||||
spin_unlock_irqrestore(&lp->devlock, flags);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lance_start_xmit);
|
||||
|
||||
/* taken from the depca driver via a2065.c */
|
||||
static void lance_load_multicast(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_init_block *ib = lp->init_block;
|
||||
volatile u16 *mcast_table = (u16 *)&ib->filter;
|
||||
struct netdev_hw_addr *ha;
|
||||
u32 crc;
|
||||
|
||||
/* set all multicast bits */
|
||||
if (dev->flags & IFF_ALLMULTI) {
|
||||
ib->filter[0] = 0xffffffff;
|
||||
ib->filter[1] = 0xffffffff;
|
||||
return;
|
||||
}
|
||||
/* clear the multicast filter */
|
||||
ib->filter[0] = 0;
|
||||
ib->filter[1] = 0;
|
||||
|
||||
/* Add addresses */
|
||||
netdev_for_each_mc_addr(ha, dev) {
|
||||
crc = ether_crc_le(6, ha->addr);
|
||||
crc = crc >> 26;
|
||||
mcast_table[crc >> 4] |= 1 << (crc & 0xf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void lance_set_multicast(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_init_block *ib = lp->init_block;
|
||||
int stopped;
|
||||
|
||||
stopped = netif_queue_stopped(dev);
|
||||
if (!stopped)
|
||||
netif_stop_queue(dev);
|
||||
|
||||
while (lp->tx_old != lp->tx_new)
|
||||
schedule();
|
||||
|
||||
WRITERAP(lp, LE_CSR0);
|
||||
WRITERDP(lp, LE_C0_STOP);
|
||||
lance_init_ring(dev);
|
||||
|
||||
if (dev->flags & IFF_PROMISC) {
|
||||
ib->mode |= LE_MO_PROM;
|
||||
} else {
|
||||
ib->mode &= ~LE_MO_PROM;
|
||||
lance_load_multicast(dev);
|
||||
}
|
||||
load_csrs(lp);
|
||||
init_restart_lance(lp);
|
||||
|
||||
if (!stopped)
|
||||
netif_start_queue(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lance_set_multicast);
|
||||
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
void lance_poll(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
|
||||
spin_lock(&lp->devlock);
|
||||
WRITERAP(lp, LE_CSR0);
|
||||
WRITERDP(lp, LE_C0_STRT);
|
||||
spin_unlock(&lp->devlock);
|
||||
lance_interrupt(dev->irq, dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
MODULE_LICENSE("GPL");
|
250
drivers/net/ethernet/amd/7990.h
Normal file
250
drivers/net/ethernet/amd/7990.h
Normal file
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* 7990.h -- LANCE ethernet IC generic routines.
|
||||
* This is an attempt to separate out the bits of various ethernet
|
||||
* drivers that are common because they all use the AMD 7990 LANCE
|
||||
* (Local Area Network Controller for Ethernet) chip.
|
||||
*
|
||||
* Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
|
||||
*
|
||||
* Most of this stuff was obtained by looking at other LANCE drivers,
|
||||
* in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful.
|
||||
*/
|
||||
|
||||
#ifndef _7990_H
|
||||
#define _7990_H
|
||||
|
||||
/* The lance only has two register locations. We communicate mostly via memory. */
|
||||
#define LANCE_RDP 0 /* Register Data Port */
|
||||
#define LANCE_RAP 2 /* Register Address Port */
|
||||
|
||||
/* Transmit/receive ring definitions.
|
||||
* We allow the specific drivers to override these defaults if they want to.
|
||||
* NB: according to lance.c, increasing the number of buffers is a waste
|
||||
* of space and reduces the chance that an upper layer will be able to
|
||||
* reorder queued Tx packets based on priority. [Clearly there is a minimum
|
||||
* limit too: too small and we drop rx packets and can't tx at full speed.]
|
||||
* 4+4 seems to be the usual setting; the atarilance driver uses 3 and 5.
|
||||
*/
|
||||
|
||||
/* Blast! This won't work. The problem is that we can't specify a default
|
||||
* setting because that would cause the lance_init_block struct to be
|
||||
* too long (and overflow the RAM on shared-memory cards like the HP LANCE.
|
||||
*/
|
||||
#ifndef LANCE_LOG_TX_BUFFERS
|
||||
#define LANCE_LOG_TX_BUFFERS 1
|
||||
#define LANCE_LOG_RX_BUFFERS 3
|
||||
#endif
|
||||
|
||||
#define TX_RING_SIZE (1 << LANCE_LOG_TX_BUFFERS)
|
||||
#define RX_RING_SIZE (1 << LANCE_LOG_RX_BUFFERS)
|
||||
#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
|
||||
#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
|
||||
#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29)
|
||||
#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29)
|
||||
#define PKT_BUFF_SIZE (1544)
|
||||
#define RX_BUFF_SIZE PKT_BUFF_SIZE
|
||||
#define TX_BUFF_SIZE PKT_BUFF_SIZE
|
||||
|
||||
/* Each receive buffer is described by a receive message descriptor (RMD) */
|
||||
struct lance_rx_desc {
|
||||
volatile unsigned short rmd0; /* low address of packet */
|
||||
volatile unsigned char rmd1_bits; /* descriptor bits */
|
||||
volatile unsigned char rmd1_hadr; /* high address of packet */
|
||||
volatile short length; /* This length is 2s complement (negative)!
|
||||
* Buffer length */
|
||||
volatile unsigned short mblength; /* Actual number of bytes received */
|
||||
};
|
||||
|
||||
/* Ditto for TMD: */
|
||||
struct lance_tx_desc {
|
||||
volatile unsigned short tmd0; /* low address of packet */
|
||||
volatile unsigned char tmd1_bits; /* descriptor bits */
|
||||
volatile unsigned char tmd1_hadr; /* high address of packet */
|
||||
volatile short length; /* Length is 2s complement (negative)! */
|
||||
volatile unsigned short misc;
|
||||
};
|
||||
|
||||
/* There are three memory structures accessed by the LANCE:
|
||||
* the initialization block, the receive and transmit descriptor rings,
|
||||
* and the data buffers themselves. In fact we might as well put the
|
||||
* init block,the Tx and Rx rings and the buffers together in memory:
|
||||
*/
|
||||
struct lance_init_block {
|
||||
volatile unsigned short mode; /* Pre-set mode (reg. 15) */
|
||||
volatile unsigned char phys_addr[6]; /* Physical ethernet address */
|
||||
volatile unsigned filter[2]; /* Multicast filter (64 bits) */
|
||||
|
||||
/* Receive and transmit ring base, along with extra bits. */
|
||||
volatile unsigned short rx_ptr; /* receive descriptor addr */
|
||||
volatile unsigned short rx_len; /* receive len and high addr */
|
||||
volatile unsigned short tx_ptr; /* transmit descriptor addr */
|
||||
volatile unsigned short tx_len; /* transmit len and high addr */
|
||||
|
||||
/* The Tx and Rx ring entries must be aligned on 8-byte boundaries.
|
||||
* This will be true if this whole struct is 8-byte aligned.
|
||||
*/
|
||||
volatile struct lance_tx_desc btx_ring[TX_RING_SIZE];
|
||||
volatile struct lance_rx_desc brx_ring[RX_RING_SIZE];
|
||||
|
||||
volatile char tx_buf[TX_RING_SIZE][TX_BUFF_SIZE];
|
||||
volatile char rx_buf[RX_RING_SIZE][RX_BUFF_SIZE];
|
||||
/* we use this just to make the struct big enough that we can move its startaddr
|
||||
* in order to force alignment to an eight byte boundary.
|
||||
*/
|
||||
};
|
||||
|
||||
/* This is where we keep all the stuff the driver needs to know about.
|
||||
* I'm definitely unhappy about the mechanism for allowing specific
|
||||
* drivers to add things...
|
||||
*/
|
||||
struct lance_private {
|
||||
const char *name;
|
||||
unsigned long base;
|
||||
volatile struct lance_init_block *init_block; /* CPU address of RAM */
|
||||
volatile struct lance_init_block *lance_init_block; /* LANCE address of RAM */
|
||||
|
||||
int rx_new, tx_new;
|
||||
int rx_old, tx_old;
|
||||
|
||||
int lance_log_rx_bufs, lance_log_tx_bufs;
|
||||
int rx_ring_mod_mask, tx_ring_mod_mask;
|
||||
|
||||
int tpe; /* TPE is selected */
|
||||
int auto_select; /* cable-selection is by carrier */
|
||||
unsigned short busmaster_regval;
|
||||
|
||||
unsigned int irq; /* IRQ to register */
|
||||
|
||||
/* This is because the HP LANCE is disgusting and you have to check
|
||||
* a DIO-specific register every time you read/write the LANCE regs :-<
|
||||
* [could we get away with making these some sort of macro?]
|
||||
*/
|
||||
void (*writerap)(void *, unsigned short);
|
||||
void (*writerdp)(void *, unsigned short);
|
||||
unsigned short (*readrdp)(void *);
|
||||
spinlock_t devlock;
|
||||
char tx_full;
|
||||
};
|
||||
|
||||
/*
|
||||
* Am7990 Control and Status Registers
|
||||
*/
|
||||
#define LE_CSR0 0x0000 /* LANCE Controller Status */
|
||||
#define LE_CSR1 0x0001 /* IADR[15:0] (bit0==0 ie word aligned) */
|
||||
#define LE_CSR2 0x0002 /* IADR[23:16] (high bits reserved) */
|
||||
#define LE_CSR3 0x0003 /* Misc */
|
||||
|
||||
/*
|
||||
* Bit definitions for CSR0 (LANCE Controller Status)
|
||||
*/
|
||||
#define LE_C0_ERR 0x8000 /* Error = BABL | CERR | MISS | MERR */
|
||||
#define LE_C0_BABL 0x4000 /* Babble: Transmitted too many bits */
|
||||
#define LE_C0_CERR 0x2000 /* No Heartbeat (10BASE-T) */
|
||||
#define LE_C0_MISS 0x1000 /* Missed Frame (no rx buffer to put it in) */
|
||||
#define LE_C0_MERR 0x0800 /* Memory Error */
|
||||
#define LE_C0_RINT 0x0400 /* Receive Interrupt */
|
||||
#define LE_C0_TINT 0x0200 /* Transmit Interrupt */
|
||||
#define LE_C0_IDON 0x0100 /* Initialization Done */
|
||||
#define LE_C0_INTR 0x0080 /* Interrupt Flag
|
||||
= BABL | MISS | MERR | RINT | TINT | IDON */
|
||||
#define LE_C0_INEA 0x0040 /* Interrupt Enable */
|
||||
#define LE_C0_RXON 0x0020 /* Receive On */
|
||||
#define LE_C0_TXON 0x0010 /* Transmit On */
|
||||
#define LE_C0_TDMD 0x0008 /* Transmit Demand */
|
||||
#define LE_C0_STOP 0x0004 /* Stop */
|
||||
#define LE_C0_STRT 0x0002 /* Start */
|
||||
#define LE_C0_INIT 0x0001 /* Initialize */
|
||||
|
||||
|
||||
/*
|
||||
* Bit definitions for CSR3
|
||||
*/
|
||||
#define LE_C3_BSWP 0x0004 /* Byte Swap (on for big endian byte order) */
|
||||
#define LE_C3_ACON 0x0002 /* ALE Control (on for active low ALE) */
|
||||
#define LE_C3_BCON 0x0001 /* Byte Control */
|
||||
|
||||
|
||||
/*
|
||||
* Mode Flags
|
||||
*/
|
||||
#define LE_MO_PROM 0x8000 /* Promiscuous Mode */
|
||||
/* these next ones 0x4000 -- 0x0080 are not available on the LANCE 7990,
|
||||
* but they are in NetBSD's am7990.h, presumably for backwards-compatible chips
|
||||
*/
|
||||
#define LE_MO_DRCVBC 0x4000 /* disable receive broadcast */
|
||||
#define LE_MO_DRCVPA 0x2000 /* disable physical address detection */
|
||||
#define LE_MO_DLNKTST 0x1000 /* disable link status */
|
||||
#define LE_MO_DAPC 0x0800 /* disable automatic polarity correction */
|
||||
#define LE_MO_MENDECL 0x0400 /* MENDEC loopback mode */
|
||||
#define LE_MO_LRTTSEL 0x0200 /* lower RX threshold / TX mode selection */
|
||||
#define LE_MO_PSEL1 0x0100 /* port selection bit1 */
|
||||
#define LE_MO_PSEL0 0x0080 /* port selection bit0 */
|
||||
/* and this one is from the C-LANCE data sheet... */
|
||||
#define LE_MO_EMBA 0x0080 /* Enable Modified Backoff Algorithm
|
||||
(C-LANCE, not original LANCE) */
|
||||
#define LE_MO_INTL 0x0040 /* Internal Loopback */
|
||||
#define LE_MO_DRTY 0x0020 /* Disable Retry */
|
||||
#define LE_MO_FCOLL 0x0010 /* Force Collision */
|
||||
#define LE_MO_DXMTFCS 0x0008 /* Disable Transmit CRC */
|
||||
#define LE_MO_LOOP 0x0004 /* Loopback Enable */
|
||||
#define LE_MO_DTX 0x0002 /* Disable Transmitter */
|
||||
#define LE_MO_DRX 0x0001 /* Disable Receiver */
|
||||
|
||||
|
||||
/*
|
||||
* Receive Flags
|
||||
*/
|
||||
#define LE_R1_OWN 0x80 /* LANCE owns the descriptor */
|
||||
#define LE_R1_ERR 0x40 /* Error */
|
||||
#define LE_R1_FRA 0x20 /* Framing Error */
|
||||
#define LE_R1_OFL 0x10 /* Overflow Error */
|
||||
#define LE_R1_CRC 0x08 /* CRC Error */
|
||||
#define LE_R1_BUF 0x04 /* Buffer Error */
|
||||
#define LE_R1_SOP 0x02 /* Start of Packet */
|
||||
#define LE_R1_EOP 0x01 /* End of Packet */
|
||||
#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */
|
||||
|
||||
|
||||
/*
|
||||
* Transmit Flags
|
||||
*/
|
||||
#define LE_T1_OWN 0x80 /* LANCE owns the descriptor */
|
||||
#define LE_T1_ERR 0x40 /* Error */
|
||||
#define LE_T1_RES 0x20 /* Reserved, LANCE writes this with a zero */
|
||||
#define LE_T1_EMORE 0x10 /* More than one retry needed */
|
||||
#define LE_T1_EONE 0x08 /* One retry needed */
|
||||
#define LE_T1_EDEF 0x04 /* Deferred */
|
||||
#define LE_T1_SOP 0x02 /* Start of Packet */
|
||||
#define LE_T1_EOP 0x01 /* End of Packet */
|
||||
#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */
|
||||
|
||||
/*
|
||||
* Error Flags
|
||||
*/
|
||||
#define LE_T3_BUF 0x8000 /* Buffer Error */
|
||||
#define LE_T3_UFL 0x4000 /* Underflow Error */
|
||||
#define LE_T3_LCOL 0x1000 /* Late Collision */
|
||||
#define LE_T3_CLOS 0x0800 /* Loss of Carrier */
|
||||
#define LE_T3_RTY 0x0400 /* Retry Error */
|
||||
#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry */
|
||||
|
||||
/* Miscellaneous useful macros */
|
||||
|
||||
#define TX_BUFFS_AVAIL ((lp->tx_old <= lp->tx_new) ? \
|
||||
lp->tx_old + lp->tx_ring_mod_mask - lp->tx_new : \
|
||||
lp->tx_old - lp->tx_new - 1)
|
||||
|
||||
/* The LANCE only uses 24 bit addresses. This does the obvious thing. */
|
||||
#define LANCE_ADDR(x) ((int)(x) & ~0xff000000)
|
||||
|
||||
/* Now the prototypes we export */
|
||||
int lance_open(struct net_device *dev);
|
||||
int lance_close(struct net_device *dev);
|
||||
int lance_start_xmit(struct sk_buff *skb, struct net_device *dev);
|
||||
void lance_set_multicast(struct net_device *dev);
|
||||
void lance_tx_timeout(struct net_device *dev);
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
void lance_poll(struct net_device *dev);
|
||||
#endif
|
||||
|
||||
#endif /* ndef _7990_H */
|
205
drivers/net/ethernet/amd/Kconfig
Normal file
205
drivers/net/ethernet/amd/Kconfig
Normal file
|
@ -0,0 +1,205 @@
|
|||
#
|
||||
# AMD network device configuration
|
||||
#
|
||||
|
||||
config NET_VENDOR_AMD
|
||||
bool "AMD devices"
|
||||
default y
|
||||
depends on DIO || MACH_DECSTATION || MVME147 || ATARI || SUN3 || \
|
||||
SUN3X || SBUS || PCI || ZORRO || (ISA && ISA_DMA_API) || \
|
||||
(ARM && ARCH_EBSA110) || ISA || EISA || PCMCIA || ARM64
|
||||
---help---
|
||||
If you have a network (Ethernet) chipset belonging to this class,
|
||||
say Y.
|
||||
|
||||
Note that the answer to this question does not directly affect
|
||||
the kernel: saying N will just case the configurator to skip all
|
||||
the questions regarding AMD chipsets. If you say Y, you will be asked
|
||||
for your specific chipset/driver in the following questions.
|
||||
|
||||
if NET_VENDOR_AMD
|
||||
|
||||
config A2065
|
||||
tristate "A2065 support"
|
||||
depends on ZORRO
|
||||
select CRC32
|
||||
---help---
|
||||
If you have a Commodore A2065 Ethernet adapter, say Y. Otherwise,
|
||||
say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called a2065.
|
||||
|
||||
config AMD8111_ETH
|
||||
tristate "AMD 8111 (new PCI LANCE) support"
|
||||
depends on PCI
|
||||
select CRC32
|
||||
select MII
|
||||
---help---
|
||||
If you have an AMD 8111-based PCI LANCE ethernet card,
|
||||
answer Y here and read the Ethernet-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called amd8111e.
|
||||
|
||||
config LANCE
|
||||
tristate "AMD LANCE and PCnet (AT1500 and NE2100) support"
|
||||
depends on ISA && ISA_DMA_API
|
||||
---help---
|
||||
If you have a network (Ethernet) card of this type, say Y and read
|
||||
the Ethernet-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>. Some LinkSys cards are
|
||||
of this type.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called lance. This is recommended.
|
||||
|
||||
config PCNET32
|
||||
tristate "AMD PCnet32 PCI support"
|
||||
depends on PCI
|
||||
select CRC32
|
||||
select MII
|
||||
---help---
|
||||
If you have a PCnet32 or PCnetPCI based network (Ethernet) card,
|
||||
answer Y here and read the Ethernet-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called pcnet32.
|
||||
|
||||
config ARIADNE
|
||||
tristate "Ariadne support"
|
||||
depends on ZORRO
|
||||
---help---
|
||||
If you have a Village Tronic Ariadne Ethernet adapter, say Y.
|
||||
Otherwise, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called ariadne.
|
||||
|
||||
config ARM_AM79C961A
|
||||
bool "ARM EBSA110 AM79C961A support"
|
||||
depends on ARM && ARCH_EBSA110
|
||||
select CRC32
|
||||
---help---
|
||||
If you wish to compile a kernel for the EBSA-110, then you should
|
||||
always answer Y to this.
|
||||
|
||||
config ATARILANCE
|
||||
tristate "Atari LANCE support"
|
||||
depends on ATARI
|
||||
---help---
|
||||
Say Y to include support for several Atari Ethernet adapters based
|
||||
on the AMD LANCE chipset: RieblCard (with or without battery), or
|
||||
PAMCard VME (also the version by Rhotron, with different addresses).
|
||||
|
||||
config DECLANCE
|
||||
tristate "DEC LANCE ethernet controller support"
|
||||
depends on MACH_DECSTATION
|
||||
select CRC32
|
||||
---help---
|
||||
This driver is for the series of Ethernet controllers produced by
|
||||
DEC (now Compaq) based on the AMD LANCE chipset, including the
|
||||
DEPCA series. (This chipset is better known via the NE2100 cards.)
|
||||
|
||||
config HPLANCE
|
||||
bool "HP on-board LANCE support"
|
||||
depends on DIO
|
||||
select CRC32
|
||||
---help---
|
||||
If you want to use the builtin "LANCE" Ethernet controller on an
|
||||
HP300 machine, say Y here.
|
||||
|
||||
config MIPS_AU1X00_ENET
|
||||
tristate "MIPS AU1000 Ethernet support"
|
||||
depends on MIPS_ALCHEMY
|
||||
select PHYLIB
|
||||
select CRC32
|
||||
---help---
|
||||
If you have an Alchemy Semi AU1X00 based system
|
||||
say Y. Otherwise, say N.
|
||||
|
||||
config MVME147_NET
|
||||
tristate "MVME147 (LANCE) Ethernet support"
|
||||
depends on MVME147
|
||||
select CRC32
|
||||
---help---
|
||||
Support for the on-board Ethernet interface on the Motorola MVME147
|
||||
single-board computer. Say Y here to include the
|
||||
driver for this chip in your kernel.
|
||||
To compile this driver as a module, choose M here.
|
||||
|
||||
config PCMCIA_NMCLAN
|
||||
tristate "New Media PCMCIA support"
|
||||
depends on PCMCIA
|
||||
help
|
||||
Say Y here if you intend to attach a New Media Ethernet or LiveWire
|
||||
PCMCIA (PC-card) Ethernet card to your computer.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called nmclan_cs. If unsure, say N.
|
||||
|
||||
config NI65
|
||||
tristate "NI6510 support"
|
||||
depends on ISA && ISA_DMA_API
|
||||
---help---
|
||||
If you have a network (Ethernet) card of this type, say Y and read
|
||||
the Ethernet-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called ni65.
|
||||
|
||||
config SUN3LANCE
|
||||
tristate "Sun3/Sun3x on-board LANCE support"
|
||||
depends on (SUN3 || SUN3X)
|
||||
---help---
|
||||
Most Sun3 and Sun3x motherboards (including the 3/50, 3/60 and 3/80)
|
||||
featured an AMD LANCE 10Mbit Ethernet controller on board; say Y
|
||||
here to compile in the Linux driver for this and enable Ethernet.
|
||||
General Linux information on the Sun 3 and 3x series (now
|
||||
discontinued) is at
|
||||
<http://www.angelfire.com/ca2/tech68k/sun3.html>.
|
||||
|
||||
If you're not building a kernel for a Sun 3, say N.
|
||||
|
||||
config SUNLANCE
|
||||
tristate "Sun LANCE support"
|
||||
depends on SBUS
|
||||
select CRC32
|
||||
---help---
|
||||
This driver supports the "le" interface present on all 32-bit Sparc
|
||||
systems, on some older Ultra systems and as an Sbus option. These
|
||||
cards are based on the AMD LANCE chipset, which is better known
|
||||
via the NE2100 cards.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called sunlance.
|
||||
|
||||
config AMD_XGBE
|
||||
tristate "AMD 10GbE Ethernet driver"
|
||||
depends on OF_NET
|
||||
select PHYLIB
|
||||
select AMD_XGBE_PHY
|
||||
select BITREVERSE
|
||||
select CRC32
|
||||
select PTP_1588_CLOCK
|
||||
---help---
|
||||
This driver supports the AMD 10GbE Ethernet device found on an
|
||||
AMD SoC.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called amd-xgbe.
|
||||
|
||||
config AMD_XGBE_DCB
|
||||
bool "Data Center Bridging (DCB) support"
|
||||
default n
|
||||
depends on AMD_XGBE && DCB
|
||||
---help---
|
||||
Say Y here to enable Data Center Bridging (DCB) support in the
|
||||
driver.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
endif # NET_VENDOR_AMD
|
20
drivers/net/ethernet/amd/Makefile
Normal file
20
drivers/net/ethernet/amd/Makefile
Normal file
|
@ -0,0 +1,20 @@
|
|||
#
|
||||
# Makefile for the AMD network device drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_A2065) += a2065.o
|
||||
obj-$(CONFIG_AMD8111_ETH) += amd8111e.o
|
||||
obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o
|
||||
obj-$(CONFIG_ARIADNE) += ariadne.o
|
||||
obj-$(CONFIG_ATARILANCE) += atarilance.o
|
||||
obj-$(CONFIG_DECLANCE) += declance.o
|
||||
obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
|
||||
obj-$(CONFIG_LANCE) += lance.o
|
||||
obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
|
||||
obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
|
||||
obj-$(CONFIG_PCMCIA_NMCLAN) += nmclan_cs.o
|
||||
obj-$(CONFIG_NI65) += ni65.o
|
||||
obj-$(CONFIG_PCNET32) += pcnet32.o
|
||||
obj-$(CONFIG_SUN3LANCE) += sun3lance.o
|
||||
obj-$(CONFIG_SUNLANCE) += sunlance.o
|
||||
obj-$(CONFIG_AMD_XGBE) += xgbe/
|
783
drivers/net/ethernet/amd/a2065.c
Normal file
783
drivers/net/ethernet/amd/a2065.c
Normal file
|
@ -0,0 +1,783 @@
|
|||
/*
|
||||
* Amiga Linux/68k A2065 Ethernet Driver
|
||||
*
|
||||
* (C) Copyright 1995-2003 by Geert Uytterhoeven <geert@linux-m68k.org>
|
||||
*
|
||||
* Fixes and tips by:
|
||||
* - Janos Farkas (CHEXUM@sparta.banki.hu)
|
||||
* - Jes Degn Soerensen (jds@kom.auc.dk)
|
||||
* - Matt Domsch (Matt_Domsch@dell.com)
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* This program is based on
|
||||
*
|
||||
* ariadne.?: Amiga Linux/68k Ariadne Ethernet Driver
|
||||
* (C) Copyright 1995 by Geert Uytterhoeven,
|
||||
* Peter De Schrijver
|
||||
*
|
||||
* lance.c: An AMD LANCE ethernet driver for linux.
|
||||
* Written 1993-94 by Donald Becker.
|
||||
*
|
||||
* Am79C960: PCnet(tm)-ISA Single-Chip Ethernet Controller
|
||||
* Advanced Micro Devices
|
||||
* Publication #16907, Rev. B, Amendment/0, May 1994
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of the Linux
|
||||
* distribution for more details.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* The A2065 is a Zorro-II board made by Commodore/Ameristar. It contains:
|
||||
*
|
||||
* - an Am7990 Local Area Network Controller for Ethernet (LANCE) with
|
||||
* both 10BASE-2 (thin coax) and AUI (DB-15) connectors
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
/*#define DEBUG*/
|
||||
/*#define TEST_HITS*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/zorro.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/amigaints.h>
|
||||
#include <asm/amigahw.h>
|
||||
|
||||
#include "a2065.h"
|
||||
|
||||
/* Transmit/Receive Ring Definitions */
|
||||
|
||||
#define LANCE_LOG_TX_BUFFERS (2)
|
||||
#define LANCE_LOG_RX_BUFFERS (4)
|
||||
|
||||
#define TX_RING_SIZE (1 << LANCE_LOG_TX_BUFFERS)
|
||||
#define RX_RING_SIZE (1 << LANCE_LOG_RX_BUFFERS)
|
||||
|
||||
#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
|
||||
#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
|
||||
|
||||
#define PKT_BUF_SIZE (1544)
|
||||
#define RX_BUFF_SIZE PKT_BUF_SIZE
|
||||
#define TX_BUFF_SIZE PKT_BUF_SIZE
|
||||
|
||||
/* Layout of the Lance's RAM Buffer */
|
||||
|
||||
struct lance_init_block {
|
||||
unsigned short mode; /* Pre-set mode (reg. 15) */
|
||||
unsigned char phys_addr[6]; /* Physical ethernet address */
|
||||
unsigned filter[2]; /* Multicast filter. */
|
||||
|
||||
/* Receive and transmit ring base, along with extra bits. */
|
||||
unsigned short rx_ptr; /* receive descriptor addr */
|
||||
unsigned short rx_len; /* receive len and high addr */
|
||||
unsigned short tx_ptr; /* transmit descriptor addr */
|
||||
unsigned short tx_len; /* transmit len and high addr */
|
||||
|
||||
/* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
|
||||
struct lance_rx_desc brx_ring[RX_RING_SIZE];
|
||||
struct lance_tx_desc btx_ring[TX_RING_SIZE];
|
||||
|
||||
char rx_buf[RX_RING_SIZE][RX_BUFF_SIZE];
|
||||
char tx_buf[TX_RING_SIZE][TX_BUFF_SIZE];
|
||||
};
|
||||
|
||||
/* Private Device Data */
|
||||
|
||||
struct lance_private {
|
||||
char *name;
|
||||
volatile struct lance_regs *ll;
|
||||
volatile struct lance_init_block *init_block; /* Hosts view */
|
||||
volatile struct lance_init_block *lance_init_block; /* Lance view */
|
||||
|
||||
int rx_new, tx_new;
|
||||
int rx_old, tx_old;
|
||||
|
||||
int lance_log_rx_bufs, lance_log_tx_bufs;
|
||||
int rx_ring_mod_mask, tx_ring_mod_mask;
|
||||
|
||||
int tpe; /* cable-selection is TPE */
|
||||
int auto_select; /* cable-selection by carrier */
|
||||
unsigned short busmaster_regval;
|
||||
|
||||
#ifdef CONFIG_SUNLANCE
|
||||
struct Linux_SBus_DMA *ledma; /* if set this points to ledma and arch=4m */
|
||||
int burst_sizes; /* ledma SBus burst sizes */
|
||||
#endif
|
||||
struct timer_list multicast_timer;
|
||||
};
|
||||
|
||||
#define LANCE_ADDR(x) ((int)(x) & ~0xff000000)
|
||||
|
||||
/* Load the CSR registers */
|
||||
static void load_csrs(struct lance_private *lp)
|
||||
{
|
||||
volatile struct lance_regs *ll = lp->ll;
|
||||
volatile struct lance_init_block *aib = lp->lance_init_block;
|
||||
int leptr = LANCE_ADDR(aib);
|
||||
|
||||
ll->rap = LE_CSR1;
|
||||
ll->rdp = (leptr & 0xFFFF);
|
||||
ll->rap = LE_CSR2;
|
||||
ll->rdp = leptr >> 16;
|
||||
ll->rap = LE_CSR3;
|
||||
ll->rdp = lp->busmaster_regval;
|
||||
|
||||
/* Point back to csr0 */
|
||||
ll->rap = LE_CSR0;
|
||||
}
|
||||
|
||||
/* Setup the Lance Rx and Tx rings */
|
||||
static void lance_init_ring(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_init_block *ib = lp->init_block;
|
||||
volatile struct lance_init_block *aib = lp->lance_init_block;
|
||||
/* for LANCE_ADDR computations */
|
||||
int leptr;
|
||||
int i;
|
||||
|
||||
/* Lock out other processes while setting up hardware */
|
||||
netif_stop_queue(dev);
|
||||
lp->rx_new = lp->tx_new = 0;
|
||||
lp->rx_old = lp->tx_old = 0;
|
||||
|
||||
ib->mode = 0;
|
||||
|
||||
/* Copy the ethernet address to the lance init block
|
||||
* Note that on the sparc you need to swap the ethernet address.
|
||||
*/
|
||||
ib->phys_addr[0] = dev->dev_addr[1];
|
||||
ib->phys_addr[1] = dev->dev_addr[0];
|
||||
ib->phys_addr[2] = dev->dev_addr[3];
|
||||
ib->phys_addr[3] = dev->dev_addr[2];
|
||||
ib->phys_addr[4] = dev->dev_addr[5];
|
||||
ib->phys_addr[5] = dev->dev_addr[4];
|
||||
|
||||
/* Setup the Tx ring entries */
|
||||
netdev_dbg(dev, "TX rings:\n");
|
||||
for (i = 0; i <= 1 << lp->lance_log_tx_bufs; i++) {
|
||||
leptr = LANCE_ADDR(&aib->tx_buf[i][0]);
|
||||
ib->btx_ring[i].tmd0 = leptr;
|
||||
ib->btx_ring[i].tmd1_hadr = leptr >> 16;
|
||||
ib->btx_ring[i].tmd1_bits = 0;
|
||||
ib->btx_ring[i].length = 0xf000; /* The ones required by tmd2 */
|
||||
ib->btx_ring[i].misc = 0;
|
||||
if (i < 3)
|
||||
netdev_dbg(dev, "%d: 0x%08x\n", i, leptr);
|
||||
}
|
||||
|
||||
/* Setup the Rx ring entries */
|
||||
netdev_dbg(dev, "RX rings:\n");
|
||||
for (i = 0; i < 1 << lp->lance_log_rx_bufs; i++) {
|
||||
leptr = LANCE_ADDR(&aib->rx_buf[i][0]);
|
||||
|
||||
ib->brx_ring[i].rmd0 = leptr;
|
||||
ib->brx_ring[i].rmd1_hadr = leptr >> 16;
|
||||
ib->brx_ring[i].rmd1_bits = LE_R1_OWN;
|
||||
ib->brx_ring[i].length = -RX_BUFF_SIZE | 0xf000;
|
||||
ib->brx_ring[i].mblength = 0;
|
||||
if (i < 3)
|
||||
netdev_dbg(dev, "%d: 0x%08x\n", i, leptr);
|
||||
}
|
||||
|
||||
/* Setup the initialization block */
|
||||
|
||||
/* Setup rx descriptor pointer */
|
||||
leptr = LANCE_ADDR(&aib->brx_ring);
|
||||
ib->rx_len = (lp->lance_log_rx_bufs << 13) | (leptr >> 16);
|
||||
ib->rx_ptr = leptr;
|
||||
netdev_dbg(dev, "RX ptr: %08x\n", leptr);
|
||||
|
||||
/* Setup tx descriptor pointer */
|
||||
leptr = LANCE_ADDR(&aib->btx_ring);
|
||||
ib->tx_len = (lp->lance_log_tx_bufs << 13) | (leptr >> 16);
|
||||
ib->tx_ptr = leptr;
|
||||
netdev_dbg(dev, "TX ptr: %08x\n", leptr);
|
||||
|
||||
/* Clear the multicast filter */
|
||||
ib->filter[0] = 0;
|
||||
ib->filter[1] = 0;
|
||||
}
|
||||
|
||||
static int init_restart_lance(struct lance_private *lp)
|
||||
{
|
||||
volatile struct lance_regs *ll = lp->ll;
|
||||
int i;
|
||||
|
||||
ll->rap = LE_CSR0;
|
||||
ll->rdp = LE_C0_INIT;
|
||||
|
||||
/* Wait for the lance to complete initialization */
|
||||
for (i = 0; (i < 100) && !(ll->rdp & (LE_C0_ERR | LE_C0_IDON)); i++)
|
||||
barrier();
|
||||
if ((i == 100) || (ll->rdp & LE_C0_ERR)) {
|
||||
pr_err("unopened after %d ticks, csr0=%04x\n", i, ll->rdp);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Clear IDON by writing a "1", enable interrupts and start lance */
|
||||
ll->rdp = LE_C0_IDON;
|
||||
ll->rdp = LE_C0_INEA | LE_C0_STRT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lance_rx(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_init_block *ib = lp->init_block;
|
||||
volatile struct lance_regs *ll = lp->ll;
|
||||
volatile struct lance_rx_desc *rd;
|
||||
unsigned char bits;
|
||||
|
||||
#ifdef TEST_HITS
|
||||
int i;
|
||||
char buf[RX_RING_SIZE + 1];
|
||||
|
||||
for (i = 0; i < RX_RING_SIZE; i++) {
|
||||
char r1_own = ib->brx_ring[i].rmd1_bits & LE_R1_OWN;
|
||||
if (i == lp->rx_new)
|
||||
buf[i] = r1_own ? '_' : 'X';
|
||||
else
|
||||
buf[i] = r1_own ? '.' : '1';
|
||||
}
|
||||
buf[RX_RING_SIZE] = 0;
|
||||
|
||||
pr_debug("RxRing TestHits: [%s]\n", buf);
|
||||
#endif
|
||||
|
||||
ll->rdp = LE_C0_RINT | LE_C0_INEA;
|
||||
for (rd = &ib->brx_ring[lp->rx_new];
|
||||
!((bits = rd->rmd1_bits) & LE_R1_OWN);
|
||||
rd = &ib->brx_ring[lp->rx_new]) {
|
||||
|
||||
/* We got an incomplete frame? */
|
||||
if ((bits & LE_R1_POK) != LE_R1_POK) {
|
||||
dev->stats.rx_over_errors++;
|
||||
dev->stats.rx_errors++;
|
||||
continue;
|
||||
} else if (bits & LE_R1_ERR) {
|
||||
/* Count only the end frame as a rx error,
|
||||
* not the beginning
|
||||
*/
|
||||
if (bits & LE_R1_BUF)
|
||||
dev->stats.rx_fifo_errors++;
|
||||
if (bits & LE_R1_CRC)
|
||||
dev->stats.rx_crc_errors++;
|
||||
if (bits & LE_R1_OFL)
|
||||
dev->stats.rx_over_errors++;
|
||||
if (bits & LE_R1_FRA)
|
||||
dev->stats.rx_frame_errors++;
|
||||
if (bits & LE_R1_EOP)
|
||||
dev->stats.rx_errors++;
|
||||
} else {
|
||||
int len = (rd->mblength & 0xfff) - 4;
|
||||
struct sk_buff *skb = netdev_alloc_skb(dev, len + 2);
|
||||
|
||||
if (!skb) {
|
||||
dev->stats.rx_dropped++;
|
||||
rd->mblength = 0;
|
||||
rd->rmd1_bits = LE_R1_OWN;
|
||||
lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
skb_reserve(skb, 2); /* 16 byte align */
|
||||
skb_put(skb, len); /* make room */
|
||||
skb_copy_to_linear_data(skb,
|
||||
(unsigned char *)&ib->rx_buf[lp->rx_new][0],
|
||||
len);
|
||||
skb->protocol = eth_type_trans(skb, dev);
|
||||
netif_rx(skb);
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += len;
|
||||
}
|
||||
|
||||
/* Return the packet to the pool */
|
||||
rd->mblength = 0;
|
||||
rd->rmd1_bits = LE_R1_OWN;
|
||||
lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lance_tx(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_init_block *ib = lp->init_block;
|
||||
volatile struct lance_regs *ll = lp->ll;
|
||||
volatile struct lance_tx_desc *td;
|
||||
int i, j;
|
||||
int status;
|
||||
|
||||
/* csr0 is 2f3 */
|
||||
ll->rdp = LE_C0_TINT | LE_C0_INEA;
|
||||
/* csr0 is 73 */
|
||||
|
||||
j = lp->tx_old;
|
||||
for (i = j; i != lp->tx_new; i = j) {
|
||||
td = &ib->btx_ring[i];
|
||||
|
||||
/* If we hit a packet not owned by us, stop */
|
||||
if (td->tmd1_bits & LE_T1_OWN)
|
||||
break;
|
||||
|
||||
if (td->tmd1_bits & LE_T1_ERR) {
|
||||
status = td->misc;
|
||||
|
||||
dev->stats.tx_errors++;
|
||||
if (status & LE_T3_RTY)
|
||||
dev->stats.tx_aborted_errors++;
|
||||
if (status & LE_T3_LCOL)
|
||||
dev->stats.tx_window_errors++;
|
||||
|
||||
if (status & LE_T3_CLOS) {
|
||||
dev->stats.tx_carrier_errors++;
|
||||
if (lp->auto_select) {
|
||||
lp->tpe = 1 - lp->tpe;
|
||||
netdev_err(dev, "Carrier Lost, trying %s\n",
|
||||
lp->tpe ? "TPE" : "AUI");
|
||||
/* Stop the lance */
|
||||
ll->rap = LE_CSR0;
|
||||
ll->rdp = LE_C0_STOP;
|
||||
lance_init_ring(dev);
|
||||
load_csrs(lp);
|
||||
init_restart_lance(lp);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* buffer errors and underflows turn off
|
||||
* the transmitter, so restart the adapter
|
||||
*/
|
||||
if (status & (LE_T3_BUF | LE_T3_UFL)) {
|
||||
dev->stats.tx_fifo_errors++;
|
||||
|
||||
netdev_err(dev, "Tx: ERR_BUF|ERR_UFL, restarting\n");
|
||||
/* Stop the lance */
|
||||
ll->rap = LE_CSR0;
|
||||
ll->rdp = LE_C0_STOP;
|
||||
lance_init_ring(dev);
|
||||
load_csrs(lp);
|
||||
init_restart_lance(lp);
|
||||
return 0;
|
||||
}
|
||||
} else if ((td->tmd1_bits & LE_T1_POK) == LE_T1_POK) {
|
||||
/* So we don't count the packet more than once. */
|
||||
td->tmd1_bits &= ~(LE_T1_POK);
|
||||
|
||||
/* One collision before packet was sent. */
|
||||
if (td->tmd1_bits & LE_T1_EONE)
|
||||
dev->stats.collisions++;
|
||||
|
||||
/* More than one collision, be optimistic. */
|
||||
if (td->tmd1_bits & LE_T1_EMORE)
|
||||
dev->stats.collisions += 2;
|
||||
|
||||
dev->stats.tx_packets++;
|
||||
}
|
||||
|
||||
j = (j + 1) & lp->tx_ring_mod_mask;
|
||||
}
|
||||
lp->tx_old = j;
|
||||
ll->rdp = LE_C0_TINT | LE_C0_INEA;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lance_tx_buffs_avail(struct lance_private *lp)
|
||||
{
|
||||
if (lp->tx_old <= lp->tx_new)
|
||||
return lp->tx_old + lp->tx_ring_mod_mask - lp->tx_new;
|
||||
return lp->tx_old - lp->tx_new - 1;
|
||||
}
|
||||
|
||||
static irqreturn_t lance_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct net_device *dev = dev_id;
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_regs *ll = lp->ll;
|
||||
int csr0;
|
||||
|
||||
ll->rap = LE_CSR0; /* LANCE Controller Status */
|
||||
csr0 = ll->rdp;
|
||||
|
||||
if (!(csr0 & LE_C0_INTR)) /* Check if any interrupt has */
|
||||
return IRQ_NONE; /* been generated by the Lance. */
|
||||
|
||||
/* Acknowledge all the interrupt sources ASAP */
|
||||
ll->rdp = csr0 & ~(LE_C0_INEA | LE_C0_TDMD | LE_C0_STOP | LE_C0_STRT |
|
||||
LE_C0_INIT);
|
||||
|
||||
if (csr0 & LE_C0_ERR) {
|
||||
/* Clear the error condition */
|
||||
ll->rdp = LE_C0_BABL | LE_C0_ERR | LE_C0_MISS | LE_C0_INEA;
|
||||
}
|
||||
|
||||
if (csr0 & LE_C0_RINT)
|
||||
lance_rx(dev);
|
||||
|
||||
if (csr0 & LE_C0_TINT)
|
||||
lance_tx(dev);
|
||||
|
||||
/* Log misc errors. */
|
||||
if (csr0 & LE_C0_BABL)
|
||||
dev->stats.tx_errors++; /* Tx babble. */
|
||||
if (csr0 & LE_C0_MISS)
|
||||
dev->stats.rx_errors++; /* Missed a Rx frame. */
|
||||
if (csr0 & LE_C0_MERR) {
|
||||
netdev_err(dev, "Bus master arbitration failure, status %04x\n",
|
||||
csr0);
|
||||
/* Restart the chip. */
|
||||
ll->rdp = LE_C0_STRT;
|
||||
}
|
||||
|
||||
if (netif_queue_stopped(dev) && lance_tx_buffs_avail(lp) > 0)
|
||||
netif_wake_queue(dev);
|
||||
|
||||
ll->rap = LE_CSR0;
|
||||
ll->rdp = (LE_C0_BABL | LE_C0_CERR | LE_C0_MISS | LE_C0_MERR |
|
||||
LE_C0_IDON | LE_C0_INEA);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int lance_open(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_regs *ll = lp->ll;
|
||||
int ret;
|
||||
|
||||
/* Stop the Lance */
|
||||
ll->rap = LE_CSR0;
|
||||
ll->rdp = LE_C0_STOP;
|
||||
|
||||
/* Install the Interrupt handler */
|
||||
ret = request_irq(IRQ_AMIGA_PORTS, lance_interrupt, IRQF_SHARED,
|
||||
dev->name, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
load_csrs(lp);
|
||||
lance_init_ring(dev);
|
||||
|
||||
netif_start_queue(dev);
|
||||
|
||||
return init_restart_lance(lp);
|
||||
}
|
||||
|
||||
static int lance_close(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_regs *ll = lp->ll;
|
||||
|
||||
netif_stop_queue(dev);
|
||||
del_timer_sync(&lp->multicast_timer);
|
||||
|
||||
/* Stop the card */
|
||||
ll->rap = LE_CSR0;
|
||||
ll->rdp = LE_C0_STOP;
|
||||
|
||||
free_irq(IRQ_AMIGA_PORTS, dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lance_reset(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_regs *ll = lp->ll;
|
||||
int status;
|
||||
|
||||
/* Stop the lance */
|
||||
ll->rap = LE_CSR0;
|
||||
ll->rdp = LE_C0_STOP;
|
||||
|
||||
load_csrs(lp);
|
||||
|
||||
lance_init_ring(dev);
|
||||
dev->trans_start = jiffies; /* prevent tx timeout */
|
||||
netif_start_queue(dev);
|
||||
|
||||
status = init_restart_lance(lp);
|
||||
netdev_dbg(dev, "Lance restart=%d\n", status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void lance_tx_timeout(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_regs *ll = lp->ll;
|
||||
|
||||
netdev_err(dev, "transmit timed out, status %04x, reset\n", ll->rdp);
|
||||
lance_reset(dev);
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
|
||||
static netdev_tx_t lance_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_regs *ll = lp->ll;
|
||||
volatile struct lance_init_block *ib = lp->init_block;
|
||||
int entry, skblen;
|
||||
int status = NETDEV_TX_OK;
|
||||
unsigned long flags;
|
||||
|
||||
if (skb_padto(skb, ETH_ZLEN))
|
||||
return NETDEV_TX_OK;
|
||||
skblen = max_t(unsigned, skb->len, ETH_ZLEN);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (!lance_tx_buffs_avail(lp)) {
|
||||
local_irq_restore(flags);
|
||||
return NETDEV_TX_LOCKED;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/* dump the packet */
|
||||
print_hex_dump(KERN_DEBUG, "skb->data: ", DUMP_PREFIX_NONE,
|
||||
16, 1, skb->data, 64, true);
|
||||
#endif
|
||||
entry = lp->tx_new & lp->tx_ring_mod_mask;
|
||||
ib->btx_ring[entry].length = (-skblen) | 0xf000;
|
||||
ib->btx_ring[entry].misc = 0;
|
||||
|
||||
skb_copy_from_linear_data(skb, (void *)&ib->tx_buf[entry][0], skblen);
|
||||
|
||||
/* Now, give the packet to the lance */
|
||||
ib->btx_ring[entry].tmd1_bits = (LE_T1_POK | LE_T1_OWN);
|
||||
lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
|
||||
dev->stats.tx_bytes += skblen;
|
||||
|
||||
if (lance_tx_buffs_avail(lp) <= 0)
|
||||
netif_stop_queue(dev);
|
||||
|
||||
/* Kick the lance: transmit now */
|
||||
ll->rdp = LE_C0_INEA | LE_C0_TDMD;
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* taken from the depca driver */
|
||||
static void lance_load_multicast(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_init_block *ib = lp->init_block;
|
||||
volatile u16 *mcast_table = (u16 *)&ib->filter;
|
||||
struct netdev_hw_addr *ha;
|
||||
u32 crc;
|
||||
|
||||
/* set all multicast bits */
|
||||
if (dev->flags & IFF_ALLMULTI) {
|
||||
ib->filter[0] = 0xffffffff;
|
||||
ib->filter[1] = 0xffffffff;
|
||||
return;
|
||||
}
|
||||
/* clear the multicast filter */
|
||||
ib->filter[0] = 0;
|
||||
ib->filter[1] = 0;
|
||||
|
||||
/* Add addresses */
|
||||
netdev_for_each_mc_addr(ha, dev) {
|
||||
crc = ether_crc_le(6, ha->addr);
|
||||
crc = crc >> 26;
|
||||
mcast_table[crc >> 4] |= 1 << (crc & 0xf);
|
||||
}
|
||||
}
|
||||
|
||||
static void lance_set_multicast(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
volatile struct lance_init_block *ib = lp->init_block;
|
||||
volatile struct lance_regs *ll = lp->ll;
|
||||
|
||||
if (!netif_running(dev))
|
||||
return;
|
||||
|
||||
if (lp->tx_old != lp->tx_new) {
|
||||
mod_timer(&lp->multicast_timer, jiffies + 4);
|
||||
netif_wake_queue(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
netif_stop_queue(dev);
|
||||
|
||||
ll->rap = LE_CSR0;
|
||||
ll->rdp = LE_C0_STOP;
|
||||
lance_init_ring(dev);
|
||||
|
||||
if (dev->flags & IFF_PROMISC) {
|
||||
ib->mode |= LE_MO_PROM;
|
||||
} else {
|
||||
ib->mode &= ~LE_MO_PROM;
|
||||
lance_load_multicast(dev);
|
||||
}
|
||||
load_csrs(lp);
|
||||
init_restart_lance(lp);
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
|
||||
static int a2065_init_one(struct zorro_dev *z,
|
||||
const struct zorro_device_id *ent);
|
||||
static void a2065_remove_one(struct zorro_dev *z);
|
||||
|
||||
|
||||
static struct zorro_device_id a2065_zorro_tbl[] = {
|
||||
{ ZORRO_PROD_CBM_A2065_1 },
|
||||
{ ZORRO_PROD_CBM_A2065_2 },
|
||||
{ ZORRO_PROD_AMERISTAR_A2065 },
|
||||
{ 0 }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(zorro, a2065_zorro_tbl);
|
||||
|
||||
static struct zorro_driver a2065_driver = {
|
||||
.name = "a2065",
|
||||
.id_table = a2065_zorro_tbl,
|
||||
.probe = a2065_init_one,
|
||||
.remove = a2065_remove_one,
|
||||
};
|
||||
|
||||
static const struct net_device_ops lance_netdev_ops = {
|
||||
.ndo_open = lance_open,
|
||||
.ndo_stop = lance_close,
|
||||
.ndo_start_xmit = lance_start_xmit,
|
||||
.ndo_tx_timeout = lance_tx_timeout,
|
||||
.ndo_set_rx_mode = lance_set_multicast,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_change_mtu = eth_change_mtu,
|
||||
.ndo_set_mac_address = eth_mac_addr,
|
||||
};
|
||||
|
||||
static int a2065_init_one(struct zorro_dev *z,
|
||||
const struct zorro_device_id *ent)
|
||||
{
|
||||
struct net_device *dev;
|
||||
struct lance_private *priv;
|
||||
unsigned long board = z->resource.start;
|
||||
unsigned long base_addr = board + A2065_LANCE;
|
||||
unsigned long mem_start = board + A2065_RAM;
|
||||
struct resource *r1, *r2;
|
||||
u32 serial;
|
||||
int err;
|
||||
|
||||
r1 = request_mem_region(base_addr, sizeof(struct lance_regs),
|
||||
"Am7990");
|
||||
if (!r1)
|
||||
return -EBUSY;
|
||||
r2 = request_mem_region(mem_start, A2065_RAM_SIZE, "RAM");
|
||||
if (!r2) {
|
||||
release_mem_region(base_addr, sizeof(struct lance_regs));
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
dev = alloc_etherdev(sizeof(struct lance_private));
|
||||
if (dev == NULL) {
|
||||
release_mem_region(base_addr, sizeof(struct lance_regs));
|
||||
release_mem_region(mem_start, A2065_RAM_SIZE);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
|
||||
r1->name = dev->name;
|
||||
r2->name = dev->name;
|
||||
|
||||
serial = be32_to_cpu(z->rom.er_SerialNumber);
|
||||
dev->dev_addr[0] = 0x00;
|
||||
if (z->id != ZORRO_PROD_AMERISTAR_A2065) { /* Commodore */
|
||||
dev->dev_addr[1] = 0x80;
|
||||
dev->dev_addr[2] = 0x10;
|
||||
} else { /* Ameristar */
|
||||
dev->dev_addr[1] = 0x00;
|
||||
dev->dev_addr[2] = 0x9f;
|
||||
}
|
||||
dev->dev_addr[3] = (serial >> 16) & 0xff;
|
||||
dev->dev_addr[4] = (serial >> 8) & 0xff;
|
||||
dev->dev_addr[5] = serial & 0xff;
|
||||
dev->base_addr = (unsigned long)ZTWO_VADDR(base_addr);
|
||||
dev->mem_start = (unsigned long)ZTWO_VADDR(mem_start);
|
||||
dev->mem_end = dev->mem_start + A2065_RAM_SIZE;
|
||||
|
||||
priv->ll = (volatile struct lance_regs *)dev->base_addr;
|
||||
priv->init_block = (struct lance_init_block *)dev->mem_start;
|
||||
priv->lance_init_block = (struct lance_init_block *)A2065_RAM;
|
||||
priv->auto_select = 0;
|
||||
priv->busmaster_regval = LE_C3_BSWP;
|
||||
|
||||
priv->lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS;
|
||||
priv->lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
|
||||
priv->rx_ring_mod_mask = RX_RING_MOD_MASK;
|
||||
priv->tx_ring_mod_mask = TX_RING_MOD_MASK;
|
||||
|
||||
dev->netdev_ops = &lance_netdev_ops;
|
||||
dev->watchdog_timeo = 5*HZ;
|
||||
dev->dma = 0;
|
||||
|
||||
init_timer(&priv->multicast_timer);
|
||||
priv->multicast_timer.data = (unsigned long) dev;
|
||||
priv->multicast_timer.function =
|
||||
(void (*)(unsigned long))lance_set_multicast;
|
||||
|
||||
err = register_netdev(dev);
|
||||
if (err) {
|
||||
release_mem_region(base_addr, sizeof(struct lance_regs));
|
||||
release_mem_region(mem_start, A2065_RAM_SIZE);
|
||||
free_netdev(dev);
|
||||
return err;
|
||||
}
|
||||
zorro_set_drvdata(z, dev);
|
||||
|
||||
netdev_info(dev, "A2065 at 0x%08lx, Ethernet Address %pM\n",
|
||||
board, dev->dev_addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void a2065_remove_one(struct zorro_dev *z)
|
||||
{
|
||||
struct net_device *dev = zorro_get_drvdata(z);
|
||||
|
||||
unregister_netdev(dev);
|
||||
release_mem_region(ZTWO_PADDR(dev->base_addr),
|
||||
sizeof(struct lance_regs));
|
||||
release_mem_region(ZTWO_PADDR(dev->mem_start), A2065_RAM_SIZE);
|
||||
free_netdev(dev);
|
||||
}
|
||||
|
||||
static int __init a2065_init_module(void)
|
||||
{
|
||||
return zorro_register_driver(&a2065_driver);
|
||||
}
|
||||
|
||||
static void __exit a2065_cleanup_module(void)
|
||||
{
|
||||
zorro_unregister_driver(&a2065_driver);
|
||||
}
|
||||
|
||||
module_init(a2065_init_module);
|
||||
module_exit(a2065_cleanup_module);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
173
drivers/net/ethernet/amd/a2065.h
Normal file
173
drivers/net/ethernet/amd/a2065.h
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Amiga Linux/68k A2065 Ethernet Driver
|
||||
*
|
||||
* (C) Copyright 1995 by Geert Uytterhoeven <geert@linux-m68k.org>
|
||||
*
|
||||
* ---------------------------------------------------------------------------
|
||||
*
|
||||
* This program is based on
|
||||
*
|
||||
* ariadne.?: Amiga Linux/68k Ariadne Ethernet Driver
|
||||
* (C) Copyright 1995 by Geert Uytterhoeven,
|
||||
* Peter De Schrijver
|
||||
*
|
||||
* lance.c: An AMD LANCE ethernet driver for linux.
|
||||
* Written 1993-94 by Donald Becker.
|
||||
*
|
||||
* Am79C960: PCnet(tm)-ISA Single-Chip Ethernet Controller
|
||||
* Advanced Micro Devices
|
||||
* Publication #16907, Rev. B, Amendment/0, May 1994
|
||||
*
|
||||
* ---------------------------------------------------------------------------
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of the Linux
|
||||
* distribution for more details.
|
||||
*
|
||||
* ---------------------------------------------------------------------------
|
||||
*
|
||||
* The A2065 is a Zorro-II board made by Commodore/Ameristar. It contains:
|
||||
*
|
||||
* - an Am7990 Local Area Network Controller for Ethernet (LANCE) with
|
||||
* both 10BASE-2 (thin coax) and AUI (DB-15) connectors
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Am7990 Local Area Network Controller for Ethernet (LANCE)
|
||||
*/
|
||||
|
||||
struct lance_regs {
|
||||
unsigned short rdp; /* Register Data Port */
|
||||
unsigned short rap; /* Register Address Port */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Am7990 Control and Status Registers
|
||||
*/
|
||||
|
||||
#define LE_CSR0 0x0000 /* LANCE Controller Status */
|
||||
#define LE_CSR1 0x0001 /* IADR[15:0] */
|
||||
#define LE_CSR2 0x0002 /* IADR[23:16] */
|
||||
#define LE_CSR3 0x0003 /* Misc */
|
||||
|
||||
|
||||
/*
|
||||
* Bit definitions for CSR0 (LANCE Controller Status)
|
||||
*/
|
||||
|
||||
#define LE_C0_ERR 0x8000 /* Error */
|
||||
#define LE_C0_BABL 0x4000 /* Babble: Transmitted too many bits */
|
||||
#define LE_C0_CERR 0x2000 /* No Heartbeat (10BASE-T) */
|
||||
#define LE_C0_MISS 0x1000 /* Missed Frame */
|
||||
#define LE_C0_MERR 0x0800 /* Memory Error */
|
||||
#define LE_C0_RINT 0x0400 /* Receive Interrupt */
|
||||
#define LE_C0_TINT 0x0200 /* Transmit Interrupt */
|
||||
#define LE_C0_IDON 0x0100 /* Initialization Done */
|
||||
#define LE_C0_INTR 0x0080 /* Interrupt Flag */
|
||||
#define LE_C0_INEA 0x0040 /* Interrupt Enable */
|
||||
#define LE_C0_RXON 0x0020 /* Receive On */
|
||||
#define LE_C0_TXON 0x0010 /* Transmit On */
|
||||
#define LE_C0_TDMD 0x0008 /* Transmit Demand */
|
||||
#define LE_C0_STOP 0x0004 /* Stop */
|
||||
#define LE_C0_STRT 0x0002 /* Start */
|
||||
#define LE_C0_INIT 0x0001 /* Initialize */
|
||||
|
||||
|
||||
/*
|
||||
* Bit definitions for CSR3
|
||||
*/
|
||||
|
||||
#define LE_C3_BSWP 0x0004 /* Byte Swap
|
||||
(on for big endian byte order) */
|
||||
#define LE_C3_ACON 0x0002 /* ALE Control
|
||||
(on for active low ALE) */
|
||||
#define LE_C3_BCON 0x0001 /* Byte Control */
|
||||
|
||||
|
||||
/*
|
||||
* Mode Flags
|
||||
*/
|
||||
|
||||
#define LE_MO_PROM 0x8000 /* Promiscuous Mode */
|
||||
#define LE_MO_INTL 0x0040 /* Internal Loopback */
|
||||
#define LE_MO_DRTY 0x0020 /* Disable Retry */
|
||||
#define LE_MO_FCOLL 0x0010 /* Force Collision */
|
||||
#define LE_MO_DXMTFCS 0x0008 /* Disable Transmit CRC */
|
||||
#define LE_MO_LOOP 0x0004 /* Loopback Enable */
|
||||
#define LE_MO_DTX 0x0002 /* Disable Transmitter */
|
||||
#define LE_MO_DRX 0x0001 /* Disable Receiver */
|
||||
|
||||
|
||||
struct lance_rx_desc {
|
||||
unsigned short rmd0; /* low address of packet */
|
||||
unsigned char rmd1_bits; /* descriptor bits */
|
||||
unsigned char rmd1_hadr; /* high address of packet */
|
||||
short length; /* This length is 2s complement (negative)!
|
||||
* Buffer length
|
||||
*/
|
||||
unsigned short mblength; /* Aactual number of bytes received */
|
||||
};
|
||||
|
||||
struct lance_tx_desc {
|
||||
unsigned short tmd0; /* low address of packet */
|
||||
unsigned char tmd1_bits; /* descriptor bits */
|
||||
unsigned char tmd1_hadr; /* high address of packet */
|
||||
short length; /* Length is 2s complement (negative)! */
|
||||
unsigned short misc;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Receive Flags
|
||||
*/
|
||||
|
||||
#define LE_R1_OWN 0x80 /* LANCE owns the descriptor */
|
||||
#define LE_R1_ERR 0x40 /* Error */
|
||||
#define LE_R1_FRA 0x20 /* Framing Error */
|
||||
#define LE_R1_OFL 0x10 /* Overflow Error */
|
||||
#define LE_R1_CRC 0x08 /* CRC Error */
|
||||
#define LE_R1_BUF 0x04 /* Buffer Error */
|
||||
#define LE_R1_SOP 0x02 /* Start of Packet */
|
||||
#define LE_R1_EOP 0x01 /* End of Packet */
|
||||
#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */
|
||||
|
||||
|
||||
/*
|
||||
* Transmit Flags
|
||||
*/
|
||||
|
||||
#define LE_T1_OWN 0x80 /* LANCE owns the descriptor */
|
||||
#define LE_T1_ERR 0x40 /* Error */
|
||||
#define LE_T1_RES 0x20 /* Reserved,
|
||||
LANCE writes this with a zero */
|
||||
#define LE_T1_EMORE 0x10 /* More than one retry needed */
|
||||
#define LE_T1_EONE 0x08 /* One retry needed */
|
||||
#define LE_T1_EDEF 0x04 /* Deferred */
|
||||
#define LE_T1_SOP 0x02 /* Start of Packet */
|
||||
#define LE_T1_EOP 0x01 /* End of Packet */
|
||||
#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */
|
||||
|
||||
|
||||
/*
|
||||
* Error Flags
|
||||
*/
|
||||
|
||||
#define LE_T3_BUF 0x8000 /* Buffer Error */
|
||||
#define LE_T3_UFL 0x4000 /* Underflow Error */
|
||||
#define LE_T3_LCOL 0x1000 /* Late Collision */
|
||||
#define LE_T3_CLOS 0x0800 /* Loss of Carrier */
|
||||
#define LE_T3_RTY 0x0400 /* Retry Error */
|
||||
#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry */
|
||||
|
||||
|
||||
/*
|
||||
* A2065 Expansion Board Structure
|
||||
*/
|
||||
|
||||
#define A2065_LANCE 0x4000
|
||||
|
||||
#define A2065_RAM 0x8000
|
||||
#define A2065_RAM_SIZE 0x8000
|
||||
|
768
drivers/net/ethernet/amd/am79c961a.c
Normal file
768
drivers/net/ethernet/amd/am79c961a.c
Normal file
|
@ -0,0 +1,768 @@
|
|||
/*
|
||||
* linux/drivers/net/ethernet/amd/am79c961a.c
|
||||
*
|
||||
* by Russell King <rmk@arm.linux.org.uk> 1995-2001.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Derived from various things including skeleton.c
|
||||
*
|
||||
* This is a special driver for the am79c961A Lance chip used in the
|
||||
* Intel (formally Digital Equipment Corp) EBSA110 platform. Please
|
||||
* note that this can not be built as a module (it doesn't make sense).
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#define TX_BUFFERS 15
|
||||
#define RX_BUFFERS 25
|
||||
|
||||
#include "am79c961a.h"
|
||||
|
||||
static irqreturn_t
|
||||
am79c961_interrupt (int irq, void *dev_id);
|
||||
|
||||
static unsigned int net_debug = NET_DEBUG;
|
||||
|
||||
static const char version[] =
|
||||
"am79c961 ethernet driver (C) 1995-2001 Russell King v0.04\n";
|
||||
|
||||
/* --------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef __arm__
|
||||
static void write_rreg(u_long base, u_int reg, u_int val)
|
||||
{
|
||||
asm volatile(
|
||||
"str%?h %1, [%2] @ NET_RAP\n\t"
|
||||
"str%?h %0, [%2, #-4] @ NET_RDP"
|
||||
:
|
||||
: "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
|
||||
}
|
||||
|
||||
static inline unsigned short read_rreg(u_long base_addr, u_int reg)
|
||||
{
|
||||
unsigned short v;
|
||||
asm volatile(
|
||||
"str%?h %1, [%2] @ NET_RAP\n\t"
|
||||
"ldr%?h %0, [%2, #-4] @ NET_RDP"
|
||||
: "=r" (v)
|
||||
: "r" (reg), "r" (ISAIO_BASE + 0x0464));
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline void write_ireg(u_long base, u_int reg, u_int val)
|
||||
{
|
||||
asm volatile(
|
||||
"str%?h %1, [%2] @ NET_RAP\n\t"
|
||||
"str%?h %0, [%2, #8] @ NET_IDP"
|
||||
:
|
||||
: "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
|
||||
}
|
||||
|
||||
static inline unsigned short read_ireg(u_long base_addr, u_int reg)
|
||||
{
|
||||
u_short v;
|
||||
asm volatile(
|
||||
"str%?h %1, [%2] @ NAT_RAP\n\t"
|
||||
"ldr%?h %0, [%2, #8] @ NET_IDP\n\t"
|
||||
: "=r" (v)
|
||||
: "r" (reg), "r" (ISAIO_BASE + 0x0464));
|
||||
return v;
|
||||
}
|
||||
|
||||
#define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1))
|
||||
#define am_readword(dev,off) __raw_readw(ISAMEM_BASE + ((off) << 1))
|
||||
|
||||
static void
|
||||
am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
|
||||
{
|
||||
offset = ISAMEM_BASE + (offset << 1);
|
||||
length = (length + 1) & ~1;
|
||||
if ((int)buf & 2) {
|
||||
asm volatile("str%?h %2, [%0], #4"
|
||||
: "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
|
||||
buf += 2;
|
||||
length -= 2;
|
||||
}
|
||||
while (length > 8) {
|
||||
register unsigned int tmp asm("r2"), tmp2 asm("r3");
|
||||
asm volatile(
|
||||
"ldm%?ia %0!, {%1, %2}"
|
||||
: "+r" (buf), "=&r" (tmp), "=&r" (tmp2));
|
||||
length -= 8;
|
||||
asm volatile(
|
||||
"str%?h %1, [%0], #4\n\t"
|
||||
"mov%? %1, %1, lsr #16\n\t"
|
||||
"str%?h %1, [%0], #4\n\t"
|
||||
"str%?h %2, [%0], #4\n\t"
|
||||
"mov%? %2, %2, lsr #16\n\t"
|
||||
"str%?h %2, [%0], #4"
|
||||
: "+r" (offset), "=&r" (tmp), "=&r" (tmp2));
|
||||
}
|
||||
while (length > 0) {
|
||||
asm volatile("str%?h %2, [%0], #4"
|
||||
: "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
|
||||
buf += 2;
|
||||
length -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
|
||||
{
|
||||
offset = ISAMEM_BASE + (offset << 1);
|
||||
length = (length + 1) & ~1;
|
||||
if ((int)buf & 2) {
|
||||
unsigned int tmp;
|
||||
asm volatile(
|
||||
"ldr%?h %2, [%0], #4\n\t"
|
||||
"str%?b %2, [%1], #1\n\t"
|
||||
"mov%? %2, %2, lsr #8\n\t"
|
||||
"str%?b %2, [%1], #1"
|
||||
: "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
|
||||
length -= 2;
|
||||
}
|
||||
while (length > 8) {
|
||||
register unsigned int tmp asm("r2"), tmp2 asm("r3"), tmp3;
|
||||
asm volatile(
|
||||
"ldr%?h %2, [%0], #4\n\t"
|
||||
"ldr%?h %4, [%0], #4\n\t"
|
||||
"ldr%?h %3, [%0], #4\n\t"
|
||||
"orr%? %2, %2, %4, lsl #16\n\t"
|
||||
"ldr%?h %4, [%0], #4\n\t"
|
||||
"orr%? %3, %3, %4, lsl #16\n\t"
|
||||
"stm%?ia %1!, {%2, %3}"
|
||||
: "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
|
||||
: "0" (offset), "1" (buf));
|
||||
length -= 8;
|
||||
}
|
||||
while (length > 0) {
|
||||
unsigned int tmp;
|
||||
asm volatile(
|
||||
"ldr%?h %2, [%0], #4\n\t"
|
||||
"str%?b %2, [%1], #1\n\t"
|
||||
"mov%? %2, %2, lsr #8\n\t"
|
||||
"str%?b %2, [%1], #1"
|
||||
: "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
|
||||
length -= 2;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error Not compatible
|
||||
#endif
|
||||
|
||||
static int
|
||||
am79c961_ramtest(struct net_device *dev, unsigned int val)
|
||||
{
|
||||
unsigned char *buffer = kmalloc (65536, GFP_KERNEL);
|
||||
int i, error = 0, errorcount = 0;
|
||||
|
||||
if (!buffer)
|
||||
return 0;
|
||||
memset (buffer, val, 65536);
|
||||
am_writebuffer(dev, 0, buffer, 65536);
|
||||
memset (buffer, val ^ 255, 65536);
|
||||
am_readbuffer(dev, 0, buffer, 65536);
|
||||
for (i = 0; i < 65536; i++) {
|
||||
if (buffer[i] != val && !error) {
|
||||
printk ("%s: buffer error (%02X %02X) %05X - ", dev->name, val, buffer[i], i);
|
||||
error = 1;
|
||||
errorcount ++;
|
||||
} else if (error && buffer[i] == val) {
|
||||
printk ("%05X\n", i);
|
||||
error = 0;
|
||||
}
|
||||
}
|
||||
if (error)
|
||||
printk ("10000\n");
|
||||
kfree (buffer);
|
||||
return errorcount;
|
||||
}
|
||||
|
||||
static void am79c961_mc_hash(char *addr, u16 *hash)
|
||||
{
|
||||
int idx, bit;
|
||||
u32 crc;
|
||||
|
||||
crc = ether_crc_le(ETH_ALEN, addr);
|
||||
|
||||
idx = crc >> 30;
|
||||
bit = (crc >> 26) & 15;
|
||||
|
||||
hash[idx] |= 1 << bit;
|
||||
}
|
||||
|
||||
static unsigned int am79c961_get_rx_mode(struct net_device *dev, u16 *hash)
|
||||
{
|
||||
unsigned int mode = MODE_PORT_10BT;
|
||||
|
||||
if (dev->flags & IFF_PROMISC) {
|
||||
mode |= MODE_PROMISC;
|
||||
memset(hash, 0xff, 4 * sizeof(*hash));
|
||||
} else if (dev->flags & IFF_ALLMULTI) {
|
||||
memset(hash, 0xff, 4 * sizeof(*hash));
|
||||
} else {
|
||||
struct netdev_hw_addr *ha;
|
||||
|
||||
memset(hash, 0, 4 * sizeof(*hash));
|
||||
|
||||
netdev_for_each_mc_addr(ha, dev)
|
||||
am79c961_mc_hash(ha->addr, hash);
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static void
|
||||
am79c961_init_for_open(struct net_device *dev)
|
||||
{
|
||||
struct dev_priv *priv = netdev_priv(dev);
|
||||
unsigned long flags;
|
||||
unsigned char *p;
|
||||
u_int hdr_addr, first_free_addr;
|
||||
u16 multi_hash[4], mode = am79c961_get_rx_mode(dev, multi_hash);
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Stop the chip.
|
||||
*/
|
||||
spin_lock_irqsave(&priv->chip_lock, flags);
|
||||
write_rreg (dev->base_addr, CSR0, CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR|CSR0_TINT|CSR0_RINT|CSR0_STOP);
|
||||
spin_unlock_irqrestore(&priv->chip_lock, flags);
|
||||
|
||||
write_ireg (dev->base_addr, 5, 0x00a0); /* Receive address LED */
|
||||
write_ireg (dev->base_addr, 6, 0x0081); /* Collision LED */
|
||||
write_ireg (dev->base_addr, 7, 0x0090); /* XMIT LED */
|
||||
write_ireg (dev->base_addr, 2, 0x0000); /* MODE register selects media */
|
||||
|
||||
for (i = LADRL; i <= LADRH; i++)
|
||||
write_rreg (dev->base_addr, i, multi_hash[i - LADRL]);
|
||||
|
||||
for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2)
|
||||
write_rreg (dev->base_addr, i, p[0] | (p[1] << 8));
|
||||
|
||||
write_rreg (dev->base_addr, MODE, mode);
|
||||
write_rreg (dev->base_addr, POLLINT, 0);
|
||||
write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS);
|
||||
write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS);
|
||||
|
||||
first_free_addr = RX_BUFFERS * 8 + TX_BUFFERS * 8 + 16;
|
||||
hdr_addr = 0;
|
||||
|
||||
priv->rxhead = 0;
|
||||
priv->rxtail = 0;
|
||||
priv->rxhdr = hdr_addr;
|
||||
|
||||
for (i = 0; i < RX_BUFFERS; i++) {
|
||||
priv->rxbuffer[i] = first_free_addr;
|
||||
am_writeword (dev, hdr_addr, first_free_addr);
|
||||
am_writeword (dev, hdr_addr + 2, RMD_OWN);
|
||||
am_writeword (dev, hdr_addr + 4, (-1600));
|
||||
am_writeword (dev, hdr_addr + 6, 0);
|
||||
first_free_addr += 1600;
|
||||
hdr_addr += 8;
|
||||
}
|
||||
priv->txhead = 0;
|
||||
priv->txtail = 0;
|
||||
priv->txhdr = hdr_addr;
|
||||
for (i = 0; i < TX_BUFFERS; i++) {
|
||||
priv->txbuffer[i] = first_free_addr;
|
||||
am_writeword (dev, hdr_addr, first_free_addr);
|
||||
am_writeword (dev, hdr_addr + 2, TMD_STP|TMD_ENP);
|
||||
am_writeword (dev, hdr_addr + 4, 0xf000);
|
||||
am_writeword (dev, hdr_addr + 6, 0);
|
||||
first_free_addr += 1600;
|
||||
hdr_addr += 8;
|
||||
}
|
||||
|
||||
write_rreg (dev->base_addr, BASERXL, priv->rxhdr);
|
||||
write_rreg (dev->base_addr, BASERXH, 0);
|
||||
write_rreg (dev->base_addr, BASETXL, priv->txhdr);
|
||||
write_rreg (dev->base_addr, BASERXH, 0);
|
||||
write_rreg (dev->base_addr, CSR0, CSR0_STOP);
|
||||
write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO);
|
||||
write_rreg (dev->base_addr, CSR4, CSR4_APAD_XMIT|CSR4_MFCOM|CSR4_RCVCCOM|CSR4_TXSTRTM|CSR4_JABM);
|
||||
write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT);
|
||||
}
|
||||
|
||||
static void am79c961_timer(unsigned long data)
|
||||
{
|
||||
struct net_device *dev = (struct net_device *)data;
|
||||
struct dev_priv *priv = netdev_priv(dev);
|
||||
unsigned int lnkstat, carrier;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->chip_lock, flags);
|
||||
lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST;
|
||||
spin_unlock_irqrestore(&priv->chip_lock, flags);
|
||||
carrier = netif_carrier_ok(dev);
|
||||
|
||||
if (lnkstat && !carrier) {
|
||||
netif_carrier_on(dev);
|
||||
printk("%s: link up\n", dev->name);
|
||||
} else if (!lnkstat && carrier) {
|
||||
netif_carrier_off(dev);
|
||||
printk("%s: link down\n", dev->name);
|
||||
}
|
||||
|
||||
mod_timer(&priv->timer, jiffies + msecs_to_jiffies(500));
|
||||
}
|
||||
|
||||
/*
|
||||
* Open/initialize the board.
|
||||
*/
|
||||
static int
|
||||
am79c961_open(struct net_device *dev)
|
||||
{
|
||||
struct dev_priv *priv = netdev_priv(dev);
|
||||
int ret;
|
||||
|
||||
ret = request_irq(dev->irq, am79c961_interrupt, 0, dev->name, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
am79c961_init_for_open(dev);
|
||||
|
||||
netif_carrier_off(dev);
|
||||
|
||||
priv->timer.expires = jiffies;
|
||||
add_timer(&priv->timer);
|
||||
|
||||
netif_start_queue(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The inverse routine to am79c961_open().
|
||||
*/
|
||||
static int
|
||||
am79c961_close(struct net_device *dev)
|
||||
{
|
||||
struct dev_priv *priv = netdev_priv(dev);
|
||||
unsigned long flags;
|
||||
|
||||
del_timer_sync(&priv->timer);
|
||||
|
||||
netif_stop_queue(dev);
|
||||
netif_carrier_off(dev);
|
||||
|
||||
spin_lock_irqsave(&priv->chip_lock, flags);
|
||||
write_rreg (dev->base_addr, CSR0, CSR0_STOP);
|
||||
write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
|
||||
spin_unlock_irqrestore(&priv->chip_lock, flags);
|
||||
|
||||
free_irq (dev->irq, dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set or clear promiscuous/multicast mode filter for this adapter.
|
||||
*/
|
||||
static void am79c961_setmulticastlist (struct net_device *dev)
|
||||
{
|
||||
struct dev_priv *priv = netdev_priv(dev);
|
||||
unsigned long flags;
|
||||
u16 multi_hash[4], mode = am79c961_get_rx_mode(dev, multi_hash);
|
||||
int i, stopped;
|
||||
|
||||
spin_lock_irqsave(&priv->chip_lock, flags);
|
||||
|
||||
stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP;
|
||||
|
||||
if (!stopped) {
|
||||
/*
|
||||
* Put the chip into suspend mode
|
||||
*/
|
||||
write_rreg(dev->base_addr, CTRL1, CTRL1_SPND);
|
||||
|
||||
/*
|
||||
* Spin waiting for chip to report suspend mode
|
||||
*/
|
||||
while ((read_rreg(dev->base_addr, CTRL1) & CTRL1_SPND) == 0) {
|
||||
spin_unlock_irqrestore(&priv->chip_lock, flags);
|
||||
nop();
|
||||
spin_lock_irqsave(&priv->chip_lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the multicast hash table
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(multi_hash); i++)
|
||||
write_rreg(dev->base_addr, i + LADRL, multi_hash[i]);
|
||||
|
||||
/*
|
||||
* Write the mode register
|
||||
*/
|
||||
write_rreg(dev->base_addr, MODE, mode);
|
||||
|
||||
if (!stopped) {
|
||||
/*
|
||||
* Put the chip back into running mode
|
||||
*/
|
||||
write_rreg(dev->base_addr, CTRL1, 0);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&priv->chip_lock, flags);
|
||||
}
|
||||
|
||||
static void am79c961_timeout(struct net_device *dev)
|
||||
{
|
||||
printk(KERN_WARNING "%s: transmit timed out, network cable problem?\n",
|
||||
dev->name);
|
||||
|
||||
/*
|
||||
* ought to do some setup of the tx side here
|
||||
*/
|
||||
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Transmit a packet
|
||||
*/
|
||||
static int
|
||||
am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct dev_priv *priv = netdev_priv(dev);
|
||||
unsigned int hdraddr, bufaddr;
|
||||
unsigned int head;
|
||||
unsigned long flags;
|
||||
|
||||
head = priv->txhead;
|
||||
hdraddr = priv->txhdr + (head << 3);
|
||||
bufaddr = priv->txbuffer[head];
|
||||
head += 1;
|
||||
if (head >= TX_BUFFERS)
|
||||
head = 0;
|
||||
|
||||
am_writebuffer (dev, bufaddr, skb->data, skb->len);
|
||||
am_writeword (dev, hdraddr + 4, -skb->len);
|
||||
am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
|
||||
priv->txhead = head;
|
||||
|
||||
spin_lock_irqsave(&priv->chip_lock, flags);
|
||||
write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA);
|
||||
spin_unlock_irqrestore(&priv->chip_lock, flags);
|
||||
|
||||
/*
|
||||
* If the next packet is owned by the ethernet device,
|
||||
* then the tx ring is full and we can't add another
|
||||
* packet.
|
||||
*/
|
||||
if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)
|
||||
netif_stop_queue(dev);
|
||||
|
||||
dev_consume_skb_any(skb);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a good packet(s), get it/them out of the buffers.
|
||||
*/
|
||||
static void
|
||||
am79c961_rx(struct net_device *dev, struct dev_priv *priv)
|
||||
{
|
||||
do {
|
||||
struct sk_buff *skb;
|
||||
u_int hdraddr;
|
||||
u_int pktaddr;
|
||||
u_int status;
|
||||
int len;
|
||||
|
||||
hdraddr = priv->rxhdr + (priv->rxtail << 3);
|
||||
pktaddr = priv->rxbuffer[priv->rxtail];
|
||||
|
||||
status = am_readword (dev, hdraddr + 2);
|
||||
if (status & RMD_OWN) /* do we own it? */
|
||||
break;
|
||||
|
||||
priv->rxtail ++;
|
||||
if (priv->rxtail >= RX_BUFFERS)
|
||||
priv->rxtail = 0;
|
||||
|
||||
if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP)) {
|
||||
am_writeword (dev, hdraddr + 2, RMD_OWN);
|
||||
dev->stats.rx_errors++;
|
||||
if (status & RMD_ERR) {
|
||||
if (status & RMD_FRAM)
|
||||
dev->stats.rx_frame_errors++;
|
||||
if (status & RMD_CRC)
|
||||
dev->stats.rx_crc_errors++;
|
||||
} else if (status & RMD_STP)
|
||||
dev->stats.rx_length_errors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
len = am_readword(dev, hdraddr + 6);
|
||||
skb = netdev_alloc_skb(dev, len + 2);
|
||||
|
||||
if (skb) {
|
||||
skb_reserve(skb, 2);
|
||||
|
||||
am_readbuffer(dev, pktaddr, skb_put(skb, len), len);
|
||||
am_writeword(dev, hdraddr + 2, RMD_OWN);
|
||||
skb->protocol = eth_type_trans(skb, dev);
|
||||
netif_rx(skb);
|
||||
dev->stats.rx_bytes += len;
|
||||
dev->stats.rx_packets++;
|
||||
} else {
|
||||
am_writeword (dev, hdraddr + 2, RMD_OWN);
|
||||
dev->stats.rx_dropped++;
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update stats for the transmitted packet
|
||||
*/
|
||||
static void
|
||||
am79c961_tx(struct net_device *dev, struct dev_priv *priv)
|
||||
{
|
||||
do {
|
||||
short len;
|
||||
u_int hdraddr;
|
||||
u_int status;
|
||||
|
||||
hdraddr = priv->txhdr + (priv->txtail << 3);
|
||||
status = am_readword (dev, hdraddr + 2);
|
||||
if (status & TMD_OWN)
|
||||
break;
|
||||
|
||||
priv->txtail ++;
|
||||
if (priv->txtail >= TX_BUFFERS)
|
||||
priv->txtail = 0;
|
||||
|
||||
if (status & TMD_ERR) {
|
||||
u_int status2;
|
||||
|
||||
dev->stats.tx_errors++;
|
||||
|
||||
status2 = am_readword (dev, hdraddr + 6);
|
||||
|
||||
/*
|
||||
* Clear the error byte
|
||||
*/
|
||||
am_writeword (dev, hdraddr + 6, 0);
|
||||
|
||||
if (status2 & TST_RTRY)
|
||||
dev->stats.collisions += 16;
|
||||
if (status2 & TST_LCOL)
|
||||
dev->stats.tx_window_errors++;
|
||||
if (status2 & TST_LCAR)
|
||||
dev->stats.tx_carrier_errors++;
|
||||
if (status2 & TST_UFLO)
|
||||
dev->stats.tx_fifo_errors++;
|
||||
continue;
|
||||
}
|
||||
dev->stats.tx_packets++;
|
||||
len = am_readword (dev, hdraddr + 4);
|
||||
dev->stats.tx_bytes += -len;
|
||||
} while (priv->txtail != priv->txhead);
|
||||
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
am79c961_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct net_device *dev = (struct net_device *)dev_id;
|
||||
struct dev_priv *priv = netdev_priv(dev);
|
||||
u_int status, n = 100;
|
||||
int handled = 0;
|
||||
|
||||
do {
|
||||
status = read_rreg(dev->base_addr, CSR0);
|
||||
write_rreg(dev->base_addr, CSR0, status &
|
||||
(CSR0_IENA|CSR0_TINT|CSR0_RINT|
|
||||
CSR0_MERR|CSR0_MISS|CSR0_CERR|CSR0_BABL));
|
||||
|
||||
if (status & CSR0_RINT) {
|
||||
handled = 1;
|
||||
am79c961_rx(dev, priv);
|
||||
}
|
||||
if (status & CSR0_TINT) {
|
||||
handled = 1;
|
||||
am79c961_tx(dev, priv);
|
||||
}
|
||||
if (status & CSR0_MISS) {
|
||||
handled = 1;
|
||||
dev->stats.rx_dropped++;
|
||||
}
|
||||
if (status & CSR0_CERR) {
|
||||
handled = 1;
|
||||
mod_timer(&priv->timer, jiffies);
|
||||
}
|
||||
} while (--n && status & (CSR0_RINT | CSR0_TINT));
|
||||
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
static void am79c961_poll_controller(struct net_device *dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
local_irq_save(flags);
|
||||
am79c961_interrupt(dev->irq, dev);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialise the chip. Note that we always expect
|
||||
* to be entered with interrupts enabled.
|
||||
*/
|
||||
static int
|
||||
am79c961_hw_init(struct net_device *dev)
|
||||
{
|
||||
struct dev_priv *priv = netdev_priv(dev);
|
||||
|
||||
spin_lock_irq(&priv->chip_lock);
|
||||
write_rreg (dev->base_addr, CSR0, CSR0_STOP);
|
||||
write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
|
||||
spin_unlock_irq(&priv->chip_lock);
|
||||
|
||||
am79c961_ramtest(dev, 0x66);
|
||||
am79c961_ramtest(dev, 0x99);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init am79c961_banner(void)
|
||||
{
|
||||
static unsigned version_printed;
|
||||
|
||||
if (net_debug && version_printed++ == 0)
|
||||
printk(KERN_INFO "%s", version);
|
||||
}
|
||||
static const struct net_device_ops am79c961_netdev_ops = {
|
||||
.ndo_open = am79c961_open,
|
||||
.ndo_stop = am79c961_close,
|
||||
.ndo_start_xmit = am79c961_sendpacket,
|
||||
.ndo_set_rx_mode = am79c961_setmulticastlist,
|
||||
.ndo_tx_timeout = am79c961_timeout,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_change_mtu = eth_change_mtu,
|
||||
.ndo_set_mac_address = eth_mac_addr,
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = am79c961_poll_controller,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int am79c961_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct net_device *dev;
|
||||
struct dev_priv *priv;
|
||||
int i, ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
dev = alloc_etherdev(sizeof(struct dev_priv));
|
||||
ret = -ENOMEM;
|
||||
if (!dev)
|
||||
goto out;
|
||||
|
||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
|
||||
/*
|
||||
* Fixed address and IRQ lines here.
|
||||
* The PNP initialisation should have been
|
||||
* done by the ether bootp loader.
|
||||
*/
|
||||
dev->base_addr = res->start;
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
|
||||
if (ret < 0) {
|
||||
ret = -ENODEV;
|
||||
goto nodev;
|
||||
}
|
||||
dev->irq = ret;
|
||||
|
||||
ret = -ENODEV;
|
||||
if (!request_region(dev->base_addr, 0x18, dev->name))
|
||||
goto nodev;
|
||||
|
||||
/*
|
||||
* Reset the device.
|
||||
*/
|
||||
inb(dev->base_addr + NET_RESET);
|
||||
udelay(5);
|
||||
|
||||
/*
|
||||
* Check the manufacturer part of the
|
||||
* ether address.
|
||||
*/
|
||||
if (inb(dev->base_addr) != 0x08 ||
|
||||
inb(dev->base_addr + 2) != 0x00 ||
|
||||
inb(dev->base_addr + 4) != 0x2b)
|
||||
goto release;
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff;
|
||||
|
||||
am79c961_banner();
|
||||
|
||||
spin_lock_init(&priv->chip_lock);
|
||||
init_timer(&priv->timer);
|
||||
priv->timer.data = (unsigned long)dev;
|
||||
priv->timer.function = am79c961_timer;
|
||||
|
||||
if (am79c961_hw_init(dev))
|
||||
goto release;
|
||||
|
||||
dev->netdev_ops = &am79c961_netdev_ops;
|
||||
|
||||
ret = register_netdev(dev);
|
||||
if (ret == 0) {
|
||||
printk(KERN_INFO "%s: ether address %pM\n",
|
||||
dev->name, dev->dev_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
release:
|
||||
release_region(dev->base_addr, 0x18);
|
||||
nodev:
|
||||
free_netdev(dev);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_driver am79c961_driver = {
|
||||
.probe = am79c961_probe,
|
||||
.driver = {
|
||||
.name = "am79c961",
|
||||
},
|
||||
};
|
||||
|
||||
static int __init am79c961_init(void)
|
||||
{
|
||||
return platform_driver_register(&am79c961_driver);
|
||||
}
|
||||
|
||||
__initcall(am79c961_init);
|
145
drivers/net/ethernet/amd/am79c961a.h
Normal file
145
drivers/net/ethernet/amd/am79c961a.h
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* linux/drivers/net/ethernet/amd/am79c961a.h
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_am79c961a_H
|
||||
#define _LINUX_am79c961a_H
|
||||
|
||||
/* use 0 for production, 1 for verification, >2 for debug. debug flags: */
|
||||
#define DEBUG_TX 2
|
||||
#define DEBUG_RX 4
|
||||
#define DEBUG_INT 8
|
||||
#define DEBUG_IC 16
|
||||
#ifndef NET_DEBUG
|
||||
#define NET_DEBUG 0
|
||||
#endif
|
||||
|
||||
#define NET_UID 0
|
||||
#define NET_RDP 0x10
|
||||
#define NET_RAP 0x12
|
||||
#define NET_RESET 0x14
|
||||
#define NET_IDP 0x16
|
||||
|
||||
/*
|
||||
* RAP registers
|
||||
*/
|
||||
#define CSR0 0
|
||||
#define CSR0_INIT 0x0001
|
||||
#define CSR0_STRT 0x0002
|
||||
#define CSR0_STOP 0x0004
|
||||
#define CSR0_TDMD 0x0008
|
||||
#define CSR0_TXON 0x0010
|
||||
#define CSR0_RXON 0x0020
|
||||
#define CSR0_IENA 0x0040
|
||||
#define CSR0_INTR 0x0080
|
||||
#define CSR0_IDON 0x0100
|
||||
#define CSR0_TINT 0x0200
|
||||
#define CSR0_RINT 0x0400
|
||||
#define CSR0_MERR 0x0800
|
||||
#define CSR0_MISS 0x1000
|
||||
#define CSR0_CERR 0x2000
|
||||
#define CSR0_BABL 0x4000
|
||||
#define CSR0_ERR 0x8000
|
||||
|
||||
#define CSR3 3
|
||||
#define CSR3_EMBA 0x0008
|
||||
#define CSR3_DXMT2PD 0x0010
|
||||
#define CSR3_LAPPEN 0x0020
|
||||
#define CSR3_DXSUFLO 0x0040
|
||||
#define CSR3_IDONM 0x0100
|
||||
#define CSR3_TINTM 0x0200
|
||||
#define CSR3_RINTM 0x0400
|
||||
#define CSR3_MERRM 0x0800
|
||||
#define CSR3_MISSM 0x1000
|
||||
#define CSR3_BABLM 0x4000
|
||||
#define CSR3_MASKALL 0x5F00
|
||||
|
||||
#define CSR4 4
|
||||
#define CSR4_JABM 0x0001
|
||||
#define CSR4_JAB 0x0002
|
||||
#define CSR4_TXSTRTM 0x0004
|
||||
#define CSR4_TXSTRT 0x0008
|
||||
#define CSR4_RCVCCOM 0x0010
|
||||
#define CSR4_RCVCCO 0x0020
|
||||
#define CSR4_MFCOM 0x0100
|
||||
#define CSR4_MFCO 0x0200
|
||||
#define CSR4_ASTRP_RCV 0x0400
|
||||
#define CSR4_APAD_XMIT 0x0800
|
||||
|
||||
#define CTRL1 5
|
||||
#define CTRL1_SPND 0x0001
|
||||
|
||||
#define LADRL 8
|
||||
#define LADRM1 9
|
||||
#define LADRM2 10
|
||||
#define LADRH 11
|
||||
#define PADRL 12
|
||||
#define PADRM 13
|
||||
#define PADRH 14
|
||||
|
||||
#define MODE 15
|
||||
#define MODE_DISRX 0x0001
|
||||
#define MODE_DISTX 0x0002
|
||||
#define MODE_LOOP 0x0004
|
||||
#define MODE_DTCRC 0x0008
|
||||
#define MODE_COLL 0x0010
|
||||
#define MODE_DRETRY 0x0020
|
||||
#define MODE_INTLOOP 0x0040
|
||||
#define MODE_PORT_AUI 0x0000
|
||||
#define MODE_PORT_10BT 0x0080
|
||||
#define MODE_DRXPA 0x2000
|
||||
#define MODE_DRXBA 0x4000
|
||||
#define MODE_PROMISC 0x8000
|
||||
|
||||
#define BASERXL 24
|
||||
#define BASERXH 25
|
||||
#define BASETXL 30
|
||||
#define BASETXH 31
|
||||
|
||||
#define POLLINT 47
|
||||
|
||||
#define SIZERXR 76
|
||||
#define SIZETXR 78
|
||||
|
||||
#define CSR_MFC 112
|
||||
|
||||
#define RMD_ENP 0x0100
|
||||
#define RMD_STP 0x0200
|
||||
#define RMD_CRC 0x0800
|
||||
#define RMD_FRAM 0x2000
|
||||
#define RMD_ERR 0x4000
|
||||
#define RMD_OWN 0x8000
|
||||
|
||||
#define TMD_ENP 0x0100
|
||||
#define TMD_STP 0x0200
|
||||
#define TMD_MORE 0x1000
|
||||
#define TMD_ERR 0x4000
|
||||
#define TMD_OWN 0x8000
|
||||
|
||||
#define TST_RTRY 0x0400
|
||||
#define TST_LCAR 0x0800
|
||||
#define TST_LCOL 0x1000
|
||||
#define TST_UFLO 0x4000
|
||||
#define TST_BUFF 0x8000
|
||||
|
||||
#define ISALED0 0x0004
|
||||
#define ISALED0_LNKST 0x8000
|
||||
|
||||
struct dev_priv {
|
||||
unsigned long rxbuffer[RX_BUFFERS];
|
||||
unsigned long txbuffer[TX_BUFFERS];
|
||||
unsigned char txhead;
|
||||
unsigned char txtail;
|
||||
unsigned char rxhead;
|
||||
unsigned char rxtail;
|
||||
unsigned long rxhdr;
|
||||
unsigned long txhdr;
|
||||
spinlock_t chip_lock;
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
#endif
|
1971
drivers/net/ethernet/amd/amd8111e.c
Normal file
1971
drivers/net/ethernet/amd/amd8111e.c
Normal file
File diff suppressed because it is too large
Load diff
813
drivers/net/ethernet/amd/amd8111e.h
Normal file
813
drivers/net/ethernet/amd/amd8111e.h
Normal file
|
@ -0,0 +1,813 @@
|
|||
/*
|
||||
* Advanced Micro Devices Inc. AMD8111E Linux Network Driver
|
||||
* Copyright (C) 2003 Advanced Micro Devices
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Module Name:
|
||||
|
||||
amd8111e.h
|
||||
|
||||
Abstract:
|
||||
|
||||
AMD8111 based 10/100 Ethernet Controller driver definitions.
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel Mode
|
||||
|
||||
Revision History:
|
||||
3.0.0
|
||||
Initial Revision.
|
||||
3.0.1
|
||||
*/
|
||||
|
||||
#ifndef _AMD811E_H
|
||||
#define _AMD811E_H
|
||||
|
||||
/* Command style register access
|
||||
|
||||
Registers CMD0, CMD2, CMD3,CMD7 and INTEN0 uses a write access technique called command style access. It allows the write to selected bits of this register without altering the bits that are not selected. Command style registers are divided into 4 bytes that can be written independently. Higher order bit of each byte is the value bit that specifies the value that will be written into the selected bits of register.
|
||||
|
||||
eg., if the value 10011010b is written into the least significant byte of a command style register, bits 1,3 and 4 of the register will be set to 1, and the other bits will not be altered. If the value 00011010b is written into the same byte, bits 1,3 and 4 will be cleared to 0 and the other bits will not be altered.
|
||||
|
||||
*/
|
||||
|
||||
/* Offset for Memory Mapped Registers. */
|
||||
/* 32 bit registers */
|
||||
|
||||
#define ASF_STAT 0x00 /* ASF status register */
|
||||
#define CHIPID 0x04 /* Chip ID regsiter */
|
||||
#define MIB_DATA 0x10 /* MIB data register */
|
||||
#define MIB_ADDR 0x14 /* MIB address register */
|
||||
#define STAT0 0x30 /* Status0 register */
|
||||
#define INT0 0x38 /* Interrupt0 register */
|
||||
#define INTEN0 0x40 /* Interrupt0 enable register*/
|
||||
#define CMD0 0x48 /* Command0 register */
|
||||
#define CMD2 0x50 /* Command2 register */
|
||||
#define CMD3 0x54 /* Command3 resiter */
|
||||
#define CMD7 0x64 /* Command7 register */
|
||||
|
||||
#define CTRL1 0x6C /* Control1 register */
|
||||
#define CTRL2 0x70 /* Control2 register */
|
||||
|
||||
#define XMT_RING_LIMIT 0x7C /* Transmit ring limit register */
|
||||
|
||||
#define AUTOPOLL0 0x88 /* Auto-poll0 register */
|
||||
#define AUTOPOLL1 0x8A /* Auto-poll1 register */
|
||||
#define AUTOPOLL2 0x8C /* Auto-poll2 register */
|
||||
#define AUTOPOLL3 0x8E /* Auto-poll3 register */
|
||||
#define AUTOPOLL4 0x90 /* Auto-poll4 register */
|
||||
#define AUTOPOLL5 0x92 /* Auto-poll5 register */
|
||||
|
||||
#define AP_VALUE 0x98 /* Auto-poll value register */
|
||||
#define DLY_INT_A 0xA8 /* Group A delayed interrupt register */
|
||||
#define DLY_INT_B 0xAC /* Group B delayed interrupt register */
|
||||
|
||||
#define FLOW_CONTROL 0xC8 /* Flow control register */
|
||||
#define PHY_ACCESS 0xD0 /* PHY access register */
|
||||
|
||||
#define STVAL 0xD8 /* Software timer value register */
|
||||
|
||||
#define XMT_RING_BASE_ADDR0 0x100 /* Transmit ring0 base addr register */
|
||||
#define XMT_RING_BASE_ADDR1 0x108 /* Transmit ring1 base addr register */
|
||||
#define XMT_RING_BASE_ADDR2 0x110 /* Transmit ring2 base addr register */
|
||||
#define XMT_RING_BASE_ADDR3 0x118 /* Transmit ring2 base addr register */
|
||||
|
||||
#define RCV_RING_BASE_ADDR0 0x120 /* Transmit ring0 base addr register */
|
||||
|
||||
#define PMAT0 0x190 /* OnNow pattern register0 */
|
||||
#define PMAT1 0x194 /* OnNow pattern register1 */
|
||||
|
||||
/* 16bit registers */
|
||||
|
||||
#define XMT_RING_LEN0 0x140 /* Transmit Ring0 length register */
|
||||
#define XMT_RING_LEN1 0x144 /* Transmit Ring1 length register */
|
||||
#define XMT_RING_LEN2 0x148 /* Transmit Ring2 length register */
|
||||
#define XMT_RING_LEN3 0x14C /* Transmit Ring3 length register */
|
||||
|
||||
#define RCV_RING_LEN0 0x150 /* Receive Ring0 length register */
|
||||
|
||||
#define SRAM_SIZE 0x178 /* SRAM size register */
|
||||
#define SRAM_BOUNDARY 0x17A /* SRAM boundary register */
|
||||
|
||||
/* 48bit register */
|
||||
|
||||
#define PADR 0x160 /* Physical address register */
|
||||
|
||||
#define IFS1 0x18C /* Inter-frame spacing Part1 register */
|
||||
#define IFS 0x18D /* Inter-frame spacing register */
|
||||
#define IPG 0x18E /* Inter-frame gap register */
|
||||
/* 64bit register */
|
||||
|
||||
#define LADRF 0x168 /* Logical address filter register */
|
||||
|
||||
|
||||
/* Register Bit Definitions */
|
||||
typedef enum {
|
||||
|
||||
ASF_INIT_DONE = (1 << 1),
|
||||
ASF_INIT_PRESENT = (1 << 0),
|
||||
|
||||
}STAT_ASF_BITS;
|
||||
|
||||
typedef enum {
|
||||
|
||||
MIB_CMD_ACTIVE = (1 << 15 ),
|
||||
MIB_RD_CMD = (1 << 13 ),
|
||||
MIB_CLEAR = (1 << 12 ),
|
||||
MIB_ADDRESS = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)|
|
||||
(1 << 4) | (1 << 5),
|
||||
}MIB_ADDR_BITS;
|
||||
|
||||
|
||||
typedef enum {
|
||||
|
||||
PMAT_DET = (1 << 12),
|
||||
MP_DET = (1 << 11),
|
||||
LC_DET = (1 << 10),
|
||||
SPEED_MASK = (1 << 9)|(1 << 8)|(1 << 7),
|
||||
FULL_DPLX = (1 << 6),
|
||||
LINK_STATS = (1 << 5),
|
||||
AUTONEG_COMPLETE = (1 << 4),
|
||||
MIIPD = (1 << 3),
|
||||
RX_SUSPENDED = (1 << 2),
|
||||
TX_SUSPENDED = (1 << 1),
|
||||
RUNNING = (1 << 0),
|
||||
|
||||
}STAT0_BITS;
|
||||
|
||||
#define PHY_SPEED_10 0x2
|
||||
#define PHY_SPEED_100 0x3
|
||||
|
||||
/* INT0 0x38, 32bit register */
|
||||
typedef enum {
|
||||
|
||||
INTR = (1 << 31),
|
||||
PCSINT = (1 << 28),
|
||||
LCINT = (1 << 27),
|
||||
APINT5 = (1 << 26),
|
||||
APINT4 = (1 << 25),
|
||||
APINT3 = (1 << 24),
|
||||
TINT_SUM = (1 << 23),
|
||||
APINT2 = (1 << 22),
|
||||
APINT1 = (1 << 21),
|
||||
APINT0 = (1 << 20),
|
||||
MIIPDTINT = (1 << 19),
|
||||
MCCINT = (1 << 17),
|
||||
MREINT = (1 << 16),
|
||||
RINT_SUM = (1 << 15),
|
||||
SPNDINT = (1 << 14),
|
||||
MPINT = (1 << 13),
|
||||
SINT = (1 << 12),
|
||||
TINT3 = (1 << 11),
|
||||
TINT2 = (1 << 10),
|
||||
TINT1 = (1 << 9),
|
||||
TINT0 = (1 << 8),
|
||||
UINT = (1 << 7),
|
||||
STINT = (1 << 4),
|
||||
RINT0 = (1 << 0),
|
||||
|
||||
}INT0_BITS;
|
||||
|
||||
typedef enum {
|
||||
|
||||
VAL3 = (1 << 31), /* VAL bit for byte 3 */
|
||||
VAL2 = (1 << 23), /* VAL bit for byte 2 */
|
||||
VAL1 = (1 << 15), /* VAL bit for byte 1 */
|
||||
VAL0 = (1 << 7), /* VAL bit for byte 0 */
|
||||
|
||||
}VAL_BITS;
|
||||
|
||||
typedef enum {
|
||||
|
||||
/* VAL3 */
|
||||
LCINTEN = (1 << 27),
|
||||
APINT5EN = (1 << 26),
|
||||
APINT4EN = (1 << 25),
|
||||
APINT3EN = (1 << 24),
|
||||
/* VAL2 */
|
||||
APINT2EN = (1 << 22),
|
||||
APINT1EN = (1 << 21),
|
||||
APINT0EN = (1 << 20),
|
||||
MIIPDTINTEN = (1 << 19),
|
||||
MCCIINTEN = (1 << 18),
|
||||
MCCINTEN = (1 << 17),
|
||||
MREINTEN = (1 << 16),
|
||||
/* VAL1 */
|
||||
SPNDINTEN = (1 << 14),
|
||||
MPINTEN = (1 << 13),
|
||||
TINTEN3 = (1 << 11),
|
||||
SINTEN = (1 << 12),
|
||||
TINTEN2 = (1 << 10),
|
||||
TINTEN1 = (1 << 9),
|
||||
TINTEN0 = (1 << 8),
|
||||
/* VAL0 */
|
||||
STINTEN = (1 << 4),
|
||||
RINTEN0 = (1 << 0),
|
||||
|
||||
INTEN0_CLEAR = 0x1F7F7F1F, /* Command style register */
|
||||
|
||||
}INTEN0_BITS;
|
||||
|
||||
typedef enum {
|
||||
/* VAL2 */
|
||||
RDMD0 = (1 << 16),
|
||||
/* VAL1 */
|
||||
TDMD3 = (1 << 11),
|
||||
TDMD2 = (1 << 10),
|
||||
TDMD1 = (1 << 9),
|
||||
TDMD0 = (1 << 8),
|
||||
/* VAL0 */
|
||||
UINTCMD = (1 << 6),
|
||||
RX_FAST_SPND = (1 << 5),
|
||||
TX_FAST_SPND = (1 << 4),
|
||||
RX_SPND = (1 << 3),
|
||||
TX_SPND = (1 << 2),
|
||||
INTREN = (1 << 1),
|
||||
RUN = (1 << 0),
|
||||
|
||||
CMD0_CLEAR = 0x000F0F7F, /* Command style register */
|
||||
|
||||
}CMD0_BITS;
|
||||
|
||||
typedef enum {
|
||||
|
||||
/* VAL3 */
|
||||
CONDUIT_MODE = (1 << 29),
|
||||
/* VAL2 */
|
||||
RPA = (1 << 19),
|
||||
DRCVPA = (1 << 18),
|
||||
DRCVBC = (1 << 17),
|
||||
PROM = (1 << 16),
|
||||
/* VAL1 */
|
||||
ASTRP_RCV = (1 << 13),
|
||||
RCV_DROP0 = (1 << 12),
|
||||
EMBA = (1 << 11),
|
||||
DXMT2PD = (1 << 10),
|
||||
LTINTEN = (1 << 9),
|
||||
DXMTFCS = (1 << 8),
|
||||
/* VAL0 */
|
||||
APAD_XMT = (1 << 6),
|
||||
DRTY = (1 << 5),
|
||||
INLOOP = (1 << 4),
|
||||
EXLOOP = (1 << 3),
|
||||
REX_RTRY = (1 << 2),
|
||||
REX_UFLO = (1 << 1),
|
||||
REX_LCOL = (1 << 0),
|
||||
|
||||
CMD2_CLEAR = 0x3F7F3F7F, /* Command style register */
|
||||
|
||||
}CMD2_BITS;
|
||||
|
||||
typedef enum {
|
||||
|
||||
/* VAL3 */
|
||||
ASF_INIT_DONE_ALIAS = (1 << 29),
|
||||
/* VAL2 */
|
||||
JUMBO = (1 << 21),
|
||||
VSIZE = (1 << 20),
|
||||
VLONLY = (1 << 19),
|
||||
VL_TAG_DEL = (1 << 18),
|
||||
/* VAL1 */
|
||||
EN_PMGR = (1 << 14),
|
||||
INTLEVEL = (1 << 13),
|
||||
FORCE_FULL_DUPLEX = (1 << 12),
|
||||
FORCE_LINK_STATUS = (1 << 11),
|
||||
APEP = (1 << 10),
|
||||
MPPLBA = (1 << 9),
|
||||
/* VAL0 */
|
||||
RESET_PHY_PULSE = (1 << 2),
|
||||
RESET_PHY = (1 << 1),
|
||||
PHY_RST_POL = (1 << 0),
|
||||
|
||||
}CMD3_BITS;
|
||||
|
||||
|
||||
typedef enum {
|
||||
|
||||
/* VAL0 */
|
||||
PMAT_SAVE_MATCH = (1 << 4),
|
||||
PMAT_MODE = (1 << 3),
|
||||
MPEN_SW = (1 << 1),
|
||||
LCMODE_SW = (1 << 0),
|
||||
|
||||
CMD7_CLEAR = 0x0000001B /* Command style register */
|
||||
|
||||
}CMD7_BITS;
|
||||
|
||||
|
||||
typedef enum {
|
||||
|
||||
RESET_PHY_WIDTH = (0xF << 16) | (0xF<< 20), /* 0x00FF0000 */
|
||||
XMTSP_MASK = (1 << 9) | (1 << 8), /* 9:8 */
|
||||
XMTSP_128 = (1 << 9), /* 9 */
|
||||
XMTSP_64 = (1 << 8),
|
||||
CACHE_ALIGN = (1 << 4),
|
||||
BURST_LIMIT_MASK = (0xF << 0 ),
|
||||
CTRL1_DEFAULT = 0x00010111,
|
||||
|
||||
}CTRL1_BITS;
|
||||
|
||||
typedef enum {
|
||||
|
||||
FMDC_MASK = (1 << 9)|(1 << 8), /* 9:8 */
|
||||
XPHYRST = (1 << 7),
|
||||
XPHYANE = (1 << 6),
|
||||
XPHYFD = (1 << 5),
|
||||
XPHYSP = (1 << 4) | (1 << 3), /* 4:3 */
|
||||
APDW_MASK = (1 << 2) | (1 << 1) | (1 << 0), /* 2:0 */
|
||||
|
||||
}CTRL2_BITS;
|
||||
|
||||
/* XMT_RING_LIMIT 0x7C, 32bit register */
|
||||
typedef enum {
|
||||
|
||||
XMT_RING2_LIMIT = (0xFF << 16), /* 23:16 */
|
||||
XMT_RING1_LIMIT = (0xFF << 8), /* 15:8 */
|
||||
XMT_RING0_LIMIT = (0xFF << 0), /* 7:0 */
|
||||
|
||||
}XMT_RING_LIMIT_BITS;
|
||||
|
||||
typedef enum {
|
||||
|
||||
AP_REG0_EN = (1 << 15),
|
||||
AP_REG0_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */
|
||||
AP_PHY0_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */
|
||||
|
||||
}AUTOPOLL0_BITS;
|
||||
|
||||
/* AUTOPOLL1 0x8A, 16bit register */
|
||||
typedef enum {
|
||||
|
||||
AP_REG1_EN = (1 << 15),
|
||||
AP_REG1_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */
|
||||
AP_PRE_SUP1 = (1 << 6),
|
||||
AP_PHY1_DFLT = (1 << 5),
|
||||
AP_PHY1_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */
|
||||
|
||||
}AUTOPOLL1_BITS;
|
||||
|
||||
|
||||
typedef enum {
|
||||
|
||||
AP_REG2_EN = (1 << 15),
|
||||
AP_REG2_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */
|
||||
AP_PRE_SUP2 = (1 << 6),
|
||||
AP_PHY2_DFLT = (1 << 5),
|
||||
AP_PHY2_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */
|
||||
|
||||
}AUTOPOLL2_BITS;
|
||||
|
||||
typedef enum {
|
||||
|
||||
AP_REG3_EN = (1 << 15),
|
||||
AP_REG3_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */
|
||||
AP_PRE_SUP3 = (1 << 6),
|
||||
AP_PHY3_DFLT = (1 << 5),
|
||||
AP_PHY3_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */
|
||||
|
||||
}AUTOPOLL3_BITS;
|
||||
|
||||
|
||||
typedef enum {
|
||||
|
||||
AP_REG4_EN = (1 << 15),
|
||||
AP_REG4_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */
|
||||
AP_PRE_SUP4 = (1 << 6),
|
||||
AP_PHY4_DFLT = (1 << 5),
|
||||
AP_PHY4_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */
|
||||
|
||||
}AUTOPOLL4_BITS;
|
||||
|
||||
|
||||
typedef enum {
|
||||
|
||||
AP_REG5_EN = (1 << 15),
|
||||
AP_REG5_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */
|
||||
AP_PRE_SUP5 = (1 << 6),
|
||||
AP_PHY5_DFLT = (1 << 5),
|
||||
AP_PHY5_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */
|
||||
|
||||
}AUTOPOLL5_BITS;
|
||||
|
||||
|
||||
|
||||
|
||||
/* AP_VALUE 0x98, 32bit ragister */
|
||||
typedef enum {
|
||||
|
||||
AP_VAL_ACTIVE = (1 << 31),
|
||||
AP_VAL_RD_CMD = ( 1 << 29),
|
||||
AP_ADDR = (1 << 18)|(1 << 17)|(1 << 16), /* 18:16 */
|
||||
AP_VAL = (0xF << 0) | (0xF << 4) |( 0xF << 8) |
|
||||
(0xF << 12), /* 15:0 */
|
||||
|
||||
}AP_VALUE_BITS;
|
||||
|
||||
typedef enum {
|
||||
|
||||
DLY_INT_A_R3 = (1 << 31),
|
||||
DLY_INT_A_R2 = (1 << 30),
|
||||
DLY_INT_A_R1 = (1 << 29),
|
||||
DLY_INT_A_R0 = (1 << 28),
|
||||
DLY_INT_A_T3 = (1 << 27),
|
||||
DLY_INT_A_T2 = (1 << 26),
|
||||
DLY_INT_A_T1 = (1 << 25),
|
||||
DLY_INT_A_T0 = ( 1 << 24),
|
||||
EVENT_COUNT_A = (0xF << 16) | (0x1 << 20),/* 20:16 */
|
||||
MAX_DELAY_TIME_A = (0xF << 0) | (0xF << 4) | (1 << 8)|
|
||||
(1 << 9) | (1 << 10), /* 10:0 */
|
||||
|
||||
}DLY_INT_A_BITS;
|
||||
|
||||
typedef enum {
|
||||
|
||||
DLY_INT_B_R3 = (1 << 31),
|
||||
DLY_INT_B_R2 = (1 << 30),
|
||||
DLY_INT_B_R1 = (1 << 29),
|
||||
DLY_INT_B_R0 = (1 << 28),
|
||||
DLY_INT_B_T3 = (1 << 27),
|
||||
DLY_INT_B_T2 = (1 << 26),
|
||||
DLY_INT_B_T1 = (1 << 25),
|
||||
DLY_INT_B_T0 = ( 1 << 24),
|
||||
EVENT_COUNT_B = (0xF << 16) | (0x1 << 20),/* 20:16 */
|
||||
MAX_DELAY_TIME_B = (0xF << 0) | (0xF << 4) | (1 << 8)|
|
||||
(1 << 9) | (1 << 10), /* 10:0 */
|
||||
}DLY_INT_B_BITS;
|
||||
|
||||
|
||||
/* FLOW_CONTROL 0xC8, 32bit register */
|
||||
typedef enum {
|
||||
|
||||
PAUSE_LEN_CHG = (1 << 30),
|
||||
FTPE = (1 << 22),
|
||||
FRPE = (1 << 21),
|
||||
NAPA = (1 << 20),
|
||||
NPA = (1 << 19),
|
||||
FIXP = ( 1 << 18),
|
||||
FCCMD = ( 1 << 16),
|
||||
PAUSE_LEN = (0xF << 0) | (0xF << 4) |( 0xF << 8) | (0xF << 12), /* 15:0 */
|
||||
|
||||
}FLOW_CONTROL_BITS;
|
||||
|
||||
/* PHY_ ACCESS 0xD0, 32bit register */
|
||||
typedef enum {
|
||||
|
||||
PHY_CMD_ACTIVE = (1 << 31),
|
||||
PHY_WR_CMD = (1 << 30),
|
||||
PHY_RD_CMD = (1 << 29),
|
||||
PHY_RD_ERR = (1 << 28),
|
||||
PHY_PRE_SUP = (1 << 27),
|
||||
PHY_ADDR = (1 << 21) | (1 << 22) | (1 << 23)|
|
||||
(1 << 24) |(1 << 25),/* 25:21 */
|
||||
PHY_REG_ADDR = (1 << 16) | (1 << 17) | (1 << 18)| (1 << 19) | (1 << 20),/* 20:16 */
|
||||
PHY_DATA = (0xF << 0)|(0xF << 4) |(0xF << 8)|
|
||||
(0xF << 12),/* 15:0 */
|
||||
|
||||
}PHY_ACCESS_BITS;
|
||||
|
||||
|
||||
/* PMAT0 0x190, 32bit register */
|
||||
typedef enum {
|
||||
PMR_ACTIVE = (1 << 31),
|
||||
PMR_WR_CMD = (1 << 30),
|
||||
PMR_RD_CMD = (1 << 29),
|
||||
PMR_BANK = (1 <<28),
|
||||
PMR_ADDR = (0xF << 16)|(1 << 20)|(1 << 21)|
|
||||
(1 << 22),/* 22:16 */
|
||||
PMR_B4 = (0xF << 0) | (0xF << 4),/* 15:0 */
|
||||
}PMAT0_BITS;
|
||||
|
||||
|
||||
/* PMAT1 0x194, 32bit register */
|
||||
typedef enum {
|
||||
PMR_B3 = (0xF << 24) | (0xF <<28),/* 31:24 */
|
||||
PMR_B2 = (0xF << 16) |(0xF << 20),/* 23:16 */
|
||||
PMR_B1 = (0xF << 8) | (0xF <<12), /* 15:8 */
|
||||
PMR_B0 = (0xF << 0)|(0xF << 4),/* 7:0 */
|
||||
}PMAT1_BITS;
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/* MIB counter definitions */
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
||||
#define rcv_miss_pkts 0x00
|
||||
#define rcv_octets 0x01
|
||||
#define rcv_broadcast_pkts 0x02
|
||||
#define rcv_multicast_pkts 0x03
|
||||
#define rcv_undersize_pkts 0x04
|
||||
#define rcv_oversize_pkts 0x05
|
||||
#define rcv_fragments 0x06
|
||||
#define rcv_jabbers 0x07
|
||||
#define rcv_unicast_pkts 0x08
|
||||
#define rcv_alignment_errors 0x09
|
||||
#define rcv_fcs_errors 0x0A
|
||||
#define rcv_good_octets 0x0B
|
||||
#define rcv_mac_ctrl 0x0C
|
||||
#define rcv_flow_ctrl 0x0D
|
||||
#define rcv_pkts_64_octets 0x0E
|
||||
#define rcv_pkts_65to127_octets 0x0F
|
||||
#define rcv_pkts_128to255_octets 0x10
|
||||
#define rcv_pkts_256to511_octets 0x11
|
||||
#define rcv_pkts_512to1023_octets 0x12
|
||||
#define rcv_pkts_1024to1518_octets 0x13
|
||||
#define rcv_unsupported_opcode 0x14
|
||||
#define rcv_symbol_errors 0x15
|
||||
#define rcv_drop_pkts_ring1 0x16
|
||||
#define rcv_drop_pkts_ring2 0x17
|
||||
#define rcv_drop_pkts_ring3 0x18
|
||||
#define rcv_drop_pkts_ring4 0x19
|
||||
#define rcv_jumbo_pkts 0x1A
|
||||
|
||||
#define xmt_underrun_pkts 0x20
|
||||
#define xmt_octets 0x21
|
||||
#define xmt_packets 0x22
|
||||
#define xmt_broadcast_pkts 0x23
|
||||
#define xmt_multicast_pkts 0x24
|
||||
#define xmt_collisions 0x25
|
||||
#define xmt_unicast_pkts 0x26
|
||||
#define xmt_one_collision 0x27
|
||||
#define xmt_multiple_collision 0x28
|
||||
#define xmt_deferred_transmit 0x29
|
||||
#define xmt_late_collision 0x2A
|
||||
#define xmt_excessive_defer 0x2B
|
||||
#define xmt_loss_carrier 0x2C
|
||||
#define xmt_excessive_collision 0x2D
|
||||
#define xmt_back_pressure 0x2E
|
||||
#define xmt_flow_ctrl 0x2F
|
||||
#define xmt_pkts_64_octets 0x30
|
||||
#define xmt_pkts_65to127_octets 0x31
|
||||
#define xmt_pkts_128to255_octets 0x32
|
||||
#define xmt_pkts_256to511_octets 0x33
|
||||
#define xmt_pkts_512to1023_octets 0x34
|
||||
#define xmt_pkts_1024to1518_octet 0x35
|
||||
#define xmt_oversize_pkts 0x36
|
||||
#define xmt_jumbo_pkts 0x37
|
||||
|
||||
|
||||
/* Driver definitions */
|
||||
|
||||
#define PCI_VENDOR_ID_AMD 0x1022
|
||||
#define PCI_DEVICE_ID_AMD8111E_7462 0x7462
|
||||
|
||||
#define MAX_UNITS 8 /* Maximum number of devices possible */
|
||||
|
||||
#define NUM_TX_BUFFERS 32 /* Number of transmit buffers */
|
||||
#define NUM_RX_BUFFERS 32 /* Number of receive buffers */
|
||||
|
||||
#define TX_BUFF_MOD_MASK 31 /* (NUM_TX_BUFFERS -1) */
|
||||
#define RX_BUFF_MOD_MASK 31 /* (NUM_RX_BUFFERS -1) */
|
||||
|
||||
#define NUM_TX_RING_DR 32
|
||||
#define NUM_RX_RING_DR 32
|
||||
|
||||
#define TX_RING_DR_MOD_MASK 31 /* (NUM_TX_RING_DR -1) */
|
||||
#define RX_RING_DR_MOD_MASK 31 /* (NUM_RX_RING_DR -1) */
|
||||
|
||||
#define MAX_FILTER_SIZE 64 /* Maximum multicast address */
|
||||
#define AMD8111E_MIN_MTU 60
|
||||
#define AMD8111E_MAX_MTU 9000
|
||||
|
||||
#define PKT_BUFF_SZ 1536
|
||||
#define MIN_PKT_LEN 60
|
||||
|
||||
#define AMD8111E_TX_TIMEOUT (3 * HZ)/* 3 sec */
|
||||
#define SOFT_TIMER_FREQ 0xBEBC /* 0.5 sec */
|
||||
#define DELAY_TIMER_CONV 50 /* msec to 10 usec conversion.
|
||||
Only 500 usec resolution */
|
||||
#define OPTION_VLAN_ENABLE 0x0001
|
||||
#define OPTION_JUMBO_ENABLE 0x0002
|
||||
#define OPTION_MULTICAST_ENABLE 0x0004
|
||||
#define OPTION_WOL_ENABLE 0x0008
|
||||
#define OPTION_WAKE_MAGIC_ENABLE 0x0010
|
||||
#define OPTION_WAKE_PHY_ENABLE 0x0020
|
||||
#define OPTION_INTR_COAL_ENABLE 0x0040
|
||||
#define OPTION_DYN_IPG_ENABLE 0x0080
|
||||
|
||||
#define PHY_REG_ADDR_MASK 0x1f
|
||||
|
||||
/* ipg parameters */
|
||||
#define DEFAULT_IPG 0x60
|
||||
#define IFS1_DELTA 36
|
||||
#define IPG_CONVERGE_JIFFIES (HZ/2)
|
||||
#define IPG_STABLE_TIME 5
|
||||
#define MIN_IPG 96
|
||||
#define MAX_IPG 255
|
||||
#define IPG_STEP 16
|
||||
#define CSTATE 1
|
||||
#define SSTATE 2
|
||||
|
||||
/* Assume contoller gets data 10 times the maximum processing time */
|
||||
#define REPEAT_CNT 10
|
||||
|
||||
/* amd8111e decriptor flag definitions */
|
||||
typedef enum {
|
||||
|
||||
OWN_BIT = (1 << 15),
|
||||
ADD_FCS_BIT = (1 << 13),
|
||||
LTINT_BIT = (1 << 12),
|
||||
STP_BIT = (1 << 9),
|
||||
ENP_BIT = (1 << 8),
|
||||
KILL_BIT = (1 << 6),
|
||||
TCC_VLAN_INSERT = (1 << 1),
|
||||
TCC_VLAN_REPLACE = (1 << 1) |( 1<< 0),
|
||||
|
||||
}TX_FLAG_BITS;
|
||||
|
||||
typedef enum {
|
||||
ERR_BIT = (1 << 14),
|
||||
FRAM_BIT = (1 << 13),
|
||||
OFLO_BIT = (1 << 12),
|
||||
CRC_BIT = (1 << 11),
|
||||
PAM_BIT = (1 << 6),
|
||||
LAFM_BIT = (1 << 5),
|
||||
BAM_BIT = (1 << 4),
|
||||
TT_VLAN_TAGGED = (1 << 3) |(1 << 2),/* 0x000 */
|
||||
TT_PRTY_TAGGED = (1 << 3),/* 0x0008 */
|
||||
|
||||
}RX_FLAG_BITS;
|
||||
|
||||
#define RESET_RX_FLAGS 0x0000
|
||||
#define TT_MASK 0x000c
|
||||
#define TCC_MASK 0x0003
|
||||
|
||||
/* driver ioctl parameters */
|
||||
#define AMD8111E_REG_DUMP_LEN 13*sizeof(u32)
|
||||
|
||||
/* amd8111e desriptor format */
|
||||
|
||||
struct amd8111e_tx_dr{
|
||||
|
||||
__le16 buff_count; /* Size of the buffer pointed by this descriptor */
|
||||
|
||||
__le16 tx_flags;
|
||||
|
||||
__le16 tag_ctrl_info;
|
||||
|
||||
__le16 tag_ctrl_cmd;
|
||||
|
||||
__le32 buff_phy_addr;
|
||||
|
||||
__le32 reserved;
|
||||
};
|
||||
|
||||
struct amd8111e_rx_dr{
|
||||
|
||||
__le32 reserved;
|
||||
|
||||
__le16 msg_count; /* Received message len */
|
||||
|
||||
__le16 tag_ctrl_info;
|
||||
|
||||
__le16 buff_count; /* Len of the buffer pointed by descriptor. */
|
||||
|
||||
__le16 rx_flags;
|
||||
|
||||
__le32 buff_phy_addr;
|
||||
|
||||
};
|
||||
struct amd8111e_link_config{
|
||||
|
||||
#define SPEED_INVALID 0xffff
|
||||
#define DUPLEX_INVALID 0xff
|
||||
#define AUTONEG_INVALID 0xff
|
||||
|
||||
unsigned long orig_phy_option;
|
||||
u16 speed;
|
||||
u8 duplex;
|
||||
u8 autoneg;
|
||||
u8 reserved; /* 32bit alignment */
|
||||
};
|
||||
|
||||
enum coal_type{
|
||||
|
||||
NO_COALESCE,
|
||||
LOW_COALESCE,
|
||||
MEDIUM_COALESCE,
|
||||
HIGH_COALESCE,
|
||||
|
||||
};
|
||||
|
||||
enum coal_mode{
|
||||
RX_INTR_COAL,
|
||||
TX_INTR_COAL,
|
||||
DISABLE_COAL,
|
||||
ENABLE_COAL,
|
||||
|
||||
};
|
||||
#define MAX_TIMEOUT 40
|
||||
#define MAX_EVENT_COUNT 31
|
||||
struct amd8111e_coalesce_conf{
|
||||
|
||||
unsigned int rx_timeout;
|
||||
unsigned int rx_event_count;
|
||||
unsigned long rx_packets;
|
||||
unsigned long rx_prev_packets;
|
||||
unsigned long rx_bytes;
|
||||
unsigned long rx_prev_bytes;
|
||||
unsigned int rx_coal_type;
|
||||
|
||||
unsigned int tx_timeout;
|
||||
unsigned int tx_event_count;
|
||||
unsigned long tx_packets;
|
||||
unsigned long tx_prev_packets;
|
||||
unsigned long tx_bytes;
|
||||
unsigned long tx_prev_bytes;
|
||||
unsigned int tx_coal_type;
|
||||
|
||||
};
|
||||
struct ipg_info{
|
||||
|
||||
unsigned int ipg_state;
|
||||
unsigned int ipg;
|
||||
unsigned int current_ipg;
|
||||
unsigned int col_cnt;
|
||||
unsigned int diff_col_cnt;
|
||||
unsigned int timer_tick;
|
||||
unsigned int prev_ipg;
|
||||
struct timer_list ipg_timer;
|
||||
};
|
||||
|
||||
struct amd8111e_priv{
|
||||
|
||||
struct amd8111e_tx_dr* tx_ring;
|
||||
struct amd8111e_rx_dr* rx_ring;
|
||||
dma_addr_t tx_ring_dma_addr; /* tx descriptor ring base address */
|
||||
dma_addr_t rx_ring_dma_addr; /* rx descriptor ring base address */
|
||||
const char *name;
|
||||
struct pci_dev *pci_dev; /* Ptr to the associated pci_dev */
|
||||
struct net_device* amd8111e_net_dev; /* ptr to associated net_device */
|
||||
/* Transmit and receive skbs */
|
||||
struct sk_buff *tx_skbuff[NUM_TX_BUFFERS];
|
||||
struct sk_buff *rx_skbuff[NUM_RX_BUFFERS];
|
||||
/* Transmit and receive dma mapped addr */
|
||||
dma_addr_t tx_dma_addr[NUM_TX_BUFFERS];
|
||||
dma_addr_t rx_dma_addr[NUM_RX_BUFFERS];
|
||||
/* Reg memory mapped address */
|
||||
void __iomem *mmio;
|
||||
|
||||
struct napi_struct napi;
|
||||
|
||||
spinlock_t lock; /* Guard lock */
|
||||
unsigned long rx_idx, tx_idx; /* The next free ring entry */
|
||||
unsigned long tx_complete_idx;
|
||||
unsigned long tx_ring_complete_idx;
|
||||
unsigned long tx_ring_idx;
|
||||
unsigned int rx_buff_len; /* Buffer length of rx buffers */
|
||||
int options; /* Options enabled/disabled for the device */
|
||||
|
||||
unsigned long ext_phy_option;
|
||||
int ext_phy_addr;
|
||||
u32 ext_phy_id;
|
||||
|
||||
struct amd8111e_link_config link_config;
|
||||
int pm_cap;
|
||||
|
||||
struct net_device *next;
|
||||
int mii;
|
||||
struct mii_if_info mii_if;
|
||||
char opened;
|
||||
unsigned int drv_rx_errors;
|
||||
struct amd8111e_coalesce_conf coal_conf;
|
||||
|
||||
struct ipg_info ipg_data;
|
||||
|
||||
};
|
||||
|
||||
/* kernel provided writeq does not write 64 bits into the amd8111e device register instead writes only higher 32bits data into lower 32bits of the register.
|
||||
BUG? */
|
||||
#define amd8111e_writeq(_UlData,_memMap) \
|
||||
writel(*(u32*)(&_UlData), _memMap); \
|
||||
writel(*(u32*)((u8*)(&_UlData)+4), _memMap+4)
|
||||
|
||||
/* maps the external speed options to internal value */
|
||||
typedef enum {
|
||||
SPEED_AUTONEG,
|
||||
SPEED10_HALF,
|
||||
SPEED10_FULL,
|
||||
SPEED100_HALF,
|
||||
SPEED100_FULL,
|
||||
}EXT_PHY_OPTION;
|
||||
|
||||
static int card_idx;
|
||||
static int speed_duplex[MAX_UNITS] = { 0, };
|
||||
static bool coalesce[MAX_UNITS] = { [ 0 ... MAX_UNITS-1] = true };
|
||||
static bool dynamic_ipg[MAX_UNITS] = { [ 0 ... MAX_UNITS-1] = false };
|
||||
static unsigned int chip_version;
|
||||
|
||||
#endif /* _AMD8111E_H */
|
||||
|
792
drivers/net/ethernet/amd/ariadne.c
Normal file
792
drivers/net/ethernet/amd/ariadne.c
Normal file
|
@ -0,0 +1,792 @@
|
|||
/*
|
||||
* Amiga Linux/m68k Ariadne Ethernet Driver
|
||||
*
|
||||
* © Copyright 1995-2003 by Geert Uytterhoeven (geert@linux-m68k.org)
|
||||
* Peter De Schrijver (p2@mind.be)
|
||||
*
|
||||
* ---------------------------------------------------------------------------
|
||||
*
|
||||
* This program is based on
|
||||
*
|
||||
* lance.c: An AMD LANCE ethernet driver for linux.
|
||||
* Written 1993-94 by Donald Becker.
|
||||
*
|
||||
* Am79C960: PCnet(tm)-ISA Single-Chip Ethernet Controller
|
||||
* Advanced Micro Devices
|
||||
* Publication #16907, Rev. B, Amendment/0, May 1994
|
||||
*
|
||||
* MC68230: Parallel Interface/Timer (PI/T)
|
||||
* Motorola Semiconductors, December, 1983
|
||||
*
|
||||
* ---------------------------------------------------------------------------
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of the Linux
|
||||
* distribution for more details.
|
||||
*
|
||||
* ---------------------------------------------------------------------------
|
||||
*
|
||||
* The Ariadne is a Zorro-II board made by Village Tronic. It contains:
|
||||
*
|
||||
* - an Am79C960 PCnet-ISA Single-Chip Ethernet Controller with both
|
||||
* 10BASE-2 (thin coax) and 10BASE-T (UTP) connectors
|
||||
*
|
||||
* - an MC68230 Parallel Interface/Timer configured as 2 parallel ports
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
/*#define DEBUG*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/zorro.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/amigaints.h>
|
||||
#include <asm/amigahw.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include "ariadne.h"
|
||||
|
||||
#ifdef ARIADNE_DEBUG
|
||||
int ariadne_debug = ARIADNE_DEBUG;
|
||||
#else
|
||||
int ariadne_debug = 1;
|
||||
#endif
|
||||
|
||||
/* Macros to Fix Endianness problems */
|
||||
|
||||
/* Swap the Bytes in a WORD */
|
||||
#define swapw(x) (((x >> 8) & 0x00ff) | ((x << 8) & 0xff00))
|
||||
/* Get the Low BYTE in a WORD */
|
||||
#define lowb(x) (x & 0xff)
|
||||
/* Get the Swapped High WORD in a LONG */
|
||||
#define swhighw(x) ((((x) >> 8) & 0xff00) | (((x) >> 24) & 0x00ff))
|
||||
/* Get the Swapped Low WORD in a LONG */
|
||||
#define swloww(x) ((((x) << 8) & 0xff00) | (((x) >> 8) & 0x00ff))
|
||||
|
||||
/* Transmit/Receive Ring Definitions */
|
||||
|
||||
#define TX_RING_SIZE 5
|
||||
#define RX_RING_SIZE 16
|
||||
|
||||
#define PKT_BUF_SIZE 1520
|
||||
|
||||
/* Private Device Data */
|
||||
|
||||
struct ariadne_private {
|
||||
volatile struct TDRE *tx_ring[TX_RING_SIZE];
|
||||
volatile struct RDRE *rx_ring[RX_RING_SIZE];
|
||||
volatile u_short *tx_buff[TX_RING_SIZE];
|
||||
volatile u_short *rx_buff[RX_RING_SIZE];
|
||||
int cur_tx, cur_rx; /* The next free ring entry */
|
||||
int dirty_tx; /* The ring entries to be free()ed */
|
||||
char tx_full;
|
||||
};
|
||||
|
||||
/* Structure Created in the Ariadne's RAM Buffer */
|
||||
|
||||
struct lancedata {
|
||||
struct TDRE tx_ring[TX_RING_SIZE];
|
||||
struct RDRE rx_ring[RX_RING_SIZE];
|
||||
u_short tx_buff[TX_RING_SIZE][PKT_BUF_SIZE / sizeof(u_short)];
|
||||
u_short rx_buff[RX_RING_SIZE][PKT_BUF_SIZE / sizeof(u_short)];
|
||||
};
|
||||
|
||||
static void memcpyw(volatile u_short *dest, u_short *src, int len)
|
||||
{
|
||||
while (len >= 2) {
|
||||
*(dest++) = *(src++);
|
||||
len -= 2;
|
||||
}
|
||||
if (len == 1)
|
||||
*dest = (*(u_char *)src) << 8;
|
||||
}
|
||||
|
||||
static void ariadne_init_ring(struct net_device *dev)
|
||||
{
|
||||
struct ariadne_private *priv = netdev_priv(dev);
|
||||
volatile struct lancedata *lancedata = (struct lancedata *)dev->mem_start;
|
||||
int i;
|
||||
|
||||
netif_stop_queue(dev);
|
||||
|
||||
priv->tx_full = 0;
|
||||
priv->cur_rx = priv->cur_tx = 0;
|
||||
priv->dirty_tx = 0;
|
||||
|
||||
/* Set up TX Ring */
|
||||
for (i = 0; i < TX_RING_SIZE; i++) {
|
||||
volatile struct TDRE *t = &lancedata->tx_ring[i];
|
||||
t->TMD0 = swloww(ARIADNE_RAM +
|
||||
offsetof(struct lancedata, tx_buff[i]));
|
||||
t->TMD1 = swhighw(ARIADNE_RAM +
|
||||
offsetof(struct lancedata, tx_buff[i])) |
|
||||
TF_STP | TF_ENP;
|
||||
t->TMD2 = swapw((u_short)-PKT_BUF_SIZE);
|
||||
t->TMD3 = 0;
|
||||
priv->tx_ring[i] = &lancedata->tx_ring[i];
|
||||
priv->tx_buff[i] = lancedata->tx_buff[i];
|
||||
netdev_dbg(dev, "TX Entry %2d at %p, Buf at %p\n",
|
||||
i, &lancedata->tx_ring[i], lancedata->tx_buff[i]);
|
||||
}
|
||||
|
||||
/* Set up RX Ring */
|
||||
for (i = 0; i < RX_RING_SIZE; i++) {
|
||||
volatile struct RDRE *r = &lancedata->rx_ring[i];
|
||||
r->RMD0 = swloww(ARIADNE_RAM +
|
||||
offsetof(struct lancedata, rx_buff[i]));
|
||||
r->RMD1 = swhighw(ARIADNE_RAM +
|
||||
offsetof(struct lancedata, rx_buff[i])) |
|
||||
RF_OWN;
|
||||
r->RMD2 = swapw((u_short)-PKT_BUF_SIZE);
|
||||
r->RMD3 = 0x0000;
|
||||
priv->rx_ring[i] = &lancedata->rx_ring[i];
|
||||
priv->rx_buff[i] = lancedata->rx_buff[i];
|
||||
netdev_dbg(dev, "RX Entry %2d at %p, Buf at %p\n",
|
||||
i, &lancedata->rx_ring[i], lancedata->rx_buff[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int ariadne_rx(struct net_device *dev)
|
||||
{
|
||||
struct ariadne_private *priv = netdev_priv(dev);
|
||||
int entry = priv->cur_rx % RX_RING_SIZE;
|
||||
int i;
|
||||
|
||||
/* If we own the next entry, it's a new packet. Send it up */
|
||||
while (!(lowb(priv->rx_ring[entry]->RMD1) & RF_OWN)) {
|
||||
int status = lowb(priv->rx_ring[entry]->RMD1);
|
||||
|
||||
if (status != (RF_STP | RF_ENP)) { /* 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
|
||||
*/
|
||||
/* Only count a general error at the end of a packet */
|
||||
if (status & RF_ENP)
|
||||
dev->stats.rx_errors++;
|
||||
if (status & RF_FRAM)
|
||||
dev->stats.rx_frame_errors++;
|
||||
if (status & RF_OFLO)
|
||||
dev->stats.rx_over_errors++;
|
||||
if (status & RF_CRC)
|
||||
dev->stats.rx_crc_errors++;
|
||||
if (status & RF_BUFF)
|
||||
dev->stats.rx_fifo_errors++;
|
||||
priv->rx_ring[entry]->RMD1 &= 0xff00 | RF_STP | RF_ENP;
|
||||
} else {
|
||||
/* Malloc up new buffer, compatible with net-3 */
|
||||
short pkt_len = swapw(priv->rx_ring[entry]->RMD3);
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = netdev_alloc_skb(dev, pkt_len + 2);
|
||||
if (skb == NULL) {
|
||||
for (i = 0; i < RX_RING_SIZE; i++)
|
||||
if (lowb(priv->rx_ring[(entry + i) % RX_RING_SIZE]->RMD1) & RF_OWN)
|
||||
break;
|
||||
|
||||
if (i > RX_RING_SIZE - 2) {
|
||||
dev->stats.rx_dropped++;
|
||||
priv->rx_ring[entry]->RMD1 |= RF_OWN;
|
||||
priv->cur_rx++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
skb_reserve(skb, 2); /* 16 byte align */
|
||||
skb_put(skb, pkt_len); /* Make room */
|
||||
skb_copy_to_linear_data(skb,
|
||||
(const void *)priv->rx_buff[entry],
|
||||
pkt_len);
|
||||
skb->protocol = eth_type_trans(skb, dev);
|
||||
netdev_dbg(dev, "RX pkt type 0x%04x from %pM to %pM data %p len %u\n",
|
||||
((u_short *)skb->data)[6],
|
||||
skb->data + 6, skb->data,
|
||||
skb->data, skb->len);
|
||||
|
||||
netif_rx(skb);
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += pkt_len;
|
||||
}
|
||||
|
||||
priv->rx_ring[entry]->RMD1 |= RF_OWN;
|
||||
entry = (++priv->cur_rx) % RX_RING_SIZE;
|
||||
}
|
||||
|
||||
priv->cur_rx = priv->cur_rx % RX_RING_SIZE;
|
||||
|
||||
/* 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 irqreturn_t ariadne_interrupt(int irq, void *data)
|
||||
{
|
||||
struct net_device *dev = (struct net_device *)data;
|
||||
volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
|
||||
struct ariadne_private *priv;
|
||||
int csr0, boguscnt;
|
||||
int handled = 0;
|
||||
|
||||
lance->RAP = CSR0; /* PCnet-ISA Controller Status */
|
||||
|
||||
if (!(lance->RDP & INTR)) /* Check if any interrupt has been */
|
||||
return IRQ_NONE; /* generated by the board */
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
|
||||
boguscnt = 10;
|
||||
while ((csr0 = lance->RDP) & (ERR | RINT | TINT) && --boguscnt >= 0) {
|
||||
/* Acknowledge all of the current interrupt sources ASAP */
|
||||
lance->RDP = csr0 & ~(INEA | TDMD | STOP | STRT | INIT);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ariadne_debug > 5) {
|
||||
netdev_dbg(dev, "interrupt csr0=%#02x new csr=%#02x [",
|
||||
csr0, lance->RDP);
|
||||
if (csr0 & INTR)
|
||||
pr_cont(" INTR");
|
||||
if (csr0 & INEA)
|
||||
pr_cont(" INEA");
|
||||
if (csr0 & RXON)
|
||||
pr_cont(" RXON");
|
||||
if (csr0 & TXON)
|
||||
pr_cont(" TXON");
|
||||
if (csr0 & TDMD)
|
||||
pr_cont(" TDMD");
|
||||
if (csr0 & STOP)
|
||||
pr_cont(" STOP");
|
||||
if (csr0 & STRT)
|
||||
pr_cont(" STRT");
|
||||
if (csr0 & INIT)
|
||||
pr_cont(" INIT");
|
||||
if (csr0 & ERR)
|
||||
pr_cont(" ERR");
|
||||
if (csr0 & BABL)
|
||||
pr_cont(" BABL");
|
||||
if (csr0 & CERR)
|
||||
pr_cont(" CERR");
|
||||
if (csr0 & MISS)
|
||||
pr_cont(" MISS");
|
||||
if (csr0 & MERR)
|
||||
pr_cont(" MERR");
|
||||
if (csr0 & RINT)
|
||||
pr_cont(" RINT");
|
||||
if (csr0 & TINT)
|
||||
pr_cont(" TINT");
|
||||
if (csr0 & IDON)
|
||||
pr_cont(" IDON");
|
||||
pr_cont(" ]\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (csr0 & RINT) { /* Rx interrupt */
|
||||
handled = 1;
|
||||
ariadne_rx(dev);
|
||||
}
|
||||
|
||||
if (csr0 & TINT) { /* Tx-done interrupt */
|
||||
int dirty_tx = priv->dirty_tx;
|
||||
|
||||
handled = 1;
|
||||
while (dirty_tx < priv->cur_tx) {
|
||||
int entry = dirty_tx % TX_RING_SIZE;
|
||||
int status = lowb(priv->tx_ring[entry]->TMD1);
|
||||
|
||||
if (status & TF_OWN)
|
||||
break; /* It still hasn't been Txed */
|
||||
|
||||
priv->tx_ring[entry]->TMD1 &= 0xff00;
|
||||
|
||||
if (status & TF_ERR) {
|
||||
/* There was an major error, log it */
|
||||
int err_status = priv->tx_ring[entry]->TMD3;
|
||||
dev->stats.tx_errors++;
|
||||
if (err_status & EF_RTRY)
|
||||
dev->stats.tx_aborted_errors++;
|
||||
if (err_status & EF_LCAR)
|
||||
dev->stats.tx_carrier_errors++;
|
||||
if (err_status & EF_LCOL)
|
||||
dev->stats.tx_window_errors++;
|
||||
if (err_status & EF_UFLO) {
|
||||
/* Ackk! On FIFO errors the Tx unit is turned off! */
|
||||
dev->stats.tx_fifo_errors++;
|
||||
/* Remove this verbosity later! */
|
||||
netdev_err(dev, "Tx FIFO error! Status %04x\n",
|
||||
csr0);
|
||||
/* Restart the chip */
|
||||
lance->RDP = STRT;
|
||||
}
|
||||
} else {
|
||||
if (status & (TF_MORE | TF_ONE))
|
||||
dev->stats.collisions++;
|
||||
dev->stats.tx_packets++;
|
||||
}
|
||||
dirty_tx++;
|
||||
}
|
||||
|
||||
#ifndef final_version
|
||||
if (priv->cur_tx - dirty_tx >= TX_RING_SIZE) {
|
||||
netdev_err(dev, "out-of-sync dirty pointer, %d vs. %d, full=%d\n",
|
||||
dirty_tx, priv->cur_tx,
|
||||
priv->tx_full);
|
||||
dirty_tx += TX_RING_SIZE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (priv->tx_full && netif_queue_stopped(dev) &&
|
||||
dirty_tx > priv->cur_tx - TX_RING_SIZE + 2) {
|
||||
/* The ring is no longer full */
|
||||
priv->tx_full = 0;
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
|
||||
priv->dirty_tx = dirty_tx;
|
||||
}
|
||||
|
||||
/* Log misc errors */
|
||||
if (csr0 & BABL) {
|
||||
handled = 1;
|
||||
dev->stats.tx_errors++; /* Tx babble */
|
||||
}
|
||||
if (csr0 & MISS) {
|
||||
handled = 1;
|
||||
dev->stats.rx_errors++; /* Missed a Rx frame */
|
||||
}
|
||||
if (csr0 & MERR) {
|
||||
handled = 1;
|
||||
netdev_err(dev, "Bus master arbitration failure, status %04x\n",
|
||||
csr0);
|
||||
/* Restart the chip */
|
||||
lance->RDP = STRT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear any other interrupt, and set interrupt enable */
|
||||
lance->RAP = CSR0; /* PCnet-ISA Controller Status */
|
||||
lance->RDP = INEA | BABL | CERR | MISS | MERR | IDON;
|
||||
|
||||
if (ariadne_debug > 4)
|
||||
netdev_dbg(dev, "exiting interrupt, csr%d=%#04x\n",
|
||||
lance->RAP, lance->RDP);
|
||||
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
static int ariadne_open(struct net_device *dev)
|
||||
{
|
||||
volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
|
||||
u_short in;
|
||||
u_long version;
|
||||
int i;
|
||||
|
||||
/* Reset the LANCE */
|
||||
in = lance->Reset;
|
||||
|
||||
/* Stop the LANCE */
|
||||
lance->RAP = CSR0; /* PCnet-ISA Controller Status */
|
||||
lance->RDP = STOP;
|
||||
|
||||
/* Check the LANCE version */
|
||||
lance->RAP = CSR88; /* Chip ID */
|
||||
version = swapw(lance->RDP);
|
||||
lance->RAP = CSR89; /* Chip ID */
|
||||
version |= swapw(lance->RDP) << 16;
|
||||
if ((version & 0x00000fff) != 0x00000003) {
|
||||
pr_warn("Couldn't find AMD Ethernet Chip\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
if ((version & 0x0ffff000) != 0x00003000) {
|
||||
pr_warn("Couldn't find Am79C960 (Wrong part number = %ld)\n",
|
||||
(version & 0x0ffff000) >> 12);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
netdev_dbg(dev, "Am79C960 (PCnet-ISA) Revision %ld\n",
|
||||
(version & 0xf0000000) >> 28);
|
||||
|
||||
ariadne_init_ring(dev);
|
||||
|
||||
/* Miscellaneous Stuff */
|
||||
lance->RAP = CSR3; /* Interrupt Masks and Deferral Control */
|
||||
lance->RDP = 0x0000;
|
||||
lance->RAP = CSR4; /* Test and Features Control */
|
||||
lance->RDP = DPOLL | APAD_XMT | MFCOM | RCVCCOM | TXSTRTM | JABM;
|
||||
|
||||
/* Set the Multicast Table */
|
||||
lance->RAP = CSR8; /* Logical Address Filter, LADRF[15:0] */
|
||||
lance->RDP = 0x0000;
|
||||
lance->RAP = CSR9; /* Logical Address Filter, LADRF[31:16] */
|
||||
lance->RDP = 0x0000;
|
||||
lance->RAP = CSR10; /* Logical Address Filter, LADRF[47:32] */
|
||||
lance->RDP = 0x0000;
|
||||
lance->RAP = CSR11; /* Logical Address Filter, LADRF[63:48] */
|
||||
lance->RDP = 0x0000;
|
||||
|
||||
/* Set the Ethernet Hardware Address */
|
||||
lance->RAP = CSR12; /* Physical Address Register, PADR[15:0] */
|
||||
lance->RDP = ((u_short *)&dev->dev_addr[0])[0];
|
||||
lance->RAP = CSR13; /* Physical Address Register, PADR[31:16] */
|
||||
lance->RDP = ((u_short *)&dev->dev_addr[0])[1];
|
||||
lance->RAP = CSR14; /* Physical Address Register, PADR[47:32] */
|
||||
lance->RDP = ((u_short *)&dev->dev_addr[0])[2];
|
||||
|
||||
/* Set the Init Block Mode */
|
||||
lance->RAP = CSR15; /* Mode Register */
|
||||
lance->RDP = 0x0000;
|
||||
|
||||
/* Set the Transmit Descriptor Ring Pointer */
|
||||
lance->RAP = CSR30; /* Base Address of Transmit Ring */
|
||||
lance->RDP = swloww(ARIADNE_RAM + offsetof(struct lancedata, tx_ring));
|
||||
lance->RAP = CSR31; /* Base Address of transmit Ring */
|
||||
lance->RDP = swhighw(ARIADNE_RAM + offsetof(struct lancedata, tx_ring));
|
||||
|
||||
/* Set the Receive Descriptor Ring Pointer */
|
||||
lance->RAP = CSR24; /* Base Address of Receive Ring */
|
||||
lance->RDP = swloww(ARIADNE_RAM + offsetof(struct lancedata, rx_ring));
|
||||
lance->RAP = CSR25; /* Base Address of Receive Ring */
|
||||
lance->RDP = swhighw(ARIADNE_RAM + offsetof(struct lancedata, rx_ring));
|
||||
|
||||
/* Set the Number of RX and TX Ring Entries */
|
||||
lance->RAP = CSR76; /* Receive Ring Length */
|
||||
lance->RDP = swapw(((u_short)-RX_RING_SIZE));
|
||||
lance->RAP = CSR78; /* Transmit Ring Length */
|
||||
lance->RDP = swapw(((u_short)-TX_RING_SIZE));
|
||||
|
||||
/* Enable Media Interface Port Auto Select (10BASE-2/10BASE-T) */
|
||||
lance->RAP = ISACSR2; /* Miscellaneous Configuration */
|
||||
lance->IDP = ASEL;
|
||||
|
||||
/* LED Control */
|
||||
lance->RAP = ISACSR5; /* LED1 Status */
|
||||
lance->IDP = PSE|XMTE;
|
||||
lance->RAP = ISACSR6; /* LED2 Status */
|
||||
lance->IDP = PSE|COLE;
|
||||
lance->RAP = ISACSR7; /* LED3 Status */
|
||||
lance->IDP = PSE|RCVE;
|
||||
|
||||
netif_start_queue(dev);
|
||||
|
||||
i = request_irq(IRQ_AMIGA_PORTS, ariadne_interrupt, IRQF_SHARED,
|
||||
dev->name, dev);
|
||||
if (i)
|
||||
return i;
|
||||
|
||||
lance->RAP = CSR0; /* PCnet-ISA Controller Status */
|
||||
lance->RDP = INEA | STRT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ariadne_close(struct net_device *dev)
|
||||
{
|
||||
volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
|
||||
|
||||
netif_stop_queue(dev);
|
||||
|
||||
lance->RAP = CSR112; /* Missed Frame Count */
|
||||
dev->stats.rx_missed_errors = swapw(lance->RDP);
|
||||
lance->RAP = CSR0; /* PCnet-ISA Controller Status */
|
||||
|
||||
if (ariadne_debug > 1) {
|
||||
netdev_dbg(dev, "Shutting down ethercard, status was %02x\n",
|
||||
lance->RDP);
|
||||
netdev_dbg(dev, "%lu packets missed\n",
|
||||
dev->stats.rx_missed_errors);
|
||||
}
|
||||
|
||||
/* We stop the LANCE here -- it occasionally polls memory if we don't */
|
||||
lance->RDP = STOP;
|
||||
|
||||
free_irq(IRQ_AMIGA_PORTS, dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ariadne_reset(struct net_device *dev)
|
||||
{
|
||||
volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
|
||||
|
||||
lance->RAP = CSR0; /* PCnet-ISA Controller Status */
|
||||
lance->RDP = STOP;
|
||||
ariadne_init_ring(dev);
|
||||
lance->RDP = INEA | STRT;
|
||||
netif_start_queue(dev);
|
||||
}
|
||||
|
||||
static void ariadne_tx_timeout(struct net_device *dev)
|
||||
{
|
||||
volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
|
||||
|
||||
netdev_err(dev, "transmit timed out, status %04x, resetting\n",
|
||||
lance->RDP);
|
||||
ariadne_reset(dev);
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
|
||||
static netdev_tx_t ariadne_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct ariadne_private *priv = netdev_priv(dev);
|
||||
volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
|
||||
int entry;
|
||||
unsigned long flags;
|
||||
int len = skb->len;
|
||||
|
||||
#if 0
|
||||
if (ariadne_debug > 3) {
|
||||
lance->RAP = CSR0; /* PCnet-ISA Controller Status */
|
||||
netdev_dbg(dev, "%s: csr0 %04x\n", __func__, lance->RDP);
|
||||
lance->RDP = 0x0000;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* FIXME: is the 79C960 new enough to do its own padding right ? */
|
||||
if (skb->len < ETH_ZLEN) {
|
||||
if (skb_padto(skb, ETH_ZLEN))
|
||||
return NETDEV_TX_OK;
|
||||
len = ETH_ZLEN;
|
||||
}
|
||||
|
||||
/* Fill in a Tx ring entry */
|
||||
|
||||
netdev_dbg(dev, "TX pkt type 0x%04x from %pM to %pM data %p len %u\n",
|
||||
((u_short *)skb->data)[6],
|
||||
skb->data + 6, skb->data,
|
||||
skb->data, skb->len);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
entry = priv->cur_tx % TX_RING_SIZE;
|
||||
|
||||
/* Caution: the write order is important here, set the base address with
|
||||
the "ownership" bits last */
|
||||
|
||||
priv->tx_ring[entry]->TMD2 = swapw((u_short)-skb->len);
|
||||
priv->tx_ring[entry]->TMD3 = 0x0000;
|
||||
memcpyw(priv->tx_buff[entry], (u_short *)skb->data, len);
|
||||
|
||||
#ifdef DEBUG
|
||||
print_hex_dump(KERN_DEBUG, "tx_buff: ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
(void *)priv->tx_buff[entry],
|
||||
skb->len > 64 ? 64 : skb->len, true);
|
||||
#endif
|
||||
|
||||
priv->tx_ring[entry]->TMD1 = (priv->tx_ring[entry]->TMD1 & 0xff00)
|
||||
| TF_OWN | TF_STP | TF_ENP;
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
priv->cur_tx++;
|
||||
if ((priv->cur_tx >= TX_RING_SIZE) &&
|
||||
(priv->dirty_tx >= TX_RING_SIZE)) {
|
||||
|
||||
netdev_dbg(dev, "*** Subtracting TX_RING_SIZE from cur_tx (%d) and dirty_tx (%d)\n",
|
||||
priv->cur_tx, priv->dirty_tx);
|
||||
|
||||
priv->cur_tx -= TX_RING_SIZE;
|
||||
priv->dirty_tx -= TX_RING_SIZE;
|
||||
}
|
||||
dev->stats.tx_bytes += len;
|
||||
|
||||
/* Trigger an immediate send poll */
|
||||
lance->RAP = CSR0; /* PCnet-ISA Controller Status */
|
||||
lance->RDP = INEA | TDMD;
|
||||
|
||||
if (lowb(priv->tx_ring[(entry + 1) % TX_RING_SIZE]->TMD1) != 0) {
|
||||
netif_stop_queue(dev);
|
||||
priv->tx_full = 1;
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static struct net_device_stats *ariadne_get_stats(struct net_device *dev)
|
||||
{
|
||||
volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
|
||||
short saved_addr;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
saved_addr = lance->RAP;
|
||||
lance->RAP = CSR112; /* Missed Frame Count */
|
||||
dev->stats.rx_missed_errors = swapw(lance->RDP);
|
||||
lance->RAP = saved_addr;
|
||||
local_irq_restore(flags);
|
||||
|
||||
return &dev->stats;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
static void set_multicast_list(struct net_device *dev)
|
||||
{
|
||||
volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
|
||||
|
||||
if (!netif_running(dev))
|
||||
return;
|
||||
|
||||
netif_stop_queue(dev);
|
||||
|
||||
/* We take the simple way out and always enable promiscuous mode */
|
||||
lance->RAP = CSR0; /* PCnet-ISA Controller Status */
|
||||
lance->RDP = STOP; /* Temporarily stop the lance */
|
||||
ariadne_init_ring(dev);
|
||||
|
||||
if (dev->flags & IFF_PROMISC) {
|
||||
lance->RAP = CSR15; /* Mode Register */
|
||||
lance->RDP = PROM; /* 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++) {
|
||||
lance->RAP = CSR8 + (i << 8);
|
||||
/* Logical Address Filter */
|
||||
lance->RDP = swapw(multicast_table[i]);
|
||||
}
|
||||
lance->RAP = CSR15; /* Mode Register */
|
||||
lance->RDP = 0x0000; /* Unset promiscuous mode */
|
||||
}
|
||||
|
||||
lance->RAP = CSR0; /* PCnet-ISA Controller Status */
|
||||
lance->RDP = INEA | STRT | IDON;/* Resume normal operation */
|
||||
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
|
||||
|
||||
static void ariadne_remove_one(struct zorro_dev *z)
|
||||
{
|
||||
struct net_device *dev = zorro_get_drvdata(z);
|
||||
|
||||
unregister_netdev(dev);
|
||||
release_mem_region(ZTWO_PADDR(dev->base_addr), sizeof(struct Am79C960));
|
||||
release_mem_region(ZTWO_PADDR(dev->mem_start), ARIADNE_RAM_SIZE);
|
||||
free_netdev(dev);
|
||||
}
|
||||
|
||||
static struct zorro_device_id ariadne_zorro_tbl[] = {
|
||||
{ ZORRO_PROD_VILLAGE_TRONIC_ARIADNE },
|
||||
{ 0 }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(zorro, ariadne_zorro_tbl);
|
||||
|
||||
static const struct net_device_ops ariadne_netdev_ops = {
|
||||
.ndo_open = ariadne_open,
|
||||
.ndo_stop = ariadne_close,
|
||||
.ndo_start_xmit = ariadne_start_xmit,
|
||||
.ndo_tx_timeout = ariadne_tx_timeout,
|
||||
.ndo_get_stats = ariadne_get_stats,
|
||||
.ndo_set_rx_mode = set_multicast_list,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_change_mtu = eth_change_mtu,
|
||||
.ndo_set_mac_address = eth_mac_addr,
|
||||
};
|
||||
|
||||
static int ariadne_init_one(struct zorro_dev *z,
|
||||
const struct zorro_device_id *ent)
|
||||
{
|
||||
unsigned long board = z->resource.start;
|
||||
unsigned long base_addr = board + ARIADNE_LANCE;
|
||||
unsigned long mem_start = board + ARIADNE_RAM;
|
||||
struct resource *r1, *r2;
|
||||
struct net_device *dev;
|
||||
u32 serial;
|
||||
int err;
|
||||
|
||||
r1 = request_mem_region(base_addr, sizeof(struct Am79C960), "Am79C960");
|
||||
if (!r1)
|
||||
return -EBUSY;
|
||||
r2 = request_mem_region(mem_start, ARIADNE_RAM_SIZE, "RAM");
|
||||
if (!r2) {
|
||||
release_mem_region(base_addr, sizeof(struct Am79C960));
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
dev = alloc_etherdev(sizeof(struct ariadne_private));
|
||||
if (dev == NULL) {
|
||||
release_mem_region(base_addr, sizeof(struct Am79C960));
|
||||
release_mem_region(mem_start, ARIADNE_RAM_SIZE);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r1->name = dev->name;
|
||||
r2->name = dev->name;
|
||||
|
||||
serial = be32_to_cpu(z->rom.er_SerialNumber);
|
||||
dev->dev_addr[0] = 0x00;
|
||||
dev->dev_addr[1] = 0x60;
|
||||
dev->dev_addr[2] = 0x30;
|
||||
dev->dev_addr[3] = (serial >> 16) & 0xff;
|
||||
dev->dev_addr[4] = (serial >> 8) & 0xff;
|
||||
dev->dev_addr[5] = serial & 0xff;
|
||||
dev->base_addr = (unsigned long)ZTWO_VADDR(base_addr);
|
||||
dev->mem_start = (unsigned long)ZTWO_VADDR(mem_start);
|
||||
dev->mem_end = dev->mem_start + ARIADNE_RAM_SIZE;
|
||||
|
||||
dev->netdev_ops = &ariadne_netdev_ops;
|
||||
dev->watchdog_timeo = 5 * HZ;
|
||||
|
||||
err = register_netdev(dev);
|
||||
if (err) {
|
||||
release_mem_region(base_addr, sizeof(struct Am79C960));
|
||||
release_mem_region(mem_start, ARIADNE_RAM_SIZE);
|
||||
free_netdev(dev);
|
||||
return err;
|
||||
}
|
||||
zorro_set_drvdata(z, dev);
|
||||
|
||||
netdev_info(dev, "Ariadne at 0x%08lx, Ethernet Address %pM\n",
|
||||
board, dev->dev_addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct zorro_driver ariadne_driver = {
|
||||
.name = "ariadne",
|
||||
.id_table = ariadne_zorro_tbl,
|
||||
.probe = ariadne_init_one,
|
||||
.remove = ariadne_remove_one,
|
||||
};
|
||||
|
||||
static int __init ariadne_init_module(void)
|
||||
{
|
||||
return zorro_register_driver(&ariadne_driver);
|
||||
}
|
||||
|
||||
static void __exit ariadne_cleanup_module(void)
|
||||
{
|
||||
zorro_unregister_driver(&ariadne_driver);
|
||||
}
|
||||
|
||||
module_init(ariadne_init_module);
|
||||
module_exit(ariadne_cleanup_module);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
415
drivers/net/ethernet/amd/ariadne.h
Normal file
415
drivers/net/ethernet/amd/ariadne.h
Normal file
|
@ -0,0 +1,415 @@
|
|||
/*
|
||||
* Amiga Linux/m68k Ariadne Ethernet Driver
|
||||
*
|
||||
* © Copyright 1995 by Geert Uytterhoeven (geert@linux-m68k.org)
|
||||
* Peter De Schrijver
|
||||
* (Peter.DeSchrijver@linux.cc.kuleuven.ac.be)
|
||||
*
|
||||
* ----------------------------------------------------------------------------------
|
||||
*
|
||||
* This program is based on
|
||||
*
|
||||
* lance.c: An AMD LANCE ethernet driver for linux.
|
||||
* Written 1993-94 by Donald Becker.
|
||||
*
|
||||
* Am79C960: PCnet(tm)-ISA Single-Chip Ethernet Controller
|
||||
* Advanced Micro Devices
|
||||
* Publication #16907, Rev. B, Amendment/0, May 1994
|
||||
*
|
||||
* MC68230: Parallel Interface/Timer (PI/T)
|
||||
* Motorola Semiconductors, December, 1983
|
||||
*
|
||||
* ----------------------------------------------------------------------------------
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of the Linux
|
||||
* distribution for more details.
|
||||
*
|
||||
* ----------------------------------------------------------------------------------
|
||||
*
|
||||
* The Ariadne is a Zorro-II board made by Village Tronic. It contains:
|
||||
*
|
||||
* - an Am79C960 PCnet-ISA Single-Chip Ethernet Controller with both
|
||||
* 10BASE-2 (thin coax) and 10BASE-T (UTP) connectors
|
||||
*
|
||||
* - an MC68230 Parallel Interface/Timer configured as 2 parallel ports
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Am79C960 PCnet-ISA
|
||||
*/
|
||||
|
||||
struct Am79C960 {
|
||||
volatile u_short AddressPROM[8];
|
||||
/* IEEE Address PROM (Unused in the Ariadne) */
|
||||
volatile u_short RDP; /* Register Data Port */
|
||||
volatile u_short RAP; /* Register Address Port */
|
||||
volatile u_short Reset; /* Reset Chip on Read Access */
|
||||
volatile u_short IDP; /* ISACSR Data Port */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Am79C960 Control and Status Registers
|
||||
*
|
||||
* These values are already swap()ed!!
|
||||
*
|
||||
* Only registers marked with a `-' are intended for network software
|
||||
* access
|
||||
*/
|
||||
|
||||
#define CSR0 0x0000 /* - PCnet-ISA Controller Status */
|
||||
#define CSR1 0x0100 /* - IADR[15:0] */
|
||||
#define CSR2 0x0200 /* - IADR[23:16] */
|
||||
#define CSR3 0x0300 /* - Interrupt Masks and Deferral Control */
|
||||
#define CSR4 0x0400 /* - Test and Features Control */
|
||||
#define CSR6 0x0600 /* RCV/XMT Descriptor Table Length */
|
||||
#define CSR8 0x0800 /* - Logical Address Filter, LADRF[15:0] */
|
||||
#define CSR9 0x0900 /* - Logical Address Filter, LADRF[31:16] */
|
||||
#define CSR10 0x0a00 /* - Logical Address Filter, LADRF[47:32] */
|
||||
#define CSR11 0x0b00 /* - Logical Address Filter, LADRF[63:48] */
|
||||
#define CSR12 0x0c00 /* - Physical Address Register, PADR[15:0] */
|
||||
#define CSR13 0x0d00 /* - Physical Address Register, PADR[31:16] */
|
||||
#define CSR14 0x0e00 /* - Physical Address Register, PADR[47:32] */
|
||||
#define CSR15 0x0f00 /* - Mode Register */
|
||||
#define CSR16 0x1000 /* Initialization Block Address Lower */
|
||||
#define CSR17 0x1100 /* Initialization Block Address Upper */
|
||||
#define CSR18 0x1200 /* Current Receive Buffer Address */
|
||||
#define CSR19 0x1300 /* Current Receive Buffer Address */
|
||||
#define CSR20 0x1400 /* Current Transmit Buffer Address */
|
||||
#define CSR21 0x1500 /* Current Transmit Buffer Address */
|
||||
#define CSR22 0x1600 /* Next Receive Buffer Address */
|
||||
#define CSR23 0x1700 /* Next Receive Buffer Address */
|
||||
#define CSR24 0x1800 /* - Base Address of Receive Ring */
|
||||
#define CSR25 0x1900 /* - Base Address of Receive Ring */
|
||||
#define CSR26 0x1a00 /* Next Receive Descriptor Address */
|
||||
#define CSR27 0x1b00 /* Next Receive Descriptor Address */
|
||||
#define CSR28 0x1c00 /* Current Receive Descriptor Address */
|
||||
#define CSR29 0x1d00 /* Current Receive Descriptor Address */
|
||||
#define CSR30 0x1e00 /* - Base Address of Transmit Ring */
|
||||
#define CSR31 0x1f00 /* - Base Address of transmit Ring */
|
||||
#define CSR32 0x2000 /* Next Transmit Descriptor Address */
|
||||
#define CSR33 0x2100 /* Next Transmit Descriptor Address */
|
||||
#define CSR34 0x2200 /* Current Transmit Descriptor Address */
|
||||
#define CSR35 0x2300 /* Current Transmit Descriptor Address */
|
||||
#define CSR36 0x2400 /* Next Next Receive Descriptor Address */
|
||||
#define CSR37 0x2500 /* Next Next Receive Descriptor Address */
|
||||
#define CSR38 0x2600 /* Next Next Transmit Descriptor Address */
|
||||
#define CSR39 0x2700 /* Next Next Transmit Descriptor Address */
|
||||
#define CSR40 0x2800 /* Current Receive Status and Byte Count */
|
||||
#define CSR41 0x2900 /* Current Receive Status and Byte Count */
|
||||
#define CSR42 0x2a00 /* Current Transmit Status and Byte Count */
|
||||
#define CSR43 0x2b00 /* Current Transmit Status and Byte Count */
|
||||
#define CSR44 0x2c00 /* Next Receive Status and Byte Count */
|
||||
#define CSR45 0x2d00 /* Next Receive Status and Byte Count */
|
||||
#define CSR46 0x2e00 /* Poll Time Counter */
|
||||
#define CSR47 0x2f00 /* Polling Interval */
|
||||
#define CSR48 0x3000 /* Temporary Storage */
|
||||
#define CSR49 0x3100 /* Temporary Storage */
|
||||
#define CSR50 0x3200 /* Temporary Storage */
|
||||
#define CSR51 0x3300 /* Temporary Storage */
|
||||
#define CSR52 0x3400 /* Temporary Storage */
|
||||
#define CSR53 0x3500 /* Temporary Storage */
|
||||
#define CSR54 0x3600 /* Temporary Storage */
|
||||
#define CSR55 0x3700 /* Temporary Storage */
|
||||
#define CSR56 0x3800 /* Temporary Storage */
|
||||
#define CSR57 0x3900 /* Temporary Storage */
|
||||
#define CSR58 0x3a00 /* Temporary Storage */
|
||||
#define CSR59 0x3b00 /* Temporary Storage */
|
||||
#define CSR60 0x3c00 /* Previous Transmit Descriptor Address */
|
||||
#define CSR61 0x3d00 /* Previous Transmit Descriptor Address */
|
||||
#define CSR62 0x3e00 /* Previous Transmit Status and Byte Count */
|
||||
#define CSR63 0x3f00 /* Previous Transmit Status and Byte Count */
|
||||
#define CSR64 0x4000 /* Next Transmit Buffer Address */
|
||||
#define CSR65 0x4100 /* Next Transmit Buffer Address */
|
||||
#define CSR66 0x4200 /* Next Transmit Status and Byte Count */
|
||||
#define CSR67 0x4300 /* Next Transmit Status and Byte Count */
|
||||
#define CSR68 0x4400 /* Transmit Status Temporary Storage */
|
||||
#define CSR69 0x4500 /* Transmit Status Temporary Storage */
|
||||
#define CSR70 0x4600 /* Temporary Storage */
|
||||
#define CSR71 0x4700 /* Temporary Storage */
|
||||
#define CSR72 0x4800 /* Receive Ring Counter */
|
||||
#define CSR74 0x4a00 /* Transmit Ring Counter */
|
||||
#define CSR76 0x4c00 /* - Receive Ring Length */
|
||||
#define CSR78 0x4e00 /* - Transmit Ring Length */
|
||||
#define CSR80 0x5000 /* - Burst and FIFO Threshold Control */
|
||||
#define CSR82 0x5200 /* - Bus Activity Timer */
|
||||
#define CSR84 0x5400 /* DMA Address */
|
||||
#define CSR85 0x5500 /* DMA Address */
|
||||
#define CSR86 0x5600 /* Buffer Byte Counter */
|
||||
#define CSR88 0x5800 /* - Chip ID */
|
||||
#define CSR89 0x5900 /* - Chip ID */
|
||||
#define CSR92 0x5c00 /* Ring Length Conversion */
|
||||
#define CSR94 0x5e00 /* Transmit Time Domain Reflectometry Count */
|
||||
#define CSR96 0x6000 /* Bus Interface Scratch Register 0 */
|
||||
#define CSR97 0x6100 /* Bus Interface Scratch Register 0 */
|
||||
#define CSR98 0x6200 /* Bus Interface Scratch Register 1 */
|
||||
#define CSR99 0x6300 /* Bus Interface Scratch Register 1 */
|
||||
#define CSR104 0x6800 /* SWAP */
|
||||
#define CSR105 0x6900 /* SWAP */
|
||||
#define CSR108 0x6c00 /* Buffer Management Scratch */
|
||||
#define CSR109 0x6d00 /* Buffer Management Scratch */
|
||||
#define CSR112 0x7000 /* - Missed Frame Count */
|
||||
#define CSR114 0x7200 /* - Receive Collision Count */
|
||||
#define CSR124 0x7c00 /* - Buffer Management Unit Test */
|
||||
|
||||
|
||||
/*
|
||||
* Am79C960 ISA Control and Status Registers
|
||||
*
|
||||
* These values are already swap()ed!!
|
||||
*/
|
||||
|
||||
#define ISACSR0 0x0000 /* Master Mode Read Active */
|
||||
#define ISACSR1 0x0100 /* Master Mode Write Active */
|
||||
#define ISACSR2 0x0200 /* Miscellaneous Configuration */
|
||||
#define ISACSR4 0x0400 /* LED0 Status (Link Integrity) */
|
||||
#define ISACSR5 0x0500 /* LED1 Status */
|
||||
#define ISACSR6 0x0600 /* LED2 Status */
|
||||
#define ISACSR7 0x0700 /* LED3 Status */
|
||||
|
||||
|
||||
/*
|
||||
* Bit definitions for CSR0 (PCnet-ISA Controller Status)
|
||||
*
|
||||
* These values are already swap()ed!!
|
||||
*/
|
||||
|
||||
#define ERR 0x0080 /* Error */
|
||||
#define BABL 0x0040 /* Babble: Transmitted too many bits */
|
||||
#define CERR 0x0020 /* No Heartbeat (10BASE-T) */
|
||||
#define MISS 0x0010 /* Missed Frame */
|
||||
#define MERR 0x0008 /* Memory Error */
|
||||
#define RINT 0x0004 /* Receive Interrupt */
|
||||
#define TINT 0x0002 /* Transmit Interrupt */
|
||||
#define IDON 0x0001 /* Initialization Done */
|
||||
#define INTR 0x8000 /* Interrupt Flag */
|
||||
#define INEA 0x4000 /* Interrupt Enable */
|
||||
#define RXON 0x2000 /* Receive On */
|
||||
#define TXON 0x1000 /* Transmit On */
|
||||
#define TDMD 0x0800 /* Transmit Demand */
|
||||
#define STOP 0x0400 /* Stop */
|
||||
#define STRT 0x0200 /* Start */
|
||||
#define INIT 0x0100 /* Initialize */
|
||||
|
||||
|
||||
/*
|
||||
* Bit definitions for CSR3 (Interrupt Masks and Deferral Control)
|
||||
*
|
||||
* These values are already swap()ed!!
|
||||
*/
|
||||
|
||||
#define BABLM 0x0040 /* Babble Mask */
|
||||
#define MISSM 0x0010 /* Missed Frame Mask */
|
||||
#define MERRM 0x0008 /* Memory Error Mask */
|
||||
#define RINTM 0x0004 /* Receive Interrupt Mask */
|
||||
#define TINTM 0x0002 /* Transmit Interrupt Mask */
|
||||
#define IDONM 0x0001 /* Initialization Done Mask */
|
||||
#define DXMT2PD 0x1000 /* Disable Transmit Two Part Deferral */
|
||||
#define EMBA 0x0800 /* Enable Modified Back-off Algorithm */
|
||||
|
||||
|
||||
/*
|
||||
* Bit definitions for CSR4 (Test and Features Control)
|
||||
*
|
||||
* These values are already swap()ed!!
|
||||
*/
|
||||
|
||||
#define ENTST 0x0080 /* Enable Test Mode */
|
||||
#define DMAPLUS 0x0040 /* Disable Burst Transaction Counter */
|
||||
#define TIMER 0x0020 /* Timer Enable Register */
|
||||
#define DPOLL 0x0010 /* Disable Transmit Polling */
|
||||
#define APAD_XMT 0x0008 /* Auto Pad Transmit */
|
||||
#define ASTRP_RCV 0x0004 /* Auto Pad Stripping */
|
||||
#define MFCO 0x0002 /* Missed Frame Counter Overflow Interrupt */
|
||||
#define MFCOM 0x0001 /* Missed Frame Counter Overflow Mask */
|
||||
#define RCVCCO 0x2000 /* Receive Collision Counter Overflow Interrupt */
|
||||
#define RCVCCOM 0x1000 /* Receive Collision Counter Overflow Mask */
|
||||
#define TXSTRT 0x0800 /* Transmit Start Status */
|
||||
#define TXSTRTM 0x0400 /* Transmit Start Mask */
|
||||
#define JAB 0x0200 /* Jabber Error */
|
||||
#define JABM 0x0100 /* Jabber Error Mask */
|
||||
|
||||
|
||||
/*
|
||||
* Bit definitions for CSR15 (Mode Register)
|
||||
*
|
||||
* These values are already swap()ed!!
|
||||
*/
|
||||
|
||||
#define PROM 0x0080 /* Promiscuous Mode */
|
||||
#define DRCVBC 0x0040 /* Disable Receive Broadcast */
|
||||
#define DRCVPA 0x0020 /* Disable Receive Physical Address */
|
||||
#define DLNKTST 0x0010 /* Disable Link Status */
|
||||
#define DAPC 0x0008 /* Disable Automatic Polarity Correction */
|
||||
#define MENDECL 0x0004 /* MENDEC Loopback Mode */
|
||||
#define LRTTSEL 0x0002 /* Low Receive Threshold/Transmit Mode Select */
|
||||
#define PORTSEL1 0x0001 /* Port Select Bits */
|
||||
#define PORTSEL2 0x8000 /* Port Select Bits */
|
||||
#define INTL 0x4000 /* Internal Loopback */
|
||||
#define DRTY 0x2000 /* Disable Retry */
|
||||
#define FCOLL 0x1000 /* Force Collision */
|
||||
#define DXMTFCS 0x0800 /* Disable Transmit CRC */
|
||||
#define LOOP 0x0400 /* Loopback Enable */
|
||||
#define DTX 0x0200 /* Disable Transmitter */
|
||||
#define DRX 0x0100 /* Disable Receiver */
|
||||
|
||||
|
||||
/*
|
||||
* Bit definitions for ISACSR2 (Miscellaneous Configuration)
|
||||
*
|
||||
* These values are already swap()ed!!
|
||||
*/
|
||||
|
||||
#define ASEL 0x0200 /* Media Interface Port Auto Select */
|
||||
|
||||
|
||||
/*
|
||||
* Bit definitions for ISACSR5-7 (LED1-3 Status)
|
||||
*
|
||||
* These values are already swap()ed!!
|
||||
*/
|
||||
|
||||
#define LEDOUT 0x0080 /* Current LED Status */
|
||||
#define PSE 0x8000 /* Pulse Stretcher Enable */
|
||||
#define XMTE 0x1000 /* Enable Transmit Status Signal */
|
||||
#define RVPOLE 0x0800 /* Enable Receive Polarity Signal */
|
||||
#define RCVE 0x0400 /* Enable Receive Status Signal */
|
||||
#define JABE 0x0200 /* Enable Jabber Signal */
|
||||
#define COLE 0x0100 /* Enable Collision Signal */
|
||||
|
||||
|
||||
/*
|
||||
* Receive Descriptor Ring Entry
|
||||
*/
|
||||
|
||||
struct RDRE {
|
||||
volatile u_short RMD0; /* LADR[15:0] */
|
||||
volatile u_short RMD1; /* HADR[23:16] | Receive Flags */
|
||||
volatile u_short RMD2; /* Buffer Byte Count (two's complement) */
|
||||
volatile u_short RMD3; /* Message Byte Count */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Transmit Descriptor Ring Entry
|
||||
*/
|
||||
|
||||
struct TDRE {
|
||||
volatile u_short TMD0; /* LADR[15:0] */
|
||||
volatile u_short TMD1; /* HADR[23:16] | Transmit Flags */
|
||||
volatile u_short TMD2; /* Buffer Byte Count (two's complement) */
|
||||
volatile u_short TMD3; /* Error Flags */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Receive Flags
|
||||
*/
|
||||
|
||||
#define RF_OWN 0x0080 /* PCnet-ISA controller owns the descriptor */
|
||||
#define RF_ERR 0x0040 /* Error */
|
||||
#define RF_FRAM 0x0020 /* Framing Error */
|
||||
#define RF_OFLO 0x0010 /* Overflow Error */
|
||||
#define RF_CRC 0x0008 /* CRC Error */
|
||||
#define RF_BUFF 0x0004 /* Buffer Error */
|
||||
#define RF_STP 0x0002 /* Start of Packet */
|
||||
#define RF_ENP 0x0001 /* End of Packet */
|
||||
|
||||
|
||||
/*
|
||||
* Transmit Flags
|
||||
*/
|
||||
|
||||
#define TF_OWN 0x0080 /* PCnet-ISA controller owns the descriptor */
|
||||
#define TF_ERR 0x0040 /* Error */
|
||||
#define TF_ADD_FCS 0x0020 /* Controls FCS Generation */
|
||||
#define TF_MORE 0x0010 /* More than one retry needed */
|
||||
#define TF_ONE 0x0008 /* One retry needed */
|
||||
#define TF_DEF 0x0004 /* Deferred */
|
||||
#define TF_STP 0x0002 /* Start of Packet */
|
||||
#define TF_ENP 0x0001 /* End of Packet */
|
||||
|
||||
|
||||
/*
|
||||
* Error Flags
|
||||
*/
|
||||
|
||||
#define EF_BUFF 0x0080 /* Buffer Error */
|
||||
#define EF_UFLO 0x0040 /* Underflow Error */
|
||||
#define EF_LCOL 0x0010 /* Late Collision */
|
||||
#define EF_LCAR 0x0008 /* Loss of Carrier */
|
||||
#define EF_RTRY 0x0004 /* Retry Error */
|
||||
#define EF_TDR 0xff03 /* Time Domain Reflectometry */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* MC68230 Parallel Interface/Timer
|
||||
*/
|
||||
|
||||
struct MC68230 {
|
||||
volatile u_char PGCR; /* Port General Control Register */
|
||||
u_char Pad1[1];
|
||||
volatile u_char PSRR; /* Port Service Request Register */
|
||||
u_char Pad2[1];
|
||||
volatile u_char PADDR; /* Port A Data Direction Register */
|
||||
u_char Pad3[1];
|
||||
volatile u_char PBDDR; /* Port B Data Direction Register */
|
||||
u_char Pad4[1];
|
||||
volatile u_char PCDDR; /* Port C Data Direction Register */
|
||||
u_char Pad5[1];
|
||||
volatile u_char PIVR; /* Port Interrupt Vector Register */
|
||||
u_char Pad6[1];
|
||||
volatile u_char PACR; /* Port A Control Register */
|
||||
u_char Pad7[1];
|
||||
volatile u_char PBCR; /* Port B Control Register */
|
||||
u_char Pad8[1];
|
||||
volatile u_char PADR; /* Port A Data Register */
|
||||
u_char Pad9[1];
|
||||
volatile u_char PBDR; /* Port B Data Register */
|
||||
u_char Pad10[1];
|
||||
volatile u_char PAAR; /* Port A Alternate Register */
|
||||
u_char Pad11[1];
|
||||
volatile u_char PBAR; /* Port B Alternate Register */
|
||||
u_char Pad12[1];
|
||||
volatile u_char PCDR; /* Port C Data Register */
|
||||
u_char Pad13[1];
|
||||
volatile u_char PSR; /* Port Status Register */
|
||||
u_char Pad14[5];
|
||||
volatile u_char TCR; /* Timer Control Register */
|
||||
u_char Pad15[1];
|
||||
volatile u_char TIVR; /* Timer Interrupt Vector Register */
|
||||
u_char Pad16[3];
|
||||
volatile u_char CPRH; /* Counter Preload Register (High) */
|
||||
u_char Pad17[1];
|
||||
volatile u_char CPRM; /* Counter Preload Register (Mid) */
|
||||
u_char Pad18[1];
|
||||
volatile u_char CPRL; /* Counter Preload Register (Low) */
|
||||
u_char Pad19[3];
|
||||
volatile u_char CNTRH; /* Count Register (High) */
|
||||
u_char Pad20[1];
|
||||
volatile u_char CNTRM; /* Count Register (Mid) */
|
||||
u_char Pad21[1];
|
||||
volatile u_char CNTRL; /* Count Register (Low) */
|
||||
u_char Pad22[1];
|
||||
volatile u_char TSR; /* Timer Status Register */
|
||||
u_char Pad23[11];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Ariadne Expansion Board Structure
|
||||
*/
|
||||
|
||||
#define ARIADNE_LANCE 0x360
|
||||
|
||||
#define ARIADNE_PIT 0x1000
|
||||
|
||||
#define ARIADNE_BOOTPROM 0x4000 /* I guess it's here :-) */
|
||||
#define ARIADNE_BOOTPROM_SIZE 0x4000
|
||||
|
||||
#define ARIADNE_RAM 0x8000 /* Always access WORDs!! */
|
||||
#define ARIADNE_RAM_SIZE 0x8000
|
||||
|
1169
drivers/net/ethernet/amd/atarilance.c
Normal file
1169
drivers/net/ethernet/amd/atarilance.c
Normal file
File diff suppressed because it is too large
Load diff
1470
drivers/net/ethernet/amd/au1000_eth.c
Normal file
1470
drivers/net/ethernet/amd/au1000_eth.c
Normal file
File diff suppressed because it is too large
Load diff
133
drivers/net/ethernet/amd/au1000_eth.h
Normal file
133
drivers/net/ethernet/amd/au1000_eth.h
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
*
|
||||
* Alchemy Au1x00 ethernet driver include file
|
||||
*
|
||||
* Author: Pete Popov <ppopov@mvista.com>
|
||||
*
|
||||
* Copyright 2001 MontaVista Software Inc.
|
||||
*
|
||||
* ########################################################################
|
||||
*
|
||||
* This program is free software; you can distribute it and/or modify it
|
||||
* under the terms of the GNU General Public License (Version 2) as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ########################################################################
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#define MAC_IOSIZE 0x10000
|
||||
#define NUM_RX_DMA 4 /* Au1x00 has 4 rx hardware descriptors */
|
||||
#define NUM_TX_DMA 4 /* Au1x00 has 4 tx hardware descriptors */
|
||||
|
||||
#define NUM_RX_BUFFS 4
|
||||
#define NUM_TX_BUFFS 4
|
||||
#define MAX_BUF_SIZE 2048
|
||||
|
||||
#define ETH_TX_TIMEOUT (HZ/4)
|
||||
#define MAC_MIN_PKT_SIZE 64
|
||||
|
||||
#define MULTICAST_FILTER_LIMIT 64
|
||||
|
||||
/*
|
||||
* Data Buffer Descriptor. Data buffers must be aligned on 32 byte
|
||||
* boundary for both, receive and transmit.
|
||||
*/
|
||||
struct db_dest {
|
||||
struct db_dest *pnext;
|
||||
u32 *vaddr;
|
||||
dma_addr_t dma_addr;
|
||||
};
|
||||
|
||||
/*
|
||||
* The transmit and receive descriptors are memory
|
||||
* mapped registers.
|
||||
*/
|
||||
struct tx_dma {
|
||||
u32 status;
|
||||
u32 buff_stat;
|
||||
u32 len;
|
||||
u32 pad;
|
||||
};
|
||||
|
||||
struct rx_dma {
|
||||
u32 status;
|
||||
u32 buff_stat;
|
||||
u32 pad[2];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* MAC control registers, memory mapped.
|
||||
*/
|
||||
struct mac_reg {
|
||||
u32 control;
|
||||
u32 mac_addr_high;
|
||||
u32 mac_addr_low;
|
||||
u32 multi_hash_high;
|
||||
u32 multi_hash_low;
|
||||
u32 mii_control;
|
||||
u32 mii_data;
|
||||
u32 flow_control;
|
||||
u32 vlan1_tag;
|
||||
u32 vlan2_tag;
|
||||
};
|
||||
|
||||
|
||||
struct au1000_private {
|
||||
struct db_dest *pDBfree;
|
||||
struct db_dest db[NUM_RX_BUFFS+NUM_TX_BUFFS];
|
||||
struct rx_dma *rx_dma_ring[NUM_RX_DMA];
|
||||
struct tx_dma *tx_dma_ring[NUM_TX_DMA];
|
||||
struct db_dest *rx_db_inuse[NUM_RX_DMA];
|
||||
struct db_dest *tx_db_inuse[NUM_TX_DMA];
|
||||
u32 rx_head;
|
||||
u32 tx_head;
|
||||
u32 tx_tail;
|
||||
u32 tx_full;
|
||||
|
||||
int mac_id;
|
||||
|
||||
int mac_enabled; /* whether MAC is currently enabled and running
|
||||
* (req. for mdio)
|
||||
*/
|
||||
|
||||
int old_link; /* used by au1000_adjust_link */
|
||||
int old_speed;
|
||||
int old_duplex;
|
||||
|
||||
struct phy_device *phy_dev;
|
||||
struct mii_bus *mii_bus;
|
||||
|
||||
/* PHY configuration */
|
||||
int phy_static_config;
|
||||
int phy_search_highest_addr;
|
||||
int phy1_search_mac0;
|
||||
|
||||
int phy_addr;
|
||||
int phy_busid;
|
||||
int phy_irq;
|
||||
|
||||
/* These variables are just for quick access
|
||||
* to certain regs addresses.
|
||||
*/
|
||||
struct mac_reg *mac; /* mac registers */
|
||||
u32 *enable; /* address of MAC Enable Register */
|
||||
void __iomem *macdma; /* base of MAC DMA port */
|
||||
u32 vaddr; /* virtual address of rx/tx buffers */
|
||||
dma_addr_t dma_addr; /* dma address of rx/tx buffers */
|
||||
|
||||
spinlock_t lock; /* Serialise access to device */
|
||||
|
||||
u32 msg_enable;
|
||||
};
|
1376
drivers/net/ethernet/amd/declance.c
Normal file
1376
drivers/net/ethernet/amd/declance.c
Normal file
File diff suppressed because it is too large
Load diff
232
drivers/net/ethernet/amd/hplance.c
Normal file
232
drivers/net/ethernet/amd/hplance.c
Normal file
|
@ -0,0 +1,232 @@
|
|||
/* hplance.c : the Linux/hp300/lance ethernet driver
|
||||
*
|
||||
* Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
|
||||
* Based on the Sun Lance driver and the NetBSD HP Lance driver
|
||||
* Uses the generic 7990.c LANCE code.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
/* Used for the temporal inet entries and routing */
|
||||
#include <linux/socket.h>
|
||||
#include <linux/route.h>
|
||||
#include <linux/dio.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
#include "hplance.h"
|
||||
|
||||
/* We have 16392 bytes of RAM for the init block and buffers. This places
|
||||
* an upper limit on the number of buffers we can use. NetBSD uses 8 Rx
|
||||
* buffers and 2 Tx buffers, it takes (8 + 2) * 1544 bytes.
|
||||
*/
|
||||
#define LANCE_LOG_TX_BUFFERS 1
|
||||
#define LANCE_LOG_RX_BUFFERS 3
|
||||
|
||||
#include "7990.h" /* use generic LANCE code */
|
||||
|
||||
/* Our private data structure */
|
||||
struct hplance_private {
|
||||
struct lance_private lance;
|
||||
};
|
||||
|
||||
/* function prototypes... This is easy because all the grot is in the
|
||||
* generic LANCE support. All we have to support is probing for boards,
|
||||
* plus board-specific init, open and close actions.
|
||||
* Oh, and we need to tell the generic code how to read and write LANCE registers...
|
||||
*/
|
||||
static int hplance_init_one(struct dio_dev *d, const struct dio_device_id *ent);
|
||||
static void hplance_init(struct net_device *dev, struct dio_dev *d);
|
||||
static void hplance_remove_one(struct dio_dev *d);
|
||||
static void hplance_writerap(void *priv, unsigned short value);
|
||||
static void hplance_writerdp(void *priv, unsigned short value);
|
||||
static unsigned short hplance_readrdp(void *priv);
|
||||
static int hplance_open(struct net_device *dev);
|
||||
static int hplance_close(struct net_device *dev);
|
||||
|
||||
static struct dio_device_id hplance_dio_tbl[] = {
|
||||
{ DIO_ID_LAN },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static struct dio_driver hplance_driver = {
|
||||
.name = "hplance",
|
||||
.id_table = hplance_dio_tbl,
|
||||
.probe = hplance_init_one,
|
||||
.remove = hplance_remove_one,
|
||||
};
|
||||
|
||||
static const struct net_device_ops hplance_netdev_ops = {
|
||||
.ndo_open = hplance_open,
|
||||
.ndo_stop = hplance_close,
|
||||
.ndo_start_xmit = lance_start_xmit,
|
||||
.ndo_set_rx_mode = lance_set_multicast,
|
||||
.ndo_change_mtu = eth_change_mtu,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_set_mac_address = eth_mac_addr,
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = lance_poll,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Find all the HP Lance boards and initialise them... */
|
||||
static int hplance_init_one(struct dio_dev *d, const struct dio_device_id *ent)
|
||||
{
|
||||
struct net_device *dev;
|
||||
int err = -ENOMEM;
|
||||
|
||||
dev = alloc_etherdev(sizeof(struct hplance_private));
|
||||
if (!dev)
|
||||
goto out;
|
||||
|
||||
err = -EBUSY;
|
||||
if (!request_mem_region(dio_resource_start(d),
|
||||
dio_resource_len(d), d->name))
|
||||
goto out_free_netdev;
|
||||
|
||||
hplance_init(dev, d);
|
||||
err = register_netdev(dev);
|
||||
if (err)
|
||||
goto out_release_mem_region;
|
||||
|
||||
dio_set_drvdata(d, dev);
|
||||
|
||||
printk(KERN_INFO "%s: %s; select code %d, addr %pM, irq %d\n",
|
||||
dev->name, d->name, d->scode, dev->dev_addr, d->ipl);
|
||||
|
||||
return 0;
|
||||
|
||||
out_release_mem_region:
|
||||
release_mem_region(dio_resource_start(d), dio_resource_len(d));
|
||||
out_free_netdev:
|
||||
free_netdev(dev);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void hplance_remove_one(struct dio_dev *d)
|
||||
{
|
||||
struct net_device *dev = dio_get_drvdata(d);
|
||||
|
||||
unregister_netdev(dev);
|
||||
release_mem_region(dio_resource_start(d), dio_resource_len(d));
|
||||
free_netdev(dev);
|
||||
}
|
||||
|
||||
/* Initialise a single lance board at the given DIO device */
|
||||
static void hplance_init(struct net_device *dev, struct dio_dev *d)
|
||||
{
|
||||
unsigned long va = (d->resource.start + DIO_VIRADDRBASE);
|
||||
struct hplance_private *lp;
|
||||
int i;
|
||||
|
||||
/* reset the board */
|
||||
out_8(va + DIO_IDOFF, 0xff);
|
||||
udelay(100); /* ariba! ariba! udelay! udelay! */
|
||||
|
||||
/* Fill the dev fields */
|
||||
dev->base_addr = va;
|
||||
dev->netdev_ops = &hplance_netdev_ops;
|
||||
dev->dma = 0;
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
/* The NVRAM holds our ethernet address, one nibble per byte,
|
||||
* at bytes NVRAMOFF+1,3,5,7,9...
|
||||
*/
|
||||
dev->dev_addr[i] = ((in_8(va + HPLANCE_NVRAMOFF + i*4 + 1) & 0xF) << 4)
|
||||
| (in_8(va + HPLANCE_NVRAMOFF + i*4 + 3) & 0xF);
|
||||
}
|
||||
|
||||
lp = netdev_priv(dev);
|
||||
lp->lance.name = d->name;
|
||||
lp->lance.base = va;
|
||||
lp->lance.init_block = (struct lance_init_block *)(va + HPLANCE_MEMOFF); /* CPU addr */
|
||||
lp->lance.lance_init_block = NULL; /* LANCE addr of same RAM */
|
||||
lp->lance.busmaster_regval = LE_C3_BSWP; /* we're bigendian */
|
||||
lp->lance.irq = d->ipl;
|
||||
lp->lance.writerap = hplance_writerap;
|
||||
lp->lance.writerdp = hplance_writerdp;
|
||||
lp->lance.readrdp = hplance_readrdp;
|
||||
lp->lance.lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS;
|
||||
lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
|
||||
lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
|
||||
lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
|
||||
}
|
||||
|
||||
/* This is disgusting. We have to check the DIO status register for ack every
|
||||
* time we read or write the LANCE registers.
|
||||
*/
|
||||
static void hplance_writerap(void *priv, unsigned short value)
|
||||
{
|
||||
struct lance_private *lp = (struct lance_private *)priv;
|
||||
do {
|
||||
out_be16(lp->base + HPLANCE_REGOFF + LANCE_RAP, value);
|
||||
} while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
|
||||
}
|
||||
|
||||
static void hplance_writerdp(void *priv, unsigned short value)
|
||||
{
|
||||
struct lance_private *lp = (struct lance_private *)priv;
|
||||
do {
|
||||
out_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP, value);
|
||||
} while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
|
||||
}
|
||||
|
||||
static unsigned short hplance_readrdp(void *priv)
|
||||
{
|
||||
struct lance_private *lp = (struct lance_private *)priv;
|
||||
__u16 value;
|
||||
do {
|
||||
value = in_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP);
|
||||
} while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
|
||||
return value;
|
||||
}
|
||||
|
||||
static int hplance_open(struct net_device *dev)
|
||||
{
|
||||
int status;
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
|
||||
status = lance_open(dev); /* call generic lance open code */
|
||||
if (status)
|
||||
return status;
|
||||
/* enable interrupts at board level. */
|
||||
out_8(lp->base + HPLANCE_STATUS, LE_IE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hplance_close(struct net_device *dev)
|
||||
{
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
|
||||
out_8(lp->base + HPLANCE_STATUS, 0); /* disable interrupts at boardlevel */
|
||||
lance_close(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init hplance_init_module(void)
|
||||
{
|
||||
return dio_register_driver(&hplance_driver);
|
||||
}
|
||||
|
||||
static void __exit hplance_cleanup_module(void)
|
||||
{
|
||||
dio_unregister_driver(&hplance_driver);
|
||||
}
|
||||
|
||||
module_init(hplance_init_module);
|
||||
module_exit(hplance_cleanup_module);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
26
drivers/net/ethernet/amd/hplance.h
Normal file
26
drivers/net/ethernet/amd/hplance.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* Random defines and structures for the HP Lance driver.
|
||||
* Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
|
||||
* Based on the Sun Lance driver and the NetBSD HP Lance driver
|
||||
*/
|
||||
|
||||
/* Registers */
|
||||
#define HPLANCE_ID 0x01 /* DIO register: ID byte */
|
||||
#define HPLANCE_STATUS 0x03 /* DIO register: interrupt enable/status */
|
||||
|
||||
/* Control and status bits for the status register */
|
||||
#define LE_IE 0x80 /* interrupt enable */
|
||||
#define LE_IR 0x40 /* interrupt requested */
|
||||
#define LE_LOCK 0x08 /* lock status register */
|
||||
#define LE_ACK 0x04 /* ack of lock */
|
||||
#define LE_JAB 0x02 /* loss of tx clock (???) */
|
||||
/* We can also extract the IPL from the status register with the standard
|
||||
* DIO_IPL(hplance) macro, or using dio_scodetoipl()
|
||||
*/
|
||||
|
||||
/* These are the offsets for the DIO regs (hplance_reg), lance_ioreg,
|
||||
* memory and NVRAM:
|
||||
*/
|
||||
#define HPLANCE_IDOFF 0 /* board baseaddr */
|
||||
#define HPLANCE_REGOFF 0x4000 /* lance registers */
|
||||
#define HPLANCE_MEMOFF 0x8000 /* struct lance_init_block */
|
||||
#define HPLANCE_NVRAMOFF 0xC008 /* etheraddress as one *nibble* per byte */
|
1312
drivers/net/ethernet/amd/lance.c
Normal file
1312
drivers/net/ethernet/amd/lance.c
Normal file
File diff suppressed because it is too large
Load diff
200
drivers/net/ethernet/amd/mvme147.c
Normal file
200
drivers/net/ethernet/amd/mvme147.c
Normal file
|
@ -0,0 +1,200 @@
|
|||
/* mvme147.c : the Linux/mvme147/lance ethernet driver
|
||||
*
|
||||
* Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
|
||||
* Based on the Sun Lance driver and the NetBSD HP Lance driver
|
||||
* Uses the generic 7990.c LANCE code.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gfp.h>
|
||||
/* Used for the temporal inet entries and routing */
|
||||
#include <linux/socket.h>
|
||||
#include <linux/route.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/mvme147hw.h>
|
||||
|
||||
/* We have 32K of RAM for the init block and buffers. This places
|
||||
* an upper limit on the number of buffers we can use. NetBSD uses 8 Rx
|
||||
* buffers and 2 Tx buffers, it takes (8 + 2) * 1544 bytes.
|
||||
*/
|
||||
#define LANCE_LOG_TX_BUFFERS 1
|
||||
#define LANCE_LOG_RX_BUFFERS 3
|
||||
|
||||
#include "7990.h" /* use generic LANCE code */
|
||||
|
||||
/* Our private data structure */
|
||||
struct m147lance_private {
|
||||
struct lance_private lance;
|
||||
unsigned long ram;
|
||||
};
|
||||
|
||||
/* function prototypes... This is easy because all the grot is in the
|
||||
* generic LANCE support. All we have to support is probing for boards,
|
||||
* plus board-specific init, open and close actions.
|
||||
* Oh, and we need to tell the generic code how to read and write LANCE registers...
|
||||
*/
|
||||
static int m147lance_open(struct net_device *dev);
|
||||
static int m147lance_close(struct net_device *dev);
|
||||
static void m147lance_writerap(struct lance_private *lp, unsigned short value);
|
||||
static void m147lance_writerdp(struct lance_private *lp, unsigned short value);
|
||||
static unsigned short m147lance_readrdp(struct lance_private *lp);
|
||||
|
||||
typedef void (*writerap_t)(void *, unsigned short);
|
||||
typedef void (*writerdp_t)(void *, unsigned short);
|
||||
typedef unsigned short (*readrdp_t)(void *);
|
||||
|
||||
static const struct net_device_ops lance_netdev_ops = {
|
||||
.ndo_open = m147lance_open,
|
||||
.ndo_stop = m147lance_close,
|
||||
.ndo_start_xmit = lance_start_xmit,
|
||||
.ndo_set_rx_mode = lance_set_multicast,
|
||||
.ndo_tx_timeout = lance_tx_timeout,
|
||||
.ndo_change_mtu = eth_change_mtu,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_set_mac_address = eth_mac_addr,
|
||||
};
|
||||
|
||||
/* Initialise the one and only on-board 7990 */
|
||||
struct net_device * __init mvme147lance_probe(int unit)
|
||||
{
|
||||
struct net_device *dev;
|
||||
static int called;
|
||||
static const char name[] = "MVME147 LANCE";
|
||||
struct m147lance_private *lp;
|
||||
u_long *addr;
|
||||
u_long address;
|
||||
int err;
|
||||
|
||||
if (!MACH_IS_MVME147 || called)
|
||||
return ERR_PTR(-ENODEV);
|
||||
called++;
|
||||
|
||||
dev = alloc_etherdev(sizeof(struct m147lance_private));
|
||||
if (!dev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (unit >= 0)
|
||||
sprintf(dev->name, "eth%d", unit);
|
||||
|
||||
/* Fill the dev fields */
|
||||
dev->base_addr = (unsigned long)MVME147_LANCE_BASE;
|
||||
dev->netdev_ops = &lance_netdev_ops;
|
||||
dev->dma = 0;
|
||||
|
||||
addr = (u_long *)ETHERNET_ADDRESS;
|
||||
address = *addr;
|
||||
dev->dev_addr[0] = 0x08;
|
||||
dev->dev_addr[1] = 0x00;
|
||||
dev->dev_addr[2] = 0x3e;
|
||||
address = address >> 8;
|
||||
dev->dev_addr[5] = address&0xff;
|
||||
address = address >> 8;
|
||||
dev->dev_addr[4] = address&0xff;
|
||||
address = address >> 8;
|
||||
dev->dev_addr[3] = address&0xff;
|
||||
|
||||
printk("%s: MVME147 at 0x%08lx, irq %d, Hardware Address %pM\n",
|
||||
dev->name, dev->base_addr, MVME147_LANCE_IRQ,
|
||||
dev->dev_addr);
|
||||
|
||||
lp = netdev_priv(dev);
|
||||
lp->ram = __get_dma_pages(GFP_ATOMIC, 3); /* 32K */
|
||||
if (!lp->ram) {
|
||||
printk("%s: No memory for LANCE buffers\n", dev->name);
|
||||
free_netdev(dev);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
lp->lance.name = name;
|
||||
lp->lance.base = dev->base_addr;
|
||||
lp->lance.init_block = (struct lance_init_block *)(lp->ram); /* CPU addr */
|
||||
lp->lance.lance_init_block = (struct lance_init_block *)(lp->ram); /* LANCE addr of same RAM */
|
||||
lp->lance.busmaster_regval = LE_C3_BSWP; /* we're bigendian */
|
||||
lp->lance.irq = MVME147_LANCE_IRQ;
|
||||
lp->lance.writerap = (writerap_t)m147lance_writerap;
|
||||
lp->lance.writerdp = (writerdp_t)m147lance_writerdp;
|
||||
lp->lance.readrdp = (readrdp_t)m147lance_readrdp;
|
||||
lp->lance.lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS;
|
||||
lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
|
||||
lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
|
||||
lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
|
||||
|
||||
err = register_netdev(dev);
|
||||
if (err) {
|
||||
free_pages(lp->ram, 3);
|
||||
free_netdev(dev);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void m147lance_writerap(struct lance_private *lp, unsigned short value)
|
||||
{
|
||||
out_be16(lp->base + LANCE_RAP, value);
|
||||
}
|
||||
|
||||
static void m147lance_writerdp(struct lance_private *lp, unsigned short value)
|
||||
{
|
||||
out_be16(lp->base + LANCE_RDP, value);
|
||||
}
|
||||
|
||||
static unsigned short m147lance_readrdp(struct lance_private *lp)
|
||||
{
|
||||
return in_be16(lp->base + LANCE_RDP);
|
||||
}
|
||||
|
||||
static int m147lance_open(struct net_device *dev)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = lance_open(dev); /* call generic lance open code */
|
||||
if (status)
|
||||
return status;
|
||||
/* enable interrupts at board level. */
|
||||
m147_pcc->lan_cntrl = 0; /* clear the interrupts (if any) */
|
||||
m147_pcc->lan_cntrl = 0x08 | 0x04; /* Enable irq 4 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int m147lance_close(struct net_device *dev)
|
||||
{
|
||||
/* disable interrupts at boardlevel */
|
||||
m147_pcc->lan_cntrl = 0x0; /* disable interrupts */
|
||||
lance_close(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MODULE
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static struct net_device *dev_mvme147_lance;
|
||||
int __init init_module(void)
|
||||
{
|
||||
dev_mvme147_lance = mvme147lance_probe(-1);
|
||||
return PTR_ERR_OR_ZERO(dev_mvme147_lance);
|
||||
}
|
||||
|
||||
void __exit cleanup_module(void)
|
||||
{
|
||||
struct m147lance_private *lp = netdev_priv(dev_mvme147_lance);
|
||||
unregister_netdev(dev_mvme147_lance);
|
||||
free_pages(lp->ram, 3);
|
||||
free_netdev(dev_mvme147_lance);
|
||||
}
|
||||
|
||||
#endif /* MODULE */
|
1252
drivers/net/ethernet/amd/ni65.c
Normal file
1252
drivers/net/ethernet/amd/ni65.c
Normal file
File diff suppressed because it is too large
Load diff
121
drivers/net/ethernet/amd/ni65.h
Normal file
121
drivers/net/ethernet/amd/ni65.h
Normal file
|
@ -0,0 +1,121 @@
|
|||
/* am7990 (lance) definitions
|
||||
*
|
||||
* This is an extension to the Linux operating system, and is covered by
|
||||
* same GNU General Public License that covers that work.
|
||||
*
|
||||
* Michael Hipp
|
||||
* email: mhipp@student.uni-tuebingen.de
|
||||
*
|
||||
* sources: (mail me or ask archie if you need them)
|
||||
* crynwr-packet-driver
|
||||
*/
|
||||
|
||||
/*
|
||||
* Control and Status Register 0 (CSR0) bit definitions
|
||||
* (R=Readable) (W=Writeable) (S=Set on write) (C-Clear on write)
|
||||
*
|
||||
*/
|
||||
|
||||
#define CSR0_ERR 0x8000 /* Error summary (R) */
|
||||
#define CSR0_BABL 0x4000 /* Babble transmitter timeout error (RC) */
|
||||
#define CSR0_CERR 0x2000 /* Collision Error (RC) */
|
||||
#define CSR0_MISS 0x1000 /* Missed packet (RC) */
|
||||
#define CSR0_MERR 0x0800 /* Memory Error (RC) */
|
||||
#define CSR0_RINT 0x0400 /* Receiver Interrupt (RC) */
|
||||
#define CSR0_TINT 0x0200 /* Transmit Interrupt (RC) */
|
||||
#define CSR0_IDON 0x0100 /* Initialization Done (RC) */
|
||||
#define CSR0_INTR 0x0080 /* Interrupt Flag (R) */
|
||||
#define CSR0_INEA 0x0040 /* Interrupt Enable (RW) */
|
||||
#define CSR0_RXON 0x0020 /* Receiver on (R) */
|
||||
#define CSR0_TXON 0x0010 /* Transmitter on (R) */
|
||||
#define CSR0_TDMD 0x0008 /* Transmit Demand (RS) */
|
||||
#define CSR0_STOP 0x0004 /* Stop (RS) */
|
||||
#define CSR0_STRT 0x0002 /* Start (RS) */
|
||||
#define CSR0_INIT 0x0001 /* Initialize (RS) */
|
||||
|
||||
#define CSR0_CLRALL 0x7f00 /* mask for all clearable bits */
|
||||
/*
|
||||
* Initialization Block Mode operation Bit Definitions.
|
||||
*/
|
||||
|
||||
#define M_PROM 0x8000 /* Promiscuous Mode */
|
||||
#define M_INTL 0x0040 /* Internal Loopback */
|
||||
#define M_DRTY 0x0020 /* Disable Retry */
|
||||
#define M_COLL 0x0010 /* Force Collision */
|
||||
#define M_DTCR 0x0008 /* Disable Transmit CRC) */
|
||||
#define M_LOOP 0x0004 /* Loopback */
|
||||
#define M_DTX 0x0002 /* Disable the Transmitter */
|
||||
#define M_DRX 0x0001 /* Disable the Receiver */
|
||||
|
||||
|
||||
/*
|
||||
* Receive message descriptor bit definitions.
|
||||
*/
|
||||
|
||||
#define RCV_OWN 0x80 /* owner bit 0 = host, 1 = lance */
|
||||
#define RCV_ERR 0x40 /* Error Summary */
|
||||
#define RCV_FRAM 0x20 /* Framing Error */
|
||||
#define RCV_OFLO 0x10 /* Overflow Error */
|
||||
#define RCV_CRC 0x08 /* CRC Error */
|
||||
#define RCV_BUF_ERR 0x04 /* Buffer Error */
|
||||
#define RCV_START 0x02 /* Start of Packet */
|
||||
#define RCV_END 0x01 /* End of Packet */
|
||||
|
||||
|
||||
/*
|
||||
* Transmit message descriptor bit definitions.
|
||||
*/
|
||||
|
||||
#define XMIT_OWN 0x80 /* owner bit 0 = host, 1 = lance */
|
||||
#define XMIT_ERR 0x40 /* Error Summary */
|
||||
#define XMIT_RETRY 0x10 /* more the 1 retry needed to Xmit */
|
||||
#define XMIT_1_RETRY 0x08 /* one retry needed to Xmit */
|
||||
#define XMIT_DEF 0x04 /* Deferred */
|
||||
#define XMIT_START 0x02 /* Start of Packet */
|
||||
#define XMIT_END 0x01 /* End of Packet */
|
||||
|
||||
/*
|
||||
* transmit status (2) (valid if XMIT_ERR == 1)
|
||||
*/
|
||||
|
||||
#define XMIT_TDRMASK 0x03ff /* time-domain-reflectometer-value */
|
||||
#define XMIT_RTRY 0x0400 /* Failed after 16 retransmissions */
|
||||
#define XMIT_LCAR 0x0800 /* Loss of Carrier */
|
||||
#define XMIT_LCOL 0x1000 /* Late collision */
|
||||
#define XMIT_RESERV 0x2000 /* Reserved */
|
||||
#define XMIT_UFLO 0x4000 /* Underflow (late memory) */
|
||||
#define XMIT_BUFF 0x8000 /* Buffering error (no ENP) */
|
||||
|
||||
struct init_block {
|
||||
unsigned short mode;
|
||||
unsigned char eaddr[6];
|
||||
unsigned char filter[8];
|
||||
/* bit 29-31: number of rmd's (power of 2) */
|
||||
u32 rrp; /* receive ring pointer (align 8) */
|
||||
/* bit 29-31: number of tmd's (power of 2) */
|
||||
u32 trp; /* transmit ring pointer (align 8) */
|
||||
};
|
||||
|
||||
struct rmd { /* Receive Message Descriptor */
|
||||
union {
|
||||
volatile u32 buffer;
|
||||
struct {
|
||||
volatile unsigned char dummy[3];
|
||||
volatile unsigned char status;
|
||||
} s;
|
||||
} u;
|
||||
volatile short blen;
|
||||
volatile unsigned short mlen;
|
||||
};
|
||||
|
||||
struct tmd {
|
||||
union {
|
||||
volatile u32 buffer;
|
||||
struct {
|
||||
volatile unsigned char dummy[3];
|
||||
volatile unsigned char status;
|
||||
} s;
|
||||
} u;
|
||||
volatile unsigned short blen;
|
||||
volatile unsigned short status2;
|
||||
};
|
1510
drivers/net/ethernet/amd/nmclan_cs.c
Normal file
1510
drivers/net/ethernet/amd/nmclan_cs.c
Normal file
File diff suppressed because it is too large
Load diff
2989
drivers/net/ethernet/amd/pcnet32.c
Normal file
2989
drivers/net/ethernet/amd/pcnet32.c
Normal file
File diff suppressed because it is too large
Load diff
956
drivers/net/ethernet/amd/sun3lance.c
Normal file
956
drivers/net/ethernet/amd/sun3lance.c
Normal file
|
@ -0,0 +1,956 @@
|
|||
/* 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 int 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 int 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 */
|
||||
|
1534
drivers/net/ethernet/amd/sunlance.c
Normal file
1534
drivers/net/ethernet/amd/sunlance.c
Normal file
File diff suppressed because it is too large
Load diff
8
drivers/net/ethernet/amd/xgbe/Makefile
Normal file
8
drivers/net/ethernet/amd/xgbe/Makefile
Normal file
|
@ -0,0 +1,8 @@
|
|||
obj-$(CONFIG_AMD_XGBE) += amd-xgbe.o
|
||||
|
||||
amd-xgbe-objs := xgbe-main.o xgbe-drv.o xgbe-dev.o \
|
||||
xgbe-desc.o xgbe-ethtool.o xgbe-mdio.o \
|
||||
xgbe-ptp.o
|
||||
|
||||
amd-xgbe-$(CONFIG_AMD_XGBE_DCB) += xgbe-dcb.o
|
||||
amd-xgbe-$(CONFIG_DEBUG_FS) += xgbe-debugfs.o
|
1093
drivers/net/ethernet/amd/xgbe/xgbe-common.h
Normal file
1093
drivers/net/ethernet/amd/xgbe/xgbe-common.h
Normal file
File diff suppressed because it is too large
Load diff
269
drivers/net/ethernet/amd/xgbe/xgbe-dcb.c
Normal file
269
drivers/net/ethernet/amd/xgbe/xgbe-dcb.c
Normal file
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
* AMD 10Gb Ethernet driver
|
||||
*
|
||||
* This file is available to you under your choice of the following two
|
||||
* licenses:
|
||||
*
|
||||
* License 1: GPLv2
|
||||
*
|
||||
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This file is free software; you may copy, redistribute and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* The Synopsys DWC ETHER XGMAC Software Driver and documentation
|
||||
* (hereinafter "Software") is an unsupported proprietary work of Synopsys,
|
||||
* Inc. unless otherwise expressly agreed to in writing between Synopsys
|
||||
* and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for Licensed
|
||||
* Product with Synopsys or any supplement thereto. Permission is hereby
|
||||
* granted, free of charge, to any person obtaining a copy of this software
|
||||
* annotated with this license and the Software, to deal in the Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* License 2: Modified BSD
|
||||
*
|
||||
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Advanced Micro Devices, Inc. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* The Synopsys DWC ETHER XGMAC Software Driver and documentation
|
||||
* (hereinafter "Software") is an unsupported proprietary work of Synopsys,
|
||||
* Inc. unless otherwise expressly agreed to in writing between Synopsys
|
||||
* and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for Licensed
|
||||
* Product with Synopsys or any supplement thereto. Permission is hereby
|
||||
* granted, free of charge, to any person obtaining a copy of this software
|
||||
* annotated with this license and the Software, to deal in the Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/dcbnl.h>
|
||||
|
||||
#include "xgbe.h"
|
||||
#include "xgbe-common.h"
|
||||
|
||||
static int xgbe_dcb_ieee_getets(struct net_device *netdev,
|
||||
struct ieee_ets *ets)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
|
||||
/* Set number of supported traffic classes */
|
||||
ets->ets_cap = pdata->hw_feat.tc_cnt;
|
||||
|
||||
if (pdata->ets) {
|
||||
ets->cbs = pdata->ets->cbs;
|
||||
memcpy(ets->tc_tx_bw, pdata->ets->tc_tx_bw,
|
||||
sizeof(ets->tc_tx_bw));
|
||||
memcpy(ets->tc_tsa, pdata->ets->tc_tsa,
|
||||
sizeof(ets->tc_tsa));
|
||||
memcpy(ets->prio_tc, pdata->ets->prio_tc,
|
||||
sizeof(ets->prio_tc));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xgbe_dcb_ieee_setets(struct net_device *netdev,
|
||||
struct ieee_ets *ets)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
unsigned int i, tc_ets, tc_ets_weight;
|
||||
|
||||
tc_ets = 0;
|
||||
tc_ets_weight = 0;
|
||||
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
|
||||
DBGPR(" TC%u: tx_bw=%hhu, rx_bw=%hhu, tsa=%hhu\n", i,
|
||||
ets->tc_tx_bw[i], ets->tc_rx_bw[i], ets->tc_tsa[i]);
|
||||
DBGPR(" PRIO%u: TC=%hhu\n", i, ets->prio_tc[i]);
|
||||
|
||||
if ((ets->tc_tx_bw[i] || ets->tc_tsa[i]) &&
|
||||
(i >= pdata->hw_feat.tc_cnt))
|
||||
return -EINVAL;
|
||||
|
||||
if (ets->prio_tc[i] >= pdata->hw_feat.tc_cnt)
|
||||
return -EINVAL;
|
||||
|
||||
switch (ets->tc_tsa[i]) {
|
||||
case IEEE_8021QAZ_TSA_STRICT:
|
||||
break;
|
||||
case IEEE_8021QAZ_TSA_ETS:
|
||||
tc_ets = 1;
|
||||
tc_ets_weight += ets->tc_tx_bw[i];
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Weights must add up to 100% */
|
||||
if (tc_ets && (tc_ets_weight != 100))
|
||||
return -EINVAL;
|
||||
|
||||
if (!pdata->ets) {
|
||||
pdata->ets = devm_kzalloc(pdata->dev, sizeof(*pdata->ets),
|
||||
GFP_KERNEL);
|
||||
if (!pdata->ets)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(pdata->ets, ets, sizeof(*pdata->ets));
|
||||
|
||||
pdata->hw_if.config_dcb_tc(pdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xgbe_dcb_ieee_getpfc(struct net_device *netdev,
|
||||
struct ieee_pfc *pfc)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
|
||||
/* Set number of supported PFC traffic classes */
|
||||
pfc->pfc_cap = pdata->hw_feat.tc_cnt;
|
||||
|
||||
if (pdata->pfc) {
|
||||
pfc->pfc_en = pdata->pfc->pfc_en;
|
||||
pfc->mbc = pdata->pfc->mbc;
|
||||
pfc->delay = pdata->pfc->delay;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xgbe_dcb_ieee_setpfc(struct net_device *netdev,
|
||||
struct ieee_pfc *pfc)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
|
||||
DBGPR(" cap=%hhu, en=%hhx, mbc=%hhu, delay=%hhu\n",
|
||||
pfc->pfc_cap, pfc->pfc_en, pfc->mbc, pfc->delay);
|
||||
|
||||
if (!pdata->pfc) {
|
||||
pdata->pfc = devm_kzalloc(pdata->dev, sizeof(*pdata->pfc),
|
||||
GFP_KERNEL);
|
||||
if (!pdata->pfc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(pdata->pfc, pfc, sizeof(*pdata->pfc));
|
||||
|
||||
pdata->hw_if.config_dcb_pfc(pdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 xgbe_dcb_getdcbx(struct net_device *netdev)
|
||||
{
|
||||
return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE;
|
||||
}
|
||||
|
||||
static u8 xgbe_dcb_setdcbx(struct net_device *netdev, u8 dcbx)
|
||||
{
|
||||
u8 support = xgbe_dcb_getdcbx(netdev);
|
||||
|
||||
DBGPR(" DCBX=%#hhx\n", dcbx);
|
||||
|
||||
if (dcbx & ~support)
|
||||
return 1;
|
||||
|
||||
if ((dcbx & support) != support)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dcbnl_rtnl_ops xgbe_dcbnl_ops = {
|
||||
/* IEEE 802.1Qaz std */
|
||||
.ieee_getets = xgbe_dcb_ieee_getets,
|
||||
.ieee_setets = xgbe_dcb_ieee_setets,
|
||||
.ieee_getpfc = xgbe_dcb_ieee_getpfc,
|
||||
.ieee_setpfc = xgbe_dcb_ieee_setpfc,
|
||||
|
||||
/* DCBX configuration */
|
||||
.getdcbx = xgbe_dcb_getdcbx,
|
||||
.setdcbx = xgbe_dcb_setdcbx,
|
||||
};
|
||||
|
||||
const struct dcbnl_rtnl_ops *xgbe_get_dcbnl_ops(void)
|
||||
{
|
||||
return &xgbe_dcbnl_ops;
|
||||
}
|
373
drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
Normal file
373
drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
Normal file
|
@ -0,0 +1,373 @@
|
|||
/*
|
||||
* AMD 10Gb Ethernet driver
|
||||
*
|
||||
* This file is available to you under your choice of the following two
|
||||
* licenses:
|
||||
*
|
||||
* License 1: GPLv2
|
||||
*
|
||||
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This file is free software; you may copy, redistribute and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* The Synopsys DWC ETHER XGMAC Software Driver and documentation
|
||||
* (hereinafter "Software") is an unsupported proprietary work of Synopsys,
|
||||
* Inc. unless otherwise expressly agreed to in writing between Synopsys
|
||||
* and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for Licensed
|
||||
* Product with Synopsys or any supplement thereto. Permission is hereby
|
||||
* granted, free of charge, to any person obtaining a copy of this software
|
||||
* annotated with this license and the Software, to deal in the Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* License 2: Modified BSD
|
||||
*
|
||||
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Advanced Micro Devices, Inc. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* The Synopsys DWC ETHER XGMAC Software Driver and documentation
|
||||
* (hereinafter "Software") is an unsupported proprietary work of Synopsys,
|
||||
* Inc. unless otherwise expressly agreed to in writing between Synopsys
|
||||
* and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for Licensed
|
||||
* Product with Synopsys or any supplement thereto. Permission is hereby
|
||||
* granted, free of charge, to any person obtaining a copy of this software
|
||||
* annotated with this license and the Software, to deal in the Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "xgbe.h"
|
||||
#include "xgbe-common.h"
|
||||
|
||||
static ssize_t xgbe_common_read(char __user *buffer, size_t count,
|
||||
loff_t *ppos, unsigned int value)
|
||||
{
|
||||
char *buf;
|
||||
ssize_t len;
|
||||
|
||||
if (*ppos != 0)
|
||||
return 0;
|
||||
|
||||
buf = kasprintf(GFP_KERNEL, "0x%08x\n", value);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (count < strlen(buf)) {
|
||||
kfree(buf);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
|
||||
kfree(buf);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t xgbe_common_write(const char __user *buffer, size_t count,
|
||||
loff_t *ppos, unsigned int *value)
|
||||
{
|
||||
char workarea[32];
|
||||
ssize_t len;
|
||||
int ret;
|
||||
|
||||
if (*ppos != 0)
|
||||
return 0;
|
||||
|
||||
if (count >= sizeof(workarea))
|
||||
return -ENOSPC;
|
||||
|
||||
len = simple_write_to_buffer(workarea, sizeof(workarea) - 1, ppos,
|
||||
buffer, count);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
workarea[len] = '\0';
|
||||
ret = kstrtouint(workarea, 16, value);
|
||||
if (ret)
|
||||
return -EIO;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t xgmac_reg_addr_read(struct file *filp, char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = filp->private_data;
|
||||
|
||||
return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xgmac_reg);
|
||||
}
|
||||
|
||||
static ssize_t xgmac_reg_addr_write(struct file *filp,
|
||||
const char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = filp->private_data;
|
||||
|
||||
return xgbe_common_write(buffer, count, ppos,
|
||||
&pdata->debugfs_xgmac_reg);
|
||||
}
|
||||
|
||||
static ssize_t xgmac_reg_value_read(struct file *filp, char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = filp->private_data;
|
||||
unsigned int value;
|
||||
|
||||
value = XGMAC_IOREAD(pdata, pdata->debugfs_xgmac_reg);
|
||||
|
||||
return xgbe_common_read(buffer, count, ppos, value);
|
||||
}
|
||||
|
||||
static ssize_t xgmac_reg_value_write(struct file *filp,
|
||||
const char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = filp->private_data;
|
||||
unsigned int value;
|
||||
ssize_t len;
|
||||
|
||||
len = xgbe_common_write(buffer, count, ppos, &value);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
XGMAC_IOWRITE(pdata, pdata->debugfs_xgmac_reg, value);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct file_operations xgmac_reg_addr_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = xgmac_reg_addr_read,
|
||||
.write = xgmac_reg_addr_write,
|
||||
};
|
||||
|
||||
static const struct file_operations xgmac_reg_value_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = xgmac_reg_value_read,
|
||||
.write = xgmac_reg_value_write,
|
||||
};
|
||||
|
||||
static ssize_t xpcs_mmd_read(struct file *filp, char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = filp->private_data;
|
||||
|
||||
return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xpcs_mmd);
|
||||
}
|
||||
|
||||
static ssize_t xpcs_mmd_write(struct file *filp, const char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = filp->private_data;
|
||||
|
||||
return xgbe_common_write(buffer, count, ppos,
|
||||
&pdata->debugfs_xpcs_mmd);
|
||||
}
|
||||
|
||||
static ssize_t xpcs_reg_addr_read(struct file *filp, char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = filp->private_data;
|
||||
|
||||
return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xpcs_reg);
|
||||
}
|
||||
|
||||
static ssize_t xpcs_reg_addr_write(struct file *filp, const char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = filp->private_data;
|
||||
|
||||
return xgbe_common_write(buffer, count, ppos,
|
||||
&pdata->debugfs_xpcs_reg);
|
||||
}
|
||||
|
||||
static ssize_t xpcs_reg_value_read(struct file *filp, char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = filp->private_data;
|
||||
unsigned int value;
|
||||
|
||||
value = XMDIO_READ(pdata, pdata->debugfs_xpcs_mmd,
|
||||
pdata->debugfs_xpcs_reg);
|
||||
|
||||
return xgbe_common_read(buffer, count, ppos, value);
|
||||
}
|
||||
|
||||
static ssize_t xpcs_reg_value_write(struct file *filp,
|
||||
const char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = filp->private_data;
|
||||
unsigned int value;
|
||||
ssize_t len;
|
||||
|
||||
len = xgbe_common_write(buffer, count, ppos, &value);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
XMDIO_WRITE(pdata, pdata->debugfs_xpcs_mmd, pdata->debugfs_xpcs_reg,
|
||||
value);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct file_operations xpcs_mmd_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = xpcs_mmd_read,
|
||||
.write = xpcs_mmd_write,
|
||||
};
|
||||
|
||||
static const struct file_operations xpcs_reg_addr_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = xpcs_reg_addr_read,
|
||||
.write = xpcs_reg_addr_write,
|
||||
};
|
||||
|
||||
static const struct file_operations xpcs_reg_value_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = xpcs_reg_value_read,
|
||||
.write = xpcs_reg_value_write,
|
||||
};
|
||||
|
||||
void xgbe_debugfs_init(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
struct dentry *pfile;
|
||||
char *buf;
|
||||
|
||||
/* Set defaults */
|
||||
pdata->debugfs_xgmac_reg = 0;
|
||||
pdata->debugfs_xpcs_mmd = 1;
|
||||
pdata->debugfs_xpcs_reg = 0;
|
||||
|
||||
buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name);
|
||||
pdata->xgbe_debugfs = debugfs_create_dir(buf, NULL);
|
||||
if (pdata->xgbe_debugfs == NULL) {
|
||||
netdev_err(pdata->netdev, "debugfs_create_dir failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pfile = debugfs_create_file("xgmac_register", 0600,
|
||||
pdata->xgbe_debugfs, pdata,
|
||||
&xgmac_reg_addr_fops);
|
||||
if (!pfile)
|
||||
netdev_err(pdata->netdev, "debugfs_create_file failed\n");
|
||||
|
||||
pfile = debugfs_create_file("xgmac_register_value", 0600,
|
||||
pdata->xgbe_debugfs, pdata,
|
||||
&xgmac_reg_value_fops);
|
||||
if (!pfile)
|
||||
netdev_err(pdata->netdev, "debugfs_create_file failed\n");
|
||||
|
||||
pfile = debugfs_create_file("xpcs_mmd", 0600,
|
||||
pdata->xgbe_debugfs, pdata,
|
||||
&xpcs_mmd_fops);
|
||||
if (!pfile)
|
||||
netdev_err(pdata->netdev, "debugfs_create_file failed\n");
|
||||
|
||||
pfile = debugfs_create_file("xpcs_register", 0600,
|
||||
pdata->xgbe_debugfs, pdata,
|
||||
&xpcs_reg_addr_fops);
|
||||
if (!pfile)
|
||||
netdev_err(pdata->netdev, "debugfs_create_file failed\n");
|
||||
|
||||
pfile = debugfs_create_file("xpcs_register_value", 0600,
|
||||
pdata->xgbe_debugfs, pdata,
|
||||
&xpcs_reg_value_fops);
|
||||
if (!pfile)
|
||||
netdev_err(pdata->netdev, "debugfs_create_file failed\n");
|
||||
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
void xgbe_debugfs_exit(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
debugfs_remove_recursive(pdata->xgbe_debugfs);
|
||||
pdata->xgbe_debugfs = NULL;
|
||||
}
|
562
drivers/net/ethernet/amd/xgbe/xgbe-desc.c
Normal file
562
drivers/net/ethernet/amd/xgbe/xgbe-desc.c
Normal file
|
@ -0,0 +1,562 @@
|
|||
/*
|
||||
* AMD 10Gb Ethernet driver
|
||||
*
|
||||
* This file is available to you under your choice of the following two
|
||||
* licenses:
|
||||
*
|
||||
* License 1: GPLv2
|
||||
*
|
||||
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This file is free software; you may copy, redistribute and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* The Synopsys DWC ETHER XGMAC Software Driver and documentation
|
||||
* (hereinafter "Software") is an unsupported proprietary work of Synopsys,
|
||||
* Inc. unless otherwise expressly agreed to in writing between Synopsys
|
||||
* and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for Licensed
|
||||
* Product with Synopsys or any supplement thereto. Permission is hereby
|
||||
* granted, free of charge, to any person obtaining a copy of this software
|
||||
* annotated with this license and the Software, to deal in the Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* License 2: Modified BSD
|
||||
*
|
||||
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Advanced Micro Devices, Inc. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* The Synopsys DWC ETHER XGMAC Software Driver and documentation
|
||||
* (hereinafter "Software") is an unsupported proprietary work of Synopsys,
|
||||
* Inc. unless otherwise expressly agreed to in writing between Synopsys
|
||||
* and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for Licensed
|
||||
* Product with Synopsys or any supplement thereto. Permission is hereby
|
||||
* granted, free of charge, to any person obtaining a copy of this software
|
||||
* annotated with this license and the Software, to deal in the Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "xgbe.h"
|
||||
#include "xgbe-common.h"
|
||||
|
||||
static void xgbe_unmap_skb(struct xgbe_prv_data *, struct xgbe_ring_data *);
|
||||
|
||||
static void xgbe_free_ring(struct xgbe_prv_data *pdata,
|
||||
struct xgbe_ring *ring)
|
||||
{
|
||||
struct xgbe_ring_data *rdata;
|
||||
unsigned int i;
|
||||
|
||||
if (!ring)
|
||||
return;
|
||||
|
||||
if (ring->rdata) {
|
||||
for (i = 0; i < ring->rdesc_count; i++) {
|
||||
rdata = XGBE_GET_DESC_DATA(ring, i);
|
||||
xgbe_unmap_skb(pdata, rdata);
|
||||
}
|
||||
|
||||
kfree(ring->rdata);
|
||||
ring->rdata = NULL;
|
||||
}
|
||||
|
||||
if (ring->rdesc) {
|
||||
dma_free_coherent(pdata->dev,
|
||||
(sizeof(struct xgbe_ring_desc) *
|
||||
ring->rdesc_count),
|
||||
ring->rdesc, ring->rdesc_dma);
|
||||
ring->rdesc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void xgbe_free_ring_resources(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
struct xgbe_channel *channel;
|
||||
unsigned int i;
|
||||
|
||||
DBGPR("-->xgbe_free_ring_resources\n");
|
||||
|
||||
channel = pdata->channel;
|
||||
for (i = 0; i < pdata->channel_count; i++, channel++) {
|
||||
xgbe_free_ring(pdata, channel->tx_ring);
|
||||
xgbe_free_ring(pdata, channel->rx_ring);
|
||||
}
|
||||
|
||||
DBGPR("<--xgbe_free_ring_resources\n");
|
||||
}
|
||||
|
||||
static int xgbe_init_ring(struct xgbe_prv_data *pdata,
|
||||
struct xgbe_ring *ring, unsigned int rdesc_count)
|
||||
{
|
||||
DBGPR("-->xgbe_init_ring\n");
|
||||
|
||||
if (!ring)
|
||||
return 0;
|
||||
|
||||
/* Descriptors */
|
||||
ring->rdesc_count = rdesc_count;
|
||||
ring->rdesc = dma_alloc_coherent(pdata->dev,
|
||||
(sizeof(struct xgbe_ring_desc) *
|
||||
rdesc_count), &ring->rdesc_dma,
|
||||
GFP_KERNEL);
|
||||
if (!ring->rdesc)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Descriptor information */
|
||||
ring->rdata = kcalloc(rdesc_count, sizeof(struct xgbe_ring_data),
|
||||
GFP_KERNEL);
|
||||
if (!ring->rdata)
|
||||
return -ENOMEM;
|
||||
|
||||
DBGPR(" rdesc=0x%p, rdesc_dma=0x%llx, rdata=0x%p\n",
|
||||
ring->rdesc, ring->rdesc_dma, ring->rdata);
|
||||
|
||||
DBGPR("<--xgbe_init_ring\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xgbe_alloc_ring_resources(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
struct xgbe_channel *channel;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
DBGPR("-->xgbe_alloc_ring_resources\n");
|
||||
|
||||
channel = pdata->channel;
|
||||
for (i = 0; i < pdata->channel_count; i++, channel++) {
|
||||
DBGPR(" %s - tx_ring:\n", channel->name);
|
||||
ret = xgbe_init_ring(pdata, channel->tx_ring,
|
||||
pdata->tx_desc_count);
|
||||
if (ret) {
|
||||
netdev_alert(pdata->netdev,
|
||||
"error initializing Tx ring\n");
|
||||
goto err_ring;
|
||||
}
|
||||
|
||||
DBGPR(" %s - rx_ring:\n", channel->name);
|
||||
ret = xgbe_init_ring(pdata, channel->rx_ring,
|
||||
pdata->rx_desc_count);
|
||||
if (ret) {
|
||||
netdev_alert(pdata->netdev,
|
||||
"error initializing Tx ring\n");
|
||||
goto err_ring;
|
||||
}
|
||||
}
|
||||
|
||||
DBGPR("<--xgbe_alloc_ring_resources\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_ring:
|
||||
xgbe_free_ring_resources(pdata);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void xgbe_wrapper_tx_descriptor_init(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
struct xgbe_hw_if *hw_if = &pdata->hw_if;
|
||||
struct xgbe_channel *channel;
|
||||
struct xgbe_ring *ring;
|
||||
struct xgbe_ring_data *rdata;
|
||||
struct xgbe_ring_desc *rdesc;
|
||||
dma_addr_t rdesc_dma;
|
||||
unsigned int i, j;
|
||||
|
||||
DBGPR("-->xgbe_wrapper_tx_descriptor_init\n");
|
||||
|
||||
channel = pdata->channel;
|
||||
for (i = 0; i < pdata->channel_count; i++, channel++) {
|
||||
ring = channel->tx_ring;
|
||||
if (!ring)
|
||||
break;
|
||||
|
||||
rdesc = ring->rdesc;
|
||||
rdesc_dma = ring->rdesc_dma;
|
||||
|
||||
for (j = 0; j < ring->rdesc_count; j++) {
|
||||
rdata = XGBE_GET_DESC_DATA(ring, j);
|
||||
|
||||
rdata->rdesc = rdesc;
|
||||
rdata->rdesc_dma = rdesc_dma;
|
||||
|
||||
rdesc++;
|
||||
rdesc_dma += sizeof(struct xgbe_ring_desc);
|
||||
}
|
||||
|
||||
ring->cur = 0;
|
||||
ring->dirty = 0;
|
||||
ring->tx.queue_stopped = 0;
|
||||
|
||||
hw_if->tx_desc_init(channel);
|
||||
}
|
||||
|
||||
DBGPR("<--xgbe_wrapper_tx_descriptor_init\n");
|
||||
}
|
||||
|
||||
static void xgbe_wrapper_rx_descriptor_init(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
struct xgbe_hw_if *hw_if = &pdata->hw_if;
|
||||
struct xgbe_channel *channel;
|
||||
struct xgbe_ring *ring;
|
||||
struct xgbe_ring_desc *rdesc;
|
||||
struct xgbe_ring_data *rdata;
|
||||
dma_addr_t rdesc_dma, skb_dma;
|
||||
struct sk_buff *skb = NULL;
|
||||
unsigned int i, j;
|
||||
|
||||
DBGPR("-->xgbe_wrapper_rx_descriptor_init\n");
|
||||
|
||||
channel = pdata->channel;
|
||||
for (i = 0; i < pdata->channel_count; i++, channel++) {
|
||||
ring = channel->rx_ring;
|
||||
if (!ring)
|
||||
break;
|
||||
|
||||
rdesc = ring->rdesc;
|
||||
rdesc_dma = ring->rdesc_dma;
|
||||
|
||||
for (j = 0; j < ring->rdesc_count; j++) {
|
||||
rdata = XGBE_GET_DESC_DATA(ring, j);
|
||||
|
||||
rdata->rdesc = rdesc;
|
||||
rdata->rdesc_dma = rdesc_dma;
|
||||
|
||||
/* Allocate skb & assign to each rdesc */
|
||||
skb = dev_alloc_skb(pdata->rx_buf_size);
|
||||
if (skb == NULL)
|
||||
break;
|
||||
skb_dma = dma_map_single(pdata->dev, skb->data,
|
||||
pdata->rx_buf_size,
|
||||
DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(pdata->dev, skb_dma)) {
|
||||
netdev_alert(pdata->netdev,
|
||||
"failed to do the dma map\n");
|
||||
dev_kfree_skb_any(skb);
|
||||
break;
|
||||
}
|
||||
rdata->skb = skb;
|
||||
rdata->skb_dma = skb_dma;
|
||||
rdata->skb_dma_len = pdata->rx_buf_size;
|
||||
|
||||
rdesc++;
|
||||
rdesc_dma += sizeof(struct xgbe_ring_desc);
|
||||
}
|
||||
|
||||
ring->cur = 0;
|
||||
ring->dirty = 0;
|
||||
ring->rx.realloc_index = 0;
|
||||
ring->rx.realloc_threshold = 0;
|
||||
|
||||
hw_if->rx_desc_init(channel);
|
||||
}
|
||||
|
||||
DBGPR("<--xgbe_wrapper_rx_descriptor_init\n");
|
||||
}
|
||||
|
||||
static void xgbe_unmap_skb(struct xgbe_prv_data *pdata,
|
||||
struct xgbe_ring_data *rdata)
|
||||
{
|
||||
if (rdata->skb_dma) {
|
||||
if (rdata->mapped_as_page) {
|
||||
dma_unmap_page(pdata->dev, rdata->skb_dma,
|
||||
rdata->skb_dma_len, DMA_TO_DEVICE);
|
||||
} else {
|
||||
dma_unmap_single(pdata->dev, rdata->skb_dma,
|
||||
rdata->skb_dma_len, DMA_TO_DEVICE);
|
||||
}
|
||||
rdata->skb_dma = 0;
|
||||
rdata->skb_dma_len = 0;
|
||||
}
|
||||
|
||||
if (rdata->skb) {
|
||||
dev_kfree_skb_any(rdata->skb);
|
||||
rdata->skb = NULL;
|
||||
}
|
||||
|
||||
rdata->tso_header = 0;
|
||||
rdata->len = 0;
|
||||
rdata->interrupt = 0;
|
||||
rdata->mapped_as_page = 0;
|
||||
|
||||
if (rdata->state_saved) {
|
||||
rdata->state_saved = 0;
|
||||
rdata->state.incomplete = 0;
|
||||
rdata->state.context_next = 0;
|
||||
rdata->state.skb = NULL;
|
||||
rdata->state.len = 0;
|
||||
rdata->state.error = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = channel->pdata;
|
||||
struct xgbe_ring *ring = channel->tx_ring;
|
||||
struct xgbe_ring_data *rdata;
|
||||
struct xgbe_packet_data *packet;
|
||||
struct skb_frag_struct *frag;
|
||||
dma_addr_t skb_dma;
|
||||
unsigned int start_index, cur_index;
|
||||
unsigned int offset, tso, vlan, datalen, len;
|
||||
unsigned int i;
|
||||
|
||||
DBGPR("-->xgbe_map_tx_skb: cur = %d\n", ring->cur);
|
||||
|
||||
offset = 0;
|
||||
start_index = ring->cur;
|
||||
cur_index = ring->cur;
|
||||
|
||||
packet = &ring->packet_data;
|
||||
packet->rdesc_count = 0;
|
||||
packet->length = 0;
|
||||
|
||||
tso = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES,
|
||||
TSO_ENABLE);
|
||||
vlan = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES,
|
||||
VLAN_CTAG);
|
||||
|
||||
/* Save space for a context descriptor if needed */
|
||||
if ((tso && (packet->mss != ring->tx.cur_mss)) ||
|
||||
(vlan && (packet->vlan_ctag != ring->tx.cur_vlan_ctag)))
|
||||
cur_index++;
|
||||
rdata = XGBE_GET_DESC_DATA(ring, cur_index);
|
||||
|
||||
if (tso) {
|
||||
DBGPR(" TSO packet\n");
|
||||
|
||||
/* Map the TSO header */
|
||||
skb_dma = dma_map_single(pdata->dev, skb->data,
|
||||
packet->header_len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(pdata->dev, skb_dma)) {
|
||||
netdev_alert(pdata->netdev, "dma_map_single failed\n");
|
||||
goto err_out;
|
||||
}
|
||||
rdata->skb_dma = skb_dma;
|
||||
rdata->skb_dma_len = packet->header_len;
|
||||
rdata->tso_header = 1;
|
||||
|
||||
offset = packet->header_len;
|
||||
|
||||
packet->length += packet->header_len;
|
||||
|
||||
cur_index++;
|
||||
rdata = XGBE_GET_DESC_DATA(ring, cur_index);
|
||||
}
|
||||
|
||||
/* Map the (remainder of the) packet */
|
||||
for (datalen = skb_headlen(skb) - offset; datalen; ) {
|
||||
len = min_t(unsigned int, datalen, XGBE_TX_MAX_BUF_SIZE);
|
||||
|
||||
skb_dma = dma_map_single(pdata->dev, skb->data + offset, len,
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(pdata->dev, skb_dma)) {
|
||||
netdev_alert(pdata->netdev, "dma_map_single failed\n");
|
||||
goto err_out;
|
||||
}
|
||||
rdata->skb_dma = skb_dma;
|
||||
rdata->skb_dma_len = len;
|
||||
DBGPR(" skb data: index=%u, dma=0x%llx, len=%u\n",
|
||||
cur_index, skb_dma, len);
|
||||
|
||||
datalen -= len;
|
||||
offset += len;
|
||||
|
||||
packet->length += len;
|
||||
|
||||
cur_index++;
|
||||
rdata = XGBE_GET_DESC_DATA(ring, cur_index);
|
||||
}
|
||||
|
||||
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
||||
DBGPR(" mapping frag %u\n", i);
|
||||
|
||||
frag = &skb_shinfo(skb)->frags[i];
|
||||
offset = 0;
|
||||
|
||||
for (datalen = skb_frag_size(frag); datalen; ) {
|
||||
len = min_t(unsigned int, datalen,
|
||||
XGBE_TX_MAX_BUF_SIZE);
|
||||
|
||||
skb_dma = skb_frag_dma_map(pdata->dev, frag, offset,
|
||||
len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(pdata->dev, skb_dma)) {
|
||||
netdev_alert(pdata->netdev,
|
||||
"skb_frag_dma_map failed\n");
|
||||
goto err_out;
|
||||
}
|
||||
rdata->skb_dma = skb_dma;
|
||||
rdata->skb_dma_len = len;
|
||||
rdata->mapped_as_page = 1;
|
||||
DBGPR(" skb data: index=%u, dma=0x%llx, len=%u\n",
|
||||
cur_index, skb_dma, len);
|
||||
|
||||
datalen -= len;
|
||||
offset += len;
|
||||
|
||||
packet->length += len;
|
||||
|
||||
cur_index++;
|
||||
rdata = XGBE_GET_DESC_DATA(ring, cur_index);
|
||||
}
|
||||
}
|
||||
|
||||
/* Save the skb address in the last entry */
|
||||
rdata->skb = skb;
|
||||
|
||||
/* Save the number of descriptor entries used */
|
||||
packet->rdesc_count = cur_index - start_index;
|
||||
|
||||
DBGPR("<--xgbe_map_tx_skb: count=%u\n", packet->rdesc_count);
|
||||
|
||||
return packet->rdesc_count;
|
||||
|
||||
err_out:
|
||||
while (start_index < cur_index) {
|
||||
rdata = XGBE_GET_DESC_DATA(ring, start_index++);
|
||||
xgbe_unmap_skb(pdata, rdata);
|
||||
}
|
||||
|
||||
DBGPR("<--xgbe_map_tx_skb: count=0\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xgbe_realloc_skb(struct xgbe_channel *channel)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = channel->pdata;
|
||||
struct xgbe_hw_if *hw_if = &pdata->hw_if;
|
||||
struct xgbe_ring *ring = channel->rx_ring;
|
||||
struct xgbe_ring_data *rdata;
|
||||
struct sk_buff *skb = NULL;
|
||||
dma_addr_t skb_dma;
|
||||
int i;
|
||||
|
||||
DBGPR("-->xgbe_realloc_skb: rx_ring->rx.realloc_index = %u\n",
|
||||
ring->rx.realloc_index);
|
||||
|
||||
for (i = 0; i < ring->dirty; i++) {
|
||||
rdata = XGBE_GET_DESC_DATA(ring, ring->rx.realloc_index);
|
||||
|
||||
/* Reset rdata values */
|
||||
xgbe_unmap_skb(pdata, rdata);
|
||||
|
||||
/* Allocate skb & assign to each rdesc */
|
||||
skb = dev_alloc_skb(pdata->rx_buf_size);
|
||||
if (skb == NULL)
|
||||
break;
|
||||
skb_dma = dma_map_single(pdata->dev, skb->data,
|
||||
pdata->rx_buf_size, DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(pdata->dev, skb_dma)) {
|
||||
netdev_alert(pdata->netdev,
|
||||
"failed to do the dma map\n");
|
||||
dev_kfree_skb_any(skb);
|
||||
break;
|
||||
}
|
||||
rdata->skb = skb;
|
||||
rdata->skb_dma = skb_dma;
|
||||
rdata->skb_dma_len = pdata->rx_buf_size;
|
||||
|
||||
hw_if->rx_desc_reset(rdata);
|
||||
|
||||
ring->rx.realloc_index++;
|
||||
}
|
||||
ring->dirty = 0;
|
||||
|
||||
DBGPR("<--xgbe_realloc_skb\n");
|
||||
}
|
||||
|
||||
void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *desc_if)
|
||||
{
|
||||
DBGPR("-->xgbe_init_function_ptrs_desc\n");
|
||||
|
||||
desc_if->alloc_ring_resources = xgbe_alloc_ring_resources;
|
||||
desc_if->free_ring_resources = xgbe_free_ring_resources;
|
||||
desc_if->map_tx_skb = xgbe_map_tx_skb;
|
||||
desc_if->realloc_skb = xgbe_realloc_skb;
|
||||
desc_if->unmap_skb = xgbe_unmap_skb;
|
||||
desc_if->wrapper_tx_desc_init = xgbe_wrapper_tx_descriptor_init;
|
||||
desc_if->wrapper_rx_desc_init = xgbe_wrapper_rx_descriptor_init;
|
||||
|
||||
DBGPR("<--xgbe_init_function_ptrs_desc\n");
|
||||
}
|
2624
drivers/net/ethernet/amd/xgbe/xgbe-dev.c
Normal file
2624
drivers/net/ethernet/amd/xgbe/xgbe-dev.c
Normal file
File diff suppressed because it is too large
Load diff
1865
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
Normal file
1865
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
Normal file
File diff suppressed because it is too large
Load diff
535
drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
Normal file
535
drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
Normal file
|
@ -0,0 +1,535 @@
|
|||
/*
|
||||
* AMD 10Gb Ethernet driver
|
||||
*
|
||||
* This file is available to you under your choice of the following two
|
||||
* licenses:
|
||||
*
|
||||
* License 1: GPLv2
|
||||
*
|
||||
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This file is free software; you may copy, redistribute and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* The Synopsys DWC ETHER XGMAC Software Driver and documentation
|
||||
* (hereinafter "Software") is an unsupported proprietary work of Synopsys,
|
||||
* Inc. unless otherwise expressly agreed to in writing between Synopsys
|
||||
* and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for Licensed
|
||||
* Product with Synopsys or any supplement thereto. Permission is hereby
|
||||
* granted, free of charge, to any person obtaining a copy of this software
|
||||
* annotated with this license and the Software, to deal in the Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* License 2: Modified BSD
|
||||
*
|
||||
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Advanced Micro Devices, Inc. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* The Synopsys DWC ETHER XGMAC Software Driver and documentation
|
||||
* (hereinafter "Software") is an unsupported proprietary work of Synopsys,
|
||||
* Inc. unless otherwise expressly agreed to in writing between Synopsys
|
||||
* and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for Licensed
|
||||
* Product with Synopsys or any supplement thereto. Permission is hereby
|
||||
* granted, free of charge, to any person obtaining a copy of this software
|
||||
* annotated with this license and the Software, to deal in the Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
|
||||
#include "xgbe.h"
|
||||
#include "xgbe-common.h"
|
||||
|
||||
struct xgbe_stats {
|
||||
char stat_string[ETH_GSTRING_LEN];
|
||||
int stat_size;
|
||||
int stat_offset;
|
||||
};
|
||||
|
||||
#define XGMAC_MMC_STAT(_string, _var) \
|
||||
{ _string, \
|
||||
FIELD_SIZEOF(struct xgbe_mmc_stats, _var), \
|
||||
offsetof(struct xgbe_prv_data, mmc_stats._var), \
|
||||
}
|
||||
|
||||
static const struct xgbe_stats xgbe_gstring_stats[] = {
|
||||
XGMAC_MMC_STAT("tx_bytes", txoctetcount_gb),
|
||||
XGMAC_MMC_STAT("tx_packets", txframecount_gb),
|
||||
XGMAC_MMC_STAT("tx_unicast_packets", txunicastframes_gb),
|
||||
XGMAC_MMC_STAT("tx_broadcast_packets", txbroadcastframes_gb),
|
||||
XGMAC_MMC_STAT("tx_multicast_packets", txmulticastframes_gb),
|
||||
XGMAC_MMC_STAT("tx_vlan_packets", txvlanframes_g),
|
||||
XGMAC_MMC_STAT("tx_64_byte_packets", tx64octets_gb),
|
||||
XGMAC_MMC_STAT("tx_65_to_127_byte_packets", tx65to127octets_gb),
|
||||
XGMAC_MMC_STAT("tx_128_to_255_byte_packets", tx128to255octets_gb),
|
||||
XGMAC_MMC_STAT("tx_256_to_511_byte_packets", tx256to511octets_gb),
|
||||
XGMAC_MMC_STAT("tx_512_to_1023_byte_packets", tx512to1023octets_gb),
|
||||
XGMAC_MMC_STAT("tx_1024_to_max_byte_packets", tx1024tomaxoctets_gb),
|
||||
XGMAC_MMC_STAT("tx_underflow_errors", txunderflowerror),
|
||||
XGMAC_MMC_STAT("tx_pause_frames", txpauseframes),
|
||||
|
||||
XGMAC_MMC_STAT("rx_bytes", rxoctetcount_gb),
|
||||
XGMAC_MMC_STAT("rx_packets", rxframecount_gb),
|
||||
XGMAC_MMC_STAT("rx_unicast_packets", rxunicastframes_g),
|
||||
XGMAC_MMC_STAT("rx_broadcast_packets", rxbroadcastframes_g),
|
||||
XGMAC_MMC_STAT("rx_multicast_packets", rxmulticastframes_g),
|
||||
XGMAC_MMC_STAT("rx_vlan_packets", rxvlanframes_gb),
|
||||
XGMAC_MMC_STAT("rx_64_byte_packets", rx64octets_gb),
|
||||
XGMAC_MMC_STAT("rx_65_to_127_byte_packets", rx65to127octets_gb),
|
||||
XGMAC_MMC_STAT("rx_128_to_255_byte_packets", rx128to255octets_gb),
|
||||
XGMAC_MMC_STAT("rx_256_to_511_byte_packets", rx256to511octets_gb),
|
||||
XGMAC_MMC_STAT("rx_512_to_1023_byte_packets", rx512to1023octets_gb),
|
||||
XGMAC_MMC_STAT("rx_1024_to_max_byte_packets", rx1024tomaxoctets_gb),
|
||||
XGMAC_MMC_STAT("rx_undersize_packets", rxundersize_g),
|
||||
XGMAC_MMC_STAT("rx_oversize_packets", rxoversize_g),
|
||||
XGMAC_MMC_STAT("rx_crc_errors", rxcrcerror),
|
||||
XGMAC_MMC_STAT("rx_crc_errors_small_packets", rxrunterror),
|
||||
XGMAC_MMC_STAT("rx_crc_errors_giant_packets", rxjabbererror),
|
||||
XGMAC_MMC_STAT("rx_length_errors", rxlengtherror),
|
||||
XGMAC_MMC_STAT("rx_out_of_range_errors", rxoutofrangetype),
|
||||
XGMAC_MMC_STAT("rx_fifo_overflow_errors", rxfifooverflow),
|
||||
XGMAC_MMC_STAT("rx_watchdog_errors", rxwatchdogerror),
|
||||
XGMAC_MMC_STAT("rx_pause_frames", rxpauseframes),
|
||||
};
|
||||
|
||||
#define XGBE_STATS_COUNT ARRAY_SIZE(xgbe_gstring_stats)
|
||||
|
||||
static void xgbe_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
DBGPR("-->%s\n", __func__);
|
||||
|
||||
switch (stringset) {
|
||||
case ETH_SS_STATS:
|
||||
for (i = 0; i < XGBE_STATS_COUNT; i++) {
|
||||
memcpy(data, xgbe_gstring_stats[i].stat_string,
|
||||
ETH_GSTRING_LEN);
|
||||
data += ETH_GSTRING_LEN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
DBGPR("<--%s\n", __func__);
|
||||
}
|
||||
|
||||
static void xgbe_get_ethtool_stats(struct net_device *netdev,
|
||||
struct ethtool_stats *stats, u64 *data)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
u8 *stat;
|
||||
int i;
|
||||
|
||||
DBGPR("-->%s\n", __func__);
|
||||
|
||||
pdata->hw_if.read_mmc_stats(pdata);
|
||||
for (i = 0; i < XGBE_STATS_COUNT; i++) {
|
||||
stat = (u8 *)pdata + xgbe_gstring_stats[i].stat_offset;
|
||||
*data++ = *(u64 *)stat;
|
||||
}
|
||||
|
||||
DBGPR("<--%s\n", __func__);
|
||||
}
|
||||
|
||||
static int xgbe_get_sset_count(struct net_device *netdev, int stringset)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DBGPR("-->%s\n", __func__);
|
||||
|
||||
switch (stringset) {
|
||||
case ETH_SS_STATS:
|
||||
ret = XGBE_STATS_COUNT;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
DBGPR("<--%s\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void xgbe_get_pauseparam(struct net_device *netdev,
|
||||
struct ethtool_pauseparam *pause)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
|
||||
DBGPR("-->xgbe_get_pauseparam\n");
|
||||
|
||||
pause->autoneg = pdata->pause_autoneg;
|
||||
pause->tx_pause = pdata->tx_pause;
|
||||
pause->rx_pause = pdata->rx_pause;
|
||||
|
||||
DBGPR("<--xgbe_get_pauseparam\n");
|
||||
}
|
||||
|
||||
static int xgbe_set_pauseparam(struct net_device *netdev,
|
||||
struct ethtool_pauseparam *pause)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
struct phy_device *phydev = pdata->phydev;
|
||||
int ret = 0;
|
||||
|
||||
DBGPR("-->xgbe_set_pauseparam\n");
|
||||
|
||||
DBGPR(" autoneg = %d, tx_pause = %d, rx_pause = %d\n",
|
||||
pause->autoneg, pause->tx_pause, pause->rx_pause);
|
||||
|
||||
pdata->pause_autoneg = pause->autoneg;
|
||||
if (pause->autoneg) {
|
||||
phydev->advertising |= ADVERTISED_Pause;
|
||||
phydev->advertising |= ADVERTISED_Asym_Pause;
|
||||
|
||||
} else {
|
||||
phydev->advertising &= ~ADVERTISED_Pause;
|
||||
phydev->advertising &= ~ADVERTISED_Asym_Pause;
|
||||
|
||||
pdata->tx_pause = pause->tx_pause;
|
||||
pdata->rx_pause = pause->rx_pause;
|
||||
}
|
||||
|
||||
if (netif_running(netdev))
|
||||
ret = phy_start_aneg(phydev);
|
||||
|
||||
DBGPR("<--xgbe_set_pauseparam\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xgbe_get_settings(struct net_device *netdev,
|
||||
struct ethtool_cmd *cmd)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
int ret;
|
||||
|
||||
DBGPR("-->xgbe_get_settings\n");
|
||||
|
||||
if (!pdata->phydev)
|
||||
return -ENODEV;
|
||||
|
||||
ret = phy_ethtool_gset(pdata->phydev, cmd);
|
||||
cmd->transceiver = XCVR_EXTERNAL;
|
||||
|
||||
DBGPR("<--xgbe_get_settings\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xgbe_set_settings(struct net_device *netdev,
|
||||
struct ethtool_cmd *cmd)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
struct phy_device *phydev = pdata->phydev;
|
||||
u32 speed;
|
||||
int ret;
|
||||
|
||||
DBGPR("-->xgbe_set_settings\n");
|
||||
|
||||
if (!pdata->phydev)
|
||||
return -ENODEV;
|
||||
|
||||
speed = ethtool_cmd_speed(cmd);
|
||||
|
||||
if (cmd->phy_address != phydev->addr)
|
||||
return -EINVAL;
|
||||
|
||||
if ((cmd->autoneg != AUTONEG_ENABLE) &&
|
||||
(cmd->autoneg != AUTONEG_DISABLE))
|
||||
return -EINVAL;
|
||||
|
||||
if (cmd->autoneg == AUTONEG_DISABLE) {
|
||||
switch (speed) {
|
||||
case SPEED_10000:
|
||||
case SPEED_2500:
|
||||
case SPEED_1000:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cmd->duplex != DUPLEX_FULL)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cmd->advertising &= phydev->supported;
|
||||
if ((cmd->autoneg == AUTONEG_ENABLE) && !cmd->advertising)
|
||||
return -EINVAL;
|
||||
|
||||
ret = 0;
|
||||
phydev->autoneg = cmd->autoneg;
|
||||
phydev->speed = speed;
|
||||
phydev->duplex = cmd->duplex;
|
||||
phydev->advertising = cmd->advertising;
|
||||
|
||||
if (cmd->autoneg == AUTONEG_ENABLE)
|
||||
phydev->advertising |= ADVERTISED_Autoneg;
|
||||
else
|
||||
phydev->advertising &= ~ADVERTISED_Autoneg;
|
||||
|
||||
if (netif_running(netdev))
|
||||
ret = phy_start_aneg(phydev);
|
||||
|
||||
DBGPR("<--xgbe_set_settings\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void xgbe_get_drvinfo(struct net_device *netdev,
|
||||
struct ethtool_drvinfo *drvinfo)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
struct xgbe_hw_features *hw_feat = &pdata->hw_feat;
|
||||
|
||||
strlcpy(drvinfo->driver, XGBE_DRV_NAME, sizeof(drvinfo->driver));
|
||||
strlcpy(drvinfo->version, XGBE_DRV_VERSION, sizeof(drvinfo->version));
|
||||
strlcpy(drvinfo->bus_info, dev_name(pdata->dev),
|
||||
sizeof(drvinfo->bus_info));
|
||||
snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%d.%d.%d",
|
||||
XGMAC_GET_BITS(hw_feat->version, MAC_VR, USERVER),
|
||||
XGMAC_GET_BITS(hw_feat->version, MAC_VR, DEVID),
|
||||
XGMAC_GET_BITS(hw_feat->version, MAC_VR, SNPSVER));
|
||||
drvinfo->n_stats = XGBE_STATS_COUNT;
|
||||
}
|
||||
|
||||
static int xgbe_get_coalesce(struct net_device *netdev,
|
||||
struct ethtool_coalesce *ec)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
struct xgbe_hw_if *hw_if = &pdata->hw_if;
|
||||
unsigned int riwt;
|
||||
|
||||
DBGPR("-->xgbe_get_coalesce\n");
|
||||
|
||||
memset(ec, 0, sizeof(struct ethtool_coalesce));
|
||||
|
||||
riwt = pdata->rx_riwt;
|
||||
ec->rx_coalesce_usecs = hw_if->riwt_to_usec(pdata, riwt);
|
||||
ec->rx_max_coalesced_frames = pdata->rx_frames;
|
||||
|
||||
ec->tx_coalesce_usecs = pdata->tx_usecs;
|
||||
ec->tx_max_coalesced_frames = pdata->tx_frames;
|
||||
|
||||
DBGPR("<--xgbe_get_coalesce\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xgbe_set_coalesce(struct net_device *netdev,
|
||||
struct ethtool_coalesce *ec)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
struct xgbe_hw_if *hw_if = &pdata->hw_if;
|
||||
unsigned int rx_frames, rx_riwt, rx_usecs;
|
||||
unsigned int tx_frames, tx_usecs;
|
||||
|
||||
DBGPR("-->xgbe_set_coalesce\n");
|
||||
|
||||
/* Check for not supported parameters */
|
||||
if ((ec->rx_coalesce_usecs_irq) ||
|
||||
(ec->rx_max_coalesced_frames_irq) ||
|
||||
(ec->tx_coalesce_usecs_irq) ||
|
||||
(ec->tx_max_coalesced_frames_irq) ||
|
||||
(ec->stats_block_coalesce_usecs) ||
|
||||
(ec->use_adaptive_rx_coalesce) ||
|
||||
(ec->use_adaptive_tx_coalesce) ||
|
||||
(ec->pkt_rate_low) ||
|
||||
(ec->rx_coalesce_usecs_low) ||
|
||||
(ec->rx_max_coalesced_frames_low) ||
|
||||
(ec->tx_coalesce_usecs_low) ||
|
||||
(ec->tx_max_coalesced_frames_low) ||
|
||||
(ec->pkt_rate_high) ||
|
||||
(ec->rx_coalesce_usecs_high) ||
|
||||
(ec->rx_max_coalesced_frames_high) ||
|
||||
(ec->tx_coalesce_usecs_high) ||
|
||||
(ec->tx_max_coalesced_frames_high) ||
|
||||
(ec->rate_sample_interval))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Can only change rx-frames when interface is down (see
|
||||
* rx_descriptor_init in xgbe-dev.c)
|
||||
*/
|
||||
rx_frames = pdata->rx_frames;
|
||||
if (rx_frames != ec->rx_max_coalesced_frames && netif_running(netdev)) {
|
||||
netdev_alert(netdev,
|
||||
"interface must be down to change rx-frames\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rx_riwt = hw_if->usec_to_riwt(pdata, ec->rx_coalesce_usecs);
|
||||
rx_frames = ec->rx_max_coalesced_frames;
|
||||
|
||||
/* Use smallest possible value if conversion resulted in zero */
|
||||
if (ec->rx_coalesce_usecs && !rx_riwt)
|
||||
rx_riwt = 1;
|
||||
|
||||
/* Check the bounds of values for Rx */
|
||||
if (rx_riwt > XGMAC_MAX_DMA_RIWT) {
|
||||
rx_usecs = hw_if->riwt_to_usec(pdata, XGMAC_MAX_DMA_RIWT);
|
||||
netdev_alert(netdev, "rx-usec is limited to %d usecs\n",
|
||||
rx_usecs);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (rx_frames > pdata->channel->rx_ring->rdesc_count) {
|
||||
netdev_alert(netdev, "rx-frames is limited to %d frames\n",
|
||||
pdata->channel->rx_ring->rdesc_count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tx_usecs = ec->tx_coalesce_usecs;
|
||||
tx_frames = ec->tx_max_coalesced_frames;
|
||||
|
||||
/* Check the bounds of values for Tx */
|
||||
if (tx_frames > pdata->channel->tx_ring->rdesc_count) {
|
||||
netdev_alert(netdev, "tx-frames is limited to %d frames\n",
|
||||
pdata->channel->tx_ring->rdesc_count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pdata->rx_riwt = rx_riwt;
|
||||
pdata->rx_frames = rx_frames;
|
||||
hw_if->config_rx_coalesce(pdata);
|
||||
|
||||
pdata->tx_usecs = tx_usecs;
|
||||
pdata->tx_frames = tx_frames;
|
||||
hw_if->config_tx_coalesce(pdata);
|
||||
|
||||
DBGPR("<--xgbe_set_coalesce\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xgbe_get_ts_info(struct net_device *netdev,
|
||||
struct ethtool_ts_info *ts_info)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
|
||||
ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_RX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_SOFTWARE |
|
||||
SOF_TIMESTAMPING_TX_HARDWARE |
|
||||
SOF_TIMESTAMPING_RX_HARDWARE |
|
||||
SOF_TIMESTAMPING_RAW_HARDWARE;
|
||||
|
||||
if (pdata->ptp_clock)
|
||||
ts_info->phc_index = ptp_clock_index(pdata->ptp_clock);
|
||||
else
|
||||
ts_info->phc_index = -1;
|
||||
|
||||
ts_info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
|
||||
ts_info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
|
||||
(1 << HWTSTAMP_FILTER_ALL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ethtool_ops xgbe_ethtool_ops = {
|
||||
.get_settings = xgbe_get_settings,
|
||||
.set_settings = xgbe_set_settings,
|
||||
.get_drvinfo = xgbe_get_drvinfo,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_coalesce = xgbe_get_coalesce,
|
||||
.set_coalesce = xgbe_set_coalesce,
|
||||
.get_pauseparam = xgbe_get_pauseparam,
|
||||
.set_pauseparam = xgbe_set_pauseparam,
|
||||
.get_strings = xgbe_get_strings,
|
||||
.get_ethtool_stats = xgbe_get_ethtool_stats,
|
||||
.get_sset_count = xgbe_get_sset_count,
|
||||
.get_ts_info = xgbe_get_ts_info,
|
||||
};
|
||||
|
||||
struct ethtool_ops *xgbe_get_ethtool_ops(void)
|
||||
{
|
||||
return (struct ethtool_ops *)&xgbe_ethtool_ops;
|
||||
}
|
552
drivers/net/ethernet/amd/xgbe/xgbe-main.c
Normal file
552
drivers/net/ethernet/amd/xgbe/xgbe-main.c
Normal file
|
@ -0,0 +1,552 @@
|
|||
/*
|
||||
* AMD 10Gb Ethernet driver
|
||||
*
|
||||
* This file is available to you under your choice of the following two
|
||||
* licenses:
|
||||
*
|
||||
* License 1: GPLv2
|
||||
*
|
||||
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This file is free software; you may copy, redistribute and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* The Synopsys DWC ETHER XGMAC Software Driver and documentation
|
||||
* (hereinafter "Software") is an unsupported proprietary work of Synopsys,
|
||||
* Inc. unless otherwise expressly agreed to in writing between Synopsys
|
||||
* and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for Licensed
|
||||
* Product with Synopsys or any supplement thereto. Permission is hereby
|
||||
* granted, free of charge, to any person obtaining a copy of this software
|
||||
* annotated with this license and the Software, to deal in the Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* License 2: Modified BSD
|
||||
*
|
||||
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Advanced Micro Devices, Inc. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* The Synopsys DWC ETHER XGMAC Software Driver and documentation
|
||||
* (hereinafter "Software") is an unsupported proprietary work of Synopsys,
|
||||
* Inc. unless otherwise expressly agreed to in writing between Synopsys
|
||||
* and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for Licensed
|
||||
* Product with Synopsys or any supplement thereto. Permission is hereby
|
||||
* granted, free of charge, to any person obtaining a copy of this software
|
||||
* annotated with this license and the Software, to deal in the Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_net.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "xgbe.h"
|
||||
#include "xgbe-common.h"
|
||||
|
||||
MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_VERSION(XGBE_DRV_VERSION);
|
||||
MODULE_DESCRIPTION(XGBE_DRV_DESC);
|
||||
|
||||
static struct xgbe_channel *xgbe_alloc_rings(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
struct xgbe_channel *channel_mem, *channel;
|
||||
struct xgbe_ring *tx_ring, *rx_ring;
|
||||
unsigned int count, i;
|
||||
|
||||
DBGPR("-->xgbe_alloc_rings\n");
|
||||
|
||||
count = max_t(unsigned int, pdata->tx_ring_count, pdata->rx_ring_count);
|
||||
|
||||
channel_mem = devm_kcalloc(pdata->dev, count,
|
||||
sizeof(struct xgbe_channel), GFP_KERNEL);
|
||||
if (!channel_mem)
|
||||
return NULL;
|
||||
|
||||
tx_ring = devm_kcalloc(pdata->dev, pdata->tx_ring_count,
|
||||
sizeof(struct xgbe_ring), GFP_KERNEL);
|
||||
if (!tx_ring)
|
||||
return NULL;
|
||||
|
||||
rx_ring = devm_kcalloc(pdata->dev, pdata->rx_ring_count,
|
||||
sizeof(struct xgbe_ring), GFP_KERNEL);
|
||||
if (!rx_ring)
|
||||
return NULL;
|
||||
|
||||
for (i = 0, channel = channel_mem; i < count; i++, channel++) {
|
||||
snprintf(channel->name, sizeof(channel->name), "channel-%d", i);
|
||||
channel->pdata = pdata;
|
||||
channel->queue_index = i;
|
||||
channel->dma_regs = pdata->xgmac_regs + DMA_CH_BASE +
|
||||
(DMA_CH_INC * i);
|
||||
|
||||
if (i < pdata->tx_ring_count) {
|
||||
spin_lock_init(&tx_ring->lock);
|
||||
channel->tx_ring = tx_ring++;
|
||||
}
|
||||
|
||||
if (i < pdata->rx_ring_count) {
|
||||
spin_lock_init(&rx_ring->lock);
|
||||
channel->rx_ring = rx_ring++;
|
||||
}
|
||||
|
||||
DBGPR(" %s - queue_index=%u, dma_regs=%p, tx=%p, rx=%p\n",
|
||||
channel->name, channel->queue_index, channel->dma_regs,
|
||||
channel->tx_ring, channel->rx_ring);
|
||||
}
|
||||
|
||||
pdata->channel_count = count;
|
||||
|
||||
DBGPR("<--xgbe_alloc_rings\n");
|
||||
|
||||
return channel_mem;
|
||||
}
|
||||
|
||||
static void xgbe_default_config(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
DBGPR("-->xgbe_default_config\n");
|
||||
|
||||
pdata->pblx8 = DMA_PBL_X8_ENABLE;
|
||||
pdata->tx_sf_mode = MTL_TSF_ENABLE;
|
||||
pdata->tx_threshold = MTL_TX_THRESHOLD_64;
|
||||
pdata->tx_pbl = DMA_PBL_16;
|
||||
pdata->tx_osp_mode = DMA_OSP_ENABLE;
|
||||
pdata->rx_sf_mode = MTL_RSF_DISABLE;
|
||||
pdata->rx_threshold = MTL_RX_THRESHOLD_64;
|
||||
pdata->rx_pbl = DMA_PBL_16;
|
||||
pdata->pause_autoneg = 1;
|
||||
pdata->tx_pause = 1;
|
||||
pdata->rx_pause = 1;
|
||||
pdata->power_down = 0;
|
||||
pdata->default_autoneg = AUTONEG_ENABLE;
|
||||
pdata->default_speed = SPEED_10000;
|
||||
|
||||
DBGPR("<--xgbe_default_config\n");
|
||||
}
|
||||
|
||||
static void xgbe_init_all_fptrs(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
xgbe_init_function_ptrs_dev(&pdata->hw_if);
|
||||
xgbe_init_function_ptrs_desc(&pdata->desc_if);
|
||||
}
|
||||
|
||||
static int xgbe_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct xgbe_prv_data *pdata;
|
||||
struct xgbe_hw_if *hw_if;
|
||||
struct xgbe_desc_if *desc_if;
|
||||
struct net_device *netdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
const u8 *mac_addr;
|
||||
int ret;
|
||||
|
||||
DBGPR("--> xgbe_probe\n");
|
||||
|
||||
netdev = alloc_etherdev_mq(sizeof(struct xgbe_prv_data),
|
||||
XGBE_MAX_DMA_CHANNELS);
|
||||
if (!netdev) {
|
||||
dev_err(dev, "alloc_etherdev failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
SET_NETDEV_DEV(netdev, dev);
|
||||
pdata = netdev_priv(netdev);
|
||||
pdata->netdev = netdev;
|
||||
pdata->pdev = pdev;
|
||||
pdata->dev = dev;
|
||||
platform_set_drvdata(pdev, netdev);
|
||||
|
||||
spin_lock_init(&pdata->lock);
|
||||
mutex_init(&pdata->xpcs_mutex);
|
||||
spin_lock_init(&pdata->tstamp_lock);
|
||||
|
||||
/* Set and validate the number of descriptors for a ring */
|
||||
BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_TX_DESC_CNT);
|
||||
pdata->tx_desc_count = XGBE_TX_DESC_CNT;
|
||||
if (pdata->tx_desc_count & (pdata->tx_desc_count - 1)) {
|
||||
dev_err(dev, "tx descriptor count (%d) is not valid\n",
|
||||
pdata->tx_desc_count);
|
||||
ret = -EINVAL;
|
||||
goto err_io;
|
||||
}
|
||||
BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_RX_DESC_CNT);
|
||||
pdata->rx_desc_count = XGBE_RX_DESC_CNT;
|
||||
if (pdata->rx_desc_count & (pdata->rx_desc_count - 1)) {
|
||||
dev_err(dev, "rx descriptor count (%d) is not valid\n",
|
||||
pdata->rx_desc_count);
|
||||
ret = -EINVAL;
|
||||
goto err_io;
|
||||
}
|
||||
|
||||
/* Obtain the system clock setting */
|
||||
pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK);
|
||||
if (IS_ERR(pdata->sysclk)) {
|
||||
dev_err(dev, "dma devm_clk_get failed\n");
|
||||
ret = PTR_ERR(pdata->sysclk);
|
||||
goto err_io;
|
||||
}
|
||||
|
||||
/* Obtain the PTP clock setting */
|
||||
pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK);
|
||||
if (IS_ERR(pdata->ptpclk)) {
|
||||
dev_err(dev, "ptp devm_clk_get failed\n");
|
||||
ret = PTR_ERR(pdata->ptpclk);
|
||||
goto err_io;
|
||||
}
|
||||
|
||||
/* Obtain the mmio areas for the device */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
pdata->xgmac_regs = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(pdata->xgmac_regs)) {
|
||||
dev_err(dev, "xgmac ioremap failed\n");
|
||||
ret = PTR_ERR(pdata->xgmac_regs);
|
||||
goto err_io;
|
||||
}
|
||||
DBGPR(" xgmac_regs = %p\n", pdata->xgmac_regs);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
pdata->xpcs_regs = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(pdata->xpcs_regs)) {
|
||||
dev_err(dev, "xpcs ioremap failed\n");
|
||||
ret = PTR_ERR(pdata->xpcs_regs);
|
||||
goto err_io;
|
||||
}
|
||||
DBGPR(" xpcs_regs = %p\n", pdata->xpcs_regs);
|
||||
|
||||
/* Set the DMA mask */
|
||||
if (!dev->dma_mask)
|
||||
dev->dma_mask = &dev->coherent_dma_mask;
|
||||
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
|
||||
if (ret) {
|
||||
dev_err(dev, "dma_set_mask_and_coherent failed\n");
|
||||
goto err_io;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(dev->of_node, "dma-coherent")) {
|
||||
pdata->axdomain = XGBE_DMA_OS_AXDOMAIN;
|
||||
pdata->arcache = XGBE_DMA_OS_ARCACHE;
|
||||
pdata->awcache = XGBE_DMA_OS_AWCACHE;
|
||||
} else {
|
||||
pdata->axdomain = XGBE_DMA_SYS_AXDOMAIN;
|
||||
pdata->arcache = XGBE_DMA_SYS_ARCACHE;
|
||||
pdata->awcache = XGBE_DMA_SYS_AWCACHE;
|
||||
}
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "platform_get_irq failed\n");
|
||||
goto err_io;
|
||||
}
|
||||
netdev->irq = ret;
|
||||
netdev->base_addr = (unsigned long)pdata->xgmac_regs;
|
||||
|
||||
/* Set all the function pointers */
|
||||
xgbe_init_all_fptrs(pdata);
|
||||
hw_if = &pdata->hw_if;
|
||||
desc_if = &pdata->desc_if;
|
||||
|
||||
/* Issue software reset to device */
|
||||
hw_if->exit(pdata);
|
||||
|
||||
/* Populate the hardware features */
|
||||
xgbe_get_all_hw_features(pdata);
|
||||
|
||||
/* Retrieve the MAC address */
|
||||
mac_addr = of_get_mac_address(dev->of_node);
|
||||
if (!mac_addr) {
|
||||
dev_err(dev, "invalid mac address for this device\n");
|
||||
ret = -EINVAL;
|
||||
goto err_io;
|
||||
}
|
||||
memcpy(netdev->dev_addr, mac_addr, netdev->addr_len);
|
||||
|
||||
/* Retrieve the PHY mode - it must be "xgmii" */
|
||||
pdata->phy_mode = of_get_phy_mode(dev->of_node);
|
||||
if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) {
|
||||
dev_err(dev, "invalid phy-mode specified for this device\n");
|
||||
ret = -EINVAL;
|
||||
goto err_io;
|
||||
}
|
||||
|
||||
/* Set default configuration data */
|
||||
xgbe_default_config(pdata);
|
||||
|
||||
/* Calculate the number of Tx and Rx rings to be created
|
||||
* -Tx (DMA) Channels map 1-to-1 to Tx Queues so set
|
||||
* the number of Tx queues to the number of Tx channels
|
||||
* enabled
|
||||
* -Rx (DMA) Channels do not map 1-to-1 so use the actual
|
||||
* number of Rx queues
|
||||
*/
|
||||
pdata->tx_ring_count = min_t(unsigned int, num_online_cpus(),
|
||||
pdata->hw_feat.tx_ch_cnt);
|
||||
pdata->tx_q_count = pdata->tx_ring_count;
|
||||
ret = netif_set_real_num_tx_queues(netdev, pdata->tx_ring_count);
|
||||
if (ret) {
|
||||
dev_err(dev, "error setting real tx queue count\n");
|
||||
goto err_io;
|
||||
}
|
||||
|
||||
pdata->rx_ring_count = min_t(unsigned int,
|
||||
netif_get_num_default_rss_queues(),
|
||||
pdata->hw_feat.rx_ch_cnt);
|
||||
pdata->rx_q_count = pdata->hw_feat.rx_q_cnt;
|
||||
ret = netif_set_real_num_rx_queues(netdev, pdata->rx_ring_count);
|
||||
if (ret) {
|
||||
dev_err(dev, "error setting real rx queue count\n");
|
||||
goto err_io;
|
||||
}
|
||||
|
||||
/* Allocate the rings for the DMA channels */
|
||||
pdata->channel = xgbe_alloc_rings(pdata);
|
||||
if (!pdata->channel) {
|
||||
dev_err(dev, "ring allocation failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_io;
|
||||
}
|
||||
|
||||
/* Prepare to regsiter with MDIO */
|
||||
pdata->mii_bus_id = kasprintf(GFP_KERNEL, "%s", pdev->name);
|
||||
if (!pdata->mii_bus_id) {
|
||||
dev_err(dev, "failed to allocate mii bus id\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_io;
|
||||
}
|
||||
ret = xgbe_mdio_register(pdata);
|
||||
if (ret)
|
||||
goto err_bus_id;
|
||||
|
||||
/* Set device operations */
|
||||
netdev->netdev_ops = xgbe_get_netdev_ops();
|
||||
netdev->ethtool_ops = xgbe_get_ethtool_ops();
|
||||
#ifdef CONFIG_AMD_XGBE_DCB
|
||||
netdev->dcbnl_ops = xgbe_get_dcbnl_ops();
|
||||
#endif
|
||||
|
||||
/* Set device features */
|
||||
netdev->hw_features = NETIF_F_SG |
|
||||
NETIF_F_IP_CSUM |
|
||||
NETIF_F_IPV6_CSUM |
|
||||
NETIF_F_RXCSUM |
|
||||
NETIF_F_TSO |
|
||||
NETIF_F_TSO6 |
|
||||
NETIF_F_GRO |
|
||||
NETIF_F_HW_VLAN_CTAG_RX |
|
||||
NETIF_F_HW_VLAN_CTAG_TX |
|
||||
NETIF_F_HW_VLAN_CTAG_FILTER;
|
||||
|
||||
netdev->vlan_features |= NETIF_F_SG |
|
||||
NETIF_F_IP_CSUM |
|
||||
NETIF_F_IPV6_CSUM |
|
||||
NETIF_F_TSO |
|
||||
NETIF_F_TSO6;
|
||||
|
||||
netdev->features |= netdev->hw_features;
|
||||
pdata->netdev_features = netdev->features;
|
||||
|
||||
netdev->priv_flags |= IFF_UNICAST_FLT;
|
||||
|
||||
xgbe_init_rx_coalesce(pdata);
|
||||
xgbe_init_tx_coalesce(pdata);
|
||||
|
||||
netif_carrier_off(netdev);
|
||||
ret = register_netdev(netdev);
|
||||
if (ret) {
|
||||
dev_err(dev, "net device registration failed\n");
|
||||
goto err_reg_netdev;
|
||||
}
|
||||
|
||||
xgbe_ptp_register(pdata);
|
||||
|
||||
xgbe_debugfs_init(pdata);
|
||||
|
||||
netdev_notice(netdev, "net device enabled\n");
|
||||
|
||||
DBGPR("<-- xgbe_probe\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_reg_netdev:
|
||||
xgbe_mdio_unregister(pdata);
|
||||
|
||||
err_bus_id:
|
||||
kfree(pdata->mii_bus_id);
|
||||
|
||||
err_io:
|
||||
free_netdev(netdev);
|
||||
|
||||
err_alloc:
|
||||
dev_notice(dev, "net device not enabled\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xgbe_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct net_device *netdev = platform_get_drvdata(pdev);
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
|
||||
DBGPR("-->xgbe_remove\n");
|
||||
|
||||
xgbe_debugfs_exit(pdata);
|
||||
|
||||
xgbe_ptp_unregister(pdata);
|
||||
|
||||
unregister_netdev(netdev);
|
||||
|
||||
xgbe_mdio_unregister(pdata);
|
||||
|
||||
kfree(pdata->mii_bus_id);
|
||||
|
||||
free_netdev(netdev);
|
||||
|
||||
DBGPR("<--xgbe_remove\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int xgbe_suspend(struct device *dev)
|
||||
{
|
||||
struct net_device *netdev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
DBGPR("-->xgbe_suspend\n");
|
||||
|
||||
if (!netif_running(netdev)) {
|
||||
DBGPR("<--xgbe_dev_suspend\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = xgbe_powerdown(netdev, XGMAC_DRIVER_CONTEXT);
|
||||
|
||||
DBGPR("<--xgbe_suspend\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xgbe_resume(struct device *dev)
|
||||
{
|
||||
struct net_device *netdev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
DBGPR("-->xgbe_resume\n");
|
||||
|
||||
if (!netif_running(netdev)) {
|
||||
DBGPR("<--xgbe_dev_resume\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = xgbe_powerup(netdev, XGMAC_DRIVER_CONTEXT);
|
||||
|
||||
DBGPR("<--xgbe_resume\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct of_device_id xgbe_of_match[] = {
|
||||
{ .compatible = "amd,xgbe-seattle-v1a", },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, xgbe_of_match);
|
||||
static SIMPLE_DEV_PM_OPS(xgbe_pm_ops, xgbe_suspend, xgbe_resume);
|
||||
|
||||
static struct platform_driver xgbe_driver = {
|
||||
.driver = {
|
||||
.name = "amd-xgbe",
|
||||
.of_match_table = xgbe_of_match,
|
||||
.pm = &xgbe_pm_ops,
|
||||
},
|
||||
.probe = xgbe_probe,
|
||||
.remove = xgbe_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(xgbe_driver);
|
325
drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
Normal file
325
drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
Normal file
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
* AMD 10Gb Ethernet driver
|
||||
*
|
||||
* This file is available to you under your choice of the following two
|
||||
* licenses:
|
||||
*
|
||||
* License 1: GPLv2
|
||||
*
|
||||
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This file is free software; you may copy, redistribute and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* The Synopsys DWC ETHER XGMAC Software Driver and documentation
|
||||
* (hereinafter "Software") is an unsupported proprietary work of Synopsys,
|
||||
* Inc. unless otherwise expressly agreed to in writing between Synopsys
|
||||
* and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for Licensed
|
||||
* Product with Synopsys or any supplement thereto. Permission is hereby
|
||||
* granted, free of charge, to any person obtaining a copy of this software
|
||||
* annotated with this license and the Software, to deal in the Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* License 2: Modified BSD
|
||||
*
|
||||
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Advanced Micro Devices, Inc. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* The Synopsys DWC ETHER XGMAC Software Driver and documentation
|
||||
* (hereinafter "Software") is an unsupported proprietary work of Synopsys,
|
||||
* Inc. unless otherwise expressly agreed to in writing between Synopsys
|
||||
* and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for Licensed
|
||||
* Product with Synopsys or any supplement thereto. Permission is hereby
|
||||
* granted, free of charge, to any person obtaining a copy of this software
|
||||
* annotated with this license and the Software, to deal in the Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include "xgbe.h"
|
||||
#include "xgbe-common.h"
|
||||
|
||||
static int xgbe_mdio_read(struct mii_bus *mii, int prtad, int mmd_reg)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = mii->priv;
|
||||
struct xgbe_hw_if *hw_if = &pdata->hw_if;
|
||||
int mmd_data;
|
||||
|
||||
DBGPR_MDIO("-->xgbe_mdio_read: prtad=%#x mmd_reg=%#x\n",
|
||||
prtad, mmd_reg);
|
||||
|
||||
mmd_data = hw_if->read_mmd_regs(pdata, prtad, mmd_reg);
|
||||
|
||||
DBGPR_MDIO("<--xgbe_mdio_read: mmd_data=%#x\n", mmd_data);
|
||||
|
||||
return mmd_data;
|
||||
}
|
||||
|
||||
static int xgbe_mdio_write(struct mii_bus *mii, int prtad, int mmd_reg,
|
||||
u16 mmd_val)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = mii->priv;
|
||||
struct xgbe_hw_if *hw_if = &pdata->hw_if;
|
||||
int mmd_data = mmd_val;
|
||||
|
||||
DBGPR_MDIO("-->xgbe_mdio_write: prtad=%#x mmd_reg=%#x mmd_data=%#x\n",
|
||||
prtad, mmd_reg, mmd_data);
|
||||
|
||||
hw_if->write_mmd_regs(pdata, prtad, mmd_reg, mmd_data);
|
||||
|
||||
DBGPR_MDIO("<--xgbe_mdio_write\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
struct device *dev = pdata->dev;
|
||||
struct phy_device *phydev = pdata->mii->phy_map[XGBE_PRTAD];
|
||||
int i;
|
||||
|
||||
dev_alert(dev, "\n************* PHY Reg dump **********************\n");
|
||||
|
||||
dev_alert(dev, "PCS Control Reg (%#04x) = %#04x\n", MDIO_CTRL1,
|
||||
XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1));
|
||||
dev_alert(dev, "PCS Status Reg (%#04x) = %#04x\n", MDIO_STAT1,
|
||||
XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1));
|
||||
dev_alert(dev, "Phy Id (PHYS ID 1 %#04x)= %#04x\n", MDIO_DEVID1,
|
||||
XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID1));
|
||||
dev_alert(dev, "Phy Id (PHYS ID 2 %#04x)= %#04x\n", MDIO_DEVID2,
|
||||
XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID2));
|
||||
dev_alert(dev, "Devices in Package (%#04x)= %#04x\n", MDIO_DEVS1,
|
||||
XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS1));
|
||||
dev_alert(dev, "Devices in Package (%#04x)= %#04x\n", MDIO_DEVS2,
|
||||
XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS2));
|
||||
|
||||
dev_alert(dev, "Auto-Neg Control Reg (%#04x) = %#04x\n", MDIO_CTRL1,
|
||||
XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1));
|
||||
dev_alert(dev, "Auto-Neg Status Reg (%#04x) = %#04x\n", MDIO_STAT1,
|
||||
XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_STAT1));
|
||||
dev_alert(dev, "Auto-Neg Ad Reg 1 (%#04x) = %#04x\n",
|
||||
MDIO_AN_ADVERTISE,
|
||||
XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE));
|
||||
dev_alert(dev, "Auto-Neg Ad Reg 2 (%#04x) = %#04x\n",
|
||||
MDIO_AN_ADVERTISE + 1,
|
||||
XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1));
|
||||
dev_alert(dev, "Auto-Neg Ad Reg 3 (%#04x) = %#04x\n",
|
||||
MDIO_AN_ADVERTISE + 2,
|
||||
XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2));
|
||||
dev_alert(dev, "Auto-Neg Completion Reg (%#04x) = %#04x\n",
|
||||
MDIO_AN_COMP_STAT,
|
||||
XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_COMP_STAT));
|
||||
|
||||
dev_alert(dev, "MMD Device Mask = %#x\n",
|
||||
phydev->c45_ids.devices_in_package);
|
||||
for (i = 0; i < ARRAY_SIZE(phydev->c45_ids.device_ids); i++)
|
||||
dev_alert(dev, " MMD %d: ID = %#08x\n", i,
|
||||
phydev->c45_ids.device_ids[i]);
|
||||
|
||||
dev_alert(dev, "\n*************************************************\n");
|
||||
}
|
||||
|
||||
int xgbe_mdio_register(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
struct device_node *phy_node;
|
||||
struct mii_bus *mii;
|
||||
struct phy_device *phydev;
|
||||
int ret = 0;
|
||||
|
||||
DBGPR("-->xgbe_mdio_register\n");
|
||||
|
||||
/* Retrieve the phy-handle */
|
||||
phy_node = of_parse_phandle(pdata->dev->of_node, "phy-handle", 0);
|
||||
if (!phy_node) {
|
||||
dev_err(pdata->dev, "unable to parse phy-handle\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mii = mdiobus_alloc();
|
||||
if (mii == NULL) {
|
||||
dev_err(pdata->dev, "mdiobus_alloc failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_node_get;
|
||||
}
|
||||
|
||||
/* Register on the MDIO bus (don't probe any PHYs) */
|
||||
mii->name = XGBE_PHY_NAME;
|
||||
mii->read = xgbe_mdio_read;
|
||||
mii->write = xgbe_mdio_write;
|
||||
snprintf(mii->id, sizeof(mii->id), "%s", pdata->mii_bus_id);
|
||||
mii->priv = pdata;
|
||||
mii->phy_mask = ~0;
|
||||
mii->parent = pdata->dev;
|
||||
ret = mdiobus_register(mii);
|
||||
if (ret) {
|
||||
dev_err(pdata->dev, "mdiobus_register failed\n");
|
||||
goto err_mdiobus_alloc;
|
||||
}
|
||||
DBGPR(" mdiobus_register succeeded for %s\n", pdata->mii_bus_id);
|
||||
|
||||
/* Probe the PCS using Clause 45 */
|
||||
phydev = get_phy_device(mii, XGBE_PRTAD, true);
|
||||
if (IS_ERR(phydev) || !phydev ||
|
||||
!phydev->c45_ids.device_ids[MDIO_MMD_PCS]) {
|
||||
dev_err(pdata->dev, "get_phy_device failed\n");
|
||||
ret = phydev ? PTR_ERR(phydev) : -ENOLINK;
|
||||
goto err_mdiobus_register;
|
||||
}
|
||||
request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT,
|
||||
MDIO_ID_ARGS(phydev->c45_ids.device_ids[MDIO_MMD_PCS]));
|
||||
|
||||
of_node_get(phy_node);
|
||||
phydev->dev.of_node = phy_node;
|
||||
ret = phy_device_register(phydev);
|
||||
if (ret) {
|
||||
dev_err(pdata->dev, "phy_device_register failed\n");
|
||||
of_node_put(phy_node);
|
||||
goto err_phy_device;
|
||||
}
|
||||
|
||||
/* Add a reference to the PHY driver so it can't be unloaded */
|
||||
pdata->phy_module = phydev->dev.driver ?
|
||||
phydev->dev.driver->owner : NULL;
|
||||
if (!try_module_get(pdata->phy_module)) {
|
||||
dev_err(pdata->dev, "try_module_get failed\n");
|
||||
ret = -EIO;
|
||||
goto err_phy_device;
|
||||
}
|
||||
|
||||
pdata->mii = mii;
|
||||
pdata->mdio_mmd = MDIO_MMD_PCS;
|
||||
|
||||
phydev->autoneg = pdata->default_autoneg;
|
||||
if (phydev->autoneg == AUTONEG_DISABLE) {
|
||||
phydev->speed = pdata->default_speed;
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
|
||||
phydev->advertising &= ~ADVERTISED_Autoneg;
|
||||
}
|
||||
|
||||
pdata->phydev = phydev;
|
||||
|
||||
of_node_put(phy_node);
|
||||
|
||||
DBGPHY_REGS(pdata);
|
||||
|
||||
DBGPR("<--xgbe_mdio_register\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_phy_device:
|
||||
phy_device_free(phydev);
|
||||
|
||||
err_mdiobus_register:
|
||||
mdiobus_unregister(mii);
|
||||
|
||||
err_mdiobus_alloc:
|
||||
mdiobus_free(mii);
|
||||
|
||||
err_node_get:
|
||||
of_node_put(phy_node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void xgbe_mdio_unregister(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
DBGPR("-->xgbe_mdio_unregister\n");
|
||||
|
||||
pdata->phydev = NULL;
|
||||
|
||||
module_put(pdata->phy_module);
|
||||
pdata->phy_module = NULL;
|
||||
|
||||
mdiobus_unregister(pdata->mii);
|
||||
pdata->mii->priv = NULL;
|
||||
|
||||
mdiobus_free(pdata->mii);
|
||||
pdata->mii = NULL;
|
||||
|
||||
DBGPR("<--xgbe_mdio_unregister\n");
|
||||
}
|
284
drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
Normal file
284
drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
Normal file
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* AMD 10Gb Ethernet driver
|
||||
*
|
||||
* This file is available to you under your choice of the following two
|
||||
* licenses:
|
||||
*
|
||||
* License 1: GPLv2
|
||||
*
|
||||
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This file is free software; you may copy, redistribute and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* The Synopsys DWC ETHER XGMAC Software Driver and documentation
|
||||
* (hereinafter "Software") is an unsupported proprietary work of Synopsys,
|
||||
* Inc. unless otherwise expressly agreed to in writing between Synopsys
|
||||
* and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for Licensed
|
||||
* Product with Synopsys or any supplement thereto. Permission is hereby
|
||||
* granted, free of charge, to any person obtaining a copy of this software
|
||||
* annotated with this license and the Software, to deal in the Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* License 2: Modified BSD
|
||||
*
|
||||
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Advanced Micro Devices, Inc. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* The Synopsys DWC ETHER XGMAC Software Driver and documentation
|
||||
* (hereinafter "Software") is an unsupported proprietary work of Synopsys,
|
||||
* Inc. unless otherwise expressly agreed to in writing between Synopsys
|
||||
* and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for Licensed
|
||||
* Product with Synopsys or any supplement thereto. Permission is hereby
|
||||
* granted, free of charge, to any person obtaining a copy of this software
|
||||
* annotated with this license and the Software, to deal in the Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
|
||||
#include "xgbe.h"
|
||||
#include "xgbe-common.h"
|
||||
|
||||
static cycle_t xgbe_cc_read(const struct cyclecounter *cc)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = container_of(cc,
|
||||
struct xgbe_prv_data,
|
||||
tstamp_cc);
|
||||
u64 nsec;
|
||||
|
||||
nsec = pdata->hw_if.get_tstamp_time(pdata);
|
||||
|
||||
return nsec;
|
||||
}
|
||||
|
||||
static int xgbe_adjfreq(struct ptp_clock_info *info, s32 delta)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = container_of(info,
|
||||
struct xgbe_prv_data,
|
||||
ptp_clock_info);
|
||||
unsigned long flags;
|
||||
u64 adjust;
|
||||
u32 addend, diff;
|
||||
unsigned int neg_adjust = 0;
|
||||
|
||||
if (delta < 0) {
|
||||
neg_adjust = 1;
|
||||
delta = -delta;
|
||||
}
|
||||
|
||||
adjust = pdata->tstamp_addend;
|
||||
adjust *= delta;
|
||||
diff = div_u64(adjust, 1000000000UL);
|
||||
|
||||
addend = (neg_adjust) ? pdata->tstamp_addend - diff :
|
||||
pdata->tstamp_addend + diff;
|
||||
|
||||
spin_lock_irqsave(&pdata->tstamp_lock, flags);
|
||||
|
||||
pdata->hw_if.update_tstamp_addend(pdata, addend);
|
||||
|
||||
spin_unlock_irqrestore(&pdata->tstamp_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xgbe_adjtime(struct ptp_clock_info *info, s64 delta)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = container_of(info,
|
||||
struct xgbe_prv_data,
|
||||
ptp_clock_info);
|
||||
unsigned long flags;
|
||||
u64 nsec;
|
||||
|
||||
spin_lock_irqsave(&pdata->tstamp_lock, flags);
|
||||
|
||||
nsec = timecounter_read(&pdata->tstamp_tc);
|
||||
|
||||
nsec += delta;
|
||||
timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, nsec);
|
||||
|
||||
spin_unlock_irqrestore(&pdata->tstamp_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xgbe_gettime(struct ptp_clock_info *info, struct timespec *ts)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = container_of(info,
|
||||
struct xgbe_prv_data,
|
||||
ptp_clock_info);
|
||||
unsigned long flags;
|
||||
u64 nsec;
|
||||
|
||||
spin_lock_irqsave(&pdata->tstamp_lock, flags);
|
||||
|
||||
nsec = timecounter_read(&pdata->tstamp_tc);
|
||||
|
||||
spin_unlock_irqrestore(&pdata->tstamp_lock, flags);
|
||||
|
||||
*ts = ns_to_timespec(nsec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xgbe_settime(struct ptp_clock_info *info, const struct timespec *ts)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = container_of(info,
|
||||
struct xgbe_prv_data,
|
||||
ptp_clock_info);
|
||||
unsigned long flags;
|
||||
u64 nsec;
|
||||
|
||||
nsec = timespec_to_ns(ts);
|
||||
|
||||
spin_lock_irqsave(&pdata->tstamp_lock, flags);
|
||||
|
||||
timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, nsec);
|
||||
|
||||
spin_unlock_irqrestore(&pdata->tstamp_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xgbe_enable(struct ptp_clock_info *info,
|
||||
struct ptp_clock_request *request, int on)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
void xgbe_ptp_register(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
struct ptp_clock_info *info = &pdata->ptp_clock_info;
|
||||
struct ptp_clock *clock;
|
||||
struct cyclecounter *cc = &pdata->tstamp_cc;
|
||||
u64 dividend;
|
||||
|
||||
snprintf(info->name, sizeof(info->name), "%s",
|
||||
netdev_name(pdata->netdev));
|
||||
info->owner = THIS_MODULE;
|
||||
info->max_adj = clk_get_rate(pdata->ptpclk);
|
||||
info->adjfreq = xgbe_adjfreq;
|
||||
info->adjtime = xgbe_adjtime;
|
||||
info->gettime = xgbe_gettime;
|
||||
info->settime = xgbe_settime;
|
||||
info->enable = xgbe_enable;
|
||||
|
||||
clock = ptp_clock_register(info, pdata->dev);
|
||||
if (IS_ERR(clock)) {
|
||||
dev_err(pdata->dev, "ptp_clock_register failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pdata->ptp_clock = clock;
|
||||
|
||||
/* Calculate the addend:
|
||||
* addend = 2^32 / (PTP ref clock / 50Mhz)
|
||||
* = (2^32 * 50Mhz) / PTP ref clock
|
||||
*/
|
||||
dividend = 50000000;
|
||||
dividend <<= 32;
|
||||
pdata->tstamp_addend = div_u64(dividend, clk_get_rate(pdata->ptpclk));
|
||||
|
||||
/* Setup the timecounter */
|
||||
cc->read = xgbe_cc_read;
|
||||
cc->mask = CLOCKSOURCE_MASK(64);
|
||||
cc->mult = 1;
|
||||
cc->shift = 0;
|
||||
|
||||
timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc,
|
||||
ktime_to_ns(ktime_get_real()));
|
||||
|
||||
/* Disable all timestamping to start */
|
||||
XGMAC_IOWRITE(pdata, MAC_TCR, 0);
|
||||
pdata->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
|
||||
pdata->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
|
||||
}
|
||||
|
||||
void xgbe_ptp_unregister(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
if (pdata->ptp_clock)
|
||||
ptp_clock_unregister(pdata->ptp_clock);
|
||||
}
|
767
drivers/net/ethernet/amd/xgbe/xgbe.h
Normal file
767
drivers/net/ethernet/amd/xgbe/xgbe.h
Normal file
|
@ -0,0 +1,767 @@
|
|||
/*
|
||||
* AMD 10Gb Ethernet driver
|
||||
*
|
||||
* This file is available to you under your choice of the following two
|
||||
* licenses:
|
||||
*
|
||||
* License 1: GPLv2
|
||||
*
|
||||
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This file is free software; you may copy, redistribute and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* The Synopsys DWC ETHER XGMAC Software Driver and documentation
|
||||
* (hereinafter "Software") is an unsupported proprietary work of Synopsys,
|
||||
* Inc. unless otherwise expressly agreed to in writing between Synopsys
|
||||
* and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for Licensed
|
||||
* Product with Synopsys or any supplement thereto. Permission is hereby
|
||||
* granted, free of charge, to any person obtaining a copy of this software
|
||||
* annotated with this license and the Software, to deal in the Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* License 2: Modified BSD
|
||||
*
|
||||
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Advanced Micro Devices, Inc. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
* The Synopsys DWC ETHER XGMAC Software Driver and documentation
|
||||
* (hereinafter "Software") is an unsupported proprietary work of Synopsys,
|
||||
* Inc. unless otherwise expressly agreed to in writing between Synopsys
|
||||
* and you.
|
||||
*
|
||||
* The Software IS NOT an item of Licensed Software or Licensed Product
|
||||
* under any End User Software License Agreement or Agreement for Licensed
|
||||
* Product with Synopsys or any supplement thereto. Permission is hereby
|
||||
* granted, free of charge, to any person obtaining a copy of this software
|
||||
* annotated with this license and the Software, to deal in the Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
||||
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __XGBE_H__
|
||||
#define __XGBE_H__
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <net/dcbnl.h>
|
||||
|
||||
#define XGBE_DRV_NAME "amd-xgbe"
|
||||
#define XGBE_DRV_VERSION "1.0.0-a"
|
||||
#define XGBE_DRV_DESC "AMD 10 Gigabit Ethernet Driver"
|
||||
|
||||
/* Descriptor related defines */
|
||||
#define XGBE_TX_DESC_CNT 512
|
||||
#define XGBE_TX_DESC_MIN_FREE (XGBE_TX_DESC_CNT >> 3)
|
||||
#define XGBE_TX_DESC_MAX_PROC (XGBE_TX_DESC_CNT >> 1)
|
||||
#define XGBE_RX_DESC_CNT 512
|
||||
|
||||
#define XGBE_TX_MAX_BUF_SIZE (0x3fff & ~(64 - 1))
|
||||
|
||||
#define XGBE_RX_MIN_BUF_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN)
|
||||
#define XGBE_RX_BUF_ALIGN 64
|
||||
|
||||
#define XGBE_MAX_DMA_CHANNELS 16
|
||||
#define XGBE_MAX_QUEUES 16
|
||||
|
||||
/* DMA cache settings - Outer sharable, write-back, write-allocate */
|
||||
#define XGBE_DMA_OS_AXDOMAIN 0x2
|
||||
#define XGBE_DMA_OS_ARCACHE 0xb
|
||||
#define XGBE_DMA_OS_AWCACHE 0xf
|
||||
|
||||
/* DMA cache settings - System, no caches used */
|
||||
#define XGBE_DMA_SYS_AXDOMAIN 0x3
|
||||
#define XGBE_DMA_SYS_ARCACHE 0x0
|
||||
#define XGBE_DMA_SYS_AWCACHE 0x0
|
||||
|
||||
#define XGBE_DMA_INTERRUPT_MASK 0x31c7
|
||||
|
||||
#define XGMAC_MIN_PACKET 60
|
||||
#define XGMAC_STD_PACKET_MTU 1500
|
||||
#define XGMAC_MAX_STD_PACKET 1518
|
||||
#define XGMAC_JUMBO_PACKET_MTU 9000
|
||||
#define XGMAC_MAX_JUMBO_PACKET 9018
|
||||
|
||||
/* MDIO bus phy name */
|
||||
#define XGBE_PHY_NAME "amd_xgbe_phy"
|
||||
#define XGBE_PRTAD 0
|
||||
|
||||
/* Device-tree clock names */
|
||||
#define XGBE_DMA_CLOCK "dma_clk"
|
||||
#define XGBE_PTP_CLOCK "ptp_clk"
|
||||
|
||||
/* Timestamp support - values based on 50MHz PTP clock
|
||||
* 50MHz => 20 nsec
|
||||
*/
|
||||
#define XGBE_TSTAMP_SSINC 20
|
||||
#define XGBE_TSTAMP_SNSINC 0
|
||||
|
||||
/* Driver PMT macros */
|
||||
#define XGMAC_DRIVER_CONTEXT 1
|
||||
#define XGMAC_IOCTL_CONTEXT 2
|
||||
|
||||
#define XGBE_FIFO_MAX 81920
|
||||
#define XGBE_FIFO_SIZE_B(x) (x)
|
||||
#define XGBE_FIFO_SIZE_KB(x) (x * 1024)
|
||||
|
||||
#define XGBE_TC_MIN_QUANTUM 10
|
||||
|
||||
/* Helper macro for descriptor handling
|
||||
* Always use XGBE_GET_DESC_DATA to access the descriptor data
|
||||
* since the index is free-running and needs to be and-ed
|
||||
* with the descriptor count value of the ring to index to
|
||||
* the proper descriptor data.
|
||||
*/
|
||||
#define XGBE_GET_DESC_DATA(_ring, _idx) \
|
||||
((_ring)->rdata + \
|
||||
((_idx) & ((_ring)->rdesc_count - 1)))
|
||||
|
||||
/* Default coalescing parameters */
|
||||
#define XGMAC_INIT_DMA_TX_USECS 50
|
||||
#define XGMAC_INIT_DMA_TX_FRAMES 25
|
||||
|
||||
#define XGMAC_MAX_DMA_RIWT 0xff
|
||||
#define XGMAC_INIT_DMA_RX_USECS 30
|
||||
#define XGMAC_INIT_DMA_RX_FRAMES 25
|
||||
|
||||
/* Flow control queue count */
|
||||
#define XGMAC_MAX_FLOW_CONTROL_QUEUES 8
|
||||
|
||||
/* Maximum MAC address hash table size (256 bits = 8 bytes) */
|
||||
#define XGBE_MAC_HASH_TABLE_SIZE 8
|
||||
|
||||
struct xgbe_prv_data;
|
||||
|
||||
struct xgbe_packet_data {
|
||||
unsigned int attributes;
|
||||
|
||||
unsigned int errors;
|
||||
|
||||
unsigned int rdesc_count;
|
||||
unsigned int length;
|
||||
|
||||
unsigned int header_len;
|
||||
unsigned int tcp_header_len;
|
||||
unsigned int tcp_payload_len;
|
||||
unsigned short mss;
|
||||
|
||||
unsigned short vlan_ctag;
|
||||
|
||||
u64 rx_tstamp;
|
||||
};
|
||||
|
||||
/* Common Rx and Tx descriptor mapping */
|
||||
struct xgbe_ring_desc {
|
||||
unsigned int desc0;
|
||||
unsigned int desc1;
|
||||
unsigned int desc2;
|
||||
unsigned int desc3;
|
||||
};
|
||||
|
||||
/* Structure used to hold information related to the descriptor
|
||||
* and the packet associated with the descriptor (always use
|
||||
* use the XGBE_GET_DESC_DATA macro to access this data from the ring)
|
||||
*/
|
||||
struct xgbe_ring_data {
|
||||
struct xgbe_ring_desc *rdesc; /* Virtual address of descriptor */
|
||||
dma_addr_t rdesc_dma; /* DMA address of descriptor */
|
||||
|
||||
struct sk_buff *skb; /* Virtual address of SKB */
|
||||
dma_addr_t skb_dma; /* DMA address of SKB data */
|
||||
unsigned int skb_dma_len; /* Length of SKB DMA area */
|
||||
unsigned int tso_header; /* TSO header indicator */
|
||||
|
||||
unsigned short len; /* Length of received Rx packet */
|
||||
|
||||
unsigned int interrupt; /* Interrupt indicator */
|
||||
|
||||
unsigned int mapped_as_page;
|
||||
|
||||
/* Incomplete receive save location. If the budget is exhausted
|
||||
* or the last descriptor (last normal descriptor or a following
|
||||
* context descriptor) has not been DMA'd yet the current state
|
||||
* of the receive processing needs to be saved.
|
||||
*/
|
||||
unsigned int state_saved;
|
||||
struct {
|
||||
unsigned int incomplete;
|
||||
unsigned int context_next;
|
||||
struct sk_buff *skb;
|
||||
unsigned int len;
|
||||
unsigned int error;
|
||||
} state;
|
||||
};
|
||||
|
||||
struct xgbe_ring {
|
||||
/* Ring lock - used just for TX rings at the moment */
|
||||
spinlock_t lock;
|
||||
|
||||
/* Per packet related information */
|
||||
struct xgbe_packet_data packet_data;
|
||||
|
||||
/* Virtual/DMA addresses and count of allocated descriptor memory */
|
||||
struct xgbe_ring_desc *rdesc;
|
||||
dma_addr_t rdesc_dma;
|
||||
unsigned int rdesc_count;
|
||||
|
||||
/* Array of descriptor data corresponding the descriptor memory
|
||||
* (always use the XGBE_GET_DESC_DATA macro to access this data)
|
||||
*/
|
||||
struct xgbe_ring_data *rdata;
|
||||
|
||||
/* Ring index values
|
||||
* cur - Tx: index of descriptor to be used for current transfer
|
||||
* Rx: index of descriptor to check for packet availability
|
||||
* dirty - Tx: index of descriptor to check for transfer complete
|
||||
* Rx: count of descriptors in which a packet has been received
|
||||
* (used with skb_realloc_index to refresh the ring)
|
||||
*/
|
||||
unsigned int cur;
|
||||
unsigned int dirty;
|
||||
|
||||
/* Coalesce frame count used for interrupt bit setting */
|
||||
unsigned int coalesce_count;
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned int queue_stopped;
|
||||
unsigned short cur_mss;
|
||||
unsigned short cur_vlan_ctag;
|
||||
} tx;
|
||||
|
||||
struct {
|
||||
unsigned int realloc_index;
|
||||
unsigned int realloc_threshold;
|
||||
} rx;
|
||||
};
|
||||
} ____cacheline_aligned;
|
||||
|
||||
/* Structure used to describe the descriptor rings associated with
|
||||
* a DMA channel.
|
||||
*/
|
||||
struct xgbe_channel {
|
||||
char name[16];
|
||||
|
||||
/* Address of private data area for device */
|
||||
struct xgbe_prv_data *pdata;
|
||||
|
||||
/* Queue index and base address of queue's DMA registers */
|
||||
unsigned int queue_index;
|
||||
void __iomem *dma_regs;
|
||||
|
||||
unsigned int saved_ier;
|
||||
|
||||
unsigned int tx_timer_active;
|
||||
struct hrtimer tx_timer;
|
||||
|
||||
struct xgbe_ring *tx_ring;
|
||||
struct xgbe_ring *rx_ring;
|
||||
} ____cacheline_aligned;
|
||||
|
||||
enum xgbe_int {
|
||||
XGMAC_INT_DMA_CH_SR_TI,
|
||||
XGMAC_INT_DMA_CH_SR_TPS,
|
||||
XGMAC_INT_DMA_CH_SR_TBU,
|
||||
XGMAC_INT_DMA_CH_SR_RI,
|
||||
XGMAC_INT_DMA_CH_SR_RBU,
|
||||
XGMAC_INT_DMA_CH_SR_RPS,
|
||||
XGMAC_INT_DMA_CH_SR_TI_RI,
|
||||
XGMAC_INT_DMA_CH_SR_FBE,
|
||||
XGMAC_INT_DMA_ALL,
|
||||
};
|
||||
|
||||
enum xgbe_int_state {
|
||||
XGMAC_INT_STATE_SAVE,
|
||||
XGMAC_INT_STATE_RESTORE,
|
||||
};
|
||||
|
||||
enum xgbe_mtl_fifo_size {
|
||||
XGMAC_MTL_FIFO_SIZE_256 = 0x00,
|
||||
XGMAC_MTL_FIFO_SIZE_512 = 0x01,
|
||||
XGMAC_MTL_FIFO_SIZE_1K = 0x03,
|
||||
XGMAC_MTL_FIFO_SIZE_2K = 0x07,
|
||||
XGMAC_MTL_FIFO_SIZE_4K = 0x0f,
|
||||
XGMAC_MTL_FIFO_SIZE_8K = 0x1f,
|
||||
XGMAC_MTL_FIFO_SIZE_16K = 0x3f,
|
||||
XGMAC_MTL_FIFO_SIZE_32K = 0x7f,
|
||||
XGMAC_MTL_FIFO_SIZE_64K = 0xff,
|
||||
XGMAC_MTL_FIFO_SIZE_128K = 0x1ff,
|
||||
XGMAC_MTL_FIFO_SIZE_256K = 0x3ff,
|
||||
};
|
||||
|
||||
struct xgbe_mmc_stats {
|
||||
/* Tx Stats */
|
||||
u64 txoctetcount_gb;
|
||||
u64 txframecount_gb;
|
||||
u64 txbroadcastframes_g;
|
||||
u64 txmulticastframes_g;
|
||||
u64 tx64octets_gb;
|
||||
u64 tx65to127octets_gb;
|
||||
u64 tx128to255octets_gb;
|
||||
u64 tx256to511octets_gb;
|
||||
u64 tx512to1023octets_gb;
|
||||
u64 tx1024tomaxoctets_gb;
|
||||
u64 txunicastframes_gb;
|
||||
u64 txmulticastframes_gb;
|
||||
u64 txbroadcastframes_gb;
|
||||
u64 txunderflowerror;
|
||||
u64 txoctetcount_g;
|
||||
u64 txframecount_g;
|
||||
u64 txpauseframes;
|
||||
u64 txvlanframes_g;
|
||||
|
||||
/* Rx Stats */
|
||||
u64 rxframecount_gb;
|
||||
u64 rxoctetcount_gb;
|
||||
u64 rxoctetcount_g;
|
||||
u64 rxbroadcastframes_g;
|
||||
u64 rxmulticastframes_g;
|
||||
u64 rxcrcerror;
|
||||
u64 rxrunterror;
|
||||
u64 rxjabbererror;
|
||||
u64 rxundersize_g;
|
||||
u64 rxoversize_g;
|
||||
u64 rx64octets_gb;
|
||||
u64 rx65to127octets_gb;
|
||||
u64 rx128to255octets_gb;
|
||||
u64 rx256to511octets_gb;
|
||||
u64 rx512to1023octets_gb;
|
||||
u64 rx1024tomaxoctets_gb;
|
||||
u64 rxunicastframes_g;
|
||||
u64 rxlengtherror;
|
||||
u64 rxoutofrangetype;
|
||||
u64 rxpauseframes;
|
||||
u64 rxfifooverflow;
|
||||
u64 rxvlanframes_gb;
|
||||
u64 rxwatchdogerror;
|
||||
};
|
||||
|
||||
struct xgbe_hw_if {
|
||||
int (*tx_complete)(struct xgbe_ring_desc *);
|
||||
|
||||
int (*set_promiscuous_mode)(struct xgbe_prv_data *, unsigned int);
|
||||
int (*set_all_multicast_mode)(struct xgbe_prv_data *, unsigned int);
|
||||
int (*add_mac_addresses)(struct xgbe_prv_data *);
|
||||
int (*set_mac_address)(struct xgbe_prv_data *, u8 *addr);
|
||||
|
||||
int (*enable_rx_csum)(struct xgbe_prv_data *);
|
||||
int (*disable_rx_csum)(struct xgbe_prv_data *);
|
||||
|
||||
int (*enable_rx_vlan_stripping)(struct xgbe_prv_data *);
|
||||
int (*disable_rx_vlan_stripping)(struct xgbe_prv_data *);
|
||||
int (*enable_rx_vlan_filtering)(struct xgbe_prv_data *);
|
||||
int (*disable_rx_vlan_filtering)(struct xgbe_prv_data *);
|
||||
int (*update_vlan_hash_table)(struct xgbe_prv_data *);
|
||||
|
||||
int (*read_mmd_regs)(struct xgbe_prv_data *, int, int);
|
||||
void (*write_mmd_regs)(struct xgbe_prv_data *, int, int, int);
|
||||
int (*set_gmii_speed)(struct xgbe_prv_data *);
|
||||
int (*set_gmii_2500_speed)(struct xgbe_prv_data *);
|
||||
int (*set_xgmii_speed)(struct xgbe_prv_data *);
|
||||
|
||||
void (*enable_tx)(struct xgbe_prv_data *);
|
||||
void (*disable_tx)(struct xgbe_prv_data *);
|
||||
void (*enable_rx)(struct xgbe_prv_data *);
|
||||
void (*disable_rx)(struct xgbe_prv_data *);
|
||||
|
||||
void (*powerup_tx)(struct xgbe_prv_data *);
|
||||
void (*powerdown_tx)(struct xgbe_prv_data *);
|
||||
void (*powerup_rx)(struct xgbe_prv_data *);
|
||||
void (*powerdown_rx)(struct xgbe_prv_data *);
|
||||
|
||||
int (*init)(struct xgbe_prv_data *);
|
||||
int (*exit)(struct xgbe_prv_data *);
|
||||
|
||||
int (*enable_int)(struct xgbe_channel *, enum xgbe_int);
|
||||
int (*disable_int)(struct xgbe_channel *, enum xgbe_int);
|
||||
void (*pre_xmit)(struct xgbe_channel *);
|
||||
int (*dev_read)(struct xgbe_channel *);
|
||||
void (*tx_desc_init)(struct xgbe_channel *);
|
||||
void (*rx_desc_init)(struct xgbe_channel *);
|
||||
void (*rx_desc_reset)(struct xgbe_ring_data *);
|
||||
void (*tx_desc_reset)(struct xgbe_ring_data *);
|
||||
int (*is_last_desc)(struct xgbe_ring_desc *);
|
||||
int (*is_context_desc)(struct xgbe_ring_desc *);
|
||||
|
||||
/* For FLOW ctrl */
|
||||
int (*config_tx_flow_control)(struct xgbe_prv_data *);
|
||||
int (*config_rx_flow_control)(struct xgbe_prv_data *);
|
||||
|
||||
/* For RX coalescing */
|
||||
int (*config_rx_coalesce)(struct xgbe_prv_data *);
|
||||
int (*config_tx_coalesce)(struct xgbe_prv_data *);
|
||||
unsigned int (*usec_to_riwt)(struct xgbe_prv_data *, unsigned int);
|
||||
unsigned int (*riwt_to_usec)(struct xgbe_prv_data *, unsigned int);
|
||||
|
||||
/* For RX and TX threshold config */
|
||||
int (*config_rx_threshold)(struct xgbe_prv_data *, unsigned int);
|
||||
int (*config_tx_threshold)(struct xgbe_prv_data *, unsigned int);
|
||||
|
||||
/* For RX and TX Store and Forward Mode config */
|
||||
int (*config_rsf_mode)(struct xgbe_prv_data *, unsigned int);
|
||||
int (*config_tsf_mode)(struct xgbe_prv_data *, unsigned int);
|
||||
|
||||
/* For TX DMA Operate on Second Frame config */
|
||||
int (*config_osp_mode)(struct xgbe_prv_data *);
|
||||
|
||||
/* For RX and TX PBL config */
|
||||
int (*config_rx_pbl_val)(struct xgbe_prv_data *);
|
||||
int (*get_rx_pbl_val)(struct xgbe_prv_data *);
|
||||
int (*config_tx_pbl_val)(struct xgbe_prv_data *);
|
||||
int (*get_tx_pbl_val)(struct xgbe_prv_data *);
|
||||
int (*config_pblx8)(struct xgbe_prv_data *);
|
||||
|
||||
/* For MMC statistics */
|
||||
void (*rx_mmc_int)(struct xgbe_prv_data *);
|
||||
void (*tx_mmc_int)(struct xgbe_prv_data *);
|
||||
void (*read_mmc_stats)(struct xgbe_prv_data *);
|
||||
|
||||
/* For Timestamp config */
|
||||
int (*config_tstamp)(struct xgbe_prv_data *, unsigned int);
|
||||
void (*update_tstamp_addend)(struct xgbe_prv_data *, unsigned int);
|
||||
void (*set_tstamp_time)(struct xgbe_prv_data *, unsigned int sec,
|
||||
unsigned int nsec);
|
||||
u64 (*get_tstamp_time)(struct xgbe_prv_data *);
|
||||
u64 (*get_tx_tstamp)(struct xgbe_prv_data *);
|
||||
|
||||
/* For Data Center Bridging config */
|
||||
void (*config_dcb_tc)(struct xgbe_prv_data *);
|
||||
void (*config_dcb_pfc)(struct xgbe_prv_data *);
|
||||
};
|
||||
|
||||
struct xgbe_desc_if {
|
||||
int (*alloc_ring_resources)(struct xgbe_prv_data *);
|
||||
void (*free_ring_resources)(struct xgbe_prv_data *);
|
||||
int (*map_tx_skb)(struct xgbe_channel *, struct sk_buff *);
|
||||
void (*realloc_skb)(struct xgbe_channel *);
|
||||
void (*unmap_skb)(struct xgbe_prv_data *, struct xgbe_ring_data *);
|
||||
void (*wrapper_tx_desc_init)(struct xgbe_prv_data *);
|
||||
void (*wrapper_rx_desc_init)(struct xgbe_prv_data *);
|
||||
};
|
||||
|
||||
/* This structure contains flags that indicate what hardware features
|
||||
* or configurations are present in the device.
|
||||
*/
|
||||
struct xgbe_hw_features {
|
||||
/* HW Version */
|
||||
unsigned int version;
|
||||
|
||||
/* HW Feature Register0 */
|
||||
unsigned int gmii; /* 1000 Mbps support */
|
||||
unsigned int vlhash; /* VLAN Hash Filter */
|
||||
unsigned int sma; /* SMA(MDIO) Interface */
|
||||
unsigned int rwk; /* PMT remote wake-up packet */
|
||||
unsigned int mgk; /* PMT magic packet */
|
||||
unsigned int mmc; /* RMON module */
|
||||
unsigned int aoe; /* ARP Offload */
|
||||
unsigned int ts; /* IEEE 1588-2008 Adavanced Timestamp */
|
||||
unsigned int eee; /* Energy Efficient Ethernet */
|
||||
unsigned int tx_coe; /* Tx Checksum Offload */
|
||||
unsigned int rx_coe; /* Rx Checksum Offload */
|
||||
unsigned int addn_mac; /* Additional MAC Addresses */
|
||||
unsigned int ts_src; /* Timestamp Source */
|
||||
unsigned int sa_vlan_ins; /* Source Address or VLAN Insertion */
|
||||
|
||||
/* HW Feature Register1 */
|
||||
unsigned int rx_fifo_size; /* MTL Receive FIFO Size */
|
||||
unsigned int tx_fifo_size; /* MTL Transmit FIFO Size */
|
||||
unsigned int adv_ts_hi; /* Advance Timestamping High Word */
|
||||
unsigned int dcb; /* DCB Feature */
|
||||
unsigned int sph; /* Split Header Feature */
|
||||
unsigned int tso; /* TCP Segmentation Offload */
|
||||
unsigned int dma_debug; /* DMA Debug Registers */
|
||||
unsigned int rss; /* Receive Side Scaling */
|
||||
unsigned int tc_cnt; /* Number of Traffic Classes */
|
||||
unsigned int hash_table_size; /* Hash Table Size */
|
||||
unsigned int l3l4_filter_num; /* Number of L3-L4 Filters */
|
||||
|
||||
/* HW Feature Register2 */
|
||||
unsigned int rx_q_cnt; /* Number of MTL Receive Queues */
|
||||
unsigned int tx_q_cnt; /* Number of MTL Transmit Queues */
|
||||
unsigned int rx_ch_cnt; /* Number of DMA Receive Channels */
|
||||
unsigned int tx_ch_cnt; /* Number of DMA Transmit Channels */
|
||||
unsigned int pps_out_num; /* Number of PPS outputs */
|
||||
unsigned int aux_snap_num; /* Number of Aux snapshot inputs */
|
||||
};
|
||||
|
||||
struct xgbe_prv_data {
|
||||
struct net_device *netdev;
|
||||
struct platform_device *pdev;
|
||||
struct device *dev;
|
||||
|
||||
/* XGMAC/XPCS related mmio registers */
|
||||
void __iomem *xgmac_regs; /* XGMAC CSRs */
|
||||
void __iomem *xpcs_regs; /* XPCS MMD registers */
|
||||
|
||||
/* Overall device lock */
|
||||
spinlock_t lock;
|
||||
|
||||
/* XPCS indirect addressing mutex */
|
||||
struct mutex xpcs_mutex;
|
||||
|
||||
int irq_number;
|
||||
|
||||
struct xgbe_hw_if hw_if;
|
||||
struct xgbe_desc_if desc_if;
|
||||
|
||||
/* AXI DMA settings */
|
||||
unsigned int axdomain;
|
||||
unsigned int arcache;
|
||||
unsigned int awcache;
|
||||
|
||||
/* Rings for Tx/Rx on a DMA channel */
|
||||
struct xgbe_channel *channel;
|
||||
unsigned int channel_count;
|
||||
unsigned int tx_ring_count;
|
||||
unsigned int tx_desc_count;
|
||||
unsigned int rx_ring_count;
|
||||
unsigned int rx_desc_count;
|
||||
|
||||
unsigned int tx_q_count;
|
||||
unsigned int rx_q_count;
|
||||
|
||||
/* Tx/Rx common settings */
|
||||
unsigned int pblx8;
|
||||
|
||||
/* Tx settings */
|
||||
unsigned int tx_sf_mode;
|
||||
unsigned int tx_threshold;
|
||||
unsigned int tx_pbl;
|
||||
unsigned int tx_osp_mode;
|
||||
|
||||
/* Rx settings */
|
||||
unsigned int rx_sf_mode;
|
||||
unsigned int rx_threshold;
|
||||
unsigned int rx_pbl;
|
||||
|
||||
/* Tx coalescing settings */
|
||||
unsigned int tx_usecs;
|
||||
unsigned int tx_frames;
|
||||
|
||||
/* Rx coalescing settings */
|
||||
unsigned int rx_riwt;
|
||||
unsigned int rx_frames;
|
||||
|
||||
/* Current MTU */
|
||||
unsigned int rx_buf_size;
|
||||
|
||||
/* Flow control settings */
|
||||
unsigned int pause_autoneg;
|
||||
unsigned int tx_pause;
|
||||
unsigned int rx_pause;
|
||||
|
||||
/* MDIO settings */
|
||||
struct module *phy_module;
|
||||
char *mii_bus_id;
|
||||
struct mii_bus *mii;
|
||||
int mdio_mmd;
|
||||
struct phy_device *phydev;
|
||||
int default_autoneg;
|
||||
int default_speed;
|
||||
|
||||
/* Current PHY settings */
|
||||
phy_interface_t phy_mode;
|
||||
int phy_link;
|
||||
int phy_speed;
|
||||
unsigned int phy_tx_pause;
|
||||
unsigned int phy_rx_pause;
|
||||
|
||||
/* Netdev related settings */
|
||||
netdev_features_t netdev_features;
|
||||
struct napi_struct napi;
|
||||
struct xgbe_mmc_stats mmc_stats;
|
||||
|
||||
/* Filtering support */
|
||||
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
|
||||
|
||||
/* Device clocks */
|
||||
struct clk *sysclk;
|
||||
struct clk *ptpclk;
|
||||
|
||||
/* Timestamp support */
|
||||
spinlock_t tstamp_lock;
|
||||
struct ptp_clock_info ptp_clock_info;
|
||||
struct ptp_clock *ptp_clock;
|
||||
struct hwtstamp_config tstamp_config;
|
||||
struct cyclecounter tstamp_cc;
|
||||
struct timecounter tstamp_tc;
|
||||
unsigned int tstamp_addend;
|
||||
struct work_struct tx_tstamp_work;
|
||||
struct sk_buff *tx_tstamp_skb;
|
||||
u64 tx_tstamp;
|
||||
|
||||
/* DCB support */
|
||||
struct ieee_ets *ets;
|
||||
struct ieee_pfc *pfc;
|
||||
unsigned int q2tc_map[XGBE_MAX_QUEUES];
|
||||
unsigned int prio2q_map[IEEE_8021QAZ_MAX_TCS];
|
||||
|
||||
/* Hardware features of the device */
|
||||
struct xgbe_hw_features hw_feat;
|
||||
|
||||
/* Device restart work structure */
|
||||
struct work_struct restart_work;
|
||||
|
||||
/* Keeps track of power mode */
|
||||
unsigned int power_down;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *xgbe_debugfs;
|
||||
|
||||
unsigned int debugfs_xgmac_reg;
|
||||
|
||||
unsigned int debugfs_xpcs_mmd;
|
||||
unsigned int debugfs_xpcs_reg;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Function prototypes*/
|
||||
|
||||
void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *);
|
||||
void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *);
|
||||
struct net_device_ops *xgbe_get_netdev_ops(void);
|
||||
struct ethtool_ops *xgbe_get_ethtool_ops(void);
|
||||
#ifdef CONFIG_AMD_XGBE_DCB
|
||||
const struct dcbnl_rtnl_ops *xgbe_get_dcbnl_ops(void);
|
||||
#endif
|
||||
|
||||
int xgbe_mdio_register(struct xgbe_prv_data *);
|
||||
void xgbe_mdio_unregister(struct xgbe_prv_data *);
|
||||
void xgbe_dump_phy_registers(struct xgbe_prv_data *);
|
||||
void xgbe_ptp_register(struct xgbe_prv_data *);
|
||||
void xgbe_ptp_unregister(struct xgbe_prv_data *);
|
||||
void xgbe_dump_tx_desc(struct xgbe_ring *, unsigned int, unsigned int,
|
||||
unsigned int);
|
||||
void xgbe_dump_rx_desc(struct xgbe_ring *, struct xgbe_ring_desc *,
|
||||
unsigned int);
|
||||
void xgbe_print_pkt(struct net_device *, struct sk_buff *, bool);
|
||||
void xgbe_get_all_hw_features(struct xgbe_prv_data *);
|
||||
int xgbe_powerup(struct net_device *, unsigned int);
|
||||
int xgbe_powerdown(struct net_device *, unsigned int);
|
||||
void xgbe_init_rx_coalesce(struct xgbe_prv_data *);
|
||||
void xgbe_init_tx_coalesce(struct xgbe_prv_data *);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void xgbe_debugfs_init(struct xgbe_prv_data *);
|
||||
void xgbe_debugfs_exit(struct xgbe_prv_data *);
|
||||
#else
|
||||
static inline void xgbe_debugfs_init(struct xgbe_prv_data *pdata) {}
|
||||
static inline void xgbe_debugfs_exit(struct xgbe_prv_data *pdata) {}
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
/* NOTE: Uncomment for TX and RX DESCRIPTOR DUMP in KERNEL LOG */
|
||||
#if 0
|
||||
#define XGMAC_ENABLE_TX_DESC_DUMP
|
||||
#define XGMAC_ENABLE_RX_DESC_DUMP
|
||||
#endif
|
||||
|
||||
/* NOTE: Uncomment for TX and RX PACKET DUMP in KERNEL LOG */
|
||||
#if 0
|
||||
#define XGMAC_ENABLE_TX_PKT_DUMP
|
||||
#define XGMAC_ENABLE_RX_PKT_DUMP
|
||||
#endif
|
||||
|
||||
/* NOTE: Uncomment for function trace log messages in KERNEL LOG */
|
||||
#if 0
|
||||
#define YDEBUG
|
||||
#define YDEBUG_MDIO
|
||||
#endif
|
||||
|
||||
/* For debug prints */
|
||||
#ifdef YDEBUG
|
||||
#define DBGPR(x...) pr_alert(x)
|
||||
#define DBGPHY_REGS(x...) xgbe_dump_phy_registers(x)
|
||||
#else
|
||||
#define DBGPR(x...) do { } while (0)
|
||||
#define DBGPHY_REGS(x...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#ifdef YDEBUG_MDIO
|
||||
#define DBGPR_MDIO(x...) pr_alert(x)
|
||||
#else
|
||||
#define DBGPR_MDIO(x...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue