a827bab097d3b200316f7ecbea0caff8b0ce92b1
[people/mcb30/edk2.git] / edk2 / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciResourceSupport.c
1 /**@file\r
2 \r
3 Copyright (c) 2006 - 2007, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 **/\r
13 \r
14 #include "PciBus.h"\r
15 #include "PciResourceSupport.h"\r
16 #include "PciCommand.h"\r
17 \r
18 /**\r
19   The function is used to skip VGA range\r
20   \r
21   @param Start    address including VGA range\r
22   @param Length   length of VGA range.\r
23   \r
24   @retval EFI_SUCCESS success\r
25 **/\r
26 EFI_STATUS\r
27 SkipVGAAperture (\r
28   OUT UINT64   *Start,\r
29   IN  UINT64   Length\r
30   )\r
31 {\r
32   UINT64  Original;\r
33   UINT64  Mask;\r
34   UINT64  StartOffset;\r
35   UINT64  LimitOffset;\r
36 \r
37   //\r
38   // For legacy VGA, bit 10 to bit 15 is not decoded\r
39   //\r
40   Mask        = 0x3FF;\r
41 \r
42   Original    = *Start;\r
43   StartOffset = Original & Mask;\r
44   LimitOffset = ((*Start) + Length - 1) & Mask;\r
45   if (LimitOffset >= VGABASE1) {\r
46     *Start = *Start - StartOffset + VGALIMIT2 + 1;\r
47   }\r
48 \r
49   return EFI_SUCCESS;\r
50 }\r
51 \r
52 /**\r
53   This function is used to skip ISA aliasing aperture\r
54   \r
55   @param Start    address including ISA aliasing aperture\r
56   @param Length   length of ISA aliasing aperture\r
57   \r
58   @retval EFI_SUCCESS success\r
59 **/\r
60 EFI_STATUS\r
61 SkipIsaAliasAperture (\r
62   OUT UINT64   *Start,\r
63   IN  UINT64   Length\r
64   )\r
65 {\r
66 \r
67   UINT64  Original;\r
68   UINT64  Mask;\r
69   UINT64  StartOffset;\r
70   UINT64  LimitOffset;\r
71 \r
72   //\r
73   // For legacy ISA, bit 10 to bit 15 is not decoded\r
74   //\r
75   Mask        = 0x3FF;\r
76 \r
77   Original    = *Start;\r
78   StartOffset = Original & Mask;\r
79   LimitOffset = ((*Start) + Length - 1) & Mask;\r
80 \r
81   if (LimitOffset >= ISABASE) {\r
82     *Start = *Start - StartOffset + ISALIMIT + 1;\r
83   }\r
84 \r
85   return EFI_SUCCESS;\r
86 }\r
87 \r
88 /**\r
89   This function inserts a resource node into the resource list.\r
90   The resource list is sorted in descend order.\r
91 \r
92   @param Bridge  PCI resource node for bridge\r
93   @param ResNode Resource node want to be inserted\r
94   \r
95   @retval EFI_SUCCESS Success\r
96 **/\r
97 EFI_STATUS\r
98 InsertResourceNode (\r
99   PCI_RESOURCE_NODE *Bridge,\r
100   PCI_RESOURCE_NODE *ResNode\r
101   )\r
102 {\r
103   LIST_ENTRY        *CurrentLink;\r
104   PCI_RESOURCE_NODE *Temp;\r
105   UINT64            ResNodeAlignRest;\r
106   UINT64            TempAlignRest;\r
107 \r
108   InsertHeadList (&Bridge->ChildList, &ResNode->Link);\r
109 \r
110   CurrentLink = Bridge->ChildList.ForwardLink->ForwardLink;\r
111   while (CurrentLink != &Bridge->ChildList) {\r
112     Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);\r
113 \r
114     if (ResNode->Alignment > Temp->Alignment) {\r
115       break;\r
116     } else if (ResNode->Alignment == Temp->Alignment) {\r
117       ResNodeAlignRest  = ResNode->Length & ResNode->Alignment;\r
118       TempAlignRest     = Temp->Length & Temp->Alignment;\r
119       if ((ResNodeAlignRest == 0) || (ResNodeAlignRest >= TempAlignRest)) {\r
120         break;\r
121       }\r
122     }\r
123 \r
124     SwapListEntries (&ResNode->Link, CurrentLink);\r
125 \r
126     CurrentLink = ResNode->Link.ForwardLink;\r
127   }\r
128 \r
129   return EFI_SUCCESS;\r
130 }\r
131 \r
132 /**\r
133 \r
134 Routine Description:\r
135 \r
136   This routine is used to merge two different resource tree in need of\r
137   resoure degradation. For example, if a upstream PPB doesn't support,\r
138   prefetchable memory decoding, the PCI bus driver will choose to call this function\r
139   to merge prefectchable memory resource list into normal memory list.\r
140 \r
141   If the TypeMerge is TRUE, Res resource type is changed to the type of destination resource\r
142   type.\r
143 \r
144   @param Dst        Point to destination resource tree\r
145   @param Res        Point to source resource tree\r
146   @param TypeMerge  If the TypeMerge is TRUE, Res resource type is changed to the type of \r
147                     destination resource type.\r
148                     \r
149                     \r
150   @retval EFI_SUCCESS Success\r
151 **/\r
152 EFI_STATUS\r
153 MergeResourceTree (\r
154   PCI_RESOURCE_NODE *Dst,\r
155   PCI_RESOURCE_NODE *Res,\r
156   BOOLEAN           TypeMerge\r
157   )\r
158 {\r
159 \r
160   LIST_ENTRY        *CurrentLink;\r
161   PCI_RESOURCE_NODE *Temp;\r
162 \r
163   while (!IsListEmpty (&Res->ChildList)) {\r
164     CurrentLink = Res->ChildList.ForwardLink;\r
165 \r
166     Temp        = RESOURCE_NODE_FROM_LINK (CurrentLink);\r
167 \r
168     if (TypeMerge) {\r
169       Temp->ResType = Dst->ResType;\r
170     }\r
171 \r
172     RemoveEntryList (CurrentLink);\r
173     InsertResourceNode (Dst, Temp);\r
174 \r
175   }\r
176 \r
177   return EFI_SUCCESS;\r
178 }\r
179 \r
180 /**\r
181   This function is used to calculate the IO16 aperture\r
182   for a bridge.\r
183 \r
184   @param Bridge PCI resource node for bridge.\r
185   \r
186   @retval EFI_SUCCESS Success\r
187 **/\r
188 EFI_STATUS\r
189 CalculateApertureIo16 (\r
190   IN PCI_RESOURCE_NODE *Bridge\r
191   )\r
192 {\r
193 \r
194   UINT64            Aperture;\r
195   LIST_ENTRY        *CurrentLink;\r
196   PCI_RESOURCE_NODE *Node;\r
197   UINT64            offset;\r
198   BOOLEAN           IsaEnable;\r
199   BOOLEAN           VGAEnable;\r
200 \r
201   //\r
202   // Always assume there is ISA device and VGA device on the platform\r
203   // will be customized later\r
204   //\r
205   IsaEnable = FALSE;\r
206   VGAEnable = FALSE;\r
207 \r
208   if (FeaturePcdGet (PcdPciIsaEnable)){\r
209     IsaEnable = TRUE;\r
210   }\r
211 \r
212   if (FeaturePcdGet (PcdPciVgaEnable)){\r
213     VGAEnable = TRUE;\r
214   }\r
215 \r
216   Aperture = 0;\r
217 \r
218   if (!Bridge) {\r
219     return EFI_SUCCESS;\r
220   }\r
221 \r
222   CurrentLink = Bridge->ChildList.ForwardLink;\r
223 \r
224   //\r
225   // Assume the bridge is aligned\r
226   //\r
227   while (CurrentLink != &Bridge->ChildList) {\r
228 \r
229     Node = RESOURCE_NODE_FROM_LINK (CurrentLink);\r
230 \r
231     //\r
232     // Consider the aperture alignment\r
233     //\r
234     offset = Aperture & (Node->Alignment);\r
235 \r
236     if (offset) {\r
237 \r
238       Aperture = Aperture + (Node->Alignment + 1) - offset;\r
239 \r
240     }\r
241 \r
242     //\r
243     // IsaEnable and VGAEnable can not be implemented now.\r
244     // If both of them are enabled, then the IO resource would\r
245     // become too limited to meet the requirement of most of devices.\r
246     //\r
247 \r
248     if (IsaEnable || VGAEnable) {\r
249       if (!IS_PCI_BRIDGE (&(Node->PciDev->Pci)) && !IS_CARDBUS_BRIDGE (&(Node->PciDev->Pci))) {\r
250         //\r
251         // Check if there is need to support ISA/VGA decoding\r
252         // If so, we need to avoid isa/vga aliasing range\r
253         //\r
254         if (IsaEnable) {\r
255           SkipIsaAliasAperture (\r
256             &Aperture,\r
257             Node->Length               \r
258             );\r
259           offset = Aperture & (Node->Alignment);\r
260           if (offset) {\r
261             Aperture = Aperture + (Node->Alignment + 1) - offset;\r
262           }\r
263         } else if (VGAEnable) {\r
264           SkipVGAAperture (\r
265             &Aperture,\r
266             Node->Length\r
267             );\r
268           offset = Aperture & (Node->Alignment);\r
269           if (offset) {\r
270             Aperture = Aperture + (Node->Alignment + 1) - offset;\r
271           }\r
272         }\r
273       }\r
274     }\r
275 \r
276     Node->Offset = Aperture;\r
277 \r
278     //\r
279     // Increment aperture by the length of node\r
280     //\r
281     Aperture += Node->Length;\r
282 \r
283     CurrentLink = CurrentLink->ForwardLink;\r
284   }\r
285 \r
286   //\r
287   // At last, adjust the aperture with the bridge's\r
288   // alignment\r
289   //\r
290   offset = Aperture & (Bridge->Alignment);\r
291 \r
292   if (offset) {\r
293     Aperture = Aperture + (Bridge->Alignment + 1) - offset;\r
294   }\r
295 \r
296   Bridge->Length = Aperture;\r
297   //\r
298   // At last, adjust the bridge's alignment to the first child's alignment\r
299   // if the bridge has at least one child\r
300   //\r
301   CurrentLink = Bridge->ChildList.ForwardLink;\r
302   if (CurrentLink != &Bridge->ChildList) {\r
303     Node = RESOURCE_NODE_FROM_LINK (CurrentLink);\r
304     if (Node->Alignment > Bridge->Alignment) {\r
305       Bridge->Alignment = Node->Alignment;\r
306     }\r
307   }\r
308 \r
309   return EFI_SUCCESS;\r
310 }\r
311 \r
312 /**\r
313   This function is used to calculate the resource aperture\r
314   for a given bridge device\r
315 \r
316   @param Bridge Give bridge device\r
317   \r
318   @retval EFI_SUCCESS Success\r
319 **/\r
320 EFI_STATUS\r
321 CalculateResourceAperture (\r
322   IN PCI_RESOURCE_NODE *Bridge\r
323   )\r
324 {\r
325   UINT64            Aperture;\r
326   LIST_ENTRY        *CurrentLink;\r
327   PCI_RESOURCE_NODE *Node;\r
328 \r
329   UINT64            offset;\r
330 \r
331   Aperture = 0;\r
332 \r
333   if (!Bridge) {\r
334     return EFI_SUCCESS;\r
335   }\r
336 \r
337   if (Bridge->ResType == PciBarTypeIo16) {\r
338     return CalculateApertureIo16 (Bridge);\r
339   }\r
340 \r
341   CurrentLink = Bridge->ChildList.ForwardLink;\r
342 \r
343   //\r
344   // Assume the bridge is aligned\r
345   //\r
346   while (CurrentLink != &Bridge->ChildList) {\r
347 \r
348     Node = RESOURCE_NODE_FROM_LINK (CurrentLink);\r
349 \r
350     //\r
351     // Apply padding resource if available\r
352     //\r
353         \r
354     offset = Aperture & (Node->Alignment);\r
355 \r
356     if (offset) {\r
357 \r
358       Aperture = Aperture + (Node->Alignment + 1) - offset;\r
359 \r
360     }\r
361 \r
362     //\r
363     // Recode current aperture as a offset\r
364     // this offset will be used in future real allocation\r
365     //\r
366     Node->Offset = Aperture;\r
367 \r
368     //\r
369     // Increment aperture by the length of node\r
370     //\r
371     Aperture += Node->Length;\r
372 \r
373     //\r
374     // Consider the aperture alignment\r
375     //\r
376     \r
377     CurrentLink = CurrentLink->ForwardLink;\r
378   }\r
379 \r
380   //\r
381   // At last, adjust the aperture with the bridge's\r
382   // alignment\r
383   //\r
384   offset = Aperture & (Bridge->Alignment);\r
385   if (offset) {\r
386     Aperture = Aperture + (Bridge->Alignment + 1) - offset;\r
387   }\r
388 \r
389   //\r
390   // If the bridge has already padded the resource and the\r
391   // amount of padded resource is larger, then keep the\r
392   // padded resource\r
393   //\r
394   if (Bridge->Length < Aperture) {\r
395     Bridge->Length = Aperture;\r
396   }\r
397   \r
398   //\r
399   // At last, adjust the bridge's alignment to the first child's alignment\r
400   // if the bridge has at least one child\r
401   //\r
402   CurrentLink = Bridge->ChildList.ForwardLink;\r
403   if (CurrentLink != &Bridge->ChildList) {\r
404     Node = RESOURCE_NODE_FROM_LINK (CurrentLink);\r
405     if (Node->Alignment > Bridge->Alignment) {\r
406       Bridge->Alignment = Node->Alignment;\r
407     }\r
408   }\r
409 \r
410   return EFI_SUCCESS;\r
411 }\r
412 \r
413 /**\r
414   Get IO/Memory resource infor for given PCI device\r
415   \r
416   @param PciDev     Pci device instance\r
417   @param IoNode     Resource info node for IO \r
418   @param Mem32Node  Resource info node for 32-bit memory\r
419   @param PMem32Node Resource info node for 32-bit PMemory\r
420   @param Mem64Node  Resource info node for 64-bit memory\r
421   @param PMem64Node Resource info node for 64-bit PMemory\r
422   \r
423   @retval EFI_SUCCESS Success\r
424 **/\r
425 EFI_STATUS\r
426 GetResourceFromDevice (\r
427   PCI_IO_DEVICE     *PciDev,\r
428   PCI_RESOURCE_NODE *IoNode,\r
429   PCI_RESOURCE_NODE *Mem32Node,\r
430   PCI_RESOURCE_NODE *PMem32Node,\r
431   PCI_RESOURCE_NODE *Mem64Node,\r
432   PCI_RESOURCE_NODE *PMem64Node\r
433   )\r
434 {\r
435 \r
436   UINT8             Index;\r
437   PCI_RESOURCE_NODE *Node;\r
438   BOOLEAN           ResourceRequested;\r
439 \r
440   Node              = NULL;\r
441   ResourceRequested = FALSE;\r
442 \r
443   for (Index = 0; Index < PCI_MAX_BAR; Index++) {\r
444 \r
445     switch ((PciDev->PciBar)[Index].BarType) {\r
446 \r
447     case PciBarTypeMem32:\r
448 \r
449       Node = CreateResourceNode (\r
450               PciDev,\r
451               (PciDev->PciBar)[Index].Length,\r
452               (PciDev->PciBar)[Index].Alignment,\r
453               Index,\r
454               PciBarTypeMem32,\r
455               PciResUsageTypical\r
456               );\r
457 \r
458       InsertResourceNode (\r
459         Mem32Node,\r
460         Node\r
461         );\r
462 \r
463       ResourceRequested = TRUE;\r
464       break;\r
465 \r
466     case PciBarTypeMem64:\r
467 \r
468       Node = CreateResourceNode (\r
469               PciDev,\r
470               (PciDev->PciBar)[Index].Length,\r
471               (PciDev->PciBar)[Index].Alignment,\r
472               Index,\r
473               PciBarTypeMem64,\r
474               PciResUsageTypical\r
475               );\r
476 \r
477       InsertResourceNode (\r
478         Mem64Node,\r
479         Node\r
480         );\r
481 \r
482       ResourceRequested = TRUE;\r
483       break;\r
484 \r
485     case PciBarTypePMem64:\r
486 \r
487       Node = CreateResourceNode (\r
488               PciDev,\r
489               (PciDev->PciBar)[Index].Length,\r
490               (PciDev->PciBar)[Index].Alignment,\r
491               Index,\r
492               PciBarTypePMem64,\r
493               PciResUsageTypical\r
494               );\r
495 \r
496       InsertResourceNode (\r
497         PMem64Node,\r
498         Node\r
499         );\r
500 \r
501       ResourceRequested = TRUE;\r
502       break;\r
503 \r
504     case PciBarTypePMem32:\r
505 \r
506       Node = CreateResourceNode (\r
507               PciDev,\r
508               (PciDev->PciBar)[Index].Length,\r
509               (PciDev->PciBar)[Index].Alignment,\r
510               Index,\r
511               PciBarTypePMem32,\r
512               PciResUsageTypical\r
513               );\r
514 \r
515       InsertResourceNode (\r
516         PMem32Node,\r
517         Node\r
518         );\r
519       ResourceRequested = TRUE;\r
520       break;\r
521 \r
522     case PciBarTypeIo16:\r
523     case PciBarTypeIo32:\r
524 \r
525       Node = CreateResourceNode (\r
526               PciDev,\r
527               (PciDev->PciBar)[Index].Length,\r
528               (PciDev->PciBar)[Index].Alignment,\r
529               Index,\r
530               PciBarTypeIo16,\r
531               PciResUsageTypical\r
532               );\r
533 \r
534       InsertResourceNode (\r
535         IoNode,\r
536         Node\r
537         );\r
538       ResourceRequested = TRUE;\r
539       break;\r
540 \r
541     case PciBarTypeUnknown:\r
542       break;\r
543 \r
544     default:\r
545       break;\r
546     }\r
547   }\r
548 \r
549   //\r
550   // If there is no resource requested from this device,\r
551   // then we indicate this device has been allocated naturally.\r
552   //\r
553   if (!ResourceRequested) {\r
554     PciDev->Allocated = TRUE;\r
555   }\r
556 \r
557   return EFI_SUCCESS;\r
558 }\r
559 \r
560 /**\r
561   This function is used to create a resource node\r
562 \r
563   @param PciDev       Pci device instance\r
564   @param Length       Length of Io/Memory resource\r
565   @param Alignment    Alignment of resource\r
566   @param Bar          Bar index \r
567   @param ResType      Type of resource: IO/Memory\r
568   @param ResUage      Resource usage\r
569 **/\r
570 PCI_RESOURCE_NODE *\r
571 CreateResourceNode (\r
572   IN PCI_IO_DEVICE         *PciDev,\r
573   IN UINT64                Length,\r
574   IN UINT64                Alignment,\r
575   IN UINT8                 Bar,\r
576   IN PCI_BAR_TYPE          ResType,\r
577   IN PCI_RESOURCE_USAGE    ResUsage\r
578   )\r
579 {\r
580   PCI_RESOURCE_NODE *Node;\r
581 \r
582   Node    = NULL;\r
583 \r
584   Node    = AllocatePool (sizeof (PCI_RESOURCE_NODE));\r
585   ASSERT (Node != NULL);\r
586   if (Node == NULL) {\r
587     return NULL;\r
588   }\r
589 \r
590   ZeroMem (Node, sizeof (PCI_RESOURCE_NODE));\r
591 \r
592   Node->Signature     = PCI_RESOURCE_SIGNATURE;\r
593   Node->PciDev        = PciDev;\r
594   Node->Length        = Length;\r
595   Node->Alignment     = Alignment;\r
596   Node->Bar           = Bar;\r
597   Node->ResType       = ResType;\r
598   Node->Reserved      = FALSE;\r
599   Node->ResourceUsage = ResUsage;\r
600   InitializeListHead (&Node->ChildList);\r
601   return Node;\r
602 }\r
603 \r
604 /**\r
605   This routine is used to extract resource request from\r
606   device node list.\r
607 \r
608   @param Bridge     Pci device instance\r
609   @param IoNode     Resource info node for IO \r
610   @param Mem32Node  Resource info node for 32-bit memory\r
611   @param PMem32Node Resource info node for 32-bit PMemory\r
612   @param Mem64Node  Resource info node for 64-bit memory\r
613   @param PMem64Node Resource info node for 64-bit PMemory\r
614 \r
615   @retval EFI_SUCCESS Success\r
616 **/\r
617 EFI_STATUS\r
618 CreateResourceMap (\r
619   IN PCI_IO_DEVICE     *Bridge,\r
620   IN PCI_RESOURCE_NODE *IoNode,\r
621   IN PCI_RESOURCE_NODE *Mem32Node,\r
622   IN PCI_RESOURCE_NODE *PMem32Node,\r
623   IN PCI_RESOURCE_NODE *Mem64Node,\r
624   IN PCI_RESOURCE_NODE *PMem64Node\r
625   )\r
626 {\r
627   PCI_IO_DEVICE     *Temp;\r
628   PCI_RESOURCE_NODE *IoBridge;\r
629   PCI_RESOURCE_NODE *Mem32Bridge;\r
630   PCI_RESOURCE_NODE *PMem32Bridge;\r
631   PCI_RESOURCE_NODE *Mem64Bridge;\r
632   PCI_RESOURCE_NODE *PMem64Bridge;\r
633   LIST_ENTRY        *CurrentLink;\r
634 \r
635   CurrentLink = Bridge->ChildList.ForwardLink;\r
636 \r
637   while (CurrentLink && CurrentLink != &Bridge->ChildList) {\r
638 \r
639     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
640 \r
641     //\r
642     // Create resource nodes for this device by scanning the\r
643     // Bar array in the device private data\r
644     // If the upstream bridge doesn't support this device,\r
645     // no any resource node will be created for this device\r
646     //\r
647     GetResourceFromDevice (\r
648       Temp,\r
649       IoNode,\r
650       Mem32Node,\r
651       PMem32Node,\r
652       Mem64Node,\r
653       PMem64Node\r
654       );\r
655 \r
656     if (IS_PCI_BRIDGE (&Temp->Pci)) {\r
657 \r
658       //\r
659       // If the device has children, create a bridge resource node for this PPB\r
660       // Note: For PPB, memory aperture is aligned with 1MB and IO aperture\r
661       // is aligned with 4KB\r
662       // This device is typically a bridge device like PPB and P2C\r
663       //\r
664       IoBridge = CreateResourceNode (\r
665                   Temp,\r
666                   0,\r
667                   0xFFF,\r
668                   PPB_IO_RANGE,\r
669                   PciBarTypeIo16,\r
670                   PciResUsageTypical\r
671                   ); //0x1000 aligned\r
672       \r
673       Mem32Bridge = CreateResourceNode (\r
674                       Temp,\r
675                       0,\r
676                       0xFFFFF,\r
677                       PPB_MEM32_RANGE,\r
678                       PciBarTypeMem32,\r
679                       PciResUsageTypical\r
680                       );\r
681 \r
682       PMem32Bridge = CreateResourceNode (\r
683                       Temp,\r
684                       0,\r
685                       0xFFFFF,\r
686                       PPB_PMEM32_RANGE,\r
687                       PciBarTypePMem32,\r
688                       PciResUsageTypical\r
689                       );\r
690 \r
691       Mem64Bridge = CreateResourceNode (\r
692                       Temp,\r
693                       0,\r
694                       0xFFFFF,\r
695                       PPB_MEM64_RANGE,\r
696                       PciBarTypeMem64,\r
697                       PciResUsageTypical\r
698                       );\r
699 \r
700       PMem64Bridge = CreateResourceNode (\r
701                       Temp,\r
702                       0,\r
703                       0xFFFFF,\r
704                       PPB_PMEM64_RANGE,\r
705                       PciBarTypePMem64,\r
706                       PciResUsageTypical\r
707                       );\r
708 \r
709       //\r
710       // Recursively create resouce map on this bridge\r
711       //\r
712       CreateResourceMap (\r
713         Temp,\r
714         IoBridge,\r
715         Mem32Bridge,\r
716         PMem32Bridge,\r
717         Mem64Bridge,\r
718         PMem64Bridge\r
719         );\r
720 \r
721       if (ResourceRequestExisted (IoBridge)) {\r
722         InsertResourceNode (\r
723           IoNode,\r
724           IoBridge\r
725           );\r
726       } else {\r
727         gBS->FreePool (IoBridge);\r
728         IoBridge = NULL;\r
729       }\r
730 \r
731       //\r
732       // If there is node under this resource bridge,\r
733       // then calculate bridge's aperture of this type\r
734       // and insert it into the respective resource tree.\r
735       // If no, delete this resource bridge\r
736       //\r
737       if (ResourceRequestExisted (Mem32Bridge)) {\r
738         InsertResourceNode (\r
739           Mem32Node,\r
740           Mem32Bridge\r
741           );\r
742       } else {\r
743         gBS->FreePool (Mem32Bridge);\r
744         Mem32Bridge = NULL;\r
745       }\r
746 \r
747       //\r
748       // If there is node under this resource bridge,\r
749       // then calculate bridge's aperture of this type\r
750       // and insert it into the respective resource tree.\r
751       // If no, delete this resource bridge\r
752       //\r
753       if (ResourceRequestExisted (PMem32Bridge)) {\r
754         InsertResourceNode (\r
755           PMem32Node,\r
756           PMem32Bridge\r
757           );\r
758       } else {\r
759         gBS->FreePool (PMem32Bridge);\r
760         PMem32Bridge = NULL;\r
761       }\r
762 \r
763       //\r
764       // If there is node under this resource bridge,\r
765       // then calculate bridge's aperture of this type\r
766       // and insert it into the respective resource tree.\r
767       // If no, delete this resource bridge\r
768       //\r
769       if (ResourceRequestExisted (Mem64Bridge)) {\r
770         InsertResourceNode (\r
771           Mem64Node,\r
772           Mem64Bridge\r
773           );\r
774       } else {\r
775         gBS->FreePool (Mem64Bridge);\r
776         Mem64Bridge = NULL;\r
777       }\r
778 \r
779       //\r
780       // If there is node under this resource bridge,\r
781       // then calculate bridge's aperture of this type\r
782       // and insert it into the respective resource tree.\r
783       // If no, delete this resource bridge\r
784       //\r
785       if (ResourceRequestExisted (PMem64Bridge)) {\r
786         InsertResourceNode (\r
787           PMem64Node,\r
788           PMem64Bridge\r
789           );\r
790       } else {\r
791         gBS->FreePool (PMem64Bridge);\r
792         PMem64Bridge = NULL;\r
793       }\r
794 \r
795     }\r
796 \r
797     //\r
798     // If it is P2C, apply hard coded resource padding\r
799     //\r
800     //\r
801     if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {\r
802       ResourcePaddingForCardBusBridge (\r
803         Temp,\r
804         IoNode,\r
805         Mem32Node,\r
806         PMem32Node,\r
807         Mem64Node,\r
808         PMem64Node\r
809         );\r
810     }\r
811 \r
812     CurrentLink = CurrentLink->ForwardLink;\r
813   }\r
814   //\r
815   //\r
816   // To do some platform specific resource padding ...\r
817   //\r
818   ResourcePaddingPolicy (\r
819     Bridge,\r
820     IoNode,\r
821     Mem32Node,\r
822     PMem32Node,\r
823     Mem64Node,\r
824     PMem64Node\r
825     );\r
826 \r
827   //\r
828   // Degrade resource if necessary\r
829   //\r
830   DegradeResource (\r
831     Bridge,\r
832     Mem32Node,\r
833     PMem32Node,\r
834     Mem64Node,\r
835     PMem64Node\r
836     );\r
837 \r
838   //\r
839   // Calculate resource aperture for this bridge device\r
840   //\r
841   CalculateResourceAperture (Mem32Node);\r
842   CalculateResourceAperture (PMem32Node);\r
843   CalculateResourceAperture (Mem64Node);\r
844   CalculateResourceAperture (PMem64Node);\r
845   CalculateResourceAperture (IoNode);\r
846 \r
847   return EFI_SUCCESS;\r
848 \r
849 }\r
850 \r
851 /**\r
852   This function is used to do the resource padding for a specific platform\r
853 \r
854   @param Bridge     Pci device instance\r
855   @param IoNode     Resource info node for IO \r
856   @param Mem32Node  Resource info node for 32-bit memory\r
857   @param PMem32Node Resource info node for 32-bit PMemory\r
858   @param Mem64Node  Resource info node for 64-bit memory\r
859   @param PMem64Node Resource info node for 64-bit PMemory\r
860 \r
861   @retval EFI_SUCCESS Success\r
862 **/\r
863 EFI_STATUS\r
864 ResourcePaddingPolicy (\r
865   PCI_IO_DEVICE     *PciDev,\r
866   PCI_RESOURCE_NODE *IoNode,\r
867   PCI_RESOURCE_NODE *Mem32Node,\r
868   PCI_RESOURCE_NODE *PMem32Node,\r
869   PCI_RESOURCE_NODE *Mem64Node,\r
870   PCI_RESOURCE_NODE *PMem64Node\r
871   )\r
872 {\r
873   //\r
874   // Create padding resource node\r
875   //\r
876   if (PciDev->ResourcePaddingDescriptors != NULL) {\r
877     ApplyResourcePadding (\r
878       PciDev,\r
879       IoNode,\r
880       Mem32Node,\r
881       PMem32Node,\r
882       Mem64Node,\r
883       PMem64Node\r
884       );\r
885   }\r
886 \r
887   return EFI_SUCCESS;\r
888 \r
889 }\r
890 \r
891 /**\r
892   This function is used to degrade resource if the upstream bridge \r
893   doesn't support certain resource. Degradation path is \r
894   PMEM64 -> MEM64  -> MEM32\r
895   PMEM64 -> PMEM32 -> MEM32\r
896   IO32   -> IO16\r
897 \r
898   @param Bridge     Pci device instance\r
899   @param IoNode     Resource info node for IO \r
900   @param Mem32Node  Resource info node for 32-bit memory\r
901   @param PMem32Node Resource info node for 32-bit PMemory\r
902   @param Mem64Node  Resource info node for 64-bit memory\r
903   @param PMem64Node Resource info node for 64-bit PMemory\r
904 \r
905   @retval EFI_SUCCESS Success\r
906 **/\r
907 EFI_STATUS\r
908 DegradeResource (\r
909   IN PCI_IO_DEVICE     *Bridge,\r
910   IN PCI_RESOURCE_NODE *Mem32Node,\r
911   IN PCI_RESOURCE_NODE *PMem32Node,\r
912   IN PCI_RESOURCE_NODE *Mem64Node,\r
913   IN PCI_RESOURCE_NODE *PMem64Node\r
914   )\r
915 {\r
916 \r
917   //\r
918   // If bridge doesn't support Prefetchable\r
919   // memory64, degrade it to Prefetchable memory32\r
920   //\r
921   if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM64_DECODE_SUPPORTED)) {\r
922     MergeResourceTree (\r
923       PMem32Node,\r
924       PMem64Node,\r
925       TRUE\r
926       );\r
927   } else {\r
928     //\r
929     // if no PMem32 request, still keep PMem64. Otherwise degrade to PMem32\r
930     //\r
931     if (PMem32Node != NULL && PMem32Node->Length != 0 && Bridge->Parent != NULL ) { \r
932       //\r
933       // Fixed the issue that there is no resource for 64-bit (above 4G)\r
934       //\r
935       MergeResourceTree (\r
936         PMem32Node,\r
937         PMem64Node,\r
938         TRUE\r
939         );\r
940     }\r
941   }\r
942 \r
943 \r
944   //\r
945   // If bridge doesn't support Mem64\r
946   // degrade it to mem32\r
947   //\r
948   if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_MEM64_DECODE_SUPPORTED)) {\r
949     MergeResourceTree (\r
950       Mem32Node,\r
951       Mem64Node,\r
952       TRUE\r
953       );\r
954   }\r
955 \r
956   //\r
957   // If bridge doesn't support Pmem32\r
958   // degrade it to mem32\r
959   //\r
960   if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM32_DECODE_SUPPORTED)) {\r
961     MergeResourceTree (\r
962       Mem32Node,\r
963       PMem32Node,\r
964       TRUE\r
965       );\r
966   }\r
967 \r
968   //\r
969   // if bridge supports combined Pmem Mem decoding\r
970   // merge these two type of resource\r
971   //\r
972   if (BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED)) {\r
973     MergeResourceTree (\r
974       Mem32Node,\r
975       PMem32Node,\r
976       FALSE\r
977       );\r
978 \r
979     MergeResourceTree (\r
980       Mem64Node,\r
981       PMem64Node,\r
982       FALSE\r
983       );\r
984   }\r
985 \r
986   return EFI_SUCCESS;\r
987 }\r
988 \r
989 /**\r
990   Test whether bridge device support decode resource\r
991   \r
992   @param Bridge    Bridge device instance\r
993   @param Decode    Decode type according to resource type\r
994   \r
995   @return whether bridge device support decode resource\r
996   \r
997 **/\r
998 BOOLEAN\r
999 BridgeSupportResourceDecode (\r
1000   IN PCI_IO_DEVICE *Bridge,\r
1001   IN UINT32        Decode\r
1002   )\r
1003 {\r
1004 \r
1005   if ((Bridge->Decodes) & Decode) {\r
1006     return TRUE;\r
1007   }\r
1008 \r
1009   return FALSE;\r
1010 }\r
1011 \r
1012 /**\r
1013   This function is used to program the resource allocated \r
1014   for each resource node\r
1015 \r
1016   \r
1017   @param Base     Base address of resource\r
1018   @param Bridge   Bridge device instance\r
1019   \r
1020   @retval EFI_SUCCESS Success\r
1021 **/\r
1022 EFI_STATUS\r
1023 ProgramResource (\r
1024   IN UINT64            Base,\r
1025   IN PCI_RESOURCE_NODE *Bridge\r
1026   )\r
1027 {\r
1028   LIST_ENTRY        *CurrentLink;\r
1029   PCI_RESOURCE_NODE *Node;\r
1030   EFI_STATUS        Status;\r
1031 \r
1032   if (Base == gAllOne) {\r
1033     return EFI_OUT_OF_RESOURCES;\r
1034   }\r
1035 \r
1036   CurrentLink = Bridge->ChildList.ForwardLink;\r
1037 \r
1038   while (CurrentLink != &Bridge->ChildList) {\r
1039 \r
1040     Node = RESOURCE_NODE_FROM_LINK (CurrentLink);\r
1041 \r
1042     if (!IS_PCI_BRIDGE (&(Node->PciDev->Pci))) {\r
1043 \r
1044       if (IS_CARDBUS_BRIDGE (&(Node->PciDev->Pci))) {\r
1045         ProgramP2C (Base, Node);\r
1046       } else {\r
1047         ProgramBar (Base, Node);\r
1048       }\r
1049     } else {\r
1050       Status = ProgramResource (Base + Node->Offset, Node);\r
1051 \r
1052       if (EFI_ERROR (Status)) {\r
1053         return Status;\r
1054       }\r
1055 \r
1056       ProgramPpbApperture (Base, Node);\r
1057     }\r
1058 \r
1059     CurrentLink = CurrentLink->ForwardLink;\r
1060   }\r
1061 \r
1062   return EFI_SUCCESS;\r
1063 }\r
1064 \r
1065 /**\r
1066   Program Bar register.\r
1067   \r
1068   @param Base  Base address for resource\r
1069   @param Node  Point to resoure node structure\r
1070   \r
1071   @retval EFI_SUCCESS Success\r
1072 **/\r
1073 EFI_STATUS\r
1074 ProgramBar (\r
1075   IN UINT64            Base,\r
1076   IN PCI_RESOURCE_NODE *Node\r
1077   )\r
1078 {\r
1079   EFI_PCI_IO_PROTOCOL *PciIo;\r
1080   UINT64              Address;\r
1081   UINT32              Address32;\r
1082 \r
1083   Address = 0;\r
1084   PciIo   = &(Node->PciDev->PciIo);\r
1085 \r
1086   Address = Base + Node->Offset;\r
1087 \r
1088   //\r
1089   // Indicate pci bus driver has allocated\r
1090   // resource for this device\r
1091   // It might be a temporary solution here since\r
1092   // pci device could have multiple bar\r
1093   //\r
1094   Node->PciDev->Allocated = TRUE;\r
1095 \r
1096   switch ((Node->PciDev->PciBar[Node->Bar]).BarType) {\r
1097 \r
1098   case PciBarTypeIo16:\r
1099   case PciBarTypeIo32:\r
1100   case PciBarTypeMem32:\r
1101   case PciBarTypePMem32:\r
1102 \r
1103     PciIoWrite (\r
1104                 PciIo,\r
1105                 EfiPciIoWidthUint32,\r
1106                 (Node->PciDev->PciBar[Node->Bar]).Offset,\r
1107                 1,\r
1108                 &Address\r
1109                 );\r
1110 \r
1111     Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;\r
1112 \r
1113     break;\r
1114 \r
1115   case PciBarTypeMem64:\r
1116   case PciBarTypePMem64:\r
1117 \r
1118     Address32 = (UINT32) (Address & 0x00000000FFFFFFFF);\r
1119 \r
1120     PciIoWrite (\r
1121                 PciIo,\r
1122                 EfiPciIoWidthUint32,\r
1123                 (Node->PciDev->PciBar[Node->Bar]).Offset,\r
1124                 1,\r
1125                 &Address32\r
1126                 );\r
1127 \r
1128     Address32 = (UINT32) RShiftU64 (Address, 32);\r
1129 \r
1130     PciIoWrite (\r
1131                 PciIo,\r
1132                 EfiPciIoWidthUint32,\r
1133                 (UINT8) ((Node->PciDev->PciBar[Node->Bar]).Offset + 4),\r
1134                 1,\r
1135                 &Address32\r
1136                 );\r
1137 \r
1138     Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;\r
1139 \r
1140     break;\r
1141 \r
1142   default:\r
1143     break;\r
1144   }\r
1145 \r
1146   return EFI_SUCCESS;\r
1147 }\r
1148 \r
1149 /**\r
1150   Program PPB apperture\r
1151   \r
1152   @param Base  Base address for resource\r
1153   @param Node  Point to resoure node structure\r
1154   \r
1155   @retval EFI_SUCCESS Success\r
1156 **/\r
1157 EFI_STATUS\r
1158 ProgramPpbApperture (\r
1159   IN UINT64            Base,\r
1160   IN PCI_RESOURCE_NODE *Node\r
1161   )\r
1162 {\r
1163   EFI_PCI_IO_PROTOCOL *PciIo;\r
1164   UINT64              Address;\r
1165   UINT32              Address32;\r
1166 \r
1167   Address = 0;\r
1168   //\r
1169   // if no device south of this PPB, return anyway\r
1170   // Apperture is set default in the initialization code\r
1171   //\r
1172   if (Node->Length == 0 || Node->ResourceUsage == PciResUsagePadding) {\r
1173     //\r
1174     // For padding resource node, just ignore when programming\r
1175     //\r
1176     return EFI_SUCCESS;\r
1177   }\r
1178 \r
1179   PciIo   = &(Node->PciDev->PciIo);\r
1180   Address = Base + Node->Offset;\r
1181 \r
1182   //\r
1183   // Indicate the PPB resource has been allocated\r
1184   //\r
1185   Node->PciDev->Allocated = TRUE;\r
1186 \r
1187   switch (Node->Bar) {\r
1188 \r
1189   case PPB_BAR_0:\r
1190   case PPB_BAR_1:\r
1191     PciIoWrite (\r
1192                 PciIo,\r
1193                 EfiPciIoWidthUint32,\r
1194                 (Node->PciDev->PciBar[Node->Bar]).Offset,\r
1195                 1,\r
1196                 &Address\r
1197                 );\r
1198 \r
1199     Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;\r
1200     Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;\r
1201 \r
1202     break;\r
1203 \r
1204   case PPB_IO_RANGE:\r
1205 \r
1206     Address32 = ((UINT32) (Address)) >> 8;\r
1207     PciIoWrite (\r
1208                 PciIo,\r
1209                 EfiPciIoWidthUint8,\r
1210                 0x1C,\r
1211                 1,\r
1212                 &Address32\r
1213                 );\r
1214 \r
1215     Address32 >>= 8;\r
1216     PciIoWrite (\r
1217                 PciIo,\r
1218                 EfiPciIoWidthUint16,\r
1219                 0x30,\r
1220                 1,\r
1221                 &Address32\r
1222                 );\r
1223 \r
1224     Address32 = (UINT32) (Address + Node->Length - 1);\r
1225     Address32 = ((UINT32) (Address32)) >> 8;\r
1226     PciIoWrite (\r
1227                 PciIo,\r
1228                 EfiPciIoWidthUint8,\r
1229                 0x1D,\r
1230                 1,\r
1231                 &Address32\r
1232                 );\r
1233 \r
1234     Address32 >>= 8;\r
1235     PciIoWrite (\r
1236                 PciIo,\r
1237                 EfiPciIoWidthUint16,\r
1238                 0x32,\r
1239                 1,\r
1240                 &Address32\r
1241                 );\r
1242 \r
1243     Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;\r
1244     Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;\r
1245     break;\r
1246 \r
1247   case PPB_MEM32_RANGE:\r
1248 \r
1249     Address32 = ((UINT32) (Address)) >> 16;\r
1250     PciIoWrite (\r
1251                 PciIo,\r
1252                 EfiPciIoWidthUint16,\r
1253                 0x20,\r
1254                 1,\r
1255                 &Address32\r
1256                 );\r
1257 \r
1258     Address32 = (UINT32) (Address + Node->Length - 1);\r
1259     Address32 = ((UINT32) (Address32)) >> 16;\r
1260     PciIoWrite (\r
1261                 PciIo,\r
1262                 EfiPciIoWidthUint16,\r
1263                 0x22,\r
1264                 1,\r
1265                 &Address32\r
1266                 );\r
1267 \r
1268     Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;\r
1269     Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;\r
1270     break;\r
1271 \r
1272   case PPB_PMEM32_RANGE:\r
1273   case PPB_PMEM64_RANGE:\r
1274 \r
1275     Address32 = ((UINT32) (Address)) >> 16;\r
1276     PciIoWrite (\r
1277                 PciIo,\r
1278                 EfiPciIoWidthUint16,\r
1279                 0x24,\r
1280                 1,\r
1281                 &Address32\r
1282                 );\r
1283 \r
1284     Address32 = (UINT32) (Address + Node->Length - 1);\r
1285     Address32 = ((UINT32) (Address32)) >> 16;\r
1286     PciIoWrite (\r
1287                 PciIo,\r
1288                 EfiPciIoWidthUint16,\r
1289                 0x26,\r
1290                 1,\r
1291                 &Address32\r
1292                 );\r
1293 \r
1294     Address32 = (UINT32) RShiftU64 (Address, 32);\r
1295     PciIoWrite (\r
1296                 PciIo,\r
1297                 EfiPciIoWidthUint32,\r
1298                 0x28,\r
1299                 1,\r
1300                 &Address32\r
1301                 );\r
1302 \r
1303     Address32 = (UINT32) RShiftU64 ((Address + Node->Length - 1), 32);\r
1304     PciIoWrite (\r
1305                 PciIo,\r
1306                 EfiPciIoWidthUint32,\r
1307                 0x2C,\r
1308                 1,\r
1309                 &Address32\r
1310                 );\r
1311 \r
1312     Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;\r
1313     Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;\r
1314     break;\r
1315 \r
1316   default:\r
1317     break;\r
1318   }\r
1319 \r
1320   return EFI_SUCCESS;\r
1321 }\r
1322 \r
1323 /**\r
1324   Program parent bridge for oprom\r
1325   \r
1326   @param PciDevice      Pci deivce instance\r
1327   @param OptionRomBase  Base address for oprom\r
1328   @param Enable         Enable/Disable\r
1329   \r
1330   @retval EFI_SUCCESS Success\r
1331 **/\r
1332 EFI_STATUS\r
1333 ProgrameUpstreamBridgeForRom (\r
1334   IN PCI_IO_DEVICE   *PciDevice,\r
1335   IN UINT32          OptionRomBase,\r
1336   IN BOOLEAN         Enable\r
1337   )\r
1338 {\r
1339   PCI_IO_DEVICE     *Parent;\r
1340   PCI_RESOURCE_NODE Node;\r
1341   //\r
1342   // For root bridge, just return.\r
1343   //\r
1344   Parent = PciDevice->Parent;\r
1345   ZeroMem (&Node, sizeof (Node));\r
1346   while (Parent) {\r
1347     if (!IS_PCI_BRIDGE (&Parent->Pci)) {\r
1348       break;\r
1349     }\r
1350 \r
1351     Node.PciDev     = Parent;\r
1352     Node.Length     = PciDevice->RomSize;\r
1353     Node.Alignment  = 0;\r
1354     Node.Bar        = PPB_MEM32_RANGE;\r
1355     Node.ResType    = PciBarTypeMem32;\r
1356     Node.Offset     = 0;\r
1357 \r
1358     //\r
1359     // Program PPB to only open a single <= 16<MB apperture\r
1360     //\r
1361     if (Enable) {\r
1362       ProgramPpbApperture (OptionRomBase, &Node);\r
1363       PciEnableCommandRegister (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);\r
1364     } else {\r
1365       InitializePpb (Parent);\r
1366       PciDisableCommandRegister (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);\r
1367     }\r
1368 \r
1369     Parent = Parent->Parent;\r
1370   }\r
1371 \r
1372   return EFI_SUCCESS;\r
1373 }\r
1374 \r
1375 /**\r
1376   Test whether resource exists for a bridge\r
1377   \r
1378   @param Bridge  Point to resource node for a bridge \r
1379   \r
1380   @return whether resource exists\r
1381 **/\r
1382 BOOLEAN\r
1383 ResourceRequestExisted (\r
1384   IN PCI_RESOURCE_NODE *Bridge\r
1385   )\r
1386 {\r
1387   if (Bridge != NULL) {\r
1388     if (!IsListEmpty (&Bridge->ChildList) || Bridge->Length != 0) {\r
1389       return TRUE;\r
1390     }\r
1391   }\r
1392 \r
1393   return FALSE;\r
1394 }\r
1395 \r
1396 /**\r
1397   Initialize resource pool structure.\r
1398   \r
1399   @param ResourcePool Point to resource pool structure\r
1400   @param ResourceType Type of resource\r
1401 **/\r
1402 EFI_STATUS\r
1403 InitializeResourcePool (\r
1404   PCI_RESOURCE_NODE   *ResourcePool,\r
1405   PCI_BAR_TYPE        ResourceType\r
1406   )\r
1407 {\r
1408 \r
1409   ZeroMem (ResourcePool, sizeof (PCI_RESOURCE_NODE));\r
1410   ResourcePool->ResType   = ResourceType;\r
1411   ResourcePool->Signature = PCI_RESOURCE_SIGNATURE;\r
1412   InitializeListHead (&ResourcePool->ChildList);\r
1413 \r
1414   return EFI_SUCCESS;\r
1415 }\r
1416 \r
1417 /**\r
1418   Get all resource information for given Pci device\r
1419   \r
1420   @param PciDev         Pci device instance\r
1421   @param IoBridge       Io resource node\r
1422   @param Mem32Bridge    32-bit memory node\r
1423   @param PMem32Bridge   32-bit Pmemory node\r
1424   @param Mem64Bridge    64-bit memory node\r
1425   @param PMem64Bridge   64-bit PMemory node\r
1426   @param IoPool         Link list header for Io resource\r
1427   @param Mem32Pool      Link list header for 32-bit memory\r
1428   @param PMem32Pool     Link list header for 32-bit Pmemory\r
1429   @param Mem64Pool      Link list header for 64-bit memory\r
1430   @param PMem64Pool     Link list header for 64-bit Pmemory\r
1431   \r
1432   @retval EFI_SUCCESS Success\r
1433 **/\r
1434 EFI_STATUS\r
1435 GetResourceMap (\r
1436   PCI_IO_DEVICE      *PciDev,\r
1437   PCI_RESOURCE_NODE  **IoBridge,\r
1438   PCI_RESOURCE_NODE  **Mem32Bridge,\r
1439   PCI_RESOURCE_NODE  **PMem32Bridge,\r
1440   PCI_RESOURCE_NODE  **Mem64Bridge,\r
1441   PCI_RESOURCE_NODE  **PMem64Bridge,\r
1442   PCI_RESOURCE_NODE  *IoPool,\r
1443   PCI_RESOURCE_NODE  *Mem32Pool,\r
1444   PCI_RESOURCE_NODE  *PMem32Pool,\r
1445   PCI_RESOURCE_NODE  *Mem64Pool,\r
1446   PCI_RESOURCE_NODE  *PMem64Pool\r
1447   )\r
1448 {\r
1449 \r
1450   PCI_RESOURCE_NODE *Temp;\r
1451   LIST_ENTRY        *CurrentLink;\r
1452 \r
1453   CurrentLink = IoPool->ChildList.ForwardLink;\r
1454 \r
1455   //\r
1456   // Get Io resource map\r
1457   //\r
1458   while (CurrentLink != &IoPool->ChildList) {\r
1459 \r
1460     Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);\r
1461 \r
1462     if (Temp->PciDev == PciDev) {\r
1463       *IoBridge = Temp;\r
1464     }\r
1465 \r
1466     CurrentLink = CurrentLink->ForwardLink;\r
1467   }\r
1468 \r
1469   //\r
1470   // Get Mem32 resource map\r
1471   //\r
1472   CurrentLink = Mem32Pool->ChildList.ForwardLink;\r
1473 \r
1474   while (CurrentLink != &Mem32Pool->ChildList) {\r
1475 \r
1476     Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);\r
1477 \r
1478     if (Temp->PciDev == PciDev) {\r
1479       *Mem32Bridge = Temp;\r
1480     }\r
1481 \r
1482     CurrentLink = CurrentLink->ForwardLink;\r
1483   }\r
1484 \r
1485   //\r
1486   // Get Pmem32 resource map\r
1487   //\r
1488   CurrentLink = PMem32Pool->ChildList.ForwardLink;\r
1489 \r
1490   while (CurrentLink != &PMem32Pool->ChildList) {\r
1491 \r
1492     Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);\r
1493 \r
1494     if (Temp->PciDev == PciDev) {\r
1495       *PMem32Bridge = Temp;\r
1496     }\r
1497 \r
1498     CurrentLink = CurrentLink->ForwardLink;\r
1499   }\r
1500 \r
1501   //\r
1502   // Get Mem64 resource map\r
1503   //\r
1504   CurrentLink = Mem64Pool->ChildList.ForwardLink;\r
1505 \r
1506   while (CurrentLink != &Mem64Pool->ChildList) {\r
1507 \r
1508     Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);\r
1509 \r
1510     if (Temp->PciDev == PciDev) {\r
1511       *Mem64Bridge = Temp;\r
1512     }\r
1513 \r
1514     CurrentLink = CurrentLink->ForwardLink;\r
1515   }\r
1516 \r
1517   //\r
1518   // Get Pmem64 resource map\r
1519   //\r
1520   CurrentLink = PMem64Pool->ChildList.ForwardLink;\r
1521 \r
1522   while (CurrentLink != &PMem64Pool->ChildList) {\r
1523 \r
1524     Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);\r
1525 \r
1526     if (Temp->PciDev == PciDev) {\r
1527       *PMem64Bridge = Temp;\r
1528     }\r
1529 \r
1530     CurrentLink = CurrentLink->ForwardLink;\r
1531   }\r
1532 \r
1533   return EFI_SUCCESS;\r
1534 }\r
1535 \r
1536 /**\r
1537   Destory given resource tree\r
1538   \r
1539   @param Bridge  root node of resource tree\r
1540   \r
1541   @retval EFI_SUCCESS Success\r
1542 **/\r
1543 EFI_STATUS\r
1544 DestroyResourceTree (\r
1545   IN PCI_RESOURCE_NODE *Bridge\r
1546   )\r
1547 {\r
1548   PCI_RESOURCE_NODE *Temp;\r
1549   LIST_ENTRY        *CurrentLink;\r
1550 \r
1551   while (!IsListEmpty (&Bridge->ChildList)) {\r
1552 \r
1553     CurrentLink = Bridge->ChildList.ForwardLink;\r
1554 \r
1555     Temp        = RESOURCE_NODE_FROM_LINK (CurrentLink);\r
1556 \r
1557     RemoveEntryList (CurrentLink);\r
1558 \r
1559     if (IS_PCI_BRIDGE (&(Temp->PciDev->Pci))) {\r
1560       DestroyResourceTree (Temp);\r
1561     }\r
1562 \r
1563     gBS->FreePool (Temp);\r
1564   }\r
1565 \r
1566   return EFI_SUCCESS;\r
1567 }\r
1568 \r
1569 /**\r
1570   Record the reserved resource and insert to reserved list.\r
1571   \r
1572   @param Base     Base address of reserved resourse\r
1573   @param Length   Length of reserved resource \r
1574   @param ResType  Resource type\r
1575   @param Bridge   Pci device instance\r
1576 **/\r
1577 EFI_STATUS\r
1578 RecordReservedResource (\r
1579   IN UINT64         Base,\r
1580   IN UINT64         Length,\r
1581   IN PCI_BAR_TYPE   ResType,\r
1582   IN PCI_IO_DEVICE  *Bridge\r
1583   )\r
1584 {\r
1585   PCI_RESERVED_RESOURCE_LIST  *ReservedNode;\r
1586 \r
1587   ReservedNode = AllocatePool (sizeof (PCI_RESERVED_RESOURCE_LIST));\r
1588   if (ReservedNode == NULL) {\r
1589     return EFI_OUT_OF_RESOURCES;\r
1590   }\r
1591 \r
1592   ReservedNode->Signature     = RESERVED_RESOURCE_SIGNATURE;\r
1593   ReservedNode->Node.Base     = Base;\r
1594   ReservedNode->Node.Length   = Length;\r
1595   ReservedNode->Node.ResType  = ResType;\r
1596 \r
1597   InsertTailList (&Bridge->ReservedResourceList, &(ReservedNode->Link));\r
1598 \r
1599   return EFI_SUCCESS;\r
1600 }\r
1601 \r
1602 /**\r
1603   Insert resource padding for P2C\r
1604   \r
1605   @param PciDev     Pci device instance\r
1606   @param IoNode     Resource info node for IO \r
1607   @param Mem32Node  Resource info node for 32-bit memory\r
1608   @param PMem32Node Resource info node for 32-bit PMemory\r
1609   @param Mem64Node  Resource info node for 64-bit memory\r
1610   @param PMem64Node Resource info node for 64-bit PMemory\r
1611   \r
1612   @retval EFI_SUCCESS Success\r
1613 **/\r
1614 EFI_STATUS\r
1615 ResourcePaddingForCardBusBridge (\r
1616   PCI_IO_DEVICE     *PciDev,\r
1617   PCI_RESOURCE_NODE *IoNode,\r
1618   PCI_RESOURCE_NODE *Mem32Node,\r
1619   PCI_RESOURCE_NODE *PMem32Node,\r
1620   PCI_RESOURCE_NODE *Mem64Node,\r
1621   PCI_RESOURCE_NODE *PMem64Node\r
1622   )\r
1623 {\r
1624   PCI_RESOURCE_NODE *Node;\r
1625 \r
1626   Node = NULL;\r
1627 \r
1628   //\r
1629   // Memory Base/Limit Register 0\r
1630   // Bar 1 denodes memory range 0\r
1631   //\r
1632   Node = CreateResourceNode (\r
1633           PciDev,\r
1634           0x2000000,\r
1635           0x1ffffff,\r
1636           1,\r
1637           PciBarTypeMem32,\r
1638           PciResUsagePadding\r
1639           );\r
1640 \r
1641   InsertResourceNode (\r
1642     Mem32Node,\r
1643     Node\r
1644     );\r
1645 \r
1646   //\r
1647   // Memory Base/Limit Register 1\r
1648   // Bar 2 denodes memory range1\r
1649   //\r
1650   Node = CreateResourceNode (\r
1651           PciDev,\r
1652           0x2000000,\r
1653           0x1ffffff,\r
1654           2,\r
1655           PciBarTypePMem32,\r
1656           PciResUsagePadding\r
1657           );\r
1658 \r
1659   InsertResourceNode (\r
1660     PMem32Node,\r
1661     Node\r
1662     );\r
1663 \r
1664   //\r
1665   // Io Base/Limit\r
1666   // Bar 3 denodes io range 0\r
1667   //\r
1668   Node = CreateResourceNode (\r
1669           PciDev,\r
1670           0x100,\r
1671           0xff,\r
1672           3,\r
1673           PciBarTypeIo16,\r
1674           PciResUsagePadding\r
1675           );\r
1676 \r
1677   InsertResourceNode (\r
1678     IoNode,\r
1679     Node\r
1680     );\r
1681 \r
1682   //\r
1683   // Io Base/Limit\r
1684   // Bar 4 denodes io range 0\r
1685   //\r
1686   Node = CreateResourceNode (\r
1687           PciDev,\r
1688           0x100,\r
1689           0xff,\r
1690           4,\r
1691           PciBarTypeIo16,\r
1692           PciResUsagePadding\r
1693           );\r
1694 \r
1695   InsertResourceNode (\r
1696     IoNode,\r
1697     Node\r
1698     );\r
1699 \r
1700   return EFI_SUCCESS;\r
1701 }\r
1702 \r
1703 /**\r
1704   Program P2C register for given resource node\r
1705   \r
1706   @param Base    Base address of P2C device\r
1707   @param Node    Given resource node.\r
1708   \r
1709   @retval EFI_SUCCESS Success\r
1710 **/\r
1711 EFI_STATUS\r
1712 ProgramP2C (\r
1713   IN UINT64            Base,\r
1714   IN PCI_RESOURCE_NODE *Node\r
1715   )\r
1716 {\r
1717   EFI_PCI_IO_PROTOCOL *PciIo;\r
1718   UINT64              Address;\r
1719   UINT64              TempAddress;\r
1720   UINT16              BridgeControl;\r
1721 \r
1722   Address = 0;\r
1723   PciIo   = &(Node->PciDev->PciIo);\r
1724 \r
1725   Address = Base + Node->Offset;\r
1726 \r
1727   //\r
1728   // Indicate pci bus driver has allocated\r
1729   // resource for this device\r
1730   // It might be a temporary solution here since\r
1731   // pci device could have multiple bar\r
1732   //\r
1733   Node->PciDev->Allocated = TRUE;\r
1734 \r
1735   switch (Node->Bar) {\r
1736 \r
1737   case P2C_BAR_0:\r
1738     PciIoWrite (\r
1739                 PciIo,\r
1740                 EfiPciIoWidthUint32,\r
1741                 (Node->PciDev->PciBar[Node->Bar]).Offset,\r
1742                 1,\r
1743                 &Address\r
1744                 );\r
1745 \r
1746     Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;\r
1747     Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;\r
1748     break;\r
1749 \r
1750   case P2C_MEM_1:\r
1751     PciIoWrite (\r
1752                 PciIo,\r
1753                 EfiPciIoWidthUint32,\r
1754                 0x1c,\r
1755                 1,\r
1756                 &Address\r
1757                 );\r
1758 \r
1759     TempAddress = Address + Node->Length - 1;\r
1760     PciIoWrite (\r
1761                 PciIo,\r
1762                 EfiPciIoWidthUint32,\r
1763                 0x20,\r
1764                 1,\r
1765                 &TempAddress\r
1766                 );\r
1767 \r
1768     if (Node->ResType == PciBarTypeMem32) {\r
1769 \r
1770       //\r
1771       // Set non-prefetchable bit\r
1772       //\r
1773       PciIoRead (\r
1774                   PciIo,\r
1775                   EfiPciIoWidthUint16,\r
1776                   0x3e,\r
1777                   1,\r
1778                   &BridgeControl\r
1779                   );\r
1780 \r
1781       BridgeControl &= 0xfeff;\r
1782       PciIoWrite (\r
1783                   PciIo,\r
1784                   EfiPciIoWidthUint16,\r
1785                   0x3e,\r
1786                   1,\r
1787                   &BridgeControl\r
1788                   );\r
1789 \r
1790     } else {\r
1791 \r
1792       //\r
1793       // Set pre-fetchable bit\r
1794       //\r
1795       PciIoRead (\r
1796                   PciIo,\r
1797                   EfiPciIoWidthUint16,\r
1798                   0x3e,\r
1799                   1,\r
1800                   &BridgeControl\r
1801                   );\r
1802 \r
1803       BridgeControl |= 0x0100;\r
1804       PciIoWrite (\r
1805                   PciIo,\r
1806                   EfiPciIoWidthUint16,\r
1807                   0x3e,\r
1808                   1,\r
1809                   &BridgeControl\r
1810                   );\r
1811     }\r
1812 \r
1813     Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;\r
1814     Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;\r
1815     Node->PciDev->PciBar[Node->Bar].BarType     = Node->ResType;\r
1816 \r
1817     break;\r
1818 \r
1819   case P2C_MEM_2:\r
1820     PciIoWrite (\r
1821                 PciIo,\r
1822                 EfiPciIoWidthUint32,\r
1823                 0x24,\r
1824                 1,\r
1825                 &Address\r
1826                 );\r
1827 \r
1828     TempAddress = Address + Node->Length - 1;\r
1829 \r
1830     PciIoWrite (\r
1831                 PciIo,\r
1832                 EfiPciIoWidthUint32,\r
1833                 0x28,\r
1834                 1,\r
1835                 &TempAddress\r
1836                 );\r
1837 \r
1838     if (Node->ResType == PciBarTypeMem32) {\r
1839 \r
1840       //\r
1841       // Set non-prefetchable bit\r
1842       //\r
1843       PciIoRead (\r
1844                   PciIo,\r
1845                   EfiPciIoWidthUint16,\r
1846                   0x3e,\r
1847                   1,\r
1848                   &BridgeControl\r
1849                   );\r
1850 \r
1851       BridgeControl &= 0xfdff;\r
1852       PciIoWrite (\r
1853                   PciIo,\r
1854                   EfiPciIoWidthUint16,\r
1855                   0x3e,\r
1856                   1,\r
1857                   &BridgeControl\r
1858                   );\r
1859     } else {\r
1860 \r
1861       //\r
1862       // Set pre-fetchable bit\r
1863       //\r
1864       PciIoRead (\r
1865                   PciIo,\r
1866                   EfiPciIoWidthUint16,\r
1867                   0x3e,\r
1868                   1,\r
1869                   &BridgeControl\r
1870                   );\r
1871 \r
1872       BridgeControl |= 0x0200;\r
1873       PciIoWrite (\r
1874                   PciIo,\r
1875                   EfiPciIoWidthUint16,\r
1876                   0x3e,\r
1877                   1,\r
1878                   &BridgeControl\r
1879                   );\r
1880     }\r
1881 \r
1882     Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;\r
1883     Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;\r
1884     Node->PciDev->PciBar[Node->Bar].BarType     = Node->ResType;\r
1885     break;\r
1886 \r
1887   case P2C_IO_1:\r
1888     PciIoWrite (\r
1889                 PciIo,\r
1890                 EfiPciIoWidthUint32,\r
1891                 0x2c,\r
1892                 1,\r
1893                 &Address\r
1894                 );\r
1895     TempAddress = Address + Node->Length - 1;\r
1896     PciIoWrite (\r
1897                 PciIo,\r
1898                 EfiPciIoWidthUint32,\r
1899                 0x30,\r
1900                 1,\r
1901                 &TempAddress\r
1902                 );\r
1903 \r
1904     Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;\r
1905     Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;\r
1906     Node->PciDev->PciBar[Node->Bar].BarType     = Node->ResType;\r
1907 \r
1908     break;\r
1909 \r
1910   case P2C_IO_2:\r
1911     PciIoWrite (\r
1912                 PciIo,\r
1913                 EfiPciIoWidthUint32,\r
1914                 0x34,\r
1915                 1,\r
1916                 &Address\r
1917                 );\r
1918 \r
1919     TempAddress = Address + Node->Length - 1;\r
1920     PciIoWrite (\r
1921                 PciIo,\r
1922                 EfiPciIoWidthUint32,\r
1923                 0x38,\r
1924                 1,\r
1925                 &TempAddress\r
1926                 );\r
1927 \r
1928     Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;\r
1929     Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;\r
1930     Node->PciDev->PciBar[Node->Bar].BarType     = Node->ResType;\r
1931     break;\r
1932 \r
1933   default:\r
1934     break;\r
1935   }\r
1936 \r
1937   return EFI_SUCCESS;\r
1938 }\r
1939 \r
1940 /**\r
1941   Create padding resource node.\r
1942   \r
1943   @param PciDev     Pci device instance\r
1944   @param IoNode     Resource info node for IO \r
1945   @param Mem32Node  Resource info node for 32-bit memory\r
1946   @param PMem32Node Resource info node for 32-bit PMemory\r
1947   @param Mem64Node  Resource info node for 64-bit memory\r
1948   @param PMem64Node Resource info node for 64-bit PMemory\r
1949   \r
1950   @retval EFI_SUCCESS Success\r
1951 \r
1952 **/\r
1953 EFI_STATUS\r
1954 ApplyResourcePadding (\r
1955   PCI_IO_DEVICE     *PciDev,\r
1956   PCI_RESOURCE_NODE *IoNode,\r
1957   PCI_RESOURCE_NODE *Mem32Node,\r
1958   PCI_RESOURCE_NODE *PMem32Node,\r
1959   PCI_RESOURCE_NODE *Mem64Node,\r
1960   PCI_RESOURCE_NODE *PMem64Node\r
1961   )\r
1962 {\r
1963   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;\r
1964   PCI_RESOURCE_NODE                 *Node;\r
1965   UINT8                             DummyBarIndex;\r
1966 \r
1967   DummyBarIndex = 0;\r
1968   Ptr           = PciDev->ResourcePaddingDescriptors;\r
1969 \r
1970   while (((EFI_ACPI_END_TAG_DESCRIPTOR *) Ptr)->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
1971 \r
1972     if (Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Ptr->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) {\r
1973       if (Ptr->AddrLen != 0) {\r
1974 \r
1975         Node = CreateResourceNode (\r
1976                 PciDev,\r
1977                 Ptr->AddrLen,\r
1978                 Ptr->AddrRangeMax,\r
1979                 DummyBarIndex,\r
1980                 PciBarTypeIo16,\r
1981                 PciResUsagePadding\r
1982                 );\r
1983         InsertResourceNode (\r
1984           IoNode,\r
1985           Node\r
1986           );\r
1987       }\r
1988 \r
1989       Ptr++;\r
1990       continue;\r
1991     }\r
1992 \r
1993     if (Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Ptr->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {\r
1994 \r
1995       if (Ptr->AddrSpaceGranularity == 32) {\r
1996 \r
1997         //\r
1998         // prefechable\r
1999         //\r
2000         if (Ptr->SpecificFlag == 0x6) {\r
2001           if (Ptr->AddrLen) {\r
2002             Node = CreateResourceNode (\r
2003                     PciDev,\r
2004                     Ptr->AddrLen,\r
2005                     Ptr->AddrRangeMax,\r
2006                     DummyBarIndex,\r
2007                     PciBarTypePMem32,\r
2008                     PciResUsagePadding\r
2009                     );\r
2010             InsertResourceNode (\r
2011               PMem32Node,\r
2012               Node\r
2013               );\r
2014           }\r
2015 \r
2016           Ptr++;\r
2017           continue;\r
2018         }\r
2019 \r
2020         //\r
2021         // Non-prefechable\r
2022         //\r
2023         if (Ptr->SpecificFlag == 0) {\r
2024           if (Ptr->AddrLen) {\r
2025             Node = CreateResourceNode (\r
2026                     PciDev,\r
2027                     Ptr->AddrLen,\r
2028                     Ptr->AddrRangeMax,\r
2029                     DummyBarIndex,\r
2030                     PciBarTypeMem32,\r
2031                     PciResUsagePadding\r
2032                     );\r
2033             InsertResourceNode (\r
2034               Mem32Node,\r
2035               Node\r
2036               );\r
2037           }\r
2038 \r
2039           Ptr++;\r
2040           continue;\r
2041         }\r
2042       }\r
2043 \r
2044       if (Ptr->AddrSpaceGranularity == 64) {\r
2045 \r
2046         //\r
2047         // prefechable\r
2048         //\r
2049         if (Ptr->SpecificFlag == 0x6) {\r
2050           if (Ptr->AddrLen) {\r
2051             Node = CreateResourceNode (\r
2052                     PciDev,\r
2053                     Ptr->AddrLen,\r
2054                     Ptr->AddrRangeMax,\r
2055                     DummyBarIndex,\r
2056                     PciBarTypePMem64,\r
2057                     PciResUsagePadding\r
2058                     );\r
2059             InsertResourceNode (\r
2060               PMem64Node,\r
2061               Node\r
2062               );\r
2063           }\r
2064 \r
2065           Ptr++;\r
2066           continue;\r
2067         }\r
2068 \r
2069         //\r
2070         // Non-prefechable\r
2071         //\r
2072         if (Ptr->SpecificFlag == 0) {\r
2073           if (Ptr->AddrLen) {\r
2074             Node = CreateResourceNode (\r
2075                     PciDev,\r
2076                     Ptr->AddrLen,\r
2077                     Ptr->AddrRangeMax,\r
2078                     DummyBarIndex,\r
2079                     PciBarTypeMem64,\r
2080                     PciResUsagePadding\r
2081                     );\r
2082             InsertResourceNode (\r
2083               Mem64Node,\r
2084               Node\r
2085               );\r
2086           }\r
2087 \r
2088           Ptr++;\r
2089           continue;\r
2090         }\r
2091       }\r
2092     }\r
2093 \r
2094     Ptr++;\r
2095   }\r
2096 \r
2097   return EFI_SUCCESS;\r
2098 }\r
2099 \r
2100 /**\r
2101   Get padding resource for PPB\r
2102   Light PCI bus driver woundn't support hotplug root device\r
2103   So no need to pad resource for them\r
2104 \r
2105   @param   PciIoDevice Pci device instance\r
2106 **/\r
2107 VOID\r
2108 GetResourcePaddingPpb (\r
2109   IN  PCI_IO_DEVICE                  *PciIoDevice\r
2110   )\r
2111 {\r
2112   if (gPciHotPlugInit) {\r
2113     if (PciIoDevice->ResourcePaddingDescriptors == NULL) {\r
2114       GetResourcePaddingForHpb (PciIoDevice);\r
2115     }\r
2116   }\r
2117 }\r
2118 \r