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(PCI_SBDF(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(PCI_SBDF(seg, bus, dev, func), pos);
25         if ( pos < 0x40 )
26             break;
27 
28         pos &= ~3;
29         id = pci_conf_read8(PCI_SBDF(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(PCI_SBDF3(seg, bus, devfn), pos);
50         if ( pos < 0x40 )
51             break;
52 
53         pos &= ~3;
54         id = pci_conf_read8(PCI_SBDF3(seg, bus, devfn), pos + PCI_CAP_LIST_ID);
55 
56         if ( id == 0xff )
57             break;
58         if ( id == cap )
59             return pos;
60 
61         pos += PCI_CAP_LIST_NEXT;
62     }
63     return 0;
64 }
65 
66 /**
67  * pci_find_ext_capability - Find an extended capability
68  * @seg/@bus/@devfn: PCI device to query
69  * @cap: capability code
70  *
71  * Returns the address of the requested extended capability structure
72  * within the device's PCI configuration space or 0 if the device does
73  * not support it.
74  */
pci_find_ext_capability(int seg,int bus,int devfn,int cap)75 int pci_find_ext_capability(int seg, int bus, int devfn, int cap)
76 {
77     return pci_find_next_ext_capability(seg, bus, devfn, 0, cap);
78 }
79 
80 /**
81  * pci_find_next_ext_capability - Find another extended capability
82  * @seg/@bus/@devfn: PCI device to query
83  * @pos: starting position
84  * @cap: capability code
85  *
86  * Returns the address of the requested extended capability structure
87  * within the device's PCI configuration space or 0 if the device does
88  * not support it.
89  */
pci_find_next_ext_capability(int seg,int bus,int devfn,int start,int cap)90 int pci_find_next_ext_capability(int seg, int bus, int devfn, int start, int cap)
91 {
92     u32 header;
93     int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */
94     int pos = max(start, 0x100);
95 
96     header = pci_conf_read32(PCI_SBDF3(seg, bus, devfn), pos);
97 
98     /*
99      * If we have no capabilities, this is indicated by cap ID,
100      * cap version and next pointer all being 0.
101      */
102     if ( (header == 0) || (header == -1) )
103         return 0;
104     ASSERT(start != pos || PCI_EXT_CAP_ID(header) == cap);
105 
106     while ( ttl-- > 0 ) {
107         if ( PCI_EXT_CAP_ID(header) == cap && pos != start )
108             return pos;
109         pos = PCI_EXT_CAP_NEXT(header);
110         if ( pos < 0x100 )
111             break;
112         header = pci_conf_read32(PCI_SBDF3(seg, bus, devfn), pos);
113     }
114     return 0;
115 }
116 
pci_intx(const struct pci_dev * pdev,bool enable)117 void pci_intx(const struct pci_dev *pdev, bool enable)
118 {
119     uint16_t cmd = pci_conf_read16(pdev->sbdf, PCI_COMMAND);
120 
121     if ( enable )
122         cmd &= ~PCI_COMMAND_INTX_DISABLE;
123     else
124         cmd |= PCI_COMMAND_INTX_DISABLE;
125     pci_conf_write16(pdev->sbdf, PCI_COMMAND, cmd);
126 }
127 
parse_pci(const char * s,unsigned int * seg_p,unsigned int * bus_p,unsigned int * dev_p,unsigned int * func_p)128 const char *__init parse_pci(const char *s, unsigned int *seg_p,
129                              unsigned int *bus_p, unsigned int *dev_p,
130                              unsigned int *func_p)
131 {
132     bool def_seg;
133 
134     return parse_pci_seg(s, seg_p, bus_p, dev_p, func_p, &def_seg);
135 }
136 
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)137 const char *__init parse_pci_seg(const char *s, unsigned int *seg_p,
138                                  unsigned int *bus_p, unsigned int *dev_p,
139                                  unsigned int *func_p, bool *def_seg)
140 {
141     unsigned long seg = simple_strtoul(s, &s, 16), bus, dev, func;
142 
143     if ( *s != ':' )
144         return NULL;
145     bus = simple_strtoul(s + 1, &s, 16);
146     *def_seg = false;
147     if ( *s == ':' )
148         dev = simple_strtoul(s + 1, &s, 16);
149     else
150     {
151         dev = bus;
152         bus = seg;
153         seg = 0;
154         *def_seg = true;
155     }
156     if ( func_p )
157     {
158         if ( *s != '.' )
159             return NULL;
160         func = simple_strtoul(s + 1, &s, 0);
161     }
162     else
163         func = 0;
164     if ( seg != (seg_p ? (u16)seg : 0) ||
165          bus != PCI_BUS(PCI_BDF2(bus, 0)) ||
166          dev != PCI_SLOT(PCI_DEVFN(dev, 0)) ||
167          func != PCI_FUNC(PCI_DEVFN(0, func)) )
168         return NULL;
169 
170     if ( seg_p )
171         *seg_p = seg;
172     *bus_p = bus;
173     *dev_p = dev;
174     if ( func_p )
175         *func_p = func;
176 
177     return s;
178 }
179