source: drsdaq/VME/struck/sis1100/V2.02/dev/pci/sis1100_write_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.1 KB
Line 
1/* $ZEL: sis1100_write_dma_linux.c,v 1.2 2004/02/10 16:33:35 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_write_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 for DMA but is not checked*/
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_written, /* words transferred */
43 const u_int8_t* data, /* source (user virtual address) */
44 int* prot_error
45 )
46{
47 int res, i, sgcount, aborted=0;
48 u_int32_t head, tmp, dmamode;
49 sigset_t oldset;
50#ifdef USE_SGL
51 int nr_pages;
52#else
53 struct kiobuf* iobuf=sc->iobuf;
54 int err, offs;
55#endif
56 /*printk(KERN_ERR "w addr=%d size=%d fifo=%d count=%d data=%p\n",
57 addr, size, fifo_mode, count, data);*/
58 count*=size;
59 if (count>DMA_MAX) count=DMA_MAX;
60
61 if ((addr^(addr+count))&0x80000000U) count=0x80000000U-addr;
62 *count_written=count/size;
63
64 {
65 u_int32_t val;
66 val=plxreadreg(sc, DMACSR0_DMACSR1);
67 if (!(val&0x10)) {
68 printk(KERN_CRIT "sis1100_write_dma: DMACSR0=%04x\n", val);
69 printk(KERN_CRIT "sis1100_write_dma: old DMA still active.\n");
70 return EIO;
71 }
72 }
73
74#ifdef USE_SGL
75 nr_pages=sgl_map_user_pages(sc->sglist, SGL_SIZE, data, count, WRITE);
76 /*printk(KERN_ERR "W nr_pages=%d\n", nr_pages);*/
77 if (nr_pages<0) {
78 printk(KERN_INFO "sis1100[%d] sgl_map_user_pages failed\n", sc->unit);
79 return -nr_pages;
80 }
81/*dump_sgl(sc->sglist, nr_pages);*/
82 sgcount=pci_map_sg(sc->pcidev, sc->sglist, nr_pages,
83 PCI_DMA_TODEVICE|0xf000);
84 /*printk(KERN_ERR "W sgcount=%d\n", sgcount);*/
85 if (!sgcount) {
86 printk(KERN_ERR "sis1100[%d] write_dma: pci_map_sg failed\n",
87 sc->unit);
88 sgl_unmap_user_pages(sc->sglist, nr_pages, 0);
89 return EIO;
90 }
91#else
92 printk(KERN_ERR "DON'T USE_SGL\n");
93 err=map_user_kiobuf(WRITE, iobuf, (unsigned long)data, count);
94 printk(KERN_ERR "err=%d\n", err);
95 if (err) {
96 printk(KERN_INFO "map_user_kiobuf failed\n");
97 return err;
98 }
99 printk(KERN_ERR "nr_pages=%d\n", iobuf->nr_pages);
100
101 offs=iobuf->offset;
102 for (i=0; i<iobuf->nr_pages-1; i++) {
103 sc->sglist[i].address=0;
104 sc->sglist[i].page=iobuf->maplist[i];
105 sc->sglist[i].offset=offs;
106 sc->sglist[i].length=PAGE_SIZE-offs;
107 sc->sglist[i].dma_length=0;
108 offs=0;
109 }
110 sc->sglist[i].address=0;
111 sc->sglist[i].page=iobuf->maplist[i];
112 sc->sglist[i].offset=offs;
113 sc->sglist[i].length=iobuf->length-i*PAGE_SIZE+iobuf->offset-offs;
114 sc->sglist[i].dma_length=0;
115 sgcount=pci_map_sg(sc->pcidev, sc->sglist, iobuf->nr_pages,
116 PCI_DMA_TODEVICE);
117 printk(KERN_ERR "sgcount=%d\n", sgcount);
118 if (!sgcount) {
119 printk(KERN_ERR "sis1100[%d] read_dma: pci_map_sg failed\n",
120 sc->unit);
121 unmap_kiobuf(iobuf);
122 return EIO;
123 }
124#endif
125 dmamode=0x43|(1<<7)|(1<<8)|(1<<10)|(1<<14)|(1<<17);
126 if (sgcount>1) { /* use scatter/gather mode */
127 struct plx9054_dmadesc* desclist=
128 (struct plx9054_dmadesc*)sc->descbuf.cpu_addr;
129 struct scatterlist* sgl=sc->sglist;
130 u_int32_t local=addr&0x7fffffffU;
131 dma_addr_t next_handle=sc->descbuf.dma_handle;
132 dmamode|=1<<9;
133 for (i=sgcount; i; i--) {
134 /*printk(KERN_ERR "sgl(%d-%d)=%p\n", sgcount, i, sgl);*/
135 next_handle+=sizeof(struct plx9054_dmadesc);
136 desclist->pcistart=cpu_to_le32(sg_dma_address(sgl));
137 desclist->localstart=cpu_to_le32(local);
138 desclist->size=cpu_to_le32(sg_dma_len(sgl));
139 desclist->next=cpu_to_le32(next_handle|1);
140 if (!fifo_mode) local+=sg_dma_len(sgl);
141 desclist++; sgl++;
142 }
143 desclist[-1].next|=2;
144 plxwritereg(sc, DMADPR0, sc->descbuf.dma_handle|1);
145 } else { /* only one page --> use block mode */
146 /*printk(KERN_ERR "dma_address=0x%08x\n", sg_dma_address(sc->sglist));*/
147 plxwritereg(sc, DMAPADR0, sg_dma_address(sc->sglist));
148 plxwritereg(sc, DMALADR0, addr&0x7fffffffU);
149 plxwritereg(sc, DMASIZ0, sg_dma_len(sc->sglist));
150 plxwritereg(sc, DMADPR0, 0);
151 }
152
153/* prepare PLX */
154 plxwritereg(sc, DMACSR0_DMACSR1, 1<<3); /* clear irq */
155 plxwritereg(sc, DMAMODE0, dmamode);
156
157/* prepare add on logic */
158 /* 4 Byte, local space 2, BT, EOT, start with t_adl */
159 head=0x0f80A402|(space&0x3f)<<16;
160 if (am>=0) {
161 head|=0x800;
162 sis1100writereg(sc, d_am, am);
163 }
164 if (fifo_mode) head|=0x4000;
165 sis1100writereg(sc, d_hdr, head);
166 wmb();
167 sis1100writereg(sc, d_adl, addr); /* only bit 31 is valid */
168
169 sis1100writereg(sc, d_bc, count);
170
171 sis1100writereg(sc, p_balance, 0);
172
173 spin_lock_irq(&current->SIGMASK_LOCK);
174 oldset = current->blocked;
175 sigfillset(&current->blocked);
176 sigdelset(&current->blocked, SIGKILL);
177 /* dangerous, should be removed later */
178 /*if (!sigismember(&oldset, SIGINT)) sigdelset(&current->blocked, SIGINT);*/
179#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
180 recalc_sigpending(current);
181#else
182 recalc_sigpending();
183#endif
184 spin_unlock_irq(&current->SIGMASK_LOCK);
185
186/* enable irq */
187 /* irq_synch_chg and irq_prot_l_err should always be enabled */
188 sis1100_enable_irq(sc, 0, irq_prot_l_err|irq_synch_chg|irq_prot_end);
189
190/* start dma */
191 sc->got_irqs=0;
192 mb();
193 plxwritereg(sc, DMACSR0_DMACSR1, 3);
194
195/* wait for confirmation */
196 res=wait_event_interruptible(
197 sc->local_wait,
198 (sc->got_irqs & (got_end|got_sync|got_l_err))
199 );
200
201 if (sc->got_irqs&got_l_err) {
202 printk(KERN_CRIT "sis1100[%d]: irq_prot_l_err in write_dma, irqs=0x%04x\n",
203 sc->unit, sc->got_irqs);
204 }
205 if (res|(sc->got_irqs&(got_sync))) {
206 aborted=0x300;
207 if (res) {
208 printk(KERN_INFO "sis1100[%d] write_dma: interrupted\n", sc->unit);
209 aborted|=1;
210 }
211 if (sc->got_irqs&got_sync) {
212 printk(KERN_WARNING "sis1100[%d] write_dma: synchronisation lost\n",
213 sc->unit);
214 aborted|=2;
215 }
216 }
217
218 sis1100_disable_irq(sc, 0, irq_prot_end);
219
220 spin_lock_irq(&current->SIGMASK_LOCK);
221 current->blocked = oldset;
222#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
223 recalc_sigpending(current);
224#else
225 recalc_sigpending();
226#endif
227 spin_unlock_irq(&current->SIGMASK_LOCK);
228
229 *prot_error=sis1100readreg(sc, prot_error);
230
231 if (aborted) {
232 *prot_error=aborted;
233 res=EIO;
234 } else if (*prot_error) {
235 if (*prot_error&0x200) {
236 u_int32_t addr;
237 head=0x0f000002;
238 addr = (int)&((struct sis3100_reg*)(0))->dma_write_counter;
239 sis1100writereg(sc, t_hdr, head);
240 sis1100writereg(sc, t_adl, addr);
241 do {
242 tmp=sis1100readreg(sc, prot_error);
243 } while (tmp==0x005);
244 if (tmp!=0) {
245 printk(KERN_WARNING "sis1100[%d] write_dma: "
246 "read count after error: prot_error=0x%03x\n",
247 sc->unit, tmp);
248 res=EIO;
249 } else {
250 *count_written=sis1100readreg(sc, tc_dal)/size;
251 }
252 } else {
253 res=EIO;
254 }
255 }
256
257 if (aborted) sis1100_dump_glink_status(sc, "after abort", 1);
258
259#ifdef USE_SGL
260 pci_unmap_sg(sc->pcidev, sc->sglist, nr_pages, PCI_DMA_TODEVICE);
261 sgl_unmap_user_pages(sc->sglist, nr_pages, 1);
262#else
263 pci_unmap_sg(sc->pcidev, sc->sglist, iobuf->nr_pages, PCI_DMA_TODEVICE);
264 unmap_kiobuf(iobuf);
265#endif
266
267 return res;
268}
Note: See TracBrowser for help on using the repository browser.