ixp425PciDma.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:20k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* ixp425PciDma.c - PCI DMA driver for the IXP425 */
  2. /* Copyright 2002 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01a,05jun02,jb  initial version...
  7. */
  8. /*
  9. DESCRIPTION
  10. This is device driver code for the Intel IXP425 PCI DMA unit.
  11. In order for the functionality defined herein to be available,
  12. INCLUDE_PCI and INCLUDE_PCI_DMA must be defined in config.h
  13. The DMA controller has two unidirectional channels. PCI to AHB transfers are
  14. performed on the PTA channel, while AHB to PCI transfers are performed on the
  15. ATP channel.
  16. Each channel has two sets of registers which accept transfer requests. These
  17. registers are provided to ensure maximum bandwidth utilisation. As soon as 
  18. the transfer corresponding to the data written to one set of registers completes
  19. the transfer corresponding to the data in the second set commences.
  20. SEE ALSO:
  21. ixp425Pci.c
  22. */
  23. /*
  24.  * system defined include files required.
  25.  */
  26. #include "vxWorks.h"
  27. #include "config.h"
  28. #include "dllLib.h"
  29. #include "intLib.h"
  30. #include "netBufLib.h"
  31. /*
  32.  * user defined include files required.
  33.  */
  34. #include "ixp425Pci.h"
  35. #include "ixp425Pci_p.h"
  36. /*
  37.  * Typedefs whose scope is limited to this file.
  38.  */
  39. typedef struct pciDmaRequest
  40. {
  41.     void *buffer;
  42.     void *pciAddr;
  43.     UINT32 length;
  44.     PCICALLBACKFUNC callback; /* ISR context callback*/
  45.     UINT32 parameter;
  46. } PCI_DMA_REQUEST;
  47. /*
  48.  * Variable declarations global to this file only.  Externs are followed by
  49.  * static variables.
  50.  */
  51. extern STATUS pciLibInitStatus;       
  52. /*These descriptors represent the transfers that have been written to the 
  53.   transfer registers in the controller*/
  54. LOCAL PCI_DMA_REQUEST currAtp0;
  55. LOCAL PCI_DMA_REQUEST currAtp1;
  56. LOCAL PCI_DMA_REQUEST currPta0;
  57. LOCAL PCI_DMA_REQUEST currPta1;
  58. /*The following are variables used to implement circular queues for
  59.   queueing DMA transfer requests
  60.   The value of [atp|pta]RequestQueueSize is used herein to track the 
  61.   current state of the transfers.
  62.   
  63.   Value                        Meaning
  64.   0                            No requests are active or queued, all requests 
  65.                                have been processed and are complete
  66.   1                            There is a single transfer currently executing,
  67.                                and one triplet of registers is vacant, we use
  68.        freeRegs to track which set.
  69.   2                            There is one DMA transfer executing and another has
  70.                                been set up and is pending in the other register triplet.
  71.   3                            One DMA transfer is executing, another is pending in 
  72.                                the second register triplet, while a third is pending on
  73.        the queue
  74.   4 and above                  One DMA transfer is executing, another is pending in 
  75.                                the second register triplet, while 2 or more are pending on
  76.        the queue
  77. */
  78. LOCAL PCI_DMA_REQUEST atpRequestPool[NUM_REQ_POOL];
  79. LOCAL UINT32 atpRequestQueueHead = 0; 
  80. LOCAL UINT32 atpRequestQueueTail = 0;
  81. LOCAL UINT32 atpRequestQueueSize = 0;
  82. LOCAL PCI_DMA_REQUEST ptaRequestPool[NUM_REQ_POOL];
  83. LOCAL UINT32 ptaRequestQueueHead = 0; 
  84. LOCAL UINT32 ptaRequestQueueTail = 0;
  85. LOCAL UINT32 ptaRequestQueueSize = 0;
  86. /*
  87.  * function prototypes.
  88.  */
  89. void pciAtpIsr (int param);
  90. void pciPtaIsr (int param);
  91. /*
  92.  * Function definition.
  93.  */
  94. /**************************************************************************
  95. *
  96. * pciDmaInit - Initialize the PCI DMA controller
  97. *
  98. * This routine performes any required initialisation for the PCI DMA driver.
  99. * The PCI controller must be initialised before this function is called.
  100. *
  101. * RETURNS: OK on success, ERROR on failure
  102. */
  103. STATUS 
  104. pciDmaInit (void)
  105. {
  106.     UINT32 regval;
  107.     
  108.     if (pciLibInitStatus != OK)
  109.     {
  110.         return ERROR;
  111.     }
  112.     /*Clear any spurious completion indicators*/
  113.     regval = PCI_DMACTRL_APDCEN | PCI_DMACTRL_APDC0 | PCI_DMACTRL_APDC1 
  114. | PCI_DMACTRL_PADCEN | PCI_DMACTRL_PADC0 | PCI_DMACTRL_PADC1;
  115.     REG_WRITE (PCI_CSR_BASE, PCI_DMACTRL_OFFSET, regval);
  116.     /*Enable PTA and ATP interrupts */
  117.     REG_READ (PCI_CSR_BASE, PCI_INTEN_OFFSET, regval);
  118.     regval |= PCI_INTEN_APDC | PCI_INTEN_PADC;
  119.     REG_WRITE (PCI_CSR_BASE, PCI_INTEN_OFFSET, regval);
  120.     /*initialize request queues*/
  121.     atpRequestQueueHead=0; 
  122.     atpRequestQueueTail=0;
  123.     atpRequestQueueSize=0;
  124.     ptaRequestQueueHead=0; 
  125.     ptaRequestQueueTail=0;
  126.     ptaRequestQueueSize=0;
  127.     return OK;
  128. }
  129. /*return the next available ATP transfer request from the ATP queue*/
  130. LOCAL PCI_DMA_REQUEST*
  131. atpTransferGet (void)
  132. {
  133.     PCI_DMA_REQUEST* req;
  134.     if (atpRequestQueueHead == atpRequestQueueTail)
  135.     {
  136. return NULL;
  137.     }
  138.     req = &atpRequestPool[atpRequestQueueHead];    
  139.     atpRequestQueueHead++;
  140.     atpRequestQueueHead %= NUM_REQ_POOL;
  141.     return req;
  142. }
  143. /*queue an ATP transfer*/
  144. LOCAL STATUS
  145. atpTransferAdd (void *buffer, 
  146. void *pciAddr, 
  147. UINT32 length, 
  148. PCICALLBACKFUNC callback,
  149. UINT32 parameter)
  150. {
  151.     PCI_DMA_REQUEST* req;
  152.     
  153.     if (((atpRequestQueueTail+1) % NUM_REQ_POOL) == atpRequestQueueHead )
  154.     { 
  155. /*No space*/
  156. return ERROR;
  157.     } 
  158.     else 
  159.     {
  160. req = &atpRequestPool[atpRequestQueueTail];
  161. req->buffer    = buffer;
  162. req->pciAddr   = pciAddr;
  163. req->length    = length;
  164. req->callback  = callback;
  165. req->parameter = parameter;
  166. atpRequestQueueTail++;
  167. atpRequestQueueTail %= NUM_REQ_POOL;
  168. return OK;
  169.     }
  170. }
  171. /*return the next available PTA transfer request from the PTA queue*/
  172. LOCAL PCI_DMA_REQUEST*
  173. ptaTransferGet (void)
  174. {
  175.     PCI_DMA_REQUEST* req;
  176.     if (ptaRequestQueueHead == ptaRequestQueueTail)
  177.     {
  178. return NULL;
  179.     }
  180.     req = &ptaRequestPool[ptaRequestQueueHead];    
  181.     ptaRequestQueueHead++;
  182.     ptaRequestQueueHead %= NUM_REQ_POOL;
  183.     return req;
  184. }
  185. /*queue a PTA transfer*/
  186. LOCAL STATUS
  187. ptaTransferAdd (void *buffer, 
  188. void *pciAddr, 
  189. UINT32 length, 
  190. PCICALLBACKFUNC callback,
  191. UINT32 parameter)
  192. {
  193.     PCI_DMA_REQUEST* req;
  194.     
  195.     if (((ptaRequestQueueTail+1) % NUM_REQ_POOL) == ptaRequestQueueHead )
  196.     { 
  197. /*No space*/
  198. return ERROR;
  199.     } 
  200.     else 
  201.     {
  202. req = &ptaRequestPool[ptaRequestQueueTail];
  203. req->buffer    = buffer;
  204. req->pciAddr   = pciAddr;
  205. req->length    = length;
  206. req->callback  = callback;
  207. req->parameter = parameter;
  208. ptaRequestQueueTail++;
  209. ptaRequestQueueTail %= NUM_REQ_POOL;
  210. return OK;
  211.     }
  212. }
  213. /**************************************************************************
  214. *
  215. * atpTransferInitiate - take a request from the queue and setup the registers
  216. *
  217. * This routine takes a DMA transfer request and sets up the
  218. * request by writing the relevant data to the control registers.
  219. *
  220. * RETURNS: N/A
  221. */
  222. LOCAL void 
  223. atpTransferInitiate (PCI_DMA_REQUEST* req)
  224. {
  225.     static UINT8 freeRegs=0;
  226.     if(req == NULL)
  227.     {
  228. return;
  229.     }        
  230.     /*put the addresses and length in the free registers*/
  231.     if (freeRegs==0)
  232.     {
  233. currAtp0.callback  = req->callback;
  234. currAtp0.parameter = req->parameter;
  235. REG_WRITE (PCI_CSR_BASE, PCI_ATPDMA0_AHBADDR, (UINT32)req->buffer);
  236. REG_WRITE (PCI_CSR_BASE, PCI_ATPDMA0_PCIADDR, (UINT32)req->pciAddr);
  237. REG_WRITE (PCI_CSR_BASE, PCI_ATPDMA0_LENADDR, (UINT32)(PCI_DMA_LEN_EN | req->length));
  238. /*we automatically set the freeRegs to the other set of registers, since 
  239.   we know that this function will not get invoked unless at least one set is free*/
  240. freeRegs=1;
  241.     }
  242.     else
  243.     {
  244. currAtp1.callback  = req->callback;
  245. currAtp1.parameter = req->parameter;
  246. REG_WRITE (PCI_CSR_BASE, PCI_ATPDMA1_AHBADDR, (UINT32)req->buffer);
  247. REG_WRITE (PCI_CSR_BASE, PCI_ATPDMA1_PCIADDR, (UINT32)req->pciAddr);
  248. REG_WRITE (PCI_CSR_BASE, PCI_ATPDMA1_LENADDR, (UINT32)(PCI_DMA_LEN_EN | req->length));
  249. freeRegs=0;
  250.     }    
  251. }
  252. /**************************************************************************
  253. *
  254. * ptaTransferInitiate - take a request from the queue and setup the registers
  255. *
  256. * This routine takes a DMA transfer request and sets up the
  257. * request by writing the relevant data to the control registers.
  258. *
  259. * RETURNS: void
  260. */
  261. LOCAL void 
  262. ptaTransferInitiate (PCI_DMA_REQUEST* req)
  263. {
  264.     static UINT8 freeRegs=0;
  265.     if(req == NULL)
  266.     {
  267. return;
  268.     }        
  269.     /*put the addresses and length in the specified registers*/
  270.     if (freeRegs==0)
  271.     {
  272. currPta0.callback  = req->callback;
  273. currPta0.parameter = req->parameter;
  274. REG_WRITE (PCI_CSR_BASE, PCI_PTADMA0_AHBADDR, (UINT32)req->buffer);
  275. REG_WRITE (PCI_CSR_BASE, PCI_PTADMA0_PCIADDR, (UINT32)req->pciAddr);
  276. REG_WRITE (PCI_CSR_BASE, PCI_PTADMA0_LENADDR, (UINT32)(PCI_DMA_LEN_EN | req->length));
  277. /*we automatically set the freeRegs to the other set of registers, since 
  278.   we know that this function will not get invoked unless at least one set is free*/
  279. freeRegs=1;
  280.     }
  281.     else
  282.     {
  283. currPta1.callback  = req->callback;
  284. currPta1.parameter = req->parameter;
  285. REG_WRITE (PCI_CSR_BASE, PCI_PTADMA1_AHBADDR, (UINT32)req->buffer);
  286. REG_WRITE (PCI_CSR_BASE, PCI_PTADMA1_PCIADDR, (UINT32)req->pciAddr);
  287. REG_WRITE (PCI_CSR_BASE, PCI_PTADMA1_LENADDR, (UINT32)(PCI_DMA_LEN_EN | req->length));
  288. freeRegs=0;
  289.     }    
  290. }
  291. /**************************************************************************
  292. *
  293. * pciAtpIsr - interrupt handler for ATP DMA channel
  294. *
  295. * This routine handles pci_atpdma_int interrupts. Such interrupts may indicate that 
  296. * one or both of the register sets' corresponding ATP DMA transfers have completed.
  297. *
  298. * RETURNS: N/A
  299. */
  300. void
  301. pciAtpIsr (int param)
  302. {
  303.     UINT32 regval;
  304.     UINT32 newval;
  305.     UINT32 key;
  306.     PCI_DMA_REQUEST lastReq0;
  307.     PCI_DMA_REQUEST lastReq1;
  308.     PCI_DMA_REQUEST* req;
  309.     UINT32 error0;
  310.     UINT32 error1;
  311.     if (atpRequestQueueSize == 0)
  312.     {
  313. return;
  314.     } 
  315.     key=intLock();
  316.     /*Check what caused the interrupt*/
  317.     REG_READ (PCI_CSR_BASE, PCI_DMACTRL_OFFSET, regval);
  318.     error0=0;
  319.     error1=0;
  320.     lastReq0.callback=NULL;
  321.     lastReq1.callback=NULL;
  322.     
  323.     if (regval & PCI_DMACTRL_APDC0)
  324.     {
  325. /*register set 0 transfer complete, enable completion interrupts
  326.  and clear the completion indicator*/
  327. newval =  (regval & PCI_DMACTRL_APDCEN) | (regval & PCI_DMACTRL_PADCEN)
  328.     | (PCI_DMACTRL_APDC0);
  329. REG_WRITE(PCI_CSR_BASE, PCI_DMACTRL_OFFSET, newval);
  330. lastReq0.callback = currAtp0.callback;
  331. lastReq0.parameter = currAtp0.parameter;
  332. error0 = regval & PCI_DMACTRL_APDE0;
  333. /*If there is a transfer queued, initiate it*/
  334. if (atpRequestQueueSize > 2)
  335. {
  336.     req=atpTransferGet ();    
  337.     atpTransferInitiate (req);
  338. }
  339. atpRequestQueueSize--;
  340.     }
  341.     /* note that this is intentionally a separate "if", and should never be an 
  342.        "else if" since both transfers can have completed by the time we read
  343.        the register*/    
  344.     if(regval & PCI_DMACTRL_APDC1)
  345.     {
  346. /*register set 1 transfer complete, enable completion interrupts
  347.  and clear the completion indicator*/
  348. newval =  (regval & PCI_DMACTRL_APDCEN) | (regval & PCI_DMACTRL_PADCEN )
  349.     | PCI_DMACTRL_APDC1;
  350. REG_WRITE(PCI_CSR_BASE, PCI_DMACTRL_OFFSET, newval);
  351. lastReq1.callback  = currAtp1.callback;
  352. lastReq1.parameter = currAtp1.parameter;
  353. error1 = regval & PCI_DMACTRL_APDE1;
  354. /*If there is a transfer queued, initiate it*/
  355. if (atpRequestQueueSize > 2)
  356. {
  357.     req = atpTransferGet ();    
  358.     atpTransferInitiate (req);
  359. }
  360. atpRequestQueueSize--;
  361.     }
  362.     /*This code would appear to be more at home within the body of the if 
  363.       blocks above, but the point of this control flow structure is to 
  364.       invoke the next atpTransferInitiate as soon as possible after
  365.       getting the interrupt, so that we maximize utilisation of the DMA
  366.       channel, so we obviously want to avoid invoking client code 
  367.       callbacks before initiating our transfer*/    
  368.     if (lastReq0.callback != NULL)
  369.     {
  370. if (error0 != 0)
  371. {
  372.     (lastReq0.callback)(PCI_ERROR, lastReq0.parameter);     
  373. }
  374. else
  375. {
  376.     (lastReq0.callback)(PCI_OK, lastReq0.parameter);     
  377. }    
  378.     }
  379.     
  380.     if (lastReq1.callback != NULL)
  381.     {
  382. if (error1 != 0)
  383. {
  384.     (lastReq1.callback)(PCI_ERROR, lastReq1.parameter);     
  385. }
  386. else
  387. {
  388.     (lastReq1.callback)(PCI_OK, lastReq1.parameter);     
  389. }    
  390.     }
  391.     
  392.     intUnlock(key);
  393.     return;
  394. }
  395. /**************************************************************************
  396. *
  397. * pciPtaIsr - interrupt handler for PTA DMA channel
  398. *
  399. * This routine handles pci_ptadma_int interrupts. Such interrupts may indicate that 
  400. * one or both of the register sets' corresponding PTA DMA transfers have completed.
  401. *
  402. * RETURNS: N/A
  403. */
  404. void
  405. pciPtaIsr (int param)
  406. {
  407.     UINT32 regval;
  408.     UINT32 newval;
  409.     UINT32 key;    
  410.     PCI_DMA_REQUEST lastReq0;
  411.     PCI_DMA_REQUEST lastReq1;
  412.     PCI_DMA_REQUEST *req;
  413.     UINT32 error0;
  414.     UINT32 error1;
  415.     if (ptaRequestQueueSize == 0)
  416.     {
  417. return;
  418.     } 
  419.     key=intLock();    
  420.     /*Check what caused the interrupt*/
  421.     REG_READ (PCI_CSR_BASE, PCI_DMACTRL_OFFSET, regval);
  422.     error0 = 0;
  423.     error1 = 0;
  424.     lastReq0.callback = NULL;
  425.     lastReq1.callback = NULL;
  426.     
  427.     if (regval & PCI_DMACTRL_PADC0)
  428.     {
  429. /*register set 0 transfer complete*/
  430. newval =  (regval & PCI_DMACTRL_APDCEN) | (regval & PCI_DMACTRL_PADCEN)
  431.           | (PCI_DMACTRL_PADC0);
  432. REG_WRITE(PCI_CSR_BASE, PCI_DMACTRL_OFFSET, newval);
  433. lastReq0.callback = currPta0.callback;
  434. lastReq0.parameter = currPta0.parameter;
  435. error0 = regval & PCI_DMACTRL_PADE0;
  436. /*If there is a transfer queued, initiate it*/
  437. if (ptaRequestQueueSize > 2)
  438. {
  439.     req=ptaTransferGet ();    
  440.     ptaTransferInitiate (req);
  441. }
  442. ptaRequestQueueSize--;
  443.     }
  444.     /* note that this is intentionally a separate "if", and should never be an 
  445.        "else if" since both transfers can have completed by the time we read
  446.        the register*/
  447.     if(regval & PCI_DMACTRL_PADC1)
  448.     {
  449. /*register set 1 transfer complete*/
  450. newval =  (regval & PCI_DMACTRL_APDCEN) | (regval & PCI_DMACTRL_PADCEN) 
  451.     | (PCI_DMACTRL_PADC1);
  452. REG_WRITE(PCI_CSR_BASE, PCI_DMACTRL_OFFSET, newval);
  453. lastReq1.callback = currPta1.callback;
  454. lastReq1.parameter = currPta1.parameter;
  455. error1 = regval & PCI_DMACTRL_PADE1;
  456. /*If there is a transfer queued, initiate it*/
  457. if (ptaRequestQueueSize > 2)
  458. {
  459.     req=ptaTransferGet ();    
  460.     ptaTransferInitiate (req);
  461. }
  462. ptaRequestQueueSize--;
  463.     }
  464.     
  465.     /*This code would appear to be more at home within the body of the if 
  466.       blocks above, but the point of this control flow structure is to 
  467.       invoke the next ptaTransferInitiate as soon as possible after
  468.       getting the interrupt, so that we maximize utilisation of the DMA
  469.       channel, so we obviously want to avoid invoking client code 
  470.       callbacks before initiating our transfer*/    
  471.     if (lastReq0.callback != NULL)
  472.     {
  473. if (error0 != 0)
  474. {
  475.     (lastReq0.callback)(PCI_ERROR, lastReq0.parameter);
  476. }
  477. else
  478. {
  479.     (lastReq0.callback)(PCI_OK, lastReq0.parameter);
  480. }
  481.     }
  482.     /*Again, both requests may have completed so this is not an "else if"*/
  483.     if (lastReq1.callback != NULL)
  484.     {
  485. if (error1 != 0)
  486. {
  487.     (lastReq1.callback)(PCI_ERROR, lastReq1.parameter);
  488. }
  489. else
  490. {
  491.     (lastReq1.callback)(PCI_OK, lastReq1.parameter);
  492. }
  493.     }
  494.     intUnlock(key);
  495.     return;
  496. }
  497. /**********************************************
  498. *
  499. * pciDmaTransfer - transfer a block of data using DMA
  500. *
  501. * This routine sets up a DMA transfer. If possible, it initiates
  502. * the transfer immediately, otherwise it adds it to a queue.
  503. * The destination and source addresses must be 4-byte aligned.
  504. *
  505. * RETURNS: OK or ERROR if invalid parameters are supplied, or if the 
  506. * relevant queue is full.
  507. */
  508. STATUS 
  509. pciDmaTransfer (void *buffer, 
  510. void *pciAddr,
  511. UINT32 direction,
  512. UINT32 length,
  513. PCICALLBACKFUNC callback,
  514. UINT32 parameter)
  515. {   
  516.     UINT32 key;
  517.     PCI_DMA_REQUEST newTransfer;
  518.     
  519.     if (length > IXP425_PCI_DMA_MAX_LEN)
  520.     {
  521. return ERROR;
  522.     }
  523.     /*Check alignment of addresses*/
  524.     if (((UINT32)buffer & (UINT32)0x3) != 0)
  525.     {
  526. return ERROR;
  527.     }
  528.     if (((UINT32)pciAddr & (UINT32)0x3) != 0)
  529.     {
  530. return ERROR;
  531.     }
  532.         
  533.     if (direction == IXP425_PCI_DMA_DIR_OUT)
  534.     {
  535. /*AHB to PCI transfer*/
  536. key=intLock();
  537. if (atpRequestQueueSize < 2)
  538. {
  539.     /*If the queue size is 0 or 1, this means that there is a free register
  540.       set, so we can send the transfer directly to the registers*/
  541.     newTransfer.buffer    = buffer;
  542.     newTransfer.pciAddr   = pciAddr;
  543.     newTransfer.length    = length;
  544.     newTransfer.callback  = callback;
  545.     newTransfer.parameter = parameter;
  546.     atpTransferInitiate(&newTransfer);     
  547. }
  548. else
  549. {
  550.     /*Otherwise we must add the request to the queue*/
  551.     if(atpTransferAdd(buffer, pciAddr, length, callback, parameter)!=OK)
  552.     {
  553. intUnlock(key);
  554. return ERROR;
  555.     }
  556. }
  557. /*regardless of whether we sent the transfer directly to the registers
  558.   or queued it, the queue size has increased, since we consider the 
  559.   registers to be part of the queue*/
  560. atpRequestQueueSize++;
  561. intUnlock(key);
  562.     }
  563.     else if (direction == IXP425_PCI_DMA_DIR_IN)
  564.     {
  565. /*PCI to AHB transfer*/
  566. key=intLock();
  567. if (ptaRequestQueueSize < 2)
  568. {
  569.     newTransfer.buffer    = buffer;
  570.     newTransfer.pciAddr   = pciAddr;
  571.     newTransfer.length    = length;
  572.     newTransfer.callback  = callback;
  573.     newTransfer.parameter = parameter;
  574.     ptaTransferInitiate(&newTransfer);     
  575. }
  576. else
  577. {
  578.     if(ptaTransferAdd(buffer, pciAddr, length, callback, parameter)!=OK)
  579.     {
  580. intUnlock(key);
  581. return ERROR;
  582.     }
  583. }
  584. ptaRequestQueueSize++;
  585. intUnlock(key);
  586.     }
  587.     else 
  588.     {
  589. return ERROR;
  590.     }
  591.     return OK;
  592. }
  593. LOCAL void
  594. pciOddByteTransfer (void *pciAddr,
  595.     UINT8 *data,
  596.     UINT32 direction,
  597.     UINT32 length)
  598. {
  599.     UINT32 i;
  600.     for (i=0; i<length; i++)
  601.     {
  602. if (direction == IXP425_PCI_DMA_DIR_OUT)
  603. {
  604.     pciMemOutByte (pciAddr, *data);
  605. }
  606. else
  607. {
  608.     pciMemInByte (pciAddr, (UINT8*)data);
  609. }
  610. pciAddr = (void*)((UINT8*)pciAddr+1);
  611. data = data + 1;
  612.     }    
  613. }
  614. LOCAL STATUS
  615. pciDmaSingleMbufTransfer (M_BLK *buffer, 
  616.   void *pciAddr, 
  617.   UINT32 direction,
  618.   PCICALLBACKFUNC callback,
  619.   UINT32 parameter)
  620. {
  621.     UINT8 *data;
  622.     UINT32 length;
  623.     UINT32 lengthInLwords;
  624.     UINT32 lengthDmaInBytes;
  625.     UINT32 nonAlMaskAhb;
  626.     UINT32 nonAlMaskPci;
  627.     UINT32 numOdd;
  628.     STATUS retval;
  629.     
  630.     data   = buffer->mBlkHdr.mData;
  631.     length = buffer->mBlkHdr.mLen;
  632.     
  633.     nonAlMaskAhb = (UINT32)data & (UINT32)0x3;
  634.     nonAlMaskPci = (UINT32)pciAddr & (UINT32)0x3;
  635.     /*If the AHB and PCI addresses are not equally misaligned we cannot do a DMA transfer*/
  636.     if (nonAlMaskPci != nonAlMaskAhb)
  637.     {
  638. return ERROR;
  639.     }
  640.     
  641.     if (nonAlMaskAhb)
  642.     {
  643. /*there are odd bytes at the start of the transfer*/
  644. numOdd = 4 - nonAlMaskAhb;
  645. pciOddByteTransfer (pciAddr, (UINT8*)data, direction, numOdd);
  646. pciAddr = (void*)((UINT8*)pciAddr+numOdd);
  647. data = data + numOdd;     
  648. length -= numOdd;
  649.     }
  650.     
  651.     /*now do the dma transfer*/
  652.     lengthDmaInBytes = ((UINT32)length & ~((UINT32)0x3));
  653.     lengthInLwords = lengthDmaInBytes >> 2;
  654.     
  655.     retval=pciDmaTransfer (data, pciAddr, direction, lengthInLwords, 
  656.    callback, parameter);
  657.     
  658.     if (retval != OK)
  659.     {
  660. return retval;
  661.     }
  662.     
  663.     /*transfer any odd bytes left over*/
  664.     length = length - lengthDmaInBytes;
  665.     
  666.     if (length != 0)
  667.     {
  668. data = data + lengthDmaInBytes;
  669. pciAddr = (void*)((UINT8*)pciAddr+lengthDmaInBytes);
  670. pciOddByteTransfer(pciAddr, (UINT8*)data, direction, length);
  671.     }
  672.     return OK;
  673. }
  674. /**********************************************
  675. *
  676. * pciDmaMbufTransfer - transfer an Mbuf or chain of Mbufs of data using DMA
  677. *
  678. * This routine transfers an mBuf's data across the PCI
  679. * bus using as much DMA as possible. If the data to be 
  680. * transferred is not word aligned, the odd bytes at the 
  681. * beginning and end of the block are transferred using 
  682. * individual non-prefetch memory transactions, which will
  683. * have a negative impact on throughput.
  684. *
  685. * RETURNS: OK, or ERROR if invalid parameters are supplied, or if the 
  686. * relevant queue is full.
  687. */
  688.     
  689. STATUS 
  690. pciDmaMbufTransfer (M_BLK* buffer, 
  691.     void *pciAddr,
  692.     UINT32 direction,
  693.     PCICALLBACKFUNC callback,
  694.     UINT32 parameter)
  695. {
  696.     M_BLK* currentMblk;
  697.     STATUS retval;
  698.     if ((direction != IXP425_PCI_DMA_DIR_IN) && (direction != IXP425_PCI_DMA_DIR_OUT))
  699.     {
  700. return ERROR;
  701.     }
  702.     currentMblk = buffer;
  703.     
  704.     while (currentMblk != NULL)
  705.     {
  706. retval=pciDmaSingleMbufTransfer (currentMblk, pciAddr, direction, 
  707.  callback, parameter);
  708. if (retval!=OK)
  709. {
  710.     return retval;
  711. }
  712. pciAddr = (void*)((UINT8*)pciAddr+currentMblk->mBlkHdr.mLen);
  713. currentMblk = currentMblk->mBlkHdr.mNext;
  714.     }
  715.     
  716.     return OK;
  717. }