xref: /linux/drivers/net/ethernet/zte/dinghai/en_pf.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
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), &notify_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), &notify_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