xref: /openbmc/phosphor-ipmi-flash/bmc/firmware-handler/pci_handler.cpp (revision b487eb47e566df7679e740559582f6d25597feba)
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