Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
1ce0a37a
Commit
1ce0a37a
authored
May 27, 2003
by
Paul Mackerras
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
PPC32: Re-open I/O windows on PCI-PCI bridges, needed for some powermacs.
parent
bfc1ce37
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
226 additions
and
0 deletions
+226
-0
arch/ppc/kernel/pci.c
arch/ppc/kernel/pci.c
+226
-0
No files found.
arch/ppc/kernel/pci.c
View file @
1ce0a37a
...
@@ -44,6 +44,7 @@ static void pcibios_fixup_resources(struct pci_dev* dev);
...
@@ -44,6 +44,7 @@ static void pcibios_fixup_resources(struct pci_dev* dev);
static
void
fixup_broken_pcnet32
(
struct
pci_dev
*
dev
);
static
void
fixup_broken_pcnet32
(
struct
pci_dev
*
dev
);
static
int
reparent_resources
(
struct
resource
*
parent
,
struct
resource
*
res
);
static
int
reparent_resources
(
struct
resource
*
parent
,
struct
resource
*
res
);
static
void
fixup_rev1_53c810
(
struct
pci_dev
*
dev
);
static
void
fixup_rev1_53c810
(
struct
pci_dev
*
dev
);
static
void
fixup_cpc710_pci64
(
struct
pci_dev
*
dev
);
#ifdef CONFIG_ALL_PPC
#ifdef CONFIG_ALL_PPC
static
void
pcibios_fixup_cardbus
(
struct
pci_dev
*
dev
);
static
void
pcibios_fixup_cardbus
(
struct
pci_dev
*
dev
);
static
u8
*
pci_to_OF_bus_map
;
static
u8
*
pci_to_OF_bus_map
;
...
@@ -62,6 +63,7 @@ static int pci_bus_count;
...
@@ -62,6 +63,7 @@ static int pci_bus_count;
struct
pci_fixup
pcibios_fixups
[]
=
{
struct
pci_fixup
pcibios_fixups
[]
=
{
{
PCI_FIXUP_HEADER
,
PCI_VENDOR_ID_TRIDENT
,
PCI_ANY_ID
,
fixup_broken_pcnet32
},
{
PCI_FIXUP_HEADER
,
PCI_VENDOR_ID_TRIDENT
,
PCI_ANY_ID
,
fixup_broken_pcnet32
},
{
PCI_FIXUP_HEADER
,
PCI_VENDOR_ID_NCR
,
PCI_DEVICE_ID_NCR_53C810
,
fixup_rev1_53c810
},
{
PCI_FIXUP_HEADER
,
PCI_VENDOR_ID_NCR
,
PCI_DEVICE_ID_NCR_53C810
,
fixup_rev1_53c810
},
{
PCI_FIXUP_HEADER
,
PCI_VENDOR_ID_IBM
,
PCI_DEVICE_ID_IBM_CPC710_PCI64
,
fixup_cpc710_pci64
},
{
PCI_FIXUP_HEADER
,
PCI_ANY_ID
,
PCI_ANY_ID
,
pcibios_fixup_resources
},
{
PCI_FIXUP_HEADER
,
PCI_ANY_ID
,
PCI_ANY_ID
,
pcibios_fixup_resources
},
#ifdef CONFIG_ALL_PPC
#ifdef CONFIG_ALL_PPC
/* We should add per-machine fixup support in xxx_setup.c or xxx_pci.c */
/* We should add per-machine fixup support in xxx_setup.c or xxx_pci.c */
...
@@ -93,6 +95,18 @@ fixup_broken_pcnet32(struct pci_dev* dev)
...
@@ -93,6 +95,18 @@ fixup_broken_pcnet32(struct pci_dev* dev)
}
}
}
}
static
void
fixup_cpc710_pci64
(
struct
pci_dev
*
dev
)
{
/* Hide the PCI64 BARs from the kernel as their content doesn't
* fit well in the resource management
*/
dev
->
resource
[
0
].
start
=
dev
->
resource
[
0
].
end
=
0
;
dev
->
resource
[
0
].
flags
=
0
;
dev
->
resource
[
1
].
start
=
dev
->
resource
[
1
].
end
=
0
;
dev
->
resource
[
1
].
flags
=
0
;
}
static
void
static
void
pcibios_fixup_resources
(
struct
pci_dev
*
dev
)
pcibios_fixup_resources
(
struct
pci_dev
*
dev
)
{
{
...
@@ -1012,6 +1026,215 @@ pci_create_OF_bus_map(void)
...
@@ -1012,6 +1026,215 @@ pci_create_OF_bus_map(void)
prom_add_property
(
find_path_device
(
"/"
),
of_prop
);
prom_add_property
(
find_path_device
(
"/"
),
of_prop
);
}
}
}
}
/*
* This set of routines checks for PCI<->PCI bridges that have closed
* IO resources and have child devices. It tries to re-open an IO
* window on them.
*
* This is a _temporary_ fix to workaround a problem with Apple's OF
* closing IO windows on P2P bridges when the OF drivers of cards
* below this bridge don't claim any IO range (typically ATI or
* Adaptec).
*
* A more complete fix would be to use drivers/pci/setup-bus.c, which
* involves a working pcibios_fixup_pbus_ranges(), some more care about
* ordering when creating the host bus resources, and maybe a few more
* minor tweaks
*/
/* Initialize bridges with base/limit values we have collected */
static
void
__init
do_update_p2p_io_resource
(
struct
pci_bus
*
bus
,
int
enable_vga
)
{
struct
pci_dev
*
bridge
=
bus
->
self
;
struct
pci_controller
*
hose
=
(
struct
pci_controller
*
)
bridge
->
sysdata
;
u32
l
;
u16
w
;
struct
resource
res
;
res
=
*
(
bus
->
resource
[
0
]);
DBG
(
"Remapping Bus %d, bridge: %s
\n
"
,
bus
->
number
,
bridge
->
name
);
res
.
start
-=
((
unsigned
long
)
hose
->
io_base_virt
-
isa_io_base
);
res
.
end
-=
((
unsigned
long
)
hose
->
io_base_virt
-
isa_io_base
);
DBG
(
" IO window: %08lx-%08lx
\n
"
,
res
.
start
,
res
.
end
);
/* Set up the top and bottom of the PCI I/O segment for this bus. */
pci_read_config_dword
(
bridge
,
PCI_IO_BASE
,
&
l
);
l
&=
0xffff000f
;
l
|=
(
res
.
start
>>
8
)
&
0x00f0
;
l
|=
res
.
end
&
0xf000
;
pci_write_config_dword
(
bridge
,
PCI_IO_BASE
,
l
);
if
((
l
&
PCI_IO_RANGE_TYPE_MASK
)
==
PCI_IO_RANGE_TYPE_32
)
{
l
=
(
res
.
start
>>
16
)
|
(
res
.
end
&
0xffff0000
);
pci_write_config_dword
(
bridge
,
PCI_IO_BASE_UPPER16
,
l
);
}
pci_read_config_word
(
bridge
,
PCI_COMMAND
,
&
w
);
w
|=
PCI_COMMAND_IO
;
pci_write_config_word
(
bridge
,
PCI_COMMAND
,
w
);
#if 0 /* Enabling this causes XFree 4.2.0 to hang during PCI probe */
if (enable_vga) {
pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &w);
w |= PCI_BRIDGE_CTL_VGA;
pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, w);
}
#endif
}
/* This function is pretty basic and actually quite broken for the
* general case, it's enough for us right now though. It's supposed
* to tell us if we need to open an IO range at all or not and what
* size.
*/
static
int
__init
check_for_io_childs
(
struct
pci_bus
*
bus
,
struct
resource
*
res
,
int
*
found_vga
)
{
struct
list_head
*
ln
;
int
i
;
int
rc
=
0
;
#define push_end(res, size) do { unsigned long __sz = (size) ; \
res->end = ((res->end + __sz) / (__sz + 1)) * (__sz + 1) + __sz; \
} while (0)
for
(
ln
=
bus
->
devices
.
next
;
ln
!=
&
bus
->
devices
;
ln
=
ln
->
next
)
{
struct
pci_dev
*
dev
=
pci_dev_b
(
ln
);
u16
class
=
dev
->
class
>>
8
;
if
(
class
==
PCI_CLASS_DISPLAY_VGA
||
class
==
PCI_CLASS_NOT_DEFINED_VGA
)
*
found_vga
=
1
;
if
(
class
>>
8
==
PCI_BASE_CLASS_BRIDGE
&&
dev
->
subordinate
)
rc
|=
check_for_io_childs
(
dev
->
subordinate
,
res
,
found_vga
);
if
(
class
==
PCI_CLASS_BRIDGE_CARDBUS
)
push_end
(
res
,
0xfff
);
for
(
i
=
0
;
i
<
PCI_NUM_RESOURCES
;
i
++
)
{
struct
resource
*
r
;
unsigned
long
r_size
;
if
(
dev
->
class
>>
8
==
PCI_CLASS_BRIDGE_PCI
&&
i
>=
PCI_BRIDGE_RESOURCES
)
continue
;
r
=
&
dev
->
resource
[
i
];
r_size
=
r
->
end
-
r
->
start
;
if
(
r_size
<
0xfff
)
r_size
=
0xfff
;
if
(
r
->
flags
&
IORESOURCE_IO
&&
(
r_size
)
!=
0
)
{
rc
=
1
;
push_end
(
res
,
r_size
);
}
}
}
return
rc
;
}
/* Here we scan all P2P bridges of a given level that have a closed
* IO window. Note that the test for the presence of a VGA card should
* be improved to take into account already configured P2P bridges,
* currently, we don't see them and might end up configuring 2 bridges
* with VGA pass through enabled
*/
static
void
__init
do_fixup_p2p_level
(
struct
pci_bus
*
bus
)
{
struct
list_head
*
ln
;
int
i
,
parent_io
;
int
has_vga
=
0
;
for
(
parent_io
=
0
;
parent_io
<
4
;
parent_io
++
)
if
(
bus
->
resource
[
parent_io
]
->
flags
&
IORESOURCE_IO
)
break
;
if
(
parent_io
>=
4
)
return
;
for
(
ln
=
bus
->
children
.
next
;
ln
!=
&
bus
->
children
;
ln
=
ln
->
next
)
{
struct
pci_bus
*
b
=
pci_bus_b
(
ln
);
struct
pci_dev
*
d
=
b
->
self
;
struct
pci_controller
*
hose
=
(
struct
pci_controller
*
)
d
->
sysdata
;
struct
resource
*
res
=
b
->
resource
[
0
];
struct
resource
tmp_res
;
unsigned
long
max
;
int
found_vga
=
0
;
memset
(
&
tmp_res
,
0
,
sizeof
(
tmp_res
));
tmp_res
.
start
=
bus
->
resource
[
parent_io
]
->
start
;
/* We don't let low addresses go through that closed P2P bridge, well,
* that may not be necessary but I feel safer that way
*/
if
(
tmp_res
.
start
==
0
)
tmp_res
.
start
=
0x1000
;
if
(
!
list_empty
(
&
b
->
devices
)
&&
res
&&
res
->
flags
==
0
&&
res
!=
bus
->
resource
[
parent_io
]
&&
(
d
->
class
>>
8
)
==
PCI_CLASS_BRIDGE_PCI
&&
check_for_io_childs
(
b
,
&
tmp_res
,
&
found_vga
))
{
u8
io_base_lo
;
printk
(
KERN_INFO
"Fixing up IO bus %s
\n
"
,
b
->
name
);
if
(
found_vga
)
{
if
(
has_vga
)
{
printk
(
KERN_WARNING
"Skipping VGA, already active"
" on bus segment
\n
"
);
found_vga
=
0
;
}
else
has_vga
=
1
;
}
pci_read_config_byte
(
d
,
PCI_IO_BASE
,
&
io_base_lo
);
if
((
io_base_lo
&
PCI_IO_RANGE_TYPE_MASK
)
==
PCI_IO_RANGE_TYPE_32
)
max
=
((
unsigned
long
)
hose
->
io_base_virt
-
isa_io_base
)
+
0xffffffff
;
else
max
=
((
unsigned
long
)
hose
->
io_base_virt
-
isa_io_base
)
+
0xffff
;
*
res
=
tmp_res
;
res
->
flags
=
IORESOURCE_IO
;
res
->
name
=
b
->
name
;
/* Find a resource in the parent where we can allocate */
for
(
i
=
0
;
i
<
4
;
i
++
)
{
struct
resource
*
r
=
bus
->
resource
[
i
];
if
(
!
r
)
continue
;
if
((
r
->
flags
&
IORESOURCE_IO
)
==
0
)
continue
;
DBG
(
"Trying to allocate from %08lx, size %08lx from parent"
" res %d: %08lx -> %08lx
\n
"
,
res
->
start
,
res
->
end
,
i
,
r
->
start
,
r
->
end
);
if
(
allocate_resource
(
r
,
res
,
res
->
end
+
1
,
res
->
start
,
max
,
res
->
end
+
1
,
NULL
,
NULL
)
<
0
)
{
DBG
(
"Failed !
\n
"
);
continue
;
}
do_update_p2p_io_resource
(
b
,
found_vga
);
break
;
}
}
do_fixup_p2p_level
(
b
);
}
}
static
void
pcibios_fixup_p2p_bridges
(
void
)
{
struct
list_head
*
ln
;
for
(
ln
=
pci_root_buses
.
next
;
ln
!=
&
pci_root_buses
;
ln
=
ln
->
next
)
{
struct
pci_bus
*
b
=
pci_bus_b
(
ln
);
do_fixup_p2p_level
(
b
);
}
}
#endif
/* CONFIG_ALL_PPC */
#endif
/* CONFIG_ALL_PPC */
static
int
__init
static
int
__init
...
@@ -1054,6 +1277,9 @@ pcibios_init(void)
...
@@ -1054,6 +1277,9 @@ pcibios_init(void)
pcibios_allocate_bus_resources
(
&
pci_root_buses
);
pcibios_allocate_bus_resources
(
&
pci_root_buses
);
pcibios_allocate_resources
(
0
);
pcibios_allocate_resources
(
0
);
pcibios_allocate_resources
(
1
);
pcibios_allocate_resources
(
1
);
#ifdef CONFIG_ALL_PPC
pcibios_fixup_p2p_bridges
();
#endif
/* CONFIG_ALL_PPC */
pcibios_assign_resources
();
pcibios_assign_resources
();
/* Call machine dependent post-init code */
/* Call machine dependent post-init code */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment