123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- /*
- * 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);
- }
|