diff --git a/components/drivers/include/drivers/pci.h b/components/drivers/include/drivers/pci.h index 1ae439351cb..414a0abf1ad 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 dfe3797e5b0..73791605024 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 369856e0e99..3ba3967e7d8 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 b4278d3321f..8deb25dc5e9 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 fc15eaae7e2..e197be4b565 100644 --- a/components/drivers/pci/probe.c +++ b/components/drivers/pci/probe.c @@ -17,6 +17,8 @@ #include #include +#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 00000000000..b2ce0b057b0 --- /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 +#include + +#define DBG_TAG "pci.procfs" +#define DBG_LVL DBG_INFO +#include + +#include "procfs.h" +#ifdef RT_USING_LWP +#include +#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 00000000000..8059538a04e --- /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 + +#ifdef RT_USING_DFS_PROCFS +#include + +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__ */