18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2012
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author(s):
68c2ecf20Sopenharmony_ci *   Jan Glauber <jang@linux.vnet.ibm.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "zpci"
108c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/compat.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/miscdevice.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <linux/err.h>
178c2ecf20Sopenharmony_ci#include <linux/delay.h>
188c2ecf20Sopenharmony_ci#include <linux/pci.h>
198c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
208c2ecf20Sopenharmony_ci#include <asm/pci_debug.h>
218c2ecf20Sopenharmony_ci#include <asm/pci_clp.h>
228c2ecf20Sopenharmony_ci#include <asm/clp.h>
238c2ecf20Sopenharmony_ci#include <uapi/asm/clp.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include "pci_bus.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cibool zpci_unique_uid;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_civoid update_uid_checking(bool new)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	if (zpci_unique_uid != new)
328c2ecf20Sopenharmony_ci		zpci_dbg(1, "uid checking:%d\n", new);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	zpci_unique_uid = new;
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic inline void zpci_err_clp(unsigned int rsp, int rc)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	struct {
408c2ecf20Sopenharmony_ci		unsigned int rsp;
418c2ecf20Sopenharmony_ci		int rc;
428c2ecf20Sopenharmony_ci	} __packed data = {rsp, rc};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	zpci_err_hex(&data, sizeof(data));
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/*
488c2ecf20Sopenharmony_ci * Call Logical Processor with c=1, lps=0 and command 1
498c2ecf20Sopenharmony_ci * to get the bit mask of installed logical processors
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_cistatic inline int clp_get_ilp(unsigned long *ilp)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	unsigned long mask;
548c2ecf20Sopenharmony_ci	int cc = 3;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	asm volatile (
578c2ecf20Sopenharmony_ci		"	.insn	rrf,0xb9a00000,%[mask],%[cmd],8,0\n"
588c2ecf20Sopenharmony_ci		"0:	ipm	%[cc]\n"
598c2ecf20Sopenharmony_ci		"	srl	%[cc],28\n"
608c2ecf20Sopenharmony_ci		"1:\n"
618c2ecf20Sopenharmony_ci		EX_TABLE(0b, 1b)
628c2ecf20Sopenharmony_ci		: [cc] "+d" (cc), [mask] "=d" (mask) : [cmd] "a" (1)
638c2ecf20Sopenharmony_ci		: "cc");
648c2ecf20Sopenharmony_ci	*ilp = mask;
658c2ecf20Sopenharmony_ci	return cc;
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/*
698c2ecf20Sopenharmony_ci * Call Logical Processor with c=0, the give constant lps and an lpcb request.
708c2ecf20Sopenharmony_ci */
718c2ecf20Sopenharmony_cistatic __always_inline int clp_req(void *data, unsigned int lps)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	struct { u8 _[CLP_BLK_SIZE]; } *req = data;
748c2ecf20Sopenharmony_ci	u64 ignored;
758c2ecf20Sopenharmony_ci	int cc = 3;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	asm volatile (
788c2ecf20Sopenharmony_ci		"	.insn	rrf,0xb9a00000,%[ign],%[req],0,%[lps]\n"
798c2ecf20Sopenharmony_ci		"0:	ipm	%[cc]\n"
808c2ecf20Sopenharmony_ci		"	srl	%[cc],28\n"
818c2ecf20Sopenharmony_ci		"1:\n"
828c2ecf20Sopenharmony_ci		EX_TABLE(0b, 1b)
838c2ecf20Sopenharmony_ci		: [cc] "+d" (cc), [ign] "=d" (ignored), "+m" (*req)
848c2ecf20Sopenharmony_ci		: [req] "a" (req), [lps] "i" (lps)
858c2ecf20Sopenharmony_ci		: "cc");
868c2ecf20Sopenharmony_ci	return cc;
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic void *clp_alloc_block(gfp_t gfp_mask)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	return (void *) __get_free_pages(gfp_mask, get_order(CLP_BLK_SIZE));
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic void clp_free_block(void *ptr)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	free_pages((unsigned long) ptr, get_order(CLP_BLK_SIZE));
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic void clp_store_query_pci_fngrp(struct zpci_dev *zdev,
1008c2ecf20Sopenharmony_ci				      struct clp_rsp_query_pci_grp *response)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	zdev->tlb_refresh = response->refresh;
1038c2ecf20Sopenharmony_ci	zdev->dma_mask = response->dasm;
1048c2ecf20Sopenharmony_ci	zdev->msi_addr = response->msia;
1058c2ecf20Sopenharmony_ci	zdev->max_msi = response->noi;
1068c2ecf20Sopenharmony_ci	zdev->fmb_update = response->mui;
1078c2ecf20Sopenharmony_ci	zdev->version = response->version;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	switch (response->version) {
1108c2ecf20Sopenharmony_ci	case 1:
1118c2ecf20Sopenharmony_ci		zdev->max_bus_speed = PCIE_SPEED_5_0GT;
1128c2ecf20Sopenharmony_ci		break;
1138c2ecf20Sopenharmony_ci	default:
1148c2ecf20Sopenharmony_ci		zdev->max_bus_speed = PCI_SPEED_UNKNOWN;
1158c2ecf20Sopenharmony_ci		break;
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic int clp_query_pci_fngrp(struct zpci_dev *zdev, u8 pfgid)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	struct clp_req_rsp_query_pci_grp *rrb;
1228c2ecf20Sopenharmony_ci	int rc;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	rrb = clp_alloc_block(GFP_KERNEL);
1258c2ecf20Sopenharmony_ci	if (!rrb)
1268c2ecf20Sopenharmony_ci		return -ENOMEM;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	memset(rrb, 0, sizeof(*rrb));
1298c2ecf20Sopenharmony_ci	rrb->request.hdr.len = sizeof(rrb->request);
1308c2ecf20Sopenharmony_ci	rrb->request.hdr.cmd = CLP_QUERY_PCI_FNGRP;
1318c2ecf20Sopenharmony_ci	rrb->response.hdr.len = sizeof(rrb->response);
1328c2ecf20Sopenharmony_ci	rrb->request.pfgid = pfgid;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	rc = clp_req(rrb, CLP_LPS_PCI);
1358c2ecf20Sopenharmony_ci	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK)
1368c2ecf20Sopenharmony_ci		clp_store_query_pci_fngrp(zdev, &rrb->response);
1378c2ecf20Sopenharmony_ci	else {
1388c2ecf20Sopenharmony_ci		zpci_err("Q PCI FGRP:\n");
1398c2ecf20Sopenharmony_ci		zpci_err_clp(rrb->response.hdr.rsp, rc);
1408c2ecf20Sopenharmony_ci		rc = -EIO;
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci	clp_free_block(rrb);
1438c2ecf20Sopenharmony_ci	return rc;
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic int clp_store_query_pci_fn(struct zpci_dev *zdev,
1478c2ecf20Sopenharmony_ci				  struct clp_rsp_query_pci *response)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	int i;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
1528c2ecf20Sopenharmony_ci		zdev->bars[i].val = le32_to_cpu(response->bar[i]);
1538c2ecf20Sopenharmony_ci		zdev->bars[i].size = response->bar_size[i];
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci	zdev->start_dma = response->sdma;
1568c2ecf20Sopenharmony_ci	zdev->end_dma = response->edma;
1578c2ecf20Sopenharmony_ci	zdev->pchid = response->pchid;
1588c2ecf20Sopenharmony_ci	zdev->pfgid = response->pfgid;
1598c2ecf20Sopenharmony_ci	zdev->pft = response->pft;
1608c2ecf20Sopenharmony_ci	zdev->vfn = response->vfn;
1618c2ecf20Sopenharmony_ci	zdev->port = response->port;
1628c2ecf20Sopenharmony_ci	zdev->uid = response->uid;
1638c2ecf20Sopenharmony_ci	zdev->fmb_length = sizeof(u32) * response->fmb_len;
1648c2ecf20Sopenharmony_ci	zdev->rid_available = response->rid_avail;
1658c2ecf20Sopenharmony_ci	zdev->is_physfn = response->is_physfn;
1668c2ecf20Sopenharmony_ci	if (!s390_pci_no_rid && zdev->rid_available)
1678c2ecf20Sopenharmony_ci		zdev->devfn = response->rid & ZPCI_RID_MASK_DEVFN;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	memcpy(zdev->pfip, response->pfip, sizeof(zdev->pfip));
1708c2ecf20Sopenharmony_ci	if (response->util_str_avail) {
1718c2ecf20Sopenharmony_ci		memcpy(zdev->util_str, response->util_str,
1728c2ecf20Sopenharmony_ci		       sizeof(zdev->util_str));
1738c2ecf20Sopenharmony_ci		zdev->util_str_avail = 1;
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci	zdev->mio_capable = response->mio_addr_avail;
1768c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
1778c2ecf20Sopenharmony_ci		if (!(response->mio.valid & (1 << (PCI_STD_NUM_BARS - i - 1))))
1788c2ecf20Sopenharmony_ci			continue;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci		zdev->bars[i].mio_wb = (void __iomem *) response->mio.addr[i].wb;
1818c2ecf20Sopenharmony_ci		zdev->bars[i].mio_wt = (void __iomem *) response->mio.addr[i].wt;
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci	return 0;
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ciint clp_query_pci_fn(struct zpci_dev *zdev)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	struct clp_req_rsp_query_pci *rrb;
1898c2ecf20Sopenharmony_ci	int rc;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	rrb = clp_alloc_block(GFP_KERNEL);
1928c2ecf20Sopenharmony_ci	if (!rrb)
1938c2ecf20Sopenharmony_ci		return -ENOMEM;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	memset(rrb, 0, sizeof(*rrb));
1968c2ecf20Sopenharmony_ci	rrb->request.hdr.len = sizeof(rrb->request);
1978c2ecf20Sopenharmony_ci	rrb->request.hdr.cmd = CLP_QUERY_PCI_FN;
1988c2ecf20Sopenharmony_ci	rrb->response.hdr.len = sizeof(rrb->response);
1998c2ecf20Sopenharmony_ci	rrb->request.fh = zdev->fh;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	rc = clp_req(rrb, CLP_LPS_PCI);
2028c2ecf20Sopenharmony_ci	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) {
2038c2ecf20Sopenharmony_ci		rc = clp_store_query_pci_fn(zdev, &rrb->response);
2048c2ecf20Sopenharmony_ci		if (rc)
2058c2ecf20Sopenharmony_ci			goto out;
2068c2ecf20Sopenharmony_ci		rc = clp_query_pci_fngrp(zdev, rrb->response.pfgid);
2078c2ecf20Sopenharmony_ci	} else {
2088c2ecf20Sopenharmony_ci		zpci_err("Q PCI FN:\n");
2098c2ecf20Sopenharmony_ci		zpci_err_clp(rrb->response.hdr.rsp, rc);
2108c2ecf20Sopenharmony_ci		rc = -EIO;
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ciout:
2138c2ecf20Sopenharmony_ci	clp_free_block(rrb);
2148c2ecf20Sopenharmony_ci	return rc;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic int clp_refresh_fh(u32 fid);
2188c2ecf20Sopenharmony_ci/**
2198c2ecf20Sopenharmony_ci * clp_set_pci_fn() - Execute a command on a PCI function
2208c2ecf20Sopenharmony_ci * @zdev: Function that will be affected
2218c2ecf20Sopenharmony_ci * @nr_dma_as: DMA address space number
2228c2ecf20Sopenharmony_ci * @command: The command code to execute
2238c2ecf20Sopenharmony_ci *
2248c2ecf20Sopenharmony_ci * Returns: 0 on success, < 0 for Linux errors (e.g. -ENOMEM), and
2258c2ecf20Sopenharmony_ci * > 0 for non-success platform responses
2268c2ecf20Sopenharmony_ci */
2278c2ecf20Sopenharmony_cistatic int clp_set_pci_fn(struct zpci_dev *zdev, u8 nr_dma_as, u8 command)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	struct clp_req_rsp_set_pci *rrb;
2308c2ecf20Sopenharmony_ci	int rc, retries = 100;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	rrb = clp_alloc_block(GFP_KERNEL);
2338c2ecf20Sopenharmony_ci	if (!rrb)
2348c2ecf20Sopenharmony_ci		return -ENOMEM;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	do {
2378c2ecf20Sopenharmony_ci		memset(rrb, 0, sizeof(*rrb));
2388c2ecf20Sopenharmony_ci		rrb->request.hdr.len = sizeof(rrb->request);
2398c2ecf20Sopenharmony_ci		rrb->request.hdr.cmd = CLP_SET_PCI_FN;
2408c2ecf20Sopenharmony_ci		rrb->response.hdr.len = sizeof(rrb->response);
2418c2ecf20Sopenharmony_ci		rrb->request.fh = zdev->fh;
2428c2ecf20Sopenharmony_ci		rrb->request.oc = command;
2438c2ecf20Sopenharmony_ci		rrb->request.ndas = nr_dma_as;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci		rc = clp_req(rrb, CLP_LPS_PCI);
2468c2ecf20Sopenharmony_ci		if (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY) {
2478c2ecf20Sopenharmony_ci			retries--;
2488c2ecf20Sopenharmony_ci			if (retries < 0)
2498c2ecf20Sopenharmony_ci				break;
2508c2ecf20Sopenharmony_ci			msleep(20);
2518c2ecf20Sopenharmony_ci		}
2528c2ecf20Sopenharmony_ci	} while (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) {
2558c2ecf20Sopenharmony_ci		zdev->fh = rrb->response.fh;
2568c2ecf20Sopenharmony_ci	} else if (!rc && rrb->response.hdr.rsp == CLP_RC_SETPCIFN_ALRDY) {
2578c2ecf20Sopenharmony_ci		/* Function is already in desired state - update handle */
2588c2ecf20Sopenharmony_ci		rc = clp_refresh_fh(zdev->fid);
2598c2ecf20Sopenharmony_ci	} else {
2608c2ecf20Sopenharmony_ci		zpci_err("Set PCI FN:\n");
2618c2ecf20Sopenharmony_ci		zpci_err_clp(rrb->response.hdr.rsp, rc);
2628c2ecf20Sopenharmony_ci		if (!rc)
2638c2ecf20Sopenharmony_ci			rc = rrb->response.hdr.rsp;
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci	clp_free_block(rrb);
2668c2ecf20Sopenharmony_ci	return rc;
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ciint clp_setup_writeback_mio(void)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	struct clp_req_rsp_slpc_pci *rrb;
2728c2ecf20Sopenharmony_ci	u8  wb_bit_pos;
2738c2ecf20Sopenharmony_ci	int rc;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	rrb = clp_alloc_block(GFP_KERNEL);
2768c2ecf20Sopenharmony_ci	if (!rrb)
2778c2ecf20Sopenharmony_ci		return -ENOMEM;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	memset(rrb, 0, sizeof(*rrb));
2808c2ecf20Sopenharmony_ci	rrb->request.hdr.len = sizeof(rrb->request);
2818c2ecf20Sopenharmony_ci	rrb->request.hdr.cmd = CLP_SLPC;
2828c2ecf20Sopenharmony_ci	rrb->response.hdr.len = sizeof(rrb->response);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	rc = clp_req(rrb, CLP_LPS_PCI);
2858c2ecf20Sopenharmony_ci	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) {
2868c2ecf20Sopenharmony_ci		if (rrb->response.vwb) {
2878c2ecf20Sopenharmony_ci			wb_bit_pos = rrb->response.mio_wb;
2888c2ecf20Sopenharmony_ci			set_bit_inv(wb_bit_pos, &mio_wb_bit_mask);
2898c2ecf20Sopenharmony_ci			zpci_dbg(3, "wb bit: %d\n", wb_bit_pos);
2908c2ecf20Sopenharmony_ci		} else {
2918c2ecf20Sopenharmony_ci			zpci_dbg(3, "wb bit: n.a.\n");
2928c2ecf20Sopenharmony_ci		}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	} else {
2958c2ecf20Sopenharmony_ci		zpci_err("SLPC PCI:\n");
2968c2ecf20Sopenharmony_ci		zpci_err_clp(rrb->response.hdr.rsp, rc);
2978c2ecf20Sopenharmony_ci		rc = -EIO;
2988c2ecf20Sopenharmony_ci	}
2998c2ecf20Sopenharmony_ci	clp_free_block(rrb);
3008c2ecf20Sopenharmony_ci	return rc;
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ciint clp_enable_fh(struct zpci_dev *zdev, u8 nr_dma_as)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	int rc;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	rc = clp_set_pci_fn(zdev, nr_dma_as, CLP_SET_ENABLE_PCI_FN);
3088c2ecf20Sopenharmony_ci	zpci_dbg(3, "ena fid:%x, fh:%x, rc:%d\n", zdev->fid, zdev->fh, rc);
3098c2ecf20Sopenharmony_ci	if (!rc && zpci_use_mio(zdev)) {
3108c2ecf20Sopenharmony_ci		rc = clp_set_pci_fn(zdev, nr_dma_as, CLP_SET_ENABLE_MIO);
3118c2ecf20Sopenharmony_ci		zpci_dbg(3, "ena mio fid:%x, fh:%x, rc:%d\n",
3128c2ecf20Sopenharmony_ci				zdev->fid, zdev->fh, rc);
3138c2ecf20Sopenharmony_ci		if (rc)
3148c2ecf20Sopenharmony_ci			clp_disable_fh(zdev);
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci	return rc;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ciint clp_disable_fh(struct zpci_dev *zdev)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	int rc;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	if (!zdev_enabled(zdev))
3248c2ecf20Sopenharmony_ci		return 0;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	rc = clp_set_pci_fn(zdev, 0, CLP_SET_DISABLE_PCI_FN);
3278c2ecf20Sopenharmony_ci	zpci_dbg(3, "dis fid:%x, fh:%x, rc:%d\n", zdev->fid, zdev->fh, rc);
3288c2ecf20Sopenharmony_ci	return rc;
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistatic int clp_list_pci(struct clp_req_rsp_list_pci *rrb, void *data,
3328c2ecf20Sopenharmony_ci			void (*cb)(struct clp_fh_list_entry *, void *))
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	u64 resume_token = 0;
3358c2ecf20Sopenharmony_ci	int entries, i, rc;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	do {
3388c2ecf20Sopenharmony_ci		memset(rrb, 0, sizeof(*rrb));
3398c2ecf20Sopenharmony_ci		rrb->request.hdr.len = sizeof(rrb->request);
3408c2ecf20Sopenharmony_ci		rrb->request.hdr.cmd = CLP_LIST_PCI;
3418c2ecf20Sopenharmony_ci		/* store as many entries as possible */
3428c2ecf20Sopenharmony_ci		rrb->response.hdr.len = CLP_BLK_SIZE - LIST_PCI_HDR_LEN;
3438c2ecf20Sopenharmony_ci		rrb->request.resume_token = resume_token;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci		/* Get PCI function handle list */
3468c2ecf20Sopenharmony_ci		rc = clp_req(rrb, CLP_LPS_PCI);
3478c2ecf20Sopenharmony_ci		if (rc || rrb->response.hdr.rsp != CLP_RC_OK) {
3488c2ecf20Sopenharmony_ci			zpci_err("List PCI FN:\n");
3498c2ecf20Sopenharmony_ci			zpci_err_clp(rrb->response.hdr.rsp, rc);
3508c2ecf20Sopenharmony_ci			rc = -EIO;
3518c2ecf20Sopenharmony_ci			goto out;
3528c2ecf20Sopenharmony_ci		}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci		update_uid_checking(rrb->response.uid_checking);
3558c2ecf20Sopenharmony_ci		WARN_ON_ONCE(rrb->response.entry_size !=
3568c2ecf20Sopenharmony_ci			sizeof(struct clp_fh_list_entry));
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci		entries = (rrb->response.hdr.len - LIST_PCI_HDR_LEN) /
3598c2ecf20Sopenharmony_ci			rrb->response.entry_size;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci		resume_token = rrb->response.resume_token;
3628c2ecf20Sopenharmony_ci		for (i = 0; i < entries; i++)
3638c2ecf20Sopenharmony_ci			cb(&rrb->response.fh_list[i], data);
3648c2ecf20Sopenharmony_ci	} while (resume_token);
3658c2ecf20Sopenharmony_ciout:
3668c2ecf20Sopenharmony_ci	return rc;
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic void __clp_add(struct clp_fh_list_entry *entry, void *data)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	struct zpci_dev *zdev;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	if (!entry->vendor_id)
3748c2ecf20Sopenharmony_ci		return;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	zdev = get_zdev_by_fid(entry->fid);
3778c2ecf20Sopenharmony_ci	if (zdev) {
3788c2ecf20Sopenharmony_ci		zpci_zdev_put(zdev);
3798c2ecf20Sopenharmony_ci		return;
3808c2ecf20Sopenharmony_ci	}
3818c2ecf20Sopenharmony_ci	zpci_create_device(entry->fid, entry->fh, entry->config_state);
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ciint clp_scan_pci_devices(void)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	struct clp_req_rsp_list_pci *rrb;
3878c2ecf20Sopenharmony_ci	int rc;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	rrb = clp_alloc_block(GFP_KERNEL);
3908c2ecf20Sopenharmony_ci	if (!rrb)
3918c2ecf20Sopenharmony_ci		return -ENOMEM;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	rc = clp_list_pci(rrb, NULL, __clp_add);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	clp_free_block(rrb);
3968c2ecf20Sopenharmony_ci	return rc;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic void __clp_refresh_fh(struct clp_fh_list_entry *entry, void *data)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	struct zpci_dev *zdev;
4028c2ecf20Sopenharmony_ci	u32 fid = *((u32 *)data);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	if (!entry->vendor_id || fid != entry->fid)
4058c2ecf20Sopenharmony_ci		return;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	zdev = get_zdev_by_fid(fid);
4088c2ecf20Sopenharmony_ci	if (!zdev)
4098c2ecf20Sopenharmony_ci		return;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	zdev->fh = entry->fh;
4128c2ecf20Sopenharmony_ci}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci/*
4158c2ecf20Sopenharmony_ci * Refresh the function handle of the function matching @fid
4168c2ecf20Sopenharmony_ci */
4178c2ecf20Sopenharmony_cistatic int clp_refresh_fh(u32 fid)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	struct clp_req_rsp_list_pci *rrb;
4208c2ecf20Sopenharmony_ci	int rc;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	rrb = clp_alloc_block(GFP_NOWAIT);
4238c2ecf20Sopenharmony_ci	if (!rrb)
4248c2ecf20Sopenharmony_ci		return -ENOMEM;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	rc = clp_list_pci(rrb, &fid, __clp_refresh_fh);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	clp_free_block(rrb);
4298c2ecf20Sopenharmony_ci	return rc;
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistruct clp_state_data {
4338c2ecf20Sopenharmony_ci	u32 fid;
4348c2ecf20Sopenharmony_ci	enum zpci_state state;
4358c2ecf20Sopenharmony_ci};
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic void __clp_get_state(struct clp_fh_list_entry *entry, void *data)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	struct clp_state_data *sd = data;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	if (entry->fid != sd->fid)
4428c2ecf20Sopenharmony_ci		return;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	sd->state = entry->config_state;
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ciint clp_get_state(u32 fid, enum zpci_state *state)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	struct clp_req_rsp_list_pci *rrb;
4508c2ecf20Sopenharmony_ci	struct clp_state_data sd = {fid, ZPCI_FN_STATE_RESERVED};
4518c2ecf20Sopenharmony_ci	int rc;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	rrb = clp_alloc_block(GFP_ATOMIC);
4548c2ecf20Sopenharmony_ci	if (!rrb)
4558c2ecf20Sopenharmony_ci		return -ENOMEM;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	rc = clp_list_pci(rrb, &sd, __clp_get_state);
4588c2ecf20Sopenharmony_ci	if (!rc)
4598c2ecf20Sopenharmony_ci		*state = sd.state;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	clp_free_block(rrb);
4628c2ecf20Sopenharmony_ci	return rc;
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_cistatic int clp_base_slpc(struct clp_req *req, struct clp_req_rsp_slpc *lpcb)
4668c2ecf20Sopenharmony_ci{
4678c2ecf20Sopenharmony_ci	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
4708c2ecf20Sopenharmony_ci	    lpcb->response.hdr.len > limit)
4718c2ecf20Sopenharmony_ci		return -EINVAL;
4728c2ecf20Sopenharmony_ci	return clp_req(lpcb, CLP_LPS_BASE) ? -EOPNOTSUPP : 0;
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic int clp_base_command(struct clp_req *req, struct clp_req_hdr *lpcb)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	switch (lpcb->cmd) {
4788c2ecf20Sopenharmony_ci	case 0x0001: /* store logical-processor characteristics */
4798c2ecf20Sopenharmony_ci		return clp_base_slpc(req, (void *) lpcb);
4808c2ecf20Sopenharmony_ci	default:
4818c2ecf20Sopenharmony_ci		return -EINVAL;
4828c2ecf20Sopenharmony_ci	}
4838c2ecf20Sopenharmony_ci}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_cistatic int clp_pci_slpc(struct clp_req *req, struct clp_req_rsp_slpc_pci *lpcb)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
4908c2ecf20Sopenharmony_ci	    lpcb->response.hdr.len > limit)
4918c2ecf20Sopenharmony_ci		return -EINVAL;
4928c2ecf20Sopenharmony_ci	return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic int clp_pci_list(struct clp_req *req, struct clp_req_rsp_list_pci *lpcb)
4968c2ecf20Sopenharmony_ci{
4978c2ecf20Sopenharmony_ci	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
5008c2ecf20Sopenharmony_ci	    lpcb->response.hdr.len > limit)
5018c2ecf20Sopenharmony_ci		return -EINVAL;
5028c2ecf20Sopenharmony_ci	if (lpcb->request.reserved2 != 0)
5038c2ecf20Sopenharmony_ci		return -EINVAL;
5048c2ecf20Sopenharmony_ci	return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
5058c2ecf20Sopenharmony_ci}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_cistatic int clp_pci_query(struct clp_req *req,
5088c2ecf20Sopenharmony_ci			 struct clp_req_rsp_query_pci *lpcb)
5098c2ecf20Sopenharmony_ci{
5108c2ecf20Sopenharmony_ci	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
5138c2ecf20Sopenharmony_ci	    lpcb->response.hdr.len > limit)
5148c2ecf20Sopenharmony_ci		return -EINVAL;
5158c2ecf20Sopenharmony_ci	if (lpcb->request.reserved2 != 0 || lpcb->request.reserved3 != 0)
5168c2ecf20Sopenharmony_ci		return -EINVAL;
5178c2ecf20Sopenharmony_ci	return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic int clp_pci_query_grp(struct clp_req *req,
5218c2ecf20Sopenharmony_ci			     struct clp_req_rsp_query_pci_grp *lpcb)
5228c2ecf20Sopenharmony_ci{
5238c2ecf20Sopenharmony_ci	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
5268c2ecf20Sopenharmony_ci	    lpcb->response.hdr.len > limit)
5278c2ecf20Sopenharmony_ci		return -EINVAL;
5288c2ecf20Sopenharmony_ci	if (lpcb->request.reserved2 != 0 || lpcb->request.reserved3 != 0 ||
5298c2ecf20Sopenharmony_ci	    lpcb->request.reserved4 != 0)
5308c2ecf20Sopenharmony_ci		return -EINVAL;
5318c2ecf20Sopenharmony_ci	return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_cistatic int clp_pci_command(struct clp_req *req, struct clp_req_hdr *lpcb)
5358c2ecf20Sopenharmony_ci{
5368c2ecf20Sopenharmony_ci	switch (lpcb->cmd) {
5378c2ecf20Sopenharmony_ci	case 0x0001: /* store logical-processor characteristics */
5388c2ecf20Sopenharmony_ci		return clp_pci_slpc(req, (void *) lpcb);
5398c2ecf20Sopenharmony_ci	case 0x0002: /* list PCI functions */
5408c2ecf20Sopenharmony_ci		return clp_pci_list(req, (void *) lpcb);
5418c2ecf20Sopenharmony_ci	case 0x0003: /* query PCI function */
5428c2ecf20Sopenharmony_ci		return clp_pci_query(req, (void *) lpcb);
5438c2ecf20Sopenharmony_ci	case 0x0004: /* query PCI function group */
5448c2ecf20Sopenharmony_ci		return clp_pci_query_grp(req, (void *) lpcb);
5458c2ecf20Sopenharmony_ci	default:
5468c2ecf20Sopenharmony_ci		return -EINVAL;
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_cistatic int clp_normal_command(struct clp_req *req)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci	struct clp_req_hdr *lpcb;
5538c2ecf20Sopenharmony_ci	void __user *uptr;
5548c2ecf20Sopenharmony_ci	int rc;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	rc = -EINVAL;
5578c2ecf20Sopenharmony_ci	if (req->lps != 0 && req->lps != 2)
5588c2ecf20Sopenharmony_ci		goto out;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	rc = -ENOMEM;
5618c2ecf20Sopenharmony_ci	lpcb = clp_alloc_block(GFP_KERNEL);
5628c2ecf20Sopenharmony_ci	if (!lpcb)
5638c2ecf20Sopenharmony_ci		goto out;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	rc = -EFAULT;
5668c2ecf20Sopenharmony_ci	uptr = (void __force __user *)(unsigned long) req->data_p;
5678c2ecf20Sopenharmony_ci	if (copy_from_user(lpcb, uptr, PAGE_SIZE) != 0)
5688c2ecf20Sopenharmony_ci		goto out_free;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	rc = -EINVAL;
5718c2ecf20Sopenharmony_ci	if (lpcb->fmt != 0 || lpcb->reserved1 != 0 || lpcb->reserved2 != 0)
5728c2ecf20Sopenharmony_ci		goto out_free;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	switch (req->lps) {
5758c2ecf20Sopenharmony_ci	case 0:
5768c2ecf20Sopenharmony_ci		rc = clp_base_command(req, lpcb);
5778c2ecf20Sopenharmony_ci		break;
5788c2ecf20Sopenharmony_ci	case 2:
5798c2ecf20Sopenharmony_ci		rc = clp_pci_command(req, lpcb);
5808c2ecf20Sopenharmony_ci		break;
5818c2ecf20Sopenharmony_ci	}
5828c2ecf20Sopenharmony_ci	if (rc)
5838c2ecf20Sopenharmony_ci		goto out_free;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	rc = -EFAULT;
5868c2ecf20Sopenharmony_ci	if (copy_to_user(uptr, lpcb, PAGE_SIZE) != 0)
5878c2ecf20Sopenharmony_ci		goto out_free;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	rc = 0;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ciout_free:
5928c2ecf20Sopenharmony_ci	clp_free_block(lpcb);
5938c2ecf20Sopenharmony_ciout:
5948c2ecf20Sopenharmony_ci	return rc;
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic int clp_immediate_command(struct clp_req *req)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	void __user *uptr;
6008c2ecf20Sopenharmony_ci	unsigned long ilp;
6018c2ecf20Sopenharmony_ci	int exists;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	if (req->cmd > 1 || clp_get_ilp(&ilp) != 0)
6048c2ecf20Sopenharmony_ci		return -EINVAL;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	uptr = (void __force __user *)(unsigned long) req->data_p;
6078c2ecf20Sopenharmony_ci	if (req->cmd == 0) {
6088c2ecf20Sopenharmony_ci		/* Command code 0: test for a specific processor */
6098c2ecf20Sopenharmony_ci		exists = test_bit_inv(req->lps, &ilp);
6108c2ecf20Sopenharmony_ci		return put_user(exists, (int __user *) uptr);
6118c2ecf20Sopenharmony_ci	}
6128c2ecf20Sopenharmony_ci	/* Command code 1: return bit mask of installed processors */
6138c2ecf20Sopenharmony_ci	return put_user(ilp, (unsigned long __user *) uptr);
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_cistatic long clp_misc_ioctl(struct file *filp, unsigned int cmd,
6178c2ecf20Sopenharmony_ci			   unsigned long arg)
6188c2ecf20Sopenharmony_ci{
6198c2ecf20Sopenharmony_ci	struct clp_req req;
6208c2ecf20Sopenharmony_ci	void __user *argp;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	if (cmd != CLP_SYNC)
6238c2ecf20Sopenharmony_ci		return -EINVAL;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	argp = is_compat_task() ? compat_ptr(arg) : (void __user *) arg;
6268c2ecf20Sopenharmony_ci	if (copy_from_user(&req, argp, sizeof(req)))
6278c2ecf20Sopenharmony_ci		return -EFAULT;
6288c2ecf20Sopenharmony_ci	if (req.r != 0)
6298c2ecf20Sopenharmony_ci		return -EINVAL;
6308c2ecf20Sopenharmony_ci	return req.c ? clp_immediate_command(&req) : clp_normal_command(&req);
6318c2ecf20Sopenharmony_ci}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_cistatic int clp_misc_release(struct inode *inode, struct file *filp)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	return 0;
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_cistatic const struct file_operations clp_misc_fops = {
6398c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
6408c2ecf20Sopenharmony_ci	.open = nonseekable_open,
6418c2ecf20Sopenharmony_ci	.release = clp_misc_release,
6428c2ecf20Sopenharmony_ci	.unlocked_ioctl = clp_misc_ioctl,
6438c2ecf20Sopenharmony_ci	.compat_ioctl = clp_misc_ioctl,
6448c2ecf20Sopenharmony_ci	.llseek = no_llseek,
6458c2ecf20Sopenharmony_ci};
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_cistatic struct miscdevice clp_misc_device = {
6488c2ecf20Sopenharmony_ci	.minor = MISC_DYNAMIC_MINOR,
6498c2ecf20Sopenharmony_ci	.name = "clp",
6508c2ecf20Sopenharmony_ci	.fops = &clp_misc_fops,
6518c2ecf20Sopenharmony_ci};
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_cistatic int __init clp_misc_init(void)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	return misc_register(&clp_misc_device);
6568c2ecf20Sopenharmony_ci}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_cidevice_initcall(clp_misc_init);
659