Commit eb6ded96 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski Committed by Federico Vaga

kernel: fix fmc find device

The usage of on-stack-variable by the callback function was a problem
on some kernels (e.g. 3.6 64bit)

Federico: again I'm including this patch because we have not time to
wait the proper solution that will come on october 2014 (hopefully)
Signed-off-by: Tomasz Wlostowski's avatarTomasz Wlostowski <tomasz.wlostowski@cern.ch>
Acked-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent 9e9c05d3
......@@ -18,10 +18,11 @@
#include "fmc-tdc.h"
typedef int (*sdb_traverse_cb) (uint32_t address, uint32_t size, uint64_t vid, uint32_t did);
typedef int (*sdb_traverse_cb) (uint32_t address, uint32_t size, uint64_t vid, uint32_t did, void *data);
static int traverse_sdb_devices(struct sdb_array *tree,
sdb_traverse_cb cb)
sdb_traverse_cb cb,
void *data)
{
union sdb_record *r;
struct sdb_product *p;
......@@ -38,7 +39,7 @@ static int traverse_sdb_devices(struct sdb_array *tree,
if (!IS_ERR(tree->subtree[i]))
{
rv = traverse_sdb_devices ( tree->subtree[i], cb );
rv = traverse_sdb_devices ( tree->subtree[i], cb, data );
if(rv > 0)
return 1;
}
......@@ -53,49 +54,62 @@ static int traverse_sdb_devices(struct sdb_array *tree,
did = __be32_to_cpu(p->device_id);
size = (uint32_t) (last + 1 - first);
if (cb (first + tree->baseaddr, size, vid, did))
if (cb (first + tree->baseaddr, size, vid, did, data))
return 1;
}
return 0;
}
/* Finds the Nth SDB device that matches (vid/did) pair, where N <= *ordinal.
If N < *ordinal, the value of N is stored at *ordinal.
This magic is used to handle hybrid bistreams (with two or more different
mezzanines). */
signed long fmc_sdb_find_nth_device (struct sdb_array *tree, uint64_t vid, uint32_t did, int *ordinal, uint32_t *size )
{
int n = -1;
struct callback_state {
int n;
int *ordinal;
uint32_t current_address;
uint32_t current_size;
uint64_t did;
uint32_t vid;
};
int callback (uint32_t address, uint32_t size, uint64_t vid_, uint32_t did_)
{
if(vid_ == vid && did_ == did)
static int callback (uint32_t address, uint32_t size, uint64_t vid_, uint32_t did_, void *data)
{
struct callback_state *st = (struct callback_state *) data;
if(vid_ == st->vid && did_ == st->did)
{
n++;
current_address = address;
current_size = size;
st->n++;
st->current_address = address;
st->current_size = size;
if(!ordinal || n == *ordinal)
if(!st->ordinal || st->n == *st->ordinal)
{
return 1;
}
}
return 0; /* continue scanning */
}
}
/* Finds the Nth SDB device that matches (vid/did) pair, where N <= *ordinal.
If N < *ordinal, the value of N is stored at *ordinal.
This magic is used to handle hybrid bistreams (with two or more different
mezzanines). */
signed long fmc_sdb_find_nth_device (struct sdb_array *tree, uint64_t vid, uint32_t did, int *ordinal, uint32_t *size )
{
struct callback_state st;
st.n = -1;
st.ordinal = ordinal;
st.vid = vid;
st.did = did;
traverse_sdb_devices (tree, callback);
traverse_sdb_devices (tree, callback, &st);
if (n >= 0)
if (st.n >= 0)
{
if(size)
*size = current_size;
*size = st.current_size;
if(ordinal)
*ordinal = n;
*ordinal = st.n;
return current_address;
return st.current_address;
}
return -ENODEV;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment