rtl81.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. rtl81.c
  5. Abstract:
  6. This module implements support for the driver portion of the Realtek
  7. RTL81xx family of Ethernet controllers.
  8. Author:
  9. Chris Stevens 20-Jun-2014
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/kernel/driver.h>
  17. #include <minoca/net/netdrv.h>
  18. #include "rtl81.h"
  19. //
  20. // ---------------------------------------------------------------- Definitions
  21. //
  22. //
  23. // ------------------------------------------------------ Data Type Definitions
  24. //
  25. //
  26. // ----------------------------------------------- Internal Function Prototypes
  27. //
  28. KSTATUS
  29. Rtl81AddDevice (
  30. PVOID Driver,
  31. PSTR DeviceId,
  32. PSTR ClassId,
  33. PSTR CompatibleIds,
  34. PVOID DeviceToken
  35. );
  36. VOID
  37. Rtl81DispatchStateChange (
  38. PIRP Irp,
  39. PVOID DeviceContext,
  40. PVOID IrpContext
  41. );
  42. VOID
  43. Rtl81DispatchOpen (
  44. PIRP Irp,
  45. PVOID DeviceContext,
  46. PVOID IrpContext
  47. );
  48. VOID
  49. Rtl81DispatchClose (
  50. PIRP Irp,
  51. PVOID DeviceContext,
  52. PVOID IrpContext
  53. );
  54. VOID
  55. Rtl81DispatchIo (
  56. PIRP Irp,
  57. PVOID DeviceContext,
  58. PVOID IrpContext
  59. );
  60. VOID
  61. Rtl81DispatchSystemControl (
  62. PIRP Irp,
  63. PVOID DeviceContext,
  64. PVOID IrpContext
  65. );
  66. VOID
  67. Rtl81DestroyLink (
  68. PVOID DeviceContext
  69. );
  70. KSTATUS
  71. Rtl81pProcessResourceRequirements (
  72. PIRP Irp,
  73. PRTL81_DEVICE Device
  74. );
  75. KSTATUS
  76. Rtl81pStartDevice (
  77. PIRP Irp,
  78. PRTL81_DEVICE Device
  79. );
  80. VOID
  81. Rtl81pProcessPciMsiInterfaceChangeNotification (
  82. PVOID Context,
  83. PDEVICE Device,
  84. PVOID InterfaceBuffer,
  85. ULONG InterfaceBufferSize,
  86. BOOL Arrival
  87. );
  88. //
  89. // -------------------------------------------------------------------- Globals
  90. //
  91. PDRIVER Rtl81Driver = NULL;
  92. UUID Rtl81PciMsiInterfaceUuid = UUID_PCI_MESSAGE_SIGNALED_INTERRUPTS;
  93. //
  94. // ------------------------------------------------------------------ Functions
  95. //
  96. KSTATUS
  97. DriverEntry (
  98. PDRIVER Driver
  99. )
  100. /*++
  101. Routine Description:
  102. This routine is the entry point for the RTL81xx driver. It registers its
  103. other dispatch functions, and performs driver-wide initialization.
  104. Arguments:
  105. Driver - Supplies a pointer to the driver object.
  106. Return Value:
  107. STATUS_SUCCESS on success.
  108. Failure code on error.
  109. --*/
  110. {
  111. DRIVER_FUNCTION_TABLE FunctionTable;
  112. KSTATUS Status;
  113. Rtl81Driver = Driver;
  114. RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
  115. FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
  116. FunctionTable.AddDevice = Rtl81AddDevice;
  117. FunctionTable.DispatchStateChange = Rtl81DispatchStateChange;
  118. FunctionTable.DispatchOpen = Rtl81DispatchOpen;
  119. FunctionTable.DispatchClose = Rtl81DispatchClose;
  120. FunctionTable.DispatchIo = Rtl81DispatchIo;
  121. FunctionTable.DispatchSystemControl = Rtl81DispatchSystemControl;
  122. Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
  123. return Status;
  124. }
  125. KSTATUS
  126. Rtl81AddDevice (
  127. PVOID Driver,
  128. PSTR DeviceId,
  129. PSTR ClassId,
  130. PSTR CompatibleIds,
  131. PVOID DeviceToken
  132. )
  133. /*++
  134. Routine Description:
  135. This routine is called when a device is detected for which the RTL81xx
  136. driver acts as the function driver. The driver will attach itself to the
  137. stack.
  138. Arguments:
  139. Driver - Supplies a pointer to the driver being called.
  140. DeviceId - Supplies a pointer to a string with the device ID.
  141. ClassId - Supplies a pointer to a string containing the device's class ID.
  142. CompatibleIds - Supplies a pointer to a string containing device IDs
  143. that would be compatible with this device.
  144. DeviceToken - Supplies an opaque token that the driver can use to identify
  145. the device in the system. This token should be used when attaching to
  146. the stack.
  147. Return Value:
  148. STATUS_SUCCESS on success.
  149. Failure code if the driver was unsuccessful in attaching itself.
  150. --*/
  151. {
  152. PRTL81_DEVICE Device;
  153. KSTATUS Status;
  154. Device = MmAllocateNonPagedPool(sizeof(RTL81_DEVICE), RTL81_ALLOCATION_TAG);
  155. if (Device == NULL) {
  156. Status = STATUS_INSUFFICIENT_RESOURCES;
  157. goto AddDeviceEnd;
  158. }
  159. RtlZeroMemory(Device, sizeof(RTL81_DEVICE));
  160. Device->InterruptHandle = INVALID_HANDLE;
  161. Device->OsDevice = DeviceToken;
  162. Status = IoAttachDriverToDevice(Driver, DeviceToken, Device);
  163. if (!KSUCCESS(Status)) {
  164. goto AddDeviceEnd;
  165. }
  166. AddDeviceEnd:
  167. if (!KSUCCESS(Status)) {
  168. if (Device != NULL) {
  169. MmFreeNonPagedPool(Device);
  170. Device = NULL;
  171. }
  172. }
  173. return Status;
  174. }
  175. VOID
  176. Rtl81DispatchStateChange (
  177. PIRP Irp,
  178. PVOID DeviceContext,
  179. PVOID IrpContext
  180. )
  181. /*++
  182. Routine Description:
  183. This routine handles State Change IRPs.
  184. Arguments:
  185. Irp - Supplies a pointer to the I/O request packet.
  186. DeviceContext - Supplies the context pointer supplied by the driver when it
  187. attached itself to the driver stack. Presumably this pointer contains
  188. driver-specific device context.
  189. IrpContext - Supplies the context pointer supplied by the driver when
  190. the IRP was created.
  191. Return Value:
  192. None.
  193. --*/
  194. {
  195. KSTATUS Status;
  196. ASSERT(Irp->MajorCode == IrpMajorStateChange);
  197. if (Irp->Direction == IrpUp) {
  198. switch (Irp->MinorCode) {
  199. case IrpMinorQueryResources:
  200. Status = Rtl81pProcessResourceRequirements(Irp, DeviceContext);
  201. if (!KSUCCESS(Status)) {
  202. IoCompleteIrp(Rtl81Driver, Irp, Status);
  203. }
  204. break;
  205. case IrpMinorStartDevice:
  206. Status = Rtl81pStartDevice(Irp, DeviceContext);
  207. if (!KSUCCESS(Status)) {
  208. IoCompleteIrp(Rtl81Driver, Irp, Status);
  209. }
  210. break;
  211. default:
  212. break;
  213. }
  214. }
  215. return;
  216. }
  217. VOID
  218. Rtl81DispatchOpen (
  219. PIRP Irp,
  220. PVOID DeviceContext,
  221. PVOID IrpContext
  222. )
  223. /*++
  224. Routine Description:
  225. This routine handles Open IRPs.
  226. Arguments:
  227. Irp - Supplies a pointer to the I/O request packet.
  228. DeviceContext - Supplies the context pointer supplied by the driver when it
  229. attached itself to the driver stack. Presumably this pointer contains
  230. driver-specific device context.
  231. IrpContext - Supplies the context pointer supplied by the driver when
  232. the IRP was created.
  233. Return Value:
  234. None.
  235. --*/
  236. {
  237. return;
  238. }
  239. VOID
  240. Rtl81DispatchClose (
  241. PIRP Irp,
  242. PVOID DeviceContext,
  243. PVOID IrpContext
  244. )
  245. /*++
  246. Routine Description:
  247. This routine handles Close IRPs.
  248. Arguments:
  249. Irp - Supplies a pointer to the I/O request packet.
  250. DeviceContext - Supplies the context pointer supplied by the driver when it
  251. attached itself to the driver stack. Presumably this pointer contains
  252. driver-specific device context.
  253. IrpContext - Supplies the context pointer supplied by the driver when
  254. the IRP was created.
  255. Return Value:
  256. None.
  257. --*/
  258. {
  259. return;
  260. }
  261. VOID
  262. Rtl81DispatchIo (
  263. PIRP Irp,
  264. PVOID DeviceContext,
  265. PVOID IrpContext
  266. )
  267. /*++
  268. Routine Description:
  269. This routine handles I/O IRPs.
  270. Arguments:
  271. Irp - Supplies a pointer to the I/O request packet.
  272. DeviceContext - Supplies the context pointer supplied by the driver when it
  273. attached itself to the driver stack. Presumably this pointer contains
  274. driver-specific device context.
  275. IrpContext - Supplies the context pointer supplied by the driver when
  276. the IRP was created.
  277. Return Value:
  278. None.
  279. --*/
  280. {
  281. return;
  282. }
  283. VOID
  284. Rtl81DispatchSystemControl (
  285. PIRP Irp,
  286. PVOID DeviceContext,
  287. PVOID IrpContext
  288. )
  289. /*++
  290. Routine Description:
  291. This routine handles System Control IRPs.
  292. Arguments:
  293. Irp - Supplies a pointer to the I/O request packet.
  294. DeviceContext - Supplies the context pointer supplied by the driver when it
  295. attached itself to the driver stack. Presumably this pointer contains
  296. driver-specific device context.
  297. IrpContext - Supplies the context pointer supplied by the driver when
  298. the IRP was created.
  299. Return Value:
  300. None.
  301. --*/
  302. {
  303. PRTL81_DEVICE Device;
  304. PSYSTEM_CONTROL_DEVICE_INFORMATION DeviceInformationRequest;
  305. KSTATUS Status;
  306. ASSERT(Irp->MajorCode == IrpMajorSystemControl);
  307. Device = DeviceContext;
  308. if (Irp->Direction == IrpDown) {
  309. switch (Irp->MinorCode) {
  310. case IrpMinorSystemControlDeviceInformation:
  311. DeviceInformationRequest = Irp->U.SystemControl.SystemContext;
  312. Status = NetGetSetLinkDeviceInformation(
  313. Device->NetworkLink,
  314. &(DeviceInformationRequest->Uuid),
  315. DeviceInformationRequest->Data,
  316. &(DeviceInformationRequest->DataSize),
  317. DeviceInformationRequest->Set);
  318. IoCompleteIrp(Rtl81Driver, Irp, Status);
  319. break;
  320. default:
  321. break;
  322. }
  323. }
  324. return;
  325. }
  326. KSTATUS
  327. Rtl81pAddNetworkDevice (
  328. PRTL81_DEVICE Device
  329. )
  330. /*++
  331. Routine Description:
  332. This routine adds the device to core networking's available links.
  333. Arguments:
  334. Device - Supplies a pointer to the device to add.
  335. Return Value:
  336. Status code.
  337. --*/
  338. {
  339. PNET_PACKET_SIZE_INFORMATION PacketSizeInformation;
  340. NET_LINK_PROPERTIES Properties;
  341. KSTATUS Status;
  342. if (Device->NetworkLink != NULL) {
  343. Status = STATUS_SUCCESS;
  344. goto AddNetworkDeviceEnd;
  345. }
  346. //
  347. // Add a link to the core networking library.
  348. //
  349. RtlZeroMemory(&Properties, sizeof(NET_LINK_PROPERTIES));
  350. Properties.Version = NET_LINK_PROPERTIES_VERSION;
  351. Properties.TransmitAlignment = RTL81_TRANSMIT_ALIGNMENT;
  352. Properties.Device = Device->OsDevice;
  353. Properties.DeviceContext = Device;
  354. PacketSizeInformation = &(Properties.PacketSizeInformation);
  355. PacketSizeInformation->MaxPacketSize = RTL81_MAX_TRANSMIT_PACKET_SIZE;
  356. if ((Device->Flags & RTL81_FLAG_TRANSMIT_MODE_LEGACY) != 0) {
  357. PacketSizeInformation->MinPacketSize = RTL81_MINIMUM_PACKET_LENGTH;
  358. }
  359. Properties.DataLinkType = NetDomainEthernet;
  360. Properties.MaxPhysicalAddress = MAX_ULONG;
  361. Properties.PhysicalAddress.Domain = NetDomainEthernet;
  362. Properties.ChecksumFlags = Device->ChecksumFlags;
  363. RtlCopyMemory(&(Properties.PhysicalAddress.Address),
  364. &(Device->MacAddress),
  365. sizeof(Device->MacAddress));
  366. Properties.Interface.Send = Rtl81Send;
  367. Properties.Interface.GetSetInformation = Rtl81GetSetInformation;
  368. Properties.Interface.DestroyLink = Rtl81DestroyLink;
  369. Status = NetAddLink(&Properties, &(Device->NetworkLink));
  370. if (!KSUCCESS(Status)) {
  371. goto AddNetworkDeviceEnd;
  372. }
  373. AddNetworkDeviceEnd:
  374. if (!KSUCCESS(Status)) {
  375. if (Device->NetworkLink != NULL) {
  376. NetRemoveLink(Device->NetworkLink);
  377. Device->NetworkLink = NULL;
  378. }
  379. }
  380. return Status;
  381. }
  382. VOID
  383. Rtl81DestroyLink (
  384. PVOID DeviceContext
  385. )
  386. /*++
  387. Routine Description:
  388. This routine notifies the device layer that the networking core is in the
  389. process of destroying the link and will no longer call into the device for
  390. this link. This allows the device layer to release any context that was
  391. supporting the device link interface.
  392. Arguments:
  393. DeviceContext - Supplies a pointer to the device context associated with
  394. the link being destroyed.
  395. Return Value:
  396. None.
  397. --*/
  398. {
  399. return;
  400. }
  401. //
  402. // --------------------------------------------------------- Internal Functions
  403. //
  404. KSTATUS
  405. Rtl81pProcessResourceRequirements (
  406. PIRP Irp,
  407. PRTL81_DEVICE Device
  408. )
  409. /*++
  410. Routine Description:
  411. This routine filters through the resource requirements presented by the
  412. bus for an RTL81xx LAN controller. It adds an interrupt vector requirement
  413. for any interrupt line requested.
  414. Arguments:
  415. Irp - Supplies a pointer to the I/O request packet.
  416. Device - Supplies a pointer to the device information.
  417. Return Value:
  418. Status code.
  419. --*/
  420. {
  421. PRESOURCE_CONFIGURATION_LIST ConfigurationList;
  422. ULONGLONG EdgeTriggered;
  423. ULONGLONG LineCharacteristics;
  424. PRESOURCE_REQUIREMENT NextRequirement;
  425. PRESOURCE_REQUIREMENT Requirement;
  426. PRESOURCE_REQUIREMENT_LIST RequirementList;
  427. KSTATUS Status;
  428. ULONGLONG VectorCharacteristics;
  429. PRESOURCE_REQUIREMENT VectorRequirement;
  430. RESOURCE_REQUIREMENT VectorTemplate;
  431. ASSERT((Irp->MajorCode == IrpMajorStateChange) &&
  432. (Irp->MinorCode == IrpMinorQueryResources));
  433. //
  434. // Initialize a nice interrupt vector requirement in preparation.
  435. //
  436. RtlZeroMemory(&VectorTemplate, sizeof(RESOURCE_REQUIREMENT));
  437. VectorTemplate.Type = ResourceTypeInterruptVector;
  438. VectorTemplate.Minimum = 0;
  439. VectorTemplate.Maximum = -1;
  440. VectorTemplate.Length = 1;
  441. //
  442. // Some RTL81xx devices support MSI/MSI-X. If this device does, then prefer
  443. // MSIs over legacy interrupts.
  444. //
  445. if ((Device->PciMsiFlags & RTL81_PCI_MSI_FLAG_INTERFACE_REGISTERED) == 0) {
  446. Status = IoRegisterForInterfaceNotifications(
  447. &Rtl81PciMsiInterfaceUuid,
  448. Rtl81pProcessPciMsiInterfaceChangeNotification,
  449. Irp->Device,
  450. Device,
  451. TRUE);
  452. if (!KSUCCESS(Status)) {
  453. goto ProcessResourceRequirementsEnd;
  454. }
  455. Device->PciMsiFlags |= RTL81_PCI_MSI_FLAG_INTERFACE_REGISTERED;
  456. }
  457. //
  458. // If the MSI interface is ever going to be present, then it should have
  459. // been registered immediately. Prepare the device to prefer MSI interrupts.
  460. //
  461. ConfigurationList = Irp->U.QueryResources.ResourceRequirements;
  462. if ((Device->PciMsiFlags & RTL81_PCI_MSI_FLAG_INTERFACE_AVAILABLE) != 0) {
  463. //
  464. // The RTl81xx devices only ever need one interrupt vector. Create one
  465. // for every configuration.
  466. //
  467. RequirementList = IoGetNextResourceConfiguration(ConfigurationList,
  468. NULL);
  469. while (RequirementList != NULL) {
  470. VectorTemplate.Characteristics = INTERRUPT_VECTOR_EDGE_TRIGGERED;
  471. VectorTemplate.OwningRequirement = NULL;
  472. Status = IoCreateAndAddResourceRequirement(&VectorTemplate,
  473. RequirementList,
  474. &VectorRequirement);
  475. if (!KSUCCESS(Status)) {
  476. goto ProcessResourceRequirementsEnd;
  477. }
  478. //
  479. // Now, just in case the above vector allocation fails, prepare to
  480. // fall back to legacy interrupts by allocating an alternative
  481. // vector for each interrupt in the requirement list.
  482. //
  483. Requirement = IoGetNextResourceRequirement(RequirementList, NULL);
  484. while (Requirement != NULL) {
  485. NextRequirement = IoGetNextResourceRequirement(RequirementList,
  486. Requirement);
  487. if (Requirement->Type != ResourceTypeInterruptLine) {
  488. Requirement = NextRequirement;
  489. continue;
  490. }
  491. VectorCharacteristics = 0;
  492. LineCharacteristics = Requirement->Characteristics;
  493. if ((LineCharacteristics & INTERRUPT_LINE_ACTIVE_LOW) != 0) {
  494. VectorCharacteristics |= INTERRUPT_VECTOR_ACTIVE_LOW;
  495. }
  496. if ((LineCharacteristics & INTERRUPT_LINE_ACTIVE_HIGH) != 0) {
  497. VectorCharacteristics |= INTERRUPT_VECTOR_ACTIVE_HIGH;
  498. }
  499. EdgeTriggered = LineCharacteristics &
  500. INTERRUPT_LINE_EDGE_TRIGGERED;
  501. if (EdgeTriggered != 0) {
  502. VectorCharacteristics |= INTERRUPT_VECTOR_EDGE_TRIGGERED;
  503. }
  504. VectorTemplate.Characteristics = VectorCharacteristics;
  505. VectorTemplate.OwningRequirement = Requirement;
  506. Status = IoCreateAndAddResourceRequirementAlternative(
  507. &VectorTemplate,
  508. VectorRequirement);
  509. if (!KSUCCESS(Status)) {
  510. goto ProcessResourceRequirementsEnd;
  511. }
  512. Requirement = NextRequirement;
  513. }
  514. RequirementList = IoGetNextResourceConfiguration(ConfigurationList,
  515. RequirementList);
  516. }
  517. Device->PciMsiFlags |= RTL81_PCI_MSI_FLAG_RESOURCES_REQUESTED;
  518. //
  519. // Otherwise stick with the good, old legacy interrupt setup.
  520. //
  521. } else {
  522. //
  523. // Loop through all configuration lists and add vectors for each line.
  524. //
  525. Status = IoCreateAndAddInterruptVectorsForLines(ConfigurationList,
  526. &VectorTemplate);
  527. if (!KSUCCESS(Status)) {
  528. goto ProcessResourceRequirementsEnd;
  529. }
  530. }
  531. ProcessResourceRequirementsEnd:
  532. return Status;
  533. }
  534. KSTATUS
  535. Rtl81pStartDevice (
  536. PIRP Irp,
  537. PRTL81_DEVICE Device
  538. )
  539. /*++
  540. Routine Description:
  541. This routine starts the RTL81xx LAN device.
  542. Arguments:
  543. Irp - Supplies a pointer to the start IRP.
  544. Device - Supplies a pointer to the device information.
  545. Return Value:
  546. Status code.
  547. --*/
  548. {
  549. ULONG AlignmentOffset;
  550. PRESOURCE_ALLOCATION Allocation;
  551. PRESOURCE_ALLOCATION_LIST AllocationList;
  552. IO_CONNECT_INTERRUPT_PARAMETERS Connect;
  553. PRESOURCE_ALLOCATION ControllerBase;
  554. PHYSICAL_ADDRESS EndAddress;
  555. BOOL Initialized;
  556. PRESOURCE_ALLOCATION LineAllocation;
  557. PCI_MSI_INFORMATION MsiInformation;
  558. PINTERFACE_PCI_MSI MsiInterface;
  559. PCI_MSI_TYPE MsiType;
  560. ULONG PageSize;
  561. PHYSICAL_ADDRESS PhysicalAddress;
  562. PROCESSOR_SET ProcessorSet;
  563. ULONG Size;
  564. KSTATUS Status;
  565. ControllerBase = NULL;
  566. Initialized = FALSE;
  567. //
  568. // Loop through the allocated resources to get the controller base and the
  569. // interrupt.
  570. //
  571. AllocationList = Irp->U.StartDevice.ProcessorLocalResources;
  572. Allocation = IoGetNextResourceAllocation(AllocationList, NULL);
  573. while (Allocation != NULL) {
  574. //
  575. // If the resource is an interrupt vector the presense of an owning
  576. // interrupt line allocation will dictate whether or not MSI/MSI-X
  577. // is used versus legacy interrupts.
  578. //
  579. if (Allocation->Type == ResourceTypeInterruptVector) {
  580. LineAllocation = Allocation->OwningAllocation;
  581. if (LineAllocation == NULL) {
  582. ASSERT((Device->PciMsiFlags &
  583. RTL81_PCI_MSI_FLAG_RESOURCES_REQUESTED) != 0);
  584. ASSERT(Allocation->Characteristics ==
  585. INTERRUPT_VECTOR_EDGE_TRIGGERED);
  586. Device->InterruptLine = INVALID_INTERRUPT_LINE;
  587. Device->PciMsiFlags |= RTL81_PCI_MSI_FLAG_RESOURCES_ALLOCATED;
  588. } else {
  589. ASSERT(LineAllocation->Type == ResourceTypeInterruptLine);
  590. Device->InterruptLine = LineAllocation->Allocation;
  591. }
  592. Device->InterruptVector = Allocation->Allocation;
  593. Device->InterruptResourcesFound = TRUE;
  594. //
  595. // Look for the first physical address reservation, the registers.
  596. //
  597. } else if (Allocation->Type == ResourceTypePhysicalAddressSpace) {
  598. if ((ControllerBase == NULL) && (Allocation->Length != 0)) {
  599. ControllerBase = Allocation;
  600. }
  601. }
  602. //
  603. // Get the next allocation in the list.
  604. //
  605. Allocation = IoGetNextResourceAllocation(AllocationList, Allocation);
  606. }
  607. //
  608. // Fail to start if the controller base was not found.
  609. //
  610. if (ControllerBase == NULL) {
  611. Status = STATUS_INVALID_CONFIGURATION;
  612. goto StartDeviceEnd;
  613. }
  614. //
  615. // Map the controller.
  616. //
  617. if (Device->ControllerBase == NULL) {
  618. //
  619. // Page align the mapping request.
  620. //
  621. PageSize = MmPageSize();
  622. PhysicalAddress = ControllerBase->Allocation;
  623. EndAddress = PhysicalAddress + ControllerBase->Length;
  624. PhysicalAddress = ALIGN_RANGE_DOWN(PhysicalAddress, PageSize);
  625. AlignmentOffset = ControllerBase->Allocation - PhysicalAddress;
  626. EndAddress = ALIGN_RANGE_UP(EndAddress, PageSize);
  627. Size = (ULONG)(EndAddress - PhysicalAddress);
  628. Device->ControllerBase = MmMapPhysicalAddress(PhysicalAddress,
  629. Size,
  630. TRUE,
  631. FALSE,
  632. TRUE);
  633. if (Device->ControllerBase == NULL) {
  634. Status = STATUS_NO_MEMORY;
  635. goto StartDeviceEnd;
  636. }
  637. Device->ControllerBase += AlignmentOffset;
  638. }
  639. ASSERT(Device->ControllerBase != NULL);
  640. //
  641. // Initialize the controller structures.
  642. //
  643. Status = Rtl81pInitializeDeviceStructures(Device);
  644. if (!KSUCCESS(Status)) {
  645. goto StartDeviceEnd;
  646. }
  647. //
  648. // Start up the controller.
  649. //
  650. Status = Rtl81pInitialize(Device);
  651. if (!KSUCCESS(Status)) {
  652. goto StartDeviceEnd;
  653. }
  654. Initialized = TRUE;
  655. //
  656. // Attempt to connect the interrupt.
  657. //
  658. ASSERT(Device->InterruptHandle == INVALID_HANDLE);
  659. RtlZeroMemory(&Connect, sizeof(IO_CONNECT_INTERRUPT_PARAMETERS));
  660. Connect.Version = IO_CONNECT_INTERRUPT_PARAMETERS_VERSION;
  661. Connect.Device = Irp->Device;
  662. Connect.LineNumber = Device->InterruptLine;
  663. Connect.Vector = Device->InterruptVector;
  664. Connect.InterruptServiceRoutine = Rtl81pInterruptService;
  665. Connect.LowLevelServiceRoutine = Rtl81pInterruptServiceWorker;
  666. Connect.Context = Device;
  667. Connect.Interrupt = &(Device->InterruptHandle);
  668. Status = IoConnectInterrupt(&Connect);
  669. if (!KSUCCESS(Status)) {
  670. goto StartDeviceEnd;
  671. }
  672. //
  673. // If MSI/MSI-X resources were allocated, then those additionally need to
  674. // be enabled through the PCI interface. Prefer MSI and fall back to MSI-X.
  675. //
  676. if (Device->InterruptLine == INVALID_INTERRUPT_LINE) {
  677. ASSERT((Device->PciMsiFlags &
  678. RTL81_PCI_MSI_FLAG_RESOURCES_ALLOCATED) != 0);
  679. ProcessorSet.Target = ProcessorTargetAny;
  680. MsiType = PciMsiTypeBasic;
  681. MsiInterface = &(Device->PciMsiInterface);
  682. Status = MsiInterface->SetVectors(MsiInterface->DeviceToken,
  683. MsiType,
  684. Device->InterruptVector,
  685. 0,
  686. 1,
  687. &ProcessorSet);
  688. if (!KSUCCESS(Status)) {
  689. MsiType = PciMsiTypeExtended;
  690. Status = MsiInterface->SetVectors(MsiInterface->DeviceToken,
  691. MsiType,
  692. Device->InterruptVector,
  693. 0,
  694. 1,
  695. &ProcessorSet);
  696. if (!KSUCCESS(Status)) {
  697. goto StartDeviceEnd;
  698. }
  699. }
  700. RtlZeroMemory(&MsiInformation, sizeof(PCI_MSI_INFORMATION));
  701. MsiInformation.Version = PCI_MSI_INTERFACE_INFORMATION_VERSION;
  702. MsiInformation.MsiType = MsiType;
  703. MsiInformation.Flags = PCI_MSI_INTERFACE_FLAG_ENABLED;
  704. MsiInformation.VectorCount = 1;
  705. Status = MsiInterface->GetSetInformation(MsiInterface->DeviceToken,
  706. &MsiInformation,
  707. TRUE);
  708. if (!KSUCCESS(Status)) {
  709. goto StartDeviceEnd;
  710. }
  711. }
  712. StartDeviceEnd:
  713. if (!KSUCCESS(Status)) {
  714. if (Initialized != FALSE) {
  715. ASSERT(Device->NetworkLink != NULL);
  716. NetRemoveLink(Device->NetworkLink);
  717. Device->NetworkLink = NULL;
  718. }
  719. Rtl81pDestroyDeviceStructures(Device);
  720. }
  721. return Status;
  722. }
  723. VOID
  724. Rtl81pProcessPciMsiInterfaceChangeNotification (
  725. PVOID Context,
  726. PDEVICE Device,
  727. PVOID InterfaceBuffer,
  728. ULONG InterfaceBufferSize,
  729. BOOL Arrival
  730. )
  731. /*++
  732. Routine Description:
  733. This routine is called when a PCI configuration space access interface
  734. changes in availability.
  735. Arguments:
  736. Context - Supplies the caller's context pointer, supplied when the caller
  737. requested interface notifications.
  738. Device - Supplies a pointer to the device exposing or deleting the
  739. interface.
  740. InterfaceBuffer - Supplies a pointer to the interface buffer of the
  741. interface.
  742. InterfaceBufferSize - Supplies the buffer size.
  743. Arrival - Supplies TRUE if a new interface is arriving, or FALSE if an
  744. interface is departing.
  745. Return Value:
  746. None.
  747. --*/
  748. {
  749. PRTL81_DEVICE Rtl81Device;
  750. Rtl81Device = (PRTL81_DEVICE)Context;
  751. if (Arrival != FALSE) {
  752. if (InterfaceBufferSize >= sizeof(INTERFACE_PCI_MSI)) {
  753. ASSERT((Rtl81Device->PciMsiFlags &
  754. RTL81_PCI_MSI_FLAG_INTERFACE_AVAILABLE) == 0);
  755. RtlCopyMemory(&(Rtl81Device->PciMsiInterface),
  756. InterfaceBuffer,
  757. sizeof(INTERFACE_PCI_MSI));
  758. Rtl81Device->PciMsiFlags |= RTL81_PCI_MSI_FLAG_INTERFACE_AVAILABLE;
  759. }
  760. } else {
  761. Rtl81Device->PciMsiFlags &= ~RTL81_PCI_MSI_FLAG_INTERFACE_AVAILABLE;
  762. }
  763. return;
  764. }