mirror of
https://github.com/torvalds/linux.git
synced 2024-12-02 09:01:34 +00:00
Merge branch 'remotes/lorenzo/pci/aardvark'
- Add bridge emulation definitions for PCIe DEVCAP2, DEVCTL2, DEVSTA2, LNKCAP2, LNKCTL2, LNKSTA2, SLTCAP2, SLTCTL2, SLTSTA2 (Pali Rohár) - Add aardvark support for DEVCAP2, DEVCTL2, LNKCAP2 and LNKCTL2 registers (Pali Rohár) - Clear all MSIs at setup to avoid spurious interrupts (Pali Rohár) - Disable bus mastering when unbinding host controller driver (Pali Rohár) - Mask all interrupts when unbinding host controller driver (Pali Rohár) - Fix memory leak in host controller unbind (Pali Rohár) - Assert PERST# when unbinding host controller driver (Pali Rohár) - Disable link training when unbinding host controller driver (Pali Rohár) - Disable common PHY when unbinding host controller driver (Pali Rohár) - Fix resource type checking to check only IORESOURCE_MEM, not IORESOURCE_MEM_64, which is a flavor of IORESOURCE_MEM (Pali Rohár) * remotes/lorenzo/pci/aardvark: PCI: aardvark: Fix checking for MEM resource type PCI: aardvark: Disable common PHY when unbinding driver PCI: aardvark: Disable link training when unbinding driver PCI: aardvark: Assert PERST# when unbinding driver PCI: aardvark: Fix memory leak in driver unbind PCI: aardvark: Mask all interrupts when unbinding driver PCI: aardvark: Disable bus mastering when unbinding driver PCI: aardvark: Comment actions in driver remove method PCI: aardvark: Clear all MSIs at setup PCI: aardvark: Add support for DEVCAP2, DEVCTL2, LNKCAP2 and LNKCTL2 registers on emulated bridge PCI: pci-bridge-emul: Add definitions for missing capabilities registers PCI: pci-bridge-emul: Add description for class_revision field
This commit is contained in:
commit
800cee8b04
@ -116,6 +116,7 @@
|
||||
#define PCIE_MSI_ADDR_HIGH_REG (CONTROL_BASE_ADDR + 0x54)
|
||||
#define PCIE_MSI_STATUS_REG (CONTROL_BASE_ADDR + 0x58)
|
||||
#define PCIE_MSI_MASK_REG (CONTROL_BASE_ADDR + 0x5C)
|
||||
#define PCIE_MSI_ALL_MASK GENMASK(31, 0)
|
||||
#define PCIE_MSI_PAYLOAD_REG (CONTROL_BASE_ADDR + 0x9C)
|
||||
#define PCIE_MSI_DATA_MASK GENMASK(15, 0)
|
||||
|
||||
@ -571,6 +572,7 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
|
||||
advk_writel(pcie, reg, PCIE_CORE_CTRL2_REG);
|
||||
|
||||
/* Clear all interrupts */
|
||||
advk_writel(pcie, PCIE_MSI_ALL_MASK, PCIE_MSI_STATUS_REG);
|
||||
advk_writel(pcie, PCIE_ISR0_ALL_MASK, PCIE_ISR0_REG);
|
||||
advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_REG);
|
||||
advk_writel(pcie, PCIE_IRQ_ALL_MASK, HOST_CTRL_INT_STATUS_REG);
|
||||
@ -583,7 +585,7 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
|
||||
advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_MASK_REG);
|
||||
|
||||
/* Unmask all MSIs */
|
||||
advk_writel(pcie, 0, PCIE_MSI_MASK_REG);
|
||||
advk_writel(pcie, ~(u32)PCIE_MSI_ALL_MASK, PCIE_MSI_MASK_REG);
|
||||
|
||||
/* Enable summary interrupt for GIC SPI source */
|
||||
reg = PCIE_IRQ_ALL_MASK & (~PCIE_IRQ_ENABLE_INTS_MASK);
|
||||
@ -884,8 +886,13 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
|
||||
case PCI_CAP_LIST_ID:
|
||||
case PCI_EXP_DEVCAP:
|
||||
case PCI_EXP_DEVCTL:
|
||||
case PCI_EXP_DEVCAP2:
|
||||
case PCI_EXP_DEVCTL2:
|
||||
case PCI_EXP_LNKCAP2:
|
||||
case PCI_EXP_LNKCTL2:
|
||||
*value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);
|
||||
return PCI_BRIDGE_EMUL_HANDLED;
|
||||
|
||||
default:
|
||||
return PCI_BRIDGE_EMUL_NOT_HANDLED;
|
||||
}
|
||||
@ -899,10 +906,6 @@ advk_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
|
||||
struct advk_pcie *pcie = bridge->data;
|
||||
|
||||
switch (reg) {
|
||||
case PCI_EXP_DEVCTL:
|
||||
advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
|
||||
break;
|
||||
|
||||
case PCI_EXP_LNKCTL:
|
||||
advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
|
||||
if (new & PCI_EXP_LNKCTL_RL)
|
||||
@ -924,6 +927,12 @@ advk_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
|
||||
advk_writel(pcie, new, PCIE_ISR0_REG);
|
||||
break;
|
||||
|
||||
case PCI_EXP_DEVCTL:
|
||||
case PCI_EXP_DEVCTL2:
|
||||
case PCI_EXP_LNKCTL2:
|
||||
advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1392,7 +1401,7 @@ static void advk_pcie_handle_msi(struct advk_pcie *pcie)
|
||||
|
||||
msi_mask = advk_readl(pcie, PCIE_MSI_MASK_REG);
|
||||
msi_val = advk_readl(pcie, PCIE_MSI_STATUS_REG);
|
||||
msi_status = msi_val & ~msi_mask;
|
||||
msi_status = msi_val & ((~msi_mask) & PCIE_MSI_ALL_MASK);
|
||||
|
||||
for (msi_idx = 0; msi_idx < MSI_IRQ_NUM; msi_idx++) {
|
||||
if (!(BIT(msi_idx) & msi_status))
|
||||
@ -1544,8 +1553,7 @@ static int advk_pcie_probe(struct platform_device *pdev)
|
||||
* only PIO for issuing configuration transfers which does
|
||||
* not use PCIe window configuration.
|
||||
*/
|
||||
if (type != IORESOURCE_MEM && type != IORESOURCE_MEM_64 &&
|
||||
type != IORESOURCE_IO)
|
||||
if (type != IORESOURCE_MEM && type != IORESOURCE_IO)
|
||||
continue;
|
||||
|
||||
/*
|
||||
@ -1553,8 +1561,7 @@ static int advk_pcie_probe(struct platform_device *pdev)
|
||||
* configuration is set to transparent memory access so it
|
||||
* does not need window configuration.
|
||||
*/
|
||||
if ((type == IORESOURCE_MEM || type == IORESOURCE_MEM_64) &&
|
||||
entry->offset == 0)
|
||||
if (type == IORESOURCE_MEM && entry->offset == 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
@ -1686,20 +1693,64 @@ static int advk_pcie_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct advk_pcie *pcie = platform_get_drvdata(pdev);
|
||||
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
/* Remove PCI bus with all devices */
|
||||
pci_lock_rescan_remove();
|
||||
pci_stop_root_bus(bridge->bus);
|
||||
pci_remove_root_bus(bridge->bus);
|
||||
pci_unlock_rescan_remove();
|
||||
|
||||
/* Disable Root Bridge I/O space, memory space and bus mastering */
|
||||
val = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG);
|
||||
val &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
|
||||
advk_writel(pcie, val, PCIE_CORE_CMD_STATUS_REG);
|
||||
|
||||
/* Disable MSI */
|
||||
val = advk_readl(pcie, PCIE_CORE_CTRL2_REG);
|
||||
val &= ~PCIE_CORE_CTRL2_MSI_ENABLE;
|
||||
advk_writel(pcie, val, PCIE_CORE_CTRL2_REG);
|
||||
|
||||
/* Clear MSI address */
|
||||
advk_writel(pcie, 0, PCIE_MSI_ADDR_LOW_REG);
|
||||
advk_writel(pcie, 0, PCIE_MSI_ADDR_HIGH_REG);
|
||||
|
||||
/* Mask all interrupts */
|
||||
advk_writel(pcie, PCIE_MSI_ALL_MASK, PCIE_MSI_MASK_REG);
|
||||
advk_writel(pcie, PCIE_ISR0_ALL_MASK, PCIE_ISR0_MASK_REG);
|
||||
advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_MASK_REG);
|
||||
advk_writel(pcie, PCIE_IRQ_ALL_MASK, HOST_CTRL_INT_MASK_REG);
|
||||
|
||||
/* Clear all interrupts */
|
||||
advk_writel(pcie, PCIE_MSI_ALL_MASK, PCIE_MSI_STATUS_REG);
|
||||
advk_writel(pcie, PCIE_ISR0_ALL_MASK, PCIE_ISR0_REG);
|
||||
advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_REG);
|
||||
advk_writel(pcie, PCIE_IRQ_ALL_MASK, HOST_CTRL_INT_STATUS_REG);
|
||||
|
||||
/* Remove IRQ domains */
|
||||
advk_pcie_remove_msi_irq_domain(pcie);
|
||||
advk_pcie_remove_irq_domain(pcie);
|
||||
|
||||
/* Free config space for emulated root bridge */
|
||||
pci_bridge_emul_cleanup(&pcie->bridge);
|
||||
|
||||
/* Assert PERST# signal which prepares PCIe card for power down */
|
||||
if (pcie->reset_gpio)
|
||||
gpiod_set_value_cansleep(pcie->reset_gpio, 1);
|
||||
|
||||
/* Disable link training */
|
||||
val = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
|
||||
val &= ~LINK_TRAINING_EN;
|
||||
advk_writel(pcie, val, PCIE_CORE_CTRL0_REG);
|
||||
|
||||
/* Disable outbound address windows mapping */
|
||||
for (i = 0; i < OB_WIN_COUNT; i++)
|
||||
advk_pcie_disable_ob_win(pcie, i);
|
||||
|
||||
/* Disable phy */
|
||||
advk_pcie_disable_phy(pcie);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -251,6 +251,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 +308,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);
|
||||
|
Loading…
Reference in New Issue
Block a user