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