2 * Generic Broadcom Home Networking Division (HND) DMA module.
3 * This supports the following chips: BCM42xx, 44xx, 47xx .
5 * Copyright 2004, Broadcom Corporation
8 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
9 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
10 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
11 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
18 #include <bcmendian.h>
21 struct dma_info
; /* forward declaration */
22 #define di_t struct dma_info
26 #define DMA_ERROR(args)
27 #define DMA_TRACE(args)
29 /* default dma message level(if input msg_level pointer is null in dma_attach()) */
30 static uint dma_msg_level
= 0;
33 #define MAXDD (DMAMAXRINGSZ / sizeof (dmadd_t))
35 /* dma engine software state */
36 typedef struct dma_info
{
37 hnddma_t hnddma
; /* exported structure */
38 uint
*msg_level
; /* message level pointer */
40 char name
[MAXNAMEL
]; /* callers name for diag msgs */
41 void *drv
; /* driver handle */
42 void *dev
; /* device handle */
43 dmaregs_t
*regs
; /* dma engine registers */
45 dmadd_t
*txd
; /* pointer to chip-specific tx descriptor ring */
46 uint txin
; /* index of next descriptor to reclaim */
47 uint txout
; /* index of next descriptor to post */
48 uint txavail
; /* # free tx descriptors */
49 void *txp
[MAXDD
]; /* parallel array of pointers to packets */
50 ulong txdpa
; /* physical address of descriptor ring */
51 uint txdalign
; /* #bytes added to alloc'd mem to align txd */
53 dmadd_t
*rxd
; /* pointer to chip-specific rx descriptor ring */
54 uint rxin
; /* index of next descriptor to reclaim */
55 uint rxout
; /* index of next descriptor to post */
56 void *rxp
[MAXDD
]; /* parallel array of pointers to packets */
57 ulong rxdpa
; /* physical address of descriptor ring */
58 uint rxdalign
; /* #bytes added to alloc'd mem to align rxd */
61 uint ntxd
; /* # tx descriptors */
62 uint nrxd
; /* # rx descriptors */
63 uint rxbufsize
; /* rx buffer size in bytes */
64 uint nrxpost
; /* # rx buffers to keep posted */
65 uint rxoffset
; /* rxcontrol offset */
66 uint ddoffset
; /* add to get dma address of descriptor ring */
67 uint dataoffset
; /* add to get dma address of data buffer */
70 /* descriptor bumping macros */
71 #define TXD(x) ((x) & (di->ntxd - 1))
72 #define RXD(x) ((x) & (di->nrxd - 1))
73 #define NEXTTXD(i) TXD(i + 1)
74 #define PREVTXD(i) TXD(i - 1)
75 #define NEXTRXD(i) RXD(i + 1)
76 #define NTXDACTIVE(h, t) TXD(t - h)
77 #define NRXDACTIVE(h, t) RXD(t - h)
79 /* macros to convert between byte offsets and indexes */
80 #define B2I(bytes) ((bytes) / sizeof (dmadd_t))
81 #define I2B(index) ((index) * sizeof (dmadd_t))
84 dma_attach(void *drv
, void *dev
, char *name
, dmaregs_t
*regs
, uint ntxd
, uint nrxd
,
85 uint rxbufsize
, uint nrxpost
, uint rxoffset
, uint ddoffset
, uint dataoffset
, uint
*msg_level
)
90 ASSERT(ntxd
<= MAXDD
);
91 ASSERT(nrxd
<= MAXDD
);
93 /* allocate private info structure */
94 if ((di
= MALLOC(sizeof (dma_info_t
))) == NULL
)
96 bzero((char*)di
, sizeof (dma_info_t
));
98 /* set message level */
99 di
->msg_level
= msg_level
? msg_level
: &dma_msg_level
;
101 DMA_TRACE(("%s: dma_attach: drv 0x%x dev 0x%x regs 0x%x ntxd %d nrxd %d rxbufsize %d nrxpost %d rxoffset %d ddoffset 0x%x dataoffset 0x%x\n", name
, (uint
)drv
, (uint
)dev
, (uint
)regs
, ntxd
, nrxd
, rxbufsize
, nrxpost
, rxoffset
, ddoffset
, dataoffset
));
103 /* make a private copy of our callers name */
104 strncpy(di
->name
, name
, MAXNAMEL
);
105 di
->name
[MAXNAMEL
-1] = '\0';
111 /* allocate transmit descriptor ring */
113 if ((va
= DMA_ALLOC_CONSISTENT(dev
, (DMAMAXRINGSZ
+ DMARINGALIGN
), &di
->txdpa
)) == NULL
)
115 di
->txd
= (dmadd_t
*) ROUNDUP(va
, DMARINGALIGN
);
116 di
->txdalign
= ((uint
)di
->txd
- (uint
)va
);
117 di
->txdpa
= di
->txdpa
+ di
->txdalign
;
118 ASSERT(ISALIGNED(di
->txd
, DMARINGALIGN
));
121 /* allocate receive descriptor ring */
123 if ((va
= DMA_ALLOC_CONSISTENT(dev
, (DMAMAXRINGSZ
+ DMARINGALIGN
), &di
->rxdpa
)) == NULL
)
125 di
->rxd
= (dmadd_t
*) ROUNDUP(va
, DMARINGALIGN
);
126 di
->rxdalign
= ((uint
)di
->rxd
- (uint
)va
);
127 di
->rxdpa
= di
->rxdpa
+ di
->rxdalign
;
128 ASSERT(ISALIGNED(di
->rxd
, DMARINGALIGN
));
134 di
->rxbufsize
= rxbufsize
;
135 di
->nrxpost
= nrxpost
;
136 di
->rxoffset
= rxoffset
;
137 di
->ddoffset
= ddoffset
;
138 di
->dataoffset
= dataoffset
;
143 dma_detach((void*)di
);
147 /* may be called with core in reset */
149 dma_detach(dma_info_t
*di
)
154 DMA_TRACE(("%s: dma_detach\n", di
->name
));
156 /* shouldn't be here if descriptors are unreclaimed */
157 ASSERT(di
->txin
== di
->txout
);
158 ASSERT(di
->rxin
== di
->rxout
);
160 /* free dma descriptor rings */
162 DMA_FREE_CONSISTENT(di
->dev
, (void *)((uint
)di
->txd
- di
->txdalign
), (DMAMAXRINGSZ
+ DMARINGALIGN
), di
->txdpa
);
164 DMA_FREE_CONSISTENT(di
->dev
, (void *)((uint
)di
->rxd
- di
->rxdalign
), (DMAMAXRINGSZ
+ DMARINGALIGN
), di
->rxdpa
);
166 /* free our private info structure */
167 MFREE((void*)di
, sizeof (dma_info_t
));
172 dma_txreset(dma_info_t
*di
)
176 DMA_TRACE(("%s: dma_txreset\n", di
->name
));
178 /* suspend tx DMA first */
179 W_REG(&di
->regs
->xmtcontrol
, XC_SE
);
180 SPINWAIT((status
= (R_REG(&di
->regs
->xmtstatus
) & XS_XS_MASK
)) != XS_XS_DISABLED
&&
181 status
!= XS_XS_IDLE
&&
182 status
!= XS_XS_STOPPED
,
185 W_REG(&di
->regs
->xmtcontrol
, 0);
186 SPINWAIT((status
= (R_REG(&di
->regs
->xmtstatus
) & XS_XS_MASK
)) != XS_XS_DISABLED
,
189 if (status
!= XS_XS_DISABLED
) {
190 DMA_ERROR(("%s: dma_txreset: dma cannot be stopped\n", di
->name
));
193 /* wait for the last transaction to complete */
198 dma_rxreset(dma_info_t
*di
)
202 DMA_TRACE(("%s: dma_rxreset\n", di
->name
));
204 W_REG(&di
->regs
->rcvcontrol
, 0);
205 SPINWAIT((status
= (R_REG(&di
->regs
->rcvstatus
) & RS_RS_MASK
)) != RS_RS_DISABLED
,
208 if (status
!= RS_RS_DISABLED
) {
209 DMA_ERROR(("%s: dma_rxreset: dma cannot be stopped\n", di
->name
));
214 dma_txinit(dma_info_t
*di
)
216 DMA_TRACE(("%s: dma_txinit\n", di
->name
));
218 di
->txin
= di
->txout
= 0;
219 di
->txavail
= di
->ntxd
- 1;
221 /* clear tx descriptor ring */
222 BZERO_SM((void*)di
->txd
, (di
->ntxd
* sizeof (dmadd_t
)));
224 W_REG(&di
->regs
->xmtcontrol
, XC_XE
);
225 W_REG(&di
->regs
->xmtaddr
, (di
->txdpa
+ di
->ddoffset
));
229 dma_txenabled(dma_info_t
*di
)
233 /* If the chip is dead, it is not enabled :-) */
234 xc
= R_REG(&di
->regs
->xmtcontrol
);
235 return ((xc
!= 0xffffffff) && (xc
& XC_XE
));
239 dma_txsuspend(dma_info_t
*di
)
241 DMA_TRACE(("%s: dma_txsuspend\n", di
->name
));
242 OR_REG(&di
->regs
->xmtcontrol
, XC_SE
);
246 dma_txresume(dma_info_t
*di
)
248 DMA_TRACE(("%s: dma_txresume\n", di
->name
));
249 AND_REG(&di
->regs
->xmtcontrol
, ~XC_SE
);
253 dma_txsuspended(dma_info_t
*di
)
255 if (!(R_REG(&di
->regs
->xmtcontrol
) & XC_SE
))
258 if ((R_REG(&di
->regs
->xmtstatus
) & XS_XS_MASK
) != XS_XS_IDLE
)
262 return ((R_REG(&di
->regs
->xmtstatus
) & XS_XS_MASK
) == XS_XS_IDLE
);
266 dma_txstopped(dma_info_t
*di
)
268 return ((R_REG(&di
->regs
->xmtstatus
) & XS_XS_MASK
) == XS_XS_STOPPED
);
272 dma_rxstopped(dma_info_t
*di
)
274 return ((R_REG(&di
->regs
->rcvstatus
) & RS_RS_MASK
) == RS_RS_STOPPED
);
278 dma_fifoloopbackenable(dma_info_t
*di
)
280 DMA_TRACE(("%s: dma_fifoloopbackenable\n", di
->name
));
281 OR_REG(&di
->regs
->xmtcontrol
, XC_LE
);
285 dma_rxinit(dma_info_t
*di
)
287 DMA_TRACE(("%s: dma_rxinit\n", di
->name
));
289 di
->rxin
= di
->rxout
= 0;
291 /* clear rx descriptor ring */
292 BZERO_SM((void*)di
->rxd
, (di
->nrxd
* sizeof (dmadd_t
)));
295 W_REG(&di
->regs
->rcvaddr
, (di
->rxdpa
+ di
->ddoffset
));
299 dma_rxenable(dma_info_t
*di
)
301 DMA_TRACE(("%s: dma_rxenable\n", di
->name
));
302 W_REG(&di
->regs
->rcvcontrol
, ((di
->rxoffset
<< RC_RO_SHIFT
) | RC_RE
));
306 dma_rxenabled(dma_info_t
*di
)
310 rc
= R_REG(&di
->regs
->rcvcontrol
);
311 return ((rc
!= 0xffffffff) && (rc
& RC_RE
));
315 * The BCM47XX family supports full 32bit dma engine buffer addressing so
316 * dma buffers can cross 4 Kbyte page boundaries.
319 dma_txfast(dma_info_t
*di
, void *p0
, uint32 coreflags
)
328 DMA_TRACE(("%s: dma_txfast\n", di
->name
));
334 * Walk the chain of packet buffers
335 * allocating and initializing transmit descriptor entries.
337 for (p
= p0
; p
; p
= next
) {
338 data
= PKTDATA(di
->drv
, p
);
339 len
= PKTLEN(di
->drv
, p
);
340 next
= PKTNEXT(di
->drv
, p
);
342 /* return nonzero if out of tx descriptors */
343 if (NEXTTXD(txout
) == di
->txin
)
349 /* get physical address of buffer start */
350 pa
= (uint32
) DMA_MAP(di
->dev
, data
, len
, DMA_TX
, p
);
352 /* build the descriptor control value */
353 ctrl
= len
& CTRL_BC_MASK
;
360 ctrl
|= (CTRL_IOC
| CTRL_EOF
);
361 if (txout
== (di
->ntxd
- 1))
364 /* init the tx descriptor */
365 W_SM(&di
->txd
[txout
].ctrl
, BUS_SWAP32(ctrl
));
366 W_SM(&di
->txd
[txout
].addr
, BUS_SWAP32(pa
+ di
->dataoffset
));
368 ASSERT(di
->txp
[txout
] == NULL
);
370 txout
= NEXTTXD(txout
);
373 /* if last txd eof not set, fix it */
374 if (!(ctrl
& CTRL_EOF
))
375 W_SM(&di
->txd
[PREVTXD(txout
)].ctrl
, BUS_SWAP32(ctrl
| CTRL_IOC
| CTRL_EOF
));
377 /* save the packet */
378 di
->txp
[PREVTXD(txout
)] = p0
;
380 /* bump the tx descriptor index */
384 W_REG(&di
->regs
->xmtptr
, I2B(txout
));
386 /* tx flow control */
387 di
->txavail
= di
->ntxd
- NTXDACTIVE(di
->txin
, di
->txout
) - 1;
392 DMA_ERROR(("%s: dma_txfast: out of txds\n", di
->name
));
393 PKTFREE(di
->drv
, p0
, TRUE
);
395 di
->hnddma
.txnobuf
++;
400 #define PAGEBASE(x) ((uint)(x) & ~4095)
403 * Just like above except go through the extra effort of splitting
404 * buffers that cross 4Kbyte boundaries into multiple tx descriptors.
407 dma_tx(dma_info_t
*di
, void *p0
, uint32 coreflags
)
412 uchar
*page
, *start
, *end
;
417 DMA_TRACE(("%s: dma_tx\n", di
->name
));
423 * Walk the chain of packet buffers
424 * splitting those that cross 4 Kbyte boundaries
425 * allocating and initializing transmit descriptor entries.
427 for (p
= p0
; p
; p
= next
) {
428 data
= PKTDATA(di
->drv
, p
);
429 plen
= PKTLEN(di
->drv
, p
);
430 next
= PKTNEXT(di
->drv
, p
);
435 for (page
= (uchar
*)PAGEBASE(data
);
436 page
<= (uchar
*)PAGEBASE(data
+ plen
- 1);
439 /* return nonzero if out of tx descriptors */
440 if (NEXTTXD(txout
) == di
->txin
)
443 start
= (page
== (uchar
*)PAGEBASE(data
))? data
: page
;
444 end
= (page
== (uchar
*)PAGEBASE(data
+ plen
))?
445 (data
+ plen
): (page
+ PAGESZ
);
448 /* build the descriptor control value */
449 ctrl
= len
& CTRL_BC_MASK
;
453 if ((p
== p0
) && (start
== data
))
455 if ((next
== NULL
) && (end
== (data
+ plen
)))
456 ctrl
|= (CTRL_IOC
| CTRL_EOF
);
457 if (txout
== (di
->ntxd
- 1))
460 /* get physical address of buffer start */
461 pa
= (uint32
) DMA_MAP(di
->dev
, start
, len
, DMA_TX
, p
);
463 /* init the tx descriptor */
464 W_SM(&di
->txd
[txout
].ctrl
, BUS_SWAP32(ctrl
));
465 W_SM(&di
->txd
[txout
].addr
, BUS_SWAP32(pa
+ di
->dataoffset
));
467 ASSERT(di
->txp
[txout
] == NULL
);
469 txout
= NEXTTXD(txout
);
473 /* if last txd eof not set, fix it */
474 if (!(ctrl
& CTRL_EOF
))
475 W_SM(&di
->txd
[PREVTXD(txout
)].ctrl
, BUS_SWAP32(ctrl
| CTRL_IOC
| CTRL_EOF
));
477 /* save the packet */
478 di
->txp
[PREVTXD(txout
)] = p0
;
480 /* bump the tx descriptor index */
484 W_REG(&di
->regs
->xmtptr
, I2B(txout
));
486 /* tx flow control */
487 di
->txavail
= di
->ntxd
- NTXDACTIVE(di
->txin
, di
->txout
) - 1;
492 DMA_ERROR(("%s: dma_tx: out of txds\n", di
->name
));
493 PKTFREE(di
->drv
, p0
, TRUE
);
495 di
->hnddma
.txnobuf
++;
499 /* returns a pointer to the next frame received, or NULL if there are no more */
501 dma_rx(dma_info_t
*di
)
507 while ((p
= dma_getnextrxp(di
, FALSE
))) {
508 /* skip giant packets which span multiple rx descriptors */
510 skiplen
-= di
->rxbufsize
;
513 PKTFREE(di
->drv
, p
, FALSE
);
517 len
= ltoh16(*(uint16
*)(PKTDATA(di
->drv
, p
)));
518 DMA_TRACE(("%s: dma_rx len %d\n", di
->name
, len
));
520 /* bad frame length check */
521 if (len
> (di
->rxbufsize
- di
->rxoffset
)) {
522 DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n", di
->name
, len
));
524 skiplen
= len
- (di
->rxbufsize
- di
->rxoffset
);
525 PKTFREE(di
->drv
, p
, FALSE
);
526 di
->hnddma
.rxgiants
++;
530 /* set actual length */
531 PKTSETLEN(di
->drv
, p
, (di
->rxoffset
+ len
));
539 /* post receive buffers */
541 dma_rxfill(dma_info_t
*di
)
552 * Determine how many receive buffers we're lacking
553 * from the full complement, allocate, initialize,
554 * and post them, then update the chip rx lastdscr.
559 rxbufsize
= di
->rxbufsize
;
561 n
= di
->nrxpost
- NRXDACTIVE(rxin
, rxout
);
563 DMA_TRACE(("%s: dma_rxfill: post %d\n", di
->name
, n
));
565 for (i
= 0; i
< n
; i
++) {
566 if ((p
= PKTGET(di
->drv
, rxbufsize
, FALSE
)) == NULL
) {
567 DMA_ERROR(("%s: dma_rxfill: out of rxbufs\n", di
->name
));
568 di
->hnddma
.rxnobuf
++;
572 *(uint32
*)(OSL_UNCACHED(PKTDATA(di
->drv
, p
))) = 0;
574 pa
= (uint32
) DMA_MAP(di
->dev
, PKTDATA(di
->drv
, p
), rxbufsize
, DMA_RX
, p
);
575 ASSERT(ISALIGNED(pa
, 4));
577 /* save the free packet pointer */
578 ASSERT(di
->rxp
[rxout
] == NULL
);
581 /* prep the descriptor control value */
583 if (rxout
== (di
->nrxd
- 1))
586 /* init the rx descriptor */
587 W_SM(&di
->rxd
[rxout
].ctrl
, BUS_SWAP32(ctrl
));
588 W_SM(&di
->rxd
[rxout
].addr
, BUS_SWAP32(pa
+ di
->dataoffset
));
590 rxout
= NEXTRXD(rxout
);
595 /* update the chip lastdscr pointer */
596 W_REG(&di
->regs
->rcvptr
, I2B(rxout
));
600 dma_txreclaim(dma_info_t
*di
, bool forceall
)
604 DMA_TRACE(("%s: dma_txreclaim %s\n", di
->name
, forceall
? "all" : ""));
606 while ((p
= dma_getnexttxp(di
, forceall
)))
607 PKTFREE(di
->drv
, p
, TRUE
);
611 * Reclaim next completed txd (txds if using chained buffers) and
612 * return associated packet.
613 * If 'force' is true, reclaim txd(s) and return associated packet
614 * regardless of the value of the hardware "curr" pointer.
617 dma_getnexttxp(dma_info_t
*di
, bool forceall
)
622 DMA_TRACE(("%s: dma_getnexttxp %s\n", di
->name
, forceall
? "all" : ""));
630 end
= B2I(R_REG(&di
->regs
->xmtstatus
) & XS_CD_MASK
);
632 if ((start
== 0) && (end
> di
->txout
))
635 for (i
= start
; i
!= end
&& !txp
; i
= NEXTTXD(i
)) {
636 DMA_UNMAP(di
->dev
, (BUS_SWAP32(R_SM(&di
->txd
[i
].addr
)) - di
->dataoffset
),
637 (BUS_SWAP32(R_SM(&di
->txd
[i
].ctrl
)) & CTRL_BC_MASK
), DMA_TX
, di
->txp
[i
]);
638 W_SM(&di
->txd
[i
].addr
, 0xdeadbeef);
645 /* tx flow control */
646 di
->txavail
= di
->ntxd
- NTXDACTIVE(di
->txin
, di
->txout
) - 1;
652 DMA_ERROR(("dma_getnexttxp: bogus curr: start %d end %d txout %d force %d\n",
653 start, end, di->txout, forceall));
658 /* like getnexttxp but no reclaim */
660 dma_peeknexttxp(dma_info_t
*di
)
664 end
= B2I(R_REG(&di
->regs
->xmtstatus
) & XS_CD_MASK
);
666 for (i
= di
->txin
; i
!= end
; i
= NEXTTXD(i
))
674 dma_rxreclaim(dma_info_t
*di
)
678 DMA_TRACE(("%s: dma_rxreclaim\n", di
->name
));
680 while ((p
= dma_getnextrxp(di
, TRUE
)))
681 PKTFREE(di
->drv
, p
, FALSE
);
685 dma_getnextrxp(dma_info_t
*di
, bool forceall
)
690 /* if forcing, dma engine must be disabled */
691 ASSERT(!forceall
|| !dma_rxenabled(di
));
695 /* return if no packets posted */
699 /* ignore curr if forceall */
700 if (!forceall
&& (i
== B2I(R_REG(&di
->regs
->rcvstatus
) & RS_CD_MASK
)))
703 /* get the packet pointer that corresponds to the rx descriptor */
708 /* clear this packet from the descriptor ring */
709 DMA_UNMAP(di
->dev
, (BUS_SWAP32(R_SM(&di
->rxd
[i
].addr
)) - di
->dataoffset
),
710 di
->rxbufsize
, DMA_RX
, rxp
);
711 W_SM(&di
->rxd
[i
].addr
, 0xdeadbeef);
713 di
->rxin
= NEXTRXD(i
);
719 dma_dumptx(dma_info_t
*di
, char *buf
)
721 buf
+= sprintf(buf
, "txd 0x%lx txdpa 0x%lx txp 0x%lx txin %d txout %d txavail %d\n",
722 (ulong
)di
->txd
, di
->txdpa
, (ulong
)di
->txp
, di
->txin
, di
->txout
, di
->txavail
);
723 buf
+= sprintf(buf
, "xmtcontrol 0x%x xmtaddr 0x%x xmtptr 0x%x xmtstatus 0x%x\n",
724 R_REG(&di
->regs
->xmtcontrol
),
725 R_REG(&di
->regs
->xmtaddr
),
726 R_REG(&di
->regs
->xmtptr
),
727 R_REG(&di
->regs
->xmtstatus
));
732 dma_dumprx(dma_info_t
*di
, char *buf
)
734 buf
+= sprintf(buf
, "rxd 0x%lx rxdpa 0x%lx rxp 0x%lx rxin %d rxout %d\n",
735 (ulong
)di
->rxd
, di
->rxdpa
, (ulong
)di
->rxp
, di
->rxin
, di
->rxout
);
736 buf
+= sprintf(buf
, "rcvcontrol 0x%x rcvaddr 0x%x rcvptr 0x%x rcvstatus 0x%x\n",
737 R_REG(&di
->regs
->rcvcontrol
),
738 R_REG(&di
->regs
->rcvaddr
),
739 R_REG(&di
->regs
->rcvptr
),
740 R_REG(&di
->regs
->rcvstatus
));
745 dma_dump(dma_info_t
*di
, char *buf
)
747 buf
= dma_dumptx(di
, buf
);
748 buf
= dma_dumprx(di
, buf
);
753 dma_getvar(dma_info_t
*di
, char *name
)
755 if (!strcmp(name
, "&txavail"))
756 return ((uint
) &di
->txavail
);
764 dma_txblock(dma_info_t
*di
)
770 dma_txunblock(dma_info_t
*di
)
772 di
->txavail
= di
->ntxd
- NTXDACTIVE(di
->txin
, di
->txout
) - 1;
776 dma_txactive(dma_info_t
*di
)
778 return (NTXDACTIVE(di
->txin
, di
->txout
));
782 * Rotate all active tx dma ring entries "forward" by (ActiveDescriptor - txin).
785 dma_txrotate(di_t
*di
)
794 ASSERT(dma_txsuspended(di
));
796 nactive
= dma_txactive(di
);
797 ad
= B2I((R_REG(&di
->regs
->xmtstatus
) & XS_AD_MASK
) >> XS_AD_SHIFT
);
798 rot
= TXD(ad
- di
->txin
);
800 ASSERT(rot
< di
->ntxd
);
802 /* full-ring case is a lot harder - don't worry about this */
803 if (rot
>= (di
->ntxd
- nactive
)) {
804 DMA_ERROR(("%s: dma_txrotate: ring full - punt\n", di
->name
));
809 last
= PREVTXD(di
->txout
);
811 /* move entries starting at last and moving backwards to first */
812 for (old
= last
; old
!= PREVTXD(first
); old
= PREVTXD(old
)) {
813 new = TXD(old
+ rot
);
816 * Move the tx dma descriptor.
817 * EOT is set only in the last entry in the ring.
819 w
= R_SM(&di
->txd
[old
].ctrl
) & ~CTRL_EOT
;
820 if (new == (di
->ntxd
- 1))
822 W_SM(&di
->txd
[new].ctrl
, w
);
823 W_SM(&di
->txd
[new].addr
, R_SM(&di
->txd
[old
].addr
));
825 /* zap the old tx dma descriptor address field */
826 W_SM(&di
->txd
[old
].addr
, 0xdeadbeef);
828 /* move the corresponding txp[] entry */
829 ASSERT(di
->txp
[new] == NULL
);
830 di
->txp
[new] = di
->txp
[old
];
834 /* update txin and txout */
836 di
->txout
= TXD(di
->txout
+ rot
);
837 di
->txavail
= di
->ntxd
- NTXDACTIVE(di
->txin
, di
->txout
) - 1;
840 W_REG(&di
->regs
->xmtptr
, I2B(di
->txout
));
This page took 0.111551 seconds and 5 git commands to generate.