25
25
#include <assert.h>
26
26
#include <errno.h>
27
27
#include <debug.h>
28
+ #include <sys/pciio.h>
29
+ #include <sys/endian.h>
28
30
29
31
#include <nuttx/kmalloc.h>
30
32
#include <nuttx/pci/pci.h>
113
115
(id)->subdevice == (dev)->subsystem_device) && \
114
116
(((id)->class ^ (dev)->class) & ((id)->class_mask == 0)))
115
117
118
+ /****************************************************************************
119
+ * Private Function Prototypes
120
+ ****************************************************************************/
121
+
122
+ static int pci_ioctl (FAR struct file * filep , int cmd , unsigned long arg );
123
+
116
124
/****************************************************************************
117
125
* Private Data
118
126
****************************************************************************/
@@ -125,6 +133,17 @@ static struct list_node g_pci_driver_list =
125
133
static struct list_node g_pci_ctrl_list =
126
134
LIST_INITIAL_VALUE (g_pci_ctrl_list );
127
135
136
+ static const struct file_operations g_pci_fops =
137
+ {
138
+ NULL , /* open */
139
+ NULL , /* close */
140
+ NULL , /* read */
141
+ NULL , /* write */
142
+ NULL , /* seek */
143
+ pci_ioctl , /* ioctl */
144
+ NULL , /* mmap */
145
+ };
146
+
128
147
/****************************************************************************
129
148
* Private Functions
130
149
****************************************************************************/
@@ -157,6 +176,219 @@ pci_do_find_device_from_bus(FAR struct pci_bus_s *bus, uint8_t busno,
157
176
return NULL ;
158
177
}
159
178
179
+ static int pci_vpd_read (FAR struct pci_bus_s * bus , uint32_t devfn ,
180
+ int offset , int count , FAR uint32_t * data )
181
+ {
182
+ uint8_t pos ;
183
+ int i ;
184
+
185
+ if (offset + count >= PCI_VPD_ADDR_MASK || data != NULL )
186
+ {
187
+ return - EINVAL ;
188
+ }
189
+
190
+ pos = pci_bus_find_capability (bus , devfn , PCI_CAP_ID_VPD );
191
+ if (pos == 0 )
192
+ {
193
+ return - ENOENT ;
194
+ }
195
+
196
+ for (i = 0 ; i < count ; i ++ , offset += 4 )
197
+ {
198
+ int j = 0 ;
199
+
200
+ pci_bus_write_config_word (bus , devfn , pos + PCI_VPD_ADDR , offset );
201
+
202
+ /**
203
+ * PCI 2.2 does not specify how long we should poll
204
+ * for completion nor whether the operation can fail.
205
+ */
206
+
207
+ for (; ; )
208
+ {
209
+ uint16_t addr ;
210
+
211
+ pci_bus_read_config_word (bus , devfn , pos + PCI_VPD_ADDR , & addr );
212
+ if (addr & PCI_VPD_ADDR_F )
213
+ {
214
+ break ;
215
+ }
216
+
217
+ if (++ j == 20 )
218
+ {
219
+ return - EIO ;
220
+ }
221
+
222
+ up_udelay (4 );
223
+ }
224
+
225
+ pci_bus_read_config_dword (bus , devfn , pos + PCI_VPD_DATA , & data [i ]);
226
+ data [i ] = le32toh (data [i ]);
227
+ }
228
+
229
+ return 0 ;
230
+ }
231
+
232
+ /****************************************************************************
233
+ * Name: pci_ioctl
234
+ *
235
+ * Description:
236
+ * for lspci read/write pci config space
237
+ *
238
+ * Input Parameters:
239
+ * filep - The open file description
240
+ * cmd - The cmd to read/write cmd
241
+ * arg - The arg to pass ioctl
242
+ * Returned Value:
243
+ * The length of the param
244
+ *
245
+ ****************************************************************************/
246
+
247
+ static int pci_ioctl (FAR struct file * filep , int cmd , unsigned long arg )
248
+ {
249
+ FAR struct pci_controller_s * ctrl ;
250
+ FAR struct pcisel * sel ;
251
+ uint32_t devfn ;
252
+ uint8_t i = 0 ;
253
+ int ret ;
254
+
255
+ sel = (FAR struct pcisel * )arg ;
256
+ devfn = PCI_DEVFN (sel -> pc_dev , sel -> pc_func );
257
+
258
+ ret = nxmutex_lock (& g_pci_lock );
259
+ if (ret < 0 )
260
+ {
261
+ return ret ;
262
+ }
263
+
264
+ list_for_every_entry (& g_pci_ctrl_list , ctrl , struct pci_controller_s , node )
265
+ {
266
+ if (i == sel -> pc_domain )
267
+ {
268
+ break ;
269
+ }
270
+
271
+ i ++ ;
272
+ }
273
+
274
+ nxmutex_unlock (& g_pci_lock );
275
+
276
+ if (i != sel -> pc_domain )
277
+ {
278
+ return - ENODEV ;
279
+ }
280
+
281
+ switch (cmd )
282
+ {
283
+ case PCIOCREAD :
284
+ {
285
+ FAR struct pci_io * io = (FAR struct pci_io * )arg ;
286
+ ret = pci_bus_read_config (ctrl -> bus , devfn , io -> pi_reg ,
287
+ io -> pi_width , & io -> pi_data );
288
+ break ;
289
+ }
290
+
291
+ case PCIOCWRITE :
292
+ {
293
+ FAR struct pci_io * io = (FAR struct pci_io * )arg ;
294
+ ret = pci_bus_write_config (ctrl -> bus , devfn , io -> pi_reg ,
295
+ io -> pi_width , io -> pi_data );
296
+ break ;
297
+ }
298
+
299
+ case PCIOCGETROMLEN :
300
+ {
301
+ FAR struct pci_rom * rom = (FAR struct pci_rom * )arg ;
302
+ FAR struct pci_device_s * dev =
303
+ pci_find_device_from_bus (ctrl -> bus , sel -> pc_bus , devfn );
304
+ if (dev == NULL )
305
+ {
306
+ return - ENODEV ;
307
+ }
308
+
309
+ rom -> pr_romlen = pci_resource_len (dev , PCI_ROM_RESOURCE );
310
+ ret = 0 ;
311
+ break ;
312
+ }
313
+
314
+ case PCIOCGETROM :
315
+ {
316
+ FAR void * p ;
317
+ uint32_t addr ;
318
+ uint32_t len ;
319
+
320
+ FAR struct pci_rom * rom = (FAR struct pci_rom * )arg ;
321
+ FAR struct pci_device_s * dev =
322
+ pci_find_device_from_bus (ctrl -> bus , sel -> pc_bus , devfn );
323
+ if (dev == NULL )
324
+ {
325
+ return - ENODEV ;
326
+ }
327
+
328
+ addr = pci_resource_start (dev , PCI_ROM_RESOURCE );
329
+ len = pci_resource_len (dev , PCI_ROM_RESOURCE );
330
+ if (rom -> pr_romlen < len )
331
+ {
332
+ rom -> pr_romlen = len ;
333
+ ret = - E2BIG ;
334
+ break ;
335
+ }
336
+
337
+ p = pci_map_bar (dev , PCI_ROM_RESOURCE );
338
+ if (p == NULL )
339
+ {
340
+ ret = - ENOENT ;
341
+ break ;
342
+ }
343
+
344
+ pci_bus_write_config_dword (ctrl -> bus , devfn , PCI_ROM_ADDRESS ,
345
+ addr | PCI_ROM_ADDRESS_ENABLE );
346
+ memcpy (rom -> pr_rom , p , len );
347
+ pci_bus_write_config_dword (ctrl -> bus , devfn ,
348
+ PCI_ROM_ADDRESS , addr );
349
+ break ;
350
+ }
351
+
352
+ case PCIOCREADMASK :
353
+ {
354
+ uint32_t data ;
355
+
356
+ FAR struct pci_io * io = (FAR struct pci_io * )arg ;
357
+ if (io -> pi_width != 4 || (io -> pi_reg & 0x3 ) ||
358
+ io -> pi_reg < PCI_BASE_ADDRESS_0 ||
359
+ io -> pi_reg >= PCI_BASE_ADDRESS_SPACE )
360
+ {
361
+ ret = - EINVAL ;
362
+ break ;
363
+ }
364
+
365
+ pci_bus_read_config_dword (ctrl -> bus , devfn , io -> pi_reg , & data );
366
+ pci_bus_write_config_dword (ctrl -> bus , devfn , io -> pi_reg ,
367
+ 0xffffffff );
368
+ pci_bus_read_config_dword (ctrl -> bus , devfn ,
369
+ io -> pi_reg , & io -> pi_data );
370
+ pci_bus_write_config_dword (ctrl -> bus , devfn , io -> pi_reg , data );
371
+ break ;
372
+ }
373
+
374
+ case PCIOCGETVPD :
375
+ {
376
+ FAR struct pci_vpd_req * pv = (FAR struct pci_vpd_req * )arg ;
377
+ ret = pci_vpd_read (ctrl -> bus , devfn , pv -> pv_offset ,
378
+ pv -> pv_count , pv -> pv_data );
379
+ break ;
380
+ }
381
+
382
+ default :
383
+ {
384
+ ret = - ENOTTY ;
385
+ break ;
386
+ }
387
+ }
388
+
389
+ return ret ;
390
+ }
391
+
160
392
/****************************************************************************
161
393
* Name: pci_change_master
162
394
*
@@ -1427,6 +1659,22 @@ uint8_t pci_bus_find_capability(FAR struct pci_bus_s *bus,
1427
1659
return pos ;
1428
1660
}
1429
1661
1662
+ /****************************************************************************
1663
+ * Name: pci_dev_register
1664
+ *
1665
+ * Description:
1666
+ * Create an pci dev driver.
1667
+ *
1668
+ * Returned Value:
1669
+ * Zero (OK) on success; A negated errno value on failure.
1670
+ *
1671
+ ****************************************************************************/
1672
+
1673
+ int pci_dev_register (void )
1674
+ {
1675
+ return register_driver ("/dev/pci" , & g_pci_fops , 0666 , NULL );
1676
+ }
1677
+
1430
1678
PCI_BUS_READ_CONFIG (byte , uint8_t , 1 )
1431
1679
PCI_BUS_READ_CONFIG (word , uint16_t , 2 )
1432
1680
PCI_BUS_READ_CONFIG (dword , uint32_t , 4 )
0 commit comments