Source code of Windows XP (NT5)
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.

726 lines
19 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. #if MCA
  17. #include "mca.h"
  18. #else
  19. #include "eisa.h"
  20. #endif
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text(PAGE,HalpAllocateAdapter)
  23. #pragma alloc_text(PAGELK,HalpGrowMapBuffers)
  24. #endif
  25. //
  26. // Some devices require a physically contiguous data buffer for DMA transfers.
  27. // Map registers are used to give the appearance that all data buffers are
  28. // contiguous. In order to pool all of the map registers a master
  29. // adapter object is used. This object is allocated and saved internal to this
  30. // file. It contains a bit map for allocation of the registers and a queue
  31. // for requests which are waiting for more map registers. This object is
  32. // allocated during the first request to allocate an adapter which requires
  33. // map registers.
  34. //
  35. #if defined(_HALPAE_)
  36. MASTER_ADAPTER_OBJECT MasterAdapter24;
  37. MASTER_ADAPTER_OBJECT MasterAdapter32;
  38. #else
  39. PADAPTER_OBJECT MasterAdapterObject;
  40. #endif
  41. BOOLEAN LessThan16Mb;
  42. BOOLEAN HalpEisaDma;
  43. #define ADAPTER_BASE_MASTER ((PVOID)-1)
  44. #if !defined(_HALPAE_)
  45. //
  46. // Map buffer prameters. These are initialized in HalInitSystem.
  47. //
  48. PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress;
  49. ULONG HalpMapBufferSize;
  50. #endif
  51. //
  52. // Define DMA operations structure.
  53. //
  54. const DMA_OPERATIONS HalpDmaOperations = {
  55. sizeof(DMA_OPERATIONS),
  56. (PPUT_DMA_ADAPTER) HalPutDmaAdapter,
  57. (PALLOCATE_COMMON_BUFFER) HalAllocateCommonBuffer,
  58. (PFREE_COMMON_BUFFER) HalFreeCommonBuffer,
  59. (PALLOCATE_ADAPTER_CHANNEL) IoAllocateAdapterChannel,
  60. (PFLUSH_ADAPTER_BUFFERS) IoFlushAdapterBuffers,
  61. (PFREE_ADAPTER_CHANNEL) IoFreeAdapterChannel,
  62. (PFREE_MAP_REGISTERS) IoFreeMapRegisters,
  63. (PMAP_TRANSFER) IoMapTransfer,
  64. (PGET_DMA_ALIGNMENT) HalGetDmaAlignment,
  65. (PREAD_DMA_COUNTER) HalReadDmaCounter,
  66. (PGET_SCATTER_GATHER_LIST) HalGetScatterGatherList,
  67. (PPUT_SCATTER_GATHER_LIST) HalPutScatterGatherList,
  68. (PCALCULATE_SCATTER_GATHER_LIST_SIZE)HalCalculateScatterGatherListSize,
  69. (PBUILD_SCATTER_GATHER_LIST) HalBuildScatterGatherList,
  70. (PBUILD_MDL_FROM_SCATTER_GATHER_LIST) HalBuildMdlFromScatterGatherList
  71. };
  72. BOOLEAN
  73. HalpGrowMapBuffers(
  74. PADAPTER_OBJECT AdapterObject,
  75. ULONG Amount
  76. )
  77. /*++
  78. Routine Description:
  79. This function attempts to allocate additional map buffers for use by I/O
  80. devices. The map register table is updated to indicate the additional
  81. buffers.
  82. Caller owns the HalpNewAdapter event
  83. Arguments:
  84. AdapterObject - Supplies the adapter object for which the buffers are to be
  85. allocated.
  86. Amount - Indicates the size of the map buffers which should be allocated.
  87. Return Value:
  88. TRUE is returned if the memory could be allocated.
  89. FALSE is returned if the memory could not be allocated.
  90. --*/
  91. {
  92. ULONG MapBufferPhysicalAddress;
  93. PVOID MapBufferVirtualAddress;
  94. PTRANSLATION_ENTRY TranslationEntry;
  95. LONG NumberOfPages;
  96. LONG i;
  97. PHYSICAL_ADDRESS physicalAddressMinimum;
  98. PHYSICAL_ADDRESS physicalAddressMaximum;
  99. PHYSICAL_ADDRESS boundaryAddress;
  100. KIRQL Irql;
  101. PVOID CodeLockHandle;
  102. ULONG maximumBufferPages;
  103. BOOLEAN dma32Bit;
  104. ULONG bytesToAllocate;
  105. PAGED_CODE();
  106. dma32Bit = AdapterObject->Dma32BitAddresses;
  107. boundaryAddress.QuadPart = 0;
  108. NumberOfPages = BYTES_TO_PAGES(Amount);
  109. //
  110. // Make sure there is room for the additional pages. The maximum number of
  111. // slots needed is equal to NumberOfPages + Amount / 64K + 1.
  112. //
  113. maximumBufferPages =
  114. HalpMaximumMapBufferRegisters( dma32Bit );
  115. i = maximumBufferPages - (NumberOfPages +
  116. (NumberOfPages * PAGE_SIZE) / 0x10000 + 1 +
  117. AdapterObject->NumberOfMapRegisters);
  118. if (i < 0) {
  119. //
  120. // Reduce the allocation amount so it will fit.
  121. //
  122. NumberOfPages += i;
  123. }
  124. if (NumberOfPages <= 0) {
  125. //
  126. // No more memory can be allocated.
  127. //
  128. return(FALSE);
  129. }
  130. if (AdapterObject->NumberOfMapRegisters == 0 &&
  131. HalpMapBufferSize( dma32Bit )) {
  132. NumberOfPages =
  133. BYTES_TO_PAGES( HalpMapBufferSize( dma32Bit ));
  134. //
  135. // Since this is the initial allocation, use the buffer allocated by
  136. // HalInitSystem rather than allocating a new one.
  137. //
  138. MapBufferPhysicalAddress =
  139. HalpMapBufferPhysicalAddress( dma32Bit ).LowPart;
  140. //
  141. // Map the buffer for access.
  142. //
  143. MapBufferVirtualAddress = MmMapIoSpace(
  144. HalpMapBufferPhysicalAddress( dma32Bit ),
  145. HalpMapBufferSize( dma32Bit ),
  146. TRUE // Cache enable.
  147. );
  148. if (MapBufferVirtualAddress == NULL) {
  149. //
  150. // The buffer could not be mapped.
  151. //
  152. HalpMapBufferSize( dma32Bit ) = 0;
  153. return(FALSE);
  154. }
  155. } else {
  156. //
  157. // Allocate the map buffers.
  158. //
  159. physicalAddressMaximum =
  160. HalpGetAdapterMaximumPhysicalAddress( AdapterObject );
  161. if (physicalAddressMaximum.LowPart == (ULONG)-1) {
  162. //
  163. // This adapter can handle at least 32-bit addresses. In an effort
  164. // to leave memory to 24-bit adapters, try to make this allocation
  165. // above the 24 bit line.
  166. //
  167. physicalAddressMinimum.QuadPart = MAXIMUM_PHYSICAL_ADDRESS;
  168. } else {
  169. physicalAddressMinimum.QuadPart = 0;
  170. }
  171. bytesToAllocate = NumberOfPages * PAGE_SIZE;
  172. //
  173. // This loop is executed a maximum of two times.
  174. //
  175. while(TRUE) {
  176. MapBufferVirtualAddress =
  177. MmAllocateContiguousMemorySpecifyCache( bytesToAllocate,
  178. physicalAddressMinimum,
  179. physicalAddressMaximum,
  180. boundaryAddress,
  181. MmCached );
  182. if (MapBufferVirtualAddress != NULL) {
  183. //
  184. // The memory was allocated.
  185. //
  186. break;
  187. }
  188. //
  189. // The allocation attempt failed.
  190. //
  191. if (physicalAddressMinimum.QuadPart != 0) {
  192. //
  193. // We were trying to allocate memory above the 16M line as
  194. // an optimization. Relax that requirement and try again.
  195. //
  196. physicalAddressMinimum.QuadPart = 0;
  197. } else {
  198. //
  199. // The memory could not be allocated.
  200. //
  201. return FALSE;
  202. }
  203. }
  204. //
  205. // Get the physical address of the map base.
  206. //
  207. MapBufferPhysicalAddress = MmGetPhysicalAddress(
  208. MapBufferVirtualAddress
  209. ).LowPart;
  210. }
  211. //
  212. // Initialize the map registers where memory has been allocated.
  213. // Serialize with master adapter object.
  214. //
  215. CodeLockHandle = MmLockPagableCodeSection (&HalpGrowMapBuffers);
  216. KeAcquireSpinLock( &AdapterObject->SpinLock, &Irql );
  217. TranslationEntry = ((PTRANSLATION_ENTRY) AdapterObject->MapRegisterBase) +
  218. AdapterObject->NumberOfMapRegisters;
  219. for (i = 0; (LONG) i < NumberOfPages; i++) {
  220. //
  221. // Make sure the perivous entry is physically contiguous with the next
  222. // entry and that a 64K physical bountry is not crossed unless this
  223. // is an Eisa system.
  224. //
  225. if (TranslationEntry != AdapterObject->MapRegisterBase &&
  226. (((TranslationEntry - 1)->PhysicalAddress + PAGE_SIZE) !=
  227. MapBufferPhysicalAddress || (!HalpEisaDma &&
  228. ((TranslationEntry - 1)->PhysicalAddress & ~0x0ffff) !=
  229. (MapBufferPhysicalAddress & ~0x0ffff)))) {
  230. //
  231. // An entry needs to be skipped in the table. This entry will
  232. // remain marked as allocated so that no allocation of map
  233. // registers will cross this bountry.
  234. //
  235. TranslationEntry++;
  236. AdapterObject->NumberOfMapRegisters++;
  237. }
  238. //
  239. // Clear the bits where the memory has been allocated.
  240. //
  241. RtlClearBits(
  242. AdapterObject->MapRegisters,
  243. (ULONG)(TranslationEntry - (PTRANSLATION_ENTRY)
  244. AdapterObject->MapRegisterBase),
  245. 1
  246. );
  247. TranslationEntry->VirtualAddress = MapBufferVirtualAddress;
  248. TranslationEntry->PhysicalAddress = MapBufferPhysicalAddress;
  249. TranslationEntry++;
  250. (PCCHAR) MapBufferVirtualAddress += PAGE_SIZE;
  251. MapBufferPhysicalAddress += PAGE_SIZE;
  252. }
  253. //
  254. // Remember the number of pages that were allocated.
  255. //
  256. AdapterObject->NumberOfMapRegisters += NumberOfPages;
  257. //
  258. // Release master adapter object.
  259. //
  260. KeReleaseSpinLock( &AdapterObject->SpinLock, Irql );
  261. MmUnlockPagableImageSection (CodeLockHandle);
  262. return(TRUE);
  263. }
  264. #if defined(HalpAllocateAdapterEx)
  265. #undef HalpAllocateAdapterEx
  266. #endif
  267. PADAPTER_OBJECT
  268. HalpAllocateAdapterEx(
  269. IN ULONG MapRegistersPerChannel,
  270. IN PVOID AdapterBaseVa,
  271. IN PVOID ChannelNumber,
  272. IN BOOLEAN Dma32Bit
  273. )
  274. /*++
  275. Routine Description:
  276. This routine allocates and initializes an adapter object to represent an
  277. adapter or a DMA controller on the system. If no map registers are required
  278. then a standalone adapter object is allocated with no master adapter.
  279. If map registers are required, then a master adapter object is used to
  280. allocate the map registers. For Isa systems these registers are really
  281. physically contiguous memory pages.
  282. Caller owns the HalpNewAdapter event
  283. Arguments:
  284. MapRegistersPerChannel - Specifies the number of map registers that each
  285. channel provides for I/O memory mapping.
  286. AdapterBaseVa - Address of the the DMA controller or ADAPTER_BASE_MASTER.
  287. ChannelNumber - Unused.
  288. Dma32Bit - Indicates whether the adapter is 24 bit or 32 bit.
  289. Return Value:
  290. The function value is a pointer to the allocate adapter object.
  291. --*/
  292. {
  293. PADAPTER_OBJECT AdapterObject;
  294. OBJECT_ATTRIBUTES ObjectAttributes;
  295. ULONG Size;
  296. ULONG BitmapSize;
  297. HANDLE Handle;
  298. NTSTATUS Status;
  299. ULONG mapBuffers;
  300. BOOLEAN creatingMaster;
  301. UNREFERENCED_PARAMETER(ChannelNumber);
  302. PAGED_CODE();
  303. if (AdapterBaseVa == ADAPTER_BASE_MASTER) {
  304. creatingMaster = TRUE;
  305. } else {
  306. creatingMaster = FALSE;
  307. }
  308. //
  309. // Initialize the master adapter if necessary.
  310. //
  311. if (creatingMaster == FALSE &&
  312. MapRegistersPerChannel != 0) {
  313. //
  314. // This is not a recursive master adapter allocation, and map registers
  315. // are necessary. Allocate a master adapter object of the appropriate
  316. // type if necessary.
  317. //
  318. if (HalpMasterAdapter( Dma32Bit ) == NULL) {
  319. AdapterObject = HalpAllocateAdapterEx( MapRegistersPerChannel,
  320. ADAPTER_BASE_MASTER,
  321. NULL,
  322. Dma32Bit );
  323. //
  324. // If we could not allocate the master adapter then give up.
  325. //
  326. if (AdapterObject == NULL) {
  327. return NULL;
  328. }
  329. AdapterObject->Dma32BitAddresses = Dma32Bit;
  330. AdapterObject->MasterDevice = Dma32Bit;
  331. HalpMasterAdapter( Dma32Bit ) = AdapterObject;
  332. }
  333. }
  334. //
  335. // Begin by initializing the object attributes structure to be used when
  336. // creating the adapter object.
  337. //
  338. InitializeObjectAttributes( &ObjectAttributes,
  339. NULL,
  340. OBJ_PERMANENT,
  341. (HANDLE) NULL,
  342. (PSECURITY_DESCRIPTOR) NULL
  343. );
  344. //
  345. // Determine the size of the adapter object. If this is the master object
  346. // then allocate space for the register bit map; otherwise, just allocate
  347. // an adapter object.
  348. //
  349. if (creatingMaster != FALSE) {
  350. //
  351. // Allocate a bit map large enough MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE
  352. // of map register buffers.
  353. //
  354. mapBuffers = HalpMaximumMapBufferRegisters( Dma32Bit );
  355. BitmapSize = (((sizeof( RTL_BITMAP ) +
  356. ((mapBuffers + 7) >> 3)) + 3) & ~3);
  357. Size = sizeof( ADAPTER_OBJECT ) + BitmapSize;
  358. } else {
  359. Size = sizeof( ADAPTER_OBJECT );
  360. }
  361. //
  362. // Now create the adapter object.
  363. //
  364. Status = ObCreateObject( KernelMode,
  365. *IoAdapterObjectType,
  366. &ObjectAttributes,
  367. KernelMode,
  368. (PVOID) NULL,
  369. Size,
  370. 0,
  371. 0,
  372. (PVOID *)&AdapterObject );
  373. //
  374. // Reference the object.
  375. //
  376. if (NT_SUCCESS(Status)) {
  377. Status = ObReferenceObjectByPointer(
  378. AdapterObject,
  379. FILE_READ_DATA | FILE_WRITE_DATA,
  380. *IoAdapterObjectType,
  381. KernelMode
  382. );
  383. }
  384. //
  385. // If the adapter object was successfully created, then attempt to insert
  386. // it into the object table.
  387. //
  388. if (NT_SUCCESS( Status )) {
  389. RtlZeroMemory (AdapterObject, sizeof (ADAPTER_OBJECT));
  390. Status = ObInsertObject( AdapterObject,
  391. NULL,
  392. FILE_READ_DATA | FILE_WRITE_DATA,
  393. 0,
  394. (PVOID *) NULL,
  395. &Handle );
  396. if (NT_SUCCESS( Status )) {
  397. ZwClose( Handle );
  398. //
  399. // Initialize the adapter object itself.
  400. //
  401. AdapterObject->DmaHeader.Version = IO_TYPE_ADAPTER;
  402. AdapterObject->DmaHeader.Size = (USHORT) Size;
  403. AdapterObject->MapRegistersPerChannel = 1;
  404. AdapterObject->AdapterBaseVa = AdapterBaseVa;
  405. AdapterObject->ChannelNumber = 0xff;
  406. AdapterObject->DmaHeader.DmaOperations = (PDMA_OPERATIONS)&HalpDmaOperations;
  407. AdapterObject->Dma32BitAddresses = Dma32Bit;
  408. if (MapRegistersPerChannel) {
  409. AdapterObject->MasterAdapter = HalpMasterAdapter( Dma32Bit );
  410. } else {
  411. AdapterObject->MasterAdapter = NULL;
  412. }
  413. //
  414. // Initialize the channel wait queue for this adapter.
  415. //
  416. KeInitializeDeviceQueue( &AdapterObject->ChannelWaitQueue );
  417. //
  418. // If this is the MasterAdatper then initialize the register bit map,
  419. // AdapterQueue and the spin lock.
  420. //
  421. if (creatingMaster != FALSE) {
  422. KeInitializeSpinLock( &AdapterObject->SpinLock );
  423. InitializeListHead( &AdapterObject->AdapterQueue );
  424. AdapterObject->MapRegisters = (PVOID) ( AdapterObject + 1);
  425. RtlInitializeBitMap( AdapterObject->MapRegisters,
  426. (PULONG) (((PCHAR) (AdapterObject->MapRegisters)) + sizeof( RTL_BITMAP )),
  427. ( mapBuffers )
  428. );
  429. //
  430. // Set all the bits in the memory to indicate that memory
  431. // has not been allocated for the map buffers.
  432. //
  433. RtlSetAllBits( AdapterObject->MapRegisters );
  434. AdapterObject->NumberOfMapRegisters = 0;
  435. AdapterObject->CommittedMapRegisters = 0;
  436. //
  437. // Allocate the memory map registers.
  438. //
  439. AdapterObject->MapRegisterBase =
  440. ExAllocatePoolWithTag(
  441. NonPagedPool,
  442. mapBuffers * sizeof(TRANSLATION_ENTRY),
  443. HAL_POOL_TAG
  444. );
  445. if (AdapterObject->MapRegisterBase == NULL) {
  446. ObDereferenceObject( AdapterObject );
  447. AdapterObject = NULL;
  448. return(NULL);
  449. }
  450. //
  451. // Zero the map registers.
  452. //
  453. RtlZeroMemory(
  454. AdapterObject->MapRegisterBase,
  455. mapBuffers * sizeof(TRANSLATION_ENTRY)
  456. );
  457. if (!HalpGrowMapBuffers(AdapterObject, INITIAL_MAP_BUFFER_SMALL_SIZE))
  458. {
  459. //
  460. // If no map registers could be allocated then free the
  461. // object.
  462. //
  463. ObDereferenceObject( AdapterObject );
  464. AdapterObject = NULL;
  465. return(NULL);
  466. }
  467. }
  468. } else {
  469. //
  470. // An error was incurred for some reason. Set the return value
  471. // to NULL.
  472. //
  473. AdapterObject = (PADAPTER_OBJECT) NULL;
  474. }
  475. } else {
  476. AdapterObject = (PADAPTER_OBJECT) NULL;
  477. }
  478. return AdapterObject;
  479. }
  480. PADAPTER_OBJECT
  481. HalpAllocateAdapter(
  482. IN ULONG MapRegistersPerChannel,
  483. IN PVOID AdapterBaseVa,
  484. IN PVOID ChannelNumber
  485. )
  486. /*++
  487. Routine Description:
  488. This routine allocates and initializes an adapter object to represent an
  489. adapter or a DMA controller on the system. If no map registers are required
  490. then a standalone adapter object is allocated with no master adapter.
  491. If map registers are required, then a master adapter object is used to
  492. allocate the map registers. For Isa systems these registers are really
  493. physically contiguous memory pages.
  494. Caller owns the HalpNewAdapter event
  495. Arguments:
  496. MapRegistersPerChannel - Specifies the number of map registers that each
  497. channel provides for I/O memory mapping.
  498. AdapterBaseVa - Address of the DMA controller or ADAPTER_BASE_MASTER.
  499. ChannelNumber - Unused.
  500. Return Value:
  501. The function value is a pointer to the allocate adapter object.
  502. --*/
  503. {
  504. return HalpAllocateAdapterEx( MapRegistersPerChannel,
  505. AdapterBaseVa,
  506. ChannelNumber,
  507. FALSE );
  508. }
  509. ULONG
  510. HalGetDmaAlignment (
  511. PVOID Conext
  512. )
  513. {
  514. return HalGetDmaAlignmentRequirement();
  515. }