1 /* Copyright 2015 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 
17 #include <skiboot.h>
18 #include <chip.h>
19 #include <xscom.h>
20 #include <io.h>
21 #include <cpu.h>
22 #include <nx.h>
23 #include <vas.h>
24 #include <opal.h>
25 
nx_cfg_umac_tx_wc(u32 gcid,u64 xcfg)26 static int nx_cfg_umac_tx_wc(u32 gcid, u64 xcfg)
27 {
28 	int rc = 0;
29 	u64 cfg;
30 
31 	cfg = vas_get_wcbs_bar(gcid);
32 	if (!cfg) {
33 		prerror("NX%d: ERROR finding WC Backing store BAR\n", gcid);
34 		return -ENOMEM;
35 	}
36 
37 	/*
38 	 * NOTE: Write the entire bar address to SCOM. VAS/NX will extract
39 	 *       the relevant (NX_P9_UMAC_TX_WINDOW_CONTEXT_ADDR) bits.
40 	 *       IOW, _don't_ just write the bit field like:
41 	 *
42 	 *       cfg = SETFIELD(NX_P9_UMAC_TX_WINDOW_CONTEXT_ADDR, 0ULL, cfg);
43 	 */
44 	rc = xscom_write(gcid, xcfg, cfg);
45 
46 	if (rc)
47 		prerror("NX%d: ERROR: UMAC SEND WC BAR, %d\n", gcid, rc);
48 	else
49 		prlog(PR_DEBUG, "NX%d: UMAC SEND WC BAR, 0x%016lx, "
50 				"xcfg 0x%llx\n",
51 			gcid, (unsigned long)cfg, xcfg);
52 
53 	return rc;
54 }
55 
nx_cfg_dma_vas_mmio(u32 gcid,u64 xcfg)56 static int nx_cfg_dma_vas_mmio(u32 gcid, u64 xcfg)
57 {
58 	int rc = 0;
59 	u64 cfg;
60 
61 	cfg = vas_get_hvwc_mmio_bar(gcid);
62 	/*
63 	 * NOTE: Write the entire bar address to SCOM. VAS/NX will extract
64 	 *       the relevant (NX_P9_UMAC_VAS_MMIO_ADDR) bits. IOW, _don't_
65 	 *       just write the bit field like:
66 	 *
67 	 *	cfg = SETFIELD(NX_P9_DMA_VAS_MMIO_ADDR, 0ULL, cfg);
68 	 */
69 	rc = xscom_write(gcid, xcfg, cfg);
70 
71 	if (rc)
72 		prerror("NX%d: ERROR: DMA VAS MMIO BAR, %d\n", gcid, rc);
73 	else
74 		prlog(PR_DEBUG, "NX%d: DMA VAS MMIO BAR, 0x%016lx, xcfg 0x%llx\n",
75 			gcid, (unsigned long)cfg, xcfg);
76 
77 	return rc;
78 }
79 
nx_cfg_umac_vas_mmio(u32 gcid,u64 xcfg)80 static int nx_cfg_umac_vas_mmio(u32 gcid, u64 xcfg)
81 {
82 	int rc = 0;
83 	u64 cfg;
84 
85 	cfg = vas_get_hvwc_mmio_bar(gcid);
86 	/*
87 	 * NOTE: Write the entire bar address to SCOM. VAS/NX will extract
88 	 *       the relevant (NX_P9_UMAC_VAS_MMIO_ADDR) bits. IOW, _don't_
89 	 *	 just write the bit field like:
90 	 *
91 	 *       cfg = SETFIELD(NX_P9_UMAC_VAS_MMIO_ADDR, 0ULL, cfg);
92 	 */
93 	rc = xscom_write(gcid, xcfg, cfg);
94 
95 	if (rc)
96 		prerror("NX%d: ERROR: UMAC VAS MMIO BAR, %d\n", gcid, rc);
97 	else
98 		prlog(PR_DEBUG, "NX%d: UMAC VAS MMIO BAR, 0x%016lx, "
99 				"xcfg 0x%llx\n",
100 			gcid, (unsigned long)cfg, xcfg);
101 
102 	return rc;
103 }
104 
nx_cfg_umac_status_ctrl(u32 gcid,u64 xcfg)105 static int nx_cfg_umac_status_ctrl(u32 gcid, u64 xcfg)
106 {
107 	u64 uctrl;
108 	int rc;
109 #define CRB_ENABLE	1
110 
111 	rc = xscom_read(gcid, xcfg, &uctrl);
112 	if (rc)
113 		return rc;
114 
115 	uctrl = SETFIELD(NX_P9_UMAC_STATUS_CTRL_CRB_ENABLE, uctrl, CRB_ENABLE);
116 	rc = xscom_write(gcid, xcfg, uctrl);
117 	if (rc)
118 		prerror("NX%d: ERROR: Setting UMAC Status Control failure %d\n",
119 			gcid, rc);
120 	else
121 		prlog(PR_DEBUG, "NX%d: Setting UMAC Status Control 0x%016lx\n",
122 			gcid, (unsigned long)uctrl);
123 
124 	return rc;
125 }
126 
nx_cfg_rx_fifo(struct dt_node * node,const char * compat,const char * priority,u32 gcid,u32 pid,u32 tid,u64 umac_bar,u64 umac_notify)127 int nx_cfg_rx_fifo(struct dt_node *node, const char *compat,
128 			const char *priority, u32 gcid, u32 pid, u32 tid,
129 			u64 umac_bar, u64 umac_notify)
130 {
131 	u64 cfg;
132 	int rc, size;
133 	uint64_t fifo;
134 	u32 lpid = 0xfff; /* All 1's for 12 bits in UMAC notify match reg */
135 #define MATCH_ENABLE    1
136 
137 	fifo = (uint64_t) local_alloc(gcid, RX_FIFO_SIZE, RX_FIFO_SIZE);
138 	assert(fifo);
139 
140 	/*
141 	 * When configuring the address of the Rx FIFO into the Receive FIFO
142 	 * BAR, we should _NOT_ shift the address into bits 8:53. Instead we
143 	 * should copy the address as is and VAS/NX will extract relevant bits.
144 	 */
145 	/*
146 	 * Section 5.21 of P9 NX Workbook Version 2.42 shows Receive FIFO BAR
147 	 * 54:56 represents FIFO size
148 	 * 000 = 1KB, 8 CRBs
149 	 * 001 = 2KB, 16 CRBs
150 	 * 010 = 4KB, 32 CRBs
151 	 * 011 = 8KB, 64 CRBs
152 	 * 100 = 16KB, 128 CRBs
153 	 * 101 = 32KB, 256 CRBs
154 	 * 110 = 111 reserved
155 	 */
156 	size = RX_FIFO_SIZE / 1024;
157 	cfg = SETFIELD(NX_P9_RX_FIFO_BAR_SIZE, fifo, ilog2(size));
158 
159 	rc = xscom_write(gcid, umac_bar, cfg);
160 	if (rc) {
161 		prerror("NX%d: ERROR: Setting UMAC FIFO bar failure %d\n",
162 			gcid, rc);
163 		return rc;
164 	} else
165 		prlog(PR_DEBUG, "NX%d: Setting UMAC FIFO bar 0x%016lx\n",
166 			gcid, (unsigned long)cfg);
167 
168 	rc = xscom_read(gcid, umac_notify, &cfg);
169 	if (rc)
170 		return rc;
171 
172 	/*
173 	 * VAS issues asb_notify with the unique ID to identify the target
174 	 * co-processor/engine. Logical partition ID (lpid), process ID (pid),
175 	 * and thread ID (tid) combination is used to define the unique ID
176 	 * in the system. Export these values in device-tree such that the
177 	 * driver configure RxFIFO with VAS. Set these values in RxFIFO notify
178 	 * match register for each engine which compares the ID with each
179 	 * request.
180 	 * To define unique indentification, 0xfff (1's for 12 bits),
181 	 * co-processor type, and counter within coprocessor type are used
182 	 * for lpid, pid, and tid respectively.
183 	 */
184 	cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_LPID, cfg, lpid);
185 	cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_PID, cfg, pid);
186 	cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_TID, cfg, tid);
187 	cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_MATCH_ENABLE, cfg,
188 			MATCH_ENABLE);
189 
190 	rc = xscom_write(gcid, umac_notify, cfg);
191 	if (rc) {
192 		prerror("NX%d: ERROR: Setting UMAC notify match failure %d\n",
193 			gcid, rc);
194 		return rc;
195 	} else
196 		prlog(PR_DEBUG, "NX%d: Setting UMAC notify match 0x%016lx\n",
197 				gcid, (unsigned long)cfg);
198 
199 	dt_add_property_string(node, "compatible", compat);
200 	dt_add_property_string(node, "priority", priority);
201 	dt_add_property_u64(node, "rx-fifo-address", fifo);
202 	dt_add_property_cells(node, "rx-fifo-size", RX_FIFO_SIZE);
203 	dt_add_property_cells(node, "lpid", lpid);
204 	dt_add_property_cells(node, "pid", pid);
205 	dt_add_property_cells(node, "tid", tid);
206 
207 	return 0;
208 }
209 
nx_init_fifo_ctrl(u32 gcid,u64 fifo_ctrl)210 static int nx_init_fifo_ctrl(u32 gcid, u64 fifo_ctrl)
211 {
212 	u64 cfg;
213 	int rc = 0;
214 
215 	rc = xscom_read(gcid, fifo_ctrl, &cfg);
216 	if (rc)
217 		return rc;
218 
219 	cfg = SETFIELD(NX_P9_RX_FIFO_CTRL_READ_OFFSET, cfg, 0);
220 	cfg = SETFIELD(NX_P9_RX_FIFO_CTRL_QUEUED, cfg, 0);
221 
222 	rc = xscom_write(gcid, fifo_ctrl, cfg);
223 
224 	return rc;
225 }
226 
227 
opal_nx_coproc_init(u32 gcid,u32 ct)228 static int opal_nx_coproc_init(u32 gcid, u32 ct)
229 {
230 	struct proc_chip *chip;
231 	u64 fifo, fifo_hi;
232 	u32 nx_base;
233 	int rc;
234 
235 	if (proc_gen < proc_gen_p9)
236 		return OPAL_UNSUPPORTED;
237 
238 	chip =  get_chip(gcid);
239 	if (!chip)
240 		return OPAL_PARAMETER;
241 
242 	nx_base =  chip->nx_base;
243 	if (!nx_base)
244 		return OPAL_PARAMETER;
245 
246 	switch (ct) {
247 	case NX_CT_842:
248 		fifo_hi = nx_base + NX_P9_842_HIGH_PRI_RX_FIFO_CTRL;
249 		fifo = nx_base + NX_P9_842_NORMAL_PRI_RX_FIFO_CTRL;
250 		break;
251 	case NX_CT_GZIP:
252 		fifo_hi = nx_base + NX_P9_GZIP_HIGH_PRI_RX_FIFO_CTRL;
253 		fifo = nx_base + NX_P9_GZIP_NORMAL_PRI_RX_FIFO_CTRL;
254 		break;
255 	default:
256 		prlog(PR_EMERG, "OPAL: Unknown NX coprocessor type\n");
257 		return OPAL_PARAMETER;
258 	}
259 
260 	rc  = nx_init_fifo_ctrl(gcid, fifo_hi);
261 
262 	if (!rc)
263 		rc  = nx_init_fifo_ctrl(gcid, fifo);
264 
265 	return rc;
266 }
267 
268 opal_call(OPAL_NX_COPROC_INIT, opal_nx_coproc_init, 2);
269 
nx_create_compress_node(struct dt_node * node)270 void nx_create_compress_node(struct dt_node *node)
271 {
272 	u32 gcid, pb_base;
273 	struct proc_chip *chip;
274 	int rc;
275 
276 	gcid = dt_get_chip_id(node);
277 	pb_base = dt_get_address(node, 0, NULL);
278 
279 	chip = get_chip(gcid);
280 	chip->nx_base =  pb_base;
281 
282 	prlog(PR_INFO, "NX%d: 842 at 0x%x\n", gcid, pb_base);
283 
284 	if (dt_node_is_compatible(node, "ibm,power9-nx")) {
285 		u64 cfg_mmio, cfg_txwc, cfg_uctrl, cfg_dma;
286 
287 		prlog(PR_DEBUG, "Found ibm,power9-nx\n");
288 		cfg_mmio = pb_base + NX_P9_UMAC_VAS_MMIO_BAR;
289 		cfg_dma = pb_base + NX_P9_DMA_VAS_MMIO_BAR;
290 		cfg_txwc = pb_base + NX_P9_UMAC_TX_WINDOW_CONTEXT_BAR;
291 		cfg_uctrl = pb_base + NX_P9_UMAC_STATUS_CTRL;
292 
293 		rc = nx_cfg_umac_vas_mmio(gcid, cfg_mmio);
294 		if (rc)
295 			return;
296 
297 		rc = nx_cfg_dma_vas_mmio(gcid, cfg_dma);
298 		if (rc)
299 			return;
300 
301 		rc = nx_cfg_umac_tx_wc(gcid, cfg_txwc);
302 		if (rc)
303 			return;
304 
305 		rc = nx_cfg_umac_status_ctrl(gcid, cfg_uctrl);
306 		if (rc)
307 			return;
308 
309 		p9_nx_enable_842(node, gcid, pb_base);
310 		p9_nx_enable_gzip(node, gcid, pb_base);
311 	} else
312 		nx_enable_842(node, gcid, pb_base);
313 }
314