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