1 /* Copyright 2013-2017 IBM Corp.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *	http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12  * implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <skiboot.h>
17 #include <io.h>
18 #include <opal.h>
19 #include <chip.h>
20 #include <xscom.h>
21 #include <capp.h>
22 
23 #define PHBERR(opal_id, chip_id, index, fmt, a...) \
24 	       prlog(PR_ERR, "PHB#%04x[%d:%d]: " fmt, \
25 		     opal_id, chip_id, \
26 		     index,  ## a)
27 
28 static struct {
29 	uint32_t			ec_level;
30 	struct capp_lid_hdr		*lid;
31 	size_t size;
32 	int load_result;
33 } capp_ucode_info = { 0, NULL, 0, false };
34 
35 #define CAPP_UCODE_MAX_SIZE 0x20000
36 
37 struct lock capi_lock = LOCK_UNLOCKED;
38 struct capp_ops capi_ops = { NULL };
39 
capp_ucode_loaded(struct proc_chip * chip,unsigned int index)40 bool capp_ucode_loaded(struct proc_chip *chip, unsigned int index)
41 {
42 	return (chip->capp_ucode_loaded & (1 << index));
43 }
44 
preload_capp_ucode(void)45 int preload_capp_ucode(void)
46 {
47 	struct dt_node *p;
48 	struct proc_chip *chip;
49 	uint32_t index;
50 	uint64_t rc;
51 	int ret;
52 
53 	p = dt_find_compatible_node(dt_root, NULL, "ibm,power8-pbcq");
54 
55 	if (!p) {
56 		p = dt_find_compatible_node(dt_root, NULL, "ibm,power9-pbcq");
57 		if (!p) {
58 			prlog(PR_INFO, "CAPI: WARNING: no compat thing found\n");
59 			return OPAL_SUCCESS;
60 		}
61 	}
62 
63 	chip = get_chip(dt_get_chip_id(p));
64 
65 	rc = xscom_read_cfam_chipid(chip->id, &index);
66 	if (rc) {
67 		prerror("CAPP: Error reading cfam chip-id\n");
68 		ret = OPAL_HARDWARE;
69 		return ret;
70 	}
71 	/* Keep ChipID and Major/Minor EC.  Mask out the Location Code. */
72 	index = index & 0xf0fff;
73 
74 	/* Assert that we're preloading */
75 	assert(capp_ucode_info.lid == NULL);
76 	capp_ucode_info.load_result = OPAL_EMPTY;
77 
78 	capp_ucode_info.ec_level = index;
79 
80 	/* Is the ucode preloaded like for BML? */
81 	if (dt_has_node_property(p, "ibm,capp-ucode", NULL)) {
82 		capp_ucode_info.lid = (struct capp_lid_hdr *)(u64)
83 			dt_prop_get_u32(p, "ibm,capp-ucode");
84 		capp_ucode_info.load_result = OPAL_SUCCESS;
85 		ret = OPAL_SUCCESS;
86 		goto end;
87 	}
88 	/* If we successfully download the ucode, we leave it around forever */
89 	capp_ucode_info.size = CAPP_UCODE_MAX_SIZE;
90 	capp_ucode_info.lid = malloc(CAPP_UCODE_MAX_SIZE);
91 	if (!capp_ucode_info.lid) {
92 		prerror("CAPP: Can't allocate space for ucode lid\n");
93 		ret = OPAL_NO_MEM;
94 		goto end;
95 	}
96 
97 	prlog(PR_INFO, "CAPI: Preloading ucode %x\n", capp_ucode_info.ec_level);
98 
99 	ret = start_preload_resource(RESOURCE_ID_CAPP, index,
100 				     capp_ucode_info.lid,
101 				     &capp_ucode_info.size);
102 
103 	if (ret != OPAL_SUCCESS) {
104 		prerror("CAPI: Failed to preload resource %d\n", ret);
105 		capp_ucode_info.load_result = ret;
106 	}
107 
108 end:
109 	return ret;
110 }
111 
capp_lid_download(void)112 static int64_t capp_lid_download(void)
113 {
114 	int64_t ret;
115 
116 	if (capp_ucode_info.load_result != OPAL_EMPTY)
117 		return capp_ucode_info.load_result;
118 
119 	capp_ucode_info.load_result = wait_for_resource_loaded(
120 		RESOURCE_ID_CAPP,
121 		capp_ucode_info.ec_level);
122 
123 	if (capp_ucode_info.load_result != OPAL_SUCCESS) {
124 		prerror("CAPP: Error loading ucode lid. index=%x\n",
125 			capp_ucode_info.ec_level);
126 		ret = OPAL_RESOURCE;
127 		free(capp_ucode_info.lid);
128 		capp_ucode_info.lid = NULL;
129 		goto end;
130 	}
131 
132 	ret = OPAL_SUCCESS;
133 end:
134 	return ret;
135 }
136 
capp_load_ucode(unsigned int chip_id,uint32_t opal_id,unsigned int index,u64 lid_eyecatcher,uint32_t reg_offset,uint64_t apc_master_addr,uint64_t apc_master_write,uint64_t snp_array_addr,uint64_t snp_array_write)137 int64_t capp_load_ucode(unsigned int chip_id, uint32_t opal_id,
138 			unsigned int index, u64 lid_eyecatcher,
139 			uint32_t reg_offset,
140 			uint64_t apc_master_addr, uint64_t apc_master_write,
141 			uint64_t snp_array_addr, uint64_t snp_array_write)
142 {
143 	struct proc_chip *chip = get_chip(chip_id);
144 	struct capp_ucode_lid *ucode;
145 	struct capp_ucode_data *data;
146 	struct capp_lid_hdr *lid;
147 	uint64_t rc, val, addr;
148 	uint32_t chunk_count, offset;
149 	int i;
150 
151 	if (capp_ucode_loaded(chip, index))
152 		return OPAL_SUCCESS;
153 
154 	rc = capp_lid_download();
155 	if (rc)
156 		return rc;
157 
158 	prlog(PR_INFO, "CHIP%i: CAPP ucode lid loaded at %p\n",
159 	      chip_id, capp_ucode_info.lid);
160 
161 	lid = capp_ucode_info.lid;
162 	/*
163 	 * If lid header is present (on FSP machines), it'll tell us where to
164 	 * find the ucode.  Otherwise this is the ucode.
165 	 */
166 	ucode = (struct capp_ucode_lid *)lid;
167 	if (be64_to_cpu(lid->eyecatcher) == lid_eyecatcher) {
168 		if (be64_to_cpu(lid->version) != 0x1) {
169 			PHBERR(opal_id, chip_id, index,
170 			       "capi ucode lid header invalid\n");
171 			return OPAL_HARDWARE;
172 		}
173 		ucode = (struct capp_ucode_lid *)
174 			((char *)ucode + be64_to_cpu(lid->ucode_offset));
175 	}
176 
177 	/* 'CAPPULID' in ASCII */
178 	if ((be64_to_cpu(ucode->eyecatcher) != 0x43415050554C4944) ||
179 	    (be64_to_cpu(ucode->version != 1))) {
180 		PHBERR(opal_id, chip_id, index,
181 		       "CAPP: ucode header invalid\n");
182 		return OPAL_HARDWARE;
183 	}
184 
185 	offset = 0;
186 	while (offset < be64_to_cpu(ucode->data_size)) {
187 		data = (struct capp_ucode_data *)
188 			((char *)&ucode->data + offset);
189 		chunk_count = be32_to_cpu(data->hdr.chunk_count);
190 		offset += sizeof(struct capp_ucode_data_hdr) + chunk_count * 8;
191 
192 		/* 'CAPPUCOD' in ASCII */
193 		if (be64_to_cpu(data->hdr.eyecatcher) != 0x4341505055434F44) {
194 			PHBERR(opal_id, chip_id, index,
195 			       "CAPP: ucode data header invalid:%i\n",
196 			       offset);
197 			return OPAL_HARDWARE;
198 		}
199 
200 		switch (data->hdr.reg) {
201 		case apc_master_cresp:
202 			xscom_write(chip_id, apc_master_addr + reg_offset,
203 				    0);
204 			addr = apc_master_write;
205 			break;
206 		case apc_master_uop_table:
207 			xscom_write(chip_id, apc_master_addr + reg_offset,
208 				    0x180ULL << 52);
209 			addr = apc_master_write;
210 			break;
211 		case snp_ttype:
212 			xscom_write(chip_id, snp_array_addr + reg_offset,
213 				    0x5000ULL << 48);
214 			addr = snp_array_write;
215 			break;
216 		case snp_uop_table:
217 			xscom_write(chip_id, snp_array_addr + reg_offset,
218 				    0x4000ULL << 48);
219 			addr = snp_array_write;
220 			break;
221 		default:
222 			continue;
223 		}
224 
225 		for (i = 0; i < chunk_count; i++) {
226 			val = be64_to_cpu(data->data[i]);
227 			xscom_write(chip_id, addr + reg_offset, val);
228 		}
229 	}
230 
231 	chip->capp_ucode_loaded |= (1 << index);
232 
233 	return OPAL_SUCCESS;
234 }
235 
capp_get_info(int chip_id,struct phb * phb,struct capp_info * info)236 int64_t capp_get_info(int chip_id, struct phb *phb, struct capp_info *info)
237 {
238 	if (capi_ops.get_capp_info)
239 		return capi_ops.get_capp_info(chip_id, phb, info);
240 
241 	return OPAL_PARAMETER;
242 }
243