1ded66d0fSJason Ling /*
2ded66d0fSJason Ling * Copyright 2018 Google Inc.
3ded66d0fSJason Ling *
4ded66d0fSJason Ling * Licensed under the Apache License, Version 2.0 (the "License");
5ded66d0fSJason Ling * you may not use this file except in compliance with the License.
6ded66d0fSJason Ling * You may obtain a copy of the License at
7ded66d0fSJason Ling *
8ded66d0fSJason Ling * http://www.apache.org/licenses/LICENSE-2.0
9ded66d0fSJason Ling *
10ded66d0fSJason Ling * Unless required by applicable law or agreed to in writing, software
11ded66d0fSJason Ling * distributed under the License is distributed on an "AS IS" BASIS,
12ded66d0fSJason Ling * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ded66d0fSJason Ling * See the License for the specific language governing permissions and
14ded66d0fSJason Ling * limitations under the License.
15ded66d0fSJason Ling */
16ded66d0fSJason Ling
17ded66d0fSJason Ling #include "pci_handler.hpp"
18ded66d0fSJason Ling
19ded66d0fSJason Ling #include "data.hpp"
20ded66d0fSJason Ling
21ded66d0fSJason Ling #include <fcntl.h>
22ded66d0fSJason Ling #include <linux/aspeed-p2a-ctrl.h>
23ded66d0fSJason Ling
24ded66d0fSJason Ling #include <cstdint>
25ded66d0fSJason Ling #include <cstring>
26ded66d0fSJason Ling #include <string>
27ded66d0fSJason Ling #include <vector>
28ded66d0fSJason Ling
29ded66d0fSJason Ling namespace ipmi_flash
30ded66d0fSJason Ling {
31ded66d0fSJason Ling
32ded66d0fSJason Ling const std::string PciDataHandler::p2aControlPath = "/dev/aspeed-p2a-ctrl";
33ded66d0fSJason Ling
open()34ded66d0fSJason Ling bool PciDataHandler::open()
35ded66d0fSJason Ling {
36ded66d0fSJason Ling mappedFd = sys->open(p2aControlPath.c_str(), O_RDWR);
37ded66d0fSJason Ling if (mappedFd == -1)
38ded66d0fSJason Ling {
39ded66d0fSJason Ling return false;
40ded66d0fSJason Ling }
41ded66d0fSJason Ling
42ded66d0fSJason Ling struct aspeed_p2a_ctrl_mapping map;
43ded66d0fSJason Ling map.addr = regionAddress;
44ded66d0fSJason Ling map.length = memoryRegionSize;
45ded66d0fSJason Ling map.flags = ASPEED_P2A_CTRL_READWRITE;
46ded66d0fSJason Ling
47ded66d0fSJason Ling if (sys->ioctl(mappedFd, ASPEED_P2A_CTRL_IOCTL_SET_WINDOW, &map))
48ded66d0fSJason Ling {
49ded66d0fSJason Ling sys->close(mappedFd);
50ded66d0fSJason Ling mappedFd = -1;
51ded66d0fSJason Ling
52ded66d0fSJason Ling return false;
53ded66d0fSJason Ling }
54ded66d0fSJason Ling
55ded66d0fSJason Ling if (sys->ioctl(mappedFd, ASPEED_P2A_CTRL_IOCTL_GET_MEMORY_CONFIG, &map))
56ded66d0fSJason Ling {
57ded66d0fSJason Ling sys->close(mappedFd);
58ded66d0fSJason Ling mappedFd = -1;
59ded66d0fSJason Ling
60ded66d0fSJason Ling return false;
61ded66d0fSJason Ling }
62ded66d0fSJason Ling
63ded66d0fSJason Ling /* The length of the region reserved is reported, and it's important
64ded66d0fSJason Ling * because the offset + memory region could be beyond that reserved
65ded66d0fSJason Ling * region.
66ded66d0fSJason Ling */
67ded66d0fSJason Ling std::uint64_t offset = regionAddress - map.addr;
68ded66d0fSJason Ling
69ded66d0fSJason Ling mapped = reinterpret_cast<std::uint8_t*>(
70ded66d0fSJason Ling mmap(0, memoryRegionSize, PROT_READ, MAP_SHARED, mappedFd, offset));
71ded66d0fSJason Ling if (mapped == MAP_FAILED)
72ded66d0fSJason Ling {
73ded66d0fSJason Ling sys->close(mappedFd);
74ded66d0fSJason Ling mappedFd = -1;
75ded66d0fSJason Ling mapped = nullptr;
76ded66d0fSJason Ling
77ded66d0fSJason Ling return false;
78ded66d0fSJason Ling }
79ded66d0fSJason Ling
80ded66d0fSJason Ling return true;
81ded66d0fSJason Ling }
82ded66d0fSJason Ling
close()83ded66d0fSJason Ling bool PciDataHandler::close()
84ded66d0fSJason Ling {
85ded66d0fSJason Ling /* TODO: Turn off the P2A bridge and region to disable host-side access.
86ded66d0fSJason Ling */
87ded66d0fSJason Ling if (mapped)
88ded66d0fSJason Ling {
89ded66d0fSJason Ling sys->munmap(mapped, memoryRegionSize);
90ded66d0fSJason Ling mapped = nullptr;
91ded66d0fSJason Ling }
92ded66d0fSJason Ling
93ded66d0fSJason Ling if (mappedFd != -1)
94ded66d0fSJason Ling {
95ded66d0fSJason Ling sys->close(mappedFd);
96ded66d0fSJason Ling mappedFd = -1;
97ded66d0fSJason Ling }
98ded66d0fSJason Ling
99ded66d0fSJason Ling return true;
100ded66d0fSJason Ling }
101ded66d0fSJason Ling
copyFrom(std::uint32_t length)102ded66d0fSJason Ling std::vector<std::uint8_t> PciDataHandler::copyFrom(std::uint32_t length)
103ded66d0fSJason Ling {
104ded66d0fSJason Ling std::vector<std::uint8_t> results(length);
105ded66d0fSJason Ling std::memcpy(results.data(), mapped, length);
106ded66d0fSJason Ling
107ded66d0fSJason Ling return results;
108ded66d0fSJason Ling }
109ded66d0fSJason Ling
writeMeta(const std::vector<std::uint8_t> &)110*b487eb47SWilly Tu bool PciDataHandler::writeMeta(const std::vector<std::uint8_t>&)
111ded66d0fSJason Ling {
112ded66d0fSJason Ling /* PCI handler doesn't require configuration write, only read. */
113ded66d0fSJason Ling return false;
114ded66d0fSJason Ling }
115ded66d0fSJason Ling
readMeta()116ded66d0fSJason Ling std::vector<std::uint8_t> PciDataHandler::readMeta()
117ded66d0fSJason Ling {
118ded66d0fSJason Ling /* PCI handler does require returning a configuration from read. */
119ded66d0fSJason Ling struct PciConfigResponse reply;
120ded66d0fSJason Ling reply.address = regionAddress;
121ded66d0fSJason Ling
122ded66d0fSJason Ling std::vector<std::uint8_t> bytes;
123ded66d0fSJason Ling bytes.resize(sizeof(reply));
124ded66d0fSJason Ling std::memcpy(bytes.data(), &reply, sizeof(reply));
125ded66d0fSJason Ling
126ded66d0fSJason Ling return bytes;
127ded66d0fSJason Ling }
128ded66d0fSJason Ling
129ded66d0fSJason Ling } // namespace ipmi_flash
130