2 * Generic Broadcom Home Networking Division (HND) DMA module.
3 * This supports the following chips: BCM42xx, 44xx, 47xx .
5 * Copyright 2006, 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.
13 * $Id: hnddma.c,v 1.11 2006/04/08 07:12:42 honor Exp $
19 #include "linux_osl.h"
20 #include <bcmendian.h>
30 #define DMA_ERROR(args)
31 #define DMA_TRACE(args)
33 /* default dma message level (if input msg_level pointer is null in dma_attach()) */
34 static uint dma_msg_level =
37 #define MAXNAMEL 8 /* 8 char names */
39 #define DI_INFO(dmah) (dma_info_t *)dmah
41 /* dma engine software state */
42 typedef struct dma_info {
43 struct hnddma_pub hnddma; /* exported structure, don't use hnddma_t,
44 * which could be const
46 uint *msg_level; /* message level pointer */
47 char name[MAXNAMEL]; /* callers name for diag msgs */
49 void *osh; /* os handle */
50 sb_t *sbh; /* sb handle */
52 bool dma64; /* dma64 enabled */
53 bool addrext; /* this dma engine supports DmaExtendedAddrChanges */
55 dma32regs_t *d32txregs; /* 32 bits dma tx engine registers */
56 dma32regs_t *d32rxregs; /* 32 bits dma rx engine registers */
57 dma64regs_t *d64txregs; /* 64 bits dma tx engine registers */
58 dma64regs_t *d64rxregs; /* 64 bits dma rx engine registers */
60 uint32 dma64align; /* either 8k or 4k depends on number of dd */
61 dma32dd_t *txd32; /* pointer to dma32 tx descriptor ring */
62 dma64dd_t *txd64; /* pointer to dma64 tx descriptor ring */
63 uint ntxd; /* # tx descriptors tunable */
64 uint txin; /* index of next descriptor to reclaim */
65 uint txout; /* index of next descriptor to post */
66 void **txp; /* pointer to parallel array of pointers to packets */
67 osldma_t *tx_dmah; /* DMA TX descriptor ring handle */
68 osldma_t **txp_dmah; /* DMA TX packet data handle */
69 ulong txdpa; /* physical address of descriptor ring */
70 uint txdalign; /* #bytes added to alloc'd mem to align txd */
71 uint txdalloc; /* #bytes allocated for the ring */
73 dma32dd_t *rxd32; /* pointer to dma32 rx descriptor ring */
74 dma64dd_t *rxd64; /* pointer to dma64 rx descriptor ring */
75 uint nrxd; /* # rx descriptors tunable */
76 uint rxin; /* index of next descriptor to reclaim */
77 uint rxout; /* index of next descriptor to post */
78 void **rxp; /* pointer to parallel array of pointers to packets */
79 osldma_t *rx_dmah; /* DMA RX descriptor ring handle */
80 osldma_t **rxp_dmah; /* DMA RX packet data handle */
81 ulong rxdpa; /* physical address of descriptor ring */
82 uint rxdalign; /* #bytes added to alloc'd mem to align rxd */
83 uint rxdalloc; /* #bytes allocated for the ring */
86 uint rxbufsize; /* rx buffer size in bytes,
87 not including the extra headroom
89 uint nrxpost; /* # rx buffers to keep posted */
90 uint rxoffset; /* rxcontrol offset */
91 uint ddoffsetlow; /* add to get dma address of descriptor ring, low 32 bits */
92 uint ddoffsethigh; /* high 32 bits */
93 uint dataoffsetlow; /* add to get dma address of data buffer, low 32 bits */
94 uint dataoffsethigh; /* high 32 bits */
98 #define DMA64_ENAB(di) ((di)->dma64)
99 #define DMA64_CAP TRUE
101 #define DMA64_ENAB(di) (0)
102 #define DMA64_CAP FALSE
105 /* descriptor bumping macros */
106 #define XXD(x, n) ((x) & ((n) - 1)) /* faster than %, but n must be power of 2 */
107 #define TXD(x) XXD((x), di->ntxd)
108 #define RXD(x) XXD((x), di->nrxd)
109 #define NEXTTXD(i) TXD(i + 1)
110 #define PREVTXD(i) TXD(i - 1)
111 #define NEXTRXD(i) RXD(i + 1)
112 #define NTXDACTIVE(h, t) TXD(t - h)
113 #define NRXDACTIVE(h, t) RXD(t - h)
115 /* macros to convert between byte offsets and indexes */
116 #define B2I(bytes, type) ((bytes) / sizeof(type))
117 #define I2B(index, type) ((index) * sizeof(type))
119 #define PCI32ADDR_HIGH 0xc0000000 /* address[31:30] */
120 #define PCI32ADDR_HIGH_SHIFT 30 /* address[31:30] */
123 /* common prototypes */
124 static bool _dma_isaddrext(dma_info_t *di);
125 static bool _dma_alloc(dma_info_t *di, uint direction);
126 static void _dma_detach(dma_info_t *di);
127 static void _dma_ddtable_init(dma_info_t *di, uint direction, ulong pa);
128 static void _dma_rxinit(dma_info_t *di);
129 static void *_dma_rx(dma_info_t *di);
130 static void _dma_rxfill(dma_info_t *di);
131 static void _dma_rxreclaim(dma_info_t *di);
132 static void _dma_rxenable(dma_info_t *di);
133 static void * _dma_getnextrxp(dma_info_t *di, bool forceall);
135 static void _dma_txblock(dma_info_t *di);
136 static void _dma_txunblock(dma_info_t *di);
137 static uint _dma_txactive(dma_info_t *di);
139 static void* _dma_peeknexttxp(dma_info_t *di);
140 static uintptr _dma_getvar(dma_info_t *di, const char *name);
141 static void _dma_counterreset(dma_info_t *di);
142 static void _dma_fifoloopbackenable(dma_info_t *di);
144 /* ** 32 bit DMA prototypes */
145 static bool dma32_alloc(dma_info_t *di, uint direction);
146 static bool dma32_txreset(dma_info_t *di);
147 static bool dma32_rxreset(dma_info_t *di);
148 static bool dma32_txsuspendedidle(dma_info_t *di);
149 static int dma32_txfast(dma_info_t *di, void *p0, bool commit);
150 static void *dma32_getnexttxp(dma_info_t *di, bool forceall);
151 static void *dma32_getnextrxp(dma_info_t *di, bool forceall);
152 static void dma32_txrotate(dma_info_t *di);
153 static bool dma32_rxidle(dma_info_t *di);
154 static void dma32_txinit(dma_info_t *di);
155 static bool dma32_txenabled(dma_info_t *di);
156 static void dma32_txsuspend(dma_info_t *di);
157 static void dma32_txresume(dma_info_t *di);
158 static bool dma32_txsuspended(dma_info_t *di);
159 static void dma32_txreclaim(dma_info_t *di, bool forceall);
160 static bool dma32_txstopped(dma_info_t *di);
161 static bool dma32_rxstopped(dma_info_t *di);
162 static bool dma32_rxenabled(dma_info_t *di);
163 static bool _dma32_addrext(osl_t *osh, dma32regs_t *dma32regs);
165 /* ** 64 bit DMA prototypes and stubs */
167 static bool dma64_alloc(dma_info_t *di, uint direction);
168 static bool dma64_txreset(dma_info_t *di);
169 static bool dma64_rxreset(dma_info_t *di);
170 static bool dma64_txsuspendedidle(dma_info_t *di);
171 static int dma64_txfast(dma_info_t *di, void *p0, bool commit);
172 static void *dma64_getnexttxp(dma_info_t *di, bool forceall);
173 static void *dma64_getnextrxp(dma_info_t *di, bool forceall);
174 static void dma64_txrotate(dma_info_t *di);
176 static bool dma64_rxidle(dma_info_t *di);
177 static void dma64_txinit(dma_info_t *di);
178 static bool dma64_txenabled(dma_info_t *di);
179 static void dma64_txsuspend(dma_info_t *di);
180 static void dma64_txresume(dma_info_t *di);
181 static bool dma64_txsuspended(dma_info_t *di);
182 static void dma64_txreclaim(dma_info_t *di, bool forceall);
183 static bool dma64_txstopped(dma_info_t *di);
184 static bool dma64_rxstopped(dma_info_t *di);
185 static bool dma64_rxenabled(dma_info_t *di);
186 static bool _dma64_addrext(osl_t *osh, dma64regs_t *dma64regs);
189 static bool dma64_alloc(dma_info_t *di, uint direction) { return FALSE; }
190 static bool dma64_txreset(dma_info_t *di) { return FALSE; }
191 static bool dma64_rxreset(dma_info_t *di) { return FALSE; }
192 static bool dma64_txsuspendedidle(dma_info_t *di) { return FALSE;}
193 static int dma64_txfast(dma_info_t *di, void *p0, bool commit) { return 0; }
194 static void *dma64_getnexttxp(dma_info_t *di, bool forceall) { return NULL; }
195 static void *dma64_getnextrxp(dma_info_t *di, bool forceall) { return NULL; }
196 static void dma64_txrotate(dma_info_t *di) { return; }
198 static bool dma64_rxidle(dma_info_t *di) { return FALSE; }
199 static void dma64_txinit(dma_info_t *di) { return; }
200 static bool dma64_txenabled(dma_info_t *di) { return FALSE; }
201 static void dma64_txsuspend(dma_info_t *di) { return; }
202 static void dma64_txresume(dma_info_t *di) { return; }
203 static bool dma64_txsuspended(dma_info_t *di) {return FALSE; }
204 static void dma64_txreclaim(dma_info_t *di, bool forceall) { return; }
205 static bool dma64_txstopped(dma_info_t *di) { return FALSE; }
206 static bool dma64_rxstopped(dma_info_t *di) { return FALSE; }
207 static bool dma64_rxenabled(dma_info_t *di) { return FALSE; }
208 static bool _dma64_addrext(osl_t *osh, dma64regs_t *dma64regs) { return FALSE; }
210 #endif /* BCMDMA64 */
214 static di_fcn_t dma64proc = {
215 (di_detach_t)_dma_detach,
216 (di_txinit_t)dma64_txinit,
217 (di_txreset_t)dma64_txreset,
218 (di_txenabled_t)dma64_txenabled,
219 (di_txsuspend_t)dma64_txsuspend,
220 (di_txresume_t)dma64_txresume,
221 (di_txsuspended_t)dma64_txsuspended,
222 (di_txsuspendedidle_t)dma64_txsuspendedidle,
223 (di_txfast_t)dma64_txfast,
224 (di_txstopped_t)dma64_txstopped,
225 (di_txreclaim_t)dma64_txreclaim,
226 (di_getnexttxp_t)dma64_getnexttxp,
227 (di_peeknexttxp_t)_dma_peeknexttxp,
228 (di_txblock_t)_dma_txblock,
229 (di_txunblock_t)_dma_txunblock,
230 (di_txactive_t)_dma_txactive,
231 (di_txrotate_t)dma64_txrotate,
233 (di_rxinit_t)_dma_rxinit,
234 (di_rxreset_t)dma64_rxreset,
235 (di_rxidle_t)dma64_rxidle,
236 (di_rxstopped_t)dma64_rxstopped,
237 (di_rxenable_t)_dma_rxenable,
238 (di_rxenabled_t)dma64_rxenabled,
240 (di_rxfill_t)_dma_rxfill,
241 (di_rxreclaim_t)_dma_rxreclaim,
242 (di_getnextrxp_t)_dma_getnextrxp,
244 (di_fifoloopbackenable_t)_dma_fifoloopbackenable,
245 (di_getvar_t)_dma_getvar,
246 (di_counterreset_t)_dma_counterreset,
254 static di_fcn_t dma32proc = {
255 (di_detach_t)_dma_detach,
256 (di_txinit_t)dma32_txinit,
257 (di_txreset_t)dma32_txreset,
258 (di_txenabled_t)dma32_txenabled,
259 (di_txsuspend_t)dma32_txsuspend,
260 (di_txresume_t)dma32_txresume,
261 (di_txsuspended_t)dma32_txsuspended,
262 (di_txsuspendedidle_t)dma32_txsuspendedidle,
263 (di_txfast_t)dma32_txfast,
264 (di_txstopped_t)dma32_txstopped,
265 (di_txreclaim_t)dma32_txreclaim,
266 (di_getnexttxp_t)dma32_getnexttxp,
267 (di_peeknexttxp_t)_dma_peeknexttxp,
268 (di_txblock_t)_dma_txblock,
269 (di_txunblock_t)_dma_txunblock,
270 (di_txactive_t)_dma_txactive,
271 (di_txrotate_t)dma32_txrotate,
273 (di_rxinit_t)_dma_rxinit,
274 (di_rxreset_t)dma32_rxreset,
275 (di_rxidle_t)dma32_rxidle,
276 (di_rxstopped_t)dma32_rxstopped,
277 (di_rxenable_t)_dma_rxenable,
278 (di_rxenabled_t)dma32_rxenabled,
280 (di_rxfill_t)_dma_rxfill,
281 (di_rxreclaim_t)_dma_rxreclaim,
282 (di_getnextrxp_t)_dma_getnextrxp,
284 (di_fifoloopbackenable_t)_dma_fifoloopbackenable,
285 (di_getvar_t)_dma_getvar,
286 (di_counterreset_t)_dma_counterreset,
295 dma_attach(osl_t *osh, char *name, sb_t *sbh, void *dmaregstx, void *dmaregsrx,
296 uint ntxd, uint nrxd, uint rxbufsize, uint nrxpost, uint rxoffset, uint *msg_level)
301 /* allocate private info structure */
302 if ((di = MALLOC(osh, sizeof (dma_info_t))) == NULL) {
305 bzero((char *)di, sizeof(dma_info_t));
307 di->msg_level = msg_level ? msg_level : &dma_msg_level;
309 /* old chips w/o sb is no longer supported */
312 di->dma64 = ((sb_coreflagshi(sbh, 0, 0) & SBTMH_DMA64) == SBTMH_DMA64);
316 DMA_ERROR(("dma_attach: driver doesn't have the capability to support "
322 /* check arguments */
323 ASSERT(ISPOWEROF2(ntxd));
324 ASSERT(ISPOWEROF2(nrxd));
326 ASSERT(dmaregsrx == NULL);
328 ASSERT(dmaregstx == NULL);
331 /* init dma reg pointer */
333 ASSERT(ntxd <= D64MAXDD);
334 ASSERT(nrxd <= D64MAXDD);
335 di->d64txregs = (dma64regs_t *)dmaregstx;
336 di->d64rxregs = (dma64regs_t *)dmaregsrx;
338 di->dma64align = D64RINGALIGN;
339 if ((ntxd < D64MAXDD / 2) && (nrxd < D64MAXDD / 2)) {
340 /* for smaller dd table, HW relax the alignment requirement */
341 di->dma64align = D64RINGALIGN / 2;
344 ASSERT(ntxd <= D32MAXDD);
345 ASSERT(nrxd <= D32MAXDD);
346 di->d32txregs = (dma32regs_t *)dmaregstx;
347 di->d32rxregs = (dma32regs_t *)dmaregsrx;
350 DMA_TRACE(("%s: dma_attach: %s osh %p ntxd %d nrxd %d rxbufsize %d nrxpost %d "
351 "rxoffset %d dmaregstx %p dmaregsrx %p\n",
352 name, (di->dma64 ? "DMA64" : "DMA32"), osh, ntxd, nrxd, rxbufsize,
353 nrxpost, rxoffset, dmaregstx, dmaregsrx));
355 /* make a private copy of our callers name */
356 strncpy(di->name, name, MAXNAMEL);
357 di->name[MAXNAMEL-1] = '\0';
366 /* the actual dma size doesn't include the extra headroom */
367 if (rxbufsize > BCMEXTRAHDROOM)
368 di->rxbufsize = rxbufsize - BCMEXTRAHDROOM;
370 di->rxbufsize = rxbufsize;
372 di->nrxpost = nrxpost;
373 di->rxoffset = rxoffset;
376 * figure out the DMA physical address offset for dd and data
377 * for old chips w/o sb, use zero
378 * for new chips w sb,
379 * PCI/PCIE: they map silicon backplace address to zero based memory, need offset
380 * Other bus: use zero
381 * SB_BUS BIGENDIAN kludge: use sdram swapped region for data buffer, not descriptor
384 di->dataoffsetlow = 0;
385 /* for pci bus, add offset */
386 if (sbh->bustype == PCI_BUS) {
387 if ((sbh->buscoretype == SB_PCIE) && di->dma64) {
388 /* pcie with DMA64 */
390 di->ddoffsethigh = SB_PCIE_DMA_H32;
392 /* pci(DMA32/DMA64) or pcie with DMA32 */
393 di->ddoffsetlow = SB_PCI_DMA;
394 di->ddoffsethigh = 0;
396 di->dataoffsetlow = di->ddoffsetlow;
397 di->dataoffsethigh = di->ddoffsethigh;
400 #if defined(__mips__) && defined(IL_BIGENDIAN)
401 di->dataoffsetlow = di->dataoffsetlow + SB_SDRAM_SWAPPED;
404 di->addrext = _dma_isaddrext(di);
406 /* allocate tx packet pointer vector */
408 size = ntxd * sizeof(void *);
409 if ((di->txp = MALLOC(osh, size)) == NULL) {
410 DMA_ERROR(("%s: dma_attach: out of tx memory, malloced %d bytes\n",
411 di->name, MALLOCED(osh)));
414 bzero((char *)di->txp, size);
417 /* allocate rx packet pointer vector */
419 size = nrxd * sizeof(void *);
420 if ((di->rxp = MALLOC(osh, size)) == NULL) {
421 DMA_ERROR(("%s: dma_attach: out of rx memory, malloced %d bytes\n",
422 di->name, MALLOCED(osh)));
425 bzero((char *)di->rxp, size);
428 /* allocate transmit descriptor ring, only need ntxd descriptors but it must be aligned */
430 if (!_dma_alloc(di, DMA_TX))
434 /* allocate receive descriptor ring, only need nrxd descriptors but it must be aligned */
436 if (!_dma_alloc(di, DMA_RX))
440 if ((di->ddoffsetlow == SB_PCI_DMA) && (di->txdpa > SB_PCI_DMA_SZ) && !di->addrext) {
441 DMA_ERROR(("%s: dma_attach: txdpa 0x%lx: addrext not supported\n",
442 di->name, di->txdpa));
445 if ((di->ddoffsetlow == SB_PCI_DMA) && (di->rxdpa > SB_PCI_DMA_SZ) && !di->addrext) {
446 DMA_ERROR(("%s: dma_attach: rxdpa 0x%lx: addrext not supported\n",
447 di->name, di->rxdpa));
451 DMA_TRACE(("ddoffsetlow 0x%x ddoffsethigh 0x%x dataoffsetlow 0x%x dataoffsethigh "
452 "0x%x addrext %d\n", di->ddoffsetlow, di->ddoffsethigh, di->dataoffsetlow,
453 di->dataoffsethigh, di->addrext));
455 /* allocate tx packet pointer vector and DMA mapping vectors */
458 size = ntxd * sizeof(osldma_t **);
459 if ((di->txp_dmah = (osldma_t **)MALLOC(osh, size)) == NULL)
461 bzero((char*)di->txp_dmah, size);
465 /* allocate rx packet pointer vector and DMA mapping vectors */
468 size = nrxd * sizeof(osldma_t **);
469 if ((di->rxp_dmah = (osldma_t **)MALLOC(osh, size)) == NULL)
471 bzero((char*)di->rxp_dmah, size);
476 /* initialize opsvec of function pointers */
477 di->hnddma.di_fn = DMA64_ENAB(di) ? dma64proc : dma32proc;
479 return ((hnddma_t *)di);
486 /* init the tx or rx descriptor */
488 dma32_dd_upd(dma_info_t *di, dma32dd_t *ddring, ulong pa, uint outidx, uint32 *flags,
491 /* dma32 uses 32 bits control to fit both flags and bufcounter */
492 *flags = *flags | (bufcount & CTRL_BC_MASK);
494 if ((di->dataoffsetlow != SB_PCI_DMA) || !(pa & PCI32ADDR_HIGH)) {
495 W_SM(&ddring[outidx].addr, BUS_SWAP32(pa + di->dataoffsetlow));
496 W_SM(&ddring[outidx].ctrl, BUS_SWAP32(*flags));
498 /* address extension */
501 ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
502 pa &= ~PCI32ADDR_HIGH;
504 *flags |= (ae << CTRL_AE_SHIFT);
505 W_SM(&ddring[outidx].addr, BUS_SWAP32(pa + di->dataoffsetlow));
506 W_SM(&ddring[outidx].ctrl, BUS_SWAP32(*flags));
511 dma64_dd_upd(dma_info_t *di, dma64dd_t *ddring, ulong pa, uint outidx, uint32 *flags,
514 uint32 ctrl2 = bufcount & D64_CTRL2_BC_MASK;
516 /* PCI bus with big(>1G) physical address, use address extension */
517 if ((di->dataoffsetlow != SB_PCI_DMA) || !(pa & PCI32ADDR_HIGH)) {
518 W_SM(&ddring[outidx].addrlow, BUS_SWAP32(pa + di->dataoffsetlow));
519 W_SM(&ddring[outidx].addrhigh, BUS_SWAP32(0 + di->dataoffsethigh));
520 W_SM(&ddring[outidx].ctrl1, BUS_SWAP32(*flags));
521 W_SM(&ddring[outidx].ctrl2, BUS_SWAP32(ctrl2));
523 /* address extension */
527 ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
528 pa &= ~PCI32ADDR_HIGH;
530 ctrl2 |= (ae << D64_CTRL2_AE_SHIFT) & D64_CTRL2_AE;
531 W_SM(&ddring[outidx].addrlow, BUS_SWAP32(pa + di->dataoffsetlow));
532 W_SM(&ddring[outidx].addrhigh, BUS_SWAP32(0 + di->dataoffsethigh));
533 W_SM(&ddring[outidx].ctrl1, BUS_SWAP32(*flags));
534 W_SM(&ddring[outidx].ctrl2, BUS_SWAP32(ctrl2));
539 _dma32_addrext(osl_t *osh, dma32regs_t *dma32regs)
543 OR_REG(osh, &dma32regs->control, XC_AE);
544 w = R_REG(osh, &dma32regs->control);
545 AND_REG(osh, &dma32regs->control, ~XC_AE);
546 return ((w & XC_AE) == XC_AE);
550 _dma_alloc(dma_info_t *di, uint direction)
552 if (DMA64_ENAB(di)) {
553 return dma64_alloc(di, direction);
555 return dma32_alloc(di, direction);
559 /* !! may be called with core in reset */
561 _dma_detach(dma_info_t *di)
566 DMA_TRACE(("%s: dma_detach\n", di->name));
568 /* shouldn't be here if descriptors are unreclaimed */
569 ASSERT(di->txin == di->txout);
570 ASSERT(di->rxin == di->rxout);
572 /* free dma descriptor rings */
573 if (DMA64_ENAB(di)) {
575 DMA_FREE_CONSISTENT(di->osh, ((int8*)(uintptr)di->txd64 - di->txdalign),
576 di->txdalloc, (di->txdpa - di->txdalign), &di->tx_dmah);
578 DMA_FREE_CONSISTENT(di->osh, ((int8*)(uintptr)di->rxd64 - di->rxdalign),
579 di->rxdalloc, (di->rxdpa - di->rxdalign), &di->rx_dmah);
582 DMA_FREE_CONSISTENT(di->osh, ((int8*)(uintptr)di->txd32 - di->txdalign),
583 di->txdalloc, (di->txdpa - di->txdalign), &di->tx_dmah);
585 DMA_FREE_CONSISTENT(di->osh, ((int8*)(uintptr)di->rxd32 - di->rxdalign),
586 di->rxdalloc, (di->rxdpa - di->rxdalign), &di->rx_dmah);
589 /* free packet pointer vectors */
591 MFREE(di->osh, (void *)di->txp, (di->ntxd * sizeof(void *)));
593 MFREE(di->osh, (void *)di->rxp, (di->nrxd * sizeof(void *)));
595 /* free tx packet DMA handles */
597 MFREE(di->osh, (void *)di->txp_dmah, di->ntxd * sizeof(osldma_t **));
599 /* free rx packet DMA handles */
601 MFREE(di->osh, (void *)di->rxp_dmah, di->nrxd * sizeof(osldma_t **));
603 /* free our private info structure */
604 MFREE(di->osh, (void *)di, sizeof(dma_info_t));
608 /* return TRUE if this dma engine supports DmaExtendedAddrChanges, otherwise FALSE */
610 _dma_isaddrext(dma_info_t *di)
612 if (DMA64_ENAB(di)) {
613 /* DMA64 supports full 32 bits or 64 bits. AE is always valid */
615 /* not all tx or rx channel are available */
616 if (di->d64txregs != NULL) {
617 if (!_dma64_addrext(di->osh, di->d64txregs)) {
618 DMA_ERROR(("%s: _dma_isaddrext: DMA64 tx doesn't have AE set\n",
623 } else if (di->d64rxregs != NULL) {
624 if (!_dma64_addrext(di->osh, di->d64rxregs)) {
625 DMA_ERROR(("%s: _dma_isaddrext: DMA64 rx doesn't have AE set\n",
632 } else if (di->d32txregs)
633 return (_dma32_addrext(di->osh, di->d32txregs));
634 else if (di->d32rxregs)
635 return (_dma32_addrext(di->osh, di->d32rxregs));
639 /* initialize descriptor table base address */
641 _dma_ddtable_init(dma_info_t *di, uint direction, ulong pa)
643 if (DMA64_ENAB(di)) {
645 if ((di->ddoffsetlow != SB_PCI_DMA) || !(pa & PCI32ADDR_HIGH)) {
646 if (direction == DMA_TX) {
647 W_REG(di->osh, &di->d64txregs->addrlow, (pa + di->ddoffsetlow));
648 W_REG(di->osh, &di->d64txregs->addrhigh, di->ddoffsethigh);
650 W_REG(di->osh, &di->d64rxregs->addrlow, (pa + di->ddoffsetlow));
651 W_REG(di->osh, &di->d64rxregs->addrhigh, di->ddoffsethigh);
654 /* DMA64 32bits address extension */
658 /* shift the high bit(s) from pa to ae */
659 ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
660 pa &= ~PCI32ADDR_HIGH;
662 if (direction == DMA_TX) {
663 W_REG(di->osh, &di->d64txregs->addrlow, (pa + di->ddoffsetlow));
664 W_REG(di->osh, &di->d64txregs->addrhigh, di->ddoffsethigh);
665 SET_REG(di->osh, &di->d64txregs->control, D64_XC_AE,
666 (ae << D64_XC_AE_SHIFT));
668 W_REG(di->osh, &di->d64rxregs->addrlow, (pa + di->ddoffsetlow));
669 W_REG(di->osh, &di->d64rxregs->addrhigh, di->ddoffsethigh);
670 SET_REG(di->osh, &di->d64rxregs->control, D64_RC_AE,
671 (ae << D64_RC_AE_SHIFT));
676 if ((di->ddoffsetlow != SB_PCI_DMA) || !(pa & PCI32ADDR_HIGH)) {
677 if (direction == DMA_TX)
678 W_REG(di->osh, &di->d32txregs->addr, (pa + di->ddoffsetlow));
680 W_REG(di->osh, &di->d32rxregs->addr, (pa + di->ddoffsetlow));
682 /* dma32 address extension */
686 /* shift the high bit(s) from pa to ae */
687 ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
688 pa &= ~PCI32ADDR_HIGH;
690 if (direction == DMA_TX) {
691 W_REG(di->osh, &di->d32txregs->addr, (pa + di->ddoffsetlow));
692 SET_REG(di->osh, &di->d32txregs->control, XC_AE, ae <<XC_AE_SHIFT);
694 W_REG(di->osh, &di->d32rxregs->addr, (pa + di->ddoffsetlow));
695 SET_REG(di->osh, &di->d32rxregs->control, RC_AE, ae <<RC_AE_SHIFT);
702 _dma_fifoloopbackenable(dma_info_t *di)
704 DMA_TRACE(("%s: dma_fifoloopbackenable\n", di->name));
706 OR_REG(di->osh, &di->d64txregs->control, D64_XC_LE);
708 OR_REG(di->osh, &di->d32txregs->control, XC_LE);
712 _dma_rxinit(dma_info_t *di)
714 DMA_TRACE(("%s: dma_rxinit\n", di->name));
719 di->rxin = di->rxout = 0;
721 /* clear rx descriptor ring */
722 if (DMA64_ENAB(di)) {
723 BZERO_SM((void *)(uintptr)di->rxd64, (di->nrxd * sizeof(dma64dd_t)));
725 _dma_ddtable_init(di, DMA_RX, di->rxdpa);
727 BZERO_SM((void *)(uintptr)di->rxd32, (di->nrxd * sizeof(dma32dd_t)));
729 _dma_ddtable_init(di, DMA_RX, di->rxdpa);
734 _dma_rxenable(dma_info_t *di)
736 DMA_TRACE(("%s: dma_rxenable\n", di->name));
739 W_REG(di->osh, &di->d64rxregs->control,
740 ((di->rxoffset << D64_RC_RO_SHIFT) | D64_RC_RE));
742 W_REG(di->osh, &di->d32rxregs->control, ((di->rxoffset << RC_RO_SHIFT) | RC_RE));
745 /* !! rx entry routine, returns a pointer to the next frame received,
746 * or NULL if there are no more
749 _dma_rx(dma_info_t *di)
755 while ((p = _dma_getnextrxp(di, FALSE))) {
756 /* skip giant packets which span multiple rx descriptors */
758 skiplen -= di->rxbufsize;
761 PKTFREE(di->osh, p, FALSE);
765 len = ltoh16(*(uint16*)(PKTDATA(di->osh, p)));
766 DMA_TRACE(("%s: dma_rx len %d\n", di->name, len));
768 /* bad frame length check */
769 if (len > (di->rxbufsize - di->rxoffset)) {
770 DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n", di->name, len));
772 skiplen = len - (di->rxbufsize - di->rxoffset);
773 PKTFREE(di->osh, p, FALSE);
774 di->hnddma.rxgiants++;
778 /* set actual length */
779 PKTSETLEN(di->osh, p, (di->rxoffset + len));
787 /* post receive buffers */
789 _dma_rxfill(dma_info_t *di)
797 uint extra_offset = 0;
800 * Determine how many receive buffers we're lacking
801 * from the full complement, allocate, initialize,
802 * and post them, then update the chip rx lastdscr.
808 n = di->nrxpost - NRXDACTIVE(rxin, rxout);
810 DMA_TRACE(("%s: dma_rxfill: post %d\n", di->name, n));
812 if (di->rxbufsize > BCMEXTRAHDROOM)
813 extra_offset = BCMEXTRAHDROOM;
815 for (i = 0; i < n; i++) {
816 /* the di->rxbufsize doesn't include the extra headroom, we need to add it to the
819 if ((p = PKTGET(di->osh, di->rxbufsize + extra_offset,
821 DMA_ERROR(("%s: dma_rxfill: out of rxbufs\n", di->name));
822 di->hnddma.rxnobuf++;
825 /* reserve an extra headroom, if applicable */
827 PKTPULL(di->osh, p, extra_offset);
829 /* Do a cached write instead of uncached write since DMA_MAP
830 * will flush the cache.
832 *(uint32*)(PKTDATA(di->osh, p)) = 0;
834 pa = (uint32) DMA_MAP(di->osh, PKTDATA(di->osh, p),
835 di->rxbufsize, DMA_RX, p);
837 ASSERT(ISALIGNED(pa, 4));
839 /* save the free packet pointer */
840 ASSERT(di->rxp[rxout] == NULL);
843 /* reset flags for each descriptor */
845 if (DMA64_ENAB(di)) {
846 if (rxout == (di->nrxd - 1))
847 flags = D64_CTRL1_EOT;
849 dma64_dd_upd(di, di->rxd64, pa, rxout, &flags, di->rxbufsize);
851 if (rxout == (di->nrxd - 1))
854 dma32_dd_upd(di, di->rxd32, pa, rxout, &flags, di->rxbufsize);
856 rxout = NEXTRXD(rxout);
861 /* update the chip lastdscr pointer */
862 if (DMA64_ENAB(di)) {
863 W_REG(di->osh, &di->d64rxregs->ptr, I2B(rxout, dma64dd_t));
865 W_REG(di->osh, &di->d32rxregs->ptr, I2B(rxout, dma32dd_t));
869 /* like getnexttxp but no reclaim */
871 _dma_peeknexttxp(dma_info_t *di)
878 if (DMA64_ENAB(di)) {
879 end = B2I(R_REG(di->osh, &di->d64txregs->status0) & D64_XS0_CD_MASK, dma64dd_t);
881 end = B2I(R_REG(di->osh, &di->d32txregs->status) & XS_CD_MASK, dma32dd_t);
884 for (i = di->txin; i != end; i = NEXTTXD(i))
892 _dma_rxreclaim(dma_info_t *di)
896 /* "unused local" warning suppression for OSLs that
897 * define PKTFREE() without using the di->osh arg
901 DMA_TRACE(("%s: dma_rxreclaim\n", di->name));
903 while ((p = _dma_getnextrxp(di, TRUE)))
904 PKTFREE(di->osh, p, FALSE);
908 _dma_getnextrxp(dma_info_t *di, bool forceall)
913 if (DMA64_ENAB(di)) {
914 return dma64_getnextrxp(di, forceall);
916 return dma32_getnextrxp(di, forceall);
921 _dma_txblock(dma_info_t *di)
923 di->hnddma.txavail = 0;
927 _dma_txunblock(dma_info_t *di)
929 di->hnddma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
933 _dma_txactive(dma_info_t *di)
935 return (NTXDACTIVE(di->txin, di->txout));
939 _dma_counterreset(dma_info_t *di)
941 /* reset all software counter */
942 di->hnddma.rxgiants = 0;
943 di->hnddma.rxnobuf = 0;
944 di->hnddma.txnobuf = 0;
947 /* get the address of the var in order to change later */
949 _dma_getvar(dma_info_t *di, const char *name)
951 if (!strcmp(name, "&txavail"))
952 return ((uintptr) &(di->hnddma.txavail));
960 dma_txpioloopback(osl_t *osh, dma32regs_t *regs)
962 OR_REG(osh, ®s->control, XC_LE);
967 /* 32 bits DMA functions */
969 dma32_txinit(dma_info_t *di)
971 DMA_TRACE(("%s: dma_txinit\n", di->name));
976 di->txin = di->txout = 0;
977 di->hnddma.txavail = di->ntxd - 1;
979 /* clear tx descriptor ring */
980 BZERO_SM((void *)(uintptr)di->txd32, (di->ntxd * sizeof(dma32dd_t)));
981 W_REG(di->osh, &di->d32txregs->control, XC_XE);
982 _dma_ddtable_init(di, DMA_TX, di->txdpa);
986 dma32_txenabled(dma_info_t *di)
990 /* If the chip is dead, it is not enabled :-) */
991 xc = R_REG(di->osh, &di->d32txregs->control);
992 return ((xc != 0xffffffff) && (xc & XC_XE));
996 dma32_txsuspend(dma_info_t *di)
998 DMA_TRACE(("%s: dma_txsuspend\n", di->name));
1003 OR_REG(di->osh, &di->d32txregs->control, XC_SE);
1007 dma32_txresume(dma_info_t *di)
1009 DMA_TRACE(("%s: dma_txresume\n", di->name));
1014 AND_REG(di->osh, &di->d32txregs->control, ~XC_SE);
1018 dma32_txsuspended(dma_info_t *di)
1020 return (di->ntxd == 0) || ((R_REG(di->osh, &di->d32txregs->control) & XC_SE) == XC_SE);
1024 dma32_txreclaim(dma_info_t *di, bool forceall)
1028 DMA_TRACE(("%s: dma_txreclaim %s\n", di->name, forceall ? "all" : ""));
1030 while ((p = dma32_getnexttxp(di, forceall)))
1031 PKTFREE(di->osh, p, TRUE);
1035 dma32_txstopped(dma_info_t *di)
1037 return ((R_REG(di->osh, &di->d32txregs->status) & XS_XS_MASK) == XS_XS_STOPPED);
1041 dma32_rxstopped(dma_info_t *di)
1043 return ((R_REG(di->osh, &di->d32rxregs->status) & RS_RS_MASK) == RS_RS_STOPPED);
1047 dma32_alloc(dma_info_t *di, uint direction)
1053 ddlen = sizeof(dma32dd_t);
1055 size = (direction == DMA_TX) ? (di->ntxd * ddlen) : (di->nrxd * ddlen);
1057 if (!ISALIGNED(DMA_CONSISTENT_ALIGN, D32RINGALIGN))
1058 size += D32RINGALIGN;
1061 if (direction == DMA_TX) {
1062 if ((va = DMA_ALLOC_CONSISTENT(di->osh, size, &di->txdpa, &di->tx_dmah)) == NULL) {
1063 DMA_ERROR(("%s: dma_attach: DMA_ALLOC_CONSISTENT(ntxd) failed\n",
1068 di->txd32 = (dma32dd_t *) ROUNDUP((uintptr)va, D32RINGALIGN);
1069 di->txdalign = (uint)((int8*)(uintptr)di->txd32 - (int8*)va);
1070 di->txdpa += di->txdalign;
1071 di->txdalloc = size;
1072 ASSERT(ISALIGNED((uintptr)di->txd32, D32RINGALIGN));
1074 if ((va = DMA_ALLOC_CONSISTENT(di->osh, size, &di->rxdpa, &di->rx_dmah)) == NULL) {
1075 DMA_ERROR(("%s: dma_attach: DMA_ALLOC_CONSISTENT(nrxd) failed\n",
1079 di->rxd32 = (dma32dd_t *) ROUNDUP((uintptr)va, D32RINGALIGN);
1080 di->rxdalign = (uint)((int8*)(uintptr)di->rxd32 - (int8*)va);
1081 di->rxdpa += di->rxdalign;
1082 di->rxdalloc = size;
1083 ASSERT(ISALIGNED((uintptr)di->rxd32, D32RINGALIGN));
1090 dma32_txreset(dma_info_t *di)
1097 /* suspend tx DMA first */
1098 W_REG(di->osh, &di->d32txregs->control, XC_SE);
1099 SPINWAIT(((status = (R_REG(di->osh, &di->d32txregs->status) & XS_XS_MASK))
1100 != XS_XS_DISABLED) &&
1101 (status != XS_XS_IDLE) &&
1102 (status != XS_XS_STOPPED),
1105 W_REG(di->osh, &di->d32txregs->control, 0);
1106 SPINWAIT(((status = (R_REG(di->osh,
1107 &di->d32txregs->status) & XS_XS_MASK)) != XS_XS_DISABLED),
1110 /* wait for the last transaction to complete */
1113 return (status == XS_XS_DISABLED);
1117 dma32_rxidle(dma_info_t *di)
1119 DMA_TRACE(("%s: dma_rxidle\n", di->name));
1124 return ((R_REG(di->osh, &di->d32rxregs->status) & RS_CD_MASK) ==
1125 R_REG(di->osh, &di->d32rxregs->ptr));
1129 dma32_rxreset(dma_info_t *di)
1136 W_REG(di->osh, &di->d32rxregs->control, 0);
1137 SPINWAIT(((status = (R_REG(di->osh,
1138 &di->d32rxregs->status) & RS_RS_MASK)) != RS_RS_DISABLED),
1141 return (status == RS_RS_DISABLED);
1145 dma32_rxenabled(dma_info_t *di)
1149 rc = R_REG(di->osh, &di->d32rxregs->control);
1150 return ((rc != 0xffffffff) && (rc & RC_RE));
1154 dma32_txsuspendedidle(dma_info_t *di)
1159 if (!(R_REG(di->osh, &di->d32txregs->control) & XC_SE))
1162 if ((R_REG(di->osh, &di->d32txregs->status) & XS_XS_MASK) != XS_XS_IDLE)
1166 return ((R_REG(di->osh, &di->d32txregs->status) & XS_XS_MASK) == XS_XS_IDLE);
1169 /* !! tx entry routine
1170 * supports full 32bit dma engine buffer addressing so
1171 * dma buffers can cross 4 Kbyte page boundaries.
1174 dma32_txfast(dma_info_t *di, void *p0, bool commit)
1183 DMA_TRACE(("%s: dma_txfast\n", di->name));
1188 * Walk the chain of packet buffers
1189 * allocating and initializing transmit descriptor entries.
1191 for (p = p0; p; p = next) {
1192 data = PKTDATA(di->osh, p);
1193 len = PKTLEN(di->osh, p);
1194 next = PKTNEXT(di->osh, p);
1196 /* return nonzero if out of tx descriptors */
1197 if (NEXTTXD(txout) == di->txin)
1203 /* get physical address of buffer start */
1204 pa = (uint32) DMA_MAP(di->osh, data, len, DMA_TX, p);
1210 flags |= (CTRL_IOC | CTRL_EOF);
1211 if (txout == (di->ntxd - 1))
1214 dma32_dd_upd(di, di->txd32, pa, txout, &flags, len);
1215 ASSERT(di->txp[txout] == NULL);
1217 txout = NEXTTXD(txout);
1220 /* if last txd eof not set, fix it */
1221 if (!(flags & CTRL_EOF))
1222 W_SM(&di->txd32[PREVTXD(txout)].ctrl, BUS_SWAP32(flags | CTRL_IOC | CTRL_EOF));
1224 /* save the packet */
1225 di->txp[PREVTXD(txout)] = p0;
1227 /* bump the tx descriptor index */
1232 W_REG(di->osh, &di->d32txregs->ptr, I2B(txout, dma32dd_t));
1234 /* tx flow control */
1235 di->hnddma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
1240 DMA_ERROR(("%s: dma_txfast: out of txds\n", di->name));
1241 PKTFREE(di->osh, p0, TRUE);
1242 di->hnddma.txavail = 0;
1243 di->hnddma.txnobuf++;
1248 * Reclaim next completed txd (txds if using chained buffers) and
1249 * return associated packet.
1250 * If 'force' is true, reclaim txd(s) and return associated packet
1251 * regardless of the value of the hardware "curr" pointer.
1254 dma32_getnexttxp(dma_info_t *di, bool forceall)
1259 DMA_TRACE(("%s: dma_getnexttxp %s\n", di->name, forceall ? "all" : ""));
1270 end = B2I(R_REG(di->osh, &di->d32txregs->status) & XS_CD_MASK, dma32dd_t);
1272 if ((start == 0) && (end > di->txout))
1275 for (i = start; i != end && !txp; i = NEXTTXD(i)) {
1276 DMA_UNMAP(di->osh, (BUS_SWAP32(R_SM(&di->txd32[i].addr)) - di->dataoffsetlow),
1277 (BUS_SWAP32(R_SM(&di->txd32[i].ctrl)) & CTRL_BC_MASK),
1278 DMA_TX, di->txp[i]);
1280 W_SM(&di->txd32[i].addr, 0xdeadbeef);
1287 /* tx flow control */
1288 di->hnddma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
1294 DMA_ERROR(("dma_getnexttxp: bogus curr: start %d end %d txout %d force %d\n",
1295 start, end, di->txout, forceall));
1301 dma32_getnextrxp(dma_info_t *di, bool forceall)
1306 /* if forcing, dma engine must be disabled */
1307 ASSERT(!forceall || !dma32_rxenabled(di));
1311 /* return if no packets posted */
1315 /* ignore curr if forceall */
1316 if (!forceall && (i == B2I(R_REG(di->osh, &di->d32rxregs->status) & RS_CD_MASK, dma32dd_t)))
1319 /* get the packet pointer that corresponds to the rx descriptor */
1324 /* clear this packet from the descriptor ring */
1325 DMA_UNMAP(di->osh, (BUS_SWAP32(R_SM(&di->rxd32[i].addr)) - di->dataoffsetlow),
1326 di->rxbufsize, DMA_RX, rxp);
1328 W_SM(&di->rxd32[i].addr, 0xdeadbeef);
1330 di->rxin = NEXTRXD(i);
1336 * Rotate all active tx dma ring entries "forward" by (ActiveDescriptor - txin).
1339 dma32_txrotate(dma_info_t *di)
1348 ASSERT(dma32_txsuspendedidle(di));
1350 nactive = _dma_txactive(di);
1351 ad = B2I(((R_REG(di->osh, &di->d32txregs->status) & XS_AD_MASK) >> XS_AD_SHIFT), dma32dd_t);
1352 rot = TXD(ad - di->txin);
1354 ASSERT(rot < di->ntxd);
1356 /* full-ring case is a lot harder - don't worry about this */
1357 if (rot >= (di->ntxd - nactive)) {
1358 DMA_ERROR(("%s: dma_txrotate: ring full - punt\n", di->name));
1363 last = PREVTXD(di->txout);
1365 /* move entries starting at last and moving backwards to first */
1366 for (old = last; old != PREVTXD(first); old = PREVTXD(old)) {
1367 new = TXD(old + rot);
1370 * Move the tx dma descriptor.
1371 * EOT is set only in the last entry in the ring.
1373 w = BUS_SWAP32(R_SM(&di->txd32[old].ctrl)) & ~CTRL_EOT;
1374 if (new == (di->ntxd - 1))
1376 W_SM(&di->txd32[new].ctrl, BUS_SWAP32(w));
1377 W_SM(&di->txd32[new].addr, R_SM(&di->txd32[old].addr));
1379 /* zap the old tx dma descriptor address field */
1380 W_SM(&di->txd32[old].addr, BUS_SWAP32(0xdeadbeef));
1382 /* move the corresponding txp[] entry */
1383 ASSERT(di->txp[new] == NULL);
1384 di->txp[new] = di->txp[old];
1385 di->txp[old] = NULL;
1388 /* update txin and txout */
1390 di->txout = TXD(di->txout + rot);
1391 di->hnddma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
1394 W_REG(di->osh, &di->d32txregs->ptr, I2B(di->txout, dma32dd_t));
1397 /* 64 bits DMA functions */
1401 dma64_txinit(dma_info_t *di)
1403 DMA_TRACE(("%s: dma_txinit\n", di->name));
1408 di->txin = di->txout = 0;
1409 di->hnddma.txavail = di->ntxd - 1;
1411 /* clear tx descriptor ring */
1412 BZERO_SM((void *)(uintptr)di->txd64, (di->ntxd * sizeof(dma64dd_t)));
1413 W_REG(di->osh, &di->d64txregs->control, D64_XC_XE);
1414 _dma_ddtable_init(di, DMA_TX, di->txdpa);
1418 dma64_txenabled(dma_info_t *di)
1422 /* If the chip is dead, it is not enabled :-) */
1423 xc = R_REG(di->osh, &di->d64txregs->control);
1424 return ((xc != 0xffffffff) && (xc & D64_XC_XE));
1428 dma64_txsuspend(dma_info_t *di)
1430 DMA_TRACE(("%s: dma_txsuspend\n", di->name));
1435 OR_REG(di->osh, &di->d64txregs->control, D64_XC_SE);
1439 dma64_txresume(dma_info_t *di)
1441 DMA_TRACE(("%s: dma_txresume\n", di->name));
1446 AND_REG(di->osh, &di->d64txregs->control, ~D64_XC_SE);
1450 dma64_txsuspended(dma_info_t *di)
1452 return (di->ntxd == 0) || ((R_REG(di->osh, &di->d64txregs->control) & D64_XC_SE)
1457 dma64_txreclaim(dma_info_t *di, bool forceall)
1461 DMA_TRACE(("%s: dma_txreclaim %s\n", di->name, forceall ? "all" : ""));
1463 while ((p = dma64_getnexttxp(di, forceall)))
1464 PKTFREE(di->osh, p, TRUE);
1468 dma64_txstopped(dma_info_t *di)
1470 return ((R_REG(di->osh, &di->d64txregs->status0) & D64_XS0_XS_MASK) == D64_XS0_XS_STOPPED);
1474 dma64_rxstopped(dma_info_t *di)
1476 return ((R_REG(di->osh, &di->d64rxregs->status0) & D64_RS0_RS_MASK) == D64_RS0_RS_STOPPED);
1480 dma64_alloc(dma_info_t *di, uint direction)
1487 ddlen = sizeof(dma64dd_t);
1489 size = (direction == DMA_TX) ? (di->ntxd * ddlen) : (di->nrxd * ddlen);
1491 alignbytes = di->dma64align;
1493 if (!ISALIGNED(DMA_CONSISTENT_ALIGN, alignbytes))
1496 if (direction == DMA_TX) {
1497 if ((va = DMA_ALLOC_CONSISTENT(di->osh, size, &di->txdpa, &di->tx_dmah)) == NULL) {
1498 DMA_ERROR(("%s: dma_attach: DMA_ALLOC_CONSISTENT(ntxd) failed\n",
1503 di->txd64 = (dma64dd_t *) ROUNDUP((uintptr)va, alignbytes);
1504 di->txdalign = (uint)((int8*)(uintptr)di->txd64 - (int8*)va);
1505 di->txdpa += di->txdalign;
1506 di->txdalloc = size;
1507 ASSERT(ISALIGNED((uintptr)di->txd64, alignbytes));
1509 if ((va = DMA_ALLOC_CONSISTENT(di->osh, size, &di->rxdpa, &di->rx_dmah)) == NULL) {
1510 DMA_ERROR(("%s: dma_attach: DMA_ALLOC_CONSISTENT(nrxd) failed\n",
1514 di->rxd64 = (dma64dd_t *) ROUNDUP((uintptr)va, alignbytes);
1515 di->rxdalign = (uint)((int8*)(uintptr)di->rxd64 - (int8*)va);
1516 di->rxdpa += di->rxdalign;
1517 di->rxdalloc = size;
1518 ASSERT(ISALIGNED((uintptr)di->rxd64, alignbytes));
1525 dma64_txreset(dma_info_t *di)
1532 /* suspend tx DMA first */
1533 W_REG(di->osh, &di->d64txregs->control, D64_XC_SE);
1534 SPINWAIT(((status = (R_REG(di->osh, &di->d64txregs->status0) & D64_XS0_XS_MASK)) !=
1535 D64_XS0_XS_DISABLED) &&
1536 (status != D64_XS0_XS_IDLE) &&
1537 (status != D64_XS0_XS_STOPPED),
1540 W_REG(di->osh, &di->d64txregs->control, 0);
1541 SPINWAIT(((status = (R_REG(di->osh, &di->d64txregs->status0) & D64_XS0_XS_MASK)) !=
1542 D64_XS0_XS_DISABLED),
1545 /* wait for the last transaction to complete */
1548 return (status == D64_XS0_XS_DISABLED);
1552 dma64_rxidle(dma_info_t *di)
1554 DMA_TRACE(("%s: dma_rxidle\n", di->name));
1559 return ((R_REG(di->osh, &di->d64rxregs->status0) & D64_RS0_CD_MASK) ==
1560 R_REG(di->osh, &di->d64rxregs->ptr));
1564 dma64_rxreset(dma_info_t *di)
1571 W_REG(di->osh, &di->d64rxregs->control, 0);
1572 SPINWAIT(((status = (R_REG(di->osh, &di->d64rxregs->status0) & D64_RS0_RS_MASK)) !=
1573 D64_RS0_RS_DISABLED),
1576 return (status == D64_RS0_RS_DISABLED);
1580 dma64_rxenabled(dma_info_t *di)
1584 rc = R_REG(di->osh, &di->d64rxregs->control);
1585 return ((rc != 0xffffffff) && (rc & D64_RC_RE));
1589 dma64_txsuspendedidle(dma_info_t *di)
1595 if (!(R_REG(di->osh, &di->d64txregs->control) & D64_XC_SE))
1598 if ((R_REG(di->osh, &di->d64txregs->status0) & D64_XS0_XS_MASK) == D64_XS0_XS_IDLE)
1605 /* !! tx entry routine */
1607 dma64_txfast(dma_info_t *di, void *p0, bool commit)
1616 DMA_TRACE(("%s: dma_txfast\n", di->name));
1621 * Walk the chain of packet buffers
1622 * allocating and initializing transmit descriptor entries.
1624 for (p = p0; p; p = next) {
1625 data = PKTDATA(di->osh, p);
1626 len = PKTLEN(di->osh, p);
1627 next = PKTNEXT(di->osh, p);
1629 /* return nonzero if out of tx descriptors */
1630 if (NEXTTXD(txout) == di->txin)
1636 /* get physical address of buffer start */
1637 pa = (uint32) DMA_MAP(di->osh, data, len, DMA_TX, p);
1641 flags |= D64_CTRL1_SOF;
1643 flags |= (D64_CTRL1_IOC | D64_CTRL1_EOF);
1644 if (txout == (di->ntxd - 1))
1645 flags |= D64_CTRL1_EOT;
1647 dma64_dd_upd(di, di->txd64, pa, txout, &flags, len);
1648 ASSERT(di->txp[txout] == NULL);
1650 txout = NEXTTXD(txout);
1653 /* if last txd eof not set, fix it */
1654 if (!(flags & D64_CTRL1_EOF))
1655 W_SM(&di->txd64[PREVTXD(txout)].ctrl1,
1656 BUS_SWAP32(flags | D64_CTRL1_IOC | D64_CTRL1_EOF));
1658 /* save the packet */
1659 di->txp[PREVTXD(txout)] = p0;
1661 /* bump the tx descriptor index */
1666 W_REG(di->osh, &di->d64txregs->ptr, I2B(txout, dma64dd_t));
1668 /* tx flow control */
1669 di->hnddma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
1674 DMA_ERROR(("%s: dma_txfast: out of txds\n", di->name));
1675 PKTFREE(di->osh, p0, TRUE);
1676 di->hnddma.txavail = 0;
1677 di->hnddma.txnobuf++;
1682 * Reclaim next completed txd (txds if using chained buffers) and
1683 * return associated packet.
1684 * If 'force' is true, reclaim txd(s) and return associated packet
1685 * regardless of the value of the hardware "curr" pointer.
1688 dma64_getnexttxp(dma_info_t *di, bool forceall)
1693 DMA_TRACE(("%s: dma_getnexttxp %s\n", di->name, forceall ? "all" : ""));
1704 end = B2I(R_REG(di->osh, &di->d64txregs->status0) & D64_XS0_CD_MASK, dma64dd_t);
1706 if ((start == 0) && (end > di->txout))
1709 for (i = start; i != end && !txp; i = NEXTTXD(i)) {
1710 DMA_UNMAP(di->osh, (BUS_SWAP32(R_SM(&di->txd64[i].addrlow)) - di->dataoffsetlow),
1711 (BUS_SWAP32(R_SM(&di->txd64[i].ctrl2)) & D64_CTRL2_BC_MASK),
1712 DMA_TX, di->txp[i]);
1714 W_SM(&di->txd64[i].addrlow, 0xdeadbeef);
1715 W_SM(&di->txd64[i].addrhigh, 0xdeadbeef);
1723 /* tx flow control */
1724 di->hnddma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
1730 DMA_ERROR(("dma_getnexttxp: bogus curr: start %d end %d txout %d force %d\n",
1731 start, end, di->txout, forceall));
1737 dma64_getnextrxp(dma_info_t *di, bool forceall)
1742 /* if forcing, dma engine must be disabled */
1743 ASSERT(!forceall || !dma64_rxenabled(di));
1747 /* return if no packets posted */
1751 /* ignore curr if forceall */
1753 (i == B2I(R_REG(di->osh, &di->d64rxregs->status0) & D64_RS0_CD_MASK, dma64dd_t)))
1756 /* get the packet pointer that corresponds to the rx descriptor */
1761 /* clear this packet from the descriptor ring */
1762 DMA_UNMAP(di->osh, (BUS_SWAP32(R_SM(&di->rxd64[i].addrlow)) - di->dataoffsetlow),
1763 di->rxbufsize, DMA_RX, rxp);
1765 W_SM(&di->rxd64[i].addrlow, 0xdeadbeef);
1766 W_SM(&di->rxd64[i].addrhigh, 0xdeadbeef);
1768 di->rxin = NEXTRXD(i);
1774 _dma64_addrext(osl_t *osh, dma64regs_t *dma64regs)
1777 OR_REG(osh, &dma64regs->control, D64_XC_AE);
1778 w = R_REG(osh, &dma64regs->control);
1779 AND_REG(osh, &dma64regs->control, ~D64_XC_AE);
1780 return ((w & D64_XC_AE) == D64_XC_AE);
1784 * Rotate all active tx dma ring entries "forward" by (ActiveDescriptor - txin).
1787 dma64_txrotate(dma_info_t *di)
1796 ASSERT(dma64_txsuspendedidle(di));
1798 nactive = _dma_txactive(di);
1799 ad = B2I((R_REG(di->osh, &di->d64txregs->status1) & D64_XS1_AD_MASK), dma64dd_t);
1800 rot = TXD(ad - di->txin);
1802 ASSERT(rot < di->ntxd);
1804 /* full-ring case is a lot harder - don't worry about this */
1805 if (rot >= (di->ntxd - nactive)) {
1806 DMA_ERROR(("%s: dma_txrotate: ring full - punt\n", di->name));
1811 last = PREVTXD(di->txout);
1813 /* move entries starting at last and moving backwards to first */
1814 for (old = last; old != PREVTXD(first); old = PREVTXD(old)) {
1815 new = TXD(old + rot);
1818 * Move the tx dma descriptor.
1819 * EOT is set only in the last entry in the ring.
1821 w = BUS_SWAP32(R_SM(&di->txd64[old].ctrl1)) & ~D64_CTRL1_EOT;
1822 if (new == (di->ntxd - 1))
1824 W_SM(&di->txd64[new].ctrl1, BUS_SWAP32(w));
1826 w = BUS_SWAP32(R_SM(&di->txd64[old].ctrl2));
1827 W_SM(&di->txd64[new].ctrl2, BUS_SWAP32(w));
1829 W_SM(&di->txd64[new].addrlow, R_SM(&di->txd64[old].addrlow));
1830 W_SM(&di->txd64[new].addrhigh, R_SM(&di->txd64[old].addrhigh));
1832 /* zap the old tx dma descriptor address field */
1833 W_SM(&di->txd64[old].addrlow, BUS_SWAP32(0xdeadbeef));
1834 W_SM(&di->txd64[old].addrhigh, BUS_SWAP32(0xdeadbeef));
1836 /* move the corresponding txp[] entry */
1837 ASSERT(di->txp[new] == NULL);
1838 di->txp[new] = di->txp[old];
1839 di->txp[old] = NULL;
1842 /* update txin and txout */
1844 di->txout = TXD(di->txout + rot);
1845 di->hnddma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
1848 W_REG(di->osh, &di->d64txregs->ptr, I2B(di->txout, dma64dd_t));
1851 #endif /* BCMDMA64 */
1854 dma_addrwidth(sb_t *sbh, void *dmaregs)
1856 dma32regs_t *dma32regs;
1862 /* DMA engine is 64-bit capable */
1863 if (((sb_coreflagshi(sbh, 0, 0) & SBTMH_DMA64) == SBTMH_DMA64)) {
1864 /* backplane are 64 bits capable */
1866 if (sb_backplane64(sbh))
1867 /* If bus is System Backplane or PCIE then we can access 64-bits */
1868 if ((BUSTYPE(sbh->bustype) == SB_BUS) ||
1869 ((BUSTYPE(sbh->bustype) == PCI_BUS) &&
1870 sbh->buscoretype == SB_PCIE))
1871 return (DMADDRWIDTH_64);
1874 /* DMA64 is always 32 bits capable, AE is always TRUE */
1876 ASSERT(_dma64_addrext(osh, (dma64regs_t *)dmaregs));
1878 return (DMADDRWIDTH_32);
1882 /* Start checking for 32-bit / 30-bit addressing */
1883 dma32regs = (dma32regs_t *)dmaregs;
1885 /* For System Backplane, PCIE bus or addrext feature, 32-bits ok */
1886 if ((BUSTYPE(sbh->bustype) == SB_BUS) ||
1887 ((BUSTYPE(sbh->bustype) == PCI_BUS) && sbh->buscoretype == SB_PCIE) ||
1888 (_dma32_addrext(osh, dma32regs)))
1889 return (DMADDRWIDTH_32);
1892 return (DMADDRWIDTH_30);