• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 *  Implementation of the PCI Root Bridge Protocol for XPress-RICH3 PCIe Root Complex
3 *
4 *  Copyright (c) 2011-2015, ARM Ltd. All rights reserved.
5 *
6 *  This program and the accompanying materials
7 *  are licensed and made available under the terms and conditions of the BSD License
8 *  which accompanies this distribution.  The full text of the license may be found at
9 *  http://opensource.org/licenses/bsd-license.php
10 *
11 *  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 *
14 **/
15 
16 #include "PciHostBridge.h"
17 
18 #include <Library/DevicePathLib.h>
19 #include <Library/DmaLib.h>
20 
21 #define CPUIO_FROM_ROOT_BRIDGE_INSTANCE(Instance) (Instance->HostBridge->CpuIo)
22 #define METRONOME_FROM_ROOT_BRIDGE_INSTANCE(Instance) (Instance->HostBridge->Metronome)
23 
24 /**
25  * PCI Root Bridge Instance Templates
26  */
27 STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH  gDevicePathTemplate = {
28     {
29       { ACPI_DEVICE_PATH,
30         ACPI_DP,
31         { (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)),
32           (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) }
33       },
34       EISA_PNP_ID (0x0A03),
35       0
36     },
37     {
38       END_DEVICE_PATH_TYPE,
39       END_ENTIRE_DEVICE_PATH_SUBTYPE,
40       { END_DEVICE_PATH_LENGTH, 0 }
41     }
42 };
43 
44 STATIC CONST EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL gIoTemplate = {
45     0,
46     PciRbPollMem,
47     PciRbPollIo,
48     {
49       PciRbMemRead,
50       PciRbMemWrite
51     },
52     {
53       PciRbIoRead,
54       PciRbIoWrite
55     },
56     {
57       PciRbPciRead,
58       PciRbPciWrite
59     },
60     PciRbCopyMem,
61     PciRbMap,
62     PciRbUnMap,
63     PciRbAllocateBuffer,
64     PciRbFreeBuffer,
65     PciRbFlush,
66     PciRbGetAttributes,
67     PciRbSetAttributes,
68     PciRbConfiguration,
69     0
70   };
71 
72 typedef struct {
73     EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR     SpaceDesp[ResTypeMax+1];
74     EFI_ACPI_END_TAG_DESCRIPTOR           EndDesp;
75 } RESOURCE_CONFIGURATION;
76 
77 
78 RESOURCE_CONFIGURATION Configuration = {
79    {{ACPI_ADDRESS_SPACE_DESCRIPTOR, 0x2B, ACPI_ADDRESS_SPACE_TYPE_IO , 0, 0, 0, 0, 0, 0, 0},
80     {ACPI_ADDRESS_SPACE_DESCRIPTOR, 0x2B, ACPI_ADDRESS_SPACE_TYPE_MEM, 0, 0, 32, 0, 0, 0, 0},
81     {ACPI_ADDRESS_SPACE_DESCRIPTOR, 0x2B, ACPI_ADDRESS_SPACE_TYPE_MEM, 0, 6, 32, 0, 0, 0, 0},
82     {ACPI_ADDRESS_SPACE_DESCRIPTOR, 0x2B, ACPI_ADDRESS_SPACE_TYPE_MEM, 0, 0, 64, 0, 0, 0, 0},
83     {ACPI_ADDRESS_SPACE_DESCRIPTOR, 0x2B, ACPI_ADDRESS_SPACE_TYPE_MEM, 0, 6, 64, 0, 0, 0, 0},
84     {ACPI_ADDRESS_SPACE_DESCRIPTOR, 0x2B, ACPI_ADDRESS_SPACE_TYPE_BUS, 0, 0, 0, 0, 255, 0, 255}},
85     {ACPI_END_TAG_DESCRIPTOR, 0}
86 };
87 
88 
89 EFI_STATUS
PciRbPollMem(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINT64 Mask,IN UINT64 Value,IN UINT64 Delay,OUT UINT64 * Result)90 PciRbPollMem (
91   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL           *This,
92   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
93   IN  UINT64                                   Address,
94   IN  UINT64                                   Mask,
95   IN  UINT64                                   Value,
96   IN  UINT64                                   Delay,
97   OUT UINT64                                   *Result
98   )
99 {
100   EFI_STATUS                      Status;
101   UINT64                          NumberOfTicks;
102   UINT32                          Remainder;
103   PCI_ROOT_BRIDGE_INSTANCE        *RootBridgeInstance;
104   EFI_METRONOME_ARCH_PROTOCOL     *Metronome;
105 
106   PCI_TRACE ("PciRbPollMem()");
107 
108   RootBridgeInstance = INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This);
109   Metronome = METRONOME_FROM_ROOT_BRIDGE_INSTANCE (RootBridgeInstance);
110 
111   if (Result == NULL) {
112     return EFI_INVALID_PARAMETER;
113   }
114 
115   if (Width > EfiPciWidthUint64) {
116     return EFI_INVALID_PARAMETER;
117   }
118 
119   // No matter what, always do a single poll.
120   Status = This->Mem.Read (This, Width, Address, 1, Result);
121   if (EFI_ERROR (Status)) {
122     return Status;
123   }
124   if ((*Result & Mask) == Value) {
125     return EFI_SUCCESS;
126   }
127 
128   if (Delay == 0) {
129     return EFI_SUCCESS;
130   }
131 
132   NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) Metronome->TickPeriod, &Remainder);
133   if (Remainder != 0) {
134     NumberOfTicks += 1;
135   }
136   NumberOfTicks += 1;
137 
138   while (NumberOfTicks) {
139     Metronome->WaitForTick (Metronome, 1);
140 
141     Status = This->Mem.Read (This, Width, Address, 1, Result);
142     if (EFI_ERROR (Status)) {
143       return Status;
144     }
145 
146     if ((*Result & Mask) == Value) {
147       return EFI_SUCCESS;
148     }
149 
150     NumberOfTicks -= 1;
151   }
152 
153   return EFI_TIMEOUT;
154 }
155 
156 EFI_STATUS
PciRbPollIo(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINT64 Mask,IN UINT64 Value,IN UINT64 Delay,OUT UINT64 * Result)157 PciRbPollIo (
158   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL           *This,
159   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
160   IN  UINT64                                   Address,
161   IN  UINT64                                   Mask,
162   IN  UINT64                                   Value,
163   IN  UINT64                                   Delay,
164   OUT UINT64                                   *Result
165   )
166 {
167   EFI_STATUS                      Status;
168   UINT64                          NumberOfTicks;
169   UINT32                          Remainder;
170   PCI_ROOT_BRIDGE_INSTANCE        *RootBridgeInstance;
171   EFI_METRONOME_ARCH_PROTOCOL     *Metronome;
172 
173   PCI_TRACE ("PciRbPollIo()");
174 
175   RootBridgeInstance = INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This);
176   Metronome = METRONOME_FROM_ROOT_BRIDGE_INSTANCE (RootBridgeInstance);
177 
178   if (Result == NULL) {
179     return EFI_INVALID_PARAMETER;
180   }
181 
182   if (Width > EfiPciWidthUint64) {
183     return EFI_INVALID_PARAMETER;
184   }
185 
186   // No matter what, always do a single poll.
187   Status = This->Io.Read (This, Width, Address, 1, Result);
188   if (EFI_ERROR (Status)) {
189     return Status;
190   }
191   if ((*Result & Mask) == Value) {
192     return EFI_SUCCESS;
193   }
194 
195   if (Delay == 0) {
196     return EFI_SUCCESS;
197   }
198 
199   NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) Metronome->TickPeriod, &Remainder);
200   if (Remainder != 0) {
201     NumberOfTicks += 1;
202   }
203   NumberOfTicks += 1;
204 
205   while (NumberOfTicks) {
206     Metronome->WaitForTick (Metronome, 1);
207 
208     Status = This->Io.Read (This, Width, Address, 1, Result);
209     if (EFI_ERROR (Status)) {
210         return Status;
211     }
212 
213     if ((*Result & Mask) == Value) {
214         return EFI_SUCCESS;
215     }
216 
217     NumberOfTicks -= 1;
218   }
219 
220   return EFI_TIMEOUT;
221 }
222 
223 EFI_STATUS
PciRbMemRead(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN OUT VOID * Buffer)224 PciRbMemRead (
225   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL              *This,
226   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
227   IN     UINT64                                   Address,
228   IN     UINTN                                    Count,
229   IN OUT VOID                                     *Buffer
230   )
231 {
232   PCI_ROOT_BRIDGE_INSTANCE    *RootBridgeInstance;
233   EFI_CPU_IO2_PROTOCOL        *CpuIo;
234 
235   PCI_TRACE ("PciRbMemRead()");
236 
237   RootBridgeInstance = INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This);
238   CpuIo = CPUIO_FROM_ROOT_BRIDGE_INSTANCE (RootBridgeInstance);
239 
240   if (Buffer == NULL) {
241     return EFI_INVALID_PARAMETER;
242   }
243 
244   if (Width >= EfiPciWidthMaximum) {
245     return EFI_INVALID_PARAMETER;
246   }
247 
248   if (((Address < PCI_MEM32_BASE) || (Address > (PCI_MEM32_BASE + PCI_MEM32_SIZE))) &&
249       ((Address < PCI_MEM64_BASE) || (Address > (PCI_MEM64_BASE + PCI_MEM64_SIZE)))) {
250     return EFI_INVALID_PARAMETER;
251   }
252 
253   return CpuIo->Mem.Read (CpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH)Width, Address, Count, Buffer);
254 }
255 
256 EFI_STATUS
PciRbMemWrite(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN OUT VOID * Buffer)257 PciRbMemWrite (
258   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL              *This,
259   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
260   IN     UINT64                                   Address,
261   IN     UINTN                                    Count,
262   IN OUT VOID                                     *Buffer
263   )
264 {
265   PCI_ROOT_BRIDGE_INSTANCE    *RootBridgeInstance;
266   EFI_CPU_IO2_PROTOCOL        *CpuIo;
267 
268   PCI_TRACE ("PciRbMemWrite()");
269 
270   RootBridgeInstance = INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This);
271   CpuIo = CPUIO_FROM_ROOT_BRIDGE_INSTANCE (RootBridgeInstance);
272 
273   if (Buffer == NULL) {
274     return EFI_INVALID_PARAMETER;
275   }
276 
277   if (Width >= EfiPciWidthMaximum) {
278     return EFI_INVALID_PARAMETER;
279   }
280 
281   if (((Address < PCI_MEM32_BASE) || (Address > (PCI_MEM32_BASE + PCI_MEM32_SIZE))) &&
282       ((Address < PCI_MEM64_BASE) || (Address > (PCI_MEM64_BASE + PCI_MEM64_SIZE)))) {
283     return EFI_INVALID_PARAMETER;
284   }
285 
286   return CpuIo->Mem.Write (CpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH)Width, Address, Count, Buffer);
287 }
288 
289 EFI_STATUS
PciRbIoRead(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN OUT VOID * Buffer)290 PciRbIoRead (
291   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL              *This,
292   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
293   IN     UINT64                                   Address,
294   IN     UINTN                                    Count,
295   IN OUT VOID                                     *Buffer
296   )
297 {
298   PCI_TRACE ("PciRbIoRead()");
299 
300   if (Buffer == NULL) {
301     return EFI_INVALID_PARAMETER;
302   }
303 
304   if (Width >= EfiPciWidthMaximum) {
305     return EFI_INVALID_PARAMETER;
306   }
307 
308   // IO currently unsupported
309   return EFI_INVALID_PARAMETER;
310 }
311 
312 EFI_STATUS
PciRbIoWrite(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN OUT VOID * Buffer)313 PciRbIoWrite (
314   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL              *This,
315   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
316   IN     UINT64                                   Address,
317   IN     UINTN                                    Count,
318   IN OUT VOID                                     *Buffer
319   )
320 {
321   PCI_TRACE ("PciRbIoWrite()");
322 
323   if (Buffer == NULL) {
324     return EFI_INVALID_PARAMETER;
325   }
326 
327   if (Width >= EfiPciWidthMaximum) {
328     return EFI_INVALID_PARAMETER;
329   }
330 
331   // IO currently unsupported
332   return EFI_INVALID_PARAMETER;
333 }
334 
335 EFI_STATUS
PciRbPciRead(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 EfiAddress,IN UINTN Count,IN OUT VOID * Buffer)336 PciRbPciRead (
337   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL              *This,
338   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
339   IN     UINT64                                   EfiAddress,
340   IN     UINTN                                    Count,
341   IN OUT VOID                                     *Buffer
342   )
343 {
344   UINT32                      Offset;
345   PCI_ROOT_BRIDGE_INSTANCE    *RootBridgeInstance;
346   EFI_CPU_IO2_PROTOCOL        *CpuIo;
347   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *EfiPciAddress;
348   UINT64                      Address;
349 
350   EfiPciAddress  = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *)&EfiAddress;
351   RootBridgeInstance = INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This);
352   CpuIo = CPUIO_FROM_ROOT_BRIDGE_INSTANCE (RootBridgeInstance);
353 
354   if (Buffer == NULL) {
355     return EFI_INVALID_PARAMETER;
356   }
357 
358   if (Width >= EfiPciWidthMaximum) {
359     return EFI_INVALID_PARAMETER;
360   }
361 
362   if (EfiPciAddress->ExtendedRegister) {
363     Offset = EfiPciAddress->ExtendedRegister;
364   } else {
365     Offset = EfiPciAddress->Register;
366   }
367 
368   // The UEFI PCI enumerator scans for devices at all possible addresses,
369   // and ignores some PCI rules - this results in some hardware being
370   // detected multiple times. We work around this by faking absent
371   // devices
372   if ((EfiPciAddress->Bus == 0) && ((EfiPciAddress->Device != 0) || (EfiPciAddress->Function != 0))) {
373     *((UINT32 *)Buffer) = 0xffffffff;
374     return EFI_SUCCESS;
375   }
376   if ((EfiPciAddress->Bus == 1) && ((EfiPciAddress->Device != 0) || (EfiPciAddress->Function != 0))) {
377     *((UINT32 *)Buffer) = 0xffffffff;
378     return EFI_SUCCESS;
379   }
380 
381   // Work around incorrect class ID in the root bridge
382   if ((EfiPciAddress->Bus == 0) && (EfiPciAddress->Device == 0) && (EfiPciAddress->Function == 0) && (Offset == 8)) {
383     *((UINT32 *)Buffer) = 0x06040001;
384     return EFI_SUCCESS;
385    }
386 
387   Address = PCI_ECAM_BASE + ((EfiPciAddress->Bus << 20) |
388                          (EfiPciAddress->Device << 15) |
389                          (EfiPciAddress->Function << 12) | Offset);
390 
391   if ((Address < PCI_ECAM_BASE) || (Address > PCI_ECAM_BASE + PCI_ECAM_SIZE)) {
392     return EFI_INVALID_PARAMETER;
393   }
394 
395   return CpuIo->Mem.Read (CpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH)Width, Address, Count, Buffer);
396 }
397 
398 EFI_STATUS
PciRbPciWrite(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 EfiAddress,IN UINTN Count,IN OUT VOID * Buffer)399 PciRbPciWrite (
400   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL              *This,
401   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
402   IN     UINT64                                   EfiAddress,
403   IN     UINTN                                    Count,
404   IN OUT VOID                                     *Buffer
405   )
406 {
407   UINT32                      Offset;
408   PCI_ROOT_BRIDGE_INSTANCE    *RootBridgeInstance;
409   EFI_CPU_IO2_PROTOCOL        *CpuIo;
410   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *EfiPciAddress;
411   UINT64                      Address;
412 
413   EfiPciAddress  = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *)&EfiAddress;
414   RootBridgeInstance = INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This);
415   CpuIo = CPUIO_FROM_ROOT_BRIDGE_INSTANCE (RootBridgeInstance);
416 
417   if (Buffer == NULL) {
418     return EFI_INVALID_PARAMETER;
419   }
420 
421   if (Width >= EfiPciWidthMaximum) {
422     return EFI_INVALID_PARAMETER;
423   }
424 
425   if (EfiPciAddress->ExtendedRegister)
426     Offset = EfiPciAddress->ExtendedRegister;
427   else
428     Offset = EfiPciAddress->Register;
429 
430   Address = PCI_ECAM_BASE + ((EfiPciAddress->Bus << 20) |
431                          (EfiPciAddress->Device << 15) |
432                          (EfiPciAddress->Function << 12) | Offset);
433 
434   if (Address < PCI_ECAM_BASE || Address > PCI_ECAM_BASE + PCI_ECAM_SIZE) {
435     return EFI_INVALID_PARAMETER;
436   }
437 
438   return CpuIo->Mem.Write (CpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH)Width, Address, Count, Buffer);
439 }
440 
441 EFI_STATUS
PciRbCopyMem(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 DestAddress,IN UINT64 SrcAddress,IN UINTN Count)442 PciRbCopyMem (
443   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL              *This,
444   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
445   IN     UINT64                                   DestAddress,
446   IN     UINT64                                   SrcAddress,
447   IN     UINTN                                    Count
448   )
449 {
450   EFI_STATUS  Status;
451   BOOLEAN     Direction;
452   UINTN       Stride;
453   UINTN       Index;
454   UINT64      Result;
455 
456   PCI_TRACE ("PciRbCopyMem()");
457 
458   if (Width > EfiPciWidthUint64) {
459     return EFI_INVALID_PARAMETER;
460   }
461 
462   if (DestAddress == SrcAddress) {
463     return EFI_SUCCESS;
464   }
465 
466   Stride = (UINTN)(1 << Width);
467 
468   Direction = TRUE;
469   if ((DestAddress > SrcAddress) && (DestAddress < (SrcAddress + Count * Stride))) {
470     Direction   = FALSE;
471     SrcAddress  = SrcAddress  + (Count-1) * Stride;
472     DestAddress = DestAddress + (Count-1) * Stride;
473   }
474 
475   for (Index = 0; Index < Count; Index++) {
476     Status = PciRbMemRead (
477                This,
478                Width,
479                SrcAddress,
480                1,
481                &Result
482                );
483     if (EFI_ERROR (Status)) {
484       return Status;
485     }
486     Status = PciRbMemWrite (
487                This,
488                Width,
489                DestAddress,
490                1,
491                &Result
492                );
493     if (EFI_ERROR (Status)) {
494       return Status;
495     }
496     if (Direction) {
497       SrcAddress  += Stride;
498       DestAddress += Stride;
499     } else {
500       SrcAddress  -= Stride;
501       DestAddress -= Stride;
502     }
503   }
504   return EFI_SUCCESS;
505 }
506 
507 EFI_STATUS
PciRbMap(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation,IN VOID * HostAddress,IN OUT UINTN * NumberOfBytes,OUT EFI_PHYSICAL_ADDRESS * DeviceAddress,OUT VOID ** Mapping)508 PciRbMap (
509   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL                *This,
510   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION  Operation,
511   IN     VOID                                       *HostAddress,
512   IN OUT UINTN                                      *NumberOfBytes,
513   OUT    EFI_PHYSICAL_ADDRESS                       *DeviceAddress,
514   OUT    VOID                                       **Mapping
515   )
516 {
517   DMA_MAP_OPERATION   DmaOperation;
518 
519   PCI_TRACE ("PciRbMap()");
520 
521   if (Operation == EfiPciOperationBusMasterRead ||
522       Operation == EfiPciOperationBusMasterRead64) {
523     DmaOperation = MapOperationBusMasterRead;
524   } else if (Operation == EfiPciOperationBusMasterWrite ||
525              Operation == EfiPciOperationBusMasterWrite64) {
526     DmaOperation = MapOperationBusMasterWrite;
527   } else if (Operation == EfiPciOperationBusMasterCommonBuffer ||
528              Operation == EfiPciOperationBusMasterCommonBuffer64) {
529     DmaOperation = MapOperationBusMasterCommonBuffer;
530   } else {
531     return EFI_INVALID_PARAMETER;
532   }
533   return DmaMap (DmaOperation, HostAddress, NumberOfBytes, DeviceAddress, Mapping);
534 }
535 
536 EFI_STATUS
PciRbUnMap(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN VOID * Mapping)537 PciRbUnMap (
538   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL           *This,
539   IN  VOID                                     *Mapping
540   )
541 {
542   PCI_TRACE ("PciRbUnMap()");
543   return DmaUnmap (Mapping);
544 }
545 
546 EFI_STATUS
PciRbAllocateBuffer(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_ALLOCATE_TYPE Type,IN EFI_MEMORY_TYPE MemoryType,IN UINTN Pages,IN OUT VOID ** HostAddress,IN UINT64 Attributes)547 PciRbAllocateBuffer (
548   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL              *This,
549   IN     EFI_ALLOCATE_TYPE                        Type,
550   IN     EFI_MEMORY_TYPE                          MemoryType,
551   IN     UINTN                                    Pages,
552   IN OUT VOID                                     **HostAddress,
553   IN     UINT64                                   Attributes
554   )
555 {
556   PCI_TRACE ("PciRbAllocateBuffer()");
557 
558   if (Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) {
559     return EFI_UNSUPPORTED;
560   }
561 
562   return DmaAllocateBuffer (MemoryType, Pages, HostAddress);
563 }
564 
565 EFI_STATUS
PciRbFreeBuffer(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN UINTN Pages,IN VOID * HostAddress)566 PciRbFreeBuffer (
567   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL           *This,
568   IN  UINTN                                    Pages,
569   IN  VOID                                     *HostAddress
570   )
571 {
572   PCI_TRACE ("PciRbFreeBuffer()");
573   return DmaFreeBuffer (Pages, HostAddress);
574 }
575 
576 EFI_STATUS
PciRbFlush(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This)577 PciRbFlush (
578   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This
579   )
580 {
581   PCI_TRACE ("PciRbFlush()");
582 
583   //TODO: Not supported yet
584 
585   return EFI_SUCCESS;
586 }
587 
588 EFI_STATUS
PciRbSetAttributes(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN UINT64 Attributes,IN OUT UINT64 * ResourceBase,IN OUT UINT64 * ResourceLength)589 PciRbSetAttributes (
590   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL              *This,
591   IN     UINT64                                   Attributes,
592   IN OUT UINT64                                   *ResourceBase,
593   IN OUT UINT64                                   *ResourceLength
594   )
595 {
596   PCI_ROOT_BRIDGE_INSTANCE    *RootBridgeInstance;
597 
598   PCI_TRACE ("PciRbSetAttributes()");
599 
600   RootBridgeInstance = INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This);
601 
602   if (Attributes) {
603     if ((Attributes & (~(RootBridgeInstance->Supports))) != 0) {
604       return EFI_UNSUPPORTED;
605     }
606   }
607 
608   //TODO: Cannot allowed to change attributes
609   if (Attributes & ~RootBridgeInstance->Attributes) {
610     return EFI_UNSUPPORTED;
611   }
612 
613   return EFI_SUCCESS;
614 }
615 
616 EFI_STATUS
PciRbGetAttributes(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,OUT UINT64 * Supported,OUT UINT64 * Attributes)617 PciRbGetAttributes (
618   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL           *This,
619   OUT UINT64                                   *Supported,
620   OUT UINT64                                   *Attributes
621   )
622 {
623   PCI_ROOT_BRIDGE_INSTANCE    *RootBridgeInstance;
624 
625   PCI_TRACE ("PciRbGetAttributes()");
626 
627   RootBridgeInstance = INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This);
628 
629   if (Attributes == NULL && Supported == NULL) {
630     return EFI_INVALID_PARAMETER;
631   }
632 
633   // Set the return value for Supported and Attributes
634   if (Supported) {
635     *Supported  = RootBridgeInstance->Supports;
636   }
637 
638   if (Attributes) {
639     *Attributes = RootBridgeInstance->Attributes;
640   }
641 
642   return EFI_SUCCESS;
643 }
644 
645 EFI_STATUS
PciRbConfiguration(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,OUT VOID ** Resources)646 PciRbConfiguration (
647   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL          *This,
648   OUT VOID                                     **Resources
649   )
650 {
651   PCI_ROOT_BRIDGE_INSTANCE              *RootBridge;
652   UINTN                                 Index;
653 
654   PCI_TRACE ("PciRbConfiguration()");
655 
656   RootBridge = INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This);
657 
658   for (Index = 0; Index < ResTypeMax; Index++) {
659     //if (ResAlloc[Index].Length != 0) => Resource allocated
660     if (RootBridge->ResAlloc[Index].Length != 0) {
661       Configuration.SpaceDesp[Index].AddrRangeMin = RootBridge->ResAlloc[Index].Base;
662       Configuration.SpaceDesp[Index].AddrRangeMax = RootBridge->ResAlloc[Index].Base + RootBridge->ResAlloc[Index].Length - 1;
663       Configuration.SpaceDesp[Index].AddrLen      = RootBridge->ResAlloc[Index].Length;
664     }
665   }
666 
667   // Set up Configuration for the bus
668   Configuration.SpaceDesp[Index].AddrRangeMin = RootBridge->BusStart;
669   Configuration.SpaceDesp[Index].AddrLen      = RootBridge->BusLength;
670 
671   *Resources = &Configuration;
672   return EFI_SUCCESS;
673 }
674 
675 EFI_STATUS
PciRbConstructor(IN PCI_HOST_BRIDGE_INSTANCE * HostBridge,IN UINT32 PciAcpiUid,IN UINT64 MemAllocAttributes)676 PciRbConstructor (
677   IN  PCI_HOST_BRIDGE_INSTANCE *HostBridge,
678   IN  UINT32 PciAcpiUid,
679   IN  UINT64 MemAllocAttributes
680   )
681 {
682   PCI_ROOT_BRIDGE_INSTANCE* RootBridge;
683   EFI_STATUS Status;
684 
685   PCI_TRACE ("PciRbConstructor()");
686 
687   // Allocate Memory for the Instance from a Template
688   RootBridge = AllocateZeroPool (sizeof (PCI_ROOT_BRIDGE_INSTANCE));
689   if (RootBridge == NULL) {
690     PCI_TRACE ("PciRbConstructor(): ERROR: Out of Resources");
691     return EFI_OUT_OF_RESOURCES;
692   }
693   RootBridge->Signature = PCI_ROOT_BRIDGE_SIGNATURE;
694   CopyMem (&(RootBridge->DevicePath), &gDevicePathTemplate, sizeof (EFI_PCI_ROOT_BRIDGE_DEVICE_PATH));
695   CopyMem (&(RootBridge->Io), &gIoTemplate, sizeof (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL));
696 
697   // Set Parent Handle
698   RootBridge->Io.ParentHandle = HostBridge->Handle;
699 
700   // Attach the Root Bridge to the PCI Host Bridge Instance
701   RootBridge->HostBridge = HostBridge;
702 
703   // Set Device Path for this Root Bridge
704   RootBridge->DevicePath.Acpi.UID = PciAcpiUid;
705 
706   RootBridge->BusStart  = FixedPcdGet32 (PcdPciBusMin);
707   RootBridge->BusLength = FixedPcdGet32 (PcdPciBusMax) - FixedPcdGet32 (PcdPciBusMin) + 1;
708 
709   // PCI Attributes
710   RootBridge->Supports = 0;
711   RootBridge->Attributes = 0;
712 
713   // Install Protocol Instances. It will also generate a device handle for the PCI Root Bridge
714   Status = gBS->InstallMultipleProtocolInterfaces (
715                       &RootBridge->Handle,
716                       &gEfiDevicePathProtocolGuid, &RootBridge->DevicePath,
717                       &gEfiPciRootBridgeIoProtocolGuid, &RootBridge->Io,
718                       NULL
719                       );
720   ASSERT (RootBridge->Signature == PCI_ROOT_BRIDGE_SIGNATURE);
721   if (EFI_ERROR (Status)) {
722     PCI_TRACE ("PciRbConstructor(): ERROR: Fail to install Protocol Interfaces");
723     FreePool (RootBridge);
724     return EFI_DEVICE_ERROR;
725   }
726 
727   HostBridge->RootBridge = RootBridge;
728   return EFI_SUCCESS;
729 }
730 
731 EFI_STATUS
PciRbDestructor(IN PCI_ROOT_BRIDGE_INSTANCE * RootBridge)732 PciRbDestructor (
733   IN  PCI_ROOT_BRIDGE_INSTANCE* RootBridge
734   )
735 {
736   EFI_STATUS Status;
737 
738   Status = gBS->UninstallMultipleProtocolInterfaces (
739                         RootBridge->Handle,
740                         &gEfiDevicePathProtocolGuid, &RootBridge->DevicePath,
741                         &gEfiPciRootBridgeIoProtocolGuid, &RootBridge->Io,
742                         NULL
743                         );
744 
745   FreePool (RootBridge);
746 
747   return Status;
748 }
749