mirror of
https://gitlab.com/etherlab.org/ethercat.git
synced 2026-02-07 04:11:50 +08:00
The error was: ``` [ 150s] gcc -Wp,-MMD,/home/abuild/rpmbuild/BUILD/build-default/devices/ccat/.netdev.o.d -nostdinc -I/usr/src/linux-6.3.1-1/arch/x86/include -I./arch/x86/include/generated -I/usr/src/linux-6.3.1-1/include -I./include -I/usr/src/linux-6.3.1-1/arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I/usr/src/linux-6.3.1-1/include/uapi -I./include/generated/uapi -include /usr/src/linux-6.3.1-1/include/linux/compiler-version.h -include /usr/src/linux-6.3.1-1/include/linux/kconfig.h -include /usr/src/linux-6.3.1-1/include/linux/compiler_types.h -D__KERNEL__ -fmacro-prefix-map=/usr/src/linux-6.3.1-1/= -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -fno-PIE -Werror=implicit-function-declaration -Werror=implicit-int -Werror=return-type -Wno-format-security -funsigned-char -std=gnu11 -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -fcf-protection=none -m64 -falign-jumps=1 -falign-loops=1 -mno-80387 -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup -mtune=generic -mno-red-zone -mcmodel=kernel -Wno-sign-compare -fno-asynchronous-unwind-tables -mindirect-branch=thunk-extern -mindirect-branch-register -mindirect-branch-cs-prefix -mfunction-return=thunk-extern -fno-jump-tables -mharden-sls=all -fpatchable-function-entry=16,16 -fno-delete-null-pointer-checks -Wno-frame-address -Wno-format-truncation -Wno-format-overflow -Wno-address-of-packed-member -O2 -fno-allow-store-data-races -Wframe-larger-than=2048 -fstack-protector-strong -Wno-main -Wno-unused-but-set-variable -Wno-unused-const-variable -Wno-dangling-pointer -fno-stack-clash-protection -pg -mrecord-mcount -mfentry -DCC_USING_FENTRY -falign-functions=16 -Wdeclaration-after-statement -Wvla -Wno-pointer-sign -Wcast-function-type -Wno-stringop-truncation -Wno-stringop-overflow -Wno-restrict -Wno-maybe-uninitialized -Wno-array-bounds -Wno-alloc-size-larger-than -Wimplicit-fallthrough=5 -fno-strict-overflow -fno-stack-check -fconserve-stack -Werror=date-time -Werror=incompatible-pointer-types -Werror=designated-init -Wno-packed-not-aligned -g -gdwarf-5 -DMODULE -DKBUILD_BASENAME='"netdev"' -DKBUILD_MODNAME='"ec_ccat"' -D__KBUILD_MODNAME=kmod_ec_ccat -c -o /home/abuild/rpmbuild/BUILD/build-default/devices/ccat/netdev.o /home/abuild/rpmbuild/BUILD/build-default/devices/ccat/netdev.c ; ./tools/objtool/objtool --hacks=jump_label --hacks=noinstr --hacks=skylake --orc --retpoline --rethunk --sls --static-call --uaccess --prefix=16 --module /home/abuild/rpmbuild/BUILD/build-default/devices/ccat/netdev.o [ 151s] /home/abuild/rpmbuild/BUILD/build-default/master/cdev.c: In function 'eccdev_mmap': [ 151s] /home/abuild/rpmbuild/BUILD/build-default/master/cdev.c:246:19: error: assignment of read-only member 'vm_flags' [ 151s] 246 | vma->vm_flags |= VM_DONTDUMP; /* Pages will not be swapped out */ [ 151s] | ^~ [ 151s] make[3]: *** [/usr/src/linux-6.3.1-1/scripts/Makefile.build:253: /home/abuild/rpmbuild/BUILD/build-default/master/cdev.o] Error 1 ```
338 lines
9.2 KiB
C
338 lines
9.2 KiB
C
/******************************************************************************
|
|
*
|
|
* Copyright (C) 2006-2020 Florian Pose, Ingenieurgemeinschaft IgH
|
|
*
|
|
* This file is part of the IgH EtherCAT Master.
|
|
*
|
|
* The IgH EtherCAT Master is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License version 2, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* The IgH EtherCAT Master is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|
* Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with the IgH EtherCAT Master; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* ---
|
|
*
|
|
* The license mentioned above concerns the source code only. Using the
|
|
* EtherCAT technology and brand is only permitted in compliance with the
|
|
* industrial property and similar rights of Beckhoff Automation GmbH.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/**
|
|
\file
|
|
EtherCAT master character device.
|
|
*/
|
|
|
|
/*****************************************************************************/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/mm.h>
|
|
|
|
#include "cdev.h"
|
|
#include "master.h"
|
|
#include "slave_config.h"
|
|
#include "voe_handler.h"
|
|
#include "ethernet.h"
|
|
#include "ioctl.h"
|
|
|
|
/** Set to 1 to enable device operations debugging.
|
|
*/
|
|
#define DEBUG 0
|
|
|
|
/*****************************************************************************/
|
|
|
|
static int eccdev_open(struct inode *, struct file *);
|
|
static int eccdev_release(struct inode *, struct file *);
|
|
static long eccdev_ioctl(struct file *, unsigned int, unsigned long);
|
|
static int eccdev_mmap(struct file *, struct vm_area_struct *);
|
|
|
|
/** This is the kernel version from which the .fault member of the
|
|
* vm_operations_struct is usable.
|
|
*/
|
|
#define PAGE_FAULT_VERSION KERNEL_VERSION(2, 6, 23)
|
|
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)
|
|
# define FAULT_RETURN_TYPE int
|
|
#else
|
|
# define FAULT_RETURN_TYPE vm_fault_t
|
|
#endif
|
|
|
|
#if LINUX_VERSION_CODE >= PAGE_FAULT_VERSION
|
|
static FAULT_RETURN_TYPE eccdev_vma_fault(
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
|
|
struct vm_area_struct *,
|
|
#endif
|
|
struct vm_fault *);
|
|
#else
|
|
static struct page *eccdev_vma_nopage(
|
|
struct vm_area_struct *, unsigned long, int *);
|
|
#endif
|
|
|
|
/*****************************************************************************/
|
|
|
|
/** File operation callbacks for the EtherCAT character device.
|
|
*/
|
|
static struct file_operations eccdev_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = eccdev_open,
|
|
.release = eccdev_release,
|
|
.unlocked_ioctl = eccdev_ioctl,
|
|
.mmap = eccdev_mmap
|
|
};
|
|
|
|
/** Callbacks for a virtual memory area retrieved with ecdevc_mmap().
|
|
*/
|
|
struct vm_operations_struct eccdev_vm_ops = {
|
|
#if LINUX_VERSION_CODE >= PAGE_FAULT_VERSION
|
|
.fault = eccdev_vma_fault
|
|
#else
|
|
.nopage = eccdev_vma_nopage
|
|
#endif
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
|
|
/** Private data structure for file handles.
|
|
*/
|
|
typedef struct {
|
|
ec_cdev_t *cdev; /**< Character device. */
|
|
ec_ioctl_context_t ctx; /**< Context. */
|
|
} ec_cdev_priv_t;
|
|
|
|
/*****************************************************************************/
|
|
|
|
/** Constructor.
|
|
*
|
|
* \return 0 in case of success, else < 0
|
|
*/
|
|
int ec_cdev_init(
|
|
ec_cdev_t *cdev, /**< EtherCAT master character device. */
|
|
ec_master_t *master, /**< Parent master. */
|
|
dev_t dev_num /**< Device number. */
|
|
)
|
|
{
|
|
int ret;
|
|
|
|
cdev->master = master;
|
|
|
|
cdev_init(&cdev->cdev, &eccdev_fops);
|
|
cdev->cdev.owner = THIS_MODULE;
|
|
|
|
ret = cdev_add(&cdev->cdev,
|
|
MKDEV(MAJOR(dev_num), master->index), 1);
|
|
if (ret) {
|
|
EC_MASTER_ERR(master, "Failed to add character device!\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/** Destructor.
|
|
*/
|
|
void ec_cdev_clear(ec_cdev_t *cdev /**< EtherCAT XML device */)
|
|
{
|
|
cdev_del(&cdev->cdev);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* File operations
|
|
*****************************************************************************/
|
|
|
|
/** Called when the cdev is opened.
|
|
*/
|
|
int eccdev_open(struct inode *inode, struct file *filp)
|
|
{
|
|
ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev);
|
|
ec_cdev_priv_t *priv;
|
|
|
|
priv = kmalloc(sizeof(ec_cdev_priv_t), GFP_KERNEL);
|
|
if (!priv) {
|
|
EC_MASTER_ERR(cdev->master,
|
|
"Failed to allocate memory for private data structure.\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
priv->cdev = cdev;
|
|
priv->ctx.writable = (filp->f_mode & FMODE_WRITE) != 0;
|
|
priv->ctx.requested = 0;
|
|
priv->ctx.process_data = NULL;
|
|
priv->ctx.process_data_size = 0;
|
|
|
|
filp->private_data = priv;
|
|
|
|
#if DEBUG
|
|
EC_MASTER_DBG(cdev->master, 0, "File opened.\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/** Called when the cdev is closed.
|
|
*/
|
|
int eccdev_release(struct inode *inode, struct file *filp)
|
|
{
|
|
ec_cdev_priv_t *priv = (ec_cdev_priv_t *) filp->private_data;
|
|
ec_master_t *master = priv->cdev->master;
|
|
|
|
if (priv->ctx.requested) {
|
|
ecrt_release_master(master);
|
|
}
|
|
|
|
if (priv->ctx.process_data) {
|
|
vfree(priv->ctx.process_data);
|
|
}
|
|
|
|
#if DEBUG
|
|
EC_MASTER_DBG(master, 0, "File closed.\n");
|
|
#endif
|
|
|
|
kfree(priv);
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/** Called when an ioctl() command is issued.
|
|
*/
|
|
long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
{
|
|
ec_cdev_priv_t *priv = (ec_cdev_priv_t *) filp->private_data;
|
|
|
|
#if DEBUG
|
|
EC_MASTER_DBG(priv->cdev->master, 0,
|
|
"ioctl(filp = 0x%p, cmd = 0x%08x (0x%02x), arg = 0x%lx)\n",
|
|
filp, cmd, _IOC_NR(cmd), arg);
|
|
#endif
|
|
|
|
return ec_ioctl(priv->cdev->master, &priv->ctx, cmd, (void __user *) arg);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
#ifndef VM_DONTDUMP
|
|
/** VM_RESERVED disappeared in 3.7.
|
|
*/
|
|
#define VM_DONTDUMP VM_RESERVED
|
|
#endif
|
|
|
|
/** Memory-map callback for the EtherCAT character device.
|
|
*
|
|
* The actual mapping will be done in the eccdev_vma_nopage() callback of the
|
|
* virtual memory area.
|
|
*
|
|
* \return Always zero (success).
|
|
*/
|
|
int eccdev_mmap(
|
|
struct file *filp,
|
|
struct vm_area_struct *vma
|
|
)
|
|
{
|
|
ec_cdev_priv_t *priv = (ec_cdev_priv_t *) filp->private_data;
|
|
|
|
EC_MASTER_DBG(priv->cdev->master, 1, "mmap()\n");
|
|
|
|
vma->vm_ops = &eccdev_vm_ops;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)
|
|
vm_flags_set(vma, VM_DONTDUMP);
|
|
#else
|
|
vma->vm_flags |= VM_DONTDUMP; /* Pages will not be swapped out */
|
|
#endif
|
|
vma->vm_private_data = priv;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
#if LINUX_VERSION_CODE >= PAGE_FAULT_VERSION
|
|
|
|
/** Page fault callback for a virtual memory area.
|
|
*
|
|
* Called at the first access on a virtual-memory area retrieved with
|
|
* ecdev_mmap().
|
|
*
|
|
* \return Zero on success, otherwise a negative error code.
|
|
*/
|
|
static FAULT_RETURN_TYPE eccdev_vma_fault(
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
|
|
struct vm_area_struct *vma, /**< Virtual memory area. */
|
|
#endif
|
|
struct vm_fault *vmf /**< Fault data. */
|
|
)
|
|
{
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
|
struct vm_area_struct *vma = vmf->vma;
|
|
#endif
|
|
unsigned long offset = vmf->pgoff << PAGE_SHIFT;
|
|
ec_cdev_priv_t *priv = (ec_cdev_priv_t *) vma->vm_private_data;
|
|
struct page *page;
|
|
|
|
if (offset >= priv->ctx.process_data_size) {
|
|
return VM_FAULT_SIGBUS;
|
|
}
|
|
|
|
page = vmalloc_to_page(priv->ctx.process_data + offset);
|
|
if (!page) {
|
|
return VM_FAULT_SIGBUS;
|
|
}
|
|
|
|
get_page(page);
|
|
vmf->page = page;
|
|
|
|
EC_MASTER_DBG(priv->cdev->master, 1, "Vma fault,"
|
|
" offset = %lu, page = %p\n", offset, page);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
|
|
/** Nopage callback for a virtual memory area.
|
|
*
|
|
* Called at the first access on a virtual-memory area retrieved with
|
|
* ecdev_mmap().
|
|
*/
|
|
struct page *eccdev_vma_nopage(
|
|
struct vm_area_struct *vma, /**< Virtual memory area initialized by
|
|
the kernel. */
|
|
unsigned long address, /**< Requested virtual address. */
|
|
int *type /**< Type output parameter. */
|
|
)
|
|
{
|
|
unsigned long offset;
|
|
struct page *page = NOPAGE_SIGBUS;
|
|
ec_cdev_priv_t *priv = (ec_cdev_priv_t *) vma->vm_private_data;
|
|
ec_master_t *master = priv->cdev->master;
|
|
|
|
offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
|
|
|
|
if (offset >= priv->ctx.process_data_size)
|
|
return NOPAGE_SIGBUS;
|
|
|
|
page = vmalloc_to_page(priv->ctx.process_data + offset);
|
|
|
|
EC_MASTER_DBG(master, 1, "Nopage fault vma, address = %#lx,"
|
|
" offset = %#lx, page = %p\n", address, offset, page);
|
|
|
|
get_page(page);
|
|
if (type)
|
|
*type = VM_FAULT_MINOR;
|
|
|
|
return page;
|
|
}
|
|
|
|
#endif
|
|
|
|
/*****************************************************************************/
|