summaryrefslogtreecommitdiff
path: root/drivers/pci/controller
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2022-12-10 19:36:36 +0300
committerBjorn Helgaas <bhelgaas@google.com>2022-12-10 19:36:36 +0300
commit0ef283080e5dc508a60977156c60358f2ac18ecc (patch)
treeaab132dce87197f95df4e7bf9a98daa7558de213 /drivers/pci/controller
parente6936c8d7c338c67ae280064ef25b342e51eded2 (diff)
parent602fb860945fd6dce7989fcd3727d5fe4282f785 (diff)
downloadlinux-0ef283080e5dc508a60977156c60358f2ac18ecc.tar.xz
Merge branch 'remotes/lorenzo/pci/brcmstb'
- Enable Multi-MSI (Jim Quinlan) - Wait for 100ms after PERST# deassert for power and clocks to stabilize (Jim Quinlan) - Use readl_poll_timeout_atomic() instead of hand-rolled timeout loop (Jim Quinlan) - Drop needless "inline" annotations (Jim Quinlan) - Set RCB_MPS mode bit so data for reads up to MPS are returned in a single completion (Jim Quinlan) * remotes/lorenzo/pci/brcmstb: PCI: brcmstb: Set RCB_{MPS,64B}_MODE bits PCI: brcmstb: Drop needless 'inline' annotations PCI: brcmstb: Replace status loops with read_poll_timeout_atomic() PCI: brcmstb: Wait for 100ms following PERST# deassert PCI: brcmstb: Enable Multi-MSI
Diffstat (limited to 'drivers/pci/controller')
-rw-r--r--drivers/pci/controller/pcie-brcmstb.c85
1 files changed, 48 insertions, 37 deletions
diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c
index 521acd632f1a..edf283e2b5dd 100644
--- a/drivers/pci/controller/pcie-brcmstb.c
+++ b/drivers/pci/controller/pcie-brcmstb.c
@@ -9,6 +9,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/ioport.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
@@ -52,6 +53,8 @@
#define PCIE_RC_DL_MDIO_RD_DATA 0x1108
#define PCIE_MISC_MISC_CTRL 0x4008
+#define PCIE_MISC_MISC_CTRL_PCIE_RCB_64B_MODE_MASK 0x80
+#define PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK 0x400
#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000
#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000
#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000
@@ -302,42 +305,34 @@ static u32 brcm_pcie_mdio_form_pkt(int port, int regad, int cmd)
/* negative return value indicates error */
static int brcm_pcie_mdio_read(void __iomem *base, u8 port, u8 regad, u32 *val)
{
- int tries;
u32 data;
+ int err;
writel(brcm_pcie_mdio_form_pkt(port, regad, MDIO_CMD_READ),
base + PCIE_RC_DL_MDIO_ADDR);
readl(base + PCIE_RC_DL_MDIO_ADDR);
-
- data = readl(base + PCIE_RC_DL_MDIO_RD_DATA);
- for (tries = 0; !MDIO_RD_DONE(data) && tries < 10; tries++) {
- udelay(10);
- data = readl(base + PCIE_RC_DL_MDIO_RD_DATA);
- }
-
+ err = readl_poll_timeout_atomic(base + PCIE_RC_DL_MDIO_RD_DATA, data,
+ MDIO_RD_DONE(data), 10, 100);
*val = FIELD_GET(MDIO_DATA_MASK, data);
- return MDIO_RD_DONE(data) ? 0 : -EIO;
+
+ return err;
}
/* negative return value indicates error */
static int brcm_pcie_mdio_write(void __iomem *base, u8 port,
u8 regad, u16 wrdata)
{
- int tries;
u32 data;
+ int err;
writel(brcm_pcie_mdio_form_pkt(port, regad, MDIO_CMD_WRITE),
base + PCIE_RC_DL_MDIO_ADDR);
readl(base + PCIE_RC_DL_MDIO_ADDR);
writel(MDIO_DATA_DONE_MASK | wrdata, base + PCIE_RC_DL_MDIO_WR_DATA);
- data = readl(base + PCIE_RC_DL_MDIO_WR_DATA);
- for (tries = 0; !MDIO_WT_DONE(data) && tries < 10; tries++) {
- udelay(10);
- data = readl(base + PCIE_RC_DL_MDIO_WR_DATA);
- }
-
- return MDIO_WT_DONE(data) ? 0 : -EIO;
+ err = readw_poll_timeout_atomic(base + PCIE_RC_DL_MDIO_WR_DATA, data,
+ MDIO_WT_DONE(data), 10, 100);
+ return err;
}
/*
@@ -445,7 +440,8 @@ static struct irq_chip brcm_msi_irq_chip = {
static struct msi_domain_info brcm_msi_domain_info = {
/* Multi MSI is supported by the controller, but not by this driver */
- .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+ MSI_FLAG_MULTI_PCI_MSI),
.chip = &brcm_msi_irq_chip,
};
@@ -505,21 +501,23 @@ static struct irq_chip brcm_msi_bottom_irq_chip = {
.irq_ack = brcm_msi_ack_irq,
};
-static int brcm_msi_alloc(struct brcm_msi *msi)
+static int brcm_msi_alloc(struct brcm_msi *msi, unsigned int nr_irqs)
{
int hwirq;
mutex_lock(&msi->lock);
- hwirq = bitmap_find_free_region(msi->used, msi->nr, 0);
+ hwirq = bitmap_find_free_region(msi->used, msi->nr,
+ order_base_2(nr_irqs));
mutex_unlock(&msi->lock);
return hwirq;
}
-static void brcm_msi_free(struct brcm_msi *msi, unsigned long hwirq)
+static void brcm_msi_free(struct brcm_msi *msi, unsigned long hwirq,
+ unsigned int nr_irqs)
{
mutex_lock(&msi->lock);
- bitmap_release_region(msi->used, hwirq, 0);
+ bitmap_release_region(msi->used, hwirq, order_base_2(nr_irqs));
mutex_unlock(&msi->lock);
}
@@ -527,16 +525,17 @@ static int brcm_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *args)
{
struct brcm_msi *msi = domain->host_data;
- int hwirq;
+ int hwirq, i;
- hwirq = brcm_msi_alloc(msi);
+ hwirq = brcm_msi_alloc(msi, nr_irqs);
if (hwirq < 0)
return hwirq;
- irq_domain_set_info(domain, virq, (irq_hw_number_t)hwirq,
- &brcm_msi_bottom_irq_chip, domain->host_data,
- handle_edge_irq, NULL, NULL);
+ for (i = 0; i < nr_irqs; i++)
+ irq_domain_set_info(domain, virq + i, hwirq + i,
+ &brcm_msi_bottom_irq_chip, domain->host_data,
+ handle_edge_irq, NULL, NULL);
return 0;
}
@@ -546,7 +545,7 @@ static void brcm_irq_domain_free(struct irq_domain *domain,
struct irq_data *d = irq_domain_get_irq_data(domain, virq);
struct brcm_msi *msi = irq_data_get_irq_chip_data(d);
- brcm_msi_free(msi, d->hwirq);
+ brcm_msi_free(msi, d->hwirq, nr_irqs);
}
static const struct irq_domain_ops msi_domain_ops = {
@@ -726,7 +725,7 @@ static void __iomem *brcm7425_pcie_map_bus(struct pci_bus *bus,
return base + DATA_ADDR(pcie);
}
-static inline void brcm_pcie_bridge_sw_init_set_generic(struct brcm_pcie *pcie, u32 val)
+static void brcm_pcie_bridge_sw_init_set_generic(struct brcm_pcie *pcie, u32 val)
{
u32 tmp, mask = RGR1_SW_INIT_1_INIT_GENERIC_MASK;
u32 shift = RGR1_SW_INIT_1_INIT_GENERIC_SHIFT;
@@ -736,7 +735,7 @@ static inline void brcm_pcie_bridge_sw_init_set_generic(struct brcm_pcie *pcie,
writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie));
}
-static inline void brcm_pcie_bridge_sw_init_set_7278(struct brcm_pcie *pcie, u32 val)
+static void brcm_pcie_bridge_sw_init_set_7278(struct brcm_pcie *pcie, u32 val)
{
u32 tmp, mask = RGR1_SW_INIT_1_INIT_7278_MASK;
u32 shift = RGR1_SW_INIT_1_INIT_7278_SHIFT;
@@ -746,7 +745,7 @@ static inline void brcm_pcie_bridge_sw_init_set_7278(struct brcm_pcie *pcie, u32
writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie));
}
-static inline void brcm_pcie_perst_set_4908(struct brcm_pcie *pcie, u32 val)
+static void brcm_pcie_perst_set_4908(struct brcm_pcie *pcie, u32 val)
{
if (WARN_ONCE(!pcie->perst_reset, "missing PERST# reset controller\n"))
return;
@@ -757,7 +756,7 @@ static inline void brcm_pcie_perst_set_4908(struct brcm_pcie *pcie, u32 val)
reset_control_deassert(pcie->perst_reset);
}
-static inline void brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, u32 val)
+static void brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, u32 val)
{
u32 tmp;
@@ -767,7 +766,7 @@ static inline void brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, u32 val)
writel(tmp, pcie->base + PCIE_MISC_PCIE_CTRL);
}
-static inline void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val)
+static void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val)
{
u32 tmp;
@@ -776,7 +775,7 @@ static inline void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val)
writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie));
}
-static inline int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie,
+static int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie,
u64 *rc_bar2_size,
u64 *rc_bar2_offset)
{
@@ -903,11 +902,16 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
else
burst = 0x2; /* 512 bytes */
- /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
+ /*
+ * Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN,
+ * RCB_MPS_MODE, RCB_64B_MODE
+ */
tmp = readl(base + PCIE_MISC_MISC_CTRL);
u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK);
u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK);
u32p_replace_bits(&tmp, burst, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK);
+ u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK);
+ u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_PCIE_RCB_64B_MODE_MASK);
writel(tmp, base + PCIE_MISC_MISC_CTRL);
ret = brcm_pcie_get_rc_bar2_size_and_offset(pcie, &rc_bar2_size,
@@ -1033,8 +1037,15 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie)
pcie->perst_set(pcie, 0);
/*
- * Give the RC/EP time to wake up, before trying to configure RC.
- * Intermittently check status for link-up, up to a total of 100ms.
+ * Wait for 100ms after PERST# deassertion; see PCIe CEM specification
+ * sections 2.2, PCIe r5.0, 6.6.1.
+ */
+ msleep(100);
+
+ /*
+ * Give the RC/EP even more time to wake up, before trying to
+ * configure RC. Intermittently check status for link-up, up to a
+ * total of 100ms.
*/
for (i = 0; i < 100 && !brcm_pcie_link_up(pcie); i += 5)
msleep(5);