|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 #include <ethernet.h> |
|
19 #include <e32hal.h> |
|
20 #include <e32cmn.h> |
|
21 #include "ethernet_device.h" |
|
22 |
|
23 // Constants specific to this file |
|
24 const TInt K1000mSecDelay = 1000; |
|
25 |
|
26 ///////////////////////////////////////// |
|
27 // Implementation of EthernetDevice class |
|
28 ///////////////////////////////////////// |
|
29 |
|
30 EthernetDevice::EthernetDevice() : iRxDfc(RxDfc, this) |
|
31 { |
|
32 DP("** (PDD) EthernetDevice()"); |
|
33 |
|
34 iInterruptId=-1; |
|
35 iCreated = FALSE; |
|
36 iStarted = FALSE; |
|
37 iRxDfc.SetDfcQ(Kern::DfcQue0()); |
|
38 } |
|
39 |
|
40 EthernetDevice::~EthernetDevice() |
|
41 { |
|
42 DP("** (PDD) ~EthernetDevice()"); |
|
43 DP("** (PDD) ~EthernetDevice Unbind Interrupt"); |
|
44 Interrupt::Unbind(EIntNet0); |
|
45 } |
|
46 |
|
47 void EthernetDevice::GetConfig(TEthernetConfigV01 &aConfig) const |
|
48 { |
|
49 DP("** (PDD) EthernetDevice::GetConfig"); |
|
50 aConfig = iDefaultConfig; |
|
51 } |
|
52 |
|
53 TInt EthernetDevice::ValidateConfig(const TEthernetConfigV01 &aConfig) const |
|
54 { |
|
55 DP("** (PDD) EthernetDevice::ValidateConfig"); |
|
56 |
|
57 switch(aConfig.iEthSpeed) |
|
58 { |
|
59 case KEthSpeedUnknown: |
|
60 return KErrNotSupported; |
|
61 default: |
|
62 break; |
|
63 } |
|
64 |
|
65 switch(aConfig.iEthDuplex) |
|
66 { |
|
67 case KEthDuplexUnknown: |
|
68 return KErrNotSupported; |
|
69 default: |
|
70 break; |
|
71 } |
|
72 |
|
73 return KErrNone; |
|
74 } |
|
75 |
|
76 void EthernetDevice::Caps(TDes8 &aCaps) const |
|
77 { |
|
78 DP("** (PDD) EthernetDevice::Caps"); |
|
79 TEthernetCaps capsBuf; |
|
80 |
|
81 aCaps.FillZ(aCaps.MaxLength()); |
|
82 aCaps=capsBuf.Left(Min(capsBuf.Length(),aCaps.MaxLength())); |
|
83 } |
|
84 |
|
85 TDfcQue* EthernetDevice::DfcQ(TInt aUnit) |
|
86 { |
|
87 DP("** (PDD) EthernetDevice::DfcQ"); |
|
88 return Kern::DfcQue0(); |
|
89 } |
|
90 |
|
91 TInt EthernetDevice::DisableIrqs() |
|
92 { |
|
93 DP("** (PDD) EthernetDevice::DisableIrqs"); |
|
94 return NKern::DisableInterrupts(1); |
|
95 } |
|
96 |
|
97 void EthernetDevice::RestoreIrqs(TInt aLevel) |
|
98 { |
|
99 DP("** (PDD) EthernetDevice::RestoreIrqs"); |
|
100 NKern::RestoreInterrupts(aLevel); |
|
101 } |
|
102 |
|
103 // |
|
104 // Enable Ethernet interrupt line, allocate memory for Rx/Tx paths and send QEMU frames for Rx transmission. |
|
105 // |
|
106 TInt EthernetDevice::DoCreate(TInt aUnit, const TDesC8* anInfo) |
|
107 { |
|
108 DP("** (PDD) Enter: EthernetDevice::DoCreate"); |
|
109 |
|
110 if(iCreated) |
|
111 return KErrNone; |
|
112 |
|
113 // Bind to Ethernet interrupt |
|
114 Interrupt::Bind(EIntNet0,Isr,this); |
|
115 SetMacAddress(); |
|
116 |
|
117 DP("** (PDD) EthernetDevice::DoCreate - VNET[VIRTIO_STATUS]"); |
|
118 |
|
119 VNET[VIRTIO_STATUS] = VIRTIO_CONFIG_S_ACKNOWLEDGE |
|
120 | VIRTIO_CONFIG_S_DRIVER; |
|
121 |
|
122 AllocRings(); |
|
123 VNET[VIRTIO_STATUS] |= VIRTIO_CONFIG_S_DRIVER_OK; |
|
124 AddRx(); |
|
125 VNET[VIRTIO_INT_ENABLE] = 1; |
|
126 |
|
127 iCreated = TRUE; |
|
128 |
|
129 DP("** (PDD) Exit: EthernetDevice::DoCreate"); |
|
130 |
|
131 return KErrNone; |
|
132 } |
|
133 |
|
134 TInt EthernetDevice::Start() |
|
135 { |
|
136 DP("** (PDD) EthernetDevice::Start()"); |
|
137 |
|
138 if(iStarted) |
|
139 return KErrNone; |
|
140 |
|
141 // wait for 1 sec as negotiation is going on... hopefully auto-neg completes by then |
|
142 NKern::Sleep(K1000mSecDelay); |
|
143 Interrupt::Enable(EIntNet0); |
|
144 |
|
145 iStarted = TRUE; |
|
146 |
|
147 return KErrNone; |
|
148 } |
|
149 |
|
150 void EthernetDevice::Stop(TStopMode aMode) |
|
151 { |
|
152 DP("** (PDD) EthernetDevice::Stop(TStopMode aMode)"); |
|
153 |
|
154 switch (aMode) |
|
155 { |
|
156 case EStopNormal: |
|
157 case EStopEmergency: |
|
158 iRxDfc.Cancel(); |
|
159 //Should we disable QEMU interrupts here? |
|
160 break; |
|
161 default: |
|
162 break; |
|
163 } |
|
164 |
|
165 iStarted = FALSE; |
|
166 Interrupt::Disable(EIntNet0); |
|
167 } |
|
168 |
|
169 // |
|
170 // Transmit Tx data to QEMU and increment iTxAvail idx counter to indicate to QEMU that a new frame is available. |
|
171 // |
|
172 TInt EthernetDevice::Send(TBuf8<KMaxEthernetPacket+32> &aBuffer) |
|
173 { |
|
174 DP("** (PDD) EthernetDevice::Send"); |
|
175 |
|
176 TInt err = KErrNone; |
|
177 TUint32 length = aBuffer.Length(); |
|
178 iTxBuffer = aBuffer; |
|
179 |
|
180 DP ("** (PDD) Value of iTxAvail->idx = %d\n", iTxAvail->idx); |
|
181 TInt ring_slot = iTxAvail->idx & (tx_ring_size - 1); |
|
182 DP ("** (PDD) Value of ring_slot = %d\n", ring_slot); |
|
183 |
|
184 memset(&tx_header, 0, sizeof(tx_header)); |
|
185 |
|
186 iTxDesc[0].addr = Epoc::LinearToPhysical((TUint32)&tx_header); |
|
187 iTxDesc[0].len = sizeof(tx_header); |
|
188 iTxDesc[0].flags = VRING_DESC_F_NEXT; |
|
189 iTxDesc[0].next = 1; |
|
190 iTxDesc[1].addr = Epoc::LinearToPhysical((TUint32) iTxBuffer.Ptr()); |
|
191 iTxDesc[1].len = length; |
|
192 iTxDesc[1].flags = 0; |
|
193 iTxAvail->ring[ring_slot] = 0; |
|
194 |
|
195 iTxAvail->idx++; |
|
196 DP ("** (PDD)iTxAvail->idx = %x, rx_last_used=%d\n", iTxAvail->idx, rx_last_used); |
|
197 |
|
198 VNET[VIRTIO_QUEUE_NOTIFY] = TX_QUEUE; |
|
199 |
|
200 DP ("** (PDD) iTxDesc[0].addr = %x\n", iTxDesc[0].addr); |
|
201 DP ("** (PDD) iTxDesc[0].len = %d\n", iTxDesc[0].len); |
|
202 DP ("** (PDD) iTxDesc[0].flags = %d\n", iTxDesc[0].flags); |
|
203 DP ("** (PDD) iTxDesc[0].next = %d\n", iTxDesc[0].next); |
|
204 DP ("** (PDD) iTxDesc[1].addr = %x\n", iTxDesc[1].addr); |
|
205 DP ("** (PDD) iTxDesc[1].len = %d\n", iTxDesc[1].len); |
|
206 DP ("** (PDD) iTxDesc[1].flags = %d\n", iTxDesc[1].flags); |
|
207 |
|
208 return err; |
|
209 } |
|
210 |
|
211 TInt EthernetDevice::ReceiveFrame(TBuf8<KMaxEthernetPacket+32> &aBuffer, |
|
212 TBool okToUse) |
|
213 { |
|
214 DP("** (PDD) EthernetDevice::ReceiveFrame"); |
|
215 |
|
216 //If no buffer available dump frame |
|
217 if (!okToUse) |
|
218 { |
|
219 DP("** (PDD) EthernetDevice::ReceiveFrame - dumping frame"); |
|
220 return KErrGeneral; |
|
221 } |
|
222 |
|
223 aBuffer.Copy(iRxBuffer.Ptr(), ETHERNET_PAYLOAD_SIZE); |
|
224 AddRx(); |
|
225 |
|
226 return KErrNone; |
|
227 } |
|
228 |
|
229 void EthernetDevice::Isr(TAny* aPtr) |
|
230 { |
|
231 DP("** (PDD) EthernetDevice::Isr(TAny* aPtr)"); |
|
232 |
|
233 Interrupt::Clear(EIntNet0); |
|
234 VNET[VIRTIO_INT_STATUS] = 1; |
|
235 EthernetDevice& d=*(EthernetDevice*)aPtr; |
|
236 d.iRxDfc.Add(); |
|
237 } |
|
238 |
|
239 void EthernetDevice::RxDfc(TAny* aPtr) |
|
240 { |
|
241 DP("** (PDD) EthernetDevice::RxDfc"); |
|
242 EthernetDevice& d=*(EthernetDevice*)aPtr; |
|
243 |
|
244 TInt x = VNET[VIRTIO_INT_STATUS]; |
|
245 DP("** (PDD) EthernetDevice::RxDfc - value of x=%d", x); |
|
246 |
|
247 TInt ring_slot = d.iRxUsed->idx & (d.rx_ring_size - 1); |
|
248 |
|
249 DP("**(PDD) RxDfc (d.iTxAvail->idx) = %d (d.iRxAvail->idx) = %d", d.iTxAvail->idx, d.iRxAvail->idx); |
|
250 DP("**(PDD) RxDfc (d.iRxUsed->idx) = %d ", d.iRxUsed->idx); |
|
251 DP("**(PDD) RxDfc ring_slot=%d, (d.iRxUsed->ring[%d].id) = %d", ring_slot, ring_slot, d.iRxUsed->ring[ring_slot].id); |
|
252 DP("**(PDD) RxDfc d.iRxDesc[1].next = %d", d.iRxDesc[1].next); |
|
253 |
|
254 //check to see if this is a Rx or Tx |
|
255 if (d.iRxUsed->idx != d.rx_last_used) |
|
256 { |
|
257 DP("** (PDD) Received Rx Interrupt"); |
|
258 d.rx_last_used++; |
|
259 DP("** (PDD) Value of rx_last_used=%d", d.rx_last_used); |
|
260 d.ReceiveIsr(); |
|
261 } |
|
262 } |
|
263 |
|
264 void EthernetDevice::MacConfigure(TEthernetConfigV01 &aConfig) |
|
265 { |
|
266 DP("** (PDD) EthernetDevice::MacConfigure"); |
|
267 |
|
268 iDefaultConfig.iEthAddress[0] = aConfig.iEthAddress[0]; |
|
269 iDefaultConfig.iEthAddress[1] = aConfig.iEthAddress[1]; |
|
270 iDefaultConfig.iEthAddress[2] = aConfig.iEthAddress[2]; |
|
271 iDefaultConfig.iEthAddress[3] = aConfig.iEthAddress[3]; |
|
272 iDefaultConfig.iEthAddress[4] = aConfig.iEthAddress[4]; |
|
273 iDefaultConfig.iEthAddress[5] = aConfig.iEthAddress[5]; |
|
274 |
|
275 DP ("** (PDD) macaddr %02x:%02x:%02x:%02x:%02x:%02x\n", |
|
276 iDefaultConfig.iEthAddress[0], |
|
277 iDefaultConfig.iEthAddress[1], |
|
278 iDefaultConfig.iEthAddress[2], |
|
279 iDefaultConfig.iEthAddress[3], |
|
280 iDefaultConfig.iEthAddress[4], |
|
281 iDefaultConfig.iEthAddress[5]); |
|
282 } |
|
283 |
|
284 //Descriptor list and vring_used must start on a 4k page boundary. |
|
285 TAny * EthernetDevice::AllocAligned(TUint16 size) |
|
286 { |
|
287 DP("** (PDD) Enter: EthernetDevice::alloc_aligned"); |
|
288 DP("** (PDD) size=%d",size); |
|
289 |
|
290 TAny * p = Kern::Alloc(size + 4095); |
|
291 |
|
292 DP("** (PDD) BEFORE: p=%x",p); |
|
293 p = (TAny *)(((TUint32)p + 4095) & ~4095); |
|
294 DP("** (PDD) AFTER: p=%x",p); |
|
295 |
|
296 DP("** (PDD) Exit: EthernetDevice::alloc_aligned"); |
|
297 |
|
298 return p; |
|
299 } |
|
300 |
|
301 TAny EthernetDevice::AllocRings() |
|
302 { |
|
303 DP("** (PDD) Enter: EthernetDevice::AllocRings"); |
|
304 |
|
305 TUint size; |
|
306 TUint used_offset; |
|
307 TUint32 p; |
|
308 |
|
309 VNET[VIRTIO_QUEUE_SEL] = TX_QUEUE; |
|
310 tx_ring_size = VNET[VIRTIO_QUEUE_NUM]; |
|
311 |
|
312 DP ("** (PDD) tx_ring_size = %d\n", tx_ring_size); |
|
313 |
|
314 size = (tx_ring_size * (16 + 2)) + 4; |
|
315 used_offset = (size + 4095) & ~1024; |
|
316 DP ("** (PDD) used_offset = %d", used_offset); |
|
317 size = used_offset + 4 + (tx_ring_size * 8); |
|
318 DP ("** (PDD) size = %d", size); |
|
319 |
|
320 p = (TUint32)AllocAligned(size); |
|
321 DP ("** (PDD) p = %x\n", p); |
|
322 |
|
323 VNET[VIRTIO_QUEUE_BASE] = Epoc::LinearToPhysical(p); |
|
324 |
|
325 iTxDesc = reinterpret_cast<vring_desc*>(p); |
|
326 iTxAvail = reinterpret_cast<vring_avail*>(p + tx_ring_size * 16); |
|
327 iTxUsed = reinterpret_cast<vring_used*>(p + used_offset); |
|
328 |
|
329 DP ("** (PDD) iTxDesc = %x", iTxDesc); |
|
330 DP ("** (PDD) iTxAvail = %x", iTxAvail); |
|
331 DP ("** (PDD) iTxUsed = %x", iTxUsed); |
|
332 |
|
333 VNET[VIRTIO_QUEUE_SEL] = RX_QUEUE; |
|
334 rx_ring_size = VNET[VIRTIO_QUEUE_NUM]; |
|
335 |
|
336 size = (rx_ring_size * (16 + 2)) + 4; |
|
337 used_offset = (size + 4095) & ~4095; |
|
338 size = used_offset + 4 + (rx_ring_size * 8); |
|
339 p = (TUint32)AllocAligned(size); |
|
340 DP ("** (PDD) p = %x\n", p); |
|
341 VNET[VIRTIO_QUEUE_BASE] = Epoc::LinearToPhysical(p); |
|
342 |
|
343 iRxDesc = reinterpret_cast<vring_desc*>(p); |
|
344 iRxAvail = reinterpret_cast<vring_avail*>(p + rx_ring_size * 16); |
|
345 iRxUsed = reinterpret_cast<vring_used*>(p + used_offset); |
|
346 |
|
347 DP ("** (PDD) iRxDesc = %x", iRxDesc); |
|
348 DP ("** (PDD) iRxAvail = %x", iRxAvail); |
|
349 DP ("** (PDD) iRxUsed = %x", iRxUsed); |
|
350 |
|
351 DP("** (PDD) Exit: EthernetDevice::AllocRings"); |
|
352 } |
|
353 |
|
354 void EthernetDevice::AddRx() |
|
355 { |
|
356 DP("** (PDD) Enter: EthernetDevice::AddRx"); |
|
357 |
|
358 TInt n = iRxAvail->idx & (rx_ring_size - 1); |
|
359 memset(&rx_header, 0, sizeof(rx_header)); |
|
360 iRxDesc[0].addr = Epoc::LinearToPhysical((TUint32)&rx_header); |
|
361 iRxDesc[0].len = sizeof(rx_header); |
|
362 iRxDesc[0].flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE; |
|
363 iRxDesc[0].next = 1; |
|
364 iRxDesc[1].addr = Epoc::LinearToPhysical((TUint32) iRxBuffer.Ptr()); |
|
365 iRxDesc[1].len = ETHERNET_PAYLOAD_SIZE; |
|
366 iRxDesc[1].flags = VRING_DESC_F_WRITE; |
|
367 iRxAvail->ring[n] = 0; |
|
368 iRxAvail->idx++; |
|
369 VNET[VIRTIO_QUEUE_NOTIFY] = RX_QUEUE; |
|
370 |
|
371 DP("** (PDD) Exit: EthernetDevice::AddRx"); |
|
372 } |
|
373 |
|
374 |
|
375 |
|
376 void EthernetDevice::SetMacAddress(void) |
|
377 { |
|
378 DP("** (PDD) Enter: EthernetDevice::SetMacAddress"); |
|
379 |
|
380 iDefaultConfig.iEthAddress[0] = VNET_MAC[0]; |
|
381 iDefaultConfig.iEthAddress[1] = VNET_MAC[1]; |
|
382 iDefaultConfig.iEthAddress[2] = VNET_MAC[2]; |
|
383 iDefaultConfig.iEthAddress[3] = VNET_MAC[3]; |
|
384 iDefaultConfig.iEthAddress[4] = VNET_MAC[4]; |
|
385 iDefaultConfig.iEthAddress[5] = VNET_MAC[5]; |
|
386 |
|
387 DP ("** (PDD) macaddr %02x:%02x:%02x:%02x:%02x:%02x\n", |
|
388 iDefaultConfig.iEthAddress[0], |
|
389 iDefaultConfig.iEthAddress[1], |
|
390 iDefaultConfig.iEthAddress[2], |
|
391 iDefaultConfig.iEthAddress[3], |
|
392 iDefaultConfig.iEthAddress[4], |
|
393 iDefaultConfig.iEthAddress[5]); |
|
394 |
|
395 DP("** (PDD) Exit: EthernetDevice::SetMacAddress"); |
|
396 } |
|
397 |
|
398 // |
|
399 // Functions that are just stubs |
|
400 // |
|
401 |
|
402 void EthernetDevice::CheckConfig(TEthernetConfigV01& aConfig) |
|
403 { |
|
404 DP("** (PDD) EthernetDevice::CheckConfig"); |
|
405 } |
|
406 |
|
407 TInt EthernetDevice::Configure(TEthernetConfigV01 &aConfig) |
|
408 { |
|
409 DP("** (PDD) EthernetDevice::Configure"); |
|
410 return KErrNone; |
|
411 } |