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