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
nexedi
linux
Commits
9e09bda8
Commit
9e09bda8
authored
Dec 13, 2002
by
Dave Jones
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[AGP] Add AGP 3.0 support and I7505 chipset driver.
parent
cb3d1c3a
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
805 additions
and
0 deletions
+805
-0
drivers/char/agp/Kconfig
drivers/char/agp/Kconfig
+15
-0
drivers/char/agp/Makefile
drivers/char/agp/Makefile
+3
-0
drivers/char/agp/generic-3.0.c
drivers/char/agp/generic-3.0.c
+556
-0
drivers/char/agp/i7x05-agp.c
drivers/char/agp/i7x05-agp.c
+227
-0
include/linux/agp_backend.h
include/linux/agp_backend.h
+1
-0
include/linux/pci_ids.h
include/linux/pci_ids.h
+3
-0
No files found.
drivers/char/agp/Kconfig
View file @
9e09bda8
...
...
@@ -29,6 +29,9 @@ config AGP_GART
bool "/dev/agpgart (AGP Support)"
depends on GART_IOMMU
config AGP3
bool "AGP 3.0 compliance (EXPERIMENTAL)"
config AGP_INTEL
tristate "Intel 440LX/BX/GX and I815/I820/I830M/I830MP/I840/I845/I850/I860 support"
depends on AGP
...
...
@@ -127,3 +130,15 @@ config AGP_HP_ZX1
This option gives you AGP GART support for the HP ZX1 chipset
for IA64 processors.
# Put AGP 3.0 entries below here.
config AGP_I7505
tristate "Intel 7205/7505 support (AGP 3.0)"
depends on AGP3
help
This option gives you AGP support for the GLX component of the
XFree86 4.x on Intel I7505 chipsets.
You should say Y here if you use XFree86 3.3.6 or 4.x and want to
use GLX or DRI. If unsure, say N
drivers/char/agp/Makefile
View file @
9e09bda8
...
...
@@ -8,6 +8,7 @@ export-objs := backend.o
agpgart-y
:=
backend.o frontend.o generic.o
agpgart-objs
:=
$
(
agpgart-y
)
obj-$(CONFIG_AGP)
+=
agpgart.o
obj-$(CONFIG_AGP3)
+=
generic-3.0.o
obj-$(CONFIG_AGP_INTEL)
+=
intel-agp.o
obj-$(CONFIG_AGP_VIA)
+=
via-agp.o
...
...
@@ -19,3 +20,5 @@ obj-$(CONFIG_AGP_I460) += i460-agp.o
obj-$(CONFIG_AGP_HP_ZX1)
+=
hp-agp.o
obj-$(CONFIG_AGP_AMD_8151)
+=
amd-k8-agp.o
obj-$(CONFIG_AGP_I7x05)
+=
i7x05-agp.o
drivers/char/agp/generic-3.0.c
0 → 100644
View file @
9e09bda8
#include <linux/list.h>
#include <linux/pci.h>
//#include <linux/pagemap.h>
//#include <linux/miscdevice.h>
//#include <linux/pm.h>
#include <linux/agp_backend.h>
#include "agp.h"
/* Generic AGP 3.0 enabling routines */
struct
agp_3_0_dev
{
struct
list_head
list
;
u8
capndx
;
u32
maxbw
;
struct
pci_dev
*
dev
;
};
static
int
agp_3_0_dev_list_insert
(
struct
list_head
*
head
,
struct
list_head
*
new
)
{
struct
agp_3_0_dev
*
cur
,
*
n
=
list_entry
(
new
,
struct
agp_3_0_dev
,
list
);
struct
list_head
*
pos
;
list_for_each
(
pos
,
head
)
{
cur
=
list_entry
(
pos
,
struct
agp_3_0_dev
,
list
);
if
(
cur
->
maxbw
>
n
->
maxbw
)
break
;
}
list_add_tail
(
new
,
pos
);
return
0
;
}
static
int
agp_3_0_dev_list_sort
(
struct
agp_3_0_dev
*
list
,
unsigned
int
ndevs
)
{
struct
agp_3_0_dev
*
cur
;
struct
pci_dev
*
dev
;
struct
list_head
*
pos
,
*
tmp
,
*
head
=
&
list
->
list
,
*
start
=
head
->
next
;
u32
nistat
;
INIT_LIST_HEAD
(
head
);
for
(
pos
=
start
;
pos
!=
head
;)
{
cur
=
list_entry
(
pos
,
struct
agp_3_0_dev
,
list
);
dev
=
cur
->
dev
;
pci_read_config_dword
(
dev
,
cur
->
capndx
+
0x0c
,
&
nistat
);
cur
->
maxbw
=
(
nistat
>>
16
)
&
0xff
;
tmp
=
pos
;
pos
=
pos
->
next
;
agp_3_0_dev_list_insert
(
head
,
tmp
);
}
return
0
;
}
/*
* Initialize all isochronous transfer parameters for an AGP 3.0
* node (i.e. a host bridge in combination with the adapters
* lying behind it...)
*/
static
int
agp_3_0_isochronous_node_enable
(
struct
agp_3_0_dev
*
dev_list
,
unsigned
int
ndevs
)
{
/*
* Convenience structure to make the calculations clearer
* here. The field names come straight from the AGP 3.0 spec.
*/
struct
isoch_data
{
u32
maxbw
;
u32
n
;
u32
y
;
u32
l
;
u32
rq
;
struct
agp_3_0_dev
*
dev
;
};
struct
pci_dev
*
td
=
agp_bridge
.
dev
,
*
dev
;
struct
list_head
*
head
=
&
dev_list
->
list
,
*
pos
;
struct
agp_3_0_dev
*
cur
;
struct
isoch_data
*
master
,
target
;
unsigned
int
cdev
=
0
;
u32
mnistat
,
tnistat
,
tstatus
,
mcmd
;
u16
tnicmd
,
mnicmd
;
u8
mcapndx
;
u32
tot_bw
=
0
,
tot_n
=
0
,
tot_rq
=
0
,
y_max
,
rq_isoch
,
rq_async
;
u32
step
,
rem
,
rem_isoch
,
rem_async
;
int
ret
=
0
;
/*
* We'll work with an array of isoch_data's (one for each
* device in dev_list) throughout this function.
*/
if
((
master
=
kmalloc
(
ndevs
*
sizeof
(
*
master
),
GFP_KERNEL
))
==
NULL
)
{
ret
=
-
ENOMEM
;
goto
get_out
;
}
/*
* Sort the device list by maxbw. We need to do this because the
* spec suggests that the devices with the smallest requirements
* have their resources allocated first, with all remaining resources
* falling to the device with the largest requirement.
*
* We don't exactly do this, we divide target resources by ndevs
* and split them amongst the AGP 3.0 devices. The remainder of such
* division operations are dropped on the last device, sort of like
* the spec mentions it should be done.
*
* We can't do this sort when we initially construct the dev_list
* because we don't know until this function whether isochronous
* transfers are enabled and consequently whether maxbw will mean
* anything.
*/
if
((
ret
=
agp_3_0_dev_list_sort
(
dev_list
,
ndevs
))
!=
0
)
goto
free_and_exit
;
pci_read_config_dword
(
td
,
agp_bridge
.
capndx
+
0x0c
,
&
tnistat
);
pci_read_config_dword
(
td
,
agp_bridge
.
capndx
+
0x04
,
&
tstatus
);
/* Extract power-on defaults from the target */
target
.
maxbw
=
(
tnistat
>>
16
)
&
0xff
;
target
.
n
=
(
tnistat
>>
8
)
&
0xff
;
target
.
y
=
(
tnistat
>>
6
)
&
0x3
;
target
.
l
=
(
tnistat
>>
3
)
&
0x7
;
target
.
rq
=
(
tstatus
>>
24
)
&
0xff
;
y_max
=
target
.
y
;
/*
* Extract power-on defaults for each device in dev_list. Along
* the way, calculate the total isochronous bandwidth required
* by these devices and the largest requested payload size.
*/
list_for_each
(
pos
,
head
)
{
cur
=
list_entry
(
pos
,
struct
agp_3_0_dev
,
list
);
dev
=
cur
->
dev
;
mcapndx
=
cur
->
capndx
;
pci_read_config_dword
(
dev
,
cur
->
capndx
+
0x0c
,
&
mnistat
);
master
[
cdev
].
maxbw
=
(
mnistat
>>
16
)
&
0xff
;
master
[
cdev
].
n
=
(
mnistat
>>
8
)
&
0xff
;
master
[
cdev
].
y
=
(
mnistat
>>
6
)
&
0x3
;
master
[
cdev
].
dev
=
cur
;
tot_bw
+=
master
[
cdev
].
maxbw
;
y_max
=
max
(
y_max
,
master
[
cdev
].
y
);
cdev
++
;
}
/* Check if this configuration has any chance of working */
if
(
tot_bw
>
target
.
maxbw
)
{
printk
(
KERN_ERR
PFX
"isochronous bandwidth required "
"by AGP 3.0 devices exceeds that which is supported by "
"the AGP 3.0 bridge!
\n
"
);
ret
=
-
ENODEV
;
goto
free_and_exit
;
}
target
.
y
=
y_max
;
/*
* Write the calculated payload size into the target's NICMD
* register. Doing this directly effects the ISOCH_N value
* in the target's NISTAT register, so we need to do this now
* to get an accurate value for ISOCH_N later.
*/
pci_read_config_word
(
td
,
agp_bridge
.
capndx
+
0x20
,
&
tnicmd
);
tnicmd
&=
~
(
0x3
<<
6
);
tnicmd
|=
target
.
y
<<
6
;
pci_write_config_word
(
td
,
agp_bridge
.
capndx
+
0x20
,
tnicmd
);
/* Reread the target's ISOCH_N */
pci_read_config_dword
(
td
,
agp_bridge
.
capndx
+
0x0c
,
&
tnistat
);
target
.
n
=
(
tnistat
>>
8
)
&
0xff
;
/* Calculate the minimum ISOCH_N needed by each master */
for
(
cdev
=
0
;
cdev
<
ndevs
;
cdev
++
)
{
master
[
cdev
].
y
=
target
.
y
;
master
[
cdev
].
n
=
master
[
cdev
].
maxbw
/
(
master
[
cdev
].
y
+
1
);
tot_n
+=
master
[
cdev
].
n
;
}
/* Exit if the minimal ISOCH_N allocation among the masters is more
* than the target can handle. */
if
(
tot_n
>
target
.
n
)
{
printk
(
KERN_ERR
PFX
"number of isochronous "
"transactions per period required by AGP 3.0 devices "
"exceeds that which is supported by the AGP 3.0 "
"bridge!
\n
"
);
ret
=
-
ENODEV
;
goto
free_and_exit
;
}
/* Calculate left over ISOCH_N capability in the target. We'll give
* this to the hungriest device (as per the spec) */
rem
=
target
.
n
-
tot_n
;
/*
* Calculate the minimum isochronous RQ depth needed by each master.
* Along the way, distribute the extra ISOCH_N capability calculated
* above.
*/
for
(
cdev
=
0
;
cdev
<
ndevs
;
cdev
++
)
{
/*
* This is a little subtle. If ISOCH_Y > 64B, then ISOCH_Y
* byte isochronous writes will be broken into 64B pieces.
* This means we need to budget more RQ depth to account for
* these kind of writes (each isochronous write is actually
* many writes on the AGP bus).
*/
master
[
cdev
].
rq
=
master
[
cdev
].
n
;
if
(
master
[
cdev
].
y
>
0x1
)
{
master
[
cdev
].
rq
*=
(
1
<<
(
master
[
cdev
].
y
-
1
));
}
tot_rq
+=
master
[
cdev
].
rq
;
if
(
cdev
==
ndevs
-
1
)
master
[
cdev
].
n
+=
rem
;
}
/* Figure the number of isochronous and asynchronous RQ slots the
* target is providing. */
rq_isoch
=
(
target
.
y
>
0x1
)
?
target
.
n
*
(
1
<<
(
target
.
y
-
1
))
:
target
.
n
;
rq_async
=
target
.
rq
-
rq_isoch
;
/* Exit if the minimal RQ needs of the masters exceeds what the target
* can provide. */
if
(
tot_rq
>
rq_isoch
)
{
printk
(
KERN_ERR
PFX
"number of request queue slots "
"required by the isochronous bandwidth requested by "
"AGP 3.0 devices exceeds the number provided by the "
"AGP 3.0 bridge!
\n
"
);
ret
=
-
ENODEV
;
goto
free_and_exit
;
}
/* Calculate asynchronous RQ capability in the target (per master) as
* well as the total number of leftover isochronous RQ slots. */
step
=
rq_async
/
ndevs
;
rem_async
=
step
+
(
rq_async
%
ndevs
);
rem_isoch
=
rq_isoch
-
tot_rq
;
/* Distribute the extra RQ slots calculated above and write our
* isochronous settings out to the actual devices. */
for
(
cdev
=
0
;
cdev
<
ndevs
;
cdev
++
)
{
cur
=
master
[
cdev
].
dev
;
dev
=
cur
->
dev
;
mcapndx
=
cur
->
capndx
;
master
[
cdev
].
rq
+=
(
cdev
==
ndevs
-
1
)
?
(
rem_async
+
rem_isoch
)
:
step
;
pci_read_config_word
(
dev
,
cur
->
capndx
+
0x20
,
&
mnicmd
);
pci_read_config_dword
(
dev
,
cur
->
capndx
+
0x08
,
&
mcmd
);
mnicmd
&=
~
(
0xff
<<
8
);
mnicmd
&=
~
(
0x3
<<
6
);
mcmd
&=
~
(
0xff
<<
24
);
mnicmd
|=
master
[
cdev
].
n
<<
8
;
mnicmd
|=
master
[
cdev
].
y
<<
6
;
mcmd
|=
master
[
cdev
].
rq
<<
24
;
pci_write_config_dword
(
dev
,
cur
->
capndx
+
0x08
,
mcmd
);
pci_write_config_word
(
dev
,
cur
->
capndx
+
0x20
,
mnicmd
);
}
free_and_exit:
kfree
(
master
);
get_out:
return
ret
;
}
/*
* This function basically allocates request queue slots among the
* AGP 3.0 systems in nonisochronous nodes. The algorithm is
* pretty stupid, divide the total number of RQ slots provided by the
* target by ndevs. Distribute this many slots to each AGP 3.0 device,
* giving any left over slots to the last device in dev_list.
*/
static
int
agp_3_0_nonisochronous_node_enable
(
struct
agp_3_0_dev
*
dev_list
,
unsigned
int
ndevs
)
{
struct
agp_3_0_dev
*
cur
;
struct
list_head
*
head
=
&
dev_list
->
list
,
*
pos
;
u32
tstatus
,
mcmd
;
u32
trq
,
mrq
,
rem
;
unsigned
int
cdev
=
0
;
pci_read_config_dword
(
agp_bridge
.
dev
,
agp_bridge
.
capndx
+
0x04
,
&
tstatus
);
trq
=
(
tstatus
>>
24
)
&
0xff
;
mrq
=
trq
/
ndevs
;
rem
=
mrq
+
(
trq
%
ndevs
);
for
(
pos
=
head
->
next
;
cdev
<
ndevs
;
cdev
++
,
pos
=
pos
->
next
)
{
cur
=
list_entry
(
pos
,
struct
agp_3_0_dev
,
list
);
pci_read_config_dword
(
cur
->
dev
,
cur
->
capndx
+
0x08
,
&
mcmd
);
mcmd
&=
~
(
0xff
<<
24
);
mcmd
|=
((
cdev
==
ndevs
-
1
)
?
rem
:
mrq
)
<<
24
;
pci_write_config_dword
(
cur
->
dev
,
cur
->
capndx
+
0x08
,
mcmd
);
}
return
0
;
}
/*
* Fully configure and enable an AGP 3.0 host bridge and all the devices
* lying behind it.
*/
static
int
agp_3_0_node_enable
(
u32
mode
,
u32
minor
)
{
struct
pci_dev
*
td
=
agp_bridge
.
dev
,
*
dev
;
u8
bus_num
,
mcapndx
;
u32
isoch
,
arqsz
,
cal_cycle
,
tmp
,
rate
;
u32
tstatus
,
tcmd
,
mcmd
,
mstatus
,
ncapid
;
u32
mmajor
,
mminor
;
u16
mpstat
;
struct
agp_3_0_dev
*
dev_list
,
*
cur
;
struct
list_head
*
head
,
*
pos
;
unsigned
int
ndevs
=
0
;
int
ret
=
0
;
/*
* Allocate a head for our AGP 3.0 device list (multiple AGP 3.0
* devices are allowed behind a single bridge).
*/
if
((
dev_list
=
kmalloc
(
sizeof
(
*
dev_list
),
GFP_KERNEL
))
==
NULL
)
{
ret
=
-
ENOMEM
;
goto
get_out
;
}
head
=
&
dev_list
->
list
;
INIT_LIST_HEAD
(
head
);
/*
* Find all the devices on this bridge's secondary bus and add them
* to dev_list.
*/
pci_read_config_byte
(
td
,
PCI_SECONDARY_BUS
,
&
bus_num
);
pci_for_each_dev
(
dev
)
{
if
(
dev
->
bus
->
number
==
bus_num
)
{
if
((
cur
=
kmalloc
(
sizeof
(
*
cur
),
GFP_KERNEL
))
==
NULL
)
{
ret
=
-
ENOMEM
;
goto
free_and_exit
;
}
cur
->
dev
=
dev
;
pos
=
&
cur
->
list
;
list_add
(
pos
,
head
);
ndevs
++
;
}
}
/* Extract some power-on defaults from the target */
pci_read_config_dword
(
td
,
agp_bridge
.
capndx
+
0x04
,
&
tstatus
);
isoch
=
(
tstatus
>>
17
)
&
0x1
;
arqsz
=
(
tstatus
>>
13
)
&
0x7
;
cal_cycle
=
(
tstatus
>>
10
)
&
0x7
;
rate
=
tstatus
&
0x7
;
/*
* Take an initial pass through the devices lying behind our host
* bridge. Make sure each one is actually an AGP 3.0 device, otherwise
* exit with an error message. Along the way store the AGP 3.0
* cap_ptr for each device, the minimum supported cal_cycle, and the
* minimum supported data rate.
*/
list_for_each
(
pos
,
head
)
{
cur
=
list_entry
(
pos
,
struct
agp_3_0_dev
,
list
);
dev
=
cur
->
dev
;
pci_read_config_word
(
dev
,
PCI_STATUS
,
&
mpstat
);
if
((
mpstat
&
PCI_STATUS_CAP_LIST
)
==
0
)
continue
;
pci_read_config_byte
(
dev
,
PCI_CAPABILITY_LIST
,
&
mcapndx
);
if
(
mcapndx
!=
0x00
)
{
do
{
pci_read_config_dword
(
dev
,
mcapndx
,
&
ncapid
);
if
((
ncapid
&
0xff
)
!=
0x02
)
mcapndx
=
(
ncapid
>>
8
)
&
0xff
;
}
while
(((
ncapid
&
0xff
)
!=
0x02
)
&&
(
mcapndx
!=
0x00
));
}
if
(
mcapndx
==
0
)
{
printk
(
KERN_ERR
PFX
"woah! Non-AGP device "
"found on the secondary bus of an AGP 3.0 "
"bridge!
\n
"
);
ret
=
-
ENODEV
;
goto
free_and_exit
;
}
mmajor
=
(
ncapid
>>
20
)
&
0xf
;
mminor
=
(
ncapid
>>
16
)
&
0xf
;
if
(
mmajor
<
3
)
{
printk
(
KERN_ERR
PFX
"woah! AGP 2.0 device "
"found on the secondary bus of an AGP 3.0 "
"bridge operating with AGP 3.0 electricals!
\n
"
);
ret
=
-
ENODEV
;
goto
free_and_exit
;
}
cur
->
capndx
=
mcapndx
;
pci_read_config_dword
(
dev
,
cur
->
capndx
+
0x04
,
&
mstatus
);
if
(((
mstatus
>>
3
)
&
0x1
)
==
0
)
{
printk
(
KERN_ERR
PFX
"woah! AGP 3.0 device "
"not operating in AGP 3.0 mode found on the "
"secondary bus of an AGP 3.0 bridge operating "
"with AGP 3.0 electricals!
\n
"
);
ret
=
-
ENODEV
;
goto
free_and_exit
;
}
tmp
=
(
mstatus
>>
10
)
&
0x7
;
cal_cycle
=
min
(
cal_cycle
,
tmp
);
/* figure the lesser rate */
tmp
=
mstatus
&
0x7
;
if
(
tmp
<
rate
)
rate
=
tmp
;
}
/* Turn rate into something we can actually write out to AGPCMD */
switch
(
rate
)
{
case
0x1
:
case
0x2
:
break
;
case
0x3
:
rate
=
0x2
;
break
;
default:
printk
(
KERN_ERR
PFX
"woah! Bogus AGP rate "
"value found advertised behind an AGP 3.0 "
"bridge!
\n
"
);
ret
=
-
ENODEV
;
goto
free_and_exit
;
}
/*
* Call functions to divide target resources amongst the AGP 3.0
* masters. This process is dramatically different depending on
* whether isochronous transfers are supported.
*/
if
(
isoch
!=
0
)
{
if
((
ret
=
agp_3_0_isochronous_node_enable
(
dev_list
,
ndevs
))
!=
0
)
goto
free_and_exit
;
}
else
{
if
((
ret
=
agp_3_0_nonisochronous_node_enable
(
dev_list
,
ndevs
))
!=
0
)
goto
free_and_exit
;
}
/*
* Set the calculated minimum supported cal_cycle and minimum
* supported transfer rate in the target's AGPCMD register.
* Also set the AGP_ENABLE bit, effectively 'turning on' the
* target (this has to be done _before_ turning on the masters).
*/
pci_read_config_dword
(
td
,
agp_bridge
.
capndx
+
0x08
,
&
tcmd
);
tcmd
&=
~
(
0x7
<<
10
);
tcmd
&=
~
0x7
;
tcmd
|=
cal_cycle
<<
10
;
tcmd
|=
0x1
<<
8
;
tcmd
|=
rate
;
pci_write_config_dword
(
td
,
agp_bridge
.
capndx
+
0x08
,
tcmd
);
/*
* Set the target's advertised arqsz value, the minimum supported
* transfer rate, and the AGP_ENABLE bit in each master's AGPCMD
* register.
*/
list_for_each
(
pos
,
head
)
{
cur
=
list_entry
(
pos
,
struct
agp_3_0_dev
,
list
);
dev
=
cur
->
dev
;
mcapndx
=
cur
->
capndx
;
pci_read_config_dword
(
dev
,
cur
->
capndx
+
0x08
,
&
mcmd
);
mcmd
&=
~
(
0x7
<<
13
);
mcmd
&=
~
0x7
;
mcmd
|=
arqsz
<<
13
;
mcmd
|=
0x1
<<
8
;
mcmd
|=
rate
;
pci_write_config_dword
(
dev
,
cur
->
capndx
+
0x08
,
mcmd
);
}
free_and_exit:
/* Be sure to free the dev_list */
for
(
pos
=
head
->
next
;
pos
!=
head
;)
{
cur
=
list_entry
(
pos
,
struct
agp_3_0_dev
,
list
);
pos
=
pos
->
next
;
kfree
(
cur
);
}
kfree
(
dev_list
);
get_out:
return
ret
;
}
/*
* Entry point to AGP 3.0 host bridge init. Check to see if we
* have an AGP 3.0 device operating in 3.0 mode. Call
* agp_3_0_node_enable or agp_generic_agp_enable if we don't
* (AGP 3.0 devices are required to operate as AGP 2.0 devices
* when not using 3.0 electricals.
*/
void
agp_generic_agp_3_0_enable
(
u32
mode
)
{
u32
ncapid
,
major
,
minor
,
agp_3_0
;
pci_read_config_dword
(
agp_bridge
.
dev
,
agp_bridge
.
capndx
,
&
ncapid
);
major
=
(
ncapid
>>
20
)
&
0xf
;
minor
=
(
ncapid
>>
16
)
&
0xf
;
printk
(
KERN_INFO
PFX
"Found an AGP %d.%d compliant device.
\n
"
,
major
,
minor
);
if
(
major
>=
3
)
{
pci_read_config_dword
(
agp_bridge
.
dev
,
agp_bridge
.
capndx
+
0x4
,
&
agp_3_0
);
/*
* Check to see if we are operating in 3.0 mode
*/
if
((
agp_3_0
>>
3
)
&
0x1
)
{
agp_3_0_node_enable
(
mode
,
minor
);
return
;
}
}
agp_generic_agp_enable
(
mode
);
}
drivers/char/agp/i7x05-agp.c
0 → 100644
View file @
9e09bda8
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/agp_backend.h>
#include "agp.h"
static
int
intel_7505_fetch_size
(
void
)
{
int
i
;
u16
tmp
;
aper_size_info_16
*
values
;
/*
* For AGP 3.0 APSIZE is now 16 bits
*/
pci_read_config_word
(
agp_bridge
.
dev
,
INTEL_I7505_APSIZE
,
&
tmp
);
tmp
=
(
tmp
&
0xfff
);
values
=
A_SIZE_16
(
agp_bridge
.
aperture_sizes
);
for
(
i
=
0
;
i
<
agp_bridge
.
num_aperture_sizes
;
i
++
)
{
if
(
tmp
==
values
[
i
].
size_value
)
{
agp_bridge
.
previous_size
=
agp_bridge
.
current_size
=
(
void
*
)(
values
+
i
);
agp_bridge
.
aperture_size_idx
=
i
;
return
values
[
i
].
size
;
}
}
return
0
;
}
static
void
intel_7505_tlbflush
(
agp_memory
*
mem
)
{
u32
temp
;
pci_read_config_dword
(
agp_bridge
.
dev
,
INTEL_I7505_AGPCTRL
,
&
temp
);
pci_write_config_dword
(
agp_bridge
.
dev
,
INTEL_I7505_AGPCTRL
,
temp
&
~
(
1
<<
7
));
pci_read_config_dword
(
agp_bridge
.
dev
,
INTEL_I7505_AGPCTRL
,
&
temp
);
pci_write_config_dword
(
agp_bridge
.
dev
,
INTEL_I7505_AGPCTRL
,
temp
|
(
1
<<
7
));
}
static
void
intel_7505_cleanup
(
void
)
{
aper_size_info_16
*
previous_size
;
previous_size
=
A_SIZE_16
(
agp_bridge
.
previous_size
);
pci_write_config_byte
(
agp_bridge
.
dev
,
INTEL_I7505_APSIZE
,
previous_size
->
size_value
);
}
static
int
intel_7505_configure
(
void
)
{
u32
temp
;
aper_size_info_16
*
current_size
;
current_size
=
A_SIZE_16
(
agp_bridge
.
current_size
);
/* aperture size */
pci_write_config_word
(
agp_bridge
.
dev
,
INTEL_I7505_APSIZE
,
current_size
->
size_value
);
/* address to map to */
pci_read_config_dword
(
agp_bridge
.
dev
,
INTEL_I7505_NAPBASELO
,
&
temp
);
agp_bridge
.
gart_bus_addr
=
(
temp
&
PCI_BASE_ADDRESS_MEM_MASK
);
/* attbase */
pci_write_config_dword
(
agp_bridge
.
dev
,
INTEL_I7505_ATTBASE
,
agp_bridge
.
gatt_bus_addr
);
/* agpctrl */
pci_write_config_dword
(
agp_bridge
.
dev
,
INTEL_I7505_AGPCTRL
,
0x0000
);
/* clear error registers */
pci_write_config_byte
(
agp_bridge
.
dev
,
INTEL_I7505_ERRSTS
,
0xff
);
return
0
;
}
static
aper_size_info_16
intel_7505_sizes
[
7
]
=
{
{
256
,
65536
,
6
,
0xf00
},
{
128
,
32768
,
5
,
0xf20
},
{
64
,
16384
,
4
,
0xf30
},
{
32
,
8192
,
3
,
0xf38
},
{
16
,
4096
,
2
,
0xf3c
},
{
8
,
2048
,
1
,
0xf3e
},
{
4
,
1024
,
0
,
0xf3f
}
};
static
int
__init
intel_7505_setup
(
struct
pci_dev
*
pdev
)
{
agp_bridge
.
masks
=
intel_generic_masks
;
agp_bridge
.
num_of_masks
=
1
;
agp_bridge
.
aperture_sizes
=
(
void
*
)
intel_7505_sizes
;
agp_bridge
.
size_type
=
U16_APER_SIZE
;
agp_bridge
.
num_aperture_sizes
=
7
;
agp_bridge
.
dev_private_data
=
NULL
;
agp_bridge
.
needs_scratch_page
=
FALSE
;
agp_bridge
.
configure
=
intel_7505_configure
;
agp_bridge
.
fetch_size
=
intel_7505_fetch_size
;
agp_bridge
.
cleanup
=
intel_7505_cleanup
;
agp_bridge
.
tlb_flush
=
intel_7505_tlbflush
;
agp_bridge
.
mask_memory
=
intel_mask_memory
;
agp_bridge
.
agp_enable
=
agp_generic_agp_3_0_enable
;
agp_bridge
.
cache_flush
=
global_cache_flush
;
agp_bridge
.
create_gatt_table
=
agp_generic_create_gatt_table
;
agp_bridge
.
free_gatt_table
=
agp_generic_free_gatt_table
;
agp_bridge
.
insert_memory
=
agp_generic_insert_memory
;
agp_bridge
.
remove_memory
=
agp_generic_remove_memory
;
agp_bridge
.
alloc_by_type
=
agp_generic_alloc_by_type
;
agp_bridge
.
free_by_type
=
agp_generic_free_by_type
;
agp_bridge
.
agp_alloc_page
=
agp_generic_alloc_page
;
agp_bridge
.
agp_destroy_page
=
agp_generic_destroy_page
;
agp_bridge
.
suspend
=
agp_generic_suspend
;
agp_bridge
.
resume
=
agp_generic_resume
;
agp_bridge
.
cant_use_aperture
=
0
;
return
0
;
}
struct
agp_device_ids
i7x05_agp_device_ids
[]
__initdata
=
{
{
.
device_id
=
PCI_DEVICE_ID_INTEL_7505_0
,
.
chipset
=
INTEL_I7505
,
.
chipset_name
=
"i7505"
,
},
{
.
device_id
=
PCI_DEVICE_ID_INTEL_7205_0
,
.
chipset
=
INTEL_I7505
,
.
chipset_name
=
"i7205"
,
},
{
},
/* dummy final entry, always present */
};
/* scan table above for supported devices */
static
int
__init
agp_lookup_host_bridge
(
struct
pci_dev
*
pdev
)
{
int
j
=
0
;
struct
agp_device_ids
*
devs
;
devs
=
i7x05_agp_device_ids
;
while
(
devs
[
j
].
chipset_name
!=
NULL
)
{
if
(
pdev
->
device
==
devs
[
j
].
device_id
)
{
printk
(
KERN_INFO
PFX
"Detected Intel %s chipset
\n
"
,
devs
[
j
].
chipset_name
);
agp_bridge
.
type
=
devs
[
j
].
chipset
;
if
(
devs
[
j
].
chipset_setup
!=
NULL
)
return
devs
[
j
].
chipset_setup
(
pdev
);
else
return
intel_7505_setup
(
pdev
);
}
j
++
;
}
printk
(
KERN_ERR
PFX
"Unsupported Intel chipset (device id: %04x),"
,
pdev
->
device
);
return
-
ENODEV
;
}
static
int
__init
agp_find_supported_device
(
struct
pci_dev
*
dev
)
{
agp_bridge
.
dev
=
dev
;
if
(
pci_find_capability
(
dev
,
PCI_CAP_ID_AGP
)
==
0
)
return
-
ENODEV
;
/* probe for known chipsets */
return
agp_lookup_host_bridge
(
dev
);
}
static
int
agp_i7x05_probe
(
struct
pci_dev
*
dev
,
const
struct
pci_device_id
*
ent
)
{
if
(
agp_find_supported_device
(
dev
)
==
0
)
{
agp_register_driver
(
dev
);
return
0
;
}
return
-
ENODEV
;
}
static
struct
pci_device_id
agp_i7x05_pci_table
[]
__initdata
=
{
{
.
class
=
(
PCI_CLASS_BRIDGE_HOST
<<
8
),
.
class_mask
=
~
0
,
.
vendor
=
PCI_VENDOR_ID_INTEL
,
.
device
=
PCI_ANY_ID
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
},
{
}
};
MODULE_DEVICE_TABLE
(
pci
,
agp_i7x05_pci_table
);
static
struct
pci_driver
agp_i7x05_pci_driver
=
{
.
name
=
"agpgart-i7x05"
,
.
id_table
=
agp_i7x05_pci_table
,
.
probe
=
agp_i7x05_probe
,
};
int
__init
agp_i7x05_init
(
void
)
{
int
ret_val
;
ret_val
=
pci_module_init
(
&
agp_i7x05_pci_driver
);
if
(
ret_val
)
agp_bridge
.
type
=
NOT_SUPPORTED
;
return
ret_val
;
}
static
void
__exit
agp_i7x05_cleanup
(
void
)
{
agp_unregister_driver
();
pci_unregister_driver
(
&
agp_i7x05_pci_driver
);
}
module_init
(
agp_i7x05_init
);
module_exit
(
agp_i7x05_cleanup
);
MODULE_AUTHOR
(
"Matthew E Tolentino <matthew.e.tolentino@intel.com>"
);
MODULE_LICENSE
(
"GPL and additional rights"
);
include/linux/agp_backend.h
View file @
9e09bda8
...
...
@@ -51,6 +51,7 @@ enum chipset_type {
INTEL_I850
,
INTEL_I860
,
INTEL_460GX
,
INTEL_I7505
,
VIA_GENERIC
,
VIA_VP3
,
VIA_MVP3
,
...
...
include/linux/pci_ids.h
View file @
9e09bda8
...
...
@@ -1727,6 +1727,9 @@
#define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221
#define PCI_DEVICE_ID_INTEL_82092AA_1 0x1222
#define PCI_DEVICE_ID_INTEL_7116 0x1223
#define PCI_DEVICE_ID_INTEL_7505_0 0x2550
#define PCI_DEVICE_ID_INTEL_7505_1 0x2552
#define PCI_DEVICE_ID_INTEL_7205_0 0x255d
#define PCI_DEVICE_ID_INTEL_82596 0x1226
#define PCI_DEVICE_ID_INTEL_82865 0x1227
#define PCI_DEVICE_ID_INTEL_82557 0x1229
...
...
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