Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

619 lines
18 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. ixphwsup.c
  5. Abstract:
  6. This module contains the HalpXxx routines for the NT I/O system that
  7. are hardware dependent. Were these routines not hardware dependent,
  8. they would normally reside in the internal.c module.
  9. Author:
  10. Darryl E. Havens (darrylh) 11-Apr-1990
  11. Environment:
  12. Kernel mode, local to I/O system
  13. Revision History:
  14. --*/
  15. #include "halp.h"
  16. #include "mca.h"
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(PAGE,HalpAllocateAdapter)
  19. #pragma alloc_text(PAGELK,HalpGrowMapBuffers)
  20. #endif
  21. //
  22. // Some devices require a physically contiguous data buffer for DMA transfers.
  23. // Map registers are used to give the appearance that all data buffers are
  24. // contiguous. In order to pool all of the map registers a master
  25. // adapter object is used. This object is allocated and saved internal to this
  26. // file. It contains a bit map for allocation of the registers and a queue
  27. // for requests which are waiting for more map registers. This object is
  28. // allocated during the first request to allocate an adapter which requires
  29. // map registers.
  30. //
  31. PADAPTER_OBJECT MasterAdapterObject;
  32. #define ADAPTER_BASE_MASTER ((PVOID)-1)
  33. //
  34. // Map buffer prameters. These are initialized in HalInitSystem.
  35. //
  36. PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress;
  37. ULONG HalpMapBufferSize;
  38. //
  39. // Define DMA operations structure.
  40. //
  41. DMA_OPERATIONS HalpDmaOperations = {
  42. sizeof(DMA_OPERATIONS),
  43. (PPUT_DMA_ADAPTER) HalPutDmaAdapter,
  44. (PALLOCATE_COMMON_BUFFER) HalAllocateCommonBuffer,
  45. (PFREE_COMMON_BUFFER) HalFreeCommonBuffer,
  46. (PALLOCATE_ADAPTER_CHANNEL) HalRealAllocateAdapterChannel,
  47. (PFLUSH_ADAPTER_BUFFERS) IoFlushAdapterBuffers,
  48. (PFREE_ADAPTER_CHANNEL) IoFreeAdapterChannel,
  49. (PFREE_MAP_REGISTERS) IoFreeMapRegisters,
  50. (PMAP_TRANSFER) IoMapTransfer,
  51. (PGET_DMA_ALIGNMENT) HalGetDmaAlignment,
  52. (PREAD_DMA_COUNTER) HalReadDmaCounter,
  53. (PGET_SCATTER_GATHER_LIST) HalGetScatterGatherList,
  54. (PPUT_SCATTER_GATHER_LIST) HalPutScatterGatherList,
  55. (PCALCULATE_SCATTER_GATHER_LIST_SIZE)HalCalculateScatterGatherListSize,
  56. (PBUILD_SCATTER_GATHER_LIST) HalBuildScatterGatherList,
  57. (PBUILD_MDL_FROM_SCATTER_GATHER_LIST) HalBuildMdlFromScatterGatherList
  58. };
  59. BOOLEAN
  60. HalpGrowMapBuffers(
  61. PADAPTER_OBJECT AdapterObject,
  62. ULONG Amount
  63. )
  64. /*++
  65. Routine Description:
  66. This function attempts to allocate additional map buffers for use by I/O
  67. devices. The map register table is updated to indicate the additional
  68. buffers.
  69. Caller owns the HalpNewAdapter event
  70. Arguments:
  71. AdapterObject - Supplies the adapter object for which the buffers are to be
  72. allocated.
  73. Amount - Indicates the size of the map buffers which should be allocated.
  74. Return Value:
  75. TRUE is returned if the memory could be allocated.
  76. FALSE is returned if the memory could not be allocated.
  77. --*/
  78. {
  79. ULONG MapBufferPhysicalAddress;
  80. PVOID MapBufferVirtualAddress;
  81. PTRANSLATION_ENTRY TranslationEntry;
  82. LONG NumberOfPages;
  83. LONG i;
  84. PHYSICAL_ADDRESS physicalAddressMinimum;
  85. PHYSICAL_ADDRESS physicalAddressMaximum;
  86. PHYSICAL_ADDRESS boundaryAddress;
  87. KIRQL Irql;
  88. PVOID CodeLockHandle;
  89. ULONG maximumBufferPages;
  90. ULONG bytesToAllocate;
  91. PAGED_CODE();
  92. boundaryAddress.QuadPart = 0;
  93. NumberOfPages = BYTES_TO_PAGES(Amount);
  94. //
  95. // Make sure there is room for the additional pages. The maximum number of
  96. // slots needed is equal to NumberOfPages + Amount / 64K + 1.
  97. //
  98. maximumBufferPages = BYTES_TO_PAGES(MAXIMUM_PCI_MAP_BUFFER_SIZE);
  99. i = maximumBufferPages - (NumberOfPages +
  100. (NumberOfPages * PAGE_SIZE) / 0x10000 + 1 +
  101. AdapterObject->NumberOfMapRegisters);
  102. if (i < 0) {
  103. //
  104. // Reduce the allocation amount so it will fit.
  105. //
  106. NumberOfPages += i;
  107. }
  108. if (NumberOfPages <= 0) {
  109. //
  110. // No more memory can be allocated.
  111. //
  112. return(FALSE);
  113. }
  114. HalDebugPrint((HAL_VERBOSE, "HGMB: NumberOfPages = %d\n",
  115. NumberOfPages));
  116. if (AdapterObject->NumberOfMapRegisters == 0 && HalpMapBufferSize) {
  117. NumberOfPages = BYTES_TO_PAGES( HalpMapBufferSize );
  118. //
  119. // Since this is the initial allocation, use the buffer allocated by
  120. // HalInitSystem rather than allocating a new one.
  121. //
  122. MapBufferPhysicalAddress = HalpMapBufferPhysicalAddress.LowPart;
  123. //
  124. // Map the buffer for access.
  125. //
  126. HalDebugPrint((HAL_VERBOSE, "HGMB: MapBufferPhys = %p\n",
  127. HalpMapBufferPhysicalAddress));
  128. HalDebugPrint((HAL_VERBOSE, "HGMB: MapBufferSize = 0x%x\n",
  129. HalpMapBufferSize));
  130. MapBufferVirtualAddress = MmMapIoSpace(
  131. HalpMapBufferPhysicalAddress,
  132. HalpMapBufferSize,
  133. TRUE // Cache enable.
  134. );
  135. if (MapBufferVirtualAddress == NULL) {
  136. //
  137. // The buffer could not be mapped.
  138. //
  139. HalpMapBufferSize = 0;
  140. return(FALSE);
  141. }
  142. } else {
  143. //
  144. // Allocate the map buffers. Restrict to 32-bit range
  145. // (TRANSLATION_ENTRY is 32-bit)
  146. //
  147. physicalAddressMinimum.QuadPart = 0;
  148. physicalAddressMaximum.LowPart = 0xFFFFFFFF;
  149. physicalAddressMaximum.HighPart = 0;
  150. bytesToAllocate = NumberOfPages * PAGE_SIZE;
  151. MapBufferVirtualAddress =
  152. MmAllocateContiguousMemorySpecifyCache( bytesToAllocate,
  153. physicalAddressMinimum,
  154. physicalAddressMaximum,
  155. boundaryAddress,
  156. MmCached );
  157. if (MapBufferVirtualAddress == NULL) {
  158. //
  159. // The allocation attempt failed.
  160. //
  161. return FALSE;
  162. }
  163. //
  164. // Get the physical address of the map base.
  165. //
  166. MapBufferPhysicalAddress =
  167. MmGetPhysicalAddress(MapBufferVirtualAddress).LowPart;
  168. HalDebugPrint((HAL_VERBOSE, "HGMB: MapBufferVa = %p\n",
  169. MapBufferVirtualAddress));
  170. HalDebugPrint((HAL_VERBOSE, "HGMB: MapBufferPhysAddr = %p\n",
  171. MapBufferPhysicalAddress));
  172. }
  173. //
  174. // Initialize the map registers where memory has been allocated.
  175. // Serialize with master adapter object.
  176. //
  177. CodeLockHandle = MmLockPagableCodeSection (&HalpGrowMapBuffers);
  178. KeAcquireSpinLock( &AdapterObject->SpinLock, &Irql );
  179. TranslationEntry = ((PTRANSLATION_ENTRY) AdapterObject->MapRegisterBase) +
  180. AdapterObject->NumberOfMapRegisters;
  181. for (i = 0; (LONG) i < NumberOfPages; i++) {
  182. //
  183. // Make sure the perivous entry is physically contiguous with the next
  184. // entry
  185. //
  186. if (TranslationEntry != AdapterObject->MapRegisterBase &&
  187. (((TranslationEntry - 1)->PhysicalAddress + PAGE_SIZE) !=
  188. MapBufferPhysicalAddress)) {
  189. //
  190. // An entry needs to be skipped in the table. This entry will
  191. // remain marked as allocated so that no allocation of map
  192. // registers will cross this bountry.
  193. //
  194. TranslationEntry++;
  195. AdapterObject->NumberOfMapRegisters++;
  196. }
  197. //
  198. // Clear the bits where the memory has been allocated.
  199. //
  200. HalDebugPrint((HAL_VERBOSE, "HGMB: ClearBits (%p, 0x%x, 0x%x\n",
  201. AdapterObject->MapRegisters,
  202. (ULONG)(TranslationEntry - (PTRANSLATION_ENTRY)AdapterObject->MapRegisterBase),
  203. 1));
  204. RtlClearBits(
  205. AdapterObject->MapRegisters,
  206. (ULONG)(TranslationEntry - (PTRANSLATION_ENTRY)
  207. AdapterObject->MapRegisterBase),
  208. 1
  209. );
  210. TranslationEntry->VirtualAddress = MapBufferVirtualAddress;
  211. TranslationEntry->PhysicalAddress = MapBufferPhysicalAddress;
  212. TranslationEntry++;
  213. (PCCHAR) MapBufferVirtualAddress += PAGE_SIZE;
  214. MapBufferPhysicalAddress += PAGE_SIZE;
  215. }
  216. //
  217. // Remember the number of pages that were allocated.
  218. //
  219. AdapterObject->NumberOfMapRegisters += NumberOfPages;
  220. //
  221. // Release master adapter object.
  222. //
  223. KeReleaseSpinLock( &AdapterObject->SpinLock, Irql );
  224. MmUnlockPagableImageSection (CodeLockHandle);
  225. return(TRUE);
  226. }
  227. PADAPTER_OBJECT
  228. HalpAllocateAdapter(
  229. IN ULONG MapRegistersPerChannel,
  230. IN PVOID AdapterBaseVa,
  231. IN PVOID ChannelNumber
  232. )
  233. /*++
  234. Routine Description:
  235. This routine allocates and initializes an adapter object to represent an
  236. adapter or a DMA controller on the system. If no map registers are required
  237. then a standalone adapter object is allocated with no master adapter.
  238. If map registers are required, then a master adapter object is used to
  239. allocate the map registers. For Isa systems these registers are really
  240. phyically contiguous memory pages.
  241. Caller owns the HalpNewAdapter event
  242. Arguments:
  243. MapRegistersPerChannel - Specifies the number of map registers that each
  244. channel provides for I/O memory mapping.
  245. AdapterBaseVa - Address of the the DMA controller.
  246. ChannelNumber - Unused.
  247. Return Value:
  248. The function value is a pointer to the allocate adapter object.
  249. --*/
  250. {
  251. PADAPTER_OBJECT AdapterObject;
  252. OBJECT_ATTRIBUTES ObjectAttributes;
  253. ULONG Size;
  254. ULONG BitmapSize;
  255. HANDLE Handle;
  256. NTSTATUS Status;
  257. UNREFERENCED_PARAMETER(ChannelNumber);
  258. PAGED_CODE();
  259. HalDebugPrint((HAL_VERBOSE, "HAA: MapRegistersPerChannel = %d\n",
  260. MapRegistersPerChannel));
  261. HalDebugPrint((HAL_VERBOSE, "HAA: BaseVa = %p\n",
  262. AdapterBaseVa));
  263. //
  264. // Initalize the master adapter if necessary.
  265. //
  266. if (MasterAdapterObject == NULL && AdapterBaseVa != (PVOID) -1 &&
  267. MapRegistersPerChannel) {
  268. MasterAdapterObject = HalpAllocateAdapter(
  269. MapRegistersPerChannel,
  270. (PVOID) -1,
  271. NULL
  272. );
  273. HalDebugPrint((HAL_VERBOSE, "HAA: MasterAdapterObject = %p\n",
  274. MasterAdapterObject));
  275. //
  276. // If we could not allocate the master adapter then give up.
  277. //
  278. if (MasterAdapterObject == NULL) {
  279. return(NULL);
  280. }
  281. }
  282. //
  283. // Begin by initializing the object attributes structure to be used when
  284. // creating the adapter object.
  285. //
  286. InitializeObjectAttributes( &ObjectAttributes,
  287. NULL,
  288. OBJ_PERMANENT | OBJ_KERNEL_HANDLE,
  289. (HANDLE) NULL,
  290. (PSECURITY_DESCRIPTOR) NULL
  291. );
  292. //
  293. // Determine the size of the adapter object. If this is the master object
  294. // then allocate space for the register bit map; otherwise, just allocate
  295. // an adapter object.
  296. //
  297. if (AdapterBaseVa == (PVOID) -1) {
  298. //
  299. // Allocate a bit map large enough MAXIMUM_PCI_MAP_BUFFER_SIZE / PAGE_SIZE
  300. // of map register buffers.
  301. //
  302. BitmapSize = (((sizeof( RTL_BITMAP ) +
  303. ((( MAXIMUM_PCI_MAP_BUFFER_SIZE / PAGE_SIZE ) + 7) >> 3)) + 3) & ~3);
  304. Size = sizeof( ADAPTER_OBJECT ) + BitmapSize;
  305. } else {
  306. Size = sizeof( ADAPTER_OBJECT );
  307. }
  308. //
  309. // Now create the adapter object.
  310. //
  311. Status = ObCreateObject( KernelMode,
  312. *IoAdapterObjectType,
  313. &ObjectAttributes,
  314. KernelMode,
  315. (PVOID) NULL,
  316. Size,
  317. 0,
  318. 0,
  319. (PVOID *)&AdapterObject );
  320. //
  321. // Reference the object.
  322. //
  323. if (NT_SUCCESS(Status)) {
  324. Status = ObReferenceObjectByPointer(
  325. AdapterObject,
  326. FILE_READ_DATA | FILE_WRITE_DATA,
  327. *IoAdapterObjectType,
  328. KernelMode
  329. );
  330. }
  331. //
  332. // If the adapter object was successfully created, then attempt to insert
  333. // it into the the object table.
  334. //
  335. if (NT_SUCCESS( Status )) {
  336. RtlZeroMemory (AdapterObject, sizeof (ADAPTER_OBJECT));
  337. Status = ObInsertObject( AdapterObject,
  338. NULL,
  339. FILE_READ_DATA | FILE_WRITE_DATA,
  340. 0,
  341. (PVOID *) NULL,
  342. &Handle );
  343. if (NT_SUCCESS( Status )) {
  344. ZwClose( Handle );
  345. //
  346. // Initialize the adapter object itself.
  347. //
  348. AdapterObject->DmaHeader.Version = IO_TYPE_ADAPTER;
  349. AdapterObject->DmaHeader.Size = (USHORT) Size;
  350. AdapterObject->MapRegistersPerChannel = 1;
  351. AdapterObject->AdapterBaseVa = AdapterBaseVa;
  352. AdapterObject->ChannelNumber = 0xff;
  353. AdapterObject->DmaHeader.DmaOperations = &HalpDmaOperations;
  354. if (MapRegistersPerChannel) {
  355. AdapterObject->MasterAdapter = MasterAdapterObject;
  356. } else {
  357. AdapterObject->MasterAdapter = NULL;
  358. }
  359. //
  360. // Initialize the channel wait queue for this
  361. // adapter.
  362. //
  363. KeInitializeDeviceQueue( &AdapterObject->ChannelWaitQueue );
  364. //
  365. // If this is the MasterAdatper then initialize register bit map,
  366. // AdapterQueue and the spin lock.
  367. //
  368. if ( AdapterBaseVa == (PVOID) -1 ) {
  369. KeInitializeSpinLock( &AdapterObject->SpinLock );
  370. InitializeListHead( &AdapterObject->AdapterQueue );
  371. AdapterObject->MapRegisters = (PVOID) ( AdapterObject + 1);
  372. HalDebugPrint((HAL_VERBOSE, "HAA: InitBitMap(%p, %p, 0x%x\n",
  373. AdapterObject->MapRegisters,
  374. (PULONG)(((PCHAR)(AdapterObject->MapRegisters)) +
  375. sizeof( RTL_BITMAP )),
  376. ( MAXIMUM_PCI_MAP_BUFFER_SIZE / PAGE_SIZE )));
  377. RtlInitializeBitMap (
  378. AdapterObject->MapRegisters,
  379. (PULONG)(((PCHAR)(AdapterObject->MapRegisters)) +
  380. sizeof( RTL_BITMAP )),
  381. ( MAXIMUM_PCI_MAP_BUFFER_SIZE / PAGE_SIZE )
  382. );
  383. //
  384. // Set all the bits in the memory to indicate that memory
  385. // has not been allocated for the map buffers
  386. //
  387. RtlSetAllBits( AdapterObject->MapRegisters );
  388. AdapterObject->NumberOfMapRegisters = 0;
  389. AdapterObject->CommittedMapRegisters = 0;
  390. //
  391. // ALlocate the memory map registers.
  392. //
  393. AdapterObject->MapRegisterBase = ExAllocatePoolWithTag(
  394. NonPagedPool,
  395. (MAXIMUM_PCI_MAP_BUFFER_SIZE / PAGE_SIZE) *
  396. sizeof(TRANSLATION_ENTRY),
  397. HAL_POOL_TAG
  398. );
  399. if (AdapterObject->MapRegisterBase == NULL) {
  400. ObDereferenceObject( AdapterObject );
  401. AdapterObject = NULL;
  402. return(NULL);
  403. }
  404. //
  405. // Zero the map registers.
  406. //
  407. RtlZeroMemory(
  408. AdapterObject->MapRegisterBase,
  409. (MAXIMUM_PCI_MAP_BUFFER_SIZE / PAGE_SIZE) *
  410. sizeof(TRANSLATION_ENTRY)
  411. );
  412. if (!HalpGrowMapBuffers(
  413. AdapterObject,
  414. INITIAL_MAP_BUFFER_LARGE_SIZE
  415. )
  416. )
  417. {
  418. //
  419. // If no map registers could be allocated then free the
  420. // object.
  421. //
  422. ObDereferenceObject( AdapterObject );
  423. AdapterObject = NULL;
  424. return(NULL);
  425. }
  426. }
  427. } else {
  428. //
  429. // An error was incurred for some reason. Set the return value
  430. // to NULL.
  431. //
  432. AdapterObject = (PADAPTER_OBJECT) NULL;
  433. }
  434. } else {
  435. AdapterObject = (PADAPTER_OBJECT) NULL;
  436. }
  437. return AdapterObject;
  438. }
  439. ULONG
  440. HalGetDmaAlignment (
  441. PVOID Conext
  442. )
  443. {
  444. return HalGetDmaAlignmentRequirement();
  445. }