Alessandro Rubini | 77864f2 | 2013-06-18 23:47:13 +0200 | [diff] [blame] | 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 */ |
| 16 | void *fru_alloc(size_t size) |
| 17 | { |
| 18 | return kzalloc(size, GFP_KERNEL); |
| 19 | } |
| 20 | |
| 21 | /* The actual match function */ |
| 22 | int 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 */ |
| 54 | int 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 | |
| 100 | out: |
| 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 */ |
| 109 | void 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 | } |