blob: 4f8b24d8106f9bb4a0f663dfe3441b339513e538 [file] [log] [blame]
Zev Weiss309c0b12022-02-25 01:44:12 +00001/*
2// Copyright (c) 2022 Equinix, Inc.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#pragma once
18
19#include <cstdint>
20#include <functional>
21#include <map>
22#include <optional>
23#include <utility>
24
25extern "C"
26{
27// For I2C_SMBUS_BLOCK_MAX
28#include <linux/i2c.h>
29}
30
31// A function to read up to I2C_SMBUS_BLOCK_MAX bytes of FRU data. Returns
32// negative on error, or the number of bytes read otherwise, which may be (but
33// is not guaranteed to be) less than len if the read would go beyond the end
34// of the FRU.
35using ReadBlockFunc =
36 std::function<int64_t(off_t offset, size_t len, uint8_t* outbuf)>;
37
Zev Weiss3f86ca32022-03-21 22:39:12 +000038class BaseFRUReader
Zev Weiss309c0b12022-02-25 01:44:12 +000039{
40 public:
Zev Weiss309c0b12022-02-25 01:44:12 +000041 // The ::read() operation here is analogous to ReadBlockFunc (with the same
42 // return value semantics), but is not subject to SMBus block size
43 // limitations; it can read as much data as needed in a single call.
Zev Weiss3f86ca32022-03-21 22:39:12 +000044 virtual ssize_t read(off_t start, size_t len, uint8_t* outbuf) = 0;
45 virtual ~BaseFRUReader() = default;
46};
47
48// A caching wrapper around a ReadBlockFunc
49class FRUReader : public BaseFRUReader
50{
51 public:
52 explicit FRUReader(ReadBlockFunc readFunc) :
53 readFunc(std::move(readFunc)), eof(std::nullopt)
54 {}
55
56 ssize_t read(off_t start, size_t len, uint8_t* outbuf) override;
Zev Weiss309c0b12022-02-25 01:44:12 +000057
58 private:
59 static constexpr size_t cacheBlockSize = 32;
60 static_assert(cacheBlockSize <= I2C_SMBUS_BLOCK_MAX);
61 using CacheBlock = std::array<uint8_t, cacheBlockSize>;
62
63 // indexed by block number (byte number / block size)
Zev Weiss3f86ca32022-03-21 22:39:12 +000064 using Cache = std::unordered_map<size_t, CacheBlock>;
Zev Weiss309c0b12022-02-25 01:44:12 +000065
66 ReadBlockFunc readFunc;
67 Cache cache;
68
69 // byte offset of the end of the FRU (if readFunc has reported it)
70 std::optional<size_t> eof;
71};
Zev Weiss3f86ca32022-03-21 22:39:12 +000072
73// wraps an existing BaseFRUReader and applies a fixed offset to all reads
74class OffsetFRUReader : public BaseFRUReader
75{
76 public:
77 OffsetFRUReader(BaseFRUReader& inner, off_t offset) :
78 inner(inner), offset(offset)
79 {}
80
81 ssize_t read(off_t start, size_t len, uint8_t* outbuf) override;
82
83 private:
84 BaseFRUReader& inner;
85 off_t offset;
86};