2 * VFIO PCI I/O Port & MMIO access
4 * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
5 * Author: Alex Williamson <alex.williamson@redhat.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * Derived from original vfio:
12 * Copyright 2010 Cisco Systems, Inc. All rights reserved.
13 * Author: Tom Lyon, pugs@cisco.com
17 #include <linux/pci.h>
18 #include <linux/uaccess.h>
21 #include "vfio_pci_private.h"
23 /* I/O Port BAR access */
24 ssize_t
vfio_pci_io_readwrite(struct vfio_pci_device
*vdev
, char __user
*buf
,
25 size_t count
, loff_t
*ppos
, bool iswrite
)
27 struct pci_dev
*pdev
= vdev
->pdev
;
28 loff_t pos
= *ppos
& VFIO_PCI_OFFSET_MASK
;
29 int bar
= VFIO_PCI_OFFSET_TO_INDEX(*ppos
);
33 if (!pci_resource_start(pdev
, bar
))
36 if (pos
+ count
> pci_resource_len(pdev
, bar
))
39 if (!vdev
->barmap
[bar
]) {
42 ret
= pci_request_selected_regions(pdev
, 1 << bar
, "vfio");
46 vdev
->barmap
[bar
] = pci_iomap(pdev
, bar
, 0);
48 if (!vdev
->barmap
[bar
]) {
49 pci_release_selected_regions(pdev
, 1 << bar
);
54 io
= vdev
->barmap
[bar
];
59 if (count
>= 3 && !(pos
% 4)) {
63 if (copy_from_user(&val
, buf
, 4))
66 iowrite32(le32_to_cpu(val
), io
+ pos
);
68 val
= cpu_to_le32(ioread32(io
+ pos
));
70 if (copy_to_user(buf
, &val
, 4))
76 } else if ((pos
% 2) == 0 && count
>= 2) {
80 if (copy_from_user(&val
, buf
, 2))
83 iowrite16(le16_to_cpu(val
), io
+ pos
);
85 val
= cpu_to_le16(ioread16(io
+ pos
));
87 if (copy_to_user(buf
, &val
, 2))
96 if (copy_from_user(&val
, buf
, 1))
99 iowrite8(val
, io
+ pos
);
101 val
= ioread8(io
+ pos
);
103 if (copy_to_user(buf
, &val
, 1))
123 * We handle two excluded ranges here as well, if the user tries to read
124 * the ROM beyond what PCI tells us is available or the MSI-X table region,
125 * we return 0xFF and writes are dropped.
127 ssize_t
vfio_pci_mem_readwrite(struct vfio_pci_device
*vdev
, char __user
*buf
,
128 size_t count
, loff_t
*ppos
, bool iswrite
)
130 struct pci_dev
*pdev
= vdev
->pdev
;
131 loff_t pos
= *ppos
& VFIO_PCI_OFFSET_MASK
;
132 int bar
= VFIO_PCI_OFFSET_TO_INDEX(*ppos
);
136 size_t x_start
= 0, x_end
= 0; /* excluded range */
138 if (!pci_resource_start(pdev
, bar
))
141 end
= pci_resource_len(pdev
, bar
);
149 if (pos
+ count
> end
)
152 if (bar
== PCI_ROM_RESOURCE
) {
153 io
= pci_map_rom(pdev
, &x_start
);
156 if (!vdev
->barmap
[bar
]) {
159 ret
= pci_request_selected_regions(pdev
, 1 << bar
,
164 vdev
->barmap
[bar
] = pci_iomap(pdev
, bar
, 0);
166 if (!vdev
->barmap
[bar
]) {
167 pci_release_selected_regions(pdev
, 1 << bar
);
172 io
= vdev
->barmap
[bar
];
174 if (bar
== vdev
->msix_bar
) {
175 x_start
= vdev
->msix_offset
;
176 x_end
= vdev
->msix_offset
+ vdev
->msix_size
;
184 size_t fillable
, filled
;
187 fillable
= x_start
- pos
;
188 else if (pos
>= x_end
)
189 fillable
= end
- pos
;
193 if (fillable
>= 4 && !(pos
% 4) && (count
>= 4)) {
197 if (copy_from_user(&val
, buf
, 4))
200 iowrite32(le32_to_cpu(val
), io
+ pos
);
202 val
= cpu_to_le32(ioread32(io
+ pos
));
204 if (copy_to_user(buf
, &val
, 4))
209 } else if (fillable
>= 2 && !(pos
% 2) && (count
>= 2)) {
213 if (copy_from_user(&val
, buf
, 2))
216 iowrite16(le16_to_cpu(val
), io
+ pos
);
218 val
= cpu_to_le16(ioread16(io
+ pos
));
220 if (copy_to_user(buf
, &val
, 2))
225 } else if (fillable
) {
229 if (copy_from_user(&val
, buf
, 1))
232 iowrite8(val
, io
+ pos
);
234 val
= ioread8(io
+ pos
);
236 if (copy_to_user(buf
, &val
, 1))
242 /* Drop writes, fill reads with FF */
247 for (i
= 0; i
< x_end
- pos
; i
++) {
248 if (put_user(val
, buf
+ i
))
253 filled
= x_end
- pos
;
265 if (bar
== PCI_ROM_RESOURCE
)
266 pci_unmap_rom(pdev
, io
);
268 return count
? -EFAULT
: done
;