Skip to content

Commit

Permalink
PCI: Add quirk for Intel DH895xCC VF PCI config erratum
Browse files Browse the repository at this point in the history
The PCI capabilities list for Intel DH895xCC VFs (device id 0x0443) with
QuickAssist Technology is prematurely terminated in hardware.
Workaround the issue by hard-coding the known expected next capability
pointer and saving the PCIE cap into internal buffer.

Patch generated against cryptodev-2.6

Signed-off-by: Tadeusz Struk <[email protected]>
Signed-off-by: Herbert Xu <[email protected]>
  • Loading branch information
tstruk authored and herbertx committed Aug 10, 2015
1 parent 89c07b8 commit 3388a61
Showing 1 changed file with 85 additions and 0 deletions.
85 changes: 85 additions & 0 deletions drivers/pci/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -4008,3 +4008,88 @@ void pci_dev_specific_enable_acs(struct pci_dev *dev)
}
}
}

/*
* The PCI capabilities list for Intel DH895xCC VFs (device id 0x0443) with
* QuickAssist Technology (QAT) is prematurely terminated in hardware. The
* Next Capability pointer in the MSI Capability Structure should point to
* the PCIe Capability Structure but is incorrectly hardwired as 0 terminating
* the list.
*/
static void quirk_intel_qat_vf_cap(struct pci_dev *pdev)
{
int pos, i = 0;
u8 next_cap;
u16 reg16, *cap;
struct pci_cap_saved_state *state;

/* Bail if the hardware bug is fixed */
if (pdev->pcie_cap || pci_find_capability(pdev, PCI_CAP_ID_EXP))
return;

/* Bail if MSI Capability Structure is not found for some reason */
pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
if (!pos)
return;

/*
* Bail if Next Capability pointer in the MSI Capability Structure
* is not the expected incorrect 0x00.
*/
pci_read_config_byte(pdev, pos + 1, &next_cap);
if (next_cap)
return;

/*
* PCIe Capability Structure is expected to be at 0x50 and should
* terminate the list (Next Capability pointer is 0x00). Verify
* Capability Id and Next Capability pointer is as expected.
* Open-code some of set_pcie_port_type() and pci_cfg_space_size_ext()
* to correctly set kernel data structures which have already been
* set incorrectly due to the hardware bug.
*/
pos = 0x50;
pci_read_config_word(pdev, pos, &reg16);
if (reg16 == (0x0000 | PCI_CAP_ID_EXP)) {
u32 status;
#ifndef PCI_EXP_SAVE_REGS
#define PCI_EXP_SAVE_REGS 7
#endif
int size = PCI_EXP_SAVE_REGS * sizeof(u16);

pdev->pcie_cap = pos;
pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
pdev->pcie_flags_reg = reg16;
pci_read_config_word(pdev, pos + PCI_EXP_DEVCAP, &reg16);
pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD;

pdev->cfg_size = PCI_CFG_SPACE_EXP_SIZE;
if (pci_read_config_dword(pdev, PCI_CFG_SPACE_SIZE, &status) !=
PCIBIOS_SUCCESSFUL || (status == 0xffffffff))
pdev->cfg_size = PCI_CFG_SPACE_SIZE;

if (pci_find_saved_cap(pdev, PCI_CAP_ID_EXP))
return;

/*
* Save PCIE cap
*/
state = kzalloc(sizeof(*state) + size, GFP_KERNEL);
if (!state)
return;

state->cap.cap_nr = PCI_CAP_ID_EXP;
state->cap.cap_extended = 0;
state->cap.size = size;
cap = (u16 *)&state->cap.data[0];
pcie_capability_read_word(pdev, PCI_EXP_DEVCTL, &cap[i++]);
pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &cap[i++]);
pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &cap[i++]);
pcie_capability_read_word(pdev, PCI_EXP_RTCTL, &cap[i++]);
pcie_capability_read_word(pdev, PCI_EXP_DEVCTL2, &cap[i++]);
pcie_capability_read_word(pdev, PCI_EXP_LNKCTL2, &cap[i++]);
pcie_capability_read_word(pdev, PCI_EXP_SLTCTL2, &cap[i++]);
hlist_add_head(&state->next, &pdev->saved_cap_space);
}
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x443, quirk_intel_qat_vf_cap);

0 comments on commit 3388a61

Please sign in to comment.