]>
Commit | Line | Data |
---|---|---|
81a23a0f LL |
1 | /*++ |
2 | ||
3 | Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR> | |
4 | This program and the accompanying materials | |
5 | are licensed and made available under the terms and conditions of the BSD License | |
6 | which accompanies this distribution. The full text of the license may be found at | |
7 | http://opensource.org/licenses/bsd-license.php | |
8 | ||
9 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
10 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
11 | ||
12 | Module Name: | |
13 | PcatPciRootBridgeIo.c | |
14 | ||
15 | Abstract: | |
16 | ||
17 | EFI PC AT PCI Root Bridge Io Protocol | |
18 | ||
19 | Revision History | |
20 | ||
21 | --*/ | |
22 | ||
23 | #include "PcatPciRootBridge.h" | |
24 | ||
25 | // | |
26 | // Protocol Member Function Prototypes | |
27 | // | |
28 | EFI_STATUS | |
29 | EFIAPI | |
30 | PcatRootBridgeIoPollMem ( | |
31 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
32 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
33 | IN UINT64 Address, | |
34 | IN UINT64 Mask, | |
35 | IN UINT64 Value, | |
36 | IN UINT64 Delay, | |
37 | OUT UINT64 *Result | |
38 | ); | |
39 | ||
40 | EFI_STATUS | |
41 | EFIAPI | |
42 | PcatRootBridgeIoPollIo ( | |
43 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
44 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
45 | IN UINT64 Address, | |
46 | IN UINT64 Mask, | |
47 | IN UINT64 Value, | |
48 | IN UINT64 Delay, | |
49 | OUT UINT64 *Result | |
50 | ); | |
51 | ||
52 | EFI_STATUS | |
53 | EFIAPI | |
54 | PcatRootBridgeIoMemRead ( | |
55 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
56 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
57 | IN UINT64 Address, | |
58 | IN UINTN Count, | |
59 | IN OUT VOID *Buffer | |
60 | ); | |
61 | ||
62 | EFI_STATUS | |
63 | EFIAPI | |
64 | PcatRootBridgeIoMemWrite ( | |
65 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
66 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
67 | IN UINT64 Address, | |
68 | IN UINTN Count, | |
69 | IN OUT VOID *Buffer | |
70 | ); | |
71 | ||
72 | EFI_STATUS | |
73 | EFIAPI | |
74 | PcatRootBridgeIoCopyMem ( | |
75 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
76 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
77 | IN UINT64 DestAddress, | |
78 | IN UINT64 SrcAddress, | |
79 | IN UINTN Count | |
80 | ); | |
81 | ||
82 | EFI_STATUS | |
83 | EFIAPI | |
84 | PcatRootBridgeIoPciRead ( | |
85 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
86 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
87 | IN UINT64 Address, | |
88 | IN UINTN Count, | |
89 | IN OUT VOID *Buffer | |
90 | ); | |
91 | ||
92 | EFI_STATUS | |
93 | EFIAPI | |
94 | PcatRootBridgeIoPciWrite ( | |
95 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
96 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
97 | IN UINT64 Address, | |
98 | IN UINTN Count, | |
99 | IN OUT VOID *Buffer | |
100 | ); | |
101 | ||
102 | EFI_STATUS | |
103 | EFIAPI | |
104 | PcatRootBridgeIoMap ( | |
105 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
106 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, | |
107 | IN VOID *HostAddress, | |
108 | IN OUT UINTN *NumberOfBytes, | |
109 | OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, | |
110 | OUT VOID **Mapping | |
111 | ); | |
112 | ||
113 | EFI_STATUS | |
114 | EFIAPI | |
115 | PcatRootBridgeIoUnmap ( | |
116 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
117 | IN VOID *Mapping | |
118 | ); | |
119 | ||
120 | EFI_STATUS | |
121 | EFIAPI | |
122 | PcatRootBridgeIoAllocateBuffer ( | |
123 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
124 | IN EFI_ALLOCATE_TYPE Type, | |
125 | IN EFI_MEMORY_TYPE MemoryType, | |
126 | IN UINTN Pages, | |
127 | OUT VOID **HostAddress, | |
128 | IN UINT64 Attributes | |
129 | ); | |
130 | ||
131 | EFI_STATUS | |
132 | EFIAPI | |
133 | PcatRootBridgeIoFreeBuffer ( | |
134 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
135 | IN UINTN Pages, | |
136 | OUT VOID *HostAddress | |
137 | ); | |
138 | ||
139 | EFI_STATUS | |
140 | EFIAPI | |
141 | PcatRootBridgeIoFlush ( | |
142 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This | |
143 | ); | |
144 | ||
145 | EFI_STATUS | |
146 | EFIAPI | |
147 | PcatRootBridgeIoGetAttributes ( | |
148 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
149 | OUT UINT64 *Supported, | |
150 | OUT UINT64 *Attributes | |
151 | ); | |
152 | ||
153 | EFI_STATUS | |
154 | EFIAPI | |
155 | PcatRootBridgeIoSetAttributes ( | |
156 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
157 | IN UINT64 Attributes, | |
158 | IN OUT UINT64 *ResourceBase, | |
159 | IN OUT UINT64 *ResourceLength | |
160 | ); | |
161 | ||
162 | EFI_STATUS | |
163 | EFIAPI | |
164 | PcatRootBridgeIoConfiguration ( | |
165 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
166 | OUT VOID **Resources | |
167 | ); | |
168 | ||
169 | // | |
170 | // Private Function Prototypes | |
171 | // | |
172 | EFI_STATUS | |
173 | EFIAPI | |
174 | PcatRootBridgeIoMemRW ( | |
175 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
176 | IN UINTN Count, | |
177 | IN BOOLEAN InStrideFlag, | |
178 | IN PTR In, | |
179 | IN BOOLEAN OutStrideFlag, | |
180 | OUT PTR Out | |
181 | ); | |
182 | ||
183 | EFI_STATUS | |
184 | PcatRootBridgeIoConstructor ( | |
185 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Protocol, | |
186 | IN UINTN SegmentNumber | |
187 | ) | |
188 | /*++ | |
189 | ||
190 | Routine Description: | |
191 | ||
192 | Contruct the Pci Root Bridge Io protocol | |
193 | ||
194 | Arguments: | |
195 | ||
196 | Protocol - protocol to initialize | |
197 | ||
198 | Returns: | |
199 | ||
200 | None | |
201 | ||
202 | --*/ | |
203 | { | |
204 | Protocol->ParentHandle = NULL; | |
205 | ||
206 | Protocol->PollMem = PcatRootBridgeIoPollMem; | |
207 | Protocol->PollIo = PcatRootBridgeIoPollIo; | |
208 | ||
209 | Protocol->Mem.Read = PcatRootBridgeIoMemRead; | |
210 | Protocol->Mem.Write = PcatRootBridgeIoMemWrite; | |
211 | ||
212 | Protocol->Io.Read = PcatRootBridgeIoIoRead; | |
213 | Protocol->Io.Write = PcatRootBridgeIoIoWrite; | |
214 | ||
215 | Protocol->CopyMem = PcatRootBridgeIoCopyMem; | |
216 | ||
217 | Protocol->Pci.Read = PcatRootBridgeIoPciRead; | |
218 | Protocol->Pci.Write = PcatRootBridgeIoPciWrite; | |
219 | ||
220 | Protocol->Map = PcatRootBridgeIoMap; | |
221 | Protocol->Unmap = PcatRootBridgeIoUnmap; | |
222 | ||
223 | Protocol->AllocateBuffer = PcatRootBridgeIoAllocateBuffer; | |
224 | Protocol->FreeBuffer = PcatRootBridgeIoFreeBuffer; | |
225 | ||
226 | Protocol->Flush = PcatRootBridgeIoFlush; | |
227 | ||
228 | Protocol->GetAttributes = PcatRootBridgeIoGetAttributes; | |
229 | Protocol->SetAttributes = PcatRootBridgeIoSetAttributes; | |
230 | ||
231 | Protocol->Configuration = PcatRootBridgeIoConfiguration; | |
232 | ||
233 | Protocol->SegmentNumber = (UINT32)SegmentNumber; | |
234 | ||
235 | return EFI_SUCCESS; | |
236 | } | |
237 | ||
238 | EFI_STATUS | |
239 | EFIAPI | |
240 | PcatRootBridgeIoPollMem ( | |
241 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
242 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
243 | IN UINT64 Address, | |
244 | IN UINT64 Mask, | |
245 | IN UINT64 Value, | |
246 | IN UINT64 Delay, | |
247 | OUT UINT64 *Result | |
248 | ) | |
249 | { | |
250 | EFI_STATUS Status; | |
251 | UINT64 NumberOfTicks; | |
252 | UINT32 Remainder; | |
253 | ||
254 | if (Result == NULL) { | |
255 | return EFI_INVALID_PARAMETER; | |
256 | } | |
257 | ||
258 | ||
259 | if ((UINT32)Width > EfiPciWidthUint64) { | |
260 | return EFI_INVALID_PARAMETER; | |
261 | } | |
262 | // | |
263 | // No matter what, always do a single poll. | |
264 | // | |
265 | Status = This->Mem.Read (This, Width, Address, 1, Result); | |
266 | if ( EFI_ERROR(Status) ) { | |
267 | return Status; | |
268 | } | |
269 | if ( (*Result & Mask) == Value ) { | |
270 | return EFI_SUCCESS; | |
271 | } | |
272 | ||
273 | if (Delay == 0) { | |
274 | return EFI_SUCCESS; | |
275 | } else { | |
276 | ||
277 | NumberOfTicks = DivU64x32Remainder (Delay, 100, &Remainder); | |
278 | if ( Remainder !=0 ) { | |
279 | NumberOfTicks += 1; | |
280 | } | |
281 | NumberOfTicks += 1; | |
282 | ||
283 | while ( NumberOfTicks ) { | |
284 | ||
285 | gBS->Stall (10); | |
286 | ||
287 | Status = This->Mem.Read (This, Width, Address, 1, Result); | |
288 | if ( EFI_ERROR(Status) ) { | |
289 | return Status; | |
290 | } | |
291 | ||
292 | if ( (*Result & Mask) == Value ) { | |
293 | return EFI_SUCCESS; | |
294 | } | |
295 | ||
296 | NumberOfTicks -= 1; | |
297 | } | |
298 | } | |
299 | return EFI_TIMEOUT; | |
300 | } | |
301 | ||
302 | EFI_STATUS | |
303 | EFIAPI | |
304 | PcatRootBridgeIoPollIo ( | |
305 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
306 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
307 | IN UINT64 Address, | |
308 | IN UINT64 Mask, | |
309 | IN UINT64 Value, | |
310 | IN UINT64 Delay, | |
311 | OUT UINT64 *Result | |
312 | ) | |
313 | { | |
314 | EFI_STATUS Status; | |
315 | UINT64 NumberOfTicks; | |
316 | UINT32 Remainder; | |
317 | ||
318 | if (Result == NULL) { | |
319 | return EFI_INVALID_PARAMETER; | |
320 | } | |
321 | ||
322 | if ((UINT32)Width > EfiPciWidthUint64) { | |
323 | return EFI_INVALID_PARAMETER; | |
324 | } | |
325 | // | |
326 | // No matter what, always do a single poll. | |
327 | // | |
328 | Status = This->Io.Read (This, Width, Address, 1, Result); | |
329 | if ( EFI_ERROR(Status) ) { | |
330 | return Status; | |
331 | } | |
332 | if ( (*Result & Mask) == Value ) { | |
333 | return EFI_SUCCESS; | |
334 | } | |
335 | ||
336 | if (Delay == 0) { | |
337 | return EFI_SUCCESS; | |
338 | } else { | |
339 | ||
340 | NumberOfTicks = DivU64x32Remainder (Delay, 100, &Remainder); | |
341 | if ( Remainder !=0 ) { | |
342 | NumberOfTicks += 1; | |
343 | } | |
344 | NumberOfTicks += 1; | |
345 | ||
346 | while ( NumberOfTicks ) { | |
347 | ||
348 | gBS->Stall(10); | |
349 | ||
350 | Status = This->Io.Read (This, Width, Address, 1, Result); | |
351 | if ( EFI_ERROR(Status) ) { | |
352 | return Status; | |
353 | } | |
354 | ||
355 | if ( (*Result & Mask) == Value ) { | |
356 | return EFI_SUCCESS; | |
357 | } | |
358 | ||
359 | NumberOfTicks -= 1; | |
360 | } | |
361 | } | |
362 | return EFI_TIMEOUT; | |
363 | } | |
364 | ||
365 | BOOLEAN | |
366 | PcatRootBridgeMemAddressValid ( | |
367 | IN PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData, | |
368 | IN UINT64 Address | |
369 | ) | |
370 | { | |
371 | if ((Address >= PrivateData->PciExpressBaseAddress) && (Address < PrivateData->PciExpressBaseAddress + 0x10000000)) { | |
372 | return TRUE; | |
373 | } | |
374 | if ((Address >= PrivateData->MemBase) && (Address < PrivateData->MemLimit)) { | |
375 | return TRUE; | |
376 | } | |
377 | ||
378 | return FALSE; | |
379 | } | |
380 | ||
381 | EFI_STATUS | |
382 | EFIAPI | |
383 | PcatRootBridgeIoMemRead ( | |
384 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
385 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
386 | IN UINT64 Address, | |
387 | IN UINTN Count, | |
388 | IN OUT VOID *Buffer | |
389 | ) | |
390 | { | |
391 | PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; | |
392 | UINTN AlignMask; | |
393 | PTR In; | |
394 | PTR Out; | |
395 | ||
396 | if ( Buffer == NULL ) { | |
397 | return EFI_INVALID_PARAMETER; | |
398 | } | |
399 | ||
400 | PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); | |
401 | ||
402 | if (!PcatRootBridgeMemAddressValid (PrivateData, Address)) { | |
403 | return EFI_INVALID_PARAMETER; | |
404 | } | |
405 | ||
406 | AlignMask = (1 << (Width & 0x03)) - 1; | |
407 | if (Address & AlignMask) { | |
408 | return EFI_INVALID_PARAMETER; | |
409 | } | |
410 | ||
411 | Address += PrivateData->PhysicalMemoryBase; | |
412 | ||
413 | In.buf = Buffer; | |
414 | Out.buf = (VOID *)(UINTN) Address; | |
415 | if ((UINT32)Width <= EfiPciWidthUint64) { | |
416 | return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out); | |
417 | } | |
418 | if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { | |
419 | return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out); | |
420 | } | |
421 | if (Width >= EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { | |
422 | return PcatRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out); | |
423 | } | |
424 | ||
425 | return EFI_INVALID_PARAMETER; | |
426 | } | |
427 | ||
428 | EFI_STATUS | |
429 | EFIAPI | |
430 | PcatRootBridgeIoMemWrite ( | |
431 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
432 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
433 | IN UINT64 Address, | |
434 | IN UINTN Count, | |
435 | IN OUT VOID *Buffer | |
436 | ) | |
437 | { | |
438 | PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; | |
439 | UINTN AlignMask; | |
440 | PTR In; | |
441 | PTR Out; | |
442 | ||
443 | if ( Buffer == NULL ) { | |
444 | return EFI_INVALID_PARAMETER; | |
445 | } | |
446 | ||
447 | PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); | |
448 | ||
449 | if (!PcatRootBridgeMemAddressValid (PrivateData, Address)) { | |
450 | return EFI_INVALID_PARAMETER; | |
451 | } | |
452 | ||
453 | AlignMask = (1 << (Width & 0x03)) - 1; | |
454 | if (Address & AlignMask) { | |
455 | return EFI_INVALID_PARAMETER; | |
456 | } | |
457 | ||
458 | Address += PrivateData->PhysicalMemoryBase; | |
459 | ||
460 | In.buf = (VOID *)(UINTN) Address; | |
461 | Out.buf = Buffer; | |
462 | if ((UINT32)Width <= EfiPciWidthUint64) { | |
463 | return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out); | |
464 | } | |
465 | if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { | |
466 | return PcatRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out); | |
467 | } | |
468 | if (Width >= EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { | |
469 | return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out); | |
470 | } | |
471 | ||
472 | return EFI_INVALID_PARAMETER; | |
473 | } | |
474 | ||
475 | EFI_STATUS | |
476 | EFIAPI | |
477 | PcatRootBridgeIoCopyMem ( | |
478 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
479 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
480 | IN UINT64 DestAddress, | |
481 | IN UINT64 SrcAddress, | |
482 | IN UINTN Count | |
483 | ) | |
484 | ||
485 | { | |
486 | EFI_STATUS Status; | |
487 | BOOLEAN Direction; | |
488 | UINTN Stride; | |
489 | UINTN Index; | |
490 | UINT64 Result; | |
491 | ||
492 | if ((UINT32)Width > EfiPciWidthUint64) { | |
493 | return EFI_INVALID_PARAMETER; | |
494 | } | |
495 | ||
496 | if (DestAddress == SrcAddress) { | |
497 | return EFI_SUCCESS; | |
498 | } | |
499 | ||
500 | Stride = (UINTN)1 << Width; | |
501 | ||
502 | Direction = TRUE; | |
503 | if ((DestAddress > SrcAddress) && (DestAddress < (SrcAddress + Count * Stride))) { | |
504 | Direction = FALSE; | |
505 | SrcAddress = SrcAddress + (Count-1) * Stride; | |
506 | DestAddress = DestAddress + (Count-1) * Stride; | |
507 | } | |
508 | ||
509 | for (Index = 0;Index < Count;Index++) { | |
510 | Status = PcatRootBridgeIoMemRead ( | |
511 | This, | |
512 | Width, | |
513 | SrcAddress, | |
514 | 1, | |
515 | &Result | |
516 | ); | |
517 | if (EFI_ERROR (Status)) { | |
518 | return Status; | |
519 | } | |
520 | Status = PcatRootBridgeIoMemWrite ( | |
521 | This, | |
522 | Width, | |
523 | DestAddress, | |
524 | 1, | |
525 | &Result | |
526 | ); | |
527 | if (EFI_ERROR (Status)) { | |
528 | return Status; | |
529 | } | |
530 | if (Direction) { | |
531 | SrcAddress += Stride; | |
532 | DestAddress += Stride; | |
533 | } else { | |
534 | SrcAddress -= Stride; | |
535 | DestAddress -= Stride; | |
536 | } | |
537 | } | |
538 | return EFI_SUCCESS; | |
539 | } | |
540 | ||
541 | EFI_STATUS | |
542 | EFIAPI | |
543 | PcatRootBridgeIoPciRead ( | |
544 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
545 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
546 | IN UINT64 Address, | |
547 | IN UINTN Count, | |
548 | IN OUT VOID *Buffer | |
549 | ) | |
550 | { | |
551 | if (Buffer == NULL) { | |
552 | return EFI_INVALID_PARAMETER; | |
553 | } | |
554 | ||
555 | return PcatRootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer); | |
556 | } | |
557 | ||
558 | EFI_STATUS | |
559 | EFIAPI | |
560 | PcatRootBridgeIoPciWrite ( | |
561 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
562 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
563 | IN UINT64 Address, | |
564 | IN UINTN Count, | |
565 | IN OUT VOID *Buffer | |
566 | ) | |
567 | { | |
568 | if (Buffer == NULL) { | |
569 | return EFI_INVALID_PARAMETER; | |
570 | } | |
571 | ||
572 | return PcatRootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer); | |
573 | } | |
574 | ||
575 | EFI_STATUS | |
576 | EFIAPI | |
577 | PcatRootBridgeIoMap ( | |
578 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
579 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, | |
580 | IN VOID *HostAddress, | |
581 | IN OUT UINTN *NumberOfBytes, | |
582 | OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, | |
583 | OUT VOID **Mapping | |
584 | ) | |
585 | ||
586 | { | |
587 | EFI_STATUS Status; | |
588 | EFI_PHYSICAL_ADDRESS PhysicalAddress; | |
589 | MAP_INFO *MapInfo; | |
590 | MAP_INFO_INSTANCE *MapInstance; | |
591 | PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; | |
592 | ||
593 | if ( HostAddress == NULL || NumberOfBytes == NULL || | |
594 | DeviceAddress == NULL || Mapping == NULL ) { | |
595 | ||
596 | return EFI_INVALID_PARAMETER; | |
597 | } | |
598 | ||
599 | // | |
600 | // Perform a fence operation to make sure all memory operations are flushed | |
601 | // | |
602 | MemoryFence(); | |
603 | ||
604 | // | |
605 | // Initialize the return values to their defaults | |
606 | // | |
607 | *Mapping = NULL; | |
608 | ||
609 | // | |
610 | // Make sure that Operation is valid | |
611 | // | |
612 | if ((UINT32)Operation >= EfiPciOperationMaximum) { | |
613 | return EFI_INVALID_PARAMETER; | |
614 | } | |
615 | ||
616 | // | |
617 | // Most PCAT like chipsets can not handle performing DMA above 4GB. | |
618 | // If any part of the DMA transfer being mapped is above 4GB, then | |
619 | // map the DMA transfer to a buffer below 4GB. | |
620 | // | |
621 | PhysicalAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress; | |
622 | if ((PhysicalAddress + *NumberOfBytes) > 0x100000000ULL) { | |
623 | ||
624 | // | |
625 | // Common Buffer operations can not be remapped. If the common buffer | |
626 | // if above 4GB, then it is not possible to generate a mapping, so return | |
627 | // an error. | |
628 | // | |
629 | if (Operation == EfiPciOperationBusMasterCommonBuffer || Operation == EfiPciOperationBusMasterCommonBuffer64) { | |
630 | return EFI_UNSUPPORTED; | |
631 | } | |
632 | ||
633 | // | |
634 | // Allocate a MAP_INFO structure to remember the mapping when Unmap() is | |
635 | // called later. | |
636 | // | |
637 | Status = gBS->AllocatePool ( | |
638 | EfiBootServicesData, | |
639 | sizeof(MAP_INFO), | |
640 | (VOID **)&MapInfo | |
641 | ); | |
642 | if (EFI_ERROR (Status)) { | |
643 | *NumberOfBytes = 0; | |
644 | return Status; | |
645 | } | |
646 | ||
647 | // | |
648 | // Return a pointer to the MAP_INFO structure in Mapping | |
649 | // | |
650 | *Mapping = MapInfo; | |
651 | ||
652 | // | |
653 | // Initialize the MAP_INFO structure | |
654 | // | |
655 | MapInfo->Operation = Operation; | |
656 | MapInfo->NumberOfBytes = *NumberOfBytes; | |
657 | MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES(*NumberOfBytes); | |
658 | MapInfo->HostAddress = PhysicalAddress; | |
659 | MapInfo->MappedHostAddress = 0x00000000ffffffff; | |
660 | ||
661 | // | |
662 | // Allocate a buffer below 4GB to map the transfer to. | |
663 | // | |
664 | Status = gBS->AllocatePages ( | |
665 | AllocateMaxAddress, | |
666 | EfiBootServicesData, | |
667 | MapInfo->NumberOfPages, | |
668 | &MapInfo->MappedHostAddress | |
669 | ); | |
670 | if (EFI_ERROR(Status)) { | |
671 | gBS->FreePool (MapInfo); | |
672 | *NumberOfBytes = 0; | |
673 | return Status; | |
674 | } | |
675 | ||
676 | // | |
677 | // If this is a read operation from the Bus Master's point of view, | |
678 | // then copy the contents of the real buffer into the mapped buffer | |
679 | // so the Bus Master can read the contents of the real buffer. | |
680 | // | |
681 | if (Operation == EfiPciOperationBusMasterRead || Operation == EfiPciOperationBusMasterRead64) { | |
682 | CopyMem ( | |
683 | (VOID *)(UINTN)MapInfo->MappedHostAddress, | |
684 | (VOID *)(UINTN)MapInfo->HostAddress, | |
685 | MapInfo->NumberOfBytes | |
686 | ); | |
687 | } | |
688 | ||
689 | ||
690 | Status =gBS->AllocatePool ( | |
691 | EfiBootServicesData, | |
692 | sizeof(MAP_INFO_INSTANCE), | |
693 | (VOID **)&MapInstance | |
694 | ); | |
695 | if (EFI_ERROR(Status)) { | |
696 | gBS->FreePages (MapInfo->MappedHostAddress,MapInfo->NumberOfPages); | |
697 | gBS->FreePool (MapInfo); | |
698 | *NumberOfBytes = 0; | |
699 | return Status; | |
700 | } | |
701 | ||
702 | MapInstance->Map=MapInfo; | |
703 | PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); | |
704 | InsertTailList(&PrivateData->MapInfo,&MapInstance->Link); | |
705 | ||
706 | // | |
707 | // The DeviceAddress is the address of the maped buffer below 4GB | |
708 | // | |
709 | *DeviceAddress = MapInfo->MappedHostAddress; | |
710 | } else { | |
711 | // | |
712 | // The transfer is below 4GB, so the DeviceAddress is simply the HostAddress | |
713 | // | |
714 | *DeviceAddress = PhysicalAddress; | |
715 | } | |
716 | ||
717 | // | |
718 | // Perform a fence operation to make sure all memory operations are flushed | |
719 | // | |
720 | MemoryFence(); | |
721 | ||
722 | return EFI_SUCCESS; | |
723 | } | |
724 | ||
725 | EFI_STATUS | |
726 | EFIAPI | |
727 | PcatRootBridgeIoUnmap ( | |
728 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
729 | IN VOID *Mapping | |
730 | ) | |
731 | ||
732 | { | |
733 | MAP_INFO *MapInfo; | |
734 | PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; | |
735 | LIST_ENTRY *Link; | |
736 | ||
737 | // | |
738 | // Perform a fence operation to make sure all memory operations are flushed | |
739 | // | |
740 | MemoryFence(); | |
741 | ||
742 | PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); | |
743 | // | |
744 | // See if the Map() operation associated with this Unmap() required a mapping buffer. | |
745 | // If a mapping buffer was not required, then this function simply returns EFI_SUCCESS. | |
746 | // | |
747 | if (Mapping != NULL) { | |
748 | // | |
749 | // Get the MAP_INFO structure from Mapping | |
750 | // | |
751 | MapInfo = (MAP_INFO *)Mapping; | |
752 | ||
753 | for (Link = PrivateData->MapInfo.ForwardLink; Link != &PrivateData->MapInfo; Link = Link->ForwardLink) { | |
754 | if (((MAP_INFO_INSTANCE*)Link)->Map == MapInfo) | |
755 | break; | |
756 | } | |
757 | ||
758 | if (Link == &PrivateData->MapInfo) { | |
759 | return EFI_INVALID_PARAMETER; | |
760 | } | |
761 | ||
762 | RemoveEntryList(Link); | |
763 | ((MAP_INFO_INSTANCE*)Link)->Map = NULL; | |
764 | gBS->FreePool((MAP_INFO_INSTANCE*)Link); | |
765 | ||
766 | // | |
767 | // If this is a write operation from the Bus Master's point of view, | |
768 | // then copy the contents of the mapped buffer into the real buffer | |
769 | // so the processor can read the contents of the real buffer. | |
770 | // | |
771 | if (MapInfo->Operation == EfiPciOperationBusMasterWrite || MapInfo->Operation == EfiPciOperationBusMasterWrite64) { | |
772 | CopyMem ( | |
773 | (VOID *)(UINTN)MapInfo->HostAddress, | |
774 | (VOID *)(UINTN)MapInfo->MappedHostAddress, | |
775 | MapInfo->NumberOfBytes | |
776 | ); | |
777 | } | |
778 | ||
779 | // | |
780 | // Free the mapped buffer and the MAP_INFO structure. | |
781 | // | |
782 | gBS->FreePages (MapInfo->MappedHostAddress, MapInfo->NumberOfPages); | |
783 | gBS->FreePool (Mapping); | |
784 | } | |
785 | ||
786 | // | |
787 | // Perform a fence operation to make sure all memory operations are flushed | |
788 | // | |
789 | MemoryFence(); | |
790 | ||
791 | return EFI_SUCCESS; | |
792 | } | |
793 | ||
794 | EFI_STATUS | |
795 | EFIAPI | |
796 | PcatRootBridgeIoAllocateBuffer ( | |
797 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
798 | IN EFI_ALLOCATE_TYPE Type, | |
799 | IN EFI_MEMORY_TYPE MemoryType, | |
800 | IN UINTN Pages, | |
801 | OUT VOID **HostAddress, | |
802 | IN UINT64 Attributes | |
803 | ) | |
804 | { | |
805 | EFI_STATUS Status; | |
806 | EFI_PHYSICAL_ADDRESS PhysicalAddress; | |
807 | ||
808 | // | |
809 | // Validate Attributes | |
810 | // | |
811 | if (Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) { | |
812 | return EFI_UNSUPPORTED; | |
813 | } | |
814 | ||
815 | // | |
816 | // Check for invalid inputs | |
817 | // | |
818 | if (HostAddress == NULL) { | |
819 | return EFI_INVALID_PARAMETER; | |
820 | } | |
821 | ||
822 | // | |
823 | // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData | |
824 | // | |
825 | if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) { | |
826 | return EFI_INVALID_PARAMETER; | |
827 | } | |
828 | ||
829 | // | |
830 | // Limit allocations to memory below 4GB | |
831 | // | |
832 | PhysicalAddress = (EFI_PHYSICAL_ADDRESS)(0xffffffff); | |
833 | ||
834 | Status = gBS->AllocatePages (AllocateMaxAddress, MemoryType, Pages, &PhysicalAddress); | |
835 | if (EFI_ERROR (Status)) { | |
836 | return Status; | |
837 | } | |
838 | ||
839 | *HostAddress = (VOID *)(UINTN)PhysicalAddress; | |
840 | ||
841 | return EFI_SUCCESS; | |
842 | } | |
843 | ||
844 | EFI_STATUS | |
845 | EFIAPI | |
846 | PcatRootBridgeIoFreeBuffer ( | |
847 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
848 | IN UINTN Pages, | |
849 | OUT VOID *HostAddress | |
850 | ) | |
851 | ||
852 | { | |
853 | ||
854 | if( HostAddress == NULL ){ | |
855 | return EFI_INVALID_PARAMETER; | |
856 | } | |
857 | return gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress, Pages); | |
858 | } | |
859 | ||
860 | EFI_STATUS | |
861 | EFIAPI | |
862 | PcatRootBridgeIoFlush ( | |
863 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This | |
864 | ) | |
865 | ||
866 | { | |
867 | // | |
868 | // Perform a fence operation to make sure all memory operations are flushed | |
869 | // | |
870 | MemoryFence(); | |
871 | ||
872 | return EFI_SUCCESS; | |
873 | } | |
874 | ||
875 | EFI_STATUS | |
876 | EFIAPI | |
877 | PcatRootBridgeIoGetAttributes ( | |
878 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
879 | OUT UINT64 *Supported, OPTIONAL | |
880 | OUT UINT64 *Attributes | |
881 | ) | |
882 | ||
883 | { | |
884 | PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; | |
885 | ||
886 | PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); | |
887 | ||
888 | if (Attributes == NULL && Supported == NULL) { | |
889 | return EFI_INVALID_PARAMETER; | |
890 | } | |
891 | ||
892 | // | |
893 | // Supported is an OPTIONAL parameter. See if it is NULL | |
894 | // | |
895 | if (Supported) { | |
896 | // | |
897 | // This is a generic driver for a PC-AT class system. It does not have any | |
898 | // chipset specific knowlegde, so none of the attributes can be set or | |
899 | // cleared. Any attempt to set attribute that are already set will succeed, | |
900 | // and any attempt to set an attribute that is not supported will fail. | |
901 | // | |
902 | *Supported = PrivateData->Attributes; | |
903 | } | |
904 | ||
905 | // | |
906 | // Set Attrbutes to the attributes detected when the PCI Root Bridge was initialized | |
907 | // | |
908 | ||
909 | if (Attributes) { | |
910 | *Attributes = PrivateData->Attributes; | |
911 | } | |
912 | ||
913 | ||
914 | return EFI_SUCCESS; | |
915 | } | |
916 | ||
917 | EFI_STATUS | |
918 | EFIAPI | |
919 | PcatRootBridgeIoSetAttributes ( | |
920 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
921 | IN UINT64 Attributes, | |
922 | IN OUT UINT64 *ResourceBase, | |
923 | IN OUT UINT64 *ResourceLength | |
924 | ) | |
925 | ||
926 | { | |
927 | PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; | |
928 | ||
929 | PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); | |
930 | ||
931 | // | |
932 | // This is a generic driver for a PC-AT class system. It does not have any | |
933 | // chipset specific knowlegde, so none of the attributes can be set or | |
934 | // cleared. Any attempt to set attribute that are already set will succeed, | |
935 | // and any attempt to set an attribute that is not supported will fail. | |
936 | // | |
937 | if (Attributes & (~PrivateData->Attributes)) { | |
938 | return EFI_UNSUPPORTED; | |
939 | } | |
940 | ||
941 | return EFI_SUCCESS; | |
942 | } | |
943 | ||
944 | EFI_STATUS | |
945 | EFIAPI | |
946 | PcatRootBridgeIoConfiguration ( | |
947 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
948 | OUT VOID **Resources | |
949 | ) | |
950 | ||
951 | { | |
952 | PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; | |
953 | ||
954 | PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); | |
955 | ||
956 | *Resources = PrivateData->Configuration; | |
957 | ||
958 | return EFI_SUCCESS; | |
959 | } | |
960 | ||
961 | // | |
962 | // Internal function | |
963 | // | |
964 | ||
965 | EFI_STATUS | |
966 | EFIAPI | |
967 | PcatRootBridgeIoMemRW ( | |
968 | IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
969 | IN UINTN Count, | |
970 | IN BOOLEAN InStrideFlag, | |
971 | IN PTR In, | |
972 | IN BOOLEAN OutStrideFlag, | |
973 | OUT PTR Out | |
974 | ) | |
975 | /*++ | |
976 | ||
977 | Routine Description: | |
978 | ||
979 | Private service to provide the memory read/write | |
980 | ||
981 | Arguments: | |
982 | ||
983 | Width of the Memory Access | |
984 | Count of the number of accesses to perform | |
985 | ||
986 | Returns: | |
987 | ||
988 | Status | |
989 | ||
990 | EFI_SUCCESS - Successful transaction | |
991 | EFI_INVALID_PARAMETER - Unsupported width and address combination | |
992 | ||
993 | --*/ | |
994 | { | |
995 | UINTN Stride; | |
996 | UINTN InStride; | |
997 | UINTN OutStride; | |
998 | ||
999 | ||
1000 | Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03); | |
1001 | Stride = (UINTN)1 << Width; | |
1002 | InStride = InStrideFlag ? Stride : 0; | |
1003 | OutStride = OutStrideFlag ? Stride : 0; | |
1004 | ||
1005 | // | |
1006 | // Loop for each iteration and move the data | |
1007 | // | |
1008 | switch (Width) { | |
1009 | case EfiPciWidthUint8: | |
1010 | for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { | |
1011 | MemoryFence(); | |
1012 | *In.ui8 = *Out.ui8; | |
1013 | MemoryFence(); | |
1014 | } | |
1015 | break; | |
1016 | case EfiPciWidthUint16: | |
1017 | for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { | |
1018 | MemoryFence(); | |
1019 | *In.ui16 = *Out.ui16; | |
1020 | MemoryFence(); | |
1021 | } | |
1022 | break; | |
1023 | case EfiPciWidthUint32: | |
1024 | for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { | |
1025 | MemoryFence(); | |
1026 | *In.ui32 = *Out.ui32; | |
1027 | MemoryFence(); | |
1028 | } | |
1029 | break; | |
1030 | default: | |
1031 | return EFI_INVALID_PARAMETER; | |
1032 | } | |
1033 | ||
1034 | return EFI_SUCCESS; | |
1035 | } | |
1036 |