source: drsdaq/VME/struck/sis1100/V2.02/dev/pci/sis1100_read_dma_linux.c@ 23

Last change on this file since 23 was 22, checked in by ogrimm, 16 years ago
First commit of drsdaq program
File size: 9.0 KB
Line 
1/* $ZEL: sis1100_read_dma_linux.c,v 1.5 2004/05/27 23:10:31 wuestner Exp $ */
2
3/*
4 * Copyright (c) 2001-2004
5 * Matthias Drochner, Peter Wuestner. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include "sis1100_sc.h"
30
31ssize_t
32_sis1100_read_dma(
33 struct sis1100_softc* sc,
34 struct sis1100_fdata* fd,
35 u_int32_t addr, /* VME or SDRAM address */
36 int32_t am, /* address modifier, not used if <0 */
37 int size, /* datasize must be 4 or 2 */
38 int space, /* remote space (1,2: VME; 6: SDRAM) */
39 int fifo_mode,
40 size_t count, /* words to be transferred */
41 /* count==0 is illegal */
42 size_t* count_read, /* words transferred */
43 u_int8_t* data, /* destination (user virtual address) */
44 int* prot_error, /* protocol error (or 0) */
45 int* eot /* end of transport indicator */
46 )
47{
48 int res, i, sgcount, aborted=0;
49 u_int32_t head, dmamode;
50 sigset_t oldset;
51#ifdef USE_SGL
52 int nr_pages;
53#else
54 struct kiobuf* iobuf=sc->iobuf;
55 int err, offs;
56#endif
57 /*
58 printk(KERN_ERR "r addr=%d size=%d fifo=%d count=%lld data=%p\n",
59 addr, size, fifo_mode, (unsigned long long)count, data);
60 */
61 count*=size;
62 if (count>DMA_MAX) count=DMA_MAX;
63 /*
64 printk(KERN_ERR "DMA_MAX=%ld count=%lld SGL_SIZE=%d\n",
65 DMA_MAX, (unsigned long long)count, SGL_SIZE);
66 */
67 {
68 u_int32_t val;
69 val=plxreadreg(sc, DMACSR0_DMACSR1);
70 if (!(val&0x10)) {
71 printk(KERN_CRIT "sis1100_read_dma: DMACSR0=%04x\n", val);
72 printk(KERN_CRIT "sis1100_read_dma: old DMA still active.\n");
73 return EIO;
74 }
75 }
76
77#ifdef USE_SGL
78 nr_pages=sgl_map_user_pages(sc->sglist, SGL_SIZE, data, count, READ);
79 /*printk(KERN_ERR "R nr_pages=%d\n", nr_pages);*/
80 if (nr_pages<0) {
81 printk(KERN_INFO "sis1100[%d] sgl_map_user_pages failed\n", sc->unit);
82 return -nr_pages;
83 }
84 sgcount=pci_map_sg(sc->pcidev, sc->sglist, nr_pages,
85 PCI_DMA_FROMDEVICE/*|0xf000*/);
86 /*printk(KERN_ERR "R sgcount=%d\n", sgcount);*/
87 if (!sgcount) {
88 printk(KERN_ERR "sis1100[%d] read_dma: pci_map_sg failed\n", sc->unit);
89 sgl_unmap_user_pages(sc->sglist, nr_pages, 0);
90 return EIO;
91 }
92#else
93 err=map_user_kiobuf(READ, iobuf, (unsigned long)data, count);
94 if (err) {
95 printk(KERN_INFO "sis1100[%d] map_user_kiobuf failed\n", sc->unit);
96 return err;
97 }
98 offs=iobuf->offset;
99 for (i=0; i<iobuf->nr_pages-1; i++) {
100 sc->sglist[i].address=0;
101 sc->sglist[i].page=iobuf->maplist[i];
102 sc->sglist[i].offset=offs;
103 sc->sglist[i].length=PAGE_SIZE-offs;
104 sc->sglist[i].dma_length=0;
105 offs=0;
106 }
107 sc->sglist[i].address=0;
108 sc->sglist[i].page=iobuf->maplist[i];
109 sc->sglist[i].offset=offs;
110 sc->sglist[i].length=iobuf->length-i*PAGE_SIZE+iobuf->offset-offs;
111 sc->sglist[i].dma_length=0;
112 sgcount=pci_map_sg(sc->pcidev, sc->sglist, iobuf->nr_pages,
113 PCI_DMA_FROMDEVICE);
114 if (!sgcount) {
115 printk(KERN_ERR "sis1100[%d] read_dma: pci_map_sg failed\n",
116 sc->unit);
117 unmap_kiobuf(iobuf);
118 return EIO;
119 }
120#endif
121
122 dmamode=0x43|(1<<7)|(1<<8)|(1<<10)|(1<<11)|(1<<12)|(1<<14)|(1<<17);
123 if (sgcount>1) { /* use scatter/gather mode */
124 struct plx9054_dmadesc* desclist=
125 (struct plx9054_dmadesc*)sc->descbuf.cpu_addr;
126 struct scatterlist* sgl=sc->sglist;
127 dma_addr_t next_handle=sc->descbuf.dma_handle;
128 dmamode|=1<<9;
129 for (i=sgcount; i; i--) {
130 next_handle+=sizeof(struct plx9054_dmadesc);
131 desclist->pcistart=cpu_to_le32(sg_dma_address(sgl));
132 desclist->localstart=cpu_to_le32(0);
133 desclist->size=cpu_to_le32(sg_dma_len(sgl));
134 desclist->next=cpu_to_le32(next_handle|9);
135 desclist++; sgl++;
136 }
137 desclist[-1].next|=2;
138 plxwritereg(sc, DMADPR0, sc->descbuf.dma_handle|1);
139 } else { /* only one page --> use block mode */
140 plxwritereg(sc, DMAPADR0, sg_dma_address(sc->sglist));
141 plxwritereg(sc, DMALADR0, 0);
142 plxwritereg(sc, DMASIZ0, sg_dma_len(sc->sglist));
143 plxwritereg(sc, DMADPR0, 8);
144 }
145
146/* prepare PLX */
147 plxwritereg(sc, DMACSR0_DMACSR1, 1<<3); /* clear irq */
148 plxwritereg(sc, DMAMODE0, dmamode);
149
150/* prepare add on logic */
151 /* 4 Byte, local space 2, BT, EOT, start with t_adl */
152 head=0x0080A002|((0x00f00000<<size)&0x0f000000)|(space&0x3f)<<16;
153 if (am>=0) {
154 head|=0x800;
155 sis1100writereg(sc, t_am, am);
156 }
157 if (fifo_mode) head|=0x4000;
158 sis1100writereg(sc, t_hdr, head);
159 wmb();
160 sis1100writereg(sc, t_dal, count);
161
162 sis1100writereg(sc, d0_bc, 0);
163 sis1100writereg(sc, d0_bc_buf, 0);
164
165 sis1100writereg(sc, p_balance, 0);
166 sis1100writereg(sc, sr, 0x200); /* clear EOT */
167
168/* block signals */
169 spin_lock_irq(&current->SIGMASK_LOCK);
170 oldset = current->blocked;
171 sigfillset(&current->blocked);
172 sigdelset(&current->blocked, SIGKILL);
173 /* dangerous, should be removed later */
174 /*if (!sigismember(&oldset, SIGINT)) sigdelset(&current->blocked, SIGINT);*/
175#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
176 recalc_sigpending(current);
177#else
178 recalc_sigpending();
179#endif
180 spin_unlock_irq(&current->SIGMASK_LOCK);
181
182/* enable dma */
183 plxwritereg(sc, DMACSR0_DMACSR1, 3);
184
185/* enable irq */
186 sc->got_irqs=0;
187 sis1100_enable_irq(sc, plxirq_dma0, irq_synch_chg|irq_prot_l_err);
188
189/* start transfer */
190 mb();
191 sis1100writereg(sc, t_adl, addr);
192 wmb();
193
194/* wait for dma */
195 res=wait_event_interruptible(
196 sc->local_wait,
197 (sc->got_irqs & (got_dma0|got_sync|got_l_err))
198 );
199 sis1100_disable_irq(sc, plxirq_dma0, irq_prot_l_err);
200/*
201 if (sc->got_irqs&got_dma0) pINFO(sc, "got_dma0");
202 if (sc->got_irqs&got_sync) pINFO(sc, "got_sync");
203 if (sc->got_irqs&got_l_err) pINFO(sc, "got_l_err");
204*/
205 if (sc->got_irqs&(got_dma0|got_l_err)) { /* transfer complete or error */
206 *count_read=sis1100readreg(sc, d0_bc)/size;
207 } else /*(res||(sc->got_irqs&(got_sync)))*/ { /* fatal */
208 aborted=0x300;
209 if (res) {
210 printk(KERN_WARNING "sis1100[%d] read_dma: interrupted\n", sc->unit);
211 aborted|=1;
212 }
213 if (sc->got_irqs&got_sync) {
214 printk(KERN_WARNING "sis1100[%d] read_dma: synchronisation lost\n",
215 sc->unit);
216 aborted|=2;
217 }
218 if (aborted==0x300) {
219 printk(KERN_CRIT "sis1100[%d] read_dma: got_irqs=0x%x\n",
220 sc->unit, sc->got_irqs);
221 }
222 }
223 if (!(sc->got_irqs&got_dma0)) {
224 u_int32_t val;
225 val=plxreadreg(sc, DMACSR0_DMACSR1);
226 if (!(val&0x10)) { /* DMA not stopped yet; abort it */
227 sis1100writereg(sc, sr, sr_abort_dma);
228 do {
229 val=plxreadreg(sc, DMACSR0_DMACSR1);
230 } while (!(val&0x10));
231 }
232 }
233
234 plxwritereg(sc, DMACSR0_DMACSR1, 0);
235
236 spin_lock_irq(&current->SIGMASK_LOCK);
237 current->blocked = oldset;
238#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
239 recalc_sigpending(current);
240#else
241 recalc_sigpending();
242#endif
243 spin_unlock_irq(&current->SIGMASK_LOCK);
244
245#ifdef USE_SGL
246 pci_unmap_sg(sc->pcidev, sc->sglist, nr_pages, PCI_DMA_FROMDEVICE);
247 sgl_unmap_user_pages(sc->sglist, nr_pages, 1);
248#else
249 pci_unmap_sg(sc->pcidev, sc->sglist, iobuf->nr_pages, PCI_DMA_FROMDEVICE);
250 unmap_kiobuf(iobuf);
251#endif
252
253 *prot_error=sis1100readreg(sc, prot_error);
254 *eot=!!(sis1100readreg(sc, sr)&0x200);
255
256 /*if (aborted) sis1100_dump_glink_status(sc, "after abort", 1);*/
257 if (aborted) sis1100_flush_fifo(sc, "after abort", 0);
258 if (aborted) *prot_error=aborted;
259 if ((*prot_error!=0) && ((*prot_error&0x200)!=0x200)) res=EIO;
260
261 return res;
262}
Note: See TracBrowser for help on using the repository browser.