conf_space_header.c 9.7 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
		       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,
213
				struct pci_bar_info *bar_info, int offset)
214
{
215 216 217 218 219 220 221 222 223 224 225 226
	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;
227
			bar_info->len_val = -resource_size(&res[pos - 1]) >> 32;
228 229 230 231
			return;
		}
	}

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

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

static void *bar_init(struct pci_dev *dev, int offset)
{
245
	struct pci_bar_info *bar = kzalloc(sizeof(*bar), GFP_KERNEL);
246 247 248 249

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

250
	read_dev_bar(dev, bar, offset);
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266

	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);
}

267
static int xen_pcibk_read_vendor(struct pci_dev *dev, int offset,
268 269 270 271 272 273 274
			       u16 *value, void *data)
{
	*value = dev->vendor;

	return 0;
}

275
static int xen_pcibk_read_device(struct pci_dev *dev, int offset,
276 277 278 279 280 281 282
			       u16 *value, void *data)
{
	*value = dev->device;

	return 0;
}

283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
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[] = {
309 310 311
	{
	 .offset    = PCI_VENDOR_ID,
	 .size      = 2,
312
	 .u.w.read  = xen_pcibk_read_vendor,
313 314 315 316
	},
	{
	 .offset    = PCI_DEVICE_ID,
	 .size      = 2,
317
	 .u.w.read  = xen_pcibk_read_device,
318
	},
319 320 321
	{
	 .offset    = PCI_COMMAND,
	 .size      = 2,
322 323
	 .init      = command_init,
	 .release   = bar_release,
324
	 .u.w.read  = command_read,
325 326 327 328 329 330 331 332 333 334
	 .u.w.write = command_write,
	},
	{
	 .offset    = PCI_INTERRUPT_LINE,
	 .size      = 1,
	 .u.b.read  = interrupt_read,
	},
	{
	 .offset    = PCI_INTERRUPT_PIN,
	 .size      = 1,
335
	 .u.b.read  = xen_pcibk_read_config_byte,
336 337 338 339 340
	},
	{
	 /* Any side effects of letting driver domain control cache line? */
	 .offset    = PCI_CACHE_LINE_SIZE,
	 .size      = 1,
341 342
	 .u.b.read  = xen_pcibk_read_config_byte,
	 .u.b.write = xen_pcibk_write_config_byte,
343 344 345 346
	},
	{
	 .offset    = PCI_LATENCY_TIMER,
	 .size      = 1,
347
	 .u.b.read  = xen_pcibk_read_config_byte,
348 349 350 351
	},
	{
	 .offset    = PCI_BIST,
	 .size      = 1,
352
	 .u.b.read  = xen_pcibk_read_config_byte,
353 354 355 356 357
	 .u.b.write = bist_write,
	},
	{}
};

358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
#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,				\
J
Jan Beulich 已提交
373
	.init       = bar_init,				\
374 375 376 377 378
	.reset      = bar_reset,			\
	.release    = bar_release,			\
	.u.dw.read  = bar_read,				\
	.u.dw.write = rom_write,			\
	}
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397

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),
	{}
};

398
int xen_pcibk_config_header_add_fields(struct pci_dev *dev)
399 400 401
{
	int err;

402
	err = xen_pcibk_config_add_fields(dev, header_common);
403 404 405 406 407
	if (err)
		goto out;

	switch (dev->hdr_type) {
	case PCI_HEADER_TYPE_NORMAL:
408
		err = xen_pcibk_config_add_fields(dev, header_0);
409 410 411
		break;

	case PCI_HEADER_TYPE_BRIDGE:
412
		err = xen_pcibk_config_add_fields(dev, header_1);
413 414 415 416
		break;

	default:
		err = -EINVAL;
J
Joe Perches 已提交
417
		pr_err("%s: Unsupported header type %d!\n",
418 419 420 421 422 423 424
		       pci_name(dev), dev->hdr_type);
		break;
	}

out:
	return err;
}