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
This commit is contained in:
Bjorn Helgaas 2022-12-10 10:36:36 -06:00
commit 0ef283080e
1 changed files with 48 additions and 37 deletions

View File

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