/[pearpc]/src/io/3c90x/3c90x.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /src/io/3c90x/3c90x.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 7 months ago) by dpavlin
File size: 50046 byte(s)
import upstream CVS
1 /*
2 * PearPC
3 * 3c90x.cc
4 *
5 * 3Com 3C905C Emulation
6 * References:
7 * [1] 3c90xc.pdf ("3C90xC NICs Technical Reference" 3Com(r) part number 89-0931-000)
8 * [2] Linux Kernel 2.4.22 (drivers/net/3c59x.c)
9 *
10 * Copyright (C) 2004 John Kelley (pearpc@kelley.ca)
11 * Copyright (C) 2003 Stefan Weyergraf
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26
27 #include <cerrno>
28 #include <cstdlib>
29 #include <cstring>
30 #include <unistd.h>
31
32 #include "system/sys.h"
33 #include "system/systhread.h"
34 #include "cpu/debug.h"
35 #include "cpu/mem.h"
36 #include "system/sysethtun.h"
37 #include "system/arch/sysendian.h"
38 #include "tools/crc32.h"
39 #include "tools/data.h"
40 #include "tools/endianess.h"
41 #include "tools/except.h"
42 #include "tools/snprintf.h"
43 #include "io/pic/pic.h"
44 #include "io/pci/pci.h"
45 #include "debug/tracers.h"
46 #include "3c90x.h"
47
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51
52 #define MAX_PACKET_SIZE 16384
53
54 enum Command {
55 CmdTotalReset = 0<<11,
56 CmdSelectWindow = 1<<11,
57 CmdEnableDC = 2<<11, // CmdStartCoax
58 CmdRxDisable = 3<<11,
59 CmdRxEnable = 4<<11,
60 CmdRxReset = 5<<11,
61 CmdStall = 6<<11,
62 CmdTxDone = 7<<11,
63 CmdRxDiscard = 8<<11,
64 CmdTxEnable = 9<<11,
65 CmdTxDisable = 10<<11,
66 CmdTxReset = 11<<11,
67 CmdReqIntr = 12<<11, // CmdFakeIntr
68 CmdAckIntr = 13<<11,
69 CmdSetIntrEnb = 14<<11,
70 CmdSetIndicationEnable = 15<<11, // CmdSetStatusEnb
71 CmdSetRxFilter = 16<<11,
72 CmdSetRxEarlyThresh = 17<<11,
73 CmdSetTxThreshold = 18<<11, // aka TxAgain ?
74 CmdSetTxStartThresh = 19<<11, // set TxStartTresh
75 // CmdStartDMAUp = 20<<11,
76 // CmdStartDMADown = (20<<11)+1,
77 CmdStatsEnable = 21<<11,
78 CmdStatsDisable = 22<<11,
79 CmdDisableDC = 23<<11, // CmdStopCoax
80 CmdSetTxReclaimThresh = 24<<11,
81 CmdSetHashFilterBit = 25<<11
82 };
83
84 /*
85 * IntStatusBits
86 */
87 enum IntStatusBits {
88 IS_interruptLatch = 1<<0,
89 IS_hostError = 1<<1,
90 IS_txComplete = 1<<2,
91 /* bit 3 is unspecified */
92 IS_rxComplete = 1<<4,
93 IS_rxEarly = 1<<5,
94 IS_intRequested = 1<<6,
95 IS_updateStats = 1<<7,
96 IS_linkEvent = 1<<8,
97 IS_dnComplete = 1<<9,
98 IS_upComplete = 1<<10,
99 IS_cmdInProgress = 1<<11,
100 /* bit 12 is unspecified */
101 /* [15:13] is currently selected window */
102 };
103
104 /*
105 * DmaCtrlBits ([1] p.96)
106 */
107 enum DmaCtrlBits {
108 /* bit 0 unspecified */
109 DC_dnCmplReq = 1<<1,
110 DC_dnStalled = 1<<2,
111 DC_upComplete = 1<<3, // FIXME: same as in IntStatus, but always visible
112 DC_dnComplete = 1<<4, // same as above ^^^
113 DC_upRxEarlyEnable = 1<<5,
114 DC_armCountdown = 1<<6,
115 DC_dnInProg = 1<<7,
116 DC_counterSpeed = 1<<8,
117 DC_countdownMode = 1<<9,
118 /* bits 10-15 unspecified */
119 DC_upAltSeqDisable = 1<<16,
120 DC_dnAltSeqDisable = 1<<17,
121 DC_defeatMWI = 1<<20,
122 DC_defeatMRL = 1<<21,
123 DC_upOverDiscEnable = 1<<22,
124 DC_targetAbort = 1<<30,
125 DC_masterAbort = 1<<31
126 };
127
128 /*
129 * MII Registers
130 */
131 /*enum MIIControlBits {
132 MIIC_collision = 1<<7,
133 MIIC_fullDuplex = 1<<8,
134 MIIC_restartNegote = 1<<9,
135 MIIC_collision = 1<<7,
136 rest missing
137 };*/
138
139 struct MIIRegisters {
140 uint16 control;
141 uint16 status;
142 uint16 id0;
143 uint16 id1;
144 uint16 advert;
145 uint16 linkPartner;
146 uint16 expansion;
147 uint16 nextPage;
148 } PACKED;
149
150 /*
151 * Registers
152 */
153 struct RegWindow {
154 byte b[16];
155 uint16 u16[8];
156 };
157
158 struct Registers {
159 // 0x10 bytes missing (current window)
160 uint32 r0;
161 uint32 r1;
162 uint8 TxPktId;
163 uint8 r2;
164 uint8 Timer;
165 uint8 TxStatus;
166 uint16 r3;
167 uint16 __dontUseMe;// really: uint16 IntStatusAuto;
168 uint32 DmaCtrl; // [1] p.95 (dn), p.100 (up)
169 uint32 DnListPtr; // [1] p.98
170 uint16 r4;
171 uint8 DnBurstThresh; // [1] p.97
172 uint8 r5;
173 uint8 DnPriorityThresh;
174 uint8 DnPoll; // [1] p.100
175 uint16 r6;
176 uint32 UpPktStatus;
177 uint16 FreeTimer;
178 uint16 Countdown;
179 uint32 UpListPtr; // [1] p.115
180 uint8 UpPriorityThresh;
181 uint8 UpPoll;
182 uint8 UpBurstThresh;
183 uint8 r7;
184 uint32 RealTimeCount;
185 uint8 ConfigAddress;
186 uint8 r8;
187 uint8 r9;
188 uint8 r10;
189 uint8 ConfigData;
190 uint8 r11;
191 uint8 r12;
192 uint8 r13;
193 uint32 r14[9];
194 uint32 DebugData;
195 uint16 DebugControl;
196 uint16 r15;
197 uint16 DnMaxBurst;
198 uint16 UpMaxBurst;
199 uint16 PowerMgmtCtrl;
200 uint16 r16;
201 } PACKED;
202
203 #define RA_INV 0
204
205 static byte gRegAccess[0x70] =
206 {
207 /* 0x10 */
208 RA_INV, RA_INV, RA_INV, RA_INV,
209 /* 0x14 */
210 RA_INV, RA_INV, RA_INV, RA_INV,
211 /* 0x18 */
212 1, /* TxPktId */
213 RA_INV,
214 1, /* Timer */
215 1, /* TxStatus */
216 /* 0x1c */
217 RA_INV, RA_INV,
218 RA_INV, RA_INV, /* IntStatusAuto */
219 /* 0x20 */
220 4, RA_INV, RA_INV, RA_INV, /* DmaCtrl */
221 /* 0x24 */
222 4, RA_INV, RA_INV, RA_INV, /* DnListPtr */
223 /* 0x28 */
224 RA_INV, RA_INV,
225 1, /* DnBurstThresh */
226 RA_INV,
227 /* 0x2c */
228 1, /* DnPriorityThresh */
229 1, /* DnPoll */
230 RA_INV,
231 1,
232 /* 0x30 */
233 4, RA_INV, RA_INV, RA_INV, /* UpPktStatus */
234 /* 0x34 */
235 2, RA_INV, /* FreeTimer */
236 2, RA_INV, /* Countdown */
237 /* 0x38 */
238 4, RA_INV, RA_INV, RA_INV, /* UpListPtr */
239 /* 0x3c */
240 1, /* UpPriorityThresh */
241 1, /* UpPoll */
242 1, /* UpBurstThresh */
243 RA_INV,
244 /* 0x40 */
245 4, RA_INV, RA_INV, RA_INV, /* RealTimeCount */
246 /* 0x44 */
247 1, /* ConfigAddress */
248 RA_INV,
249 RA_INV,
250 RA_INV,
251 /* 0x48 */
252 1, /* ConfigData */
253 RA_INV,
254 RA_INV,
255 RA_INV,
256 /* 0x4c */
257 RA_INV, RA_INV, RA_INV, RA_INV,
258 /* 0x50 */
259 RA_INV, RA_INV, RA_INV, RA_INV,
260 RA_INV, RA_INV, RA_INV, RA_INV,
261 RA_INV, RA_INV, RA_INV, RA_INV,
262 RA_INV, RA_INV, RA_INV, RA_INV,
263 RA_INV, RA_INV, RA_INV, RA_INV,
264 RA_INV, RA_INV, RA_INV, RA_INV,
265 RA_INV, RA_INV, RA_INV, RA_INV,
266 RA_INV, RA_INV, RA_INV, RA_INV,
267 /* 0x70 */
268 4, RA_INV, RA_INV, RA_INV, /* DebugData */
269 /* 0x74 */
270 2, RA_INV, /* DebugControl */
271 RA_INV, RA_INV,
272 /* 0x78 */
273 2, RA_INV, /* DnMaxBurst */
274 2, RA_INV, /* UpMaxBurst */
275 /* 0x7c */
276 2, RA_INV, /* PowerMgmtCtrl */
277 RA_INV, RA_INV
278 };
279
280 /*
281 * Window 0
282 */
283 struct RegWindow0 {
284 uint32 r0;
285 uint32 BiosRomAddr;
286 uint8 BiosRomData;
287 uint8 r1;
288 uint16 EepromCommand;
289 uint16 EepromData;
290 uint16 XXX; // IntStatus/CommandRegister
291 } PACKED;
292
293 enum W0_Offsets {
294 W0_EEPROMCmd = 0xa,
295 W0_EEPROMData = 0xc
296 };
297
298 enum W0_EEPROMOpcode {
299 EEOP_SubCmd = 0<<6,
300 EEOP_WriteReg = 1<<6,
301 EEOP_ReadReg = 2<<6,
302 EEOP_EraseReg = 3<<6
303 };
304
305 enum W0_EEPROMSubCmd {
306 EESC_WriteDisable = 0<<4,
307 EESC_WriteAll = 1<<4,
308 EESC_EraseAll = 2<<4,
309 EESC_WriteEnable = 3<<4
310 };
311
312 /*
313 * Window 2
314 */
315 struct RegWindow2 {
316 uint16 StationAddress[6];
317 uint16 StationMask[6];
318 uint16 ResetOptions;
319 uint16 XXX; // IntStatus/CommandRegister
320 } PACKED;
321
322 /*
323 * Window 3
324 */
325 struct RegWindow3 {
326 uint32 InternalConfig; // [1] p.58,76
327 uint16 MaxPktSize;
328 uint16 MacControl; // [1] p.179
329 uint16 MediaOptions; // [1] p.78 (EE), p.181
330 uint16 RxFree;
331 uint16 TxFree; // [1] p.101
332 uint16 XXX; // IntStatus/CommandRegister
333 } PACKED;
334
335 /*
336 * Window 4
337 */
338 enum W4_PhysMgmtBits {
339 PM_mgmtClk = 1<<0,
340 PM_mgmtData = 1<<1,
341 PM_mgmtDir = 1<<2
342 };
343
344 struct RegWindow4 {
345 uint16 r0;
346 uint16 r1;
347 uint16 FifoDiagnostic;
348 uint16 NetDiagnostic; // [1] p.184
349 uint16 PhysMgmt; // [1] p.186
350 uint16 MediaStatus; // [1] p.182
351 byte BadSSD;
352 byte UpperBytesOK;
353 uint16 XXX; // IntStatus/CommandRegister
354 } PACKED;
355
356 /*
357 * Window 5
358 */
359 enum RxFilterBits { // [1] p.112
360 RXFILT_receiveIndividual = 1,
361 RXFILT_receiveMulticast = 2,
362 RXFILT_receiveBroadcast = 4,
363 RXFILT_receiveAllFrames = 8,
364 RXFILT_receiveMulticastHash = 16
365 };
366
367 struct RegWindow5 {
368 uint16 TxStartThresh;
369 uint16 r0;
370 uint16 r1;
371 uint16 RxEarlyThresh;
372 byte RxFilter; // [1] p.112
373 byte TxReclaimThresh;
374 uint16 InterruptEnable; // [1] p.120
375 uint16 IndicationEnable;// [1] p.120
376 uint16 XXX; // IntStatus/CommandRegister
377 } PACKED;
378
379 /*
380 * Window 6
381 */
382 struct RegWindow6 {
383 uint8 CarrierLost;
384 uint8 SqeErrors;
385 uint8 MultipleCollisions;
386 uint8 SingleCollisions;
387 uint8 LateCollisions;
388 uint8 RxOverruns;
389 uint8 FramesXmittedOk;
390 uint8 FramesRcvdOk;
391 uint8 FramesDeferred;
392 uint8 UpperFramesOk;
393 uint16 BytesRcvdOk;
394 uint16 BytesXmittedOk;
395 uint16 XXX; // IntStatus/CommandRegister
396 } PACKED;
397
398 /*
399 * EEPROM
400 */
401 enum EEPROMField {
402 EEPROM_NodeAddress0 = 0x00,
403 EEPROM_NodeAddress1 = 0x01,
404 EEPROM_NodeAddress2 = 0x02,
405 EEPROM_DeviceID = 0x03,
406 EEPROM_ManifacturerID = 0x07,
407 EEPROM_PCIParam = 0x08,
408 EEPROM_RomInfo = 0x09,
409 EEPROM_OEMNodeAddress0 = 0x0a,
410 EEPROM_OEMNodeAddress1 = 0x0b,
411 EEPROM_OEMNodeAddress2 = 0x0c,
412 EEPROM_SoftwareInfo = 0x0d,
413 EEPROM_CompWord = 0x0e,
414 EEPROM_SoftwareInfo2 = 0x0f,
415 EEPROM_Caps = 0x10,
416 EEPROM_InternalConfig0 = 0x12,
417 EEPROM_InternalConfig1 = 0x13,
418 EEPROM_SubsystemVendorID = 0x17,
419 EEPROM_SubsystemID = 0x18,
420 EEPROM_MediaOptions = 0x19,
421 EEPROM_SmbAddress = 0x1b,
422 EEPROM_PCIParam2 = 0x1c,
423 EEPROM_PCIParam3 = 0x1d,
424 EEPROM_Checksum = 0x20
425 };
426
427 /*
428 * Up/Downloading
429 */
430
431 // must be on 8-byte physical address boundary
432 struct DPD0 {
433 uint32 DnNextPtr;
434 uint32 FrameStartHeader;
435 /* DPDFragDesc Frags[n] */
436 };
437
438 enum FrameStartHeaderBits {
439 FSH_rndupBndry = 3<<0,
440 FSH_pktId = 15<<2,
441 /* 12:10 unspecified */
442 FSH_crcAppendDisable = 1<<13,
443 FSH_txIndicate = 1<<15,
444 FSH_dnComplete = 1<<16,
445 FSH_reArmDisable = 1<<23,
446 FSH_lastKap = 1<<24,
447 FSH_addIpChecksum = 1<<25,
448 FSH_addTcpChecksum = 1<<26,
449 FSH_addUdpChecksum = 1<<27,
450 FSH_rndupDefeat = 1<<28,
451 FSH_dpdEmpty = 1<<29,
452 /* 30 unspecified */
453 FSH_dnIndicate = 1<<31
454 };
455
456 // must be on 16-byte physical address boundary
457 struct DPD1 {
458 uint32 DnNextPtr;
459 uint32 ScheduleTime;
460 uint32 FrameStartHeader;
461 uint32 res;
462 /* DPDFragDesc Frags[n] */
463 };
464
465 struct DPDFragDesc {
466 uint32 DnFragAddr;
467 uint32 DnFragLen; // [12:0] fragLen, [31] lastFrag
468 } PACKED;
469
470 // must be on 8-byte physical address boundary
471 struct UPD {
472 uint32 UpNextPtr;
473 uint32 UpPktStatus;
474 /* UPDFragDesc Frags[n] */
475 };
476
477 struct UPDFragDesc {
478 uint32 UpFragAddr;
479 uint32 UpFragLen; // [12:0] fragLen, [31] lastFrag
480 } PACKED;
481
482 #define MAX_DPD_FRAGS 63
483 #define MAX_UPD_FRAGS 63
484 #define MAX_UPD_SIZE (sizeof(UPD) + sizeof(UPDFragDesc)*MAX_UPD_FRAGS) // 512
485
486 enum UpPktStatusBits {
487 UPS_upPktLen = 0x1fff,
488 /* 13 unspecified */
489 UPS_upError = 1<<14,
490 UPS_upComplete = 1<<15,
491 UPS_upOverrun = 1<<16,
492 UPS_runtFrame = 1<<17,
493 UPS_alignmentError = 1<<18,
494 UPS_crcError = 1<<19,
495 UPS_oversizedFrame = 1<<20,
496 /* 22:21 unspecified */
497 UPS_dribbleBits = 1<<23,
498 UPS_upOverflow = 1<<24,
499 UPS_ipChecksumError = 1<<25,
500 UPS_tcpChecksumError = 1<<26,
501 UPS_udpChecksumError = 1<<27,
502 UPD_impliedBufferEnable = 1<<28,
503 UPS_ipChecksumChecked = 1<<29,
504 UPS_tcpChecksumChecked = 1<<30,
505 UPS_udpChecksumChecked = 1<<31
506 };
507
508 // IEEE 802.3 MAC, Ethernet-II
509 struct EthFrameII {
510 byte destMAC[6];
511 byte srcMAC[6];
512 byte type[2];
513 } PACKED;
514
515 /*
516 * misc
517 */
518 static int compareMACs(byte a[6], byte b[6])
519 {
520 for (uint i = 0; i < 6; i++) {
521 if (a[i] != b[i]) return a[i] - b[i];
522 }
523 return 0;
524 }
525
526 /*
527 *
528 */
529 class _3c90x_NIC: public PCI_Device {
530 protected:
531 uint16 mEEPROM[0x40];
532 bool mEEPROMWritable;
533 Registers mRegisters;
534 RegWindow mWindows[8];
535 uint16 mIntStatus;
536 bool mRxEnabled;
537 bool mTxEnabled;
538 bool mUpStalled;
539 bool mDnStalled;
540 byte mRxPacket[MAX_PACKET_SIZE];
541 uint mRxPacketSize;
542 EthTunDevice * mEthTun;
543 sys_mutex mLock;
544
545 union {
546 MIIRegisters s;
547 uint16 reg[8];
548 } mMIIRegs;
549
550 uint32 mMIIReadWord;
551 uint64 mMIIWriteWord;
552 uint mMIIWrittenBits;
553 uint16 mLastHiClkPhysMgmt;
554 byte mMAC[6];
555
556 void PCIReset()
557 {
558 // PCI config
559 memset(mConfig, 0, sizeof mConfig);
560 // 0-3 set by totalReset()
561 // mConfig[0x04] = 0x07; // io+memory+master
562
563 mConfig[0x08] = 0x00; // revision
564 mConfig[0x09] = 0x00; //
565 mConfig[0x0a] = 0x00; // ClassCode 0x20000: Ethernet network controller
566 mConfig[0x0b] = 0x02; //
567
568 mConfig[0x0e] = 0x00; // header-type (single-function PCI device)
569
570 mConfig[0x3c] = IO_PIC_IRQ_ETHERNET0; // interrupt line
571 mConfig[0x3d] = 1; // interrupt pin (default is 1)
572 mConfig[0x3e] = 5; // MinGnt (default is 5 = 0x05 = 0101b)
573 mConfig[0x3f] = 48; // MaxLat (default is 48 = 0x30 = 110000b)
574
575 mConfig[0x34] = 0xdc;
576
577 mIORegSize[0] = 0x100;
578 mIORegType[0] = PCI_ADDRESS_SPACE_IO;
579 assignIOPort(0, 0x1000);
580 }
581
582 void totalReset()
583 {
584 /* FIXME: resetting can be done more fine-grained (see TotalReset cmd).
585 * this is reset ALL regs.
586 */
587 if (sizeof (Registers) != 0x70) {
588 IO_3C90X_ERR("sizeof Registers = %08x/%d\n", sizeof (Registers), sizeof (Registers));
589 }
590
591 RegWindow3 &w3 = (RegWindow3&)mWindows[3];
592 RegWindow5 &w5 = (RegWindow5&)mWindows[5];
593
594 // internals
595 mEEPROMWritable = false;
596 memset(&mWindows, 0, sizeof mWindows);
597 memset(&mRegisters, 0, sizeof mRegisters);
598 mIntStatus = 0;
599 mRxEnabled = false;
600 mTxEnabled = false;
601 mUpStalled = false;
602 mDnStalled = false;
603 w3.MaxPktSize = 1514 /* FIXME: should depend on sizeof mRxPacket*/;
604 w3.RxFree = 16*1024;
605 w3.TxFree = 16*1024;
606 mRxPacketSize = 0;
607 w5.TxStartThresh = 8188;
608 memset(mEEPROM, 0, sizeof mEEPROM);
609 mEEPROM[EEPROM_NodeAddress0] = (mMAC[0]<<8) | mMAC[1];
610 mEEPROM[EEPROM_NodeAddress1] = (mMAC[2]<<8) | mMAC[3];
611 mEEPROM[EEPROM_NodeAddress2] = (mMAC[4]<<8) | mMAC[5];
612 mEEPROM[EEPROM_DeviceID] = 0x9200;
613 mEEPROM[EEPROM_ManifacturerID] = 0x6d50;
614 mEEPROM[EEPROM_PCIParam] = 0x2940;
615 mEEPROM[EEPROM_RomInfo] = 0; // no ROM
616 mEEPROM[EEPROM_OEMNodeAddress0] = mEEPROM[EEPROM_NodeAddress0];
617 mEEPROM[EEPROM_OEMNodeAddress1] = mEEPROM[EEPROM_NodeAddress1];
618 mEEPROM[EEPROM_OEMNodeAddress2] = mEEPROM[EEPROM_NodeAddress2];
619 mEEPROM[EEPROM_SoftwareInfo] = 0x4010;
620 mEEPROM[EEPROM_CompWord] = 0;
621 mEEPROM[EEPROM_SoftwareInfo2] = 0x00aa;
622 mEEPROM[EEPROM_Caps] = 0x72a2;
623 mEEPROM[EEPROM_InternalConfig0] = 0;
624 mEEPROM[EEPROM_InternalConfig1] = 0x0050; // default is 0x0180
625 mEEPROM[EEPROM_SubsystemVendorID] = 0x10b7;
626 mEEPROM[EEPROM_SubsystemID] = 0x9200;
627 mEEPROM[EEPROM_MediaOptions] = 0x000a;
628 mEEPROM[EEPROM_SmbAddress] = 0x6300;
629 mEEPROM[EEPROM_PCIParam2] = 0xffb7;
630 mEEPROM[EEPROM_PCIParam3] = 0xb7b7;
631 mEEPROM[EEPROM_Checksum] = 0;
632
633 // MII
634 memset(&mMIIRegs, 0, sizeof mMIIRegs);
635 mMIIRegs.s.status = (1<<14) | (1<<13) | (1<<12) | (1<<11) | (1<<5) | (1<<3) | (1<<2) | 1;
636 mMIIRegs.s.linkPartner = (1<<14) | (1<<7) | 1;
637 mMIIRegs.s.advert = (1<<14) | (1 << 10) | (1<<7) | 1;
638 mMIIReadWord = 0;
639 mMIIWriteWord = 0;
640 mMIIWrittenBits = 0;
641 mLastHiClkPhysMgmt = 0;
642
643 // Register follow-ups
644 w3.MediaOptions = mEEPROM[EEPROM_MediaOptions];
645 w3.InternalConfig = mEEPROM[EEPROM_InternalConfig0] |
646 (mEEPROM[EEPROM_InternalConfig1] << 16);
647
648 // PCI config follow-ups
649 mConfig[0x00] = mEEPROM[EEPROM_SubsystemVendorID] & 0xff; // vendor ID
650 mConfig[0x01] = mEEPROM[EEPROM_SubsystemVendorID] >> 8;
651 mConfig[0x02] = mEEPROM[EEPROM_DeviceID] & 0xff; // unit ID
652 mConfig[0x03] = mEEPROM[EEPROM_DeviceID] >> 8;
653 }
654
655 void readRegWindow(uint window, uint32 port, uint32 &data, uint size)
656 {
657 IO_3C90X_TRACE("readRegWindow(%d, %08x, %08x)\n", window, port, size);
658 switch (window) {
659 /* window 0 */
660 case 0: {
661 RegWindow0 &w0 = (RegWindow0&)mWindows[0];
662 switch (port) {
663 case W0_EEPROMCmd: {
664 if (size != 2) {
665 IO_3C90X_WARN("EepromCommand, size != 2\n");
666 SINGLESTEP("");
667 }
668 data = w0.EepromCommand;
669 break;
670 }
671 case W0_EEPROMData: {
672 if (size != 2) {
673 IO_3C90X_WARN("EepromData, size != 2\n");
674 SINGLESTEP("");
675 }
676 data = w0.EepromData;
677 break;
678 }
679 default:
680 IO_3C90X_WARN("reading here unimpl.0\n");
681 SINGLESTEP("");
682 break;
683 }
684 break;
685 }
686 /* window 1 */
687 case 1: {
688 data = 0;
689 //RegWindow1 &w1 = (RegWindow1&)mWindows[1];
690 memcpy(&data, &mWindows[1].b[port], size);
691 break;
692 }
693 /* window 2 */
694 case 2: {
695 data = 0;
696 //RegWindow2 &w2 = (RegWindow2&)mWindows[2];
697 memcpy(&data, &mWindows[2].b[port], size);
698 break;
699 }
700 /* window 3 */
701 case 3: {
702 data = 0;
703 //RegWindow3 &w3 = (RegWindow3&)mWindows[3];
704 memcpy(&data, &mWindows[3].b[port], size);
705 break;
706 }
707 /* window 4 */
708 case 4: {
709 RegWindow4 &w4 = (RegWindow4&)mWindows[4];
710 data = 0;
711 switch (port) {
712 case 8: {
713 // MII-interface
714 if (size != 2) {
715 IO_3C90X_WARN("alignment.4.8.read\n");
716 SINGLESTEP("");
717 }
718 bool mgmtData = mMIIReadWord & 0x80000000;
719 // IO_3C90X_TRACE("Read cycle mgmtData=%d\n", mgmtData ? 1 : 0);
720 if (mgmtData) {
721 data = w4.PhysMgmt | PM_mgmtData;
722 } else {
723 data = w4.PhysMgmt & (~PM_mgmtData);
724 }
725 /* IO_3C90X_TRACE("read PhysMgmt = %04x (mgmtData = %d)\n",
726 data, mgmtData ? 1 : 0);*/
727 break;
728 }
729 case 0xc: {
730 if (size != 1) {
731 IO_3C90X_WARN("alignment.4.c.read\n");
732 }
733 // reading clears
734 w4.BadSSD = 0;
735 memcpy(&data, &mWindows[4].b[port], size);
736 break;
737 }
738 default:
739 memcpy(&data, &mWindows[4].b[port], size);
740 }
741 break;
742 }
743 /* Window 5 */
744 case 5: {
745 data = 0;
746 //RegWindow5 &w5 = (RegWindow5&)mWindows[5];
747 memcpy(&data, &mWindows[5].b[port], size);
748 break;
749 }
750 /* Window 6 */
751 case 6: {
752 RegWindow6 &w6 = (RegWindow6&)mWindows[6];
753 // reading clears
754 if ((port == 0xa) && (size == 2)) {
755 // FIXME: BytesRcvdOk really is 20 bits !
756 // when reading here, write upper 4 bits
757 // in w4.UpperBytesOk[3:0]. no clearing.
758 w6.BytesRcvdOk = 0;
759 } else if ((port == 0xc) && (size == 2)) {
760 // FIXME: BytesXmittedOk really is 20 bits !
761 // when reading here, write upper 4 bits
762 // in w4.UpperBytesOk[7:4]. no clearing.
763 w6.BytesXmittedOk = 0;
764 } else if ((port == 0) && (size == 1)) {
765 w6.CarrierLost = 0;
766 } else if ((port == 8) && (size == 1)) {
767 w6.FramesDeferred = 0;
768 } else if ((port == 7) && (size == 1)) {
769 // FIXME: FramesRcvdOk really is 10 bits !
770 // when reading here, write upper 2 bits
771 // in w6.UpperFramesOk[1:0]. no clearing.
772 } else if ((port == 6) && (size == 1)) {
773 // FIXME: FramesXmittedOk really is 10 bits !
774 // when reading here, write upper 2 bits
775 // in w6.UpperFramesOk[5:4]. no clearing.
776 } else if ((port == 4) && (size == 1)) {
777 w6.LateCollisions = 0;
778 } else if ((port == 2) && (size == 1)) {
779 w6.MultipleCollisions = 0;
780 } else if ((port == 5) && (size == 1)) {
781 w6.RxOverruns = 0;
782 } else if ((port == 3) && (size == 1)) {
783 w6.SingleCollisions = 0;
784 } else if ((port == 1) && (size == 1)) {
785 w6.SqeErrors = 0;
786 }
787 data = 0;
788 memcpy(&data, &mWindows[6].b[port], size);
789 break;
790 }
791 /* Window 7 */
792 case 7: {
793 data = 0;
794 //RegWindow7 &w7 = (RegWindow7&)mWindows[7];
795 memcpy(&data, &mWindows[7].b[port], size);
796 break;
797 }
798 default:
799 IO_3C90X_WARN("reading here unimpl.\n");
800 SINGLESTEP("");
801 }
802 IO_3C90X_TRACE("= %04x\n", data);
803 }
804
805 void writeRegWindow(uint window, uint32 port, uint32 data, uint size)
806 {
807 IO_3C90X_TRACE("writeRegWindow(%d, %08x, %08x, %08x)\n", window, port, data, size);
808 switch (window) {
809 /* Window 0 */
810 case 0: {
811 RegWindow0 &w0 = (RegWindow0&)mWindows[0];
812 switch (port) {
813 case W0_EEPROMCmd: {
814 if (size != 2) {
815 IO_3C90X_WARN("EepromCommand, size != 2\n");
816 SINGLESTEP("");
817 }
818 w0.EepromCommand = data & 0xff7f; // clear eepromBusy
819 uint eeprom_addr = ((data >> 2) & 0xffc0) | (data & 0x3f);
820 switch (data & 0xc0) {
821 case EEOP_SubCmd:
822 switch (data & 0x30) {
823 case EESC_WriteDisable:
824 IO_3C90X_TRACE("EESC_WriteDisable\n");
825 mEEPROMWritable = false;
826 break;
827 case EESC_WriteAll:
828 IO_3C90X_WARN("WriteAll not impl.\n");
829 SINGLESTEP("");
830 memset(mEEPROM, 0xff, sizeof mEEPROM);
831 mEEPROMWritable = false;
832 break;
833 case EESC_EraseAll:
834 IO_3C90X_WARN("EraseAll not impl.\n");
835 SINGLESTEP("");
836 memset(mEEPROM, 0, sizeof mEEPROM);
837 mEEPROMWritable = false;
838 break;
839 case EESC_WriteEnable:
840 IO_3C90X_TRACE("EESC_WriteEnable\n");
841 mEEPROMWritable = true;
842 break;
843 default:
844 IO_3C90X_WARN("impossible\n");
845 SINGLESTEP("");
846 }
847 break;
848 case EEOP_WriteReg:
849 if (mEEPROMWritable) {
850 if (eeprom_addr*2 < sizeof mEEPROM) {
851 // disabled
852 IO_3C90X_WARN("EEOP_WriteReg(addr = %04x, %04x) oldvalue = %04x\n", eeprom_addr, w0.EepromData, mEEPROM[eeprom_addr]);
853 SINGLESTEP("");
854 mEEPROM[eeprom_addr] = w0.EepromData;
855 } else {
856 IO_3C90X_WARN("FAILED(out of bounds): EEOP_WriteReg(addr = %04x, %04x) oldvalue = %04x\n", eeprom_addr, w0.EepromData, mEEPROM[eeprom_addr]);
857 SINGLESTEP("");
858 }
859 mEEPROMWritable = false;
860 } else {
861 IO_3C90X_WARN("FAILED(not writable): EEOP_WriteReg(addr = %04x, %04x) oldvalue = %04x\n", eeprom_addr, w0.EepromData, mEEPROM[eeprom_addr]);
862 SINGLESTEP("");
863 }
864 break;
865 case EEOP_ReadReg:
866 if (eeprom_addr*2 < sizeof mEEPROM) {
867 w0.EepromData = mEEPROM[eeprom_addr];
868 IO_3C90X_TRACE("EEOP_ReadReg(addr = %04x) = %04x\n", eeprom_addr, w0.EepromData);
869 } else {
870 IO_3C90X_WARN("FAILED(out of bounds): EEOP_ReadReg(addr = %04x)\n", eeprom_addr);
871 SINGLESTEP("");
872 }
873 break;
874 case EEOP_EraseReg:
875 if (mEEPROMWritable) {
876 if (eeprom_addr*2 < sizeof mEEPROM) {
877 // disabled
878 IO_3C90X_WARN("EEOP_EraseReg(addr = %04x) oldvalue = %04x\n", eeprom_addr, mEEPROM[eeprom_addr]);
879 SINGLESTEP("");
880 mEEPROM[eeprom_addr] = 0;
881 } else {
882 IO_3C90X_WARN("FAILED(out of bounds): EEOP_EraseReg(addr = %04x) oldvalue = %04x\n", eeprom_addr, mEEPROM[eeprom_addr]);
883 SINGLESTEP("");
884 }
885 mEEPROMWritable = false;
886 } else {
887 IO_3C90X_WARN("FAILED(not writable): EEOP_EraseReg(addr = %04x) oldvalue = %04x\n", eeprom_addr, mEEPROM[eeprom_addr]);
888 SINGLESTEP("");
889 }
890 break;
891 default:
892 IO_3C90X_WARN("impossible\n");
893 SINGLESTEP("");
894 }
895 break;
896 }
897 case W0_EEPROMData:
898 if (size != 2) {
899 IO_3C90X_WARN("EepromData, size != 2\n");
900 SINGLESTEP("");
901 }
902 w0.EepromData = data;
903 break;
904 default:
905 IO_3C90X_WARN("writing here unimpl.0\n");
906 SINGLESTEP("");
907 break;
908 }
909 break;
910 }
911 /* Window 2 */
912 case 2: {
913 // RegWindow2 &w2 = (RegWindow2&)mWindows[2];
914 if (port+size<=0xc) {
915 IO_3C90X_TRACE("StationAddress or StationMask\n");
916 /* StationAddress or StationMask */
917 memcpy(&mWindows[2].b[port], &data, size);
918 } else {
919 IO_3C90X_WARN("writing here unimpl.2\n");
920 SINGLESTEP("");
921 }
922 break;
923 }
924 /* Window 3 */
925 case 3: {
926 /* uint32 InternalConfig PACKED;
927 uint16 MaxPktSize PACKED;
928 uint16 MacControl PACKED;
929 uint16 MediaOptions PACKED;
930 uint16 RxFree PACKED;
931 uint16 TxFree PACKED;*/
932 RegWindow3 &w3 = (RegWindow3&)mWindows[3];
933 switch (port) {
934 case 0:
935 if (size != 4) {
936 IO_3C90X_WARN("alignment.3.0\n");
937 SINGLESTEP("");
938 }
939 IO_3C90X_TRACE("InternalConfig\n");
940 w3.InternalConfig = data;
941 break;
942 case 4:
943 if (size != 2) {
944 IO_3C90X_WARN("alignment.3.4\n");
945 SINGLESTEP("");
946 }
947 IO_3C90X_ERR("MaxPktSize\n");
948 w3.MaxPktSize = data;
949 break;
950 case 6:
951 if (size != 2) {
952 IO_3C90X_WARN("alignment.3.6\n");
953 SINGLESTEP("");
954 }
955 IO_3C90X_TRACE("MacControl\n");
956 if (data != 0) {
957 IO_3C90X_WARN("setting MacControl != 0\n");
958 SINGLESTEP("");
959 }
960 w3.MacControl = data;
961 break;
962 case 8:
963 if (size != 2) {
964 IO_3C90X_WARN("alignment.3.8\n");
965 SINGLESTEP("");
966 }
967 IO_3C90X_TRACE("MediaOptions\n");
968 w3.MediaOptions = data;
969 break;
970 case 10:
971 if (size != 2) {
972 IO_3C90X_WARN("alignment.3.10\n");
973 SINGLESTEP("");
974 }
975 IO_3C90X_WARN("RxFree\n");
976 SINGLESTEP("");
977 w3.RxFree = data;
978 break;
979 case 12:
980 if (size != 2) {
981 IO_3C90X_WARN("alignment.3.12\n");
982 SINGLESTEP("");
983 }
984 IO_3C90X_WARN("TxFree\n");
985 SINGLESTEP("");
986 w3.TxFree = data;
987 break;
988 default:
989 IO_3C90X_WARN("writing here unimpl.3\n");
990 SINGLESTEP("");
991 }
992 break;
993 }
994 /* Window 4 */
995 case 4: {
996 RegWindow4 &w4 = (RegWindow4&)mWindows[4];
997 switch (port) {
998 case 6: {
999 if (size != 2) {
1000 IO_3C90X_WARN("alignment.4.6\n");
1001 SINGLESTEP("");
1002 }
1003 uint mask = 0xf341;
1004 IO_3C90X_TRACE("NetDiagnostic = %04x, old = %04x\n", ((w4.NetDiagnostic)&~mask)|(data&mask), w4.NetDiagnostic);
1005 w4.NetDiagnostic &= ~mask;
1006 w4.NetDiagnostic |= data & mask;
1007 break;
1008 }
1009 case 8: {
1010 // MII-interface
1011 if (size != 2) {
1012 IO_3C90X_WARN("alignment.4.8\n");
1013 SINGLESTEP("");
1014 }
1015 /* IO_3C90X_TRACE("PhysMgmt = %04x (clk=%d, data=%d, dir=%d), old = %04x\n",
1016 data, (data & PM_mgmtClk) ? 1 : 0, (data & PM_mgmtData) ? 1 : 0,
1017 (data & PM_mgmtDir) ? 1 : 0, w4.PhysMgmt);*/
1018 bool hiClk = !(w4.PhysMgmt & PM_mgmtClk) && (data & PM_mgmtClk);
1019 if (hiClk) {
1020 // Z means lo edge of mgmtDir
1021 bool Z = (mLastHiClkPhysMgmt & PM_mgmtDir) && !(data & PM_mgmtDir);
1022 // IO_3C90X_TRACE("hi-edge, Z=%d\n", Z ? 1 : 0);
1023 if (Z) {
1024 // IO_3C90X_TRACE("Z-cycle, %016qx, written bits=%d\n", &mMIIWriteWord, mMIIWrittenBits);
1025 // check if the 5 frames have been sent
1026 if (((mMIIWriteWord >> (mMIIWrittenBits-32-2)) & 0x3ffffffffULL) == 0x3fffffffdULL) {
1027 uint opcode = (mMIIWriteWord >> (mMIIWrittenBits-32-2-2)) & 3;
1028 uint PHYaddr = (mMIIWriteWord >> (mMIIWrittenBits-32-2-2-5)) & 0x1f;
1029 uint REGaddr = (mMIIWriteWord >> (mMIIWrittenBits-32-2-2-5-5)) & 0x1f;
1030 // IO_3C90X_TRACE("prefixed Z-cycle, opcode=%d, PHY=%02x, REG=%02x\n", opcode, PHYaddr, REGaddr);
1031 if ((PHYaddr == 0x18 /* hardcoded address [1] p.196 */)
1032 && (REGaddr < 0x10)) {
1033 switch (opcode) {
1034 case 1: {
1035 // Opcode Write
1036 IO_3C90X_TRACE("Opcode Write\n");
1037 if (mMIIWrittenBits == 64) {
1038 uint32 value = mMIIWriteWord & 0xffff;
1039 // IO_3C90X_TRACE("NOT writing 0x%04x to register. feature disabled. (old = 0x%04x)\n", value, mMIIRegs[REGaddr]);
1040 IO_3C90X_TRACE("Writing 0x%04x to MII register %d (old = 0x%04x)\n", value, REGaddr, mMIIRegs.reg[REGaddr]);
1041 mMIIRegs.reg[REGaddr] = value;
1042 } else {
1043 IO_3C90X_TRACE("But invalid write count=%d\n", mMIIWrittenBits);
1044 }
1045 mMIIWriteWord = 0;
1046 break;
1047 }
1048 case 2: {
1049 // Opcode Read
1050 IO_3C90X_TRACE("Opcode Read\n");
1051 if (mMIIWrittenBits == 32+2+2+5+5) {
1052 // msb gets sent first and is zero to indicated success
1053 // the register to be sent follows msb to lsb
1054 mMIIReadWord = mMIIRegs.reg[REGaddr] << 15;
1055 IO_3C90X_TRACE("Read 0x%04x from register %d\n", mMIIRegs.reg[REGaddr], REGaddr);
1056 } else {
1057 IO_3C90X_TRACE("But invalid write count=%d\n", mMIIWrittenBits);
1058 }
1059 mMIIWriteWord = 0;
1060 break;
1061 }
1062 default:
1063 // error
1064 IO_3C90X_TRACE("Invalid opcode %d\n", (mMIIWriteWord >> 10) & 3);
1065 mMIIReadWord = 0xffffffff;
1066 }
1067 } else {
1068 // error
1069 IO_3C90X_TRACE("Invalid PHY or REG\n");
1070 mMIIReadWord = 0xffffffff;
1071 }
1072 }
1073 mMIIWrittenBits = 0;
1074 w4.PhysMgmt = data;
1075 } else if (data & PM_mgmtDir) {
1076 // write
1077 bool mgmtData = data & PM_mgmtData;
1078 // IO_3C90X_TRACE("Write cycle mgmtData=%d\n", mgmtData ? 1 : 0);
1079 w4.PhysMgmt = data;
1080 mMIIWriteWord <<= 1;
1081 mMIIWriteWord |= mgmtData ? 1 : 0;
1082 mMIIWrittenBits++;
1083 } else {
1084 // read
1085 bool mgmtData = mMIIReadWord & 0x80000000;
1086 // IO_3C90X_TRACE("Read cycle mgmtData=%d\n", mgmtData ? 1 : 0);
1087 w4.PhysMgmt = data;
1088 if (mgmtData) {
1089 w4.PhysMgmt = w4.PhysMgmt | PM_mgmtData;
1090 } else {
1091 w4.PhysMgmt = w4.PhysMgmt & (~PM_mgmtData);
1092 }
1093 mMIIReadWord <<= 1;
1094 }
1095 mLastHiClkPhysMgmt = w4.PhysMgmt;
1096 } else {
1097 w4.PhysMgmt = data;
1098 }
1099 break;
1100 }
1101 case 10: {
1102 if (size != 2) {
1103 IO_3C90X_WARN("alignment.4.10\n");
1104 SINGLESTEP("");
1105 }
1106 uint mask = 0x10cc;
1107 IO_3C90X_TRACE("MediaStatus = %04x, old = %04x\n", ((w4.MediaStatus)&~mask)|(data&mask), w4.MediaStatus);
1108 w4.MediaStatus &= ~mask;
1109 w4.MediaStatus |= data & mask;
1110 w4.MediaStatus |= 0x8000; // auiDisable always on
1111 break;
1112 }
1113 default:
1114 IO_3C90X_WARN("generic to window 4\n");
1115 SINGLESTEP("");
1116 memcpy(&mWindows[4].b[port], &data, size);
1117 }
1118 break;
1119 }
1120 /**/
1121 default:
1122 IO_3C90X_WARN("writing here unimpl.\n");
1123 SINGLESTEP("");
1124 }
1125 }
1126
1127 void setCR(uint16 cr)
1128 {
1129 IO_3C90X_TRACE("setCR(cr = %x)\n", cr);
1130 switch (cr & (31<<11)) {
1131 case CmdTotalReset:
1132 // FIXME: care about params
1133 IO_3C90X_TRACE("TotalReset\n");
1134 totalReset();
1135 break;
1136 case CmdSelectWindow: {
1137 IO_3C90X_TRACE("SelectWindow (window = %d) oldwindow = %d\n", cr & 7, mIntStatus >> 13);
1138 mIntStatus &= 0x1fff;
1139 mIntStatus |= (cr & 7)<<13;
1140 break;
1141 }
1142 case CmdTxReset:
1143 IO_3C90X_TRACE("TxReset\n");
1144 break;
1145 case CmdRxReset:
1146 IO_3C90X_TRACE("RxReset\n");
1147 break;
1148 case CmdSetIndicationEnable: {
1149 RegWindow5 &w5 = (RegWindow5&)mWindows[5];
1150 IO_3C90X_TRACE("SetIndicationEnable(%04x) oldvalue = %04x\n", cr & 0x7fe, w5.IndicationEnable);
1151 w5.IndicationEnable = cr & 0x7fe;
1152 break;
1153 }
1154 case CmdSetIntrEnb: {
1155 RegWindow5 &w5 = (RegWindow5&)mWindows[5];
1156 IO_3C90X_TRACE("SetIntrEnab(%04x) oldvalue = %04x\n", cr & 0x7fe, w5.InterruptEnable);
1157 w5.InterruptEnable = cr & 0x7fe;
1158 break;
1159 }
1160 case CmdStatsEnable:
1161 /* implement me */
1162 IO_3C90X_TRACE("StatsEnable\n");
1163 break;
1164 case CmdStatsDisable:
1165 /* implement me */
1166 IO_3C90X_TRACE("StatsDisable\n");
1167 break;
1168 case CmdEnableDC:
1169 /* implement me */
1170 IO_3C90X_TRACE("EnableDC\n");
1171 break;
1172 case CmdDisableDC:
1173 /* implement me */
1174 IO_3C90X_TRACE("DisableDC\n");
1175 break;
1176 case CmdStall: {
1177 /* FIXME: threading */
1178 switch (cr & 3) {
1179 case 0: /* UpStall */
1180 case 1: /* UpUnstall */ {
1181 IO_3C90X_TRACE("Stall(%s)\n", ((cr & 3) == 0) ? "UpStall" : "UpUnstall");
1182 bool stall = !(cr & 1);
1183 mUpStalled = stall;
1184 /* bool stall = cr & 1;
1185 mRegisters.DmaCtrl &= ~DC_upStalled;
1186 if (stall) mRegisters.DmaCtrl |= DC_upStalled;*/
1187 checkUpWork();
1188 break;
1189 }
1190 case 2: /* DnStall */
1191 case 3: /* DnUnstall */ {
1192 IO_3C90X_TRACE("Stall(%s)\n", ((cr & 3) == 2) ? "DnStall" : "DnUnstall");
1193 bool stall = !(cr & 1);
1194 mDnStalled = stall;
1195 mRegisters.DmaCtrl &= ~DC_dnStalled;
1196 if (stall) mRegisters.DmaCtrl |= DC_dnStalled;
1197 checkDnWork();
1198 break;
1199 }
1200 }
1201 break;
1202 }
1203 case CmdSetRxFilter: {
1204 IO_3C90X_TRACE("SetRxFilter(%02x)\n", cr & 31);
1205 RegWindow5 &w5 = (RegWindow5&)mWindows[5];
1206 w5.RxFilter = cr & 31;
1207 break;
1208 }
1209 case CmdSetTxReclaimThresh: {
1210 IO_3C90X_TRACE("SetTxReclaimHash(%02x)\n", cr & 255);
1211 RegWindow5 &w5 = (RegWindow5&)mWindows[5];
1212 w5.TxReclaimThresh = cr & 255;
1213 break;
1214 }
1215 case CmdSetTxStartThresh: {
1216 IO_3C90X_WARN("SetTxStartTresh(%02x)\n", (cr & 0x7ff) << 2);
1217 // SINGLESTEP("");
1218 RegWindow5 &w5 = (RegWindow5&)mWindows[5];
1219 w5.TxStartThresh = (cr & 0x7ff) << 2;
1220 break;
1221 }
1222 case CmdSetHashFilterBit: {
1223 bool value = cr & 0x400;
1224 uint which = cr & 0x3f;
1225 IO_3C90X_WARN("SetHashFilterBit(which=%d, value=%d)\n", which, value ? 1 : 0);
1226 break;
1227 }
1228 case CmdSetRxEarlyThresh: {
1229 IO_3C90X_TRACE("SetTxStartTresh(%02x)\n", (cr & 0x7ff) << 2);
1230 RegWindow5 &w5 = (RegWindow5&)mWindows[5];
1231 w5.RxEarlyThresh = (cr & 0x7ff) << 2;
1232 break;
1233 }
1234 case CmdRxEnable: {
1235 IO_3C90X_TRACE("RxEnable\n");
1236 mRxEnabled = true;
1237 break;
1238 }
1239 case CmdRxDisable: {
1240 IO_3C90X_TRACE("ExDisable\n");
1241 mRxEnabled = false;
1242 break;
1243 }
1244 case CmdTxEnable: {
1245 IO_3C90X_TRACE("TxEnable\n");
1246 mTxEnabled = true;
1247 break;
1248 }
1249 case CmdTxDisable: {
1250 IO_3C90X_TRACE("TxDisable\n");
1251 mTxEnabled = false;
1252 break;
1253 }
1254 case CmdAckIntr: {
1255 /*
1256 0x1 interruptLatchAck
1257 0x2 linkEventAck
1258 0x20 rxEarlyAck
1259 0x40 intRequestedAck
1260 0x200 dnCompleteAck
1261 0x400 upCompleteAck
1262 */
1263 IO_3C90X_TRACE("AckIntr(%04x)\n", cr & 0x7ff);
1264 // ack/clear corresponding bits in IntStatus
1265 uint ISack = 0;
1266 if (cr & 0x01) ISack |= IS_interruptLatch;
1267 if (cr & 0x02) ISack |= IS_linkEvent;
1268 if (cr & 0x20) ISack |= IS_rxEarly;
1269 if (cr & 0x40) ISack |= IS_intRequested;
1270 if (cr & 0x200) ISack |= IS_dnComplete;
1271 if (cr & 0x400) ISack |= IS_upComplete;
1272 acknowledge(ISack);
1273 break;
1274 }
1275 /* case CmdReqIntr: {
1276 RegWindow5 &w5 = (RegWindow5&)mWindows[5];
1277 // set intRequested in IntStatus
1278 mIntStatus |= IS_intRequested;
1279
1280 // FIXME: generate Interrupt (if enabled)
1281 break;
1282 }*/
1283
1284 /*
1285 case CmdTxDone:
1286 case CmdRxDiscard:
1287 case CmdSetTxThreshold:
1288 */
1289 default:
1290 IO_3C90X_WARN("command not implemented: %x\n", cr);
1291 SINGLESTEP("");
1292 }
1293 }
1294
1295 void txDPD0(DPD0 *dpd)
1296 {
1297 // FIXME: createHostStruct()
1298 DPDFragDesc *frags = (DPDFragDesc*)(dpd+1);
1299 uint32 fsh = dpd->FrameStartHeader;
1300 IO_3C90X_TRACE("fsh = %08x\n", fsh);
1301 if (fsh & FSH_dpdEmpty) {
1302 // modify FrameStartHeader in DPD (!)
1303 dpd->FrameStartHeader |= FSH_dnComplete;
1304 // set next DnListPtr
1305 mRegisters.DnListPtr = dpd->DnNextPtr;
1306 IO_3C90X_TRACE("dpd empty\n");
1307 return;
1308 }
1309 byte pbuf[MAX_PACKET_SIZE];
1310 byte *p = pbuf;
1311 // some packet drivers need padding
1312 uint framePrefix = mEthTun->getWriteFramePrefix();
1313 memset(p, 0, framePrefix);
1314 p += framePrefix;
1315 //
1316 uint i = 0;
1317 // assemble packet from fragments (up to MAX_DPD_FRAGS fragments)
1318 while (i < MAX_DPD_FRAGS) {
1319 uint addr = frags->DnFragAddr;
1320 uint len = frags->DnFragLen & 0x1fff;
1321 IO_3C90X_TRACE("frag %d: %08x, len %04x (full: %08x)\n", i, addr, len, frags->DnFragLen);
1322 // dumpMem(addr, len);
1323 if (p-pbuf+len >= sizeof pbuf) {
1324 IO_3C90X_WARN("packet too big ! (%d >= %d)\n", p-pbuf+len, sizeof pbuf);
1325 SINGLESTEP("");
1326 return;
1327 }
1328 if (!ppc_dma_read(p, addr, len)) {
1329 IO_3C90X_WARN("frag addr invalid! cancelling\n");
1330 SINGLESTEP("");
1331 return;
1332 }
1333 p += len;
1334 // last fragment ?
1335 if (frags->DnFragLen & 0x80000000) break;
1336 frags++;
1337 i++;
1338 }
1339 uint psize = p-pbuf;
1340 if (!(fsh & FSH_rndupDefeat)) {
1341 // round packet length
1342 switch (fsh & FSH_rndupBndry) {
1343 case 0: {
1344 // 4 bytes
1345 uint gap = ((psize+3) & ~3) -psize;
1346 memset(pbuf+psize, 0, gap);
1347 psize += gap;
1348 break;
1349 }
1350 case 2: {
1351 // 2 bytes
1352 uint gap = ((psize+1) & ~1) -psize;
1353 memset(pbuf+psize, 0, gap);
1354 psize += gap;
1355 break;
1356 }
1357 }
1358 }
1359 //FSH_reArmDisable = 1<<23,
1360 //FSH_lastKap = 1<<24,
1361 //FSH_addIpChecksum = 1<<25,
1362 //FSH_addTcpChecksum = 1<<26,
1363 //FSH_addUdpChecksum = 1<<27,
1364 if (fsh & (0x1f << 23)) {
1365 IO_3C90X_WARN("unsupported flags in fsh, fsh = %08x\n", fsh);
1366 SINGLESTEP("");
1367 }
1368
1369 if (psize<60) {
1370 // pad packet to at least 60 bytes (+4 bytes crc = 64 bytes)
1371 memset(pbuf+psize, 0, (60-psize));
1372 psize = 60;
1373 }
1374 // append crc
1375 if (!(fsh & FSH_crcAppendDisable)) {
1376 uint32 crc = ether_crc(psize, pbuf);
1377 pbuf[psize+0] = crc;
1378 pbuf[psize+1] = crc>>8;
1379 pbuf[psize+2] = crc>>16;
1380 pbuf[psize+3] = crc>>24;
1381 psize += 4;
1382 IO_3C90X_TRACE("packet has crc: %08x\n", crc);
1383 }
1384
1385 // IO_3C90X_TRACE("tx(%d):\n", psize);
1386 // dumpMem(pbuf, psize);
1387 uint w = mEthTun->sendPacket(pbuf, psize);
1388 if (w) {
1389 if (w == psize) {
1390 IO_3C90X_TRACE("EthTun: %d bytes sent.\n", psize);
1391 } else {
1392 IO_3C90X_TRACE("EthTun: ARGH! send error: only %d of %d bytes sent\n", w, psize);
1393 }
1394 } else {
1395 IO_3C90X_TRACE("EthTun: ARGH! send error in packet driver.\n");
1396 }
1397 // indications
1398 mRegisters.DmaCtrl |= DC_dnComplete;
1399 uint inds = 0;
1400 if (fsh & FSH_dnIndicate) inds |= IS_dnComplete;
1401 if (fsh & FSH_txIndicate) inds |= IS_txComplete;
1402 indicate(inds);
1403 // modify FrameStartHeader in DPD (!)
1404 dpd->FrameStartHeader |= FSH_dnComplete;
1405 // set next DnListPtr, TxPktId
1406 mRegisters.DnListPtr = dpd->DnNextPtr;
1407 uint pktId = (fsh & FSH_pktId) >> 2;
1408 mRegisters.TxPktId = pktId;
1409 // maybe generate interrupt
1410 maybeRaiseIntr();
1411 }
1412
1413 bool passesRxFilter(byte *pbuf, uint psize)
1414 {
1415 EthFrameII *f = (EthFrameII*)pbuf;
1416 RegWindow5 &w5 = (RegWindow5&)mWindows[5];
1417 if (w5.RxFilter & RXFILT_receiveAllFrames) return true;
1418 // FIXME: Multicast hashing not implemented
1419 if (w5.RxFilter & RXFILT_receiveMulticastHash) return true;
1420 // FIXME: Multicasting not understood
1421 if (w5.RxFilter & RXFILT_receiveMulticast) return true;
1422 if (w5.RxFilter & RXFILT_receiveBroadcast) {
1423 byte broadcastMAC[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
1424 if (compareMACs(f->destMAC, broadcastMAC) == 0) return true;
1425 }
1426 if (w5.RxFilter & RXFILT_receiveIndividual) {
1427 byte destMAC[6];
1428 byte thisMAC[6];
1429 RegWindow2 &w2 = (RegWindow2&)mWindows[2];
1430 for (uint i = 0; i < 6; i++) {
1431 destMAC[i] = f->destMAC[i] & ~w2.StationMask[i];
1432 thisMAC[i] = w2.StationAddress[i] & ~w2.StationMask[i];
1433 }
1434 return compareMACs(destMAC, thisMAC) == 0;
1435 }
1436 return false;
1437 }
1438
1439 void rxUPD(UPD *upd)
1440 {
1441 // FIXME: threading to care about (mRegisters.DmaCtrl & DC_upAltSeqDisable)
1442 IO_3C90X_TRACE("rxUPD()\n");
1443
1444 bool error = false;
1445
1446 if (upd->UpPktStatus & UPS_upComplete) {
1447 // IO_3C90X_WARN("UPD already upComplete!\n");
1448
1449 // the top of the ring buffer is already used,
1450 // stall the upload and throw away the packet.
1451 // the ring buffers are filled.
1452
1453 mUpStalled = true;
1454 return;
1455 }
1456
1457 uint upPktStatus = 0;
1458
1459 if (mRegisters.UpPoll) {
1460 IO_3C90X_WARN("UpPoll unsupported\n");
1461 SINGLESTEP("");
1462 return;
1463 }
1464 // FIXME:
1465 // if (mRegisters.DmaCtrl & DC_upRxEarlyEnable)
1466 // IO_3C90X_ERR("DC_upRxEarlyEnable unsupported\n");
1467
1468 if ((mRxPacketSize > 0x1fff) || (mRxPacketSize > sizeof mRxPacket)) {
1469 IO_3C90X_TRACE("oversized frame\n");
1470 upd->UpPktStatus = UPS_upError | UPS_oversizedFrame;
1471 error = true;
1472 }
1473
1474 if (mRxPacketSize < 60) {
1475 // pad packet to at least 60 bytes (+4 bytes crc = 64 bytes)
1476 memset(mRxPacket+mRxPacketSize, 0, (60-mRxPacketSize));
1477 mRxPacketSize = 60;
1478 }
1479
1480 // IO_3C90X_TRACE("rx(%d):\n", mRxPacketSize);
1481 // dumpMem((unsigned char*)mRxPacket, mRxPacketSize);
1482
1483 /* RegWindow5 &w5 = (RegWindow5&)mWindows[5];
1484 if ((mRxPacketSize < 60) && (w5.RxEarlyThresh >= 60)) {
1485 IO_3C90X_TRACE("runt frame\n");
1486 upPktStatus |= UPS_upError | UPS_runtFrame;
1487 upd->UpPktStatus = upPktStatus;
1488 error = true;
1489 }*/
1490 if (upd->UpPktStatus & UPD_impliedBufferEnable) {
1491 IO_3C90X_WARN("UPD_impliedBufferEnable unsupported\n");
1492 SINGLESTEP("");
1493 return;
1494 }
1495 UPDFragDesc *frags = (UPDFragDesc*)(upd+1);
1496
1497 byte *p = mRxPacket;
1498 uint i = 0;
1499 while (!error && i < MAX_UPD_FRAGS) { // (up to MAX_UPD_FRAGS fragments)
1500 uint32 addr = frags->UpFragAddr;
1501 uint len = frags->UpFragLen & 0x1fff;
1502 IO_3C90X_TRACE("frag %d: %08x, len %04x (full: %08x)\n", i, addr, len, frags->UpFragLen);
1503 if (p-mRxPacket+len > sizeof mRxPacket) {
1504 upPktStatus |= UPS_upError | UPS_upOverflow;
1505 upd->UpPktStatus = upPktStatus;
1506 IO_3C90X_TRACE("UPD overflow!\n");
1507 SINGLESTEP("");
1508 error = true;
1509 break;
1510 }
1511
1512 if (!ppc_dma_write(addr, p, len)) {
1513 upPktStatus |= UPS_upError;
1514 upd->UpPktStatus = upPktStatus;
1515 IO_3C90X_WARN("invalid UPD fragment address! (%08x)\n", addr);
1516 SINGLESTEP("");
1517 error = true;
1518 break;
1519 }
1520 p += len;
1521 // last fragment ?
1522 if (frags->UpFragLen & 0x80000000) break;
1523 frags++;
1524 i++;
1525 }
1526
1527 if (!error) {
1528 IO_3C90X_TRACE("successfully uploaded packet of %d bytes\n", mRxPacketSize);
1529 }
1530 upPktStatus |= mRxPacketSize & 0x1fff;
1531 upPktStatus |= UPS_upComplete;
1532 upd->UpPktStatus = upPktStatus;
1533
1534 mRxPacketSize = 0;
1535
1536 /* the client OS is waiting for a change in status, but won't see it */
1537 /* until we dma our local copy upd->UpPktStatus back to the client address space */
1538 if (!ppc_dma_write(mRegisters.UpListPtr+4, &upd->UpPktStatus, sizeof(upd->UpPktStatus))) {
1539 upPktStatus |= UPS_upError;
1540 upd->UpPktStatus = upPktStatus; /* can't get this error out, anyways */
1541 IO_3C90X_WARN("invalid UPD UpListPtr address! (%08x)\n",mRegisters.UpListPtr+4);
1542 SINGLESTEP("");
1543 error = true;
1544 }
1545
1546 mRegisters.UpListPtr = upd->UpNextPtr;
1547
1548 // indications
1549 mRegisters.DmaCtrl |= DC_upComplete;
1550 indicate(IS_upComplete);
1551 maybeRaiseIntr();
1552 }
1553
1554 void indicate(uint indications)
1555 {
1556 RegWindow5 &w5 = (RegWindow5&)mWindows[5];
1557 if (w5.IndicationEnable & indications != indications) {
1558 IO_3C90X_TRACE("some masked: %08x\n", w5.IndicationEnable & indications);
1559 }
1560 mIntStatus |= w5.IndicationEnable & indications;
1561 if (indications & IS_upComplete) {
1562 mRegisters.DmaCtrl |= DC_upComplete;
1563 }
1564 if (indications & IS_dnComplete) {
1565 mRegisters.DmaCtrl |= DC_dnComplete;
1566 }
1567 IO_3C90X_TRACE("indicate(%08x) mIntStatus now = %08x\n", indications, mIntStatus);
1568 }
1569
1570 void acknowledge(uint indications)
1571 {
1572 // RegWindow5 &w5 = (RegWindow5&)mWindows[5];
1573 mIntStatus &= ~indications;
1574 if (indications & IS_upComplete) {
1575 mRegisters.DmaCtrl &= ~DC_upComplete;
1576 }
1577 if (indications & IS_dnComplete) {
1578 mRegisters.DmaCtrl &= ~DC_dnComplete;
1579 }
1580 IO_3C90X_TRACE("acknowledge(%08x) mIntStatus now = %08x\n", indications, mIntStatus);
1581 }
1582
1583 void maybeRaiseIntr()
1584 {
1585 RegWindow5 &w5 = (RegWindow5&)mWindows[5];
1586 if (w5.IndicationEnable & w5.InterruptEnable & mIntStatus) {
1587 mIntStatus |= IS_interruptLatch;
1588 IO_3C90X_TRACE("Generating interrupt. mIntStatus=%04x\n", mIntStatus);
1589 pic_raise_interrupt(mConfig[0x3c]);
1590 }
1591 }
1592
1593 void checkDnWork()
1594 {
1595 while (!mDnStalled && (mRegisters.DnListPtr != 0)) {
1596 byte dpd[512];
1597
1598 if (ppc_dma_read(dpd, mRegisters.DnListPtr, sizeof dpd)) {
1599 // get packet type
1600 byte type = dpd[7]>>6;
1601 switch (type) {
1602 case 0:
1603 case 2: {
1604 DPD0 *p = (DPD0*)dpd;
1605 IO_3C90X_TRACE("Got a type 0 DPD !\n");
1606 IO_3C90X_TRACE("DnNextPtr is %08x\n", p->DnNextPtr);
1607 txDPD0(p);
1608 break;
1609 }
1610 case 1: {
1611 IO_3C90X_TRACE("Got a type 1 DPD ! not implemented !\n");
1612 IO_3C90X_TRACE("DnNextPtr is %08x\n", ((DPD1*)dpd)->DnNextPtr);
1613 SINGLESTEP("");
1614 mRegisters.DnListPtr = 0;
1615 break;
1616 }
1617 default:
1618 IO_3C90X_TRACE("unsupported packet type 3\n");
1619 mRegisters.DnListPtr = 0;
1620 SINGLESTEP("");
1621 break;
1622 }
1623 } else {
1624 IO_3C90X_WARN("DnListPtr invalid!\n");
1625 break;
1626 }
1627 }
1628 }
1629
1630 void checkUpWork()
1631 {
1632 if (mRxEnabled && !mUpStalled && mRxPacketSize && (mRegisters.UpListPtr != 0) ) {
1633 byte upd[MAX_UPD_SIZE];
1634 if (ppc_dma_read(upd, mRegisters.UpListPtr, sizeof upd)) {
1635 UPD *p = (UPD*)upd;
1636 rxUPD(p);
1637 } else {
1638 IO_3C90X_WARN("invalid address in UpListPtr!\n");
1639 SINGLESTEP("");
1640 }
1641 } else {
1642 IO_3C90X_TRACE("Not uploading, because: mUpStalled(=%d) or UpListPtr == 0 (=%08x) or not mRxPacketSize(=%d)\n", mUpStalled, mRegisters.UpListPtr, mRxPacketSize);
1643 }
1644 }
1645
1646 public:
1647 _3c90x_NIC(EthTunDevice *aEthTun, const byte *mac)
1648 : PCI_Device("3c90x Network interface card", 0x1, 0xc)
1649 {
1650 int e;
1651 if ((e = sys_create_mutex(&mLock))) throw IOException(e);
1652 mEthTun = aEthTun;
1653 memcpy(mMAC, mac, 6);
1654 PCIReset();
1655 totalReset();
1656 }
1657
1658 virtual ~_3c90x_NIC()
1659 {
1660 mEthTun->shutdownDevice();
1661 delete mEthTun;
1662 sys_destroy_mutex(mLock);
1663 }
1664
1665 void readConfig(uint reg)
1666 {
1667 if (reg >= 0xdc) {
1668 IO_3C90X_WARN("re\n");
1669 SINGLESTEP("");
1670 }
1671 sys_lock_mutex(mLock);
1672 PCI_Device::readConfig(reg);
1673 sys_unlock_mutex(mLock);
1674 }
1675
1676 void writeConfig(uint reg, int offset, int size)
1677 {
1678 sys_lock_mutex(mLock);
1679 if (reg >= 0xdc) {
1680 IO_3C90X_WARN("jg\n");
1681 SINGLESTEP("");
1682 }
1683 PCI_Device::writeConfig(reg, offset, size);
1684 sys_unlock_mutex(mLock);
1685 }
1686
1687 bool readDeviceIO(uint r, uint32 port, uint32 &data, uint size)
1688 {
1689 if (r != 0) return false;
1690 bool retval = false;
1691 sys_lock_mutex(mLock);
1692 if (port == 0xe) {
1693 // IntStatus (no matter which window)
1694 if (size != 2) {
1695 IO_3C90X_WARN("unaligned read from IntStatus\n");
1696 SINGLESTEP("");
1697 }
1698 IO_3C90X_TRACE("read IntStatus = %04x\n", mIntStatus);
1699 data = mIntStatus;
1700 retval = true;
1701 } else if (port >= 0 && (port+size <= 0x0e)) {
1702 // read from window
1703 uint curwindow = mIntStatus >> 13;
1704 readRegWindow(curwindow, port, data, size);
1705 retval = true;
1706 } else if ((port+size > 0x1e) && (port <= 0x1f)) {
1707 if ((port != 0x1e) || (size != 2)) {
1708 IO_3C90X_WARN("unaligned read from IntStatusAuto\n");
1709 SINGLESTEP("");
1710 }
1711 RegWindow5 &w5 = (RegWindow5&)mWindows[5];
1712 // side-effects of reading IntStatusAuto:
1713 // 1.clear InterruptEnable
1714 w5.InterruptEnable = 0;
1715 // 2.clear some flags
1716 acknowledge(IS_dnComplete | IS_upComplete
1717 | IS_rxEarly | IS_intRequested
1718 | IS_interruptLatch | IS_linkEvent);
1719 data = mIntStatus;
1720 IO_3C90X_TRACE("read IntStatusAuto = %04x\n", data);
1721 retval = true;
1722 } else if ((port >= 0x10) && (port+size <= 0x10 + sizeof(Registers))) {
1723 byte l = gRegAccess[port-0x10];
1724 if (l != size) {
1725 IO_3C90X_WARN("invalid/unaligned read from register port=%04x, size=%d (expecting size %d)\n", port, size, l);
1726 SINGLESTEP("");
1727 }
1728 // read from (standard) register
1729 data = 0;
1730 memcpy(&data, ((byte*)&mRegisters)+port-0x10, size);
1731 switch (port) {
1732 case 0x1a:
1733 IO_3C90X_TRACE("read Timer = %08x\n", data);
1734 break;
1735 case 0x20:
1736 IO_3C90X_TRACE("read DmaCtrl = %08x\n", data);
1737 break;
1738 case 0x24:
1739 IO_3C90X_TRACE("read DownListPtr = %08x\n", data);
1740 break;
1741 case 0x38:
1742 IO_3C90X_TRACE("read UpListPtr = %08x\n", data);
1743 break;
1744 default:
1745 IO_3C90X_WARN("read reg %04x (size %d) = %08x\n", port, size, data);
1746 SINGLESTEP("");
1747 break;
1748 }
1749 retval = true;
1750 }
1751 sys_unlock_mutex(mLock);
1752 return retval;
1753 }
1754
1755 bool writeDeviceIO(uint r, uint32 port, uint32 data, uint size)
1756 {
1757 if (r != 0) return false;
1758 bool retval = false;
1759 sys_lock_mutex(mLock);
1760 if (port == 0xe) {
1761 // CommandReg (no matter which window)
1762 if (size != 2) {
1763 IO_3C90X_WARN("unaligned write to CommandReg\n");
1764 SINGLESTEP("");
1765 }
1766 setCR(data);
1767 retval = true;
1768 } else if (port >= 0 && (port+size <= 0x0e)) {
1769 // write to window
1770 uint curwindow = mIntStatus >> 13;
1771 writeRegWindow(curwindow, port, data, size);
1772 retval = true;
1773 } else if (port >= 0x10 && (port + size <= 0x10 + sizeof(Registers))) {
1774 byte l = gRegAccess[port-0x10];
1775 if (l != size) {
1776 IO_3C90X_WARN("invalid/unaligned write to register port=%04x, size=%d\n", port, size);
1777 SINGLESTEP("");
1778 }
1779 switch (port) {
1780 case 0x20: {
1781 uint DmaCtrlRWMask = DC_upRxEarlyEnable | DC_counterSpeed |
1782 DC_countdownMode | DC_defeatMWI | DC_defeatMRL |
1783 DC_upOverDiscEnable;
1784 mRegisters.DmaCtrl &= ~DmaCtrlRWMask;
1785 mRegisters.DmaCtrl |= data & DmaCtrlRWMask;
1786 IO_3C90X_TRACE("write DmaCtrl %08x (now = %08x)\n", data, mRegisters.DmaCtrl);
1787 break;
1788 }
1789 case 0x24: {
1790 if (!mRegisters.DnListPtr) {
1791 mRegisters.DnListPtr = data;
1792 IO_3C90X_TRACE("write DnListPtr (now = %08x)\n", mRegisters.DnListPtr);
1793 } else {
1794 IO_3C90X_TRACE("didn't write DnListPtr cause it's not 0 (now = %08x)\n", mRegisters.DnListPtr);
1795 }
1796 checkDnWork();
1797 break;
1798 }
1799 case 0x38: {
1800 mRegisters.UpListPtr = data;
1801 IO_3C90X_TRACE("write UpListPtr (now = %08x)\n", mRegisters.UpListPtr);
1802 checkUpWork();
1803 break;
1804 }
1805 case 0x2d:
1806 IO_3C90X_WARN("DnPoll\n");
1807 SINGLESTEP("");
1808 break;
1809 case 0x2a:
1810 memcpy(((byte*)&mRegisters)+port-0x10, &data, size);
1811 IO_3C90X_TRACE("write DnBurstThresh\n");
1812 break;
1813 case 0x2c:
1814 memcpy(((byte*)&mRegisters)+port-0x10, &data, size);
1815 IO_3C90X_TRACE("write DnPriorityThresh\n");
1816 break;
1817 case 0x2f:
1818 // used by Darwin as TxFreeThresh. Not documented in [1].
1819 memcpy(((byte*)&mRegisters)+port-0x10, &data, size);
1820 IO_3C90X_TRACE("write TxFreeThresh\n");
1821 break;
1822 case 0x3c:
1823 memcpy(((byte*)&mRegisters)+port-0x10, &data, size);
1824 IO_3C90X_TRACE("write UpPriorityThresh\n");
1825 break;
1826 case 0x3e:
1827 memcpy(((byte*)&mRegisters)+port-0x10, &data, size);
1828 IO_3C90X_TRACE("write UpBurstThresh\n");
1829 break;
1830 default:
1831 IO_3C90X_WARN("write to register port=%04x, size=%d\n", port, size);
1832 SINGLESTEP("");
1833 // write to (standard) register
1834 memcpy(((byte*)&mRegisters)+port-0x10, &data, size);
1835 }
1836 retval = true;
1837 }
1838 sys_unlock_mutex(mLock);
1839 return retval;
1840 }
1841
1842 /* new */
1843 void handleRxQueue()
1844 {
1845 while (1) {
1846 while (mEthTun->waitRecvPacket() != 0) {
1847 // don't block the system in case of (repeated) error(s)
1848 sys_suspend();
1849 }
1850 sys_lock_mutex(mLock);
1851 if (mRxPacketSize) {
1852 IO_3C90X_TRACE("Argh. old packet not yet uploaded. waiting some more...\n");
1853 } else {
1854 mRxPacketSize = mEthTun->recvPacket(mRxPacket, sizeof mRxPacket);
1855 if (mRxEnabled && (mRxPacketSize > sizeof(EthFrameII))) {
1856 indicate(IS_rxComplete);
1857 maybeRaiseIntr();
1858 acknowledge(IS_rxComplete);
1859 if (!passesRxFilter(mRxPacket, mRxPacketSize)) {
1860 IO_3C90X_TRACE("EthTun: %d bytes received. But they don't pass the filter.\n", mRxPacketSize);
1861 mRxPacketSize = 0;
1862 } else {
1863 IO_3C90X_TRACE("EthTun: %d bytes received.\n", mRxPacketSize);
1864 }
1865 } else {
1866 // don't block the system in case of (repeated) error(s)
1867 mRxPacketSize = 0;
1868 sys_suspend();
1869 }
1870 }
1871 checkUpWork();
1872 sys_unlock_mutex(mLock);
1873 }
1874 }
1875
1876 };
1877
1878 static void *_3c90xHandleRxQueue(void *nic)
1879 {
1880 _3c90x_NIC *NIC = (_3c90x_NIC *)nic;
1881 NIC->handleRxQueue();
1882 return NULL;
1883 }
1884
1885 #include "configparser.h"
1886 #include "tools/strtools.h"
1887
1888 bool _3c90x_installed = false;
1889
1890 #define _3C90X_KEY_INSTALLED "pci_3c90x_installed"
1891 #define _3C90X_KEY_MAC "pci_3c90x_mac"
1892
1893 void _3c90x_init()
1894 {
1895 if (gConfig->getConfigInt(_3C90X_KEY_INSTALLED)) {
1896 _3c90x_installed = true;
1897 byte mac[6];
1898 mac[0] = 0xde;
1899 mac[1] = 0xad;
1900 mac[2] = 0xca;
1901 mac[3] = 0xfe;
1902 mac[4] = 0x12;
1903 mac[5] = 0x34;
1904 if (gConfig->haveKey(_3C90X_KEY_MAC)) {
1905 String macstr_;
1906 gConfig->getConfigString(_3C90X_KEY_MAC, macstr_);
1907 // do something useful with mac
1908 const char *macstr = macstr_.contentChar();
1909 byte cfgmac[6];
1910 for (uint i = 0; i < 6; i++) {
1911 uint64 v;
1912 if (!parseIntStr(macstr, v, 16) || (v>255) || ((*macstr != ':') && (i!=5))) {
1913 IO_3C90X_ERR("error in config key %s:"
1914 "expected format: XX:XX:XX:XX:XX:XX, "
1915 "where X stands for any digit or the letters a-f, A-F (error at: %s)\n",_3C90X_KEY_MAC, macstr);
1916 }
1917 macstr++;
1918 cfgmac[i] = v;
1919 }
1920 memcpy(mac, cfgmac, sizeof mac);
1921 }
1922 EthTunDevice *ethTun = createEthernetTunnel();
1923 if (!ethTun) {
1924 IO_3C90X_ERR("Couldn't create ethernet tunnel\n");
1925 exit(1);
1926 }
1927 if (ethTun->initDevice()) {
1928 IO_3C90X_ERR("Couldn't initialize ethernet tunnel\n");
1929 exit(1);
1930 }
1931 #if 0
1932 printf("Creating 3com 3c90x NIC emulation with eth_addr = ");
1933 for (uint i = 0; i < 6; i++) {
1934 if (i < 5) {
1935 printf("%02x:", mac[i]);
1936 } else {
1937 printf("%02x", mac[i]);
1938 }
1939 }
1940 printf("\n");
1941 #endif
1942 _3c90x_NIC *MyNIC = new _3c90x_NIC(ethTun, mac);
1943 gPCI_Devices->insert(MyNIC);
1944 sys_thread rxthread;
1945 sys_create_thread(&rxthread, 0, _3c90xHandleRxQueue, MyNIC);
1946 }
1947 }
1948
1949 void _3c90x_done()
1950 {
1951 }
1952
1953 void _3c90x_init_config()
1954 {
1955 gConfig->acceptConfigEntryIntDef(_3C90X_KEY_INSTALLED, 0);
1956 gConfig->acceptConfigEntryString(_3C90X_KEY_MAC, false);
1957 }

  ViewVC Help
Powered by ViewVC 1.1.26