xref: /linux/drivers/xen/xen-pciback/conf_space_header.c (revision c4ee0af3fa0dc65f690fc908f02b8355f9576ea0)
1 /*
2  * PCI Backend - Handles the virtual fields in the configuration space headers.
3  *
4  * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
5  */
6 
7 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8 
9 #include <linux/kernel.h>
10 #include <linux/pci.h>
11 #include "pciback.h"
12 #include "conf_space.h"
13 
14 struct pci_bar_info {
15 	u32 val;
16 	u32 len_val;
17 	int which;
18 };
19 
20 #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
21 #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
22 
23 static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
24 {
25 	int i;
26 	int ret;
27 
28 	ret = xen_pcibk_read_config_word(dev, offset, value, data);
29 	if (!pci_is_enabled(dev))
30 		return ret;
31 
32 	for (i = 0; i < PCI_ROM_RESOURCE; i++) {
33 		if (dev->resource[i].flags & IORESOURCE_IO)
34 			*value |= PCI_COMMAND_IO;
35 		if (dev->resource[i].flags & IORESOURCE_MEM)
36 			*value |= PCI_COMMAND_MEMORY;
37 	}
38 
39 	return ret;
40 }
41 
42 static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
43 {
44 	struct xen_pcibk_dev_data *dev_data;
45 	int err;
46 
47 	dev_data = pci_get_drvdata(dev);
48 	if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
49 		if (unlikely(verbose_request))
50 			printk(KERN_DEBUG DRV_NAME ": %s: enable\n",
51 			       pci_name(dev));
52 		err = pci_enable_device(dev);
53 		if (err)
54 			return err;
55 		if (dev_data)
56 			dev_data->enable_intx = 1;
57 	} else if (pci_is_enabled(dev) && !is_enable_cmd(value)) {
58 		if (unlikely(verbose_request))
59 			printk(KERN_DEBUG DRV_NAME ": %s: disable\n",
60 			       pci_name(dev));
61 		pci_disable_device(dev);
62 		if (dev_data)
63 			dev_data->enable_intx = 0;
64 	}
65 
66 	if (!dev->is_busmaster && is_master_cmd(value)) {
67 		if (unlikely(verbose_request))
68 			printk(KERN_DEBUG DRV_NAME ": %s: set bus master\n",
69 			       pci_name(dev));
70 		pci_set_master(dev);
71 	}
72 
73 	if (value & PCI_COMMAND_INVALIDATE) {
74 		if (unlikely(verbose_request))
75 			printk(KERN_DEBUG
76 			       DRV_NAME ": %s: enable memory-write-invalidate\n",
77 			       pci_name(dev));
78 		err = pci_set_mwi(dev);
79 		if (err) {
80 			pr_warn("%s: cannot enable memory-write-invalidate (%d)\n",
81 				pci_name(dev), err);
82 			value &= ~PCI_COMMAND_INVALIDATE;
83 		}
84 	}
85 
86 	return pci_write_config_word(dev, offset, value);
87 }
88 
89 static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
90 {
91 	struct pci_bar_info *bar = data;
92 
93 	if (unlikely(!bar)) {
94 		pr_warn(DRV_NAME ": driver data not found for %s\n",
95 		       pci_name(dev));
96 		return XEN_PCI_ERR_op_failed;
97 	}
98 
99 	/* A write to obtain the length must happen as a 32-bit write.
100 	 * This does not (yet) support writing individual bytes
101 	 */
102 	if (value == ~PCI_ROM_ADDRESS_ENABLE)
103 		bar->which = 1;
104 	else {
105 		u32 tmpval;
106 		pci_read_config_dword(dev, offset, &tmpval);
107 		if (tmpval != bar->val && value == bar->val) {
108 			/* Allow restoration of bar value. */
109 			pci_write_config_dword(dev, offset, bar->val);
110 		}
111 		bar->which = 0;
112 	}
113 
114 	/* Do we need to support enabling/disabling the rom address here? */
115 
116 	return 0;
117 }
118 
119 /* For the BARs, only allow writes which write ~0 or
120  * the correct resource information
121  * (Needed for when the driver probes the resource usage)
122  */
123 static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
124 {
125 	struct pci_bar_info *bar = data;
126 
127 	if (unlikely(!bar)) {
128 		pr_warn(DRV_NAME ": driver data not found for %s\n",
129 		       pci_name(dev));
130 		return XEN_PCI_ERR_op_failed;
131 	}
132 
133 	/* A write to obtain the length must happen as a 32-bit write.
134 	 * This does not (yet) support writing individual bytes
135 	 */
136 	if (value == ~0)
137 		bar->which = 1;
138 	else {
139 		u32 tmpval;
140 		pci_read_config_dword(dev, offset, &tmpval);
141 		if (tmpval != bar->val && value == bar->val) {
142 			/* Allow restoration of bar value. */
143 			pci_write_config_dword(dev, offset, bar->val);
144 		}
145 		bar->which = 0;
146 	}
147 
148 	return 0;
149 }
150 
151 static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
152 {
153 	struct pci_bar_info *bar = data;
154 
155 	if (unlikely(!bar)) {
156 		pr_warn(DRV_NAME ": driver data not found for %s\n",
157 		       pci_name(dev));
158 		return XEN_PCI_ERR_op_failed;
159 	}
160 
161 	*value = bar->which ? bar->len_val : bar->val;
162 
163 	return 0;
164 }
165 
166 static inline void read_dev_bar(struct pci_dev *dev,
167 				struct pci_bar_info *bar_info, int offset,
168 				u32 len_mask)
169 {
170 	int	pos;
171 	struct resource	*res = dev->resource;
172 
173 	if (offset == PCI_ROM_ADDRESS || offset == PCI_ROM_ADDRESS1)
174 		pos = PCI_ROM_RESOURCE;
175 	else {
176 		pos = (offset - PCI_BASE_ADDRESS_0) / 4;
177 		if (pos && ((res[pos - 1].flags & (PCI_BASE_ADDRESS_SPACE |
178 				PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
179 			   (PCI_BASE_ADDRESS_SPACE_MEMORY |
180 				PCI_BASE_ADDRESS_MEM_TYPE_64))) {
181 			bar_info->val = res[pos - 1].start >> 32;
182 			bar_info->len_val = res[pos - 1].end >> 32;
183 			return;
184 		}
185 	}
186 
187 	bar_info->val = res[pos].start |
188 			(res[pos].flags & PCI_REGION_FLAG_MASK);
189 	bar_info->len_val = resource_size(&res[pos]);
190 }
191 
192 static void *bar_init(struct pci_dev *dev, int offset)
193 {
194 	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
195 
196 	if (!bar)
197 		return ERR_PTR(-ENOMEM);
198 
199 	read_dev_bar(dev, bar, offset, ~0);
200 	bar->which = 0;
201 
202 	return bar;
203 }
204 
205 static void *rom_init(struct pci_dev *dev, int offset)
206 {
207 	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
208 
209 	if (!bar)
210 		return ERR_PTR(-ENOMEM);
211 
212 	read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
213 	bar->which = 0;
214 
215 	return bar;
216 }
217 
218 static void bar_reset(struct pci_dev *dev, int offset, void *data)
219 {
220 	struct pci_bar_info *bar = data;
221 
222 	bar->which = 0;
223 }
224 
225 static void bar_release(struct pci_dev *dev, int offset, void *data)
226 {
227 	kfree(data);
228 }
229 
230 static int xen_pcibk_read_vendor(struct pci_dev *dev, int offset,
231 			       u16 *value, void *data)
232 {
233 	*value = dev->vendor;
234 
235 	return 0;
236 }
237 
238 static int xen_pcibk_read_device(struct pci_dev *dev, int offset,
239 			       u16 *value, void *data)
240 {
241 	*value = dev->device;
242 
243 	return 0;
244 }
245 
246 static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
247 			  void *data)
248 {
249 	*value = (u8) dev->irq;
250 
251 	return 0;
252 }
253 
254 static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
255 {
256 	u8 cur_value;
257 	int err;
258 
259 	err = pci_read_config_byte(dev, offset, &cur_value);
260 	if (err)
261 		goto out;
262 
263 	if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
264 	    || value == PCI_BIST_START)
265 		err = pci_write_config_byte(dev, offset, value);
266 
267 out:
268 	return err;
269 }
270 
271 static const struct config_field header_common[] = {
272 	{
273 	 .offset    = PCI_VENDOR_ID,
274 	 .size      = 2,
275 	 .u.w.read  = xen_pcibk_read_vendor,
276 	},
277 	{
278 	 .offset    = PCI_DEVICE_ID,
279 	 .size      = 2,
280 	 .u.w.read  = xen_pcibk_read_device,
281 	},
282 	{
283 	 .offset    = PCI_COMMAND,
284 	 .size      = 2,
285 	 .u.w.read  = command_read,
286 	 .u.w.write = command_write,
287 	},
288 	{
289 	 .offset    = PCI_INTERRUPT_LINE,
290 	 .size      = 1,
291 	 .u.b.read  = interrupt_read,
292 	},
293 	{
294 	 .offset    = PCI_INTERRUPT_PIN,
295 	 .size      = 1,
296 	 .u.b.read  = xen_pcibk_read_config_byte,
297 	},
298 	{
299 	 /* Any side effects of letting driver domain control cache line? */
300 	 .offset    = PCI_CACHE_LINE_SIZE,
301 	 .size      = 1,
302 	 .u.b.read  = xen_pcibk_read_config_byte,
303 	 .u.b.write = xen_pcibk_write_config_byte,
304 	},
305 	{
306 	 .offset    = PCI_LATENCY_TIMER,
307 	 .size      = 1,
308 	 .u.b.read  = xen_pcibk_read_config_byte,
309 	},
310 	{
311 	 .offset    = PCI_BIST,
312 	 .size      = 1,
313 	 .u.b.read  = xen_pcibk_read_config_byte,
314 	 .u.b.write = bist_write,
315 	},
316 	{}
317 };
318 
319 #define CFG_FIELD_BAR(reg_offset)			\
320 	{						\
321 	.offset     = reg_offset,			\
322 	.size       = 4,				\
323 	.init       = bar_init,				\
324 	.reset      = bar_reset,			\
325 	.release    = bar_release,			\
326 	.u.dw.read  = bar_read,				\
327 	.u.dw.write = bar_write,			\
328 	}
329 
330 #define CFG_FIELD_ROM(reg_offset)			\
331 	{						\
332 	.offset     = reg_offset,			\
333 	.size       = 4,				\
334 	.init       = rom_init,				\
335 	.reset      = bar_reset,			\
336 	.release    = bar_release,			\
337 	.u.dw.read  = bar_read,				\
338 	.u.dw.write = rom_write,			\
339 	}
340 
341 static const struct config_field header_0[] = {
342 	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
343 	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
344 	CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
345 	CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
346 	CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
347 	CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
348 	CFG_FIELD_ROM(PCI_ROM_ADDRESS),
349 	{}
350 };
351 
352 static const struct config_field header_1[] = {
353 	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
354 	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
355 	CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
356 	{}
357 };
358 
359 int xen_pcibk_config_header_add_fields(struct pci_dev *dev)
360 {
361 	int err;
362 
363 	err = xen_pcibk_config_add_fields(dev, header_common);
364 	if (err)
365 		goto out;
366 
367 	switch (dev->hdr_type) {
368 	case PCI_HEADER_TYPE_NORMAL:
369 		err = xen_pcibk_config_add_fields(dev, header_0);
370 		break;
371 
372 	case PCI_HEADER_TYPE_BRIDGE:
373 		err = xen_pcibk_config_add_fields(dev, header_1);
374 		break;
375 
376 	default:
377 		err = -EINVAL;
378 		pr_err("%s: Unsupported header type %d!\n",
379 		       pci_name(dev), dev->hdr_type);
380 		break;
381 	}
382 
383 out:
384 	return err;
385 }
386