conf_space_header.c 10.0 KB
Newer Older
1 2 3 4 5 6
/*
 * PCI Backend - Handles the virtual fields in the configuration space headers.
 *
 * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
 */

J
Joe Perches 已提交
7 8
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

9 10 11 12 13
#include <linux/kernel.h>
#include <linux/pci.h>
#include "pciback.h"
#include "conf_space.h"

14 15 16 17
struct pci_cmd_info {
	u16 val;
};

18 19 20 21 22 23 24 25 26
struct pci_bar_info {
	u32 val;
	u32 len_val;
	int which;
};

#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)

27 28 29 30 31 32
/* Bits guests are allowed to control in permissive mode. */
#define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \
			   PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \
			   PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK)

static void *command_init(struct pci_dev *dev, int offset)
33
{
34 35 36 37 38 39 40 41 42 43
	struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
	int err;

	if (!cmd)
		return ERR_PTR(-ENOMEM);

	err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val);
	if (err) {
		kfree(cmd);
		return ERR_PTR(err);
44 45
	}

46 47 48 49 50 51 52 53 54 55 56
	return cmd;
}

static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
{
	int ret = pci_read_config_word(dev, offset, value);
	const struct pci_cmd_info *cmd = data;

	*value &= PCI_COMMAND_GUEST;
	*value |= cmd->val & ~PCI_COMMAND_GUEST;

57 58 59
	return ret;
}

60 61
static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
{
62
	struct xen_pcibk_dev_data *dev_data;
63
	int err;
64 65
	u16 val;
	struct pci_cmd_info *cmd = data;
66

67
	dev_data = pci_get_drvdata(dev);
68 69
	if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
		if (unlikely(verbose_request))
70
			printk(KERN_DEBUG DRV_NAME ": %s: enable\n",
71 72 73 74
			       pci_name(dev));
		err = pci_enable_device(dev);
		if (err)
			return err;
75 76
		if (dev_data)
			dev_data->enable_intx = 1;
77 78
	} else if (pci_is_enabled(dev) && !is_enable_cmd(value)) {
		if (unlikely(verbose_request))
79
			printk(KERN_DEBUG DRV_NAME ": %s: disable\n",
80 81
			       pci_name(dev));
		pci_disable_device(dev);
82 83
		if (dev_data)
			dev_data->enable_intx = 0;
84 85 86 87
	}

	if (!dev->is_busmaster && is_master_cmd(value)) {
		if (unlikely(verbose_request))
88
			printk(KERN_DEBUG DRV_NAME ": %s: set bus master\n",
89 90
			       pci_name(dev));
		pci_set_master(dev);
91 92 93 94 95
	} else if (dev->is_busmaster && !is_master_cmd(value)) {
		if (unlikely(verbose_request))
			printk(KERN_DEBUG DRV_NAME ": %s: clear bus master\n",
			       pci_name(dev));
		pci_clear_master(dev);
96 97
	}

98 99
	if (!(cmd->val & PCI_COMMAND_INVALIDATE) &&
	    (value & PCI_COMMAND_INVALIDATE)) {
100 101
		if (unlikely(verbose_request))
			printk(KERN_DEBUG
102
			       DRV_NAME ": %s: enable memory-write-invalidate\n",
103 104 105
			       pci_name(dev));
		err = pci_set_mwi(dev);
		if (err) {
J
Joe Perches 已提交
106 107
			pr_warn("%s: cannot enable memory-write-invalidate (%d)\n",
				pci_name(dev), err);
108 109
			value &= ~PCI_COMMAND_INVALIDATE;
		}
110 111 112 113 114 115 116
	} else if ((cmd->val & PCI_COMMAND_INVALIDATE) &&
		   !(value & PCI_COMMAND_INVALIDATE)) {
		if (unlikely(verbose_request))
			printk(KERN_DEBUG
			       DRV_NAME ": %s: disable memory-write-invalidate\n",
			       pci_name(dev));
		pci_clear_mwi(dev);
117 118
	}

119 120
	cmd->val = value;

121
	if (!xen_pcibk_permissive && (!dev_data || !dev_data->permissive))
122 123 124 125 126 127 128 129 130 131
		return 0;

	/* Only allow the guest to control certain bits. */
	err = pci_read_config_word(dev, offset, &val);
	if (err || val == value)
		return err;

	value &= PCI_COMMAND_GUEST;
	value |= val & ~PCI_COMMAND_GUEST;

132 133 134 135 136 137 138 139
	return pci_write_config_word(dev, offset, value);
}

static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
{
	struct pci_bar_info *bar = data;

	if (unlikely(!bar)) {
J
Joe Perches 已提交
140
		pr_warn(DRV_NAME ": driver data not found for %s\n",
141 142 143 144 145 146 147
		       pci_name(dev));
		return XEN_PCI_ERR_op_failed;
	}

	/* A write to obtain the length must happen as a 32-bit write.
	 * This does not (yet) support writing individual bytes
	 */
148
	if ((value | ~PCI_ROM_ADDRESS_MASK) == ~0U)
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
		bar->which = 1;
	else {
		u32 tmpval;
		pci_read_config_dword(dev, offset, &tmpval);
		if (tmpval != bar->val && value == bar->val) {
			/* Allow restoration of bar value. */
			pci_write_config_dword(dev, offset, bar->val);
		}
		bar->which = 0;
	}

	/* Do we need to support enabling/disabling the rom address here? */

	return 0;
}

/* For the BARs, only allow writes which write ~0 or
 * the correct resource information
 * (Needed for when the driver probes the resource usage)
 */
static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
{
	struct pci_bar_info *bar = data;

	if (unlikely(!bar)) {
J
Joe Perches 已提交
174
		pr_warn(DRV_NAME ": driver data not found for %s\n",
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
		       pci_name(dev));
		return XEN_PCI_ERR_op_failed;
	}

	/* A write to obtain the length must happen as a 32-bit write.
	 * This does not (yet) support writing individual bytes
	 */
	if (value == ~0)
		bar->which = 1;
	else {
		u32 tmpval;
		pci_read_config_dword(dev, offset, &tmpval);
		if (tmpval != bar->val && value == bar->val) {
			/* Allow restoration of bar value. */
			pci_write_config_dword(dev, offset, bar->val);
		}
		bar->which = 0;
	}

	return 0;
}

static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
{
	struct pci_bar_info *bar = data;

	if (unlikely(!bar)) {
J
Joe Perches 已提交
202
		pr_warn(DRV_NAME ": driver data not found for %s\n",
203 204 205 206 207 208 209 210 211 212 213 214 215
		       pci_name(dev));
		return XEN_PCI_ERR_op_failed;
	}

	*value = bar->which ? bar->len_val : bar->val;

	return 0;
}

static inline void read_dev_bar(struct pci_dev *dev,
				struct pci_bar_info *bar_info, int offset,
				u32 len_mask)
{
216 217 218 219 220 221 222 223 224 225 226 227
	int	pos;
	struct resource	*res = dev->resource;

	if (offset == PCI_ROM_ADDRESS || offset == PCI_ROM_ADDRESS1)
		pos = PCI_ROM_RESOURCE;
	else {
		pos = (offset - PCI_BASE_ADDRESS_0) / 4;
		if (pos && ((res[pos - 1].flags & (PCI_BASE_ADDRESS_SPACE |
				PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
			   (PCI_BASE_ADDRESS_SPACE_MEMORY |
				PCI_BASE_ADDRESS_MEM_TYPE_64))) {
			bar_info->val = res[pos - 1].start >> 32;
228
			bar_info->len_val = -resource_size(&res[pos - 1]) >> 32;
229 230 231 232
			return;
		}
	}

233 234 235 236 237
	if (!res[pos].flags ||
	    (res[pos].flags & (IORESOURCE_DISABLED | IORESOURCE_UNSET |
			       IORESOURCE_BUSY)))
		return;

238 239
	bar_info->val = res[pos].start |
			(res[pos].flags & PCI_REGION_FLAG_MASK);
240 241
	bar_info->len_val = -resource_size(&res[pos]) |
			    (res[pos].flags & PCI_REGION_FLAG_MASK);
242 243 244 245
}

static void *bar_init(struct pci_dev *dev, int offset)
{
246
	struct pci_bar_info *bar = kzalloc(sizeof(*bar), GFP_KERNEL);
247 248 249 250 251 252 253 254 255 256 257

	if (!bar)
		return ERR_PTR(-ENOMEM);

	read_dev_bar(dev, bar, offset, ~0);

	return bar;
}

static void *rom_init(struct pci_dev *dev, int offset)
{
258
	struct pci_bar_info *bar = kzalloc(sizeof(*bar), GFP_KERNEL);
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279

	if (!bar)
		return ERR_PTR(-ENOMEM);

	read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);

	return bar;
}

static void bar_reset(struct pci_dev *dev, int offset, void *data)
{
	struct pci_bar_info *bar = data;

	bar->which = 0;
}

static void bar_release(struct pci_dev *dev, int offset, void *data)
{
	kfree(data);
}

280
static int xen_pcibk_read_vendor(struct pci_dev *dev, int offset,
281 282 283 284 285 286 287
			       u16 *value, void *data)
{
	*value = dev->vendor;

	return 0;
}

288
static int xen_pcibk_read_device(struct pci_dev *dev, int offset,
289 290 291 292 293 294 295
			       u16 *value, void *data)
{
	*value = dev->device;

	return 0;
}

296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
			  void *data)
{
	*value = (u8) dev->irq;

	return 0;
}

static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
{
	u8 cur_value;
	int err;

	err = pci_read_config_byte(dev, offset, &cur_value);
	if (err)
		goto out;

	if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
	    || value == PCI_BIST_START)
		err = pci_write_config_byte(dev, offset, value);

out:
	return err;
}

static const struct config_field header_common[] = {
322 323 324
	{
	 .offset    = PCI_VENDOR_ID,
	 .size      = 2,
325
	 .u.w.read  = xen_pcibk_read_vendor,
326 327 328 329
	},
	{
	 .offset    = PCI_DEVICE_ID,
	 .size      = 2,
330
	 .u.w.read  = xen_pcibk_read_device,
331
	},
332 333 334
	{
	 .offset    = PCI_COMMAND,
	 .size      = 2,
335 336
	 .init      = command_init,
	 .release   = bar_release,
337
	 .u.w.read  = command_read,
338 339 340 341 342 343 344 345 346 347
	 .u.w.write = command_write,
	},
	{
	 .offset    = PCI_INTERRUPT_LINE,
	 .size      = 1,
	 .u.b.read  = interrupt_read,
	},
	{
	 .offset    = PCI_INTERRUPT_PIN,
	 .size      = 1,
348
	 .u.b.read  = xen_pcibk_read_config_byte,
349 350 351 352 353
	},
	{
	 /* Any side effects of letting driver domain control cache line? */
	 .offset    = PCI_CACHE_LINE_SIZE,
	 .size      = 1,
354 355
	 .u.b.read  = xen_pcibk_read_config_byte,
	 .u.b.write = xen_pcibk_write_config_byte,
356 357 358 359
	},
	{
	 .offset    = PCI_LATENCY_TIMER,
	 .size      = 1,
360
	 .u.b.read  = xen_pcibk_read_config_byte,
361 362 363 364
	},
	{
	 .offset    = PCI_BIST,
	 .size      = 1,
365
	 .u.b.read  = xen_pcibk_read_config_byte,
366 367 368 369 370
	 .u.b.write = bist_write,
	},
	{}
};

371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
#define CFG_FIELD_BAR(reg_offset)			\
	{						\
	.offset     = reg_offset,			\
	.size       = 4,				\
	.init       = bar_init,				\
	.reset      = bar_reset,			\
	.release    = bar_release,			\
	.u.dw.read  = bar_read,				\
	.u.dw.write = bar_write,			\
	}

#define CFG_FIELD_ROM(reg_offset)			\
	{						\
	.offset     = reg_offset,			\
	.size       = 4,				\
	.init       = rom_init,				\
	.reset      = bar_reset,			\
	.release    = bar_release,			\
	.u.dw.read  = bar_read,				\
	.u.dw.write = rom_write,			\
	}
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410

static const struct config_field header_0[] = {
	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
	CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
	CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
	CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
	CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
	CFG_FIELD_ROM(PCI_ROM_ADDRESS),
	{}
};

static const struct config_field header_1[] = {
	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
	CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
	{}
};

411
int xen_pcibk_config_header_add_fields(struct pci_dev *dev)
412 413 414
{
	int err;

415
	err = xen_pcibk_config_add_fields(dev, header_common);
416 417 418 419 420
	if (err)
		goto out;

	switch (dev->hdr_type) {
	case PCI_HEADER_TYPE_NORMAL:
421
		err = xen_pcibk_config_add_fields(dev, header_0);
422 423 424
		break;

	case PCI_HEADER_TYPE_BRIDGE:
425
		err = xen_pcibk_config_add_fields(dev, header_1);
426 427 428 429
		break;

	default:
		err = -EINVAL;
J
Joe Perches 已提交
430
		pr_err("%s: Unsupported header type %d!\n",
431 432 433 434 435 436 437
		       pci_name(dev), dev->hdr_type);
		break;
	}

out:
	return err;
}