ab87e4e2df2fa45e48ab65b92eaf980de60b1451
[10.03/openwrt.git] / package / linux / kernel-source / drivers / net / hnd / hnddma.c
1 /*
2  * Generic Broadcom Home Networking Division (HND) DMA module.
3  * This supports the following chips: BCM42xx, 44xx, 47xx .
4  *
5  * Copyright 2004, Broadcom Corporation
6  * All Rights Reserved.
7  * 
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.
12  *
13  * $Id$
14  */
15
16 #include <typedefs.h>
17 #include <osl.h>
18 #include <bcmendian.h>
19 #include <bcmutils.h>
20
21 struct dma_info;        /* forward declaration */
22 #define di_t struct dma_info
23 #include <hnddma.h>
24
25 /* debug/trace */
26 #define DMA_ERROR(args)
27 #define DMA_TRACE(args)
28
29 /* default dma message level(if input msg_level pointer is null in dma_attach()) */
30 static uint dma_msg_level = 0;
31
32 #define MAXNAMEL        8
33 #define MAXDD           (DMAMAXRINGSZ / sizeof (dmadd_t))
34
35 /* dma engine software state */
36 typedef struct dma_info {
37         hnddma_t        hnddma;         /* exported structure */
38         uint            *msg_level;     /* message level pointer */
39
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 */
44
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 */
52
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 */
59
60         /* tunables */
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 */
68 } dma_info_t;
69
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)
78
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))
82
83 void*
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)
86 {
87         dma_info_t *di;
88         void *va;
89
90         ASSERT(ntxd <= MAXDD);
91         ASSERT(nrxd <= MAXDD);
92
93         /* allocate private info structure */
94         if ((di = MALLOC(sizeof (dma_info_t))) == NULL)
95                 return (NULL);
96         bzero((char*)di, sizeof (dma_info_t));
97
98         /* set message level */
99         di->msg_level = msg_level ? msg_level : &dma_msg_level;
100
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));
102
103         /* make a private copy of our callers name */
104         strncpy(di->name, name, MAXNAMEL);
105         di->name[MAXNAMEL-1] = '\0';
106
107         di->drv = drv;
108         di->dev = dev;
109         di->regs = regs;
110
111         /* allocate transmit descriptor ring */
112         if (ntxd) {
113                 if ((va = DMA_ALLOC_CONSISTENT(dev, (DMAMAXRINGSZ + DMARINGALIGN), &di->txdpa)) == NULL)
114                         goto fail;
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));
119         }
120
121         /* allocate receive descriptor ring */
122         if (nrxd) {
123                 if ((va = DMA_ALLOC_CONSISTENT(dev, (DMAMAXRINGSZ + DMARINGALIGN), &di->rxdpa)) == NULL)
124                         goto fail;
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));
129         }
130
131         /* save tunables */
132         di->ntxd = ntxd;
133         di->nrxd = nrxd;
134         di->rxbufsize = rxbufsize;
135         di->nrxpost = nrxpost;
136         di->rxoffset = rxoffset;
137         di->ddoffset = ddoffset;
138         di->dataoffset = dataoffset;
139
140         return ((void*)di);
141
142 fail:
143         dma_detach((void*)di);
144         return (NULL);
145 }
146
147 /* may be called with core in reset */
148 void
149 dma_detach(dma_info_t *di)
150 {
151         if (di == NULL)
152                 return;
153
154         DMA_TRACE(("%s: dma_detach\n", di->name));
155
156         /* shouldn't be here if descriptors are unreclaimed */
157         ASSERT(di->txin == di->txout);
158         ASSERT(di->rxin == di->rxout);
159
160         /* free dma descriptor rings */
161         if (di->txd)
162                 DMA_FREE_CONSISTENT(di->dev, (void *)((uint)di->txd - di->txdalign), (DMAMAXRINGSZ + DMARINGALIGN), di->txdpa);
163         if (di->rxd)
164                 DMA_FREE_CONSISTENT(di->dev, (void *)((uint)di->rxd - di->rxdalign), (DMAMAXRINGSZ + DMARINGALIGN), di->rxdpa);
165
166         /* free our private info structure */
167         MFREE((void*)di, sizeof (dma_info_t));
168 }
169
170
171 void
172 dma_txreset(dma_info_t *di)
173 {
174         uint32 status;
175
176         DMA_TRACE(("%s: dma_txreset\n", di->name));
177
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,
183                  10000);
184
185         W_REG(&di->regs->xmtcontrol, 0);
186         SPINWAIT((status = (R_REG(&di->regs->xmtstatus) & XS_XS_MASK)) != XS_XS_DISABLED,
187                  10000);
188
189         if (status != XS_XS_DISABLED) {
190                 DMA_ERROR(("%s: dma_txreset: dma cannot be stopped\n", di->name));
191         }
192
193         /* wait for the last transaction to complete */
194         OSL_DELAY(300);
195 }
196
197 void
198 dma_rxreset(dma_info_t *di)
199 {
200         uint32 status;
201
202         DMA_TRACE(("%s: dma_rxreset\n", di->name));
203
204         W_REG(&di->regs->rcvcontrol, 0);
205         SPINWAIT((status = (R_REG(&di->regs->rcvstatus) & RS_RS_MASK)) != RS_RS_DISABLED,
206                  10000);
207
208         if (status != RS_RS_DISABLED) {
209                 DMA_ERROR(("%s: dma_rxreset: dma cannot be stopped\n", di->name));
210         }
211 }
212
213 void
214 dma_txinit(dma_info_t *di)
215 {
216         DMA_TRACE(("%s: dma_txinit\n", di->name));
217
218         di->txin = di->txout = 0;
219         di->txavail = di->ntxd - 1;
220
221         /* clear tx descriptor ring */
222         BZERO_SM((void*)di->txd, (di->ntxd * sizeof (dmadd_t)));
223
224         W_REG(&di->regs->xmtcontrol, XC_XE);
225         W_REG(&di->regs->xmtaddr, (di->txdpa + di->ddoffset));
226 }
227
228 bool
229 dma_txenabled(dma_info_t *di)
230 {
231         uint32 xc;
232
233         /* If the chip is dead, it is not enabled :-) */
234         xc = R_REG(&di->regs->xmtcontrol);
235         return ((xc != 0xffffffff) && (xc & XC_XE));
236 }
237
238 void
239 dma_txsuspend(dma_info_t *di)
240 {
241         DMA_TRACE(("%s: dma_txsuspend\n", di->name));
242         OR_REG(&di->regs->xmtcontrol, XC_SE);
243 }
244
245 void
246 dma_txresume(dma_info_t *di)
247 {
248         DMA_TRACE(("%s: dma_txresume\n", di->name));
249         AND_REG(&di->regs->xmtcontrol, ~XC_SE);
250 }
251
252 bool
253 dma_txsuspended(dma_info_t *di)
254 {
255         if (!(R_REG(&di->regs->xmtcontrol) & XC_SE))
256                 return 0;
257         
258         if ((R_REG(&di->regs->xmtstatus) & XS_XS_MASK) != XS_XS_IDLE)
259                 return 0;
260
261         OSL_DELAY(2);
262         return ((R_REG(&di->regs->xmtstatus) & XS_XS_MASK) == XS_XS_IDLE);
263 }
264
265 bool
266 dma_txstopped(dma_info_t *di)
267 {
268         return ((R_REG(&di->regs->xmtstatus) & XS_XS_MASK) == XS_XS_STOPPED);
269 }
270
271 bool
272 dma_rxstopped(dma_info_t *di)
273 {
274         return ((R_REG(&di->regs->rcvstatus) & RS_RS_MASK) == RS_RS_STOPPED);
275 }
276
277 void
278 dma_fifoloopbackenable(dma_info_t *di)
279 {
280         DMA_TRACE(("%s: dma_fifoloopbackenable\n", di->name));
281         OR_REG(&di->regs->xmtcontrol, XC_LE);
282 }
283
284 void
285 dma_rxinit(dma_info_t *di)
286 {
287         DMA_TRACE(("%s: dma_rxinit\n", di->name));
288
289         di->rxin = di->rxout = 0;
290
291         /* clear rx descriptor ring */
292         BZERO_SM((void*)di->rxd, (di->nrxd * sizeof (dmadd_t)));
293
294         dma_rxenable(di);
295         W_REG(&di->regs->rcvaddr, (di->rxdpa + di->ddoffset));
296 }
297
298 void
299 dma_rxenable(dma_info_t *di)
300 {
301         DMA_TRACE(("%s: dma_rxenable\n", di->name));
302         W_REG(&di->regs->rcvcontrol, ((di->rxoffset << RC_RO_SHIFT) | RC_RE));
303 }
304
305 bool
306 dma_rxenabled(dma_info_t *di)
307 {
308         uint32 rc;
309
310         rc = R_REG(&di->regs->rcvcontrol);
311         return ((rc != 0xffffffff) && (rc & RC_RE));
312 }
313
314 /*
315  * The BCM47XX family supports full 32bit dma engine buffer addressing so
316  * dma buffers can cross 4 Kbyte page boundaries.
317  */
318 int
319 dma_txfast(dma_info_t *di, void *p0, uint32 coreflags)
320 {
321         void *p, *next;
322         uchar *data;
323         uint len;
324         uint txout;
325         uint32 ctrl;
326         uint32 pa;
327
328         DMA_TRACE(("%s: dma_txfast\n", di->name));
329
330         txout = di->txout;
331         ctrl = 0;
332
333         /*
334          * Walk the chain of packet buffers
335          * allocating and initializing transmit descriptor entries.
336          */
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);
341
342                 /* return nonzero if out of tx descriptors */
343                 if (NEXTTXD(txout) == di->txin)
344                         goto outoftxd;
345
346                 if (len == 0)
347                         continue;
348
349                 /* get physical address of buffer start */
350                 pa = (uint32) DMA_MAP(di->dev, data, len, DMA_TX, p);
351
352                 /* build the descriptor control value */
353                 ctrl = len & CTRL_BC_MASK;
354
355                 ctrl |= coreflags;
356                 
357                 if (p == p0)
358                         ctrl |= CTRL_SOF;
359                 if (next == NULL)
360                         ctrl |= (CTRL_IOC | CTRL_EOF);
361                 if (txout == (di->ntxd - 1))
362                         ctrl |= CTRL_EOT;
363
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));
367
368                 ASSERT(di->txp[txout] == NULL);
369
370                 txout = NEXTTXD(txout);
371         }
372
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));
376
377         /* save the packet */
378         di->txp[PREVTXD(txout)] = p0;
379
380         /* bump the tx descriptor index */
381         di->txout = txout;
382
383         /* kick the chip */
384         W_REG(&di->regs->xmtptr, I2B(txout));
385
386         /* tx flow control */
387         di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
388
389         return (0);
390
391 outoftxd:
392         DMA_ERROR(("%s: dma_txfast: out of txds\n", di->name));
393         PKTFREE(di->drv, p0, TRUE);
394         di->txavail = 0;
395         di->hnddma.txnobuf++;
396         return (-1);
397 }
398
399 #define PAGESZ          4096
400 #define PAGEBASE(x)     ((uint)(x) & ~4095)
401
402 /*
403  * Just like above except go through the extra effort of splitting
404  * buffers that cross 4Kbyte boundaries into multiple tx descriptors.
405  */
406 int
407 dma_tx(dma_info_t *di, void *p0, uint32 coreflags)
408 {
409         void *p, *next;
410         uchar *data;
411         uint plen, len;
412         uchar *page, *start, *end;
413         uint txout;
414         uint32 ctrl;
415         uint32 pa;
416
417         DMA_TRACE(("%s: dma_tx\n", di->name));
418
419         txout = di->txout;
420         ctrl = 0;
421
422         /*
423          * Walk the chain of packet buffers
424          * splitting those that cross 4 Kbyte boundaries
425          * allocating and initializing transmit descriptor entries.
426          */
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);
431
432                 if (plen == 0)
433                         continue;
434
435                 for (page = (uchar*)PAGEBASE(data);
436                         page <= (uchar*)PAGEBASE(data + plen - 1);
437                         page += PAGESZ) {
438
439                         /* return nonzero if out of tx descriptors */
440                         if (NEXTTXD(txout) == di->txin)
441                                 goto outoftxd;
442
443                         start = (page == (uchar*)PAGEBASE(data))?  data: page;
444                         end = (page == (uchar*)PAGEBASE(data + plen))?
445                                 (data + plen): (page + PAGESZ);
446                         len = end - start;
447
448                         /* build the descriptor control value */
449                         ctrl = len & CTRL_BC_MASK;
450
451                         ctrl |= coreflags;
452
453                         if ((p == p0) && (start == data))
454                                 ctrl |= CTRL_SOF;
455                         if ((next == NULL) && (end == (data + plen)))
456                                 ctrl |= (CTRL_IOC | CTRL_EOF);
457                         if (txout == (di->ntxd - 1))
458                                 ctrl |= CTRL_EOT;
459
460                         /* get physical address of buffer start */
461                         pa = (uint32) DMA_MAP(di->dev, start, len, DMA_TX, p);
462
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));
466
467                         ASSERT(di->txp[txout] == NULL);
468
469                         txout = NEXTTXD(txout);
470                 }
471         }
472
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));
476
477         /* save the packet */
478         di->txp[PREVTXD(txout)] = p0;
479
480         /* bump the tx descriptor index */
481         di->txout = txout;
482
483         /* kick the chip */
484         W_REG(&di->regs->xmtptr, I2B(txout));
485
486         /* tx flow control */
487         di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
488
489         return (0);
490
491 outoftxd:
492         DMA_ERROR(("%s: dma_tx: out of txds\n", di->name));
493         PKTFREE(di->drv, p0, TRUE);
494         di->txavail = 0;
495         di->hnddma.txnobuf++;
496         return (-1);
497 }
498
499 /* returns a pointer to the next frame received, or NULL if there are no more */
500 void*
501 dma_rx(dma_info_t *di)
502 {
503         void *p;
504         uint len;
505         int skiplen = 0;
506
507         while ((p = dma_getnextrxp(di, FALSE))) {
508                 /* skip giant packets which span multiple rx descriptors */
509                 if (skiplen > 0) {
510                         skiplen -= di->rxbufsize;
511                         if (skiplen < 0)
512                                 skiplen = 0;
513                         PKTFREE(di->drv, p, FALSE);
514                         continue;
515                 }
516
517                 len = ltoh16(*(uint16*)(PKTDATA(di->drv, p)));
518                 DMA_TRACE(("%s: dma_rx len %d\n", di->name, len));
519
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));
523                         if (len > 0)
524                                 skiplen = len - (di->rxbufsize - di->rxoffset);
525                         PKTFREE(di->drv, p, FALSE);
526                         di->hnddma.rxgiants++;
527                         continue;
528                 }
529
530                 /* set actual length */
531                 PKTSETLEN(di->drv, p, (di->rxoffset + len));
532
533                 break;
534         }
535
536         return (p);
537 }
538
539 /* post receive buffers */
540 void
541 dma_rxfill(dma_info_t *di)
542 {
543         void *p;
544         uint rxin, rxout;
545         uint ctrl;
546         uint n;
547         uint i;
548         uint32 pa;
549         uint rxbufsize;
550
551         /*
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.
555          */
556
557         rxin = di->rxin;
558         rxout = di->rxout;
559         rxbufsize = di->rxbufsize;
560
561         n = di->nrxpost - NRXDACTIVE(rxin, rxout);
562
563         DMA_TRACE(("%s: dma_rxfill: post %d\n", di->name, n));
564
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++;
569                         break;
570                 }
571
572                 *(uint32*)(OSL_UNCACHED(PKTDATA(di->drv, p))) = 0;
573
574                 pa = (uint32) DMA_MAP(di->dev, PKTDATA(di->drv, p), rxbufsize, DMA_RX, p);
575                 ASSERT(ISALIGNED(pa, 4));
576
577                 /* save the free packet pointer */
578                 ASSERT(di->rxp[rxout] == NULL);
579                 di->rxp[rxout] = p;
580
581                 /* prep the descriptor control value */
582                 ctrl = rxbufsize;
583                 if (rxout == (di->nrxd - 1))
584                         ctrl |= CTRL_EOT;
585
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));
589
590                 rxout = NEXTRXD(rxout);
591         }
592
593         di->rxout = rxout;
594
595         /* update the chip lastdscr pointer */
596         W_REG(&di->regs->rcvptr, I2B(rxout));
597 }
598
599 void
600 dma_txreclaim(dma_info_t *di, bool forceall)
601 {
602         void *p;
603
604         DMA_TRACE(("%s: dma_txreclaim %s\n", di->name, forceall ? "all" : ""));
605
606         while ((p = dma_getnexttxp(di, forceall)))
607                 PKTFREE(di->drv, p, TRUE);
608 }
609
610 /*
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.
615  */
616 void*
617 dma_getnexttxp(dma_info_t *di, bool forceall)
618 {
619         uint start, end, i;
620         void *txp;
621
622         DMA_TRACE(("%s: dma_getnexttxp %s\n", di->name, forceall ? "all" : ""));
623
624         txp = NULL;
625
626         start = di->txin;
627         if (forceall)
628                 end = di->txout;
629         else
630                 end = B2I(R_REG(&di->regs->xmtstatus) & XS_CD_MASK);
631
632         if ((start == 0) && (end > di->txout))
633                 goto bogus;
634
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);
639                 txp = di->txp[i];
640                 di->txp[i] = NULL;
641         }
642
643         di->txin = i;
644
645         /* tx flow control */
646         di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
647
648         return (txp);
649
650 bogus:
651 /*
652         DMA_ERROR(("dma_getnexttxp: bogus curr: start %d end %d txout %d force %d\n",
653                 start, end, di->txout, forceall));
654 */
655         return (NULL);
656 }
657
658 /* like getnexttxp but no reclaim */
659 void*
660 dma_peeknexttxp(dma_info_t *di)
661 {
662         uint end, i;
663
664         end = B2I(R_REG(&di->regs->xmtstatus) & XS_CD_MASK);
665
666         for (i = di->txin; i != end; i = NEXTTXD(i))
667                 if (di->txp[i])
668                         return (di->txp[i]);
669
670         return (NULL);
671 }
672
673 void
674 dma_rxreclaim(dma_info_t *di)
675 {
676         void *p;
677
678         DMA_TRACE(("%s: dma_rxreclaim\n", di->name));
679
680         while ((p = dma_getnextrxp(di, TRUE)))
681                 PKTFREE(di->drv, p, FALSE);
682 }
683
684 void *
685 dma_getnextrxp(dma_info_t *di, bool forceall)
686 {
687         uint i;
688         void *rxp;
689
690         /* if forcing, dma engine must be disabled */
691         ASSERT(!forceall || !dma_rxenabled(di));
692
693         i = di->rxin;
694
695         /* return if no packets posted */
696         if (i == di->rxout)
697                 return (NULL);
698
699         /* ignore curr if forceall */
700         if (!forceall && (i == B2I(R_REG(&di->regs->rcvstatus) & RS_CD_MASK)))
701                 return (NULL);
702
703         /* get the packet pointer that corresponds to the rx descriptor */
704         rxp = di->rxp[i];
705         ASSERT(rxp);
706         di->rxp[i] = NULL;
707
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);
712
713         di->rxin = NEXTRXD(i);
714
715         return (rxp);
716 }
717
718 char*
719 dma_dumptx(dma_info_t *di, char *buf)
720 {
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));
728         return (buf);
729 }
730
731 char*
732 dma_dumprx(dma_info_t *di, char *buf)
733 {
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));
741         return (buf);
742 }
743
744 char*
745 dma_dump(dma_info_t *di, char *buf)
746 {
747         buf = dma_dumptx(di, buf);
748         buf = dma_dumprx(di, buf);
749         return (buf);
750 }
751
752 uint
753 dma_getvar(dma_info_t *di, char *name)
754 {
755         if (!strcmp(name, "&txavail"))
756                 return ((uint) &di->txavail);
757         else {
758                 ASSERT(0);
759         }
760         return (0);
761 }
762
763 void
764 dma_txblock(dma_info_t *di)
765 {
766         di->txavail = 0;
767 }
768
769 void
770 dma_txunblock(dma_info_t *di)
771 {
772         di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
773 }
774
775 uint
776 dma_txactive(dma_info_t *di)
777 {
778         return (NTXDACTIVE(di->txin, di->txout));
779 }
780
781 /*
782  * Rotate all active tx dma ring entries "forward" by (ActiveDescriptor - txin).
783  */
784 void
785 dma_txrotate(di_t *di)
786 {
787         uint ad;
788         uint nactive;
789         uint rot;
790         uint old, new;
791         uint32 w;
792         uint first, last;
793
794         ASSERT(dma_txsuspended(di));
795
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);
799
800         ASSERT(rot < di->ntxd);
801
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));
805                 return;
806         }
807
808         first = di->txin;
809         last = PREVTXD(di->txout);
810
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);
814
815                 /*
816                  * Move the tx dma descriptor.
817                  * EOT is set only in the last entry in the ring.
818                  */
819                 w = R_SM(&di->txd[old].ctrl) & ~CTRL_EOT;
820                 if (new == (di->ntxd - 1))
821                         w |= CTRL_EOT;
822                 W_SM(&di->txd[new].ctrl, w);
823                 W_SM(&di->txd[new].addr, R_SM(&di->txd[old].addr));
824
825                 /* zap the old tx dma descriptor address field */
826                 W_SM(&di->txd[old].addr, 0xdeadbeef);
827
828                 /* move the corresponding txp[] entry */
829                 ASSERT(di->txp[new] == NULL);
830                 di->txp[new] = di->txp[old];
831                 di->txp[old] = NULL;
832         }
833
834         /* update txin and txout */
835         di->txin = ad;
836         di->txout = TXD(di->txout + rot);
837         di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
838
839         /* kick the chip */
840         W_REG(&di->regs->xmtptr, I2B(di->txout));
841 }