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.
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.
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]
22 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/types.h>
27 #include <sys/sunndi.h>
29 #include <sys/pci_impl.h>
30 #include <sys/pci_cfgspace.h>
31 #include <sys/pci_cfgspace_impl.h>
32 #include <sys/memlist.h>
33 #include <sys/bootconf.h>
37 * pci irq routing information table
40 static pci_irq_route_t
*pci_irq_routes
;
43 static int pci_bios_get_irq_routing(pci_irq_route_t
*, int, int *);
44 static void pci_get_irq_routing_table(void);
48 * Retrieve information from the bios needed for system
49 * configuration early during startup.
52 startup_pci_bios(void)
54 pci_get_irq_routing_table();
59 * Issue the bios get irq routing information table interrupt
61 * Despite the name, the information in the table is only
62 * used to derive slot names for some named pci hot-plug slots.
64 * Returns the number of irq routing table entries returned
65 * by the bios, or 0 and optionally, the number of entries required.
68 pci_bios_get_irq_routing(pci_irq_route_t
*routes
, int nroutes
, int *nneededp
)
80 * Set up irq routing header with the size and address
81 * of some useable low-memory data addresses. Initalize
82 * data area to zero, avoiding memcpy/bzero.
84 hdrp
= (uchar_t
*)BIOS_IRQ_ROUTING_HDR
;
85 bufp
= (uchar_t
*)BIOS_IRQ_ROUTING_DATA
;
87 n
= nroutes
* sizeof (pci_irq_route_t
);
88 for (i
= 0; i
< n
; i
++)
90 ((pci_irq_route_hdr_t
*)hdrp
)->pir_size
= n
;
91 ((pci_irq_route_hdr_t
*)hdrp
)->pir_addr
= (uint32_t)(uintptr_t)bufp
;
93 bzero(®s
, sizeof (regs
));
94 regs
.eax
.word
.ax
= (PCI_FUNCTION_ID
<< 8) | PCI_GET_IRQ_ROUTING
;
97 regs
.es
= FP_SEG((uint_t
)(uintptr_t)hdrp
);
98 regs
.edi
.word
.di
= FP_OFF((uint_t
)(uintptr_t)hdrp
);
100 BOP_DOINT(bootops
, 0x1a, ®s
);
102 n
= (int)(((pci_irq_route_hdr_t
*)hdrp
)->pir_size
/
103 sizeof (pci_irq_route_t
));
105 if ((regs
.eflags
& PS_C
) != 0) {
110 * Copy resulting irq routing data from low memory up to
111 * the kernel address space, avoiding memcpy as usual.
114 for (i
= 0; i
< n
* sizeof (pci_irq_route_t
); i
++)
115 ((uchar_t
*)routes
)[i
] = bufp
[i
];
123 pci_get_irq_routing_table(void)
125 pci_irq_route_t
*routes
;
126 int n
= N_PCI_IRQ_ROUTES
;
131 * Get irq routing table information.
132 * Allocate a buffer for an initial default number of entries.
133 * If the bios indicates it needs a larger buffer, try it again.
134 * Drive on if it still won't cooperate and play nice after that.
136 routes
= kmem_zalloc(n
* sizeof (pci_irq_route_t
), KM_SLEEP
);
137 nroutes
= pci_bios_get_irq_routing(routes
, n
, &nneeded
);
138 if (nroutes
== 0 && nneeded
> n
) {
139 kmem_free(routes
, n
* sizeof (pci_irq_route_t
));
140 if (nneeded
> N_PCI_IRQ_ROUTES_MAX
) {
142 "pci: unable to get IRQ routing information, "
143 "required buffer space of %d entries exceeds max\n",
148 routes
= kmem_zalloc(n
* sizeof (pci_irq_route_t
), KM_SLEEP
);
149 nroutes
= pci_bios_get_irq_routing(routes
, n
, NULL
);
152 "pci: unable to get IRQ routing information, "
153 "required buffer space for %d entries\n", n
);
154 kmem_free(routes
, n
* sizeof (pci_irq_route_t
));
159 pci_irq_routes
= routes
;
160 pci_irq_nroutes
= nroutes
;
165 * Use the results of the PCI BIOS call that returned the routing tables
166 * to build the 1275 slot-names property for the indicated bus.
167 * Results are returned in buf. Length is return value, -1 is returned on
168 * overflow and zero is returned if no data exists to build a property.
171 pci_slot_names_prop(int bus
, char *buf
, int len
)
174 uchar_t slot
[N_PCI_IRQ_ROUTES_MAX
+1];
178 ASSERT(pci_irq_nroutes
<= N_PCI_IRQ_ROUTES_MAX
);
180 if (pci_irq_nroutes
== 0)
184 for (i
= 0; i
< pci_irq_nroutes
; i
++)
186 for (i
= 0; i
< pci_irq_nroutes
; i
++) {
187 if (pci_irq_routes
[i
].pir_bus
!= bus
)
189 if (pci_irq_routes
[i
].pir_slot
!= 0) {
190 dev
= (pci_irq_routes
[i
].pir_dev
& 0xf8) >> 3;
191 slot
[dev
] = pci_irq_routes
[i
].pir_slot
;
200 if (len
< (4 + nnames
* 8))
202 *(uint32_t *)buf
= mask
;
204 for (i
= 0; i
< pci_irq_nroutes
; i
++) {
207 (void) sprintf(buf
+ plen
, "Slot%d", slot
[i
]);
208 plen
+= strlen(buf
+plen
) + 1;
211 for (; plen
% 4; plen
++)