diff --git a/src/arch/armnommu/Config b/src/arch/armnommu/Config index 4c220cd5..57942038 100644 --- a/src/arch/armnommu/Config +++ b/src/arch/armnommu/Config @@ -17,6 +17,12 @@ CFLAGS+= -DRAWADDR=0x40100000 # NIC Debug Outputs #CFLAGS+= -DDEBUG_NIC +# Reduced Media Independent Interface +# MAZBR LPEC2001: MII (Intel LXT971ALE at 0..1) +# Elmeg D@VOS : RMII (Altima AC104-QF at 4..7) +# Telekom XI521 : RMII (Altima AC104-QF at 4..7) +#CFLAGS+= -DRMII + # Fixed MAC address # p2001_eth has no flash and fixed mac address #CFLAGS+= -DMAC_HW_ADDR_DRV="'H','Y','L','N','X','1'" diff --git a/src/arch/armnommu/core/serial.c b/src/arch/armnommu/core/serial.c index 3ae98d47..0fb6e79b 100644 --- a/src/arch/armnommu/core/serial.c +++ b/src/arch/armnommu/core/serial.c @@ -17,7 +17,7 @@ void serial_putc(int ch) { /* wait for room in the 32 byte tx FIFO */ while ((P2001_UART->r.STATUS & 0x3f) > /* 30 */ 0) ; - P2001_UART->w.TX1 = ch & 0xff; + P2001_UART->w.TX[0] = ch & 0xff; } /* @@ -27,7 +27,7 @@ void serial_putc(int ch) int serial_getc(void) { while (((P2001_UART->r.STATUS >> 6) & 0x3f) == 0) ; - return P2001_UART->r.RX1 & 0xff; + return P2001_UART->r.RX[0] & 0xff; } /* diff --git a/src/arch/armnommu/drivers/net/p2001_eth.c b/src/arch/armnommu/drivers/net/p2001_eth.c index 81bc84c3..bdf2f0e9 100644 --- a/src/arch/armnommu/drivers/net/p2001_eth.c +++ b/src/arch/armnommu/drivers/net/p2001_eth.c @@ -1,10 +1,10 @@ /************************************************************************** -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 @@ -19,7 +19,7 @@ P2001 NIC driver for Etherboot #include "isa.h" #include "hardware.h" -#include "lxt971a.h" +#include "mii.h" #include "timer.h" @@ -31,25 +31,20 @@ static unsigned char MAC_HW_ADDR[6]={MAC_HW_ADDR_DRV}; #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); @@ -60,103 +55,107 @@ static void p2001_eth_init (); 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"); - - /* 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; - - /* 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"); -} - -static void p2001_eth_mdio_write(unsigned int phyadr, unsigned int regadr, unsigned int data) -{ - static unsigned int count; - count = 0; - - /* Warten bis Hardware inaktiv (MIU = "0") */ - while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT)) - count++; - - /* Schreiben MU_DATA */ - MU->MU_DATA = data; - - /* Schreiben MU_CNTL */ - MU->MU_CNTL = regadr + (phyadr<<5) + (1<<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++; - - mdio_error = (count >= MDIO_MAXCOUNT); -} - -static unsigned int p2001_eth_mdio_read(unsigned int phyadr, unsigned int regadr) -{ - static unsigned int count; - count = 0; + int result, boguscnt = 1000; do { /* Warten bis Hardware inaktiv (MIU = "0") */ - while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT)) - count++; + while (P2001_MU->MU_CNTL & 0x8000) + barrier(); /* Schreiben MU_CNTL */ - MU->MU_CNTL = regadr + (phyadr<<5) + (2<<10); + P2001_MU->MU_CNTL = location + (phy_id<<5) + (2<<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++; + while (P2001_MU->MU_CNTL & 0x8000) + barrier(); /* Fehler, wenn MDIO Read Error (MRE = "1") */ - } while ((MU->MU_CNTL & 0x4000) && (count < MDIO_MAXCOUNT)); + } while ((P2001_MU->MU_CNTL & 0x4000) && (--boguscnt > 0)); /* Lesen MU_DATA */ - mdio_error = (count >= MDIO_MAXCOUNT); - return MU->MU_DATA; + result = P2001_MU->MU_DATA; + + if (boguscnt == 0) + return 0; + if ((result & 0xffff) == 0xffff) + return 0; + + return result & 0xffff; } +/** + * 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 (P2001_MU->MU_CNTL & 0x8000) + barrier(); + + /* Schreiben MU_DATA */ + P2001_MU->MU_DATA = val; + + /* Schreiben MU_CNTL */ + P2001_MU->MU_CNTL = location + (phy_id<<5) + (1<<10); + + /* 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(); +} + + + /************************************************************************** -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. @@ -231,9 +230,11 @@ static int p2001_eth_poll(struct nic *nic, int retrieve) } + /************************************************************************** -TRANSMIT - Transmit a frame -***************************************************************************/ + * TRANSMIT - Transmit a frame + **************************************************************************/ + /* Function: p2001_eth_transmit * * Description: transmits a packet and waits for completion or timeout. @@ -271,7 +272,7 @@ static void p2001_eth_transmit( // 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 */ @@ -281,12 +282,12 @@ static void p2001_eth_transmit( /* 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); @@ -294,9 +295,11 @@ static void p2001_eth_transmit( } + /************************************************************************** -IRQ - Enable, Disable or Force Interrupts -***************************************************************************/ + * IRQ - Enable, Disable or Force Interrupts + **************************************************************************/ + /* Function: p2001_eth_irq * * Description: Enable, Disable, or Force, interrupts @@ -321,9 +324,11 @@ p2001_eth_irq(struct nic *nic __unused, irq_action_t action __unused) } + /************************************************************************** -INIT - Initialize device -***************************************************************************/ + * INIT - Initialize device + **************************************************************************/ + /* Function: p2001_init * * Description: resets the ethernet controller chip and various @@ -335,6 +340,23 @@ static void p2001_eth_init() { 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 */ @@ -353,7 +375,7 @@ static void p2001_eth_init() // 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; @@ -371,9 +393,12 @@ static void p2001_eth_init() 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 */ @@ -384,9 +409,10 @@ static void p2001_eth_init() } + /************************************************************************** -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 */ @@ -408,40 +434,52 @@ static void p2001_eth_disable(struct dev *dev __unused) } + /************************************************************************** -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"); @@ -449,49 +487,79 @@ failed: } + /************************************************************************** -PROBE - Look for an adapter, this routine's visible to the outside -***************************************************************************/ + * 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 + **************************************************************************/ + 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); @@ -507,7 +575,6 @@ static int p2001_eth_probe(struct dev *dev, unsigned short *probe_addrs __unused /* Report the ISA pnp id of the board */ dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR); - dev->devid.vendor_id = htons(0x1234); return 1; } } diff --git a/src/arch/armnommu/include/hardware.h b/src/arch/armnommu/include/hardware.h index 203b78b7..49264d63 100644 --- a/src/arch/armnommu/include/hardware.h +++ b/src/arch/armnommu/include/hardware.h @@ -100,10 +100,7 @@ typedef struct { // 0x00130000U typedef union { // 0x00140000U struct { // write - volatile unsigned int TX1; // 0x00000000U - volatile unsigned int TX2; // 0x00000004U - volatile unsigned int TX3; // 0x00000008U - volatile unsigned int TX4; // 0x0000000CU + volatile unsigned int TX[4]; // 0x00000000-0x000CU volatile unsigned int Baudrate; // 0x00000010U volatile unsigned int reserved1[0x3]; volatile unsigned int Config; // 0x00000020U @@ -113,10 +110,7 @@ typedef union { // 0x00140000U } w; // write struct { // read - volatile unsigned int RX1; // 0x00000000U - volatile unsigned int RX2; // 0x00000004U - volatile unsigned int RX3; // 0x00000008U - volatile unsigned int RX4; // 0x0000000CU + volatile unsigned int RX[4]; // 0x00000000-0x000CU volatile unsigned int reserved1[0x4]; volatile unsigned int PRE_STATUS; // 0x00000020U volatile unsigned int STATUS; // 0x00000024U @@ -168,11 +162,8 @@ typedef struct { // 0x0018_000U _=0,1,2,3 volatile unsigned int TMAC_DMA_DATA; // 0x00000FF8U volatile unsigned int TMAC_DMA_ADR; // 0x00000FFCU } *P2001_ETH_regs_ptr; -#define P2001_EU0 ((volatile P2001_ETH_regs_ptr) 0x00180000) -#define P2001_EU1 ((volatile P2001_ETH_regs_ptr) 0x00181000) -#define P2001_EU2 ((volatile P2001_ETH_regs_ptr) 0x00182000) -#define P2001_EU3 ((volatile P2001_ETH_regs_ptr) 0x00183000) -#define P2001_MU P2001_EU0 +#define P2001_EU(x) ((volatile P2001_ETH_regs_ptr) ((unsigned int) 0x00180000UL+(0x1000UL*(x)))) /* x = 0..3 */ +#define P2001_MU P2001_EU(0) #endif diff --git a/src/arch/armnommu/include/lxt971a.h b/src/arch/armnommu/include/lxt971a.h deleted file mode 100644 index 16314ec2..00000000 --- a/src/arch/armnommu/include/lxt971a.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2004 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 - * published by the Free Software Foundation. - */ - -/* - * Intel LXT971ALE (MII-compatible PHY) - */ - -#define Adr_LXT971A_Control 0 /* Control Register */ -#define Adr_LXT971A_Status1 1 /* MII Status Register #1 */ -#define Adr_LXT971A_PHY_ID1 2 /* PHY Identification Register 1 */ -#define Adr_LXT971A_PHY_ID2 3 /* PHY Identification Register 2 */ -#define Adr_LXT971A_AN_Advertise 4 /* Auto Negotiation Advertisement Register */ -#define Adr_LXT971A_AN_Link_Ability 5 /* Auto Negotiation Link Partner Base Page Ability Register */ -#define Adr_LXT971A_AN_Expansion 6 /* Auto Negotiation Expansion */ -#define Adr_LXT971A_AN_Next_Page_Txmit 7 /* Auto Negotiation Next Page Transmit Register */ -#define Adr_LXT971A_AN_Link_Next_Page 8 /* Auto Negotiation Link Partner Next Page Receive Register */ -#define Adr_LXT971A_Fast_Control 9 /* Not Implemented */ -#define Adr_LXT971A_Fast_Status 10 /* Not Implemented */ -#define Adr_LXT971A_Extended_Status 15 /* Not Implemented */ -#define Adr_LXT971A_Port_Config 16 /* Configuration Register */ -#define Adr_LXT971A_Status2 17 /* Status Register #2 */ -#define Adr_LXT971A_Interrupt_Enable 18 /* Interrupt Enable Register */ -#define Adr_LXT971A_Interrupt_Status 19 /* Interrupt Status Register */ -#define Adr_LXT971A_LED_Config 20 /* LED Configuration Register */ -#define Adr_LXT971A_Transmit_Control 30 /* Transmit Control Register */ diff --git a/src/arch/armnommu/include/stdint.h b/src/arch/armnommu/include/stdint.h index 3f5dc3f9..1cb00851 100644 --- a/src/arch/armnommu/include/stdint.h +++ b/src/arch/armnommu/include/stdint.h @@ -20,4 +20,16 @@ typedef signed short int16_t; typedef signed int int32_t; typedef signed long long int64_t; +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed long s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + #endif /* STDINT_H */ diff --git a/src/arch/e1/include/stdint.h b/src/arch/e1/include/stdint.h index 8a7ad978..505cc375 100644 --- a/src/arch/e1/include/stdint.h +++ b/src/arch/e1/include/stdint.h @@ -13,4 +13,16 @@ typedef signed short int16_t; typedef signed int int32_t; typedef signed long long int64_t; +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed long s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + #endif /* STDINT_H */ diff --git a/src/arch/i386/core/freebsd_loader.c b/src/arch/i386/core/freebsd_loader.c index 4e820e8e..464f6d93 100644 --- a/src/arch/i386/core/freebsd_loader.c +++ b/src/arch/i386/core/freebsd_loader.c @@ -216,7 +216,7 @@ static int elf_freebsd_debug_loader(unsigned int offset) estate.toread, estate.curaddr); #endif /* Save where we are loading this... */ - symtab_load = phys_to_virt(estate.curaddr); + symtab_load = estate.curaddr; *((long *)phys_to_virt(estate.curaddr)) = estate.toread; estate.curaddr += sizeof(long); @@ -244,7 +244,7 @@ static int elf_freebsd_debug_loader(unsigned int offset) estate.toread, estate.curaddr); #endif /* Save where we are loading this... */ - symstr_load = phys_to_virt(estate.curaddr); + symstr_load = estate.curaddr; *((long *)phys_to_virt(estate.curaddr)) = estate.toread; estate.curaddr += sizeof(long); @@ -290,7 +290,7 @@ static void elf_freebsd_boot(unsigned long entry) /* Assumes size of long is a power of 2... */ bsdinfo.bi_esymtab = (symstr_load + sizeof(long) + - *((long *)symstr_load) + + *((long *)phys_to_virt(symstr_load)) + sizeof(long) - 1) & ~(sizeof(long) - 1); /* Where we will build the meta data... */ diff --git a/src/arch/i386/include/stdint.h b/src/arch/i386/include/stdint.h index b9ade4e0..c801cf6f 100644 --- a/src/arch/i386/include/stdint.h +++ b/src/arch/i386/include/stdint.h @@ -16,4 +16,16 @@ typedef signed long long int64_t; typedef unsigned long physaddr_t; +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + #endif /* STDINT_H */ diff --git a/src/arch/ia64/include/stdint.h b/src/arch/ia64/include/stdint.h index 2f9c592c..8d8270be 100644 --- a/src/arch/ia64/include/stdint.h +++ b/src/arch/ia64/include/stdint.h @@ -13,4 +13,16 @@ typedef signed short int16_t; typedef signed int int32_t; typedef signed long int64_t; +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long s64; +typedef unsigned long u64; + #endif /* STDINT_H */ diff --git a/src/core/config.c b/src/core/config.c index f8683063..7756c634 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -74,6 +74,9 @@ void print_config ( void ) { #ifdef DOWNLOAD_PROTO_TFTP "TFTP " #endif +#ifdef DOWNLOAD_PROTO_FSP + "FSP " +#endif #ifdef DOWNLOAD_PROTO_NFS "NFS " #endif diff --git a/src/drivers/net/3c515.c b/src/drivers/net/3c515.c index 7fcc9f0f..c8749500 100644 --- a/src/drivers/net/3c515.c +++ b/src/drivers/net/3c515.c @@ -61,10 +61,6 @@ static void t3c515_wait(unsigned int nticks) /* TJL definations */ #define HZ 100 -#define u16 unsigned short -#define u32 unsigned long -#define s16 signed short -#define s32 signed long static int if_port; static struct corkscrew_private *vp; /* Brought directly from 3c515.c by Becker */ diff --git a/src/drivers/net/davicom.c b/src/drivers/net/davicom.c index fdbf9834..d087e29e 100644 --- a/src/drivers/net/davicom.c +++ b/src/drivers/net/davicom.c @@ -50,13 +50,6 @@ #define TX_TIME_OUT 2*TICKS_PER_SEC -typedef unsigned char u8; -typedef signed char s8; -typedef unsigned short u16; -typedef signed short s16; -typedef unsigned int u32; -typedef signed int s32; - /* Register offsets for davicom device */ enum davicom_offsets { CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28, diff --git a/src/drivers/net/depca.c b/src/drivers/net/depca.c index 3707da64..cc904c71 100644 --- a/src/drivers/net/depca.c +++ b/src/drivers/net/depca.c @@ -413,13 +413,6 @@ static char *adapter_name[] = { #define ALIGN8 ((u32)8 - 1) /* 2 longword (quadword) align */ #define ALIGN ALIGN8 /* Keep the LANCE happy... */ -typedef long s32; -typedef unsigned long u32; -typedef short s16; -typedef unsigned short u16; -typedef char s8; -typedef unsigned char u8; - /* ** The DEPCA Rx and Tx ring descriptors. */ diff --git a/src/drivers/net/dmfe.c b/src/drivers/net/dmfe.c index 4061ebfc..e1ff44ec 100644 --- a/src/drivers/net/dmfe.c +++ b/src/drivers/net/dmfe.c @@ -51,13 +51,6 @@ #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; - /* Condensed operations for readability. */ #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) #define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) diff --git a/src/drivers/net/eepro.c b/src/drivers/net/eepro.c index 6c2318bd..65c6c8f5 100644 --- a/src/drivers/net/eepro.c +++ b/src/drivers/net/eepro.c @@ -18,6 +18,12 @@ Be careful with seating the EPROM as the socket on my board actually has 34 pins, the top row of 2 are not used. ***************************************************************************/ +/* + + timlegge 2005-05-18 remove the relocation changes cards that + write directly to the hardware don't need it +*/ + /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -257,8 +263,8 @@ static unsigned eeprom_reg = EEPROM_REG_PRO; #define eeprom_delay() { udelay(40); } #define EE_READ_CMD (6 << 6) -/* do a full reset */ -#define eepro_full_reset(ioaddr) outb(RESET_CMD, ioaddr); udelay(40); +/* do a full reset; data sheet asks for 250us delay */ +#define eepro_full_reset(ioaddr) outb(RESET_CMD, ioaddr); udelay(255); /* do a nice reset */ #define eepro_sel_reset(ioaddr) { \ @@ -320,13 +326,15 @@ static void eepro_reset(struct nic *nic) eepro_sw2bank0(nic->ioaddr); /* Switch back to bank 0 */ eepro_clear_int(nic->ioaddr); /* Initialise RCV */ - rx_start = (unsigned int)bus_to_virt(RCV_LOWER_LIMIT << 8); - outw(RCV_LOWER_LIMIT << 8, nic->ioaddr + RCV_BAR); + outw(rx_start = (RCV_LOWER_LIMIT << 8), nic->ioaddr + RCV_BAR); outw(((RCV_UPPER_LIMIT << 8) | 0xFE), nic->ioaddr + RCV_STOP); + /* Make sure 1st poll won't find a valid packet header */ + outw((RCV_LOWER_LIMIT << 8), nic->ioaddr + HOST_ADDRESS_REG); + outw(0, nic->ioaddr + IO_PORT); /* Intialise XMT */ outw((XMT_LOWER_LIMIT << 8), nic->ioaddr + xmt_bar); eepro_sel_reset(nic->ioaddr); - tx_start = tx_end = (unsigned int)bus_to_virt(XMT_LOWER_LIMIT << 8); + tx_start = tx_end = (XMT_LOWER_LIMIT << 8); tx_last = 0; eepro_en_rx(nic->ioaddr); } @@ -336,7 +344,7 @@ POLL - Wait for a frame ***************************************************************************/ static int eepro_poll(struct nic *nic, int retrieve) { - unsigned int rcv_car = virt_to_bus((void *)rx_start); + unsigned int rcv_car = rx_start; unsigned int rcv_event, rcv_status, rcv_next_frame, rcv_size; /* return true if there's an ethernet packet ready to read */ @@ -380,8 +388,12 @@ static int eepro_poll(struct nic *nic, int retrieve) } #endif nic->packetlen = rcv_size; - rcv_car = virt_to_bus((void *) (rx_start + RCV_HEADER + rcv_size)); - rx_start = (unsigned int)bus_to_virt(rcv_next_frame << 8); + rcv_car = (rx_start + RCV_HEADER + rcv_size); + rx_start = rcv_next_frame; +/* + hex_dump(rcv_car, nic->packetlen); +*/ + if (rcv_car == 0) rcv_car = ((RCV_UPPER_LIMIT << 8) | 0xff); outw(rcv_car - 1, nic->ioaddr + RCV_STOP); @@ -455,7 +467,7 @@ static void eepro_disable ( struct nic *nic, struct isa_device *isa __unused ) { eepro_sw2bank0(nic->ioaddr); /* Switch to bank 0 */ /* Flush the Tx and disable Rx */ outb(STOP_RCV_CMD, nic->ioaddr); - tx_start = tx_end = (unsigned int) (bus_to_virt(XMT_LOWER_LIMIT << 8)); + tx_start = tx_end = (XMT_LOWER_LIMIT << 8); tx_last = 0; /* Reset the 82595 */ eepro_full_reset(nic->ioaddr); diff --git a/src/drivers/net/eepro100.c b/src/drivers/net/eepro100.c index 590b37c8..d97b1b18 100644 --- a/src/drivers/net/eepro100.c +++ b/src/drivers/net/eepro100.c @@ -110,13 +110,6 @@ static int ioaddr; -typedef unsigned char u8; -typedef signed char s8; -typedef unsigned short u16; -typedef signed short s16; -typedef unsigned int u32; -typedef signed int s32; - enum speedo_offsets { SCBStatus = 0, SCBCmd = 2, /* Rx/Command Unit command and status. */ SCBPointer = 4, /* General purpose pointer. */ diff --git a/src/drivers/net/forcedeth.c b/src/drivers/net/forcedeth.c index 3297effd..63773836 100644 --- a/src/drivers/net/forcedeth.c +++ b/src/drivers/net/forcedeth.c @@ -30,14 +30,16 @@ * (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 ***************************************************************************/ @@ -49,9 +51,10 @@ #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 @@ -60,12 +63,7 @@ #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)) @@ -73,22 +71,35 @@ typedef signed int s32; 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 @@ -98,7 +109,7 @@ enum { #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 @@ -125,7 +136,7 @@ enum { 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, @@ -134,6 +145,8 @@ enum { 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 @@ -147,6 +160,9 @@ enum { NvRegMulticastMaskA = 0xB8, NvRegMulticastMaskB = 0xBC, + NvRegPhyInterface = 0xC0, +#define PHY_RGMII 0x10000000 + NvRegTxRingPhysAddr = 0x100, NvRegRxRingPhysAddr = 0x104, NvRegRingSizes = 0x108, @@ -155,12 +171,12 @@ enum { 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 @@ -168,6 +184,7 @@ enum { #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 @@ -179,15 +196,15 @@ enum { 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, @@ -201,6 +218,7 @@ enum { #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, @@ -218,30 +236,61 @@ enum { #define NVREG_POWERSTATE_D3 0x0003 }; +#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_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_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<<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 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 @@ -266,27 +315,73 @@ enum { #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 */ +#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; }; @@ -310,22 +405,25 @@ static struct forcedeth_private { 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; @@ -335,6 +433,13 @@ static inline void pci_push(u8 * base) /* 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) { @@ -383,18 +488,11 @@ static int mii_rw(struct nic *nic __unused, int addr, int miireg, 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); @@ -402,7 +500,7 @@ static int mii_rw(struct nic *nic __unused, int addr, int miireg, } 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; @@ -424,20 +522,123 @@ static int mii_rw(struct nic *nic __unused, int addr, int miireg, 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; @@ -497,11 +698,12 @@ static void txrx_reset(struct nic *nic __unused) 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); } @@ -519,9 +721,9 @@ static int alloc_rx(struct nic *nic __unused) //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++; @@ -534,8 +736,67 @@ static int alloc_rx(struct nic *nic __unused) 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", @@ -560,30 +821,81 @@ static int update_linkspeed(struct nic *nic) 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); } @@ -637,15 +949,21 @@ static int forcedeth_reset(struct nic *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 */ { @@ -661,51 +979,40 @@ static int forcedeth_reset(struct nic *nic) 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(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); @@ -714,8 +1021,8 @@ static int forcedeth_reset(struct nic *nic) 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); @@ -724,36 +1031,24 @@ static int forcedeth_reset(struct nic *nic) 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); @@ -768,22 +1063,32 @@ static int forcedeth_reset(struct nic *nic) 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 ***************************************************************************/ @@ -793,26 +1098,35 @@ static int forcedeth_poll(struct nic *nic, int retrieve) /* 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); @@ -831,7 +1145,6 @@ static void forcedeth_transmit(struct nic *nic, const char *d, /* Destination */ /* send the packet to destination */ u8 *ptxb; u16 nstype; - //u16 status; u8 *base = (u8 *) BASE; int nr = np->next_tx % TX_RING; @@ -851,14 +1164,12 @@ static void forcedeth_transmit(struct nic *nic, const char *d, /* Destination */ 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++; } @@ -896,16 +1207,17 @@ static void forcedeth_disable ( struct nic *nic __unused ) { /************************************************************************** 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 = { @@ -916,14 +1228,6 @@ 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 ***************************************************************************/ @@ -935,6 +1239,7 @@ static int forcedeth_probe ( struct nic *nic, struct pci_device *pci ) { unsigned long addr; int sz; u8 *base; + int i; if (pci->ioaddr == 0) return 0; @@ -956,6 +1261,15 @@ static int forcedeth_probe ( struct nic *nic, struct pci_device *pci ) { 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; @@ -992,36 +1306,121 @@ static int forcedeth_probe ( struct nic *nic, struct pci_device *pci ) { #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 ); diff --git a/src/drivers/net/mtd80x.c b/src/drivers/net/mtd80x.c index 3d974abc..c7754a94 100644 --- a/src/drivers/net/mtd80x.c +++ b/src/drivers/net/mtd80x.c @@ -30,13 +30,6 @@ /* to get the PCI support functions, if this is a PCI NIC */ #include "pci.h" -typedef unsigned char u8; -typedef signed char s8; -typedef unsigned short u16; -typedef signed short s16; -typedef unsigned int u32; -typedef signed int s32; - /* Condensed operations for readability. */ #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) #define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 003b9798..774b5e31 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -71,13 +71,6 @@ #define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */ -typedef uint8_t u8; -typedef int8_t s8; -typedef uint16_t u16; -typedef int16_t s16; -typedef uint32_t u32; -typedef int32_t s32; - /* helpful macroes if on a big_endian machine for changing byte order. not strictly needed on Intel */ #define get_unaligned(ptr) (*(ptr)) diff --git a/src/drivers/net/ns83820.c b/src/drivers/net/ns83820.c index d4fafb68..df9eec5a 100755 --- a/src/drivers/net/ns83820.c +++ b/src/drivers/net/ns83820.c @@ -53,13 +53,6 @@ #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 HZ 100 /* Condensed operations for readability. */ diff --git a/src/drivers/net/pcnet32.c b/src/drivers/net/pcnet32.c index 5a0bb14c..4255269b 100644 --- a/src/drivers/net/pcnet32.c +++ b/src/drivers/net/pcnet32.c @@ -54,13 +54,6 @@ #define drv_version "v1.3" #define drv_date "03-29-2004" -typedef unsigned char u8; -typedef signed char s8; -typedef unsigned short u16; -typedef signed short s16; -typedef unsigned int u32; -typedef signed int s32; - static u32 ioaddr; /* Globally used for the card's io address */ static struct nic_operations pcnet32_operations; static struct pci_driver pcnet32_driver; diff --git a/src/drivers/net/r8169.c b/src/drivers/net/r8169.c index ad3b62bd..427fad0f 100644 --- a/src/drivers/net/r8169.c +++ b/src/drivers/net/r8169.c @@ -52,13 +52,6 @@ #define drv_version "v1.6" #define drv_date "03-27-2004" -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 HZ 1000 static u32 ioaddr; diff --git a/src/drivers/net/sis900.h b/src/drivers/net/sis900.h index 89aa3aa5..e88e111d 100644 --- a/src/drivers/net/sis900.h +++ b/src/drivers/net/sis900.h @@ -363,13 +363,6 @@ enum sis630_revision_id { #define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */ -typedef unsigned char u8; -typedef signed char s8; -typedef unsigned short u16; -typedef signed short s16; -typedef unsigned int u32; -typedef signed int s32; - /* Time in ticks before concluding the transmitter is hung. */ #define TX_TIMEOUT (4*TICKS_PER_SEC) diff --git a/src/drivers/net/sundance.c b/src/drivers/net/sundance.c index 05621d4f..701f922a 100644 --- a/src/drivers/net/sundance.c +++ b/src/drivers/net/sundance.c @@ -52,13 +52,6 @@ #define drv_version "v1.12" #define drv_date "2004-03-21" -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 HZ 100 /* Condensed operations for readability. */ diff --git a/src/drivers/net/tg3.c b/src/drivers/net/tg3.c index 2d881f08..ace2dfec 100644 --- a/src/drivers/net/tg3.c +++ b/src/drivers/net/tg3.c @@ -9,6 +9,7 @@ /* 11-13-2003 timlegge Fix Issue with NetGear GA302T * 11-18-2003 ebiederm Generalize NetGear Fix to what the code was supposed to be. * 01-06-2005 Alf (Frederic Olivie) Add Dell bcm 5751 (0x1677) support + * 04-15-2005 Martin Vogt Add Fujitsu Siemens Computer (FSC) 0x1734 bcm 5751 0x105d support */ #include "etherboot.h" @@ -2413,6 +2414,9 @@ static struct subsys_tbl_ent subsys_id_to_phy_id[] = { { PCI_VENDOR_ID_DELL, 0x0109, PHY_ID_BCM5411 }, /* MERLOT */ { PCI_VENDOR_ID_DELL, 0x010a, PHY_ID_BCM5411 }, /* SLIM_MERLOT */ { PCI_VENDOR_ID_DELL, 0x0179, PHY_ID_BCM5751 }, /* EtherXpress */ + + /* Fujitsu Siemens Computer */ + { PCI_VENDOR_ID_FSC, 0x105d, PHY_ID_BCM5751 }, /* Futro C200 */ /* Compaq boards. */ { PCI_VENDOR_ID_COMPAQ, 0x007c, PHY_ID_BCM5701 }, /* BANSHEE */ diff --git a/src/drivers/net/tg3.h b/src/drivers/net/tg3.h index 6e05b9cc..fd038f58 100644 --- a/src/drivers/net/tg3.h +++ b/src/drivers/net/tg3.h @@ -2156,7 +2156,7 @@ struct tg3 { ((X) == PHY_ID_BCM5400 || (X) == PHY_ID_BCM5401 || \ (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \ (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \ - (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5751 || \ + (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || (X) == PHY_ID_BCM5751 || \ (X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES) unsigned long regs; diff --git a/src/drivers/net/tlan.h b/src/drivers/net/tlan.h index e0379a7b..de57d598 100644 --- a/src/drivers/net/tlan.h +++ b/src/drivers/net/tlan.h @@ -34,22 +34,10 @@ * Indent Style: indent -kr -i8 ***************************************************************************/ -/* -#include -#include -#include -*/ - -typedef unsigned char u8; -typedef signed char s8; -typedef unsigned short u16; -typedef signed short s16; -typedef unsigned int u32; -typedef signed int s32; - /***************************************************************** - * TLan Definitions - * - ****************************************************************/ +/***************************************************************** +* TLan Definitions +* +****************************************************************/ #define FALSE 0 #define TRUE 1 diff --git a/src/drivers/net/tulip.c b/src/drivers/net/tulip.c index 28e38d95..279e0dbc 100644 --- a/src/drivers/net/tulip.c +++ b/src/drivers/net/tulip.c @@ -48,6 +48,8 @@ /*********************************************************************/ /* + 08 Feb 2005 Ramesh Chander chhabaramesh at yahoo.co.in added table entries + for SGThomson STE10/100A 07 Sep 2003 timlegge Multicast Support Added 11 Apr 2001 mdc [patch to etherboot 4.7.24] Major rewrite to include Linux tulip driver media detection @@ -118,13 +120,6 @@ static int tulip_debug = 2; /* 1 normal messages, 0 quiet .. 7 verbo #define TX_TIME_OUT 2*TICKS_PER_SEC -typedef uint8_t u8; -typedef int8_t s8; -typedef uint16_t u16; -typedef int16_t s16; -typedef uint32_t u32; -typedef int32_t s32; - /* helpful macros if on a big_endian machine for changing byte order. not strictly needed on Intel */ #define get_unaligned(ptr) (*(ptr)) @@ -157,7 +152,7 @@ static const char * const medianame[32] = { enum tulip_chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3, LC82C168, MX98713, MX98715, MX98725, AX88141, AX88140, PNIC2, COMET, - COMPEX9881, I21145, XIRCOM + COMPEX9881, I21145, XIRCOM, SGThomson, /*Ramesh Chander*/ }; enum pci_id_flags_bits { @@ -233,6 +228,8 @@ static const struct pci_id_info pci_id_tbl[] = { TULIP_IOTYPE, 256, MX98715 }, { "3Com 3cSOHO100B-TX (ADMtek Centuar)", { 0x930010b7, 0xffffffff, 0, 0, 0, 0 }, TULIP_IOTYPE, TULIP_SIZE, COMET }, + { "SG Thomson STE10/100A", { 0x2774104a, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 256, COMET }, /*Ramesh Chander*/ { 0, { 0, 0, 0, 0, 0, 0 }, 0, 0, 0 }, }; @@ -268,6 +265,7 @@ static struct tulip_chip_table { | HAS_PWRDWN | HAS_NWAY }, { "Xircom tulip work-alike", HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY }, + { "SGThomson STE10/100A", HAS_MII | MC_HASH_ONLY }, /*Ramesh Chander*/ { 0, 0 }, }; @@ -2068,7 +2066,7 @@ PCI_ROM(0x125b, 0x1400, "ax88140", "ASIX AX88140"), PCI_ROM(0x11f6, 0x9881, "rl100tx", "Compex RL100-TX"), PCI_ROM(0x115d, 0x0003, "xircomtulip", "Xircom Tulip"), PCI_ROM(0x104a, 0x0981, "tulip-0981", "Tulip 0x104a 0x0981"), -PCI_ROM(0x104a, 0x2774, "tulip-2774", "Tulip 0x104a 0x2774"), +PCI_ROM(0x104a, 0x2774, "SGThomson-STE10100A", "Tulip 0x104a 0x2774"), /*Modified by Ramesh Chander*/ PCI_ROM(0x1113, 0x9511, "tulip-9511", "Tulip 0x1113 0x9511"), PCI_ROM(0x1186, 0x1561, "tulip-1561", "Tulip 0x1186 0x1561"), PCI_ROM(0x1259, 0xa120, "tulip-a120", "Tulip 0x1259 0xa120"), diff --git a/src/drivers/net/w89c840.c b/src/drivers/net/w89c840.c index 1ed3503c..c3f03f9f 100644 --- a/src/drivers/net/w89c840.c +++ b/src/drivers/net/w89c840.c @@ -84,13 +84,6 @@ static const char *w89c840_version = "driver Version 0.94 - December 12, 2003"; -typedef unsigned char u8; -typedef signed char s8; -typedef unsigned short u16; -typedef signed short s16; -typedef unsigned int u32; -typedef signed int s32; - /* Linux support functions */ #define virt_to_le32desc(addr) virt_to_bus(addr) #define le32desc_to_virt(addr) bus_to_virt(addr) diff --git a/src/include/pci_ids.h b/src/include/pci_ids.h index bcf4c3cd..a853d4dc 100644 --- a/src/include/pci_ids.h +++ b/src/include/pci_ids.h @@ -319,6 +319,7 @@ #define PCI_VENDOR_ID_MORETON 0x15aa #define PCI_VENDOR_ID_ZOLTRIX 0x15b0 #define PCI_VENDOR_ID_PDC 0x15e9 +#define PCI_VENDOR_ID_FSC 0x1734 #define PCI_VENDOR_ID_SYMPHONY 0x1c1c #define PCI_VENDOR_ID_TEKRAM 0x1de1 #define PCI_VENDOR_ID_3DLABS 0x3d3d diff --git a/src/util/makerom.pl b/src/util/makerom.pl index 695468c2..9d751e19 100755 --- a/src/util/makerom.pl +++ b/src/util/makerom.pl @@ -157,7 +157,7 @@ sub makerom () { # If PXE image, just fill the length field and write it out if ($opts{'x'}) { substr($rom, 2, 1) = chr((length($rom) + 511) / 512); - &writerom($ARGV[0], \$rom); + writerom($ARGV[0], \$rom); return; } # Size specified with -s overrides value in 3rd byte in image @@ -168,7 +168,7 @@ sub makerom () { $romsize = ($filesize + 511) & ~511 } } else { - $romsize = &getromsize(\$rom); + $romsize = getromsize(\$rom); # 0 put there by *loader.S means makerom should pick the size if ($romsize == 0) { # Shrink romsize down to the smallest power of two that will do @@ -190,14 +190,16 @@ sub makerom () { } substr($rom, 2, 1) = chr(($romsize / 512) % 256); print "ROM size is $romsize\n" if $opts{'v'}; - my $identoffset = &addident(\$rom); - &pcipnpheaders(\$rom, $identoffset); - &undiheaders(\$rom); + # set the product string only if we don't have one yet + my $pnp_hdr_offset = unpack('v', substr($rom, PNP_PTR_LOC, 2)); + my $identoffset = substr($rom, $pnp_hdr_offset+PNP_DEVICE_OFF, 2) eq "\0\0" ? addident(\$rom) : undef; + pcipnpheaders(\$rom, $identoffset); + undiheaders(\$rom); # 3c503 requires last two bytes to be 0x80 substr($rom, MINROMSIZE-2, 2) = "\x80\x80" if ($opts{'3'} and $romsize == MINROMSIZE); - &checksum(\$rom); - &writerom($ARGV[0], \$rom); + checksum(\$rom); + writerom($ARGV[0], \$rom); } sub modrom () { @@ -211,16 +213,16 @@ sub modrom () { close(R); defined($filesize) and $filesize >= 3 or die "Cannot get first 3 bytes of file\n"; print "$filesize bytes read\n" if $opts{'v'}; - &pcipnpheaders(\$rom); - &undiheaders(\$rom); - &checksum(\$rom); - &writerom($ARGV[0], \$rom); + pcipnpheaders(\$rom, undef); + undiheaders(\$rom); + checksum(\$rom); + writerom($ARGV[0], \$rom); } # Main routine. See how we were called and behave accordingly if ($0 =~ m:modrom(\.pl)?$:) { - &modrom(); + modrom(); } else { - &makerom(); + makerom(); } exit(0);