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

kernel: use 'enumerate n-th' mezzanine up to current slot scheme to allow…

kernel: use 'enumerate n-th' mezzanine up to current slot scheme to allow bitstreams with different FMCs
parent c99af7b0
......@@ -232,9 +232,10 @@ struct zio_channel;
int ft_read_sw_fifo(struct fmctdc_dev *ft, int channel,
struct zio_channel *chan);
int ft_enable_termination(struct fmctdc_dev *ft, int channel, int enable);
signed long fmc_find_sdb_device_ext(struct sdb_array *tree,
uint64_t vid, uint32_t did, int index,
unsigned long *sz);
signed long fmc_sdb_find_nth_device (struct sdb_array *tree, uint64_t vid,
uint32_t did, int *ordinal,
uint32_t *size );
#endif // __KERNEL__
......
/*
* Some utility functions not supported in the current version of fmc-bus.
*
* Copyright (C) 2012-2013 CERN (www.cern.ch)
* Copyright (C) 2012-2014 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Alessandro Rubini <rubini@gnudd.com>
*
......@@ -18,18 +18,17 @@
#include "fmc-tdc.h"
/* Finds index-th SDB device that matches (vid/did) pair. */
signed long fmc_find_sdb_device_ext(struct sdb_array *tree,
uint64_t vid, uint32_t did, int index,
unsigned long *sz)
typedef int (*sdb_traverse_cb) (uint32_t address, uint32_t size, uint64_t vid, uint32_t did);
static int traverse_sdb_devices(struct sdb_array *tree,
sdb_traverse_cb cb)
{
signed long res = -ENODEV;
union sdb_record *r;
struct sdb_product *p;
struct sdb_component *c;
int i, n = tree->len;
uint64_t last, first;
int ci = 0;
int i, n = tree->len, rv;
uint64_t last, first, vid;
uint32_t did, size;
/* FIXME: what if the first interconnect is not at zero? */
for (i = 0; i < n; i++) {
......@@ -38,26 +37,66 @@ signed long fmc_find_sdb_device_ext(struct sdb_array *tree,
p = &c->product;
if (!IS_ERR(tree->subtree[i]))
res = fmc_find_sdb_device(tree->subtree[i],
vid, did, sz);
/* FIXME: this index SHOULD be recursive, too */
if (ci == index && res >= 0)
return res + tree->baseaddr;
{
rv = traverse_sdb_devices ( tree->subtree[i], cb );
if(rv > 0)
return 1;
}
if (r->empty.record_type != sdb_type_device)
continue;
if (__be64_to_cpu(p->vendor_id) != vid)
continue;
if (__be32_to_cpu(p->device_id) != did)
continue;
/* found */
/* record is a device?*/
last = __be64_to_cpu(c->addr_last);
first = __be64_to_cpu(c->addr_first);
if (sz)
*sz = (typeof(*sz)) (last + 1 - first);
if (ci == index)
return first + tree->baseaddr;
ci++;
vid = __be64_to_cpu(p->vendor_id);
did = __be32_to_cpu(p->device_id);
size = (uint32_t) (last + 1 - first);
if (cb (first + tree->baseaddr, size, vid, did))
return 1;
}
return res;
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;
uint32_t current_address;
uint32_t current_size;
int callback (uint32_t address, uint32_t size, uint64_t vid_, uint32_t did_)
{
if(vid_ == vid && did_ == did)
{
n++;
current_address = address;
current_size = size;
if(!ordinal || n == *ordinal)
{
return 1;
}
}
return 0; /* continue scanning */
}
traverse_sdb_devices (tree, callback);
if (n >= 0)
{
if(size)
*size = current_size;
if(ordinal)
*ordinal = n;
return current_address;
}
return -ENODEV;
}
\ No newline at end of file
......@@ -199,7 +199,8 @@ int ft_probe(struct fmc_device *fmc)
struct fmctdc_dev *ft;
struct device *dev = fmc->hwdev;
char *fwname;
int i, index, ret;
int i, index, ret, ord;
signed long addr;
ft = kzalloc(sizeof(struct fmctdc_dev), GFP_KERNEL);
if (!ft) {
......@@ -269,24 +270,12 @@ int ft_probe(struct fmc_device *fmc)
fmc_show_sdb_tree(fmc);
/* Now use SDB to find the base addresses */
ft->ft_core_base =
fmc_find_sdb_device_ext(fmc->sdb, 0xce42, 0x604, fmc->slot_id,
NULL);
ft->ft_carrier_base =
fmc_find_sdb_device(fmc->sdb, 0xce42, 0x603, NULL);
ft->ft_irq_base =
fmc_find_sdb_device_ext(fmc->sdb, 0xce42, 0x605, fmc->slot_id,
NULL);
/* the 0th onewire controller is the carrier one */
ft->ft_owregs_base =
fmc_find_sdb_device_ext(fmc->sdb, 0xce42, 0x602, fmc->slot_id + 1,
NULL);
ft->ft_buffer_base =
fmc_find_sdb_device_ext(fmc->sdb, 0xce42, 0x601, fmc->slot_id,
NULL);
ord = fmc->slot_id;
ft->ft_core_base = fmc_sdb_find_nth_device(fmc->sdb, 0xce42, 0x604, &ord, NULL);
ft->ft_irq_base = ft->ft_core_base + TDC_MEZZ_EIC_OFFSET;
ft->ft_owregs_base = ft->ft_core_base + TDC_MEZZ_ONEWIRE_OFFSET;
ft->ft_buffer_base = ft->ft_core_base + TDC_MEZZ_MEM_OFFSET;
if (ft_verbose) {
dev_info(dev,
......
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