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.

649 lines
17 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. device.c
  5. Abstract:
  6. This module contains functions associated with enumerating
  7. ordinary (PCI Header type 0) devices.
  8. Author:
  9. Peter Johnston (peterj) 09-Mar-1997
  10. Revision History:
  11. --*/
  12. #include "pcip.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE, Device_MassageHeaderForLimitsDetermination)
  15. #pragma alloc_text(PAGE, Device_SaveLimits)
  16. #pragma alloc_text(PAGE, Device_SaveCurrentSettings)
  17. #pragma alloc_text(PAGE, Device_GetAdditionalResourceDescriptors)
  18. #endif
  19. VOID
  20. Device_MassageHeaderForLimitsDetermination(
  21. IN PPCI_CONFIGURABLE_OBJECT This
  22. )
  23. /*++
  24. Description:
  25. The limits for a device are determined by writing ones to the
  26. Base Address Registers (BARs) and examining what the hardware does
  27. to them. For example, if a device requires 256 bytes of space,
  28. writing 0xffffffff to the BAR which configures this requirement
  29. tells the device to begin decoding its 256 bytes at that address.
  30. Clearly this is impossible, at most one byte can be configured
  31. at that address. The hardware will lower the address by clearing
  32. the least significant bits until the range requirement can be met.
  33. In this case, we would get 0xffffff00 back from the register when
  34. it is next read.
  35. Arguments:
  36. This - Pointer to a PCI driver "configurable" object. This
  37. object contains configuration data for the function
  38. currently being configured.
  39. Return Value:
  40. The Working configuration has been modified so that all range
  41. fields have been set to their maximum possible values.
  42. The Current configuration has been modified such that writing it
  43. to the hardware will restore the hardware to it's current (disabled)
  44. state.
  45. --*/
  46. {
  47. ULONG index;
  48. index = 0;
  49. //
  50. // PCI IDE controllers operating in legacy mode implement
  51. // the first 4 BARs but don't actually use them,... nor are
  52. // they initialized correctly, and sometimes, nothing will
  53. // change if we change them,... but we can't read them to determine
  54. // if they are implemented or not,... so,...
  55. //
  56. if (PCI_IS_LEGACY_IDE_CONTROLLER(This->PdoExtension)) {
  57. //
  58. // If both interfaces are in native mode and the BARs behave
  59. // normally. If both are in legacy mode then we should skip
  60. // the first 4 BARs. Any other combination is meaningless so
  61. // we skip the BARs and let PCIIDE take the system out when
  62. // its turn comes.
  63. //
  64. index = 4;
  65. }
  66. do {
  67. This->Working->u.type0.BaseAddresses[index] = 0xffffffff;
  68. index++;
  69. } while (index < PCI_TYPE0_ADDRESSES);
  70. //
  71. // Set the ROM to its maximum as well,... and disable it.
  72. //
  73. This->Working->u.type0.ROMBaseAddress =
  74. 0xffffffff & PCI_ADDRESS_ROM_ADDRESS_MASK;
  75. return;
  76. }
  77. VOID
  78. Device_RestoreCurrent(
  79. IN PPCI_CONFIGURABLE_OBJECT This
  80. )
  81. /*++
  82. Description:
  83. Restore any type specific fields in the original copy of config
  84. space. In the case of type 0 devices, there are none.
  85. Arguments:
  86. This - Pointer to a PCI driver "configurable" object. This
  87. object contains configuration data for the function
  88. currently being configured.
  89. Return Value:
  90. None.
  91. --*/
  92. {
  93. return;
  94. }
  95. VOID
  96. Device_SaveLimits(
  97. IN PPCI_CONFIGURABLE_OBJECT This
  98. )
  99. /*++
  100. Description:
  101. Fill in the Limit structure with a IO_RESOURCE_REQUIREMENT
  102. for each implemented BAR.
  103. Arguments:
  104. This - Pointer to a PCI driver "configurable" object. This
  105. object contains configuration data for the function
  106. currently being configured.
  107. Return Value:
  108. None.
  109. --*/
  110. {
  111. ULONG index;
  112. PIO_RESOURCE_DESCRIPTOR descriptor;
  113. PULONG bar = This->Working->u.type0.BaseAddresses;
  114. //
  115. // PCI IDE controllers operating in legacy mode implement
  116. // the first 4 BARs but don't actually use them,... nor are
  117. // they initialized correctly, and sometimes, nothing will
  118. // change if we change them,... but we can't read them to determine
  119. // if they are implemented or not,... so,...
  120. //
  121. if (PCI_IS_LEGACY_IDE_CONTROLLER(This->PdoExtension)) {
  122. //
  123. // If both interfaces are in native mode and the BARs behave
  124. // normally. If both are in legacy mode then we should skip
  125. // the first 4 BARs. Any other combination is meaningless so
  126. // we skip the BARs and let PCIIDE take the system out when
  127. // its turn comes.
  128. //
  129. //
  130. // Set the limit to zero in the first 4 bars so we will
  131. // 'detect' the bars as unimplemented.
  132. //
  133. for (index = 0; index < 4; index++) {
  134. bar[index] = 0;
  135. }
  136. }
  137. #if defined(PCI_S3_HACKS)
  138. //
  139. // Check for S3 868 and 968. These cards report memory
  140. // requirements of 32MB but decode 64MB. Gross huh?
  141. //
  142. #if defined(PCIIDE_HACKS)
  143. //
  144. // Ok, it looks gross but turning the above and below into
  145. // an elseif seems marginally more efficient. plj.
  146. //
  147. else
  148. #endif
  149. if (This->PdoExtension->VendorId == 0x5333) {
  150. USHORT deviceId = This->PdoExtension->DeviceId;
  151. if ((deviceId == 0x88f0) || (deviceId == 0x8880)) {
  152. for (index = 0; index < PCI_TYPE0_ADDRESSES; index++) {
  153. //
  154. // Check for memory requirement of 32MB and
  155. // change it to 64MB.
  156. //
  157. if (bar[index] == 0xfe000000) {
  158. bar[index] = 0xfc000000;
  159. PciDebugPrint(
  160. PciDbgObnoxious,
  161. "PCI - Adjusted broken S3 requirement from 32MB to 64MB\n"
  162. );
  163. }
  164. }
  165. }
  166. }
  167. #endif
  168. #if defined(PCI_CIRRUS_54XX_HACK)
  169. //
  170. // This device reports an IO requirement of 0x400 ports, in
  171. // the second BAR. What it really wants is access to the VGA
  172. // registers (3b0 thru 3bb and 3c0 thru 3df). It will actually
  173. // allow them to move but (a) the driver doesn't understand this
  174. // and the device no longer sees the VGA registers, ie vga.sys
  175. // won't work any more, (b) if the device is under a bridge and
  176. // the ISA bit is set, we can't satisfy the requirement,.......
  177. // however, if we left it where it was, it will work under the
  178. // bridge as long as the bridge has the VGA bit set.
  179. //
  180. // Basically, Cirrus tried to make the VGA registers moveable
  181. // which is a noble thing, unfortunately the implementation
  182. // requires a bunch of software knowledge that across all the
  183. // drivers involved, we just don't have.
  184. //
  185. // Solution? Delete the requirement.
  186. //
  187. if ((This->PdoExtension->VendorId == 0x1013) &&
  188. (This->PdoExtension->DeviceId == 0x00a0)) {
  189. //
  190. // If the second requirement is IO for length 0x400,
  191. // currently unassigned, don't report it at all.
  192. //
  193. if ((bar[1] & 0xffff) == 0x0000fc01) {
  194. //
  195. // Only do this if the device does not have a valid
  196. // current setting in this BAR.
  197. //
  198. if (This->Current->u.type0.BaseAddresses[1] == 1) {
  199. bar[1] = 0;
  200. #if DBG
  201. PciDebugPrint(
  202. PciDbgObnoxious,
  203. "PCI - Ignored Cirrus GD54xx broken IO requirement (400 ports)\n"
  204. );
  205. } else {
  206. PciDebugPrint(
  207. PciDbgInformative,
  208. "PCI - Cirrus GD54xx 400 port IO requirement has a valid setting (%08x)\n",
  209. This->Current->u.type0.BaseAddresses[1]
  210. );
  211. #endif
  212. }
  213. #if DBG
  214. } else {
  215. //
  216. // The device doesn't look like we expected it to, complain.
  217. // (unless 0 in which case we assume cirrus already fixed it).
  218. //
  219. if (bar[1] != 0) {
  220. PciDebugPrint(
  221. PciDbgInformative,
  222. "PCI - Warning Cirrus Adapter 101300a0 has unexpected resource requirement (%08x)\n",
  223. bar[1]
  224. );
  225. }
  226. #endif
  227. }
  228. }
  229. #endif
  230. descriptor = This->PdoExtension->Resources->Limit;
  231. //
  232. // Create an IO_RESOURCE_DESCRIPTOR for each implemented
  233. // resource supported by this function.
  234. //
  235. for (index = 0; index < PCI_TYPE0_ADDRESSES; index++) {
  236. if (PciCreateIoDescriptorFromBarLimit(descriptor, bar, FALSE)) {
  237. //
  238. // This base address register is 64 bit, skip one.
  239. //
  240. PCI_ASSERT((index+1) < PCI_TYPE0_ADDRESSES);
  241. index++;
  242. bar++;
  243. //
  244. // Null descriptor in place holder.
  245. //
  246. descriptor++;
  247. descriptor->Type = CmResourceTypeNull;
  248. }
  249. descriptor++;
  250. bar++;
  251. }
  252. //
  253. // Do the same for the ROM
  254. //
  255. PciCreateIoDescriptorFromBarLimit(descriptor,
  256. &This->Working->u.type0.ROMBaseAddress,
  257. TRUE);
  258. }
  259. VOID
  260. Device_SaveCurrentSettings(
  261. IN PPCI_CONFIGURABLE_OBJECT This
  262. )
  263. /*++
  264. Description:
  265. Fill in the Current array in the PDO extension with the current
  266. settings for each implemented BAR.
  267. Arguments:
  268. This - Pointer to a PCI driver "configurable" object. This
  269. object contains configuration data for the function
  270. currently being configured.
  271. Return Value:
  272. None.
  273. --*/
  274. {
  275. ULONG index;
  276. PCM_PARTIAL_RESOURCE_DESCRIPTOR partial;
  277. PIO_RESOURCE_DESCRIPTOR ioResourceDescriptor;
  278. PULONG baseAddress = This->Current->u.type0.BaseAddresses;
  279. ULONG bar;
  280. ULONG addressMask;
  281. BOOLEAN nonZeroBars = FALSE;
  282. partial = This->PdoExtension->Resources->Current;
  283. ioResourceDescriptor = This->PdoExtension->Resources->Limit;
  284. //
  285. // Create an CM_PARTIAL_RESOURCE_DESCRIPTOR for each implemented
  286. // resource supported by this function.
  287. //
  288. // Note: SaveLimits must have been called before SaveCurrentSettings
  289. // so we can tell which BARs are implemented.
  290. //
  291. // Note: The following loop runs one extra time to get the ROM.
  292. //
  293. for (index = 0;
  294. index <= PCI_TYPE0_ADDRESSES;
  295. index++, partial++, ioResourceDescriptor++) {
  296. partial->Type = ioResourceDescriptor->Type;
  297. bar = *baseAddress++;
  298. //
  299. // If this BAR is not implemented, no further processing for
  300. // this partial descriptor.
  301. //
  302. if (partial->Type == CmResourceTypeNull) {
  303. continue;
  304. }
  305. //
  306. // Copy the length from the limits descriptor, then we
  307. // actually need to do a little processing to figure out
  308. // the current limits.
  309. //
  310. partial->Flags = ioResourceDescriptor->Flags;
  311. partial->ShareDisposition = ioResourceDescriptor->ShareDisposition;
  312. partial->u.Generic.Length = ioResourceDescriptor->u.Generic.Length;
  313. partial->u.Generic.Start.HighPart = 0;
  314. if (index == PCI_TYPE0_ADDRESSES) {
  315. bar = This->Current->u.type0.ROMBaseAddress;
  316. addressMask = PCI_ADDRESS_ROM_ADDRESS_MASK;
  317. //
  318. // If the ROM Enabled bit is clear, don't record
  319. // a current setting for this ROM BAR.
  320. //
  321. if ((bar & PCI_ROMADDRESS_ENABLED) == 0) {
  322. partial->Type = CmResourceTypeNull;
  323. continue;
  324. }
  325. } else if (bar & PCI_ADDRESS_IO_SPACE) {
  326. PCI_ASSERT(partial->Type == CmResourceTypePort);
  327. addressMask = PCI_ADDRESS_IO_ADDRESS_MASK;
  328. } else {
  329. PCI_ASSERT(partial->Type == CmResourceTypeMemory);
  330. addressMask = PCI_ADDRESS_MEMORY_ADDRESS_MASK;
  331. if ((bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT) {
  332. //
  333. // This is a 64 bit PCI device. Get the high 32 bits
  334. // from the next BAR.
  335. //
  336. partial->u.Generic.Start.HighPart = *baseAddress;
  337. } else if ((bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_20BIT) {
  338. //
  339. // This device must locate below 1MB, the BAR shouldn't
  340. // have any top bits set but this isn't clear from the
  341. // spec. Enforce it by clearing the top bits.
  342. //
  343. addressMask &= 0x000fffff;
  344. }
  345. }
  346. partial->u.Generic.Start.LowPart = bar & addressMask;
  347. if (partial->u.Generic.Start.QuadPart == 0) {
  348. //
  349. // No current setting if the value is current setting
  350. // is 0.
  351. //
  352. partial->Type = CmResourceTypeNull;
  353. continue;
  354. }
  355. nonZeroBars = TRUE;
  356. }
  357. //
  358. // Save type 0 specific data in the PDO.
  359. //
  360. This->PdoExtension->SubsystemVendorId =
  361. This->Current->u.type0.SubVendorID;
  362. This->PdoExtension->SubsystemId =
  363. This->Current->u.type0.SubSystemID;
  364. }
  365. VOID
  366. Device_ChangeResourceSettings(
  367. IN PPCI_PDO_EXTENSION PdoExtension,
  368. IN PPCI_COMMON_CONFIG CommonConfig
  369. )
  370. /*++
  371. Description:
  372. Reconfigure each BAR using the settings from the Current array
  373. in the PDO extension. All we actually do here is write the new
  374. settings into the memory pointed to by CommonConfig, the actual
  375. write to the hardware is done elsewhere.
  376. Note: Possibly not all BARs will be changed, at least one has
  377. changed or this routine would not have been called.
  378. Arguments:
  379. PdoExtension A pointer to the PDO extension for this device.
  380. CurrentConfig A pointer to the current contents of PCI config
  381. space.
  382. Return Value:
  383. None.
  384. --*/
  385. {
  386. ULONG index;
  387. PCM_PARTIAL_RESOURCE_DESCRIPTOR partial;
  388. PULONG baseAddress;
  389. ULONG bar;
  390. ULONG lowPart;
  391. if (PdoExtension->Resources == NULL) {
  392. //
  393. // Nothing to play with.
  394. //
  395. return;
  396. }
  397. partial = PdoExtension->Resources->Current;
  398. baseAddress = CommonConfig->u.type0.BaseAddresses;
  399. for (index = 0;
  400. index <= PCI_TYPE0_ADDRESSES;
  401. index++, partial++, baseAddress++) {
  402. //
  403. // If this BAR is not implemented, no further processing for
  404. // this partial descriptor.
  405. //
  406. if (partial->Type == CmResourceTypeNull) {
  407. continue;
  408. }
  409. lowPart = partial->u.Generic.Start.LowPart;
  410. bar = *baseAddress;
  411. if (index == PCI_TYPE0_ADDRESSES) {
  412. PCI_ASSERT(partial->Type == CmResourceTypeMemory);
  413. bar = CommonConfig->u.type0.ROMBaseAddress;
  414. bar &= ~PCI_ADDRESS_ROM_ADDRESS_MASK;
  415. bar |= (lowPart & PCI_ADDRESS_ROM_ADDRESS_MASK);
  416. CommonConfig->u.type0.ROMBaseAddress = bar;
  417. } else if (bar & PCI_ADDRESS_IO_SPACE) {
  418. PCI_ASSERT(partial->Type == CmResourceTypePort);
  419. *baseAddress = lowPart;
  420. } else {
  421. PCI_ASSERT(partial->Type == CmResourceTypeMemory);
  422. *baseAddress = lowPart;
  423. if ((bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT) {
  424. //
  425. // This is a 64 bit address. Need to set the upper
  426. // 32 bits in the next BAR.
  427. //
  428. baseAddress++;
  429. *baseAddress = partial->u.Generic.Start.HighPart;
  430. //
  431. // We need to skip the next partial entry and descrement
  432. // the loop count because we consumed a BAR here.
  433. //
  434. index++;
  435. partial++;
  436. #if DBG
  437. } else if ((bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_20BIT) {
  438. //
  439. // This device must locate below 1MB, make sure we're
  440. // configuring it that way.
  441. //
  442. PCI_ASSERT((lowPart & 0xfff00000) == 0);
  443. #endif
  444. }
  445. }
  446. }
  447. }
  448. VOID
  449. Device_GetAdditionalResourceDescriptors(
  450. IN PPCI_PDO_EXTENSION PdoExtension,
  451. IN PPCI_COMMON_CONFIG CommonConfig,
  452. IN PIO_RESOURCE_DESCRIPTOR Resource
  453. )
  454. {
  455. //
  456. // Type 0 (devices) don't require resources not adequately
  457. // described in the BARs.
  458. //
  459. return;
  460. }
  461. NTSTATUS
  462. Device_ResetDevice(
  463. IN PPCI_PDO_EXTENSION PdoExtension,
  464. IN PPCI_COMMON_CONFIG CommonConfig
  465. )
  466. {
  467. return STATUS_SUCCESS;
  468. }