1 /** @file 2 This file contains the callback routines for undi3.1. 3 the callback routines for Undi3.1 have an extra parameter UniqueId which 4 stores the interface context for the NIC that snp is trying to talk. 5 6 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> 7 This program and the accompanying materials 8 are licensed and made available under the terms and conditions of the BSD License 9 which accompanies this distribution. The full text of the license may be found at 10 http://opensource.org/licenses/bsd-license.php 11 12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 15 **/ 16 17 #include "Snp.h" 18 19 /** 20 Acquire or release a lock of the exclusive access to a critical section of the 21 code/data. 22 23 This is a callback routine supplied to UNDI3.1 at undi_start time. 24 New callbacks for 3.1: there won't be a virtual2physical callback for UNDI 3.1 25 because undi3.1 uses the MemMap call to map the required address by itself! 26 27 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to 28 store Undi interface context (Undi does not read or write 29 this variable). 30 @param Enable Non-zero indicates acquire; Zero indicates release. 31 32 **/ 33 VOID 34 EFIAPI 35 SnpUndi32CallbackBlock ( 36 IN UINT64 UniqueId, 37 IN UINT32 Enable 38 ) 39 { 40 SNP_DRIVER *Snp; 41 42 Snp = (SNP_DRIVER *) (UINTN) UniqueId; 43 // 44 // tcpip was calling snp at tpl_notify and when we acquire a lock that was 45 // created at a lower level (TPL_CALLBACK) it gives an assert! 46 // 47 if (Enable != 0) { 48 EfiAcquireLock (&Snp->Lock); 49 } else { 50 EfiReleaseLock (&Snp->Lock); 51 } 52 } 53 54 /** 55 Delay MicroSeconds of micro seconds. 56 57 This is a callback routine supplied to UNDI at undi_start time. 58 59 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to 60 store Undi interface context (Undi does not read or write 61 this variable). 62 @param MicroSeconds Number of micro seconds to pause, ususlly multiple of 10. 63 64 **/ 65 VOID 66 EFIAPI 67 SnpUndi32CallbackDelay ( 68 IN UINT64 UniqueId, 69 IN UINT64 MicroSeconds 70 ) 71 { 72 if (MicroSeconds != 0) { 73 gBS->Stall ((UINTN) MicroSeconds); 74 } 75 } 76 77 /** 78 IO routine for UNDI3.1. 79 80 This is a callback routine supplied to UNDI at undi_start time. 81 82 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this 83 to store Undi interface context (Undi does not read or 84 write this variable). 85 @param ReadOrWrite Indicates read or write, IO or Memory. 86 @param NumBytes Number of bytes to read or write. 87 @param MemOrPortAddr IO or memory address to read from or write to. 88 @param BufferPtr Memory location to read into or that contains the bytes 89 to write. 90 91 **/ 92 VOID 93 EFIAPI 94 SnpUndi32CallbackMemio ( 95 IN UINT64 UniqueId, 96 IN UINT8 ReadOrWrite, 97 IN UINT8 NumBytes, 98 IN UINT64 MemOrPortAddr, 99 IN OUT UINT64 BufferPtr 100 ) 101 { 102 SNP_DRIVER *Snp; 103 EFI_PCI_IO_PROTOCOL_WIDTH Width; 104 105 Snp = (SNP_DRIVER *) (UINTN) UniqueId; 106 107 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0; 108 switch (NumBytes) { 109 case 2: 110 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1; 111 break; 112 113 case 4: 114 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2; 115 break; 116 117 case 8: 118 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3; 119 break; 120 } 121 122 switch (ReadOrWrite) { 123 case PXE_IO_READ: 124 Snp->PciIo->Io.Read ( 125 Snp->PciIo, 126 Width, 127 Snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address 128 MemOrPortAddr, 129 1, // count 130 (VOID *) (UINTN) BufferPtr 131 ); 132 break; 133 134 case PXE_IO_WRITE: 135 Snp->PciIo->Io.Write ( 136 Snp->PciIo, 137 Width, 138 Snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address 139 MemOrPortAddr, 140 1, // count 141 (VOID *) (UINTN) BufferPtr 142 ); 143 break; 144 145 case PXE_MEM_READ: 146 Snp->PciIo->Mem.Read ( 147 Snp->PciIo, 148 Width, 149 Snp->MemoryBarIndex, // BAR 0, Memory base address 150 MemOrPortAddr, 151 1, // count 152 (VOID *) (UINTN) BufferPtr 153 ); 154 break; 155 156 case PXE_MEM_WRITE: 157 Snp->PciIo->Mem.Write ( 158 Snp->PciIo, 159 Width, 160 Snp->MemoryBarIndex, // BAR 0, Memory base address 161 MemOrPortAddr, 162 1, // count 163 (VOID *) (UINTN) BufferPtr 164 ); 165 break; 166 } 167 168 return ; 169 } 170 171 /** 172 Map a CPU address to a device address. 173 174 This is a callback routine supplied to UNDI at undi_start time. 175 176 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to 177 store Undi interface context (Undi does not read or write 178 this variable). 179 @param CpuAddr Virtual address to be mapped. 180 @param NumBytes Size of memory to be mapped. 181 @param Direction Direction of data flow for this memory's usage: 182 cpu->device, device->cpu or both ways. 183 @param DeviceAddrPtr Pointer to return the mapped device address. 184 185 **/ 186 VOID 187 EFIAPI 188 SnpUndi32CallbackMap ( 189 IN UINT64 UniqueId, 190 IN UINT64 CpuAddr, 191 IN UINT32 NumBytes, 192 IN UINT32 Direction, 193 IN OUT UINT64 DeviceAddrPtr 194 ) 195 { 196 EFI_PHYSICAL_ADDRESS *DevAddrPtr; 197 EFI_PCI_IO_PROTOCOL_OPERATION DirectionFlag; 198 UINTN BuffSize; 199 SNP_DRIVER *Snp; 200 UINTN Index; 201 EFI_STATUS Status; 202 203 BuffSize = (UINTN) NumBytes; 204 Snp = (SNP_DRIVER *) (UINTN) UniqueId; 205 DevAddrPtr = (EFI_PHYSICAL_ADDRESS *) (UINTN) DeviceAddrPtr; 206 207 if (CpuAddr == 0) { 208 *DevAddrPtr = 0; 209 return ; 210 } 211 212 switch (Direction) { 213 case TO_AND_FROM_DEVICE: 214 DirectionFlag = EfiPciIoOperationBusMasterCommonBuffer; 215 break; 216 217 case FROM_DEVICE: 218 DirectionFlag = EfiPciIoOperationBusMasterWrite; 219 break; 220 221 case TO_DEVICE: 222 DirectionFlag = EfiPciIoOperationBusMasterRead; 223 break; 224 225 default: 226 *DevAddrPtr = 0; 227 // 228 // any non zero indicates error! 229 // 230 return ; 231 } 232 // 233 // find an unused map_list entry 234 // 235 for (Index = 0; Index < MAX_MAP_LENGTH; Index++) { 236 if (Snp->MapList[Index].VirtualAddress == 0) { 237 break; 238 } 239 } 240 241 if (Index >= MAX_MAP_LENGTH) { 242 DEBUG ((EFI_D_INFO, "SNP maplist is FULL\n")); 243 *DevAddrPtr = 0; 244 return ; 245 } 246 247 Snp->MapList[Index].VirtualAddress = (EFI_PHYSICAL_ADDRESS) CpuAddr; 248 249 Status = Snp->PciIo->Map ( 250 Snp->PciIo, 251 DirectionFlag, 252 (VOID *) (UINTN) CpuAddr, 253 &BuffSize, 254 DevAddrPtr, 255 &(Snp->MapList[Index].MapCookie) 256 ); 257 if (Status != EFI_SUCCESS) { 258 *DevAddrPtr = 0; 259 Snp->MapList[Index].VirtualAddress = 0; 260 } 261 262 return ; 263 } 264 265 /** 266 Unmap an address that was previously mapped using map callback. 267 268 This is a callback routine supplied to UNDI at undi_start time. 269 270 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to 271 store. Undi interface context (Undi does not read or write 272 this variable). 273 @param CpuAddr Virtual address that was mapped. 274 @param NumBytes Size of memory mapped. 275 @param Direction Direction of data flow for this memory's usage: 276 cpu->device, device->cpu or both ways. 277 @param DeviceAddr The mapped device address. 278 279 **/ 280 VOID 281 EFIAPI 282 SnpUndi32CallbackUnmap ( 283 IN UINT64 UniqueId, 284 IN UINT64 CpuAddr, 285 IN UINT32 NumBytes, 286 IN UINT32 Direction, 287 IN UINT64 DeviceAddr 288 ) 289 { 290 SNP_DRIVER *Snp; 291 UINT16 Index; 292 293 Snp = (SNP_DRIVER *) (UINTN) UniqueId; 294 295 for (Index = 0; Index < MAX_MAP_LENGTH; Index++) { 296 if (Snp->MapList[Index].VirtualAddress == CpuAddr) { 297 break; 298 } 299 } 300 301 if (Index >= MAX_MAP_LENGTH) { 302 DEBUG ((EFI_D_ERROR, "SNP could not find a mapping, failed to unmap.\n")); 303 return ; 304 } 305 306 Snp->PciIo->Unmap (Snp->PciIo, Snp->MapList[Index].MapCookie); 307 Snp->MapList[Index].VirtualAddress = 0; 308 Snp->MapList[Index].MapCookie = NULL; 309 return ; 310 } 311 312 /** 313 Synchronize the virtual buffer contents with the mapped buffer contents. 314 315 This is a callback routine supplied to UNDI at undi_start time. The virtual 316 and mapped buffers need not correspond to the same physical memory (especially 317 if the virtual address is > 4GB). Depending on the direction for which the 318 buffer is mapped, undi will need to synchronize their contents whenever it 319 writes to/reads from the buffer using either the cpu address or the device 320 address. 321 EFI does not provide a sync call since virt=physical, we should just do the 322 synchronization ourselves here. 323 324 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to 325 store Undi interface context (Undi does not read or write 326 this variable). 327 @param CpuAddr Virtual address that was mapped. 328 @param NumBytes Size of memory mapped. 329 @param Direction Direction of data flow for this memory's usage: 330 cpu->device, device->cpu or both ways. 331 @param DeviceAddr The mapped device address. 332 333 **/ 334 VOID 335 EFIAPI 336 SnpUndi32CallbackSync ( 337 IN UINT64 UniqueId, 338 IN UINT64 CpuAddr, 339 IN UINT32 NumBytes, 340 IN UINT32 Direction, 341 IN UINT64 DeviceAddr 342 ) 343 { 344 if ((CpuAddr == 0) || (DeviceAddr == 0) || (NumBytes == 0)) { 345 return ; 346 347 } 348 349 switch (Direction) { 350 case FROM_DEVICE: 351 CopyMem ((UINT8 *) (UINTN) CpuAddr, (UINT8 *) (UINTN) DeviceAddr, NumBytes); 352 break; 353 354 case TO_DEVICE: 355 CopyMem ((UINT8 *) (UINTN) DeviceAddr, (UINT8 *) (UINTN) CpuAddr, NumBytes); 356 break; 357 } 358 359 return ; 360 } 361