cxgb4: Use FW interface to get BAR0 value
Use the firmware interface to get the BAR0 value since we really don't want
to use the PCI-E Configuration Space Backdoor access which is owned by the
firmware.
Set up PCI-E Memory Window registers using the true values programmed into
BAR registers. When the PF4 "Master Function" is exported to a Virtual
Machine, the values returned by pci_resource_start() will be for the
synthetic PCI-E Configuration Space and not the real addresses. But we need
to program the PCI-E Memory Window address decoders with the real addresses
that we're going to be using in order to have accesses through the Memory
Windows work.
Based on origninal work by Casey Leedom <leedom@chelsio.com>
Signed-off-by: Casey Leedom <leedom@chelsio.com>
Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index e8e77b8..524a8b2 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -4773,20 +4773,75 @@
dev_alert(adap->pdev_dev, "encountered fatal error, adapter stopped\n");
}
+/* Return the specified PCI-E Configuration Space register from our Physical
+ * Function. We try first via a Firmware LDST Command since we prefer to let
+ * the firmware own all of these registers, but if that fails we go for it
+ * directly ourselves.
+ */
+static u32 t4_read_pcie_cfg4(struct adapter *adap, int reg)
+{
+ struct fw_ldst_cmd ldst_cmd;
+ u32 val;
+ int ret;
+
+ /* Construct and send the Firmware LDST Command to retrieve the
+ * specified PCI-E Configuration Space register.
+ */
+ memset(&ldst_cmd, 0, sizeof(ldst_cmd));
+ ldst_cmd.op_to_addrspace =
+ htonl(FW_CMD_OP(FW_LDST_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_READ |
+ FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FUNC_PCIE));
+ ldst_cmd.cycles_to_len16 = htonl(FW_LEN16(ldst_cmd));
+ ldst_cmd.u.pcie.select_naccess = FW_LDST_CMD_NACCESS(1);
+ ldst_cmd.u.pcie.ctrl_to_fn =
+ (FW_LDST_CMD_LC | FW_LDST_CMD_FN(adap->fn));
+ ldst_cmd.u.pcie.r = reg;
+ ret = t4_wr_mbox(adap, adap->mbox, &ldst_cmd, sizeof(ldst_cmd),
+ &ldst_cmd);
+
+ /* If the LDST Command suucceeded, exctract the returned register
+ * value. Otherwise read it directly ourself.
+ */
+ if (ret == 0)
+ val = ntohl(ldst_cmd.u.pcie.data[0]);
+ else
+ t4_hw_pci_read_cfg4(adap, reg, &val);
+
+ return val;
+}
+
static void setup_memwin(struct adapter *adap)
{
- u32 bar0, mem_win0_base, mem_win1_base, mem_win2_base;
+ u32 mem_win0_base, mem_win1_base, mem_win2_base, mem_win2_aperture;
- bar0 = pci_resource_start(adap->pdev, 0); /* truncation intentional */
if (is_t4(adap->params.chip)) {
+ u32 bar0;
+
+ /* Truncation intentional: we only read the bottom 32-bits of
+ * the 64-bit BAR0/BAR1 ... We use the hardware backdoor
+ * mechanism to read BAR0 instead of using
+ * pci_resource_start() because we could be operating from
+ * within a Virtual Machine which is trapping our accesses to
+ * our Configuration Space and we need to set up the PCI-E
+ * Memory Window decoders with the actual addresses which will
+ * be coming across the PCI-E link.
+ */
+ bar0 = t4_read_pcie_cfg4(adap, PCI_BASE_ADDRESS_0);
+ bar0 &= PCI_BASE_ADDRESS_MEM_MASK;
+ adap->t4_bar0 = bar0;
+
mem_win0_base = bar0 + MEMWIN0_BASE;
mem_win1_base = bar0 + MEMWIN1_BASE;
mem_win2_base = bar0 + MEMWIN2_BASE;
+ mem_win2_aperture = MEMWIN2_APERTURE;
} else {
/* For T5, only relative offset inside the PCIe BAR is passed */
mem_win0_base = MEMWIN0_BASE;
- mem_win1_base = MEMWIN1_BASE_T5;
+ mem_win1_base = MEMWIN1_BASE;
mem_win2_base = MEMWIN2_BASE_T5;
+ mem_win2_aperture = MEMWIN2_APERTURE_T5;
}
t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 0),
mem_win0_base | BIR(0) |
@@ -4796,16 +4851,19 @@
WINDOW(ilog2(MEMWIN1_APERTURE) - 10));
t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2),
mem_win2_base | BIR(0) |
- WINDOW(ilog2(MEMWIN2_APERTURE) - 10));
+ WINDOW(ilog2(mem_win2_aperture) - 10));
+ t4_read_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2));
}
static void setup_memwin_rdma(struct adapter *adap)
{
if (adap->vres.ocq.size) {
- unsigned int start, sz_kb;
+ u32 start;
+ unsigned int sz_kb;
- start = pci_resource_start(adap->pdev, 2) +
- OCQ_WIN_OFFSET(adap->pdev, &adap->vres);
+ start = t4_read_pcie_cfg4(adap, PCI_BASE_ADDRESS_2);
+ start &= PCI_BASE_ADDRESS_MEM_MASK;
+ start += OCQ_WIN_OFFSET(adap->pdev, &adap->vres);
sz_kb = roundup_pow_of_two(adap->vres.ocq.size) >> 10;
t4_write_reg(adap,
PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 3),