2 * SHPCHPRM Legacy: PHP Resource Manager for Non-ACPI/Legacy platform
4 * Copyright (C) 1995,2001 Compaq Computer Corporation
5 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
6 * Copyright (C) 2001 IBM Corp.
7 * Copyright (C) 2003-2004 Intel Corporation
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or (at
14 * your option) any later version.
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
19 * NON INFRINGEMENT. See the GNU General Public License for more
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 * Send feedback to <greg@kroah.com>,<dely.l.sy@intel.com>
30 #include <linux/config.h>
31 #include <linux/module.h>
32 #include <linux/kernel.h>
33 #include <linux/types.h>
34 #include <linux/pci.h>
35 #include <linux/init.h>
36 #include <asm/uaccess.h>
38 #include <asm/iosapic.h>
42 #include "shpchprm_legacy.h"
44 static void __iomem
*shpchp_rom_start
;
45 static u16 unused_IRQ
;
47 void shpchprm_cleanup(void)
50 iounmap(shpchp_rom_start
);
53 int shpchprm_print_pirt(void)
58 int shpchprm_get_physical_slot_number(struct controller
*ctrl
, u32
*sun
, u8 busnum
, u8 devnum
)
60 int offset
= devnum
- ctrl
->slot_device_offset
;
62 *sun
= (u8
) (ctrl
->first_slot
+ ctrl
->slot_num_inc
* offset
);
66 /* Find the Hot Plug Resource Table in the specified region of memory */
67 static void __iomem
*detect_HRT_floating_pointer(void __iomem
*begin
, void __iomem
*end
)
71 u8 temp1
, temp2
, temp3
, temp4
;
74 endp
= (end
- sizeof(struct hrt
) + 1);
76 for (fp
= begin
; fp
<= endp
; fp
+= 16) {
77 temp1
= readb(fp
+ SIG0
);
78 temp2
= readb(fp
+ SIG1
);
79 temp3
= readb(fp
+ SIG2
);
80 temp4
= readb(fp
+ SIG3
);
81 if (temp1
== '$' && temp2
== 'H' && temp3
== 'R' && temp4
== 'T') {
90 dbg("Discovered Hotplug Resource Table at %p\n", fp
);
95 * shpchprm_find_available_resources
97 * Finds available memory, IO, and IRQ resources for programming
98 * devices which may be added to the system
99 * this function is for hot plug ADD!
101 * returns 0 if success
103 int shpchprm_find_available_resources(struct controller
*ctrl
)
107 void __iomem
*one_slot
;
108 struct pci_func
*func
= NULL
;
109 int i
= 10, index
= 0;
112 struct pci_resource
*mem_node
;
113 struct pci_resource
*p_mem_node
;
114 struct pci_resource
*io_node
;
115 struct pci_resource
*bus_node
;
116 void __iomem
*rom_resource_table
;
117 struct pci_bus lpci_bus
, *pci_bus
;
120 memcpy(&lpci_bus
, ctrl
->pci_bus
, sizeof(lpci_bus
));
122 rom_resource_table
= detect_HRT_floating_pointer(shpchp_rom_start
, shpchp_rom_start
+ 0xffff);
123 dbg("rom_resource_table = %p\n", rom_resource_table
);
124 if (rom_resource_table
== NULL
)
127 /* Sum all resources and setup resource maps */
128 unused_IRQ
= readl(rom_resource_table
+ UNUSED_IRQ
);
129 dbg("unused_IRQ = %x\n", unused_IRQ
);
133 if (unused_IRQ
& 1) {
134 shpchp_disk_irq
= temp
;
137 unused_IRQ
= unused_IRQ
>> 1;
141 dbg("shpchp_disk_irq= %d\n", shpchp_disk_irq
);
142 unused_IRQ
= unused_IRQ
>> 1;
146 if (unused_IRQ
& 1) {
147 shpchp_nic_irq
= temp
;
150 unused_IRQ
= unused_IRQ
>> 1;
154 dbg("shpchp_nic_irq= %d\n", shpchp_nic_irq
);
155 unused_IRQ
= readl(rom_resource_table
+ PCIIRQ
);
159 pci_read_config_byte(ctrl
->pci_dev
, PCI_INTERRUPT_LINE
, &cfgspc_irq
);
161 if (!shpchp_nic_irq
) {
162 shpchp_nic_irq
= cfgspc_irq
;
165 if (!shpchp_disk_irq
) {
166 shpchp_disk_irq
= cfgspc_irq
;
169 dbg("shpchp_disk_irq, shpchp_nic_irq= %d, %d\n", shpchp_disk_irq
, shpchp_nic_irq
);
171 one_slot
= rom_resource_table
+ sizeof(struct hrt
);
173 i
= readb(rom_resource_table
+ NUMBER_OF_ENTRIES
);
174 dbg("number_of_entries = %d\n", i
);
176 if (!readb(one_slot
+ SECONDARY_BUS
))
179 dbg("dev|IO base|length|MEMbase|length|PM base|length|PB SB MB\n");
181 while (i
&& readb(one_slot
+ SECONDARY_BUS
)) {
182 u8 dev_func
= readb(one_slot
+ DEV_FUNC
);
183 u8 primary_bus
= readb(one_slot
+ PRIMARY_BUS
);
184 u8 secondary_bus
= readb(one_slot
+ SECONDARY_BUS
);
185 u8 max_bus
= readb(one_slot
+ MAX_BUS
);
186 u16 io_base
= readw(one_slot
+ IO_BASE
);
187 u16 io_length
= readw(one_slot
+ IO_LENGTH
);
188 u16 mem_base
= readw(one_slot
+ MEM_BASE
);
189 u16 mem_length
= readw(one_slot
+ MEM_LENGTH
);
190 u16 pre_mem_base
= readw(one_slot
+ PRE_MEM_BASE
);
191 u16 pre_mem_length
= readw(one_slot
+ PRE_MEM_LENGTH
);
193 dbg("%2.2x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x |%2.2x %2.2x %2.2x\n",
194 dev_func
, io_base
, io_length
, mem_base
, mem_length
, pre_mem_base
, pre_mem_length
,
195 primary_bus
, secondary_bus
, max_bus
);
197 /* If this entry isn't for our controller's bus, ignore it */
198 if (primary_bus
!= ctrl
->slot_bus
) {
200 one_slot
+= sizeof(struct slot_rt
);
203 /* find out if this entry is for an occupied slot */
204 temp_dword
= 0xFFFFFFFF;
205 pci_bus
->number
= primary_bus
;
206 pci_bus_read_config_dword(pci_bus
, dev_func
, PCI_VENDOR_ID
, &temp_dword
);
208 dbg("temp_D_word = %x\n", temp_dword
);
210 if (temp_dword
!= 0xFFFFFFFF) {
212 func
= shpchp_slot_find(primary_bus
, dev_func
>> 3, 0);
214 while (func
&& (func
->function
!= (dev_func
& 0x07))) {
215 dbg("func = %p b:d:f(%x:%x:%x)\n", func
, primary_bus
, dev_func
>> 3, index
);
216 func
= shpchp_slot_find(primary_bus
, dev_func
>> 3, index
++);
219 /* If we can't find a match, skip this table entry */
222 one_slot
+= sizeof(struct slot_rt
);
225 /* this may not work and shouldn't be used */
226 if (secondary_bus
!= primary_bus
)
236 dbg("slot populated =%s \n", populated_slot
?"yes":"no");
238 /* If we've got a valid IO base, use it */
240 temp_ulong
= io_base
+ io_length
;
242 if ((io_base
) && (temp_ulong
<= 0x10000)) {
243 io_node
= (struct pci_resource
*) kmalloc(sizeof(struct pci_resource
), GFP_KERNEL
);
247 io_node
->base
= (ulong
)io_base
;
248 io_node
->length
= (ulong
)io_length
;
249 dbg("found io_node(base, length) = %x, %x\n", io_node
->base
, io_node
->length
);
251 if (!populated_slot
) {
252 io_node
->next
= ctrl
->io_head
;
253 ctrl
->io_head
= io_node
;
255 io_node
->next
= func
->io_head
;
256 func
->io_head
= io_node
;
260 /* If we've got a valid memory base, use it */
261 temp_ulong
= mem_base
+ mem_length
;
262 if ((mem_base
) && (temp_ulong
<= 0x10000)) {
263 mem_node
= (struct pci_resource
*) kmalloc(sizeof(struct pci_resource
), GFP_KERNEL
);
267 mem_node
->base
= (ulong
)mem_base
<< 16;
268 mem_node
->length
= (ulong
)(mem_length
<< 16);
269 dbg("found mem_node(base, length) = %x, %x\n", mem_node
->base
, mem_node
->length
);
271 if (!populated_slot
) {
272 mem_node
->next
= ctrl
->mem_head
;
273 ctrl
->mem_head
= mem_node
;
275 mem_node
->next
= func
->mem_head
;
276 func
->mem_head
= mem_node
;
281 * If we've got a valid prefetchable memory base, and
282 * the base + length isn't greater than 0xFFFF
284 temp_ulong
= pre_mem_base
+ pre_mem_length
;
285 if ((pre_mem_base
) && (temp_ulong
<= 0x10000)) {
286 p_mem_node
= (struct pci_resource
*) kmalloc(sizeof(struct pci_resource
), GFP_KERNEL
);
290 p_mem_node
->base
= (ulong
)pre_mem_base
<< 16;
291 p_mem_node
->length
= (ulong
)pre_mem_length
<< 16;
292 dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node
->base
, p_mem_node
->length
);
294 if (!populated_slot
) {
295 p_mem_node
->next
= ctrl
->p_mem_head
;
296 ctrl
->p_mem_head
= p_mem_node
;
298 p_mem_node
->next
= func
->p_mem_head
;
299 func
->p_mem_head
= p_mem_node
;
304 * If we've got a valid bus number, use it
305 * The second condition is to ignore bus numbers on
306 * populated slots that don't have PCI-PCI bridges
308 if (secondary_bus
&& (secondary_bus
!= primary_bus
)) {
309 bus_node
= (struct pci_resource
*) kmalloc(sizeof(struct pci_resource
), GFP_KERNEL
);
313 bus_node
->base
= (ulong
)secondary_bus
;
314 bus_node
->length
= (ulong
)(max_bus
- secondary_bus
+ 1);
315 dbg("found bus_node(base, length) = %x, %x\n", bus_node
->base
, bus_node
->length
);
317 if (!populated_slot
) {
318 bus_node
->next
= ctrl
->bus_head
;
319 ctrl
->bus_head
= bus_node
;
321 bus_node
->next
= func
->bus_head
;
322 func
->bus_head
= bus_node
;
327 one_slot
+= sizeof(struct slot_rt
);
330 /* If all of the following fail, we don't have any resources for hot plug add */
332 rc
&= shpchp_resource_sort_and_combine(&(ctrl
->mem_head
));
333 rc
&= shpchp_resource_sort_and_combine(&(ctrl
->p_mem_head
));
334 rc
&= shpchp_resource_sort_and_combine(&(ctrl
->io_head
));
335 rc
&= shpchp_resource_sort_and_combine(&(ctrl
->bus_head
));
340 int shpchprm_set_hpp(
341 struct controller
*ctrl
,
342 struct pci_func
*func
,
347 struct pci_bus lpci_bus
, *pci_bus
;
349 memcpy(&lpci_bus
, ctrl
->pci_bus
, sizeof(lpci_bus
));
351 pci_bus
->number
= func
->bus
;
352 devfn
= PCI_DEVFN(func
->device
, func
->function
);
354 temp_byte
= 0x40; /* hard coded value for LT */
355 if (card_type
== PCI_HEADER_TYPE_BRIDGE
) {
356 /* set subordinate Latency Timer */
357 rc
= pci_bus_write_config_byte(pci_bus
, devfn
, PCI_SEC_LATENCY_TIMER
, temp_byte
);
359 dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__
, func
->bus
,
360 func
->device
, func
->function
);
365 /* set base Latency Timer */
366 rc
= pci_bus_write_config_byte(pci_bus
, devfn
, PCI_LATENCY_TIMER
, temp_byte
);
368 dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__
, func
->bus
, func
->device
, func
->function
);
372 /* set Cache Line size */
373 temp_byte
= 0x08; /* hard coded value for CLS */
374 rc
= pci_bus_write_config_byte(pci_bus
, devfn
, PCI_CACHE_LINE_SIZE
, temp_byte
);
376 dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__
, func
->bus
, func
->device
, func
->function
);
379 /* set enable_perr */
380 /* set enable_serr */
385 void shpchprm_enable_card(
386 struct controller
*ctrl
,
387 struct pci_func
*func
,
390 u16 command
, bcommand
;
391 struct pci_bus lpci_bus
, *pci_bus
;
395 memcpy(&lpci_bus
, ctrl
->pci_bus
, sizeof(lpci_bus
));
397 pci_bus
->number
= func
->bus
;
398 devfn
= PCI_DEVFN(func
->device
, func
->function
);
400 rc
= pci_bus_read_config_word(pci_bus
, devfn
, PCI_COMMAND
, &command
);
401 command
|= PCI_COMMAND_PARITY
| PCI_COMMAND_SERR
402 | PCI_COMMAND_MASTER
| PCI_COMMAND_INVALIDATE
403 | PCI_COMMAND_IO
| PCI_COMMAND_MEMORY
;
404 rc
= pci_bus_write_config_word(pci_bus
, devfn
, PCI_COMMAND
, command
);
406 if (card_type
== PCI_HEADER_TYPE_BRIDGE
) {
407 rc
= pci_bus_read_config_word(pci_bus
, devfn
, PCI_BRIDGE_CONTROL
, &bcommand
);
408 bcommand
|= PCI_BRIDGE_CTL_PARITY
| PCI_BRIDGE_CTL_SERR
409 | PCI_BRIDGE_CTL_NO_ISA
;
410 rc
= pci_bus_write_config_word(pci_bus
, devfn
, PCI_BRIDGE_CONTROL
, bcommand
);
414 static int legacy_shpchprm_init_pci(void)
416 shpchp_rom_start
= ioremap(ROM_PHY_ADDR
, ROM_PHY_LEN
);
417 if (!shpchp_rom_start
) {
418 err("Could not ioremap memory region for ROM\n");
425 int shpchprm_init(enum php_ctlr_type ctrl_type
)
431 retval
= legacy_shpchprm_init_pci();