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:
commit
0ef283080e
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue