Working example
This commit is contained in:
parent
d3cd980e4b
commit
4a0eb4f2b0
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
/cmake-build-debug
|
||||
/build
|
||||
.idea
|
|
@ -1,7 +1,9 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
project(src)
|
||||
project(fsm)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
add_executable(fsmd src/fsmd.cpp src/device/PCIEDevice.cpp src/device/PCIEDevice.h src/FM10K.cpp src/FM10K.h)
|
||||
include_directories(${fsm_SOURCE_DIR}/src)
|
||||
|
||||
add_executable(fsmd src/fsmd.cpp src/device/PCIEDevice.cpp src/device/PCIEDevice.h src/fm10k/FM10K.cpp src/fm10k/FM10K.h src/fm10k/Functions.h src/fm10k/Functions.cpp)
|
||||
add_executable(fsm src/fsm.cpp)
|
||||
|
|
14
build.sh
Executable file
14
build.sh
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
pushd "${0%/*}"
|
||||
rm -rvf build
|
||||
mkdir build
|
||||
pushd build
|
||||
|
||||
export CC=clang
|
||||
export CXX=clang++
|
||||
export CFLAGS="-ggdb -O0 -march=x86-64 -mtune=generic"
|
||||
export CXXFLAGS="-ggdb -O0 -march=x86-64 -mtune=generic"
|
||||
cmake ..
|
||||
make -j$(nproc)
|
25
src/FM10K.h
25
src/FM10K.h
|
@ -1,25 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include "device/Device.h"
|
||||
#include "registers/MGMT.h"
|
||||
|
||||
class FM10K {
|
||||
public:
|
||||
static const uint64_t BAR4_SIZE = 0x0000000004000000;
|
||||
static const uint64_t BAR4_OFFSET = 0x0;
|
||||
|
||||
explicit FM10K(std::unique_ptr<Device> device) : m_device(std::move(device)) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
std::unique_ptr<Device> m_device;
|
||||
};
|
||||
|
||||
|
|
@ -5,9 +5,11 @@ public:
|
|||
virtual ~Device()= default;
|
||||
virtual bool valid() const = 0;
|
||||
|
||||
virtual uint32_t get32(uint64_t address) const = 0;
|
||||
virtual void set32(uint64_t address, uint32_t value) const = 0;
|
||||
virtual uint32_t get32(uint32_t address) const = 0;
|
||||
virtual void set32(uint32_t address, uint32_t value) const = 0;
|
||||
|
||||
virtual uint64_t get64(uint64_t address) const = 0;
|
||||
virtual void set64(uint64_t address, uint64_t value) const = 0;
|
||||
virtual volatile uint32_t* map32(uint32_t address) const = 0;
|
||||
|
||||
virtual uint64_t get64(uint32_t address) const = 0;
|
||||
virtual void set64(uint32_t address, uint64_t value) const = 0;
|
||||
};
|
|
@ -3,8 +3,48 @@
|
|||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include "PCIEDevice.h"
|
||||
#include "../FM10K.h"
|
||||
#include "fm10k/FM10K.h"
|
||||
|
||||
std::vector<uint8_t> get_file_contents(const std::string& path){
|
||||
std::ifstream file;
|
||||
file.open(path, std::ios::in | std::ios::binary);
|
||||
if(file.fail()){
|
||||
file.close();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
std::for_each(std::istreambuf_iterator<char>(file),
|
||||
std::istreambuf_iterator<char>(),
|
||||
[&data](const char c){
|
||||
data.push_back(c);
|
||||
});
|
||||
|
||||
file.close();
|
||||
return std::move(data);
|
||||
}
|
||||
|
||||
uint64_t get_file_integer(const std::string& path){
|
||||
auto s = get_file_contents(path);
|
||||
std::string t;
|
||||
t.reserve(s.empty() ? 0 : s.size() - 1);
|
||||
|
||||
for(auto& c : s){
|
||||
if(c == '\n'){
|
||||
break;
|
||||
}
|
||||
t += c;
|
||||
}
|
||||
|
||||
if(t.empty()){
|
||||
return -1;
|
||||
}
|
||||
return std::strtoul(t.c_str(), nullptr, 0);
|
||||
}
|
||||
|
||||
std::vector<PCIEDevice::DeviceEntry> PCIEDevice::DeviceEntry::find() {
|
||||
std::vector<PCIEDevice::DeviceEntry> entries;
|
||||
|
@ -20,73 +60,42 @@ std::vector<PCIEDevice::DeviceEntry> PCIEDevice::DeviceEntry::find() {
|
|||
|
||||
struct dirent *entry;
|
||||
|
||||
std::string fileName;
|
||||
|
||||
while ((entry = readdir(folder))) {
|
||||
std::string basePath("/sys/bus/pci/devices/");
|
||||
basePath += entry->d_name;
|
||||
|
||||
if (entry->d_type == DT_DIR || entry->d_type == DT_LNK) {
|
||||
fileName = "/sys/bus/pci/devices/";
|
||||
fileName += entry->d_name;
|
||||
fileName += "/vendor";
|
||||
|
||||
FILE *vendorBytesPointer = fopen(fileName.c_str(), "rb");
|
||||
if (vendorBytesPointer != nullptr) {
|
||||
char *vendorBytesBuffer = nullptr;
|
||||
size_t vendorBytesLen;
|
||||
size_t vendorBytesRead = getdelim(&vendorBytesBuffer, &vendorBytesLen, '\0', vendorBytesPointer);
|
||||
if (vendorBytesRead != -1) {
|
||||
int vendor = (int) strtol(vendorBytesBuffer, nullptr, 0);
|
||||
uint16_t vendor = get_file_integer(basePath + "/vendor");
|
||||
uint16_t _class = get_file_integer(basePath + "/device");
|
||||
|
||||
if (vendor == 0x8086) { //Intel Corporation
|
||||
if (
|
||||
vendor == 0x8086 //Intel Corporation
|
||||
&&
|
||||
(_class == 0x15a4 || _class == 0x15d0 || _class == 0x15d5) //FM10000 devices
|
||||
) {
|
||||
if (access((basePath + "/resource4").c_str(), F_OK) == 0) {
|
||||
|
||||
fileName = "/sys/bus/pci/devices/";
|
||||
fileName += entry->d_name;
|
||||
fileName += "/device";
|
||||
FILE *classBytesPointer = fopen(fileName.c_str(), "rb");
|
||||
if (classBytesPointer != nullptr) {
|
||||
char *classBytesBuffer = nullptr;
|
||||
size_t classBytesLen;
|
||||
size_t classBytesRead = getdelim(&classBytesBuffer, &classBytesLen, '\0',
|
||||
classBytesPointer);
|
||||
if (classBytesRead != -1) {
|
||||
int _class = (int) strtol(classBytesBuffer, nullptr, 0);
|
||||
|
||||
if (_class == 0x15a4 || _class == 0x15d0 || _class == 0x15d5) { //FM10000 devices
|
||||
fileName = "/sys/bus/pci/devices/";
|
||||
fileName += entry->d_name;
|
||||
fileName += "/resource4";
|
||||
if (access(fileName.c_str(), F_OK) == 0) {
|
||||
entries.emplace_back(fileName, vendor, _class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (classBytesBuffer != nullptr) {
|
||||
free(classBytesBuffer);
|
||||
}
|
||||
fclose(classBytesPointer);
|
||||
}
|
||||
}
|
||||
auto vpd = get_file_contents(basePath + "/vpd");
|
||||
entries.emplace_back(basePath + "/resource4", vendor, _class, vpd);
|
||||
}
|
||||
|
||||
if (vendorBytesBuffer != nullptr) {
|
||||
free(vendorBytesBuffer);
|
||||
}
|
||||
fclose(vendorBytesPointer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(folder);
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
PCIEDevice::PCIEDevice(PCIEDevice::DeviceEntry device) : m_device (std::move(device)){
|
||||
PCIEDevice::PCIEDevice(const PCIEDevice::DeviceEntry& device) : m_device (device){
|
||||
m_bar4Resource = open(m_device.getPath().c_str(), O_RDWR);
|
||||
if(m_bar4Resource <= 0){
|
||||
//TODO printf("Unable to open BAR4 resource %s\n", m_device.getPath().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
m_bar4mmap = mmap(nullptr, FM10K::BAR4_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, m_bar4Resource, 0);
|
||||
m_bar4mmap = static_cast<uint32_t *>(mmap(nullptr, FM10K::BAR4_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, m_bar4Resource, 0));
|
||||
if(m_bar4mmap == MAP_FAILED){
|
||||
//TODO printf("Unable to map BAR4 resource %s\n", m_device.getPath().c_str());
|
||||
close(m_bar4Resource);
|
||||
|
@ -110,18 +119,109 @@ PCIEDevice::~PCIEDevice() {
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t PCIEDevice::get32(uint64_t address) const {
|
||||
return *(((volatile uintptr_t *) m_bar4mmap) + address);
|
||||
uint32_t PCIEDevice::get32(uint32_t address) const {
|
||||
return (m_bar4mmap && address < FM10K::BAR4_SIZE) ? *getaddress(address) : 0;
|
||||
}
|
||||
|
||||
void PCIEDevice::set32(uint64_t address, uint32_t value) const {
|
||||
*(volatile uintptr_t *) (((uintptr_t *) m_bar4mmap) + address) = value;
|
||||
void PCIEDevice::set32(uint32_t address, uint32_t value) const {
|
||||
if(m_bar4mmap && address < FM10K::BAR4_SIZE){
|
||||
*getaddress(address) = value;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t PCIEDevice::get64(uint64_t address) const {
|
||||
return *(((volatile uintptr_t *) m_bar4mmap) + address);
|
||||
uint64_t PCIEDevice::get64(uint32_t address) const {
|
||||
return (m_bar4mmap && (address + 1) < FM10K::BAR4_SIZE) ? *reinterpret_cast<volatile uint64_t*>(getaddress(address)) : 0;
|
||||
}
|
||||
|
||||
void PCIEDevice::set64(uint64_t address, uint64_t value) const {
|
||||
*(uintptr_t volatile *) (((uintptr_t *) m_bar4mmap) + address) = value;
|
||||
void PCIEDevice::set64(uint32_t address, uint64_t value) const {
|
||||
if(m_bar4mmap && (address + 1) < FM10K::BAR4_SIZE){
|
||||
*reinterpret_cast<volatile uint64_t*>(getaddress(address)) = value;
|
||||
}
|
||||
}
|
||||
|
||||
volatile uint32_t* PCIEDevice::map32(uint32_t address) const {
|
||||
return (m_bar4mmap && address < FM10K::BAR4_SIZE) ? getaddress(address) : nullptr;
|
||||
}
|
||||
|
||||
PCIEDevice::VitalProductData::VitalProductData(const std::vector<uint8_t>& s) {
|
||||
size_t offset = 0;
|
||||
|
||||
while(offset < s.size()){
|
||||
ResourceType t(s, offset);
|
||||
|
||||
|
||||
switch (t.getName()) {
|
||||
|
||||
case ResourceType::TypeName::StringTag:
|
||||
if(m_vpd.empty()){
|
||||
//Product Name
|
||||
m_vpd.emplace("Product Name", t.getData());
|
||||
}
|
||||
break;
|
||||
case ResourceType::TypeName::VPD_R:
|
||||
{
|
||||
size_t o = 0;
|
||||
while (o < t.getData().size()){
|
||||
fillFromEntry(t.getData(), o);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ResourceType::TypeName::VPD_W:
|
||||
{
|
||||
size_t o = 0;
|
||||
while (o < t.getData().size()){
|
||||
fillFromEntry(t.getData(), o);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ResourceType::TypeName::End:
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void PCIEDevice::VitalProductData::fillFromEntry(const std::vector<uint8_t> &v, size_t& offset) {
|
||||
std::string keyword;
|
||||
keyword.reserve(2);
|
||||
|
||||
keyword += static_cast<char>(v[offset++]);
|
||||
keyword += static_cast<char>(v[offset++]);
|
||||
uint8_t length = v[offset++];
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
std::copy(v.begin() + offset, v.begin() + offset + length, std::back_inserter(data));
|
||||
offset += length;
|
||||
|
||||
m_vpd.emplace(std::move(keyword), std::move(data));
|
||||
}
|
||||
|
||||
PCIEDevice::VitalProductData::ResourceType::ResourceType(const std::vector<uint8_t>& s, size_t& offset) {
|
||||
uint8_t h = s[offset++];
|
||||
|
||||
uint16_t length = 0;
|
||||
|
||||
if(((h>>7)&1) == 0){ //Small Data Type
|
||||
PACKED(struct {
|
||||
uint8_t length : 3;
|
||||
uint8_t name : 4;
|
||||
uint8_t type : 1;
|
||||
}, uint8_t) header{};
|
||||
header.value = h;
|
||||
|
||||
m_name = static_cast<TypeName>(header.fields.name);
|
||||
length = header.fields.length;
|
||||
}else{ //Large Data Type
|
||||
PACKED(struct {
|
||||
uint8_t name : 7;
|
||||
uint8_t type : 1;
|
||||
}, uint8_t) header{};
|
||||
header.value = h;
|
||||
|
||||
m_name = static_cast<TypeName>(header.fields.name);
|
||||
length = s[offset] | s[offset + 1] << 8;
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
std::copy(s.begin() + offset, s.begin() + offset + length, std::back_inserter(m_data));
|
||||
offset += length;
|
||||
}
|
||||
|
|
|
@ -2,24 +2,66 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include "Device.h"
|
||||
|
||||
class PCIEDevice: public Device {
|
||||
|
||||
public:
|
||||
|
||||
class VitalProductData{
|
||||
public:
|
||||
class ResourceType {
|
||||
public:
|
||||
enum class TypeName : uint8_t{
|
||||
StringTag = 0x02,
|
||||
VPD_R = 0x10,
|
||||
VPD_W = 0x11,
|
||||
End = 0x0f,
|
||||
};
|
||||
|
||||
explicit ResourceType(const std::vector<uint8_t>& s, size_t& offset);
|
||||
|
||||
TypeName getName() const{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
const auto& getData() const{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
protected:
|
||||
TypeName m_name;
|
||||
std::vector<uint8_t> m_data;
|
||||
};
|
||||
|
||||
explicit VitalProductData(const std::vector<uint8_t>& s);
|
||||
|
||||
private:
|
||||
void fillFromEntry(const std::vector<uint8_t>& v, size_t& offset);
|
||||
|
||||
std::unordered_map<std::string, std::vector<uint8_t>> m_vpd;
|
||||
};
|
||||
|
||||
class DeviceEntry{
|
||||
|
||||
public:
|
||||
DeviceEntry(std::string path, uint16_t vendor, uint16_t _class) : m_path(std::move(path)), m_class(_class), m_vendor(vendor){
|
||||
DeviceEntry(std::string path, uint16_t vendor, uint16_t _class, const std::vector<uint8_t>& vpd) : m_path(std::move(path)), m_class(_class), m_vendor(vendor), m_vpd(vpd){
|
||||
|
||||
}
|
||||
DeviceEntry(const DeviceEntry& a) =default;
|
||||
|
||||
static std::vector<DeviceEntry> find();
|
||||
|
||||
const std::string& getPath() const{
|
||||
const auto& getPath() const{
|
||||
return m_path;
|
||||
}
|
||||
|
||||
const auto& getVPD() const{
|
||||
return m_vpd;
|
||||
}
|
||||
|
||||
uint16_t getVendor() const{
|
||||
return m_vendor;
|
||||
}
|
||||
|
@ -31,15 +73,17 @@ public:
|
|||
std::string m_path;
|
||||
uint16_t m_vendor;
|
||||
uint16_t m_class;
|
||||
VitalProductData m_vpd;
|
||||
};
|
||||
|
||||
explicit PCIEDevice(PCIEDevice::DeviceEntry device);
|
||||
explicit PCIEDevice(const PCIEDevice::DeviceEntry& device);
|
||||
|
||||
uint32_t get32(uint64_t address) const override;
|
||||
void set32(uint64_t address, uint32_t value) const override;
|
||||
uint32_t get32(uint32_t address) const override;
|
||||
volatile uint32_t* map32(uint32_t address) const override;
|
||||
void set32(uint32_t address, uint32_t value) const override;
|
||||
|
||||
uint64_t get64(uint64_t address) const override;
|
||||
void set64(uint64_t address, uint64_t value) const override;
|
||||
uint64_t get64(uint32_t address) const override;
|
||||
void set64(uint32_t address, uint64_t value) const override;
|
||||
|
||||
const PCIEDevice::DeviceEntry& getDeviceEntry() const{
|
||||
return m_device;
|
||||
|
@ -49,11 +93,15 @@ public:
|
|||
return m_bar4mmap != nullptr && m_bar4Resource > 0;
|
||||
}
|
||||
|
||||
~PCIEDevice();
|
||||
~PCIEDevice() override;
|
||||
|
||||
|
||||
private:
|
||||
volatile uint32_t* getaddress(uint32_t address) const {
|
||||
return m_bar4mmap + address;
|
||||
}
|
||||
int m_bar4Resource = 0;
|
||||
void* m_bar4mmap = nullptr;
|
||||
uint32_t* m_bar4mmap = nullptr;
|
||||
PCIEDevice::DeviceEntry m_device;
|
||||
};
|
||||
|
||||
|
|
12
src/fm10k/Constants.h
Normal file
12
src/fm10k/Constants.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "Functions.h"
|
||||
|
||||
namespace FM10K {
|
||||
const uint64_t BAR4_SIZE = 0x0000000004000000;
|
||||
const uint64_t BAR4_OFFSET = 0x0;
|
||||
|
||||
//These should not be set (on hw) to more than 1100 or less than 800
|
||||
constexpr uint32_t DEFAULT_VDDS_VOLTAGE = 850; //Spec says 0.9 Volts, and also 0.85
|
||||
constexpr uint32_t DEFAULT_VDDF_VOLTAGE = 950; //Spec says 0.9 Volts, and also 0.95
|
||||
}
|
57
src/fm10k/FM10K.h
Normal file
57
src/fm10k/FM10K.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include <cfloat>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include "device/Device.h"
|
||||
#include "registers/MGMT.h"
|
||||
#include "Constants.h"
|
||||
|
||||
#define FM10K_GET_REGISTER(i, t) i.getType<t>(t ## __Address)
|
||||
#define FM10K_MAP_REGISTER(i, t) i.mapType<t>(t ## __Address)
|
||||
#define FM10K_SET_REGISTER(i, t, v) i.setType<t>(t ## __Address, v)
|
||||
#define FM10K_SET_REGISTER_FIELD(i, t, f, v) \
|
||||
auto __f = FM10K_MAP_REGISTER(i, t); \
|
||||
__f->fields. f = v
|
||||
|
||||
namespace FM10K{
|
||||
|
||||
class FM10K {
|
||||
public:
|
||||
|
||||
explicit FM10K(std::unique_ptr<Device> device) : m_device(std::move(device)) {
|
||||
|
||||
}
|
||||
|
||||
template<typename T> volatile T* mapType(uint32_t address) const {
|
||||
return reinterpret_cast<volatile T*>(m_device->map32(address));
|
||||
}
|
||||
|
||||
template<typename T> T getType(uint32_t address) const {
|
||||
T t;
|
||||
t.value = m_device->get32(address);
|
||||
return std::move(t);
|
||||
}
|
||||
|
||||
template<typename T> void setType(uint32_t address, const T& t) const {
|
||||
t.value = m_device->set32(address, t.value);
|
||||
return std::move(t);
|
||||
}
|
||||
|
||||
template<typename T> void setTypeMask(uint32_t address, uint32_t mask, const T& t) const {
|
||||
t.value = m_device->set32(address, t.value & mask);
|
||||
return std::move(t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
std::unique_ptr<Device> m_device;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
2
src/fm10k/Functions.cpp
Normal file
2
src/fm10k/Functions.cpp
Normal file
|
@ -0,0 +1,2 @@
|
|||
#include "Functions.h"
|
||||
|
20
src/fm10k/Functions.h
Normal file
20
src/fm10k/Functions.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cfloat>
|
||||
|
||||
namespace FM10K{
|
||||
|
||||
constexpr uint32_t VR12_VID_to_Millivolts(uint8_t v){
|
||||
return v == 0 ? 0 : 5 * (v - 1) + 250;
|
||||
}
|
||||
|
||||
constexpr uint32_t Volts_to_Millivolts(double v){
|
||||
return static_cast<uint32_t>(v * 1000.0);
|
||||
}
|
||||
|
||||
constexpr uint8_t Millivolts_to_VR12_VID(uint32_t v){
|
||||
return ((v - 250) / 5) + 1;
|
||||
}
|
||||
|
||||
}
|
50
src/fm10k/registers/MGMT.h
Normal file
50
src/fm10k/registers/MGMT.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
#pragma once
|
||||
|
||||
#include "Register.h"
|
||||
|
||||
namespace FM10K{
|
||||
namespace registers{
|
||||
namespace MGMT{
|
||||
enum class DEVICE_CFG_FeatureCode: uint8_t {
|
||||
FULL = 0b00,
|
||||
HALF = 0b01,
|
||||
BASIC = 0b10,
|
||||
RESERVED = 0b11,
|
||||
};
|
||||
|
||||
typedef PACKED(struct {
|
||||
uint8_t PCIeMode: 4; //Bitfield array [0..3]
|
||||
uint8_t Eth100GDisabled: 1;
|
||||
DEVICE_CFG_FeatureCode FeatureCode: 2;
|
||||
uint16_t PCIeEnable: 9; //Bitfield array [0..8]
|
||||
uint8_t SystimeClockSource: 1;
|
||||
uint16_t : 15;
|
||||
}, uint32_t) DEVICE_CFG;
|
||||
const uint32_t DEVICE_CFG__Address = 0x4;
|
||||
|
||||
|
||||
typedef PACKED(struct {
|
||||
uint16_t PartNumber : 16;
|
||||
uint16_t : 16;
|
||||
}, uint32_t) VITAL_PRODUCT_DATA;
|
||||
const uint32_t VITAL_PRODUCT_DATA__Address = 0x304;
|
||||
|
||||
typedef PACKED(struct {
|
||||
uint16_t ChipVersion : 7;
|
||||
uint32_t : 25;
|
||||
}, uint32_t) CHIP_VERSION;
|
||||
const uint32_t CHIP_VERSION__Address = 0x452;
|
||||
|
||||
typedef PACKED(struct {
|
||||
uint16_t : 11;
|
||||
uint8_t SKU : 5;
|
||||
uint8_t VDDS_VRM : 8;
|
||||
uint8_t VDDF_VRM : 8;
|
||||
}, uint32_t) FUSE_DATA_0;
|
||||
const uint32_t FUSE_DATA_0__Address = 0xC0E;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
11
src/fm10k/registers/Register.h
Normal file
11
src/fm10k/registers/Register.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "pack.h"
|
||||
#include "MGMT.h"
|
||||
|
||||
namespace FM10K{
|
||||
namespace registers{
|
||||
|
||||
|
||||
}
|
||||
}
|
36
src/fsmd.cpp
36
src/fsmd.cpp
|
@ -1,6 +1,17 @@
|
|||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include "device/PCIEDevice.h"
|
||||
#include "fm10k/FM10K.h"
|
||||
#include "fm10k/registers/Register.h"
|
||||
|
||||
template <typename T> std::string tohex(T v){
|
||||
std::stringstream o;
|
||||
o << std::hex << std::setw(sizeof(v) * 2) << std::setfill('0') << v;
|
||||
|
||||
return o.str();
|
||||
}
|
||||
|
||||
int main() {
|
||||
auto entries = PCIEDevice::DeviceEntry::find();
|
||||
|
@ -8,13 +19,24 @@ int main() {
|
|||
std::cout << "Found " << entries.size() << " FM10K management device(s)." << std::endl;
|
||||
|
||||
for(auto& entry : entries){
|
||||
auto dev = std::make_unique<PCIEDevice>(entry);
|
||||
std::cout << "dev.path: " << dev->getDeviceEntry().getPath() << std::endl;
|
||||
std::cout << "dev.vendor: " << dev->getDeviceEntry().getVendor() << std::endl;
|
||||
std::cout << "dev.class: " << dev->getDeviceEntry().getClass() << std::endl;
|
||||
std::cout << "DEVICE_CFG: " << dev->get32(0x4) << std::endl;
|
||||
std::cout << "BSM_ARGS: " << dev->get32(0xC00) << std::endl;
|
||||
std::cout << "FUSE_DATA(64): " << dev->get64(0xC0E) << std::endl;
|
||||
auto dev = std::make_unique<PCIEDevice>(entry);
|
||||
|
||||
std::cout << "dev.path: " << dev->getDeviceEntry().getPath() << std::endl;
|
||||
std::cout << "dev.vendor: " << tohex(dev->getDeviceEntry().getVendor()) << std::endl;
|
||||
std::cout << "dev.class: " << tohex(dev->getDeviceEntry().getClass()) << std::endl;
|
||||
|
||||
FM10K::FM10K fm10k(std::move(dev));
|
||||
|
||||
auto fuseData_0 = FM10K_MAP_REGISTER(fm10k, FM10K::registers::MGMT::FUSE_DATA_0);
|
||||
std::cout << "FUSE_DATA_0: " << tohex(fuseData_0->value) << std::endl;
|
||||
std::cout << "FUSE_DATA_0.SKU: " << std::to_string(fuseData_0->fields.SKU) << std::endl;
|
||||
std::cout << "FUSE_DATA_0.VDDF_VRM: " << std::to_string(fuseData_0->fields.VDDS_VRM) << std::endl;
|
||||
std::cout << "FUSE_DATA_0.VDDF_VRM: " << std::to_string(fuseData_0->fields.VDDF_VRM) << std::endl;
|
||||
|
||||
auto deviceCfg = FM10K_MAP_REGISTER(fm10k, FM10K::registers::MGMT::DEVICE_CFG);
|
||||
std::cout << "DEVICE_CFG: " << tohex(deviceCfg->value) << std::endl;
|
||||
auto vpd = FM10K_MAP_REGISTER(fm10k, FM10K::registers::MGMT::VITAL_PRODUCT_DATA);
|
||||
std::cout << "VITAL_PRODUCT_DATA.PartNumber: " << tohex(vpd->fields.PartNumber) << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
46
src/pack.h
Normal file
46
src/pack.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#error "GCC is currently not supported due to volatile union packed struct issue. Use clang instead"
|
||||
#endif
|
||||
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 4)) || defined(__clang__) || defined(__TINYC__)
|
||||
|
||||
#if defined(__TINYC__)
|
||||
|
||||
#define PACKED(x, s) \
|
||||
_Pragma("pack(1)") \
|
||||
union { \
|
||||
s value; \
|
||||
x __attribute__((packed)) fields; \
|
||||
} \
|
||||
_Pragma("pack(1)")
|
||||
|
||||
#define PACKEDM(x, s, n) \
|
||||
_Pragma("pack(1)") \
|
||||
union { \
|
||||
s value[n]; \
|
||||
x __attribute__((packed)) fields; \
|
||||
} \
|
||||
_Pragma("pack(1)")
|
||||
|
||||
#else
|
||||
|
||||
#define PACKED(x, s) \
|
||||
union { \
|
||||
s value; \
|
||||
x __attribute__((packed, aligned(sizeof(s)))) fields; \
|
||||
} __attribute__((packed, aligned(sizeof(s))))
|
||||
|
||||
#define PACKEDM(x, s, n) \
|
||||
union { \
|
||||
s value[n]; \
|
||||
x __attribute__((packed, aligned(sizeof(s)))) fields; \
|
||||
} __attribute__((packed, aligned(sizeof(s))))
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error "Packed bit-fields of type char were not properly bit-packed on many targets prior to GCC 4.4, upgrade to GCC >= 4.4."
|
||||
#endif
|
|
@ -1,8 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "pack.h"
|
||||
|
||||
namespace MGMT{
|
||||
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
#pragma once
|
||||
#include "stdint.h"
|
||||
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 4)) || __clang__ || __TINYC__
|
||||
|
||||
#if defined(__TINYC__)
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
|
||||
#define PACKED(x, s) union { \
|
||||
s value; \
|
||||
x __attribute__((packed)) fields; \
|
||||
}
|
||||
|
||||
#define PACKEDM(x, s, n) union { \
|
||||
s value[n]; \
|
||||
x __attribute__((packed)) fields; \
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Packed bit-fields of type char were not properly bit-packed on many targets prior to GCC 4.4, upgrade to GCC >= 4.4."
|
||||
#endif
|
28
test/test-gcc-struct.cpp
Normal file
28
test/test-gcc-struct.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
#define PACKED(x, s) \
|
||||
union { \
|
||||
s value; \
|
||||
x __attribute__((packed, aligned(sizeof(s)))) fields; \
|
||||
} __attribute__((packed, aligned(sizeof(s))))
|
||||
|
||||
typedef PACKED(struct {
|
||||
uint16_t PartNumber : 16;
|
||||
uint16_t _reserved: 16;
|
||||
}, uint32_t) VITAL_PRODUCT_DATA;
|
||||
|
||||
static volatile uint32_t v = 0x0000ae21;
|
||||
static volatile uint32_t* vpd = &v;
|
||||
|
||||
template<typename T> volatile T* mapType() {
|
||||
return reinterpret_cast<volatile T*>(vpd);
|
||||
}
|
||||
|
||||
int main(){
|
||||
auto tt = mapType<VITAL_PRODUCT_DATA>();
|
||||
uint16_t t = tt->fields.PartNumber;
|
||||
|
||||
printf("%d\n", tt->value);
|
||||
printf("%d\n", t);
|
||||
}
|
Loading…
Reference in a new issue