/**************************************************************************
--Etherboot - BOOTP/TFTP Bootstrap Program
--P2001 NIC driver for Etherboot
--***************************************************************************/
++ * Etherboot - BOOTP/TFTP Bootstrap Program
++ * P2001 NIC driver for Etherboot
++ **************************************************************************/
/*
-- * Copyright (C) 2004 Tobias Lorenz
++ * Copyright (C) 2005 Tobias Lorenz
*
* 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
#include "isa.h"
#include "hardware.h"
--#include "lxt971a.h"
++#include "mii.h"
#include "timer.h"
#define DMA_BUF_SIZE 2048 /* Buffer size */
static DMA_DSC txd __attribute__ ((__section__(".dma.desc")));
static DMA_DSC rxd[NUM_RX_DESC] __attribute__ ((__section__(".dma.desc")));
--static unsigned char rxb[NUM_RX_DESC * DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
--static unsigned char txb[ DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
++static char rxb[NUM_RX_DESC * DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
++static char txb[ DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
static unsigned int cur_rx;
/* Device selectors */
static unsigned int cur_channel; // DMA channel : 0..3
static unsigned int cur_phy; // PHY Address : 0..31
static P2001_ETH_regs_ptr EU; // Ethernet Unit : 0x0018_000 with _=0..3
--static P2001_ETH_regs_ptr MU; // Management Unit: 0x00180000
--#define MDIO_MAXCOUNT 1000 /* mdio abort */
--static unsigned int mdio_error; /* mdio error */
--
--/* Function prototypes */
--static void p2001_eth_mdio_init ();
--static void p2001_eth_mdio_write(unsigned int phyadr, unsigned int regadr, unsigned int data);
--static unsigned int p2001_eth_mdio_read (unsigned int phyadr, unsigned int regadr);
--extern unsigned int p2001_eth_mdio_error;
++/* mdio handling */
++static int p2001_eth_mdio_read (int phy_id, int location);
++static void p2001_eth_mdio_write(int phy_id, int location, int val);
++/* net_device functions */
static int p2001_eth_poll (struct nic *nic, int retrieve);
static void p2001_eth_transmit (struct nic *nic, const char *d,
unsigned int t, unsigned int s, const char *p);
static void p2001_eth_disable (struct dev *dev);
static int p2001_eth_check_link(unsigned int phy);
++static int link;
++static void p2001_eth_phyreset ();
static int p2001_eth_probe (struct dev *dev, unsigned short *probe_addrs __unused);
++/* Supported MII list */
++static struct mii_chip_info {
++ const char * name;
++ unsigned int physid; // (MII_PHYSID2 << 16) | MII_PHYSID1
++} mii_chip_table[] = {
++ { "Intel LXT971A", 0x78e20013 },
++ { "Altima AC104-QF", 0x55410022 },
++ {NULL,0},
++};
++
++
/**************************************************************************
--PHY MANAGEMENT UNIT - Read/write
--***************************************************************************/
--static void p2001_eth_mdio_init()
++ * PHY MANAGEMENT UNIT - Read/write
++ **************************************************************************/
++
++/**
++ * mdio_read - read MII PHY register
++ * @dev: the net device to read
++ * @regadr: the phy register id to read
++ *
++ * Read MII registers through MDIO and MDC
++ * using MDIO management frame structure and protocol(defined by ISO/IEC).
++ */
++static int p2001_eth_mdio_read(int phy_id, int location)
{
-- /* reset ethernet PHYs */
-- printf("Resetting PHYs...\n");
++ int result, boguscnt = 1000;
-- /* GPIO24/25: TX_ER2/TX_ER0 */
-- /* GPIO26/27: PHY_RESET/TX_ER1 */
-- P2001_GPIO->PIN_MUX |= 0x0018;
-- // 31-16: 0000 1111 0000 0000
-- P2001_GPIO->GPIO2_En |= 0x0400;
++ do {
++ /* Warten bis Hardware inaktiv (MIU = "0") */
++ while (P2001_MU->MU_CNTL & 0x8000)
++ barrier();
-- P2001_GPIO->GPIO2_Out |= 0x04000000;
-- P2001_GPIO->GPIO2_Out &= ~0x0400;
-- mdelay(500);
-- P2001_GPIO->GPIO2_Out |= 0x0400;
++ /* Schreiben MU_CNTL */
++ P2001_MU->MU_CNTL = location + (phy_id<<5) + (2<<10);
-- /* set management unit clock divisor */
-- // max. MDIO CLK = 2.048 MHz (EU.doc)
-- // max. MDIO CLK = 8.000 MHz (LXT971A)
-- // sysclk/(2*(n+1)) = MDIO CLK <= 2.048 MHz
-- // n >= sysclk/4.096 MHz - 1
--#if SYSCLK == 73728000
-- P2001_MU->MU_DIV = 17; // 73.728 MHZ =17=> 2.020 MHz
--#else
-- //MU->MU_DIV = (SYSCLK/4.096)-1;
--#error "Please define a proper MDIO CLK divisor for that sysclk."
--#endif
-- asm("nop \n nop");
++ /* Warten bis Hardware aktiv (MIU = "1") */
++ while ((P2001_MU->MU_CNTL & 0x8000) == 0)
++ barrier();
++ //asm("nop \r\n nop");
++
++ /* Warten bis Hardware inaktiv (MIU = "0") */
++ while (P2001_MU->MU_CNTL & 0x8000)
++ barrier();
++
++ /* Fehler, wenn MDIO Read Error (MRE = "1") */
++ } while ((P2001_MU->MU_CNTL & 0x4000) && (--boguscnt > 0));
++
++ /* Lesen MU_DATA */
++ result = P2001_MU->MU_DATA;
++
++ if (boguscnt == 0)
++ return 0;
++ if ((result & 0xffff) == 0xffff)
++ return 0;
++
++ return result & 0xffff;
}
--static void p2001_eth_mdio_write(unsigned int phyadr, unsigned int regadr, unsigned int data)
--{
-- static unsigned int count;
-- count = 0;
++/**
++ * mdio_write - write MII PHY register
++ * @dev: the net device to write
++ * @regadr: the phy register id to write
++ * @value: the register value to write with
++ *
++ * Write MII registers with @value through MDIO and MDC
++ * using MDIO management frame structure and protocol(defined by ISO/IEC)
++ */
++static void p2001_eth_mdio_write(int phy_id, int location, int val)
++{
/* Warten bis Hardware inaktiv (MIU = "0") */
-- while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
-- count++;
++ while (P2001_MU->MU_CNTL & 0x8000)
++ barrier();
/* Schreiben MU_DATA */
-- MU->MU_DATA = data;
++ P2001_MU->MU_DATA = val;
/* Schreiben MU_CNTL */
-- MU->MU_CNTL = regadr + (phyadr<<5) + (1<<10);
++ P2001_MU->MU_CNTL = location + (phy_id<<5) + (1<<10);
/* Warten bis Hardware aktiv (MIU = "1") */
-- while (((MU->MU_CNTL & 0x8000) == 0) && (count < MDIO_MAXCOUNT))
-- count++;
++ while ((P2001_MU->MU_CNTL & 0x8000) == 0)
++ barrier();
//asm("nop \r\n nop");
/* Warten bis Hardware inaktiv (MIU = "0") */
-- while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
-- count++;
--
-- mdio_error = (count >= MDIO_MAXCOUNT);
++ while (P2001_MU->MU_CNTL & 0x8000)
++ barrier();
}
--static unsigned int p2001_eth_mdio_read(unsigned int phyadr, unsigned int regadr)
--{
-- static unsigned int count;
-- count = 0;
--
-- do {
-- /* Warten bis Hardware inaktiv (MIU = "0") */
-- while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
-- count++;
--
-- /* Schreiben MU_CNTL */
-- MU->MU_CNTL = regadr + (phyadr<<5) + (2<<10);
--
-- /* Warten bis Hardware aktiv (MIU = "1") */
-- while (((MU->MU_CNTL & 0x8000) == 0) && (count < MDIO_MAXCOUNT))
-- count++;
-- //asm("nop \r\n nop");
--
-- /* Warten bis Hardware inaktiv (MIU = "0") */
-- while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
-- count++;
--
-- /* Fehler, wenn MDIO Read Error (MRE = "1") */
-- } while ((MU->MU_CNTL & 0x4000) && (count < MDIO_MAXCOUNT));
--
-- /* Lesen MU_DATA */
-- mdio_error = (count >= MDIO_MAXCOUNT);
-- return MU->MU_DATA;
--}
/**************************************************************************
--POLL - Wait for a frame
--***************************************************************************/
++ * POLL - Wait for a frame
++ **************************************************************************/
++
/* Function: p2001_eth_poll
*
* Description: checks for a received packet and returns it if found.
}
++
/**************************************************************************
--TRANSMIT - Transmit a frame
--***************************************************************************/
++ * TRANSMIT - Transmit a frame
++ **************************************************************************/
++
/* Function: p2001_eth_transmit
*
* Description: transmits a packet and waits for completion or timeout.
// TMAC_CNTL.ATP does the same
#ifdef DEBUG_NIC
-- printf("p2001_eth_transmit: packet from %! to %! sent\n", txb+ETH_ALEN, txb);
++ printf("p2001_eth_transmit: packet from %! to %! sent (size: %d)\n", txb+ETH_ALEN, txb, s);
#endif
/* configure descriptor */
/* restart the transmitter */
EU->TMAC_DMA_EN = 0x01; /* set run bit */
-- while(EU->TMAC_DMA_EN & 0x01) ; /* wait */
++ while(EU->TMAC_DMA_EN & 0x01); /* wait */
#ifdef DEBUG_NIC
/* check status */
status = EU->TMAC_DMA_STAT;
-- if (status & ~(0x40))
++ if (status & ~(0x40)) // not END
printf("p2001_eth_transmit: dma status=0x%hx\n", status);
printf("TMAC_MIB6..7: %d:%d\n", EU->TMAC_MIB6, EU->TMAC_MIB7);
}
++
/**************************************************************************
--IRQ - Enable, Disable or Force Interrupts
--***************************************************************************/
++ * IRQ - Enable, Disable or Force Interrupts
++ **************************************************************************/
++
/* Function: p2001_eth_irq
*
* Description: Enable, Disable, or Force, interrupts
}
++
/**************************************************************************
--INIT - Initialize device
--***************************************************************************/
++ * INIT - Initialize device
++ **************************************************************************/
++
/* Function: p2001_init
*
* Description: resets the ethernet controller chip and various
{
static int i;
++ /* activate MII 3 */
++ if (cur_channel == 3)
++ P2001_GPIO->PIN_MUX |= (1<<8); // MII_3_en = 1
++
++#ifdef RMII
++ /* RMII init sequence */
++ if (link & LPA_100) {
++ EU->CONF_RMII = (1<<2) | (1<<1); // softres | 100Mbit
++ EU->CONF_RMII = (1<<2) | (1<<1) | (1<<0); // softres | 100Mbit | RMII
++ EU->CONF_RMII = (1<<1) | (1<<0); // 100 Mbit | RMII
++ } else {
++ EU->CONF_RMII = (1<<2); // softres
++ EU->CONF_RMII = (1<<2) | (1<<0); // softres | RMII
++ EU->CONF_RMII = (1<<0); // RMII
++ }
++#endif
++
/* disable transceiver */
// EU->TMAC_DMA_EN = 0; /* clear run bit */
// EU->RMAC_DMA_EN = 0; /* clear run bit */
// txd.stat = (1<<31) | (1<<30) | (1<<29); // DSC0 OWN|START|END
// txd.cntl = cur_channel << 16; // DSC1 CHANNEL
// txd.cntl |= DMA_BUF_SIZE; // DSC1 LEN
-- txd.buf = &txb; // DSC2 BUFFER
++ txd.buf = (char *)&txb; // DSC2 BUFFER
txd.next = &txd; // DSC3 NEXTDSC @self
EU->TMAC_DMA_DESC = &txd;
EU->RMAC_DMA_DESC = &rxd[0];
/* set transmitter mode */
-- EU->TMAC_CNTL = (1<<4) | /* COI: Collision ignore */
-- //(1<<3) | /* CSI: Carrier Sense ignore */
-- (1<<2); /* ATP: Automatic Transmit Padding */
++ if (link & LPA_DUPLEX)
++ EU->TMAC_CNTL = (1<<4) | /* COI: Collision ignore */
++ (1<<3) | /* CSI: Carrier Sense ignore */
++ (1<<2); /* ATP: Automatic Transmit Padding */
++ else
++ EU->TMAC_CNTL = (1<<2); /* ATP: Automatic Transmit Padding */
/* set receive mode */
EU->RMAC_CNTL = (1<<3) | /* BROAD: Broadcast packets */
}
++
/**************************************************************************
--DISABLE - Turn off ethernet interface
--***************************************************************************/
++ * DISABLE - Turn off ethernet interface
++ **************************************************************************/
static void p2001_eth_disable(struct dev *dev __unused)
{
/* put the card in its initial state */
}
++
/**************************************************************************
--LINK - Check for valid link
--***************************************************************************/
++ * LINK - Check for valid link
++ **************************************************************************/
static int p2001_eth_check_link(unsigned int phy)
{
static int status;
-- static unsigned int count;
-- count = 0;
++ static unsigned int i, physid;
++
++ /* print some information about out PHY */
++ physid = (p2001_eth_mdio_read(phy, MII_PHYSID2) << 16) |
++ p2001_eth_mdio_read(phy, MII_PHYSID1);
++ printf("PHY %d, ID 0x%x ", phy, physid);
++ for (i = 0; mii_chip_table[i].physid; i++)
++ if (mii_chip_table[i].physid == physid) {
++ printf("(%s).\n", mii_chip_table[i].name);
++ break;
++ }
++ if (!mii_chip_table[i].physid)
++ printf("(unknown).\n");
/* Use 0x3300 for restarting NWay */
printf("Starting auto-negotiation... ");
-- p2001_eth_mdio_write(phy, Adr_LXT971A_Control, 0x3300);
-- if (mdio_error)
-- goto failed;
++ p2001_eth_mdio_write(phy, MII_BMCR, 0x3300);
-- /* Bits 1.5 and 17.7 are set to 1 once the Auto-Negotiation process to completed. */
++ /* Bit 1.5 is set once the Auto-Negotiation process is completed. */
++ i = 0;
do {
mdelay(500);
-- status = p2001_eth_mdio_read(phy, Adr_LXT971A_Status1);
-- if (mdio_error || (count++ > 6)) // 6*500ms = 3s timeout
++ status = p2001_eth_mdio_read(phy, MII_BMSR);
++ if (!status || (i++ > 6)) // 6*500ms = 3s timeout
goto failed;
-- } while (!(status & 0x20));
--
-- /* Bits 1.2 and 17.10 are set to 1 once the link is established. */
-- if (p2001_eth_mdio_read(phy, Adr_LXT971A_Status1) & 0x04) {
-- /* Bits 17.14 and 17.9 can be used to determine the link operation conditions (speed and duplex). */
-- printf("Valid link, operating at: %sMb-%s\n",
-- (p2001_eth_mdio_read(phy, Adr_LXT971A_Status2) & 0x4000) ? "100" : "10",
-- (p2001_eth_mdio_read(phy, Adr_LXT971A_Status2) & 0x0200) ? "FD" : "HD");
-- return 1;
++ } while (!(status & BMSR_ANEGCOMPLETE));
++
++ /* Bits 1.2 is set once the link is established. */
++ if ((status = p2001_eth_mdio_read(phy, MII_BMSR)) & BMSR_LSTATUS) {
++ link = p2001_eth_mdio_read(phy, MII_ADVERTISE) &
++ p2001_eth_mdio_read(phy, MII_LPA);
++ printf(" Valid link, operating at: %sMb-%s\n",
++ (link & LPA_100) ? "100" : "10",
++ (link & LPA_DUPLEX) ? "FD" : "HD");
++ return 1;
}
failed:
-- if (mdio_error)
++ if (!status)
printf("Failed\n");
else
printf("No valid link\n");
}
++
++/**************************************************************************
++ * PHYRESET - hardware reset all MII PHYs
++ **************************************************************************/
++
++/**
++ * p2001_eth_phyreset - hardware reset all MII PHYs
++ */
++static void p2001_eth_phyreset()
++{
++ /* GPIO24/25: TX_ER2/TX_ER0 */
++ /* GPIO26/27: PHY_RESET/TX_ER1 */
++ P2001_GPIO->PIN_MUX |= 0x0018;
++ // 31-16: 0000 1111 0000 0000
++ P2001_GPIO->GPIO2_En |= 0x0400;
++
++ P2001_GPIO->GPIO2_Out |= 0x04000000;
++ P2001_GPIO->GPIO2_Out &= ~0x0400;
++ mdelay(500);
++ P2001_GPIO->GPIO2_Out |= 0x0400;
++
++#ifdef RMII
++ /* RMII_clk_sel = 0xxb no RMII (default) */
++ /* RMII_clk_sel = 100b COL_0 */
++ /* RMII_clk_sel = 101b COL_1 */
++ /* RMII_clk_sel = 110b COL_2 */
++ /* RMII_clk_sel = 111b COL_3 */
++ P2001_GPIO->PIN_MUX |= (4 << 13);
++#endif
++}
++
++
++
/**************************************************************************
--PROBE - Look for an adapter, this routine's visible to the outside
--***************************************************************************/
++ * PROBE - Look for an adapter, this routine's visible to the outside
++ **************************************************************************/
++
static int p2001_eth_probe(struct dev *dev, unsigned short *probe_addrs __unused)
{
struct nic *nic = (struct nic *)dev;
/* if probe_addrs is 0, then routine can use a hardwired default */
-- static int board_found;
-- static int valid_link;
/* reset phys and configure mdio clk */
-- p2001_eth_mdio_init();
++ printf("Resetting PHYs...\n");
++ p2001_eth_phyreset();
++
++ /* set management unit clock divisor */
++ // max. MDIO CLK = 2.048 MHz (EU.doc)
++ P2001_MU->MU_DIV = (SYSCLK/4096000)-1; // 2.048 MHz
++ //asm("nop \n nop");
/* find the correct PHY/DMA/MAC combination */
-- MU = P2001_MU; // MU for all PHYs is only in EU0
printf("Searching for P2001 NICs...\n");
++ cur_phy = -1;
for (cur_channel=0; cur_channel<4; cur_channel++) {
-- switch(cur_channel) {
-- case 0:
-- EU = P2001_EU0;
-- cur_phy = 0;
-- break;
-- case 1:
-- EU = P2001_EU1;
-- cur_phy = 1;
-- break;
-- case 2:
-- EU = P2001_EU2;
-- cur_phy = 2;
-- break;
-- case 3:
-- EU = P2001_EU3;
-- cur_phy = 3;
++ EU = P2001_EU(cur_channel);
++
++ /* find next phy */
++ while (++cur_phy < 16) {
++ //printf("phy detect %d\n", cur_phy);
++ if (p2001_eth_mdio_read(cur_phy, MII_BMSR) != 0)
break;
}
++ if (cur_phy == 16) {
++ printf("no more MII PHYs found\n");
++ break;
++ }
/* first a non destructive test for initial value RMAC_TLEN=1518 */
-- board_found = (EU->RMAC_TLEN == 1518);
-- if (board_found) {
++ if (EU->RMAC_TLEN == 1518) {
printf("Checking EU%d...\n", cur_channel);
-- valid_link = p2001_eth_check_link(cur_phy);
-- if (valid_link) {
++ if (p2001_eth_check_link(cur_phy)) {
/* initialize device */
p2001_eth_init(nic);
/* Report the ISA pnp id of the board */
dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
-- dev->devid.vendor_id = htons(0x1234);
return 1;
}
}
* (C) 2003 Manfred Spraul
* See Linux Driver for full information
*
--* Linux Driver Version 0.22, 19 Jan 2004
++* Linux Driver Version 0.30, 25 Sep 2004
++* Linux Kernel 2.6.10
*
*
* REVISION HISTORY:
* ================
* v1.0 01-31-2004 timlegge Initial port of Linux driver
* v1.1 02-03-2004 timlegge Large Clean up, first release
--*
++* v1.2 05-14-2005 timlegge Add Linux 0.22 to .030 features
++*
* Indent Options: indent -kr -i8
***************************************************************************/
#include "pci.h"
/* Include timer support functions */
#include "timer.h"
++#include "mii.h"
--#define drv_version "v1.1"
--#define drv_date "02-03-2004"
++#define drv_version "v1.2"
++#define drv_date "05-14-2005"
//#define TFTM_DEBUG
#ifdef TFTM_DEBUG
#define dprintf(x)
#endif
--typedef unsigned char u8;
--typedef signed char s8;
--typedef unsigned short u16;
--typedef signed short s16;
--typedef unsigned int u32;
--typedef signed int s32;
++#define ETH_DATA_LEN 1500
/* Condensed operations for readability. */
#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
static unsigned long BASE;
/* NIC specific static variables go here */
++#define PCI_DEVICE_ID_NVIDIA_NVENET_1 0x01c3
++#define PCI_DEVICE_ID_NVIDIA_NVENET_2 0x0066
++#define PCI_DEVICE_ID_NVIDIA_NVENET_4 0x0086
++#define PCI_DEVICE_ID_NVIDIA_NVENET_5 0x008c
++#define PCI_DEVICE_ID_NVIDIA_NVENET_3 0x00d6
++#define PCI_DEVICE_ID_NVIDIA_NVENET_7 0x00df
++#define PCI_DEVICE_ID_NVIDIA_NVENET_6 0x00e6
++#define PCI_DEVICE_ID_NVIDIA_NVENET_8 0x0056
++#define PCI_DEVICE_ID_NVIDIA_NVENET_9 0x0057
++#define PCI_DEVICE_ID_NVIDIA_NVENET_10 0x0037
++#define PCI_DEVICE_ID_NVIDIA_NVENET_11 0x0038
/*
* Hardware access:
*/
--#define DEV_NEED_LASTPACKET1 0x0001
--#define DEV_IRQMASK_1 0x0002
--#define DEV_IRQMASK_2 0x0004
--#define DEV_NEED_TIMERIRQ 0x0008
++#define DEV_NEED_LASTPACKET1 0x0001 /* set LASTPACKET1 in tx flags */
++#define DEV_IRQMASK_1 0x0002 /* use NVREG_IRQMASK_WANTED_1 for irq mask */
++#define DEV_IRQMASK_2 0x0004 /* use NVREG_IRQMASK_WANTED_2 for irq mask */
++#define DEV_NEED_TIMERIRQ 0x0008 /* set the timer irq flag in the irq mask */
++#define DEV_NEED_LINKTIMER 0x0010 /* poll link settings. Relies on the timer irq */
enum {
NvRegIrqStatus = 0x000,
#define NVREG_IRQSTAT_MIIEVENT 0040
#define NVREG_IRQSTAT_MASK 0x1ff
NvRegIrqMask = 0x004,
++#define NVREG_IRQ_RX_ERROR 0x0001
#define NVREG_IRQ_RX 0x0002
#define NVREG_IRQ_RX_NOBUF 0x0004
#define NVREG_IRQ_TX_ERR 0x0008
#define NVREG_IRQ_TX1 0x0100
#define NVREG_IRQMASK_WANTED_1 0x005f
#define NVREG_IRQMASK_WANTED_2 0x0147
--#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1))
++#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1))
NvRegUnknownSetupReg6 = 0x008,
#define NVREG_UNKSETUP6_VAL 3
NvRegOffloadConfig = 0x90,
#define NVREG_OFFLOAD_HOMEPHY 0x601
--#define NVREG_OFFLOAD_NORMAL 0x5ee
++#define NVREG_OFFLOAD_NORMAL RX_NIC_BUFSIZE
NvRegReceiverControl = 0x094,
#define NVREG_RCVCTL_START 0x01
NvRegReceiverStatus = 0x98,
NvRegRandomSeed = 0x9c,
#define NVREG_RNDSEED_MASK 0x00ff
#define NVREG_RNDSEED_FORCE 0x7f00
++#define NVREG_RNDSEED_FORCE2 0x2d00
++#define NVREG_RNDSEED_FORCE3 0x7400
NvRegUnknownSetupReg1 = 0xA0,
#define NVREG_UNKSETUP1_VAL 0x16070f
NvRegMulticastMaskA = 0xB8,
NvRegMulticastMaskB = 0xBC,
++ NvRegPhyInterface = 0xC0,
++#define PHY_RGMII 0x10000000
++
NvRegTxRingPhysAddr = 0x100,
NvRegRxRingPhysAddr = 0x104,
NvRegRingSizes = 0x108,
NvRegUnknownTransmitterReg = 0x10c,
NvRegLinkSpeed = 0x110,
#define NVREG_LINKSPEED_FORCE 0x10000
--#define NVREG_LINKSPEED_10 10
++#define NVREG_LINKSPEED_10 1000
#define NVREG_LINKSPEED_100 100
--#define NVREG_LINKSPEED_1000 1000
++#define NVREG_LINKSPEED_1000 50
NvRegUnknownSetupReg5 = 0x130,
#define NVREG_UNKSETUP5_BIT31 (1<<31)
-- NvRegUnknownSetupReg3 = 0x134,
++ NvRegUnknownSetupReg3 = 0x13c,
#define NVREG_UNKSETUP3_VAL1 0x200010
NvRegTxRxControl = 0x144,
#define NVREG_TXRXCTL_KICK 0x0001
#define NVREG_TXRXCTL_BIT2 0x0004
#define NVREG_TXRXCTL_IDLE 0x0008
#define NVREG_TXRXCTL_RESET 0x0010
++#define NVREG_TXRXCTL_RXCHECK 0x0400
NvRegMIIStatus = 0x180,
#define NVREG_MIISTAT_ERROR 0x0001
#define NVREG_MIISTAT_LINKCHANGE 0x0008
NvRegAdapterControl = 0x188,
#define NVREG_ADAPTCTL_START 0x02
#define NVREG_ADAPTCTL_LINKUP 0x04
--#define NVREG_ADAPTCTL_PHYVALID 0x4000
++#define NVREG_ADAPTCTL_PHYVALID 0x40000
#define NVREG_ADAPTCTL_RUNNING 0x100000
#define NVREG_ADAPTCTL_PHYSHIFT 24
NvRegMIISpeed = 0x18c,
#define NVREG_MIISPEED_BIT8 (1<<8)
#define NVREG_MIIDELAY 5
NvRegMIIControl = 0x190,
--#define NVREG_MIICTL_INUSE 0x10000
--#define NVREG_MIICTL_WRITE 0x08000
++#define NVREG_MIICTL_INUSE 0x08000
++#define NVREG_MIICTL_WRITE 0x00400
#define NVREG_MIICTL_ADDRSHIFT 5
NvRegMIIData = 0x194,
NvRegWakeUpFlags = 0x200,
#define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT 0x01
#define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x02
#define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04
++#define NVREG_WAKEUPFLAGS_ENABLE 0x1111
NvRegPatternCRC = 0x204,
NvRegPatternMask = 0x208,
#define NVREG_POWERSTATE_D3 0x0003
};
--
--
--#define NV_TX_LASTPACKET (1<<0)
--#define NV_TX_RETRYERROR (1<<3)
--#define NV_TX_LASTPACKET1 (1<<8)
--#define NV_TX_DEFERRED (1<<10)
--#define NV_TX_CARRIERLOST (1<<11)
--#define NV_TX_LATECOLLISION (1<<12)
--#define NV_TX_UNDERFLOW (1<<13)
--#define NV_TX_ERROR (1<<14)
--#define NV_TX_VALID (1<<15)
--
--#define NV_RX_DESCRIPTORVALID (1<<0)
--#define NV_RX_MISSEDFRAME (1<<1)
--#define NV_RX_SUBSTRACT1 (1<<3)
--#define NV_RX_ERROR1 (1<<7)
--#define NV_RX_ERROR2 (1<<8)
--#define NV_RX_ERROR3 (1<<9)
--#define NV_RX_ERROR4 (1<<10)
--#define NV_RX_CRCERR (1<<11)
--#define NV_RX_OVERFLOW (1<<12)
--#define NV_RX_FRAMINGERR (1<<13)
--#define NV_RX_ERROR (1<<14)
--#define NV_RX_AVAIL (1<<15)
++#define FLAG_MASK_V1 0xffff0000
++#define FLAG_MASK_V2 0xffffc000
++#define LEN_MASK_V1 (0xffffffff ^ FLAG_MASK_V1)
++#define LEN_MASK_V2 (0xffffffff ^ FLAG_MASK_V2)
++
++#define NV_TX_LASTPACKET (1<<16)
++#define NV_TX_RETRYERROR (1<<19)
++#define NV_TX_LASTPACKET1 (1<<24)
++#define NV_TX_DEFERRED (1<<26)
++#define NV_TX_CARRIERLOST (1<<27)
++#define NV_TX_LATECOLLISION (1<<28)
++#define NV_TX_UNDERFLOW (1<<29)
++#define NV_TX_ERROR (1<<30)
++#define NV_TX_VALID (1<<31)
++
++#define NV_TX2_LASTPACKET (1<<29)
++#define NV_TX2_RETRYERROR (1<<18)
++#define NV_TX2_LASTPACKET1 (1<<23)
++#define NV_TX2_DEFERRED (1<<25)
++#define NV_TX2_CARRIERLOST (1<<26)
++#define NV_TX2_LATECOLLISION (1<<27)
++#define NV_TX2_UNDERFLOW (1<<28)
++/* error and valid are the same for both */
++#define NV_TX2_ERROR (1<<30)
++#define NV_TX2_VALID (1<<31)
++
++#define NV_RX_DESCRIPTORVALID (1<<16)
++#define NV_RX_MISSEDFRAME (1<<17)
++#define NV_RX_SUBSTRACT1 (1<<18)
++#define NV_RX_ERROR1 (1<<23)
++#define NV_RX_ERROR2 (1<<24)
++#define NV_RX_ERROR3 (1<<25)
++#define NV_RX_ERROR4 (1<<26)
++#define NV_RX_CRCERR (1<<27)
++#define NV_RX_OVERFLOW (1<<28)
++#define NV_RX_FRAMINGERR (1<<29)
++#define NV_RX_ERROR (1<<30)
++#define NV_RX_AVAIL (1<<31)
++
++#define NV_RX2_CHECKSUMMASK (0x1C000000)
++#define NV_RX2_CHECKSUMOK1 (0x10000000)
++#define NV_RX2_CHECKSUMOK2 (0x14000000)
++#define NV_RX2_CHECKSUMOK3 (0x18000000)
++#define NV_RX2_DESCRIPTORVALID (1<<29)
++#define NV_RX2_SUBSTRACT1 (1<<25)
++#define NV_RX2_ERROR1 (1<<18)
++#define NV_RX2_ERROR2 (1<<19)
++#define NV_RX2_ERROR3 (1<<20)
++#define NV_RX2_ERROR4 (1<<21)
++#define NV_RX2_CRCERR (1<<22)
++#define NV_RX2_OVERFLOW (1<<23)
++#define NV_RX2_FRAMINGERR (1<<24)
++/* error and avail are the same for both */
++#define NV_RX2_ERROR (1<<30)
++#define NV_RX2_AVAIL (1<<31)
/* Miscelaneous hardware related defines: */
#define NV_PCI_REGSZ 0x270
#define NV_WAKEUPMASKENTRIES 4
/* General driver defaults */
--#define NV_WATCHDOG_TIMEO (2*HZ)
--#define DEFAULT_MTU 1500 /* also maximum supported, at least for now */
++#define NV_WATCHDOG_TIMEO (5*HZ)
#define RX_RING 4
#define TX_RING 2
--/* limited to 1 packet until we understand NV_TX_LASTPACKET */
--#define TX_LIMIT_STOP 10
--#define TX_LIMIT_START 5
++
++/*
++ * If your nic mysteriously hangs then try to reduce the limits
++ * to 1/0: It might be required to set NV_TX_LASTPACKET in the
++ * last valid ring entry. But this would be impossible to
++ * implement - probably a disassembly error.
++ */
++#define TX_LIMIT_STOP 63
++#define TX_LIMIT_START 62
/* rx/tx mac addr + type + vlan + align + slack*/
--#define RX_NIC_BUFSIZE (DEFAULT_MTU + 64)
++#define RX_NIC_BUFSIZE (ETH_DATA_LEN + 64)
/* even more slack */
--#define RX_ALLOC_BUFSIZE (DEFAULT_MTU + 128)
++#define RX_ALLOC_BUFSIZE (ETH_DATA_LEN + 128)
#define OOM_REFILL (1+HZ/20)
#define POLL_WAIT (1+HZ/100)
--
++#define LINK_TIMEOUT (3*HZ)
++
++/*
++ * desc_ver values:
++ * This field has two purposes:
++ * - Newer nics uses a different ring layout. The layout is selected by
++ * comparing np->desc_ver with DESC_VER_xy.
++ * - It contains bits that are forced on when writing to NvRegTxRxControl.
++ */
++#define DESC_VER_1 0x0
++#define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK)
++
++/* PHY defines */
++#define PHY_OUI_MARVELL 0x5043
++#define PHY_OUI_CICADA 0x03f1
++#define PHYID1_OUI_MASK 0x03ff
++#define PHYID1_OUI_SHFT 6
++#define PHYID2_OUI_MASK 0xfc00
++#define PHYID2_OUI_SHFT 10
++#define PHY_INIT1 0x0f000
++#define PHY_INIT2 0x0e00
++#define PHY_INIT3 0x01000
++#define PHY_INIT4 0x0200
++#define PHY_INIT5 0x0004
++#define PHY_INIT6 0x02000
++#define PHY_GIGABIT 0x0100
++
++#define PHY_TIMEOUT 0x1
++#define PHY_ERROR 0x2
++
++#define PHY_100 0x1
++#define PHY_1000 0x2
++#define PHY_HALF 0x100
++
++/* FIXME: MII defines that should be added to <linux/mii.h> */
++#define MII_1000BT_CR 0x09
++#define MII_1000BT_SR 0x0a
++#define ADVERTISE_1000FULL 0x0200
++#define ADVERTISE_1000HALF 0x0100
++#define LPA_1000FULL 0x0800
++#define LPA_1000HALF 0x0400
++
++/* Big endian: should work, but is untested */
struct ring_desc {
u32 PacketBuffer;
-- u16 Length;
-- u16 Flags;
++ u32 FlagLen;
};
u32 linkspeed;
int duplex;
int phyaddr;
++ int wolenabled;
++ unsigned int phy_oui;
++ u16 gigabit;
/* General data: RO fields */
u8 *ring_addr;
u32 orig_mac[2];
u32 irqmask;
++ u32 desc_ver;
/* rx specific fields.
* Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
*/
unsigned int cur_rx, refill_rx;
-- unsigned int rx_buf_sz;
/*
* tx specific fields.
*/
unsigned int next_tx, nic_tx;
-- u16 tx_flags;
++ u32 tx_flags;
} npx;
static struct forcedeth_private *np;
/* force out pending posted writes */
readl(base);
}
++
++static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v)
++{
++ return le32_to_cpu(prd->FlagLen)
++ & ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2);
++}
++
static int reg_delay(int offset, u32 mask,
u32 target, int delay, int delaymax, const char *msg)
{
int value)
{
u8 *base = (u8 *) BASE;
-- int was_running;
u32 reg;
int retval;
writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
-- was_running = 0;
-- reg = readl(base + NvRegAdapterControl);
-- if (reg & NVREG_ADAPTCTL_RUNNING) {
-- was_running = 1;
-- writel(reg & ~NVREG_ADAPTCTL_RUNNING,
-- base + NvRegAdapterControl);
-- }
++
reg = readl(base + NvRegMIIControl);
if (reg & NVREG_MIICTL_INUSE) {
writel(NVREG_MIICTL_INUSE, base + NvRegMIIControl);
}
reg =
-- NVREG_MIICTL_INUSE | (addr << NVREG_MIICTL_ADDRSHIFT) | miireg;
++ (addr << NVREG_MIICTL_ADDRSHIFT) | miireg;
if (value != MII_READ) {
writel(value, base + NvRegMIIData);
reg |= NVREG_MIICTL_WRITE;
miireg, addr));
retval = -1;
} else {
-- /* FIXME: why is that required? */
-- udelay(50);
retval = readl(base + NvRegMIIData);
dprintf(("mii_rw read from reg %d at PHY %d: 0x%x.\n",
miireg, addr, retval));
}
-- if (was_running) {
-- reg = readl(base + NvRegAdapterControl);
-- writel(reg | NVREG_ADAPTCTL_RUNNING,
-- base + NvRegAdapterControl);
-- }
return retval;
}
++static int phy_reset(struct nic *nic)
++{
++
++ u32 miicontrol;
++ unsigned int tries = 0;
++
++ miicontrol = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ);
++ miicontrol |= BMCR_RESET;
++ if (mii_rw(nic, np->phyaddr, MII_BMCR, miicontrol)) {
++ return -1;
++ }
++
++ /* wait for 500ms */
++ mdelay(500);
++
++ /* must wait till reset is deasserted */
++ while (miicontrol & BMCR_RESET) {
++ mdelay(10);
++ miicontrol = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ);
++ /* FIXME: 100 tries seem excessive */
++ if (tries++ > 100)
++ return -1;
++ }
++ return 0;
++}
++
++static int phy_init(struct nic *nic)
++{
++ u8 *base = (u8 *) BASE;
++ u32 phyinterface, phy_reserved, mii_status, mii_control,
++ mii_control_1000, reg;
++
++ /* set advertise register */
++ reg = mii_rw(nic, np->phyaddr, MII_ADVERTISE, MII_READ);
++ reg |=
++ (ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF |
++ ADVERTISE_100FULL | 0x800 | 0x400);
++ if (mii_rw(nic, np->phyaddr, MII_ADVERTISE, reg)) {
++ printf("phy write to advertise failed.\n");
++ return PHY_ERROR;
++ }
++
++ /* get phy interface type */
++ phyinterface = readl(base + NvRegPhyInterface);
++
++ /* see if gigabit phy */
++ mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ);
++
++ if (mii_status & PHY_GIGABIT) {
++ np->gigabit = PHY_GIGABIT;
++ mii_control_1000 =
++ mii_rw(nic, np->phyaddr, MII_1000BT_CR, MII_READ);
++ mii_control_1000 &= ~ADVERTISE_1000HALF;
++ if (phyinterface & PHY_RGMII)
++ mii_control_1000 |= ADVERTISE_1000FULL;
++ else
++ mii_control_1000 &= ~ADVERTISE_1000FULL;
++
++ if (mii_rw
++ (nic, np->phyaddr, MII_1000BT_CR, mii_control_1000)) {
++ printf("phy init failed.\n");
++ return PHY_ERROR;
++ }
++ } else
++ np->gigabit = 0;
++
++ /* reset the phy */
++ if (phy_reset(nic)) {
++ printf("phy reset failed\n");
++ return PHY_ERROR;
++ }
++
++ /* phy vendor specific configuration */
++ if ((np->phy_oui == PHY_OUI_CICADA) && (phyinterface & PHY_RGMII)) {
++ phy_reserved =
++ mii_rw(nic, np->phyaddr, MII_RESV1, MII_READ);
++ phy_reserved &= ~(PHY_INIT1 | PHY_INIT2);
++ phy_reserved |= (PHY_INIT3 | PHY_INIT4);
++ if (mii_rw(nic, np->phyaddr, MII_RESV1, phy_reserved)) {
++ printf("phy init failed.\n");
++ return PHY_ERROR;
++ }
++ phy_reserved =
++ mii_rw(nic, np->phyaddr, MII_NCONFIG, MII_READ);
++ phy_reserved |= PHY_INIT5;
++ if (mii_rw(nic, np->phyaddr, MII_NCONFIG, phy_reserved)) {
++ printf("phy init failed.\n");
++ return PHY_ERROR;
++ }
++ }
++ if (np->phy_oui == PHY_OUI_CICADA) {
++ phy_reserved =
++ mii_rw(nic, np->phyaddr, MII_SREVISION, MII_READ);
++ phy_reserved |= PHY_INIT6;
++ if (mii_rw(nic, np->phyaddr, MII_SREVISION, phy_reserved)) {
++ printf("phy init failed.\n");
++ return PHY_ERROR;
++ }
++ }
++
++ /* restart auto negotiation */
++ mii_control = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ);
++ mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE);
++ if (mii_rw(nic, np->phyaddr, MII_BMCR, mii_control)) {
++ return PHY_ERROR;
++ }
++
++ return 0;
++}
++
static void start_rx(struct nic *nic __unused)
{
u8 *base = (u8 *) BASE;
u8 *base = (u8 *) BASE;
dprintf(("txrx_reset\n"));
-- writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET,
++ writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver,
base + NvRegTxRxControl);
++
pci_push(base);
udelay(NV_TXRX_RESET_DELAY);
-- writel(NVREG_TXRXCTL_BIT2, base + NvRegTxRxControl);
++ writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl);
pci_push(base);
}
//int nr = refill_rx % RX_RING;
rx_ring[i].PacketBuffer =
virt_to_le32desc(&rxb[i * RX_NIC_BUFSIZE]);
-- rx_ring[i].Length = cpu_to_le16(RX_NIC_BUFSIZE);
wmb();
-- rx_ring[i].Flags = cpu_to_le16(NV_RX_AVAIL);
++ rx_ring[i].FlagLen =
++ cpu_to_le32(RX_NIC_BUFSIZE | NV_RX_AVAIL);
/* printf("alloc_rx: Packet %d marked as Available\n",
refill_rx); */
refill_rx++;
static int update_linkspeed(struct nic *nic)
{
-- int adv, lpa, newdup;
++ int adv, lpa;
u32 newls;
++ int newdup = np->duplex;
++ u32 mii_status;
++ int retval = 0;
++ u32 control_1000, status_1000, phyreg;
++ u8 *base = (u8 *) BASE;
++ int i;
++
++ /* BMSR_LSTATUS is latched, read it twice:
++ * we want the current value.
++ */
++ mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ);
++ mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ);
++
++#if 1
++ //yhlu
++ for(i=0;i<30;i++) {
++ mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ);
++ if((mii_status & BMSR_LSTATUS) && (mii_status & BMSR_ANEGCOMPLETE)) break;
++ mdelay(100);
++ }
++#endif
++
++ if (!(mii_status & BMSR_LSTATUS)) {
++ printf
++ ("no link detected by phy - falling back to 10HD.\n");
++ newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
++ newdup = 0;
++ retval = 0;
++ goto set_speed;
++ }
++
++ /* check auto negotiation is complete */
++ if (!(mii_status & BMSR_ANEGCOMPLETE)) {
++ /* still in autonegotiation - configure nic for 10 MBit HD and wait. */
++ newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
++ newdup = 0;
++ retval = 0;
++ printf("autoneg not completed - falling back to 10HD.\n");
++ goto set_speed;
++ }
++
++ retval = 1;
++ if (np->gigabit == PHY_GIGABIT) {
++ control_1000 =
++ mii_rw(nic, np->phyaddr, MII_1000BT_CR, MII_READ);
++ status_1000 =
++ mii_rw(nic, np->phyaddr, MII_1000BT_SR, MII_READ);
++
++ if ((control_1000 & ADVERTISE_1000FULL) &&
++ (status_1000 & LPA_1000FULL)) {
++ printf
++ ("update_linkspeed: GBit ethernet detected.\n");
++ newls =
++ NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_1000;
++ newdup = 1;
++ goto set_speed;
++ }
++ }
++
adv = mii_rw(nic, np->phyaddr, MII_ADVERTISE, MII_READ);
lpa = mii_rw(nic, np->phyaddr, MII_LPA, MII_READ);
dprintf(("update_linkspeed: PHY advertises 0x%hX, lpa 0x%hX.\n",
newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
newdup = 0;
}
-- if (np->duplex != newdup || np->linkspeed != newls) {
-- np->duplex = newdup;
-- np->linkspeed = newls;
-- return 1;
++
++ set_speed:
++ if (np->duplex == newdup && np->linkspeed == newls)
++ return retval;
++
++ dprintf(("changing link setting from %d/%s to %d/%s.\n",
++ np->linkspeed, np->duplex ? "Full-Duplex": "Half-Duplex", newls, newdup ? "Full-Duplex": "Half-Duplex"));
++
++ np->duplex = newdup;
++ np->linkspeed = newls;
++
++ if (np->gigabit == PHY_GIGABIT) {
++ phyreg = readl(base + NvRegRandomSeed);
++ phyreg &= ~(0x3FF00);
++ if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_10)
++ phyreg |= NVREG_RNDSEED_FORCE3;
++ else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100)
++ phyreg |= NVREG_RNDSEED_FORCE2;
++ else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000)
++ phyreg |= NVREG_RNDSEED_FORCE;
++ writel(phyreg, base + NvRegRandomSeed);
}
-- return 0;
--}
++ phyreg = readl(base + NvRegPhyInterface);
++ phyreg &= ~(PHY_HALF | PHY_100 | PHY_1000);
++ if (np->duplex == 0)
++ phyreg |= PHY_HALF;
++ if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100)
++ phyreg |= PHY_100;
++ else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000)
++ phyreg |= PHY_1000;
++ writel(phyreg, base + NvRegPhyInterface);
++ writel(NVREG_MISC1_FORCE | (np->duplex ? 0 : NVREG_MISC1_HD),
++ base + NvRegMisc1);
++ pci_push(base);
++ writel(np->linkspeed, base + NvRegLinkSpeed);
++ pci_push(base);
++
++ return retval;
++}
++
++#if 0 /* Not used */
++static void nv_linkchange(struct nic *nic)
++{
++ if (update_linkspeed(nic)) {
++// if (netif_carrier_ok(nic)) {
++ stop_rx();
++//= } else {
++ // netif_carrier_on(dev);
++ // printk(KERN_INFO "%s: link up.\n", dev->name);
++ // }
++ start_rx(nic);
++ } else {
++ // if (netif_carrier_ok(dev)) {
++ // netif_carrier_off(dev);
++ // printk(KERN_INFO "%s: link down.\n", dev->name);
++ stop_rx();
++ // }
++ }
++}
++#endif
static int init_ring(struct nic *nic)
{
int i;
np->next_tx = np->nic_tx = 0;
-- for (i = 0; i < TX_RING; i++) {
-- tx_ring[i].Flags = 0;
-- }
++ for (i = 0; i < TX_RING; i++)
++ tx_ring[i].FlagLen = 0;
np->cur_rx = 0;
np->refill_rx = 0;
-- for (i = 0; i < RX_RING; i++) {
-- rx_ring[i].Flags = 0;
-- }
++ for (i = 0; i < RX_RING; i++)
++ rx_ring[i].FlagLen = 0;
return alloc_rx(nic);
}
writel(0, base + NvRegMulticastMaskA);
writel(0, base + NvRegMulticastMaskB);
writel(0, base + NvRegPacketFilterFlags);
++
++ writel(0, base + NvRegTransmitterControl);
++ writel(0, base + NvRegReceiverControl);
++
writel(0, base + NvRegAdapterControl);
++
++ /* 2) initialize descriptor rings */
++ oom = init_ring(nic);
++
writel(0, base + NvRegLinkSpeed);
writel(0, base + NvRegUnknownTransmitterReg);
txrx_reset(nic);
writel(0, base + NvRegUnknownSetupReg6);
-- /* 2) initialize descriptor rings */
np->in_shutdown = 0;
-- oom = init_ring(nic);
/* 3) set mac address */
{
writel(mac[1], base + NvRegMacAddrB);
}
-- /* 4) continue setup */
++ /* 4) give hw rings */
++ writel((u32) virt_to_le32desc(&rx_ring[0]),
++ base + NvRegRxRingPhysAddr);
++ writel((u32) virt_to_le32desc(&tx_ring[0]),
++ base + NvRegTxRingPhysAddr);
++
++ writel(((RX_RING - 1) << NVREG_RINGSZ_RXSHIFT) +
++ ((TX_RING - 1) << NVREG_RINGSZ_TXSHIFT),
++ base + NvRegRingSizes);
++
++ /* 5) continue setup */
np->linkspeed = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
np->duplex = 0;
++ writel(np->linkspeed, base + NvRegLinkSpeed);
writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3);
-- writel(0, base + NvRegTxRxControl);
++ writel(np->desc_ver, base + NvRegTxRxControl);
pci_push(base);
-- writel(NVREG_TXRXCTL_BIT1, base + NvRegTxRxControl);
--
++ writel(NVREG_TXRXCTL_BIT1 | np->desc_ver, base + NvRegTxRxControl);
reg_delay(NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31,
NVREG_UNKSETUP5_BIT31, NV_SETUP5_DELAY,
NV_SETUP5_DELAYMAX,
"open: SetupReg5, Bit 31 remained off\n");
-- writel(0, base + NvRegUnknownSetupReg4);
--
-- /* 5) Find a suitable PHY */
-- writel(NVREG_MIISPEED_BIT8 | NVREG_MIIDELAY, base + NvRegMIISpeed);
-- for (i = 1; i < 32; i++) {
-- int id1, id2;
--
-- id1 = mii_rw(nic, i, MII_PHYSID1, MII_READ);
-- if (id1 < 0)
-- continue;
-- id2 = mii_rw(nic, i, MII_PHYSID2, MII_READ);
-- if (id2 < 0)
-- continue;
-- dprintf(("open: Found PHY %04x:%04x at address %d.\n",
-- id1, id2, i));
-- np->phyaddr = i;
--
-- update_linkspeed(nic);
--
-- break;
-- }
-- if (i == 32) {
-- printf("open: failing due to lack of suitable PHY.\n");
-- ret = -1;
-- goto out_drain;
-- }
++ writel(0, base + NvRegUnknownSetupReg4);
++// writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
++ writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
++#if 0
printf("%d-Mbs Link, %s-Duplex\n",
np->linkspeed & NVREG_LINKSPEED_10 ? 10 : 100,
np->duplex ? "Full" : "Half");
++#endif
++
/* 6) continue setup */
-- writel(NVREG_MISC1_FORCE | (np->duplex ? 0 : NVREG_MISC1_HD),
-- base + NvRegMisc1);
++ writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1);
writel(readl(base + NvRegTransmitterStatus),
base + NvRegTransmitterStatus);
writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags);
writel(readl(base + NvRegReceiverStatus),
base + NvRegReceiverStatus);
-- /* FIXME: I cheated and used the calculator to get a random number */
-- i = 75963081;
++ /* Get a random number */
++ i = random();
writel(NVREG_RNDSEED_FORCE | (i & NVREG_RNDSEED_MASK),
base + NvRegRandomSeed);
writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1);
writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6);
writel((np->
phyaddr << NVREG_ADAPTCTL_PHYSHIFT) |
-- NVREG_ADAPTCTL_PHYVALID, base + NvRegAdapterControl);
++ NVREG_ADAPTCTL_PHYVALID | NVREG_ADAPTCTL_RUNNING,
++ base + NvRegAdapterControl);
++ writel(NVREG_MIISPEED_BIT8 | NVREG_MIIDELAY, base + NvRegMIISpeed);
writel(NVREG_UNKSETUP4_VAL, base + NvRegUnknownSetupReg4);
writel(NVREG_WAKEUPFLAGS_VAL, base + NvRegWakeUpFlags);
-- /* 7) start packet processing */
-- writel((u32) virt_to_le32desc(&rx_ring[0]),
-- base + NvRegRxRingPhysAddr);
-- writel((u32) virt_to_le32desc(&tx_ring[0]),
-- base + NvRegTxRingPhysAddr);
--
--
-- writel(((RX_RING - 1) << NVREG_RINGSZ_RXSHIFT) +
-- ((TX_RING - 1) << NVREG_RINGSZ_TXSHIFT),
-- base + NvRegRingSizes);
--
i = readl(base + NvRegPowerState);
-- if ((i & NVREG_POWERSTATE_POWEREDUP) == 0) {
++ if ((i & NVREG_POWERSTATE_POWEREDUP) == 0)
writel(NVREG_POWERSTATE_POWEREDUP | i,
base + NvRegPowerState);
-- }
++
pci_push(base);
udelay(10);
writel(readl(base + NvRegPowerState) | NVREG_POWERSTATE_VALID,
base + NvRegPowerState);
-- writel(NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl);
writel(0, base + NvRegIrqMask);
pci_push(base);
-- writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
-- pci_push(base);
writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
pci_push(base);
base + NvRegPacketFilterFlags);
set_multicast(nic);
++ /* One manual link speed update: Interrupts are enabled, future link
++ * speed changes cause interrupts and are handled by nv_link_irq().
++ */
++ {
++ u32 miistat;
++ miistat = readl(base + NvRegMIIStatus);
++ writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
++ dprintf(("startup: got 0x%hX.\n", miistat));
++ }
++ ret = update_linkspeed(nic);
++
//start_rx(nic);
start_tx(nic);
-- if (!
-- (mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ) &
-- BMSR_ANEGCOMPLETE)) {
++ if (ret) {
++ //Start Connection netif_carrier_on(dev);
++ } else {
printf("no link during initialization.\n");
}
-- udelay(10000);
-- out_drain:
return ret;
}
--//extern void hex_dump(const char *data, const unsigned int len);
--
++/*
++ * extern void hex_dump(const char *data, const unsigned int len);
++*/
/**************************************************************************
POLL - Wait for a frame
***************************************************************************/
/* nic->packet should contain data on return */
/* nic->packetlen should contain length of data */
-- struct ring_desc *prd;
int len;
int i;
++ u32 Flags;
i = np->cur_rx % RX_RING;
-- prd = &rx_ring[i];
-- if ( ! (prd->Flags & cpu_to_le16(NV_RX_DESCRIPTORVALID)) ) {
-- return 0;
++ Flags = le32_to_cpu(rx_ring[i].FlagLen);
++ len = nv_descr_getlength(&rx_ring[i], np->desc_ver);
++
++ if (Flags & NV_RX_AVAIL)
++ return 0; /* still owned by hardware, */
++
++ if (np->desc_ver == DESC_VER_1) {
++ if (!(Flags & NV_RX_DESCRIPTORVALID))
++ return 0;
++ } else {
++ if (!(Flags & NV_RX2_DESCRIPTORVALID))
++ return 0;
}
-- if ( ! retrieve ) return 1;
++ if (!retrieve)
++ return 1;
/* got a valid packet - forward it to the network core */
-- len = cpu_to_le16(prd->Length);
nic->packetlen = len;
-- //hex_dump(rxb + (i * RX_NIC_BUFSIZE), len);
-- memcpy(nic->packet, rxb +
-- (i * RX_NIC_BUFSIZE), nic->packetlen);
--
++ memcpy(nic->packet, rxb + (i * RX_NIC_BUFSIZE), nic->packetlen);
++/*
++ * hex_dump(rxb + (i * RX_NIC_BUFSIZE), len);
++*/
wmb();
np->cur_rx++;
alloc_rx(nic);
/* send the packet to destination */
u8 *ptxb;
u16 nstype;
-- //u16 status;
u8 *base = (u8 *) BASE;
int nr = np->next_tx % TX_RING;
ptxb[s++] = '\0';
tx_ring[nr].PacketBuffer = (u32) virt_to_le32desc(ptxb);
-- tx_ring[nr].Length = cpu_to_le16(s - 1);
wmb();
-- tx_ring[nr].Flags = np->tx_flags;
++ tx_ring[nr].FlagLen = cpu_to_le32((s - 1) | np->tx_flags);
-- writel(NVREG_TXRXCTL_KICK, base + NvRegTxRxControl);
++ writel(NVREG_TXRXCTL_KICK | np->desc_ver, base + NvRegTxRxControl);
pci_push(base);
-- tx_ring[nr].Flags = np->tx_flags;
np->next_tx++;
}
/**************************************************************************
IRQ - Enable, Disable, or Force interrupts
***************************************************************************/
--static void forcedeth_irq(struct nic *nic __unused, irq_action_t action __unused)
++static void forcedeth_irq(struct nic *nic __unused,
++ irq_action_t action __unused)
{
-- switch ( action ) {
-- case DISABLE :
-- break;
-- case ENABLE :
-- break;
-- case FORCE :
-- break;
-- }
++ switch (action) {
++ case DISABLE:
++ break;
++ case ENABLE:
++ break;
++ case FORCE:
++ break;
++ }
}
static struct nic_operations forcedeth_operations = {
};
--static struct pci_id forcedeth_nics[] = {
-- PCI_ROM(0x10de, 0x01C3, "nforce", "nForce Ethernet Controller"),
-- PCI_ROM(0x10de, 0x0066, "nforce2", "nForce2 Ethernet Controller"),
-- PCI_ROM(0x10de, 0x00D6, "nforce3", "nForce3 Ethernet Controller"),
--};
--
--PCI_DRIVER ( forcedeth_driver, forcedeth_nics, PCI_NO_CLASS );
--
/**************************************************************************
PROBE - Look for an adapter, this routine's visible to the outside
***************************************************************************/
unsigned long addr;
int sz;
u8 *base;
++ int i;
if (pci->ioaddr == 0)
return 0;
BASE = (unsigned long) ioremap(addr, sz);
if (!BASE)
return 0;
++
++ /* handle different descriptor versions */
++ if (pci->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_1 ||
++ pci->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_2 ||
++ pci->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_3)
++ np->desc_ver = DESC_VER_1;
++ else
++ np->desc_ver = DESC_VER_2;
++
//rx_ring[0] = rx_ring;
//tx_ring[0] = tx_ring;
#endif
printf("%s: MAC Address %!, ", pci->name, nic->node_addr);
-- np->tx_flags =
-- cpu_to_le16(NV_TX_LASTPACKET | NV_TX_LASTPACKET1 |
-- NV_TX_VALID);
-- switch (pci->device_id) {
-- case 0x01C3: // nforce
-- np->irqmask = NVREG_IRQMASK_WANTED_2;
-- np->irqmask |= NVREG_IRQ_TIMER;
-- break;
-- case 0x0066: // nforce2
-- np->tx_flags |= cpu_to_le16(NV_TX_LASTPACKET1);
-- np->irqmask = NVREG_IRQMASK_WANTED_2;
-- np->irqmask |= NVREG_IRQ_TIMER;
-- break;
-- case 0x00D6: // nforce3
-- np->tx_flags |= cpu_to_le16(NV_TX_LASTPACKET1);
-- np->irqmask = NVREG_IRQMASK_WANTED_2;
-- np->irqmask |= NVREG_IRQ_TIMER;
--
-- }
++ /* disable WOL */
++ writel(0, base + NvRegWakeUpFlags);
++ np->wolenabled = 0;
++
++ if (np->desc_ver == DESC_VER_1) {
++ np->tx_flags = NV_TX_LASTPACKET | NV_TX_VALID;
++ } else {
++ np->tx_flags = NV_TX2_LASTPACKET | NV_TX2_VALID;
++ }
++
++ switch (pci->device_id) {
++ case 0x01C3: // nforce
++ // DEV_IRQMASK_1|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
++ np->irqmask = NVREG_IRQMASK_WANTED_2 | NVREG_IRQ_TIMER;
++ // np->need_linktimer = 1;
++ // np->link_timeout = jiffies + LINK_TIMEOUT;
++ break;
++ case 0x0066:
++ /* Fall Through */
++ case 0x00D6:
++ // DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER
++ np->irqmask = NVREG_IRQMASK_WANTED_2;
++ np->irqmask |= NVREG_IRQ_TIMER;
++ // np->need_linktimer = 1;
++ // np->link_timeout = jiffies + LINK_TIMEOUT;
++ if (np->desc_ver == DESC_VER_1)
++ np->tx_flags |= NV_TX_LASTPACKET1;
++ else
++ np->tx_flags |= NV_TX2_LASTPACKET1;
++ break;
++ case 0x0086:
++ /* Fall Through */
++ case 0x008c:
++ /* Fall Through */
++ case 0x00e6:
++ /* Fall Through */
++ case 0x00df:
++ /* Fall Through */
++ case 0x0056:
++ /* Fall Through */
++ case 0x0057:
++ /* Fall Through */
++ case 0x0037:
++ /* Fall Through */
++ case 0x0038:
++ //DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ
++ np->irqmask = NVREG_IRQMASK_WANTED_2;
++ np->irqmask |= NVREG_IRQ_TIMER;
++ // np->need_linktimer = 1;
++ // np->link_timeout = jiffies + LINK_TIMEOUT;
++ if (np->desc_ver == DESC_VER_1)
++ np->tx_flags |= NV_TX_LASTPACKET1;
++ else
++ np->tx_flags |= NV_TX2_LASTPACKET1;
++ break;
++ default:
++ printf
++ ("Your card was undefined in this driver. Review driver_data in Linux driver and send a patch\n");
++ }
++
++ /* find a suitable phy */
++ for (i = 1; i < 32; i++) {
++ int id1, id2;
++ id1 = mii_rw(nic, i, MII_PHYSID1, MII_READ);
++ if (id1 < 0 || id1 == 0xffff)
++ continue;
++ id2 = mii_rw(nic, i, MII_PHYSID2, MII_READ);
++ if (id2 < 0 || id2 == 0xffff)
++ continue;
++ id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT;
++ id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT;
++ dprintf
++ (("%s: open: Found PHY %hX:%hX at address %d.\n",
++ pci->name, id1, id2, i));
++ np->phyaddr = i;
++ np->phy_oui = id1 | id2;
++ break;
++ }
++ if (i == 32) {
++ /* PHY in isolate mode? No phy attached and user wants to
++ * test loopback? Very odd, but can be correct.
++ */
++ printf
++ ("%s: open: Could not find a valid PHY.\n", pci->name);
++ }
++
++ if (i != 32) {
++ /* reset it */
++ phy_init(nic);
++ }
++
dprintf(("%s: forcedeth.c: subsystem: %hX:%hX bound to %s\n",
pci->name, pci->vendor, pci->dev_id, pci->name));
++ if(!forcedeth_reset(nic)) return 0; // no valid link
-- forcedeth_reset(nic);
--// if (board_found && valid_link)
/* point to NIC specific routines */
nic->nic_op = &forcedeth_operations;
return 1;
--// }
-- /* else */
}
++static struct pci_id forcedeth_nics[] = {
++PCI_ROM(0x10de, 0x01C3, "nforce", "nForce NVENET_1 Ethernet Controller"),
++PCI_ROM(0x10de, 0x0066, "nforce2", "nForce NVENET_2 Ethernet Controller"),
++PCI_ROM(0x10de, 0x00D6, "nforce3", "nForce NVENET_3 Ethernet Controller"),
++PCI_ROM(0x10de, 0x0086, "nforce4", "nForce NVENET_4 Ethernet Controller"),
++PCI_ROM(0x10de, 0x008c, "nforce5", "nForce NVENET_5 Ethernet Controller"),
++PCI_ROM(0x10de, 0x00e6, "nforce6", "nForce NVENET_6 Ethernet Controller"),
++PCI_ROM(0x10de, 0x00df, "nforce7", "nForce NVENET_7 Ethernet Controller"),
++PCI_ROM(0x10de, 0x0056, "nforce8", "nForce NVENET_8 Ethernet Controller"),
++PCI_ROM(0x10de, 0x0057, "nforce9", "nForce NVENET_9 Ethernet Controller"),
++PCI_ROM(0x10de, 0x0037, "nforce10", "nForce NVENET_10 Ethernet Controller"),
++PCI_ROM(0x10de, 0x0038, "nforce11", "nForce NVENET_11 Ethernet Controller"),
++};
++
++PCI_DRIVER ( forcedeth_driver, forcedeth_nics, PCI_NO_CLASS );
++
DRIVER ( "forcedeth", nic_driver, pci_driver, forcedeth_driver,
forcedeth_probe, forcedeth_disable );