1 /******************************************************************************
2  * pci.c
3  *
4  * Architecture-independent PCI access functions.
5  */
6 
7 #include <xen/init.h>
8 #include <xen/pci.h>
9 #include <xen/pci_regs.h>
10 
pci_find_cap_offset(u16 seg,u8 bus,u8 dev,u8 func,u8 cap)11 int pci_find_cap_offset(u16 seg, u8 bus, u8 dev, u8 func, u8 cap)
12 {
13     u8 id;
14     int max_cap = 48;
15     u8 pos = PCI_CAPABILITY_LIST;
16     u16 status;
17 
18     status = pci_conf_read16(seg, bus, dev, func, PCI_STATUS);
19     if ( (status & PCI_STATUS_CAP_LIST) == 0 )
20         return 0;
21 
22     while ( max_cap-- )
23     {
24         pos = pci_conf_read8(seg, bus, dev, func, pos);
25         if ( pos < 0x40 )
26             break;
27 
28         pos &= ~3;
29         id = pci_conf_read8(seg, bus, dev, func, pos + PCI_CAP_LIST_ID);
30 
31         if ( id == 0xff )
32             break;
33         else if ( id == cap )
34             return pos;
35 
36         pos += PCI_CAP_LIST_NEXT;
37     }
38 
39     return 0;
40 }
41 
pci_find_next_cap(u16 seg,u8 bus,unsigned int devfn,u8 pos,int cap)42 int pci_find_next_cap(u16 seg, u8 bus, unsigned int devfn, u8 pos, int cap)
43 {
44     u8 id;
45     int ttl = 48;
46 
47     while ( ttl-- )
48     {
49         pos = pci_conf_read8(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
50         if ( pos < 0x40 )
51             break;
52 
53         pos &= ~3;
54         id = pci_conf_read8(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
55                             pos + PCI_CAP_LIST_ID);
56 
57         if ( id == 0xff )
58             break;
59         if ( id == cap )
60             return pos;
61 
62         pos += PCI_CAP_LIST_NEXT;
63     }
64     return 0;
65 }
66 
67 /**
68  * pci_find_ext_capability - Find an extended capability
69  * @seg/@bus/@devfn: PCI device to query
70  * @cap: capability code
71  *
72  * Returns the address of the requested extended capability structure
73  * within the device's PCI configuration space or 0 if the device does
74  * not support it.
75  */
pci_find_ext_capability(int seg,int bus,int devfn,int cap)76 int pci_find_ext_capability(int seg, int bus, int devfn, int cap)
77 {
78     return pci_find_next_ext_capability(seg, bus, devfn, 0, cap);
79 }
80 
81 /**
82  * pci_find_next_ext_capability - Find another extended capability
83  * @seg/@bus/@devfn: PCI device to query
84  * @pos: starting position
85  * @cap: capability code
86  *
87  * Returns the address of the requested extended capability structure
88  * within the device's PCI configuration space or 0 if the device does
89  * not support it.
90  */
pci_find_next_ext_capability(int seg,int bus,int devfn,int start,int cap)91 int pci_find_next_ext_capability(int seg, int bus, int devfn, int start, int cap)
92 {
93     u32 header;
94     int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */
95     int pos = max(start, 0x100);
96 
97     header = pci_conf_read32(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
98 
99     /*
100      * If we have no capabilities, this is indicated by cap ID,
101      * cap version and next pointer all being 0.
102      */
103     if ( (header == 0) || (header == -1) )
104         return 0;
105     ASSERT(start != pos || PCI_EXT_CAP_ID(header) == cap);
106 
107     while ( ttl-- > 0 ) {
108         if ( PCI_EXT_CAP_ID(header) == cap && pos != start )
109             return pos;
110         pos = PCI_EXT_CAP_NEXT(header);
111         if ( pos < 0x100 )
112             break;
113         header = pci_conf_read32(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
114     }
115     return 0;
116 }
117 
parse_pci(const char * s,unsigned int * seg_p,unsigned int * bus_p,unsigned int * dev_p,unsigned int * func_p)118 const char *__init parse_pci(const char *s, unsigned int *seg_p,
119                              unsigned int *bus_p, unsigned int *dev_p,
120                              unsigned int *func_p)
121 {
122     bool def_seg;
123 
124     return parse_pci_seg(s, seg_p, bus_p, dev_p, func_p, &def_seg);
125 }
126 
parse_pci_seg(const char * s,unsigned int * seg_p,unsigned int * bus_p,unsigned int * dev_p,unsigned int * func_p,bool * def_seg)127 const char *__init parse_pci_seg(const char *s, unsigned int *seg_p,
128                                  unsigned int *bus_p, unsigned int *dev_p,
129                                  unsigned int *func_p, bool *def_seg)
130 {
131     unsigned long seg = simple_strtoul(s, &s, 16), bus, dev, func;
132 
133     if ( *s != ':' )
134         return NULL;
135     bus = simple_strtoul(s + 1, &s, 16);
136     *def_seg = false;
137     if ( *s == ':' )
138         dev = simple_strtoul(s + 1, &s, 16);
139     else
140     {
141         dev = bus;
142         bus = seg;
143         seg = 0;
144         *def_seg = true;
145     }
146     if ( func_p )
147     {
148         if ( *s != '.' )
149             return NULL;
150         func = simple_strtoul(s + 1, &s, 0);
151     }
152     else
153         func = 0;
154     if ( seg != (seg_p ? (u16)seg : 0) ||
155          bus != PCI_BUS(PCI_BDF2(bus, 0)) ||
156          dev != PCI_SLOT(PCI_DEVFN(dev, 0)) ||
157          func != PCI_FUNC(PCI_DEVFN(0, func)) )
158         return NULL;
159 
160     if ( seg_p )
161         *seg_p = seg;
162     *bus_p = bus;
163     *dev_p = dev;
164     if ( func_p )
165         *func_p = func;
166 
167     return s;
168 }
169