I am currently working on a project involving modifying the way linux priorities are implemented.
To do so I have :
a custom syscall : That modifies the task_struct of a process to change its priority
modified kernel/sched/fair.c
modified the standard task_struct to add new fields
While the custom syscall works : it gets correctly called and prints to dmesg the fair.c file doesn't seem to take into account the changes.
original fair.c
Changes to fair.c :
/*
* move_task - move a task from one runqueue to another runqueue.
* Both runqueues must be locked.
*/
static void move_task(struct task_struct *p, struct lb_env *env)
{
deactivate_task(env->src_rq, p, 0);
if (p->prio_per_cpu)
{
p->rt_priority = p->smp_prio[env->dst_cpu];
printk(KERN_EMERG "We are in move_task function");
}
set_task_cpu(p, env->dst_cpu);
activate_task(env->dst_rq, p, 0);
check_preempt_curr(env->dst_rq, p, 0);
}
p->prio_per_cpu is set to 1 in the syscall, but move_task function doesn't seem to see it.
The syscall :
/* system call to set the new field in
* task struct 'smp_prio' that allows
* one priority per processor on SMP machines
*/
asmlinkage long sys_set_smp_prio(pid_t pid, const char *smp_prio)
{
struct pid *pid_struct;
struct task_struct *p;
pid_struct = find_get_pid(pid);
p = pid_task(pid_struct,PIDTYPE_PID);
p->prio_per_cpu = 1;
p->smp_prio = (char*) smp_prio;
printk(KERN_EMERG "SMP priorities are correctly set \n");
return 1;
}
I get the syscall printk message.
The original task_struct
The modified task_struct :
#define INIT_TASK(tsk) \
{ \
.state = 0, \
.stack = &init_thread_info, \
.usage = ATOMIC_INIT(2), \
.flags = PF_KTHREAD, \
.prio_per_cpu = 0, \
.smp_prio = NULL, \
.prio = MAX_PRIO-20, \
.static_prio = MAX_PRIO-20, \
.normal_prio = MAX_PRIO-20, \
.policy = SCHED_NORMAL, \
.cpus_allowed = CPU_MASK_ALL, \
.nr_cpus_allowed= NR_CPUS, \
.mm = NULL, \
.active_mm = &init_mm, \
.se = { \
.group_node = LIST_HEAD_INIT(tsk.se.group_node), \
}, \
.rt = { \
.run_list = LIST_HEAD_INIT(tsk.rt.run_list), \
.time_slice = RR_TIMESLICE, \
},
[...]
When I modified move_task() to print a message unconditionally it did print that message.
I am sure
move_task
gets called with the task_struct argument of the thread modified by the syscall because I manually force thread migration by setting cpusets (bitmask) and move_task is the very bit of code that performs migration from one cpu to another.
Why aren't the changes done by the custom syscall not effective in the move_task() function ?
Thank you for any help!
I found the solution a long time ago, but just for the record : I am testing this new kernel facilities with real-time threads. They aren't scheduled by the CFS scheduler (fair.c)
The locally defined struct task_struct *p; in this function:
asmlinkage long sys_set_smp_prio(pid_t pid, const char *smp_prio)
{
struct pid *pid_struct;
struct task_struct *p; //THIS COPY OF task_struct *p HAS NO CONNECTION...
pid_struct = find_get_pid(pid);
task = pid_task(pid_struct,PIDTYPE_PID);
p->prio_per_cpu = 1;
p->smp_prio = (char*) smp_prio;
printk(KERN_EMERG "SMP priorities are correctly set \n");
return 1;
}
Has no visible relationship to the argument passed struct task_struct *p (at least in the provided code)
static void move_task(struct task_struct *p, struct lb_env *env) //TO THIS ONE
{
deactivate_task(env->src_rq, p, 0);
if (p->prio_per_cpu) //If this value is zero, printk will never be called.
{
p->rt_priority = p->smp_prio[env->dst_cpu];
printk(KERN_EMERG "We are in move_task function");
}
set_task_cpu(p, env->dst_cpu);
activate_task(env->dst_rq, p, 0);
check_preempt_curr(env->dst_rq, p, 0);
}
That is, I do not see where you are calling move_task() from within sys_set_smp_prio() with its updated value for p->prio_per_cpu = 1;. Could this be the problem?
Related
First off, I am not a programmer, I do electrical engineering. I have done some programming, but would never say that I am a good programmer. This question will probably be downvoted, but that is ok because I have been trying to do this for two months now.
I no nothing about event.h, but I have an existing code that works and uses this. It goes like this (I changed some things to hide information, but the code works):
struct event_base *base;
struct event *read_event;
struct event *signal_event;
typedef struct sample_ctx {
sens_handle_t *sens_handler;
sens_data_t data;
} sample_ctx_t;
// signal handler to break the event loop
void
signal_handler(evutil_socket_t sock, short event, void *user_data)
{
event_base_loopbreak(base);
}
// receive callback
void
sens_recv_cb(evutil_socket_t sock, short event, void *user_data)
{
static int i = 0;
int timeout = 0;
static struct timeval timestamp;
struct timeval timestamp2;
struct timeval diff;
sens_status_t status;
sample_ctx_t *ctx;
ctx = (sample_ctx_t *)user_data;
if (i == 0) {
gettimeofday(×tamp, NULL);
i = 1;
}
status = sens_read(&ctx->data, ctx->sens_handler);
if ((status == SENS_SUCCESS) &&
!isnan(ctx->data.info1) &&
!isnan(ctx->data.info2) &&
!isnan(ctx->data.info3) &&
!isnan(ctx->data.info4)) {
fprintf(stderr, "%lf %lf %lf %lf\n",
ctx->data.info1,
ctx->data.info2,
ctx->data.info3,
ctx->data.info4);
gettimeofday(×tamp, NULL);
} else {
gettimeofday(×tamp2, NULL);
timersub(×tamp2, ×tamp, &diff);
timeout = diff.tv_sec + (diff.tv_usec / 1000000);
}
}
int main()
{
int fd;
status_t status;
sample_ctx_t ctx;
memset(&ctx, 0, sizeof(ctx));
status = sensor_open(&fd, &ctx.gps_handler);
if (status != V2X_SUCCESS) {
fprintf(stderr, "Open failed ... sensor might not be running\n");
goto deinit_4;
}
base = event_base_new();
if (!base) {
fprintf(stderr, "Failed to create event base\n");
goto deinit_3;
}
// register for the read events
read_event = event_new(base, fd, EV_PERSIST|EV_READ, sens_recv_cb, &ctx);
if (!read_event) {
fprintf(stderr, "Failed to create read event\n");
goto deinit_2;
}
// register for the SIGINT signal on ctrl + c key combo
signal_event = evsignal_new(base, SIGINT, signal_handler, NULL);
if (!signal_event) {
fprintf(stderr, "Failed to create signal event\n");
goto deinit_1;
}
event_add(read_event, NULL);
evsignal_add(signal_event, NULL);
event_base_dispatch(base);
evsignal_del(signal_event);
deinit_1:
event_free(read_event);
deinit_2:
event_base_free(base);
deinit_3:
sensor_close(ctx.sens_handler);
deinit_4:
return 0;
}
This code retrieves data from a sensor and prints it to the screen. It's purpose is pretty simple, but the way it has to be done is what is complicated; for me at least.
Ok, so in the sens_recv_cb function, the ctx->data is printed to the screen, but I need to access that in the main function. The only time this function is called is in the event_new function in main. Is there a way get that data in main? Like lets say I just want to print ctx->data.info1 in main while still printing out everything from before in the sens_recv_cb function.
Is what I want to do possible without changing the entire code?
Because main and sens_recv_cb are asynchronous, you'll need a way to signal between them and a way for the call-back to store the data. You can combine both with a linked list:
struct node {
sample_ctx_t data;
struct node *next;
struct node *previous;
}
struct node *head = NULL;
struct node *tail = NULL;
The event handler adds to the head of the list and the main function removes them from the tail. It's a FIFO. You'll need to use atomic operations when reading/writing data to the list. The links provide what you need to know, and if you search, you'll find lots of example code around here and at other sites. You can probably find an open source, thread-safe linked list implementation on GitHub.
Basically, when the list is empty, there's nothing for main to consume.
mon_param is allocated memory by the main process invoking the thread function.
This function will be invoked by multiple threads.So, can I safely assume that it is thread safe as I am using only the variables on the stack?
struct table* get_row_of_machine(int row_num,struct mon_agent *mon_param)
{
struct table *table_row = mon_param->s_table_rows;
if(row_num < mon_param->total_states)
{
table_row = table_row + row_num;
}
return table_row;
}
//in the main function code goes like this ....
int main()
{
int msg_type,ret;
while(!s_interrupted)
{
inter_thread_pair = zsock_new(ZMQ_PAIR);
if(inter_thread_pair != NULL)
zsock_bind (inter_thread_pair, "inproc://zmq_main_pair");
int ret_val = zmq_poll(&socket_items[0], 1, 0); // Do not POLL indefinitely.
if(socket_items[0].revents & ZMQ_POLLIN)
{
char *msg = zstr_recv (inter_thread_pair); //
if(msg != NULL)
{
struct mon_agent *mon_params;
//This is where mon_params is getting its memory
mon_params = (struct mon_agent*)malloc(sizeof(struct mon_agent));
msg_type = get_msg_type(msg);
if(msg_type == /*will check for some message type here*/)
{
struct thread_sock_params *thd_sock = create_connect_pair_socket(thread_count);
// copy the contents of thread_sock_params and also the mon_params to this struct
struct thread_parameters parameters;
parameters.sock_params = thd_sock;
parameters.params = mon_params; //mon_params getting copid here.
//Every time I receive a particular message, I create a new thread and pass on the parameters.
//So, each thread gets its own mon_params memory allocated.
ret = pthread_create(&thread,NULL,monitoring_thread,(void*)¶meters);
and then it goes on like this.
}
}
}
and the code continues..... there is a breakpoint somewhere down..
}
}
void* mon_thread(void *data)
{
// First time data is sent as a function parameter and later will be received as messages.
struct thread_parameters *th_param = (struct thread_parameters *)data;
struct mon_agent *mon_params = th_param->params;
zsock_t* thread_pair_client = zsock_new(ZMQ_PAIR);
//printf("Value of socket is %s: \n",th_param->socket_ep);
rc = zsock_connect(thread_pair_client,th_param->sock_params->socket_ep);
if(rc == -1)
{
printf("zmq_connect failed in monitoring thread.\n");
}
while(!s_interrupted)
{
int row;
//logic to maintain the curent row.
//also receive other messages from thread_pair_client czmq socket.
run_machine(row,mon_params);
}
}
void run_machine(int row_num, struct mon_agent *mon_params)
{
struct table* table_row = get_row_of_state_machine(row_num,mon_param);
}
In short, no.
The way to make parameters thread safe is by design.
There is no fool proof way to do this or a rule of thumb. If you know your codes design well enough and you know no other thread will access the same struct then it's possibly thread safe.
If you do know some other thread might try to access the struct you can use all sorts of synchronization primitives like mutexes, critical sections, semaphores or more generally locks.
I try to use the DMAengine API from a custom kernel driver to perform a scatter-gather operation. I have a contiguous memory region as source and I want to copy its data in several distributed buffers through a scatterlist structure. The DMA controller is the PL330 one that supports the DMAengine API (see PL330 DMA controller).
My test code is the following:
In my driver header file (test_driver.h):
#ifndef __TEST_DRIVER_H__
#define __TEST_DRIVER_H__
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/of_dma.h>
#define SG_ENTRIES 3
#define BUF_SIZE 16
#define DEV_BUF 0x10000000
struct dma_block {
void * data;
int size;
};
struct dma_private_info {
struct sg_table sgt;
struct dma_block * blocks;
int nblocks;
int dma_started;
struct dma_chan * dma_chan;
struct dma_slave_config dma_config;
struct dma_async_tx_descriptor * dma_desc;
dma_cookie_t cookie;
};
struct test_platform_device {
struct platform_device * pdev;
struct dma_private_info dma_priv;
};
#define _get_devp(tdev) (&((tdev)->pdev->dev))
#define _get_dmapip(tdev) (&((tdev)->dma_priv))
int dma_stop(struct test_platform_device * tdev);
int dma_start(struct test_platform_device * tdev);
int dma_start_block(struct test_platform_device * tdev);
int dma_init(struct test_platform_device * tdev);
int dma_exit(struct test_platform_device * tdev);
#endif
In my source that contains the dma functions (dma_functions.c):
#include <linux/slab.h>
#include "test_driver.h"
#define BARE_RAM_BASE 0x10000000
#define BARE_RAM_SIZE 0x10000000
struct ram_bare {
uint32_t * __iomem map;
uint32_t base;
uint32_t size;
};
static void dma_sg_check(struct test_platform_device * tdev)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
uint32_t * buf;
unsigned int bufsize;
int nwords;
int nbytes_word = sizeof(uint32_t);
int nblocks;
struct ram_bare ramb;
uint32_t * p;
int i;
int j;
ramb.map = ioremap(BARE_RAM_BASE,BARE_RAM_SIZE);
ramb.base = BARE_RAM_BASE;
ramb.size = BARE_RAM_SIZE;
dev_info(dev,"nblocks: %d \n",dma_priv->nblocks);
p = ramb.map;
nblocks = dma_priv->nblocks;
for( i = 0 ; i < nblocks ; i++ ) {
buf = (uint32_t *) dma_priv->blocks[i].data;
bufsize = dma_priv->blocks[i].size;
nwords = dma_priv->blocks[i].size/nbytes_word;
dev_info(dev,"block[%d],size %d: ",i,bufsize);
for ( j = 0 ; j < nwords; j++, p++) {
dev_info(dev,"DMA: 0x%x, RAM: 0x%x",buf[j],ioread32(p));
}
}
iounmap(ramb.map);
}
static int dma_sg_exit(struct test_platform_device * tdev)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
int ret = 0;
int i;
for( i = 0 ; i < dma_priv->nblocks ; i++ ) {
kfree(dma_priv->blocks[i].data);
}
kfree(dma_priv->blocks);
sg_free_table(&(dma_priv->sgt));
return ret;
}
int dma_stop(struct test_platform_device * tdev)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
int ret = 0;
dma_unmap_sg(dev,dma_priv->sgt.sgl,\
dma_priv->sgt.nents, DMA_FROM_DEVICE);
dma_sg_exit(tdev);
dma_priv->dma_started = 0;
return ret;
}
static void dma_callback(void * param)
{
enum dma_status dma_stat;
struct test_platform_device * tdev = (struct test_platform_device *) param;
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
dev_info(dev,"Checking the DMA state....\n");
dma_stat = dma_async_is_tx_complete(dma_priv->dma_chan,\
dma_priv->cookie, NULL, NULL);
if(dma_stat == DMA_COMPLETE) {
dev_info(dev,"DMA complete! \n");
dma_sg_check(tdev);
dma_stop(tdev);
} else if (unlikely(dma_stat == DMA_ERROR)) {
dev_info(dev,"DMA error! \n");
dma_stop(tdev);
}
}
static void dma_busy_loop(struct test_platform_device * tdev)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
enum dma_status status;
int status_change = -1;
do {
status = dma_async_is_tx_complete(dma_priv->dma_chan, dma_priv->cookie, NULL, NULL);
switch(status) {
case DMA_COMPLETE:
if(status_change != 0)
dev_info(dev,"DMA status: COMPLETE\n");
status_change = 0;
break;
case DMA_PAUSED:
if (status_change != 1)
dev_info(dev,"DMA status: PAUSED\n");
status_change = 1;
break;
case DMA_IN_PROGRESS:
if(status_change != 2)
dev_info(dev,"DMA status: IN PROGRESS\n");
status_change = 2;
break;
case DMA_ERROR:
if (status_change != 3)
dev_info(dev,"DMA status: ERROR\n");
status_change = 3;
break;
default:
dev_info(dev,"DMA status: UNKNOWN\n");
status_change = -1;
break;
}
} while(status != DMA_COMPLETE);
dev_info(dev,"DMA transaction completed! \n");
}
static int dma_sg_init(struct test_platform_device * tdev)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct scatterlist *sg;
int ret = 0;
int i;
ret = sg_alloc_table(&(dma_priv->sgt), SG_ENTRIES, GFP_ATOMIC);
if(ret)
goto out_mem2;
dma_priv->nblocks = SG_ENTRIES;
dma_priv->blocks = (struct dma_block *) kmalloc(dma_priv->nblocks\
*sizeof(struct dma_block), GFP_ATOMIC);
if(dma_priv->blocks == NULL)
goto out_mem1;
for( i = 0 ; i < dma_priv->nblocks ; i++ ) {
dma_priv->blocks[i].size = BUF_SIZE;
dma_priv->blocks[i].data = kmalloc(dma_priv->blocks[i].size, GFP_ATOMIC);
if(dma_priv->blocks[i].data == NULL)
goto out_mem3;
}
for_each_sg(dma_priv->sgt.sgl, sg, dma_priv->sgt.nents, i)
sg_set_buf(sg,dma_priv->blocks[i].data,dma_priv->blocks[i].size);
return ret;
out_mem3:
i--;
while(i >= 0)
kfree(dma_priv->blocks[i].data);
kfree(dma_priv->blocks);
out_mem2:
sg_free_table(&(dma_priv->sgt));
out_mem1:
ret = -ENOMEM;
return ret;
}
static int _dma_start(struct test_platform_device * tdev,int block)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
int ret = 0;
int sglen;
/* Step 1: Allocate and initialize the SG list */
dma_sg_init(tdev);
/* Step 2: Map the SG list */
sglen = dma_map_sg(dev,dma_priv->sgt.sgl,\
dma_priv->sgt.nents, DMA_FROM_DEVICE);
if(! sglen)
goto out2;
/* Step 3: Configure the DMA */
(dma_priv->dma_config).direction = DMA_DEV_TO_MEM;
(dma_priv->dma_config).src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
(dma_priv->dma_config).src_maxburst = 1;
(dma_priv->dma_config).src_addr = (dma_addr_t) DEV_BUF;
dmaengine_slave_config(dma_priv->dma_chan, \
&(dma_priv->dma_config));
/* Step 4: Prepare the SG descriptor */
dma_priv->dma_desc = dmaengine_prep_slave_sg(dma_priv->dma_chan, \
dma_priv->sgt.sgl, dma_priv->sgt.nents, DMA_DEV_TO_MEM, \
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (dma_priv->dma_desc == NULL) {
dev_err(dev,"DMA could not assign a descriptor! \n");
goto out1;
}
/* Step 5: Set the callback method */
(dma_priv->dma_desc)->callback = dma_callback;
(dma_priv->dma_desc)->callback_param = (void *) tdev;
/* Step 6: Put the DMA descriptor in the queue */
dma_priv->cookie = dmaengine_submit(dma_priv->dma_desc);
/* Step 7: Fires the DMA transaction */
dma_async_issue_pending(dma_priv->dma_chan);
dma_priv->dma_started = 1;
if(block)
dma_busy_loop(tdev);
return ret;
out1:
dma_stop(tdev);
out2:
ret = -1;
return ret;
}
int dma_start(struct test_platform_device * tdev) {
return _dma_start(tdev,0);
}
int dma_start_block(struct test_platform_device * tdev) {
return _dma_start(tdev,1);
}
int dma_init(struct test_platform_device * tdev)
{
int ret = 0;
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
dma_priv->dma_chan = dma_request_slave_channel(dev, \
"dma_chan0");
if (dma_priv->dma_chan == NULL) {
dev_err(dev,"DMA channel busy! \n");
ret = -1;
}
dma_priv->dma_started = 0;
return ret;
}
int dma_exit(struct test_platform_device * tdev)
{
int ret = 0;
struct dma_private_info * dma_priv = _get_dmapip(tdev);
if(dma_priv->dma_started) {
dmaengine_terminate_all(dma_priv->dma_chan);
dma_stop(tdev);
dma_priv->dma_started = 0;
}
if(dma_priv->dma_chan != NULL)
dma_release_channel(dma_priv->dma_chan);
return ret;
}
In my driver source file (test_driver.c):
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include "test_driver.h"
static int dma_block=0;
module_param_named(dma_block, dma_block, int, 0444);
static struct test_platform_device tdev;
static struct of_device_id test_of_match[] = {
{ .compatible = "custom,test-driver-1.0", },
{}
};
static int test_probe(struct platform_device *op)
{
int ret = 0;
struct device * dev = &(op->dev);
const struct of_device_id *match = of_match_device(test_of_match, &op->dev);
if (!match)
return -EINVAL;
tdev.pdev = op;
dma_init(&tdev);
if(dma_block)
ret = dma_start_block(&tdev);
else
ret = dma_start(&tdev);
if(ret) {
dev_err(dev,"Error to start DMA transaction! \n");
} else {
dev_info(dev,"DMA OK! \n");
}
return ret;
}
static int test_remove(struct platform_device *op)
{
dma_exit(&tdev);
return 0;
}
static struct platform_driver test_platform_driver = {
.probe = test_probe,
.remove = test_remove,
.driver = {
.name = "test-driver",
.owner = THIS_MODULE,
.of_match_table = test_of_match,
},
};
static int test_init(void)
{
platform_driver_register(&test_platform_driver);
return 0;
}
static void test_exit(void)
{
platform_driver_unregister(&test_platform_driver);
}
module_init(test_init);
module_exit(test_exit);
MODULE_AUTHOR("klyone");
MODULE_DESCRIPTION("DMA SG test module");
MODULE_LICENSE("GPL");
However, the DMA never calls my callback function and I do not have any idea why it happens. Maybe, I am misunderstanding something...
Could anyone help me?
Thanks in advance.
Caveat: I don't have a definitive solution for you, but merely some observations and suggestions on how to debug this [based on many years of experience writing/debugging linux device drivers].
I presume you believe the callback is not being done because you don't get any printk messages. But, the callback is the only place that has them. But, is the printk level set high enough to see the messages? I'd add a dev_info to your module init, to prove it prints as expected.
Also, you [probably] won't get a callback if dma_start doesn't work as expected, so I'd add some dev_info calls there, too (e.g. before and after the call in step 7). I also notice that not all calls in dma_start check error returns [may be fine or void return, just mentioning in case you missed one]
At this point, it should be noted that there are really two questions here: (1) Did your DMA request start successfully [and complete]? (2) Did you get a callback?
So, I'd split off some code from dma_complete into (e.g.) dma_test_done. The latter does the same checking but only prints the "complete" message. You can call this in a poll mode to verify DMA completion.
So, if you [eventually] get a completion, then the problem reduces to why you didn't get the callback. If, however, you don't [even] get a completion, that's an even more fundamental problem.
This reminds me. You didn't show any code that calls dma_start or how you wait for the completion. I presume that if your callback were working, it would issue a wakeup of some sort that the base level would wait on. Or, the callback would do the request deallocate/cleanup (i.e. more code you'd write)
At step 7, you're calling dma_async_issue_pending, which should call pl330_issue_pending. pl330_issue_pending will call pl330_tasklet.
pl330_tasklet is a tasklet function, but it can also be called directly [to kick off DMA when there are no active requests].
pl330_tasklet will loop on its "work" queue and move any completed items to its "completed" queue. It then tries to start new requests. It then loops on its completed queue and issues the callbacks.
pl330_tasklet grabs the callback pointer, but if it's null it is silently ignored. You've set a callback, but it might be good to verify that where you set the callback is the same place [or propagates to] the place where pl330_tasklet will fetch it from.
When you make the call, everything may be busy, so there are no completed requests, no room to start a new request, so nothing to complete. In that case, pl330_tasklet will be called again later.
So, when dma_async_issue_pending returns, nothing may have happened yet. This is quite probable for your case.
pl330_tasklet tries to start new DMA by calling fill_queue. It will check that a descriptor is not [already] busy by looking at status != BUSY. So, you may wish to verify that yours has the correct value. Otherwise, you'd never get a callback [or even any DMA start].
Then, fill_queue will try to start the request via pl330_submit_req. But, that can return an error (e.g. queue already full), so, again, things are deferred.
For reference, notice the following comment at the top of pl330_submit_req:
Submit a list of xfers after which the client wants notification.
Client is not notified after each xfer unit, just once after all
xfer units are done or some error occurs.
What I'd do is start hacking up pl330.c and add debug messages and cross-checking. If your system is such that pl330 is servicing many other requests, you might limit the debug messages by checking that the device's private data pointer matches yours.
In particular, you'd like to get a message when your request actually gets started, so you could add a debug message to the end of pl330_submit_req
Then, adding messages within pl330_tasklet for requests will help, too.
Those are two good starting points. But, don't be afraid to add more printk calls as needed. You may be surprised by what gets called [or doesn't get called] or in what order.
UPDATE:
If I install the kernel module with the blocking behaviour, everything is initialized well. However, the dma_busy_loop function shows that the DMA descriptor is always IN PROGESS and the DMA transaction never completes. For this reason, the callback function is not executed. What could be happening?
Did a little more research. Cookies are just sequence numbers that increment. For example, if you issue a request that gets broken up into [say] 10 separate scatter/gather operations [descriptors], each one gets a unique cookie value. The cookie return value is the latest/last of the bunch (e.g. 10).
When you're calling (1) dma_async_is_tx_complete, (2) it calls chan->device->device_tx_status, (3) which is pl330_tx_status, (4) which calls dma_cookie_status
Side note/tip: When I was tracking this down, I just kept flipping back and forth between dmaengine.h and pl330.c. It was like: Look at (1), it calls (2). Where is that set? In pl330.c, I presume. So, I grepped for the string and got the name of pl330's function (i.e. (3)). So, I go there, and see that it does (4). So ... Back to dmaengine.h ...
However, when you make the outer call, you're ignoring [setting to NULL] the last two arguments. These can be useful because they return the "last" and "used" cookies. So, even if you don't get full completion, these values could change and show partial progress.
One of them should eventually be >= to the "return" cookie value. (i.e.) The entire operation should be complete. So, this will help differentiate what may be happening.
Also, note that in dmaengine.h, right below dma_async_is_tx_complete, there is dma_async_is_complete. This function is what decides whether to return DMA_COMPLETE or DMA_IN_PROGRESS, based on the cookie value you pass and the "last" and "used" cookie values. It's passive, and not used in the code path [AFAICT], but it does show how to calculate completion yourself.
I am reasonably new to sysfs with respect to driver development and I seem to be observing some rather odd behavior. To make a long story short, it seems that the kernel is not passing back complete structs to my callback. This driver is a rather simple SPI-ADC driver that is being used to read analog thermal / voltage data.
Now, I have a hard time believing that I just found a bug in the Linux kernel in such a widely-used subsystem. I have scoured the internet for anything that might help, but all signs indicate that this should work as is. Other passed structures seem to be populated correctly, it is only the attr->attr member that appears to be NULL.
I should also mention that this is against the 3.2 kernel.
So, in short, what would causes sysfs callbacks to not receive a fully populated kobj_attribute struct?
Sample Code:
static ssize_t ads7960_sysfs_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
int var, rc, i = 0, j = 0;
long channel = 0;
//DEBUG
printk("%s: kobj->name = %s\n", __func__, kobj->name);
printk("%s: attr = %p\n", __func__, attr);
printk("%s: attr->attr = %p\n", __func__, attr->attr);
printk("%s: attr->attr.name = %s\n", __func__, attr->attr.name);
printk("%s: attr->attr.mode = %o\n", __func__, attr->attr.mode);
/* check for silly things */
if ((attr->attr.name == NULL) || (strlen(attr->attr.name) < 1)) {
printk("%s: invalid channel number. = %s\n", __func__, attr->attr.name);
return -EINVAL;
}
... snip (We never get past here) ...
static struct kobj_attribute ads7960_ch0 = __ATTR(0, 0444, ads7960_sysfs_show, NULL);
static struct kobj_attribute ads7960_ch1 = __ATTR(1, 0444, ads7960_sysfs_show, NULL);
static struct kobj_attribute ads7960_ch2 = __ATTR(2, 0444, ads7960_sysfs_show, NULL);
... snip (there are 12 total ADC channels in the same format) ...
static struct attribute *ch_attrs[] = {
&ads7960_ch0.attr,
&ads7960_ch1.attr,
&ads7960_ch2.attr,
... snip (same 12 channels as above)...
NULL,
};
static struct attribute_group attr_group = {
.attrs = ch_attrs,
};
static struct attribute_group *attr_group_ptr = &attr_group;
... snip ...
static struct spi_driver ads7960_driver = {
.driver = {
.name = "ads7960",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.groups = &attr_group_ptr,
},
.probe = ads7960_probe,
.remove = __devexit_p(ads7960_remove),
.id_table = ads7960_id,
};
... snip ...
Output Produced:
[root#172.17.152.42: ]# cat /sys/bus/spi/drivers/ads7960/4
[ 65.344789] ads7960_sysfs_show: kobj->name = ads7960
[ 65.350026] ads7960_sysfs_show: attr = dc934000
[ 65.354859] ads7960_sysfs_show: attr->attr = (null)
[ 65.360155] ads7960_sysfs_show: attr->attr.name = (null)
[ 65.365746] ads7960_sysfs_show: attr->attr.mode = 0
[ 65.370861] ads7960_sysfs_show: invalid channel number. = (null)
cat: read error: Invalid argument
References
http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/samples/kobject/kobject-example.c
http://kroah.com/log/blog/2013/06/26/how-to-create-a-sysfs-file-correctly/
Edit 1:
To summarize the comments below, I manually called sysfs_create_group from my _init and the kobj_attribute struct passed to the callback appeared to be correctly populated. The callback now works without issue (or modification, for that matter). As was stated below, spi_register_driver just calls sysfs_create_group. So, why would one invoke the callback properly while the other does not?
Per comments below, below is the complete _init function and spi_driver structure. The test that I did to manually create the paths myself was based off the _init code in the first reference with almost no modification.
static struct spi_driver ads7960_driver = {
.driver = {
.name = "ads7960",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.groups = attr_groups,
},
.probe = ads7960_probe,
.remove = __devexit_p(ads7960_remove),
.id_table = ads7960_id,
};
static int __init ads7960_init(void)
{
return spi_register_driver(&ads7960_driver);
}
module_init(ads7960_init);
The .groups member of struct device_driver must point to a NULL-terminated list of pointers to attribute groups, not to a single pointer to an attribute group. So, instead of attr_group_ptr, you need:
static struct attribute_group *attr_groups[] = { &attr_group, NULL };
...and then
static struct spi_driver ads7960_driver = {
.driver = {
.name = "ads7960",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.groups = attr_groups,
},
However, there's a helper macro to declare both the attribute group and list of attribute groups that you can use instead:
static struct attribute *ch_attrs[] = {
&ads7960_ch0.attr,
&ads7960_ch1.attr,
&ads7960_ch2.attr,
/* ... */
NULL,
};
ATTRIBUTE_GROUPS(ch); /* declares ch_group and ch_groups */
static struct spi_driver ads7960_driver = {
.driver = {
.name = "ads7960",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.groups = ch_groups,
},
I have been trying to write a new system call(called sys_defclose) in the raspberry's kernel, but upon compiling i get this error:
arch/arm/kernel/built-in.o: In function `__sys_trace_return':
:(.text+0xd50): undefined reference to `sys_defclose'
i have modified the following file:
-include/linux/syscalls.h : where i put the prototype of my syscall
-arch/arm/include/asm/unistd.h : where i put the new raw of the syscall table:
#define __NR_sys_defclose (__NR_SYSCALL_BASE+380)
-arch/arm/kernel/calls.S : where i put:
CALL(sys_defclose)
-i put the source of sys_defclose in arch/arm/kernel and i have modified the makefile in the same directory with the new line
obj-y +=sys_defclose.o
the kernel version is 3.6 of raspberrypi.
can somebody explain me how to solve this error?
thanks
this is the implementation of my syscall
static struct task_struct* get_task_by_pid(pid_t pid)
{
return pid_task(find_pid_ns(pid, task_active_pid_ns(current)), PIDTYPE_PID);
}
static void close_files(struct files_struct * files)
{
int i, j;
struct fdtable *fdt;
j = 0;
rcu_read_lock();
fdt = files_fdtable(files);
rcu_read_unlock();
for (;;) {
unsigned long set;
i = j * BITS_PER_LONG;
if (i >= fdt->max_fds)
break;
set = fdt->open_fds[j++];
while (set) {
if (set & 1) {
struct file * file = xchg(&fdt->fd[i], NULL);
if (file) {
filp_close(file, files);
cond_resched();
}
}
i++;
set >>= 1;
}
}
}
asmlinkage long sys_defclose(pid_t pid)
{
struct task_struct *result = NULL;
rcu_read_lock();
result = get_task_by_pid(pid);
rcu_read_unlock();
close_files(result->files);
}
You should use SYSCALL_DEFINE* to define syscall (I think, this step you did wrong), then add your syscall into sys_call_table, which is architecture-dependent (arch/arm/kernel/calls.S for arm).
Change your sys_defclose to look like this:
SYSCALL_DEFINE1(defclose, pid_t, pid)
{
struct task_struct *result = NULL;
rcu_read_lock();
result = get_task_by_pid(pid);
rcu_read_unlock();
close_files(result->files);
}