Adaptation from old init_timer to new timer_setup - c

I have been trying to port a driver from 2.6 to 4.X without support from the original board manufacturer (and very limited Linux experience).
The original driver uses init_timer() and passes in a pointer to the timer_list structure. That timer_list structure's data element was set to a pointer to another memory structure and the function element set to the callback. Inside the callback function the data element was used to access other bits of stuff.
The current timer init-method uses:
timer_setup( timer_list *, callback, (unsigned int) flags);
and the timer_list structure was changed to eliminate the data field.
I'm not sure what is the best/proper way to inform the callback function of the equivalent data element. Can anyone provide some guidance?
Here is a snippet of the old driver:
myDevice * dev;
dev->getIntrTimer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
init_timer(dev->getIntrTimer);
dev->getIntrTimer->data = (unsigned long) dev;
dev->getIntrTimer->function = GetIntrTimerCallback;
The callback function starts off like this:
void GetIntrTimerCallback(unsigned long devAddr)
{
myDevice *dev = (myDevice *) devAddr;
dev->blahBlah++; // etc.
So the old code gets passed the pointer to myDevice so inside the callback that structure can be accessed.
But with the new timer method only has available an int that is 4 bytes but a pointer is 8 (or whatever).
What I'd like to do is this:
dev->getIntrTimer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
timer_setup(dev->getIntrTimer, GetIntrTimerCallback, dev);
but of course that generates compile errors because dev is a pointer to type myDevice, which does not fit in an int.

The timer_setup() with three args is present since 4.14 Linux kernel (FYI there was setup_timer() in slightly earlier versions). If you maintain some code which should be relevant up to recent kernels - you have to change it in appropriate way every time the API changes. Now you can access your data through the special function from_timer() based on container_of().
timer_list is normally used not as pointer inside struct, so the example implies normal usage and could be something like:
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)
init_timer(&dev->getIntrTimer);
dev->getIntrTimer.data = (unsigned long) dev;
dev->getIntrTimer.function = GetIntrTimerCallback;
/* ... */
add_timer(&dev->getIntrTimer);
#else
timer_setup(&dev->getIntrTimer, GetIntrTimerCallback, 0);
/* the third argument may include TIMER_* flags */
/* ... */
#endif
The callback function:
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)
void GetIntrTimerCallback(unsigned long devAddr)
{
myDevice *dev = (myDevice *) devAddr;
#else
void GetIntrTimerCallback(struct timer_list *t)
{
myDevice *dev = from_timer(dev, t, getIntrTimer);
#endif
/* Do something with "dev" */
Read also:
Linux kernel timers new API
Example
Linux kernel versions

Related

Synchronizing a usermode application to a kernel driver

We have a driver that schedules work using a timer (using add_timer). Whenever the work results in a change, an application should be notified of this change.
Currently this is done by providing a sysfs entry from the driver, that blocks a read operation until there is a change in the data.
(Please see the relevant code from the driver and the application in the code block below.)
I have inspected the source of most functions related to this in the linux kernel (4.14.98), and I did not notice any obvious problems in dev_attr_show, sysfs_kf_seq_show,__vfs_read and vfs_read.
However in seq_read the mutex file->private_data->lock is held for the duration of the read:
https://elixir.bootlin.com/linux/v4.14.98/source/fs/seq_file.c#L165
Will this pose a problem?
Are there any other (potential?) problems that I should be aware of?
Please note that:
The data will change at least once per second, usually way faster
The application should respond as soon as possible to a change in the data
This runs in a controlled (embedded) environment
// driver.c
static DECLARE_WAIT_QUEUE_HEAD(wq);
static int xxx_block_c = 0;
// driver calls this to notify the application that something changed (from a timer, `timer_list`)
void xxx_Persist(void)
{
xxx_block_c = 1;
wake_up_interruptible(&wq);
}
// Sysfs entry that blocks until there is a change in the data.
static ssize_t xxx_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
wait_event_interruptible(wq, xxx_block_c != 0);
xxx_block_c = 0;
/* Remainder of the implementation */
}
//application.cpp
std::ifstream xxx;
xxx.open("xxx", std::ios::binary | std::ios::in);
while (true)
{
xxx.clear();
xxx.seekg(0, std::ios_base::beg);
xxx.read(data, size);
/* Do something with data */
}

How to properly utilize masks to send index information to perf event output?

According to the documentation for bpf_perf_event_output found here: http://man7.org/linux/man-pages/man7/bpf-helpers.7.html
"The flags are used to indicate the index in map for which the value must be put, masked with BPF_F_INDEX_MASK."
In the following code:
SEC("xdp_sniffer")
int xdp_sniffer_prog(struct xdp_md *ctx)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
if (data < data_end) {
/* If we have reached here, that means this
* is a useful packet for us. Pass on-the-wire
* size and our cookie via metadata.
*/
/* If we have reached here, that means this
* is a useful packet for us. Pass on-the-wire
* size and our cookie via metadata.
*/
__u64 flags = BPF_F_INDEX_MASK;
__u16 sample_size;
int ret;
struct S metadata;
metadata.cookie = 0xdead;
metadata.pkt_len = (__u16)(data_end - data);
/* To minimize writes to disk, only
* pass necessary information to userspace;
* that is just the header info.
*/
sample_size = min(metadata.pkt_len, SAMPLE_SIZE);
flags |= (__u64)sample_size << 32;
ret = bpf_perf_event_output(ctx, &my_map, flags,
&metadata, sizeof(metadata));
if (ret)
bpf_printk("perf_event_output failed: %d\n", ret);
}
return XDP_PASS;
}
It works as you would expect and stores the information for the given CPU number.
However, suppose I want all packets to be sent to index 1.
I swap
__u64 flags = BPF_F_INDEX_MASK;
for
__u64 flags = 0x1ULL;
The code compiles correctly and throws no errors, however no packets get saved at all anymore. What am I doing wrong if I want all of the packets to be sent to index 1?
Partial answer: I see no reason why the packets would not be sent to the perf buffer, but I suspect the error is on the user space code (not provided). It could be that you do not “open” the perf event for all CPUs when trying to read from the buffer. Have a look at the man page for perf_event_open(2): check that the combination of values for pid and cpu allows you to read data written for CPU 1.
As a side note, this:
__u64 flags = BPF_F_INDEX_MASK;
is misleading. The mask should be used to mask the index, not to set its value. BPF_F_CURRENT_CPU should be used instead, the former only happens to work because the two enum attributes have the same value.

Porting generic C driver with function pointer

I am trying to port a generic C driver available for a IMU to my embedded platform based on a nordic module. the most optimal way would be to correctly modify the interface functions to adapt it to my system. So the driver available on github here, has this interface for write/read register:
typedef int32_t (*lsm6dso_write_ptr)(void *, uint8_t, uint8_t*, uint16_t);
typedef int32_t (*lsm6dso_read_ptr) (void *, uint8_t, uint8_t*, uint16_t);
typedef struct {
/** Component mandatory fields **/
lsm6dso_write_ptr write_reg;
lsm6dso_read_ptr read_reg;
/** Customizable optional pointer **/
void *handle;
} lsm6dso_ctx_t;
My read/write register functions are:
void write_i2c_data(nrf_drv_twi_t const *m_twi, uint8_t reg, uint8_t val)
{
uint8_t cmd[2] = {0, 0};
cmd[0] = reg;
cmd[1] = val;
nrf_drv_twi_tx(m_twi, ADDR, cmd, 2, true);
nrf_delay_ms(1);
}
void read_i2c_data(nrf_drv_twi_t const *m_twi, uint8_t reg, uint8_t *val)
{
nrf_drv_twi_tx(m_twi, ADDR, &reg, 1, true);
nrf_delay_ms(1);
nrf_drv_twi_rx(m_twi, ADDR, val, 1);
nrf_delay_ms(1);
}
Questions -
1 - I am not sure how to pass along the m_twi driver instance function along to the lsm6dso_ctx_t struct. It says the struct is customizable, but I am not sure how to augment it.
2 - The function pointer kind of got me too - how can I point my function to the lsm6dso_write_ptr pointer. I know will need to modify my function to provide for multiple byte read/write, which I think is doable.
You should implement two functions:
static int32_t your_callback_lsm6dso_read_reg(void *ctx, uint8_t reg, uint8_t* data,
uint16_t len) {
// read from register ret
// len length of data to data pointer
// return 0 on success
// something like: (I have no idea about nrf_* interface)
nrf_drv_twi_t const *m_twi = ctx;
nrf_drv_twi_rx(m_twi, reg, data, len);
return 0;
}
static int32_t your_callback_lsm6dso_write_reg(void *ctx, uint8_t reg, uint8_t* data,
uint16_t len)
// write to register ret len length od data from data pointer
// return 0 on success
// something like: (I have no idea about nrf* interface)
nrf_drv_twi_t const *m_twi = ctx;
nrf_drv_twi_tx(m_twi, reg, data, len);
return 0;
}
Then instantiate the structure:
lsm6dso_ctx_t lsm6dso_ctx = { your_callback_lsm6dso_write_reg, your_callback_lsm6dso_read_reg, m_twi };
and use it like:
lsm6dso_some_function_from_the_library(&lsm6dso_ctx, ...)
The function from the library will call the function pointers from lsm6dso_ctx with the first argument as the void* pointer from the structure. The void* pointer from the structure is used to pass your custom data along. You can then cast the handle from void* pointer into a custom pointer and call the appropriate functions.
how can I point my function to the lsm6dso_write_ptr pointer.
I think your confusion comes from it, that's it's the other way round. The function pointers inside lsm6dso_ctx_t should point to your functions.
Then you have just an instance of lsm6dso_ctx_t structure you use with all functions from the driver. The driver has some logic and it calls your functions as passed with the structure to do input/output operations.

In u-boot, kernel_entry points to which function?

This is the function from u-boot:
static void boot_jump_linux(bootm_headers_t *images, int flag)
{
#ifdef CONFIG_ARM64
void (*kernel_entry)(void *fdt_addr);
int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
kernel_entry = (void (*)(void *fdt_addr))images->ep;
debug("## Transferring control to Linux (at address %lx)...\n",
(ulong) kernel_entry);
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
announce_and_cleanup(fake);
if (!fake)
kernel_entry(images->ft_addr);
#else
unsigned long machid = gd->bd->bi_arch_number;
char *s;
void (*kernel_entry)(int zero, int arch, uint params);
unsigned long r2;
int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
kernel_entry = (void (*)(int, int, uint))images->ep;
s = getenv("machid");
if (s) {
strict_strtoul(s, 16, &machid);
printf("Using machid 0x%lx from environment\n", machid);
}
debug("## Transferring control to Linux (at address %08lx)" \
"...\n", (ulong) kernel_entry);
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
announce_and_cleanup(fake);
if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
r2 = (unsigned long)images->ft_addr;
else
r2 = gd->bd->bi_boot_params;
if (!fake)
kernel_entry(0, machid, r2);
#endif
}
I understood from the related question: Trying to understand the usage of function pointer that kernel_entryis a pointer to a function. Can someone help me understand where that function is defined? I don't even know the name of this function so I failed to grepit.
NOTE: The entire u-boot source code is here.
Indeed kernel_entry is a function pointer. It is initialized from the ep field of the piece of data passed in called images, of type bootm_header_t. The definition of that struct is in include/image.h. This is the definition of a bootable image header, ie the header of a kernel image which contain the basic info to boot that image from the boot loader. Obviously, to start it, you need a program entry point, similarly to the main function in regular C programs.
In that structure, the entry point is simply defined as a memory address (unsigned long), which the code you listed cast into that function pointer.
That structure as been obtained from loading the first blocks of the image file on disk, whose location is known already by the boot loader.
Hence the actual code pointed by that function pointer belongs to a different binary, and the definition of the function must be located in a different source code. For a linux kernel, this entry point is an assembly hand coded function, whose source is in head.S. This function being highly arch dependent, you will find many files of that name implementing it accross the kernel tree.

alternative to container_of()

I am a newbie trying to code a serial driver(PCI based ) and I don't want to use the container_of() for lack of downward compatibility.The kernel version I may compile the module
would be < 2.6.x so I want to make it compatible with most of the old and new versions.
i want to access the structure member(s) of a serial card driver.the structure is a custom one containing the atomic variable for example - use_count and the related operation on it-- atomic_inc(&serial_card->use_count).I dont want to access them by using the container_of() function which will give me the containing structure
Is there any alternate to container_of() function.If I am not wrong the text LINux device drivers by Allesandro Roubini describes a way on page no 174 | Chapter 6: Advanced Char Driver Operations.
But I am still fixed about how to assign something like struct scull_dev *dev = &scull_s_device.
if the structure itself contains a variable of type struct pc_device *dev,the above statement populates a similar variable and that is assigned to dev,
in my case i have declared a structure and related function as below
struct serial_card
{
unsigned int id; // to identify the each card
//atomic_t use_count; // variable used to check whether the device is already opened or not
wait_queue_head_t rx_queue[64]; // queue in which the process are stored
unsigned int data_ready[64]; // queue in which the process is ready
unsigned int rx_chan; // used by interrupt handler
unsigned int base, len; // holds physical base address , holds the total area ( for each card )
unsigned int *base; // holds virtual address
/*struct cdev cdev; // kernel uses this structure to represent the EACH char device
not using the new method to represent char devices in kernel instead using the old method of register_chrdev();*/
struct pci_dev *device; // pci_dev structure for EACH device.
//struct semaphore sem; //Semaphore needed to handle the co-ordination of processes,use incase need arises
};
static struct serial_card *serial_cards; // pointer to array of structures [ depending on number of cards ],NO_OF_CARDS #defined in header file
static int serialcard_open(struct inode *inode,struct file *filep)
{
//getting the structure details of type struct serialcard,using the pointer inode->i_cdev and field type cdev
//struct serial_card *serial_cards = container_of(inode->i_cdev, struct serial_card, cdev);
// read the current value of use_count
static int Device_Open = 0;
if ( Device_Open ) //Device_Open is static varibale used here for checking the no of times a device is opened
{
printk("cPCIserial: Open attempt rejected\n");
return -EBUSY;
}
Device_Open++;
// using the card so increment use_count
//atomic_inc(&serial_cards->use_count);
//filep->private_data = serial_cards;
return 0;
}
the complete description on page 174 - 175 is as follows
Single-Open Devices
The brute-force way to provide access control is to permit a device to be opened by
only one process at a time (single openness). This technique is best avoided because it
inhibits user ingenuity. A user might want to run different processes on the same
device, one reading status information while the other is writing data. In some cases,
users can get a lot done by running a few simple programs through a shell script, as
long as they can access the device concurrently. In other words, implementing a singleopen
behavior amounts to creating policy, which may get in the way of what your
users want to do. Allowing only a single process to open a device has undesirable properties, but it is also the easiest access control to implement for a device driver, so it’s shown here.
The source code is extracted from a device called scullsingle.
The scullsingle device maintains an atomic_t variable called scull_s_available; that
variable is initialized to a value of one, indicating that the device is indeed available.
The open call decrements and tests scull_s_available and refuses access if somebody
else already has the device open:
static atomic_t scull_s_available = ATOMIC_INIT(1);
static int scull_s_open(struct inode *inode, struct file *filp)
{
struct scull_dev *dev = &scull_s_device; /* device information */
if (! atomic_dec_and_test (&scull_s_available)) {
atomic_inc(&scull_s_available);
return -EBUSY; /* already open */
}
/* then, everything else is copied from the bare scull device */
if ( (filp->f_flags & O_ACCMODE) = = O_WRONLY) {
scull_trim(dev);
filp->private_data = dev;
return 0; /* success */
}
The release call, on the other hand, marks the device as no longer busy:
static int scull_s_release(struct inode *inode, struct file *filp)
{
atomic_inc(&scull_s_available); /* release the device */
return 0;
}
Normally, we recommend that you put the open flag scull_s_available within the
device structure (Scull_Dev here) because, conceptually, it belongs to the device. The
scull driver, however, uses standalone variables to hold the flag so it can use the same
device structure and methods as the bare scull device and minimize code duplication.
Please let me know any alternative for this
thanks and regards
perhaps I am missing the point, but "cotainer_of" is not a function, but a macro. If you have porting concerns, you can safely define it by yourserlf if the system headers don't implement it. Here a basic implementation:
#ifndef container_of
#define container_of(ptr, type, member) \
((type *) \
( ((char *)(ptr)) \
- ((char *)(&((type*)0)->member)) ))
#endif
Or here's the implementation - more accurate - from recent linux headers:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr);
(type *)( (char *)__mptr - offsetof(type,member) );})
In that code the containerof is used to store and retrieve the correct dev structure easily. The correct structure can be retrieved inside the read and write functions also without accessing to the private_data.
I do not know why you do not want to use private->data and containerof, but you can always retrieve your minor number from the struct file pointer.
int minor=MINOR(filp->f_dentry_d_inode->i__rdev);
then accessing to your multiple devices vector using something like
struct scull_dev* dev = &scull_devices[minor]:
and using it.
You will need to use filp->privatedata to store "per-open" information that you also use in read/write. You will need to decide what to store to ensure that the right information is available.
Probably you want two structures. One "device structure" and one "open structure". The open structure can get dynamically allocated in "open" and stored at private_data. In release, it gets freed. It should have the members such that you can use them in read/write to get access to the data you need.
The device structure is going to be per "card". In your driver init, you probably want to loop on the number of cards and create a new device structure (serial_card) for each. You can make them a static array, or dynamically allocate, it doesn't matter. I would store the minor number in the structure as well. The minor number is chosen by you, so start with 1 and go through #cards. You can reserve "0" for a system level interface, if you want, or just start at 0 for the cards.
In open, you will get the minor number that the user opened. Go through your serial_card list looking for a match. If you don't find it, error out of open. Otherwise, you have your info and can use it to allocate a "open structure", populate it, and store it in filp->private_data.
#Giuseppe Guerrini Some compiler just cannot recognize the linux implementation of container_of.
The basic define is fine, but I wonder if there is any safety or compatibility risk at this implementation:
#ifndef container_of
#define container_of(ptr, type, member) \
((type *) \
( ((char *)(ptr)) \
- ((char *)(&((type*)0)->member)) ))
#endif

Resources