1 /*++
2 
3 Copyright (c) 2005 - 2014, 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 
14   PciIo.c
15 
16 Abstract:
17 
18   PCI I/O Abstraction Driver
19 
20 Revision History
21 
22 --*/
23 
24 #include "PciBus.h"
25 
26 //
27 // PCI I/O Support Function Prototypes
28 //
29 //
30 
31 BOOLEAN
32 PciDevicesOnTheSamePath (
33   IN PCI_IO_DEVICE       *PciDevice1,
34   IN PCI_IO_DEVICE       *PciDevice2
35 );
36 
37 
38 EFI_STATUS
39 UpStreamBridgesAttributes (
40   IN  PCI_IO_DEVICE                            *PciIoDevice,
41   IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
42   IN  UINT64                                   Attributes
43 );
44 
45 
46 BOOLEAN
47 CheckBarType (
48   IN PCI_IO_DEVICE  *PciIoDevice,
49   UINT8             BarIndex,
50   PCI_BAR_TYPE      BarType
51 );
52 
53 
54 EFI_STATUS
55 SetBootVGA (
56   IN  PCI_IO_DEVICE                  *PciIoDevice
57 );
58 
59 EFI_STATUS
60 DisableBootVGA (
61   IN  PCI_IO_DEVICE                  *PciIoDevice
62 );
63 
64 
65 EFI_STATUS
66 PciIoVerifyBarAccess (
67   PCI_IO_DEVICE                 *PciIoDevice,
68   UINT8                         BarIndex,
69   PCI_BAR_TYPE                  Type,
70   IN EFI_PCI_IO_PROTOCOL_WIDTH  Width,
71   IN UINTN                      Count,
72   UINT64                        *Offset
73 );
74 
75 EFI_STATUS
76 PciIoVerifyConfigAccess (
77   PCI_IO_DEVICE                 *PciIoDevice,
78   IN EFI_PCI_IO_PROTOCOL_WIDTH  Width,
79   IN UINTN                      Count,
80   IN UINT64                     *Offset
81 );
82 
83 EFI_STATUS
84 EFIAPI
85 PciIoPollMem (
86   IN  EFI_PCI_IO_PROTOCOL        *This,
87   IN  EFI_PCI_IO_PROTOCOL_WIDTH  Width,
88   IN  UINT8                      BarIndex,
89   IN  UINT64                     Offset,
90   IN  UINT64                     Mask,
91   IN  UINT64                     Value,
92   IN  UINT64                     Delay,
93   OUT UINT64                     *Result
94 );
95 
96 EFI_STATUS
97 EFIAPI
98 PciIoPollIo (
99   IN  EFI_PCI_IO_PROTOCOL        *This,
100   IN  EFI_PCI_IO_PROTOCOL_WIDTH  Width,
101   IN  UINT8                      BarIndex,
102   IN  UINT64                     Offset,
103   IN  UINT64                     Mask,
104   IN  UINT64                     Value,
105   IN  UINT64                     Delay,
106   OUT UINT64                     *Result
107 );
108 
109 EFI_STATUS
110 EFIAPI
111 PciIoMemRead (
112   IN     EFI_PCI_IO_PROTOCOL        *This,
113   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
114   IN     UINT8                      BarIndex,
115   IN     UINT64                     Offset,
116   IN     UINTN                      Count,
117   IN OUT VOID                       *Buffer
118 );
119 
120 EFI_STATUS
121 EFIAPI
122 PciIoMemWrite (
123   IN     EFI_PCI_IO_PROTOCOL        *This,
124   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
125   IN     UINT8                      BarIndex,
126   IN     UINT64                     Offset,
127   IN     UINTN                      Count,
128   IN OUT VOID                       *Buffer
129 );
130 
131 EFI_STATUS
132 EFIAPI
133 PciIoIoRead (
134   IN     EFI_PCI_IO_PROTOCOL        *This,
135   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
136   IN     UINT8                      BarIndex,
137   IN     UINT64                     Offset,
138   IN     UINTN                      Count,
139   IN OUT VOID                       *Buffer
140 );
141 
142 EFI_STATUS
143 EFIAPI
144 PciIoIoWrite (
145   IN     EFI_PCI_IO_PROTOCOL        *This,
146   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
147   IN     UINT8                      BarIndex,
148   IN     UINT64                     Offset,
149   IN     UINTN                      Count,
150   IN OUT VOID                       *Buffer
151 );
152 
153 EFI_STATUS
154 EFIAPI
155 PciIoConfigRead (
156   IN     EFI_PCI_IO_PROTOCOL        *This,
157   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
158   IN     UINT32                     Offset,
159   IN     UINTN                      Count,
160   IN OUT VOID                       *Buffer
161 );
162 
163 EFI_STATUS
164 EFIAPI
165 PciIoConfigWrite (
166   IN     EFI_PCI_IO_PROTOCOL        *This,
167   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
168   IN     UINT32                     Offset,
169   IN     UINTN                      Count,
170   IN OUT VOID                       *Buffer
171 );
172 
173 EFI_STATUS
174 EFIAPI
175 PciIoCopyMem (
176   IN     EFI_PCI_IO_PROTOCOL  *This,
177   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
178   IN     UINT8                        DestBarIndex,
179   IN     UINT64                       DestOffset,
180   IN     UINT8                        SrcBarIndex,
181   IN     UINT64                       SrcOffset,
182   IN     UINTN                        Count
183 );
184 
185 EFI_STATUS
186 EFIAPI
187 PciIoMap (
188   IN     EFI_PCI_IO_PROTOCOL            *This,
189   IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,
190   IN     VOID                           *HostAddress,
191   IN OUT UINTN                          *NumberOfBytes,
192   OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
193   OUT    VOID                           **Mapping
194 );
195 
196 EFI_STATUS
197 EFIAPI
198 PciIoUnmap (
199   IN  EFI_PCI_IO_PROTOCOL  *This,
200   IN  VOID                 *Mapping
201 );
202 
203 EFI_STATUS
204 EFIAPI
205 PciIoAllocateBuffer (
206   IN  EFI_PCI_IO_PROTOCOL    *This,
207   IN  EFI_ALLOCATE_TYPE      Type,
208   IN  EFI_MEMORY_TYPE        MemoryType,
209   IN  UINTN                  Pages,
210   OUT VOID                   **HostAddress,
211   IN  UINT64                 Attributes
212 );
213 
214 EFI_STATUS
215 EFIAPI
216 PciIoFreeBuffer (
217   IN  EFI_PCI_IO_PROTOCOL   *This,
218   IN  UINTN                 Pages,
219   IN  VOID                  *HostAddress
220   );
221 
222 EFI_STATUS
223 EFIAPI
224 PciIoFlush (
225   IN  EFI_PCI_IO_PROTOCOL  *This
226   );
227 
228 EFI_STATUS
229 EFIAPI
230 PciIoGetLocation (
231   IN  EFI_PCI_IO_PROTOCOL  *This,
232   OUT UINTN                *Segment,
233   OUT UINTN                *Bus,
234   OUT UINTN                *Device,
235   OUT UINTN                *Function
236   );
237 
238 EFI_STATUS
239 EFIAPI
240 PciIoAttributes (
241   IN  EFI_PCI_IO_PROTOCOL              *This,
242   IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
243   IN  UINT64                                   Attributes,
244   OUT UINT64                                   *Result   OPTIONAL
245   );
246 
247 EFI_STATUS
248 EFIAPI
249 PciIoGetBarAttributes(
250   IN  EFI_PCI_IO_PROTOCOL    *This,
251   IN  UINT8                          BarIndex,
252   OUT UINT64                         *Supports,   OPTIONAL
253   OUT VOID                           **Resources  OPTIONAL
254   );
255 
256 EFI_STATUS
257 EFIAPI
258 PciIoSetBarAttributes(
259   IN     EFI_PCI_IO_PROTOCOL  *This,
260   IN     UINT64                       Attributes,
261   IN     UINT8                        BarIndex,
262   IN OUT UINT64                       *Offset,
263   IN OUT UINT64                       *Length
264   );
265 
266 
267 //
268 // Pci Io Protocol Interface
269 //
270 EFI_PCI_IO_PROTOCOL  PciIoInterface = {
271   PciIoPollMem,
272   PciIoPollIo,
273   {
274     PciIoMemRead,
275     PciIoMemWrite
276   },
277   {
278     PciIoIoRead,
279     PciIoIoWrite
280   },
281   {
282     PciIoConfigRead,
283     PciIoConfigWrite
284   },
285   PciIoCopyMem,
286   PciIoMap,
287   PciIoUnmap,
288   PciIoAllocateBuffer,
289   PciIoFreeBuffer,
290   PciIoFlush,
291   PciIoGetLocation,
292   PciIoAttributes,
293   PciIoGetBarAttributes,
294   PciIoSetBarAttributes,
295   0,
296   NULL
297 };
298 
299 
300 EFI_STATUS
InitializePciIoInstance(PCI_IO_DEVICE * PciIoDevice)301 InitializePciIoInstance (
302   PCI_IO_DEVICE  *PciIoDevice
303   )
304 /*++
305 
306 Routine Description:
307 
308   Initializes a PCI I/O Instance
309 
310 Arguments:
311 
312 Returns:
313 
314   None
315 
316 --*/
317 
318 {
319   CopyMem (&PciIoDevice->PciIo, &PciIoInterface, sizeof (EFI_PCI_IO_PROTOCOL));
320   return EFI_SUCCESS;
321 }
322 
323 EFI_STATUS
PciIoVerifyBarAccess(PCI_IO_DEVICE * PciIoDevice,UINT8 BarIndex,PCI_BAR_TYPE Type,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINTN Count,UINT64 * Offset)324 PciIoVerifyBarAccess (
325   PCI_IO_DEVICE                   *PciIoDevice,
326   UINT8                           BarIndex,
327   PCI_BAR_TYPE                    Type,
328   IN EFI_PCI_IO_PROTOCOL_WIDTH    Width,
329   IN UINTN                        Count,
330   UINT64                          *Offset
331   )
332 /*++
333 
334 Routine Description:
335 
336   Verifies access to a PCI Base Address Register (BAR)
337 
338 Arguments:
339 
340 Returns:
341 
342   None
343 
344 --*/
345 {
346   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
347     return EFI_INVALID_PARAMETER;
348   }
349 
350   if (BarIndex == EFI_PCI_IO_PASS_THROUGH_BAR) {
351     return EFI_SUCCESS;
352   }
353 
354   //
355   // BarIndex 0-5 is legal
356   //
357   if (BarIndex >= PCI_MAX_BAR) {
358     return EFI_INVALID_PARAMETER;
359   }
360 
361   if (!CheckBarType (PciIoDevice, BarIndex, Type)) {
362     return EFI_INVALID_PARAMETER;
363   }
364 
365   //
366   // If Width is EfiPciIoWidthFifoUintX then convert to EfiPciIoWidthUintX
367   // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX
368   //
369   if (Width >= EfiPciIoWidthFifoUint8 && Width <= EfiPciIoWidthFifoUint64) {
370     Count = 1;
371   }
372 
373   Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03);
374 
375   if ((*Offset + Count * ((UINTN)1 << Width)) - 1 >= PciIoDevice->PciBar[BarIndex].Length) {
376     return EFI_INVALID_PARAMETER;
377   }
378 
379   *Offset = *Offset + PciIoDevice->PciBar[BarIndex].BaseAddress;
380 
381   return EFI_SUCCESS;
382 }
383 
384 EFI_STATUS
PciIoVerifyConfigAccess(PCI_IO_DEVICE * PciIoDevice,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINTN Count,IN UINT64 * Offset)385 PciIoVerifyConfigAccess (
386   PCI_IO_DEVICE                 *PciIoDevice,
387   IN EFI_PCI_IO_PROTOCOL_WIDTH  Width,
388   IN UINTN                      Count,
389   IN UINT64                     *Offset
390   )
391 /*++
392 
393 Routine Description:
394 
395   Verifies access to a PCI Config Header
396 
397 Arguments:
398 
399 Returns:
400 
401   None
402 
403 --*/
404 {
405   UINT64  ExtendOffset;
406 
407   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
408     return EFI_INVALID_PARAMETER;
409   }
410 
411   //
412   // If Width is EfiPciIoWidthFifoUintX then convert to EfiPciIoWidthUintX
413   // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX
414   //
415   Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03);
416 
417   if (PciIoDevice->IsPciExp) {
418     if ((*Offset + Count * ((UINTN)1 << Width)) - 1 >= PCI_EXP_MAX_CONFIG_OFFSET) {
419       return EFI_UNSUPPORTED;
420     }
421 
422     ExtendOffset  = LShiftU64 (*Offset, 32);
423     *Offset       = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, 0);
424     *Offset       = (*Offset) | ExtendOffset;
425 
426   } else {
427     if ((*Offset + Count * ((UINTN)1 << Width)) - 1 >= PCI_MAX_CONFIG_OFFSET) {
428       return EFI_UNSUPPORTED;
429     }
430 
431     *Offset = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, *Offset);
432   }
433 
434   return EFI_SUCCESS;
435 }
436 
437 EFI_STATUS
438 EFIAPI
PciIoPollMem(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINT64 Mask,IN UINT64 Value,IN UINT64 Delay,OUT UINT64 * Result)439 PciIoPollMem (
440   IN  EFI_PCI_IO_PROTOCOL        *This,
441   IN  EFI_PCI_IO_PROTOCOL_WIDTH  Width,
442   IN  UINT8                      BarIndex,
443   IN  UINT64                     Offset,
444   IN  UINT64                     Mask,
445   IN  UINT64                     Value,
446   IN  UINT64                     Delay,
447   OUT UINT64                     *Result
448   )
449 /*++
450 
451 Routine Description:
452 
453   Poll PCI Memmory
454 
455 Arguments:
456 
457 Returns:
458 
459   None
460 
461 --*/
462 {
463   EFI_STATUS    Status;
464   PCI_IO_DEVICE *PciIoDevice;
465 
466   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
467 
468   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
469     return EFI_INVALID_PARAMETER;
470   }
471 
472   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, 1, &Offset);
473   if (EFI_ERROR (Status)) {
474     return EFI_UNSUPPORTED;
475   }
476 
477   if (Width > EfiPciIoWidthUint64) {
478     return EFI_INVALID_PARAMETER;
479   }
480 
481   Status = PciIoDevice->PciRootBridgeIo->PollMem (
482                                           PciIoDevice->PciRootBridgeIo,
483                                           (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
484                                           Offset,
485                                           Mask,
486                                           Value,
487                                           Delay,
488                                           Result
489                                           );
490   return Status;
491 }
492 
493 EFI_STATUS
494 EFIAPI
PciIoPollIo(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINT64 Mask,IN UINT64 Value,IN UINT64 Delay,OUT UINT64 * Result)495 PciIoPollIo (
496   IN  EFI_PCI_IO_PROTOCOL        *This,
497   IN  EFI_PCI_IO_PROTOCOL_WIDTH  Width,
498   IN  UINT8                      BarIndex,
499   IN  UINT64                     Offset,
500   IN  UINT64                     Mask,
501   IN  UINT64                     Value,
502   IN  UINT64                     Delay,
503   OUT UINT64                     *Result
504   )
505 /*++
506 
507 Routine Description:
508 
509   Poll PCI IO
510 
511 Arguments:
512 
513 Returns:
514 
515   None
516 
517 --*/
518 {
519   EFI_STATUS    Status;
520   PCI_IO_DEVICE *PciIoDevice;
521 
522   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
523 
524   if ((UINT32)Width > EfiPciIoWidthUint64) {
525     return EFI_INVALID_PARAMETER;
526   }
527 
528   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, 1, &Offset);
529   if (EFI_ERROR (Status)) {
530     return EFI_UNSUPPORTED;
531   }
532 
533   Status = PciIoDevice->PciRootBridgeIo->PollIo (
534                                           PciIoDevice->PciRootBridgeIo,
535                                           (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
536                                           Offset,
537                                           Mask,
538                                           Value,
539                                           Delay,
540                                           Result
541                                           );
542 
543   return Status;
544 }
545 
546 EFI_STATUS
547 EFIAPI
PciIoMemRead(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINTN Count,IN OUT VOID * Buffer)548 PciIoMemRead (
549   IN     EFI_PCI_IO_PROTOCOL        *This,
550   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
551   IN     UINT8                      BarIndex,
552   IN     UINT64                     Offset,
553   IN     UINTN                      Count,
554   IN OUT VOID                       *Buffer
555   )
556 /*++
557 
558 Routine Description:
559 
560   Performs a PCI Memory Read Cycle
561 
562 Arguments:
563 
564 Returns:
565 
566   None
567 
568 --*/
569 {
570   EFI_STATUS    Status;
571   PCI_IO_DEVICE *PciIoDevice;
572 
573   if (Buffer == NULL){
574     return EFI_INVALID_PARAMETER;
575   }
576 
577   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
578 
579   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
580     return EFI_INVALID_PARAMETER;
581   }
582 
583   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset);
584   if (EFI_ERROR (Status)) {
585     return EFI_UNSUPPORTED;
586   }
587 
588   Status = PciIoDevice->PciRootBridgeIo->Mem.Read (
589                                               PciIoDevice->PciRootBridgeIo,
590                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
591                                               Offset,
592                                               Count,
593                                               Buffer
594                                               );
595 
596   return Status;
597 }
598 
599 EFI_STATUS
600 EFIAPI
PciIoMemWrite(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINTN Count,IN OUT VOID * Buffer)601 PciIoMemWrite (
602   IN     EFI_PCI_IO_PROTOCOL        *This,
603   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
604   IN     UINT8                      BarIndex,
605   IN     UINT64                     Offset,
606   IN     UINTN                      Count,
607   IN OUT VOID                       *Buffer
608   )
609 /*++
610 
611 Routine Description:
612 
613   Performs a PCI Memory Write Cycle
614 
615 Arguments:
616 
617 Returns:
618 
619   None
620 
621 --*/
622 {
623   EFI_STATUS    Status;
624   PCI_IO_DEVICE *PciIoDevice;
625 
626   if (Buffer == NULL){
627     return EFI_INVALID_PARAMETER;
628   }
629 
630   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
631 
632   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
633     return EFI_INVALID_PARAMETER;
634   }
635 
636   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset);
637   if (EFI_ERROR (Status)) {
638     return EFI_UNSUPPORTED;
639   }
640 
641   Status = PciIoDevice->PciRootBridgeIo->Mem.Write (
642                                               PciIoDevice->PciRootBridgeIo,
643                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
644                                               Offset,
645                                               Count,
646                                               Buffer
647                                               );
648 
649   return Status;
650 }
651 
652 EFI_STATUS
653 EFIAPI
PciIoIoRead(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINTN Count,IN OUT VOID * Buffer)654 PciIoIoRead (
655   IN     EFI_PCI_IO_PROTOCOL        *This,
656   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
657   IN     UINT8                      BarIndex,
658   IN     UINT64                     Offset,
659   IN     UINTN                      Count,
660   IN OUT VOID                       *Buffer
661   )
662 /*++
663 
664 Routine Description:
665 
666   Performs a PCI I/O Read Cycle
667 
668 Arguments:
669 
670 Returns:
671 
672   None
673 
674 --*/
675 {
676   EFI_STATUS    Status;
677   PCI_IO_DEVICE *PciIoDevice;
678 
679   if (Buffer == NULL){
680     return EFI_INVALID_PARAMETER;
681   }
682 
683   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
684 
685   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
686     return EFI_INVALID_PARAMETER;
687   }
688 
689   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset);
690   if (EFI_ERROR (Status)) {
691     return EFI_UNSUPPORTED;
692   }
693 
694   Status = PciIoDevice->PciRootBridgeIo->Io.Read (
695                                               PciIoDevice->PciRootBridgeIo,
696                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
697                                               Offset,
698                                               Count,
699                                               Buffer
700                                               );
701 
702   return Status;
703 }
704 
705 EFI_STATUS
706 EFIAPI
PciIoIoWrite(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINTN Count,IN OUT VOID * Buffer)707 PciIoIoWrite (
708   IN     EFI_PCI_IO_PROTOCOL        *This,
709   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
710   IN     UINT8                      BarIndex,
711   IN     UINT64                     Offset,
712   IN     UINTN                      Count,
713   IN OUT VOID                       *Buffer
714   )
715 /*++
716 
717 Routine Description:
718 
719   Performs a PCI I/O Write Cycle
720 
721 Arguments:
722 
723 Returns:
724 
725   None
726 
727 --*/
728 {
729   EFI_STATUS    Status;
730   PCI_IO_DEVICE *PciIoDevice;
731 
732   if (Buffer == NULL){
733     return EFI_INVALID_PARAMETER;
734   }
735 
736   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
737 
738   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
739     return EFI_INVALID_PARAMETER;
740   }
741 
742   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset);
743   if (EFI_ERROR (Status)) {
744     return EFI_UNSUPPORTED;
745   }
746 
747   Status = PciIoDevice->PciRootBridgeIo->Io.Write (
748                                               PciIoDevice->PciRootBridgeIo,
749                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
750                                               Offset,
751                                               Count,
752                                               Buffer
753                                               );
754 
755   return Status;
756 }
757 
758 EFI_STATUS
759 EFIAPI
PciIoConfigRead(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT32 Offset,IN UINTN Count,IN OUT VOID * Buffer)760 PciIoConfigRead (
761   IN     EFI_PCI_IO_PROTOCOL        *This,
762   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
763   IN     UINT32                     Offset,
764   IN     UINTN                      Count,
765   IN OUT VOID                       *Buffer
766   )
767 /*++
768 
769 Routine Description:
770 
771   Performs a PCI Configuration Read Cycle
772 
773 Arguments:
774 
775 Returns:
776 
777   None
778 
779 --*/
780 {
781   EFI_STATUS    Status;
782   PCI_IO_DEVICE *PciIoDevice;
783   UINT64        Address;
784 
785   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
786 
787   Address     = Offset;
788   Status      = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);
789   if (EFI_ERROR (Status)) {
790     return Status;
791   }
792 
793   Status = PciIoDevice->PciRootBridgeIo->Pci.Read (
794                                               PciIoDevice->PciRootBridgeIo,
795                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
796                                               Address,
797                                               Count,
798                                               Buffer
799                                               );
800 
801   return Status;
802 }
803 
804 EFI_STATUS
805 EFIAPI
PciIoConfigWrite(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT32 Offset,IN UINTN Count,IN OUT VOID * Buffer)806 PciIoConfigWrite (
807   IN     EFI_PCI_IO_PROTOCOL        *This,
808   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
809   IN     UINT32                     Offset,
810   IN     UINTN                      Count,
811   IN OUT VOID                       *Buffer
812   )
813 /*++
814 
815 Routine Description:
816 
817   Performs a PCI Configuration Write Cycle
818 
819 Arguments:
820 
821 Returns:
822 
823   None
824 
825 --*/
826 {
827   EFI_STATUS    Status;
828   PCI_IO_DEVICE *PciIoDevice;
829   UINT64        Address;
830 
831   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
832 
833   Address     = Offset;
834   Status      = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);
835   if (EFI_ERROR (Status)) {
836     return Status;
837   }
838 
839   Status = PciIoDevice->PciRootBridgeIo->Pci.Write (
840                                               PciIoDevice->PciRootBridgeIo,
841                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
842                                               Address,
843                                               Count,
844                                               Buffer
845                                               );
846 
847   return Status;
848 }
849 
850 EFI_STATUS
851 EFIAPI
PciIoCopyMem(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 DestBarIndex,IN UINT64 DestOffset,IN UINT8 SrcBarIndex,IN UINT64 SrcOffset,IN UINTN Count)852 PciIoCopyMem (
853   IN EFI_PCI_IO_PROTOCOL              *This,
854   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
855   IN     UINT8                        DestBarIndex,
856   IN     UINT64                       DestOffset,
857   IN     UINT8                        SrcBarIndex,
858   IN     UINT64                       SrcOffset,
859   IN     UINTN                        Count
860   )
861 /*++
862 
863 Routine Description:
864 
865   Copy PCI Memory
866 
867 Arguments:
868 
869 Returns:
870 
871   None
872 
873 --*/
874 {
875   EFI_STATUS    Status;
876   PCI_IO_DEVICE *PciIoDevice;
877 
878   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
879 
880   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
881     return EFI_INVALID_PARAMETER;
882   }
883 
884   if (Width == EfiPciIoWidthFifoUint8  ||
885       Width == EfiPciIoWidthFifoUint16 ||
886       Width == EfiPciIoWidthFifoUint32 ||
887       Width == EfiPciIoWidthFifoUint64 ||
888       Width == EfiPciIoWidthFillUint8  ||
889       Width == EfiPciIoWidthFillUint16 ||
890       Width == EfiPciIoWidthFillUint32 ||
891       Width == EfiPciIoWidthFillUint64) {
892     return EFI_INVALID_PARAMETER;
893   }
894 
895   Status = PciIoVerifyBarAccess (PciIoDevice, DestBarIndex, PciBarTypeMem, Width, Count, &DestOffset);
896   if (EFI_ERROR (Status)) {
897     return EFI_UNSUPPORTED;
898   }
899 
900   Status = PciIoVerifyBarAccess (PciIoDevice, SrcBarIndex, PciBarTypeMem, Width, Count, &SrcOffset);
901   if (EFI_ERROR (Status)) {
902     return EFI_UNSUPPORTED;
903   }
904 
905   Status = PciIoDevice->PciRootBridgeIo->CopyMem (
906                                           PciIoDevice->PciRootBridgeIo,
907                                           (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
908                                           DestOffset,
909                                           SrcOffset,
910                                           Count
911                                           );
912 
913   return Status;
914 }
915 
916 EFI_STATUS
917 EFIAPI
PciIoMap(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,IN VOID * HostAddress,IN OUT UINTN * NumberOfBytes,OUT EFI_PHYSICAL_ADDRESS * DeviceAddress,OUT VOID ** Mapping)918 PciIoMap (
919   IN     EFI_PCI_IO_PROTOCOL            *This,
920   IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,
921   IN     VOID                           *HostAddress,
922   IN OUT UINTN                          *NumberOfBytes,
923   OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
924   OUT    VOID                           **Mapping
925   )
926 /*++
927 
928 Routine Description:
929 
930   Maps a memory region for DMA
931 
932 Arguments:
933 
934 Returns:
935 
936   None
937 
938 --*/
939 {
940   EFI_STATUS    Status;
941   PCI_IO_DEVICE *PciIoDevice;
942 
943   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
944 
945   if ((UINT32)Operation >= EfiPciIoOperationMaximum) {
946     return EFI_INVALID_PARAMETER;
947   }
948 
949   if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) {
950     return EFI_INVALID_PARAMETER;
951   }
952 
953   if (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) {
954     Operation = (EFI_PCI_IO_PROTOCOL_OPERATION) (Operation + EfiPciOperationBusMasterRead64);
955   }
956 
957   Status = PciIoDevice->PciRootBridgeIo->Map (
958                                           PciIoDevice->PciRootBridgeIo,
959                                           (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) Operation,
960                                           HostAddress,
961                                           NumberOfBytes,
962                                           DeviceAddress,
963                                           Mapping
964                                           );
965 
966   return Status;
967 }
968 
969 EFI_STATUS
970 EFIAPI
PciIoUnmap(IN EFI_PCI_IO_PROTOCOL * This,IN VOID * Mapping)971 PciIoUnmap (
972   IN  EFI_PCI_IO_PROTOCOL  *This,
973   IN  VOID                 *Mapping
974   )
975 /*++
976 
977 Routine Description:
978 
979   Unmaps a memory region for DMA
980 
981 Arguments:
982 
983 Returns:
984 
985   None
986 
987 --*/
988 {
989   EFI_STATUS    Status;
990   PCI_IO_DEVICE *PciIoDevice;
991 
992   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
993 
994   Status = PciIoDevice->PciRootBridgeIo->Unmap (
995                                           PciIoDevice->PciRootBridgeIo,
996                                           Mapping
997                                           );
998 
999   return Status;
1000 }
1001 
1002 EFI_STATUS
1003 EFIAPI
PciIoAllocateBuffer(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_ALLOCATE_TYPE Type,IN EFI_MEMORY_TYPE MemoryType,IN UINTN Pages,OUT VOID ** HostAddress,IN UINT64 Attributes)1004 PciIoAllocateBuffer (
1005   IN  EFI_PCI_IO_PROTOCOL   *This,
1006   IN  EFI_ALLOCATE_TYPE     Type,
1007   IN  EFI_MEMORY_TYPE       MemoryType,
1008   IN  UINTN                 Pages,
1009   OUT VOID                  **HostAddress,
1010   IN  UINT64                Attributes
1011   )
1012 /*++
1013 
1014 Routine Description:
1015 
1016   Allocates a common buffer for DMA
1017 
1018 Arguments:
1019 
1020 Returns:
1021 
1022   None
1023 
1024 --*/
1025 {
1026   EFI_STATUS    Status;
1027   PCI_IO_DEVICE *PciIoDevice;
1028 
1029   if (Attributes &
1030       (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) {
1031     return EFI_UNSUPPORTED;
1032   }
1033 
1034   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
1035 
1036   if (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) {
1037     Attributes |= EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
1038   }
1039 
1040   Status = PciIoDevice->PciRootBridgeIo->AllocateBuffer (
1041                                           PciIoDevice->PciRootBridgeIo,
1042                                           Type,
1043                                           MemoryType,
1044                                           Pages,
1045                                           HostAddress,
1046                                           Attributes
1047                                           );
1048 
1049   return Status;
1050 }
1051 
1052 EFI_STATUS
1053 EFIAPI
PciIoFreeBuffer(IN EFI_PCI_IO_PROTOCOL * This,IN UINTN Pages,IN VOID * HostAddress)1054 PciIoFreeBuffer (
1055   IN  EFI_PCI_IO_PROTOCOL   *This,
1056   IN  UINTN                 Pages,
1057   IN  VOID                  *HostAddress
1058   )
1059 /*++
1060 
1061 Routine Description:
1062 
1063   Frees a common buffer
1064 
1065 Arguments:
1066 
1067 Returns:
1068 
1069   None
1070 
1071 --*/
1072 {
1073   EFI_STATUS    Status;
1074   PCI_IO_DEVICE *PciIoDevice;
1075 
1076   if( HostAddress == NULL ){
1077      return EFI_INVALID_PARAMETER;
1078   }
1079 
1080   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
1081 
1082   Status = PciIoDevice->PciRootBridgeIo->FreeBuffer (
1083                                           PciIoDevice->PciRootBridgeIo,
1084                                           Pages,
1085                                           HostAddress
1086                                           );
1087 
1088   return Status;
1089 }
1090 
1091 EFI_STATUS
1092 EFIAPI
PciIoFlush(IN EFI_PCI_IO_PROTOCOL * This)1093 PciIoFlush (
1094   IN  EFI_PCI_IO_PROTOCOL  *This
1095   )
1096 /*++
1097 
1098 Routine Description:
1099 
1100   Flushes a DMA buffer
1101 
1102 Arguments:
1103 
1104 Returns:
1105 
1106   None
1107 
1108 --*/
1109 
1110 {
1111   EFI_STATUS    Status;
1112   UINT32         Register;
1113   PCI_IO_DEVICE  *PciIoDevice;
1114 
1115   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
1116 
1117   //
1118   // If the device is behind a PCI-PCI Bridge, then perform a read cycles to the device to
1119   // flush the posted write cycles through the PCI-PCI bridges
1120   //
1121   if (PciIoDevice->Parent != NULL) {
1122     Status = This->Pci.Read (This, EfiPciIoWidthUint32, 0, 1, &Register);
1123   }
1124 
1125   //
1126   // Call the PCI Root Bridge I/O Protocol to flush the posted write cycles through the chipset
1127   //
1128   Status = PciIoDevice->PciRootBridgeIo->Flush (
1129                                            PciIoDevice->PciRootBridgeIo
1130                                            );
1131 
1132   return Status;
1133 }
1134 
1135 EFI_STATUS
1136 EFIAPI
PciIoGetLocation(IN EFI_PCI_IO_PROTOCOL * This,OUT UINTN * Segment,OUT UINTN * Bus,OUT UINTN * Device,OUT UINTN * Function)1137 PciIoGetLocation (
1138   IN  EFI_PCI_IO_PROTOCOL  *This,
1139   OUT UINTN                *Segment,
1140   OUT UINTN                *Bus,
1141   OUT UINTN                *Device,
1142   OUT UINTN                *Function
1143   )
1144 /*++
1145 
1146 Routine Description:
1147 
1148   Gets a PCI device's current bus number, device number, and function number.
1149 
1150 Arguments:
1151 
1152 Returns:
1153 
1154   None
1155 
1156 --*/
1157 {
1158   PCI_IO_DEVICE *PciIoDevice;
1159 
1160   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
1161 
1162   if (Segment == NULL || Bus == NULL || Device == NULL || Function == NULL) {
1163     return EFI_INVALID_PARAMETER;
1164   }
1165 
1166   *Segment  = PciIoDevice->PciRootBridgeIo->SegmentNumber;
1167   *Bus      = PciIoDevice->BusNumber;
1168   *Device   = PciIoDevice->DeviceNumber;
1169   *Function = PciIoDevice->FunctionNumber;
1170 
1171   return EFI_SUCCESS;
1172 }
1173 
1174 BOOLEAN
CheckBarType(IN PCI_IO_DEVICE * PciIoDevice,UINT8 BarIndex,PCI_BAR_TYPE BarType)1175 CheckBarType (
1176   IN PCI_IO_DEVICE       *PciIoDevice,
1177   UINT8                  BarIndex,
1178   PCI_BAR_TYPE           BarType
1179   )
1180 /*++
1181 
1182 Routine Description:
1183 
1184   Sets a PCI controllers attributes on a resource range
1185 
1186 Arguments:
1187 
1188 Returns:
1189 
1190   None
1191 
1192 --*/
1193 {
1194   switch (BarType) {
1195 
1196   case PciBarTypeMem:
1197 
1198     if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem32  &&
1199         PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem32 &&
1200         PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem64 &&
1201         PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem64    ) {
1202       return FALSE;
1203     }
1204 
1205     return TRUE;
1206 
1207   case PciBarTypeIo:
1208     if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo32 &&
1209         PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo16){
1210       return FALSE;
1211     }
1212 
1213     return TRUE;
1214 
1215   default:
1216     break;
1217   }
1218 
1219   return FALSE;
1220 }
1221 
1222 EFI_STATUS
1223 EFIAPI
PciIoAttributes(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,IN UINT64 Attributes,OUT UINT64 * Result OPTIONAL)1224 PciIoAttributes (
1225   IN EFI_PCI_IO_PROTOCOL                       * This,
1226   IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
1227   IN  UINT64                                   Attributes,
1228   OUT UINT64                                   *Result OPTIONAL
1229   )
1230 /*++
1231 
1232 Routine Description:
1233 
1234 
1235 Arguments:
1236 
1237 Returns:
1238 
1239   None
1240 
1241 --*/
1242 {
1243   EFI_STATUS    Status;
1244 
1245   PCI_IO_DEVICE *PciIoDevice;
1246   PCI_IO_DEVICE *Temp;
1247   UINT64         NewAttributes;
1248   UINT64         PciRootBridgeSupports;
1249   UINT64         PciRootBridgeAttributes;
1250   UINT64         NewPciRootBridgeAttributes;
1251   UINT64         NewUpStreamBridgeAttributes;
1252   UINT64         ModifiedPciRootBridgeAttributes;
1253   UINT16         EnableCommand;
1254   UINT16         DisableCommand;
1255   UINT16         EnableBridge;
1256   UINT16         DisableBridge;
1257   UINT16         Command;
1258 
1259   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
1260   NewUpStreamBridgeAttributes = 0;
1261 
1262   EnableCommand   = 0;
1263   DisableCommand  = 0;
1264   EnableBridge    = 0;
1265   DisableBridge   = 0;
1266 
1267   switch (Operation) {
1268   case EfiPciIoAttributeOperationGet:
1269     if (Result == NULL) {
1270       return EFI_INVALID_PARAMETER;
1271     }
1272 
1273     *Result = PciIoDevice->Attributes;
1274     return EFI_SUCCESS;
1275 
1276   case EfiPciIoAttributeOperationSupported:
1277     if (Result == NULL) {
1278       return EFI_INVALID_PARAMETER;
1279     }
1280 
1281     *Result = PciIoDevice->Supports;
1282     return EFI_SUCCESS;
1283 
1284   case EfiPciIoAttributeOperationEnable:
1285     if(Attributes & ~(PciIoDevice->Supports)) {
1286       return EFI_UNSUPPORTED;
1287     }
1288     NewAttributes = PciIoDevice->Attributes | Attributes;
1289     break;
1290   case EfiPciIoAttributeOperationDisable:
1291     if(Attributes & ~(PciIoDevice->Supports)) {
1292       return EFI_UNSUPPORTED;
1293     }
1294     NewAttributes = PciIoDevice->Attributes & (~Attributes);
1295     break;
1296   case EfiPciIoAttributeOperationSet:
1297     if(Attributes & ~(PciIoDevice->Supports)) {
1298       return EFI_UNSUPPORTED;
1299     }
1300     NewAttributes = Attributes;
1301     break;
1302   default:
1303     return EFI_INVALID_PARAMETER;
1304   }
1305 
1306   //
1307   // If VGA_IO is set, then set VGA_MEMORY too.  This driver can not enable them seperately.
1308   //
1309   if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) {
1310     NewAttributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
1311   }
1312 
1313   //
1314   // If VGA_MEMORY is set, then set VGA_IO too.  This driver can not enable them seperately.
1315   //
1316   if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY) {
1317     NewAttributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
1318   }
1319 
1320   //
1321   // If the attributes are already set correctly, then just return EFI_SUCCESS;
1322   //
1323   if ((NewAttributes ^ PciIoDevice->Attributes) == 0) {
1324     return EFI_SUCCESS;
1325   }
1326 
1327   //
1328   // This driver takes care of EFI_PCI_IO_ATTRIBUTE_IO, EFI_PCI_IO_ATTRIBUTE_MEMORY, and
1329   // EFI_PCI_IO_ATTRIBUTE_BUS_MASTER.  Strip these 3 bits off the new attribute mask so
1330   // a call to the PCI Root Bridge I/O Protocol can be made
1331   //
1332 
1333   if (!IS_PCI_BRIDGE(&PciIoDevice->Pci)) {
1334     NewPciRootBridgeAttributes = NewAttributes & (~(EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE));
1335 
1336     //
1337     // Get the current attributes of this PCI device's PCI Root Bridge
1338     //
1339     Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
1340                                             PciIoDevice->PciRootBridgeIo,
1341                                             &PciRootBridgeSupports,
1342                                             &PciRootBridgeAttributes
1343                                             );
1344 
1345     //
1346     // Check to see if any of the PCI Root Bridge attributes are being modified
1347     //
1348     ModifiedPciRootBridgeAttributes = NewPciRootBridgeAttributes ^ PciRootBridgeAttributes;
1349     if (ModifiedPciRootBridgeAttributes) {
1350 
1351       //
1352       // Check to see if the PCI Root Bridge supports modifiying the attributes that are changing
1353       //
1354       if ((ModifiedPciRootBridgeAttributes & PciRootBridgeSupports) != ModifiedPciRootBridgeAttributes) {
1355   //     return EFI_UNSUPPORTED;
1356       }
1357       //
1358       // Call the PCI Root Bridge to attempt to modify the attributes
1359       //
1360       Status = PciIoDevice->PciRootBridgeIo->SetAttributes (
1361                                              PciIoDevice->PciRootBridgeIo,
1362                                              NewPciRootBridgeAttributes,
1363                                              NULL,
1364                                              NULL
1365                                              );
1366       if (EFI_ERROR (Status)) {
1367       //
1368       // The PCI Root Bridge could not modify the attributes, so return the error.
1369       //
1370         return Status;
1371       }
1372     }
1373   }
1374 
1375 
1376   if (IS_PCI_BRIDGE(&PciIoDevice->Pci)) {
1377 
1378 
1379     //
1380     // Check to see if an VGA related attributes are being set.
1381     //
1382     if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO)) {
1383 
1384       if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) {
1385         EnableBridge  |= EFI_PCI_BRIDGE_CONTROL_VGA;
1386       } else {
1387         DisableBridge  |= EFI_PCI_BRIDGE_CONTROL_VGA;
1388       }
1389     }
1390 
1391     //
1392     // Check to see if an VGA related attributes are being set.
1393     // If ISA Enable on the PPB is set, the PPB will block the
1394     // 0x100-0x3FF for each 1KB block in the first 64K I/O block
1395     //
1396     if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO)) {
1397 
1398       if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO) {
1399         DisableBridge  |= EFI_PCI_BRIDGE_CONTROL_ISA;
1400       } else {
1401         EnableBridge  |= EFI_PCI_BRIDGE_CONTROL_ISA;
1402       }
1403     }
1404 
1405     //
1406     // Check to see if an VGA related attributes are being set.
1407     //
1408     if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO)) {
1409 
1410       if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO) {
1411         EnableCommand  |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
1412       } else {
1413         DisableCommand  |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
1414       }
1415     }
1416 
1417   } else {
1418 
1419     if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO)) {
1420 
1421       if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) {
1422 
1423         //
1424         //Check if there have been an active VGA device on the same segment
1425         //
1426         Temp = ActiveVGADeviceOnTheSameSegment (PciIoDevice);
1427 
1428         if (Temp && Temp != PciIoDevice) {
1429           return EFI_UNSUPPORTED;
1430         }
1431       }
1432     }
1433 
1434     if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO)) {
1435       if (IS_PCI_GFX(&PciIoDevice->Pci)) {
1436 
1437         //
1438         //Get the boot VGA on the same segement
1439         //
1440         Temp = ActiveVGADeviceOnTheSameSegment (PciIoDevice);
1441 
1442         if (!Temp) {
1443 
1444           //
1445           // If there is no VGA device on the segement, set
1446           // this graphics card to decode the palette range
1447           //
1448           DisableCommand  |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
1449         } else {
1450 
1451           //
1452           // Check these two agents are on the same path
1453           //
1454           if (PciDevicesOnTheSamePath(Temp, PciIoDevice)) {
1455 
1456             //
1457             // Check if they are on the same bus
1458             //
1459             if (Temp->Parent == PciIoDevice->Parent) {
1460 
1461               PciReadCommandRegister (Temp, &Command);
1462 
1463               //
1464               // If they are on the same bus, either one can
1465               // be set to snoop, the other set to decode
1466               //
1467               if (Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) {
1468                 DisableCommand  |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
1469               } else {
1470                 EnableCommand  |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
1471               }
1472             } else {
1473 
1474               //
1475               // If they are on  the same path but on the different bus
1476               // The first agent is set to snoop, the second one set to
1477               // decode
1478               //
1479               if (Temp->BusNumber > PciIoDevice->BusNumber) {
1480                 PciEnableCommandRegister(Temp,EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
1481                 DisableCommand  |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
1482               } else {
1483                 PciDisableCommandRegister(Temp,EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
1484                 EnableCommand  |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
1485               }
1486             }
1487           } else {
1488 
1489             EnableCommand  |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
1490           }
1491         }
1492       }
1493     }
1494   }
1495 
1496   //
1497   // Check to see of the I/O enable is being modified
1498   //
1499   if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_IO)) {
1500     if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_IO) {
1501       EnableCommand |= EFI_PCI_COMMAND_IO_SPACE;
1502     } else {
1503       DisableCommand |= EFI_PCI_COMMAND_IO_SPACE;
1504     }
1505   }
1506 
1507   //
1508   // Check to see of the Memory enable is being modified
1509   //
1510   if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_MEMORY) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_MEMORY)) {
1511     if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_MEMORY) {
1512       EnableCommand |= EFI_PCI_COMMAND_MEMORY_SPACE;
1513     } else {
1514       DisableCommand |= EFI_PCI_COMMAND_MEMORY_SPACE;
1515     }
1516   }
1517 
1518   //
1519   // Check to see of the Bus Master enable is being modified
1520   //
1521   if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER)) {
1522     if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) {
1523       EnableCommand  |= EFI_PCI_COMMAND_BUS_MASTER;
1524     } else {
1525       DisableCommand |= EFI_PCI_COMMAND_BUS_MASTER;
1526     }
1527   }
1528 
1529   Status = EFI_SUCCESS;
1530   if (EnableCommand) {
1531     Status = PciEnableCommandRegister(PciIoDevice, EnableCommand);
1532   }
1533 
1534   if (DisableCommand) {
1535     Status = PciDisableCommandRegister(PciIoDevice, DisableCommand);
1536   }
1537 
1538   if (EFI_ERROR(Status)) {
1539     return EFI_UNSUPPORTED;
1540   }
1541 
1542   if (EnableBridge) {
1543     Status = PciEnableBridgeControlRegister(PciIoDevice, EnableBridge);
1544   }
1545 
1546   if (DisableBridge) {
1547     Status = PciDisableBridgeControlRegister(PciIoDevice, DisableBridge);
1548   }
1549 
1550   if (EFI_ERROR(Status)) {
1551     return EFI_UNSUPPORTED;
1552   }
1553 
1554   //
1555   // Set the upstream bridge attributes
1556   //
1557   if (Operation != EfiPciIoAttributeOperationGet && Operation != EfiPciIoAttributeOperationSupported) {
1558 
1559     //
1560     // EFI_PCI_IO_ATTRIBUTE_MEMORY, EFI_PCI_IO_ATTRIBUTE_IO, EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
1561     // EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE, EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED
1562     // EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE will not effect to upstream bridge
1563     //
1564     NewUpStreamBridgeAttributes = Attributes & \
1565                                 (~(EFI_PCI_IO_ATTRIBUTE_IO | \
1566                                 EFI_PCI_IO_ATTRIBUTE_MEMORY | \
1567                                 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER | \
1568                                 EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE | \
1569                                 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED | \
1570                                 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE));
1571 
1572     if (NewUpStreamBridgeAttributes){
1573       UpStreamBridgesAttributes(PciIoDevice, Operation, NewUpStreamBridgeAttributes);
1574     }
1575   }
1576 
1577   PciIoDevice->Attributes = NewAttributes;
1578 
1579   return Status;
1580 }
1581 
1582 EFI_STATUS
1583 EFIAPI
PciIoGetBarAttributes(IN EFI_PCI_IO_PROTOCOL * This,IN UINT8 BarIndex,OUT UINT64 * Supports,OPTIONAL OUT VOID ** Resources OPTIONAL)1584 PciIoGetBarAttributes (
1585   IN EFI_PCI_IO_PROTOCOL             * This,
1586   IN  UINT8                          BarIndex,
1587   OUT UINT64                         *Supports, OPTIONAL
1588   OUT VOID                           **Resources OPTIONAL
1589   )
1590 /*++
1591 
1592 Routine Description:
1593 
1594 
1595 Arguments:
1596 
1597 Returns:
1598 
1599   None
1600 
1601 --*/
1602 {
1603   UINT8                             *Configuration;
1604   PCI_IO_DEVICE                     *PciIoDevice;
1605   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AddressSpace;
1606   EFI_ACPI_END_TAG_DESCRIPTOR       *End;
1607 
1608   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
1609 
1610   if (Supports == NULL && Resources == NULL) {
1611     return EFI_INVALID_PARAMETER;
1612   }
1613 
1614   if ((BarIndex >= PCI_MAX_BAR) || (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown)) {
1615     return EFI_UNSUPPORTED;
1616   }
1617 
1618   //
1619   // This driver does not support modifications to the WRITE_COMBINE or
1620   // CACHED attributes for BAR ranges.
1621   //
1622   if (Supports != NULL) {
1623     *Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
1624   }
1625 
1626   if (Resources != NULL) {
1627     Configuration = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
1628     if (Configuration == NULL) {
1629       return EFI_OUT_OF_RESOURCES;
1630     }
1631 
1632     AddressSpace = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
1633 
1634     AddressSpace->Desc         = ACPI_ADDRESS_SPACE_DESCRIPTOR;
1635     AddressSpace->Len          = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);
1636 
1637     AddressSpace->AddrRangeMin = PciIoDevice->PciBar[BarIndex].BaseAddress;
1638     AddressSpace->AddrLen      = PciIoDevice->PciBar[BarIndex].Length;
1639     AddressSpace->AddrRangeMax = PciIoDevice->PciBar[BarIndex].Alignment;
1640 
1641     switch (PciIoDevice->PciBar[BarIndex].BarType) {
1642     case PciBarTypeIo16:
1643     case PciBarTypeIo32:
1644       //
1645       // Io
1646       //
1647       AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
1648       break;
1649 
1650     case PciBarTypeMem32:
1651       //
1652       // Mem
1653       //
1654       AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
1655       //
1656       // 32 bit
1657       //
1658       AddressSpace->AddrSpaceGranularity = 32;
1659       break;
1660 
1661     case PciBarTypePMem32:
1662       //
1663       // Mem
1664       //
1665       AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
1666       //
1667       // prefechable
1668       //
1669       AddressSpace->SpecificFlag = 0x6;
1670       //
1671       // 32 bit
1672       //
1673       AddressSpace->AddrSpaceGranularity = 32;
1674       break;
1675 
1676     case PciBarTypeMem64:
1677       //
1678       // Mem
1679       //
1680       AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
1681       //
1682       // 64 bit
1683       //
1684       AddressSpace->AddrSpaceGranularity = 64;
1685       break;
1686 
1687     case PciBarTypePMem64:
1688       //
1689       // Mem
1690       //
1691       AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
1692       //
1693       // prefechable
1694       //
1695       AddressSpace->SpecificFlag = 0x6;
1696       //
1697       // 64 bit
1698       //
1699       AddressSpace->AddrSpaceGranularity = 64;
1700       break;
1701 
1702     default:
1703       break;
1704     }
1705 
1706     //
1707     // put the checksum
1708     //
1709     End           = (EFI_ACPI_END_TAG_DESCRIPTOR *) (AddressSpace + 1);
1710     End->Desc     = ACPI_END_TAG_DESCRIPTOR;
1711     End->Checksum = 0;
1712 
1713     *Resources    = Configuration;
1714   }
1715 
1716   return EFI_SUCCESS;
1717 }
1718 
1719 EFI_STATUS
1720 EFIAPI
PciIoSetBarAttributes(IN EFI_PCI_IO_PROTOCOL * This,IN UINT64 Attributes,IN UINT8 BarIndex,IN OUT UINT64 * Offset,IN OUT UINT64 * Length)1721 PciIoSetBarAttributes (
1722   IN EFI_PCI_IO_PROTOCOL              *This,
1723   IN     UINT64                       Attributes,
1724   IN     UINT8                        BarIndex,
1725   IN OUT UINT64                       *Offset,
1726   IN OUT UINT64                       *Length
1727   )
1728 /*++
1729 
1730 Routine Description:
1731 
1732 
1733 Arguments:
1734 
1735 Returns:
1736 
1737   None
1738 
1739 --*/
1740 {
1741   EFI_STATUS    Status;
1742   PCI_IO_DEVICE *PciIoDevice;
1743   UINT64        NonRelativeOffset;
1744   UINT64        Supports;
1745 
1746   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
1747 
1748   //
1749   // Make sure Offset and Length are not NULL
1750   //
1751   if (Offset == NULL || Length == NULL) {
1752     return EFI_INVALID_PARAMETER;
1753   }
1754 
1755   if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown) {
1756     return EFI_UNSUPPORTED;
1757   }
1758   //
1759   // This driver does not support setting the WRITE_COMBINE or the CACHED attributes.
1760   // If Attributes is not 0, then return EFI_UNSUPPORTED.
1761   //
1762   Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
1763 
1764   if (Attributes != (Attributes & Supports)) {
1765     return EFI_UNSUPPORTED;
1766   }
1767   //
1768   // Attributes must be supported.  Make sure the BAR range describd by BarIndex, Offset, and
1769   // Length are valid for this PCI device.
1770   //
1771   NonRelativeOffset = *Offset;
1772   Status = PciIoVerifyBarAccess (
1773             PciIoDevice,
1774             BarIndex,
1775             PciBarTypeMem,
1776             EfiPciIoWidthUint8,
1777             (UINT32) *Length,
1778             &NonRelativeOffset
1779             );
1780   if (EFI_ERROR (Status)) {
1781     return EFI_UNSUPPORTED;
1782   }
1783 
1784   return EFI_SUCCESS;
1785 }
1786 
1787 EFI_STATUS
UpStreamBridgesAttributes(IN PCI_IO_DEVICE * PciIoDevice,IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,IN UINT64 Attributes)1788 UpStreamBridgesAttributes (
1789   IN  PCI_IO_DEVICE                            *PciIoDevice,
1790   IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
1791   IN  UINT64                                   Attributes
1792   )
1793 /*++
1794 
1795 Routine Description:
1796 
1797 Arguments:
1798 
1799 Returns:
1800 
1801   None
1802 
1803 --*/
1804 {
1805   PCI_IO_DEVICE       *Parent;
1806   EFI_PCI_IO_PROTOCOL *PciIo;
1807 
1808   Parent = PciIoDevice->Parent;
1809 
1810   while (Parent && IS_PCI_BRIDGE (&Parent->Pci)) {
1811 
1812     //
1813     // Get the PciIo Protocol
1814     //
1815     PciIo = &Parent->PciIo;
1816 
1817     PciIo->Attributes (PciIo, Operation, Attributes, NULL);
1818 
1819     Parent = Parent->Parent;
1820   }
1821 
1822   return EFI_SUCCESS;
1823 }
1824 
1825 BOOLEAN
PciDevicesOnTheSamePath(IN PCI_IO_DEVICE * PciDevice1,IN PCI_IO_DEVICE * PciDevice2)1826 PciDevicesOnTheSamePath (
1827   IN PCI_IO_DEVICE        *PciDevice1,
1828   IN PCI_IO_DEVICE        *PciDevice2
1829   )
1830 /*++
1831 
1832 Routine Description:
1833 
1834 Arguments:
1835 
1836   PciDevice1  -  The pointer to the first PCI_IO_DEVICE.
1837   PciDevice2  -  The pointer to the second PCI_IO_DEVICE.
1838 
1839 Returns:
1840 
1841   TRUE   -  The two Pci devices are on the same path.
1842   FALSE  -  The two Pci devices are not on the same path.
1843 
1844 --*/
1845 {
1846 
1847   if (PciDevice1->Parent == PciDevice2->Parent) {
1848     return TRUE;
1849   }
1850 
1851   return (BOOLEAN) ((PciDeviceExisted (PciDevice1->Parent, PciDevice2)|| PciDeviceExisted (PciDevice2->Parent, PciDevice1)));
1852 }
1853