1 /*
2  * Copyright (c) 2006-2022, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2024-07-07     GuEe-GUI     first version
9  */
10 
11 #include <rtdef.h>
12 #include <drivers/byteorder.h>
13 
14 #define DBG_TAG "pci.procfs"
15 #define DBG_LVL DBG_INFO
16 #include <rtdbg.h>
17 
18 #include "procfs.h"
19 #ifdef RT_USING_LWP
20 #include <lwp_user_mm.h>
21 #endif
22 
23 static struct rt_bus *pci_bus;
24 static struct proc_dentry *pci_proc_dentry;
25 
copy_to_user(void * to,void * from,size_t size)26 rt_inline void copy_to_user(void *to, void *from, size_t size)
27 {
28 #ifdef RT_USING_LWP
29     if (!lwp_put_to_user(to, from, size))
30 #endif
31     {
32         rt_memcpy(to, from, size);
33     }
34 }
35 
copy_from_user(void * to,const void * from,size_t size)36 rt_inline void copy_from_user(void *to, const void *from, size_t size)
37 {
38 #ifdef RT_USING_LWP
39     if (!lwp_get_from_user(to, (void *)from, size))
40 #endif
41     {
42         rt_memcpy(to, (void *)from, size);
43     }
44 }
45 
pci_pm_runtime_get(struct rt_pci_device * pdev,rt_ubase_t * out_flags)46 static void pci_pm_runtime_get(struct rt_pci_device *pdev, rt_ubase_t *out_flags)
47 {
48     *out_flags = pdev->pm_enabled;
49 
50     if (!pdev->pm_enabled)
51     {
52         rt_pci_pme_active(pdev, RT_TRUE);
53     }
54 }
55 
pci_pm_runtime_put(struct rt_pci_device * pdev,rt_ubase_t * flags)56 static void pci_pm_runtime_put(struct rt_pci_device *pdev, rt_ubase_t *flags)
57 {
58     if (!*flags)
59     {
60         rt_pci_pme_active(pdev, RT_FALSE);
61     }
62 }
63 
pci_read(struct dfs_file * file,void * buf,size_t count,off_t * ppos)64 static ssize_t pci_read(struct dfs_file *file, void *buf, size_t count, off_t *ppos)
65 {
66     off_t pos = *ppos;
67     size_t res = count;
68     rt_ubase_t pm_flags;
69     struct proc_dentry *dentry = file->vnode->data;
70     struct rt_pci_device *pdev = dentry->data;
71 
72     pci_pm_runtime_get(pdev, &pm_flags);
73 
74     if ((pos & 1) && count)
75     {
76         rt_uint8_t val;
77 
78         rt_pci_read_config_u8(pdev, pos, &val);
79         copy_to_user(buf, &val, sizeof(val));
80 
81         ++buf;
82         ++pos;
83         --count;
84     }
85 
86     if ((pos & 3) && count > 2)
87     {
88         rt_uint16_t val;
89 
90         rt_pci_read_config_u16(pdev, pos, &val);
91 
92         val = rt_cpu_to_le16(val);
93         copy_to_user(buf, &val, sizeof(val));
94 
95         buf += 2;
96         pos += 2;
97         count -= 2;
98     }
99 
100     while (count >= 4)
101     {
102         rt_uint32_t val;
103 
104         rt_pci_read_config_u32(pdev, pos, &val);
105 
106         val = rt_cpu_to_le32(val);
107         copy_to_user(buf, &val, sizeof(val));
108 
109         buf += 4;
110         pos += 4;
111         count -= 4;
112     }
113 
114     if (count >= 2)
115     {
116         rt_uint16_t val;
117 
118         rt_pci_read_config_u16(pdev, pos, &val);
119 
120         val = rt_cpu_to_le16(val);
121         copy_to_user(buf, &val, sizeof(val));
122 
123         buf += 2;
124         pos += 2;
125         count -= 2;
126     }
127 
128     if (count)
129     {
130         rt_uint8_t val;
131 
132         rt_pci_read_config_u8(pdev, pos, &val);
133         copy_to_user(buf, &val, sizeof(val));
134 
135         ++pos;
136     }
137 
138     pci_pm_runtime_put(pdev, &pm_flags);
139 
140     *ppos = pos;
141 
142     return res;
143 }
144 
pci_write(struct dfs_file * file,const void * buf,size_t count,off_t * ppos)145 static ssize_t pci_write(struct dfs_file *file, const void *buf, size_t count, off_t *ppos)
146 {
147     off_t pos = *ppos;
148     size_t res = count;
149     rt_ubase_t pm_flags;
150     struct proc_dentry *dentry = file->vnode->data;
151     struct rt_pci_device *pdev = dentry->data;
152 
153     pci_pm_runtime_get(pdev, &pm_flags);
154 
155     if ((pos & 1) && count)
156     {
157         rt_uint8_t val;
158 
159         copy_from_user(&val, buf, sizeof(val));
160         rt_pci_write_config_u8(pdev, pos, val);
161 
162         ++buf;
163         ++pos;
164         --count;
165     }
166 
167     if ((pos & 3) && count > 2)
168     {
169         rt_le16_t val;
170 
171         copy_from_user(&val, buf, sizeof(val));
172         rt_pci_write_config_u16(pdev, pos, rt_le16_to_cpu(val));
173 
174         buf += 2;
175         pos += 2;
176         count -= 2;
177     }
178 
179     while (count >= 4)
180     {
181         rt_le32_t val;
182 
183         copy_from_user(&val, buf, sizeof(val));
184         rt_pci_write_config_u32(pdev, pos, rt_le32_to_cpu(val));
185 
186         buf += 4;
187         pos += 4;
188         count -= 4;
189     }
190 
191     if (count >= 2)
192     {
193         rt_le16_t val;
194 
195         copy_from_user(&val, buf, sizeof(val));
196         rt_pci_write_config_u16(pdev, pos, rt_le16_to_cpu(val));
197 
198         buf += 2;
199         pos += 2;
200         count -= 2;
201     }
202 
203     if (count)
204     {
205         rt_uint8_t val;
206 
207         copy_from_user(&val, buf, sizeof(val));
208         rt_pci_write_config_u8(pdev, pos, val);
209 
210         ++pos;
211     }
212 
213     pci_pm_runtime_put(pdev, &pm_flags);
214 
215     *ppos = pos;
216 
217     return res;
218 }
219 
pci_lseek(struct dfs_file * file,off_t offset,int wherece)220 static off_t pci_lseek(struct dfs_file *file, off_t offset, int wherece)
221 {
222     struct proc_dentry *dentry = file->vnode->data;
223     struct rt_pci_device *pdev = dentry->data;
224 
225     switch (wherece)
226     {
227     case SEEK_SET:
228         break;
229 
230     case SEEK_CUR:
231         offset += file->fpos;
232         break;
233 
234     case SEEK_END:
235         offset += pdev->cfg_size;
236         break;
237 
238     default:
239         return -EINVAL;
240     }
241 
242     if (offset <= (off_t)pdev->cfg_size)
243     {
244         return offset;
245     }
246 
247     return -EIO;
248 }
249 
250 static const struct dfs_file_ops pci_fops =
251 {
252     .read = pci_read,
253     .write = pci_write,
254     .lseek = pci_lseek,
255 };
256 
pci_procfs_attach(struct rt_pci_device * pdev)257 void pci_procfs_attach(struct rt_pci_device *pdev)
258 {
259     const char *name;
260     struct proc_dentry *dentry;
261 
262     if (!pci_proc_dentry)
263     {
264         return;
265     }
266 
267     name = rt_dm_dev_get_name(&pdev->parent);
268     dentry = proc_create_data(name, 0644, pci_proc_dentry, &pci_fops, pdev);
269 
270     if (!dentry)
271     {
272         LOG_E("Create %s file fail", name);
273         return;
274     }
275     proc_release(dentry);
276 }
277 
pci_procfs_detach(struct rt_pci_device * pdev)278 void pci_procfs_detach(struct rt_pci_device *pdev)
279 {
280     if (!pci_proc_dentry)
281     {
282         return;
283     }
284 
285     proc_remove_dentry(rt_dm_dev_get_name(&pdev->parent), pci_proc_dentry);
286 }
287 
pci_single_show(struct dfs_seq_file * seq,void * data)288 static int pci_single_show(struct dfs_seq_file *seq, void *data)
289 {
290     struct rt_device *dev;
291     struct rt_pci_driver *pdrv;
292     struct rt_pci_device *pdev;
293 
294     rt_hw_spin_lock(&pci_bus->dev_lock.lock);
295 
296     rt_list_for_each_entry(dev, &pci_bus->dev_list, node)
297     {
298         pdev = rt_container_of(dev, struct rt_pci_device, parent);
299 
300         dfs_seq_printf(seq, "%02x%02x\t%04x%04x\t%x",
301                 pdev->bus->number,
302                 pdev->devfn,
303                 pdev->vendor,
304                 pdev->device,
305                 pdev->irq);
306 
307         /* BAR, ROM base */
308         for (int bar = 0; bar < RT_PCI_BAR_NR_MAX; ++bar)
309         {
310             dfs_seq_printf(seq, "\t%16llx", (rt_uint64_t)pdev->resource[bar].base);
311         }
312         dfs_seq_printf(seq, "\t%16llx", (rt_uint64_t)pdev->rom.base);
313 
314         /* BAR, ROM size */
315         for (int bar = 0; bar < RT_PCI_BAR_NR_MAX; ++bar)
316         {
317             dfs_seq_printf(seq, "\t%16llx", (rt_uint64_t)pdev->resource[bar].size);
318         }
319         dfs_seq_printf(seq, "\t%16llx", (rt_uint64_t)pdev->rom.size);
320 
321         dfs_seq_puts(seq, "\t");
322 
323         /* Driver Name */
324         if (dev->drv)
325         {
326             pdrv = rt_container_of(dev->drv, struct rt_pci_driver, parent);
327 
328             dfs_seq_puts(seq, pdrv->name);
329         }
330 
331         /* End of a seq */
332         dfs_seq_puts(seq, "\n");
333     }
334 
335     rt_hw_spin_unlock(&pci_bus->dev_lock.lock);
336 
337     return 0;
338 }
339 
pci_procfs_init(void)340 static int pci_procfs_init(void)
341 {
342     struct proc_dentry *dentry;
343 
344     pci_bus = rt_bus_find_by_name("pci");
345 
346     RT_ASSERT(pci_bus != RT_NULL);
347 
348     pci_proc_dentry = proc_mkdir("pci", RT_NULL);
349 
350     if (!pci_proc_dentry)
351     {
352         LOG_E("Create pci entry fail");
353         return (int)-RT_ERROR;
354     }
355     proc_release(pci_proc_dentry);
356 
357     dentry = proc_create_single_data("devices", 0644, pci_proc_dentry, &pci_single_show, NULL);
358 
359     if (!dentry)
360     {
361         proc_remove(pci_proc_dentry);
362         pci_proc_dentry = RT_NULL;
363 
364         LOG_E("Create pci devices fail");
365         return (int)-RT_ERROR;
366     }
367     proc_release(dentry);
368 
369     return 0;
370 }
371 INIT_PREV_EXPORT(pci_procfs_init);
372