Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/alpha/kernel/io.c
10817 views
1
/*
2
* Alpha IO and memory functions.
3
*/
4
5
#include <linux/kernel.h>
6
#include <linux/types.h>
7
#include <linux/string.h>
8
#include <linux/module.h>
9
#include <asm/io.h>
10
11
/* Out-of-line versions of the i/o routines that redirect into the
12
platform-specific version. Note that "platform-specific" may mean
13
"generic", which bumps through the machine vector. */
14
15
unsigned int
16
ioread8(void __iomem *addr)
17
{
18
unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr);
19
mb();
20
return ret;
21
}
22
23
unsigned int ioread16(void __iomem *addr)
24
{
25
unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr);
26
mb();
27
return ret;
28
}
29
30
unsigned int ioread32(void __iomem *addr)
31
{
32
unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr);
33
mb();
34
return ret;
35
}
36
37
void iowrite8(u8 b, void __iomem *addr)
38
{
39
IO_CONCAT(__IO_PREFIX,iowrite8)(b, addr);
40
mb();
41
}
42
43
void iowrite16(u16 b, void __iomem *addr)
44
{
45
IO_CONCAT(__IO_PREFIX,iowrite16)(b, addr);
46
mb();
47
}
48
49
void iowrite32(u32 b, void __iomem *addr)
50
{
51
IO_CONCAT(__IO_PREFIX,iowrite32)(b, addr);
52
mb();
53
}
54
55
EXPORT_SYMBOL(ioread8);
56
EXPORT_SYMBOL(ioread16);
57
EXPORT_SYMBOL(ioread32);
58
EXPORT_SYMBOL(iowrite8);
59
EXPORT_SYMBOL(iowrite16);
60
EXPORT_SYMBOL(iowrite32);
61
62
u8 inb(unsigned long port)
63
{
64
return ioread8(ioport_map(port, 1));
65
}
66
67
u16 inw(unsigned long port)
68
{
69
return ioread16(ioport_map(port, 2));
70
}
71
72
u32 inl(unsigned long port)
73
{
74
return ioread32(ioport_map(port, 4));
75
}
76
77
void outb(u8 b, unsigned long port)
78
{
79
iowrite8(b, ioport_map(port, 1));
80
}
81
82
void outw(u16 b, unsigned long port)
83
{
84
iowrite16(b, ioport_map(port, 2));
85
}
86
87
void outl(u32 b, unsigned long port)
88
{
89
iowrite32(b, ioport_map(port, 4));
90
}
91
92
EXPORT_SYMBOL(inb);
93
EXPORT_SYMBOL(inw);
94
EXPORT_SYMBOL(inl);
95
EXPORT_SYMBOL(outb);
96
EXPORT_SYMBOL(outw);
97
EXPORT_SYMBOL(outl);
98
99
u8 __raw_readb(const volatile void __iomem *addr)
100
{
101
return IO_CONCAT(__IO_PREFIX,readb)(addr);
102
}
103
104
u16 __raw_readw(const volatile void __iomem *addr)
105
{
106
return IO_CONCAT(__IO_PREFIX,readw)(addr);
107
}
108
109
u32 __raw_readl(const volatile void __iomem *addr)
110
{
111
return IO_CONCAT(__IO_PREFIX,readl)(addr);
112
}
113
114
u64 __raw_readq(const volatile void __iomem *addr)
115
{
116
return IO_CONCAT(__IO_PREFIX,readq)(addr);
117
}
118
119
void __raw_writeb(u8 b, volatile void __iomem *addr)
120
{
121
IO_CONCAT(__IO_PREFIX,writeb)(b, addr);
122
}
123
124
void __raw_writew(u16 b, volatile void __iomem *addr)
125
{
126
IO_CONCAT(__IO_PREFIX,writew)(b, addr);
127
}
128
129
void __raw_writel(u32 b, volatile void __iomem *addr)
130
{
131
IO_CONCAT(__IO_PREFIX,writel)(b, addr);
132
}
133
134
void __raw_writeq(u64 b, volatile void __iomem *addr)
135
{
136
IO_CONCAT(__IO_PREFIX,writeq)(b, addr);
137
}
138
139
EXPORT_SYMBOL(__raw_readb);
140
EXPORT_SYMBOL(__raw_readw);
141
EXPORT_SYMBOL(__raw_readl);
142
EXPORT_SYMBOL(__raw_readq);
143
EXPORT_SYMBOL(__raw_writeb);
144
EXPORT_SYMBOL(__raw_writew);
145
EXPORT_SYMBOL(__raw_writel);
146
EXPORT_SYMBOL(__raw_writeq);
147
148
u8 readb(const volatile void __iomem *addr)
149
{
150
u8 ret = __raw_readb(addr);
151
mb();
152
return ret;
153
}
154
155
u16 readw(const volatile void __iomem *addr)
156
{
157
u16 ret = __raw_readw(addr);
158
mb();
159
return ret;
160
}
161
162
u32 readl(const volatile void __iomem *addr)
163
{
164
u32 ret = __raw_readl(addr);
165
mb();
166
return ret;
167
}
168
169
u64 readq(const volatile void __iomem *addr)
170
{
171
u64 ret = __raw_readq(addr);
172
mb();
173
return ret;
174
}
175
176
void writeb(u8 b, volatile void __iomem *addr)
177
{
178
__raw_writeb(b, addr);
179
mb();
180
}
181
182
void writew(u16 b, volatile void __iomem *addr)
183
{
184
__raw_writew(b, addr);
185
mb();
186
}
187
188
void writel(u32 b, volatile void __iomem *addr)
189
{
190
__raw_writel(b, addr);
191
mb();
192
}
193
194
void writeq(u64 b, volatile void __iomem *addr)
195
{
196
__raw_writeq(b, addr);
197
mb();
198
}
199
200
EXPORT_SYMBOL(readb);
201
EXPORT_SYMBOL(readw);
202
EXPORT_SYMBOL(readl);
203
EXPORT_SYMBOL(readq);
204
EXPORT_SYMBOL(writeb);
205
EXPORT_SYMBOL(writew);
206
EXPORT_SYMBOL(writel);
207
EXPORT_SYMBOL(writeq);
208
209
210
/*
211
* Read COUNT 8-bit bytes from port PORT into memory starting at SRC.
212
*/
213
void ioread8_rep(void __iomem *port, void *dst, unsigned long count)
214
{
215
while ((unsigned long)dst & 0x3) {
216
if (!count)
217
return;
218
count--;
219
*(unsigned char *)dst = ioread8(port);
220
dst += 1;
221
}
222
223
while (count >= 4) {
224
unsigned int w;
225
count -= 4;
226
w = ioread8(port);
227
w |= ioread8(port) << 8;
228
w |= ioread8(port) << 16;
229
w |= ioread8(port) << 24;
230
*(unsigned int *)dst = w;
231
dst += 4;
232
}
233
234
while (count) {
235
--count;
236
*(unsigned char *)dst = ioread8(port);
237
dst += 1;
238
}
239
}
240
241
void insb(unsigned long port, void *dst, unsigned long count)
242
{
243
ioread8_rep(ioport_map(port, 1), dst, count);
244
}
245
246
EXPORT_SYMBOL(ioread8_rep);
247
EXPORT_SYMBOL(insb);
248
249
/*
250
* Read COUNT 16-bit words from port PORT into memory starting at
251
* SRC. SRC must be at least short aligned. This is used by the
252
* IDE driver to read disk sectors. Performance is important, but
253
* the interfaces seems to be slow: just using the inlined version
254
* of the inw() breaks things.
255
*/
256
void ioread16_rep(void __iomem *port, void *dst, unsigned long count)
257
{
258
if (unlikely((unsigned long)dst & 0x3)) {
259
if (!count)
260
return;
261
BUG_ON((unsigned long)dst & 0x1);
262
count--;
263
*(unsigned short *)dst = ioread16(port);
264
dst += 2;
265
}
266
267
while (count >= 2) {
268
unsigned int w;
269
count -= 2;
270
w = ioread16(port);
271
w |= ioread16(port) << 16;
272
*(unsigned int *)dst = w;
273
dst += 4;
274
}
275
276
if (count) {
277
*(unsigned short*)dst = ioread16(port);
278
}
279
}
280
281
void insw(unsigned long port, void *dst, unsigned long count)
282
{
283
ioread16_rep(ioport_map(port, 2), dst, count);
284
}
285
286
EXPORT_SYMBOL(ioread16_rep);
287
EXPORT_SYMBOL(insw);
288
289
290
/*
291
* Read COUNT 32-bit words from port PORT into memory starting at
292
* SRC. Now works with any alignment in SRC. Performance is important,
293
* but the interfaces seems to be slow: just using the inlined version
294
* of the inl() breaks things.
295
*/
296
void ioread32_rep(void __iomem *port, void *dst, unsigned long count)
297
{
298
if (unlikely((unsigned long)dst & 0x3)) {
299
while (count--) {
300
struct S { int x __attribute__((packed)); };
301
((struct S *)dst)->x = ioread32(port);
302
dst += 4;
303
}
304
} else {
305
/* Buffer 32-bit aligned. */
306
while (count--) {
307
*(unsigned int *)dst = ioread32(port);
308
dst += 4;
309
}
310
}
311
}
312
313
void insl(unsigned long port, void *dst, unsigned long count)
314
{
315
ioread32_rep(ioport_map(port, 4), dst, count);
316
}
317
318
EXPORT_SYMBOL(ioread32_rep);
319
EXPORT_SYMBOL(insl);
320
321
322
/*
323
* Like insb but in the opposite direction.
324
* Don't worry as much about doing aligned memory transfers:
325
* doing byte reads the "slow" way isn't nearly as slow as
326
* doing byte writes the slow way (no r-m-w cycle).
327
*/
328
void iowrite8_rep(void __iomem *port, const void *xsrc, unsigned long count)
329
{
330
const unsigned char *src = xsrc;
331
while (count--)
332
iowrite8(*src++, port);
333
}
334
335
void outsb(unsigned long port, const void *src, unsigned long count)
336
{
337
iowrite8_rep(ioport_map(port, 1), src, count);
338
}
339
340
EXPORT_SYMBOL(iowrite8_rep);
341
EXPORT_SYMBOL(outsb);
342
343
344
/*
345
* Like insw but in the opposite direction. This is used by the IDE
346
* driver to write disk sectors. Performance is important, but the
347
* interfaces seems to be slow: just using the inlined version of the
348
* outw() breaks things.
349
*/
350
void iowrite16_rep(void __iomem *port, const void *src, unsigned long count)
351
{
352
if (unlikely((unsigned long)src & 0x3)) {
353
if (!count)
354
return;
355
BUG_ON((unsigned long)src & 0x1);
356
iowrite16(*(unsigned short *)src, port);
357
src += 2;
358
--count;
359
}
360
361
while (count >= 2) {
362
unsigned int w;
363
count -= 2;
364
w = *(unsigned int *)src;
365
src += 4;
366
iowrite16(w >> 0, port);
367
iowrite16(w >> 16, port);
368
}
369
370
if (count) {
371
iowrite16(*(unsigned short *)src, port);
372
}
373
}
374
375
void outsw(unsigned long port, const void *src, unsigned long count)
376
{
377
iowrite16_rep(ioport_map(port, 2), src, count);
378
}
379
380
EXPORT_SYMBOL(iowrite16_rep);
381
EXPORT_SYMBOL(outsw);
382
383
384
/*
385
* Like insl but in the opposite direction. This is used by the IDE
386
* driver to write disk sectors. Works with any alignment in SRC.
387
* Performance is important, but the interfaces seems to be slow:
388
* just using the inlined version of the outl() breaks things.
389
*/
390
void iowrite32_rep(void __iomem *port, const void *src, unsigned long count)
391
{
392
if (unlikely((unsigned long)src & 0x3)) {
393
while (count--) {
394
struct S { int x __attribute__((packed)); };
395
iowrite32(((struct S *)src)->x, port);
396
src += 4;
397
}
398
} else {
399
/* Buffer 32-bit aligned. */
400
while (count--) {
401
iowrite32(*(unsigned int *)src, port);
402
src += 4;
403
}
404
}
405
}
406
407
void outsl(unsigned long port, const void *src, unsigned long count)
408
{
409
iowrite32_rep(ioport_map(port, 4), src, count);
410
}
411
412
EXPORT_SYMBOL(iowrite32_rep);
413
EXPORT_SYMBOL(outsl);
414
415
416
/*
417
* Copy data from IO memory space to "real" memory space.
418
* This needs to be optimized.
419
*/
420
void memcpy_fromio(void *to, const volatile void __iomem *from, long count)
421
{
422
/* Optimize co-aligned transfers. Everything else gets handled
423
a byte at a time. */
424
425
if (count >= 8 && ((u64)to & 7) == ((u64)from & 7)) {
426
count -= 8;
427
do {
428
*(u64 *)to = __raw_readq(from);
429
count -= 8;
430
to += 8;
431
from += 8;
432
} while (count >= 0);
433
count += 8;
434
}
435
436
if (count >= 4 && ((u64)to & 3) == ((u64)from & 3)) {
437
count -= 4;
438
do {
439
*(u32 *)to = __raw_readl(from);
440
count -= 4;
441
to += 4;
442
from += 4;
443
} while (count >= 0);
444
count += 4;
445
}
446
447
if (count >= 2 && ((u64)to & 1) == ((u64)from & 1)) {
448
count -= 2;
449
do {
450
*(u16 *)to = __raw_readw(from);
451
count -= 2;
452
to += 2;
453
from += 2;
454
} while (count >= 0);
455
count += 2;
456
}
457
458
while (count > 0) {
459
*(u8 *) to = __raw_readb(from);
460
count--;
461
to++;
462
from++;
463
}
464
mb();
465
}
466
467
EXPORT_SYMBOL(memcpy_fromio);
468
469
470
/*
471
* Copy data from "real" memory space to IO memory space.
472
* This needs to be optimized.
473
*/
474
void memcpy_toio(volatile void __iomem *to, const void *from, long count)
475
{
476
/* Optimize co-aligned transfers. Everything else gets handled
477
a byte at a time. */
478
/* FIXME -- align FROM. */
479
480
if (count >= 8 && ((u64)to & 7) == ((u64)from & 7)) {
481
count -= 8;
482
do {
483
__raw_writeq(*(const u64 *)from, to);
484
count -= 8;
485
to += 8;
486
from += 8;
487
} while (count >= 0);
488
count += 8;
489
}
490
491
if (count >= 4 && ((u64)to & 3) == ((u64)from & 3)) {
492
count -= 4;
493
do {
494
__raw_writel(*(const u32 *)from, to);
495
count -= 4;
496
to += 4;
497
from += 4;
498
} while (count >= 0);
499
count += 4;
500
}
501
502
if (count >= 2 && ((u64)to & 1) == ((u64)from & 1)) {
503
count -= 2;
504
do {
505
__raw_writew(*(const u16 *)from, to);
506
count -= 2;
507
to += 2;
508
from += 2;
509
} while (count >= 0);
510
count += 2;
511
}
512
513
while (count > 0) {
514
__raw_writeb(*(const u8 *) from, to);
515
count--;
516
to++;
517
from++;
518
}
519
mb();
520
}
521
522
EXPORT_SYMBOL(memcpy_toio);
523
524
525
/*
526
* "memset" on IO memory space.
527
*/
528
void _memset_c_io(volatile void __iomem *to, unsigned long c, long count)
529
{
530
/* Handle any initial odd byte */
531
if (count > 0 && ((u64)to & 1)) {
532
__raw_writeb(c, to);
533
to++;
534
count--;
535
}
536
537
/* Handle any initial odd halfword */
538
if (count >= 2 && ((u64)to & 2)) {
539
__raw_writew(c, to);
540
to += 2;
541
count -= 2;
542
}
543
544
/* Handle any initial odd word */
545
if (count >= 4 && ((u64)to & 4)) {
546
__raw_writel(c, to);
547
to += 4;
548
count -= 4;
549
}
550
551
/* Handle all full-sized quadwords: we're aligned
552
(or have a small count) */
553
count -= 8;
554
if (count >= 0) {
555
do {
556
__raw_writeq(c, to);
557
to += 8;
558
count -= 8;
559
} while (count >= 0);
560
}
561
count += 8;
562
563
/* The tail is word-aligned if we still have count >= 4 */
564
if (count >= 4) {
565
__raw_writel(c, to);
566
to += 4;
567
count -= 4;
568
}
569
570
/* The tail is half-word aligned if we have count >= 2 */
571
if (count >= 2) {
572
__raw_writew(c, to);
573
to += 2;
574
count -= 2;
575
}
576
577
/* And finally, one last byte.. */
578
if (count) {
579
__raw_writeb(c, to);
580
}
581
mb();
582
}
583
584
EXPORT_SYMBOL(_memset_c_io);
585
586
/* A version of memcpy used by the vga console routines to move data around
587
arbitrarily between screen and main memory. */
588
589
void
590
scr_memcpyw(u16 *d, const u16 *s, unsigned int count)
591
{
592
const u16 __iomem *ios = (const u16 __iomem *) s;
593
u16 __iomem *iod = (u16 __iomem *) d;
594
int s_isio = __is_ioaddr(s);
595
int d_isio = __is_ioaddr(d);
596
597
if (s_isio) {
598
if (d_isio) {
599
/* FIXME: Should handle unaligned ops and
600
operation widening. */
601
602
count /= 2;
603
while (count--) {
604
u16 tmp = __raw_readw(ios++);
605
__raw_writew(tmp, iod++);
606
}
607
}
608
else
609
memcpy_fromio(d, ios, count);
610
} else {
611
if (d_isio)
612
memcpy_toio(iod, s, count);
613
else
614
memcpy(d, s, count);
615
}
616
}
617
618
EXPORT_SYMBOL(scr_memcpyw);
619
620
void __iomem *ioport_map(unsigned long port, unsigned int size)
621
{
622
return IO_CONCAT(__IO_PREFIX,ioportmap) (port);
623
}
624
625
void ioport_unmap(void __iomem *addr)
626
{
627
}
628
629
EXPORT_SYMBOL(ioport_map);
630
EXPORT_SYMBOL(ioport_unmap);
631
632