1b8180f79SJunyang Han // SPDX-License-Identifier: GPL-2.0-only
2b8180f79SJunyang Han /*
3b8180f79SJunyang Han * ZTE DingHai Ethernet driver
4b8180f79SJunyang Han * Copyright (c) 2022-2026, ZTE Corporation.
5b8180f79SJunyang Han */
6b8180f79SJunyang Han
7b8180f79SJunyang Han #include <linux/module.h>
8b8180f79SJunyang Han #include <linux/pci.h>
9b8180f79SJunyang Han #include <net/devlink.h>
10b8180f79SJunyang Han #include <linux/dma-mapping.h>
11b8180f79SJunyang Han #include "en_pf.h"
12*19df707eSJunyang Han #include "dh_queue.h"
13b8180f79SJunyang Han
14b8180f79SJunyang Han MODULE_AUTHOR("Junyang Han <han.junyang@zte.com.cn>");
15b8180f79SJunyang Han MODULE_DESCRIPTION("ZTE DingHai series Ethernet driver");
16b8180f79SJunyang Han MODULE_LICENSE("GPL");
17b8180f79SJunyang Han
18b8180f79SJunyang Han static const struct devlink_ops zxdh_pf_devlink_ops = {};
19b8180f79SJunyang Han
20b8180f79SJunyang Han static const struct pci_device_id zxdh_pf_pci_table[] = {
21b8180f79SJunyang Han { PCI_DEVICE(ZXDH_PF_VENDOR_ID, ZXDH_PF_DEVICE_ID) },
22b8180f79SJunyang Han { PCI_DEVICE(ZXDH_PF_VENDOR_ID, ZXDH_VF_DEVICE_ID) },
23b8180f79SJunyang Han { }
24b8180f79SJunyang Han };
25b8180f79SJunyang Han
26b8180f79SJunyang Han MODULE_DEVICE_TABLE(pci, zxdh_pf_pci_table);
27b8180f79SJunyang Han
zxdh_core_alloc_priv(struct zxdh_core_dev * zxdh_dev,size_t size)28b8180f79SJunyang Han void *zxdh_core_alloc_priv(struct zxdh_core_dev *zxdh_dev, size_t size)
29b8180f79SJunyang Han {
30b8180f79SJunyang Han void *priv = kzalloc(size, GFP_KERNEL);
31b8180f79SJunyang Han
32b8180f79SJunyang Han if (priv)
33b8180f79SJunyang Han zxdh_dev->priv = priv;
34b8180f79SJunyang Han return priv;
35b8180f79SJunyang Han }
36b8180f79SJunyang Han
zxdh_core_free_priv(struct zxdh_core_dev * zxdh_dev)37b8180f79SJunyang Han void zxdh_core_free_priv(struct zxdh_core_dev *zxdh_dev)
38b8180f79SJunyang Han {
39b8180f79SJunyang Han kfree(zxdh_dev->priv);
40b8180f79SJunyang Han }
41b8180f79SJunyang Han
zxdh_pf_pci_init(struct zxdh_core_dev * zxdh_dev)42b8180f79SJunyang Han static int zxdh_pf_pci_init(struct zxdh_core_dev *zxdh_dev)
43b8180f79SJunyang Han {
44b8180f79SJunyang Han struct zxdh_pf_dev *pf_dev = zxdh_dev->priv;
45b8180f79SJunyang Han int ret;
46b8180f79SJunyang Han
47b8180f79SJunyang Han pci_set_drvdata(zxdh_dev->pdev, zxdh_dev);
48b8180f79SJunyang Han
49b8180f79SJunyang Han ret = pci_enable_device(zxdh_dev->pdev);
50b8180f79SJunyang Han if (ret) {
51b8180f79SJunyang Han dev_err(zxdh_dev->device, "pci_enable_device failed: %d\n", ret);
52b8180f79SJunyang Han return ret;
53b8180f79SJunyang Han }
54b8180f79SJunyang Han
55b8180f79SJunyang Han dma_set_mask_and_coherent(zxdh_dev->device, DMA_BIT_MASK(64));
56b8180f79SJunyang Han
57b8180f79SJunyang Han ret = pci_request_selected_regions(zxdh_dev->pdev,
58b8180f79SJunyang Han pci_select_bars(zxdh_dev->pdev, IORESOURCE_MEM),
59b8180f79SJunyang Han "dh-pf");
60b8180f79SJunyang Han if (ret) {
61b8180f79SJunyang Han dev_err(zxdh_dev->device, "pci_request_selected_regions failed: %d\n", ret);
62b8180f79SJunyang Han goto err_pci;
63b8180f79SJunyang Han }
64b8180f79SJunyang Han
65b8180f79SJunyang Han pci_set_master(zxdh_dev->pdev);
66b8180f79SJunyang Han ret = pci_save_state(zxdh_dev->pdev);
67b8180f79SJunyang Han if (ret) {
68b8180f79SJunyang Han dev_err(zxdh_dev->device, "pci_save_state failed: %d\n", ret);
69b8180f79SJunyang Han goto err_pci_save_state;
70b8180f79SJunyang Han }
71b8180f79SJunyang Han
72b8180f79SJunyang Han if (!(pci_resource_flags(zxdh_dev->pdev, 0) & IORESOURCE_MEM)) {
73b8180f79SJunyang Han ret = -ENODEV;
74b8180f79SJunyang Han dev_err(zxdh_dev->device, "BAR 0 is not an MMIO resource\n");
75b8180f79SJunyang Han goto err_pci_save_state;
76b8180f79SJunyang Han }
77b8180f79SJunyang Han
78b8180f79SJunyang Han pf_dev->pci_ioremap_addr[0] =
79b8180f79SJunyang Han ioremap(pci_resource_start(zxdh_dev->pdev, 0),
80b8180f79SJunyang Han pci_resource_len(zxdh_dev->pdev, 0));
81b8180f79SJunyang Han if (!pf_dev->pci_ioremap_addr[0]) {
82b8180f79SJunyang Han ret = -ENOMEM;
83b8180f79SJunyang Han dev_err(zxdh_dev->device, "dh pf pci ioremap failed\n");
84b8180f79SJunyang Han goto err_pci_save_state;
85b8180f79SJunyang Han }
86b8180f79SJunyang Han
87b8180f79SJunyang Han return 0;
88b8180f79SJunyang Han
89b8180f79SJunyang Han err_pci_save_state:
90b8180f79SJunyang Han pci_release_selected_regions(zxdh_dev->pdev,
91b8180f79SJunyang Han pci_select_bars(zxdh_dev->pdev, IORESOURCE_MEM));
92b8180f79SJunyang Han err_pci:
93b8180f79SJunyang Han pci_disable_device(zxdh_dev->pdev);
94b8180f79SJunyang Han return ret;
95b8180f79SJunyang Han }
96b8180f79SJunyang Han
zxdh_pf_pci_close(struct zxdh_core_dev * zxdh_dev)97b8180f79SJunyang Han void zxdh_pf_pci_close(struct zxdh_core_dev *zxdh_dev)
98b8180f79SJunyang Han {
99b8180f79SJunyang Han struct zxdh_pf_dev *pf_dev = zxdh_dev->priv;
100b8180f79SJunyang Han
101b8180f79SJunyang Han iounmap(pf_dev->pci_ioremap_addr[0]);
102b8180f79SJunyang Han pci_release_selected_regions(zxdh_dev->pdev,
103b8180f79SJunyang Han pci_select_bars(zxdh_dev->pdev, IORESOURCE_MEM));
104b8180f79SJunyang Han pci_disable_device(zxdh_dev->pdev);
105b8180f79SJunyang Han }
106b8180f79SJunyang Han
zxdh_pf_pci_find_capability(struct pci_dev * pdev,u8 cfg_type,u32 ioresource_types,int * bars)107*19df707eSJunyang Han int zxdh_pf_pci_find_capability(struct pci_dev *pdev, u8 cfg_type,
108*19df707eSJunyang Han u32 ioresource_types, int *bars)
109*19df707eSJunyang Han {
110*19df707eSJunyang Han int pos;
111*19df707eSJunyang Han u8 type;
112*19df707eSJunyang Han u8 bar;
113*19df707eSJunyang Han
114*19df707eSJunyang Han for (pos = pci_find_capability(pdev, PCI_CAP_ID_VNDR); pos > 0;
115*19df707eSJunyang Han pos = pci_find_next_capability(pdev, pos, PCI_CAP_ID_VNDR)) {
116*19df707eSJunyang Han pci_read_config_byte(pdev,
117*19df707eSJunyang Han pos + offsetof(struct zxdh_pf_pci_cap,
118*19df707eSJunyang Han cfg_type), &type);
119*19df707eSJunyang Han pci_read_config_byte(pdev,
120*19df707eSJunyang Han pos + offsetof(struct zxdh_pf_pci_cap, bar), &bar);
121*19df707eSJunyang Han
122*19df707eSJunyang Han /* ignore structures with reserved BAR values */
123*19df707eSJunyang Han if (bar > ZXDH_PF_MAX_BAR_VAL)
124*19df707eSJunyang Han continue;
125*19df707eSJunyang Han
126*19df707eSJunyang Han if (type == cfg_type) {
127*19df707eSJunyang Han if (pci_resource_len(pdev, bar) &&
128*19df707eSJunyang Han pci_resource_flags(pdev, bar) & ioresource_types) {
129*19df707eSJunyang Han *bars |= (1 << bar);
130*19df707eSJunyang Han return pos;
131*19df707eSJunyang Han }
132*19df707eSJunyang Han }
133*19df707eSJunyang Han }
134*19df707eSJunyang Han
135*19df707eSJunyang Han return 0;
136*19df707eSJunyang Han }
137*19df707eSJunyang Han
zxdh_pf_map_capability(struct zxdh_core_dev * zxdh_dev,int off,size_t minlen,u32 align,u32 start,u32 size,size_t * len,resource_size_t * pa,u32 * bar_off)138*19df707eSJunyang Han void __iomem *zxdh_pf_map_capability(struct zxdh_core_dev *zxdh_dev, int off,
139*19df707eSJunyang Han size_t minlen, u32 align,
140*19df707eSJunyang Han u32 start, u32 size,
141*19df707eSJunyang Han size_t *len, resource_size_t *pa,
142*19df707eSJunyang Han u32 *bar_off)
143*19df707eSJunyang Han {
144*19df707eSJunyang Han struct pci_dev *pdev = zxdh_dev->pdev;
145*19df707eSJunyang Han void __iomem *p;
146*19df707eSJunyang Han u32 offset;
147*19df707eSJunyang Han u32 length;
148*19df707eSJunyang Han u8 bar;
149*19df707eSJunyang Han
150*19df707eSJunyang Han pci_read_config_byte(pdev,
151*19df707eSJunyang Han off + offsetof(struct zxdh_pf_pci_cap, bar), &bar);
152*19df707eSJunyang Han
153*19df707eSJunyang Han if (bar > ZXDH_PF_MAX_BAR_VAL) {
154*19df707eSJunyang Han dev_err(zxdh_dev->device, "invalid bar %u\n", bar);
155*19df707eSJunyang Han return NULL;
156*19df707eSJunyang Han }
157*19df707eSJunyang Han
158*19df707eSJunyang Han pci_read_config_dword(pdev,
159*19df707eSJunyang Han off + offsetof(struct zxdh_pf_pci_cap,
160*19df707eSJunyang Han offset), &offset);
161*19df707eSJunyang Han pci_read_config_dword(pdev,
162*19df707eSJunyang Han off + offsetof(struct zxdh_pf_pci_cap,
163*19df707eSJunyang Han length), &length);
164*19df707eSJunyang Han
165*19df707eSJunyang Han if (bar_off)
166*19df707eSJunyang Han *bar_off = offset;
167*19df707eSJunyang Han
168*19df707eSJunyang Han if (length <= start) {
169*19df707eSJunyang Han dev_err(zxdh_dev->device, "bad capability len %u (>%u expected)\n",
170*19df707eSJunyang Han length, start);
171*19df707eSJunyang Han return NULL;
172*19df707eSJunyang Han }
173*19df707eSJunyang Han
174*19df707eSJunyang Han if (length - start < minlen) {
175*19df707eSJunyang Han dev_err(zxdh_dev->device, "bad capability len %u (>=%zu expected)\n",
176*19df707eSJunyang Han length, minlen);
177*19df707eSJunyang Han return NULL;
178*19df707eSJunyang Han }
179*19df707eSJunyang Han
180*19df707eSJunyang Han length -= start;
181*19df707eSJunyang Han if (start + offset < offset) {
182*19df707eSJunyang Han dev_err(zxdh_dev->device, "map wrap-around %u+%u\n", start, offset);
183*19df707eSJunyang Han return NULL;
184*19df707eSJunyang Han }
185*19df707eSJunyang Han
186*19df707eSJunyang Han offset += start;
187*19df707eSJunyang Han if (offset & (align - 1)) {
188*19df707eSJunyang Han dev_err(zxdh_dev->device, "offset %u not aligned to %u\n", offset, align);
189*19df707eSJunyang Han return NULL;
190*19df707eSJunyang Han }
191*19df707eSJunyang Han
192*19df707eSJunyang Han if (length > size)
193*19df707eSJunyang Han length = size;
194*19df707eSJunyang Han
195*19df707eSJunyang Han if (len)
196*19df707eSJunyang Han *len = length;
197*19df707eSJunyang Han
198*19df707eSJunyang Han if (length + offset < offset ||
199*19df707eSJunyang Han length + offset > pci_resource_len(pdev, bar)) {
200*19df707eSJunyang Han dev_err(zxdh_dev->device,
201*19df707eSJunyang Han "map %u@%u out of range on bar %u length %lu\n",
202*19df707eSJunyang Han length, offset, bar,
203*19df707eSJunyang Han (unsigned long)pci_resource_len(pdev, bar));
204*19df707eSJunyang Han return NULL;
205*19df707eSJunyang Han }
206*19df707eSJunyang Han
207*19df707eSJunyang Han p = pci_iomap_range(pdev, bar, offset, length);
208*19df707eSJunyang Han if (!p) {
209*19df707eSJunyang Han dev_err(zxdh_dev->device, "unable to map custom queue %u@%u on bar %u\n",
210*19df707eSJunyang Han length, offset, bar);
211*19df707eSJunyang Han } else if (pa) {
212*19df707eSJunyang Han *pa = pci_resource_start(pdev, bar) + offset;
213*19df707eSJunyang Han }
214*19df707eSJunyang Han
215*19df707eSJunyang Han return p;
216*19df707eSJunyang Han }
217*19df707eSJunyang Han
zxdh_pf_common_cfg_init(struct zxdh_core_dev * zxdh_dev)218*19df707eSJunyang Han int zxdh_pf_common_cfg_init(struct zxdh_core_dev *zxdh_dev)
219*19df707eSJunyang Han {
220*19df707eSJunyang Han struct zxdh_pf_dev *pf_dev = zxdh_dev->priv;
221*19df707eSJunyang Han struct pci_dev *pdev = zxdh_dev->pdev;
222*19df707eSJunyang Han int common;
223*19df707eSJunyang Han
224*19df707eSJunyang Han /* check for a common config: if not, use legacy mode (bar 0). */
225*19df707eSJunyang Han common = zxdh_pf_pci_find_capability(pdev, ZXDH_PCI_CAP_COMMON_CFG,
226*19df707eSJunyang Han IORESOURCE_MEM,
227*19df707eSJunyang Han &pf_dev->modern_bars);
228*19df707eSJunyang Han if (!common) {
229*19df707eSJunyang Han dev_err(zxdh_dev->device,
230*19df707eSJunyang Han "missing capabilities, leaving for legacy driver\n");
231*19df707eSJunyang Han return -ENODEV;
232*19df707eSJunyang Han }
233*19df707eSJunyang Han
234*19df707eSJunyang Han pf_dev->common = zxdh_pf_map_capability(zxdh_dev, common,
235*19df707eSJunyang Han sizeof(struct zxdh_pf_pci_common_cfg),
236*19df707eSJunyang Han ZXDH_PF_ALIGN4, 0,
237*19df707eSJunyang Han sizeof(struct zxdh_pf_pci_common_cfg),
238*19df707eSJunyang Han NULL, NULL, NULL);
239*19df707eSJunyang Han if (!pf_dev->common) {
240*19df707eSJunyang Han dev_err(zxdh_dev->device, "pf_dev->common is null\n");
241*19df707eSJunyang Han return -EINVAL;
242*19df707eSJunyang Han }
243*19df707eSJunyang Han
244*19df707eSJunyang Han return 0;
245*19df707eSJunyang Han }
246*19df707eSJunyang Han
zxdh_pf_notify_cfg_init(struct zxdh_core_dev * zxdh_dev)247*19df707eSJunyang Han int zxdh_pf_notify_cfg_init(struct zxdh_core_dev *zxdh_dev)
248*19df707eSJunyang Han {
249*19df707eSJunyang Han struct zxdh_pf_dev *pf_dev = zxdh_dev->priv;
250*19df707eSJunyang Han struct pci_dev *pdev = zxdh_dev->pdev;
251*19df707eSJunyang Han u32 notify_length;
252*19df707eSJunyang Han u32 notify_offset;
253*19df707eSJunyang Han int notify;
254*19df707eSJunyang Han
255*19df707eSJunyang Han /* If common is there, these should be too... */
256*19df707eSJunyang Han notify = zxdh_pf_pci_find_capability(pdev, ZXDH_PCI_CAP_NOTIFY_CFG,
257*19df707eSJunyang Han IORESOURCE_MEM,
258*19df707eSJunyang Han &pf_dev->modern_bars);
259*19df707eSJunyang Han if (!notify) {
260*19df707eSJunyang Han dev_err(zxdh_dev->device, "missing notify cfg capability\n");
261*19df707eSJunyang Han return -EINVAL;
262*19df707eSJunyang Han }
263*19df707eSJunyang Han
264*19df707eSJunyang Han pci_read_config_dword(pdev,
265*19df707eSJunyang Han notify + offsetof(struct zxdh_pf_pci_notify_cap,
266*19df707eSJunyang Han notify_off_multiplier),
267*19df707eSJunyang Han &pf_dev->notify_offset_multiplier);
268*19df707eSJunyang Han pci_read_config_dword(pdev,
269*19df707eSJunyang Han notify + offsetof(struct zxdh_pf_pci_notify_cap,
270*19df707eSJunyang Han cap.length), ¬ify_length);
271*19df707eSJunyang Han pci_read_config_dword(pdev,
272*19df707eSJunyang Han notify + offsetof(struct zxdh_pf_pci_notify_cap,
273*19df707eSJunyang Han cap.offset), ¬ify_offset);
274*19df707eSJunyang Han
275*19df707eSJunyang Han /* We don't know how many VQs we'll map, ahead of the time.
276*19df707eSJunyang Han * If notify length is small, map it all now. Otherwise,
277*19df707eSJunyang Han * map each VQ individually later.
278*19df707eSJunyang Han */
279*19df707eSJunyang Han if (notify_length <= PAGE_SIZE - (notify_offset % PAGE_SIZE)) {
280*19df707eSJunyang Han pf_dev->notify_base = zxdh_pf_map_capability(zxdh_dev, notify,
281*19df707eSJunyang Han ZXDH_PF_MAP_MINLEN2,
282*19df707eSJunyang Han ZXDH_PF_ALIGN2, 0,
283*19df707eSJunyang Han notify_length,
284*19df707eSJunyang Han &pf_dev->notify_len,
285*19df707eSJunyang Han &pf_dev->notify_pa, NULL);
286*19df707eSJunyang Han if (!pf_dev->notify_base) {
287*19df707eSJunyang Han dev_err(zxdh_dev->device, "pf_dev->notify_base is null\n");
288*19df707eSJunyang Han return -EINVAL;
289*19df707eSJunyang Han }
290*19df707eSJunyang Han } else {
291*19df707eSJunyang Han pf_dev->notify_map_cap = notify;
292*19df707eSJunyang Han }
293*19df707eSJunyang Han
294*19df707eSJunyang Han return 0;
295*19df707eSJunyang Han }
296*19df707eSJunyang Han
zxdh_pf_device_cfg_init(struct zxdh_core_dev * zxdh_dev)297*19df707eSJunyang Han int zxdh_pf_device_cfg_init(struct zxdh_core_dev *zxdh_dev)
298*19df707eSJunyang Han {
299*19df707eSJunyang Han struct zxdh_pf_dev *pf_dev = zxdh_dev->priv;
300*19df707eSJunyang Han struct pci_dev *pdev = zxdh_dev->pdev;
301*19df707eSJunyang Han int device;
302*19df707eSJunyang Han
303*19df707eSJunyang Han /* Device capability is only mandatory for
304*19df707eSJunyang Han * devices that have device-specific configuration.
305*19df707eSJunyang Han */
306*19df707eSJunyang Han device = zxdh_pf_pci_find_capability(pdev, ZXDH_PCI_CAP_DEVICE_CFG,
307*19df707eSJunyang Han IORESOURCE_MEM,
308*19df707eSJunyang Han &pf_dev->modern_bars);
309*19df707eSJunyang Han
310*19df707eSJunyang Han /* we don't know how much we should map,
311*19df707eSJunyang Han * but PAGE_SIZE is more than enough for all existing devices.
312*19df707eSJunyang Han */
313*19df707eSJunyang Han if (device) {
314*19df707eSJunyang Han pf_dev->device = zxdh_pf_map_capability(zxdh_dev, device, 0,
315*19df707eSJunyang Han ZXDH_PF_ALIGN4, 0, PAGE_SIZE,
316*19df707eSJunyang Han &pf_dev->device_len, NULL,
317*19df707eSJunyang Han &pf_dev->dev_cfg_bar_off);
318*19df707eSJunyang Han if (!pf_dev->device) {
319*19df707eSJunyang Han dev_err(zxdh_dev->device, "pf_dev->device is null\n");
320*19df707eSJunyang Han return -EINVAL;
321*19df707eSJunyang Han }
322*19df707eSJunyang Han }
323*19df707eSJunyang Han return 0;
324*19df707eSJunyang Han }
325*19df707eSJunyang Han
zxdh_pf_modern_cfg_uninit(struct zxdh_core_dev * zxdh_dev)326*19df707eSJunyang Han void zxdh_pf_modern_cfg_uninit(struct zxdh_core_dev *zxdh_dev)
327*19df707eSJunyang Han {
328*19df707eSJunyang Han struct zxdh_pf_dev *pf_dev = zxdh_dev->priv;
329*19df707eSJunyang Han struct pci_dev *pdev = zxdh_dev->pdev;
330*19df707eSJunyang Han
331*19df707eSJunyang Han if (pf_dev->device)
332*19df707eSJunyang Han pci_iounmap(pdev, pf_dev->device);
333*19df707eSJunyang Han if (pf_dev->notify_base)
334*19df707eSJunyang Han pci_iounmap(pdev, pf_dev->notify_base);
335*19df707eSJunyang Han pci_iounmap(pdev, pf_dev->common);
336*19df707eSJunyang Han }
337*19df707eSJunyang Han
zxdh_pf_modern_cfg_init(struct zxdh_core_dev * zxdh_dev)338*19df707eSJunyang Han int zxdh_pf_modern_cfg_init(struct zxdh_core_dev *zxdh_dev)
339*19df707eSJunyang Han {
340*19df707eSJunyang Han struct zxdh_pf_dev *pf_dev = zxdh_dev->priv;
341*19df707eSJunyang Han struct pci_dev *pdev = zxdh_dev->pdev;
342*19df707eSJunyang Han int ret;
343*19df707eSJunyang Han
344*19df707eSJunyang Han ret = zxdh_pf_common_cfg_init(zxdh_dev);
345*19df707eSJunyang Han if (ret) {
346*19df707eSJunyang Han dev_err(zxdh_dev->device, "zxdh_pf_common_cfg_init failed: %d\n", ret);
347*19df707eSJunyang Han return ret;
348*19df707eSJunyang Han }
349*19df707eSJunyang Han
350*19df707eSJunyang Han ret = zxdh_pf_notify_cfg_init(zxdh_dev);
351*19df707eSJunyang Han if (ret) {
352*19df707eSJunyang Han dev_err(zxdh_dev->device, "zxdh_pf_notify_cfg_init failed: %d\n", ret);
353*19df707eSJunyang Han goto err_map_notify;
354*19df707eSJunyang Han }
355*19df707eSJunyang Han
356*19df707eSJunyang Han ret = zxdh_pf_device_cfg_init(zxdh_dev);
357*19df707eSJunyang Han if (ret) {
358*19df707eSJunyang Han dev_err(zxdh_dev->device, "zxdh_pf_device_cfg_init failed: %d\n", ret);
359*19df707eSJunyang Han goto err_map_device;
360*19df707eSJunyang Han }
361*19df707eSJunyang Han
362*19df707eSJunyang Han return 0;
363*19df707eSJunyang Han
364*19df707eSJunyang Han err_map_device:
365*19df707eSJunyang Han if (pf_dev->notify_base)
366*19df707eSJunyang Han pci_iounmap(pdev, pf_dev->notify_base);
367*19df707eSJunyang Han err_map_notify:
368*19df707eSJunyang Han pci_iounmap(pdev, pf_dev->common);
369*19df707eSJunyang Han return ret;
370*19df707eSJunyang Han }
371*19df707eSJunyang Han
zxdh_pf_probe(struct pci_dev * pdev,const struct pci_device_id * id)372b8180f79SJunyang Han static int zxdh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
373b8180f79SJunyang Han {
374b8180f79SJunyang Han struct zxdh_core_dev *zxdh_dev;
375b8180f79SJunyang Han struct zxdh_pf_dev *pf_dev;
376b8180f79SJunyang Han struct devlink *devlink;
377b8180f79SJunyang Han int ret;
378b8180f79SJunyang Han
379b8180f79SJunyang Han devlink = devlink_alloc(&zxdh_pf_devlink_ops, sizeof(struct zxdh_core_dev),
380b8180f79SJunyang Han &pdev->dev);
381b8180f79SJunyang Han if (!devlink)
382b8180f79SJunyang Han return -ENOMEM;
383b8180f79SJunyang Han
384b8180f79SJunyang Han zxdh_dev = devlink_priv(devlink);
385b8180f79SJunyang Han zxdh_dev->device = &pdev->dev;
386b8180f79SJunyang Han zxdh_dev->pdev = pdev;
387b8180f79SJunyang Han zxdh_dev->devlink = devlink;
388b8180f79SJunyang Han
389b8180f79SJunyang Han pf_dev = zxdh_core_alloc_priv(zxdh_dev, sizeof(*pf_dev));
390b8180f79SJunyang Han if (!pf_dev) {
391b8180f79SJunyang Han dev_err(&pdev->dev, "zxdh_pf_dev alloc failed\n");
392b8180f79SJunyang Han ret = -ENOMEM;
393b8180f79SJunyang Han goto err_pf_dev;
394b8180f79SJunyang Han }
395b8180f79SJunyang Han
396b8180f79SJunyang Han ret = zxdh_pf_pci_init(zxdh_dev);
397b8180f79SJunyang Han if (ret) {
398b8180f79SJunyang Han dev_err(&pdev->dev, "zxdh_pf_pci_init failed: %d\n", ret);
399b8180f79SJunyang Han goto err_pci_init;
400b8180f79SJunyang Han }
401b8180f79SJunyang Han
402*19df707eSJunyang Han ret = zxdh_pf_modern_cfg_init(zxdh_dev);
403*19df707eSJunyang Han if (ret) {
404*19df707eSJunyang Han dev_err(&pdev->dev, "zxdh_pf_modern_cfg_init failed: %d\n", ret);
405*19df707eSJunyang Han goto err_cfg_init;
406*19df707eSJunyang Han }
407*19df707eSJunyang Han
408b8180f79SJunyang Han devlink_register(devlink);
409b8180f79SJunyang Han
410b8180f79SJunyang Han return 0;
411b8180f79SJunyang Han
412*19df707eSJunyang Han err_cfg_init:
413*19df707eSJunyang Han zxdh_pf_pci_close(zxdh_dev);
414b8180f79SJunyang Han err_pci_init:
415b8180f79SJunyang Han zxdh_core_free_priv(zxdh_dev);
416b8180f79SJunyang Han err_pf_dev:
417b8180f79SJunyang Han devlink_free(devlink);
418b8180f79SJunyang Han return ret;
419b8180f79SJunyang Han }
420b8180f79SJunyang Han
zxdh_pf_remove(struct pci_dev * pdev)421b8180f79SJunyang Han static void zxdh_pf_remove(struct pci_dev *pdev)
422b8180f79SJunyang Han {
423b8180f79SJunyang Han struct zxdh_core_dev *zxdh_dev = pci_get_drvdata(pdev);
424b8180f79SJunyang Han struct devlink *devlink = priv_to_devlink(zxdh_dev);
425b8180f79SJunyang Han
426b8180f79SJunyang Han devlink_unregister(devlink);
427*19df707eSJunyang Han zxdh_pf_modern_cfg_uninit(zxdh_dev);
428b8180f79SJunyang Han zxdh_pf_pci_close(zxdh_dev);
429b8180f79SJunyang Han zxdh_core_free_priv(zxdh_dev);
430b8180f79SJunyang Han devlink_free(devlink);
431b8180f79SJunyang Han pci_set_drvdata(pdev, NULL);
432b8180f79SJunyang Han }
433b8180f79SJunyang Han
zxdh_pf_shutdown(struct pci_dev * pdev)434b8180f79SJunyang Han static void zxdh_pf_shutdown(struct pci_dev *pdev)
435b8180f79SJunyang Han {
436b8180f79SJunyang Han if (system_state == SYSTEM_POWER_OFF)
437b8180f79SJunyang Han pci_set_power_state(pdev, PCI_D3hot);
438b8180f79SJunyang Han pci_disable_device(pdev);
439b8180f79SJunyang Han }
440b8180f79SJunyang Han
441b8180f79SJunyang Han static struct pci_driver zxdh_pf_driver = {
442b8180f79SJunyang Han .name = "dinghai10e",
443b8180f79SJunyang Han .id_table = zxdh_pf_pci_table,
444b8180f79SJunyang Han .probe = zxdh_pf_probe,
445b8180f79SJunyang Han .remove = zxdh_pf_remove,
446b8180f79SJunyang Han .shutdown = zxdh_pf_shutdown,
447b8180f79SJunyang Han };
448b8180f79SJunyang Han
449b8180f79SJunyang Han module_pci_driver(zxdh_pf_driver);
450