]> git.proxmox.com Git - mirror_edk2.git/blame - DuetPkg/PciRootBridgeNoEnumerationDxe/Ipf/PcatIo.c
Porting Duet module from EDKI to EDKII
[mirror_edk2.git] / DuetPkg / PciRootBridgeNoEnumerationDxe / Ipf / PcatIo.c
CommitLineData
c69dd9df 1/*++\r
2\r
3Copyright (c) 2005, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13 PcatPciRootBridgeIo.c\r
14 \r
15Abstract:\r
16\r
17 EFI PC AT PCI Root Bridge Io Protocol\r
18\r
19Revision History\r
20\r
21--*/\r
22\r
23#include "PcatPciRootBridge.h"\r
24#include "pci22.h"\r
25#include "SalProc.h"\r
26\r
27#include EFI_GUID_DEFINITION (SalSystemTable)\r
28\r
29//\r
30// Might be good to put this in an include file, but people may start\r
31// using it! They should always access the EFI abstraction that is\r
32// contained in this file. Just a little information hiding.\r
33//\r
34#define PORT_TO_MEM(_Port) ( ((_Port) & 0xffffffffffff0000) | (((_Port) & 0xfffc) << 10) | ((_Port) & 0x0fff) )\r
35 \r
36// \r
37// Macro's with casts make this much easier to use and read.\r
38//\r
39#define PORT_TO_MEM8(_Port) (*(UINT8 *)(PORT_TO_MEM(_Port)))\r
40#define PORT_TO_MEM16(_Port) (*(UINT16 *)(PORT_TO_MEM(_Port)))\r
41#define PORT_TO_MEM32(_Port) (*(UINT32 *)(PORT_TO_MEM(_Port)))\r
42\r
43#define EFI_PCI_ADDRESS_IA64(_seg, _bus,_dev,_func,_reg) \\r
44 ( (UINT64) ( (((UINTN)_seg) << 24) + (((UINTN)_bus) << 16) + (((UINTN)_dev) << 11) + (((UINTN)_func) << 8) + ((UINTN)_reg)) )\r
45\r
46//\r
47// Local variables for performing SAL Proc calls\r
48//\r
49static PLABEL mSalProcPlabel;\r
50static CALL_SAL_PROC mGlobalSalProc;\r
51\r
52EFI_STATUS\r
53PcatRootBridgeIoIoRead (\r
54 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
55 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
56 IN UINT64 UserAddress,\r
57 IN UINTN Count,\r
58 IN OUT VOID *UserBuffer\r
59 )\r
60{\r
61 PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData;\r
62 UINTN InStride;\r
63 UINTN OutStride;\r
64 UINTN AlignMask;\r
65 UINTN Address;\r
66 PTR Buffer;\r
67 UINT16 Data16;\r
68 UINT32 Data32;\r
69 \r
70 \r
71 if ( UserBuffer == NULL ) {\r
72 return EFI_INVALID_PARAMETER;\r
73 }\r
74 \r
75 PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);\r
76\r
77 Address = (UINTN) UserAddress;\r
78 Buffer.buf = (UINT8 *)UserBuffer;\r
79\r
80 if ( Address < PrivateData->IoBase || Address > PrivateData->IoLimit ) {\r
81 return EFI_INVALID_PARAMETER;\r
82 }\r
83 \r
84 if (Width < 0 || Width >= EfiPciWidthMaximum) {\r
85 return EFI_INVALID_PARAMETER;\r
86 }\r
87\r
88 if ((Width & 0x03) == EfiPciWidthUint64) {\r
89 return EFI_INVALID_PARAMETER;\r
90 }\r
91\r
92 AlignMask = (1 << (Width & 0x03)) - 1;\r
93 if ( Address & AlignMask ) {\r
94 return EFI_INVALID_PARAMETER;\r
95 }\r
96\r
97 InStride = 1 << (Width & 0x03);\r
98 OutStride = InStride;\r
99 if (Width >=EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {\r
100 InStride = 0;\r
101 }\r
102 if (Width >=EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) {\r
103 OutStride = 0;\r
104 }\r
105 Width = Width & 0x03;\r
106\r
107 Address += PrivateData->PhysicalIoBase;\r
108\r
109 //\r
110 // Loop for each iteration and move the data\r
111 //\r
112\r
113 switch (Width) {\r
114 case EfiPciWidthUint8:\r
115 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {\r
116 MEMORY_FENCE();\r
117 *Buffer.ui8 = PORT_TO_MEM8(Address);\r
118 MEMORY_FENCE();\r
119 }\r
120 break;\r
121\r
122 case EfiPciWidthUint16:\r
123 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {\r
124 MEMORY_FENCE();\r
125 if (Buffer.ui & 0x1) {\r
126 Data16 = PORT_TO_MEM16(Address);\r
127 *Buffer.ui8 = (UINT8)(Data16 & 0xff);\r
128 *(Buffer.ui8+1) = (UINT8)((Data16 >> 8) & 0xff);\r
129 } else {\r
130 *Buffer.ui16 = PORT_TO_MEM16(Address);\r
131 }\r
132 MEMORY_FENCE();\r
133 }\r
134 break;\r
135\r
136 case EfiPciWidthUint32:\r
137 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {\r
138 MEMORY_FENCE();\r
139 if (Buffer.ui & 0x3) {\r
140 Data32 = PORT_TO_MEM32(Address);\r
141 *Buffer.ui8 = (UINT8)(Data32 & 0xff);\r
142 *(Buffer.ui8+1) = (UINT8)((Data32 >> 8) & 0xff);\r
143 *(Buffer.ui8+2) = (UINT8)((Data32 >> 16) & 0xff);\r
144 *(Buffer.ui8+3) = (UINT8)((Data32 >> 24) & 0xff);\r
145 } else {\r
146 *Buffer.ui32 = PORT_TO_MEM32(Address);\r
147 }\r
148 MEMORY_FENCE();\r
149 }\r
150 break;\r
151 }\r
152\r
153 return EFI_SUCCESS;\r
154}\r
155\r
156EFI_STATUS\r
157PcatRootBridgeIoIoWrite (\r
158 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
159 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
160 IN UINT64 UserAddress,\r
161 IN UINTN Count,\r
162 IN OUT VOID *UserBuffer\r
163 )\r
164{\r
165 PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData;\r
166 UINTN InStride;\r
167 UINTN OutStride;\r
168 UINTN AlignMask;\r
169 UINTN Address;\r
170 PTR Buffer;\r
171 UINT16 Data16;\r
172 UINT32 Data32;\r
173\r
174 if ( UserBuffer == NULL ) {\r
175 return EFI_INVALID_PARAMETER;\r
176 }\r
177\r
178 PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);\r
179\r
180 Address = (UINTN) UserAddress;\r
181 Buffer.buf = (UINT8 *)UserBuffer;\r
182\r
183 if ( Address < PrivateData->IoBase || Address > PrivateData->IoLimit ) {\r
184 return EFI_INVALID_PARAMETER;\r
185 }\r
186 \r
187 if (Width < 0 || Width >= EfiPciWidthMaximum) {\r
188 return EFI_INVALID_PARAMETER;\r
189 }\r
190\r
191 if ((Width & 0x03) == EfiPciWidthUint64) {\r
192 return EFI_INVALID_PARAMETER;\r
193 }\r
194\r
195 AlignMask = (1 << (Width & 0x03)) - 1;\r
196 if ( Address & AlignMask ) {\r
197 return EFI_INVALID_PARAMETER;\r
198 }\r
199\r
200 InStride = 1 << (Width & 0x03);\r
201 OutStride = InStride;\r
202 if (Width >=EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {\r
203 InStride = 0;\r
204 }\r
205 if (Width >=EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) {\r
206 OutStride = 0;\r
207 }\r
208 Width = Width & 0x03;\r
209\r
210 Address += PrivateData->PhysicalIoBase;\r
211\r
212 //\r
213 // Loop for each iteration and move the data\r
214 //\r
215\r
216 switch (Width) {\r
217 case EfiPciWidthUint8:\r
218 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {\r
219 MEMORY_FENCE();\r
220 PORT_TO_MEM8(Address) = *Buffer.ui8;\r
221 MEMORY_FENCE();\r
222 }\r
223 break;\r
224\r
225 case EfiPciWidthUint16:\r
226 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {\r
227 MEMORY_FENCE();\r
228 if (Buffer.ui & 0x1) {\r
229 Data16 = *Buffer.ui8;\r
230 Data16 = Data16 | (*(Buffer.ui8+1) << 8);\r
231 PORT_TO_MEM16(Address) = Data16;\r
232 } else {\r
233 PORT_TO_MEM16(Address) = *Buffer.ui16;\r
234 }\r
235 MEMORY_FENCE();\r
236 }\r
237 break;\r
238 case EfiPciWidthUint32:\r
239 for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) {\r
240 MEMORY_FENCE();\r
241 if (Buffer.ui & 0x3) {\r
242 Data32 = *Buffer.ui8;\r
243 Data32 = Data32 | (*(Buffer.ui8+1) << 8);\r
244 Data32 = Data32 | (*(Buffer.ui8+2) << 16);\r
245 Data32 = Data32 | (*(Buffer.ui8+3) << 24);\r
246 PORT_TO_MEM32(Address) = Data32;\r
247 } else {\r
248 PORT_TO_MEM32(Address) = *Buffer.ui32;\r
249 }\r
250 MEMORY_FENCE();\r
251 }\r
252 break;\r
253 }\r
254\r
255 return EFI_SUCCESS;\r
256}\r
257\r
258EFI_STATUS\r
259PcatRootBridgeIoGetIoPortMapping (\r
260 OUT EFI_PHYSICAL_ADDRESS *IoPortMapping,\r
261 OUT EFI_PHYSICAL_ADDRESS *MemoryPortMapping\r
262 )\r
263/*++\r
264\r
265 Get the IO Port Map from the SAL System Table.\r
266 \r
267--*/\r
268{\r
269 SAL_SYSTEM_TABLE_ASCENDING_ORDER *SalSystemTable;\r
270 SAL_ST_MEMORY_DESCRIPTOR_ENTRY *SalMemDesc;\r
271 EFI_STATUS Status;\r
272\r
273 //\r
274 // On all Itanium architectures, bit 63 is the I/O bit for performming Memory Mapped I/O operations\r
275 //\r
276 *MemoryPortMapping = 0x8000000000000000;\r
277\r
278 Status = EfiLibGetSystemConfigurationTable(&gEfiSalSystemTableGuid, &SalSystemTable);\r
279 if (EFI_ERROR(Status)) {\r
280 return EFI_NOT_FOUND;\r
281 }\r
282\r
283 //\r
284 // BugBug: Add code to test checksum on the Sal System Table\r
285 //\r
286 if (SalSystemTable->Entry0.Type != 0) {\r
287 return EFI_UNSUPPORTED;\r
288 }\r
289\r
290 mSalProcPlabel.ProcEntryPoint = SalSystemTable->Entry0.SalProcEntry; \r
291 mSalProcPlabel.GP = SalSystemTable->Entry0.GlobalDataPointer;\r
292 mGlobalSalProc = (CALL_SAL_PROC)&mSalProcPlabel.ProcEntryPoint;\r
293\r
294 //\r
295 // The SalSystemTable pointer includes the Type 0 entry.\r
296 // The SalMemDesc is Type 1 so it comes next.\r
297 //\r
298 SalMemDesc = (SAL_ST_MEMORY_DESCRIPTOR_ENTRY *)(SalSystemTable + 1);\r
299 while (SalMemDesc->Type == SAL_ST_MEMORY_DESCRIPTOR) {\r
300 if (SalMemDesc->MemoryType == SAL_IO_PORT_MAPPING) {\r
301 *IoPortMapping = SalMemDesc->PhysicalMemoryAddress;\r
302 *IoPortMapping |= 0x8000000000000000;\r
303 return EFI_SUCCESS;\r
304 }\r
305 SalMemDesc++;\r
306 }\r
307 return EFI_UNSUPPORTED;\r
308}\r
309\r
310EFI_STATUS\r
311PcatRootBridgeIoPciRW (\r
312 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,\r
313 IN BOOLEAN Write,\r
314 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
315 IN UINT64 UserAddress,\r
316 IN UINTN Count,\r
317 IN OUT UINT8 *UserBuffer\r
318 )\r
319{\r
320 PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData;\r
321 UINTN AlignMask;\r
322 UINTN InStride;\r
323 UINTN OutStride;\r
324 UINT64 Address;\r
325 DEFIO_PCI_ADDR *Defio;\r
326 PTR Buffer;\r
327 UINT32 Data32;\r
328 UINT16 Data16;\r
329 rArg Return;\r
330\r
331 if (Width < 0 || Width >= EfiPciWidthMaximum) {\r
332 return EFI_INVALID_PARAMETER;\r
333 }\r
334\r
335 if ((Width & 0x03) == EfiPciWidthUint64) {\r
336 return EFI_INVALID_PARAMETER;\r
337 }\r
338\r
339 AlignMask = (1 << (Width & 0x03)) - 1;\r
340 if ( UserAddress & AlignMask ) {\r
341 return EFI_INVALID_PARAMETER;\r
342 }\r
343\r
344 InStride = 1 << (Width & 0x03);\r
345 OutStride = InStride;\r
346 if (Width >=EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {\r
347 InStride = 0;\r
348 }\r
349 if (Width >=EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) {\r
350 OutStride = 0;\r
351 }\r
352 Width = Width & 0x03;\r
353\r
354 Defio = (DEFIO_PCI_ADDR *)&UserAddress;\r
355\r
356 if ((Defio->Function > PCI_MAX_FUNC) || (Defio->Device > PCI_MAX_DEVICE)) {\r
357 return EFI_UNSUPPORTED;\r
358 }\r
359 \r
360 Buffer.buf = (UINT8 *)UserBuffer;\r
361 \r
362 PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);\r
363\r
364 Address = EFI_PCI_ADDRESS_IA64(\r
365 This->SegmentNumber, \r
366 Defio->Bus, \r
367 Defio->Device, \r
368 Defio->Function, \r
369 Defio->Register\r
370 );\r
371\r
372 //\r
373 // PCI Config access are all 32-bit alligned, but by accessing the\r
374 // CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types\r
375 // are possible on PCI.\r
376 //\r
377 // SalProc takes care of reading the proper register depending on stride\r
378 //\r
379\r
380 EfiAcquireLock(&PrivateData->PciLock);\r
381\r
382 while (Count) {\r
383\r
384 if(Write) {\r
385\r
386 if (Buffer.ui & 0x3) {\r
387 Data32 = (*(Buffer.ui8+0) << 0);\r
388 Data32 |= (*(Buffer.ui8+1) << 8);\r
389 Data32 |= (*(Buffer.ui8+2) << 16);\r
390 Data32 |= (*(Buffer.ui8+3) << 24);\r
391 } else {\r
392 Data32 = *Buffer.ui32;\r
393 }\r
394\r
395 Return.p0 = -3;\r
396 Return = mGlobalSalProc((UINT64) SAL_PCI_CONFIG_WRITE,\r
397 Address, 1 << Width, Data32, 0, 0, 0, 0);\r
398 \r
399 if(Return.p0) {\r
400 EfiReleaseLock(&PrivateData->PciLock);\r
401 return EFI_UNSUPPORTED;\r
402 }\r
403\r
404 } else {\r
405\r
406 Return.p0 = -3;\r
407 Return = mGlobalSalProc((UINT64) SAL_PCI_CONFIG_READ,\r
408 Address, 1 << Width, 0, 0, 0, 0, 0);\r
409\r
410 if(Return.p0) {\r
411 EfiReleaseLock(&PrivateData->PciLock);\r
412 return EFI_UNSUPPORTED;\r
413 }\r
414\r
415 switch (Width) {\r
416 case EfiPciWidthUint8:\r
417 *Buffer.ui8 = (UINT8)Return.p1;\r
418 break;\r
419 case EfiPciWidthUint16:\r
420 if (Buffer.ui & 0x1) {\r
421 Data16 = (UINT16)Return.p1;\r
422 *(Buffer.ui8 + 0) = Data16 & 0xff;\r
423 *(Buffer.ui8 + 1) = (Data16 >> 8) & 0xff;\r
424 } else {\r
425 *Buffer.ui16 = (UINT16)Return.p1;\r
426 }\r
427 break;\r
428 case EfiPciWidthUint32:\r
429 if (Buffer.ui & 0x3) {\r
430 Data32 = (UINT32)Return.p1;\r
431 *(Buffer.ui8 + 0) = (UINT8)(Data32 & 0xff);\r
432 *(Buffer.ui8 + 1) = (UINT8)((Data32 >> 8) & 0xff);\r
433 *(Buffer.ui8 + 2) = (UINT8)((Data32 >> 16) & 0xff);\r
434 *(Buffer.ui8 + 3) = (UINT8)((Data32 >> 24) & 0xff);\r
435 } else {\r
436 *Buffer.ui32 = (UINT32)Return.p1;\r
437 }\r
438 break;\r
439 }\r
440 }\r
441\r
442 Address += InStride;\r
443 Buffer.buf += OutStride;\r
444 Count -= 1;\r
445 }\r
446 \r
447 EfiReleaseLock(&PrivateData->PciLock);\r
448\r
449 return EFI_SUCCESS;\r
450}\r
451\r
452EFI_STATUS\r
453ScanPciRootBridgeForRoms(\r
454 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev\r
455 )\r
456 \r
457{\r
458 return EFI_UNSUPPORTED;\r
459}\r