blob: 775112964eefcef3696bcd0048e9b9e4da5cb952 [file] [log] [blame]
Michael Holzheue657d8f2013-11-13 10:38:27 +01001/*
2 * SCLP early driver
3 *
4 * Copyright IBM Corp. 2013
5 */
6
7#define KMSG_COMPONENT "sclp_early"
8#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
9
10#include <asm/sclp.h>
11#include <asm/ipl.h>
12#include "sclp_sdias.h"
13#include "sclp.h"
14
15static __initdata char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE);
16static unsigned long sclp_hsa_size;
17
18static int __init sclp_cmd_early(sclp_cmdw_t cmd, void *sccb)
19{
20 int rc;
21
22 do {
23 rc = sclp_cmd_sync_early(cmd, sccb);
24 } while (rc == -EBUSY);
25
26 if (rc)
27 return -EIO;
28 if (((struct sccb_header *) sccb)->response_code != 0x0020)
29 return -EIO;
30 return 0;
31}
32
33static void __init sccb_init_eq_size(struct sdias_sccb *sccb)
34{
35 memset(sccb, 0, sizeof(*sccb));
36
37 sccb->hdr.length = sizeof(*sccb);
38 sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
39 sccb->evbuf.hdr.type = EVTYP_SDIAS;
40 sccb->evbuf.event_qual = SDIAS_EQ_SIZE;
41 sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
42 sccb->evbuf.event_id = 4712;
43 sccb->evbuf.dbs = 1;
44}
45
46static int __init sclp_set_event_mask(unsigned long receive_mask,
47 unsigned long send_mask)
48{
49 struct init_sccb *sccb = (void *) &sccb_early;
50
51 memset(sccb, 0, sizeof(*sccb));
52 sccb->header.length = sizeof(*sccb);
53 sccb->mask_length = sizeof(sccb_mask_t);
54 sccb->receive_mask = receive_mask;
55 sccb->send_mask = send_mask;
56 return sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_MASK, sccb);
57}
58
59static long __init sclp_hsa_size_init(void)
60{
61 struct sdias_sccb *sccb = (void *) &sccb_early;
62
63 sccb_init_eq_size(sccb);
64 if (sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_DATA, sccb))
65 return -EIO;
66 if (sccb->evbuf.blk_cnt != 0)
67 return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
68 return 0;
69}
70
71static long __init sclp_hsa_copy_wait(void)
72{
73 struct sccb_header *sccb = (void *) &sccb_early;
74
75 memset(sccb, 0, PAGE_SIZE);
76 sccb->length = PAGE_SIZE;
77 if (sclp_cmd_early(SCLP_CMDW_READ_EVENT_DATA, sccb))
78 return -EIO;
79 return (((struct sdias_sccb *) sccb)->evbuf.blk_cnt - 1) * PAGE_SIZE;
80}
81
82unsigned long sclp_get_hsa_size(void)
83{
84 return sclp_hsa_size;
85}
86
87void __init sclp_hsa_size_detect(void)
88{
89 long size;
90
91 /* First try synchronous interface (LPAR) */
92 if (sclp_set_event_mask(0, 0x40000010))
93 return;
94 size = sclp_hsa_size_init();
95 if (size < 0)
96 return;
97 if (size != 0)
98 goto out;
99 /* Then try asynchronous interface (z/VM) */
100 if (sclp_set_event_mask(0x00000010, 0x40000010))
101 return;
102 size = sclp_hsa_size_init();
103 if (size < 0)
104 return;
105 size = sclp_hsa_copy_wait();
106 if (size < 0)
107 return;
108out:
109 sclp_set_event_mask(0, 0);
110 sclp_hsa_size = size;
111}