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) |
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),
}
}
+/*
+ * Read a 32-bit PCI Configuration Space register via the PCI-E backdoor
+ * mechanism. This guarantees that we get the real value even if we're
+ * operating within a Virtual Machine and the Hypervisor is trapping our
+ * Configuration Space accesses.
+ */
+void t4_hw_pci_read_cfg4(struct adapter *adap, int reg, u32 *val)
+{
+ u32 req = ENABLE | FUNCTION(adap->fn) | reg;
+
+ if (is_t4(adap->params.chip))
+ req |= F_LOCALCFG;
+
+ t4_write_reg(adap, PCIE_CFG_SPACE_REQ, req);
+ *val = t4_read_reg(adap, PCIE_CFG_SPACE_DATA);
+
+ /* Reset ENABLE to 0 so reads of PCIE_CFG_SPACE_DATA won't cause a
+ * Configuration Space read. (None of the other fields matter when
+ * ENABLE is 0 so a simple register write is easier than a
+ * read-modify-write via t4_set_reg_field().)
+ */
+ t4_write_reg(adap, PCIE_CFG_SPACE_REQ, 0);
+}
+
/*
* Get the reply to a mailbox command and store it in @rpl in big-endian order.
*/