* Patches by Udi Finkelstein, 2 June 2003:
[platform/kernel/u-boot.git] / net / eth.c
1 /*
2  * (C) Copyright 2001, 2002
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 #include <common.h>
25 #include <command.h>
26 #include <net.h>
27
28 #if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI)
29
30 #ifdef CFG_GT_6426x
31 extern int gt6426x_eth_initialize(bd_t *bis);
32 #endif
33
34 extern int e1000_initialize(bd_t*);
35 extern int eepro100_initialize(bd_t*);
36 extern int natsemi_initialize(bd_t*);
37 extern int ns8382x_initialize(bd_t*);
38 extern int dc21x4x_initialize(bd_t*);
39 extern int eth_3com_initialize(bd_t*);
40 extern int pcnet_initialize(bd_t*);
41 extern int fec_initialize(bd_t*);
42 extern int scc_initialize(bd_t*);
43 extern int inca_switch_initialize(bd_t*);
44 extern int plb2800_eth_initialize(bd_t*);
45
46 static struct eth_device *eth_devices, *eth_current;
47
48 struct eth_device *eth_get_dev(void)
49 {
50         return eth_current;
51 }
52
53 int eth_get_dev_index (void)
54 {
55         struct eth_device *dev;
56         int num = 0;
57
58         if (!eth_devices) {
59                 return (-1);
60         }
61
62         for (dev = eth_devices; dev; dev = dev->next) {
63                 if (dev == eth_current)
64                         break;
65                 ++num;
66         }
67
68         if (dev) {
69                 return (num);
70         }
71
72         return (0);
73 }
74
75 int eth_register(struct eth_device* dev)
76 {
77         struct eth_device *d;
78
79         if (!eth_devices) {
80                 eth_current = eth_devices = dev;
81         } else {
82                 for (d=eth_devices; d->next!=eth_devices; d=d->next);
83                 d->next = dev;
84         }
85
86         dev->state = ETH_STATE_INIT;
87         dev->next  = eth_devices;
88
89         return 0;
90 }
91
92 int eth_initialize(bd_t *bis)
93 {
94         unsigned char enetvar[32], env_enetaddr[6];
95         int i, eth_number = 0;
96         char *tmp, *end;
97
98         eth_devices = NULL;
99         eth_current = NULL;
100
101 #ifdef CONFIG_INCA_IP_SWITCH
102         inca_switch_initialize(bis);
103 #endif
104 #ifdef CONFIG_PLB2800_ETHER
105         plb2800_eth_initialize(bis);
106 #endif
107 #ifdef CONFIG_E1000
108         e1000_initialize(bis);
109 #endif
110 #ifdef CONFIG_EEPRO100
111         eepro100_initialize(bis);
112 #endif
113 #ifdef CONFIG_TULIP
114         dc21x4x_initialize(bis);
115 #endif
116 #ifdef CONFIG_3COM
117         eth_3com_initialize(bis);
118 #endif
119 #ifdef CONFIG_PCNET
120         pcnet_initialize(bis);
121 #endif
122 #ifdef CFG_GT_6426x
123         gt6426x_eth_initialize(bis);
124 #endif
125 #ifdef CONFIG_NATSEMI
126         natsemi_initialize(bis);
127 #endif
128 #ifdef CONFIG_NS8382X
129         ns8382x_initialize(bis);
130 #endif
131 #ifdef SCC_ENET
132         scc_initialize(bis);
133 #endif
134 #if defined(FEC_ENET) || defined(CONFIG_ETHER_ON_FCC)
135         fec_initialize(bis);
136 #endif
137
138         if (!eth_devices) {
139                 puts ("No ethernet found.\n");
140         } else {
141                 struct eth_device *dev = eth_devices;
142                 char *ethprime = getenv ("ethprime");
143
144                 do {
145                         if (eth_number)
146                                 puts (", ");
147
148                         printf("%s", dev->name);
149
150                         if (ethprime && strcmp (dev->name, ethprime) == 0) {
151                                 eth_current = dev;
152                                 puts (" [PRIME]");
153                         }
154
155                         sprintf(enetvar, eth_number ? "eth%daddr" : "ethaddr", eth_number);
156                         tmp = getenv (enetvar);
157
158                         for (i=0; i<6; i++) {
159                                 env_enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
160                                 if (tmp)
161                                         tmp = (*end) ? end+1 : end;
162                         }
163
164                         if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6)) {
165                                 if (memcmp(dev->enetaddr, "\0\0\0\0\0\0", 6) &&
166                                     memcmp(dev->enetaddr, env_enetaddr, 6))
167                                 {
168                                         printf("\nWarning: %s MAC addresses don't match:\n", dev->name);
169                                         printf("Address in SROM is         "
170                                                "%02X:%02X:%02X:%02X:%02X:%02X\n",
171                                                dev->enetaddr[0], dev->enetaddr[1],
172                                                dev->enetaddr[2], dev->enetaddr[3],
173                                                dev->enetaddr[4], dev->enetaddr[5]);
174                                         printf("Address in environment is  "
175                                                "%02X:%02X:%02X:%02X:%02X:%02X\n",
176                                                env_enetaddr[0], env_enetaddr[1],
177                                                env_enetaddr[2], env_enetaddr[3],
178                                                env_enetaddr[4], env_enetaddr[5]);
179                                 }
180
181                                 memcpy(dev->enetaddr, env_enetaddr, 6);
182                         }
183
184                         eth_number++;
185                         dev = dev->next;
186                 } while(dev != eth_devices);
187
188                 putc ('\n');
189         }
190
191         return eth_number;
192 }
193
194 void eth_set_enetaddr(int num, char *addr) {
195         struct eth_device *dev;
196         unsigned char enetaddr[6];
197         char *end;
198         int i;
199
200 #ifdef DEBUG
201         printf("eth_set_enetaddr(num=%d, addr=%s)\n", num, addr);
202 #endif
203         if (!eth_devices)
204                 return;
205
206         for (i=0; i<6; i++) {
207                 enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
208                 if (addr)
209                         addr = (*end) ? end+1 : end;
210         }
211
212         dev = eth_devices;
213         while(num-- > 0) {
214                 dev = dev->next;
215
216                 if (dev == eth_devices)
217                         return;
218         }
219
220 #ifdef DEBUG
221         printf("Setting new HW address on %s\n", dev->name);
222         printf("New Address is             "
223                "%02X:%02X:%02X:%02X:%02X:%02X\n",
224                dev->enetaddr[0], dev->enetaddr[1],
225                dev->enetaddr[2], dev->enetaddr[3],
226                dev->enetaddr[4], dev->enetaddr[5]);
227 #endif
228
229         memcpy(dev->enetaddr, enetaddr, 6);
230 }
231
232 int eth_init(bd_t *bis)
233 {
234         struct eth_device* old_current;
235
236         if (!eth_current)
237                 return 0;
238
239         old_current = eth_current;
240         do {
241 #ifdef DEBUG
242                 printf("Trying %s\n", eth_current->name);
243 #endif
244
245                 if (eth_current->init(eth_current, bis)) {
246                         eth_current->state = ETH_STATE_ACTIVE;
247
248                         return 1;
249                 }
250
251 #ifdef DEBUG
252                 puts ("FAIL\n");
253 #endif
254
255                 eth_try_another(0);
256         } while (old_current != eth_current);
257
258         return 0;
259 }
260
261 void eth_halt(void)
262 {
263         if (!eth_current)
264                 return;
265
266         eth_current->halt(eth_current);
267
268         eth_current->state = ETH_STATE_PASSIVE;
269 }
270
271 int eth_send(volatile void *packet, int length)
272 {
273         if (!eth_current)
274                 return -1;
275
276         return eth_current->send(eth_current, packet, length);
277 }
278
279 int eth_rx(void)
280 {
281         if (!eth_current)
282                 return -1;
283
284         return eth_current->recv(eth_current);
285 }
286
287 void eth_try_another(int first_restart)
288 {
289         static struct eth_device *first_failed = NULL;
290
291         if (!eth_current)
292                 return;
293
294         if (first_restart)
295         {
296                 first_failed = eth_current;
297         }
298
299         eth_current = eth_current->next;
300
301         if (first_failed == eth_current)
302         {
303                 NetRestartWrap = 1;
304         }
305 }
306
307 #endif