Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Michael Walle | 672 | 91.68% | 2 | 33.33% |
Miquel Raynal | 41 | 5.59% | 2 | 33.33% |
Rafał Miłecki | 19 | 2.59% | 1 | 16.67% |
Tom Rix | 1 | 0.14% | 1 | 16.67% |
Total | 733 | 6 |
// SPDX-License-Identifier: GPL-2.0 #include <linux/crc8.h> #include <linux/etherdevice.h> #include <linux/nvmem-consumer.h> #include <linux/nvmem-provider.h> #include <linux/of.h> #include <uapi/linux/if_ether.h> #define SL28VPD_MAGIC 'V' struct sl28vpd_header { u8 magic; u8 version; } __packed; struct sl28vpd_v1 { struct sl28vpd_header header; char serial_number[15]; u8 base_mac_address[ETH_ALEN]; u8 crc8; } __packed; static int sl28vpd_mac_address_pp(void *priv, const char *id, int index, unsigned int offset, void *buf, size_t bytes) { if (bytes != ETH_ALEN) return -EINVAL; if (index < 0) return -EINVAL; if (!is_valid_ether_addr(buf)) return -EINVAL; eth_addr_add(buf, index); return 0; } static const struct nvmem_cell_info sl28vpd_v1_entries[] = { { .name = "serial-number", .offset = offsetof(struct sl28vpd_v1, serial_number), .bytes = sizeof_field(struct sl28vpd_v1, serial_number), }, { .name = "base-mac-address", .offset = offsetof(struct sl28vpd_v1, base_mac_address), .bytes = sizeof_field(struct sl28vpd_v1, base_mac_address), .read_post_process = sl28vpd_mac_address_pp, }, }; static int sl28vpd_v1_check_crc(struct device *dev, struct nvmem_device *nvmem) { struct sl28vpd_v1 data_v1; u8 table[CRC8_TABLE_SIZE]; int ret; u8 crc; crc8_populate_msb(table, 0x07); ret = nvmem_device_read(nvmem, 0, sizeof(data_v1), &data_v1); if (ret < 0) return ret; else if (ret != sizeof(data_v1)) return -EIO; crc = crc8(table, (void *)&data_v1, sizeof(data_v1) - 1, 0); if (crc != data_v1.crc8) { dev_err(dev, "Checksum is invalid (got %02x, expected %02x).\n", crc, data_v1.crc8); return -EINVAL; } return 0; } static int sl28vpd_add_cells(struct nvmem_layout *layout) { struct nvmem_device *nvmem = layout->nvmem; struct device *dev = &layout->dev; const struct nvmem_cell_info *pinfo; struct nvmem_cell_info info = {0}; struct device_node *layout_np; struct sl28vpd_header hdr; int ret, i; /* check header */ ret = nvmem_device_read(nvmem, 0, sizeof(hdr), &hdr); if (ret < 0) return ret; else if (ret != sizeof(hdr)) return -EIO; if (hdr.magic != SL28VPD_MAGIC) { dev_err(dev, "Invalid magic value (%02x)\n", hdr.magic); return -EINVAL; } if (hdr.version != 1) { dev_err(dev, "Version %d is unsupported.\n", hdr.version); return -EINVAL; } ret = sl28vpd_v1_check_crc(dev, nvmem); if (ret) return ret; layout_np = of_nvmem_layout_get_container(nvmem); if (!layout_np) return -ENOENT; for (i = 0; i < ARRAY_SIZE(sl28vpd_v1_entries); i++) { pinfo = &sl28vpd_v1_entries[i]; info.name = pinfo->name; info.offset = pinfo->offset; info.bytes = pinfo->bytes; info.read_post_process = pinfo->read_post_process; info.np = of_get_child_by_name(layout_np, pinfo->name); ret = nvmem_add_one_cell(nvmem, &info); if (ret) { of_node_put(layout_np); return ret; } } of_node_put(layout_np); return 0; } static int sl28vpd_probe(struct nvmem_layout *layout) { layout->add_cells = sl28vpd_add_cells; return nvmem_layout_register(layout); } static void sl28vpd_remove(struct nvmem_layout *layout) { nvmem_layout_unregister(layout); } static const struct of_device_id sl28vpd_of_match_table[] = { { .compatible = "kontron,sl28-vpd" }, {}, }; MODULE_DEVICE_TABLE(of, sl28vpd_of_match_table); static struct nvmem_layout_driver sl28vpd_layout = { .driver = { .name = "kontron-sl28vpd-layout", .of_match_table = sl28vpd_of_match_table, }, .probe = sl28vpd_probe, .remove = sl28vpd_remove, }; module_nvmem_layout_driver(sl28vpd_layout); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michael Walle <michael@walle.cc>"); MODULE_DESCRIPTION("NVMEM layout driver for the VPD of Kontron sl28 boards");
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1