Direct PCIe resource access without depending on fm10k driver #2
5 changed files with 182 additions and 84 deletions
15
README.md
15
README.md
|
@ -5,10 +5,9 @@ Utility that allows dumping/flashing the SPI Flash Non-Volatile Memory of the FM
|
|||
## Requirements
|
||||
* GCC >= 4.4.0 or clang
|
||||
* make
|
||||
* [fm10k kernel module](https://git.gammaspectra.live/FM10K/fm10k) compiled with UIO.
|
||||
* `# cd src && make clean && make -j $(nproc) CONFIG_UIO=1 && make install CONFIG_UIO=1`
|
||||
* `# rmmod fm10k && modprobe uio && modprobe fm10k`
|
||||
* If this works an UIO device (`/dev/uio0`) will exist. If not, check your bifurcation settings and/or whether the slot supports 16x PCIe 3.0
|
||||
* Only one FM10K device installed on hardware.
|
||||
* A management resource (BAR4) must be exposed, check bifurcation settings if needed.
|
||||
* Usually FM10K cards use two 8x PCIe groups per 16x slot.
|
||||
|
||||
## Compilation
|
||||
* `$ make clean && make`
|
||||
|
@ -17,13 +16,13 @@ Utility that allows dumping/flashing the SPI Flash Non-Volatile Memory of the FM
|
|||
|
||||
## fm10k-dump usage example
|
||||
* If the chip on the card is known to the tool, it'll set the image size to match. Alternatively it will use the platform minimum of 8Mbit.
|
||||
* `# ./fm10k-dump /dev/uio0 outputImage.bin`
|
||||
* You can also force the image/chip size: `# ./fm10k-dump /dev/uio0 outputImage.bin 32`
|
||||
* `# ./fm10k-dump outputImage.bin`
|
||||
* You can also force the image/chip size: `# ./fm10k-dump outputImage.bin 32`
|
||||
|
||||
## fm10k-flash usage example
|
||||
* _fm10k-flash_ requires a backup of the existing image before flashing a new one, for safety measures. Use _fm10k-dump_ to take a backup copy of the current state before flashing.
|
||||
* `# ./fm10k-dump /dev/uio0 backupImage.bin`
|
||||
* `# ./fm10k-flash /dev/uio0 inputImage.bin backupImage.bin`
|
||||
* `# ./fm10k-dump backupImage.bin`
|
||||
* `# ./fm10k-flash inputImage.bin backupImage.bin`
|
||||
|
||||
## License
|
||||
* BSD-3-Clause
|
||||
|
|
|
@ -41,35 +41,42 @@
|
|||
|
||||
|
||||
int main(int argc, char** argv){
|
||||
int fdUIO;
|
||||
int fdBAR4;
|
||||
FILE* fdOutput;
|
||||
|
||||
if(argc < 3){
|
||||
printf("Usage: %s </dev/uio0> <output.bin> [forceSizeInMegabits, default 8]\n", argv[0]);
|
||||
if(argc < 2){
|
||||
printf("Usage: %s <output.bin> [forceSizeInMegabits, default 8]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fdOutput = fopen(argv[2], "wb");
|
||||
fdOutput = fopen(argv[1], "wb");
|
||||
|
||||
if(fdOutput == NULL){
|
||||
printf("Could not create %s\n", argv[2]);
|
||||
printf("Could not create %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fdUIO = open(argv[1], O_RDWR);
|
||||
if(fdUIO <= 0){
|
||||
printf("Unable to open uio device %s to read NVM\n", argv[1]);
|
||||
FM10K_PCI_DEVICE device = fm10k_pci_findDevice();
|
||||
|
||||
if(device.vendor == 0){
|
||||
printf("Unable to find FM10K device with BAR4 port access. Check bifurcation settings?\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fdBAR4 = open(device.bar4Path, O_RDWR);
|
||||
if(fdBAR4 <= 0){
|
||||
printf("Unable to open BAR4 resource %s to read NVM\n", device.bar4Path);
|
||||
return 1;
|
||||
}
|
||||
void* memmapAddr;
|
||||
memmapAddr = mmap(NULL, FM10K_UIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fdUIO, 0);
|
||||
memmapAddr = mmap(NULL, FM10K_BAR4_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fdBAR4, 0);
|
||||
if (memmapAddr == MAP_FAILED) {
|
||||
printf("Unable to map uio device %s to read NVM\n", argv[1]);
|
||||
close(fdUIO);
|
||||
printf("Unable to map BAR4 resource %s to read NVM\n", device.bar4Path);
|
||||
close(fdBAR4);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SPI_COMMAND_READ_MANUFACTURER_RESULT manufacturerInfo = fm10k_uio_spi_ReadManufacturerData((uintptr_t)memmapAddr);
|
||||
SPI_COMMAND_READ_MANUFACTURER_RESULT manufacturerInfo = fm10k_mem_spi_ReadManufacturerData((uintptr_t) memmapAddr);
|
||||
if(manufacturerInfo.value == 0){
|
||||
printf("Error getting manufacturer information\n");
|
||||
return 1;
|
||||
|
@ -87,11 +94,11 @@ int main(int argc, char** argv){
|
|||
printf("Device: Unknown, defaulting %uMbit size\n", mbitsToRead);
|
||||
}
|
||||
|
||||
if(argc > 3){
|
||||
if(argc > 2){
|
||||
if(mbitsToRead != 8){
|
||||
printf("WARNING: %uMbit size was already auto-detected\n", mbitsToRead);
|
||||
}
|
||||
mbitsToRead = strtoul(argv[3], NULL, 10);
|
||||
mbitsToRead = strtoul(argv[2], NULL, 10);
|
||||
printf("Forcing %uMbit size\n", mbitsToRead);
|
||||
}
|
||||
|
||||
|
@ -113,7 +120,7 @@ int main(int argc, char** argv){
|
|||
|
||||
for(uint32_t addr = 0; addr < bootImageSize; addr += strideSize){
|
||||
printf("\rread @ 0x%08x / 0x%08x %d bytes", addr, bootImageSize, strideSize);
|
||||
if(fm10k_uio_spi_ReadFlash((uintptr_t)memmapAddr, addr, value + addr, strideSize)){
|
||||
if(fm10k_mem_spi_ReadFlash((uintptr_t) memmapAddr, addr, value + addr, strideSize)){
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,27 +42,27 @@
|
|||
|
||||
|
||||
int main(int argc, char** argv){
|
||||
int fdUIO;
|
||||
int fdBAR4;
|
||||
FILE* fdBackup;
|
||||
FILE* fdInput;
|
||||
|
||||
|
||||
|
||||
if(argc < 4){
|
||||
printf("Usage: %s </dev/uio0> <input.bin> <backup.bin>\n", argv[0]);
|
||||
if(argc < 3){
|
||||
printf("Usage: %s <input.bin> <backup.bin>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fdInput = fopen(argv[2], "rb");
|
||||
fdInput = fopen(argv[1], "rb");
|
||||
|
||||
if(fdInput == NULL){
|
||||
printf("Could not open %s\n", argv[2]);
|
||||
printf("Could not open %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fdBackup = fopen(argv[3], "rb");
|
||||
fdBackup = fopen(argv[2], "rb");
|
||||
if(fdBackup == NULL){
|
||||
printf("Could not open existing backup %s\n", argv[3]);
|
||||
printf("Could not open existing backup %s\n", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -79,20 +79,27 @@ int main(int argc, char** argv){
|
|||
return 1;
|
||||
}
|
||||
|
||||
fdUIO = open(argv[1], O_RDWR);
|
||||
if(fdUIO <= 0){
|
||||
printf("Unable to open uio device %s to write NVM\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
void* memmapAddr;
|
||||
memmapAddr = mmap(NULL, FM10K_UIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fdUIO, 0);
|
||||
if (memmapAddr == MAP_FAILED) {
|
||||
printf("Unable to map uio device %s to write NVM\n", argv[1]);
|
||||
close(fdUIO);
|
||||
FM10K_PCI_DEVICE device = fm10k_pci_findDevice();
|
||||
|
||||
if(device.vendor == 0){
|
||||
printf("Unable to find FM10K device with BAR4 port access. Check bifurcation settings?\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
SPI_COMMAND_READ_MANUFACTURER_RESULT manufacturerInfo = fm10k_uio_spi_ReadManufacturerData((uintptr_t)memmapAddr);
|
||||
fdBAR4 = open(device.bar4Path, O_RDWR);
|
||||
if(fdBAR4 <= 0){
|
||||
printf("Unable to open BAR4 resource %s to read NVM\n", device.bar4Path);
|
||||
return 1;
|
||||
}
|
||||
void* memmapAddr;
|
||||
memmapAddr = mmap(NULL, FM10K_BAR4_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fdBAR4, 0);
|
||||
if (memmapAddr == MAP_FAILED) {
|
||||
printf("Unable to map BAR4 resource %s to read NVM\n", device.bar4Path);
|
||||
close(fdBAR4);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SPI_COMMAND_READ_MANUFACTURER_RESULT manufacturerInfo = fm10k_mem_spi_ReadManufacturerData((uintptr_t) memmapAddr);
|
||||
if(manufacturerInfo.value == 0){
|
||||
printf("Error getting manufacturer information\n");
|
||||
return 1;
|
||||
|
@ -153,7 +160,7 @@ int main(int argc, char** argv){
|
|||
|
||||
for(uint32_t addr = 0; addr < bootImageSizeMax; addr += strideSize){
|
||||
printf("\rbackup check @ 0x%08x / 0x%08x %d bytes", addr, bootImageSizeMax, strideSize);
|
||||
if(fm10k_uio_spi_ReadFlash((uintptr_t)memmapAddr, addr, valueCheck + addr, strideSize)){
|
||||
if(fm10k_mem_spi_ReadFlash((uintptr_t) memmapAddr, addr, valueCheck + addr, strideSize)){
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +177,7 @@ int main(int argc, char** argv){
|
|||
sleep(1);
|
||||
|
||||
printf("Disabling sector protection.\n");
|
||||
fm10k_uio_spi_DisableSectorProtection((uintptr_t)memmapAddr);
|
||||
fm10k_mem_spi_DisableSectorProtection((uintptr_t) memmapAddr);
|
||||
|
||||
sleep(1);
|
||||
|
||||
|
@ -178,7 +185,7 @@ int main(int argc, char** argv){
|
|||
for(uint32_t addr = 0; addr < bootImageSizeMax; addr += strideSize){
|
||||
if(memcmp(valueBackup + addr, value + addr, strideSize) != 0){
|
||||
printf("write @ 0x%08x\n", addr);
|
||||
if(fm10k_uio_spi_WriteFlash((uintptr_t)memmapAddr, addr, value + addr, strideSize)){
|
||||
if(fm10k_mem_spi_WriteFlash((uintptr_t) memmapAddr, addr, value + addr, strideSize)){
|
||||
return 2;
|
||||
}
|
||||
sleep(1);
|
||||
|
@ -192,7 +199,7 @@ int main(int argc, char** argv){
|
|||
|
||||
for(uint32_t addr = 0; addr < bootImageSizeMax; addr += strideSize){
|
||||
printf("\rverify check @ 0x%08x / 0x%08x %d bytes", addr, bootImageSizeMax, strideSize);
|
||||
if(fm10k_uio_spi_ReadFlash((uintptr_t)memmapAddr, addr, valueCheck + addr, strideSize)){
|
||||
if(fm10k_mem_spi_ReadFlash((uintptr_t) memmapAddr, addr, valueCheck + addr, strideSize)){
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
@ -213,7 +220,7 @@ int main(int argc, char** argv){
|
|||
for(uint32_t addr = 0; addr < bootImageSizeMax; addr += strideSize){
|
||||
if(memcmp(valueBackup + addr, valueCheck + addr, strideSize) != 0){
|
||||
printf("write backup @ 0x%08x\n", addr);
|
||||
if(fm10k_uio_spi_WriteFlash((uintptr_t)memmapAddr, addr, valueBackup + addr, strideSize)){
|
||||
if(fm10k_mem_spi_WriteFlash((uintptr_t) memmapAddr, addr, valueBackup + addr, strideSize)){
|
||||
return 2;
|
||||
}
|
||||
sleep(1);
|
||||
|
|
131
src/fm10k.c
131
src/fm10k.c
|
@ -32,6 +32,10 @@
|
|||
#include "fm10k.h"
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
KNOWN_FLASH_DEVICE KNOWN_FLASH_DEVICE_LIST[] = {
|
||||
{{0x0101271f}, "Adesto AT45DB321E 32-Mbit", 32}, // Present on Silicom PE3100G2DQiRM-QX4
|
||||
|
@ -73,7 +77,7 @@ uint32_t get_interval_diff(struct timeval *begin, struct timeval *end) {
|
|||
return (diff.tv_sec * 1000 + diff.tv_usec / 1000);
|
||||
}
|
||||
|
||||
uint32_t fm10k_uio_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value){
|
||||
uint32_t fm10k_mem_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value){
|
||||
struct timeval startTime;
|
||||
uint8_t isTimeout = 0;
|
||||
SPI_CTRL spiCtrl = {0};
|
||||
|
@ -102,7 +106,7 @@ uint32_t fm10k_uio_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value){
|
|||
return 0;
|
||||
}
|
||||
|
||||
void fm10k_uio_spi_Enable(uintptr_t mem){
|
||||
void fm10k_mem_spi_Enable(uintptr_t mem){
|
||||
//ENABLE SPI
|
||||
SPI_CTRL spiCtrl;
|
||||
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value);
|
||||
|
@ -114,7 +118,7 @@ void fm10k_uio_spi_Enable(uintptr_t mem){
|
|||
WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, newSpiCtrl.value);
|
||||
}
|
||||
|
||||
void fm10k_uio_spi_Disable(uintptr_t mem){
|
||||
void fm10k_mem_spi_Disable(uintptr_t mem){
|
||||
//DISABLE SPI
|
||||
SPI_CTRL spiCtrl;
|
||||
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value);
|
||||
|
@ -127,7 +131,7 @@ void fm10k_uio_spi_Disable(uintptr_t mem){
|
|||
|
||||
|
||||
//Error if result.value is 0x00
|
||||
SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_uio_spi_ReadManufacturerData(uintptr_t mem){
|
||||
SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_mem_spi_ReadManufacturerData(uintptr_t mem){
|
||||
|
||||
SPI_COMMAND_READ_MANUFACTURER_RESULT result = {0};
|
||||
SPI_CTRL currentSpiCtrl;
|
||||
|
@ -136,7 +140,7 @@ SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_uio_spi_ReadManufacturerData(uintptr_
|
|||
uint32_t header;
|
||||
int32_t freq;
|
||||
|
||||
fm10k_uio_spi_Enable(mem);
|
||||
fm10k_mem_spi_Enable(mem);
|
||||
|
||||
|
||||
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, ¤tSpiCtrl.value);
|
||||
|
@ -161,7 +165,7 @@ SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_uio_spi_ReadManufacturerData(uintptr_
|
|||
spiCtrl.fields.HeaderSize = 1;
|
||||
spiCtrl.fields.DataSize = 4 & 0b11;
|
||||
|
||||
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -174,18 +178,18 @@ SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_uio_spi_ReadManufacturerData(uintptr_
|
|||
|
||||
/* release CS */
|
||||
spiCtrl.fields.Command = 0b1000;
|
||||
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
result.value = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
fm10k_uio_spi_Disable(mem);
|
||||
fm10k_mem_spi_Disable(mem);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, uint32_t len){
|
||||
uint32_t fm10k_mem_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, uint32_t len){
|
||||
|
||||
SPI_CTRL currentSpiCtrl;
|
||||
SPI_CTRL spiCtrl = {0};
|
||||
|
@ -196,7 +200,7 @@ uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data,
|
|||
uint32_t cnt;
|
||||
uint32_t numRead;
|
||||
|
||||
fm10k_uio_spi_Enable(mem);
|
||||
fm10k_mem_spi_Enable(mem);
|
||||
|
||||
|
||||
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, ¤tSpiCtrl.value);
|
||||
|
@ -226,7 +230,7 @@ uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data,
|
|||
spiCtrl.fields.Command |= 0b0100;
|
||||
spiCtrl.fields.DataSize = numRead & 0b11;
|
||||
|
||||
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -245,24 +249,24 @@ uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data,
|
|||
|
||||
/* release CS */
|
||||
spiCtrl.fields.Command = 0b1000;
|
||||
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
fm10k_uio_spi_Disable(mem);
|
||||
fm10k_mem_spi_Disable(mem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t fm10k_uio_spi_EnableSectorProtection(uintptr_t mem){
|
||||
uint32_t fm10k_mem_spi_EnableSectorProtection(uintptr_t mem){
|
||||
SPI_CTRL currentSpiCtrl;
|
||||
SPI_CTRL spiCtrl = {0};
|
||||
|
||||
uint32_t header;
|
||||
int32_t freq;
|
||||
|
||||
fm10k_uio_spi_Enable(mem);
|
||||
fm10k_mem_spi_Enable(mem);
|
||||
|
||||
|
||||
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, ¤tSpiCtrl.value);
|
||||
|
@ -284,29 +288,29 @@ uint32_t fm10k_uio_spi_EnableSectorProtection(uintptr_t mem){
|
|||
spiCtrl.fields.Command |= 0b0001;
|
||||
|
||||
/* send command to the flash */
|
||||
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* release CS */
|
||||
spiCtrl.fields.Command = 0b1000;
|
||||
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
return 1;
|
||||
}
|
||||
|
||||
fm10k_uio_spi_Disable(mem);
|
||||
fm10k_mem_spi_Disable(mem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t fm10k_uio_spi_DisableSectorProtection(uintptr_t mem){
|
||||
uint32_t fm10k_mem_spi_DisableSectorProtection(uintptr_t mem){
|
||||
SPI_CTRL currentSpiCtrl;
|
||||
SPI_CTRL spiCtrl = {0};
|
||||
|
||||
uint32_t header;
|
||||
int32_t freq;
|
||||
|
||||
fm10k_uio_spi_Enable(mem);
|
||||
fm10k_mem_spi_Enable(mem);
|
||||
|
||||
|
||||
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, ¤tSpiCtrl.value);
|
||||
|
@ -328,22 +332,22 @@ uint32_t fm10k_uio_spi_DisableSectorProtection(uintptr_t mem){
|
|||
spiCtrl.fields.Command |= 0b0001;
|
||||
|
||||
/* send command to the flash */
|
||||
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* release CS */
|
||||
spiCtrl.fields.Command = 0b1000;
|
||||
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
return 1;
|
||||
}
|
||||
|
||||
fm10k_uio_spi_Disable(mem);
|
||||
fm10k_mem_spi_Disable(mem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t fm10k_uio_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t* data, uint32_t len){
|
||||
uint32_t fm10k_mem_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t* data, uint32_t len){
|
||||
|
||||
SPI_CTRL currentSpiCtrl;
|
||||
SPI_CTRL spiCtrl = {0};
|
||||
|
@ -354,7 +358,7 @@ uint32_t fm10k_uio_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t
|
|||
uint32_t cnt;
|
||||
uint32_t numWrite;
|
||||
|
||||
fm10k_uio_spi_Enable(mem);
|
||||
fm10k_mem_spi_Enable(mem);
|
||||
|
||||
|
||||
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, ¤tSpiCtrl.value);
|
||||
|
@ -392,7 +396,7 @@ uint32_t fm10k_uio_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t
|
|||
WriteRegister32(mem, FM10K_REGISTER_SPI_TX_DATA, txData);
|
||||
|
||||
/* send command to the flash */
|
||||
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -402,12 +406,12 @@ uint32_t fm10k_uio_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t
|
|||
|
||||
/* release CS */
|
||||
spiCtrl.fields.Command = 0b1000;
|
||||
if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
fm10k_uio_spi_Disable(mem);
|
||||
fm10k_mem_spi_Disable(mem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -421,4 +425,75 @@ const KNOWN_FLASH_DEVICE* getKnownFlashFromManufacturerData(SPI_COMMAND_READ_MAN
|
|||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FM10K_PCI_DEVICE fm10k_pci_findDevice(){
|
||||
DIR *folder;
|
||||
char fileName[PATH_MAX];
|
||||
FM10K_PCI_DEVICE device = {0, 0, ""};
|
||||
|
||||
folder = opendir("/sys/bus/pci/devices");
|
||||
if(folder == NULL){
|
||||
return device;
|
||||
}
|
||||
|
||||
struct dirent *entry;
|
||||
while((entry = readdir(folder))){
|
||||
if(entry->d_type == DT_DIR || entry->d_type == DT_LNK){
|
||||
sprintf(fileName, "/sys/bus/pci/devices/%s/vendor", entry->d_name);
|
||||
|
||||
FILE* vendorBytesPointer = fopen(fileName, "rb");
|
||||
if(vendorBytesPointer != NULL){
|
||||
char* vendorBytesBuffer = NULL;
|
||||
size_t vendorBytesLen;
|
||||
size_t vendorBytesRead = getdelim(&vendorBytesBuffer, &vendorBytesLen, '\0', vendorBytesPointer);
|
||||
if(vendorBytesRead != -1){
|
||||
int vendor = (int)strtol(vendorBytesBuffer, NULL, 0);
|
||||
|
||||
if(vendor == 0x8086){ //Intel Corporation
|
||||
|
||||
sprintf(fileName, "/sys/bus/pci/devices/%s/device", entry->d_name);
|
||||
FILE* classBytesPointer = fopen(fileName, "rb");
|
||||
if(classBytesPointer != NULL){
|
||||
char* classBytesBuffer = NULL;
|
||||
size_t classBytesLen;
|
||||
size_t classBytesRead = getdelim(&classBytesBuffer, &classBytesLen, '\0', classBytesPointer);
|
||||
if(classBytesRead != -1){
|
||||
int class = (int)strtol(classBytesBuffer, NULL, 0);
|
||||
|
||||
if(class == 0x15a4 || class == 0x15d0 || class == 0x15d5){ //FM10000 devices
|
||||
sprintf(fileName, "/sys/bus/pci/devices/%s/resource4", entry->d_name);
|
||||
if(access(fileName, F_OK ) == 0 ) {
|
||||
device.vendor = vendor;
|
||||
device.class = class;
|
||||
|
||||
sprintf(device.bar4Path, "/sys/bus/pci/devices/%s/resource4", entry->d_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(classBytesBuffer != NULL){
|
||||
free(classBytesBuffer);
|
||||
}
|
||||
fclose(classBytesPointer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(vendorBytesBuffer != NULL){
|
||||
free(vendorBytesBuffer);
|
||||
}
|
||||
fclose(vendorBytesPointer);
|
||||
}
|
||||
|
||||
if(device.vendor != 0){
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
closedir(folder);
|
||||
|
||||
return device;
|
||||
}
|
30
src/fm10k.h
30
src/fm10k.h
|
@ -33,9 +33,10 @@
|
|||
|
||||
#include <inttypes.h>
|
||||
#include <sys/time.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define FM10K_UIO_SIZE 0x0000000004000000
|
||||
#define FM10K_UIO_OFFSET 0
|
||||
#define FM10K_BAR4_SIZE 0x0000000004000000
|
||||
#define FM10K_BAR4_OFFSET 0
|
||||
|
||||
//From Datasheet, 11.25.1 MGMT Map, Table 11-37
|
||||
#define FM10K_REGISTER_BASE 0
|
||||
|
@ -104,19 +105,28 @@ void WriteRegister32(uintptr_t mem, uint32_t addr, uint32_t value);
|
|||
|
||||
uint32_t get_interval_diff(struct timeval *begin, struct timeval *end);
|
||||
|
||||
uint32_t fm10k_uio_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value);
|
||||
uint32_t fm10k_mem_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value);
|
||||
|
||||
void fm10k_uio_spi_Enable(uintptr_t mem);
|
||||
void fm10k_mem_spi_Enable(uintptr_t mem);
|
||||
|
||||
void fm10k_mem_spi_Disable(uintptr_t mem);
|
||||
|
||||
void fm10k_uio_spi_Disable(uintptr_t mem);
|
||||
|
||||
|
||||
//Error if result.value is 0x00
|
||||
SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_uio_spi_ReadManufacturerData(uintptr_t mem);
|
||||
SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_mem_spi_ReadManufacturerData(uintptr_t mem);
|
||||
const KNOWN_FLASH_DEVICE* getKnownFlashFromManufacturerData(SPI_COMMAND_READ_MANUFACTURER_RESULT data);
|
||||
|
||||
uint32_t fm10k_uio_spi_EnableSectorProtection(uintptr_t mem);
|
||||
uint32_t fm10k_uio_spi_DisableSectorProtection(uintptr_t mem);
|
||||
uint32_t fm10k_mem_spi_EnableSectorProtection(uintptr_t mem);
|
||||
uint32_t fm10k_mem_spi_DisableSectorProtection(uintptr_t mem);
|
||||
|
||||
uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, uint32_t len);
|
||||
uint32_t fm10k_uio_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t* data, uint32_t len);
|
||||
uint32_t fm10k_mem_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, uint32_t len);
|
||||
uint32_t fm10k_mem_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t* data, uint32_t len);
|
||||
|
||||
typedef struct{
|
||||
uint16_t vendor;
|
||||
uint16_t class;
|
||||
char bar4Path[PATH_MAX];
|
||||
} FM10K_PCI_DEVICE;
|
||||
|
||||
FM10K_PCI_DEVICE fm10k_pci_findDevice();
|
Loading…
Reference in a new issue