pci.h revision 1.1.2.12 1 /* $NetBSD: pci.h,v 1.1.2.12 2013/07/24 03:20:05 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2013 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Taylor R. Campbell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #ifndef _LINUX_PCI_H_
33 #define _LINUX_PCI_H_
34
35 #include <sys/types.h>
36 #include <sys/bus.h>
37 #include <sys/kmem.h>
38 #include <sys/systm.h>
39
40 #include <dev/pci/pcidevs.h>
41 #include <dev/pci/pcireg.h>
42 #include <dev/pci/pcivar.h>
43
44 #include <linux/ioport.h>
45
46 struct pci_bus;
47
48 struct pci_device_id {
49 uint32_t vendor;
50 uint32_t device;
51 uint32_t subvendor;
52 uint32_t subdevice;
53 uint32_t class;
54 uint32_t class_mask;
55 unsigned long driver_data;
56 };
57
58 #define PCI_ANY_ID ((pcireg_t)-1)
59
60 #define PCI_BASE_CLASS_DISPLAY PCI_CLASS_DISPLAY
61
62 #define PCI_CLASS_BRIDGE_ISA PCI_SUBCLASS_BRIDGE_ISA
63
64 #define PCI_VENDOR_ID_INTEL PCI_VENDOR_INTEL
65
66 struct pci_dev {
67 struct pci_attach_args pd_pa;
68 bool pd_kludged; /* XXX pci_kludgey_find_dev */
69 device_t pd_dev;
70 struct pci_bus *bus;
71 uint32_t devfn;
72 uint16_t vendor;
73 uint16_t device;
74 uint16_t subsystem_vendor;
75 uint16_t subsystem_device;
76 uint8_t revision;
77 uint32_t class;
78 bool msi_enabled;
79 };
80
81 static inline device_t
82 pci_dev_dev(struct pci_dev *pdev)
83 {
84 return pdev->pd_dev;
85 }
86
87 #define PCI_DEVFN(DEV, FN) \
88 (__SHIFTIN((DEV), __BITS(3, 7)) | __SHIFTIN((FN), __BITS(0, 2)))
89 #define PCI_SLOT(DEVFN) __SHIFTOUT((DEVFN), __BITS(3, 7))
90 #define PCI_FUNC(DEVFN) __SHIFTOUT((DEVFN), __BITS(0, 2))
91
92 #define PCI_CAP_ID_AGP PCI_CAP_AGP
93
94 static inline int
95 pci_find_capability(struct pci_dev *pdev, int cap)
96 {
97 return pci_get_capability(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, cap,
98 NULL, NULL);
99 }
100
101 static inline void
102 pci_read_config_dword(struct pci_dev *pdev, int reg, uint32_t *valuep)
103 {
104 KASSERT(!ISSET(reg, 3));
105 *valuep = pci_conf_read(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, reg);
106 }
107
108 static inline void
109 pci_read_config_word(struct pci_dev *pdev, int reg, uint16_t *valuep)
110 {
111 KASSERT(!ISSET(reg, 1));
112 *valuep = pci_conf_read(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag,
113 (reg &~ 3)) >> (8 * (reg & 3));
114 }
115
116 static inline void
117 pci_read_config_byte(struct pci_dev *pdev, int reg, uint8_t *valuep)
118 {
119 *valuep = pci_conf_read(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag,
120 (reg &~ 1)) >> (8 * (reg & 1));
121 }
122
123 static inline void
124 pci_write_config_dword(struct pci_dev *pdev, int reg, uint32_t value)
125 {
126 KASSERT(!ISSET(reg, 3));
127 pci_conf_write(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, reg, value);
128 }
129
130 static inline void
131 pci_rmw_config(struct pci_dev *pdev, int reg, unsigned int bytes,
132 uint32_t value)
133 {
134 const uint32_t mask = ~((~0UL) << (8 * bytes));
135 const int reg32 = (reg &~ 3);
136 const unsigned int shift = (8 * (reg & 3));
137 uint32_t value32;
138
139 KASSERT(bytes <= 4);
140 KASSERT(!ISSET(value, ~mask));
141 pci_read_config_dword(pdev, reg32, &value32);
142 value32 &=~ (mask << shift);
143 value32 |= (value << shift);
144 pci_write_config_dword(pdev, reg32, value32);
145 }
146
147 static inline void
148 pci_write_config_word(struct pci_dev *pdev, int reg, uint16_t value)
149 {
150 KASSERT(!ISSET(reg, 1));
151 pci_rmw_config(pdev, reg, 2, value);
152 }
153
154 static inline void
155 pci_write_config_byte(struct pci_dev *pdev, int reg, uint8_t value)
156 {
157 pci_rmw_config(pdev, reg, 1, value);
158 }
159
160 /*
161 * XXX pci msi
162 */
163 static inline void
164 pci_enable_msi(struct pci_dev *pdev)
165 {
166 KASSERT(!pdev->msi_enabled);
167 pdev->msi_enabled = true;
168 }
169
170 static inline void
171 pci_disable_msi(struct pci_dev *pdev)
172 {
173 KASSERT(pdev->msi_enabled);
174 pdev->msi_enabled = false;
175 }
176
177 static inline void
178 pci_set_master(struct pci_dev *pdev)
179 {
180 pcireg_t csr;
181
182 csr = pci_conf_read(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag,
183 PCI_COMMAND_STATUS_REG);
184 csr |= PCI_COMMAND_MASTER_ENABLE;
185 pci_conf_write(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag,
186 PCI_COMMAND_STATUS_REG, csr);
187 }
188
189 #define PCIBIOS_MIN_MEM 0 /* XXX bogus x86 kludge bollocks */
190
191 static inline bus_addr_t
192 pcibios_align_resource(void *p, const struct resource *resource,
193 bus_addr_t addr, bus_size_t size)
194 {
195 panic("pcibios_align_resource has accessed unaligned neurons!");
196 }
197
198 static inline int
199 pci_bus_alloc_resource(struct pci_bus *bus, struct resource *resource,
200 bus_size_t size, bus_size_t align, bus_addr_t start, int type __unused,
201 bus_addr_t (*align_fn)(void *, const struct resource *, bus_addr_t,
202 bus_size_t) __unused,
203 struct pci_dev *pdev)
204 {
205 const struct pci_attach_args *const pa = &pdev->pd_pa;
206 bus_space_tag_t bst;
207 int error;
208
209 switch (resource->flags) {
210 case IORESOURCE_MEM:
211 bst = pa->pa_memt;
212 break;
213
214 case IORESOURCE_IO:
215 bst = pa->pa_iot;
216 break;
217
218 default:
219 panic("I don't know what kind of resource you want!");
220 }
221
222 resource->r_bst = bst;
223 error = bus_space_alloc(bst, start, 0xffffffffffffffffULL /* XXX */,
224 size, align, 0, 0, &resource->start, &resource->r_bsh);
225 if (error)
226 return error;
227
228 resource->size = size;
229 return 0;
230 }
231
232 /*
233 * XXX Mega-kludgerific!
234 *
235 * XXX Doesn't check whether any such device actually exists.
236 */
237
238 static inline struct pci_dev *
239 pci_kludgey_find_dev(struct pci_dev *pdev, int bus, int dev, int func)
240 {
241 struct pci_dev *const otherdev = kmem_zalloc(sizeof(*otherdev),
242 KM_SLEEP);
243
244 #ifdef DIAGNOSTIC
245 {
246 int obus, odev, ofunc;
247
248 pci_decompose_tag(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, &obus,
249 &odev, &ofunc);
250 KASSERT(obus == bus);
251 }
252 #endif
253
254 otherdev->bus = NULL; /* XXX struct pci_dev::bus */
255 otherdev->device = dev;
256 otherdev->pd_pa = pdev->pd_pa;
257 otherdev->pd_pa.pa_tag = pci_make_tag(otherdev->pd_pa.pa_pc,
258 bus, dev, func);
259 otherdev->pd_kludged = true;
260
261 return otherdev;
262 }
263
264 static inline void
265 pci_dev_put(struct pci_dev *pdev)
266 {
267
268 KASSERT(pdev->pd_kludged);
269 kmem_free(pdev, sizeof(*pdev));
270 }
271
272 #endif /* _LINUX_PCI_H_ */
273