summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuEe-GUI <[email protected]>2025-04-17 14:32:07 +0800
committerRbb666 <[email protected]>2025-05-23 13:22:25 +0800
commit99fc1bb72b81b8da744ef8eb89d6a9e1d28716ce (patch)
treefaca89001415e3ab1081ac43b98a2cd6b840bc86
parent51b6df9c16b2261d7d4f0f7caa84d869b52fbd66 (diff)
[DM/PCI] Add /proc access in RT-Smart user.
1. Add ROM base info. 2. Save th PM status. Signed-off-by: GuEe-GUI <[email protected]>
-rw-r--r--components/drivers/include/drivers/pci.h3
-rw-r--r--components/drivers/pci/SConscript3
-rw-r--r--components/drivers/pci/pci.c4
-rw-r--r--components/drivers/pci/pme.c1
-rw-r--r--components/drivers/pci/probe.c5
-rw-r--r--components/drivers/pci/procfs.c371
-rw-r--r--components/drivers/pci/procfs.h31
7 files changed, 418 insertions, 0 deletions
diff --git a/components/drivers/include/drivers/pci.h b/components/drivers/include/drivers/pci.h
index 1ae439351c..414a0abf1a 100644
--- a/components/drivers/include/drivers/pci.h
+++ b/components/drivers/include/drivers/pci.h
@@ -157,7 +157,10 @@ struct rt_pci_device
rt_uint8_t pin;
struct rt_pic *intx_pic;
+ rt_bool_t pm_enabled;
+
struct rt_pci_bus_resource resource[RT_PCI_BAR_NR_MAX];
+ struct rt_pci_bus_resource rom;
rt_uint8_t pme_cap;
rt_uint8_t msi_cap;
diff --git a/components/drivers/pci/SConscript b/components/drivers/pci/SConscript
index dfe3797e5b..7379160502 100644
--- a/components/drivers/pci/SConscript
+++ b/components/drivers/pci/SConscript
@@ -14,6 +14,9 @@ src = ['access.c', 'host-bridge.c', 'irq.c', 'pci.c', 'pme.c', 'probe.c']
if GetDepend(['RT_USING_OFW']):
src += ['ofw.c']
+if GetDepend(['RT_USING_DFS_PROCFS']):
+ src += ['procfs.c']
+
if GetDepend(['RT_PCI_ECAM']):
src += ['ecam.c']
diff --git a/components/drivers/pci/pci.c b/components/drivers/pci/pci.c
index 369856e0e9..3ba3967e7d 100644
--- a/components/drivers/pci/pci.c
+++ b/components/drivers/pci/pci.c
@@ -695,6 +695,10 @@ rt_err_t rt_pci_device_alloc_resource(struct rt_pci_host_bridge *host_bridge,
rt_pci_write_config_u32(pdev, rom_addr, addr);
}
command |= PCIM_CMD_MEMEN;
+
+ pdev->rom.base = addr;
+ pdev->rom.size = size;
+ pdev->rom.flags = PCI_BUS_REGION_F_MEM;
}
}
diff --git a/components/drivers/pci/pme.c b/components/drivers/pci/pme.c
index b4278d3321..8deb25dc5e 100644
--- a/components/drivers/pci/pme.c
+++ b/components/drivers/pci/pme.c
@@ -107,6 +107,7 @@ static void pci_pme_active(struct rt_pci_device *pdev, rt_bool_t enable)
}
rt_pci_write_config_u16(pdev, pdev->pme_cap + PCIR_POWER_STATUS, pmcsr);
+ pdev->pm_enabled = enable;
}
void rt_pci_pme_active(struct rt_pci_device *pdev, rt_bool_t enable)
diff --git a/components/drivers/pci/probe.c b/components/drivers/pci/probe.c
index fc15eaae7e..e197be4b56 100644
--- a/components/drivers/pci/probe.c
+++ b/components/drivers/pci/probe.c
@@ -17,6 +17,8 @@
#include <drivers/pci.h>
#include <drivers/core/bus.h>
+#include "procfs.h"
+
rt_inline void spin_lock(struct rt_spinlock *spinlock)
{
rt_hw_spin_lock(&spinlock->lock);
@@ -146,6 +148,7 @@ struct rt_pci_device *rt_pci_scan_single_device(struct rt_pci_bus *bus, rt_uint3
goto _end;
}
+ pci_procfs_attach(pdev);
rt_pci_device_register(pdev);
_end:
@@ -901,6 +904,8 @@ rt_err_t rt_pci_device_remove(struct rt_pci_device *pdev)
{
struct rt_pci_bus *bus = pdev->bus;
+ pci_procfs_detach(pdev);
+
spin_lock(&bus->lock);
while (pdev->parent.ref_count > 1)
diff --git a/components/drivers/pci/procfs.c b/components/drivers/pci/procfs.c
new file mode 100644
index 0000000000..b2ce0b057b
--- /dev/null
+++ b/components/drivers/pci/procfs.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-07-07 GuEe-GUI first version
+ */
+
+#include <rtdef.h>
+#include <drivers/byteorder.h>
+
+#define DBG_TAG "pci.procfs"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include "procfs.h"
+#ifdef RT_USING_LWP
+#include <lwp_user_mm.h>
+#endif
+
+static struct rt_bus *pci_bus;
+static struct proc_dentry *pci_proc_dentry;
+
+rt_inline void copy_to_user(void *to, void *from, size_t size)
+{
+#ifdef RT_USING_LWP
+ if (!lwp_put_to_user(to, from, size))
+#endif
+ {
+ rt_memcpy(to, from, size);
+ }
+}
+
+rt_inline void copy_from_user(void *to, const void *from, size_t size)
+{
+#ifdef RT_USING_LWP
+ if (!lwp_get_from_user(to, (void *)from, size))
+#endif
+ {
+ rt_memcpy(to, (void *)from, size);
+ }
+}
+
+static void pci_pm_runtime_get(struct rt_pci_device *pdev, rt_ubase_t *out_flags)
+{
+ *out_flags = pdev->pm_enabled;
+
+ if (!pdev->pm_enabled)
+ {
+ rt_pci_pme_active(pdev, RT_TRUE);
+ }
+}
+
+static void pci_pm_runtime_put(struct rt_pci_device *pdev, rt_ubase_t *flags)
+{
+ if (!*flags)
+ {
+ rt_pci_pme_active(pdev, RT_FALSE);
+ }
+}
+
+static ssize_t pci_read(struct dfs_file *file, void *buf, size_t count, off_t *ppos)
+{
+ off_t pos = *ppos;
+ size_t res = count;
+ rt_ubase_t pm_flags;
+ struct proc_dentry *dentry = file->vnode->data;
+ struct rt_pci_device *pdev = dentry->data;
+
+ pci_pm_runtime_get(pdev, &pm_flags);
+
+ if ((pos & 1) && count)
+ {
+ rt_uint8_t val;
+
+ rt_pci_read_config_u8(pdev, pos, &val);
+ copy_to_user(buf, &val, sizeof(val));
+
+ ++buf;
+ ++pos;
+ --count;
+ }
+
+ if ((pos & 3) && count > 2)
+ {
+ rt_uint16_t val;
+
+ rt_pci_read_config_u16(pdev, pos, &val);
+
+ val = rt_cpu_to_le16(val);
+ copy_to_user(buf, &val, sizeof(val));
+
+ buf += 2;
+ pos += 2;
+ count -= 2;
+ }
+
+ while (count >= 4)
+ {
+ rt_uint32_t val;
+
+ rt_pci_read_config_u32(pdev, pos, &val);
+
+ val = rt_cpu_to_le32(val);
+ copy_to_user(buf, &val, sizeof(val));
+
+ buf += 4;
+ pos += 4;
+ count -= 4;
+ }
+
+ if (count >= 2)
+ {
+ rt_uint16_t val;
+
+ rt_pci_read_config_u16(pdev, pos, &val);
+
+ val = rt_cpu_to_le16(val);
+ copy_to_user(buf, &val, sizeof(val));
+
+ buf += 2;
+ pos += 2;
+ count -= 2;
+ }
+
+ if (count)
+ {
+ rt_uint8_t val;
+
+ rt_pci_read_config_u8(pdev, pos, &val);
+ copy_to_user(buf, &val, sizeof(val));
+
+ ++pos;
+ }
+
+ pci_pm_runtime_put(pdev, &pm_flags);
+
+ *ppos = pos;
+
+ return res;
+}
+
+static ssize_t pci_write(struct dfs_file *file, const void *buf, size_t count, off_t *ppos)
+{
+ off_t pos = *ppos;
+ size_t res = count;
+ rt_ubase_t pm_flags;
+ struct proc_dentry *dentry = file->vnode->data;
+ struct rt_pci_device *pdev = dentry->data;
+
+ pci_pm_runtime_get(pdev, &pm_flags);
+
+ if ((pos & 1) && count)
+ {
+ rt_uint8_t val;
+
+ copy_from_user(&val, buf, sizeof(val));
+ rt_pci_write_config_u8(pdev, pos, val);
+
+ ++buf;
+ ++pos;
+ --count;
+ }
+
+ if ((pos & 3) && count > 2)
+ {
+ rt_le16_t val;
+
+ copy_from_user(&val, buf, sizeof(val));
+ rt_pci_write_config_u16(pdev, pos, rt_le16_to_cpu(val));
+
+ buf += 2;
+ pos += 2;
+ count -= 2;
+ }
+
+ while (count >= 4)
+ {
+ rt_le32_t val;
+
+ copy_from_user(&val, buf, sizeof(val));
+ rt_pci_write_config_u32(pdev, pos, rt_le32_to_cpu(val));
+
+ buf += 4;
+ pos += 4;
+ count -= 4;
+ }
+
+ if (count >= 2)
+ {
+ rt_le16_t val;
+
+ copy_from_user(&val, buf, sizeof(val));
+ rt_pci_write_config_u16(pdev, pos, rt_le16_to_cpu(val));
+
+ buf += 2;
+ pos += 2;
+ count -= 2;
+ }
+
+ if (count)
+ {
+ rt_uint8_t val;
+
+ copy_from_user(&val, buf, sizeof(val));
+ rt_pci_write_config_u8(pdev, pos, val);
+
+ ++pos;
+ }
+
+ pci_pm_runtime_put(pdev, &pm_flags);
+
+ *ppos = pos;
+
+ return res;
+}
+
+static off_t pci_lseek(struct dfs_file *file, off_t offset, int wherece)
+{
+ struct proc_dentry *dentry = file->vnode->data;
+ struct rt_pci_device *pdev = dentry->data;
+
+ switch (wherece)
+ {
+ case SEEK_SET:
+ break;
+
+ case SEEK_CUR:
+ offset += file->fpos;
+ break;
+
+ case SEEK_END:
+ offset += pdev->cfg_size;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (offset <= (off_t)pdev->cfg_size)
+ {
+ return offset;
+ }
+
+ return -EIO;
+}
+
+static const struct dfs_file_ops pci_fops =
+{
+ .read = pci_read,
+ .write = pci_write,
+ .lseek = pci_lseek,
+};
+
+void pci_procfs_attach(struct rt_pci_device *pdev)
+{
+ const char *name;
+ struct proc_dentry *dentry;
+
+ if (!pci_proc_dentry)
+ {
+ return;
+ }
+
+ name = rt_dm_dev_get_name(&pdev->parent);
+ dentry = proc_create_data(name, 0644, pci_proc_dentry, &pci_fops, pdev);
+
+ if (!dentry)
+ {
+ LOG_E("Create %s file fail", name);
+ return;
+ }
+ proc_release(dentry);
+}
+
+void pci_procfs_detach(struct rt_pci_device *pdev)
+{
+ if (!pci_proc_dentry)
+ {
+ return;
+ }
+
+ proc_remove_dentry(rt_dm_dev_get_name(&pdev->parent), pci_proc_dentry);
+}
+
+static int pci_single_show(struct dfs_seq_file *seq, void *data)
+{
+ struct rt_device *dev;
+ struct rt_pci_driver *pdrv;
+ struct rt_pci_device *pdev;
+
+ rt_hw_spin_lock(&pci_bus->dev_lock.lock);
+
+ rt_list_for_each_entry(dev, &pci_bus->dev_list, node)
+ {
+ pdev = rt_container_of(dev, struct rt_pci_device, parent);
+
+ dfs_seq_printf(seq, "%02x%02x\t%04x%04x\t%x",
+ pdev->bus->number,
+ pdev->devfn,
+ pdev->vendor,
+ pdev->device,
+ pdev->irq);
+
+ /* BAR, ROM base */
+ for (int bar = 0; bar < RT_PCI_BAR_NR_MAX; ++bar)
+ {
+ dfs_seq_printf(seq, "\t%16llx", (rt_uint64_t)pdev->resource[bar].base);
+ }
+ dfs_seq_printf(seq, "\t%16llx", (rt_uint64_t)pdev->rom.base);
+
+ /* BAR, ROM size */
+ for (int bar = 0; bar < RT_PCI_BAR_NR_MAX; ++bar)
+ {
+ dfs_seq_printf(seq, "\t%16llx", (rt_uint64_t)pdev->resource[bar].size);
+ }
+ dfs_seq_printf(seq, "\t%16llx", (rt_uint64_t)pdev->rom.size);
+
+ dfs_seq_puts(seq, "\t");
+
+ /* Driver Name */
+ if (dev->drv)
+ {
+ pdrv = rt_container_of(dev->drv, struct rt_pci_driver, parent);
+
+ dfs_seq_puts(seq, pdrv->name);
+ }
+
+ /* End of a seq */
+ dfs_seq_puts(seq, "\n");
+ }
+
+ rt_hw_spin_unlock(&pci_bus->dev_lock.lock);
+
+ return 0;
+}
+
+static int pci_procfs_init(void)
+{
+ struct proc_dentry *dentry;
+
+ pci_bus = rt_bus_find_by_name("pci");
+
+ RT_ASSERT(pci_bus != RT_NULL);
+
+ pci_proc_dentry = proc_mkdir("pci", RT_NULL);
+
+ if (!pci_proc_dentry)
+ {
+ LOG_E("Create pci entry fail");
+ return (int)-RT_ERROR;
+ }
+ proc_release(pci_proc_dentry);
+
+ dentry = proc_create_single_data("devices", 0644, pci_proc_dentry, &pci_single_show, NULL);
+
+ if (!dentry)
+ {
+ proc_remove(pci_proc_dentry);
+ pci_proc_dentry = RT_NULL;
+
+ LOG_E("Create pci devices fail");
+ return (int)-RT_ERROR;
+ }
+ proc_release(dentry);
+
+ return 0;
+}
+INIT_PREV_EXPORT(pci_procfs_init);
diff --git a/components/drivers/pci/procfs.h b/components/drivers/pci/procfs.h
new file mode 100644
index 0000000000..8059538a04
--- /dev/null
+++ b/components/drivers/pci/procfs.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-07-07 GuEe-GUI first version
+ */
+
+#ifndef __PCI_PROCFS_H__
+#define __PCI_PROCFS_H__
+
+#include <drivers/pci.h>
+
+#ifdef RT_USING_DFS_PROCFS
+#include <proc.h>
+
+void pci_procfs_attach(struct rt_pci_device *pdev);
+void pci_procfs_detach(struct rt_pci_device *pdev);
+#else
+rt_inline void pci_procfs_attach(struct rt_pci_device *pdev)
+{
+}
+
+rt_inline void pci_procfs_detach(struct rt_pci_device *pdev)
+{
+}
+#endif /* RT_USING_DFS_PROCFS */
+
+#endif /* __PCI_PROCFS_H__ */