VirtualBox

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

Last change on this file since 32431 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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

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