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