Commit 2a19a588 authored by Federico Vaga's avatar Federico Vaga

sw:drv: review calibration

Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent a7ab2109
# ZIO comes from the Makefile
KBUILD_EXTRA_SYMBOLS := \
$(ZIO_ABS)/Module.symvers \
KBUILD_EXTRA_SYMBOLS += $(ZIO_EXTRA_SYMBOLS-y)
KBUILD_EXTRA_SYMBOLS += $(FMC_EXTRA_SYMBOLS-y)
ccflags-y = -DGIT_VERSION=\"$(GIT_VERSION)\"
ccflags-y += -I$(src)
ccflags-y += -I$(ZIO_ABS)/include
ccflags-y += -I$(FMC_ABS)/include
ccflags-y = -DGIT_VERSION=\"$(GIT_VERSION)\" \
-I$(src) \
-I$(ZIO_ABS)/include \
ccflags-$(CONFIG_FMC_TDC_DEBUG) += -DDEBUG
ccflags-$(CONFIG_FMC_TDC_VERBOSE_DEBUG) += -DVERBOSE_DEBUG
......
......@@ -11,6 +11,10 @@ ZIO ?= ../zio
# ZIO_ABS has to be absolut path, due to beeing
# passed to the Kbuild
ZIO_ABS ?= $(abspath $(ZIO) )
ZIO_EXTRA_SYMBOLS-y = $(ZIO_ABS)/Module.symvers
FMC_ABS ?= $(abspath $(FMC))
FMC_EXTRA_SYMBOLS-y = $(FMC_ABS)/drivers/fmc/Module.symvers
GIT_VERSION = $(shell git describe --always --dirty --long --tags)
export GIT_VERSION
......@@ -24,7 +28,11 @@ CPPCHECK ?= cppcheck
all: modules
modules_install modules:
$(MAKE) -C $(LINUX) M=$(shell /bin/pwd) ZIO_ABS=$(ZIO_ABS) SPEC_SW_ABS=$(SPEC_SW_ABS) $@
$(MAKE) -C $(LINUX) M=$(shell /bin/pwd) \
ZIO_ABS=$(ZIO_ABS) FMC_ABS=$(FMC_ABS) \
ZIO_EXTRA_SYMBOLS-y=$(ZIO_EXTRA_SYMBOLS-y) \
FMC_EXTRA_SYMBOLS-y=$(FMC_EXTRA_SYMBOLS-y) \
SPEC_SW_ABS=$(SPEC_SW_ABS) $@
clean:
$(MAKE) -C $(LINUX) M=$(shell /bin/pwd) $@
......
......@@ -13,10 +13,10 @@
#include <linux/firmware.h>
#include <linux/jhash.h>
#include <linux/slab.h>
#include <linux/fmc.h>
#include <linux/ipmi-fru.h>
#include <linux/zio.h>
#include "libsdbfs.h"
#include "fmc-tdc.h"
#define WR_CALIB_OFFSET 229460
......@@ -40,36 +40,7 @@ static struct ft_calibration default_calibration = {
};
#define WR_OFFSET_FIX_YEAR (2018)
/* sdbfs-related function */
static int ft_read_calibration_eeprom(struct fmc_device *fmc, void *buf,
int length)
{
int i, ret = 0;
static struct sdbfs fs;
fs.data = fmc->eeprom;
fs.datalen = fmc->eeprom_len;
/* Look for sdb entry point */
for (i = 0x40; i < fmc->eeprom_len - 0x40; i += 0x40) {
fs.entrypoint = i;
ret = sdbfs_dev_create(&fs, 0);
if (ret == 0)
break;
}
if (ret)
return ret;
/* Open "cali" as a device id, vendor is "FileData" -- big endian */
ret = sdbfs_open_name(&fs, "calib");
if (ret)
return ret;
ret = sdbfs_fread(&fs, 0, buf, length);
sdbfs_dev_destroy(&fs);
return ret;
}
#define IPMI_FRU_SIZE 256
/**
* HACK area to get the calibration year
......@@ -79,31 +50,37 @@ static u32 __get_ipmi_fru_id_year(struct fmctdc_dev *ft)
struct fru_board_info_area *bia;
struct fru_type_length *tmp;
unsigned long year = 0;
char *buf = NULL;
char year_ascii[5];
void *fru = NULL;
int err, i;
bia = fru_get_board_area((const struct fru_common_header *)ft->fmc->eeprom);
fru = kmalloc(IPMI_FRU_SIZE, GFP_KERNEL);
if (!fru)
goto out_mem;
err = fmc_slot_eeprom_read(ft->slot, fru, 0x0, IPMI_FRU_SIZE);
if (err)
goto out_read;
bia = fru_get_board_area((const struct fru_common_header *)fru);
tmp = bia->tl;
for (i = 0; i < 4; ++i) {
tmp = fru_next_tl(tmp);
if (!tmp)
goto out;
goto out_fru;
}
if (!fru_length(tmp))
goto out;
goto out_fru;
if (fru_type(tmp) != FRU_TYPE_ASCII)
goto out;
buf = kmalloc(fru_length(tmp), GFP_ATOMIC);
if (!buf)
goto out;
buf = fru_strcpy(buf, tmp);
buf[4] = '\0';
err = kstrtoul(buf, 10, &year);
goto out_fru;
memcpy(year_ascii, tmp->data, 4);
year_ascii[4] = '\0';
err = kstrtoul(year_ascii, 10, &year);
if (err)
goto out;
year = 0;
out:
kfree(buf);
out_fru:
out_read:
kfree(fru);
out_mem:
return year;
}
......@@ -164,41 +141,6 @@ static void ft_calib_cpy_to_raw(struct ft_calibration_raw *calib_raw,
ft_calib_cpu_to_le32s(calib_raw);
}
/* This is the only thing called by outside */
int ft_handle_eeprom_calibration(struct fmctdc_dev *ft)
{
struct ft_calibration *calib;
struct ft_calibration_raw calib_raw;
struct device *d = &ft->fmc->dev;
int i;
/* Retrieve and validate the calibration */
calib = &ft->calib;
i = ft_read_calibration_eeprom(ft->fmc, &calib_raw, sizeof(calib_raw));
if (i >= 0) {
u32 year;
ft_calib_cpy_from_raw(calib, &calib_raw);
year = __get_ipmi_fru_id_year(ft);
if (year < WR_OFFSET_FIX_YEAR) {
calib->wr_offset = wr_calibration_offset;
calib->wr_offset += wr_calibration_offset_carrier;
dev_warn(d,
"Apply default calibration correction to White-Rabbit offset if done before 2018 (%d)\n",
year);
}
} else {
dev_err(d,
"Failed to read calibration EEPROM. Using default.\n");
memcpy(calib, &default_calibration, sizeof(*calib));
calib->wr_offset += wr_calibration_offset_carrier;
}
return 0;
}
static ssize_t ft_write_eeprom(struct file *file, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
......@@ -240,3 +182,35 @@ struct bin_attribute dev_attr_calibration = {
.write = ft_write_eeprom,
.read = ft_read_eeprom,
};
#define FT_EEPROM_CALIB_OFFSET 0x100
int ft_calib_init(struct fmctdc_dev *ft)
{
struct ft_calibration_raw calib;
int ret;
ret = fmc_slot_eeprom_read(ft->slot, &calib,
FT_EEPROM_CALIB_OFFSET, sizeof(calib));
if (ret < 0) {
dev_warn(&ft->pdev->dev,
"Failed to read calibration from EEPROM: using identity calibration %d\n",
ret);
memcpy(&calib, &default_calibration, sizeof(calib));
goto out;
}
ft_calib_cpy_from_raw(&ft->calib, &calib);
/* FIX wrong calibration on old FMC-TDC mezzanine */
if (__get_ipmi_fru_id_year(ft) < WR_OFFSET_FIX_YEAR)
ft->calib.wr_offset = wr_calibration_offset;
out:
ft->calib.wr_offset += wr_calibration_offset_carrier;
return 0;
}
void ft_calib_exit(struct fmctdc_dev *ft)
{
}
......@@ -126,6 +126,7 @@ struct ft_calibration_raw {
#include <linux/timer.h>
#include <linux/version.h>
#include <linux/platform_device.h>
#include <linux/fmc.h>
struct ft_memory_ops {
u32 (*read)(void *addr);
......@@ -247,6 +248,7 @@ struct fmctdc_dev {
void *ft_dma_eic_base;
struct ft_memory_ops memops;
/* IRQ base index (for SVEC) */
struct fmc_slot *slot;
struct platform_device *pdev;
struct zio_device *zdev, *hwzdev;
/* carrier private data */
......@@ -307,6 +309,8 @@ static inline void dma_writel(struct fmctdc_dev *ft, uint32_t data, uint32_t reg
}
int ft_calib_init(struct fmctdc_dev *ft);
void ft_calib_exit(struct fmctdc_dev *ft);
void ft_enable_acquisition(struct fmctdc_dev *ft, int enable);
......@@ -327,7 +331,6 @@ void ft_set_host_time(struct fmctdc_dev *ft);
int ft_wr_mode(struct fmctdc_dev *ft, int on);
int ft_wr_query(struct fmctdc_dev *ft);
int ft_handle_eeprom_calibration(struct fmctdc_dev *ft);
extern struct bin_attribute dev_attr_calibration;
int ft_fifo_init(struct fmctdc_dev *ft);
......
......@@ -20,6 +20,8 @@
#include <linux/list.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/ipmi-fru.h>
#include <linux/fmc.h>
#include <linux/zio.h>
#include <linux/zio-trigger.h>
......@@ -40,6 +42,7 @@ static int ft_verbose;
module_param_named(verbose, ft_verbose, int, 0444);
MODULE_PARM_DESC(verbose, "Print a lot of debugging messages.");
#define FT_EEPROM_TYPE "at24c64"
/**
* It sets the coalescing timeout for the DMA buffers
......@@ -639,6 +642,49 @@ static int ft_resource_validation(struct platform_device *pdev)
return 0;
}
#define FT_FMC_NAME "FmcTdc1ns4cha"
static bool ft_fmc_slot_is_valid(struct fmctdc_dev *ft)
{
int ret;
void *fru = NULL;
char *fmc_name = NULL;
if (!fmc_slot_fru_valid(ft->slot)) {
dev_err(&ft->pdev->dev,
"Can't identify FMC card: invalid FRU\n");
return -EINVAL;
}
fru = kmalloc(FRU_SIZE_MAX, GFP_KERNEL);
if (!fru)
return -ENOMEM;
ret = fmc_slot_eeprom_read(ft->slot, fru, 0x0, FRU_SIZE_MAX);
if (ret != FRU_SIZE_MAX) {
dev_err(&ft->pdev->dev, "Failed to read FRU header\n");
goto err;
}
fmc_name = fru_get_product_name(fru);
ret = strcmp(fmc_name, FT_FMC_NAME);
if (ret) {
dev_err(&ft->pdev->dev,
"Invalid FMC card: expectd '%s', found '%s'\n",
FT_FMC_NAME, fmc_name);
goto err;
}
kfree(fmc_name);
kfree(fru);
return true;
err:
kfree(fmc_name);
kfree(fru);
return false;
}
static int ft_endianess(struct fmctdc_dev *ft)
{
switch (ft->pdev->id_entry->driver_data) {
......@@ -682,6 +728,7 @@ int ft_probe(struct platform_device *pdev)
struct resource *r;
int i, ret, err;
uint32_t stat;
uint32_t slot_nr;
err = ft_resource_validation(pdev);
if (err)
......@@ -744,9 +791,38 @@ int ft_probe(struct platform_device *pdev)
ret = ft_reset_core(ft);
if (ret < 0)
return ret;
slot_nr = ft_readl(ft, FT_REG_FMC_SLOT_ID) + 1;
ft->slot = fmc_slot_get(pdev->dev.parent->parent, slot_nr);
if (IS_ERR(ft->slot)) {
dev_err(&ft->pdev->dev,
"Can't find FMC slot %d err: %ld\n",
slot_nr, PTR_ERR(ft->slot));
goto out_fmc;
}
if (!fmc_slot_present(ft->slot)) {
dev_err(&ft->pdev->dev,
"Can't identify FMC card: missing card\n");
goto out_fmc_pre;
}
if (strcmp(fmc_slot_eeprom_type_get(ft->slot), FT_EEPROM_TYPE)) {
dev_warn(&ft->pdev->dev,
"use non standard EERPOM type \"%s\"\n",
FT_EEPROM_TYPE);
ret = fmc_slot_eeprom_type_set(ft->slot, FT_EEPROM_TYPE);
if (ret < 0) {
dev_err(&ft->pdev->dev,
"Failed to change EEPROM type to \"%s\"",
FT_EEPROM_TYPE);
goto out_fmc_eeprom;
}
}
if(!ft_fmc_slot_is_valid(ft))
goto out_fmc_err;
/* Retrieve calibration from the eeprom, and validate */
ret = ft_handle_eeprom_calibration(ft);
ret = ft_calib_init(ft);
if (ret < 0)
goto err_calib;
......@@ -782,7 +858,13 @@ err:
while (--m, --i >= 0)
if (m->exit)
m->exit(ft);
ft_calib_exit(ft);
err_calib:
out_fmc_err:
out_fmc_eeprom:
out_fmc_pre:
fmc_slot_put(ft->slot);
out_fmc:
err_mode_selection:
err_memops:
iounmap(ft->ft_base);
......@@ -817,6 +899,8 @@ int ft_remove(struct platform_device *pdev)
if (m->exit)
m->exit(ft);
}
ft_calib_exit(ft);
fmc_slot_put(ft->slot);
iounmap(ft->ft_base);
iounmap(ft->ft_carrier_base);
kfree(ft);
......
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