Skip to content

Commit 1844b34

Browse files
authored
Merge pull request torvalds#487 from liva/x86
add PCI device interface and a vfio backend driver
2 parents 5398299 + 96de6a9 commit 1844b34

File tree

23 files changed

+1065
-25
lines changed

23 files changed

+1065
-25
lines changed

.circleci/config.yml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ do_steps: &do_steps
5656
command: |
5757
if [[ $CROSS_COMPILE == *android* ]]; then
5858
emulator -avd Nexus5_API24 -no-window -no-audio -no-boot-anim;
59-
elif [[ $CROSS_COMPILE == *freebsd* ]]; then
60-
cd /home/ubuntu && $QEMU
59+
elif [[ $CROSS_COMPILE == *freebsd* ]] || [[ -n "$LKL_QEMU_TEST" ]]; then
60+
cd /home/ubuntu && eval $QEMU
6161
fi
6262
background: true
6363
- run: cd tools/lkl && make -j8 ${MKARG}
@@ -71,7 +71,7 @@ do_steps: &do_steps
7171
command: |
7272
if [[ $CROSS_COMPILE == *android* ]]; then
7373
/home/ubuntu/circle-android.sh wait-for-boot;
74-
elif [[ $CROSS_COMPILE == *freebsd* ]]; then
74+
elif [[ $CROSS_COMPILE == *freebsd* ]] || [[ -n "$LKL_QEMU_TEST" ]]; then
7575
while ! $MYSSH -o ConnectTimeout=1 exit 2> /dev/null
7676
do
7777
sleep 5
@@ -147,6 +147,15 @@ jobs:
147147
VALGRIND: 1
148148
<<: *do_steps
149149

150+
x86_64_qemu:
151+
docker:
152+
- image: lkldocker/circleci-qemu-x86_64:v1.1
153+
environment:
154+
CROSS_COMPILE: ""
155+
MKARG: "dpdk=no"
156+
LKL_QEMU_TEST: 1
157+
<<: *do_steps
158+
150159
checkpatch:
151160
docker:
152161
- image: lkldocker/circleci:0.5
@@ -167,6 +176,7 @@ workflows:
167176
build:
168177
jobs:
169178
- x86_64
179+
- x86_64_qemu
170180
- mingw32
171181
- android-arm32
172182
- android-aarch64

arch/lkl/Kconfig

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ config LKL
3636
select ARCH_NO_COHERENT_DMA_MMAP
3737
select HAVE_MEMBLOCK
3838
select NO_BOOTMEM
39+
select BLK_DEV_NVME
3940

4041
config OUTPUT_FORMAT
4142
string "Output format"
@@ -93,4 +94,8 @@ config CONSOLE_LOGLEVEL_QUIET
9394
will be used as the loglevel. IOW passing "quiet" will be the
9495
equivalent of passing "loglevel=<CONSOLE_LOGLEVEL_QUIET>"
9596

96-
97+
config PCI
98+
bool "PCI support"
99+
select NO_GENERIC_PCI_IOPORT_MAP
100+
select GENERIC_PCI_IOMAP
101+
default y

arch/lkl/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ endif
3636

3737
core-y += arch/lkl/kernel/
3838
core-y += arch/lkl/mm/
39+
core-y += arch/lkl/drivers/
3940

4041
all: lkl.o
4142

arch/lkl/drivers/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
obj-y = pci.o

arch/lkl/drivers/pci.c

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <linux/init.h>
3+
#include <linux/kernel.h>
4+
#include <linux/pci.h>
5+
#include <linux/slab.h>
6+
#include <linux/interrupt.h>
7+
#include <linux/types.h>
8+
#include <linux/io.h>
9+
#include <linux/platform_device.h>
10+
#include <linux/dma-mapping.h>
11+
#include <linux/scatterlist.h>
12+
#include <linux/mm.h>
13+
#include <asm/host_ops.h>
14+
15+
static int lkl_pci_generic_read(struct pci_bus *bus, unsigned int devfn,
16+
int where, int size, u32 *val)
17+
{
18+
if (devfn == 0 &&
19+
lkl_ops->pci_ops->read(bus->sysdata, where, size, val) == size)
20+
return PCIBIOS_SUCCESSFUL;
21+
else
22+
return PCIBIOS_FUNC_NOT_SUPPORTED;
23+
}
24+
25+
static int lkl_pci_generic_write(struct pci_bus *bus, unsigned int devfn,
26+
int where, int size, u32 val)
27+
{
28+
if (devfn == 0 &&
29+
lkl_ops->pci_ops->write(bus->sysdata, where, size, &val) == size)
30+
return PCIBIOS_SUCCESSFUL;
31+
else
32+
return PCIBIOS_FUNC_NOT_SUPPORTED;
33+
}
34+
35+
void __iomem *__pci_ioport_map(struct pci_dev *dev, unsigned long port,
36+
unsigned int nr)
37+
{
38+
panic("%s is not supported\n", __func__);
39+
return NULL;
40+
}
41+
42+
static int lkl_pci_override_resource(struct pci_dev *dev, void *data)
43+
{
44+
int i;
45+
struct resource *r;
46+
resource_size_t start, size;
47+
void *remapped_start = NULL;
48+
49+
if (dev->devfn != 0)
50+
return 0;
51+
52+
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
53+
r = &dev->resource[i];
54+
55+
if (!r->parent && r->start && r->flags) {
56+
dev_info(&dev->dev, "claiming resource %s/%d\n",
57+
pci_name(dev), i);
58+
if (pci_claim_resource(dev, i)) {
59+
dev_err(&dev->dev,
60+
"Could not claim resource %s/%d!",
61+
pci_name(dev), i);
62+
}
63+
64+
size = pci_resource_len(dev, i);
65+
66+
if (pci_resource_flags(dev, i) & IORESOURCE_MEM) {
67+
remapped_start =
68+
lkl_ops->pci_ops->resource_alloc(
69+
dev->sysdata, size, i);
70+
}
71+
72+
if (remapped_start) {
73+
/* override values */
74+
start = (resource_size_t)remapped_start;
75+
pci_resource_start(dev, i) = start;
76+
pci_resource_end(dev, i) = start + size - 1;
77+
} else {
78+
/*
79+
* A host library or the application could
80+
* not handle the resource. Disable it
81+
* not to be touched by drivers.
82+
*/
83+
pci_resource_flags(dev, i) |=
84+
IORESOURCE_DISABLED;
85+
}
86+
}
87+
}
88+
89+
dev->irq = lkl_get_free_irq("pci");
90+
91+
if (lkl_ops->pci_ops->irq_init(dev->sysdata, dev->irq) < 0)
92+
return -ENOMEM;
93+
94+
return 0;
95+
}
96+
97+
static int lkl_pci_remove_devices(struct pci_dev *dev, void *data)
98+
{
99+
lkl_ops->pci_ops->remove(dev->sysdata);
100+
return 0;
101+
}
102+
103+
static struct pci_ops lkl_pci_root_ops = {
104+
.read = lkl_pci_generic_read,
105+
.write = lkl_pci_generic_write,
106+
};
107+
108+
static void *lkl_dma_alloc(struct device *dev, size_t size,
109+
dma_addr_t *dma_handle, gfp_t gfp,
110+
unsigned long attrs)
111+
{
112+
void *vaddr = page_to_virt(alloc_pages(gfp, get_order(size)));
113+
*dma_handle = (dma_addr_t)lkl_ops->pci_ops->map_page(
114+
to_pci_dev(dev)->sysdata, vaddr, size);
115+
return vaddr;
116+
}
117+
118+
static void lkl_dma_free(struct device *dev, size_t size, void *cpu_addr,
119+
dma_addr_t dma_addr, unsigned long attrs)
120+
{
121+
lkl_ops->pci_ops->unmap_page(to_pci_dev(dev)->sysdata, dma_addr, size);
122+
__free_pages(cpu_addr, get_order(size));
123+
}
124+
125+
static dma_addr_t lkl_dma_map_page(struct device *dev, struct page *page,
126+
unsigned long offset, size_t size,
127+
enum dma_data_direction dir,
128+
unsigned long attrs)
129+
{
130+
dma_addr_t dma_handle = (dma_addr_t)lkl_ops->pci_ops->map_page(
131+
to_pci_dev(dev)->sysdata, page_to_virt(page) + offset, size);
132+
if (dma_handle == 0)
133+
return DMA_MAPPING_ERROR;
134+
135+
return dma_handle;
136+
}
137+
138+
static void lkl_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
139+
size_t size, enum dma_data_direction dir,
140+
unsigned long attrs)
141+
{
142+
lkl_ops->pci_ops->unmap_page(to_pci_dev(dev)->sysdata, dma_addr, size);
143+
}
144+
145+
static int lkl_dma_map_sg(struct device *dev, struct scatterlist *sgl,
146+
int nents, enum dma_data_direction dir,
147+
unsigned long attrs)
148+
{
149+
int i;
150+
struct scatterlist *sg;
151+
152+
for_each_sg(sgl, sg, nents, i) {
153+
void *va;
154+
155+
WARN_ON(!sg_page(sg));
156+
va = sg_virt(sg);
157+
sg_dma_address(sg) = (dma_addr_t)lkl_dma_map_page(
158+
dev, sg_page(sg), sg->offset, sg->length, dir, attrs);
159+
sg_dma_len(sg) = sg->length;
160+
}
161+
return nents;
162+
}
163+
164+
static void lkl_dma_unmap_sg(struct device *dev, struct scatterlist *sgl,
165+
int nents, enum dma_data_direction dir,
166+
unsigned long attrs)
167+
{
168+
int i;
169+
struct scatterlist *sg;
170+
171+
for_each_sg(sgl, sg, nents, i)
172+
lkl_dma_unmap_page(dev, sg_dma_address(sg), sg_dma_len(sg), dir,
173+
attrs);
174+
}
175+
176+
static int lkl_dma_supported(struct device *dev, u64 mask)
177+
{
178+
return 1;
179+
}
180+
181+
static char *pcidev_name;
182+
183+
static int __init setup_pci_device(char *str)
184+
{
185+
if (pcidev_name) {
186+
pr_info("The PCI driver supports only one PCI device.");
187+
pr_info("'%s' will be discarded.", str);
188+
return -1;
189+
}
190+
pcidev_name = str;
191+
return 0;
192+
}
193+
194+
early_param("lkl_pci", setup_pci_device);
195+
196+
const struct dma_map_ops lkl_dma_ops = {
197+
.alloc = lkl_dma_alloc,
198+
.free = lkl_dma_free,
199+
.map_sg = lkl_dma_map_sg,
200+
.unmap_sg = lkl_dma_unmap_sg,
201+
.map_page = lkl_dma_map_page,
202+
.unmap_page = lkl_dma_unmap_page,
203+
.dma_supported = lkl_dma_supported,
204+
};
205+
206+
static int lkl_pci_probe(struct platform_device *pdev)
207+
{
208+
struct lkl_pci_dev *dev;
209+
struct pci_bus *bus;
210+
211+
if (!lkl_ops->pci_ops || !pcidev_name)
212+
return -1;
213+
214+
dev = lkl_ops->pci_ops->add(pcidev_name, (void *)memory_start,
215+
memory_end - memory_start);
216+
if (!dev)
217+
return -1;
218+
219+
bus = pci_scan_bus(0, &lkl_pci_root_ops, (void *)dev);
220+
if (!bus) {
221+
lkl_ops->pci_ops->remove(dev);
222+
return -1;
223+
}
224+
pci_walk_bus(bus, lkl_pci_override_resource, NULL);
225+
pci_bus_add_devices(bus);
226+
dev_set_drvdata(&pdev->dev, bus);
227+
228+
return 0;
229+
}
230+
231+
static void lkl_pci_shutdown(struct platform_device *pdev)
232+
{
233+
struct pci_bus *bus = (struct pci_bus *)dev_get_drvdata(&pdev->dev);
234+
235+
if (bus)
236+
pci_walk_bus(bus, lkl_pci_remove_devices, NULL);
237+
}
238+
239+
static struct platform_driver lkl_pci_driver = {
240+
.driver = {
241+
.name = "lkl_pci",
242+
},
243+
.probe = lkl_pci_probe,
244+
.shutdown = lkl_pci_shutdown,
245+
};
246+
247+
static int __init lkl_pci_init(void)
248+
{
249+
int ret;
250+
struct platform_device *dev;
251+
252+
/*register a platform driver*/
253+
ret = platform_driver_register(&lkl_pci_driver);
254+
if (ret != 0)
255+
return ret;
256+
257+
dev = platform_device_alloc("lkl_pci", -1);
258+
if (!dev)
259+
return -ENOMEM;
260+
261+
ret = platform_device_add(dev);
262+
if (ret != 0)
263+
goto error;
264+
265+
return 0;
266+
error:
267+
platform_device_put(dev);
268+
return ret;
269+
}
270+
271+
subsys_initcall(lkl_pci_init);

arch/lkl/include/asm/Kbuild

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ generic-y += current.h
1414
generic-y += delay.h
1515
generic-y += device.h
1616
generic-y += div64.h
17-
generic-y += dma.h
18-
generic-y += dma-mapping.h
1917
generic-y += emergency-restart.h
2018
generic-y += errno.h
2119
generic-y += extable.h
@@ -42,7 +40,7 @@ generic-y += module.h
4240
generic-y += msgbuf.h
4341
generic-y += param.h
4442
generic-y += parport.h
45-
generic-y += pci.h
43+
generic-y += pci_iomap.h
4644
generic-y += percpu.h
4745
generic-y += pgalloc.h
4846
generic-y += poll.h
@@ -75,5 +73,6 @@ generic-y += topology.h
7573
generic-y += trace_clock.h
7674
generic-y += unaligned.h
7775
generic-y += user.h
76+
generic-y += vga.h
7877
generic-y += word-at-a-time.h
7978
generic-y += kprobes.h

arch/lkl/include/asm/dma-mapping.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _ASM_LKL_DMA_MAPPING_H
3+
#define _ASM_LKL_DMA_MAPPING_H
4+
5+
extern const struct dma_map_ops lkl_dma_ops;
6+
7+
static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus)
8+
{
9+
return &lkl_dma_ops;
10+
}
11+
12+
#endif

arch/lkl/include/asm/dma.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _ASM_LKL_DMA_H
3+
#define _ASM_LKL_DMA_H
4+
5+
#include <asm-generic/dma.h>
6+
7+
#ifdef CONFIG_PCI
8+
extern int isa_dma_bridge_buggy;
9+
#else
10+
#define isa_dma_bridge_buggy (0)
11+
#endif
12+
13+
#endif /* _ASM_LKL_DMA_H */

0 commit comments

Comments
 (0)