- Bugfixes in bootp code: need to swap Netmask, Gateway IP, etc.
- Change to (hopefully consistent) usage of htons/ntohs/htonl/ntohl
instead of SWAP16/SWAP32
- Bugfixes in 3c589 driver:
+ set correct MAC address (instead of swapped one)
+ additional delay required after init to make sure board
is ready to transmit
+ transmit data must be padded to *double* words (4 bytes)
+======================================================================
+Recent Modifications
+======================================================================
+
+* Big network patch by Robert Kaiser <rob@sysgo.de>:
+
+ - Bugfixes in bootp code: need to swap Netmask, Gateway IP, etc.
+
+ - Change to (hopefully consistent) usage of htons/ntohs/htonl/ntohl
+ instead of SWAP16/SWAP32
+
+ - Bugfixes in 3c589 driver:
+ + set correct MAC address (instead of swapped one)
+ + additional delay required after init to make sure board
+ is ready to transmit
+ + transmit data must be padded to *double* words (4 bytes)
+
======================================================================
Modifications for 1.1.0
======================================================================
N: Kyle Harris
E: kharris@nexus-tech.net
D: Support for the Xscale Lubbock and Cradle boards
+
+N: Robert Kaiser
+E: rob@sysgo.de
+D: Improvement for some of the networking code and 3c589 driver
/*------------------------------------------------------------------------
- . smc91111.c
- . This is a driver for SMSC's 91C111 single-chip Ethernet device.
+ . 3c589.c
+ . This is a driver for 3Com's 3C589 (Etherlink III) PCMCIA Ethernet device.
.
. (C) Copyright 2002
. Sysgo Real-Time Solutions, GmbH <www.elinos.com>
. Rolf Offermanns <rof@sysgo.de>
.
- . Copyright (C) 2001 Standard Microsystems Corporation (SMSC)
- . Developed by Simple Network Magic Corporation (SNMC)
- . Copyright (C) 1996 by Erik Stahlman (ES)
- .
. This program is free software; you can redistribute it and/or modify
. it under the terms of the GNU General Public License as published by
. the Free Software Foundation; either version 2 of the License, or
. along with this program; if not, write to the Free Software
. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
.
- . Information contained in this file was obtained from the LAN91C111
- . manual from SMC. To get a copy, if you really want one, you can find
- . information under www.smsc.com.
- .
- .
- . "Features" of the SMC chip:
- . Integrated PHY/MAC for 10/100BaseT Operation
- . Supports internal and external MII
- . Integrated 8K packet memory
- . EEPROM interface for configuration
- .
- . Arguments:
- . io = for the base address
- . irq = for the IRQ
- .
- . author:
- . Erik Stahlman ( erik@vt.edu )
- . Daris A Nevil ( dnevil@snmc.com )
- .
- .
- . Hardware multicast code from Peter Cammaert ( pc@denkart.be )
- .
- . Sources:
- . o SMSC LAN91C111 databook (www.smsc.com)
- . o smc9194.c by Erik Stahlman
- . o skeleton.c by Donald Becker ( becker@cesdis.gsfc.nasa.gov )
- .
- . History:
- . 10/17/01 Marco Hasewinkel Modify for DNP/1110
- . 07/25/01 Woojung Huh Modify for ADS Bitsy
- . 04/25/01 Daris A Nevil Initial public release through SMSC
- . 03/16/01 Daris A Nevil Modified smc9194.c for use with LAN91C111
----------------------------------------------------------------------------*/
#include "armboot.h"
/*------------------------------------------------------------------------
.
. The internal workings of the driver. If you are changing anything
- . here with the SMC stuff, you should have the datasheet and know
+ . here with the 3Com stuff, you should have the datasheet and know
. what you are doing.
.
-------------------------------------------------------------------------*/
return inw(ioaddr + 0xc);
}
-static void el_get_mac_addr( word *mac_addr )
+static void el_get_mac_addr( unsigned char *mac_addr )
{
int i;
+ union
+ {
+ word w;
+ unsigned char b[2];
+ } wrd;
unsigned char old_window = inw( EL_BASE_ADDR + EL3_STATUS ) >> 13;
GO_WINDOW(0);
VX_BUSY_WAIT;
for (i = 0; i < 3; i++)
{
- *(mac_addr+i) = read_eeprom(EL_BASE_ADDR, 0xa+i);
+ wrd.w = read_eeprom(EL_BASE_ADDR, 0xa+i);
+#ifdef __BIG_ENDIAN
+ mac_addr[2*i] = wrd.b[0];
+ mac_addr[2*i+1] = wrd.b[1];
+#else
+ mac_addr[2*i] = wrd.b[1];
+ mac_addr[2*i+1] = wrd.b[0];
+#endif
}
GO_WINDOW(old_window);
VX_BUSY_WAIT;
}
+#if EL_DEBUG > 1
static void print_packet( byte * buf, int length )
{
int i;
}
PRINTK2("\n");
}
+#endif /* EL_DEBUG > 1 */
udelay(100000000);
/* set mac addr */
-/*
- outw(0xfeca, BASE + VX_W2_ADDR_0);
- VX_BUSY_WAIT;
- outw(0xadde, BASE + VX_W2_ADDR_2);
- VX_BUSY_WAIT;
- outw(0xefbe, BASE + VX_W2_ADDR_4);
- VX_BUSY_WAIT;
-*/
{
- word *mac_addr = (word *)bd->bi_enetaddr;
+ unsigned char *mac_addr = bd->bi_enetaddr;
int i;
el_get_mac_addr( mac_addr );
VX_BUSY_WAIT;
printf("3C589 MAC Addr.: ");
- for (i = 0; i < 3; i++)
+ for (i = 0; i < 6; i++)
{
- printf("%04x", mac_addr[i]);
- outw(mac_addr[i], BASE + VX_W2_ADDR_0 + i*2);
+ printf("%02x", mac_addr[i]);
+ outb(mac_addr[i], BASE + VX_W2_ADDR_0 + i);
VX_BUSY_WAIT;
}
printf("\n\n");
GO_WINDOW(1);
VX_BUSY_WAIT;
+ /* wait for another 1ms */
+ udelay(100000000);
}
{
/* error in packet -> discard */
PRINTK("[ERROR] Invalid packet -> discarding\n");
+ PRINTK("-- error code 0x%02x\n", rx_status & ERR_MASK);
+ PRINTK("-- rx bytes 0x%04d\n", rx_status & ((1<<11) - 1));
+ PRINTK("[ERROR] Invalid packet -> discarding\n");
outw( RX_DISCARD_TOP_PACK, BASE + VX_COMMAND );
return 0;
}
/* Second dword meaningless */
outw(0x0, EL_BASE_ADDR + VX_W1_TX_PIO_WR_1);
+#if EL_DEBUG > 1
print_packet((byte *)buf, length);
+#endif
+
/* write packet */
{
- unsigned int i, totdw;
+ unsigned int i, totw;
- totdw = ((length + 3) >> 1);
- PRINTK("Buffer: (totdw = %d)\n", totdw);
- for (i = 0; i < totdw; i++) {
+ totw = ((length + 1) >> 1);
+ PRINTK("Buffer: (totw = %d)\n", totw);
+ for (i = 0; i < totw; i++) {
outw( *(buf+i), EL_BASE_ADDR + VX_W1_TX_PIO_WR_1);
- PRINTK("%04x ", *(buf+i));
- if ( ((i % 8) == 0) && (i != 0) )
- PRINTK("\n");
+ udelay(10);
+ }
+ if(totw & 1)
+ { /* pad to double word length */
+ outw( 0, EL_BASE_ADDR + VX_W1_TX_PIO_WR_1);
udelay(10);
}
PRINTK("\n\n");
/* wait for Tx complete */
PRINTK("Waiting for Tx to complete...\n");
- while((inw(EL_BASE_ADDR + VX_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
+ while(((status = inw(EL_BASE_ADDR + VX_STATUS)) & S_COMMAND_IN_PROGRESS) != 0)
{
udelay(10);
}
- PRINTK(" ---> Tx completed\n");
+ PRINTK(" ---> Tx completed, status = 0x%04x\n", status);
return length;
}
/* Byte swapping stuff */
#define SWAP16(x) ((((x) & 0xff) << 8) | ((x) >> 8))
-#define SWAP16c(x) ((((x) & 0xff) << 8) | ((x) >> 8))
#define SWAP32(x) ( \
(((x) >> 24) & 0x000000ff) | \
(((x) >> 8) & 0x0000ff00) | \
(((x) << 8) & 0x00ff0000) | \
(((x) << 24) & 0xff000000) )
+#define htons(x) SWAP16(x)
+#define ntohs(x) SWAP16(x)
+#define htonl(x) SWAP32(x)
+#define ntohl(x) SWAP32(x)
+
#endif /* HOST_TOOLS */
#endif /* _ARMBOOT_H_ */
arp = (ARP_t *)pkt;
- arp->ar_hrd = SWAP16(ARP_ETHER);
- arp->ar_pro = SWAP16(PROT_IP);
+ arp->ar_hrd = htons(ARP_ETHER);
+ arp->ar_pro = htons(PROT_IP);
arp->ar_hln = 6;
arp->ar_pln = 4;
- arp->ar_op = SWAP16(ARPOP_REQUEST);
+ arp->ar_op = htons(ARPOP_REQUEST);
NetCopyEther(&arp->ar_data[0], NetOurEther); /* source ET addr */
NetWriteIP((uchar*)&arp->ar_data[6], NetOurIP); /* source IP addr */
if (dest != PORT_BOOTPC || src != PORT_BOOTPS)
retval = -1;
- if (len < sizeof (Bootp_t) - OPT_SIZE)
+ /* note: use "else if" instead of "if" or the debug message
+ below shows a wrong retval */
+ else if (len < sizeof (Bootp_t) - OPT_SIZE)
retval = -2;
- if (bp->bp_op != OP_BOOTREQUEST &&
+ else if (bp->bp_op != OP_BOOTREQUEST &&
bp->bp_op != OP_BOOTREPLY &&
bp->bp_op != DHCP_OFFER &&
bp->bp_op != DHCP_ACK &&
bp->bp_op != DHCP_NAK ) {
retval = -3;
}
- if (bp->bp_htype != HWT_ETHER)
+ else if (bp->bp_htype != HWT_ETHER)
retval = -4;
- if (bp->bp_hlen != HWL_ETHER)
+ else if (bp->bp_hlen != HWL_ETHER)
retval = -5;
- memcpy(&id, &bp->bp_id, sizeof(bp->bp_id));
- if (id != BootpID)
- retval = -6;
-
+ else
+ {
+ memcpy(&id, &bp->bp_id, sizeof(id));
+ id = ntohl(id);
+ if (id != BootpID)
+ retval = -6;
+ }
debug ("Filtering pkt = %d\n", retval);
return retval;
/* Fixed length fields */
case 1: /* Subnet mask */
if (NetOurSubnetMask == 0)
- memcpy(&NetOurSubnetMask, ext+2, 4);
+ NetOurSubnetMask = NetReadIP(ext+2);
break;
case 2: /* Time offset - Not yet supported */
break;
/* Variable length fields */
case 3: /* Gateways list */
if (NetOurGatewayIP == 0) {
- memcpy(&NetOurGatewayIP, ext+2, 4);
+ NetOurGatewayIP = NetReadIP(ext+2);
}
break;
case 4: /* Time server - Not yet supported */
break;
case 6:
if (NetOurDNSIP == 0) {
- memcpy(&NetOurDNSIP, ext+2, 4);
+ NetOurDNSIP = NetReadIP(ext+2);
}
break;
case 7: /* Log server - Not yet supported */
}
break;
case 13: /* Boot file size */
- memcpy(&NetBootFileSize, ext+2, size);
+ if(size == 2)
+ NetBootFileSize = ntohs(*(ushort*)(ext+2));
+ else if(size == 4)
+ NetBootFileSize = ntohl(*(ulong*)(ext+2));
break;
case 14: /* Merit dump file - Not yet supported */
break;
if (NetOurNISDomain[0]) {
printf("NetOurNISDomain : %s\n", NetOurNISDomain);
}
+
+ if (NetBootFileSize) {
+ printf("NetBootFileSize: %d\n", NetBootFileSize);
+ }
#endif
}
BootpCopyNetParams(bp); /* Store net parameters from reply */
/* Retrieve extended informations (we must parse the vendor area) */
- memcpy(&vendmagic, bp->bp_vend, 4);
- if (SWAP32(vendmagic) == BOOTP_VENDOR_MAGIC)
+ memcpy(&vendmagic, bp->bp_vend, sizeof(vendmagic));
+ if (ntohl(vendmagic) == BOOTP_VENDOR_MAGIC)
BootpVendorProcess(&bp->bp_vend[4], len);
NetSetTimeout(0, (thand_f *)0);
volatile uchar *pkt, *iphdr;
Bootp_t *bp;
int ext_len, pktlen, iplen;
+ ulong id;
#if (CONFIG_COMMANDS & CFG_CMD_DHCP)
dhcp_state = INIT;
bp->bp_htype = HWT_ETHER;
bp->bp_hlen = HWL_ETHER;
bp->bp_hops = 0;
- bp->bp_secs = SWAP16( get_timer(0) / CFG_HZ);
+ bp->bp_secs = htons( get_timer(0) / CFG_HZ);
NetWriteIP((vuchar*)&bp->bp_ciaddr, 0);
NetWriteIP((vuchar*)&bp->bp_yiaddr, 0);
NetWriteIP((vuchar*)&bp->bp_siaddr, 0);
| ((ulong)NetOurEther[4] << 8)
| (ulong)NetOurEther[5];
BootpID += get_timer(0);
- memcpy(&bp->bp_id, &BootpID, sizeof(bp->bp_id));
+
+ id = htonl(BootpID);
+ memcpy(&bp->bp_id, &id, sizeof(id));
/*
* Calculate proper packet lengths taking into account the
static int DhcpMessageType(unsigned char *popt)
{
ulong vendmagic;
- memcpy(&vendmagic, popt, 4);
- if (SWAP32(vendmagic) != BOOTP_VENDOR_MAGIC)
+ memcpy(&vendmagic, popt, sizeof(vendmagic));
+ if (ntohl(vendmagic) != BOOTP_VENDOR_MAGIC)
return -1;
popt += 4;
bp->bp_htype = HWT_ETHER;
bp->bp_hlen = HWL_ETHER;
bp->bp_hops = 0;
- bp->bp_secs = SWAP16( get_timer(0) / CFG_HZ);
+ bp->bp_secs = htons( get_timer(0) / CFG_HZ);
NetCopyIP((vuchar*)&bp->bp_ciaddr, (vuchar*)&bp_offer->bp_ciaddr);
NetCopyIP((vuchar*)&bp->bp_yiaddr, (vuchar*)&bp_offer->bp_yiaddr);
NetCopyIP((vuchar*)&bp->bp_siaddr, (vuchar*)&bp_offer->bp_siaddr);
* ID is the id of the OFFER packet
*/
- memcpy(bp->bp_id, bp_offer->bp_id, sizeof(bp->bp_id);
+ memcpy(&bp->bp_id, &bp_offer->bp_id, sizeof(bp->bp_id));
/*
* Copy options from OFFER packet if present
static void
DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
{
+ ulong vendmagic;
Bootp_t *bp = (Bootp_t *)pkt;
debug ("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",
debug ("TRANSITIONING TO REQUESTING STATE\n");
dhcp_state = REQUESTING;
#if 0
- if ((*(uint *)bp->bp_vend) == BOOTP_VENDOR_MAGIC)
+ memcpy(&vendmagic, bp->bp_vend, sizeof(vendmagic));
+ if (ntohl(vendmagic) == BOOTP_VENDOR_MAGIC)
DhcpOptionsProcess(&bp->bp_vend[4]);
#endif
debug ("DHCP State: REQUESTING\n");
if ( DhcpMessageType(bp->bp_vend) == DHCP_ACK ) {
- if ((*(uint *)bp->bp_vend) == BOOTP_VENDOR_MAGIC)
+ memcpy(&vendmagic, bp->bp_vend, sizeof(vendmagic));
+ if (ntohl(vendmagic) == BOOTP_VENDOR_MAGIC)
DhcpOptionsProcess(&bp->bp_vend[4]);
BootpCopyNetParams(bp); /* Store net params from reply */
dhcp_state = BOUND;
NetRxPktLen = len;
et = (Ethernet_t *)pkt;
- x = SWAP16(et->et_protlen);
+ x = ntohs(et->et_protlen);
if (x < 1514) {
/*
* Got a 802 packet. Check the other protocol field.
*/
- x = SWAP16(et->et_prot);
+ x = ntohs(et->et_prot);
ip = (IP_t *)(pkt + E802_HDR_SIZE);
len -= E802_HDR_SIZE;
#ifdef ET_DEBUG
printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
return;
}
- if (SWAP16(arp->ar_hrd) != ARP_ETHER) {
+ if (ntohs(arp->ar_hrd) != ARP_ETHER) {
return;
}
- if (SWAP16(arp->ar_pro) != PROT_IP) {
+ if (ntohs(arp->ar_pro) != PROT_IP) {
return;
}
if (arp->ar_hln != 6) {
}
}
- switch (SWAP16(arp->ar_op)) {
+ switch (ntohs(arp->ar_op)) {
case ARPOP_REQUEST: /* reply with our Ether address */
#ifdef ET_DEBUG
printf("Got ARP REQUEST, return our EtherAddr.\n");
#endif
NetSetEther((uchar *)et, et->et_src, PROT_ARP);
- arp->ar_op = SWAP16(ARPOP_REPLY);
+ arp->ar_op = htons(ARPOP_REPLY);
NetCopyEther(&arp->ar_data[0], NetOurEther);
NetWriteIP( &arp->ar_data[6], NetOurIP);
NetCopyEther(&arp->ar_data[10], NetOurEther);
return;
default:
#ifdef ET_DEBUG
- printf("Unexpected ARP opcode 0x%x\n", SWAP16(arp->ar_op));
+ printf("Unexpected ARP opcode 0x%x\n", ntohs(arp->ar_op));
#endif
return;
}
return;
}
- if ((SWAP16(arp->ar_op) != RARPOP_REPLY) ||
- (SWAP16(arp->ar_hrd) != ARP_ETHER) ||
- (SWAP16(arp->ar_pro) != PROT_IP) ||
+ if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||
+ (ntohs(arp->ar_hrd) != ARP_ETHER) ||
+ (ntohs(arp->ar_pro) != PROT_IP) ||
(arp->ar_hln != 6) || (arp->ar_pln != 4)) {
printf("invalid RARP header\n");
debug ("len bad %d < %d\n", len, IP_HDR_SIZE);
return;
}
- if (len < SWAP16(ip->ip_len)) {
- printf("len bad %d < %d\n", len, SWAP16(ip->ip_len));
+ if (len < ntohs(ip->ip_len)) {
+ printf("len bad %d < %d\n", len, ntohs(ip->ip_len));
return;
}
- len = SWAP16(ip->ip_len);
+ len = ntohs(ip->ip_len);
#ifdef ET_DEBUG
printf("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);
#endif
printf("version bad %x\n", ip->ip_hl_v & 0xf0);
return;
}
- if (ip->ip_off & SWAP16c(0x1fff)) { /* Can't deal w/ fragments */
+ if (ip->ip_off & htons(0x1fff)) { /* Can't deal w/ fragments */
printf("can't deal with fragments\n");
return;
}
* IP header OK. Pass the packet to the current handler.
*/
(*packetHandler)((uchar *)ip +IP_HDR_SIZE,
- SWAP16(ip->udp_dst),
- SWAP16(ip->udp_src),
- SWAP16(ip->udp_len) - 8);
+ ntohs(ip->udp_dst),
+ ntohs(ip->udp_src),
+ ntohs(ip->udp_len) - 8);
break;
default:
NetCopyEther(et->et_dest, addr);
NetCopyEther(et->et_src, NetOurEther);
- et->et_protlen = SWAP16(prot);
+ et->et_protlen = htons(prot);
}
*/
ip->ip_hl_v = 0x45; /* IP_HDR_SIZE / 4 (not including UDP) */
ip->ip_tos = 0;
- ip->ip_len = SWAP16(IP_HDR_SIZE + len);
- ip->ip_id = SWAP16(NetIPID++);
- ip->ip_off = SWAP16c(0x4000); /* No fragmentation */
+ ip->ip_len = htons(IP_HDR_SIZE + len);
+ ip->ip_id = htons(NetIPID++);
+ ip->ip_off = htons(0x4000); /* No fragmentation */
ip->ip_ttl = 255;
ip->ip_p = 17; /* UDP */
ip->ip_sum = 0;
NetWriteIP((uchar*)&ip->ip_src, NetOurIP);
NetWriteIP((uchar*)&ip->ip_dst, dest);
- ip->udp_src = SWAP16(sport);
- ip->udp_dst = SWAP16(dport);
- ip->udp_len = SWAP16(8 + len);
+ ip->udp_src = htons(sport);
+ ip->udp_dst = htons(dport);
+ ip->udp_len = htons(8 + len);
ip->udp_xsum = 0;
ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
}
case STATE_RRQ:
xp = pkt;
- *((ushort *)pkt)++ = SWAP16c(TFTP_RRQ);
+ *((ushort *)pkt)++ = htons(TFTP_RRQ);
strcpy ((char *)pkt, tftp_filename);
pkt += strlen(tftp_filename) + 1;
strcpy ((char *)pkt, "octet");
case STATE_DATA:
xp = pkt;
- *((ushort *)pkt)++ = SWAP16c(TFTP_ACK);
- *((ushort *)pkt)++ = SWAP16(TftpBlock);
+ *((ushort *)pkt)++ = htons(TFTP_ACK);
+ *((ushort *)pkt)++ = htons(TftpBlock);
len = pkt - xp;
break;
case STATE_TOO_LARGE:
xp = pkt;
- *((ushort *)pkt)++ = SWAP16c(TFTP_ERROR);
- *((ushort *)pkt)++ = SWAP16(3);
+ *((ushort *)pkt)++ = htons(TFTP_ERROR);
+ *((ushort *)pkt)++ = htons(3);
strcpy ((char *)pkt, "File too large");
pkt += 14 /*strlen("File too large")*/ + 1;
len = pkt - xp;
case STATE_BAD_MAGIC:
xp = pkt;
- *((ushort *)pkt)++ = SWAP16c(TFTP_ERROR);
- *((ushort *)pkt)++ = SWAP16(2);
+ *((ushort *)pkt)++ = htons(TFTP_ERROR);
+ *((ushort *)pkt)++ = htons(2);
strcpy ((char *)pkt, "File has bad magic");
pkt += 18 /*strlen("File has bad magic")*/ + 1;
len = pkt - xp;
}
len -= 2;
- /* warning: don't use increment (++) in SWAP() macros!! */
+ /* warning: don't use increment (++) in ntohs() macros!! */
proto = *((ushort *)pkt)++;
- proto = SWAP16(proto);
+ proto = ntohs(proto);
switch (proto) {
case TFTP_RRQ:
if (len < 2)
return;
len -= 2;
- TftpBlock = SWAP16(*(ushort *)pkt);
+ TftpBlock = ntohs(*(ushort *)pkt);
if (((TftpBlock - 1) % 10) == 0) putc ('#');
if (TftpState == STATE_RRQ) {
case TFTP_ERROR:
printf ("\nTFTP error: '%s' (%d)\n",
- pkt + 2, SWAP16(*(ushort *)pkt));
+ pkt + 2, ntohs(*(ushort *)pkt));
puts ("Starting again\n\n");
NetStartAgain ();
break;