fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / xen / pciback / conf_space_header.c
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 #include <linux/kernel.h>
8 #include <linux/pci.h>
9 #include "pciback.h"
10 #include "conf_space.h"
11
12 struct pci_bar_info {
13         u32 val;
14         u32 len_val;
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_write(struct pci_dev *dev, int offset, u16 value, void *data)
22 {
23         if (!atomic_read(&dev->enable_cnt) && is_enable_cmd(value)) {
24                 if (unlikely(verbose_request))
25                         printk(KERN_DEBUG "pciback: %s: enable\n",
26                                pci_name(dev));
27                 if (pci_enable_device(dev))
28                         return -ENODEV;
29         } else if (atomic_read(&dev->enable_cnt) && !is_enable_cmd(value)) {
30                 if (unlikely(verbose_request))
31                         printk(KERN_DEBUG "pciback: %s: disable\n",
32                                pci_name(dev));
33                 pci_disable_device(dev);
34         }
35
36         if (!dev->is_busmaster && is_master_cmd(value)) {
37                 if (unlikely(verbose_request))
38                         printk(KERN_DEBUG "pciback: %s: set bus master\n",
39                                pci_name(dev));
40                 pci_set_master(dev);
41         }
42
43         if (value & PCI_COMMAND_INVALIDATE) {
44                 if (unlikely(verbose_request))
45                         printk(KERN_DEBUG
46                                "pciback: %s: enable memory-write-invalidate\n",
47                                pci_name(dev));
48                 if (pci_set_mwi(dev))
49                         return -EINVAL;
50         }
51
52         return pci_write_config_word(dev, offset, value);
53 }
54
55 static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
56 {
57         struct pci_bar_info *bar = data;
58
59         if (unlikely(!bar)) {
60                 printk(KERN_WARNING "pciback: driver data not found for %s\n",
61                        pci_name(dev));
62                 return XEN_PCI_ERR_op_failed;
63         }
64
65         /* A write to obtain the length must happen as a 32-bit write.
66          * This does not (yet) support writing individual bytes
67          */
68         if (value == ~PCI_ROM_ADDRESS_ENABLE)
69                 bar->which = 1;
70         else
71                 bar->which = 0;
72
73         /* Do we need to support enabling/disabling the rom address here? */
74
75         return 0;
76 }
77
78 /* For the BARs, only allow writes which write ~0 or
79  * the correct resource information
80  * (Needed for when the driver probes the resource usage)
81  */
82 static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
83 {
84         struct pci_bar_info *bar = data;
85
86         if (unlikely(!bar)) {
87                 printk(KERN_WARNING "pciback: driver data not found for %s\n",
88                        pci_name(dev));
89                 return XEN_PCI_ERR_op_failed;
90         }
91
92         /* A write to obtain the length must happen as a 32-bit write.
93          * This does not (yet) support writing individual bytes
94          */
95         if (value == ~0)
96                 bar->which = 1;
97         else
98                 bar->which = 0;
99
100         return 0;
101 }
102
103 static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
104 {
105         struct pci_bar_info *bar = data;
106
107         if (unlikely(!bar)) {
108                 printk(KERN_WARNING "pciback: driver data not found for %s\n",
109                        pci_name(dev));
110                 return XEN_PCI_ERR_op_failed;
111         }
112
113         *value = bar->which ? bar->len_val : bar->val;
114
115         return 0;
116 }
117
118 static inline void read_dev_bar(struct pci_dev *dev,
119                                 struct pci_bar_info *bar_info, int offset,
120                                 u32 len_mask)
121 {
122         pci_read_config_dword(dev, offset, &bar_info->val);
123         pci_write_config_dword(dev, offset, len_mask);
124         pci_read_config_dword(dev, offset, &bar_info->len_val);
125         pci_write_config_dword(dev, offset, bar_info->val);
126 }
127
128 static void *bar_init(struct pci_dev *dev, int offset)
129 {
130         struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
131
132         if (!bar)
133                 return ERR_PTR(-ENOMEM);
134
135         read_dev_bar(dev, bar, offset, ~0);
136         bar->which = 0;
137
138         return bar;
139 }
140
141 static void *rom_init(struct pci_dev *dev, int offset)
142 {
143         struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
144
145         if (!bar)
146                 return ERR_PTR(-ENOMEM);
147
148         read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
149         bar->which = 0;
150
151         return bar;
152 }
153
154 static void bar_reset(struct pci_dev *dev, int offset, void *data)
155 {
156         struct pci_bar_info *bar = data;
157
158         bar->which = 0;
159 }
160
161 static void bar_release(struct pci_dev *dev, int offset, void *data)
162 {
163         kfree(data);
164 }
165
166 static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
167                           void *data)
168 {
169         *value = (u8) dev->irq;
170
171         return 0;
172 }
173
174 static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
175 {
176         u8 cur_value;
177         int err;
178
179         err = pci_read_config_byte(dev, offset, &cur_value);
180         if (err)
181                 goto out;
182
183         if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
184             || value == PCI_BIST_START)
185                 err = pci_write_config_byte(dev, offset, value);
186
187       out:
188         return err;
189 }
190
191 static struct config_field header_common[] = {
192         {
193          .offset    = PCI_COMMAND,
194          .size      = 2,
195          .u.w.read  = pciback_read_config_word,
196          .u.w.write = command_write,
197         },
198         {
199          .offset    = PCI_INTERRUPT_LINE,
200          .size      = 1,
201          .u.b.read  = interrupt_read,
202         },
203         {
204          .offset    = PCI_INTERRUPT_PIN,
205          .size      = 1,
206          .u.b.read  = pciback_read_config_byte,
207         },
208         {
209          /* Any side effects of letting driver domain control cache line? */
210          .offset    = PCI_CACHE_LINE_SIZE,
211          .size      = 1,
212          .u.b.read  = pciback_read_config_byte,
213          .u.b.write = pciback_write_config_byte,
214         },
215         {
216          .offset    = PCI_LATENCY_TIMER,
217          .size      = 1,
218          .u.b.read  = pciback_read_config_byte,
219         },
220         {
221          .offset    = PCI_BIST,
222          .size      = 1,
223          .u.b.read  = pciback_read_config_byte,
224          .u.b.write = bist_write,
225         },
226         {
227          .size = 0,
228         },
229 };
230
231 #define CFG_FIELD_BAR(reg_offset)                       \
232         {                                               \
233          .offset     = reg_offset,                      \
234          .size       = 4,                               \
235          .init       = bar_init,                        \
236          .reset      = bar_reset,                       \
237          .release    = bar_release,                     \
238          .u.dw.read  = bar_read,                        \
239          .u.dw.write = bar_write,                       \
240          }
241
242 #define CFG_FIELD_ROM(reg_offset)                       \
243         {                                               \
244          .offset     = reg_offset,                      \
245          .size       = 4,                               \
246          .init       = rom_init,                        \
247          .reset      = bar_reset,                       \
248          .release    = bar_release,                     \
249          .u.dw.read  = bar_read,                        \
250          .u.dw.write = rom_write,                       \
251          }
252
253 static struct config_field header_0[] = {
254         CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
255         CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
256         CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
257         CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
258         CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
259         CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
260         CFG_FIELD_ROM(PCI_ROM_ADDRESS),
261         {
262          .size = 0,
263         },
264 };
265
266 static struct config_field header_1[] = {
267         CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
268         CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
269         CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
270         {
271          .size = 0,
272         },
273 };
274
275 int pciback_config_header_add_fields(struct pci_dev *dev)
276 {
277         int err;
278
279         err = pciback_config_add_fields(dev, header_common);
280         if (err)
281                 goto out;
282
283         switch (dev->hdr_type) {
284         case PCI_HEADER_TYPE_NORMAL:
285                 err = pciback_config_add_fields(dev, header_0);
286                 break;
287
288         case PCI_HEADER_TYPE_BRIDGE:
289                 err = pciback_config_add_fields(dev, header_1);
290                 break;
291
292         default:
293                 err = -EINVAL;
294                 printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n",
295                        pci_name(dev), dev->hdr_type);
296                 break;
297         }
298
299       out:
300         return err;
301 }