VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DevE1000Phy.cpp@ 15953

最後變更 在這個檔案從15953是 15953,由 vboxsync 提交於 16 年 前

export E1000 to OSE

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 17.6 KB
 
1/** $Id: DevE1000Phy.cpp 15953 2009-01-14 19:21:31Z vboxsync $ */
2/** @file
3 * DevE1000Phy - Intel 82540EM Ethernet Controller Internal PHY Emulation.
4 *
5 * Implemented in accordance with the specification:
6 * PCI/PCI-X Family of Gigabit Ethernet Controllers Software Developer�s Manual
7 * 82540EP/EM, 82541xx, 82544GC/EI, 82545GM/EM, 82546GB/EB, and 82547xx
8 *
9 * 317453-002 Revision 3.5
10 */
11
12/*
13 * Copyright (C) 2007 Sun Microsystems, Inc.
14 *
15 * Sun Microsystems, Inc. confidential
16 * All rights reserved
17 */
18
19#define LOG_GROUP LOG_GROUP_DEV_E1000
20
21/** @todo Remove me! For now I want asserts to work in release code. */
22// #ifndef RT_STRICT
23// #define RT_STRICT
24#include <iprt/assert.h>
25// #undef RT_STRICT
26// #endif
27
28#include <VBox/err.h>
29#include <VBox/log.h>
30#include <VBox/ssm.h>
31#include "DevE1000Phy.h"
32
33/* Little helpers ************************************************************/
34#ifdef PHY_UNIT_TEST
35# define SSMR3PutMem(a,b,c)
36# define SSMR3GetMem(a,b,c)
37#include <stdio.h>
38# define PhyLog(a) printf a
39#else /* PHY_UNIT_TEST */
40# define PhyLog(a) Log(a)
41#endif /* PHY_UNIT_TEST */
42
43#define REG(x) pPhy->au16Regs[x##_IDX]
44
45
46/* Internals */
47namespace Phy {
48 /** Retrieves state name by id */
49 static const char * getStateName(uint16_t u16State);
50 /** Look up register index by address. */
51 static int lookupRegister(uint32_t u32Address);
52 /** Software-triggered reset. */
53 static void softReset(PPHY pPhy);
54
55 /* Generic handlers ******************************************************/
56 static uint16_t regReadDefault (PPHY pPhy, uint32_t index);
57 static void regWriteDefault (PPHY pPhy, uint32_t index, uint16_t u16Value);
58 static uint16_t regReadForbidden (PPHY pPhy, uint32_t index);
59 static void regWriteForbidden (PPHY pPhy, uint32_t index, uint16_t u16Value);
60 static uint16_t regReadUnimplemented (PPHY pPhy, uint32_t index);
61 static void regWriteUnimplemented(PPHY pPhy, uint32_t index, uint16_t u16Value);
62 /* Register-specific handlers ********************************************/
63 static void regWritePCTRL (PPHY pPhy, uint32_t index, uint16_t u16Value);
64 static uint16_t regReadPSTATUS (PPHY pPhy, uint32_t index);
65 static uint16_t regReadGSTATUS (PPHY pPhy, uint32_t index);
66
67 /**
68 * PHY register map table.
69 *
70 * Override pfnRead and pfnWrite to implement register-specific behavior.
71 */
72 static struct RegMap_st
73 {
74 /** PHY register address. */
75 uint32_t u32Address;
76 /** Read callback. */
77 uint16_t (*pfnRead)(PPHY pPhy, uint32_t index);
78 /** Write callback. */
79 void (*pfnWrite)(PPHY pPhy, uint32_t index, uint16_t u16Value);
80 /** Abbreviated name. */
81 const char *szAbbrev;
82 /** Full name. */
83 const char *szName;
84 } s_regMap[NUM_OF_PHY_REGS] =
85 {
86 /*ra read callback write callback abbrev full name */
87 /*-- ------------------------- -------------------------- ---------- ------------------------------*/
88 { 0, Phy::regReadDefault , Phy::regWritePCTRL , "PCTRL" , "PHY Control" },
89 { 1, Phy::regReadPSTATUS , Phy::regWriteForbidden , "PSTATUS" , "PHY Status" },
90 { 2, Phy::regReadDefault , Phy::regWriteForbidden , "PID" , "PHY Identifier" },
91 { 3, Phy::regReadDefault , Phy::regWriteForbidden , "EPID" , "Extended PHY Identifier" },
92 { 4, Phy::regReadDefault , Phy::regWriteDefault , "ANA" , "Auto-Negotiation Advertisement" },
93 { 5, Phy::regReadDefault , Phy::regWriteForbidden , "LPA" , "Link Partner Ability" },
94 { 6, Phy::regReadUnimplemented, Phy::regWriteForbidden , "ANE" , "Auto-Negotiation Expansion" },
95 { 7, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "NPT" , "Next Page Transmit" },
96 { 8, Phy::regReadUnimplemented, Phy::regWriteForbidden , "LPN" , "Link Partner Next Page" },
97 { 9, Phy::regReadDefault , Phy::regWriteUnimplemented, "GCON" , "1000BASE-T Control" },
98 { 10, Phy::regReadGSTATUS , Phy::regWriteForbidden , "GSTATUS" , "1000BASE-T Status" },
99 { 15, Phy::regReadUnimplemented, Phy::regWriteForbidden , "EPSTATUS" , "Extended PHY Status" },
100 { 16, Phy::regReadDefault , Phy::regWriteDefault , "PSCON" , "PHY Specific Control" },
101 { 17, Phy::regReadDefault , Phy::regWriteForbidden , "PSSTAT" , "PHY Specific Status" },
102 { 18, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "PINTE" , "PHY Interrupt Enable" },
103 { 19, Phy::regReadUnimplemented, Phy::regWriteForbidden , "PINTS" , "PHY Interrupt Status" },
104 { 20, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "EPSCON1" , "Extended PHY Specific Control 1" },
105 { 21, Phy::regReadUnimplemented, Phy::regWriteForbidden , "PREC" , "PHY Receive Error Counter" },
106 { 26, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "EPSCON2" , "Extended PHY Specific Control 2" },
107 { 29, Phy::regReadForbidden , Phy::regWriteUnimplemented, "R30PS" , "MDI Register 30 Page Select" },
108 { 30, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "R30AW" , "MDI Register 30 Access Window" }
109 };
110}
111
112/**
113 * Default read handler.
114 *
115 * Fetches register value from the state structure.
116 *
117 * @returns Register value
118 *
119 * @param index Register index in register array.
120 */
121static uint16_t Phy::regReadDefault(PPHY pPhy, uint32_t index)
122{
123 AssertReturn(index<Phy::NUM_OF_PHY_REGS, 0);
124 return pPhy->au16Regs[index];
125}
126
127/**
128 * Default write handler.
129 *
130 * Writes the specified register value to the state structure.
131 *
132 * @param index Register index in register array.
133 * @param value The value to store (ignored).
134 */
135static void Phy::regWriteDefault(PPHY pPhy, uint32_t index, uint16_t u16Value)
136{
137 AssertReturnVoid(index<NUM_OF_PHY_REGS);
138 pPhy->au16Regs[index] = u16Value;
139}
140
141/**
142 * Read handler for write-only registers.
143 *
144 * Merely reports reads from write-only registers.
145 *
146 * @returns Register value (always 0)
147 *
148 * @param index Register index in register array.
149 */
150static uint16_t Phy::regReadForbidden(PPHY pPhy, uint32_t index)
151{
152 PhyLog(("PHY#%d At %02d read attempted from write-only '%s'\n",
153 pPhy->iInstance, s_regMap[index].u32Address, s_regMap[index].szName));
154 return 0;
155}
156
157/**
158 * Write handler for read-only registers.
159 *
160 * Merely reports writes to read-only registers.
161 *
162 * @param index Register index in register array.
163 * @param value The value to store (ignored).
164 */
165static void Phy::regWriteForbidden(PPHY pPhy, uint32_t index, uint16_t u16Value)
166{
167 PhyLog(("PHY#%d At %02d write attempted to read-only '%s'\n",
168 pPhy->iInstance, s_regMap[index].u32Address, s_regMap[index].szName));
169}
170
171/**
172 * Read handler for unimplemented registers.
173 *
174 * Merely reports reads from unimplemented registers.
175 *
176 * @returns Register value (always 0)
177 *
178 * @param index Register index in register array.
179 */
180static uint16_t Phy::regReadUnimplemented(PPHY pPhy, uint32_t index)
181{
182 PhyLog(("PHY#%d At %02d read attempted from unimplemented '%s'\n",
183 pPhy->iInstance, s_regMap[index].u32Address, s_regMap[index].szName));
184 return 0;
185}
186
187/**
188 * Write handler for unimplemented registers.
189 *
190 * Merely reports writes to unimplemented registers.
191 *
192 * @param index Register index in register array.
193 * @param value The value to store (ignored).
194 */
195static void Phy::regWriteUnimplemented(PPHY pPhy, uint32_t index, uint16_t u16Value)
196{
197 PhyLog(("PHY#%d At %02d write attempted to unimplemented '%s'\n",
198 pPhy->iInstance, s_regMap[index].u32Address, s_regMap[index].szName));
199}
200
201
202/**
203 * Search PHY register table for register with matching address.
204 *
205 * @returns Index in the register table or -1 if not found.
206 *
207 * @param u32Address Register address.
208 */
209static int Phy::lookupRegister(uint32_t u32Address)
210{
211 unsigned int index;
212
213 for (index = 0; index < RT_ELEMENTS(s_regMap); index++)
214 {
215 if (s_regMap[index].u32Address == u32Address)
216 {
217 return index;
218 }
219 }
220
221 return -1;
222}
223
224/**
225 * Read PHY register.
226 *
227 * @returns Value of specified PHY register.
228 *
229 * @param u32Address Register address.
230 */
231uint16_t Phy::readRegister(PPHY pPhy, uint32_t u32Address)
232{
233 int index = Phy::lookupRegister(u32Address);
234 uint16_t u16 = 0;
235
236 if (index != -1)
237 {
238 u16 = s_regMap[index].pfnRead(pPhy, index);
239 PhyLog(("PHY#%d At %02d read %04X from %s (%s)\n",
240 pPhy->iInstance, s_regMap[index].u32Address, u16,
241 s_regMap[index].szAbbrev, s_regMap[index].szName));
242 }
243 else
244 {
245 PhyLog(("PHY#%d read attempted from non-existing register %08x\n",
246 pPhy->iInstance, u32Address));
247 }
248 return u16;
249}
250
251/**
252 * Write to PHY register.
253 *
254 * @param u32Address Register address.
255 * @param u16Value Value to store.
256 */
257void Phy::writeRegister(PPHY pPhy, uint32_t u32Address, uint16_t u16Value)
258{
259 int index = Phy::lookupRegister(u32Address);
260
261 if (index != -1)
262 {
263 PhyLog(("PHY#%d At %02d write %04X to %s (%s)\n",
264 pPhy->iInstance, s_regMap[index].u32Address, u16Value,
265 s_regMap[index].szAbbrev, s_regMap[index].szName));
266 s_regMap[index].pfnWrite(pPhy, index, u16Value);
267 }
268 else
269 {
270 PhyLog(("PHY#%d write attempted to non-existing register %08x\n",
271 pPhy->iInstance, u32Address));
272 }
273}
274
275/**
276 * PHY contructor.
277 *
278 * Stores E1000 instance internally. Triggers PHY hard reset.
279 *
280 * @param iNICInstance Number of network controller instance this PHY is
281 * attached to.
282 * @param u16EPid Extended PHY Id.
283 */
284void Phy::init(PPHY pPhy, int iNICInstance, uint16_t u16EPid)
285{
286 pPhy->iInstance = iNICInstance;
287 /* Make sure the link is down */
288 REG(PSTATUS) = 0;
289 /* The PHY identifier composed of bits 3 through 18 of the OUI */
290 /* (Organizationally Unique Identifier). OUI is 0x05043. */
291 REG(PID) = 0x0141;
292 /* Extended PHY identifier */
293 REG(EPID) = u16EPid;
294 hardReset(pPhy);
295}
296
297/**
298 * Hardware PHY reset.
299 *
300 * Sets all PHY registers to their initial values.
301 */
302void Phy::hardReset(PPHY pPhy)
303{
304 PhyLog(("PHY#%d Hard reset\n", pPhy->iInstance));
305 REG(PCTRL) = PCTRL_SPDSELM | PCTRL_DUPMOD | PCTRL_ANEG;
306 /*
307 * 100 and 10 FD/HD, MF Preamble Suppresion, Auto-Negotiation Complete,
308 * AUTO NEG AB, EXT CAP
309 */
310 REG(PSTATUS) = (REG(PSTATUS) & ~PSTATUS_LNKSTAT) | 0x7969;
311 REG(ANA) = 0x01E1;
312 /* No flow control by our link partner, all speeds */
313 REG(LPA) = 0x01E0;
314 REG(ANE) = 0x0000;
315 REG(NPT) = 0x2001;
316 REG(LPN) = 0x0000;
317 REG(GCON) = 0x1E00;
318 REG(GSTATUS) = 0x0000;
319 REG(EPSTATUS) = 0x3000;
320 REG(PSCON) = 0x0068;
321 REG(PSSTAT) = 0x0000;
322 REG(PINTE) = 0x0000;
323 REG(PINTS) = 0x0000;
324 REG(EPSCON1) = 0x0D60;
325 REG(PREC) = 0x0000;
326 REG(EPSCON2) = 0x000C;
327 REG(R30PS) = 0x0000;
328 REG(R30AW) = 0x0000;
329
330 pPhy->u16State = MDIO_IDLE;
331}
332
333/**
334 * Software PHY reset.
335 */
336static void Phy::softReset(PPHY pPhy)
337{
338 PhyLog(("PHY#%d Soft reset is not yet implemented!\n", pPhy->iInstance));
339}
340
341/**
342 * Get the current state of the link.
343 *
344 * @returns true if link is up.
345 */
346bool Phy::isLinkUp(PPHY pPhy)
347{
348 return (REG(PSSTAT) & PSSTAT_LINK) != 0;
349}
350
351/**
352 * Set the current state of the link.
353 *
354 * @remarks Link Status bit in PHY Status register is latched-low and does
355 * not change the state when the link goes up.
356 *
357 * @param fLinkIsUp New state of the link.
358 */
359void Phy::setLinkStatus(PPHY pPhy, bool fLinkIsUp)
360{
361 if (fLinkIsUp)
362 REG(PSSTAT) |= PSSTAT_LINK;
363 else
364 {
365 REG(PSSTAT) &= ~PSSTAT_LINK;
366 REG(PSTATUS) &= ~PSTATUS_LNKSTAT;
367 }
368}
369
370#ifdef IN_RING3
371/**
372 * Save PHY state.
373 *
374 * @remarks Since PHY is agregated into E1K it does not currently supports
375 * versioning of its own.
376 *
377 * @returns VBox status code.
378 * @param pSSMHandle The handle to save the state to.
379 * @param pPhy The pointer to this instance.
380 */
381int Phy::saveState(PSSMHANDLE pSSMHandle, PPHY pPhy)
382{
383 SSMR3PutMem(pSSMHandle, pPhy->au16Regs, sizeof(pPhy->au16Regs));
384 return VINF_SUCCESS;
385}
386
387/**
388 * Restore previously saved PHY state.
389 *
390 * @remarks Since PHY is agregated into E1K it does not currently supports
391 * versioning of its own.
392 *
393 * @returns VBox status code.
394 * @param pSSMHandle The handle to save the state to.
395 * @param pPhy The pointer to this instance.
396 */
397int Phy::loadState(PSSMHANDLE pSSMHandle, PPHY pPhy)
398{
399 SSMR3GetMem(pSSMHandle, pPhy->au16Regs, sizeof(pPhy->au16Regs));
400 return VINF_SUCCESS;
401}
402#endif /* IN_RING3 */
403
404/* Register-specific handlers ************************************************/
405
406/**
407 * Write handler for PHY Control register.
408 *
409 * Handles reset.
410 *
411 * @param index Register index in register array.
412 * @param value The value to store (ignored).
413 */
414static void Phy::regWritePCTRL(PPHY pPhy, uint32_t index, uint16_t u16Value)
415{
416 if (u16Value & PCTRL_RESET)
417 softReset(pPhy);
418 else
419 regWriteDefault(pPhy, index, u16Value);
420}
421
422/**
423 * Read handler for PHY Status register.
424 *
425 * Handles Latched-Low Link Status bit.
426 *
427 * @returns Register value
428 *
429 * @param index Register index in register array.
430 */
431static uint16_t Phy::regReadPSTATUS(PPHY pPhy, uint32_t index)
432{
433 /* Read latched value */
434 uint16_t u16 = REG(PSTATUS);
435 if (REG(PSSTAT) & PSSTAT_LINK)
436 REG(PSTATUS) |= PSTATUS_LNKSTAT;
437 else
438 REG(PSTATUS) &= ~PSTATUS_LNKSTAT;
439 return u16;
440}
441
442/**
443 * Read handler for 1000BASE-T Status register.
444 *
445 * @returns Register value
446 *
447 * @param index Register index in register array.
448 */
449static uint16_t Phy::regReadGSTATUS(PPHY pPhy, uint32_t index)
450{
451 /*
452 * - Link partner is capable of 1000BASE-T half duplex
453 * - Link partner is capable of 1000BASE-T full duplex
454 * - Remote receiver OK
455 * - Local receiver OK
456 * - Local PHY config resolved to SLAVE
457 */
458 return 0x3C00;
459}
460
461static const char * Phy::getStateName(uint16_t u16State)
462{
463 static const char *pcszState[] =
464 {
465 "MDIO_IDLE",
466 "MDIO_ST",
467 "MDIO_OP_ADR",
468 "MDIO_TA_RD",
469 "MDIO_TA_WR",
470 "MDIO_READ",
471 "MDIO_WRITE"
472 };
473
474 return (u16State < RT_ELEMENTS(pcszState)) ? pcszState[u16State] : "<invalid>";
475}
476
477bool Phy::readMDIO(PPHY pPhy)
478{
479 bool fPin = false;
480
481 switch (pPhy->u16State)
482 {
483 case MDIO_TA_RD:
484 Assert(pPhy->u16Cnt == 1);
485 fPin = false;
486 pPhy->u16State = MDIO_READ;
487 pPhy->u16Cnt = 16;
488 break;
489 case MDIO_READ:
490 /* Bits are shifted out in MSB to LSB order */
491 fPin = pPhy->u16Acc & 0x8000;
492 pPhy->u16Acc <<= 1;
493 if (--pPhy->u16Cnt == 0)
494 pPhy->u16State = MDIO_IDLE;
495 break;
496 default:
497 PhyLog(("PHY#%d WARNING! MDIO pin read in %s state\n", pPhy->iInstance, Phy::getStateName(pPhy->u16State)));
498 pPhy->u16State = MDIO_IDLE;
499 }
500 return fPin;
501}
502
503/** Set the value of MDIO pin. */
504void Phy::writeMDIO(PPHY pPhy, bool fPin)
505{
506 switch (pPhy->u16State)
507 {
508 case MDIO_IDLE:
509 if (!fPin)
510 pPhy->u16State = MDIO_ST;
511 break;
512 case MDIO_ST:
513 if (fPin)
514 {
515 pPhy->u16State = MDIO_OP_ADR;
516 pPhy->u16Cnt = 12; /* OP + PHYADR + REGADR */
517 pPhy->u16Acc = 0;
518 }
519 break;
520 case MDIO_OP_ADR:
521 Assert(pPhy->u16Cnt);
522 /* Shift in 'u16Cnt' bits into accumulator */
523 pPhy->u16Acc <<= 1;
524 if (fPin)
525 pPhy->u16Acc |= 1;
526 if (--pPhy->u16Cnt == 0)
527 {
528 /* Got OP(2) + PHYADR(5) + REGADR(5) */
529 /* Note: A single PHY is supported, ignore PHYADR */
530 switch (pPhy->u16Acc >> 10)
531 {
532 case MDIO_READ_OP:
533 pPhy->u16Acc = readRegister(pPhy, pPhy->u16Acc & 0x1F);
534 pPhy->u16State = MDIO_TA_RD;
535 pPhy->u16Cnt = 1;
536 break;
537 case MDIO_WRITE_OP:
538 pPhy->u16RegAdr = pPhy->u16Acc & 0x1F;
539 pPhy->u16State = MDIO_TA_WR;
540 pPhy->u16Cnt = 2;
541 break;
542 default:
543 PhyLog(("PHY#%d ERROR! Invalid MDIO op: %d\n", pPhy->iInstance, pPhy->u16Acc >> 10));
544 pPhy->u16State = MDIO_IDLE;
545 break;
546 }
547 }
548 break;
549 case MDIO_TA_WR:
550 Assert(pPhy->u16Cnt <= 2);
551 Assert(pPhy->u16Cnt > 0);
552 if (--pPhy->u16Cnt == 0)
553 {
554 pPhy->u16State = MDIO_WRITE;
555 pPhy->u16Cnt = 16;
556 }
557 break;
558 case MDIO_WRITE:
559 Assert(pPhy->u16Cnt);
560 pPhy->u16Acc <<= 1;
561 if (fPin)
562 pPhy->u16Acc |= 1;
563 if (--pPhy->u16Cnt == 0)
564 {
565 writeRegister(pPhy, pPhy->u16RegAdr, pPhy->u16Acc);
566 pPhy->u16State = MDIO_IDLE;
567 }
568 break;
569 default:
570 PhyLog(("PHY#%d ERROR! MDIO pin write in %s state\n", pPhy->iInstance, Phy::getStateName(pPhy->u16State)));
571 pPhy->u16State = MDIO_IDLE;
572 break;
573 }
574}
575
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette