diff options
Diffstat (limited to 'drivers/pci/pci-bridge-emul.c')
| -rw-r--r-- | drivers/pci/pci-bridge-emul.c | 119 | 
1 files changed, 102 insertions, 17 deletions
diff --git a/drivers/pci/pci-bridge-emul.c b/drivers/pci/pci-bridge-emul.c index db97cddfc85e..c994ebec2360 100644 --- a/drivers/pci/pci-bridge-emul.c +++ b/drivers/pci/pci-bridge-emul.c @@ -139,8 +139,13 @@ struct pci_bridge_reg_behavior pci_regs_behavior[PCI_STD_HEADER_SIZEOF / 4] = {  		.ro = GENMASK(7, 0),  	}, +	/* +	 * If expansion ROM is unsupported then ROM Base Address register must +	 * be implemented as read-only register that return 0 when read, same +	 * as for unused Base Address registers. +	 */  	[PCI_ROM_ADDRESS1 / 4] = { -		.rw = GENMASK(31, 11) | BIT(0), +		.ro = ~0,  	},  	/* @@ -171,41 +176,55 @@ struct pci_bridge_reg_behavior pcie_cap_regs_behavior[PCI_CAP_PCIE_SIZEOF / 4] =  	[PCI_CAP_LIST_ID / 4] = {  		/*  		 * Capability ID, Next Capability Pointer and -		 * Capabilities register are all read-only. +		 * bits [14:0] of Capabilities register are all read-only. +		 * Bit 15 of Capabilities register is reserved.  		 */ -		.ro = ~0, +		.ro = GENMASK(30, 0),  	},  	[PCI_EXP_DEVCAP / 4] = { -		.ro = ~0, +		/* +		 * Bits [31:29] and [17:16] are reserved. +		 * Bits [27:18] are reserved for non-upstream ports. +		 * Bits 28 and [14:6] are reserved for non-endpoint devices. +		 * Other bits are read-only. +		 */ +		.ro = BIT(15) | GENMASK(5, 0),  	},  	[PCI_EXP_DEVCTL / 4] = { -		/* Device control register is RW */ -		.rw = GENMASK(15, 0), +		/* +		 * Device control register is RW, except bit 15 which is +		 * reserved for non-endpoints or non-PCIe-to-PCI/X bridges. +		 */ +		.rw = GENMASK(14, 0),  		/*  		 * Device status register has bits 6 and [3:0] W1C, [5:4] RO, -		 * the rest is reserved +		 * the rest is reserved. Also bit 6 is reserved for non-upstream +		 * ports.  		 */ -		.w1c = (BIT(6) | GENMASK(3, 0)) << 16, +		.w1c = GENMASK(3, 0) << 16,  		.ro = GENMASK(5, 4) << 16,  	},  	[PCI_EXP_LNKCAP / 4] = { -		/* All bits are RO, except bit 23 which is reserved */ -		.ro = lower_32_bits(~BIT(23)), +		/* +		 * All bits are RO, except bit 23 which is reserved and +		 * bit 18 which is reserved for non-upstream ports. +		 */ +		.ro = lower_32_bits(~(BIT(23) | PCI_EXP_LNKCAP_CLKPM)),  	},  	[PCI_EXP_LNKCTL / 4] = {  		/*  		 * Link control has bits [15:14], [11:3] and [1:0] RW, the -		 * rest is reserved. +		 * rest is reserved. Bit 8 is reserved for non-upstream ports.  		 *  		 * Link status has bits [13:0] RO, and bits [15:14]  		 * W1C.  		 */ -		.rw = GENMASK(15, 14) | GENMASK(11, 3) | GENMASK(1, 0), +		.rw = GENMASK(15, 14) | GENMASK(11, 9) | GENMASK(7, 3) | GENMASK(1, 0),  		.ro = GENMASK(13, 0) << 16,  		.w1c = GENMASK(15, 14) << 16,  	}, @@ -251,6 +270,49 @@ struct pci_bridge_reg_behavior pcie_cap_regs_behavior[PCI_CAP_PCIE_SIZEOF / 4] =  		.ro = GENMASK(15, 0) | PCI_EXP_RTSTA_PENDING,  		.w1c = PCI_EXP_RTSTA_PME,  	}, + +	[PCI_EXP_DEVCAP2 / 4] = { +		/* +		 * Device capabilities 2 register has reserved bits [30:27]. +		 * Also bits [26:24] are reserved for non-upstream ports. +		 */ +		.ro = BIT(31) | GENMASK(23, 0), +	}, + +	[PCI_EXP_DEVCTL2 / 4] = { +		/* +		 * Device control 2 register is RW. Bit 11 is reserved for +		 * non-upstream ports. +		 * +		 * Device status 2 register is reserved. +		 */ +		.rw = GENMASK(15, 12) | GENMASK(10, 0), +	}, + +	[PCI_EXP_LNKCAP2 / 4] = { +		/* Link capabilities 2 register has reserved bits [30:25] and 0. */ +		.ro = BIT(31) | GENMASK(24, 1), +	}, + +	[PCI_EXP_LNKCTL2 / 4] = { +		/* +		 * Link control 2 register is RW. +		 * +		 * Link status 2 register has bits 5, 15 W1C; +		 * bits 10, 11 reserved and others are RO. +		 */ +		.rw = GENMASK(15, 0), +		.w1c = (BIT(15) | BIT(5)) << 16, +		.ro = (GENMASK(14, 12) | GENMASK(9, 6) | GENMASK(4, 0)) << 16, +	}, + +	[PCI_EXP_SLTCAP2 / 4] = { +		/* Slot capabilities 2 register is reserved. */ +	}, + +	[PCI_EXP_SLTCTL2 / 4] = { +		/* Both Slot control 2 and Slot status 2 registers are reserved. */ +	},  };  /* @@ -265,7 +327,11 @@ int pci_bridge_emul_init(struct pci_bridge_emul *bridge,  {  	BUILD_BUG_ON(sizeof(bridge->conf) != PCI_BRIDGE_CONF_END); -	bridge->conf.class_revision |= cpu_to_le32(PCI_CLASS_BRIDGE_PCI << 16); +	/* +	 * class_revision: Class is high 24 bits and revision is low 8 bit of this member, +	 * while class for PCI Bridge Normal Decode has the 24-bit value: PCI_CLASS_BRIDGE_PCI << 8 +	 */ +	bridge->conf.class_revision |= cpu_to_le32((PCI_CLASS_BRIDGE_PCI << 8) << 8);  	bridge->conf.header_type = PCI_HEADER_TYPE_BRIDGE;  	bridge->conf.cache_line_size = 0x10;  	bridge->conf.status = cpu_to_le16(PCI_STATUS_CAP_LIST); @@ -277,11 +343,9 @@ int pci_bridge_emul_init(struct pci_bridge_emul *bridge,  	if (bridge->has_pcie) {  		bridge->conf.capabilities_pointer = PCI_CAP_PCIE_START; +		bridge->conf.status |= cpu_to_le16(PCI_STATUS_CAP_LIST);  		bridge->pcie_conf.cap_id = PCI_CAP_ID_EXP; -		/* Set PCIe v2, root port, slot support */ -		bridge->pcie_conf.cap = -			cpu_to_le16(PCI_EXP_TYPE_ROOT_PORT << 4 | 2 | -				    PCI_EXP_FLAGS_SLOT); +		bridge->pcie_conf.cap |= cpu_to_le16(PCI_EXP_TYPE_ROOT_PORT << 4);  		bridge->pcie_cap_regs_behavior =  			kmemdup(pcie_cap_regs_behavior,  				sizeof(pcie_cap_regs_behavior), @@ -290,6 +354,27 @@ int pci_bridge_emul_init(struct pci_bridge_emul *bridge,  			kfree(bridge->pci_regs_behavior);  			return -ENOMEM;  		} +		/* These bits are applicable only for PCI and reserved on PCIe */ +		bridge->pci_regs_behavior[PCI_CACHE_LINE_SIZE / 4].ro &= +			~GENMASK(15, 8); +		bridge->pci_regs_behavior[PCI_COMMAND / 4].ro &= +			~((PCI_COMMAND_SPECIAL | PCI_COMMAND_INVALIDATE | +			   PCI_COMMAND_VGA_PALETTE | PCI_COMMAND_WAIT | +			   PCI_COMMAND_FAST_BACK) | +			  (PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK | +			   PCI_STATUS_DEVSEL_MASK) << 16); +		bridge->pci_regs_behavior[PCI_PRIMARY_BUS / 4].ro &= +			~GENMASK(31, 24); +		bridge->pci_regs_behavior[PCI_IO_BASE / 4].ro &= +			~((PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK | +			   PCI_STATUS_DEVSEL_MASK) << 16); +		bridge->pci_regs_behavior[PCI_INTERRUPT_LINE / 4].rw &= +			~((PCI_BRIDGE_CTL_MASTER_ABORT | +			   BIT(8) | BIT(9) | BIT(11)) << 16); +		bridge->pci_regs_behavior[PCI_INTERRUPT_LINE / 4].ro &= +			~((PCI_BRIDGE_CTL_FAST_BACK) << 16); +		bridge->pci_regs_behavior[PCI_INTERRUPT_LINE / 4].w1c &= +			~(BIT(10) << 16);  	}  	if (flags & PCI_BRIDGE_EMUL_NO_PREFETCHABLE_BAR) {  |