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

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

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ 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.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

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

kernel.org | git.kernel.org | LWN.net | Project Home | 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.

sflogo.php