22
22
#include <linux/errno.h>
23
23
#include <linux/aer.h>
24
24
25
+ #include "dfl.h"
26
+
25
27
#define DRV_VERSION "0.8"
26
28
#define DRV_NAME "dfl-pci"
27
29
30
+ struct cci_drvdata {
31
+ struct dfl_fpga_cdev * cdev ; /* container device */
32
+ };
33
+
34
+ static void __iomem * cci_pci_ioremap_bar (struct pci_dev * pcidev , int bar )
35
+ {
36
+ if (pcim_iomap_regions (pcidev , BIT (bar ), DRV_NAME ))
37
+ return NULL ;
38
+
39
+ return pcim_iomap_table (pcidev )[bar ];
40
+ }
41
+
28
42
/* PCI Device ID */
29
43
#define PCIE_DEVICE_ID_PF_INT_5_X 0xBCBD
30
44
#define PCIE_DEVICE_ID_PF_INT_6_X 0xBCC0
@@ -45,6 +59,120 @@ static struct pci_device_id cci_pcie_id_tbl[] = {
45
59
};
46
60
MODULE_DEVICE_TABLE (pci , cci_pcie_id_tbl );
47
61
62
+ static int cci_init_drvdata (struct pci_dev * pcidev )
63
+ {
64
+ struct cci_drvdata * drvdata ;
65
+
66
+ drvdata = devm_kzalloc (& pcidev -> dev , sizeof (* drvdata ), GFP_KERNEL );
67
+ if (!drvdata )
68
+ return - ENOMEM ;
69
+
70
+ pci_set_drvdata (pcidev , drvdata );
71
+
72
+ return 0 ;
73
+ }
74
+
75
+ static void cci_remove_feature_devs (struct pci_dev * pcidev )
76
+ {
77
+ struct cci_drvdata * drvdata = pci_get_drvdata (pcidev );
78
+
79
+ /* remove all children feature devices */
80
+ dfl_fpga_feature_devs_remove (drvdata -> cdev );
81
+ }
82
+
83
+ /* enumerate feature devices under pci device */
84
+ static int cci_enumerate_feature_devs (struct pci_dev * pcidev )
85
+ {
86
+ struct cci_drvdata * drvdata = pci_get_drvdata (pcidev );
87
+ struct dfl_fpga_enum_info * info ;
88
+ struct dfl_fpga_cdev * cdev ;
89
+ resource_size_t start , len ;
90
+ int port_num , bar , i , ret = 0 ;
91
+ void __iomem * base ;
92
+ u32 offset ;
93
+ u64 v ;
94
+
95
+ /* allocate enumeration info via pci_dev */
96
+ info = dfl_fpga_enum_info_alloc (& pcidev -> dev );
97
+ if (!info )
98
+ return - ENOMEM ;
99
+
100
+ /* start to find Device Feature List from Bar 0 */
101
+ base = cci_pci_ioremap_bar (pcidev , 0 );
102
+ if (!base ) {
103
+ ret = - ENOMEM ;
104
+ goto enum_info_free_exit ;
105
+ }
106
+
107
+ /*
108
+ * PF device has FME and Ports/AFUs, and VF device only has one
109
+ * Port/AFU. Check them and add related "Device Feature List" info
110
+ * for the next step enumeration.
111
+ */
112
+ if (dfl_feature_is_fme (base )) {
113
+ start = pci_resource_start (pcidev , 0 );
114
+ len = pci_resource_len (pcidev , 0 );
115
+
116
+ dfl_fpga_enum_info_add_dfl (info , start , len , base );
117
+
118
+ /*
119
+ * find more Device Feature Lists (e.g. Ports) per information
120
+ * indicated by FME module.
121
+ */
122
+ v = readq (base + FME_HDR_CAP );
123
+ port_num = FIELD_GET (FME_CAP_NUM_PORTS , v );
124
+
125
+ WARN_ON (port_num > MAX_DFL_FPGA_PORT_NUM );
126
+
127
+ for (i = 0 ; i < port_num ; i ++ ) {
128
+ v = readq (base + FME_HDR_PORT_OFST (i ));
129
+
130
+ /* skip ports which are not implemented. */
131
+ if (!(v & FME_PORT_OFST_IMP ))
132
+ continue ;
133
+
134
+ /*
135
+ * add Port's Device Feature List information for next
136
+ * step enumeration.
137
+ */
138
+ bar = FIELD_GET (FME_PORT_OFST_BAR_ID , v );
139
+ offset = FIELD_GET (FME_PORT_OFST_DFH_OFST , v );
140
+ base = cci_pci_ioremap_bar (pcidev , bar );
141
+ if (!base )
142
+ continue ;
143
+
144
+ start = pci_resource_start (pcidev , bar ) + offset ;
145
+ len = pci_resource_len (pcidev , bar ) - offset ;
146
+
147
+ dfl_fpga_enum_info_add_dfl (info , start , len ,
148
+ base + offset );
149
+ }
150
+ } else if (dfl_feature_is_port (base )) {
151
+ start = pci_resource_start (pcidev , 0 );
152
+ len = pci_resource_len (pcidev , 0 );
153
+
154
+ dfl_fpga_enum_info_add_dfl (info , start , len , base );
155
+ } else {
156
+ ret = - ENODEV ;
157
+ goto enum_info_free_exit ;
158
+ }
159
+
160
+ /* start enumeration with prepared enumeration information */
161
+ cdev = dfl_fpga_feature_devs_enumerate (info );
162
+ if (IS_ERR (cdev )) {
163
+ dev_err (& pcidev -> dev , "Enumeration failure\n" );
164
+ ret = PTR_ERR (cdev );
165
+ goto enum_info_free_exit ;
166
+ }
167
+
168
+ drvdata -> cdev = cdev ;
169
+
170
+ enum_info_free_exit :
171
+ dfl_fpga_enum_info_free (info );
172
+
173
+ return ret ;
174
+ }
175
+
48
176
static
49
177
int cci_pci_probe (struct pci_dev * pcidev , const struct pci_device_id * pcidevid )
50
178
{
@@ -76,8 +204,19 @@ int cci_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *pcidevid)
76
204
goto disable_error_report_exit ;
77
205
}
78
206
79
- /* TODO: create and add the platform device per feature list */
80
- return 0 ;
207
+ ret = cci_init_drvdata (pcidev );
208
+ if (ret ) {
209
+ dev_err (& pcidev -> dev , "Fail to init drvdata %d.\n" , ret );
210
+ goto disable_error_report_exit ;
211
+ }
212
+
213
+ ret = cci_enumerate_feature_devs (pcidev );
214
+ if (ret ) {
215
+ dev_err (& pcidev -> dev , "enumeration failure %d.\n" , ret );
216
+ goto disable_error_report_exit ;
217
+ }
218
+
219
+ return ret ;
81
220
82
221
disable_error_report_exit :
83
222
pci_disable_pcie_error_reporting (pcidev );
@@ -86,6 +225,7 @@ int cci_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *pcidevid)
86
225
87
226
static void cci_pci_remove (struct pci_dev * pcidev )
88
227
{
228
+ cci_remove_feature_devs (pcidev );
89
229
pci_disable_pcie_error_reporting (pcidev );
90
230
}
91
231
0 commit comments