Blame view

drivers/fmc/fmc-match.c 3.09 KB
77864f2e0   Alessandro Rubini   FMC: add core bus...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  /*
   * 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
  ");
  		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
  ", 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
  ");
  		goto out;
  	}
  	if (!fru_header_cksum_ok(h)) {
  		pr_info("      FRU: wrong header checksum
  ");
  		goto out;
  	}
  	bia = fru_get_board_area(h);
  	if (!fru_bia_cksum_ok(bia)) {
  		pr_info("      FRU: wrong board area checksum
  ");
  		goto out;
  	}
  	fmc->id.manufacturer = fru_get_board_manufacturer(h);
  	fmc->id.product_name = fru_get_product_name(h);
  	pr_info("      Manufacturer: %s
  ", fmc->id.manufacturer);
  	pr_info("      Product name: %s
  ", 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);
  }