1 | #ifdef ALLMULTI |
---|
2 | #error multicast support is not yet implemented |
---|
3 | #endif |
---|
4 | /*------------------------------------------------------------------------ |
---|
5 | * smc9000.c |
---|
6 | * This is a Etherboot driver for SMC's 9000 series of Ethernet cards. |
---|
7 | * |
---|
8 | * Copyright (C) 1998 Daniel Engström <daniel.engstrom@riksnett.no> |
---|
9 | * Based on the Linux SMC9000 driver, smc9194.c by Eric Stahlman |
---|
10 | * Copyright (C) 1996 by Erik Stahlman <eric@vt.edu> |
---|
11 | * |
---|
12 | * This software may be used and distributed according to the terms |
---|
13 | * of the GNU Public License, incorporated herein by reference. |
---|
14 | * |
---|
15 | * "Features" of the SMC chip: |
---|
16 | * 4608 byte packet memory. ( for the 91C92/4. Others have more ) |
---|
17 | * EEPROM for configuration |
---|
18 | * AUI/TP selection |
---|
19 | * |
---|
20 | * Authors |
---|
21 | * Erik Stahlman <erik@vt.edu> |
---|
22 | * Daniel Engström <daniel.engstrom@riksnett.no> |
---|
23 | * |
---|
24 | * History |
---|
25 | * 98-09-25 Daniel Engström Etherboot driver crated from Eric's |
---|
26 | * Linux driver. |
---|
27 | * |
---|
28 | *---------------------------------------------------------------------------*/ |
---|
29 | |
---|
30 | FILE_LICENCE ( GPL_ANY ); |
---|
31 | |
---|
32 | #define LINUX_OUT_MACROS 1 |
---|
33 | #define SMC9000_DEBUG 0 |
---|
34 | |
---|
35 | #if SMC9000_DEBUG > 1 |
---|
36 | #define PRINTK2 printf |
---|
37 | #else |
---|
38 | #define PRINTK2(args...) |
---|
39 | #endif |
---|
40 | |
---|
41 | #include <gpxe/ethernet.h> |
---|
42 | #include <errno.h> |
---|
43 | #include "etherboot.h" |
---|
44 | #include "nic.h" |
---|
45 | #include <gpxe/isa.h> |
---|
46 | #include "smc9000.h" |
---|
47 | |
---|
48 | # define _outb outb |
---|
49 | # define _outw outw |
---|
50 | |
---|
51 | static const char smc9000_version[] = "Version 0.99 98-09-30"; |
---|
52 | static const char *interfaces[ 2 ] = { "TP", "AUI" }; |
---|
53 | static const char *chip_ids[ 15 ] = { |
---|
54 | NULL, NULL, NULL, |
---|
55 | /* 3 */ "SMC91C90/91C92", |
---|
56 | /* 4 */ "SMC91C94", |
---|
57 | /* 5 */ "SMC91C95", |
---|
58 | NULL, |
---|
59 | /* 7 */ "SMC91C100", |
---|
60 | /* 8 */ "SMC91C100FD", |
---|
61 | /* 9 */ "SMC91C11xFD", |
---|
62 | NULL, NULL, |
---|
63 | NULL, NULL, NULL |
---|
64 | }; |
---|
65 | static const char smc91c96_id[] = "SMC91C96"; |
---|
66 | |
---|
67 | /*------------------------------------------------------------ |
---|
68 | . Reads a register from the MII Management serial interface |
---|
69 | .-------------------------------------------------------------*/ |
---|
70 | static word smc_read_phy_register(int ioaddr, byte phyaddr, byte phyreg) |
---|
71 | { |
---|
72 | int oldBank; |
---|
73 | unsigned int i; |
---|
74 | byte mask; |
---|
75 | word mii_reg; |
---|
76 | byte bits[64]; |
---|
77 | int clk_idx = 0; |
---|
78 | int input_idx; |
---|
79 | word phydata; |
---|
80 | |
---|
81 | // 32 consecutive ones on MDO to establish sync |
---|
82 | for (i = 0; i < 32; ++i) |
---|
83 | bits[clk_idx++] = MII_MDOE | MII_MDO; |
---|
84 | |
---|
85 | // Start code <01> |
---|
86 | bits[clk_idx++] = MII_MDOE; |
---|
87 | bits[clk_idx++] = MII_MDOE | MII_MDO; |
---|
88 | |
---|
89 | // Read command <10> |
---|
90 | bits[clk_idx++] = MII_MDOE | MII_MDO; |
---|
91 | bits[clk_idx++] = MII_MDOE; |
---|
92 | |
---|
93 | // Output the PHY address, msb first |
---|
94 | mask = (byte)0x10; |
---|
95 | for (i = 0; i < 5; ++i) |
---|
96 | { |
---|
97 | if (phyaddr & mask) |
---|
98 | bits[clk_idx++] = MII_MDOE | MII_MDO; |
---|
99 | else |
---|
100 | bits[clk_idx++] = MII_MDOE; |
---|
101 | |
---|
102 | // Shift to next lowest bit |
---|
103 | mask >>= 1; |
---|
104 | } |
---|
105 | |
---|
106 | // Output the phy register number, msb first |
---|
107 | mask = (byte)0x10; |
---|
108 | for (i = 0; i < 5; ++i) |
---|
109 | { |
---|
110 | if (phyreg & mask) |
---|
111 | bits[clk_idx++] = MII_MDOE | MII_MDO; |
---|
112 | else |
---|
113 | bits[clk_idx++] = MII_MDOE; |
---|
114 | |
---|
115 | // Shift to next lowest bit |
---|
116 | mask >>= 1; |
---|
117 | } |
---|
118 | |
---|
119 | // Tristate and turnaround (2 bit times) |
---|
120 | bits[clk_idx++] = 0; |
---|
121 | //bits[clk_idx++] = 0; |
---|
122 | |
---|
123 | // Input starts at this bit time |
---|
124 | input_idx = clk_idx; |
---|
125 | |
---|
126 | // Will input 16 bits |
---|
127 | for (i = 0; i < 16; ++i) |
---|
128 | bits[clk_idx++] = 0; |
---|
129 | |
---|
130 | // Final clock bit |
---|
131 | bits[clk_idx++] = 0; |
---|
132 | |
---|
133 | // Save the current bank |
---|
134 | oldBank = inw( ioaddr+BANK_SELECT ); |
---|
135 | |
---|
136 | // Select bank 3 |
---|
137 | SMC_SELECT_BANK(ioaddr, 3); |
---|
138 | |
---|
139 | // Get the current MII register value |
---|
140 | mii_reg = inw( ioaddr+MII_REG ); |
---|
141 | |
---|
142 | // Turn off all MII Interface bits |
---|
143 | mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO); |
---|
144 | |
---|
145 | // Clock all 64 cycles |
---|
146 | for (i = 0; i < sizeof(bits); ++i) |
---|
147 | { |
---|
148 | // Clock Low - output data |
---|
149 | outw( mii_reg | bits[i], ioaddr+MII_REG ); |
---|
150 | udelay(50); |
---|
151 | |
---|
152 | |
---|
153 | // Clock Hi - input data |
---|
154 | outw( mii_reg | bits[i] | MII_MCLK, ioaddr+MII_REG ); |
---|
155 | udelay(50); |
---|
156 | bits[i] |= inw( ioaddr+MII_REG ) & MII_MDI; |
---|
157 | } |
---|
158 | |
---|
159 | // Return to idle state |
---|
160 | // Set clock to low, data to low, and output tristated |
---|
161 | outw( mii_reg, ioaddr+MII_REG ); |
---|
162 | udelay(50); |
---|
163 | |
---|
164 | // Restore original bank select |
---|
165 | SMC_SELECT_BANK(ioaddr, oldBank); |
---|
166 | |
---|
167 | // Recover input data |
---|
168 | phydata = 0; |
---|
169 | for (i = 0; i < 16; ++i) |
---|
170 | { |
---|
171 | phydata <<= 1; |
---|
172 | |
---|
173 | if (bits[input_idx++] & MII_MDI) |
---|
174 | phydata |= 0x0001; |
---|
175 | } |
---|
176 | |
---|
177 | #if (SMC_DEBUG > 2 ) |
---|
178 | printf("smc_read_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n", |
---|
179 | phyaddr, phyreg, phydata); |
---|
180 | #endif |
---|
181 | |
---|
182 | return(phydata); |
---|
183 | } |
---|
184 | |
---|
185 | |
---|
186 | /*------------------------------------------------------------ |
---|
187 | . Writes a register to the MII Management serial interface |
---|
188 | .-------------------------------------------------------------*/ |
---|
189 | static void smc_write_phy_register(int ioaddr, |
---|
190 | byte phyaddr, byte phyreg, word phydata) |
---|
191 | { |
---|
192 | int oldBank; |
---|
193 | unsigned int i; |
---|
194 | word mask; |
---|
195 | word mii_reg; |
---|
196 | byte bits[65]; |
---|
197 | int clk_idx = 0; |
---|
198 | |
---|
199 | // 32 consecutive ones on MDO to establish sync |
---|
200 | for (i = 0; i < 32; ++i) |
---|
201 | bits[clk_idx++] = MII_MDOE | MII_MDO; |
---|
202 | |
---|
203 | // Start code <01> |
---|
204 | bits[clk_idx++] = MII_MDOE; |
---|
205 | bits[clk_idx++] = MII_MDOE | MII_MDO; |
---|
206 | |
---|
207 | // Write command <01> |
---|
208 | bits[clk_idx++] = MII_MDOE; |
---|
209 | bits[clk_idx++] = MII_MDOE | MII_MDO; |
---|
210 | |
---|
211 | // Output the PHY address, msb first |
---|
212 | mask = (byte)0x10; |
---|
213 | for (i = 0; i < 5; ++i) |
---|
214 | { |
---|
215 | if (phyaddr & mask) |
---|
216 | bits[clk_idx++] = MII_MDOE | MII_MDO; |
---|
217 | else |
---|
218 | bits[clk_idx++] = MII_MDOE; |
---|
219 | |
---|
220 | // Shift to next lowest bit |
---|
221 | mask >>= 1; |
---|
222 | } |
---|
223 | |
---|
224 | // Output the phy register number, msb first |
---|
225 | mask = (byte)0x10; |
---|
226 | for (i = 0; i < 5; ++i) |
---|
227 | { |
---|
228 | if (phyreg & mask) |
---|
229 | bits[clk_idx++] = MII_MDOE | MII_MDO; |
---|
230 | else |
---|
231 | bits[clk_idx++] = MII_MDOE; |
---|
232 | |
---|
233 | // Shift to next lowest bit |
---|
234 | mask >>= 1; |
---|
235 | } |
---|
236 | |
---|
237 | // Tristate and turnaround (2 bit times) |
---|
238 | bits[clk_idx++] = 0; |
---|
239 | bits[clk_idx++] = 0; |
---|
240 | |
---|
241 | // Write out 16 bits of data, msb first |
---|
242 | mask = 0x8000; |
---|
243 | for (i = 0; i < 16; ++i) |
---|
244 | { |
---|
245 | if (phydata & mask) |
---|
246 | bits[clk_idx++] = MII_MDOE | MII_MDO; |
---|
247 | else |
---|
248 | bits[clk_idx++] = MII_MDOE; |
---|
249 | |
---|
250 | // Shift to next lowest bit |
---|
251 | mask >>= 1; |
---|
252 | } |
---|
253 | |
---|
254 | // Final clock bit (tristate) |
---|
255 | bits[clk_idx++] = 0; |
---|
256 | |
---|
257 | // Save the current bank |
---|
258 | oldBank = inw( ioaddr+BANK_SELECT ); |
---|
259 | |
---|
260 | // Select bank 3 |
---|
261 | SMC_SELECT_BANK(ioaddr, 3); |
---|
262 | |
---|
263 | // Get the current MII register value |
---|
264 | mii_reg = inw( ioaddr+MII_REG ); |
---|
265 | |
---|
266 | // Turn off all MII Interface bits |
---|
267 | mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO); |
---|
268 | |
---|
269 | // Clock all cycles |
---|
270 | for (i = 0; i < sizeof(bits); ++i) |
---|
271 | { |
---|
272 | // Clock Low - output data |
---|
273 | outw( mii_reg | bits[i], ioaddr+MII_REG ); |
---|
274 | udelay(50); |
---|
275 | |
---|
276 | |
---|
277 | // Clock Hi - input data |
---|
278 | outw( mii_reg | bits[i] | MII_MCLK, ioaddr+MII_REG ); |
---|
279 | udelay(50); |
---|
280 | bits[i] |= inw( ioaddr+MII_REG ) & MII_MDI; |
---|
281 | } |
---|
282 | |
---|
283 | // Return to idle state |
---|
284 | // Set clock to low, data to low, and output tristated |
---|
285 | outw( mii_reg, ioaddr+MII_REG ); |
---|
286 | udelay(50); |
---|
287 | |
---|
288 | // Restore original bank select |
---|
289 | SMC_SELECT_BANK(ioaddr, oldBank); |
---|
290 | |
---|
291 | #if (SMC_DEBUG > 2 ) |
---|
292 | printf("smc_write_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n", |
---|
293 | phyaddr, phyreg, phydata); |
---|
294 | #endif |
---|
295 | } |
---|
296 | |
---|
297 | |
---|
298 | /*------------------------------------------------------------ |
---|
299 | . Finds and reports the PHY address |
---|
300 | .-------------------------------------------------------------*/ |
---|
301 | static int smc_detect_phy(int ioaddr, byte *pphyaddr) |
---|
302 | { |
---|
303 | word phy_id1; |
---|
304 | word phy_id2; |
---|
305 | int phyaddr; |
---|
306 | int found = 0; |
---|
307 | |
---|
308 | // Scan all 32 PHY addresses if necessary |
---|
309 | for (phyaddr = 0; phyaddr < 32; ++phyaddr) |
---|
310 | { |
---|
311 | // Read the PHY identifiers |
---|
312 | phy_id1 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID1_REG); |
---|
313 | phy_id2 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID2_REG); |
---|
314 | |
---|
315 | // Make sure it is a valid identifier |
---|
316 | if ((phy_id2 > 0x0000) && (phy_id2 < 0xffff) && |
---|
317 | (phy_id1 > 0x0000) && (phy_id1 < 0xffff)) |
---|
318 | { |
---|
319 | if ((phy_id1 != 0x8000) && (phy_id2 != 0x8000)) |
---|
320 | { |
---|
321 | // Save the PHY's address |
---|
322 | *pphyaddr = phyaddr; |
---|
323 | found = 1; |
---|
324 | break; |
---|
325 | } |
---|
326 | } |
---|
327 | } |
---|
328 | |
---|
329 | if (!found) |
---|
330 | { |
---|
331 | printf("No PHY found\n"); |
---|
332 | return(0); |
---|
333 | } |
---|
334 | |
---|
335 | // Set the PHY type |
---|
336 | if ( (phy_id1 == 0x0016) && ((phy_id2 & 0xFFF0) == 0xF840 ) ) |
---|
337 | { |
---|
338 | printf("PHY=LAN83C183 (LAN91C111 Internal)\n"); |
---|
339 | } |
---|
340 | |
---|
341 | if ( (phy_id1 == 0x0282) && ((phy_id2 & 0xFFF0) == 0x1C50) ) |
---|
342 | { |
---|
343 | printf("PHY=LAN83C180\n"); |
---|
344 | } |
---|
345 | |
---|
346 | return(1); |
---|
347 | } |
---|
348 | |
---|
349 | /*------------------------------------------------------------ |
---|
350 | . Configures the specified PHY using Autonegotiation. Calls |
---|
351 | . smc_phy_fixed() if the user has requested a certain config. |
---|
352 | .-------------------------------------------------------------*/ |
---|
353 | static void smc_phy_configure(int ioaddr) |
---|
354 | { |
---|
355 | int timeout; |
---|
356 | byte phyaddr; |
---|
357 | word my_phy_caps; // My PHY capabilities |
---|
358 | word my_ad_caps; // My Advertised capabilities |
---|
359 | word status; |
---|
360 | int failed = 0; |
---|
361 | int rpc_cur_mode = RPC_DEFAULT; |
---|
362 | int lastPhy18; |
---|
363 | |
---|
364 | // Find the address and type of our phy |
---|
365 | if (!smc_detect_phy(ioaddr, &phyaddr)) |
---|
366 | { |
---|
367 | return; |
---|
368 | } |
---|
369 | |
---|
370 | // Reset the PHY, setting all other bits to zero |
---|
371 | smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, PHY_CNTL_RST); |
---|
372 | |
---|
373 | // Wait for the reset to complete, or time out |
---|
374 | timeout = 6; // Wait up to 3 seconds |
---|
375 | while (timeout--) |
---|
376 | { |
---|
377 | if (!(smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG) |
---|
378 | & PHY_CNTL_RST)) |
---|
379 | { |
---|
380 | // reset complete |
---|
381 | break; |
---|
382 | } |
---|
383 | |
---|
384 | mdelay(500); // wait 500 millisecs |
---|
385 | } |
---|
386 | |
---|
387 | if (timeout < 1) |
---|
388 | { |
---|
389 | PRINTK2("PHY reset timed out\n"); |
---|
390 | return; |
---|
391 | } |
---|
392 | |
---|
393 | // Read PHY Register 18, Status Output |
---|
394 | lastPhy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG); |
---|
395 | |
---|
396 | // Enable PHY Interrupts (for register 18) |
---|
397 | // Interrupts listed here are disabled |
---|
398 | smc_write_phy_register(ioaddr, phyaddr, PHY_MASK_REG, |
---|
399 | PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD | |
---|
400 | PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB | |
---|
401 | PHY_INT_SPDDET | PHY_INT_DPLXDET); |
---|
402 | |
---|
403 | /* Configure the Receive/Phy Control register */ |
---|
404 | SMC_SELECT_BANK(ioaddr, 0); |
---|
405 | outw( rpc_cur_mode, ioaddr + RPC_REG ); |
---|
406 | |
---|
407 | // Copy our capabilities from PHY_STAT_REG to PHY_AD_REG |
---|
408 | my_phy_caps = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG); |
---|
409 | my_ad_caps = PHY_AD_CSMA; // I am CSMA capable |
---|
410 | |
---|
411 | if (my_phy_caps & PHY_STAT_CAP_T4) |
---|
412 | my_ad_caps |= PHY_AD_T4; |
---|
413 | |
---|
414 | if (my_phy_caps & PHY_STAT_CAP_TXF) |
---|
415 | my_ad_caps |= PHY_AD_TX_FDX; |
---|
416 | |
---|
417 | if (my_phy_caps & PHY_STAT_CAP_TXH) |
---|
418 | my_ad_caps |= PHY_AD_TX_HDX; |
---|
419 | |
---|
420 | if (my_phy_caps & PHY_STAT_CAP_TF) |
---|
421 | my_ad_caps |= PHY_AD_10_FDX; |
---|
422 | |
---|
423 | if (my_phy_caps & PHY_STAT_CAP_TH) |
---|
424 | my_ad_caps |= PHY_AD_10_HDX; |
---|
425 | |
---|
426 | // Update our Auto-Neg Advertisement Register |
---|
427 | smc_write_phy_register(ioaddr, phyaddr, PHY_AD_REG, my_ad_caps); |
---|
428 | |
---|
429 | PRINTK2("phy caps=%x\n", my_phy_caps); |
---|
430 | PRINTK2("phy advertised caps=%x\n", my_ad_caps); |
---|
431 | |
---|
432 | // Restart auto-negotiation process in order to advertise my caps |
---|
433 | smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG, |
---|
434 | PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST ); |
---|
435 | |
---|
436 | // Wait for the auto-negotiation to complete. This may take from |
---|
437 | // 2 to 3 seconds. |
---|
438 | // Wait for the reset to complete, or time out |
---|
439 | timeout = 20; // Wait up to 10 seconds |
---|
440 | while (timeout--) |
---|
441 | { |
---|
442 | status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG); |
---|
443 | if (status & PHY_STAT_ANEG_ACK) |
---|
444 | { |
---|
445 | // auto-negotiate complete |
---|
446 | break; |
---|
447 | } |
---|
448 | |
---|
449 | mdelay(500); // wait 500 millisecs |
---|
450 | |
---|
451 | // Restart auto-negotiation if remote fault |
---|
452 | if (status & PHY_STAT_REM_FLT) |
---|
453 | { |
---|
454 | PRINTK2("PHY remote fault detected\n"); |
---|
455 | |
---|
456 | // Restart auto-negotiation |
---|
457 | PRINTK2("PHY restarting auto-negotiation\n"); |
---|
458 | smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG, |
---|
459 | PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST | |
---|
460 | PHY_CNTL_SPEED | PHY_CNTL_DPLX); |
---|
461 | } |
---|
462 | } |
---|
463 | |
---|
464 | if (timeout < 1) |
---|
465 | { |
---|
466 | PRINTK2("PHY auto-negotiate timed out\n"); |
---|
467 | failed = 1; |
---|
468 | } |
---|
469 | |
---|
470 | // Fail if we detected an auto-negotiate remote fault |
---|
471 | if (status & PHY_STAT_REM_FLT) |
---|
472 | { |
---|
473 | PRINTK2("PHY remote fault detected\n"); |
---|
474 | failed = 1; |
---|
475 | } |
---|
476 | |
---|
477 | // Set our sysctl parameters to match auto-negotiation results |
---|
478 | if ( lastPhy18 & PHY_INT_SPDDET ) |
---|
479 | { |
---|
480 | PRINTK2("PHY 100BaseT\n"); |
---|
481 | rpc_cur_mode |= RPC_SPEED; |
---|
482 | } |
---|
483 | else |
---|
484 | { |
---|
485 | PRINTK2("PHY 10BaseT\n"); |
---|
486 | rpc_cur_mode &= ~RPC_SPEED; |
---|
487 | } |
---|
488 | |
---|
489 | if ( lastPhy18 & PHY_INT_DPLXDET ) |
---|
490 | { |
---|
491 | PRINTK2("PHY Full Duplex\n"); |
---|
492 | rpc_cur_mode |= RPC_DPLX; |
---|
493 | } |
---|
494 | else |
---|
495 | { |
---|
496 | PRINTK2("PHY Half Duplex\n"); |
---|
497 | rpc_cur_mode &= ~RPC_DPLX; |
---|
498 | } |
---|
499 | |
---|
500 | // Re-Configure the Receive/Phy Control register |
---|
501 | outw( rpc_cur_mode, ioaddr + RPC_REG ); |
---|
502 | } |
---|
503 | |
---|
504 | /* |
---|
505 | * Function: smc_reset( int ioaddr ) |
---|
506 | * Purpose: |
---|
507 | * This sets the SMC91xx chip to its normal state, hopefully from whatever |
---|
508 | * mess that any other DOS driver has put it in. |
---|
509 | * |
---|
510 | * Maybe I should reset more registers to defaults in here? SOFTRESET should |
---|
511 | * do that for me. |
---|
512 | * |
---|
513 | * Method: |
---|
514 | * 1. send a SOFT RESET |
---|
515 | * 2. wait for it to finish |
---|
516 | * 3. reset the memory management unit |
---|
517 | * 4. clear all interrupts |
---|
518 | * |
---|
519 | */ |
---|
520 | static void smc_reset(int ioaddr) |
---|
521 | { |
---|
522 | /* This resets the registers mostly to defaults, but doesn't |
---|
523 | * affect EEPROM. That seems unnecessary */ |
---|
524 | SMC_SELECT_BANK(ioaddr, 0); |
---|
525 | _outw( RCR_SOFTRESET, ioaddr + RCR ); |
---|
526 | |
---|
527 | /* this should pause enough for the chip to be happy */ |
---|
528 | SMC_DELAY(ioaddr); |
---|
529 | |
---|
530 | /* Set the transmit and receive configuration registers to |
---|
531 | * default values */ |
---|
532 | _outw(RCR_CLEAR, ioaddr + RCR); |
---|
533 | _outw(TCR_CLEAR, ioaddr + TCR); |
---|
534 | |
---|
535 | /* Reset the MMU */ |
---|
536 | SMC_SELECT_BANK(ioaddr, 2); |
---|
537 | _outw( MC_RESET, ioaddr + MMU_CMD ); |
---|
538 | |
---|
539 | /* Note: It doesn't seem that waiting for the MMU busy is needed here, |
---|
540 | * but this is a place where future chipsets _COULD_ break. Be wary |
---|
541 | * of issuing another MMU command right after this */ |
---|
542 | _outb(0, ioaddr + INT_MASK); |
---|
543 | } |
---|
544 | |
---|
545 | |
---|
546 | /*---------------------------------------------------------------------- |
---|
547 | * Function: smc9000_probe_addr( int ioaddr ) |
---|
548 | * |
---|
549 | * Purpose: |
---|
550 | * Tests to see if a given ioaddr points to an SMC9xxx chip. |
---|
551 | * Returns a 1 on success |
---|
552 | * |
---|
553 | * Algorithm: |
---|
554 | * (1) see if the high byte of BANK_SELECT is 0x33 |
---|
555 | * (2) compare the ioaddr with the base register's address |
---|
556 | * (3) see if I recognize the chip ID in the appropriate register |
---|
557 | * |
---|
558 | * --------------------------------------------------------------------- |
---|
559 | */ |
---|
560 | static int smc9000_probe_addr( isa_probe_addr_t ioaddr ) |
---|
561 | { |
---|
562 | word bank; |
---|
563 | word revision_register; |
---|
564 | word base_address_register; |
---|
565 | |
---|
566 | /* First, see if the high byte is 0x33 */ |
---|
567 | bank = inw(ioaddr + BANK_SELECT); |
---|
568 | if ((bank & 0xFF00) != 0x3300) { |
---|
569 | return 0; |
---|
570 | } |
---|
571 | /* The above MIGHT indicate a device, but I need to write to further |
---|
572 | * test this. */ |
---|
573 | _outw(0x0, ioaddr + BANK_SELECT); |
---|
574 | bank = inw(ioaddr + BANK_SELECT); |
---|
575 | if ((bank & 0xFF00) != 0x3300) { |
---|
576 | return 0; |
---|
577 | } |
---|
578 | |
---|
579 | /* well, we've already written once, so hopefully another time won't |
---|
580 | * hurt. This time, I need to switch the bank register to bank 1, |
---|
581 | * so I can access the base address register */ |
---|
582 | SMC_SELECT_BANK(ioaddr, 1); |
---|
583 | base_address_register = inw(ioaddr + BASE); |
---|
584 | |
---|
585 | if (ioaddr != (base_address_register >> 3 & 0x3E0)) { |
---|
586 | DBG("SMC9000: IOADDR %hX doesn't match configuration (%hX)." |
---|
587 | "Probably not a SMC chip\n", |
---|
588 | ioaddr, base_address_register >> 3 & 0x3E0); |
---|
589 | /* well, the base address register didn't match. Must not have |
---|
590 | * been a SMC chip after all. */ |
---|
591 | return 0; |
---|
592 | } |
---|
593 | |
---|
594 | |
---|
595 | /* check if the revision register is something that I recognize. |
---|
596 | * These might need to be added to later, as future revisions |
---|
597 | * could be added. */ |
---|
598 | SMC_SELECT_BANK(ioaddr, 3); |
---|
599 | revision_register = inw(ioaddr + REVISION); |
---|
600 | if (!chip_ids[(revision_register >> 4) & 0xF]) { |
---|
601 | /* I don't recognize this chip, so... */ |
---|
602 | DBG( "SMC9000: IO %hX: Unrecognized revision register:" |
---|
603 | " %hX, Contact author.\n", ioaddr, revision_register ); |
---|
604 | return 0; |
---|
605 | } |
---|
606 | |
---|
607 | /* at this point I'll assume that the chip is an SMC9xxx. |
---|
608 | * It might be prudent to check a listing of MAC addresses |
---|
609 | * against the hardware address, or do some other tests. */ |
---|
610 | return 1; |
---|
611 | } |
---|
612 | |
---|
613 | |
---|
614 | /************************************************************************** |
---|
615 | * ETH_TRANSMIT - Transmit a frame |
---|
616 | ***************************************************************************/ |
---|
617 | static void smc9000_transmit( |
---|
618 | struct nic *nic, |
---|
619 | const char *d, /* Destination */ |
---|
620 | unsigned int t, /* Type */ |
---|
621 | unsigned int s, /* size */ |
---|
622 | const char *p) /* Packet */ |
---|
623 | { |
---|
624 | word length; /* real, length incl. header */ |
---|
625 | word numPages; |
---|
626 | unsigned long time_out; |
---|
627 | byte packet_no; |
---|
628 | word status; |
---|
629 | int i; |
---|
630 | |
---|
631 | /* We dont pad here since we can have the hardware doing it for us */ |
---|
632 | length = (s + ETH_HLEN + 1)&~1; |
---|
633 | |
---|
634 | /* convert to MMU pages */ |
---|
635 | numPages = length / 256; |
---|
636 | |
---|
637 | if (numPages > 7 ) { |
---|
638 | DBG("SMC9000: Far too big packet error. \n"); |
---|
639 | return; |
---|
640 | } |
---|
641 | |
---|
642 | /* dont try more than, say 30 times */ |
---|
643 | for (i=0;i<30;i++) { |
---|
644 | /* now, try to allocate the memory */ |
---|
645 | SMC_SELECT_BANK(nic->ioaddr, 2); |
---|
646 | _outw(MC_ALLOC | numPages, nic->ioaddr + MMU_CMD); |
---|
647 | |
---|
648 | status = 0; |
---|
649 | /* wait for the memory allocation to finnish */ |
---|
650 | for (time_out = currticks() + 5*TICKS_PER_SEC; currticks() < time_out; ) { |
---|
651 | status = inb(nic->ioaddr + INTERRUPT); |
---|
652 | if ( status & IM_ALLOC_INT ) { |
---|
653 | /* acknowledge the interrupt */ |
---|
654 | _outb(IM_ALLOC_INT, nic->ioaddr + INTERRUPT); |
---|
655 | break; |
---|
656 | } |
---|
657 | } |
---|
658 | |
---|
659 | if ((status & IM_ALLOC_INT) != 0 ) { |
---|
660 | /* We've got the memory */ |
---|
661 | break; |
---|
662 | } else { |
---|
663 | printf("SMC9000: Memory allocation timed out, resetting MMU.\n"); |
---|
664 | _outw(MC_RESET, nic->ioaddr + MMU_CMD); |
---|
665 | } |
---|
666 | } |
---|
667 | |
---|
668 | /* If I get here, I _know_ there is a packet slot waiting for me */ |
---|
669 | packet_no = inb(nic->ioaddr + PNR_ARR + 1); |
---|
670 | if (packet_no & 0x80) { |
---|
671 | /* or isn't there? BAD CHIP! */ |
---|
672 | printf("SMC9000: Memory allocation failed. \n"); |
---|
673 | return; |
---|
674 | } |
---|
675 | |
---|
676 | /* we have a packet address, so tell the card to use it */ |
---|
677 | _outb(packet_no, nic->ioaddr + PNR_ARR); |
---|
678 | |
---|
679 | /* point to the beginning of the packet */ |
---|
680 | _outw(PTR_AUTOINC, nic->ioaddr + POINTER); |
---|
681 | |
---|
682 | #if SMC9000_DEBUG > 2 |
---|
683 | printf("Trying to xmit packet of length %hX\n", length ); |
---|
684 | #endif |
---|
685 | |
---|
686 | /* send the packet length ( +6 for status, length and ctl byte ) |
---|
687 | * and the status word ( set to zeros ) */ |
---|
688 | _outw(0, nic->ioaddr + DATA_1 ); |
---|
689 | |
---|
690 | /* send the packet length ( +6 for status words, length, and ctl) */ |
---|
691 | _outb((length+6) & 0xFF, nic->ioaddr + DATA_1); |
---|
692 | _outb((length+6) >> 8 , nic->ioaddr + DATA_1); |
---|
693 | |
---|
694 | /* Write the contents of the packet */ |
---|
695 | |
---|
696 | /* The ethernet header first... */ |
---|
697 | outsw(nic->ioaddr + DATA_1, d, ETH_ALEN >> 1); |
---|
698 | outsw(nic->ioaddr + DATA_1, nic->node_addr, ETH_ALEN >> 1); |
---|
699 | _outw(htons(t), nic->ioaddr + DATA_1); |
---|
700 | |
---|
701 | /* ... the data ... */ |
---|
702 | outsw(nic->ioaddr + DATA_1 , p, s >> 1); |
---|
703 | |
---|
704 | /* ... and the last byte, if there is one. */ |
---|
705 | if ((s & 1) == 0) { |
---|
706 | _outw(0, nic->ioaddr + DATA_1); |
---|
707 | } else { |
---|
708 | _outb(p[s-1], nic->ioaddr + DATA_1); |
---|
709 | _outb(0x20, nic->ioaddr + DATA_1); |
---|
710 | } |
---|
711 | |
---|
712 | /* and let the chipset deal with it */ |
---|
713 | _outw(MC_ENQUEUE , nic->ioaddr + MMU_CMD); |
---|
714 | |
---|
715 | status = 0; time_out = currticks() + 5*TICKS_PER_SEC; |
---|
716 | do { |
---|
717 | status = inb(nic->ioaddr + INTERRUPT); |
---|
718 | |
---|
719 | if ((status & IM_TX_INT ) != 0) { |
---|
720 | word tx_status; |
---|
721 | |
---|
722 | /* ack interrupt */ |
---|
723 | _outb(IM_TX_INT, nic->ioaddr + INTERRUPT); |
---|
724 | |
---|
725 | packet_no = inw(nic->ioaddr + FIFO_PORTS); |
---|
726 | packet_no &= 0x7F; |
---|
727 | |
---|
728 | /* select this as the packet to read from */ |
---|
729 | _outb( packet_no, nic->ioaddr + PNR_ARR ); |
---|
730 | |
---|
731 | /* read the first word from this packet */ |
---|
732 | _outw( PTR_AUTOINC | PTR_READ, nic->ioaddr + POINTER ); |
---|
733 | |
---|
734 | tx_status = inw( nic->ioaddr + DATA_1 ); |
---|
735 | |
---|
736 | if (0 == (tx_status & TS_SUCCESS)) { |
---|
737 | DBG("SMC9000: TX FAIL STATUS: %hX \n", tx_status); |
---|
738 | /* re-enable transmit */ |
---|
739 | SMC_SELECT_BANK(nic->ioaddr, 0); |
---|
740 | _outw(inw(nic->ioaddr + TCR ) | TCR_ENABLE, nic->ioaddr + TCR ); |
---|
741 | } |
---|
742 | |
---|
743 | /* kill the packet */ |
---|
744 | SMC_SELECT_BANK(nic->ioaddr, 2); |
---|
745 | _outw(MC_FREEPKT, nic->ioaddr + MMU_CMD); |
---|
746 | |
---|
747 | return; |
---|
748 | } |
---|
749 | }while(currticks() < time_out); |
---|
750 | |
---|
751 | printf("SMC9000: TX timed out, resetting board\n"); |
---|
752 | smc_reset(nic->ioaddr); |
---|
753 | return; |
---|
754 | } |
---|
755 | |
---|
756 | /************************************************************************** |
---|
757 | * ETH_POLL - Wait for a frame |
---|
758 | ***************************************************************************/ |
---|
759 | static int smc9000_poll(struct nic *nic, int retrieve) |
---|
760 | { |
---|
761 | SMC_SELECT_BANK(nic->ioaddr, 2); |
---|
762 | if (inw(nic->ioaddr + FIFO_PORTS) & FP_RXEMPTY) |
---|
763 | return 0; |
---|
764 | |
---|
765 | if ( ! retrieve ) return 1; |
---|
766 | |
---|
767 | /* start reading from the start of the packet */ |
---|
768 | _outw(PTR_READ | PTR_RCV | PTR_AUTOINC, nic->ioaddr + POINTER); |
---|
769 | |
---|
770 | /* First read the status and check that we're ok */ |
---|
771 | if (!(inw(nic->ioaddr + DATA_1) & RS_ERRORS)) { |
---|
772 | /* Next: read the packet length and mask off the top bits */ |
---|
773 | nic->packetlen = (inw(nic->ioaddr + DATA_1) & 0x07ff); |
---|
774 | |
---|
775 | /* the packet length includes the 3 extra words */ |
---|
776 | nic->packetlen -= 6; |
---|
777 | #if SMC9000_DEBUG > 2 |
---|
778 | printf(" Reading %d words (and %d byte(s))\n", |
---|
779 | (nic->packetlen >> 1), nic->packetlen & 1); |
---|
780 | #endif |
---|
781 | /* read the packet (and the last "extra" word) */ |
---|
782 | insw(nic->ioaddr + DATA_1, nic->packet, (nic->packetlen+2) >> 1); |
---|
783 | /* is there an odd last byte ? */ |
---|
784 | if (nic->packet[nic->packetlen+1] & 0x20) |
---|
785 | nic->packetlen++; |
---|
786 | |
---|
787 | /* error or good, tell the card to get rid of this packet */ |
---|
788 | _outw(MC_RELEASE, nic->ioaddr + MMU_CMD); |
---|
789 | return 1; |
---|
790 | } |
---|
791 | |
---|
792 | printf("SMC9000: RX error\n"); |
---|
793 | /* error or good, tell the card to get rid of this packet */ |
---|
794 | _outw(MC_RELEASE, nic->ioaddr + MMU_CMD); |
---|
795 | return 0; |
---|
796 | } |
---|
797 | |
---|
798 | static void smc9000_disable ( struct nic *nic, struct isa_device *isa __unused ) { |
---|
799 | |
---|
800 | smc_reset(nic->ioaddr); |
---|
801 | |
---|
802 | /* no more interrupts for me */ |
---|
803 | SMC_SELECT_BANK(nic->ioaddr, 2); |
---|
804 | _outb( 0, nic->ioaddr + INT_MASK); |
---|
805 | |
---|
806 | /* and tell the card to stay away from that nasty outside world */ |
---|
807 | SMC_SELECT_BANK(nic->ioaddr, 0); |
---|
808 | _outb( RCR_CLEAR, nic->ioaddr + RCR ); |
---|
809 | _outb( TCR_CLEAR, nic->ioaddr + TCR ); |
---|
810 | } |
---|
811 | |
---|
812 | static void smc9000_irq(struct nic *nic __unused, irq_action_t action __unused) |
---|
813 | { |
---|
814 | switch ( action ) { |
---|
815 | case DISABLE : |
---|
816 | break; |
---|
817 | case ENABLE : |
---|
818 | break; |
---|
819 | case FORCE : |
---|
820 | break; |
---|
821 | } |
---|
822 | } |
---|
823 | |
---|
824 | static struct nic_operations smc9000_operations = { |
---|
825 | .connect = dummy_connect, |
---|
826 | .poll = smc9000_poll, |
---|
827 | .transmit = smc9000_transmit, |
---|
828 | .irq = smc9000_irq, |
---|
829 | |
---|
830 | }; |
---|
831 | |
---|
832 | /************************************************************************** |
---|
833 | * ETH_PROBE - Look for an adapter |
---|
834 | ***************************************************************************/ |
---|
835 | |
---|
836 | static int smc9000_probe ( struct nic *nic, struct isa_device *isa ) { |
---|
837 | |
---|
838 | unsigned short revision; |
---|
839 | int memory; |
---|
840 | int media; |
---|
841 | const char * version_string; |
---|
842 | const char * if_string; |
---|
843 | int i; |
---|
844 | |
---|
845 | nic->irqno = 0; |
---|
846 | nic->ioaddr = isa->ioaddr; |
---|
847 | |
---|
848 | /* |
---|
849 | * Get the MAC address ( bank 1, regs 4 - 9 ) |
---|
850 | */ |
---|
851 | SMC_SELECT_BANK(nic->ioaddr, 1); |
---|
852 | for ( i = 0; i < 6; i += 2 ) { |
---|
853 | word address; |
---|
854 | |
---|
855 | address = inw(nic->ioaddr + ADDR0 + i); |
---|
856 | nic->node_addr[i+1] = address >> 8; |
---|
857 | nic->node_addr[i] = address & 0xFF; |
---|
858 | } |
---|
859 | |
---|
860 | /* get the memory information */ |
---|
861 | SMC_SELECT_BANK(nic->ioaddr, 0); |
---|
862 | memory = ( inw(nic->ioaddr + MCR) >> 9 ) & 0x7; /* multiplier */ |
---|
863 | memory *= 256 * (inw(nic->ioaddr + MIR) & 0xFF); |
---|
864 | |
---|
865 | /* |
---|
866 | * Now, I want to find out more about the chip. This is sort of |
---|
867 | * redundant, but it's cleaner to have it in both, rather than having |
---|
868 | * one VERY long probe procedure. |
---|
869 | */ |
---|
870 | SMC_SELECT_BANK(nic->ioaddr, 3); |
---|
871 | revision = inw(nic->ioaddr + REVISION); |
---|
872 | version_string = chip_ids[(revision >> 4) & 0xF]; |
---|
873 | |
---|
874 | if (((revision & 0xF0) >> 4 == CHIP_9196) && |
---|
875 | ((revision & 0x0F) >= REV_9196)) { |
---|
876 | /* This is a 91c96. 'c96 has the same chip id as 'c94 (4) but |
---|
877 | * a revision starting at 6 */ |
---|
878 | version_string = smc91c96_id; |
---|
879 | } |
---|
880 | |
---|
881 | if ( !version_string ) { |
---|
882 | /* I shouldn't get here because this call was done before.... */ |
---|
883 | return 0; |
---|
884 | } |
---|
885 | |
---|
886 | /* is it using AUI or 10BaseT ? */ |
---|
887 | SMC_SELECT_BANK(nic->ioaddr, 1); |
---|
888 | if (inw(nic->ioaddr + CONFIG) & CFG_AUI_SELECT) |
---|
889 | media = 2; |
---|
890 | else |
---|
891 | media = 1; |
---|
892 | |
---|
893 | if_string = interfaces[media - 1]; |
---|
894 | |
---|
895 | /* now, reset the chip, and put it into a known state */ |
---|
896 | smc_reset(nic->ioaddr); |
---|
897 | |
---|
898 | printf("SMC9000 %s\n", smc9000_version); |
---|
899 | DBG("Copyright (C) 1998 Daniel Engstr\x94m\n"); |
---|
900 | DBG("Copyright (C) 1996 Eric Stahlman\n"); |
---|
901 | |
---|
902 | printf("%s rev:%d I/O port:%hX Interface:%s RAM:%d bytes \n", |
---|
903 | version_string, revision & 0xF, |
---|
904 | nic->ioaddr, if_string, memory ); |
---|
905 | |
---|
906 | DBG ( "Ethernet MAC address: %s\n", eth_ntoa ( nic->node_addr ) ); |
---|
907 | |
---|
908 | SMC_SELECT_BANK(nic->ioaddr, 0); |
---|
909 | |
---|
910 | /* see the header file for options in TCR/RCR NORMAL*/ |
---|
911 | _outw(TCR_NORMAL, nic->ioaddr + TCR); |
---|
912 | _outw(RCR_NORMAL, nic->ioaddr + RCR); |
---|
913 | |
---|
914 | /* Select which interface to use */ |
---|
915 | SMC_SELECT_BANK(nic->ioaddr, 1); |
---|
916 | if ( media == 1 ) { |
---|
917 | _outw( inw( nic->ioaddr + CONFIG ) & ~CFG_AUI_SELECT, |
---|
918 | nic->ioaddr + CONFIG ); |
---|
919 | } |
---|
920 | else if ( media == 2 ) { |
---|
921 | _outw( inw( nic->ioaddr + CONFIG ) | CFG_AUI_SELECT, |
---|
922 | nic->ioaddr + CONFIG ); |
---|
923 | } |
---|
924 | |
---|
925 | smc_phy_configure(nic->ioaddr); |
---|
926 | |
---|
927 | nic->nic_op = &smc9000_operations; |
---|
928 | return 1; |
---|
929 | } |
---|
930 | |
---|
931 | /* |
---|
932 | * The SMC9000 can be at any of the following port addresses. To |
---|
933 | * change for a slightly different card, you can add it to the array. |
---|
934 | * |
---|
935 | */ |
---|
936 | static isa_probe_addr_t smc9000_probe_addrs[] = { |
---|
937 | 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, |
---|
938 | 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, |
---|
939 | }; |
---|
940 | |
---|
941 | ISA_DRIVER ( smc9000_driver, smc9000_probe_addrs, smc9000_probe_addr, |
---|
942 | GENERIC_ISAPNP_VENDOR, 0x8228 ); |
---|
943 | |
---|
944 | DRIVER ( "SMC9000", nic_driver, isa_driver, smc9000_driver, |
---|
945 | smc9000_probe, smc9000_disable ); |
---|
946 | |
---|
947 | ISA_ROM ( "smc9000", "SMC9000" ); |
---|
948 | |
---|
949 | /* |
---|
950 | * Local variables: |
---|
951 | * c-basic-offset: 8 |
---|
952 | * c-indent-level: 8 |
---|
953 | * tab-width: 8 |
---|
954 | * End: |
---|
955 | */ |
---|