Skip to content

Commit 098e723

Browse files
sw/kernel: Add kernel module to control the pciemu virtual device
Notes : - still missing tests with kunit. - less comments than hw part as the goal is to focus on the virtual device part
1 parent 51ad69a commit 098e723

File tree

7 files changed

+678
-0
lines changed

7 files changed

+678
-0
lines changed

include/sw/module/pciemu_ioctl.h

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* pciemu_ioctl.h - IOCTL definitions
2+
*
3+
* Copyright (c) 2023 Luiz Henrique Suraty Filho <[email protected]>
4+
*
5+
* SPDX-License-Identifier: GPL-2.0
6+
*
7+
*/
8+
9+
#ifndef _PCIEMU_IOCTL_H_
10+
#define _PCIEMU_IOCTL_H_
11+
12+
#define PCIEMU_IOCTL_MAGIC 0xE1
13+
14+
#define PCIEMU_IOCTL_DMA_TO_DEVICE _IOW(PCIEMU_IOCTL_MAGIC, 1, void *)
15+
#define PCIEMU_IOCTL_DMA_FROM_DEVICE _IOR(PCIEMU_IOCTL_MAGIC, 2, void *)
16+
17+
#endif /* _PCIEMU_IOCTL_H_ */

src/sw/kernel/.gitignore

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#
2+
# .gitignore copied from the linux kernel
3+
#
4+
5+
## Adding the following for kernel modules
6+
*.mod
7+
8+
.*
9+
*.o
10+
*.o.*
11+
*.a
12+
*.s
13+
*.ko
14+
*.so
15+
*.so.dbg
16+
*.mod.c
17+
*.i
18+
*.lst
19+
*.symtypes
20+
*.order
21+
modules.builtin
22+
*.elf
23+
*.bin
24+
*.gz
25+
*.bz2
26+
*.lzma
27+
*.xz
28+
*.lzo
29+
*.patch
30+
*.gcno
31+
32+
#
33+
# Top-level generic files
34+
#
35+
/tags
36+
/TAGS
37+
/linux
38+
/vmlinux
39+
/vmlinuz
40+
/System.map
41+
/Module.markers
42+
/Module.symvers
43+
44+
#
45+
# git files that we don't want to ignore even it they are dot-files
46+
#
47+
!.gitignore
48+
!.mailmap
49+
50+
#
51+
# Generated include files
52+
#
53+
include/config
54+
include/linux/version.h
55+
include/generated
56+
arch/*/include/generated
57+
58+
# stgit generated dirs
59+
patches-*
60+
61+
# quilt's files
62+
patches
63+
series
64+
65+
# cscope files
66+
cscope.*
67+
ncscope.*
68+
69+
# gnu global files
70+
GPATH
71+
GRTAGS
72+
GSYMS
73+
GTAGS
74+
75+
*.orig
76+
*~
77+
\#*#

src/sw/kernel/Makefile

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Makefile for the kernel module
2+
#
3+
# Copyright (c) 2023 Luiz Henrique Suraty Filho <[email protected]>
4+
#
5+
# SPDX-License-Identifier: GPL-2.0
6+
#
7+
8+
obj-m += pciemu.o
9+
pciemu-objs += pciemu_module.o pciemu_dma.o pciemu_irq.o
10+
ccflags-y=-I/hostdir/include
11+
12+
all:
13+
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
14+
15+
clean:
16+
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

src/sw/kernel/pciemu_dma.c

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/* pciemu_dma.c - pciemu virtual device DMA operations
2+
*
3+
* These are functions that map BARs inside the kernel module and
4+
* access them directly from the kernel module.
5+
*
6+
* Copyright (c) 2023 Luiz Henrique Suraty Filho <[email protected]>
7+
*
8+
* SPDX-License-Identifier: GPL-2.0
9+
*
10+
*/
11+
12+
#include <linux/dma-mapping.h>
13+
#include "pciemu_module.h"
14+
#include "hw/pciemu_hw.h"
15+
16+
static void pciemu_dma_struct_init(struct pciemu_dma *dma, size_t ofs,
17+
size_t len, enum dma_data_direction drctn)
18+
{
19+
dma->offset = ofs;
20+
dma->len = len;
21+
dma->direction = drctn;
22+
}
23+
24+
int pciemu_dma_from_host_to_device(struct pciemu_dev *pciemu_dev,
25+
struct page *page, size_t ofs, size_t len)
26+
{
27+
struct pci_dev *pdev = pciemu_dev->pdev;
28+
void __iomem *mmio = pciemu_dev->bar.mmio;
29+
pciemu_dma_struct_init(&pciemu_dev->dma, ofs, len, DMA_TO_DEVICE);
30+
pciemu_dev->dma.dma_handle =
31+
dma_map_page(&(pdev->dev), page, pciemu_dev->dma.offset,
32+
pciemu_dev->dma.len, pciemu_dev->dma.direction);
33+
if (dma_mapping_error(&(pdev->dev), pciemu_dev->dma.dma_handle))
34+
return -ENOMEM;
35+
dev_dbg(&(pdev->dev), "dma_handle_from = %llx\n",
36+
(unsigned long long)pciemu_dev->dma.dma_handle);
37+
dev_dbg(&(pdev->dev), "cmd = %x\n", PCIEMU_HW_DMA_DIRECTION_TO_DEVICE);
38+
iowrite32((u32)pciemu_dev->dma.dma_handle,
39+
mmio + PCIEMU_HW_BAR0_DMA_CFG_TXDESC_SRC);
40+
iowrite32(PCIEMU_HW_DMA_AREA_START,
41+
mmio + PCIEMU_HW_BAR0_DMA_CFG_TXDESC_DST);
42+
iowrite32(pciemu_dev->dma.len,
43+
mmio + PCIEMU_HW_BAR0_DMA_CFG_TXDESC_LEN);
44+
iowrite32(PCIEMU_HW_DMA_DIRECTION_TO_DEVICE,
45+
mmio + PCIEMU_HW_BAR0_DMA_CFG_CMD);
46+
iowrite32(1, mmio + PCIEMU_HW_BAR0_DMA_DOORBELL_RING);
47+
dev_dbg(&(pdev->dev), "done host->device...\n");
48+
return 0;
49+
}
50+
51+
int pciemu_dma_from_device_to_host(struct pciemu_dev *pciemu_dev,
52+
struct page *page, size_t ofs, size_t len)
53+
{
54+
struct pci_dev *pdev = pciemu_dev->pdev;
55+
void __iomem *mmio = pciemu_dev->bar.mmio;
56+
pciemu_dma_struct_init(&pciemu_dev->dma, ofs, len, DMA_FROM_DEVICE);
57+
pciemu_dev->dma.dma_handle =
58+
dma_map_page(&(pdev->dev), page, pciemu_dev->dma.offset,
59+
pciemu_dev->dma.len, pciemu_dev->dma.direction);
60+
if (dma_mapping_error(&(pdev->dev), pciemu_dev->dma.dma_handle))
61+
return -ENOMEM;
62+
dev_dbg(&(pdev->dev), "dma_handle_to = %llx\n",
63+
(unsigned long long)pciemu_dev->dma.dma_handle);
64+
dev_dbg(&(pdev->dev), "cmd = %x\n",
65+
PCIEMU_HW_DMA_DIRECTION_FROM_DEVICE);
66+
iowrite32(PCIEMU_HW_DMA_AREA_START,
67+
mmio + PCIEMU_HW_BAR0_DMA_CFG_TXDESC_SRC);
68+
iowrite32((u32)pciemu_dev->dma.dma_handle,
69+
mmio + PCIEMU_HW_BAR0_DMA_CFG_TXDESC_DST);
70+
iowrite32(pciemu_dev->dma.len,
71+
mmio + PCIEMU_HW_BAR0_DMA_CFG_TXDESC_LEN);
72+
iowrite32(PCIEMU_HW_DMA_DIRECTION_FROM_DEVICE,
73+
mmio + PCIEMU_HW_BAR0_DMA_CFG_CMD);
74+
iowrite32(1, mmio + PCIEMU_HW_BAR0_DMA_DOORBELL_RING);
75+
dev_dbg(&(pdev->dev), "done device->host...\n\n");
76+
return 0;
77+
}

src/sw/kernel/pciemu_irq.c

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/* pciemu_irq.c - pciemu virtual device IRQ operations
2+
*
3+
* These are functions that configure IRQs and the appropriate handlers.
4+
*
5+
* Copyright (c) 2023 Luiz Henrique Suraty Filho <[email protected]>
6+
*
7+
* SPDX-License-Identifier: GPL-2.0
8+
*
9+
*/
10+
#include "hw/pciemu_hw.h"
11+
#include "pciemu_module.h"
12+
#include <linux/pci.h>
13+
14+
static irqreturn_t pciemu_irq_handler(int irq, void *data)
15+
{
16+
struct pciemu_dev *pciemu_dev = data;
17+
18+
dev_dbg(&pciemu_dev->pdev->dev, "irq_handler irq = %d dev = %d\n", irq,
19+
pciemu_dev->major);
20+
21+
dma_unmap_page((&pciemu_dev->pdev->dev), pciemu_dev->dma.dma_handle,
22+
pciemu_dev->dma.len, pciemu_dev->dma.direction);
23+
24+
unpin_user_page(pciemu_dev->dma.page);
25+
/* Must do this ACK, or else the interrupt just keeps firing. */
26+
iowrite32(1, pciemu_dev->irq.mmio_ack_irq);
27+
return IRQ_HANDLED;
28+
}
29+
30+
static int pciemu_irq_enable_msi(struct pciemu_dev *pciemu_dev)
31+
{
32+
int msi_vecs_req;
33+
int msi_vecs;
34+
int err;
35+
36+
/*
37+
* Reserve the max msi vectors we might need
38+
*/
39+
msi_vecs_req = min_t(int, pci_msi_vec_count(pciemu_dev->pdev),
40+
num_online_cpus() + 1);
41+
dev_dbg(&pciemu_dev->pdev->dev,
42+
"Trying to enable MSI, requesting %d vectors\n", msi_vecs_req);
43+
44+
msi_vecs = pci_alloc_irq_vectors(pciemu_dev->pdev, msi_vecs_req,
45+
msi_vecs_req, PCI_IRQ_MSI);
46+
47+
if (msi_vecs < 0) {
48+
dev_err(&pciemu_dev->pdev->dev,
49+
"pciemu_irq_enable_msi failed, vectors %d\n", msi_vecs);
50+
return -ENOSPC;
51+
}
52+
53+
if (msi_vecs != msi_vecs_req) {
54+
pci_free_irq_vectors(pciemu_dev->pdev);
55+
dev_err(&pciemu_dev->pdev->dev,
56+
"allocated %d MSI (out of %d requested)\n", msi_vecs,
57+
msi_vecs_req);
58+
return -ENOSPC;
59+
}
60+
61+
pciemu_dev->irq.irq_num = pci_irq_vector(
62+
pciemu_dev->pdev, PCIEMU_HW_IRQ_DMA_ENDED_VECTOR);
63+
if (pciemu_dev->irq.irq_num < 0) {
64+
pci_free_irq_vectors(pciemu_dev->pdev);
65+
dev_err(&pciemu_dev->pdev->dev, "vector %d out of range\n",
66+
PCIEMU_HW_IRQ_DMA_ENDED_VECTOR);
67+
return -EINVAL;
68+
}
69+
70+
err = request_irq(pciemu_dev->irq.irq_num, pciemu_irq_handler,
71+
PCIEMU_HW_IRQ_DMA_ENDED_VECTOR,
72+
"pciemu_irq_dma_ended", pciemu_dev);
73+
if (err) {
74+
dev_err(&pciemu_dev->pdev->dev,
75+
"failed to request irq %s (%d)\n",
76+
"pciemu_irq_dma_ended", err);
77+
pci_free_irq_vectors(pciemu_dev->pdev);
78+
return err;
79+
}
80+
81+
pciemu_dev->irq.mmio_ack_irq =
82+
pciemu_dev->bar.mmio + PCIEMU_HW_IRQ_DMA_ACK_ADDR;
83+
return 0;
84+
}
85+
86+
int pciemu_irq_enable(struct pciemu_dev *pciemu_dev)
87+
{
88+
return pciemu_irq_enable_msi(pciemu_dev);
89+
}

0 commit comments

Comments
 (0)