fmc-match.c 3.09 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * 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 */
16
void *fru_alloc(size_t size)
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
{
	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) {
32
		dev_warn(&fdev->dev, "Driver has no ID: matches all\n");
33 34
		matched = 1;
	} else {
35 36
		if (!fdev->id.manufacturer || !fdev->id.product_name)
			return 0; /* the device has no FRU information */
37
		for (i = 0; i < fdrv->id_table.fru_id_nr; i++, fid++) {
38 39
			if (fid->manufacturer &&
			    strcmp(fid->manufacturer, fdev->id.manufacturer))
40
				continue;
41 42
			if (fid->product_name &&
			    strcmp(fid->product_name, fdev->id.product_name))
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
				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;

60
	/* If we know the eeprom length, try to read it off the device */
61 62 63 64 65 66 67 68 69 70 71 72 73 74
	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;

75 76
	dev_info(fmc->hwdev, "mezzanine %i\n", fmc->slot_id); /* header */

77 78 79
	/* So we have the eeprom: parse the FRU part (if any) */
	h = (void *)fmc->eeprom;
	if (h->format != 1) {
80
		pr_info("      EEPROM has no FRU information\n");
81 82 83
		goto out;
	}
	if (!fru_header_cksum_ok(h)) {
84
		pr_info("      FRU: wrong header checksum\n");
85 86 87 88
		goto out;
	}
	bia = fru_get_board_area(h);
	if (!fru_bia_cksum_ok(bia)) {
89
		pr_info("      FRU: wrong board area checksum\n");
90 91 92 93
		goto out;
	}
	fmc->id.manufacturer = fru_get_board_manufacturer(h);
	fmc->id.product_name = fru_get_product_name(h);
94 95
	pr_info("      Manufacturer: %s\n", fmc->id.manufacturer);
	pr_info("      Product name: %s\n", fmc->id.product_name);
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114

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