aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2016-01-13 06:54:28 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2016-03-07 10:54:32 -0500
commit988b86e69ded17f0f1209fd3ef1c4c7f1567dcc1 (patch)
tree7ef6e69d88c827190cc5f66f417efc04f0d03d6f
parentbaebc70a4db86515d55ff1f226088a8e7f5821a0 (diff)
s390/pci: add ioctl interface for CLP
Provide a user space interface to issue call logical-processor instructions. Only selected CLP commands are allowed, enough to get the full overview of the installed PCI functions. Reviewed-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/clp.h27
-rw-r--r--arch/s390/include/asm/pci_clp.h30
-rw-r--r--arch/s390/include/uapi/asm/clp.h28
-rw-r--r--arch/s390/pci/pci_clp.c247
4 files changed, 293 insertions, 39 deletions
diff --git a/arch/s390/include/asm/clp.h b/arch/s390/include/asm/clp.h
index a0e71a501f7c..5687d62fb0cb 100644
--- a/arch/s390/include/asm/clp.h
+++ b/arch/s390/include/asm/clp.h
@@ -4,14 +4,23 @@
4/* CLP common request & response block size */ 4/* CLP common request & response block size */
5#define CLP_BLK_SIZE PAGE_SIZE 5#define CLP_BLK_SIZE PAGE_SIZE
6 6
7#define CLP_LPS_BASE 0
8#define CLP_LPS_PCI 2
9
7struct clp_req_hdr { 10struct clp_req_hdr {
8 u16 len; 11 u16 len;
9 u16 cmd; 12 u16 cmd;
13 u32 fmt : 4;
14 u32 reserved1 : 28;
15 u64 reserved2;
10} __packed; 16} __packed;
11 17
12struct clp_rsp_hdr { 18struct clp_rsp_hdr {
13 u16 len; 19 u16 len;
14 u16 rsp; 20 u16 rsp;
21 u32 fmt : 4;
22 u32 reserved1 : 28;
23 u64 reserved2;
15} __packed; 24} __packed;
16 25
17/* CLP Response Codes */ 26/* CLP Response Codes */
@@ -25,4 +34,22 @@ struct clp_rsp_hdr {
25#define CLP_RC_NODATA 0x0080 /* No data available */ 34#define CLP_RC_NODATA 0x0080 /* No data available */
26#define CLP_RC_FC_UNKNOWN 0x0100 /* Function code not recognized */ 35#define CLP_RC_FC_UNKNOWN 0x0100 /* Function code not recognized */
27 36
37/* Store logical-processor characteristics request */
38struct clp_req_slpc {
39 struct clp_req_hdr hdr;
40} __packed;
41
42struct clp_rsp_slpc {
43 struct clp_rsp_hdr hdr;
44 u32 reserved2[4];
45 u32 lpif[8];
46 u32 reserved3[8];
47 u32 lpic[8];
48} __packed;
49
50struct clp_req_rsp_slpc {
51 struct clp_req_slpc request;
52 struct clp_rsp_slpc response;
53} __packed;
54
28#endif 55#endif
diff --git a/arch/s390/include/asm/pci_clp.h b/arch/s390/include/asm/pci_clp.h
index dd78f92f1cce..e75c64cbcf08 100644
--- a/arch/s390/include/asm/pci_clp.h
+++ b/arch/s390/include/asm/pci_clp.h
@@ -49,9 +49,6 @@ struct clp_fh_list_entry {
49/* List PCI functions request */ 49/* List PCI functions request */
50struct clp_req_list_pci { 50struct clp_req_list_pci {
51 struct clp_req_hdr hdr; 51 struct clp_req_hdr hdr;
52 u32 fmt : 4; /* cmd request block format */
53 u32 : 28;
54 u64 reserved1;
55 u64 resume_token; 52 u64 resume_token;
56 u64 reserved2; 53 u64 reserved2;
57} __packed; 54} __packed;
@@ -59,9 +56,6 @@ struct clp_req_list_pci {
59/* List PCI functions response */ 56/* List PCI functions response */
60struct clp_rsp_list_pci { 57struct clp_rsp_list_pci {
61 struct clp_rsp_hdr hdr; 58 struct clp_rsp_hdr hdr;
62 u32 fmt : 4; /* cmd request block format */
63 u32 : 28;
64 u64 reserved1;
65 u64 resume_token; 59 u64 resume_token;
66 u32 reserved2; 60 u32 reserved2;
67 u16 max_fn; 61 u16 max_fn;
@@ -73,9 +67,6 @@ struct clp_rsp_list_pci {
73/* Query PCI function request */ 67/* Query PCI function request */
74struct clp_req_query_pci { 68struct clp_req_query_pci {
75 struct clp_req_hdr hdr; 69 struct clp_req_hdr hdr;
76 u32 fmt : 4; /* cmd request block format */
77 u32 : 28;
78 u64 reserved1;
79 u32 fh; /* function handle */ 70 u32 fh; /* function handle */
80 u32 reserved2; 71 u32 reserved2;
81 u64 reserved3; 72 u64 reserved3;
@@ -84,9 +75,6 @@ struct clp_req_query_pci {
84/* Query PCI function response */ 75/* Query PCI function response */
85struct clp_rsp_query_pci { 76struct clp_rsp_query_pci {
86 struct clp_rsp_hdr hdr; 77 struct clp_rsp_hdr hdr;
87 u32 fmt : 4; /* cmd request block format */
88 u32 : 28;
89 u64 : 64;
90 u16 vfn; /* virtual fn number */ 78 u16 vfn; /* virtual fn number */
91 u16 : 7; 79 u16 : 7;
92 u16 util_str_avail : 1; /* utility string available? */ 80 u16 util_str_avail : 1; /* utility string available? */
@@ -108,21 +96,15 @@ struct clp_rsp_query_pci {
108/* Query PCI function group request */ 96/* Query PCI function group request */
109struct clp_req_query_pci_grp { 97struct clp_req_query_pci_grp {
110 struct clp_req_hdr hdr; 98 struct clp_req_hdr hdr;
111 u32 fmt : 4; /* cmd request block format */ 99 u32 reserved2 : 24;
112 u32 : 28;
113 u64 reserved1;
114 u32 : 24;
115 u32 pfgid : 8; /* function group id */ 100 u32 pfgid : 8; /* function group id */
116 u32 reserved2; 101 u32 reserved3;
117 u64 reserved3; 102 u64 reserved4;
118} __packed; 103} __packed;
119 104
120/* Query PCI function group response */ 105/* Query PCI function group response */
121struct clp_rsp_query_pci_grp { 106struct clp_rsp_query_pci_grp {
122 struct clp_rsp_hdr hdr; 107 struct clp_rsp_hdr hdr;
123 u32 fmt : 4; /* cmd request block format */
124 u32 : 28;
125 u64 reserved1;
126 u16 : 4; 108 u16 : 4;
127 u16 noi : 12; /* number of interrupts */ 109 u16 noi : 12; /* number of interrupts */
128 u8 version; 110 u8 version;
@@ -141,9 +123,6 @@ struct clp_rsp_query_pci_grp {
141/* Set PCI function request */ 123/* Set PCI function request */
142struct clp_req_set_pci { 124struct clp_req_set_pci {
143 struct clp_req_hdr hdr; 125 struct clp_req_hdr hdr;
144 u32 fmt : 4; /* cmd request block format */
145 u32 : 28;
146 u64 reserved1;
147 u32 fh; /* function handle */ 126 u32 fh; /* function handle */
148 u16 reserved2; 127 u16 reserved2;
149 u8 oc; /* operation controls */ 128 u8 oc; /* operation controls */
@@ -154,9 +133,6 @@ struct clp_req_set_pci {
154/* Set PCI function response */ 133/* Set PCI function response */
155struct clp_rsp_set_pci { 134struct clp_rsp_set_pci {
156 struct clp_rsp_hdr hdr; 135 struct clp_rsp_hdr hdr;
157 u32 fmt : 4; /* cmd request block format */
158 u32 : 28;
159 u64 reserved1;
160 u32 fh; /* function handle */ 136 u32 fh; /* function handle */
161 u32 reserved3; 137 u32 reserved3;
162 u64 reserved4; 138 u64 reserved4;
diff --git a/arch/s390/include/uapi/asm/clp.h b/arch/s390/include/uapi/asm/clp.h
new file mode 100644
index 000000000000..ab72d9d24373
--- /dev/null
+++ b/arch/s390/include/uapi/asm/clp.h
@@ -0,0 +1,28 @@
1/*
2 * ioctl interface for /dev/clp
3 *
4 * Copyright IBM Corp. 2016
5 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
6 */
7
8#ifndef _ASM_CLP_H
9#define _ASM_CLP_H
10
11#include <linux/types.h>
12#include <linux/ioctl.h>
13
14struct clp_req {
15 unsigned int c : 1;
16 unsigned int r : 1;
17 unsigned int lps : 6;
18 unsigned int cmd : 8;
19 unsigned int : 16;
20 unsigned int reserved;
21 __u64 data_p;
22};
23
24#define CLP_IOCTL_MAGIC 'c'
25
26#define CLP_SYNC _IOWR(CLP_IOCTL_MAGIC, 0xC1, struct clp_req)
27
28#endif
diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c
index d6e411ed8b1f..21591ddb4c1f 100644
--- a/arch/s390/pci/pci_clp.c
+++ b/arch/s390/pci/pci_clp.c
@@ -8,13 +8,19 @@
8#define KMSG_COMPONENT "zpci" 8#define KMSG_COMPONENT "zpci"
9#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 9#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
10 10
11#include <linux/compat.h>
11#include <linux/kernel.h> 12#include <linux/kernel.h>
13#include <linux/miscdevice.h>
12#include <linux/slab.h> 14#include <linux/slab.h>
13#include <linux/err.h> 15#include <linux/err.h>
14#include <linux/delay.h> 16#include <linux/delay.h>
15#include <linux/pci.h> 17#include <linux/pci.h>
18#include <linux/uaccess.h>
16#include <asm/pci_debug.h> 19#include <asm/pci_debug.h>
17#include <asm/pci_clp.h> 20#include <asm/pci_clp.h>
21#include <asm/compat.h>
22#include <asm/clp.h>
23#include <uapi/asm/clp.h>
18 24
19static inline void zpci_err_clp(unsigned int rsp, int rc) 25static inline void zpci_err_clp(unsigned int rsp, int rc)
20{ 26{
@@ -27,21 +33,43 @@ static inline void zpci_err_clp(unsigned int rsp, int rc)
27} 33}
28 34
29/* 35/*
30 * Call Logical Processor 36 * Call Logical Processor with c=1, lps=0 and command 1
31 * Retry logic is handled by the caller. 37 * to get the bit mask of installed logical processors
32 */ 38 */
33static inline u8 clp_instr(void *data) 39static inline int clp_get_ilp(unsigned long *ilp)
40{
41 unsigned long mask;
42 int cc = 3;
43
44 asm volatile (
45 " .insn rrf,0xb9a00000,%[mask],%[cmd],8,0\n"
46 "0: ipm %[cc]\n"
47 " srl %[cc],28\n"
48 "1:\n"
49 EX_TABLE(0b, 1b)
50 : [cc] "+d" (cc), [mask] "=d" (mask) : [cmd] "a" (1)
51 : "cc");
52 *ilp = mask;
53 return cc;
54}
55
56/*
57 * Call Logical Processor with c=0, the give constant lps and an lpcb request.
58 */
59static inline int clp_req(void *data, unsigned int lps)
34{ 60{
35 struct { u8 _[CLP_BLK_SIZE]; } *req = data; 61 struct { u8 _[CLP_BLK_SIZE]; } *req = data;
36 u64 ignored; 62 u64 ignored;
37 u8 cc; 63 int cc = 3;
38 64
39 asm volatile ( 65 asm volatile (
40 " .insn rrf,0xb9a00000,%[ign],%[req],0x0,0x2\n" 66 " .insn rrf,0xb9a00000,%[ign],%[req],0,%[lps]\n"
41 " ipm %[cc]\n" 67 "0: ipm %[cc]\n"
42 " srl %[cc],28\n" 68 " srl %[cc],28\n"
43 : [cc] "=d" (cc), [ign] "=d" (ignored), "+m" (*req) 69 "1:\n"
44 : [req] "a" (req) 70 EX_TABLE(0b, 1b)
71 : [cc] "+d" (cc), [ign] "=d" (ignored), "+m" (*req)
72 : [req] "a" (req), [lps] "i" (lps)
45 : "cc"); 73 : "cc");
46 return cc; 74 return cc;
47} 75}
@@ -90,7 +118,7 @@ static int clp_query_pci_fngrp(struct zpci_dev *zdev, u8 pfgid)
90 rrb->response.hdr.len = sizeof(rrb->response); 118 rrb->response.hdr.len = sizeof(rrb->response);
91 rrb->request.pfgid = pfgid; 119 rrb->request.pfgid = pfgid;
92 120
93 rc = clp_instr(rrb); 121 rc = clp_req(rrb, CLP_LPS_PCI);
94 if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) 122 if (!rc && rrb->response.hdr.rsp == CLP_RC_OK)
95 clp_store_query_pci_fngrp(zdev, &rrb->response); 123 clp_store_query_pci_fngrp(zdev, &rrb->response);
96 else { 124 else {
@@ -143,7 +171,7 @@ static int clp_query_pci_fn(struct zpci_dev *zdev, u32 fh)
143 rrb->response.hdr.len = sizeof(rrb->response); 171 rrb->response.hdr.len = sizeof(rrb->response);
144 rrb->request.fh = fh; 172 rrb->request.fh = fh;
145 173
146 rc = clp_instr(rrb); 174 rc = clp_req(rrb, CLP_LPS_PCI);
147 if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) { 175 if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) {
148 rc = clp_store_query_pci_fn(zdev, &rrb->response); 176 rc = clp_store_query_pci_fn(zdev, &rrb->response);
149 if (rc) 177 if (rc)
@@ -214,7 +242,7 @@ static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command)
214 rrb->request.oc = command; 242 rrb->request.oc = command;
215 rrb->request.ndas = nr_dma_as; 243 rrb->request.ndas = nr_dma_as;
216 244
217 rc = clp_instr(rrb); 245 rc = clp_req(rrb, CLP_LPS_PCI);
218 if (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY) { 246 if (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY) {
219 retries--; 247 retries--;
220 if (retries < 0) 248 if (retries < 0)
@@ -280,7 +308,7 @@ static int clp_list_pci(struct clp_req_rsp_list_pci *rrb,
280 rrb->request.resume_token = resume_token; 308 rrb->request.resume_token = resume_token;
281 309
282 /* Get PCI function handle list */ 310 /* Get PCI function handle list */
283 rc = clp_instr(rrb); 311 rc = clp_req(rrb, CLP_LPS_PCI);
284 if (rc || rrb->response.hdr.rsp != CLP_RC_OK) { 312 if (rc || rrb->response.hdr.rsp != CLP_RC_OK) {
285 zpci_err("List PCI FN:\n"); 313 zpci_err("List PCI FN:\n");
286 zpci_err_clp(rrb->response.hdr.rsp, rc); 314 zpci_err_clp(rrb->response.hdr.rsp, rc);
@@ -391,3 +419,198 @@ int clp_rescan_pci_devices_simple(void)
391 clp_free_block(rrb); 419 clp_free_block(rrb);
392 return rc; 420 return rc;
393} 421}
422
423static int clp_base_slpc(struct clp_req *req, struct clp_req_rsp_slpc *lpcb)
424{
425 unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
426
427 if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
428 lpcb->response.hdr.len > limit)
429 return -EINVAL;
430 return clp_req(lpcb, CLP_LPS_BASE) ? -EOPNOTSUPP : 0;
431}
432
433static int clp_base_command(struct clp_req *req, struct clp_req_hdr *lpcb)
434{
435 switch (lpcb->cmd) {
436 case 0x0001: /* store logical-processor characteristics */
437 return clp_base_slpc(req, (void *) lpcb);
438 default:
439 return -EINVAL;
440 }
441}
442
443static int clp_pci_slpc(struct clp_req *req, struct clp_req_rsp_slpc *lpcb)
444{
445 unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
446
447 if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
448 lpcb->response.hdr.len > limit)
449 return -EINVAL;
450 return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
451}
452
453static int clp_pci_list(struct clp_req *req, struct clp_req_rsp_list_pci *lpcb)
454{
455 unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
456
457 if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
458 lpcb->response.hdr.len > limit)
459 return -EINVAL;
460 if (lpcb->request.reserved2 != 0)
461 return -EINVAL;
462 return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
463}
464
465static int clp_pci_query(struct clp_req *req,
466 struct clp_req_rsp_query_pci *lpcb)
467{
468 unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
469
470 if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
471 lpcb->response.hdr.len > limit)
472 return -EINVAL;
473 if (lpcb->request.reserved2 != 0 || lpcb->request.reserved3 != 0)
474 return -EINVAL;
475 return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
476}
477
478static int clp_pci_query_grp(struct clp_req *req,
479 struct clp_req_rsp_query_pci_grp *lpcb)
480{
481 unsigned long limit = PAGE_SIZE - sizeof(lpcb->request);
482
483 if (lpcb->request.hdr.len != sizeof(lpcb->request) ||
484 lpcb->response.hdr.len > limit)
485 return -EINVAL;
486 if (lpcb->request.reserved2 != 0 || lpcb->request.reserved3 != 0 ||
487 lpcb->request.reserved4 != 0)
488 return -EINVAL;
489 return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0;
490}
491
492static int clp_pci_command(struct clp_req *req, struct clp_req_hdr *lpcb)
493{
494 switch (lpcb->cmd) {
495 case 0x0001: /* store logical-processor characteristics */
496 return clp_pci_slpc(req, (void *) lpcb);
497 case 0x0002: /* list PCI functions */
498 return clp_pci_list(req, (void *) lpcb);
499 case 0x0003: /* query PCI function */
500 return clp_pci_query(req, (void *) lpcb);
501 case 0x0004: /* query PCI function group */
502 return clp_pci_query_grp(req, (void *) lpcb);
503 default:
504 return -EINVAL;
505 }
506}
507
508static int clp_normal_command(struct clp_req *req)
509{
510 struct clp_req_hdr *lpcb;
511 void __user *uptr;
512 int rc;
513
514 rc = -EINVAL;
515 if (req->lps != 0 && req->lps != 2)
516 goto out;
517
518 rc = -ENOMEM;
519 lpcb = clp_alloc_block(GFP_KERNEL);
520 if (!lpcb)
521 goto out;
522
523 rc = -EFAULT;
524 uptr = (void __force __user *)(unsigned long) req->data_p;
525 if (copy_from_user(lpcb, uptr, PAGE_SIZE) != 0)
526 goto out_free;
527
528 rc = -EINVAL;
529 if (lpcb->fmt != 0 || lpcb->reserved1 != 0 || lpcb->reserved2 != 0)
530 goto out_free;
531
532 switch (req->lps) {
533 case 0:
534 rc = clp_base_command(req, lpcb);
535 break;
536 case 2:
537 rc = clp_pci_command(req, lpcb);
538 break;
539 }
540 if (rc)
541 goto out_free;
542
543 rc = -EFAULT;
544 if (copy_to_user(uptr, lpcb, PAGE_SIZE) != 0)
545 goto out_free;
546
547 rc = 0;
548
549out_free:
550 clp_free_block(lpcb);
551out:
552 return rc;
553}
554
555static int clp_immediate_command(struct clp_req *req)
556{
557 void __user *uptr;
558 unsigned long ilp;
559 int exists;
560
561 if (req->cmd > 1 || clp_get_ilp(&ilp) != 0)
562 return -EINVAL;
563
564 uptr = (void __force __user *)(unsigned long) req->data_p;
565 if (req->cmd == 0) {
566 /* Command code 0: test for a specific processor */
567 exists = test_bit_inv(req->lps, &ilp);
568 return put_user(exists, (int __user *) uptr);
569 }
570 /* Command code 1: return bit mask of installed processors */
571 return put_user(ilp, (unsigned long __user *) uptr);
572}
573
574static long clp_misc_ioctl(struct file *filp, unsigned int cmd,
575 unsigned long arg)
576{
577 struct clp_req req;
578 void __user *argp;
579
580 if (cmd != CLP_SYNC)
581 return -EINVAL;
582
583 argp = is_compat_task() ? compat_ptr(arg) : (void __user *) arg;
584 if (copy_from_user(&req, argp, sizeof(req)))
585 return -EFAULT;
586 if (req.r != 0)
587 return -EINVAL;
588 return req.c ? clp_immediate_command(&req) : clp_normal_command(&req);
589}
590
591static int clp_misc_release(struct inode *inode, struct file *filp)
592{
593 return 0;
594}
595
596static const struct file_operations clp_misc_fops = {
597 .owner = THIS_MODULE,
598 .open = nonseekable_open,
599 .release = clp_misc_release,
600 .unlocked_ioctl = clp_misc_ioctl,
601 .compat_ioctl = clp_misc_ioctl,
602 .llseek = no_llseek,
603};
604
605static struct miscdevice clp_misc_device = {
606 .minor = MISC_DYNAMIC_MINOR,
607 .name = "clp",
608 .fops = &clp_misc_fops,
609};
610
611static int __init clp_misc_init(void)
612{
613 return misc_register(&clp_misc_device);
614}
615
616device_initcall(clp_misc_init);