Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
conf_space_header.c
Go to the documentation of this file.
1 /*
2  * PCI Backend - Handles the virtual fields in the configuration space headers.
3  *
4  * Author: Ryan Wilson <[email protected]>
5  */
6 
7 #include <linux/kernel.h>
8 #include <linux/pci.h>
9 #include "pciback.h"
10 #include "conf_space.h"
11 
12 struct pci_bar_info {
15  int which;
16 };
17 
18 #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
19 #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
20 
21 static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
22 {
23  int i;
24  int ret;
25 
26  ret = xen_pcibk_read_config_word(dev, offset, value, data);
27  if (!pci_is_enabled(dev))
28  return ret;
29 
30  for (i = 0; i < PCI_ROM_RESOURCE; i++) {
31  if (dev->resource[i].flags & IORESOURCE_IO)
32  *value |= PCI_COMMAND_IO;
33  if (dev->resource[i].flags & IORESOURCE_MEM)
34  *value |= PCI_COMMAND_MEMORY;
35  }
36 
37  return ret;
38 }
39 
40 static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
41 {
43  int err;
44 
45  dev_data = pci_get_drvdata(dev);
46  if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
47  if (unlikely(verbose_request))
48  printk(KERN_DEBUG DRV_NAME ": %s: enable\n",
49  pci_name(dev));
50  err = pci_enable_device(dev);
51  if (err)
52  return err;
53  if (dev_data)
54  dev_data->enable_intx = 1;
55  } else if (pci_is_enabled(dev) && !is_enable_cmd(value)) {
56  if (unlikely(verbose_request))
57  printk(KERN_DEBUG DRV_NAME ": %s: disable\n",
58  pci_name(dev));
59  pci_disable_device(dev);
60  if (dev_data)
61  dev_data->enable_intx = 0;
62  }
63 
64  if (!dev->is_busmaster && is_master_cmd(value)) {
65  if (unlikely(verbose_request))
66  printk(KERN_DEBUG DRV_NAME ": %s: set bus master\n",
67  pci_name(dev));
68  pci_set_master(dev);
69  }
70 
71  if (value & PCI_COMMAND_INVALIDATE) {
72  if (unlikely(verbose_request))
74  DRV_NAME ": %s: enable memory-write-invalidate\n",
75  pci_name(dev));
76  err = pci_set_mwi(dev);
77  if (err) {
79  DRV_NAME ": %s: cannot enable "
80  "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  printk(KERN_WARNING 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  printk(KERN_WARNING 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  printk(KERN_WARNING 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 |
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[] = {
349  {}
350 };
351 
352 static const struct config_field header_1[] = {
356  {}
357 };
358 
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) {
369  err = xen_pcibk_config_add_fields(dev, header_0);
370  break;
371 
373  err = xen_pcibk_config_add_fields(dev, header_1);
374  break;
375 
376  default:
377  err = -EINVAL;
378  printk(KERN_ERR DRV_NAME ": %s: Unsupported header type %d!\n",
379  pci_name(dev), dev->hdr_type);
380  break;
381  }
382 
383 out:
384  return err;
385 }