~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/parisc/lib/io.c

Version: ~ [ linux-5.9 ] ~ [ linux-5.8.14 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.70 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.150 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.200 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.238 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.238 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * arch/parisc/lib/io.c
  3  *
  4  * Copyright (c) Matthew Wilcox 2001 for Hewlett-Packard
  5  * Copyright (c) Randolph Chung 2001 <tausq@debian.org>
  6  *
  7  * IO accessing functions which shouldn't be inlined because they're too big
  8  */
  9 
 10 #include <linux/kernel.h>
 11 #include <linux/module.h>
 12 #include <asm/io.h>
 13 
 14 /* Copies a block of memory to a device in an efficient manner.
 15  * Assumes the device can cope with 32-bit transfers.  If it can't,
 16  * don't use this function.
 17  */
 18 void __memcpy_toio(unsigned long dest, unsigned long src, int count)
 19 {
 20         if ((dest & 3) != (src & 3))
 21                 goto bytecopy;
 22         while (dest & 3) {
 23                 writeb(*(char *)src, dest++);
 24                 ((char *)src)++;
 25                 count--;
 26         }
 27         while (count > 3) {
 28                 __raw_writel(*(u32 *)src, dest);
 29                 src += 4;
 30                 dest += 4;
 31                 count -= 4;
 32         }
 33  bytecopy:
 34         while (count--) {
 35                 writeb(*(char *)src, dest++);
 36                 ((char *)src)++;
 37         }
 38 }
 39 
 40 /*
 41 ** Copies a block of memory from a device in an efficient manner.
 42 ** Assumes the device can cope with 32-bit transfers.  If it can't,
 43 ** don't use this function.
 44 **
 45 ** CR16 counts on C3000 reading 256 bytes from Symbios 896 RAM:
 46 **      27341/64    = 427 cyc per int
 47 **      61311/128   = 478 cyc per short
 48 **      122637/256  = 479 cyc per byte
 49 ** Ergo bus latencies dominant (not transfer size).
 50 **      Minimize total number of transfers at cost of CPU cycles.
 51 **      TODO: only look at src alignment and adjust the stores to dest.
 52 */
 53 void __memcpy_fromio(unsigned long dest, unsigned long src, int count)
 54 {
 55         /* first compare alignment of src/dst */ 
 56         if ( ((dest ^ src) & 1) || (count < 2) )
 57                 goto bytecopy;
 58 
 59         if ( ((dest ^ src) & 2) || (count < 4) )
 60                 goto shortcopy;
 61 
 62         /* Then check for misaligned start address */
 63         if (src & 1) {
 64                 *(u8 *)dest = readb(src);
 65                 ((u8 *)src)++;
 66                 ((u8 *)dest)++;
 67                 count--;
 68                 if (count < 2) goto bytecopy;
 69         }
 70 
 71         if (src & 2) {
 72                 *(u16 *)dest = __raw_readw(src);
 73                 ((u16 *)src)++;
 74                 ((u16 *)dest)++;
 75                 count-=2;
 76         }
 77 
 78         while (count > 3) {
 79                 *(u32 *)dest = __raw_readl(src);
 80                 dest += 4;
 81                 src += 4;
 82                 count -= 4;
 83         }
 84 
 85  shortcopy:
 86         while (count > 1) {
 87                 *(u16 *)dest = __raw_readw(src);
 88                 ((u16 *)src)++;
 89                 ((u16 *)dest)++;
 90                 count-=2;
 91         }
 92 
 93  bytecopy:
 94         while (count--) {
 95                 *(char *)dest = readb(src);
 96                 ((char *)src)++;
 97                 ((char *)dest)++;
 98         }
 99 }
100 
101 /* Sets a block of memory on a device to a given value.
102  * Assumes the device can cope with 32-bit transfers.  If it can't,
103  * don't use this function.
104  */
105 void __memset_io(unsigned long dest, char fill, int count)
106 {
107         u32 fill32 = (fill << 24) | (fill << 16) | (fill << 8) | fill;
108         while (dest & 3) {
109                 writeb(fill, dest++);
110                 count--;
111         }
112         while (count > 3) {
113                 __raw_writel(fill32, dest);
114                 dest += 4;
115                 count -= 4;
116         }
117         while (count--) {
118                 writeb(fill, dest++);
119         }
120 }
121 
122 /*
123  * Read COUNT 8-bit bytes from port PORT into memory starting at
124  * SRC.
125  */
126 void insb (unsigned long port, void *dst, unsigned long count)
127 {
128         while (((unsigned long)dst) & 0x3) {
129                 if (!count)
130                         return;
131                 count--;
132                 *(unsigned char *) dst = inb(port);
133                 ((unsigned char *) dst)++;
134         }
135 
136         while (count >= 4) {
137                 unsigned int w;
138                 count -= 4;
139                 w = inb(port) << 24;
140                 w |= inb(port) << 16;
141                 w |= inb(port) << 8;
142                 w |= inb(port);
143                 *(unsigned int *) dst = w;
144                 ((unsigned int *) dst)++;
145         }
146 
147         while (count) {
148                 --count;
149                 *(unsigned char *) dst = inb(port);
150                 ((unsigned char *) dst)++;
151         }
152 }
153 
154 
155 /*
156  * Read COUNT 16-bit words from port PORT into memory starting at
157  * SRC.  SRC must be at least short aligned.  This is used by the
158  * IDE driver to read disk sectors.  Performance is important, but
159  * the interfaces seems to be slow: just using the inlined version
160  * of the inw() breaks things.
161  */
162 void insw (unsigned long port, void *dst, unsigned long count)
163 {
164         unsigned int l = 0, l2;
165         
166         if (!count)
167                 return;
168         
169         switch (((unsigned long) dst) & 0x3)
170         {
171          case 0x00:                     /* Buffer 32-bit aligned */
172                 while (count>=2) {
173                         
174                         count -= 2;
175                         l = cpu_to_le16(inw(port)) << 16;
176                         l |= cpu_to_le16(inw(port));
177                         *(unsigned int *) dst = l;
178                         ((unsigned int *) dst)++;
179                 }
180                 if (count) {
181                         *(unsigned short *) dst = cpu_to_le16(inw(port));
182                 }
183                 break;
184         
185          case 0x02:                     /* Buffer 16-bit aligned */
186                 *(unsigned short *) dst = cpu_to_le16(inw(port));
187                 ((unsigned short *) dst)++;
188                 count--;
189                 while (count>=2) {
190                         
191                         count -= 2;
192                         l = cpu_to_le16(inw(port)) << 16;
193                         l |= cpu_to_le16(inw(port));
194                         *(unsigned int *) dst = l;
195                         ((unsigned int *) dst)++;
196                 }
197                 if (count) {
198                         *(unsigned short *) dst = cpu_to_le16(inw(port));
199                 }
200                 break;
201                 
202          case 0x01:                     /* Buffer 8-bit aligned */
203          case 0x03:
204                 /* I don't bother with 32bit transfers
205                  * in this case, 16bit will have to do -- DE */
206                 --count;
207                 
208                 l = cpu_to_le16(inw(port));
209                 *(unsigned char *) dst = l >> 8;
210                 ((unsigned char *) dst)++;
211                 while (count--)
212                 {
213                         l2 = cpu_to_le16(inw(port));
214                         *(unsigned short *) dst = (l & 0xff) << 8 | (l2 >> 8);
215                         ((unsigned short *) dst)++;
216                         l = l2;
217                 }
218                 *(unsigned char *) dst = l & 0xff;
219                 break;
220         }
221 }
222 
223 
224 
225 /*
226  * Read COUNT 32-bit words from port PORT into memory starting at
227  * SRC. Now works with any alignment in SRC. Performance is important,
228  * but the interfaces seems to be slow: just using the inlined version
229  * of the inl() breaks things.
230  */
231 void insl (unsigned long port, void *dst, unsigned long count)
232 {
233         unsigned int l = 0, l2;
234         
235         if (!count)
236                 return;
237         
238         switch (((unsigned long) dst) & 0x3)
239         {
240          case 0x00:                     /* Buffer 32-bit aligned */
241                 while (count--)
242                 {
243                         *(unsigned int *) dst = cpu_to_le32(inl(port));
244                         ((unsigned int *) dst)++;
245                 }
246                 break;
247         
248          case 0x02:                     /* Buffer 16-bit aligned */
249                 --count;
250                 
251                 l = cpu_to_le32(inl(port));
252                 *(unsigned short *) dst = l >> 16;
253                 ((unsigned short *) dst)++;
254                 
255                 while (count--)
256                 {
257                         l2 = cpu_to_le32(inl(port));
258                         *(unsigned int *) dst = (l & 0xffff) << 16 | (l2 >> 16);
259                         ((unsigned int *) dst)++;
260                         l = l2;
261                 }
262                 *(unsigned short *) dst = l & 0xffff;
263                 break;
264          case 0x01:                     /* Buffer 8-bit aligned */
265                 --count;
266                 
267                 l = cpu_to_le32(inl(port));
268                 *(unsigned char *) dst = l >> 24;
269                 ((unsigned char *) dst)++;
270                 *(unsigned short *) dst = (l >> 8) & 0xffff;
271                 ((unsigned short *) dst)++;
272                 while (count--)
273                 {
274                         l2 = cpu_to_le32(inl(port));
275                         *(unsigned int *) dst = (l & 0xff) << 24 | (l2 >> 8);
276                         ((unsigned int *) dst)++;
277                         l = l2;
278                 }
279                 *(unsigned char *) dst = l & 0xff;
280                 break;
281          case 0x03:                     /* Buffer 8-bit aligned */
282                 --count;
283                 
284                 l = cpu_to_le32(inl(port));
285                 *(unsigned char *) dst = l >> 24;
286                 ((unsigned char *) dst)++;
287                 while (count--)
288                 {
289                         l2 = cpu_to_le32(inl(port));
290                         *(unsigned int *) dst = (l & 0xffffff) << 8 | l2 >> 24;
291                         ((unsigned int *) dst)++;
292                         l = l2;
293                 }
294                 *(unsigned short *) dst = (l >> 8) & 0xffff;
295                 ((unsigned short *) dst)++;
296                 *(unsigned char *) dst = l & 0xff;
297                 break;
298         }
299 }
300 
301 
302 /*
303  * Like insb but in the opposite direction.
304  * Don't worry as much about doing aligned memory transfers:
305  * doing byte reads the "slow" way isn't nearly as slow as
306  * doing byte writes the slow way (no r-m-w cycle).
307  */
308 void outsb(unsigned long port, const void * src, unsigned long count)
309 {
310         while (count) {
311                 count--;
312                 outb(*(char *)src, port);
313                 ((char *) src)++;
314         }
315 }
316 
317 /*
318  * Like insw but in the opposite direction.  This is used by the IDE
319  * driver to write disk sectors.  Performance is important, but the
320  * interfaces seems to be slow: just using the inlined version of the
321  * outw() breaks things.
322  */
323 void outsw (unsigned long port, const void *src, unsigned long count)
324 {
325         unsigned int l = 0, l2;
326         
327         if (!count)
328                 return;
329         
330         switch (((unsigned long) src) & 0x3)
331         {
332          case 0x00:                     /* Buffer 32-bit aligned */
333                 while (count>=2) {
334                         count -= 2;
335                         l = *(unsigned int *) src;
336                         ((unsigned int *) src)++;
337                         outw(le16_to_cpu(l >> 16), port);
338                         outw(le16_to_cpu(l & 0xffff), port);
339                 }
340                 if (count) {
341                         outw(le16_to_cpu(*(unsigned short*)src), port);
342                 }
343                 break;
344         
345          case 0x02:                     /* Buffer 16-bit aligned */
346                 
347                 outw(le16_to_cpu(*(unsigned short*)src), port);
348                 ((unsigned short *) src)++;
349                 count--;
350                 
351                 while (count>=2) {
352                         count -= 2;
353                         l = *(unsigned int *) src;
354                         ((unsigned int *) src)++;
355                         outw(le16_to_cpu(l >> 16), port);
356                         outw(le16_to_cpu(l & 0xffff), port);
357                 }
358                 if (count) {
359                         outw(le16_to_cpu(*(unsigned short*)src), port);
360                 }
361                 break;
362                 
363          case 0x01:                     /* Buffer 8-bit aligned */      
364                 /* I don't bother with 32bit transfers
365                  * in this case, 16bit will have to do -- DE */
366                 
367                 l  = *(unsigned char *) src << 8;
368                 ((unsigned char *) src)++;
369                 count--;
370                 while (count)
371                 {
372                         count--;
373                         l2 = *(unsigned short *) src;
374                         ((unsigned short *) src)++;
375                         outw(le16_to_cpu(l | l2 >> 8), port);
376                         l = l2 << 8;
377                 }
378                 l2 = *(unsigned char *) src;
379                 outw (le16_to_cpu(l | l2>>8), port);
380                 break;
381         
382         }
383 }
384 
385 
386 /*
387  * Like insl but in the opposite direction.  This is used by the IDE
388  * driver to write disk sectors.  Works with any alignment in SRC.
389  *  Performance is important, but the interfaces seems to be slow:
390  * just using the inlined version of the outl() breaks things.
391  */
392 void outsl (unsigned long port, const void *src, unsigned long count)
393 {
394         unsigned int l = 0, l2;
395         
396         if (!count)
397                 return;
398         
399         switch (((unsigned long) src) & 0x3)
400         {
401          case 0x00:                     /* Buffer 32-bit aligned */
402                 while (count--)
403                 {
404                         outl(le32_to_cpu(*(unsigned int *) src), port);
405                         ((unsigned int *) src)++;
406                 }
407                 break;
408         
409          case 0x02:                     /* Buffer 16-bit aligned */
410                 --count;
411                 
412                 l = *(unsigned short *) src;
413                 ((unsigned short *) src)++;
414                 
415                 while (count--)
416                 {
417                         l2 = *(unsigned int *) src;
418                         ((unsigned int *) src)++;
419                         outl (le32_to_cpu(l << 16 | l2 >> 16), port);
420                         l = l2;
421                 }
422                 l2 = *(unsigned short *) src;
423                 outl (le32_to_cpu(l << 16 | l2), port);
424                 break;
425          case 0x01:                     /* Buffer 8-bit aligned */
426                 --count;
427                 
428                 l  = *(unsigned char *) src << 24;
429                 ((unsigned char *) src)++;
430                 l |= *(unsigned short *) src << 8;
431                 ((unsigned short *) src)++;
432                 while (count--)
433                 {
434                         l2 = *(unsigned int *) src;
435                         ((unsigned int *) src)++;
436                         outl (le32_to_cpu(l | l2 >> 24), port);
437                         l = l2 << 8;
438                 }
439                 l2 = *(unsigned char *) src;
440                       outl (le32_to_cpu(l | l2), port);
441                 break;
442          case 0x03:                     /* Buffer 8-bit aligned */
443                 --count;
444                 
445                 l  = *(unsigned char *) src << 24;
446                 ((unsigned char *) src)++;
447                 while (count--)
448                 {
449                         l2 = *(unsigned int *) src;
450                         ((unsigned int *) src)++;
451                         outl (le32_to_cpu(l | l2 >> 8), port);
452                         l = l2 << 24;
453                 }
454                 l2  = *(unsigned short *) src << 16;
455                 ((unsigned short *) src)++;
456                 l2 |= *(unsigned char *) src;
457                 outl (le32_to_cpu(l | l2), port);
458                 break;
459         }
460 }
461 
462 EXPORT_SYMBOL(insb);
463 EXPORT_SYMBOL(insw);
464 EXPORT_SYMBOL(insl);
465 EXPORT_SYMBOL(outsb);
466 EXPORT_SYMBOL(outsw);
467 EXPORT_SYMBOL(outsl);
468 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp