xref: /openbmc/linux/arch/s390/pci/pci_clp.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2a755a45dSJan Glauber /*
3a755a45dSJan Glauber  * Copyright IBM Corp. 2012
4a755a45dSJan Glauber  *
5a755a45dSJan Glauber  * Author(s):
6a755a45dSJan Glauber  *   Jan Glauber <jang@linux.vnet.ibm.com>
7a755a45dSJan Glauber  */
8a755a45dSJan Glauber 
9896cb7e6SGerald Schaefer #define KMSG_COMPONENT "zpci"
10896cb7e6SGerald Schaefer #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11a755a45dSJan Glauber 
12988b86e6SMartin Schwidefsky #include <linux/compat.h>
13a755a45dSJan Glauber #include <linux/kernel.h>
14988b86e6SMartin Schwidefsky #include <linux/miscdevice.h>
15a755a45dSJan Glauber #include <linux/slab.h>
16a755a45dSJan Glauber #include <linux/err.h>
17a755a45dSJan Glauber #include <linux/delay.h>
18a755a45dSJan Glauber #include <linux/pci.h>
19988b86e6SMartin Schwidefsky #include <linux/uaccess.h>
20d09a307fSHeiko Carstens #include <asm/asm-extable.h>
21a2ab8333SSebastian Ott #include <asm/pci_debug.h>
22a755a45dSJan Glauber #include <asm/pci_clp.h>
23988b86e6SMartin Schwidefsky #include <asm/clp.h>
24988b86e6SMartin Schwidefsky #include <uapi/asm/clp.h>
25a755a45dSJan Glauber 
26c122383dSNiklas Schnelle #include "pci_bus.h"
27c122383dSNiklas Schnelle 
285c5afd02SSebastian Ott bool zpci_unique_uid;
295c5afd02SSebastian Ott 
update_uid_checking(bool new)307a11c67aSNiklas Schnelle void update_uid_checking(bool new)
315db23179SSebastian Ott {
325db23179SSebastian Ott 	if (zpci_unique_uid != new)
3352c79e63SNiklas Schnelle 		zpci_dbg(3, "uid checking:%d\n", new);
345db23179SSebastian Ott 
355db23179SSebastian Ott 	zpci_unique_uid = new;
365db23179SSebastian Ott }
375db23179SSebastian Ott 
zpci_err_clp(unsigned int rsp,int rc)381f1dcbd4SSebastian Ott static inline void zpci_err_clp(unsigned int rsp, int rc)
391f1dcbd4SSebastian Ott {
401f1dcbd4SSebastian Ott 	struct {
411f1dcbd4SSebastian Ott 		unsigned int rsp;
421f1dcbd4SSebastian Ott 		int rc;
431f1dcbd4SSebastian Ott 	} __packed data = {rsp, rc};
441f1dcbd4SSebastian Ott 
451f1dcbd4SSebastian Ott 	zpci_err_hex(&data, sizeof(data));
461f1dcbd4SSebastian Ott }
471f1dcbd4SSebastian Ott 
48a755a45dSJan Glauber /*
49988b86e6SMartin Schwidefsky  * Call Logical Processor with c=1, lps=0 and command 1
50988b86e6SMartin Schwidefsky  * to get the bit mask of installed logical processors
51a755a45dSJan Glauber  */
clp_get_ilp(unsigned long * ilp)52988b86e6SMartin Schwidefsky static inline int clp_get_ilp(unsigned long *ilp)
53988b86e6SMartin Schwidefsky {
54988b86e6SMartin Schwidefsky 	unsigned long mask;
55988b86e6SMartin Schwidefsky 	int cc = 3;
56988b86e6SMartin Schwidefsky 
57988b86e6SMartin Schwidefsky 	asm volatile (
58988b86e6SMartin Schwidefsky 		"	.insn	rrf,0xb9a00000,%[mask],%[cmd],8,0\n"
59988b86e6SMartin Schwidefsky 		"0:	ipm	%[cc]\n"
60988b86e6SMartin Schwidefsky 		"	srl	%[cc],28\n"
61988b86e6SMartin Schwidefsky 		"1:\n"
62988b86e6SMartin Schwidefsky 		EX_TABLE(0b, 1b)
63988b86e6SMartin Schwidefsky 		: [cc] "+d" (cc), [mask] "=d" (mask) : [cmd] "a" (1)
64988b86e6SMartin Schwidefsky 		: "cc");
65988b86e6SMartin Schwidefsky 	*ilp = mask;
66988b86e6SMartin Schwidefsky 	return cc;
67988b86e6SMartin Schwidefsky }
68988b86e6SMartin Schwidefsky 
69988b86e6SMartin Schwidefsky /*
70988b86e6SMartin Schwidefsky  * Call Logical Processor with c=0, the give constant lps and an lpcb request.
71988b86e6SMartin Schwidefsky  */
clp_req(void * data,unsigned int lps)72771c24f6SHeiko Carstens static __always_inline int clp_req(void *data, unsigned int lps)
73a755a45dSJan Glauber {
74bf4ec24fSSebastian Ott 	struct { u8 _[CLP_BLK_SIZE]; } *req = data;
75bf4ec24fSSebastian Ott 	u64 ignored;
76988b86e6SMartin Schwidefsky 	int cc = 3;
77a755a45dSJan Glauber 
78a755a45dSJan Glauber 	asm volatile (
79988b86e6SMartin Schwidefsky 		"	.insn	rrf,0xb9a00000,%[ign],%[req],0,%[lps]\n"
80988b86e6SMartin Schwidefsky 		"0:	ipm	%[cc]\n"
81a755a45dSJan Glauber 		"	srl	%[cc],28\n"
82988b86e6SMartin Schwidefsky 		"1:\n"
83988b86e6SMartin Schwidefsky 		EX_TABLE(0b, 1b)
84988b86e6SMartin Schwidefsky 		: [cc] "+d" (cc), [ign] "=d" (ignored), "+m" (*req)
85988b86e6SMartin Schwidefsky 		: [req] "a" (req), [lps] "i" (lps)
86bf4ec24fSSebastian Ott 		: "cc");
87a755a45dSJan Glauber 	return cc;
88a755a45dSJan Glauber }
89a755a45dSJan Glauber 
clp_alloc_block(gfp_t gfp_mask)901d578966SSebastian Ott static void *clp_alloc_block(gfp_t gfp_mask)
91a755a45dSJan Glauber {
921d578966SSebastian Ott 	return (void *) __get_free_pages(gfp_mask, get_order(CLP_BLK_SIZE));
93a755a45dSJan Glauber }
94a755a45dSJan Glauber 
clp_free_block(void * ptr)95a755a45dSJan Glauber static void clp_free_block(void *ptr)
96a755a45dSJan Glauber {
97a755a45dSJan Glauber 	free_pages((unsigned long) ptr, get_order(CLP_BLK_SIZE));
98a755a45dSJan Glauber }
99a755a45dSJan Glauber 
clp_store_query_pci_fngrp(struct zpci_dev * zdev,struct clp_rsp_query_pci_grp * response)100a755a45dSJan Glauber static void clp_store_query_pci_fngrp(struct zpci_dev *zdev,
101a755a45dSJan Glauber 				      struct clp_rsp_query_pci_grp *response)
102a755a45dSJan Glauber {
103828b35f6SJan Glauber 	zdev->tlb_refresh = response->refresh;
104828b35f6SJan Glauber 	zdev->dma_mask = response->dasm;
1059a4da8a5SJan Glauber 	zdev->msi_addr = response->msia;
106b19148f6SSebastian Ott 	zdev->max_msi = response->noi;
107d0b08853SJan Glauber 	zdev->fmb_update = response->mui;
108dc8c638dSMatthew Rosato 	zdev->version = response->version;
109d1038467SMatthew Rosato 	zdev->maxstbl = response->maxstbl;
110d1038467SMatthew Rosato 	zdev->dtsm = response->dtsm;
1119a4da8a5SJan Glauber 
112a755a45dSJan Glauber 	switch (response->version) {
113a755a45dSJan Glauber 	case 1:
114a755a45dSJan Glauber 		zdev->max_bus_speed = PCIE_SPEED_5_0GT;
115a755a45dSJan Glauber 		break;
116a755a45dSJan Glauber 	default:
117a755a45dSJan Glauber 		zdev->max_bus_speed = PCI_SPEED_UNKNOWN;
118a755a45dSJan Glauber 		break;
119a755a45dSJan Glauber 	}
120a755a45dSJan Glauber }
121a755a45dSJan Glauber 
clp_query_pci_fngrp(struct zpci_dev * zdev,u8 pfgid)122a755a45dSJan Glauber static int clp_query_pci_fngrp(struct zpci_dev *zdev, u8 pfgid)
123a755a45dSJan Glauber {
124a755a45dSJan Glauber 	struct clp_req_rsp_query_pci_grp *rrb;
125a755a45dSJan Glauber 	int rc;
126a755a45dSJan Glauber 
1271d578966SSebastian Ott 	rrb = clp_alloc_block(GFP_KERNEL);
128a755a45dSJan Glauber 	if (!rrb)
129a755a45dSJan Glauber 		return -ENOMEM;
130a755a45dSJan Glauber 
131a755a45dSJan Glauber 	memset(rrb, 0, sizeof(*rrb));
132a755a45dSJan Glauber 	rrb->request.hdr.len = sizeof(rrb->request);
133a755a45dSJan Glauber 	rrb->request.hdr.cmd = CLP_QUERY_PCI_FNGRP;
134a755a45dSJan Glauber 	rrb->response.hdr.len = sizeof(rrb->response);
135a755a45dSJan Glauber 	rrb->request.pfgid = pfgid;
136a755a45dSJan Glauber 
137988b86e6SMartin Schwidefsky 	rc = clp_req(rrb, CLP_LPS_PCI);
138a755a45dSJan Glauber 	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK)
139a755a45dSJan Glauber 		clp_store_query_pci_fngrp(zdev, &rrb->response);
140a755a45dSJan Glauber 	else {
1411f1dcbd4SSebastian Ott 		zpci_err("Q PCI FGRP:\n");
1421f1dcbd4SSebastian Ott 		zpci_err_clp(rrb->response.hdr.rsp, rc);
143a755a45dSJan Glauber 		rc = -EIO;
144a755a45dSJan Glauber 	}
145a755a45dSJan Glauber 	clp_free_block(rrb);
146a755a45dSJan Glauber 	return rc;
147a755a45dSJan Glauber }
148a755a45dSJan Glauber 
clp_store_query_pci_fn(struct zpci_dev * zdev,struct clp_rsp_query_pci * response)149a755a45dSJan Glauber static int clp_store_query_pci_fn(struct zpci_dev *zdev,
150a755a45dSJan Glauber 				  struct clp_rsp_query_pci *response)
151a755a45dSJan Glauber {
152a755a45dSJan Glauber 	int i;
153a755a45dSJan Glauber 
154c9c13ba4SDenis Efremov 	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
155a755a45dSJan Glauber 		zdev->bars[i].val = le32_to_cpu(response->bar[i]);
156a755a45dSJan Glauber 		zdev->bars[i].size = response->bar_size[i];
157a755a45dSJan Glauber 	}
158828b35f6SJan Glauber 	zdev->start_dma = response->sdma;
159828b35f6SJan Glauber 	zdev->end_dma = response->edma;
160a755a45dSJan Glauber 	zdev->pchid = response->pchid;
161a755a45dSJan Glauber 	zdev->pfgid = response->pfgid;
162ac4995b9SSebastian Ott 	zdev->pft = response->pft;
163ac4995b9SSebastian Ott 	zdev->vfn = response->vfn;
164e6ab7490SAlexander Schmidt 	zdev->port = response->port;
165ac4995b9SSebastian Ott 	zdev->uid = response->uid;
1660b7589ecSSebastian Ott 	zdev->fmb_length = sizeof(u32) * response->fmb_len;
167c9a1752bSPierre Morel 	zdev->rid_available = response->rid_avail;
168e5794cf1SNiklas Schnelle 	zdev->is_physfn = response->is_physfn;
169c9a1752bSPierre Morel 	if (!s390_pci_no_rid && zdev->rid_available)
170c9a1752bSPierre Morel 		zdev->devfn = response->rid & ZPCI_RID_MASK_DEVFN;
171ac4995b9SSebastian Ott 
172ac4995b9SSebastian Ott 	memcpy(zdev->pfip, response->pfip, sizeof(zdev->pfip));
173ac4995b9SSebastian Ott 	if (response->util_str_avail) {
174ac4995b9SSebastian Ott 		memcpy(zdev->util_str, response->util_str,
175ac4995b9SSebastian Ott 		       sizeof(zdev->util_str));
176517fe298SMatthew Rosato 		zdev->util_str_avail = 1;
177ac4995b9SSebastian Ott 	}
17871ba41c9SSebastian Ott 	zdev->mio_capable = response->mio_addr_avail;
179c9c13ba4SDenis Efremov 	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
180c9c13ba4SDenis Efremov 		if (!(response->mio.valid & (1 << (PCI_STD_NUM_BARS - i - 1))))
18171ba41c9SSebastian Ott 			continue;
182ac4995b9SSebastian Ott 
1831354b38bSSebastian Ott 		zdev->bars[i].mio_wb = (void __iomem *) response->mio.addr[i].wb;
1841354b38bSSebastian Ott 		zdev->bars[i].mio_wt = (void __iomem *) response->mio.addr[i].wt;
18571ba41c9SSebastian Ott 	}
186a755a45dSJan Glauber 	return 0;
187a755a45dSJan Glauber }
188a755a45dSJan Glauber 
clp_query_pci_fn(struct zpci_dev * zdev)189ba764dd7SNiklas Schnelle int clp_query_pci_fn(struct zpci_dev *zdev)
190a755a45dSJan Glauber {
191a755a45dSJan Glauber 	struct clp_req_rsp_query_pci *rrb;
192a755a45dSJan Glauber 	int rc;
193a755a45dSJan Glauber 
1941d578966SSebastian Ott 	rrb = clp_alloc_block(GFP_KERNEL);
195a755a45dSJan Glauber 	if (!rrb)
196a755a45dSJan Glauber 		return -ENOMEM;
197a755a45dSJan Glauber 
198a755a45dSJan Glauber 	memset(rrb, 0, sizeof(*rrb));
199a755a45dSJan Glauber 	rrb->request.hdr.len = sizeof(rrb->request);
200a755a45dSJan Glauber 	rrb->request.hdr.cmd = CLP_QUERY_PCI_FN;
201a755a45dSJan Glauber 	rrb->response.hdr.len = sizeof(rrb->response);
202ba764dd7SNiklas Schnelle 	rrb->request.fh = zdev->fh;
203a755a45dSJan Glauber 
204988b86e6SMartin Schwidefsky 	rc = clp_req(rrb, CLP_LPS_PCI);
205a755a45dSJan Glauber 	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) {
206a755a45dSJan Glauber 		rc = clp_store_query_pci_fn(zdev, &rrb->response);
207a755a45dSJan Glauber 		if (rc)
208a755a45dSJan Glauber 			goto out;
209a755a45dSJan Glauber 		rc = clp_query_pci_fngrp(zdev, rrb->response.pfgid);
210a755a45dSJan Glauber 	} else {
2111f1dcbd4SSebastian Ott 		zpci_err("Q PCI FN:\n");
2121f1dcbd4SSebastian Ott 		zpci_err_clp(rrb->response.hdr.rsp, rc);
213a755a45dSJan Glauber 		rc = -EIO;
214a755a45dSJan Glauber 	}
215a755a45dSJan Glauber out:
216a755a45dSJan Glauber 	clp_free_block(rrb);
217a755a45dSJan Glauber 	return rc;
218a755a45dSJan Glauber }
219a755a45dSJan Glauber 
220f7addcddSNiklas Schnelle /**
221f7addcddSNiklas Schnelle  * clp_set_pci_fn() - Execute a command on a PCI function
222f7addcddSNiklas Schnelle  * @zdev: Function that will be affected
223cc049eecSNiklas Schnelle  * @fh: Out parameter for updated function handle
224f7addcddSNiklas Schnelle  * @nr_dma_as: DMA address space number
225f7addcddSNiklas Schnelle  * @command: The command code to execute
226f7addcddSNiklas Schnelle  *
227f7addcddSNiklas Schnelle  * Returns: 0 on success, < 0 for Linux errors (e.g. -ENOMEM), and
228f7addcddSNiklas Schnelle  * > 0 for non-success platform responses
229a755a45dSJan Glauber  */
clp_set_pci_fn(struct zpci_dev * zdev,u32 * fh,u8 nr_dma_as,u8 command)230cc049eecSNiklas Schnelle static int clp_set_pci_fn(struct zpci_dev *zdev, u32 *fh, u8 nr_dma_as, u8 command)
231a755a45dSJan Glauber {
232a755a45dSJan Glauber 	struct clp_req_rsp_set_pci *rrb;
233d03abe58SSebastian Ott 	int rc, retries = 100;
234c68468edSMatthew Rosato 	u32 gisa = 0;
235a755a45dSJan Glauber 
236cc049eecSNiklas Schnelle 	*fh = 0;
2371d578966SSebastian Ott 	rrb = clp_alloc_block(GFP_KERNEL);
238a755a45dSJan Glauber 	if (!rrb)
239a755a45dSJan Glauber 		return -ENOMEM;
240a755a45dSJan Glauber 
241c68468edSMatthew Rosato 	if (command != CLP_SET_DISABLE_PCI_FN)
242c68468edSMatthew Rosato 		gisa = zdev->gisa;
243c68468edSMatthew Rosato 
244a755a45dSJan Glauber 	do {
245a755a45dSJan Glauber 		memset(rrb, 0, sizeof(*rrb));
246a755a45dSJan Glauber 		rrb->request.hdr.len = sizeof(rrb->request);
247a755a45dSJan Glauber 		rrb->request.hdr.cmd = CLP_SET_PCI_FN;
248a755a45dSJan Glauber 		rrb->response.hdr.len = sizeof(rrb->response);
24917cdec96SNiklas Schnelle 		rrb->request.fh = zdev->fh;
250a755a45dSJan Glauber 		rrb->request.oc = command;
251a755a45dSJan Glauber 		rrb->request.ndas = nr_dma_as;
252c68468edSMatthew Rosato 		rrb->request.gisa = gisa;
253a755a45dSJan Glauber 
254988b86e6SMartin Schwidefsky 		rc = clp_req(rrb, CLP_LPS_PCI);
255a755a45dSJan Glauber 		if (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY) {
256a755a45dSJan Glauber 			retries--;
257a755a45dSJan Glauber 			if (retries < 0)
258a755a45dSJan Glauber 				break;
259d03abe58SSebastian Ott 			msleep(20);
260a755a45dSJan Glauber 		}
261a755a45dSJan Glauber 	} while (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY);
262a755a45dSJan Glauber 
26317cdec96SNiklas Schnelle 	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) {
264cc049eecSNiklas Schnelle 		*fh = rrb->response.fh;
265f7addcddSNiklas Schnelle 	} else {
266f7addcddSNiklas Schnelle 		zpci_err("Set PCI FN:\n");
267f7addcddSNiklas Schnelle 		zpci_err_clp(rrb->response.hdr.rsp, rc);
268f7addcddSNiklas Schnelle 		if (!rc)
269f7addcddSNiklas Schnelle 			rc = rrb->response.hdr.rsp;
270a755a45dSJan Glauber 	}
271a755a45dSJan Glauber 	clp_free_block(rrb);
272a755a45dSJan Glauber 	return rc;
273a755a45dSJan Glauber }
274a755a45dSJan Glauber 
clp_setup_writeback_mio(void)275b02002ccSNiklas Schnelle int clp_setup_writeback_mio(void)
276b02002ccSNiklas Schnelle {
277b02002ccSNiklas Schnelle 	struct clp_req_rsp_slpc_pci *rrb;
278b02002ccSNiklas Schnelle 	u8  wb_bit_pos;
279b02002ccSNiklas Schnelle 	int rc;
280b02002ccSNiklas Schnelle 
281b02002ccSNiklas Schnelle 	rrb = clp_alloc_block(GFP_KERNEL);
282b02002ccSNiklas Schnelle 	if (!rrb)
283b02002ccSNiklas Schnelle 		return -ENOMEM;
284b02002ccSNiklas Schnelle 
285b02002ccSNiklas Schnelle 	memset(rrb, 0, sizeof(*rrb));
286b02002ccSNiklas Schnelle 	rrb->request.hdr.len = sizeof(rrb->request);
287b02002ccSNiklas Schnelle 	rrb->request.hdr.cmd = CLP_SLPC;
288b02002ccSNiklas Schnelle 	rrb->response.hdr.len = sizeof(rrb->response);
289b02002ccSNiklas Schnelle 
290b02002ccSNiklas Schnelle 	rc = clp_req(rrb, CLP_LPS_PCI);
291b02002ccSNiklas Schnelle 	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) {
292b02002ccSNiklas Schnelle 		if (rrb->response.vwb) {
293b02002ccSNiklas Schnelle 			wb_bit_pos = rrb->response.mio_wb;
294b02002ccSNiklas Schnelle 			set_bit_inv(wb_bit_pos, &mio_wb_bit_mask);
295b02002ccSNiklas Schnelle 			zpci_dbg(3, "wb bit: %d\n", wb_bit_pos);
296b02002ccSNiklas Schnelle 		} else {
297b02002ccSNiklas Schnelle 			zpci_dbg(3, "wb bit: n.a.\n");
298b02002ccSNiklas Schnelle 		}
299b02002ccSNiklas Schnelle 
300b02002ccSNiklas Schnelle 	} else {
301b02002ccSNiklas Schnelle 		zpci_err("SLPC PCI:\n");
302b02002ccSNiklas Schnelle 		zpci_err_clp(rrb->response.hdr.rsp, rc);
303b02002ccSNiklas Schnelle 		rc = -EIO;
304b02002ccSNiklas Schnelle 	}
305b02002ccSNiklas Schnelle 	clp_free_block(rrb);
306b02002ccSNiklas Schnelle 	return rc;
307b02002ccSNiklas Schnelle }
308b02002ccSNiklas Schnelle 
clp_enable_fh(struct zpci_dev * zdev,u32 * fh,u8 nr_dma_as)309cc049eecSNiklas Schnelle int clp_enable_fh(struct zpci_dev *zdev, u32 *fh, u8 nr_dma_as)
310a755a45dSJan Glauber {
311a755a45dSJan Glauber 	int rc;
312a755a45dSJan Glauber 
313cc049eecSNiklas Schnelle 	rc = clp_set_pci_fn(zdev, fh, nr_dma_as, CLP_SET_ENABLE_PCI_FN);
314cc049eecSNiklas Schnelle 	zpci_dbg(3, "ena fid:%x, fh:%x, rc:%d\n", zdev->fid, *fh, rc);
315f7addcddSNiklas Schnelle 	if (!rc && zpci_use_mio(zdev)) {
316cc049eecSNiklas Schnelle 		rc = clp_set_pci_fn(zdev, fh, nr_dma_as, CLP_SET_ENABLE_MIO);
31717cdec96SNiklas Schnelle 		zpci_dbg(3, "ena mio fid:%x, fh:%x, rc:%d\n",
318cc049eecSNiklas Schnelle 				zdev->fid, *fh, rc);
31971ba41c9SSebastian Ott 		if (rc)
320cc049eecSNiklas Schnelle 			clp_disable_fh(zdev, fh);
32171ba41c9SSebastian Ott 	}
322a755a45dSJan Glauber 	return rc;
323a755a45dSJan Glauber }
324a755a45dSJan Glauber 
clp_disable_fh(struct zpci_dev * zdev,u32 * fh)325cc049eecSNiklas Schnelle int clp_disable_fh(struct zpci_dev *zdev, u32 *fh)
326a755a45dSJan Glauber {
327a755a45dSJan Glauber 	int rc;
328a755a45dSJan Glauber 
329a755a45dSJan Glauber 	if (!zdev_enabled(zdev))
330a755a45dSJan Glauber 		return 0;
331a755a45dSJan Glauber 
332cc049eecSNiklas Schnelle 	rc = clp_set_pci_fn(zdev, fh, 0, CLP_SET_DISABLE_PCI_FN);
333cc049eecSNiklas Schnelle 	zpci_dbg(3, "dis fid:%x, fh:%x, rc:%d\n", zdev->fid, *fh, rc);
334cc049eecSNiklas Schnelle 	return rc;
335cc049eecSNiklas Schnelle }
336cc049eecSNiklas Schnelle 
clp_list_pci_req(struct clp_req_rsp_list_pci * rrb,u64 * resume_token,int * nentries)337cc049eecSNiklas Schnelle static int clp_list_pci_req(struct clp_req_rsp_list_pci *rrb,
338cc049eecSNiklas Schnelle 			    u64 *resume_token, int *nentries)
339cc049eecSNiklas Schnelle {
340cc049eecSNiklas Schnelle 	int rc;
341cc049eecSNiklas Schnelle 
342cc049eecSNiklas Schnelle 	memset(rrb, 0, sizeof(*rrb));
343cc049eecSNiklas Schnelle 	rrb->request.hdr.len = sizeof(rrb->request);
344cc049eecSNiklas Schnelle 	rrb->request.hdr.cmd = CLP_LIST_PCI;
345cc049eecSNiklas Schnelle 	/* store as many entries as possible */
346cc049eecSNiklas Schnelle 	rrb->response.hdr.len = CLP_BLK_SIZE - LIST_PCI_HDR_LEN;
347cc049eecSNiklas Schnelle 	rrb->request.resume_token = *resume_token;
348cc049eecSNiklas Schnelle 
349cc049eecSNiklas Schnelle 	/* Get PCI function handle list */
350cc049eecSNiklas Schnelle 	rc = clp_req(rrb, CLP_LPS_PCI);
351cc049eecSNiklas Schnelle 	if (rc || rrb->response.hdr.rsp != CLP_RC_OK) {
352cc049eecSNiklas Schnelle 		zpci_err("List PCI FN:\n");
353cc049eecSNiklas Schnelle 		zpci_err_clp(rrb->response.hdr.rsp, rc);
354cc049eecSNiklas Schnelle 		return -EIO;
355cc049eecSNiklas Schnelle 	}
356cc049eecSNiklas Schnelle 
357cc049eecSNiklas Schnelle 	update_uid_checking(rrb->response.uid_checking);
358cc049eecSNiklas Schnelle 	WARN_ON_ONCE(rrb->response.entry_size !=
359cc049eecSNiklas Schnelle 		sizeof(struct clp_fh_list_entry));
360cc049eecSNiklas Schnelle 
361cc049eecSNiklas Schnelle 	*nentries = (rrb->response.hdr.len - LIST_PCI_HDR_LEN) /
362cc049eecSNiklas Schnelle 		rrb->response.entry_size;
363cc049eecSNiklas Schnelle 	*resume_token = rrb->response.resume_token;
364cc049eecSNiklas Schnelle 
365a755a45dSJan Glauber 	return rc;
366a755a45dSJan Glauber }
367a755a45dSJan Glauber 
clp_list_pci(struct clp_req_rsp_list_pci * rrb,void * data,void (* cb)(struct clp_fh_list_entry *,void *))368783684f1SSebastian Ott static int clp_list_pci(struct clp_req_rsp_list_pci *rrb, void *data,
369783684f1SSebastian Ott 			void (*cb)(struct clp_fh_list_entry *, void *))
370a755a45dSJan Glauber {
371a755a45dSJan Glauber 	u64 resume_token = 0;
372cc049eecSNiklas Schnelle 	int nentries, i, rc;
373a755a45dSJan Glauber 
374a755a45dSJan Glauber 	do {
375cc049eecSNiklas Schnelle 		rc = clp_list_pci_req(rrb, &resume_token, &nentries);
376cc049eecSNiklas Schnelle 		if (rc)
377cc049eecSNiklas Schnelle 			return rc;
378cc049eecSNiklas Schnelle 		for (i = 0; i < nentries; i++)
379783684f1SSebastian Ott 			cb(&rrb->response.fh_list[i], data);
380a755a45dSJan Glauber 	} while (resume_token);
381cc049eecSNiklas Schnelle 
3821d578966SSebastian Ott 	return rc;
3831d578966SSebastian Ott }
3841d578966SSebastian Ott 
clp_find_pci(struct clp_req_rsp_list_pci * rrb,u32 fid,struct clp_fh_list_entry * entry)385cc049eecSNiklas Schnelle static int clp_find_pci(struct clp_req_rsp_list_pci *rrb, u32 fid,
386cc049eecSNiklas Schnelle 			struct clp_fh_list_entry *entry)
387cc049eecSNiklas Schnelle {
388cc049eecSNiklas Schnelle 	struct clp_fh_list_entry *fh_list;
389cc049eecSNiklas Schnelle 	u64 resume_token = 0;
390cc049eecSNiklas Schnelle 	int nentries, i, rc;
391cc049eecSNiklas Schnelle 
392cc049eecSNiklas Schnelle 	do {
393cc049eecSNiklas Schnelle 		rc = clp_list_pci_req(rrb, &resume_token, &nentries);
394cc049eecSNiklas Schnelle 		if (rc)
395cc049eecSNiklas Schnelle 			return rc;
396cc049eecSNiklas Schnelle 		fh_list = rrb->response.fh_list;
39785ad2721SPierre Morel 		for (i = 0; i < nentries; i++) {
398cc049eecSNiklas Schnelle 			if (fh_list[i].fid == fid) {
399cc049eecSNiklas Schnelle 				*entry = fh_list[i];
400cc049eecSNiklas Schnelle 				return 0;
401cc049eecSNiklas Schnelle 			}
402cc049eecSNiklas Schnelle 		}
403cc049eecSNiklas Schnelle 	} while (resume_token);
404cc049eecSNiklas Schnelle 
405cc049eecSNiklas Schnelle 	return -ENODEV;
406cc049eecSNiklas Schnelle }
407cc049eecSNiklas Schnelle 
__clp_add(struct clp_fh_list_entry * entry,void * data)408783684f1SSebastian Ott static void __clp_add(struct clp_fh_list_entry *entry, void *data)
4091d578966SSebastian Ott {
4101d578966SSebastian Ott 	struct zpci_dev *zdev;
4111d578966SSebastian Ott 
4121d578966SSebastian Ott 	if (!entry->vendor_id)
4131d578966SSebastian Ott 		return;
4141d578966SSebastian Ott 
4151d578966SSebastian Ott 	zdev = get_zdev_by_fid(entry->fid);
416c122383dSNiklas Schnelle 	if (zdev) {
417c122383dSNiklas Schnelle 		zpci_zdev_put(zdev);
418c122383dSNiklas Schnelle 		return;
419c122383dSNiklas Schnelle 	}
420ba764dd7SNiklas Schnelle 	zpci_create_device(entry->fid, entry->fh, entry->config_state);
4211d578966SSebastian Ott }
4221d578966SSebastian Ott 
clp_scan_pci_devices(void)4231d578966SSebastian Ott int clp_scan_pci_devices(void)
4241d578966SSebastian Ott {
4251d578966SSebastian Ott 	struct clp_req_rsp_list_pci *rrb;
4261d578966SSebastian Ott 	int rc;
4271d578966SSebastian Ott 
4281d578966SSebastian Ott 	rrb = clp_alloc_block(GFP_KERNEL);
4291d578966SSebastian Ott 	if (!rrb)
4301d578966SSebastian Ott 		return -ENOMEM;
4311d578966SSebastian Ott 
432783684f1SSebastian Ott 	rc = clp_list_pci(rrb, NULL, __clp_add);
4331d578966SSebastian Ott 
4341d578966SSebastian Ott 	clp_free_block(rrb);
4351d578966SSebastian Ott 	return rc;
4361d578966SSebastian Ott }
4371d578966SSebastian Ott 
438c3b2c906SNiklas Schnelle /*
439cc049eecSNiklas Schnelle  * Get the current function handle of the function matching @fid
44017cdec96SNiklas Schnelle  */
clp_refresh_fh(u32 fid,u32 * fh)441cc049eecSNiklas Schnelle int clp_refresh_fh(u32 fid, u32 *fh)
44257b5918cSSebastian Ott {
44357b5918cSSebastian Ott 	struct clp_req_rsp_list_pci *rrb;
444cc049eecSNiklas Schnelle 	struct clp_fh_list_entry entry;
44557b5918cSSebastian Ott 	int rc;
44657b5918cSSebastian Ott 
44757b5918cSSebastian Ott 	rrb = clp_alloc_block(GFP_NOWAIT);
44857b5918cSSebastian Ott 	if (!rrb)
44957b5918cSSebastian Ott 		return -ENOMEM;
45057b5918cSSebastian Ott 
451cc049eecSNiklas Schnelle 	rc = clp_find_pci(rrb, fid, &entry);
452cc049eecSNiklas Schnelle 	if (!rc)
453cc049eecSNiklas Schnelle 		*fh = entry.fh;
454783684f1SSebastian Ott 
455783684f1SSebastian Ott 	clp_free_block(rrb);
456783684f1SSebastian Ott 	return rc;
457783684f1SSebastian Ott }
458783684f1SSebastian Ott 
clp_get_state(u32 fid,enum zpci_state * state)459783684f1SSebastian Ott int clp_get_state(u32 fid, enum zpci_state *state)
460783684f1SSebastian Ott {
461783684f1SSebastian Ott 	struct clp_req_rsp_list_pci *rrb;
462cc049eecSNiklas Schnelle 	struct clp_fh_list_entry entry;
463783684f1SSebastian Ott 	int rc;
464783684f1SSebastian Ott 
46598dfd326SSebastian Ott 	rrb = clp_alloc_block(GFP_ATOMIC);
466783684f1SSebastian Ott 	if (!rrb)
467783684f1SSebastian Ott 		return -ENOMEM;
468783684f1SSebastian Ott 
469cc049eecSNiklas Schnelle 	rc = clp_find_pci(rrb, fid, &entry);
470ebd9cc65SNiklas Schnelle 	if (!rc) {
471cc049eecSNiklas Schnelle 		*state = entry.config_state;
472ebd9cc65SNiklas Schnelle 	} else if (rc == -ENODEV) {
473ebd9cc65SNiklas Schnelle 		*state = ZPCI_FN_STATE_RESERVED;
474ebd9cc65SNiklas Schnelle 		rc = 0;
475ebd9cc65SNiklas Schnelle 	}
47657b5918cSSebastian Ott 
47757b5918cSSebastian Ott 	clp_free_block(rrb);
47857b5918cSSebastian Ott 	return rc;
47957b5918cSSebastian Ott }
480988b86e6SMartin Schwidefsky 
clp_base_slpc(struct clp_req * req,struct clp_req_rsp_slpc * lpcb)481988b86e6SMartin Schwidefsky static int clp_base_slpc(struct clp_req *req, struct clp_req_rsp_slpc *lpcb)
482988b86e6SMartin Schwidefsky {
483988b86e6SMartin Schwidefsky 	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
484988b86e6SMartin Schwidefsky 
485988b86e6SMartin Schwidefsky 	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
486988b86e6SMartin Schwidefsky 	    lpcb->response.hdr.len > limit)
487988b86e6SMartin Schwidefsky 		return -EINVAL;
488988b86e6SMartin Schwidefsky 	return clp_req(lpcb, CLP_LPS_BASE) ? -EOPNOTSUPP : 0;
489988b86e6SMartin Schwidefsky }
490988b86e6SMartin Schwidefsky 
clp_base_command(struct clp_req * req,struct clp_req_hdr * lpcb)491988b86e6SMartin Schwidefsky static int clp_base_command(struct clp_req *req, struct clp_req_hdr *lpcb)
492988b86e6SMartin Schwidefsky {
493988b86e6SMartin Schwidefsky 	switch (lpcb->cmd) {
494988b86e6SMartin Schwidefsky 	case 0x0001: /* store logical-processor characteristics */
495988b86e6SMartin Schwidefsky 		return clp_base_slpc(req, (void *) lpcb);
496988b86e6SMartin Schwidefsky 	default:
497988b86e6SMartin Schwidefsky 		return -EINVAL;
498988b86e6SMartin Schwidefsky 	}
499988b86e6SMartin Schwidefsky }
500988b86e6SMartin Schwidefsky 
clp_pci_slpc(struct clp_req * req,struct clp_req_rsp_slpc_pci * lpcb)501b02002ccSNiklas Schnelle static int clp_pci_slpc(struct clp_req *req, struct clp_req_rsp_slpc_pci *lpcb)
502988b86e6SMartin Schwidefsky {
503988b86e6SMartin Schwidefsky 	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
504988b86e6SMartin Schwidefsky 
505988b86e6SMartin Schwidefsky 	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
506988b86e6SMartin Schwidefsky 	    lpcb->response.hdr.len > limit)
507988b86e6SMartin Schwidefsky 		return -EINVAL;
508988b86e6SMartin Schwidefsky 	return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
509988b86e6SMartin Schwidefsky }
510988b86e6SMartin Schwidefsky 
clp_pci_list(struct clp_req * req,struct clp_req_rsp_list_pci * lpcb)511988b86e6SMartin Schwidefsky static int clp_pci_list(struct clp_req *req, struct clp_req_rsp_list_pci *lpcb)
512988b86e6SMartin Schwidefsky {
513988b86e6SMartin Schwidefsky 	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
514988b86e6SMartin Schwidefsky 
515988b86e6SMartin Schwidefsky 	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
516988b86e6SMartin Schwidefsky 	    lpcb->response.hdr.len > limit)
517988b86e6SMartin Schwidefsky 		return -EINVAL;
518988b86e6SMartin Schwidefsky 	if (lpcb->request.reserved2 != 0)
519988b86e6SMartin Schwidefsky 		return -EINVAL;
520988b86e6SMartin Schwidefsky 	return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
521988b86e6SMartin Schwidefsky }
522988b86e6SMartin Schwidefsky 
clp_pci_query(struct clp_req * req,struct clp_req_rsp_query_pci * lpcb)523988b86e6SMartin Schwidefsky static int clp_pci_query(struct clp_req *req,
524988b86e6SMartin Schwidefsky 			 struct clp_req_rsp_query_pci *lpcb)
525988b86e6SMartin Schwidefsky {
526988b86e6SMartin Schwidefsky 	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
527988b86e6SMartin Schwidefsky 
528988b86e6SMartin Schwidefsky 	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
529988b86e6SMartin Schwidefsky 	    lpcb->response.hdr.len > limit)
530988b86e6SMartin Schwidefsky 		return -EINVAL;
531988b86e6SMartin Schwidefsky 	if (lpcb->request.reserved2 != 0 || lpcb->request.reserved3 != 0)
532988b86e6SMartin Schwidefsky 		return -EINVAL;
533988b86e6SMartin Schwidefsky 	return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
534988b86e6SMartin Schwidefsky }
535988b86e6SMartin Schwidefsky 
clp_pci_query_grp(struct clp_req * req,struct clp_req_rsp_query_pci_grp * lpcb)536988b86e6SMartin Schwidefsky static int clp_pci_query_grp(struct clp_req *req,
537988b86e6SMartin Schwidefsky 			     struct clp_req_rsp_query_pci_grp *lpcb)
538988b86e6SMartin Schwidefsky {
539988b86e6SMartin Schwidefsky 	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
540988b86e6SMartin Schwidefsky 
541988b86e6SMartin Schwidefsky 	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
542988b86e6SMartin Schwidefsky 	    lpcb->response.hdr.len > limit)
543988b86e6SMartin Schwidefsky 		return -EINVAL;
544988b86e6SMartin Schwidefsky 	if (lpcb->request.reserved2 != 0 || lpcb->request.reserved3 != 0 ||
545988b86e6SMartin Schwidefsky 	    lpcb->request.reserved4 != 0)
546988b86e6SMartin Schwidefsky 		return -EINVAL;
547988b86e6SMartin Schwidefsky 	return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
548988b86e6SMartin Schwidefsky }
549988b86e6SMartin Schwidefsky 
clp_pci_command(struct clp_req * req,struct clp_req_hdr * lpcb)550988b86e6SMartin Schwidefsky static int clp_pci_command(struct clp_req *req, struct clp_req_hdr *lpcb)
551988b86e6SMartin Schwidefsky {
552988b86e6SMartin Schwidefsky 	switch (lpcb->cmd) {
553988b86e6SMartin Schwidefsky 	case 0x0001: /* store logical-processor characteristics */
554988b86e6SMartin Schwidefsky 		return clp_pci_slpc(req, (void *) lpcb);
555988b86e6SMartin Schwidefsky 	case 0x0002: /* list PCI functions */
556988b86e6SMartin Schwidefsky 		return clp_pci_list(req, (void *) lpcb);
557988b86e6SMartin Schwidefsky 	case 0x0003: /* query PCI function */
558988b86e6SMartin Schwidefsky 		return clp_pci_query(req, (void *) lpcb);
559988b86e6SMartin Schwidefsky 	case 0x0004: /* query PCI function group */
560988b86e6SMartin Schwidefsky 		return clp_pci_query_grp(req, (void *) lpcb);
561988b86e6SMartin Schwidefsky 	default:
562988b86e6SMartin Schwidefsky 		return -EINVAL;
563988b86e6SMartin Schwidefsky 	}
564988b86e6SMartin Schwidefsky }
565988b86e6SMartin Schwidefsky 
clp_normal_command(struct clp_req * req)566988b86e6SMartin Schwidefsky static int clp_normal_command(struct clp_req *req)
567988b86e6SMartin Schwidefsky {
568988b86e6SMartin Schwidefsky 	struct clp_req_hdr *lpcb;
569988b86e6SMartin Schwidefsky 	void __user *uptr;
570988b86e6SMartin Schwidefsky 	int rc;
571988b86e6SMartin Schwidefsky 
572988b86e6SMartin Schwidefsky 	rc = -EINVAL;
573988b86e6SMartin Schwidefsky 	if (req->lps != 0 && req->lps != 2)
574988b86e6SMartin Schwidefsky 		goto out;
575988b86e6SMartin Schwidefsky 
576988b86e6SMartin Schwidefsky 	rc = -ENOMEM;
577988b86e6SMartin Schwidefsky 	lpcb = clp_alloc_block(GFP_KERNEL);
578988b86e6SMartin Schwidefsky 	if (!lpcb)
579988b86e6SMartin Schwidefsky 		goto out;
580988b86e6SMartin Schwidefsky 
581988b86e6SMartin Schwidefsky 	rc = -EFAULT;
582988b86e6SMartin Schwidefsky 	uptr = (void __force __user *)(unsigned long) req->data_p;
583988b86e6SMartin Schwidefsky 	if (copy_from_user(lpcb, uptr, PAGE_SIZE) != 0)
584988b86e6SMartin Schwidefsky 		goto out_free;
585988b86e6SMartin Schwidefsky 
586988b86e6SMartin Schwidefsky 	rc = -EINVAL;
587988b86e6SMartin Schwidefsky 	if (lpcb->fmt != 0 || lpcb->reserved1 != 0 || lpcb->reserved2 != 0)
588988b86e6SMartin Schwidefsky 		goto out_free;
589988b86e6SMartin Schwidefsky 
590988b86e6SMartin Schwidefsky 	switch (req->lps) {
591988b86e6SMartin Schwidefsky 	case 0:
592988b86e6SMartin Schwidefsky 		rc = clp_base_command(req, lpcb);
593988b86e6SMartin Schwidefsky 		break;
594988b86e6SMartin Schwidefsky 	case 2:
595988b86e6SMartin Schwidefsky 		rc = clp_pci_command(req, lpcb);
596988b86e6SMartin Schwidefsky 		break;
597988b86e6SMartin Schwidefsky 	}
598988b86e6SMartin Schwidefsky 	if (rc)
599988b86e6SMartin Schwidefsky 		goto out_free;
600988b86e6SMartin Schwidefsky 
601988b86e6SMartin Schwidefsky 	rc = -EFAULT;
602988b86e6SMartin Schwidefsky 	if (copy_to_user(uptr, lpcb, PAGE_SIZE) != 0)
603988b86e6SMartin Schwidefsky 		goto out_free;
604988b86e6SMartin Schwidefsky 
605988b86e6SMartin Schwidefsky 	rc = 0;
606988b86e6SMartin Schwidefsky 
607988b86e6SMartin Schwidefsky out_free:
608988b86e6SMartin Schwidefsky 	clp_free_block(lpcb);
609988b86e6SMartin Schwidefsky out:
610988b86e6SMartin Schwidefsky 	return rc;
611988b86e6SMartin Schwidefsky }
612988b86e6SMartin Schwidefsky 
clp_immediate_command(struct clp_req * req)613988b86e6SMartin Schwidefsky static int clp_immediate_command(struct clp_req *req)
614988b86e6SMartin Schwidefsky {
615988b86e6SMartin Schwidefsky 	void __user *uptr;
616988b86e6SMartin Schwidefsky 	unsigned long ilp;
617988b86e6SMartin Schwidefsky 	int exists;
618988b86e6SMartin Schwidefsky 
619988b86e6SMartin Schwidefsky 	if (req->cmd > 1 || clp_get_ilp(&ilp) != 0)
620988b86e6SMartin Schwidefsky 		return -EINVAL;
621988b86e6SMartin Schwidefsky 
622988b86e6SMartin Schwidefsky 	uptr = (void __force __user *)(unsigned long) req->data_p;
623988b86e6SMartin Schwidefsky 	if (req->cmd == 0) {
624988b86e6SMartin Schwidefsky 		/* Command code 0: test for a specific processor */
625988b86e6SMartin Schwidefsky 		exists = test_bit_inv(req->lps, &ilp);
626988b86e6SMartin Schwidefsky 		return put_user(exists, (int __user *) uptr);
627988b86e6SMartin Schwidefsky 	}
628988b86e6SMartin Schwidefsky 	/* Command code 1: return bit mask of installed processors */
629988b86e6SMartin Schwidefsky 	return put_user(ilp, (unsigned long __user *) uptr);
630988b86e6SMartin Schwidefsky }
631988b86e6SMartin Schwidefsky 
clp_misc_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)632988b86e6SMartin Schwidefsky static long clp_misc_ioctl(struct file *filp, unsigned int cmd,
633988b86e6SMartin Schwidefsky 			   unsigned long arg)
634988b86e6SMartin Schwidefsky {
635988b86e6SMartin Schwidefsky 	struct clp_req req;
636988b86e6SMartin Schwidefsky 	void __user *argp;
637988b86e6SMartin Schwidefsky 
638988b86e6SMartin Schwidefsky 	if (cmd != CLP_SYNC)
639988b86e6SMartin Schwidefsky 		return -EINVAL;
640988b86e6SMartin Schwidefsky 
641988b86e6SMartin Schwidefsky 	argp = is_compat_task() ? compat_ptr(arg) : (void __user *) arg;
642988b86e6SMartin Schwidefsky 	if (copy_from_user(&req, argp, sizeof(req)))
643988b86e6SMartin Schwidefsky 		return -EFAULT;
644988b86e6SMartin Schwidefsky 	if (req.r != 0)
645988b86e6SMartin Schwidefsky 		return -EINVAL;
646988b86e6SMartin Schwidefsky 	return req.c ? clp_immediate_command(&req) : clp_normal_command(&req);
647988b86e6SMartin Schwidefsky }
648988b86e6SMartin Schwidefsky 
clp_misc_release(struct inode * inode,struct file * filp)649988b86e6SMartin Schwidefsky static int clp_misc_release(struct inode *inode, struct file *filp)
650988b86e6SMartin Schwidefsky {
651988b86e6SMartin Schwidefsky 	return 0;
652988b86e6SMartin Schwidefsky }
653988b86e6SMartin Schwidefsky 
654988b86e6SMartin Schwidefsky static const struct file_operations clp_misc_fops = {
655988b86e6SMartin Schwidefsky 	.owner = THIS_MODULE,
656988b86e6SMartin Schwidefsky 	.open = nonseekable_open,
657988b86e6SMartin Schwidefsky 	.release = clp_misc_release,
658988b86e6SMartin Schwidefsky 	.unlocked_ioctl = clp_misc_ioctl,
659988b86e6SMartin Schwidefsky 	.compat_ioctl = clp_misc_ioctl,
660988b86e6SMartin Schwidefsky 	.llseek = no_llseek,
661988b86e6SMartin Schwidefsky };
662988b86e6SMartin Schwidefsky 
663988b86e6SMartin Schwidefsky static struct miscdevice clp_misc_device = {
664988b86e6SMartin Schwidefsky 	.minor = MISC_DYNAMIC_MINOR,
665988b86e6SMartin Schwidefsky 	.name = "clp",
666988b86e6SMartin Schwidefsky 	.fops = &clp_misc_fops,
667988b86e6SMartin Schwidefsky };
668988b86e6SMartin Schwidefsky 
669*dedf98ddSLi Zetao builtin_misc_device(clp_misc_device);
670