1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2010 Broadcom Corporation
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Permission to use, copy, modify, and/or distribute this software for any
5*4882a593Smuzhiyun * purpose with or without fee is hereby granted, provided that the above
6*4882a593Smuzhiyun * copyright notice and this permission notice appear in all copies.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9*4882a593Smuzhiyun * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10*4882a593Smuzhiyun * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11*4882a593Smuzhiyun * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12*4882a593Smuzhiyun * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13*4882a593Smuzhiyun * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14*4882a593Smuzhiyun * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <linux/slab.h>
18*4882a593Smuzhiyun #include <linux/delay.h>
19*4882a593Smuzhiyun #include <linux/pci.h>
20*4882a593Smuzhiyun #include <net/cfg80211.h>
21*4882a593Smuzhiyun #include <net/mac80211.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include <brcmu_utils.h>
24*4882a593Smuzhiyun #include <aiutils.h>
25*4882a593Smuzhiyun #include "types.h"
26*4882a593Smuzhiyun #include "main.h"
27*4882a593Smuzhiyun #include "dma.h"
28*4882a593Smuzhiyun #include "soc.h"
29*4882a593Smuzhiyun #include "scb.h"
30*4882a593Smuzhiyun #include "ampdu.h"
31*4882a593Smuzhiyun #include "debug.h"
32*4882a593Smuzhiyun #include "brcms_trace_events.h"
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun /*
35*4882a593Smuzhiyun * dma register field offset calculation
36*4882a593Smuzhiyun */
37*4882a593Smuzhiyun #define DMA64REGOFFS(field) offsetof(struct dma64regs, field)
38*4882a593Smuzhiyun #define DMA64TXREGOFFS(di, field) (di->d64txregbase + DMA64REGOFFS(field))
39*4882a593Smuzhiyun #define DMA64RXREGOFFS(di, field) (di->d64rxregbase + DMA64REGOFFS(field))
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /*
42*4882a593Smuzhiyun * DMA hardware requires each descriptor ring to be 8kB aligned, and fit within
43*4882a593Smuzhiyun * a contiguous 8kB physical address.
44*4882a593Smuzhiyun */
45*4882a593Smuzhiyun #define D64RINGALIGN_BITS 13
46*4882a593Smuzhiyun #define D64MAXRINGSZ (1 << D64RINGALIGN_BITS)
47*4882a593Smuzhiyun #define D64RINGALIGN (1 << D64RINGALIGN_BITS)
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun #define D64MAXDD (D64MAXRINGSZ / sizeof(struct dma64desc))
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun /* transmit channel control */
52*4882a593Smuzhiyun #define D64_XC_XE 0x00000001 /* transmit enable */
53*4882a593Smuzhiyun #define D64_XC_SE 0x00000002 /* transmit suspend request */
54*4882a593Smuzhiyun #define D64_XC_LE 0x00000004 /* loopback enable */
55*4882a593Smuzhiyun #define D64_XC_FL 0x00000010 /* flush request */
56*4882a593Smuzhiyun #define D64_XC_PD 0x00000800 /* parity check disable */
57*4882a593Smuzhiyun #define D64_XC_AE 0x00030000 /* address extension bits */
58*4882a593Smuzhiyun #define D64_XC_AE_SHIFT 16
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun /* transmit descriptor table pointer */
61*4882a593Smuzhiyun #define D64_XP_LD_MASK 0x00000fff /* last valid descriptor */
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun /* transmit channel status */
64*4882a593Smuzhiyun #define D64_XS0_CD_MASK 0x00001fff /* current descriptor pointer */
65*4882a593Smuzhiyun #define D64_XS0_XS_MASK 0xf0000000 /* transmit state */
66*4882a593Smuzhiyun #define D64_XS0_XS_SHIFT 28
67*4882a593Smuzhiyun #define D64_XS0_XS_DISABLED 0x00000000 /* disabled */
68*4882a593Smuzhiyun #define D64_XS0_XS_ACTIVE 0x10000000 /* active */
69*4882a593Smuzhiyun #define D64_XS0_XS_IDLE 0x20000000 /* idle wait */
70*4882a593Smuzhiyun #define D64_XS0_XS_STOPPED 0x30000000 /* stopped */
71*4882a593Smuzhiyun #define D64_XS0_XS_SUSP 0x40000000 /* suspend pending */
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun #define D64_XS1_AD_MASK 0x00001fff /* active descriptor */
74*4882a593Smuzhiyun #define D64_XS1_XE_MASK 0xf0000000 /* transmit errors */
75*4882a593Smuzhiyun #define D64_XS1_XE_SHIFT 28
76*4882a593Smuzhiyun #define D64_XS1_XE_NOERR 0x00000000 /* no error */
77*4882a593Smuzhiyun #define D64_XS1_XE_DPE 0x10000000 /* descriptor protocol error */
78*4882a593Smuzhiyun #define D64_XS1_XE_DFU 0x20000000 /* data fifo underrun */
79*4882a593Smuzhiyun #define D64_XS1_XE_DTE 0x30000000 /* data transfer error */
80*4882a593Smuzhiyun #define D64_XS1_XE_DESRE 0x40000000 /* descriptor read error */
81*4882a593Smuzhiyun #define D64_XS1_XE_COREE 0x50000000 /* core error */
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun /* receive channel control */
84*4882a593Smuzhiyun /* receive enable */
85*4882a593Smuzhiyun #define D64_RC_RE 0x00000001
86*4882a593Smuzhiyun /* receive frame offset */
87*4882a593Smuzhiyun #define D64_RC_RO_MASK 0x000000fe
88*4882a593Smuzhiyun #define D64_RC_RO_SHIFT 1
89*4882a593Smuzhiyun /* direct fifo receive (pio) mode */
90*4882a593Smuzhiyun #define D64_RC_FM 0x00000100
91*4882a593Smuzhiyun /* separate rx header descriptor enable */
92*4882a593Smuzhiyun #define D64_RC_SH 0x00000200
93*4882a593Smuzhiyun /* overflow continue */
94*4882a593Smuzhiyun #define D64_RC_OC 0x00000400
95*4882a593Smuzhiyun /* parity check disable */
96*4882a593Smuzhiyun #define D64_RC_PD 0x00000800
97*4882a593Smuzhiyun /* address extension bits */
98*4882a593Smuzhiyun #define D64_RC_AE 0x00030000
99*4882a593Smuzhiyun #define D64_RC_AE_SHIFT 16
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /* flags for dma controller */
102*4882a593Smuzhiyun /* partity enable */
103*4882a593Smuzhiyun #define DMA_CTRL_PEN (1 << 0)
104*4882a593Smuzhiyun /* rx overflow continue */
105*4882a593Smuzhiyun #define DMA_CTRL_ROC (1 << 1)
106*4882a593Smuzhiyun /* allow rx scatter to multiple descriptors */
107*4882a593Smuzhiyun #define DMA_CTRL_RXMULTI (1 << 2)
108*4882a593Smuzhiyun /* Unframed Rx/Tx data */
109*4882a593Smuzhiyun #define DMA_CTRL_UNFRAMED (1 << 3)
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun /* receive descriptor table pointer */
112*4882a593Smuzhiyun #define D64_RP_LD_MASK 0x00000fff /* last valid descriptor */
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun /* receive channel status */
115*4882a593Smuzhiyun #define D64_RS0_CD_MASK 0x00001fff /* current descriptor pointer */
116*4882a593Smuzhiyun #define D64_RS0_RS_MASK 0xf0000000 /* receive state */
117*4882a593Smuzhiyun #define D64_RS0_RS_SHIFT 28
118*4882a593Smuzhiyun #define D64_RS0_RS_DISABLED 0x00000000 /* disabled */
119*4882a593Smuzhiyun #define D64_RS0_RS_ACTIVE 0x10000000 /* active */
120*4882a593Smuzhiyun #define D64_RS0_RS_IDLE 0x20000000 /* idle wait */
121*4882a593Smuzhiyun #define D64_RS0_RS_STOPPED 0x30000000 /* stopped */
122*4882a593Smuzhiyun #define D64_RS0_RS_SUSP 0x40000000 /* suspend pending */
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun #define D64_RS1_AD_MASK 0x0001ffff /* active descriptor */
125*4882a593Smuzhiyun #define D64_RS1_RE_MASK 0xf0000000 /* receive errors */
126*4882a593Smuzhiyun #define D64_RS1_RE_SHIFT 28
127*4882a593Smuzhiyun #define D64_RS1_RE_NOERR 0x00000000 /* no error */
128*4882a593Smuzhiyun #define D64_RS1_RE_DPO 0x10000000 /* descriptor protocol error */
129*4882a593Smuzhiyun #define D64_RS1_RE_DFU 0x20000000 /* data fifo overflow */
130*4882a593Smuzhiyun #define D64_RS1_RE_DTE 0x30000000 /* data transfer error */
131*4882a593Smuzhiyun #define D64_RS1_RE_DESRE 0x40000000 /* descriptor read error */
132*4882a593Smuzhiyun #define D64_RS1_RE_COREE 0x50000000 /* core error */
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /* fifoaddr */
135*4882a593Smuzhiyun #define D64_FA_OFF_MASK 0xffff /* offset */
136*4882a593Smuzhiyun #define D64_FA_SEL_MASK 0xf0000 /* select */
137*4882a593Smuzhiyun #define D64_FA_SEL_SHIFT 16
138*4882a593Smuzhiyun #define D64_FA_SEL_XDD 0x00000 /* transmit dma data */
139*4882a593Smuzhiyun #define D64_FA_SEL_XDP 0x10000 /* transmit dma pointers */
140*4882a593Smuzhiyun #define D64_FA_SEL_RDD 0x40000 /* receive dma data */
141*4882a593Smuzhiyun #define D64_FA_SEL_RDP 0x50000 /* receive dma pointers */
142*4882a593Smuzhiyun #define D64_FA_SEL_XFD 0x80000 /* transmit fifo data */
143*4882a593Smuzhiyun #define D64_FA_SEL_XFP 0x90000 /* transmit fifo pointers */
144*4882a593Smuzhiyun #define D64_FA_SEL_RFD 0xc0000 /* receive fifo data */
145*4882a593Smuzhiyun #define D64_FA_SEL_RFP 0xd0000 /* receive fifo pointers */
146*4882a593Smuzhiyun #define D64_FA_SEL_RSD 0xe0000 /* receive frame status data */
147*4882a593Smuzhiyun #define D64_FA_SEL_RSP 0xf0000 /* receive frame status pointers */
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun /* descriptor control flags 1 */
150*4882a593Smuzhiyun #define D64_CTRL_COREFLAGS 0x0ff00000 /* core specific flags */
151*4882a593Smuzhiyun #define D64_CTRL1_EOT ((u32)1 << 28) /* end of descriptor table */
152*4882a593Smuzhiyun #define D64_CTRL1_IOC ((u32)1 << 29) /* interrupt on completion */
153*4882a593Smuzhiyun #define D64_CTRL1_EOF ((u32)1 << 30) /* end of frame */
154*4882a593Smuzhiyun #define D64_CTRL1_SOF ((u32)1 << 31) /* start of frame */
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /* descriptor control flags 2 */
157*4882a593Smuzhiyun /* buffer byte count. real data len must <= 16KB */
158*4882a593Smuzhiyun #define D64_CTRL2_BC_MASK 0x00007fff
159*4882a593Smuzhiyun /* address extension bits */
160*4882a593Smuzhiyun #define D64_CTRL2_AE 0x00030000
161*4882a593Smuzhiyun #define D64_CTRL2_AE_SHIFT 16
162*4882a593Smuzhiyun /* parity bit */
163*4882a593Smuzhiyun #define D64_CTRL2_PARITY 0x00040000
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun /* control flags in the range [27:20] are core-specific and not defined here */
166*4882a593Smuzhiyun #define D64_CTRL_CORE_MASK 0x0ff00000
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun #define D64_RX_FRM_STS_LEN 0x0000ffff /* frame length mask */
169*4882a593Smuzhiyun #define D64_RX_FRM_STS_OVFL 0x00800000 /* RxOverFlow */
170*4882a593Smuzhiyun #define D64_RX_FRM_STS_DSCRCNT 0x0f000000 /* no. of descriptors used - 1 */
171*4882a593Smuzhiyun #define D64_RX_FRM_STS_DATATYPE 0xf0000000 /* core-dependent data type */
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun /*
174*4882a593Smuzhiyun * packet headroom necessary to accommodate the largest header
175*4882a593Smuzhiyun * in the system, (i.e TXOFF). By doing, we avoid the need to
176*4882a593Smuzhiyun * allocate an extra buffer for the header when bridging to WL.
177*4882a593Smuzhiyun * There is a compile time check in wlc.c which ensure that this
178*4882a593Smuzhiyun * value is at least as big as TXOFF. This value is used in
179*4882a593Smuzhiyun * dma_rxfill().
180*4882a593Smuzhiyun */
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun #define BCMEXTRAHDROOM 172
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun #define MAXNAMEL 8 /* 8 char names */
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun /* macros to convert between byte offsets and indexes */
187*4882a593Smuzhiyun #define B2I(bytes, type) ((bytes) / sizeof(type))
188*4882a593Smuzhiyun #define I2B(index, type) ((index) * sizeof(type))
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun #define PCI32ADDR_HIGH 0xc0000000 /* address[31:30] */
191*4882a593Smuzhiyun #define PCI32ADDR_HIGH_SHIFT 30 /* address[31:30] */
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun #define PCI64ADDR_HIGH 0x80000000 /* address[63] */
194*4882a593Smuzhiyun #define PCI64ADDR_HIGH_SHIFT 31 /* address[63] */
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun /*
197*4882a593Smuzhiyun * DMA Descriptor
198*4882a593Smuzhiyun * Descriptors are only read by the hardware, never written back.
199*4882a593Smuzhiyun */
200*4882a593Smuzhiyun struct dma64desc {
201*4882a593Smuzhiyun __le32 ctrl1; /* misc control bits & bufcount */
202*4882a593Smuzhiyun __le32 ctrl2; /* buffer count and address extension */
203*4882a593Smuzhiyun __le32 addrlow; /* memory address of the date buffer, bits 31:0 */
204*4882a593Smuzhiyun __le32 addrhigh; /* memory address of the date buffer, bits 63:32 */
205*4882a593Smuzhiyun };
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /* dma engine software state */
208*4882a593Smuzhiyun struct dma_info {
209*4882a593Smuzhiyun struct dma_pub dma; /* exported structure */
210*4882a593Smuzhiyun char name[MAXNAMEL]; /* callers name for diag msgs */
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun struct bcma_device *core;
213*4882a593Smuzhiyun struct device *dmadev;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun /* session information for AMPDU */
216*4882a593Smuzhiyun struct brcms_ampdu_session ampdu_session;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun bool dma64; /* this dma engine is operating in 64-bit mode */
219*4882a593Smuzhiyun bool addrext; /* this dma engine supports DmaExtendedAddrChanges */
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun /* 64-bit dma tx engine registers */
222*4882a593Smuzhiyun uint d64txregbase;
223*4882a593Smuzhiyun /* 64-bit dma rx engine registers */
224*4882a593Smuzhiyun uint d64rxregbase;
225*4882a593Smuzhiyun /* pointer to dma64 tx descriptor ring */
226*4882a593Smuzhiyun struct dma64desc *txd64;
227*4882a593Smuzhiyun /* pointer to dma64 rx descriptor ring */
228*4882a593Smuzhiyun struct dma64desc *rxd64;
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun u16 dmadesc_align; /* alignment requirement for dma descriptors */
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun u16 ntxd; /* # tx descriptors tunable */
233*4882a593Smuzhiyun u16 txin; /* index of next descriptor to reclaim */
234*4882a593Smuzhiyun u16 txout; /* index of next descriptor to post */
235*4882a593Smuzhiyun /* pointer to parallel array of pointers to packets */
236*4882a593Smuzhiyun struct sk_buff **txp;
237*4882a593Smuzhiyun /* Aligned physical address of descriptor ring */
238*4882a593Smuzhiyun dma_addr_t txdpa;
239*4882a593Smuzhiyun /* Original physical address of descriptor ring */
240*4882a593Smuzhiyun dma_addr_t txdpaorig;
241*4882a593Smuzhiyun u16 txdalign; /* #bytes added to alloc'd mem to align txd */
242*4882a593Smuzhiyun u32 txdalloc; /* #bytes allocated for the ring */
243*4882a593Smuzhiyun u32 xmtptrbase; /* When using unaligned descriptors, the ptr register
244*4882a593Smuzhiyun * is not just an index, it needs all 13 bits to be
245*4882a593Smuzhiyun * an offset from the addr register.
246*4882a593Smuzhiyun */
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun u16 nrxd; /* # rx descriptors tunable */
249*4882a593Smuzhiyun u16 rxin; /* index of next descriptor to reclaim */
250*4882a593Smuzhiyun u16 rxout; /* index of next descriptor to post */
251*4882a593Smuzhiyun /* pointer to parallel array of pointers to packets */
252*4882a593Smuzhiyun struct sk_buff **rxp;
253*4882a593Smuzhiyun /* Aligned physical address of descriptor ring */
254*4882a593Smuzhiyun dma_addr_t rxdpa;
255*4882a593Smuzhiyun /* Original physical address of descriptor ring */
256*4882a593Smuzhiyun dma_addr_t rxdpaorig;
257*4882a593Smuzhiyun u16 rxdalign; /* #bytes added to alloc'd mem to align rxd */
258*4882a593Smuzhiyun u32 rxdalloc; /* #bytes allocated for the ring */
259*4882a593Smuzhiyun u32 rcvptrbase; /* Base for ptr reg when using unaligned descriptors */
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun /* tunables */
262*4882a593Smuzhiyun unsigned int rxbufsize; /* rx buffer size in bytes, not including
263*4882a593Smuzhiyun * the extra headroom
264*4882a593Smuzhiyun */
265*4882a593Smuzhiyun uint rxextrahdrroom; /* extra rx headroom, reverseved to assist upper
266*4882a593Smuzhiyun * stack, e.g. some rx pkt buffers will be
267*4882a593Smuzhiyun * bridged to tx side without byte copying.
268*4882a593Smuzhiyun * The extra headroom needs to be large enough
269*4882a593Smuzhiyun * to fit txheader needs. Some dongle driver may
270*4882a593Smuzhiyun * not need it.
271*4882a593Smuzhiyun */
272*4882a593Smuzhiyun uint nrxpost; /* # rx buffers to keep posted */
273*4882a593Smuzhiyun unsigned int rxoffset; /* rxcontrol offset */
274*4882a593Smuzhiyun /* add to get dma address of descriptor ring, low 32 bits */
275*4882a593Smuzhiyun uint ddoffsetlow;
276*4882a593Smuzhiyun /* high 32 bits */
277*4882a593Smuzhiyun uint ddoffsethigh;
278*4882a593Smuzhiyun /* add to get dma address of data buffer, low 32 bits */
279*4882a593Smuzhiyun uint dataoffsetlow;
280*4882a593Smuzhiyun /* high 32 bits */
281*4882a593Smuzhiyun uint dataoffsethigh;
282*4882a593Smuzhiyun /* descriptor base need to be aligned or not */
283*4882a593Smuzhiyun bool aligndesc_4k;
284*4882a593Smuzhiyun };
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun /* Check for odd number of 1's */
parity32(__le32 data)287*4882a593Smuzhiyun static u32 parity32(__le32 data)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun /* no swap needed for counting 1's */
290*4882a593Smuzhiyun u32 par_data = *(u32 *)&data;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun par_data ^= par_data >> 16;
293*4882a593Smuzhiyun par_data ^= par_data >> 8;
294*4882a593Smuzhiyun par_data ^= par_data >> 4;
295*4882a593Smuzhiyun par_data ^= par_data >> 2;
296*4882a593Smuzhiyun par_data ^= par_data >> 1;
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun return par_data & 1;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
dma64_dd_parity(struct dma64desc * dd)301*4882a593Smuzhiyun static bool dma64_dd_parity(struct dma64desc *dd)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun return parity32(dd->addrlow ^ dd->addrhigh ^ dd->ctrl1 ^ dd->ctrl2);
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun /* descriptor bumping functions */
307*4882a593Smuzhiyun
xxd(uint x,uint n)308*4882a593Smuzhiyun static uint xxd(uint x, uint n)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun return x & (n - 1); /* faster than %, but n must be power of 2 */
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun
txd(struct dma_info * di,uint x)313*4882a593Smuzhiyun static uint txd(struct dma_info *di, uint x)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun return xxd(x, di->ntxd);
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
rxd(struct dma_info * di,uint x)318*4882a593Smuzhiyun static uint rxd(struct dma_info *di, uint x)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun return xxd(x, di->nrxd);
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
nexttxd(struct dma_info * di,uint i)323*4882a593Smuzhiyun static uint nexttxd(struct dma_info *di, uint i)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun return txd(di, i + 1);
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun
prevtxd(struct dma_info * di,uint i)328*4882a593Smuzhiyun static uint prevtxd(struct dma_info *di, uint i)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun return txd(di, i - 1);
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
nextrxd(struct dma_info * di,uint i)333*4882a593Smuzhiyun static uint nextrxd(struct dma_info *di, uint i)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun return rxd(di, i + 1);
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun
ntxdactive(struct dma_info * di,uint h,uint t)338*4882a593Smuzhiyun static uint ntxdactive(struct dma_info *di, uint h, uint t)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun return txd(di, t-h);
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
nrxdactive(struct dma_info * di,uint h,uint t)343*4882a593Smuzhiyun static uint nrxdactive(struct dma_info *di, uint h, uint t)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun return rxd(di, t-h);
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
_dma_ctrlflags(struct dma_info * di,uint mask,uint flags)348*4882a593Smuzhiyun static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun uint dmactrlflags;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun if (di == NULL)
353*4882a593Smuzhiyun return 0;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun dmactrlflags = di->dma.dmactrlflags;
356*4882a593Smuzhiyun dmactrlflags &= ~mask;
357*4882a593Smuzhiyun dmactrlflags |= flags;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun /* If trying to enable parity, check if parity is actually supported */
360*4882a593Smuzhiyun if (dmactrlflags & DMA_CTRL_PEN) {
361*4882a593Smuzhiyun u32 control;
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun control = bcma_read32(di->core, DMA64TXREGOFFS(di, control));
364*4882a593Smuzhiyun bcma_write32(di->core, DMA64TXREGOFFS(di, control),
365*4882a593Smuzhiyun control | D64_XC_PD);
366*4882a593Smuzhiyun if (bcma_read32(di->core, DMA64TXREGOFFS(di, control)) &
367*4882a593Smuzhiyun D64_XC_PD)
368*4882a593Smuzhiyun /* We *can* disable it so it is supported,
369*4882a593Smuzhiyun * restore control register
370*4882a593Smuzhiyun */
371*4882a593Smuzhiyun bcma_write32(di->core, DMA64TXREGOFFS(di, control),
372*4882a593Smuzhiyun control);
373*4882a593Smuzhiyun else
374*4882a593Smuzhiyun /* Not supported, don't allow it to be enabled */
375*4882a593Smuzhiyun dmactrlflags &= ~DMA_CTRL_PEN;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun di->dma.dmactrlflags = dmactrlflags;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun return dmactrlflags;
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun
_dma64_addrext(struct dma_info * di,uint ctrl_offset)383*4882a593Smuzhiyun static bool _dma64_addrext(struct dma_info *di, uint ctrl_offset)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun u32 w;
386*4882a593Smuzhiyun bcma_set32(di->core, ctrl_offset, D64_XC_AE);
387*4882a593Smuzhiyun w = bcma_read32(di->core, ctrl_offset);
388*4882a593Smuzhiyun bcma_mask32(di->core, ctrl_offset, ~D64_XC_AE);
389*4882a593Smuzhiyun return (w & D64_XC_AE) == D64_XC_AE;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun /*
393*4882a593Smuzhiyun * return true if this dma engine supports DmaExtendedAddrChanges,
394*4882a593Smuzhiyun * otherwise false
395*4882a593Smuzhiyun */
_dma_isaddrext(struct dma_info * di)396*4882a593Smuzhiyun static bool _dma_isaddrext(struct dma_info *di)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun /* DMA64 supports full 32- or 64-bit operation. AE is always valid */
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun /* not all tx or rx channel are available */
401*4882a593Smuzhiyun if (di->d64txregbase != 0) {
402*4882a593Smuzhiyun if (!_dma64_addrext(di, DMA64TXREGOFFS(di, control)))
403*4882a593Smuzhiyun brcms_dbg_dma(di->core,
404*4882a593Smuzhiyun "%s: DMA64 tx doesn't have AE set\n",
405*4882a593Smuzhiyun di->name);
406*4882a593Smuzhiyun return true;
407*4882a593Smuzhiyun } else if (di->d64rxregbase != 0) {
408*4882a593Smuzhiyun if (!_dma64_addrext(di, DMA64RXREGOFFS(di, control)))
409*4882a593Smuzhiyun brcms_dbg_dma(di->core,
410*4882a593Smuzhiyun "%s: DMA64 rx doesn't have AE set\n",
411*4882a593Smuzhiyun di->name);
412*4882a593Smuzhiyun return true;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun return false;
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun
_dma_descriptor_align(struct dma_info * di)418*4882a593Smuzhiyun static bool _dma_descriptor_align(struct dma_info *di)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun u32 addrl;
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun /* Check to see if the descriptors need to be aligned on 4K/8K or not */
423*4882a593Smuzhiyun if (di->d64txregbase != 0) {
424*4882a593Smuzhiyun bcma_write32(di->core, DMA64TXREGOFFS(di, addrlow), 0xff0);
425*4882a593Smuzhiyun addrl = bcma_read32(di->core, DMA64TXREGOFFS(di, addrlow));
426*4882a593Smuzhiyun if (addrl != 0)
427*4882a593Smuzhiyun return false;
428*4882a593Smuzhiyun } else if (di->d64rxregbase != 0) {
429*4882a593Smuzhiyun bcma_write32(di->core, DMA64RXREGOFFS(di, addrlow), 0xff0);
430*4882a593Smuzhiyun addrl = bcma_read32(di->core, DMA64RXREGOFFS(di, addrlow));
431*4882a593Smuzhiyun if (addrl != 0)
432*4882a593Smuzhiyun return false;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun return true;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun /*
438*4882a593Smuzhiyun * Descriptor table must start at the DMA hardware dictated alignment, so
439*4882a593Smuzhiyun * allocated memory must be large enough to support this requirement.
440*4882a593Smuzhiyun */
dma_alloc_consistent(struct dma_info * di,uint size,u16 align_bits,uint * alloced,dma_addr_t * pap)441*4882a593Smuzhiyun static void *dma_alloc_consistent(struct dma_info *di, uint size,
442*4882a593Smuzhiyun u16 align_bits, uint *alloced,
443*4882a593Smuzhiyun dma_addr_t *pap)
444*4882a593Smuzhiyun {
445*4882a593Smuzhiyun if (align_bits) {
446*4882a593Smuzhiyun u16 align = (1 << align_bits);
447*4882a593Smuzhiyun if (!IS_ALIGNED(PAGE_SIZE, align))
448*4882a593Smuzhiyun size += align;
449*4882a593Smuzhiyun *alloced = size;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun return dma_alloc_coherent(di->dmadev, size, pap, GFP_ATOMIC);
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun static
dma_align_sizetobits(uint size)455*4882a593Smuzhiyun u8 dma_align_sizetobits(uint size)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun u8 bitpos = 0;
458*4882a593Smuzhiyun while (size >>= 1)
459*4882a593Smuzhiyun bitpos++;
460*4882a593Smuzhiyun return bitpos;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun /* This function ensures that the DMA descriptor ring will not get allocated
464*4882a593Smuzhiyun * across Page boundary. If the allocation is done across the page boundary
465*4882a593Smuzhiyun * at the first time, then it is freed and the allocation is done at
466*4882a593Smuzhiyun * descriptor ring size aligned location. This will ensure that the ring will
467*4882a593Smuzhiyun * not cross page boundary
468*4882a593Smuzhiyun */
dma_ringalloc(struct dma_info * di,u32 boundary,uint size,u16 * alignbits,uint * alloced,dma_addr_t * descpa)469*4882a593Smuzhiyun static void *dma_ringalloc(struct dma_info *di, u32 boundary, uint size,
470*4882a593Smuzhiyun u16 *alignbits, uint *alloced,
471*4882a593Smuzhiyun dma_addr_t *descpa)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun void *va;
474*4882a593Smuzhiyun u32 desc_strtaddr;
475*4882a593Smuzhiyun u32 alignbytes = 1 << *alignbits;
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun va = dma_alloc_consistent(di, size, *alignbits, alloced, descpa);
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun if (NULL == va)
480*4882a593Smuzhiyun return NULL;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun desc_strtaddr = (u32) roundup((unsigned long)va, alignbytes);
483*4882a593Smuzhiyun if (((desc_strtaddr + size - 1) & boundary) != (desc_strtaddr
484*4882a593Smuzhiyun & boundary)) {
485*4882a593Smuzhiyun *alignbits = dma_align_sizetobits(size);
486*4882a593Smuzhiyun dma_free_coherent(di->dmadev, size, va, *descpa);
487*4882a593Smuzhiyun va = dma_alloc_consistent(di, size, *alignbits,
488*4882a593Smuzhiyun alloced, descpa);
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun return va;
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun
dma64_alloc(struct dma_info * di,uint direction)493*4882a593Smuzhiyun static bool dma64_alloc(struct dma_info *di, uint direction)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun u16 size;
496*4882a593Smuzhiyun uint ddlen;
497*4882a593Smuzhiyun void *va;
498*4882a593Smuzhiyun uint alloced = 0;
499*4882a593Smuzhiyun u16 align;
500*4882a593Smuzhiyun u16 align_bits;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun ddlen = sizeof(struct dma64desc);
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun size = (direction == DMA_TX) ? (di->ntxd * ddlen) : (di->nrxd * ddlen);
505*4882a593Smuzhiyun align_bits = di->dmadesc_align;
506*4882a593Smuzhiyun align = (1 << align_bits);
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun if (direction == DMA_TX) {
509*4882a593Smuzhiyun va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits,
510*4882a593Smuzhiyun &alloced, &di->txdpaorig);
511*4882a593Smuzhiyun if (va == NULL) {
512*4882a593Smuzhiyun brcms_dbg_dma(di->core,
513*4882a593Smuzhiyun "%s: DMA_ALLOC_CONSISTENT(ntxd) failed\n",
514*4882a593Smuzhiyun di->name);
515*4882a593Smuzhiyun return false;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun align = (1 << align_bits);
518*4882a593Smuzhiyun di->txd64 = (struct dma64desc *)
519*4882a593Smuzhiyun roundup((unsigned long)va, align);
520*4882a593Smuzhiyun di->txdalign = (uint) ((s8 *)di->txd64 - (s8 *) va);
521*4882a593Smuzhiyun di->txdpa = di->txdpaorig + di->txdalign;
522*4882a593Smuzhiyun di->txdalloc = alloced;
523*4882a593Smuzhiyun } else {
524*4882a593Smuzhiyun va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits,
525*4882a593Smuzhiyun &alloced, &di->rxdpaorig);
526*4882a593Smuzhiyun if (va == NULL) {
527*4882a593Smuzhiyun brcms_dbg_dma(di->core,
528*4882a593Smuzhiyun "%s: DMA_ALLOC_CONSISTENT(nrxd) failed\n",
529*4882a593Smuzhiyun di->name);
530*4882a593Smuzhiyun return false;
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun align = (1 << align_bits);
533*4882a593Smuzhiyun di->rxd64 = (struct dma64desc *)
534*4882a593Smuzhiyun roundup((unsigned long)va, align);
535*4882a593Smuzhiyun di->rxdalign = (uint) ((s8 *)di->rxd64 - (s8 *) va);
536*4882a593Smuzhiyun di->rxdpa = di->rxdpaorig + di->rxdalign;
537*4882a593Smuzhiyun di->rxdalloc = alloced;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun return true;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun
_dma_alloc(struct dma_info * di,uint direction)543*4882a593Smuzhiyun static bool _dma_alloc(struct dma_info *di, uint direction)
544*4882a593Smuzhiyun {
545*4882a593Smuzhiyun return dma64_alloc(di, direction);
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun
dma_attach(char * name,struct brcms_c_info * wlc,uint txregbase,uint rxregbase,uint ntxd,uint nrxd,uint rxbufsize,int rxextheadroom,uint nrxpost,uint rxoffset)548*4882a593Smuzhiyun struct dma_pub *dma_attach(char *name, struct brcms_c_info *wlc,
549*4882a593Smuzhiyun uint txregbase, uint rxregbase, uint ntxd, uint nrxd,
550*4882a593Smuzhiyun uint rxbufsize, int rxextheadroom,
551*4882a593Smuzhiyun uint nrxpost, uint rxoffset)
552*4882a593Smuzhiyun {
553*4882a593Smuzhiyun struct si_pub *sih = wlc->hw->sih;
554*4882a593Smuzhiyun struct bcma_device *core = wlc->hw->d11core;
555*4882a593Smuzhiyun struct dma_info *di;
556*4882a593Smuzhiyun u8 rev = core->id.rev;
557*4882a593Smuzhiyun uint size;
558*4882a593Smuzhiyun struct si_info *sii = container_of(sih, struct si_info, pub);
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun /* allocate private info structure */
561*4882a593Smuzhiyun di = kzalloc(sizeof(struct dma_info), GFP_ATOMIC);
562*4882a593Smuzhiyun if (di == NULL)
563*4882a593Smuzhiyun return NULL;
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun di->dma64 =
566*4882a593Smuzhiyun ((bcma_aread32(core, BCMA_IOST) & SISF_DMA64) == SISF_DMA64);
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun /* init dma reg info */
569*4882a593Smuzhiyun di->core = core;
570*4882a593Smuzhiyun di->d64txregbase = txregbase;
571*4882a593Smuzhiyun di->d64rxregbase = rxregbase;
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun /*
574*4882a593Smuzhiyun * Default flags (which can be changed by the driver calling
575*4882a593Smuzhiyun * dma_ctrlflags before enable): For backwards compatibility
576*4882a593Smuzhiyun * both Rx Overflow Continue and Parity are DISABLED.
577*4882a593Smuzhiyun */
578*4882a593Smuzhiyun _dma_ctrlflags(di, DMA_CTRL_ROC | DMA_CTRL_PEN, 0);
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s: %s flags 0x%x ntxd %d nrxd %d "
581*4882a593Smuzhiyun "rxbufsize %d rxextheadroom %d nrxpost %d rxoffset %d "
582*4882a593Smuzhiyun "txregbase %u rxregbase %u\n", name, "DMA64",
583*4882a593Smuzhiyun di->dma.dmactrlflags, ntxd, nrxd, rxbufsize,
584*4882a593Smuzhiyun rxextheadroom, nrxpost, rxoffset, txregbase, rxregbase);
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun /* make a private copy of our callers name */
587*4882a593Smuzhiyun strncpy(di->name, name, MAXNAMEL);
588*4882a593Smuzhiyun di->name[MAXNAMEL - 1] = '\0';
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun di->dmadev = core->dma_dev;
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun /* save tunables */
593*4882a593Smuzhiyun di->ntxd = (u16) ntxd;
594*4882a593Smuzhiyun di->nrxd = (u16) nrxd;
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun /* the actual dma size doesn't include the extra headroom */
597*4882a593Smuzhiyun di->rxextrahdrroom =
598*4882a593Smuzhiyun (rxextheadroom == -1) ? BCMEXTRAHDROOM : rxextheadroom;
599*4882a593Smuzhiyun if (rxbufsize > BCMEXTRAHDROOM)
600*4882a593Smuzhiyun di->rxbufsize = (u16) (rxbufsize - di->rxextrahdrroom);
601*4882a593Smuzhiyun else
602*4882a593Smuzhiyun di->rxbufsize = (u16) rxbufsize;
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun di->nrxpost = (u16) nrxpost;
605*4882a593Smuzhiyun di->rxoffset = (u8) rxoffset;
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun /*
608*4882a593Smuzhiyun * figure out the DMA physical address offset for dd and data
609*4882a593Smuzhiyun * PCI/PCIE: they map silicon backplace address to zero
610*4882a593Smuzhiyun * based memory, need offset
611*4882a593Smuzhiyun * Other bus: use zero SI_BUS BIGENDIAN kludge: use sdram
612*4882a593Smuzhiyun * swapped region for data buffer, not descriptor
613*4882a593Smuzhiyun */
614*4882a593Smuzhiyun di->ddoffsetlow = 0;
615*4882a593Smuzhiyun di->dataoffsetlow = 0;
616*4882a593Smuzhiyun /* for pci bus, add offset */
617*4882a593Smuzhiyun if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) {
618*4882a593Smuzhiyun /* add offset for pcie with DMA64 bus */
619*4882a593Smuzhiyun di->ddoffsetlow = 0;
620*4882a593Smuzhiyun di->ddoffsethigh = SI_PCIE_DMA_H32;
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun di->dataoffsetlow = di->ddoffsetlow;
623*4882a593Smuzhiyun di->dataoffsethigh = di->ddoffsethigh;
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun /* WAR64450 : DMACtl.Addr ext fields are not supported in SDIOD core. */
626*4882a593Smuzhiyun if ((core->id.id == BCMA_CORE_SDIO_DEV)
627*4882a593Smuzhiyun && ((rev > 0) && (rev <= 2)))
628*4882a593Smuzhiyun di->addrext = false;
629*4882a593Smuzhiyun else if ((core->id.id == BCMA_CORE_I2S) &&
630*4882a593Smuzhiyun ((rev == 0) || (rev == 1)))
631*4882a593Smuzhiyun di->addrext = false;
632*4882a593Smuzhiyun else
633*4882a593Smuzhiyun di->addrext = _dma_isaddrext(di);
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun /* does the descriptor need to be aligned and if yes, on 4K/8K or not */
636*4882a593Smuzhiyun di->aligndesc_4k = _dma_descriptor_align(di);
637*4882a593Smuzhiyun if (di->aligndesc_4k) {
638*4882a593Smuzhiyun di->dmadesc_align = D64RINGALIGN_BITS;
639*4882a593Smuzhiyun if ((ntxd < D64MAXDD / 2) && (nrxd < D64MAXDD / 2))
640*4882a593Smuzhiyun /* for smaller dd table, HW relax alignment reqmnt */
641*4882a593Smuzhiyun di->dmadesc_align = D64RINGALIGN_BITS - 1;
642*4882a593Smuzhiyun } else {
643*4882a593Smuzhiyun di->dmadesc_align = 4; /* 16 byte alignment */
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun brcms_dbg_dma(di->core, "DMA descriptor align_needed %d, align %d\n",
647*4882a593Smuzhiyun di->aligndesc_4k, di->dmadesc_align);
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun /* allocate tx packet pointer vector */
650*4882a593Smuzhiyun if (ntxd) {
651*4882a593Smuzhiyun size = ntxd * sizeof(void *);
652*4882a593Smuzhiyun di->txp = kzalloc(size, GFP_ATOMIC);
653*4882a593Smuzhiyun if (di->txp == NULL)
654*4882a593Smuzhiyun goto fail;
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun /* allocate rx packet pointer vector */
658*4882a593Smuzhiyun if (nrxd) {
659*4882a593Smuzhiyun size = nrxd * sizeof(void *);
660*4882a593Smuzhiyun di->rxp = kzalloc(size, GFP_ATOMIC);
661*4882a593Smuzhiyun if (di->rxp == NULL)
662*4882a593Smuzhiyun goto fail;
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun /*
666*4882a593Smuzhiyun * allocate transmit descriptor ring, only need ntxd descriptors
667*4882a593Smuzhiyun * but it must be aligned
668*4882a593Smuzhiyun */
669*4882a593Smuzhiyun if (ntxd) {
670*4882a593Smuzhiyun if (!_dma_alloc(di, DMA_TX))
671*4882a593Smuzhiyun goto fail;
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun /*
675*4882a593Smuzhiyun * allocate receive descriptor ring, only need nrxd descriptors
676*4882a593Smuzhiyun * but it must be aligned
677*4882a593Smuzhiyun */
678*4882a593Smuzhiyun if (nrxd) {
679*4882a593Smuzhiyun if (!_dma_alloc(di, DMA_RX))
680*4882a593Smuzhiyun goto fail;
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun if ((di->ddoffsetlow != 0) && !di->addrext) {
684*4882a593Smuzhiyun if (di->txdpa > SI_PCI_DMA_SZ) {
685*4882a593Smuzhiyun brcms_dbg_dma(di->core,
686*4882a593Smuzhiyun "%s: txdpa 0x%x: addrext not supported\n",
687*4882a593Smuzhiyun di->name, (u32)di->txdpa);
688*4882a593Smuzhiyun goto fail;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun if (di->rxdpa > SI_PCI_DMA_SZ) {
691*4882a593Smuzhiyun brcms_dbg_dma(di->core,
692*4882a593Smuzhiyun "%s: rxdpa 0x%x: addrext not supported\n",
693*4882a593Smuzhiyun di->name, (u32)di->rxdpa);
694*4882a593Smuzhiyun goto fail;
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun /* Initialize AMPDU session */
699*4882a593Smuzhiyun brcms_c_ampdu_reset_session(&di->ampdu_session, wlc);
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun brcms_dbg_dma(di->core,
702*4882a593Smuzhiyun "ddoffsetlow 0x%x ddoffsethigh 0x%x dataoffsetlow 0x%x dataoffsethigh 0x%x addrext %d\n",
703*4882a593Smuzhiyun di->ddoffsetlow, di->ddoffsethigh,
704*4882a593Smuzhiyun di->dataoffsetlow, di->dataoffsethigh,
705*4882a593Smuzhiyun di->addrext);
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun return (struct dma_pub *) di;
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun fail:
710*4882a593Smuzhiyun dma_detach((struct dma_pub *)di);
711*4882a593Smuzhiyun return NULL;
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun static inline void
dma64_dd_upd(struct dma_info * di,struct dma64desc * ddring,dma_addr_t pa,uint outidx,u32 * flags,u32 bufcount)715*4882a593Smuzhiyun dma64_dd_upd(struct dma_info *di, struct dma64desc *ddring,
716*4882a593Smuzhiyun dma_addr_t pa, uint outidx, u32 *flags, u32 bufcount)
717*4882a593Smuzhiyun {
718*4882a593Smuzhiyun u32 ctrl2 = bufcount & D64_CTRL2_BC_MASK;
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun /* PCI bus with big(>1G) physical address, use address extension */
721*4882a593Smuzhiyun if ((di->dataoffsetlow == 0) || !(pa & PCI32ADDR_HIGH)) {
722*4882a593Smuzhiyun ddring[outidx].addrlow = cpu_to_le32(pa + di->dataoffsetlow);
723*4882a593Smuzhiyun ddring[outidx].addrhigh = cpu_to_le32(di->dataoffsethigh);
724*4882a593Smuzhiyun ddring[outidx].ctrl1 = cpu_to_le32(*flags);
725*4882a593Smuzhiyun ddring[outidx].ctrl2 = cpu_to_le32(ctrl2);
726*4882a593Smuzhiyun } else {
727*4882a593Smuzhiyun /* address extension for 32-bit PCI */
728*4882a593Smuzhiyun u32 ae;
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
731*4882a593Smuzhiyun pa &= ~PCI32ADDR_HIGH;
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun ctrl2 |= (ae << D64_CTRL2_AE_SHIFT) & D64_CTRL2_AE;
734*4882a593Smuzhiyun ddring[outidx].addrlow = cpu_to_le32(pa + di->dataoffsetlow);
735*4882a593Smuzhiyun ddring[outidx].addrhigh = cpu_to_le32(di->dataoffsethigh);
736*4882a593Smuzhiyun ddring[outidx].ctrl1 = cpu_to_le32(*flags);
737*4882a593Smuzhiyun ddring[outidx].ctrl2 = cpu_to_le32(ctrl2);
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun if (di->dma.dmactrlflags & DMA_CTRL_PEN) {
740*4882a593Smuzhiyun if (dma64_dd_parity(&ddring[outidx]))
741*4882a593Smuzhiyun ddring[outidx].ctrl2 =
742*4882a593Smuzhiyun cpu_to_le32(ctrl2 | D64_CTRL2_PARITY);
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun /* !! may be called with core in reset */
dma_detach(struct dma_pub * pub)747*4882a593Smuzhiyun void dma_detach(struct dma_pub *pub)
748*4882a593Smuzhiyun {
749*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s:\n", di->name);
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun /* free dma descriptor rings */
754*4882a593Smuzhiyun if (di->txd64)
755*4882a593Smuzhiyun dma_free_coherent(di->dmadev, di->txdalloc,
756*4882a593Smuzhiyun ((s8 *)di->txd64 - di->txdalign),
757*4882a593Smuzhiyun (di->txdpaorig));
758*4882a593Smuzhiyun if (di->rxd64)
759*4882a593Smuzhiyun dma_free_coherent(di->dmadev, di->rxdalloc,
760*4882a593Smuzhiyun ((s8 *)di->rxd64 - di->rxdalign),
761*4882a593Smuzhiyun (di->rxdpaorig));
762*4882a593Smuzhiyun
763*4882a593Smuzhiyun /* free packet pointer vectors */
764*4882a593Smuzhiyun kfree(di->txp);
765*4882a593Smuzhiyun kfree(di->rxp);
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun /* free our private info structure */
768*4882a593Smuzhiyun kfree(di);
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun }
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun /* initialize descriptor table base address */
773*4882a593Smuzhiyun static void
_dma_ddtable_init(struct dma_info * di,uint direction,dma_addr_t pa)774*4882a593Smuzhiyun _dma_ddtable_init(struct dma_info *di, uint direction, dma_addr_t pa)
775*4882a593Smuzhiyun {
776*4882a593Smuzhiyun if (!di->aligndesc_4k) {
777*4882a593Smuzhiyun if (direction == DMA_TX)
778*4882a593Smuzhiyun di->xmtptrbase = pa;
779*4882a593Smuzhiyun else
780*4882a593Smuzhiyun di->rcvptrbase = pa;
781*4882a593Smuzhiyun }
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun if ((di->ddoffsetlow == 0)
784*4882a593Smuzhiyun || !(pa & PCI32ADDR_HIGH)) {
785*4882a593Smuzhiyun if (direction == DMA_TX) {
786*4882a593Smuzhiyun bcma_write32(di->core, DMA64TXREGOFFS(di, addrlow),
787*4882a593Smuzhiyun pa + di->ddoffsetlow);
788*4882a593Smuzhiyun bcma_write32(di->core, DMA64TXREGOFFS(di, addrhigh),
789*4882a593Smuzhiyun di->ddoffsethigh);
790*4882a593Smuzhiyun } else {
791*4882a593Smuzhiyun bcma_write32(di->core, DMA64RXREGOFFS(di, addrlow),
792*4882a593Smuzhiyun pa + di->ddoffsetlow);
793*4882a593Smuzhiyun bcma_write32(di->core, DMA64RXREGOFFS(di, addrhigh),
794*4882a593Smuzhiyun di->ddoffsethigh);
795*4882a593Smuzhiyun }
796*4882a593Smuzhiyun } else {
797*4882a593Smuzhiyun /* DMA64 32bits address extension */
798*4882a593Smuzhiyun u32 ae;
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun /* shift the high bit(s) from pa to ae */
801*4882a593Smuzhiyun ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
802*4882a593Smuzhiyun pa &= ~PCI32ADDR_HIGH;
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun if (direction == DMA_TX) {
805*4882a593Smuzhiyun bcma_write32(di->core, DMA64TXREGOFFS(di, addrlow),
806*4882a593Smuzhiyun pa + di->ddoffsetlow);
807*4882a593Smuzhiyun bcma_write32(di->core, DMA64TXREGOFFS(di, addrhigh),
808*4882a593Smuzhiyun di->ddoffsethigh);
809*4882a593Smuzhiyun bcma_maskset32(di->core, DMA64TXREGOFFS(di, control),
810*4882a593Smuzhiyun D64_XC_AE, (ae << D64_XC_AE_SHIFT));
811*4882a593Smuzhiyun } else {
812*4882a593Smuzhiyun bcma_write32(di->core, DMA64RXREGOFFS(di, addrlow),
813*4882a593Smuzhiyun pa + di->ddoffsetlow);
814*4882a593Smuzhiyun bcma_write32(di->core, DMA64RXREGOFFS(di, addrhigh),
815*4882a593Smuzhiyun di->ddoffsethigh);
816*4882a593Smuzhiyun bcma_maskset32(di->core, DMA64RXREGOFFS(di, control),
817*4882a593Smuzhiyun D64_RC_AE, (ae << D64_RC_AE_SHIFT));
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun }
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun
_dma_rxenable(struct dma_info * di)822*4882a593Smuzhiyun static void _dma_rxenable(struct dma_info *di)
823*4882a593Smuzhiyun {
824*4882a593Smuzhiyun uint dmactrlflags = di->dma.dmactrlflags;
825*4882a593Smuzhiyun u32 control;
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s:\n", di->name);
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun control = D64_RC_RE | (bcma_read32(di->core,
830*4882a593Smuzhiyun DMA64RXREGOFFS(di, control)) &
831*4882a593Smuzhiyun D64_RC_AE);
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun if ((dmactrlflags & DMA_CTRL_PEN) == 0)
834*4882a593Smuzhiyun control |= D64_RC_PD;
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun if (dmactrlflags & DMA_CTRL_ROC)
837*4882a593Smuzhiyun control |= D64_RC_OC;
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun bcma_write32(di->core, DMA64RXREGOFFS(di, control),
840*4882a593Smuzhiyun ((di->rxoffset << D64_RC_RO_SHIFT) | control));
841*4882a593Smuzhiyun }
842*4882a593Smuzhiyun
dma_rxinit(struct dma_pub * pub)843*4882a593Smuzhiyun void dma_rxinit(struct dma_pub *pub)
844*4882a593Smuzhiyun {
845*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s:\n", di->name);
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun if (di->nrxd == 0)
850*4882a593Smuzhiyun return;
851*4882a593Smuzhiyun
852*4882a593Smuzhiyun di->rxin = di->rxout = 0;
853*4882a593Smuzhiyun
854*4882a593Smuzhiyun /* clear rx descriptor ring */
855*4882a593Smuzhiyun memset(di->rxd64, '\0', di->nrxd * sizeof(struct dma64desc));
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun /* DMA engine with out alignment requirement requires table to be inited
858*4882a593Smuzhiyun * before enabling the engine
859*4882a593Smuzhiyun */
860*4882a593Smuzhiyun if (!di->aligndesc_4k)
861*4882a593Smuzhiyun _dma_ddtable_init(di, DMA_RX, di->rxdpa);
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun _dma_rxenable(di);
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun if (di->aligndesc_4k)
866*4882a593Smuzhiyun _dma_ddtable_init(di, DMA_RX, di->rxdpa);
867*4882a593Smuzhiyun }
868*4882a593Smuzhiyun
dma64_getnextrxp(struct dma_info * di,bool forceall)869*4882a593Smuzhiyun static struct sk_buff *dma64_getnextrxp(struct dma_info *di, bool forceall)
870*4882a593Smuzhiyun {
871*4882a593Smuzhiyun uint i, curr;
872*4882a593Smuzhiyun struct sk_buff *rxp;
873*4882a593Smuzhiyun dma_addr_t pa;
874*4882a593Smuzhiyun
875*4882a593Smuzhiyun i = di->rxin;
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun /* return if no packets posted */
878*4882a593Smuzhiyun if (i == di->rxout)
879*4882a593Smuzhiyun return NULL;
880*4882a593Smuzhiyun
881*4882a593Smuzhiyun curr =
882*4882a593Smuzhiyun B2I(((bcma_read32(di->core,
883*4882a593Smuzhiyun DMA64RXREGOFFS(di, status0)) & D64_RS0_CD_MASK) -
884*4882a593Smuzhiyun di->rcvptrbase) & D64_RS0_CD_MASK, struct dma64desc);
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun /* ignore curr if forceall */
887*4882a593Smuzhiyun if (!forceall && (i == curr))
888*4882a593Smuzhiyun return NULL;
889*4882a593Smuzhiyun
890*4882a593Smuzhiyun /* get the packet pointer that corresponds to the rx descriptor */
891*4882a593Smuzhiyun rxp = di->rxp[i];
892*4882a593Smuzhiyun di->rxp[i] = NULL;
893*4882a593Smuzhiyun
894*4882a593Smuzhiyun pa = le32_to_cpu(di->rxd64[i].addrlow) - di->dataoffsetlow;
895*4882a593Smuzhiyun
896*4882a593Smuzhiyun /* clear this packet from the descriptor ring */
897*4882a593Smuzhiyun dma_unmap_single(di->dmadev, pa, di->rxbufsize, DMA_FROM_DEVICE);
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun di->rxd64[i].addrlow = cpu_to_le32(0xdeadbeef);
900*4882a593Smuzhiyun di->rxd64[i].addrhigh = cpu_to_le32(0xdeadbeef);
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun di->rxin = nextrxd(di, i);
903*4882a593Smuzhiyun
904*4882a593Smuzhiyun return rxp;
905*4882a593Smuzhiyun }
906*4882a593Smuzhiyun
_dma_getnextrxp(struct dma_info * di,bool forceall)907*4882a593Smuzhiyun static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall)
908*4882a593Smuzhiyun {
909*4882a593Smuzhiyun if (di->nrxd == 0)
910*4882a593Smuzhiyun return NULL;
911*4882a593Smuzhiyun
912*4882a593Smuzhiyun return dma64_getnextrxp(di, forceall);
913*4882a593Smuzhiyun }
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun /*
916*4882a593Smuzhiyun * !! rx entry routine
917*4882a593Smuzhiyun * returns the number packages in the next frame, or 0 if there are no more
918*4882a593Smuzhiyun * if DMA_CTRL_RXMULTI is defined, DMA scattering(multiple buffers) is
919*4882a593Smuzhiyun * supported with pkts chain
920*4882a593Smuzhiyun * otherwise, it's treated as giant pkt and will be tossed.
921*4882a593Smuzhiyun * The DMA scattering starts with normal DMA header, followed by first
922*4882a593Smuzhiyun * buffer data. After it reaches the max size of buffer, the data continues
923*4882a593Smuzhiyun * in next DMA descriptor buffer WITHOUT DMA header
924*4882a593Smuzhiyun */
dma_rx(struct dma_pub * pub,struct sk_buff_head * skb_list)925*4882a593Smuzhiyun int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list)
926*4882a593Smuzhiyun {
927*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
928*4882a593Smuzhiyun struct sk_buff_head dma_frames;
929*4882a593Smuzhiyun struct sk_buff *p, *next;
930*4882a593Smuzhiyun uint len;
931*4882a593Smuzhiyun uint pkt_len;
932*4882a593Smuzhiyun int resid = 0;
933*4882a593Smuzhiyun int pktcnt = 1;
934*4882a593Smuzhiyun
935*4882a593Smuzhiyun skb_queue_head_init(&dma_frames);
936*4882a593Smuzhiyun next_frame:
937*4882a593Smuzhiyun p = _dma_getnextrxp(di, false);
938*4882a593Smuzhiyun if (p == NULL)
939*4882a593Smuzhiyun return 0;
940*4882a593Smuzhiyun
941*4882a593Smuzhiyun len = le16_to_cpu(*(__le16 *) (p->data));
942*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s: dma_rx len %d\n", di->name, len);
943*4882a593Smuzhiyun dma_spin_for_len(len, p);
944*4882a593Smuzhiyun
945*4882a593Smuzhiyun /* set actual length */
946*4882a593Smuzhiyun pkt_len = min((di->rxoffset + len), di->rxbufsize);
947*4882a593Smuzhiyun __skb_trim(p, pkt_len);
948*4882a593Smuzhiyun skb_queue_tail(&dma_frames, p);
949*4882a593Smuzhiyun resid = len - (di->rxbufsize - di->rxoffset);
950*4882a593Smuzhiyun
951*4882a593Smuzhiyun /* check for single or multi-buffer rx */
952*4882a593Smuzhiyun if (resid > 0) {
953*4882a593Smuzhiyun while ((resid > 0) && (p = _dma_getnextrxp(di, false))) {
954*4882a593Smuzhiyun pkt_len = min_t(uint, resid, di->rxbufsize);
955*4882a593Smuzhiyun __skb_trim(p, pkt_len);
956*4882a593Smuzhiyun skb_queue_tail(&dma_frames, p);
957*4882a593Smuzhiyun resid -= di->rxbufsize;
958*4882a593Smuzhiyun pktcnt++;
959*4882a593Smuzhiyun }
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun #ifdef DEBUG
962*4882a593Smuzhiyun if (resid > 0) {
963*4882a593Smuzhiyun uint cur;
964*4882a593Smuzhiyun cur =
965*4882a593Smuzhiyun B2I(((bcma_read32(di->core,
966*4882a593Smuzhiyun DMA64RXREGOFFS(di, status0)) &
967*4882a593Smuzhiyun D64_RS0_CD_MASK) - di->rcvptrbase) &
968*4882a593Smuzhiyun D64_RS0_CD_MASK, struct dma64desc);
969*4882a593Smuzhiyun brcms_dbg_dma(di->core,
970*4882a593Smuzhiyun "rxin %d rxout %d, hw_curr %d\n",
971*4882a593Smuzhiyun di->rxin, di->rxout, cur);
972*4882a593Smuzhiyun }
973*4882a593Smuzhiyun #endif /* DEBUG */
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun if ((di->dma.dmactrlflags & DMA_CTRL_RXMULTI) == 0) {
976*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s: bad frame length (%d)\n",
977*4882a593Smuzhiyun di->name, len);
978*4882a593Smuzhiyun skb_queue_walk_safe(&dma_frames, p, next) {
979*4882a593Smuzhiyun skb_unlink(p, &dma_frames);
980*4882a593Smuzhiyun brcmu_pkt_buf_free_skb(p);
981*4882a593Smuzhiyun }
982*4882a593Smuzhiyun di->dma.rxgiants++;
983*4882a593Smuzhiyun pktcnt = 1;
984*4882a593Smuzhiyun goto next_frame;
985*4882a593Smuzhiyun }
986*4882a593Smuzhiyun }
987*4882a593Smuzhiyun
988*4882a593Smuzhiyun skb_queue_splice_tail(&dma_frames, skb_list);
989*4882a593Smuzhiyun return pktcnt;
990*4882a593Smuzhiyun }
991*4882a593Smuzhiyun
dma64_rxidle(struct dma_info * di)992*4882a593Smuzhiyun static bool dma64_rxidle(struct dma_info *di)
993*4882a593Smuzhiyun {
994*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s:\n", di->name);
995*4882a593Smuzhiyun
996*4882a593Smuzhiyun if (di->nrxd == 0)
997*4882a593Smuzhiyun return true;
998*4882a593Smuzhiyun
999*4882a593Smuzhiyun return ((bcma_read32(di->core,
1000*4882a593Smuzhiyun DMA64RXREGOFFS(di, status0)) & D64_RS0_CD_MASK) ==
1001*4882a593Smuzhiyun (bcma_read32(di->core, DMA64RXREGOFFS(di, ptr)) &
1002*4882a593Smuzhiyun D64_RS0_CD_MASK));
1003*4882a593Smuzhiyun }
1004*4882a593Smuzhiyun
dma64_txidle(struct dma_info * di)1005*4882a593Smuzhiyun static bool dma64_txidle(struct dma_info *di)
1006*4882a593Smuzhiyun {
1007*4882a593Smuzhiyun if (di->ntxd == 0)
1008*4882a593Smuzhiyun return true;
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun return ((bcma_read32(di->core,
1011*4882a593Smuzhiyun DMA64TXREGOFFS(di, status0)) & D64_XS0_CD_MASK) ==
1012*4882a593Smuzhiyun (bcma_read32(di->core, DMA64TXREGOFFS(di, ptr)) &
1013*4882a593Smuzhiyun D64_XS0_CD_MASK));
1014*4882a593Smuzhiyun }
1015*4882a593Smuzhiyun
1016*4882a593Smuzhiyun /*
1017*4882a593Smuzhiyun * post receive buffers
1018*4882a593Smuzhiyun * Return false if refill failed completely or dma mapping failed. The ring
1019*4882a593Smuzhiyun * is empty, which will stall the rx dma and user might want to call rxfill
1020*4882a593Smuzhiyun * again asap. This is unlikely to happen on a memory-rich NIC, but often on
1021*4882a593Smuzhiyun * memory-constrained dongle.
1022*4882a593Smuzhiyun */
dma_rxfill(struct dma_pub * pub)1023*4882a593Smuzhiyun bool dma_rxfill(struct dma_pub *pub)
1024*4882a593Smuzhiyun {
1025*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
1026*4882a593Smuzhiyun struct sk_buff *p;
1027*4882a593Smuzhiyun u16 rxin, rxout;
1028*4882a593Smuzhiyun u32 flags = 0;
1029*4882a593Smuzhiyun uint n;
1030*4882a593Smuzhiyun uint i;
1031*4882a593Smuzhiyun dma_addr_t pa;
1032*4882a593Smuzhiyun uint extra_offset = 0;
1033*4882a593Smuzhiyun bool ring_empty;
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun ring_empty = false;
1036*4882a593Smuzhiyun
1037*4882a593Smuzhiyun /*
1038*4882a593Smuzhiyun * Determine how many receive buffers we're lacking
1039*4882a593Smuzhiyun * from the full complement, allocate, initialize,
1040*4882a593Smuzhiyun * and post them, then update the chip rx lastdscr.
1041*4882a593Smuzhiyun */
1042*4882a593Smuzhiyun
1043*4882a593Smuzhiyun rxin = di->rxin;
1044*4882a593Smuzhiyun rxout = di->rxout;
1045*4882a593Smuzhiyun
1046*4882a593Smuzhiyun n = di->nrxpost - nrxdactive(di, rxin, rxout);
1047*4882a593Smuzhiyun
1048*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s: post %d\n", di->name, n);
1049*4882a593Smuzhiyun
1050*4882a593Smuzhiyun if (di->rxbufsize > BCMEXTRAHDROOM)
1051*4882a593Smuzhiyun extra_offset = di->rxextrahdrroom;
1052*4882a593Smuzhiyun
1053*4882a593Smuzhiyun for (i = 0; i < n; i++) {
1054*4882a593Smuzhiyun /*
1055*4882a593Smuzhiyun * the di->rxbufsize doesn't include the extra headroom,
1056*4882a593Smuzhiyun * we need to add it to the size to be allocated
1057*4882a593Smuzhiyun */
1058*4882a593Smuzhiyun p = brcmu_pkt_buf_get_skb(di->rxbufsize + extra_offset);
1059*4882a593Smuzhiyun
1060*4882a593Smuzhiyun if (p == NULL) {
1061*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s: out of rxbufs\n",
1062*4882a593Smuzhiyun di->name);
1063*4882a593Smuzhiyun if (i == 0 && dma64_rxidle(di)) {
1064*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s: ring is empty !\n",
1065*4882a593Smuzhiyun di->name);
1066*4882a593Smuzhiyun ring_empty = true;
1067*4882a593Smuzhiyun }
1068*4882a593Smuzhiyun di->dma.rxnobuf++;
1069*4882a593Smuzhiyun break;
1070*4882a593Smuzhiyun }
1071*4882a593Smuzhiyun /* reserve an extra headroom, if applicable */
1072*4882a593Smuzhiyun if (extra_offset)
1073*4882a593Smuzhiyun skb_pull(p, extra_offset);
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun /* Do a cached write instead of uncached write since DMA_MAP
1076*4882a593Smuzhiyun * will flush the cache.
1077*4882a593Smuzhiyun */
1078*4882a593Smuzhiyun *(u32 *) (p->data) = 0;
1079*4882a593Smuzhiyun
1080*4882a593Smuzhiyun pa = dma_map_single(di->dmadev, p->data, di->rxbufsize,
1081*4882a593Smuzhiyun DMA_FROM_DEVICE);
1082*4882a593Smuzhiyun if (dma_mapping_error(di->dmadev, pa)) {
1083*4882a593Smuzhiyun brcmu_pkt_buf_free_skb(p);
1084*4882a593Smuzhiyun return false;
1085*4882a593Smuzhiyun }
1086*4882a593Smuzhiyun
1087*4882a593Smuzhiyun /* save the free packet pointer */
1088*4882a593Smuzhiyun di->rxp[rxout] = p;
1089*4882a593Smuzhiyun
1090*4882a593Smuzhiyun /* reset flags for each descriptor */
1091*4882a593Smuzhiyun flags = 0;
1092*4882a593Smuzhiyun if (rxout == (di->nrxd - 1))
1093*4882a593Smuzhiyun flags = D64_CTRL1_EOT;
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun dma64_dd_upd(di, di->rxd64, pa, rxout, &flags,
1096*4882a593Smuzhiyun di->rxbufsize);
1097*4882a593Smuzhiyun rxout = nextrxd(di, rxout);
1098*4882a593Smuzhiyun }
1099*4882a593Smuzhiyun
1100*4882a593Smuzhiyun di->rxout = rxout;
1101*4882a593Smuzhiyun
1102*4882a593Smuzhiyun /* update the chip lastdscr pointer */
1103*4882a593Smuzhiyun bcma_write32(di->core, DMA64RXREGOFFS(di, ptr),
1104*4882a593Smuzhiyun di->rcvptrbase + I2B(rxout, struct dma64desc));
1105*4882a593Smuzhiyun
1106*4882a593Smuzhiyun return ring_empty;
1107*4882a593Smuzhiyun }
1108*4882a593Smuzhiyun
dma_rxreclaim(struct dma_pub * pub)1109*4882a593Smuzhiyun void dma_rxreclaim(struct dma_pub *pub)
1110*4882a593Smuzhiyun {
1111*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
1112*4882a593Smuzhiyun struct sk_buff *p;
1113*4882a593Smuzhiyun
1114*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s:\n", di->name);
1115*4882a593Smuzhiyun
1116*4882a593Smuzhiyun while ((p = _dma_getnextrxp(di, true)))
1117*4882a593Smuzhiyun brcmu_pkt_buf_free_skb(p);
1118*4882a593Smuzhiyun }
1119*4882a593Smuzhiyun
dma_counterreset(struct dma_pub * pub)1120*4882a593Smuzhiyun void dma_counterreset(struct dma_pub *pub)
1121*4882a593Smuzhiyun {
1122*4882a593Smuzhiyun /* reset all software counters */
1123*4882a593Smuzhiyun pub->rxgiants = 0;
1124*4882a593Smuzhiyun pub->rxnobuf = 0;
1125*4882a593Smuzhiyun pub->txnobuf = 0;
1126*4882a593Smuzhiyun }
1127*4882a593Smuzhiyun
1128*4882a593Smuzhiyun /* get the address of the var in order to change later */
dma_getvar(struct dma_pub * pub,const char * name)1129*4882a593Smuzhiyun unsigned long dma_getvar(struct dma_pub *pub, const char *name)
1130*4882a593Smuzhiyun {
1131*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
1132*4882a593Smuzhiyun
1133*4882a593Smuzhiyun if (!strcmp(name, "&txavail"))
1134*4882a593Smuzhiyun return (unsigned long)&(di->dma.txavail);
1135*4882a593Smuzhiyun return 0;
1136*4882a593Smuzhiyun }
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun /* 64-bit DMA functions */
1139*4882a593Smuzhiyun
dma_txinit(struct dma_pub * pub)1140*4882a593Smuzhiyun void dma_txinit(struct dma_pub *pub)
1141*4882a593Smuzhiyun {
1142*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
1143*4882a593Smuzhiyun u32 control = D64_XC_XE;
1144*4882a593Smuzhiyun
1145*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s:\n", di->name);
1146*4882a593Smuzhiyun
1147*4882a593Smuzhiyun if (di->ntxd == 0)
1148*4882a593Smuzhiyun return;
1149*4882a593Smuzhiyun
1150*4882a593Smuzhiyun di->txin = di->txout = 0;
1151*4882a593Smuzhiyun di->dma.txavail = di->ntxd - 1;
1152*4882a593Smuzhiyun
1153*4882a593Smuzhiyun /* clear tx descriptor ring */
1154*4882a593Smuzhiyun memset(di->txd64, '\0', (di->ntxd * sizeof(struct dma64desc)));
1155*4882a593Smuzhiyun
1156*4882a593Smuzhiyun /* DMA engine with out alignment requirement requires table to be inited
1157*4882a593Smuzhiyun * before enabling the engine
1158*4882a593Smuzhiyun */
1159*4882a593Smuzhiyun if (!di->aligndesc_4k)
1160*4882a593Smuzhiyun _dma_ddtable_init(di, DMA_TX, di->txdpa);
1161*4882a593Smuzhiyun
1162*4882a593Smuzhiyun if ((di->dma.dmactrlflags & DMA_CTRL_PEN) == 0)
1163*4882a593Smuzhiyun control |= D64_XC_PD;
1164*4882a593Smuzhiyun bcma_set32(di->core, DMA64TXREGOFFS(di, control), control);
1165*4882a593Smuzhiyun
1166*4882a593Smuzhiyun /* DMA engine with alignment requirement requires table to be inited
1167*4882a593Smuzhiyun * before enabling the engine
1168*4882a593Smuzhiyun */
1169*4882a593Smuzhiyun if (di->aligndesc_4k)
1170*4882a593Smuzhiyun _dma_ddtable_init(di, DMA_TX, di->txdpa);
1171*4882a593Smuzhiyun }
1172*4882a593Smuzhiyun
dma_txsuspend(struct dma_pub * pub)1173*4882a593Smuzhiyun void dma_txsuspend(struct dma_pub *pub)
1174*4882a593Smuzhiyun {
1175*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
1176*4882a593Smuzhiyun
1177*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s:\n", di->name);
1178*4882a593Smuzhiyun
1179*4882a593Smuzhiyun if (di->ntxd == 0)
1180*4882a593Smuzhiyun return;
1181*4882a593Smuzhiyun
1182*4882a593Smuzhiyun bcma_set32(di->core, DMA64TXREGOFFS(di, control), D64_XC_SE);
1183*4882a593Smuzhiyun }
1184*4882a593Smuzhiyun
dma_txresume(struct dma_pub * pub)1185*4882a593Smuzhiyun void dma_txresume(struct dma_pub *pub)
1186*4882a593Smuzhiyun {
1187*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
1188*4882a593Smuzhiyun
1189*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s:\n", di->name);
1190*4882a593Smuzhiyun
1191*4882a593Smuzhiyun if (di->ntxd == 0)
1192*4882a593Smuzhiyun return;
1193*4882a593Smuzhiyun
1194*4882a593Smuzhiyun bcma_mask32(di->core, DMA64TXREGOFFS(di, control), ~D64_XC_SE);
1195*4882a593Smuzhiyun }
1196*4882a593Smuzhiyun
dma_txsuspended(struct dma_pub * pub)1197*4882a593Smuzhiyun bool dma_txsuspended(struct dma_pub *pub)
1198*4882a593Smuzhiyun {
1199*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
1200*4882a593Smuzhiyun
1201*4882a593Smuzhiyun return (di->ntxd == 0) ||
1202*4882a593Smuzhiyun ((bcma_read32(di->core,
1203*4882a593Smuzhiyun DMA64TXREGOFFS(di, control)) & D64_XC_SE) ==
1204*4882a593Smuzhiyun D64_XC_SE);
1205*4882a593Smuzhiyun }
1206*4882a593Smuzhiyun
dma_txreclaim(struct dma_pub * pub,enum txd_range range)1207*4882a593Smuzhiyun void dma_txreclaim(struct dma_pub *pub, enum txd_range range)
1208*4882a593Smuzhiyun {
1209*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
1210*4882a593Smuzhiyun struct sk_buff *p;
1211*4882a593Smuzhiyun
1212*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s: %s\n",
1213*4882a593Smuzhiyun di->name,
1214*4882a593Smuzhiyun range == DMA_RANGE_ALL ? "all" :
1215*4882a593Smuzhiyun range == DMA_RANGE_TRANSMITTED ? "transmitted" :
1216*4882a593Smuzhiyun "transferred");
1217*4882a593Smuzhiyun
1218*4882a593Smuzhiyun if (di->txin == di->txout)
1219*4882a593Smuzhiyun return;
1220*4882a593Smuzhiyun
1221*4882a593Smuzhiyun while ((p = dma_getnexttxp(pub, range))) {
1222*4882a593Smuzhiyun /* For unframed data, we don't have any packets to free */
1223*4882a593Smuzhiyun if (!(di->dma.dmactrlflags & DMA_CTRL_UNFRAMED))
1224*4882a593Smuzhiyun brcmu_pkt_buf_free_skb(p);
1225*4882a593Smuzhiyun }
1226*4882a593Smuzhiyun }
1227*4882a593Smuzhiyun
dma_txreset(struct dma_pub * pub)1228*4882a593Smuzhiyun bool dma_txreset(struct dma_pub *pub)
1229*4882a593Smuzhiyun {
1230*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
1231*4882a593Smuzhiyun u32 status;
1232*4882a593Smuzhiyun
1233*4882a593Smuzhiyun if (di->ntxd == 0)
1234*4882a593Smuzhiyun return true;
1235*4882a593Smuzhiyun
1236*4882a593Smuzhiyun /* suspend tx DMA first */
1237*4882a593Smuzhiyun bcma_write32(di->core, DMA64TXREGOFFS(di, control), D64_XC_SE);
1238*4882a593Smuzhiyun SPINWAIT(((status =
1239*4882a593Smuzhiyun (bcma_read32(di->core, DMA64TXREGOFFS(di, status0)) &
1240*4882a593Smuzhiyun D64_XS0_XS_MASK)) != D64_XS0_XS_DISABLED) &&
1241*4882a593Smuzhiyun (status != D64_XS0_XS_IDLE) && (status != D64_XS0_XS_STOPPED),
1242*4882a593Smuzhiyun 10000);
1243*4882a593Smuzhiyun
1244*4882a593Smuzhiyun bcma_write32(di->core, DMA64TXREGOFFS(di, control), 0);
1245*4882a593Smuzhiyun SPINWAIT(((status =
1246*4882a593Smuzhiyun (bcma_read32(di->core, DMA64TXREGOFFS(di, status0)) &
1247*4882a593Smuzhiyun D64_XS0_XS_MASK)) != D64_XS0_XS_DISABLED), 10000);
1248*4882a593Smuzhiyun
1249*4882a593Smuzhiyun /* wait for the last transaction to complete */
1250*4882a593Smuzhiyun udelay(300);
1251*4882a593Smuzhiyun
1252*4882a593Smuzhiyun return status == D64_XS0_XS_DISABLED;
1253*4882a593Smuzhiyun }
1254*4882a593Smuzhiyun
dma_rxreset(struct dma_pub * pub)1255*4882a593Smuzhiyun bool dma_rxreset(struct dma_pub *pub)
1256*4882a593Smuzhiyun {
1257*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
1258*4882a593Smuzhiyun u32 status;
1259*4882a593Smuzhiyun
1260*4882a593Smuzhiyun if (di->nrxd == 0)
1261*4882a593Smuzhiyun return true;
1262*4882a593Smuzhiyun
1263*4882a593Smuzhiyun bcma_write32(di->core, DMA64RXREGOFFS(di, control), 0);
1264*4882a593Smuzhiyun SPINWAIT(((status =
1265*4882a593Smuzhiyun (bcma_read32(di->core, DMA64RXREGOFFS(di, status0)) &
1266*4882a593Smuzhiyun D64_RS0_RS_MASK)) != D64_RS0_RS_DISABLED), 10000);
1267*4882a593Smuzhiyun
1268*4882a593Smuzhiyun return status == D64_RS0_RS_DISABLED;
1269*4882a593Smuzhiyun }
1270*4882a593Smuzhiyun
dma_txenq(struct dma_info * di,struct sk_buff * p)1271*4882a593Smuzhiyun static void dma_txenq(struct dma_info *di, struct sk_buff *p)
1272*4882a593Smuzhiyun {
1273*4882a593Smuzhiyun unsigned char *data;
1274*4882a593Smuzhiyun uint len;
1275*4882a593Smuzhiyun u16 txout;
1276*4882a593Smuzhiyun u32 flags = 0;
1277*4882a593Smuzhiyun dma_addr_t pa;
1278*4882a593Smuzhiyun
1279*4882a593Smuzhiyun txout = di->txout;
1280*4882a593Smuzhiyun
1281*4882a593Smuzhiyun if (WARN_ON(nexttxd(di, txout) == di->txin))
1282*4882a593Smuzhiyun return;
1283*4882a593Smuzhiyun
1284*4882a593Smuzhiyun /*
1285*4882a593Smuzhiyun * obtain and initialize transmit descriptor entry.
1286*4882a593Smuzhiyun */
1287*4882a593Smuzhiyun data = p->data;
1288*4882a593Smuzhiyun len = p->len;
1289*4882a593Smuzhiyun
1290*4882a593Smuzhiyun /* get physical address of buffer start */
1291*4882a593Smuzhiyun pa = dma_map_single(di->dmadev, data, len, DMA_TO_DEVICE);
1292*4882a593Smuzhiyun /* if mapping failed, free skb */
1293*4882a593Smuzhiyun if (dma_mapping_error(di->dmadev, pa)) {
1294*4882a593Smuzhiyun brcmu_pkt_buf_free_skb(p);
1295*4882a593Smuzhiyun return;
1296*4882a593Smuzhiyun }
1297*4882a593Smuzhiyun /* With a DMA segment list, Descriptor table is filled
1298*4882a593Smuzhiyun * using the segment list instead of looping over
1299*4882a593Smuzhiyun * buffers in multi-chain DMA. Therefore, EOF for SGLIST
1300*4882a593Smuzhiyun * is when end of segment list is reached.
1301*4882a593Smuzhiyun */
1302*4882a593Smuzhiyun flags = D64_CTRL1_SOF | D64_CTRL1_IOC | D64_CTRL1_EOF;
1303*4882a593Smuzhiyun if (txout == (di->ntxd - 1))
1304*4882a593Smuzhiyun flags |= D64_CTRL1_EOT;
1305*4882a593Smuzhiyun
1306*4882a593Smuzhiyun dma64_dd_upd(di, di->txd64, pa, txout, &flags, len);
1307*4882a593Smuzhiyun
1308*4882a593Smuzhiyun txout = nexttxd(di, txout);
1309*4882a593Smuzhiyun
1310*4882a593Smuzhiyun /* save the packet */
1311*4882a593Smuzhiyun di->txp[prevtxd(di, txout)] = p;
1312*4882a593Smuzhiyun
1313*4882a593Smuzhiyun /* bump the tx descriptor index */
1314*4882a593Smuzhiyun di->txout = txout;
1315*4882a593Smuzhiyun }
1316*4882a593Smuzhiyun
ampdu_finalize(struct dma_info * di)1317*4882a593Smuzhiyun static void ampdu_finalize(struct dma_info *di)
1318*4882a593Smuzhiyun {
1319*4882a593Smuzhiyun struct brcms_ampdu_session *session = &di->ampdu_session;
1320*4882a593Smuzhiyun struct sk_buff *p;
1321*4882a593Smuzhiyun
1322*4882a593Smuzhiyun trace_brcms_ampdu_session(&session->wlc->hw->d11core->dev,
1323*4882a593Smuzhiyun session->max_ampdu_len,
1324*4882a593Smuzhiyun session->max_ampdu_frames,
1325*4882a593Smuzhiyun session->ampdu_len,
1326*4882a593Smuzhiyun skb_queue_len(&session->skb_list),
1327*4882a593Smuzhiyun session->dma_len);
1328*4882a593Smuzhiyun
1329*4882a593Smuzhiyun if (WARN_ON(skb_queue_empty(&session->skb_list)))
1330*4882a593Smuzhiyun return;
1331*4882a593Smuzhiyun
1332*4882a593Smuzhiyun brcms_c_ampdu_finalize(session);
1333*4882a593Smuzhiyun
1334*4882a593Smuzhiyun while (!skb_queue_empty(&session->skb_list)) {
1335*4882a593Smuzhiyun p = skb_dequeue(&session->skb_list);
1336*4882a593Smuzhiyun dma_txenq(di, p);
1337*4882a593Smuzhiyun }
1338*4882a593Smuzhiyun
1339*4882a593Smuzhiyun bcma_write32(di->core, DMA64TXREGOFFS(di, ptr),
1340*4882a593Smuzhiyun di->xmtptrbase + I2B(di->txout, struct dma64desc));
1341*4882a593Smuzhiyun brcms_c_ampdu_reset_session(session, session->wlc);
1342*4882a593Smuzhiyun }
1343*4882a593Smuzhiyun
prep_ampdu_frame(struct dma_info * di,struct sk_buff * p)1344*4882a593Smuzhiyun static void prep_ampdu_frame(struct dma_info *di, struct sk_buff *p)
1345*4882a593Smuzhiyun {
1346*4882a593Smuzhiyun struct brcms_ampdu_session *session = &di->ampdu_session;
1347*4882a593Smuzhiyun int ret;
1348*4882a593Smuzhiyun
1349*4882a593Smuzhiyun ret = brcms_c_ampdu_add_frame(session, p);
1350*4882a593Smuzhiyun if (ret == -ENOSPC) {
1351*4882a593Smuzhiyun /*
1352*4882a593Smuzhiyun * AMPDU cannot accomodate this frame. Close out the in-
1353*4882a593Smuzhiyun * progress AMPDU session and start a new one.
1354*4882a593Smuzhiyun */
1355*4882a593Smuzhiyun ampdu_finalize(di);
1356*4882a593Smuzhiyun ret = brcms_c_ampdu_add_frame(session, p);
1357*4882a593Smuzhiyun }
1358*4882a593Smuzhiyun
1359*4882a593Smuzhiyun WARN_ON(ret);
1360*4882a593Smuzhiyun }
1361*4882a593Smuzhiyun
1362*4882a593Smuzhiyun /* Update count of available tx descriptors based on current DMA state */
dma_update_txavail(struct dma_info * di)1363*4882a593Smuzhiyun static void dma_update_txavail(struct dma_info *di)
1364*4882a593Smuzhiyun {
1365*4882a593Smuzhiyun /*
1366*4882a593Smuzhiyun * Available space is number of descriptors less the number of
1367*4882a593Smuzhiyun * active descriptors and the number of queued AMPDU frames.
1368*4882a593Smuzhiyun */
1369*4882a593Smuzhiyun di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) -
1370*4882a593Smuzhiyun skb_queue_len(&di->ampdu_session.skb_list) - 1;
1371*4882a593Smuzhiyun }
1372*4882a593Smuzhiyun
1373*4882a593Smuzhiyun /*
1374*4882a593Smuzhiyun * !! tx entry routine
1375*4882a593Smuzhiyun * WARNING: call must check the return value for error.
1376*4882a593Smuzhiyun * the error(toss frames) could be fatal and cause many subsequent hard
1377*4882a593Smuzhiyun * to debug problems
1378*4882a593Smuzhiyun */
dma_txfast(struct brcms_c_info * wlc,struct dma_pub * pub,struct sk_buff * p)1379*4882a593Smuzhiyun int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub,
1380*4882a593Smuzhiyun struct sk_buff *p)
1381*4882a593Smuzhiyun {
1382*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
1383*4882a593Smuzhiyun struct brcms_ampdu_session *session = &di->ampdu_session;
1384*4882a593Smuzhiyun struct ieee80211_tx_info *tx_info;
1385*4882a593Smuzhiyun bool is_ampdu;
1386*4882a593Smuzhiyun
1387*4882a593Smuzhiyun /* no use to transmit a zero length packet */
1388*4882a593Smuzhiyun if (p->len == 0)
1389*4882a593Smuzhiyun return 0;
1390*4882a593Smuzhiyun
1391*4882a593Smuzhiyun /* return nonzero if out of tx descriptors */
1392*4882a593Smuzhiyun if (di->dma.txavail == 0 || nexttxd(di, di->txout) == di->txin)
1393*4882a593Smuzhiyun goto outoftxd;
1394*4882a593Smuzhiyun
1395*4882a593Smuzhiyun tx_info = IEEE80211_SKB_CB(p);
1396*4882a593Smuzhiyun is_ampdu = tx_info->flags & IEEE80211_TX_CTL_AMPDU;
1397*4882a593Smuzhiyun if (is_ampdu)
1398*4882a593Smuzhiyun prep_ampdu_frame(di, p);
1399*4882a593Smuzhiyun else
1400*4882a593Smuzhiyun dma_txenq(di, p);
1401*4882a593Smuzhiyun
1402*4882a593Smuzhiyun /* tx flow control */
1403*4882a593Smuzhiyun dma_update_txavail(di);
1404*4882a593Smuzhiyun
1405*4882a593Smuzhiyun /* kick the chip */
1406*4882a593Smuzhiyun if (is_ampdu) {
1407*4882a593Smuzhiyun /*
1408*4882a593Smuzhiyun * Start sending data if we've got a full AMPDU, there's
1409*4882a593Smuzhiyun * no more space in the DMA ring, or the ring isn't
1410*4882a593Smuzhiyun * currently transmitting.
1411*4882a593Smuzhiyun */
1412*4882a593Smuzhiyun if (skb_queue_len(&session->skb_list) == session->max_ampdu_frames ||
1413*4882a593Smuzhiyun di->dma.txavail == 0 || dma64_txidle(di))
1414*4882a593Smuzhiyun ampdu_finalize(di);
1415*4882a593Smuzhiyun } else {
1416*4882a593Smuzhiyun bcma_write32(di->core, DMA64TXREGOFFS(di, ptr),
1417*4882a593Smuzhiyun di->xmtptrbase + I2B(di->txout, struct dma64desc));
1418*4882a593Smuzhiyun }
1419*4882a593Smuzhiyun
1420*4882a593Smuzhiyun return 0;
1421*4882a593Smuzhiyun
1422*4882a593Smuzhiyun outoftxd:
1423*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s: out of txds !!!\n", di->name);
1424*4882a593Smuzhiyun brcmu_pkt_buf_free_skb(p);
1425*4882a593Smuzhiyun di->dma.txavail = 0;
1426*4882a593Smuzhiyun di->dma.txnobuf++;
1427*4882a593Smuzhiyun return -ENOSPC;
1428*4882a593Smuzhiyun }
1429*4882a593Smuzhiyun
dma_txflush(struct dma_pub * pub)1430*4882a593Smuzhiyun void dma_txflush(struct dma_pub *pub)
1431*4882a593Smuzhiyun {
1432*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
1433*4882a593Smuzhiyun struct brcms_ampdu_session *session = &di->ampdu_session;
1434*4882a593Smuzhiyun
1435*4882a593Smuzhiyun if (!skb_queue_empty(&session->skb_list))
1436*4882a593Smuzhiyun ampdu_finalize(di);
1437*4882a593Smuzhiyun }
1438*4882a593Smuzhiyun
dma_txpending(struct dma_pub * pub)1439*4882a593Smuzhiyun int dma_txpending(struct dma_pub *pub)
1440*4882a593Smuzhiyun {
1441*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
1442*4882a593Smuzhiyun return ntxdactive(di, di->txin, di->txout);
1443*4882a593Smuzhiyun }
1444*4882a593Smuzhiyun
1445*4882a593Smuzhiyun /*
1446*4882a593Smuzhiyun * If we have an active AMPDU session and are not transmitting,
1447*4882a593Smuzhiyun * this function will force tx to start.
1448*4882a593Smuzhiyun */
dma_kick_tx(struct dma_pub * pub)1449*4882a593Smuzhiyun void dma_kick_tx(struct dma_pub *pub)
1450*4882a593Smuzhiyun {
1451*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
1452*4882a593Smuzhiyun struct brcms_ampdu_session *session = &di->ampdu_session;
1453*4882a593Smuzhiyun
1454*4882a593Smuzhiyun if (!skb_queue_empty(&session->skb_list) && dma64_txidle(di))
1455*4882a593Smuzhiyun ampdu_finalize(di);
1456*4882a593Smuzhiyun }
1457*4882a593Smuzhiyun
1458*4882a593Smuzhiyun /*
1459*4882a593Smuzhiyun * Reclaim next completed txd (txds if using chained buffers) in the range
1460*4882a593Smuzhiyun * specified and return associated packet.
1461*4882a593Smuzhiyun * If range is DMA_RANGE_TRANSMITTED, reclaim descriptors that have be
1462*4882a593Smuzhiyun * transmitted as noted by the hardware "CurrDescr" pointer.
1463*4882a593Smuzhiyun * If range is DMA_RANGE_TRANSFERED, reclaim descriptors that have be
1464*4882a593Smuzhiyun * transferred by the DMA as noted by the hardware "ActiveDescr" pointer.
1465*4882a593Smuzhiyun * If range is DMA_RANGE_ALL, reclaim all txd(s) posted to the ring and
1466*4882a593Smuzhiyun * return associated packet regardless of the value of hardware pointers.
1467*4882a593Smuzhiyun */
dma_getnexttxp(struct dma_pub * pub,enum txd_range range)1468*4882a593Smuzhiyun struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range)
1469*4882a593Smuzhiyun {
1470*4882a593Smuzhiyun struct dma_info *di = container_of(pub, struct dma_info, dma);
1471*4882a593Smuzhiyun u16 start, end, i;
1472*4882a593Smuzhiyun u16 active_desc;
1473*4882a593Smuzhiyun struct sk_buff *txp;
1474*4882a593Smuzhiyun
1475*4882a593Smuzhiyun brcms_dbg_dma(di->core, "%s: %s\n",
1476*4882a593Smuzhiyun di->name,
1477*4882a593Smuzhiyun range == DMA_RANGE_ALL ? "all" :
1478*4882a593Smuzhiyun range == DMA_RANGE_TRANSMITTED ? "transmitted" :
1479*4882a593Smuzhiyun "transferred");
1480*4882a593Smuzhiyun
1481*4882a593Smuzhiyun if (di->ntxd == 0)
1482*4882a593Smuzhiyun return NULL;
1483*4882a593Smuzhiyun
1484*4882a593Smuzhiyun txp = NULL;
1485*4882a593Smuzhiyun
1486*4882a593Smuzhiyun start = di->txin;
1487*4882a593Smuzhiyun if (range == DMA_RANGE_ALL)
1488*4882a593Smuzhiyun end = di->txout;
1489*4882a593Smuzhiyun else {
1490*4882a593Smuzhiyun end = (u16) (B2I(((bcma_read32(di->core,
1491*4882a593Smuzhiyun DMA64TXREGOFFS(di, status0)) &
1492*4882a593Smuzhiyun D64_XS0_CD_MASK) - di->xmtptrbase) &
1493*4882a593Smuzhiyun D64_XS0_CD_MASK, struct dma64desc));
1494*4882a593Smuzhiyun
1495*4882a593Smuzhiyun if (range == DMA_RANGE_TRANSFERED) {
1496*4882a593Smuzhiyun active_desc =
1497*4882a593Smuzhiyun (u16)(bcma_read32(di->core,
1498*4882a593Smuzhiyun DMA64TXREGOFFS(di, status1)) &
1499*4882a593Smuzhiyun D64_XS1_AD_MASK);
1500*4882a593Smuzhiyun active_desc =
1501*4882a593Smuzhiyun (active_desc - di->xmtptrbase) & D64_XS0_CD_MASK;
1502*4882a593Smuzhiyun active_desc = B2I(active_desc, struct dma64desc);
1503*4882a593Smuzhiyun if (end != active_desc)
1504*4882a593Smuzhiyun end = prevtxd(di, active_desc);
1505*4882a593Smuzhiyun }
1506*4882a593Smuzhiyun }
1507*4882a593Smuzhiyun
1508*4882a593Smuzhiyun if ((start == 0) && (end > di->txout))
1509*4882a593Smuzhiyun goto bogus;
1510*4882a593Smuzhiyun
1511*4882a593Smuzhiyun for (i = start; i != end && !txp; i = nexttxd(di, i)) {
1512*4882a593Smuzhiyun dma_addr_t pa;
1513*4882a593Smuzhiyun uint size;
1514*4882a593Smuzhiyun
1515*4882a593Smuzhiyun pa = le32_to_cpu(di->txd64[i].addrlow) - di->dataoffsetlow;
1516*4882a593Smuzhiyun
1517*4882a593Smuzhiyun size =
1518*4882a593Smuzhiyun (le32_to_cpu(di->txd64[i].ctrl2) &
1519*4882a593Smuzhiyun D64_CTRL2_BC_MASK);
1520*4882a593Smuzhiyun
1521*4882a593Smuzhiyun di->txd64[i].addrlow = cpu_to_le32(0xdeadbeef);
1522*4882a593Smuzhiyun di->txd64[i].addrhigh = cpu_to_le32(0xdeadbeef);
1523*4882a593Smuzhiyun
1524*4882a593Smuzhiyun txp = di->txp[i];
1525*4882a593Smuzhiyun di->txp[i] = NULL;
1526*4882a593Smuzhiyun
1527*4882a593Smuzhiyun dma_unmap_single(di->dmadev, pa, size, DMA_TO_DEVICE);
1528*4882a593Smuzhiyun }
1529*4882a593Smuzhiyun
1530*4882a593Smuzhiyun di->txin = i;
1531*4882a593Smuzhiyun
1532*4882a593Smuzhiyun /* tx flow control */
1533*4882a593Smuzhiyun dma_update_txavail(di);
1534*4882a593Smuzhiyun
1535*4882a593Smuzhiyun return txp;
1536*4882a593Smuzhiyun
1537*4882a593Smuzhiyun bogus:
1538*4882a593Smuzhiyun brcms_dbg_dma(di->core, "bogus curr: start %d end %d txout %d\n",
1539*4882a593Smuzhiyun start, end, di->txout);
1540*4882a593Smuzhiyun return NULL;
1541*4882a593Smuzhiyun }
1542*4882a593Smuzhiyun
1543*4882a593Smuzhiyun /*
1544*4882a593Smuzhiyun * Mac80211 initiated actions sometimes require packets in the DMA queue to be
1545*4882a593Smuzhiyun * modified. The modified portion of the packet is not under control of the DMA
1546*4882a593Smuzhiyun * engine. This function calls a caller-supplied function for each packet in
1547*4882a593Smuzhiyun * the caller specified dma chain.
1548*4882a593Smuzhiyun */
dma_walk_packets(struct dma_pub * dmah,void (* callback_fnc)(void * pkt,void * arg_a),void * arg_a)1549*4882a593Smuzhiyun void dma_walk_packets(struct dma_pub *dmah, void (*callback_fnc)
1550*4882a593Smuzhiyun (void *pkt, void *arg_a), void *arg_a)
1551*4882a593Smuzhiyun {
1552*4882a593Smuzhiyun struct dma_info *di = container_of(dmah, struct dma_info, dma);
1553*4882a593Smuzhiyun uint i = di->txin;
1554*4882a593Smuzhiyun uint end = di->txout;
1555*4882a593Smuzhiyun struct sk_buff *skb;
1556*4882a593Smuzhiyun struct ieee80211_tx_info *tx_info;
1557*4882a593Smuzhiyun
1558*4882a593Smuzhiyun while (i != end) {
1559*4882a593Smuzhiyun skb = di->txp[i];
1560*4882a593Smuzhiyun if (skb != NULL) {
1561*4882a593Smuzhiyun tx_info = (struct ieee80211_tx_info *)skb->cb;
1562*4882a593Smuzhiyun (callback_fnc)(tx_info, arg_a);
1563*4882a593Smuzhiyun }
1564*4882a593Smuzhiyun i = nexttxd(di, i);
1565*4882a593Smuzhiyun }
1566*4882a593Smuzhiyun }
1567