Skip to content

Commit b70922c

Browse files
lipengfei28xiaoxiang781216
authored andcommitted
pci: add ioctl for userspace
which is same as OpenBSD: https://github.com/openbsd/src/blob/master/sys/sys/pciio.h Signed-off-by: lipengfei28 <[email protected]>
1 parent dba7700 commit b70922c

File tree

3 files changed

+331
-0
lines changed

3 files changed

+331
-0
lines changed

drivers/pci/pci.c

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include <assert.h>
2626
#include <errno.h>
2727
#include <debug.h>
28+
#include <sys/pciio.h>
29+
#include <sys/endian.h>
2830

2931
#include <nuttx/kmalloc.h>
3032
#include <nuttx/pci/pci.h>
@@ -113,6 +115,12 @@
113115
(id)->subdevice == (dev)->subsystem_device) && \
114116
(((id)->class ^ (dev)->class) & ((id)->class_mask == 0)))
115117

118+
/****************************************************************************
119+
* Private Function Prototypes
120+
****************************************************************************/
121+
122+
static int pci_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
123+
116124
/****************************************************************************
117125
* Private Data
118126
****************************************************************************/
@@ -125,6 +133,17 @@ static struct list_node g_pci_driver_list =
125133
static struct list_node g_pci_ctrl_list =
126134
LIST_INITIAL_VALUE(g_pci_ctrl_list);
127135

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+
128147
/****************************************************************************
129148
* Private Functions
130149
****************************************************************************/
@@ -157,6 +176,219 @@ pci_do_find_device_from_bus(FAR struct pci_bus_s *bus, uint8_t busno,
157176
return NULL;
158177
}
159178

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+
160392
/****************************************************************************
161393
* Name: pci_change_master
162394
*
@@ -1427,6 +1659,22 @@ uint8_t pci_bus_find_capability(FAR struct pci_bus_s *bus,
14271659
return pos;
14281660
}
14291661

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+
14301678
PCI_BUS_READ_CONFIG(byte, uint8_t, 1)
14311679
PCI_BUS_READ_CONFIG(word, uint16_t, 2)
14321680
PCI_BUS_READ_CONFIG(dword, uint32_t, 4)

include/nuttx/fs/ioctl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
#define _SYSLOGBASE (0x3c00) /* Syslog device ioctl commands */
101101
#define _STEPIOBASE (0x3d00) /* Stepper device ioctl commands */
102102
#define _FPGACFGBASE (0x3e00) /* FPGA configuration ioctl commands */
103+
#define _PCIBASE (0x4100) /* Pci ioctl commands */
103104
#define _WLIOCBASE (0x8b00) /* Wireless modules ioctl network commands */
104105

105106
/* boardctl() commands share the same number space */
@@ -710,6 +711,11 @@
710711
#define _FPGACFGVALID(c) (_IOC_TYPE(c) == _FPGACFGBASE)
711712
#define _FPGACFGIOC(nr) _IOC(_FPGACFGBASE, nr)
712713

714+
/* Pci controller drivers ***************************************************/
715+
716+
#define _PCIIOCVALID(c) (_IOC_TYPE(c)==_PCIBASE)
717+
#define _PCIIOC(nr) _IOC(_PCIBASE,nr)
718+
713719
/****************************************************************************
714720
* Public Type Definitions
715721
****************************************************************************/

include/sys/pciio.h

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/****************************************************************************
2+
* include/sys/pciio.h
3+
*
4+
* Licensed to the Apache Software Foundation (ASF) under one or more
5+
* contributor license agreements. See the NOTICE file distributed with
6+
* this work for additional information regarding copyright ownership. The
7+
* ASF licenses this file to you under the Apache License, Version 2.0 (the
8+
* "License"); you may not use this file except in compliance with the
9+
* License. You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
* License for the specific language governing permissions and limitations
17+
* under the License.
18+
*
19+
****************************************************************************/
20+
21+
#ifndef __INCLUDE_SYS_PCIIO_H
22+
#define __INCLUDE_SYS_PCIIO_H
23+
24+
/****************************************************************************
25+
* Included Files
26+
****************************************************************************/
27+
28+
#include <nuttx/fs/ioctl.h>
29+
#include <stdint.h>
30+
31+
/****************************************************************************
32+
* Pre-processor Definitions
33+
****************************************************************************/
34+
35+
#define PCIOCREAD _PCIIOC(1)
36+
#define PCIOCWRITE _PCIIOC(2)
37+
#define PCIOCGETROMLEN _PCIIOC(3)
38+
#define PCIOCGETROM _PCIIOC(4)
39+
#define PCIOCREADMASK _PCIIOC(5)
40+
#define PCIOCGETVPD _PCIIOC(6)
41+
42+
/****************************************************************************
43+
* Public Type Declarations
44+
****************************************************************************/
45+
46+
struct pcisel
47+
{
48+
uint8_t pc_domain;
49+
uint8_t pc_bus;
50+
uint8_t pc_dev;
51+
uint8_t pc_func;
52+
};
53+
54+
struct pci_io
55+
{
56+
struct pcisel pi_sel;
57+
int pi_reg;
58+
int pi_width;
59+
uint32_t pi_data;
60+
};
61+
62+
struct pci_rom
63+
{
64+
struct pcisel pr_sel;
65+
int pr_romlen;
66+
FAR char *pr_rom;
67+
};
68+
69+
struct pci_vpd_req
70+
{
71+
struct pcisel pv_sel;
72+
int pv_offset;
73+
int pv_count;
74+
FAR uint32_t *pv_data;
75+
};
76+
77+
#endif /* __INCLUDE_SYS_PCIIO_H */

0 commit comments

Comments
 (0)