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.

496 lines
14 KiB

  1. /*****************************************************************************
  2. ** **
  3. ** COPYRIGHT (C) 2000, 2001 MKNET CORPORATION **
  4. ** DEVELOPED FOR THE MK7100-BASED VFIR PCI CONTROLLER. **
  5. ** **
  6. *****************************************************************************/
  7. /**********************************************************************
  8. Module Name:
  9. SEND.C
  10. Routines:
  11. MKMiniportMultiSend
  12. SendPkt
  13. PrepareForTransmit
  14. CopyFromPacketToBuffer
  15. MinTurnaroundTxTimeout
  16. [TestDataToTXBuff]
  17. Comments:
  18. Transmits in the NDIS env.
  19. **********************************************************************/
  20. #include "precomp.h"
  21. #include "protot.h"
  22. #pragma hdrstop
  23. #if DBG
  24. // for debug/test
  25. extern VOID TestDataToTXBuff(PCHAR, UINT, PUINT);
  26. #define TEST_PATTERN_SIZE 16
  27. CHAR TestPattern[] = {0,1,2,3,4,5,6,7,8,9,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F};
  28. #endif
  29. //-----------------------------------------------------------------------------
  30. // Procedure: [MKMiniportMultiSend]
  31. //
  32. // Description: This routine simply takes the pkt(s) passed down and queues
  33. // it to the trasmit queue (FirstTxQueue) for later processing. Each
  34. // pkt is marked NDIS_STATUS_PENDING) before returning.
  35. //
  36. // Arguments:
  37. // MiniportAdapterContext (Adapter Structure pointer)
  38. // PacketArray - an array of pointers to NDIS_PACKET structs
  39. // PacketCount - number of packets in PacketArray
  40. //
  41. // Returns: (none)
  42. //
  43. //-----------------------------------------------------------------------------
  44. VOID
  45. MKMiniportMultiSend(NDIS_HANDLE MiniportAdapterContext,
  46. PPNDIS_PACKET PacketArray,
  47. UINT NumberOfPackets)
  48. {
  49. PMK7_ADAPTER Adapter;
  50. NDIS_STATUS Status;
  51. UINT PacketCount;
  52. UINT i;
  53. PNDIS_PACKET QueuePacket;
  54. DBGFUNC("=> MKMiniportMultiSend");
  55. DBGLOG("=> MKMiniportMultiSend", 0);
  56. Adapter = PMK7_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
  57. NdisAcquireSpinLock(&Adapter->Lock);
  58. #if DBG
  59. Adapter->DbgSendCallCnt++;
  60. GDbgStat.txSndCnt++;
  61. Adapter->DbgSentCnt++;
  62. Adapter->DbgSentPktsCnt += NumberOfPackets;
  63. #endif
  64. // Q 'em up 1st
  65. for(PacketCount=0; PacketCount < NumberOfPackets; PacketCount++) {
  66. Adapter->NumPacketsQueued++;
  67. EnqueuePacket( Adapter->FirstTxQueue,
  68. Adapter->LastTxQueue,
  69. PacketArray[PacketCount] );
  70. NDIS_SET_PACKET_STATUS(PacketArray[PacketCount], NDIS_STATUS_PENDING);
  71. }
  72. if (Adapter->writePending || (Adapter->IOMode == TX_MODE)) {
  73. // In TX mode: Meaning TX outstanding. We wait for the TX comp to kick
  74. // off the next TX.
  75. // Or we have writePending, which means a pkt is on q waiting for
  76. // MinTurnaroundTimeout.
  77. DBGLOG("<= MKMiniportMultiSend: TX_MODE", 0);
  78. NdisReleaseSpinLock(&Adapter->Lock);
  79. return;
  80. }
  81. ASSERT(Adapter->tcbUsed == 0);
  82. QueuePacket = Adapter->FirstTxQueue;
  83. Status = SendPkt(Adapter, QueuePacket);
  84. DBGLOG("<= MKMiniportMultiSend", 0);
  85. NdisReleaseSpinLock(&Adapter->Lock);
  86. MK7EnableInterrupt(Adapter);
  87. }
  88. //-----------------------------------------------------------------------------
  89. // Procedure: [SendPkt]
  90. //
  91. // Description: This sets up (copies) the pkt to the TX ring data buffer in
  92. // preparation for TX. The caller then needs to Enable Int & Prompt to
  93. // initiate the actual tx at hw level.
  94. //
  95. // Arguments:
  96. // Adapter - ptr to Adapter object instance
  97. // Packet - A pointer to a descriptor for the packet that is to be
  98. // transmitted.
  99. // Returns:
  100. // NDIS_STATUS_SUCCESS - We copied the entire packet into a TRD data buff,
  101. // so we can immediately return the packet/buffer
  102. // back to the upper layers.
  103. // NDIS_STATUS_RESOURCE - No resource. NDIS should re-send this to us
  104. // at a later time. (Caller should re-Q the pkt.)
  105. //----------------------------------------------------------------------
  106. NDIS_STATUS
  107. SendPkt( PMK7_ADAPTER Adapter,
  108. PNDIS_PACKET Packet)
  109. {
  110. PTCB tcb;
  111. UINT bytestosend, sndcnt, nextavail;
  112. MK7REG mk7reg;
  113. BOOLEAN timeout;
  114. PNDIS_IRDA_PACKET_INFO packetInfo;
  115. PNDIS_PACKET QueuePacket;
  116. //****************************************
  117. // To send a pkt we do the following:
  118. // 1. Check Min Turnaround Time.
  119. // 2. Check if there's avail TX resource. It not we return "resource".
  120. // (We assume that there's outstanding TXs to trigger subseuqent TX
  121. // completion interrupts, which will keep the ball rolling.)
  122. // (RYM-IRDA-5+ Need to talk to Wayne about missed interrupts.)
  123. // 3. Copy the NDIS pkt into the contiguous TX buffer.
  124. // 4. The copied pkt could have been marked as the last pkt to go out
  125. // at the old speed after which we change speed. We check for this.
  126. //****************************************
  127. DBGFUNC("=> SendPkt");
  128. DBGLOG("=> SendPkt", 0);
  129. packetInfo = GetPacketInfo(Packet);
  130. if (packetInfo->MinTurnAroundTime) {
  131. UINT usecToWait = packetInfo->MinTurnAroundTime;
  132. UINT msecToWait;
  133. packetInfo->MinTurnAroundTime = 0;
  134. DBGLOG("<= SendPkt: Delay TX", 0);
  135. // Need to set IOMode = TX so if a multisend comes down before
  136. // the delayed TX timer goes off we just q.
  137. // Ndis timer has a 1ms granularity (in theory). Let's round off.
  138. msecToWait = (usecToWait<1000) ? 1 : (usecToWait+500)/1000;
  139. NdisMSetTimer(&Adapter->MinTurnaroundTxTimer, msecToWait);
  140. // 4.0.1 BOC
  141. MK7SwitchToTXMode(Adapter);
  142. // 4.0.1 EOC
  143. Adapter->writePending = TRUE;
  144. return (NDIS_STATUS_PENDING); // Say we're successful. We'll come back here.
  145. }
  146. // Avail TX resource
  147. if (Adapter->tcbUsed >= Adapter->NumTcb) {
  148. #if DBG
  149. GDbgStat.txNoTcb++;
  150. #endif
  151. DBGSTR(("STATUS (SendPkt): No avail TCB\n"));
  152. return (NDIS_STATUS_RESOURCES);
  153. }
  154. tcb = Adapter->pTcbArray[Adapter->nextAvailTcbIdx];
  155. bytestosend = PrepareForTransmit(Adapter, Packet, tcb);
  156. if (Adapter->changeSpeedAfterThisPkt == Packet) {
  157. Adapter->changeSpeedAfterThisPkt = NULL;
  158. Adapter->changeSpeedPending = CHANGESPEED_ON_DONE;
  159. }
  160. #if DBG
  161. if (bytestosend > GDbgStat.txLargestPkt) {
  162. GDbgStat.txLargestPkt = bytestosend;
  163. }
  164. #endif
  165. // 1.0.0
  166. if (bytestosend == 0) {
  167. #if DBG
  168. DbgPrint ("==> OB \n\r");
  169. #endif
  170. // Simplified change speed
  171. if (Adapter->changeSpeedPending == CHANGESPEED_ON_DONE) {
  172. // Note: We're changing speed in TX mode.
  173. MK7ChangeSpeedNow(Adapter);
  174. Adapter->changeSpeedPending = 0;
  175. }
  176. // For each completing TX there's a corresponding q'd pkt.
  177. // We release it here.
  178. QueuePacket = Adapter->FirstTxQueue;
  179. DequeuePacket(Adapter->FirstTxQueue, Adapter->LastTxQueue);
  180. Adapter->NumPacketsQueued--;
  181. NDIS_SET_PACKET_STATUS(QueuePacket, NDIS_STATUS_RESOURCES);
  182. NdisMSendComplete( Adapter->MK7AdapterHandle,
  183. QueuePacket,
  184. NDIS_STATUS_RESOURCES);
  185. return(NDIS_STATUS_RESOURCES);
  186. }
  187. // Take care of ring wrap when incrementing.
  188. Adapter->nextAvailTcbIdx++;
  189. Adapter->nextAvailTcbIdx %= Adapter->NumTcb;
  190. Adapter->tcbUsed++;
  191. tcb->trd->count = bytestosend;
  192. GrantTrdToHw(tcb->trd);
  193. MK7SwitchToTXMode(Adapter);
  194. #if DBG
  195. NdisGetCurrentSystemTime((PLARGE_INTEGER)&GDbgTACmdTime[GDbgTATimeIdx]);
  196. #endif
  197. DBGLOG("<= SendPkt", 0);
  198. return (NDIS_STATUS_SUCCESS);
  199. }
  200. //-----------------------------------------------------------------------------
  201. // Procedure: [PrepareForTransmit]
  202. //
  203. // Description: When we come here we know there's an available TCB for the next
  204. // TX. We move the Packet data into the tx buff associated w/ the TCB.
  205. //
  206. // Arguments:
  207. // Adapter - ptr to Adapter object instance
  208. // Packet - A pointer to a descriptor for the packet that is to be
  209. // transmitted.
  210. // SwTcb - Pointer to a software structure that represents a hardware TCB.
  211. //
  212. // Returns:
  213. // TRUE If we were able to acquire the necessary TRD's or Coalesce buffer
  214. // for the packet in we are attempting to prepare for transmission.
  215. // FALSE If we needed a coalesce buffer, and we didn't have any available.
  216. //-----------------------------------------------------------------------------
  217. UINT PrepareForTransmit(PMK7_ADAPTER Adapter,
  218. PNDIS_PACKET Packet,
  219. PTCB tcb)
  220. {
  221. UINT BytesCopied;
  222. if (Adapter->CurrentSpeed <= MAX_SIR_SPEED) {
  223. // SIR needs additional software process
  224. if ( NdisToSirPacket(Adapter,
  225. Packet,
  226. (UCHAR *)tcb->buff,
  227. MK7_MAXIMUM_PACKET_SIZE,
  228. &BytesCopied) ) {
  229. return(BytesCopied);
  230. }
  231. return(0);
  232. }
  233. #if DBG
  234. if (Adapter->DbgTestDataCnt > 0) {
  235. TestDataToTXBuff(tcb->buff, Adapter->DbgTestDataCnt, &BytesCopied);
  236. return(BytesCopied);
  237. }
  238. #endif
  239. tcb->Packet = Packet;
  240. NdisQueryPacket(tcb->Packet,
  241. &tcb->NumPhysDesc,
  242. &tcb->BufferCount,
  243. &tcb->FirstBuffer,
  244. &tcb->PacketLength);
  245. // Alignment??
  246. //
  247. // Copy from packet to TCB data buffer
  248. CopyFromPacketToBuffer( Adapter,
  249. tcb->Packet,
  250. tcb->PacketLength,
  251. tcb->buff,
  252. tcb->FirstBuffer,
  253. &BytesCopied );
  254. // ASSERT(BytesCopied == tcb->PacketLength);
  255. if (BytesCopied != tcb->PacketLength) {
  256. #if DBG
  257. DbgPrint (" ==> BytesCopied Unmatched\n\r");
  258. #endif
  259. return(0);
  260. }
  261. else
  262. return(BytesCopied);
  263. }
  264. //-----------------------------------------------------------------------------
  265. // Procedure: [CopyFromPacketToBuffer]
  266. //
  267. // Description: This routine will copy a packet to a the passed buffer (which
  268. // in this case will be a coalesce buffer).
  269. //
  270. // Arguments:
  271. // Adapter - ptr to Adapter object instance
  272. // Packet - The packet to copy from.
  273. // BytesToCopy - The number of bytes to copy from the packet.
  274. // DestBuffer - The destination of the copy.
  275. // FirstBuffer - The first buffer of the packet that we are copying from.
  276. //
  277. // Result:
  278. // BytesCopied - The number of bytes actually copied
  279. //
  280. // Returns: (none)
  281. //-----------------------------------------------------------------------------
  282. VOID
  283. CopyFromPacketToBuffer( PMK7_ADAPTER Adapter,
  284. PNDIS_PACKET Packet,
  285. UINT BytesToCopy,
  286. PCHAR DestBuffer,
  287. PNDIS_BUFFER FirstBuffer,
  288. PUINT BytesCopied)
  289. {
  290. PNDIS_BUFFER CurrentBuffer, NextBuffer;
  291. PVOID VirtualAddress;
  292. UINT CurrentLength;
  293. UINT AmountToMove;
  294. *BytesCopied = 0;
  295. if (!BytesToCopy)
  296. return;
  297. if (FirstBuffer == NULL)
  298. return;
  299. CurrentBuffer = FirstBuffer;
  300. while (CurrentBuffer != NULL) {
  301. NdisQueryBufferSafe(CurrentBuffer, &VirtualAddress, &CurrentLength, 16);
  302. if (!VirtualAddress) {
  303. #if DBG
  304. DbgPrint("==> Throw Away Failed Packet\n\r");
  305. #endif
  306. return;
  307. }
  308. NdisGetNextBuffer(CurrentBuffer, &NextBuffer);
  309. CurrentBuffer = NextBuffer;
  310. }
  311. CurrentBuffer = FirstBuffer;
  312. // NDIS requirement
  313. // NdisQueryBuffer(CurrentBuffer,&VirtualAddress,&CurrentLength);
  314. NdisQueryBufferSafe(CurrentBuffer, &VirtualAddress, &CurrentLength, 16);
  315. while (BytesToCopy) {
  316. while (!CurrentLength) {
  317. NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer);
  318. // If we've reached the end of the packet. We return with what
  319. // we've done so far (which must be shorter than requested).
  320. if (!CurrentBuffer)
  321. return;
  322. // NDIS requirement
  323. // NdisQueryBuffer(CurrentBuffer,&VirtualAddress,&CurrentLength);
  324. NdisQueryBufferSafe(CurrentBuffer, &VirtualAddress, &CurrentLength, 16);
  325. }
  326. // Compute how much data to move from this fragment
  327. if (CurrentLength > BytesToCopy)
  328. AmountToMove = BytesToCopy;
  329. else
  330. AmountToMove = CurrentLength;
  331. // Copy the data.
  332. NdisMoveMemory(DestBuffer, VirtualAddress, AmountToMove);
  333. // Update destination pointer
  334. DestBuffer = (PCHAR) DestBuffer + AmountToMove;
  335. // Update counters
  336. *BytesCopied +=AmountToMove;
  337. BytesToCopy -=AmountToMove;
  338. CurrentLength = 0;
  339. }
  340. DBGLOG(" CopyFromPacketToBuffer: Bytes to Copy = ", BytesToCopy);
  341. DBGLOG(" CopyFromPacketToBuffer: Bytes Copied = ", *BytesCopied);
  342. }
  343. //-----------------------------------------------------------------------------
  344. // Procedure: [MinTurnaroundTxTimeout] RYM-2K-1TX
  345. //
  346. // Description: Delayed write because of Min Turnaround requirement. Just
  347. // do send.
  348. //-----------------------------------------------------------------------------
  349. VOID MinTurnaroundTxTimeout(PVOID sysspiff1,
  350. NDIS_HANDLE MiniportAdapterContext,
  351. PVOID sysspiff2,
  352. PVOID sysspiff3)
  353. {
  354. PMK7_ADAPTER Adapter;
  355. PNDIS_PACKET QueuePacket;
  356. NDIS_STATUS Status;
  357. Adapter = PMK7_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
  358. DBGLOG("=> MinTurnaroundTxTimeout", 0);
  359. NdisAcquireSpinLock(&Adapter->Lock);
  360. QueuePacket = Adapter->FirstTxQueue;
  361. if (!QueuePacket) {
  362. NdisReleaseSpinLock(&Adapter->Lock);
  363. return;
  364. }
  365. Status = SendPkt(Adapter, QueuePacket);
  366. // Note: We set false here because we just processed a q'd TX pkt
  367. // that was waiting for MinTurnaround. However, we may still stay
  368. // in TX mode based on other pkts on the q. This is determined in
  369. // TX comp. Either writePending or IOMode will prevent new pkts
  370. // from above to get thru out of sequence.
  371. Adapter->writePending = FALSE;
  372. NdisReleaseSpinLock(&Adapter->Lock);
  373. MK7EnableInterrupt(Adapter);
  374. }
  375. #if DBG
  376. //--------------------------------------------------------------------------------
  377. // Procedure: [TestDataToTXBuff]
  378. //
  379. // Description: Put test data in tx buff instead of data that came down.
  380. //--------------------------------------------------------------------------------
  381. VOID TestDataToTXBuff( PCHAR DestBuffer,
  382. UINT BytesToCopy,
  383. PUINT BytesCopied)
  384. {
  385. UINT i, j;
  386. for(i=0,j=0; j<BytesToCopy; j++) {
  387. DestBuffer[j] = TestPattern[i];
  388. i++;
  389. i %= TEST_PATTERN_SIZE;
  390. }
  391. *BytesCopied = BytesToCopy;
  392. }
  393. #endif