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
Show 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
...
@@ -29,6 +29,9 @@ config AGP_GART
bool "/dev/agpgart (AGP Support)"
bool "/dev/agpgart (AGP Support)"
depends on GART_IOMMU
depends on GART_IOMMU
config AGP3
bool "AGP 3.0 compliance (EXPERIMENTAL)"
config AGP_INTEL
config AGP_INTEL
tristate "Intel 440LX/BX/GX and I815/I820/I830M/I830MP/I840/I845/I850/I860 support"
tristate "Intel 440LX/BX/GX and I815/I820/I830M/I830MP/I840/I845/I850/I860 support"
depends on AGP
depends on AGP
...
@@ -127,3 +130,15 @@ config AGP_HP_ZX1
...
@@ -127,3 +130,15 @@ config AGP_HP_ZX1
This option gives you AGP GART support for the HP ZX1 chipset
This option gives you AGP GART support for the HP ZX1 chipset
for IA64 processors.
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
...
@@ -8,6 +8,7 @@ export-objs := backend.o
agpgart-y
:=
backend.o frontend.o generic.o
agpgart-y
:=
backend.o frontend.o generic.o
agpgart-objs
:=
$
(
agpgart-y
)
agpgart-objs
:=
$
(
agpgart-y
)
obj-$(CONFIG_AGP)
+=
agpgart.o
obj-$(CONFIG_AGP)
+=
agpgart.o
obj-$(CONFIG_AGP3)
+=
generic-3.0.o
obj-$(CONFIG_AGP_INTEL)
+=
intel-agp.o
obj-$(CONFIG_AGP_INTEL)
+=
intel-agp.o
obj-$(CONFIG_AGP_VIA)
+=
via-agp.o
obj-$(CONFIG_AGP_VIA)
+=
via-agp.o
...
@@ -19,3 +20,5 @@ obj-$(CONFIG_AGP_I460) += i460-agp.o
...
@@ -19,3 +20,5 @@ obj-$(CONFIG_AGP_I460) += i460-agp.o
obj-$(CONFIG_AGP_HP_ZX1)
+=
hp-agp.o
obj-$(CONFIG_AGP_HP_ZX1)
+=
hp-agp.o
obj-$(CONFIG_AGP_AMD_8151)
+=
amd-k8-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 {
...
@@ -51,6 +51,7 @@ enum chipset_type {
INTEL_I850
,
INTEL_I850
,
INTEL_I860
,
INTEL_I860
,
INTEL_460GX
,
INTEL_460GX
,
INTEL_I7505
,
VIA_GENERIC
,
VIA_GENERIC
,
VIA_VP3
,
VIA_VP3
,
VIA_MVP3
,
VIA_MVP3
,
...
...
include/linux/pci_ids.h
View file @
9e09bda8
...
@@ -1727,6 +1727,9 @@
...
@@ -1727,6 +1727,9 @@
#define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221
#define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221
#define PCI_DEVICE_ID_INTEL_82092AA_1 0x1222
#define PCI_DEVICE_ID_INTEL_82092AA_1 0x1222
#define PCI_DEVICE_ID_INTEL_7116 0x1223
#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_82596 0x1226
#define PCI_DEVICE_ID_INTEL_82865 0x1227
#define PCI_DEVICE_ID_INTEL_82865 0x1227
#define PCI_DEVICE_ID_INTEL_82557 0x1229
#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