/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide 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 dpavlin 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