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