xref: /titanic_50/usr/src/uts/sun4u/starcat/io/fcgp2.c (revision f500b19684bd0346ac05bec02a50af07f369da1a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * fcgp2.c: Framework gp2 (Safari) fcode ops
29  */
30 #include <sys/types.h>
31 #include <sys/kmem.h>
32 #include <sys/systm.h>
33 #include <sys/pci.h>
34 #include <sys/ddi.h>
35 #include <sys/sunddi.h>
36 #include <sys/sunndi.h>
37 #include <sys/ddidmareq.h>
38 #include <sys/modctl.h>
39 #include <sys/ndi_impldefs.h>
40 #include <sys/fcode.h>
41 #include <sys/promif.h>
42 #include <sys/promimpl.h>
43 
44 static int gfc_map_in(dev_info_t *, fco_handle_t, fc_ci_t *);
45 static int gfc_map_out(dev_info_t *, fco_handle_t, fc_ci_t *);
46 static int gfc_register_fetch(dev_info_t *, fco_handle_t, fc_ci_t *);
47 static int gfc_register_store(dev_info_t *, fco_handle_t, fc_ci_t *);
48 static int gfc_claim_address(dev_info_t *, fco_handle_t, fc_ci_t *);
49 static int gfc_claim_memory(dev_info_t *, fco_handle_t, fc_ci_t *);
50 static int gfc_release_memory(dev_info_t *, fco_handle_t, fc_ci_t *);
51 static int gfc_vtop(dev_info_t *, fco_handle_t, fc_ci_t *);
52 static int gfc_master_intr(dev_info_t *, fco_handle_t, fc_ci_t *);
53 
54 static int gfc_config_child(dev_info_t *, fco_handle_t, fc_ci_t *);
55 
56 static int gfc_get_fcode_size(dev_info_t *, fco_handle_t, fc_ci_t *);
57 static int gfc_get_fcode(dev_info_t *, fco_handle_t, fc_ci_t *);
58 
59 int prom_get_fcode_size(char *);
60 int prom_get_fcode(char *, char *);
61 
62 int fcpci_unloadable;
63 int no_advisory_dma;
64 
65 #define	HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32))
66 #define	LOADDR(n)((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
67 #define	LADDR(lo, hi)    (((uint64_t)(hi) << 32) | (uint32_t)(lo))
68 #define	PCI_4GIG_LIMIT 0xFFFFFFFFUL
69 
70 
71 /*
72  * Module linkage information for the kernel.
73  */
74 static struct modlmisc modlmisc = {
75 	&mod_miscops, "FCode gp2 (safari) bus functions"
76 };
77 
78 static struct modlinkage modlinkage = {
79 	MODREV_1, (void *)&modlmisc, NULL
80 };
81 
82 int
_init(void)83 _init(void)
84 {
85 	return (mod_install(&modlinkage));
86 }
87 
88 int
_fini(void)89 _fini(void)
90 {
91 	if (fcpci_unloadable)
92 		return (mod_remove(&modlinkage));
93 	return (EBUSY);
94 }
95 
96 int
_info(struct modinfo * modinfop)97 _info(struct modinfo *modinfop)
98 {
99 	return (mod_info(&modlinkage, modinfop));
100 }
101 
102 
103 struct gfc_ops_v {
104 	char *svc_name;
105 	fc_ops_t *f;
106 };
107 
108 struct gfc_ops_v gp2_pov[] = {
109 	{	"map-in",		gfc_map_in},
110 	{	"map-out",		gfc_map_out},
111 	{	"rx@",			gfc_register_fetch},
112 	{	"rl@",			gfc_register_fetch},
113 	{	"rw@",			gfc_register_fetch},
114 	{	"rb@",			gfc_register_fetch},
115 	{	"rx!",			gfc_register_store},
116 	{	"rl!",			gfc_register_store},
117 	{	"rw!",			gfc_register_store},
118 	{	"rb!",			gfc_register_store},
119 	{	"claim-address",	gfc_claim_address},
120 	{	"master-interrupt",	gfc_master_intr},
121 	{	"claim-memory",		gfc_claim_memory},
122 	{	"release-memory",	gfc_release_memory},
123 	{	"vtop",			gfc_vtop},
124 	{	FC_CONFIG_CHILD,	gfc_config_child},
125 	{	FC_GET_FCODE_SIZE,	gfc_get_fcode_size},
126 	{	FC_GET_FCODE,		gfc_get_fcode},
127 	{	NULL,			NULL}
128 };
129 
130 struct gfc_ops_v gp2_shared_pov[] = {
131 	{	NULL,			NULL}
132 };
133 
134 static int gp2_map_phys(dev_info_t *, struct regspec *,  caddr_t *,
135     ddi_device_acc_attr_t *, ddi_acc_handle_t *);
136 static void gp2_unmap_phys(ddi_acc_handle_t *);
137 
138 fco_handle_t
gp2_fc_ops_alloc_handle(dev_info_t * ap,dev_info_t * child,void * fcode,size_t fcode_size,char * unit_address,char * my_args)139 gp2_fc_ops_alloc_handle(dev_info_t *ap, dev_info_t *child,
140     void *fcode, size_t fcode_size, char *unit_address,
141     char *my_args)
142 {
143 	fco_handle_t rp;
144 	phandle_t h;
145 
146 	rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP);
147 	rp->next_handle = fc_ops_alloc_handle(ap, child, fcode, fcode_size,
148 	    unit_address, NULL);
149 	rp->ap = ap;
150 	rp->child = child;
151 	rp->fcode = fcode;
152 	rp->fcode_size = fcode_size;
153 	rp->my_args = my_args;
154 
155 	if (unit_address) {
156 		char *buf;
157 
158 		buf = kmem_zalloc(strlen(unit_address) + 1, KM_SLEEP);
159 		(void) strcpy(buf, unit_address);
160 		rp->unit_address = buf;
161 	}
162 
163 	/*
164 	 * Add the child's nodeid to our table...
165 	 */
166 	h = ddi_get_nodeid(rp->child);
167 	fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child, h);
168 
169 	return (rp);
170 }
171 
172 void
gp2_fc_ops_free_handle(fco_handle_t rp)173 gp2_fc_ops_free_handle(fco_handle_t rp)
174 {
175 	struct fc_resource *ip, *np;
176 
177 	ASSERT(rp);
178 
179 	if (rp->next_handle)
180 		fc_ops_free_handle(rp->next_handle);
181 	if (rp->unit_address)
182 		kmem_free(rp->unit_address, strlen(rp->unit_address) + 1);
183 	if (rp->my_args != NULL)
184 		kmem_free(rp->my_args, strlen(rp->my_args) + 1);
185 
186 	/*
187 	 * Release all the resources from the resource list
188 	 */
189 	for (ip = rp->head; ip != NULL; ip = np) {
190 		np = ip->next;
191 		switch (ip->type) {
192 		case RT_MAP:
193 			FC_DEBUG1(1, CE_CONT, "gp2_fc_ops_free: "
194 			    " map handle - %p\n", ip->fc_map_handle);
195 			break;
196 		case RT_DMA:
197 			/* DMA has to be freed up at exit time */
198 			cmn_err(CE_CONT, "gfc_fc_ops_free: DMA seen!\n");
199 			break;
200 		case RT_CONTIGIOUS:
201 			FC_DEBUG2(1, CE_CONT, "gp2_fc_ops_free: "
202 			    "Free claim-memory resource 0x%lx size 0x%x\n",
203 			    ip->fc_contig_virt, ip->fc_contig_len);
204 
205 			(void) ndi_ra_free(ddi_root_node(),
206 			    (uint64_t)ip->fc_contig_virt,
207 			    ip->fc_contig_len, "gptwo-contigousmem",
208 			    NDI_RA_PASS);
209 
210 			break;
211 		default:
212 			cmn_err(CE_CONT, "gp2_fc_ops_free: "
213 			    "unknown resource type %d\n", ip->type);
214 			break;
215 		}
216 		fc_rem_resource(rp, ip);
217 		kmem_free(ip, sizeof (struct fc_resource));
218 	}
219 	kmem_free(rp, sizeof (struct fc_resource_list));
220 }
221 
222 int
gp2_fc_ops(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)223 gp2_fc_ops(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
224 {
225 	struct gfc_ops_v *pv;
226 	char *name = fc_cell2ptr(cp->svc_name);
227 
228 	ASSERT(rp);
229 
230 	/*
231 	 * First try the generic fc_ops. If the ops is a shared op,
232 	 * also call our local function.
233 	 */
234 	if (fc_ops(ap, rp->next_handle, cp) == 0) {
235 		for (pv = gp2_shared_pov; pv->svc_name != NULL; ++pv)
236 			if (strcmp(pv->svc_name, name) == 0)
237 				return (pv->f(ap, rp, cp));
238 		return (0);
239 	}
240 
241 	for (pv = gp2_pov; pv->svc_name != NULL; ++pv)
242 		if (strcmp(pv->svc_name, name) == 0)
243 			return (pv->f(ap, rp, cp));
244 
245 	FC_DEBUG1(9, CE_CONT, "gp2_fc_ops: <%s> not serviced\n", name);
246 
247 	return (-1);
248 }
249 
250 /*
251  * map-in  (phys.lo phys.hi size -- virt )
252  */
253 static int
gfc_map_in(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)254 gfc_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
255 {
256 	size_t len;
257 	int error;
258 	caddr_t virt;
259 	struct fc_resource *ip;
260 	struct regspec r;
261 	ddi_device_acc_attr_t acc;
262 	ddi_acc_handle_t h;
263 
264 	if (fc_cell2int(cp->nargs) != 3)
265 		return (fc_syntax_error(cp, "nargs must be 3"));
266 
267 	if (fc_cell2int(cp->nresults) < 1)
268 		return (fc_syntax_error(cp, "nresults must be >= 1"));
269 
270 	r.regspec_size = len = fc_cell2size(fc_arg(cp, 0));
271 	r.regspec_bustype = fc_cell2uint(fc_arg(cp, 1));
272 	r.regspec_addr = fc_cell2uint(fc_arg(cp, 2));
273 
274 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
275 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
276 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
277 
278 	FC_DEBUG3(1, CE_CONT, "gfc_map_in: attempting map in "
279 	    "address 0x%08x.%08x length %x\n", r.regspec_bustype,
280 	    r.regspec_addr, r.regspec_size);
281 
282 	error = gp2_map_phys(rp->child, &r, &virt, &acc, &h);
283 
284 	if (error)  {
285 		FC_DEBUG3(1, CE_CONT, "gfc_map_in: map in failed - "
286 		    "address 0x%08x.%08x length %x\n", r.regspec_bustype,
287 		    r.regspec_addr, r.regspec_size);
288 
289 		return (fc_priv_error(cp, "gp2 map-in failed"));
290 	}
291 
292 	FC_DEBUG1(3, CE_CONT, "gp2_map_in: returning virt %p\n", virt);
293 
294 	cp->nresults = fc_int2cell(1);
295 	fc_result(cp, 0) = fc_ptr2cell(virt);
296 
297 	/*
298 	 * Log this resource ...
299 	 */
300 	ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP);
301 	ip->type = RT_MAP;
302 	ip->fc_map_virt = virt;
303 	ip->fc_map_len = len;
304 	ip->fc_map_handle = h;
305 	fc_add_resource(rp, ip);
306 
307 	return (fc_success_op(ap, rp, cp));
308 }
309 
310 /*
311  * map-out ( virt size -- )
312  */
313 static int
gfc_map_out(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)314 gfc_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
315 {
316 	caddr_t virt;
317 	size_t len;
318 	struct fc_resource *ip;
319 
320 	if (fc_cell2int(cp->nargs) != 2)
321 		return (fc_syntax_error(cp, "nargs must be 2"));
322 
323 	virt = fc_cell2ptr(fc_arg(cp, 1));
324 
325 	len = fc_cell2size(fc_arg(cp, 0));
326 
327 	FC_DEBUG2(1, CE_CONT, "gp2_map_out: attempting map out %p %x\n",
328 	    virt, len);
329 
330 	/*
331 	 * Find if this request matches a mapping resource we set up.
332 	 */
333 	fc_lock_resource_list(rp);
334 	for (ip = rp->head; ip != NULL; ip = ip->next) {
335 		if (ip->type != RT_MAP)
336 			continue;
337 		if (ip->fc_map_virt != virt)
338 			continue;
339 		if (ip->fc_map_len == len)
340 			break;
341 	}
342 	fc_unlock_resource_list(rp);
343 
344 	if (ip == NULL)
345 		return (fc_priv_error(cp, "request doesn't match a "
346 		    "known mapping"));
347 
348 	gp2_unmap_phys(&ip->fc_map_handle);
349 
350 	/*
351 	 * remove the resource from the list and release it.
352 	 */
353 	fc_rem_resource(rp, ip);
354 	kmem_free(ip, sizeof (struct fc_resource));
355 
356 	cp->nresults = fc_int2cell(0);
357 	return (fc_success_op(ap, rp, cp));
358 }
359 
360 static int
gfc_register_fetch(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)361 gfc_register_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
362 {
363 	size_t len;
364 	caddr_t virt;
365 	int error = 0;
366 	uint64_t x;
367 	uint32_t l;
368 	uint16_t w;
369 	uint8_t b;
370 	char *name = fc_cell2ptr(cp->svc_name);
371 	struct fc_resource *ip;
372 
373 	if (fc_cell2int(cp->nargs) != 1)
374 		return (fc_syntax_error(cp, "nargs must be 1"));
375 
376 	if (fc_cell2int(cp->nresults) < 1)
377 		return (fc_syntax_error(cp, "nresults must be >= 1"));
378 
379 	virt = fc_cell2ptr(fc_arg(cp, 0));
380 
381 	/*
382 	 * Determine the access width .. we can switch on the 2nd
383 	 * character of the name which is "rx@", "rl@", "rb@" or "rw@"
384 	 */
385 	switch (*(name + 1)) {
386 	case 'x':	len = sizeof (x); break;
387 	case 'l':	len = sizeof (l); break;
388 	case 'w':	len = sizeof (w); break;
389 	case 'b':	len = sizeof (b); break;
390 	}
391 
392 	/*
393 	 * Check the alignment ...
394 	 */
395 	if (((intptr_t)virt & (len - 1)) != 0)
396 		return (fc_priv_error(cp, "unaligned access"));
397 
398 	/*
399 	 * Find if this virt is 'within' a request we know about
400 	 */
401 	fc_lock_resource_list(rp);
402 	for (ip = rp->head; ip != NULL; ip = ip->next) {
403 		if (ip->type == RT_MAP) {
404 		    if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <=
405 			((caddr_t)ip->fc_map_virt + ip->fc_map_len)))
406 				break;
407 		} else if (ip->type == RT_CONTIGIOUS) {
408 		    if ((virt >= (caddr_t)ip->fc_contig_virt) && ((virt + len)
409 			<= ((caddr_t)ip->fc_contig_virt + ip->fc_contig_len)))
410 				break;
411 		}
412 	}
413 	fc_unlock_resource_list(rp);
414 
415 	if (ip == NULL) {
416 		return (fc_priv_error(cp, "request not within a "
417 		    "known mapping or contigious adddress"));
418 	}
419 
420 	switch (len) {
421 	case sizeof (x):
422 		if (ip->type == RT_MAP)
423 		    error = ddi_peek64(rp->child,
424 			(int64_t *)virt, (int64_t *)&x);
425 		else /* RT_CONTIGIOUS */
426 		    x = *(int64_t *)virt;
427 		break;
428 	case sizeof (l):
429 		if (ip->type == RT_MAP)
430 		    error = ddi_peek32(rp->child,
431 			(int32_t *)virt, (int32_t *)&l);
432 		else /* RT_CONTIGIOUS */
433 		    l = *(int32_t *)virt;
434 		break;
435 	case sizeof (w):
436 		if (ip->type == RT_MAP)
437 		    error = ddi_peek16(rp->child,
438 			(int16_t *)virt, (int16_t *)&w);
439 		else /* RT_CONTIGIOUS */
440 		    w = *(int16_t *)virt;
441 		break;
442 	case sizeof (b):
443 		if (ip->type == RT_MAP)
444 		    error = ddi_peek8(rp->child,
445 			(int8_t *)virt, (int8_t *)&b);
446 		else /* RT_CONTIGIOUS */
447 		    b = *(int8_t *)virt;
448 		break;
449 	}
450 
451 	if (error) {
452 		FC_DEBUG2(1, CE_CONT, "gfc_register_fetch: access error "
453 		    "accessing virt %p len %d\n", virt, len);
454 		return (fc_priv_error(cp, "access error"));
455 	}
456 
457 	cp->nresults = fc_int2cell(1);
458 	switch (len) {
459 	case sizeof (x): fc_result(cp, 0) = x; break;
460 	case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break;
461 	case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break;
462 	case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break;
463 	}
464 	return (fc_success_op(ap, rp, cp));
465 }
466 
467 static int
gfc_register_store(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)468 gfc_register_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
469 {
470 	size_t len;
471 	caddr_t virt;
472 	uint64_t x;
473 	uint32_t l;
474 	uint16_t w;
475 	uint8_t b;
476 	char *name = fc_cell2ptr(cp->svc_name);
477 	struct fc_resource *ip;
478 	int error = 0;
479 
480 	if (fc_cell2int(cp->nargs) != 2)
481 		return (fc_syntax_error(cp, "nargs must be 2"));
482 
483 	virt = fc_cell2ptr(fc_arg(cp, 0));
484 
485 	/*
486 	 * Determine the access width .. we can switch on the 2nd
487 	 * character of the name which is "rx!", "rl!", "rb!" or "rw!"
488 	 */
489 	switch (*(name + 1)) {
490 	case 'x': len = sizeof (x); x = fc_arg(cp, 1); break;
491 	case 'l': len = sizeof (l); l = fc_cell2uint32_t(fc_arg(cp, 1)); break;
492 	case 'w': len = sizeof (w); w = fc_cell2uint16_t(fc_arg(cp, 1)); break;
493 	case 'b': len = sizeof (b); b = fc_cell2uint8_t(fc_arg(cp, 1)); break;
494 	}
495 
496 	/*
497 	 * Check the alignment ...
498 	 */
499 	if (((intptr_t)virt & (len - 1)) != 0)
500 		return (fc_priv_error(cp, "unaligned access"));
501 
502 	/*
503 	 * Find if this virt is 'within' a request we know about
504 	 */
505 	fc_lock_resource_list(rp);
506 	for (ip = rp->head; ip != NULL; ip = ip->next) {
507 		if (ip->type == RT_MAP) {
508 		    if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <=
509 			((caddr_t)ip->fc_map_virt + ip->fc_map_len)))
510 				break;
511 		} else if (ip->type == RT_CONTIGIOUS) {
512 		    if ((virt >= (caddr_t)ip->fc_contig_virt) && ((virt + len)
513 			<= ((caddr_t)ip->fc_contig_virt + ip->fc_contig_len)))
514 				break;
515 		}
516 	}
517 	fc_unlock_resource_list(rp);
518 
519 	if (ip == NULL)
520 		return (fc_priv_error(cp, "request not within a "
521 		    "known mapping or contigious address"));
522 
523 	switch (len) {
524 	case sizeof (x):
525 		if (ip->type == RT_MAP)
526 			error = ddi_poke64(rp->child, (int64_t *)virt, x);
527 		else if (ip->type == RT_CONTIGIOUS)
528 			*(uint64_t *)virt = x;
529 		break;
530 	case sizeof (l):
531 		if (ip->type == RT_MAP)
532 			error = ddi_poke32(rp->child, (int32_t *)virt, l);
533 		else if (ip->type == RT_CONTIGIOUS)
534 			*(uint32_t *)virt = l;
535 		break;
536 	case sizeof (w):
537 		if (ip->type == RT_MAP)
538 			error = ddi_poke16(rp->child, (int16_t *)virt, w);
539 		else if (ip->type == RT_CONTIGIOUS)
540 			*(uint16_t *)virt = w;
541 		break;
542 	case sizeof (b):
543 		if (ip->type == RT_MAP)
544 			error = ddi_poke8(rp->child, (int8_t *)virt, b);
545 		else if (ip->type == RT_CONTIGIOUS)
546 			*(uint8_t *)virt = b;
547 		break;
548 	}
549 
550 	if (error == DDI_FAILURE) {
551 		FC_DEBUG2(1, CE_CONT, "gfc_register_store: access error "
552 		    "accessing virt %p len %d\n", virt, len);
553 		return (fc_priv_error(cp, "access error"));
554 	}
555 
556 	cp->nresults = fc_int2cell(0);
557 	return (fc_success_op(ap, rp, cp));
558 }
559 
560 static int
gfc_master_intr(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)561 gfc_master_intr(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
562 {
563 	int xt, portid;
564 
565 	if (fc_cell2int(cp->nargs) != 2)
566 		return (fc_syntax_error(cp, "nargs must be 4"));
567 
568 	if (fc_cell2int(cp->nresults) < 1)
569 		return (fc_syntax_error(cp, "nresults must be >= 1"));
570 
571 	xt = fc_cell2int(fc_arg(cp, 1));
572 	portid = fc_cell2int(fc_arg(cp, 0));
573 
574 	FC_DEBUG2(1, CE_CONT, "gfc_master_intr: reset-int-xt=%x portid=%x",
575 	    xt, portid);
576 
577 	cp->nresults = fc_int2cell(1);
578 	fc_result(cp, 0) = 0;
579 
580 	return (fc_success_op(ap, rp, cp));
581 }
582 
583 /*
584  * gfc_claim_address
585  *
586  * claim-address (size.lo size.hi type align bar portid -- base.lo base.hi )
587  */
588 static int
gfc_claim_address(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)589 gfc_claim_address(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
590 {
591 	int bar, portid;
592 	uint64_t exp, slot, port, slice;
593 	uint64_t paddr;
594 
595 	if (fc_cell2int(cp->nargs) != 6)
596 		return (fc_syntax_error(cp, "nargs must be 6"));
597 
598 	if (fc_cell2int(cp->nresults) < 2)
599 		return (fc_syntax_error(cp, "nresults must be 2"));
600 
601 	bar = fc_cell2int(fc_arg(cp, 1));
602 	portid = fc_cell2int(fc_arg(cp, 0));
603 
604 	exp = portid >> 5;
605 	slot = (0x8 & portid) >> 3;
606 	port = portid & 0x1;
607 
608 	switch (bar) {
609 	case 0: /* PCI IO Bus A */
610 		paddr = (exp << 28) | (port << 26) | (slot << 27) |
611 		    ((uint64_t)0x402 << 32);
612 
613 		break;
614 	case 1: /* PCI Memory Bus A */
615 		slice = (exp * 2) + slot + 1;
616 
617 		paddr = ((uint64_t)1 << 42) | ((uint64_t)slice << 34) |
618 		    ((uint64_t)port << 33);
619 
620 		break;
621 	case 2: /* PCI IO Bus B */
622 		paddr = (exp << 28) | (port << 26) | (slot << 27) |
623 		    ((uint64_t)0x402 << 32)  | (1 << 25);
624 
625 		break;
626 	case 3: /* PCI Memory Bus B */
627 		slice = (exp * 2) + slot + 1;
628 
629 		paddr = ((uint64_t)1 << 42) | ((uint64_t)slice << 34) |
630 		    ((uint64_t)port << 33);
631 
632 		paddr |= ((uint64_t)1 << 32);
633 
634 		break;
635 	default:
636 		cmn_err(CE_WARN,
637 		    "gfc_claim_address - invalid BAR=0x%x\n", bar);
638 
639 		return (fc_syntax_error(cp, "invalid argument"));
640 	}
641 
642 	FC_DEBUG1(1, CE_CONT, "gfc_claim_address: returning 0x%lx\n", paddr);
643 
644 	cp->nresults = fc_int2cell(2);
645 	fc_result(cp, 0) = LOADDR(paddr);
646 	fc_result(cp, 1) = HIADDR(paddr);
647 
648 	return (fc_success_op(ap, rp, cp));
649 }
650 
651 /*
652  * gfc_claim_memory
653  *
654  * claim-memory ( align size vhint -- vaddr)
655  */
656 static int
gfc_claim_memory(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)657 gfc_claim_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
658 {
659 	int align, size, vhint;
660 	ndi_ra_request_t request;
661 	uint64_t answer, alen;
662 	struct fc_resource *ip;
663 
664 	if (fc_cell2int(cp->nargs) != 3)
665 		return (fc_syntax_error(cp, "nargs must be 3"));
666 
667 	if (fc_cell2int(cp->nresults) < 1)
668 		return (fc_syntax_error(cp, "nresults must be >= 1"));
669 
670 	vhint = fc_cell2int(fc_arg(cp, 2));
671 	size = fc_cell2int(fc_arg(cp, 1));
672 	align = fc_cell2int(fc_arg(cp, 0));
673 
674 	FC_DEBUG3(1, CE_CONT, "gfc_claim_memory: align=0x%x size=0x%x "
675 	    "vhint=0x%x\n", align, size, vhint);
676 
677 	if (size == 0) {
678 		cmn_err(CE_WARN, " gfc_claim_memory - unable to allocate "
679 		    "contigiuos memory of size zero\n");
680 		return (fc_priv_error(cp, "allocation error"));
681 	}
682 
683 	if (vhint) {
684 		cmn_err(CE_WARN, "gfc_claim_memory - vhint is not zero "
685 		    "vhint=0x%x - Ignoring Argument\n", vhint);
686 	}
687 
688 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
689 	request.ra_flags  = NDI_RA_ALLOC_BOUNDED;
690 	request.ra_boundbase = 0;
691 	request.ra_boundlen = 0xffffffff;
692 	request.ra_len = size;
693 	request.ra_align_mask = align - 1;
694 
695 	if (ndi_ra_alloc(ddi_root_node(), &request, &answer, &alen,
696 	    "gptwo-contigousmem", NDI_RA_PASS) != NDI_SUCCESS) {
697 		cmn_err(CE_WARN, " gfc_claim_memory - unable to allocate "
698 		    "contigiuos memory\n");
699 		return (fc_priv_error(cp, "allocation error"));
700 
701 	}
702 
703 	FC_DEBUG2(1, CE_CONT, "gfc_claim_memory: address allocated=0x%lx "
704 	    "size=0x%x\n", answer, alen);
705 
706 	cp->nresults = fc_int2cell(1);
707 	fc_result(cp, 0) = answer;
708 
709 	/*
710 	 * Log this resource ...
711 	 */
712 	ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP);
713 	ip->type = RT_CONTIGIOUS;
714 	ip->fc_contig_virt = (void *)answer;
715 	ip->fc_contig_len = size;
716 	fc_add_resource(rp, ip);
717 
718 	return (fc_success_op(ap, rp, cp));
719 }
720 
721 /*
722  * gfc_release_memory
723  *
724  * release-memory ( size vaddr -- )
725  */
726 static int
gfc_release_memory(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)727 gfc_release_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
728 {
729 	int32_t vaddr, size;
730 	struct fc_resource *ip;
731 
732 	if (fc_cell2int(cp->nargs) != 2)
733 		return (fc_syntax_error(cp, "nargs must be 2"));
734 
735 	if (fc_cell2int(cp->nresults) != 0)
736 		return (fc_syntax_error(cp, "nresults must be 0"));
737 
738 	vaddr = fc_cell2int(fc_arg(cp, 1));
739 	size = fc_cell2int(fc_arg(cp, 0));
740 
741 	FC_DEBUG2(1, CE_CONT, "gfc_release_memory: vaddr=0x%x size=0x%x\n",
742 	    vaddr, size);
743 	/*
744 	 * Find if this request matches a mapping resource we set up.
745 	 */
746 	fc_lock_resource_list(rp);
747 	for (ip = rp->head; ip != NULL; ip = ip->next) {
748 		if (ip->type != RT_CONTIGIOUS)
749 			continue;
750 		if (ip->fc_contig_virt != (void *)(uintptr_t)vaddr)
751 			continue;
752 		if (ip->fc_contig_len == size)
753 			break;
754 	}
755 	fc_unlock_resource_list(rp);
756 
757 	if (ip == NULL)
758 		return (fc_priv_error(cp, "request doesn't match a "
759 		    "known mapping"));
760 
761 	(void) ndi_ra_free(ddi_root_node(), vaddr, size,
762 	    "gptwo-contigousmem", NDI_RA_PASS);
763 
764 	/*
765 	 * remove the resource from the list and release it.
766 	 */
767 	fc_rem_resource(rp, ip);
768 	kmem_free(ip, sizeof (struct fc_resource));
769 
770 	cp->nresults = fc_int2cell(0);
771 
772 	return (fc_success_op(ap, rp, cp));
773 }
774 
775 /*
776  * gfc_vtop
777  *
778  * vtop ( vaddr -- paddr.lo paddr.hi)
779  */
780 static int
gfc_vtop(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)781 gfc_vtop(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
782 {
783 	int vaddr;
784 	uint64_t paddr;
785 	struct fc_resource *ip;
786 
787 	if (fc_cell2int(cp->nargs) != 1)
788 		return (fc_syntax_error(cp, "nargs must be 1"));
789 
790 	if (fc_cell2int(cp->nresults) >= 3)
791 		return (fc_syntax_error(cp, "nresults must be less than 2"));
792 
793 	vaddr = fc_cell2int(fc_arg(cp, 0));
794 
795 	/*
796 	 * Find if this request matches a mapping resource we set up.
797 	 */
798 	fc_lock_resource_list(rp);
799 	for (ip = rp->head; ip != NULL; ip = ip->next) {
800 		if (ip->type != RT_CONTIGIOUS)
801 			continue;
802 		if (ip->fc_contig_virt == (void *)(uintptr_t)vaddr)
803 				break;
804 	}
805 	fc_unlock_resource_list(rp);
806 
807 	if (ip == NULL)
808 		return (fc_priv_error(cp, "request doesn't match a "
809 		    "known mapping"));
810 
811 
812 	paddr = va_to_pa((void *)(uintptr_t)vaddr);
813 
814 	FC_DEBUG2(1, CE_CONT, "gfc_vtop: vaddr=0x%x paddr=0x%x\n",
815 	    vaddr, paddr);
816 
817 	cp->nresults = fc_int2cell(2);
818 
819 	fc_result(cp, 0) = paddr;
820 	fc_result(cp, 1) = 0;
821 
822 	return (fc_success_op(ap, rp, cp));
823 }
824 
825 static int
gfc_config_child(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)826 gfc_config_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
827 {
828 	fc_phandle_t h;
829 
830 	if (fc_cell2int(cp->nargs) != 0)
831 		return (fc_syntax_error(cp, "nargs must be 0"));
832 
833 	if (fc_cell2int(cp->nresults) < 1)
834 		return (fc_syntax_error(cp, "nresults must be >= 1"));
835 
836 	h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child);
837 
838 	cp->nresults = fc_int2cell(1);
839 	fc_result(cp, 0) = fc_phandle2cell(h);
840 
841 	return (fc_success_op(ap, rp, cp));
842 }
843 
844 static int
gfc_get_fcode(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)845 gfc_get_fcode(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
846 {
847 	caddr_t name_virt, fcode_virt;
848 	char *name, *fcode;
849 	int fcode_len, status;
850 
851 	if (fc_cell2int(cp->nargs) != 3)
852 		return (fc_syntax_error(cp, "nargs must be 3"));
853 
854 	if (fc_cell2int(cp->nresults) < 1)
855 		return (fc_syntax_error(cp, "nresults must be >= 1"));
856 
857 	name_virt = fc_cell2ptr(fc_arg(cp, 0));
858 
859 	fcode_virt = fc_cell2ptr(fc_arg(cp, 1));
860 
861 	fcode_len = fc_cell2int(fc_arg(cp, 2));
862 
863 	name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP);
864 
865 	if (copyinstr(fc_cell2ptr(name_virt), name,
866 	    FC_SVC_NAME_LEN - 1, NULL))  {
867 		FC_DEBUG1(1, CE_CONT, "gfc_get_fcode: "
868 		    "fault copying in drop in name %p\n", name_virt);
869 		status = 0;
870 	} else {
871 
872 		fcode = kmem_zalloc(fcode_len, KM_SLEEP);
873 
874 		if ((status = prom_get_fcode(name, fcode)) != 0) {
875 
876 			if (copyout((void *)fcode, (void *)fcode_virt,
877 			    fcode_len)) {
878 				cmn_err(CE_WARN, " gfc_get_fcode: Unable "
879 				    "to copy out fcode image\n");
880 				status = 0;
881 			}
882 		}
883 
884 		kmem_free(fcode, fcode_len);
885 	}
886 
887 	kmem_free(name, FC_SVC_NAME_LEN);
888 
889 	cp->nresults = fc_int2cell(1);
890 	fc_result(cp, 0) = status;
891 
892 	return (fc_success_op(ap, rp, cp));
893 }
894 
895 static int
gfc_get_fcode_size(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)896 gfc_get_fcode_size(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
897 {
898 	caddr_t virt;
899 	char *name;
900 	int len;
901 
902 	if (fc_cell2int(cp->nargs) != 1)
903 		return (fc_syntax_error(cp, "nargs must be 1"));
904 
905 	if (fc_cell2int(cp->nresults) < 1)
906 		return (fc_syntax_error(cp, "nresults must be >= 1"));
907 
908 	virt = fc_cell2ptr(fc_arg(cp, 0));
909 
910 	name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP);
911 
912 	if (copyinstr(fc_cell2ptr(virt), name,
913 	    FC_SVC_NAME_LEN - 1, NULL))  {
914 		FC_DEBUG1(1, CE_CONT, "gfc_get_fcode_size: "
915 		    "fault copying in drop in name %p\n", virt);
916 		len = 0;
917 	} else {
918 
919 		len = prom_get_fcode_size(name);
920 	}
921 
922 	kmem_free(name, FC_SVC_NAME_LEN);
923 
924 	cp->nresults = fc_int2cell(1);
925 	fc_result(cp, 0) = len;
926 
927 	return (fc_success_op(ap, rp, cp));
928 }
929 
930 static int
gp2_map_phys(dev_info_t * dip,struct regspec * phys_spec,caddr_t * addrp,ddi_device_acc_attr_t * accattrp,ddi_acc_handle_t * handlep)931 gp2_map_phys(dev_info_t *dip, struct regspec *phys_spec,
932 	caddr_t *addrp, ddi_device_acc_attr_t *accattrp,
933 	ddi_acc_handle_t *handlep)
934 {
935 	ddi_map_req_t mr;
936 	ddi_acc_hdl_t *hp;
937 	int result;
938 	struct regspec *ph;
939 
940 	*handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
941 	hp = impl_acc_hdl_get(*handlep);
942 	hp->ah_vers = VERS_ACCHDL;
943 	hp->ah_dip = dip;
944 	hp->ah_rnumber = 0;
945 	hp->ah_offset = 0;
946 	hp->ah_len = 0;
947 	hp->ah_acc = *accattrp;
948 	ph = kmem_zalloc(sizeof (struct regspec), KM_SLEEP);
949 	*ph = *phys_spec;
950 	hp->ah_bus_private = ph;	/* cache a copy of the reg spec */
951 
952 	mr.map_op = DDI_MO_MAP_LOCKED;
953 	mr.map_type = DDI_MT_REGSPEC;
954 	mr.map_obj.rp = (struct regspec *)phys_spec;
955 	mr.map_prot = PROT_READ | PROT_WRITE;
956 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
957 	mr.map_handlep = hp;
958 	mr.map_vers = DDI_MAP_VERSION;
959 
960 	result = ddi_map(dip, &mr, 0, 0, addrp);
961 
962 	if (result != DDI_SUCCESS) {
963 		impl_acc_hdl_free(*handlep);
964 		*handlep = (ddi_acc_handle_t)NULL;
965 	} else {
966 		hp->ah_addr = *addrp;
967 	}
968 
969 	return (result);
970 }
971 
972 static void
gp2_unmap_phys(ddi_acc_handle_t * handlep)973 gp2_unmap_phys(ddi_acc_handle_t *handlep)
974 {
975 	ddi_map_req_t mr;
976 	ddi_acc_hdl_t *hp;
977 	struct regspec_t *ph;
978 
979 	hp = impl_acc_hdl_get(*handlep);
980 	ASSERT(hp);
981 	ph = hp->ah_bus_private;
982 
983 	mr.map_op = DDI_MO_UNMAP;
984 	mr.map_type = DDI_MT_REGSPEC;
985 	mr.map_obj.rp = (struct regspec *)ph;
986 	mr.map_prot = PROT_READ | PROT_WRITE;
987 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
988 	mr.map_handlep = hp;
989 	mr.map_vers = DDI_MAP_VERSION;
990 
991 	(void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
992 		hp->ah_len, &hp->ah_addr);
993 
994 	impl_acc_hdl_free(*handlep);
995 	kmem_free(ph, sizeof (struct regspec));	/* Free the cached copy */
996 	*handlep = (ddi_acc_handle_t)NULL;
997 }
998