PCIe driver: Added sysfs bindings
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
# but it helps in code completion in CLion IDE
|
||||
|
||||
ADD_LIBRARY(jfjoch_kernel_module STATIC
|
||||
jfjoch_ioctl.h jfjoch_drv.c jfjoch_drv.h jfjoch_ioctl.h jfjoch_pcie_setup.c jfjoch_memory.c jfjoch_ioctl.c jfjoch_function.c jfjoch_miscdev.c)
|
||||
jfjoch_ioctl.h jfjoch_drv.c jfjoch_drv.h jfjoch_ioctl.h jfjoch_pcie_setup.c jfjoch_memory.c jfjoch_ioctl.c jfjoch_function.c jfjoch_miscdev.c
|
||||
jfjoch_sysfs.c)
|
||||
|
||||
EXECUTE_PROCESS(COMMAND uname -r
|
||||
OUTPUT_VARIABLE KERNEL_RELEASE
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
obj-m += jfjoch.o
|
||||
cflags-m=-std=c99
|
||||
|
||||
jfjoch-y := jfjoch_drv.o jfjoch_ioctl.o jfjoch_memory.o jfjoch_pcie_setup.o jfjoch_function.o jfjoch_miscdev.o
|
||||
jfjoch-y := jfjoch_drv.o jfjoch_ioctl.o jfjoch_memory.o jfjoch_pcie_setup.o jfjoch_function.o jfjoch_miscdev.o jfjoch_sysfs.o
|
||||
|
||||
all:
|
||||
make -C /lib/modules/$(shell uname -r)/build M=$(CURDIR) modules
|
||||
|
||||
@@ -83,9 +83,16 @@ static int jfjoch_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
|
||||
jfjoch_setup_cms(drvdata);
|
||||
jfjoch_setup_network(drvdata);
|
||||
|
||||
err = jfjoch_register_sysfs(drvdata);
|
||||
if (err)
|
||||
goto unregister_sysfs;
|
||||
|
||||
dev_info(drvdata->miscdev.this_device, "Jungfraujoch FPGA loaded with FW build: %x", drvdata->git_sha1);
|
||||
return 0;
|
||||
|
||||
unregister_sysfs:
|
||||
jfjoch_unregister_sysfs(drvdata);
|
||||
|
||||
deregister_misc:
|
||||
misc_deregister(&drvdata->miscdev);
|
||||
|
||||
@@ -119,6 +126,7 @@ static void jfjoch_pci_remove(struct pci_dev *pdev) {
|
||||
|
||||
pci_clear_master(pdev);
|
||||
|
||||
jfjoch_unregister_sysfs(drvdata);
|
||||
jfjoch_unregister_misc_dev(pdev);
|
||||
jfjoch_free_phys_continous_buf(pdev);
|
||||
pci_iounmap(pdev, drvdata->bar0);
|
||||
|
||||
@@ -142,6 +142,9 @@ void jfjoch_reset(struct jfjoch_drvdata *drvdata);
|
||||
void jfjoch_write_register(struct jfjoch_drvdata *drvdata, uint32_t addr, uint32_t val);
|
||||
uint32_t jfjoch_read_register(struct jfjoch_drvdata *drvdata, uint32_t addr);
|
||||
|
||||
int jfjoch_register_sysfs(struct jfjoch_drvdata *drvdata);
|
||||
void jfjoch_unregister_sysfs(struct jfjoch_drvdata *drvdata);
|
||||
|
||||
static const struct file_operations jfjoch_cdev_fileops = {
|
||||
.mmap = jfjoch_cdev_mmap,
|
||||
.unlocked_ioctl = jfjoch_cdev_ioctl,
|
||||
|
||||
@@ -10,7 +10,7 @@ int jfjoch_register_misc_dev(struct pci_dev *pdev) {
|
||||
struct jfjoch_drvdata *drvdata = pci_get_drvdata(pdev);
|
||||
|
||||
snprintf( drvdata->name, 255, "jfjoch%d", device_index++);
|
||||
|
||||
drvdata->miscdev.parent = &pdev->dev;
|
||||
drvdata->miscdev.mode = 0660;
|
||||
drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
|
||||
drvdata->miscdev.fops = &jfjoch_cdev_fileops;
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
// Copyright (2019-2023) Paul Scherrer Institute
|
||||
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "jfjoch_drv.h"
|
||||
|
||||
static ssize_t hbm0_temp_degC_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf) {
|
||||
struct miscdevice* miscdev = dev_get_drvdata(dev);
|
||||
struct jfjoch_drvdata* drvdata = container_of(miscdev, struct jfjoch_drvdata, miscdev);
|
||||
|
||||
unsigned int val = ioread32(drvdata->bar0 + CMS_OFFSET + ADDR_CMS_HBM_TEMP1_INS_REG);
|
||||
return scnprintf(buf, PAGE_SIZE, "%d", val);
|
||||
}
|
||||
|
||||
static ssize_t hbm1_temp_degC_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf) {
|
||||
struct miscdevice* miscdev = dev_get_drvdata(dev);
|
||||
struct jfjoch_drvdata* drvdata = container_of(miscdev, struct jfjoch_drvdata, miscdev);
|
||||
|
||||
unsigned int val = ioread32(drvdata->bar0 + CMS_OFFSET + ADDR_CMS_HBM_TEMP2_INS_REG);
|
||||
return scnprintf(buf, PAGE_SIZE, "%d", val);
|
||||
}
|
||||
|
||||
static ssize_t fpga_temp_degC_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf) {
|
||||
struct miscdevice* miscdev = dev_get_drvdata(dev);
|
||||
struct jfjoch_drvdata* drvdata = container_of(miscdev, struct jfjoch_drvdata, miscdev);
|
||||
|
||||
unsigned int val = ioread32(drvdata->bar0 + CMS_OFFSET + ADDR_CMS_FPGA_TEMP_INS_REG);
|
||||
return scnprintf(buf, PAGE_SIZE, "%d", val);
|
||||
}
|
||||
|
||||
static ssize_t fpga_power_mW_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf) {
|
||||
struct miscdevice* miscdev = dev_get_drvdata(dev);
|
||||
struct jfjoch_drvdata* drvdata = container_of(miscdev, struct jfjoch_drvdata, miscdev);
|
||||
|
||||
u32 fpga_pcie_3p3V_I_mA = ioread32(drvdata->bar0 + CMS_OFFSET + ADDR_CMS_3V3PEX_I_IN_INS_REG);
|
||||
u32 fpga_pcie_12V_I_mA = ioread32(drvdata->bar0 + CMS_OFFSET + ADDR_CMS_12VPEX_I_IN_INS_REG);
|
||||
u32 fpga_pcie_3p3V_V_mV = ioread32(drvdata->bar0 + CMS_OFFSET + ADDR_CMS_3V3_PEX_INS_REG);
|
||||
u32 fpga_pcie_12V_V_mV = ioread32(drvdata->bar0 + CMS_OFFSET + ADDR_CMS_12V_PEX_INS_REG);
|
||||
u32 power_mW = (fpga_pcie_3p3V_I_mA * fpga_pcie_3p3V_V_mV + fpga_pcie_12V_I_mA * fpga_pcie_12V_V_mV) / 1000;
|
||||
return scnprintf(buf, PAGE_SIZE, "%d", power_mW);
|
||||
}
|
||||
|
||||
static ssize_t status_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf) {
|
||||
struct miscdevice* miscdev = dev_get_drvdata(dev);
|
||||
struct jfjoch_drvdata* drvdata = container_of(miscdev, struct jfjoch_drvdata, miscdev);
|
||||
|
||||
unsigned int val = ioread32(drvdata->bar0 + ACTION_CONFIG_OFFSET + ADDR_CTRL_REGISTER);
|
||||
return scnprintf(buf, PAGE_SIZE, "%d", val);
|
||||
}
|
||||
|
||||
static ssize_t eth_aligned_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf) {
|
||||
struct miscdevice* miscdev = dev_get_drvdata(dev);
|
||||
struct jfjoch_drvdata* drvdata = container_of(miscdev, struct jfjoch_drvdata, miscdev);
|
||||
|
||||
// Need to ask twice to get recent answer
|
||||
ioread32(drvdata->bar0 + CMAC_OFFSET + 0x0204);
|
||||
unsigned int val = ioread32(drvdata->bar0 + CMAC_OFFSET + 0x0204) & 0x2;
|
||||
return scnprintf(buf, PAGE_SIZE, "%d", val);
|
||||
}
|
||||
|
||||
static ssize_t git_sha1_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf) {
|
||||
struct miscdevice* miscdev = dev_get_drvdata(dev);
|
||||
struct jfjoch_drvdata* drvdata = container_of(miscdev, struct jfjoch_drvdata, miscdev);
|
||||
return scnprintf(buf, PAGE_SIZE, "%x", drvdata->git_sha1);
|
||||
}
|
||||
|
||||
static ssize_t max_modules_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf) {
|
||||
struct miscdevice* miscdev = dev_get_drvdata(dev);
|
||||
struct jfjoch_drvdata* drvdata = container_of(miscdev, struct jfjoch_drvdata, miscdev);
|
||||
return scnprintf(buf, PAGE_SIZE, "%x", drvdata->max_modules);
|
||||
}
|
||||
|
||||
static ssize_t stalls_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf) {
|
||||
struct miscdevice* miscdev = dev_get_drvdata(dev);
|
||||
struct jfjoch_drvdata* drvdata = container_of(miscdev, struct jfjoch_drvdata, miscdev);
|
||||
|
||||
u64 val0 = ioread32(drvdata->bar0 + ACTION_CONFIG_OFFSET + ADDR_STALLS_HBM_LO);
|
||||
u64 val1 = ioread32(drvdata->bar0 + ACTION_CONFIG_OFFSET + ADDR_STALLS_HBM_HI);
|
||||
u64 val = (val1 << 32) | val0;
|
||||
return scnprintf(buf, PAGE_SIZE, "%lld", val);
|
||||
}
|
||||
|
||||
static ssize_t ipv4_addr_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf) {
|
||||
struct miscdevice* miscdev = dev_get_drvdata(dev);
|
||||
struct jfjoch_drvdata* drvdata = container_of(miscdev, struct jfjoch_drvdata, miscdev);
|
||||
|
||||
u32 val = ioread32((drvdata->bar0) + ACTION_CONFIG_OFFSET + ADDR_IPV4_ADDR);
|
||||
return scnprintf(buf, PAGE_SIZE, "0x%x", val);
|
||||
}
|
||||
|
||||
static ssize_t mac_addr_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf) {
|
||||
struct miscdevice* miscdev = dev_get_drvdata(dev);
|
||||
struct jfjoch_drvdata* drvdata = container_of(miscdev, struct jfjoch_drvdata, miscdev);
|
||||
|
||||
u64 val0 = ioread32(drvdata->bar0 + ACTION_CONFIG_OFFSET + ADDR_MAC_ADDR_LO);
|
||||
u64 val1 = ioread32(drvdata->bar0 + ACTION_CONFIG_OFFSET + ADDR_MAC_ADDR_HI);
|
||||
u64 val = (val1 << 32) | val0;
|
||||
return scnprintf(buf, PAGE_SIZE, "0x%llx", val);
|
||||
}
|
||||
|
||||
static ssize_t nbuffers_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf) {
|
||||
return scnprintf(buf, 25, "%d", nbuffer);
|
||||
}
|
||||
|
||||
static ssize_t release_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf) {
|
||||
return scnprintf(buf, 25, "%d", RELEASE_LEVEL);
|
||||
}
|
||||
|
||||
static struct device_attribute device_attrs[] = {
|
||||
__ATTR_RO(hbm0_temp_degC),
|
||||
__ATTR_RO(hbm1_temp_degC),
|
||||
__ATTR_RO(fpga_temp_degC),
|
||||
__ATTR_RO(fpga_power_mW),
|
||||
__ATTR_RO(nbuffers),
|
||||
__ATTR_RO(stalls),
|
||||
__ATTR_RO(status),
|
||||
__ATTR_RO(git_sha1),
|
||||
__ATTR_RO(release),
|
||||
__ATTR_RO(max_modules),
|
||||
__ATTR_RO(eth_aligned),
|
||||
__ATTR_RO(mac_addr),
|
||||
__ATTR_RO(ipv4_addr)
|
||||
};
|
||||
|
||||
int jfjoch_register_sysfs(struct jfjoch_drvdata *drvdata) {
|
||||
if (!drvdata)
|
||||
return -EINVAL;
|
||||
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
|
||||
err = device_create_file(drvdata->miscdev.this_device, &device_attrs[i]);
|
||||
if (err) {
|
||||
dev_err(drvdata->miscdev.this_device, "Failed to create sysfs file");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
while (--i >= 0)
|
||||
device_remove_file(drvdata->miscdev.this_device,
|
||||
&device_attrs[i]);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void jfjoch_unregister_sysfs(struct jfjoch_drvdata *drvdata) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
|
||||
device_remove_file(drvdata->miscdev.this_device, &device_attrs[i]);
|
||||
}
|
||||
Reference in New Issue
Block a user