You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
3.1 KiB
114 lines
3.1 KiB
/* |
|
* Copyright (C) 2012 CERN (www.cern.ch) |
|
* Author: Alessandro Rubini <rubini@gnudd.com> |
|
* |
|
* Released according to the GNU GPL, version 2 or any later version. |
|
* |
|
* This work is part of the White Rabbit project, a research effort led |
|
* by CERN, the European Institute for Nuclear Research. |
|
*/ |
|
#include <linux/kernel.h> |
|
#include <linux/slab.h> |
|
#include <linux/fmc.h> |
|
#include <linux/ipmi-fru.h> |
|
|
|
/* The fru parser is both user and kernel capable: it needs alloc */ |
|
void *fru_alloc(size_t size) |
|
{ |
|
return kzalloc(size, GFP_KERNEL); |
|
} |
|
|
|
/* The actual match function */ |
|
int fmc_match(struct device *dev, struct device_driver *drv) |
|
{ |
|
struct fmc_driver *fdrv = to_fmc_driver(drv); |
|
struct fmc_device *fdev = to_fmc_device(dev); |
|
struct fmc_fru_id *fid; |
|
int i, matched = 0; |
|
|
|
/* This currently only matches the EEPROM (FRU id) */ |
|
fid = fdrv->id_table.fru_id; |
|
if (!fid) { |
|
dev_warn(&fdev->dev, "Driver has no ID: matches all\n"); |
|
matched = 1; |
|
} else { |
|
if (!fdev->id.manufacturer || !fdev->id.product_name) |
|
return 0; /* the device has no FRU information */ |
|
for (i = 0; i < fdrv->id_table.fru_id_nr; i++, fid++) { |
|
if (fid->manufacturer && |
|
strcmp(fid->manufacturer, fdev->id.manufacturer)) |
|
continue; |
|
if (fid->product_name && |
|
strcmp(fid->product_name, fdev->id.product_name)) |
|
continue; |
|
matched = 1; |
|
break; |
|
} |
|
} |
|
|
|
/* FIXME: match SDB contents */ |
|
return matched; |
|
} |
|
|
|
/* This function creates ID info for a newly registered device */ |
|
int fmc_fill_id_info(struct fmc_device *fmc) |
|
{ |
|
struct fru_common_header *h; |
|
struct fru_board_info_area *bia; |
|
int ret, allocated = 0; |
|
|
|
/* If we know the eeprom length, try to read it off the device */ |
|
if (fmc->eeprom_len && !fmc->eeprom) { |
|
fmc->eeprom = kzalloc(fmc->eeprom_len, GFP_KERNEL); |
|
if (!fmc->eeprom) |
|
return -ENOMEM; |
|
allocated = 1; |
|
ret = fmc->op->read_ee(fmc, 0, fmc->eeprom, fmc->eeprom_len); |
|
if (ret < 0) |
|
goto out; |
|
} |
|
|
|
/* If no eeprom, continue with other matches */ |
|
if (!fmc->eeprom) |
|
return 0; |
|
|
|
dev_info(fmc->hwdev, "mezzanine %i\n", fmc->slot_id); /* header */ |
|
|
|
/* So we have the eeprom: parse the FRU part (if any) */ |
|
h = (void *)fmc->eeprom; |
|
if (h->format != 1) { |
|
pr_info(" EEPROM has no FRU information\n"); |
|
goto out; |
|
} |
|
if (!fru_header_cksum_ok(h)) { |
|
pr_info(" FRU: wrong header checksum\n"); |
|
goto out; |
|
} |
|
bia = fru_get_board_area(h); |
|
if (!fru_bia_cksum_ok(bia)) { |
|
pr_info(" FRU: wrong board area checksum\n"); |
|
goto out; |
|
} |
|
fmc->id.manufacturer = fru_get_board_manufacturer(h); |
|
fmc->id.product_name = fru_get_product_name(h); |
|
pr_info(" Manufacturer: %s\n", fmc->id.manufacturer); |
|
pr_info(" Product name: %s\n", fmc->id.product_name); |
|
|
|
/* Create the short name (FIXME: look in sdb as well) */ |
|
fmc->mezzanine_name = kstrdup(fmc->id.product_name, GFP_KERNEL); |
|
|
|
out: |
|
if (allocated) { |
|
kfree(fmc->eeprom); |
|
fmc->eeprom = NULL; |
|
} |
|
return 0; /* no error: let other identification work */ |
|
} |
|
|
|
/* Some ID data is allocated using fru_alloc() above, so release it */ |
|
void fmc_free_id_info(struct fmc_device *fmc) |
|
{ |
|
kfree(fmc->mezzanine_name); |
|
kfree(fmc->id.manufacturer); |
|
kfree(fmc->id.product_name); |
|
}
|
|
|