1/* 2 * Copyright (C) 2012 CERN (www.cern.ch) 3 * Author: Alessandro Rubini <rubini@gnudd.com> 4 * 5 * Released according to the GNU GPL, version 2 or any later version. 6 * 7 * This work is part of the White Rabbit project, a research effort led 8 * by CERN, the European Institute for Nuclear Research. 9 */ 10#include <linux/kernel.h> 11#include <linux/slab.h> 12#include <linux/fmc.h> 13#include <linux/ipmi-fru.h> 14 15/* The fru parser is both user and kernel capable: it needs alloc */ 16void *fru_alloc(size_t size) 17{ 18 return kzalloc(size, GFP_KERNEL); 19} 20 21/* The actual match function */ 22int fmc_match(struct device *dev, struct device_driver *drv) 23{ 24 struct fmc_driver *fdrv = to_fmc_driver(drv); 25 struct fmc_device *fdev = to_fmc_device(dev); 26 struct fmc_fru_id *fid; 27 int i, matched = 0; 28 29 /* This currently only matches the EEPROM (FRU id) */ 30 fid = fdrv->id_table.fru_id; 31 if (!fid) { 32 dev_warn(&fdev->dev, "Driver has no ID: matches all\n"); 33 matched = 1; 34 } else { 35 if (!fdev->id.manufacturer || !fdev->id.product_name) 36 return 0; /* the device has no FRU information */ 37 for (i = 0; i < fdrv->id_table.fru_id_nr; i++, fid++) { 38 if (fid->manufacturer && 39 strcmp(fid->manufacturer, fdev->id.manufacturer)) 40 continue; 41 if (fid->product_name && 42 strcmp(fid->product_name, fdev->id.product_name)) 43 continue; 44 matched = 1; 45 break; 46 } 47 } 48 49 /* FIXME: match SDB contents */ 50 return matched; 51} 52 53/* This function creates ID info for a newly registered device */ 54int fmc_fill_id_info(struct fmc_device *fmc) 55{ 56 struct fru_common_header *h; 57 struct fru_board_info_area *bia; 58 int ret, allocated = 0; 59 60 /* If we know the eeprom length, try to read it off the device */ 61 if (fmc->eeprom_len && !fmc->eeprom) { 62 fmc->eeprom = kzalloc(fmc->eeprom_len, GFP_KERNEL); 63 if (!fmc->eeprom) 64 return -ENOMEM; 65 allocated = 1; 66 ret = fmc->op->read_ee(fmc, 0, fmc->eeprom, fmc->eeprom_len); 67 if (ret < 0) 68 goto out; 69 } 70 71 /* If no eeprom, continue with other matches */ 72 if (!fmc->eeprom) 73 return 0; 74 75 dev_info(fmc->hwdev, "mezzanine %i\n", fmc->slot_id); /* header */ 76 77 /* So we have the eeprom: parse the FRU part (if any) */ 78 h = (void *)fmc->eeprom; 79 if (h->format != 1) { 80 pr_info(" EEPROM has no FRU information\n"); 81 goto out; 82 } 83 if (!fru_header_cksum_ok(h)) { 84 pr_info(" FRU: wrong header checksum\n"); 85 goto out; 86 } 87 bia = fru_get_board_area(h); 88 if (!fru_bia_cksum_ok(bia)) { 89 pr_info(" FRU: wrong board area checksum\n"); 90 goto out; 91 } 92 fmc->id.manufacturer = fru_get_board_manufacturer(h); 93 fmc->id.product_name = fru_get_product_name(h); 94 pr_info(" Manufacturer: %s\n", fmc->id.manufacturer); 95 pr_info(" Product name: %s\n", fmc->id.product_name); 96 97 /* Create the short name (FIXME: look in sdb as well) */ 98 fmc->mezzanine_name = kstrdup(fmc->id.product_name, GFP_KERNEL); 99 100out: 101 if (allocated) { 102 kfree(fmc->eeprom); 103 fmc->eeprom = NULL; 104 } 105 return 0; /* no error: let other identification work */ 106} 107 108/* Some ID data is allocated using fru_alloc() above, so release it */ 109void fmc_free_id_info(struct fmc_device *fmc) 110{ 111 kfree(fmc->mezzanine_name); 112 kfree(fmc->id.manufacturer); 113 kfree(fmc->id.product_name); 114} 115