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_ADDR_HIGH_REG (CONTROL_BASE_ADDR + 0x54)
|
||||||
#define PCIE_MSI_STATUS_REG (CONTROL_BASE_ADDR + 0x58)
|
#define PCIE_MSI_STATUS_REG (CONTROL_BASE_ADDR + 0x58)
|
||||||
#define PCIE_MSI_MASK_REG (CONTROL_BASE_ADDR + 0x5C)
|
#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_PAYLOAD_REG (CONTROL_BASE_ADDR + 0x9C)
|
||||||
#define PCIE_MSI_DATA_MASK GENMASK(15, 0)
|
#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);
|
advk_writel(pcie, reg, PCIE_CORE_CTRL2_REG);
|
||||||
|
|
||||||
/* Clear all interrupts */
|
/* 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_ISR0_ALL_MASK, PCIE_ISR0_REG);
|
||||||
advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_REG);
|
advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_REG);
|
||||||
advk_writel(pcie, PCIE_IRQ_ALL_MASK, HOST_CTRL_INT_STATUS_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);
|
advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_MASK_REG);
|
||||||
|
|
||||||
/* Unmask all MSIs */
|
/* 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 */
|
/* Enable summary interrupt for GIC SPI source */
|
||||||
reg = PCIE_IRQ_ALL_MASK & (~PCIE_IRQ_ENABLE_INTS_MASK);
|
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_CAP_LIST_ID:
|
||||||
case PCI_EXP_DEVCAP:
|
case PCI_EXP_DEVCAP:
|
||||||
case PCI_EXP_DEVCTL:
|
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);
|
*value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);
|
||||||
return PCI_BRIDGE_EMUL_HANDLED;
|
return PCI_BRIDGE_EMUL_HANDLED;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return PCI_BRIDGE_EMUL_NOT_HANDLED;
|
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;
|
struct advk_pcie *pcie = bridge->data;
|
||||||
|
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case PCI_EXP_DEVCTL:
|
|
||||||
advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PCI_EXP_LNKCTL:
|
case PCI_EXP_LNKCTL:
|
||||||
advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
|
advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
|
||||||
if (new & PCI_EXP_LNKCTL_RL)
|
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);
|
advk_writel(pcie, new, PCIE_ISR0_REG);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PCI_EXP_DEVCTL:
|
||||||
|
case PCI_EXP_DEVCTL2:
|
||||||
|
case PCI_EXP_LNKCTL2:
|
||||||
|
advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
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_mask = advk_readl(pcie, PCIE_MSI_MASK_REG);
|
||||||
msi_val = advk_readl(pcie, PCIE_MSI_STATUS_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++) {
|
for (msi_idx = 0; msi_idx < MSI_IRQ_NUM; msi_idx++) {
|
||||||
if (!(BIT(msi_idx) & msi_status))
|
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
|
* only PIO for issuing configuration transfers which does
|
||||||
* not use PCIe window configuration.
|
* not use PCIe window configuration.
|
||||||
*/
|
*/
|
||||||
if (type != IORESOURCE_MEM && type != IORESOURCE_MEM_64 &&
|
if (type != IORESOURCE_MEM && type != IORESOURCE_IO)
|
||||||
type != IORESOURCE_IO)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1553,8 +1561,7 @@ static int advk_pcie_probe(struct platform_device *pdev)
|
|||||||
* configuration is set to transparent memory access so it
|
* configuration is set to transparent memory access so it
|
||||||
* does not need window configuration.
|
* does not need window configuration.
|
||||||
*/
|
*/
|
||||||
if ((type == IORESOURCE_MEM || type == IORESOURCE_MEM_64) &&
|
if (type == IORESOURCE_MEM && entry->offset == 0)
|
||||||
entry->offset == 0)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1686,20 +1693,64 @@ static int advk_pcie_remove(struct platform_device *pdev)
|
|||||||
{
|
{
|
||||||
struct advk_pcie *pcie = platform_get_drvdata(pdev);
|
struct advk_pcie *pcie = platform_get_drvdata(pdev);
|
||||||
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
|
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
|
||||||
|
u32 val;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/* Remove PCI bus with all devices */
|
||||||
pci_lock_rescan_remove();
|
pci_lock_rescan_remove();
|
||||||
pci_stop_root_bus(bridge->bus);
|
pci_stop_root_bus(bridge->bus);
|
||||||
pci_remove_root_bus(bridge->bus);
|
pci_remove_root_bus(bridge->bus);
|
||||||
pci_unlock_rescan_remove();
|
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_msi_irq_domain(pcie);
|
||||||
advk_pcie_remove_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 */
|
/* Disable outbound address windows mapping */
|
||||||
for (i = 0; i < OB_WIN_COUNT; i++)
|
for (i = 0; i < OB_WIN_COUNT; i++)
|
||||||
advk_pcie_disable_ob_win(pcie, i);
|
advk_pcie_disable_ob_win(pcie, i);
|
||||||
|
|
||||||
|
/* Disable phy */
|
||||||
|
advk_pcie_disable_phy(pcie);
|
||||||
|
|
||||||
return 0;
|
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,
|
.ro = GENMASK(15, 0) | PCI_EXP_RTSTA_PENDING,
|
||||||
.w1c = PCI_EXP_RTSTA_PME,
|
.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);
|
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.header_type = PCI_HEADER_TYPE_BRIDGE;
|
||||||
bridge->conf.cache_line_size = 0x10;
|
bridge->conf.cache_line_size = 0x10;
|
||||||
bridge->conf.status = cpu_to_le16(PCI_STATUS_CAP_LIST);
|
bridge->conf.status = cpu_to_le16(PCI_STATUS_CAP_LIST);
|
||||||
|
Loading…
Reference in New Issue
Block a user