cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pci_clp.c (15616B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright IBM Corp. 2012
      4 *
      5 * Author(s):
      6 *   Jan Glauber <jang@linux.vnet.ibm.com>
      7 */
      8
      9#define KMSG_COMPONENT "zpci"
     10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
     11
     12#include <linux/compat.h>
     13#include <linux/kernel.h>
     14#include <linux/miscdevice.h>
     15#include <linux/slab.h>
     16#include <linux/err.h>
     17#include <linux/delay.h>
     18#include <linux/pci.h>
     19#include <linux/uaccess.h>
     20#include <asm/asm-extable.h>
     21#include <asm/pci_debug.h>
     22#include <asm/pci_clp.h>
     23#include <asm/clp.h>
     24#include <uapi/asm/clp.h>
     25
     26#include "pci_bus.h"
     27
     28bool zpci_unique_uid;
     29
     30void update_uid_checking(bool new)
     31{
     32	if (zpci_unique_uid != new)
     33		zpci_dbg(3, "uid checking:%d\n", new);
     34
     35	zpci_unique_uid = new;
     36}
     37
     38static inline void zpci_err_clp(unsigned int rsp, int rc)
     39{
     40	struct {
     41		unsigned int rsp;
     42		int rc;
     43	} __packed data = {rsp, rc};
     44
     45	zpci_err_hex(&data, sizeof(data));
     46}
     47
     48/*
     49 * Call Logical Processor with c=1, lps=0 and command 1
     50 * to get the bit mask of installed logical processors
     51 */
     52static inline int clp_get_ilp(unsigned long *ilp)
     53{
     54	unsigned long mask;
     55	int cc = 3;
     56
     57	asm volatile (
     58		"	.insn	rrf,0xb9a00000,%[mask],%[cmd],8,0\n"
     59		"0:	ipm	%[cc]\n"
     60		"	srl	%[cc],28\n"
     61		"1:\n"
     62		EX_TABLE(0b, 1b)
     63		: [cc] "+d" (cc), [mask] "=d" (mask) : [cmd] "a" (1)
     64		: "cc");
     65	*ilp = mask;
     66	return cc;
     67}
     68
     69/*
     70 * Call Logical Processor with c=0, the give constant lps and an lpcb request.
     71 */
     72static __always_inline int clp_req(void *data, unsigned int lps)
     73{
     74	struct { u8 _[CLP_BLK_SIZE]; } *req = data;
     75	u64 ignored;
     76	int cc = 3;
     77
     78	asm volatile (
     79		"	.insn	rrf,0xb9a00000,%[ign],%[req],0,%[lps]\n"
     80		"0:	ipm	%[cc]\n"
     81		"	srl	%[cc],28\n"
     82		"1:\n"
     83		EX_TABLE(0b, 1b)
     84		: [cc] "+d" (cc), [ign] "=d" (ignored), "+m" (*req)
     85		: [req] "a" (req), [lps] "i" (lps)
     86		: "cc");
     87	return cc;
     88}
     89
     90static void *clp_alloc_block(gfp_t gfp_mask)
     91{
     92	return (void *) __get_free_pages(gfp_mask, get_order(CLP_BLK_SIZE));
     93}
     94
     95static void clp_free_block(void *ptr)
     96{
     97	free_pages((unsigned long) ptr, get_order(CLP_BLK_SIZE));
     98}
     99
    100static void clp_store_query_pci_fngrp(struct zpci_dev *zdev,
    101				      struct clp_rsp_query_pci_grp *response)
    102{
    103	zdev->tlb_refresh = response->refresh;
    104	zdev->dma_mask = response->dasm;
    105	zdev->msi_addr = response->msia;
    106	zdev->max_msi = response->noi;
    107	zdev->fmb_update = response->mui;
    108	zdev->version = response->version;
    109
    110	switch (response->version) {
    111	case 1:
    112		zdev->max_bus_speed = PCIE_SPEED_5_0GT;
    113		break;
    114	default:
    115		zdev->max_bus_speed = PCI_SPEED_UNKNOWN;
    116		break;
    117	}
    118}
    119
    120static int clp_query_pci_fngrp(struct zpci_dev *zdev, u8 pfgid)
    121{
    122	struct clp_req_rsp_query_pci_grp *rrb;
    123	int rc;
    124
    125	rrb = clp_alloc_block(GFP_KERNEL);
    126	if (!rrb)
    127		return -ENOMEM;
    128
    129	memset(rrb, 0, sizeof(*rrb));
    130	rrb->request.hdr.len = sizeof(rrb->request);
    131	rrb->request.hdr.cmd = CLP_QUERY_PCI_FNGRP;
    132	rrb->response.hdr.len = sizeof(rrb->response);
    133	rrb->request.pfgid = pfgid;
    134
    135	rc = clp_req(rrb, CLP_LPS_PCI);
    136	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK)
    137		clp_store_query_pci_fngrp(zdev, &rrb->response);
    138	else {
    139		zpci_err("Q PCI FGRP:\n");
    140		zpci_err_clp(rrb->response.hdr.rsp, rc);
    141		rc = -EIO;
    142	}
    143	clp_free_block(rrb);
    144	return rc;
    145}
    146
    147static int clp_store_query_pci_fn(struct zpci_dev *zdev,
    148				  struct clp_rsp_query_pci *response)
    149{
    150	int i;
    151
    152	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
    153		zdev->bars[i].val = le32_to_cpu(response->bar[i]);
    154		zdev->bars[i].size = response->bar_size[i];
    155	}
    156	zdev->start_dma = response->sdma;
    157	zdev->end_dma = response->edma;
    158	zdev->pchid = response->pchid;
    159	zdev->pfgid = response->pfgid;
    160	zdev->pft = response->pft;
    161	zdev->vfn = response->vfn;
    162	zdev->port = response->port;
    163	zdev->uid = response->uid;
    164	zdev->fmb_length = sizeof(u32) * response->fmb_len;
    165	zdev->rid_available = response->rid_avail;
    166	zdev->is_physfn = response->is_physfn;
    167	if (!s390_pci_no_rid && zdev->rid_available)
    168		zdev->devfn = response->rid & ZPCI_RID_MASK_DEVFN;
    169
    170	memcpy(zdev->pfip, response->pfip, sizeof(zdev->pfip));
    171	if (response->util_str_avail) {
    172		memcpy(zdev->util_str, response->util_str,
    173		       sizeof(zdev->util_str));
    174		zdev->util_str_avail = 1;
    175	}
    176	zdev->mio_capable = response->mio_addr_avail;
    177	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
    178		if (!(response->mio.valid & (1 << (PCI_STD_NUM_BARS - i - 1))))
    179			continue;
    180
    181		zdev->bars[i].mio_wb = (void __iomem *) response->mio.addr[i].wb;
    182		zdev->bars[i].mio_wt = (void __iomem *) response->mio.addr[i].wt;
    183	}
    184	return 0;
    185}
    186
    187int clp_query_pci_fn(struct zpci_dev *zdev)
    188{
    189	struct clp_req_rsp_query_pci *rrb;
    190	int rc;
    191
    192	rrb = clp_alloc_block(GFP_KERNEL);
    193	if (!rrb)
    194		return -ENOMEM;
    195
    196	memset(rrb, 0, sizeof(*rrb));
    197	rrb->request.hdr.len = sizeof(rrb->request);
    198	rrb->request.hdr.cmd = CLP_QUERY_PCI_FN;
    199	rrb->response.hdr.len = sizeof(rrb->response);
    200	rrb->request.fh = zdev->fh;
    201
    202	rc = clp_req(rrb, CLP_LPS_PCI);
    203	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) {
    204		rc = clp_store_query_pci_fn(zdev, &rrb->response);
    205		if (rc)
    206			goto out;
    207		rc = clp_query_pci_fngrp(zdev, rrb->response.pfgid);
    208	} else {
    209		zpci_err("Q PCI FN:\n");
    210		zpci_err_clp(rrb->response.hdr.rsp, rc);
    211		rc = -EIO;
    212	}
    213out:
    214	clp_free_block(rrb);
    215	return rc;
    216}
    217
    218/**
    219 * clp_set_pci_fn() - Execute a command on a PCI function
    220 * @zdev: Function that will be affected
    221 * @fh: Out parameter for updated function handle
    222 * @nr_dma_as: DMA address space number
    223 * @command: The command code to execute
    224 *
    225 * Returns: 0 on success, < 0 for Linux errors (e.g. -ENOMEM), and
    226 * > 0 for non-success platform responses
    227 */
    228static int clp_set_pci_fn(struct zpci_dev *zdev, u32 *fh, u8 nr_dma_as, u8 command)
    229{
    230	struct clp_req_rsp_set_pci *rrb;
    231	int rc, retries = 100;
    232
    233	*fh = 0;
    234	rrb = clp_alloc_block(GFP_KERNEL);
    235	if (!rrb)
    236		return -ENOMEM;
    237
    238	do {
    239		memset(rrb, 0, sizeof(*rrb));
    240		rrb->request.hdr.len = sizeof(rrb->request);
    241		rrb->request.hdr.cmd = CLP_SET_PCI_FN;
    242		rrb->response.hdr.len = sizeof(rrb->response);
    243		rrb->request.fh = zdev->fh;
    244		rrb->request.oc = command;
    245		rrb->request.ndas = nr_dma_as;
    246
    247		rc = clp_req(rrb, CLP_LPS_PCI);
    248		if (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY) {
    249			retries--;
    250			if (retries < 0)
    251				break;
    252			msleep(20);
    253		}
    254	} while (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY);
    255
    256	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) {
    257		*fh = rrb->response.fh;
    258	} else {
    259		zpci_err("Set PCI FN:\n");
    260		zpci_err_clp(rrb->response.hdr.rsp, rc);
    261		if (!rc)
    262			rc = rrb->response.hdr.rsp;
    263	}
    264	clp_free_block(rrb);
    265	return rc;
    266}
    267
    268int clp_setup_writeback_mio(void)
    269{
    270	struct clp_req_rsp_slpc_pci *rrb;
    271	u8  wb_bit_pos;
    272	int rc;
    273
    274	rrb = clp_alloc_block(GFP_KERNEL);
    275	if (!rrb)
    276		return -ENOMEM;
    277
    278	memset(rrb, 0, sizeof(*rrb));
    279	rrb->request.hdr.len = sizeof(rrb->request);
    280	rrb->request.hdr.cmd = CLP_SLPC;
    281	rrb->response.hdr.len = sizeof(rrb->response);
    282
    283	rc = clp_req(rrb, CLP_LPS_PCI);
    284	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) {
    285		if (rrb->response.vwb) {
    286			wb_bit_pos = rrb->response.mio_wb;
    287			set_bit_inv(wb_bit_pos, &mio_wb_bit_mask);
    288			zpci_dbg(3, "wb bit: %d\n", wb_bit_pos);
    289		} else {
    290			zpci_dbg(3, "wb bit: n.a.\n");
    291		}
    292
    293	} else {
    294		zpci_err("SLPC PCI:\n");
    295		zpci_err_clp(rrb->response.hdr.rsp, rc);
    296		rc = -EIO;
    297	}
    298	clp_free_block(rrb);
    299	return rc;
    300}
    301
    302int clp_enable_fh(struct zpci_dev *zdev, u32 *fh, u8 nr_dma_as)
    303{
    304	int rc;
    305
    306	rc = clp_set_pci_fn(zdev, fh, nr_dma_as, CLP_SET_ENABLE_PCI_FN);
    307	zpci_dbg(3, "ena fid:%x, fh:%x, rc:%d\n", zdev->fid, *fh, rc);
    308	if (!rc && zpci_use_mio(zdev)) {
    309		rc = clp_set_pci_fn(zdev, fh, nr_dma_as, CLP_SET_ENABLE_MIO);
    310		zpci_dbg(3, "ena mio fid:%x, fh:%x, rc:%d\n",
    311				zdev->fid, *fh, rc);
    312		if (rc)
    313			clp_disable_fh(zdev, fh);
    314	}
    315	return rc;
    316}
    317
    318int clp_disable_fh(struct zpci_dev *zdev, u32 *fh)
    319{
    320	int rc;
    321
    322	if (!zdev_enabled(zdev))
    323		return 0;
    324
    325	rc = clp_set_pci_fn(zdev, fh, 0, CLP_SET_DISABLE_PCI_FN);
    326	zpci_dbg(3, "dis fid:%x, fh:%x, rc:%d\n", zdev->fid, *fh, rc);
    327	return rc;
    328}
    329
    330static int clp_list_pci_req(struct clp_req_rsp_list_pci *rrb,
    331			    u64 *resume_token, int *nentries)
    332{
    333	int rc;
    334
    335	memset(rrb, 0, sizeof(*rrb));
    336	rrb->request.hdr.len = sizeof(rrb->request);
    337	rrb->request.hdr.cmd = CLP_LIST_PCI;
    338	/* store as many entries as possible */
    339	rrb->response.hdr.len = CLP_BLK_SIZE - LIST_PCI_HDR_LEN;
    340	rrb->request.resume_token = *resume_token;
    341
    342	/* Get PCI function handle list */
    343	rc = clp_req(rrb, CLP_LPS_PCI);
    344	if (rc || rrb->response.hdr.rsp != CLP_RC_OK) {
    345		zpci_err("List PCI FN:\n");
    346		zpci_err_clp(rrb->response.hdr.rsp, rc);
    347		return -EIO;
    348	}
    349
    350	update_uid_checking(rrb->response.uid_checking);
    351	WARN_ON_ONCE(rrb->response.entry_size !=
    352		sizeof(struct clp_fh_list_entry));
    353
    354	*nentries = (rrb->response.hdr.len - LIST_PCI_HDR_LEN) /
    355		rrb->response.entry_size;
    356	*resume_token = rrb->response.resume_token;
    357
    358	return rc;
    359}
    360
    361static int clp_list_pci(struct clp_req_rsp_list_pci *rrb, void *data,
    362			void (*cb)(struct clp_fh_list_entry *, void *))
    363{
    364	u64 resume_token = 0;
    365	int nentries, i, rc;
    366
    367	do {
    368		rc = clp_list_pci_req(rrb, &resume_token, &nentries);
    369		if (rc)
    370			return rc;
    371		for (i = 0; i < nentries; i++)
    372			cb(&rrb->response.fh_list[i], data);
    373	} while (resume_token);
    374
    375	return rc;
    376}
    377
    378static int clp_find_pci(struct clp_req_rsp_list_pci *rrb, u32 fid,
    379			struct clp_fh_list_entry *entry)
    380{
    381	struct clp_fh_list_entry *fh_list;
    382	u64 resume_token = 0;
    383	int nentries, i, rc;
    384
    385	do {
    386		rc = clp_list_pci_req(rrb, &resume_token, &nentries);
    387		if (rc)
    388			return rc;
    389		fh_list = rrb->response.fh_list;
    390		for (i = 0; i < nentries; i++) {
    391			if (fh_list[i].fid == fid) {
    392				*entry = fh_list[i];
    393				return 0;
    394			}
    395		}
    396	} while (resume_token);
    397
    398	return -ENODEV;
    399}
    400
    401static void __clp_add(struct clp_fh_list_entry *entry, void *data)
    402{
    403	struct zpci_dev *zdev;
    404
    405	if (!entry->vendor_id)
    406		return;
    407
    408	zdev = get_zdev_by_fid(entry->fid);
    409	if (zdev) {
    410		zpci_zdev_put(zdev);
    411		return;
    412	}
    413	zpci_create_device(entry->fid, entry->fh, entry->config_state);
    414}
    415
    416int clp_scan_pci_devices(void)
    417{
    418	struct clp_req_rsp_list_pci *rrb;
    419	int rc;
    420
    421	rrb = clp_alloc_block(GFP_KERNEL);
    422	if (!rrb)
    423		return -ENOMEM;
    424
    425	rc = clp_list_pci(rrb, NULL, __clp_add);
    426
    427	clp_free_block(rrb);
    428	return rc;
    429}
    430
    431/*
    432 * Get the current function handle of the function matching @fid
    433 */
    434int clp_refresh_fh(u32 fid, u32 *fh)
    435{
    436	struct clp_req_rsp_list_pci *rrb;
    437	struct clp_fh_list_entry entry;
    438	int rc;
    439
    440	rrb = clp_alloc_block(GFP_NOWAIT);
    441	if (!rrb)
    442		return -ENOMEM;
    443
    444	rc = clp_find_pci(rrb, fid, &entry);
    445	if (!rc)
    446		*fh = entry.fh;
    447
    448	clp_free_block(rrb);
    449	return rc;
    450}
    451
    452int clp_get_state(u32 fid, enum zpci_state *state)
    453{
    454	struct clp_req_rsp_list_pci *rrb;
    455	struct clp_fh_list_entry entry;
    456	int rc;
    457
    458	rrb = clp_alloc_block(GFP_ATOMIC);
    459	if (!rrb)
    460		return -ENOMEM;
    461
    462	rc = clp_find_pci(rrb, fid, &entry);
    463	if (!rc) {
    464		*state = entry.config_state;
    465	} else if (rc == -ENODEV) {
    466		*state = ZPCI_FN_STATE_RESERVED;
    467		rc = 0;
    468	}
    469
    470	clp_free_block(rrb);
    471	return rc;
    472}
    473
    474static int clp_base_slpc(struct clp_req *req, struct clp_req_rsp_slpc *lpcb)
    475{
    476	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
    477
    478	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
    479	    lpcb->response.hdr.len > limit)
    480		return -EINVAL;
    481	return clp_req(lpcb, CLP_LPS_BASE) ? -EOPNOTSUPP : 0;
    482}
    483
    484static int clp_base_command(struct clp_req *req, struct clp_req_hdr *lpcb)
    485{
    486	switch (lpcb->cmd) {
    487	case 0x0001: /* store logical-processor characteristics */
    488		return clp_base_slpc(req, (void *) lpcb);
    489	default:
    490		return -EINVAL;
    491	}
    492}
    493
    494static int clp_pci_slpc(struct clp_req *req, struct clp_req_rsp_slpc_pci *lpcb)
    495{
    496	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
    497
    498	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
    499	    lpcb->response.hdr.len > limit)
    500		return -EINVAL;
    501	return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
    502}
    503
    504static int clp_pci_list(struct clp_req *req, struct clp_req_rsp_list_pci *lpcb)
    505{
    506	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
    507
    508	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
    509	    lpcb->response.hdr.len > limit)
    510		return -EINVAL;
    511	if (lpcb->request.reserved2 != 0)
    512		return -EINVAL;
    513	return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
    514}
    515
    516static int clp_pci_query(struct clp_req *req,
    517			 struct clp_req_rsp_query_pci *lpcb)
    518{
    519	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
    520
    521	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
    522	    lpcb->response.hdr.len > limit)
    523		return -EINVAL;
    524	if (lpcb->request.reserved2 != 0 || lpcb->request.reserved3 != 0)
    525		return -EINVAL;
    526	return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
    527}
    528
    529static int clp_pci_query_grp(struct clp_req *req,
    530			     struct clp_req_rsp_query_pci_grp *lpcb)
    531{
    532	unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
    533
    534	if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
    535	    lpcb->response.hdr.len > limit)
    536		return -EINVAL;
    537	if (lpcb->request.reserved2 != 0 || lpcb->request.reserved3 != 0 ||
    538	    lpcb->request.reserved4 != 0)
    539		return -EINVAL;
    540	return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
    541}
    542
    543static int clp_pci_command(struct clp_req *req, struct clp_req_hdr *lpcb)
    544{
    545	switch (lpcb->cmd) {
    546	case 0x0001: /* store logical-processor characteristics */
    547		return clp_pci_slpc(req, (void *) lpcb);
    548	case 0x0002: /* list PCI functions */
    549		return clp_pci_list(req, (void *) lpcb);
    550	case 0x0003: /* query PCI function */
    551		return clp_pci_query(req, (void *) lpcb);
    552	case 0x0004: /* query PCI function group */
    553		return clp_pci_query_grp(req, (void *) lpcb);
    554	default:
    555		return -EINVAL;
    556	}
    557}
    558
    559static int clp_normal_command(struct clp_req *req)
    560{
    561	struct clp_req_hdr *lpcb;
    562	void __user *uptr;
    563	int rc;
    564
    565	rc = -EINVAL;
    566	if (req->lps != 0 && req->lps != 2)
    567		goto out;
    568
    569	rc = -ENOMEM;
    570	lpcb = clp_alloc_block(GFP_KERNEL);
    571	if (!lpcb)
    572		goto out;
    573
    574	rc = -EFAULT;
    575	uptr = (void __force __user *)(unsigned long) req->data_p;
    576	if (copy_from_user(lpcb, uptr, PAGE_SIZE) != 0)
    577		goto out_free;
    578
    579	rc = -EINVAL;
    580	if (lpcb->fmt != 0 || lpcb->reserved1 != 0 || lpcb->reserved2 != 0)
    581		goto out_free;
    582
    583	switch (req->lps) {
    584	case 0:
    585		rc = clp_base_command(req, lpcb);
    586		break;
    587	case 2:
    588		rc = clp_pci_command(req, lpcb);
    589		break;
    590	}
    591	if (rc)
    592		goto out_free;
    593
    594	rc = -EFAULT;
    595	if (copy_to_user(uptr, lpcb, PAGE_SIZE) != 0)
    596		goto out_free;
    597
    598	rc = 0;
    599
    600out_free:
    601	clp_free_block(lpcb);
    602out:
    603	return rc;
    604}
    605
    606static int clp_immediate_command(struct clp_req *req)
    607{
    608	void __user *uptr;
    609	unsigned long ilp;
    610	int exists;
    611
    612	if (req->cmd > 1 || clp_get_ilp(&ilp) != 0)
    613		return -EINVAL;
    614
    615	uptr = (void __force __user *)(unsigned long) req->data_p;
    616	if (req->cmd == 0) {
    617		/* Command code 0: test for a specific processor */
    618		exists = test_bit_inv(req->lps, &ilp);
    619		return put_user(exists, (int __user *) uptr);
    620	}
    621	/* Command code 1: return bit mask of installed processors */
    622	return put_user(ilp, (unsigned long __user *) uptr);
    623}
    624
    625static long clp_misc_ioctl(struct file *filp, unsigned int cmd,
    626			   unsigned long arg)
    627{
    628	struct clp_req req;
    629	void __user *argp;
    630
    631	if (cmd != CLP_SYNC)
    632		return -EINVAL;
    633
    634	argp = is_compat_task() ? compat_ptr(arg) : (void __user *) arg;
    635	if (copy_from_user(&req, argp, sizeof(req)))
    636		return -EFAULT;
    637	if (req.r != 0)
    638		return -EINVAL;
    639	return req.c ? clp_immediate_command(&req) : clp_normal_command(&req);
    640}
    641
    642static int clp_misc_release(struct inode *inode, struct file *filp)
    643{
    644	return 0;
    645}
    646
    647static const struct file_operations clp_misc_fops = {
    648	.owner = THIS_MODULE,
    649	.open = nonseekable_open,
    650	.release = clp_misc_release,
    651	.unlocked_ioctl = clp_misc_ioctl,
    652	.compat_ioctl = clp_misc_ioctl,
    653	.llseek = no_llseek,
    654};
    655
    656static struct miscdevice clp_misc_device = {
    657	.minor = MISC_DYNAMIC_MINOR,
    658	.name = "clp",
    659	.fops = &clp_misc_fops,
    660};
    661
    662static int __init clp_misc_init(void)
    663{
    664	return misc_register(&clp_misc_device);
    665}
    666
    667device_initcall(clp_misc_init);