-
-
Notifications
You must be signed in to change notification settings - Fork 66
/
Copy path0001-PCI-add-a-reset-quirk-for-Intel-I219LM-ethernet-adap.patch
140 lines (131 loc) · 4.27 KB
/
0001-PCI-add-a-reset-quirk-for-Intel-I219LM-ethernet-adap.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
From 8f14220e1eedf12788ca6055a04bab936eb70421 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?=
<marmarek@invisiblethingslab.com>
Date: Mon, 15 Jul 2024 16:55:56 +0200
Subject: [PATCH] PCI: add a reset quirk for Intel I219LM ethernet adapter
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The device does support FLR, has the relevant registers in the config
space, but fails to link them to the pci caps list. Fix it by linking
them manually, so the standard pci_af_flr() will find it. The fixup
needs to be repeated after reset.
The fixup will be visible via sysfs, which is intended side effect so
that libvirt can see FLR as supported too.
Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
---
drivers/pci/pci.c | 2 +-
drivers/pci/pci.h | 1 +
drivers/pci/quirks.c | 70 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 72 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 0b29ec6e8e5e..63aa06fd99d0 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4583,7 +4583,7 @@ int pcie_reset_flr(struct pci_dev *dev, bool probe)
}
EXPORT_SYMBOL_GPL(pcie_reset_flr);
-static int pci_af_flr(struct pci_dev *dev, bool probe)
+int pci_af_flr(struct pci_dev *dev, bool probe)
{
int pos;
u8 cap;
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 2e40fc63ba31..2b438c262bf8 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -755,6 +755,7 @@ static inline int pcie_lbms_count(struct pci_dev *port, unsigned long *val)
return -EOPNOTSUPP;
}
#endif
+int pci_af_flr(struct pci_dev *dev, bool probe);
struct pci_dev_reset_methods {
u16 vendor;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 76f4df75b08a..cde5a6351626 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -4208,6 +4208,74 @@ static int reset_hinic_vf_dev(struct pci_dev *pdev, bool probe)
return 0;
}
+#define PCI_DEVICE_ID_INTEL_I219LM 0x550A
+#define I219_PCI_MSI_POS 0xd0
+#define I219_PCI_AF_POS 0xe0
+
+/* FLR fixup for Intel I219LM Ethernet controller.
+ * The device does support FLR, has the relevant registers in the config space,
+ * but fails to link them to the pci caps list. Fix it by linking them
+ * manually, so the standard pci_af_flr() will find it. The fixup needs to be
+ * repeated after reset, so do that in probe stage.
+ * The fixup will be visible via sysfs, which is intended side effect so that
+ * libvirt can see FLR as supported too.
+ */
+static void fixup_intel_i219lm_flr(struct pci_dev *dev)
+{
+ int pos;
+ u8 cap;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_AF);
+ if (pos)
+ return;
+
+ /*
+ * If not found, check if we can find it - the last listed cap should
+ * be MSI at 0xd0 (I219_PCI_MSI_POS), and AF should be at 0xe0
+ * (I219_PCI_AF_POS).
+ */
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+ if (pos != I219_PCI_MSI_POS)
+ return;
+
+ pci_read_config_byte(dev, pos + PCI_CAP_LIST_NEXT, &cap);
+ /*
+ * Linked to something else already? Already linked to PCI_AF was
+ * handled earlier.
+ */
+ if (cap)
+ return;
+ /* Check if PCI_AF indeed is at I219_PCI_AF_POS. */
+ pci_read_config_byte(dev, I219_PCI_AF_POS, &cap);
+ if (cap != PCI_CAP_ID_AF)
+ return;
+
+ /* All sanity checks done, link the cap */
+ pci_write_config_byte(dev, pos + PCI_CAP_LIST_NEXT, I219_PCI_AF_POS);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I219LM,
+ fixup_intel_i219lm_flr);
+
+static int reset_i219lm_dev(struct pci_dev *dev, bool probe)
+{
+ int ret;
+
+ /* Ensure AF FLR is visible before using it */
+ if (!probe)
+ fixup_intel_i219lm_flr(dev);
+
+ /* Call normal FLR, but re-apply fixup_intel_i219lm_flr() afterwards. */
+ ret = pci_af_flr(dev, probe);
+ if (ret)
+ return ret;
+
+ if (!probe)
+ fixup_intel_i219lm_flr(dev);
+
+ return 0;
+}
+
static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF,
reset_intel_82599_sfp_virtfn },
@@ -4223,6 +4291,8 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
reset_chelsio_generic_dev },
{ PCI_VENDOR_ID_HUAWEI, PCI_DEVICE_ID_HINIC_VF,
reset_hinic_vf_dev },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I219LM,
+ reset_i219lm_dev },
{ 0 }
};
--
2.46.0