dwceth.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. dwceth.c
  5. Abstract:
  6. This module implements the DesignWare Ethernet controller.
  7. Author:
  8. Evan Green 5-Dec-2014
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/driver.h>
  16. #include <minoca/net/netdrv.h>
  17. #include "dwceth.h"
  18. //
  19. // ---------------------------------------------------------------- Definitions
  20. //
  21. //
  22. // ------------------------------------------------------ Data Type Definitions
  23. //
  24. //
  25. // ----------------------------------------------- Internal Function Prototypes
  26. //
  27. KSTATUS
  28. DweAddDevice (
  29. PVOID Driver,
  30. PSTR DeviceId,
  31. PSTR ClassId,
  32. PSTR CompatibleIds,
  33. PVOID DeviceToken
  34. );
  35. VOID
  36. DweDispatchStateChange (
  37. PIRP Irp,
  38. PVOID DeviceContext,
  39. PVOID IrpContext
  40. );
  41. VOID
  42. DweDispatchOpen (
  43. PIRP Irp,
  44. PVOID DeviceContext,
  45. PVOID IrpContext
  46. );
  47. VOID
  48. DweDispatchClose (
  49. PIRP Irp,
  50. PVOID DeviceContext,
  51. PVOID IrpContext
  52. );
  53. VOID
  54. DweDispatchIo (
  55. PIRP Irp,
  56. PVOID DeviceContext,
  57. PVOID IrpContext
  58. );
  59. VOID
  60. DweDispatchSystemControl (
  61. PIRP Irp,
  62. PVOID DeviceContext,
  63. PVOID IrpContext
  64. );
  65. VOID
  66. DweDestroyLink (
  67. PVOID DeviceContext
  68. );
  69. KSTATUS
  70. DwepProcessResourceRequirements (
  71. PIRP Irp
  72. );
  73. KSTATUS
  74. DwepStartDevice (
  75. PIRP Irp,
  76. PDWE_DEVICE Device
  77. );
  78. //
  79. // -------------------------------------------------------------------- Globals
  80. //
  81. PDRIVER DweDriver = NULL;
  82. //
  83. // ------------------------------------------------------------------ Functions
  84. //
  85. KSTATUS
  86. DriverEntry (
  87. PDRIVER Driver
  88. )
  89. /*++
  90. Routine Description:
  91. This routine is the entry point for the e100 driver. It registers its other
  92. dispatch functions, and performs driver-wide initialization.
  93. Arguments:
  94. Driver - Supplies a pointer to the driver object.
  95. Return Value:
  96. STATUS_SUCCESS on success.
  97. Failure code on error.
  98. --*/
  99. {
  100. DRIVER_FUNCTION_TABLE FunctionTable;
  101. KSTATUS Status;
  102. DweDriver = Driver;
  103. RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
  104. FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
  105. FunctionTable.AddDevice = DweAddDevice;
  106. FunctionTable.DispatchStateChange = DweDispatchStateChange;
  107. FunctionTable.DispatchOpen = DweDispatchOpen;
  108. FunctionTable.DispatchClose = DweDispatchClose;
  109. FunctionTable.DispatchIo = DweDispatchIo;
  110. FunctionTable.DispatchSystemControl = DweDispatchSystemControl;
  111. Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
  112. return Status;
  113. }
  114. KSTATUS
  115. DweAddDevice (
  116. PVOID Driver,
  117. PSTR DeviceId,
  118. PSTR ClassId,
  119. PSTR CompatibleIds,
  120. PVOID DeviceToken
  121. )
  122. /*++
  123. Routine Description:
  124. This routine is called when a device is detected for which the e100 driver
  125. acts as the function driver. The driver will attach itself to the stack.
  126. Arguments:
  127. Driver - Supplies a pointer to the driver being called.
  128. DeviceId - Supplies a pointer to a string with the device ID.
  129. ClassId - Supplies a pointer to a string containing the device's class ID.
  130. CompatibleIds - Supplies a pointer to a string containing device IDs
  131. that would be compatible with this device.
  132. DeviceToken - Supplies an opaque token that the driver can use to identify
  133. the device in the system. This token should be used when attaching to
  134. the stack.
  135. Return Value:
  136. STATUS_SUCCESS on success.
  137. Failure code if the driver was unsuccessful in attaching itself.
  138. --*/
  139. {
  140. PDWE_DEVICE Device;
  141. KSTATUS Status;
  142. Device = MmAllocateNonPagedPool(sizeof(DWE_DEVICE), DWE_ALLOCATION_TAG);
  143. if (Device == NULL) {
  144. Status = STATUS_INSUFFICIENT_RESOURCES;
  145. goto AddDeviceEnd;
  146. }
  147. RtlZeroMemory(Device, sizeof(DWE_DEVICE));
  148. Device->InterruptHandle = INVALID_HANDLE;
  149. Device->OsDevice = DeviceToken;
  150. Status = IoAttachDriverToDevice(Driver, DeviceToken, Device);
  151. if (!KSUCCESS(Status)) {
  152. goto AddDeviceEnd;
  153. }
  154. AddDeviceEnd:
  155. if (!KSUCCESS(Status)) {
  156. if (Device != NULL) {
  157. MmFreeNonPagedPool(Device);
  158. Device = NULL;
  159. }
  160. }
  161. return Status;
  162. }
  163. VOID
  164. DweDispatchStateChange (
  165. PIRP Irp,
  166. PVOID DeviceContext,
  167. PVOID IrpContext
  168. )
  169. /*++
  170. Routine Description:
  171. This routine handles State Change IRPs.
  172. Arguments:
  173. Irp - Supplies a pointer to the I/O request packet.
  174. DeviceContext - Supplies the context pointer supplied by the driver when it
  175. attached itself to the driver stack. Presumably this pointer contains
  176. driver-specific device context.
  177. IrpContext - Supplies the context pointer supplied by the driver when
  178. the IRP was created.
  179. Return Value:
  180. None.
  181. --*/
  182. {
  183. KSTATUS Status;
  184. ASSERT(Irp->MajorCode == IrpMajorStateChange);
  185. if (Irp->Direction == IrpUp) {
  186. switch (Irp->MinorCode) {
  187. case IrpMinorQueryResources:
  188. Status = DwepProcessResourceRequirements(Irp);
  189. if (!KSUCCESS(Status)) {
  190. IoCompleteIrp(DweDriver, Irp, Status);
  191. }
  192. break;
  193. case IrpMinorStartDevice:
  194. Status = DwepStartDevice(Irp, DeviceContext);
  195. if (!KSUCCESS(Status)) {
  196. IoCompleteIrp(DweDriver, Irp, Status);
  197. }
  198. break;
  199. default:
  200. break;
  201. }
  202. }
  203. return;
  204. }
  205. VOID
  206. DweDispatchOpen (
  207. PIRP Irp,
  208. PVOID DeviceContext,
  209. PVOID IrpContext
  210. )
  211. /*++
  212. Routine Description:
  213. This routine handles Open IRPs.
  214. Arguments:
  215. Irp - Supplies a pointer to the I/O request packet.
  216. DeviceContext - Supplies the context pointer supplied by the driver when it
  217. attached itself to the driver stack. Presumably this pointer contains
  218. driver-specific device context.
  219. IrpContext - Supplies the context pointer supplied by the driver when
  220. the IRP was created.
  221. Return Value:
  222. None.
  223. --*/
  224. {
  225. return;
  226. }
  227. VOID
  228. DweDispatchClose (
  229. PIRP Irp,
  230. PVOID DeviceContext,
  231. PVOID IrpContext
  232. )
  233. /*++
  234. Routine Description:
  235. This routine handles Close IRPs.
  236. Arguments:
  237. Irp - Supplies a pointer to the I/O request packet.
  238. DeviceContext - Supplies the context pointer supplied by the driver when it
  239. attached itself to the driver stack. Presumably this pointer contains
  240. driver-specific device context.
  241. IrpContext - Supplies the context pointer supplied by the driver when
  242. the IRP was created.
  243. Return Value:
  244. None.
  245. --*/
  246. {
  247. return;
  248. }
  249. VOID
  250. DweDispatchIo (
  251. PIRP Irp,
  252. PVOID DeviceContext,
  253. PVOID IrpContext
  254. )
  255. /*++
  256. Routine Description:
  257. This routine handles I/O IRPs.
  258. Arguments:
  259. Irp - Supplies a pointer to the I/O request packet.
  260. DeviceContext - Supplies the context pointer supplied by the driver when it
  261. attached itself to the driver stack. Presumably this pointer contains
  262. driver-specific device context.
  263. IrpContext - Supplies the context pointer supplied by the driver when
  264. the IRP was created.
  265. Return Value:
  266. None.
  267. --*/
  268. {
  269. return;
  270. }
  271. VOID
  272. DweDispatchSystemControl (
  273. PIRP Irp,
  274. PVOID DeviceContext,
  275. PVOID IrpContext
  276. )
  277. /*++
  278. Routine Description:
  279. This routine handles System Control IRPs.
  280. Arguments:
  281. Irp - Supplies a pointer to the I/O request packet.
  282. DeviceContext - Supplies the context pointer supplied by the driver when it
  283. attached itself to the driver stack. Presumably this pointer contains
  284. driver-specific device context.
  285. IrpContext - Supplies the context pointer supplied by the driver when
  286. the IRP was created.
  287. Return Value:
  288. None.
  289. --*/
  290. {
  291. PDWE_DEVICE Device;
  292. PSYSTEM_CONTROL_DEVICE_INFORMATION DeviceInformationRequest;
  293. KSTATUS Status;
  294. ASSERT(Irp->MajorCode == IrpMajorSystemControl);
  295. Device = DeviceContext;
  296. if (Irp->Direction == IrpDown) {
  297. switch (Irp->MinorCode) {
  298. case IrpMinorSystemControlDeviceInformation:
  299. DeviceInformationRequest = Irp->U.SystemControl.SystemContext;
  300. Status = NetGetSetLinkDeviceInformation(
  301. Device->NetworkLink,
  302. &(DeviceInformationRequest->Uuid),
  303. DeviceInformationRequest->Data,
  304. &(DeviceInformationRequest->DataSize),
  305. DeviceInformationRequest->Set);
  306. IoCompleteIrp(DweDriver, Irp, Status);
  307. break;
  308. default:
  309. break;
  310. }
  311. }
  312. return;
  313. }
  314. KSTATUS
  315. DwepAddNetworkDevice (
  316. PDWE_DEVICE Device
  317. )
  318. /*++
  319. Routine Description:
  320. This routine adds the device to core networking's available links.
  321. Arguments:
  322. Device - Supplies a pointer to the device to add.
  323. Return Value:
  324. Status code.
  325. --*/
  326. {
  327. PNET_PACKET_SIZE_INFORMATION PacketSizeInformation;
  328. NET_LINK_PROPERTIES Properties;
  329. KSTATUS Status;
  330. if (Device->NetworkLink != NULL) {
  331. Status = STATUS_SUCCESS;
  332. goto AddNetworkDeviceEnd;
  333. }
  334. //
  335. // Add a link to the core networking library.
  336. //
  337. RtlZeroMemory(&Properties, sizeof(NET_LINK_PROPERTIES));
  338. Properties.Version = NET_LINK_PROPERTIES_VERSION;
  339. Properties.TransmitAlignment = 1;
  340. Properties.Device = Device->OsDevice;
  341. Properties.DeviceContext = Device;
  342. PacketSizeInformation = &(Properties.PacketSizeInformation);
  343. PacketSizeInformation->MaxPacketSize = DWE_RECEIVE_FRAME_DATA_SIZE;
  344. Properties.DataLinkType = NetDomainEthernet;
  345. Properties.MaxPhysicalAddress = MAX_ULONG;
  346. Properties.PhysicalAddress.Domain = NetDomainEthernet;
  347. ASSERT(Device->MacAddressAssigned != FALSE);
  348. RtlCopyMemory(&(Properties.PhysicalAddress.Address),
  349. &(Device->MacAddress),
  350. sizeof(Device->MacAddress));
  351. Properties.Interface.Send = DweSend;
  352. Properties.Interface.GetSetInformation = DweGetSetInformation;
  353. Properties.Interface.DestroyLink = DweDestroyLink;
  354. Properties.ChecksumFlags = NET_LINK_CHECKSUM_FLAG_TRANSMIT_IP_OFFLOAD |
  355. NET_LINK_CHECKSUM_FLAG_TRANSMIT_UDP_OFFLOAD |
  356. NET_LINK_CHECKSUM_FLAG_TRANSMIT_TCP_OFFLOAD |
  357. NET_LINK_CHECKSUM_FLAG_RECEIVE_IP_OFFLOAD |
  358. NET_LINK_CHECKSUM_FLAG_RECEIVE_TCP_OFFLOAD |
  359. NET_LINK_CHECKSUM_FLAG_RECEIVE_UDP_OFFLOAD;
  360. Device->ChecksumFlags = Properties.ChecksumFlags;
  361. Status = NetAddLink(&Properties, &(Device->NetworkLink));
  362. if (!KSUCCESS(Status)) {
  363. goto AddNetworkDeviceEnd;
  364. }
  365. AddNetworkDeviceEnd:
  366. if (!KSUCCESS(Status)) {
  367. if (Device->NetworkLink != NULL) {
  368. NetRemoveLink(Device->NetworkLink);
  369. Device->NetworkLink = NULL;
  370. }
  371. }
  372. return Status;
  373. }
  374. VOID
  375. DweDestroyLink (
  376. PVOID DeviceContext
  377. )
  378. /*++
  379. Routine Description:
  380. This routine notifies the device layer that the networking core is in the
  381. process of destroying the link and will no longer call into the device for
  382. this link. This allows the device layer to release any context that was
  383. supporting the device link interface.
  384. Arguments:
  385. DeviceContext - Supplies a pointer to the device context associated with
  386. the link being destroyed.
  387. Return Value:
  388. None.
  389. --*/
  390. {
  391. return;
  392. }
  393. //
  394. // --------------------------------------------------------- Internal Functions
  395. //
  396. KSTATUS
  397. DwepProcessResourceRequirements (
  398. PIRP Irp
  399. )
  400. /*++
  401. Routine Description:
  402. This routine filters through the resource requirements presented by the
  403. bus for an e100 LAN controller. It adds an interrupt vector requirement for
  404. any interrupt line requested.
  405. Arguments:
  406. Irp - Supplies a pointer to the I/O request packet.
  407. Return Value:
  408. Status code.
  409. --*/
  410. {
  411. PRESOURCE_CONFIGURATION_LIST Requirements;
  412. KSTATUS Status;
  413. RESOURCE_REQUIREMENT VectorRequirement;
  414. ASSERT((Irp->MajorCode == IrpMajorStateChange) &&
  415. (Irp->MinorCode == IrpMinorQueryResources));
  416. //
  417. // Initialize a nice interrupt vector requirement in preparation.
  418. //
  419. RtlZeroMemory(&VectorRequirement, sizeof(RESOURCE_REQUIREMENT));
  420. VectorRequirement.Type = ResourceTypeInterruptVector;
  421. VectorRequirement.Minimum = 0;
  422. VectorRequirement.Maximum = -1;
  423. VectorRequirement.Length = 1;
  424. //
  425. // Loop through all configuration lists, creating a vector for each line.
  426. //
  427. Requirements = Irp->U.QueryResources.ResourceRequirements;
  428. Status = IoCreateAndAddInterruptVectorsForLines(Requirements,
  429. &VectorRequirement);
  430. if (!KSUCCESS(Status)) {
  431. goto ProcessResourceRequirementsEnd;
  432. }
  433. ProcessResourceRequirementsEnd:
  434. return Status;
  435. }
  436. KSTATUS
  437. DwepStartDevice (
  438. PIRP Irp,
  439. PDWE_DEVICE Device
  440. )
  441. /*++
  442. Routine Description:
  443. This routine starts the DesignWare Ethernet device.
  444. Arguments:
  445. Irp - Supplies a pointer to the start IRP.
  446. Device - Supplies a pointer to the device information.
  447. Return Value:
  448. Status code.
  449. --*/
  450. {
  451. ULONG AlignmentOffset;
  452. PRESOURCE_ALLOCATION Allocation;
  453. PRESOURCE_ALLOCATION_LIST AllocationList;
  454. IO_CONNECT_INTERRUPT_PARAMETERS Connect;
  455. PRESOURCE_ALLOCATION ControllerBase;
  456. PHYSICAL_ADDRESS EndAddress;
  457. PRESOURCE_ALLOCATION LineAllocation;
  458. ULONG PageSize;
  459. PHYSICAL_ADDRESS PhysicalAddress;
  460. ULONG Size;
  461. KSTATUS Status;
  462. ControllerBase = NULL;
  463. //
  464. // Loop through the allocated resources to get the controller base and the
  465. // interrupt.
  466. //
  467. AllocationList = Irp->U.StartDevice.ProcessorLocalResources;
  468. Allocation = IoGetNextResourceAllocation(AllocationList, NULL);
  469. while (Allocation != NULL) {
  470. //
  471. // If the resource is an interrupt vector, then it should have an
  472. // owning interrupt line allocation.
  473. //
  474. if (Allocation->Type == ResourceTypeInterruptVector) {
  475. //
  476. // Currently only one interrupt resource is expected.
  477. //
  478. ASSERT(Device->InterruptResourcesFound == FALSE);
  479. ASSERT(Allocation->OwningAllocation != NULL);
  480. //
  481. // Save the line and vector number.
  482. //
  483. LineAllocation = Allocation->OwningAllocation;
  484. Device->InterruptLine = LineAllocation->Allocation;
  485. Device->InterruptVector = Allocation->Allocation;
  486. Device->InterruptResourcesFound = TRUE;
  487. //
  488. // Look for the first physical address reservation, the registers.
  489. //
  490. } else if (Allocation->Type == ResourceTypePhysicalAddressSpace) {
  491. if (ControllerBase == NULL) {
  492. ControllerBase = Allocation;
  493. }
  494. }
  495. //
  496. // Get the next allocation in the list.
  497. //
  498. Allocation = IoGetNextResourceAllocation(AllocationList, Allocation);
  499. }
  500. //
  501. // Fail to start if the controller base was not found.
  502. //
  503. if (ControllerBase == NULL) {
  504. Status = STATUS_INVALID_CONFIGURATION;
  505. goto StartDeviceEnd;
  506. }
  507. //
  508. // Map the controller.
  509. //
  510. if (Device->ControllerBase == NULL) {
  511. //
  512. // Page align the mapping request.
  513. //
  514. PageSize = MmPageSize();
  515. PhysicalAddress = ControllerBase->Allocation;
  516. EndAddress = PhysicalAddress + ControllerBase->Length;
  517. PhysicalAddress = ALIGN_RANGE_DOWN(PhysicalAddress, PageSize);
  518. AlignmentOffset = ControllerBase->Allocation - PhysicalAddress;
  519. EndAddress = ALIGN_RANGE_UP(EndAddress, PageSize);
  520. Size = (ULONG)(EndAddress - PhysicalAddress);
  521. Device->ControllerBase = MmMapPhysicalAddress(PhysicalAddress,
  522. Size,
  523. TRUE,
  524. FALSE,
  525. TRUE);
  526. if (Device->ControllerBase == NULL) {
  527. Status = STATUS_NO_MEMORY;
  528. goto StartDeviceEnd;
  529. }
  530. Device->ControllerBase += AlignmentOffset;
  531. }
  532. ASSERT(Device->ControllerBase != NULL);
  533. //
  534. // Allocate the controller structures.
  535. //
  536. Status = DwepInitializeDeviceStructures(Device);
  537. if (!KSUCCESS(Status)) {
  538. goto StartDeviceEnd;
  539. }
  540. //
  541. // Attempt to connect the interrupt.
  542. //
  543. ASSERT(Device->InterruptHandle == INVALID_HANDLE);
  544. RtlZeroMemory(&Connect, sizeof(IO_CONNECT_INTERRUPT_PARAMETERS));
  545. Connect.Version = IO_CONNECT_INTERRUPT_PARAMETERS_VERSION;
  546. Connect.Device = Irp->Device;
  547. Connect.LineNumber = Device->InterruptLine;
  548. Connect.Vector = Device->InterruptVector;
  549. Connect.InterruptServiceRoutine = DwepInterruptService;
  550. Connect.LowLevelServiceRoutine = DwepInterruptServiceWorker;
  551. Connect.Context = Device;
  552. Connect.Interrupt = &(Device->InterruptHandle);
  553. Status = IoConnectInterrupt(&Connect);
  554. if (!KSUCCESS(Status)) {
  555. goto StartDeviceEnd;
  556. }
  557. //
  558. // Start up the controller.
  559. //
  560. Status = DwepResetDevice(Device);
  561. if (!KSUCCESS(Status)) {
  562. goto StartDeviceEnd;
  563. }
  564. ASSERT(Device->NetworkLink != NULL);
  565. StartDeviceEnd:
  566. return Status;
  567. }