Merge branch 'for-rmk' of git://git.marvell.com/orion into devel
This commit is contained in:
commit
d1a7fddf42
|
@ -0,0 +1,62 @@
|
||||||
|
What: /sys/bus/usb/drivers/usbtmc/devices/*/interface_capabilities
|
||||||
|
What: /sys/bus/usb/drivers/usbtmc/devices/*/device_capabilities
|
||||||
|
Date: August 2008
|
||||||
|
Contact: Greg Kroah-Hartman <gregkh@suse.de>
|
||||||
|
Description:
|
||||||
|
These files show the various USB TMC capabilities as described
|
||||||
|
by the device itself. The full description of the bitfields
|
||||||
|
can be found in the USB TMC documents from the USB-IF entitled
|
||||||
|
"Universal Serial Bus Test and Measurement Class Specification
|
||||||
|
(USBTMC) Revision 1.0" section 4.2.1.8.
|
||||||
|
|
||||||
|
The files are read only.
|
||||||
|
|
||||||
|
|
||||||
|
What: /sys/bus/usb/drivers/usbtmc/devices/*/usb488_interface_capabilities
|
||||||
|
What: /sys/bus/usb/drivers/usbtmc/devices/*/usb488_device_capabilities
|
||||||
|
Date: August 2008
|
||||||
|
Contact: Greg Kroah-Hartman <gregkh@suse.de>
|
||||||
|
Description:
|
||||||
|
These files show the various USB TMC capabilities as described
|
||||||
|
by the device itself. The full description of the bitfields
|
||||||
|
can be found in the USB TMC documents from the USB-IF entitled
|
||||||
|
"Universal Serial Bus Test and Measurement Class, Subclass
|
||||||
|
USB488 Specification (USBTMC-USB488) Revision 1.0" section
|
||||||
|
4.2.2.
|
||||||
|
|
||||||
|
The files are read only.
|
||||||
|
|
||||||
|
|
||||||
|
What: /sys/bus/usb/drivers/usbtmc/devices/*/TermChar
|
||||||
|
Date: August 2008
|
||||||
|
Contact: Greg Kroah-Hartman <gregkh@suse.de>
|
||||||
|
Description:
|
||||||
|
This file is the TermChar value to be sent to the USB TMC
|
||||||
|
device as described by the document, "Universal Serial Bus Test
|
||||||
|
and Measurement Class Specification
|
||||||
|
(USBTMC) Revision 1.0" as published by the USB-IF.
|
||||||
|
|
||||||
|
Note that the TermCharEnabled file determines if this value is
|
||||||
|
sent to the device or not.
|
||||||
|
|
||||||
|
|
||||||
|
What: /sys/bus/usb/drivers/usbtmc/devices/*/TermCharEnabled
|
||||||
|
Date: August 2008
|
||||||
|
Contact: Greg Kroah-Hartman <gregkh@suse.de>
|
||||||
|
Description:
|
||||||
|
This file determines if the TermChar is to be sent to the
|
||||||
|
device on every transaction or not. For more details about
|
||||||
|
this, please see the document, "Universal Serial Bus Test and
|
||||||
|
Measurement Class Specification (USBTMC) Revision 1.0" as
|
||||||
|
published by the USB-IF.
|
||||||
|
|
||||||
|
|
||||||
|
What: /sys/bus/usb/drivers/usbtmc/devices/*/auto_abort
|
||||||
|
Date: August 2008
|
||||||
|
Contact: Greg Kroah-Hartman <gregkh@suse.de>
|
||||||
|
Description:
|
||||||
|
This file determines if the the transaction of the USB TMC
|
||||||
|
device is to be automatically aborted if there is any error.
|
||||||
|
For more details about this, please see the document,
|
||||||
|
"Universal Serial Bus Test and Measurement Class Specification
|
||||||
|
(USBTMC) Revision 1.0" as published by the USB-IF.
|
|
@ -85,3 +85,19 @@ Description:
|
||||||
Users:
|
Users:
|
||||||
PowerTOP <power@bughost.org>
|
PowerTOP <power@bughost.org>
|
||||||
http://www.lesswatts.org/projects/powertop/
|
http://www.lesswatts.org/projects/powertop/
|
||||||
|
|
||||||
|
What: /sys/bus/usb/device/<busnum>-<devnum>...:<config num>-<interface num>/supports_autosuspend
|
||||||
|
Date: January 2008
|
||||||
|
KernelVersion: 2.6.27
|
||||||
|
Contact: Sarah Sharp <sarah.a.sharp@intel.com>
|
||||||
|
Description:
|
||||||
|
When read, this file returns 1 if the interface driver
|
||||||
|
for this interface supports autosuspend. It also
|
||||||
|
returns 1 if no driver has claimed this interface, as an
|
||||||
|
unclaimed interface will not stop the device from being
|
||||||
|
autosuspended if all other interface drivers are idle.
|
||||||
|
The file returns 0 if autosuspend support has not been
|
||||||
|
added to the driver.
|
||||||
|
Users:
|
||||||
|
USB PM tool
|
||||||
|
git://git.moblin.org/users/sarah/usb-pm-tool/
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
Where: /sys/bus/usb/.../powered
|
||||||
|
Date: August 2008
|
||||||
|
Kernel Version: 2.6.26
|
||||||
|
Contact: Harrison Metzger <harrisonmetz@gmail.com>
|
||||||
|
Description: Controls whether the device's display will powered.
|
||||||
|
A value of 0 is off and a non-zero value is on.
|
||||||
|
|
||||||
|
Where: /sys/bus/usb/.../mode_msb
|
||||||
|
Where: /sys/bus/usb/.../mode_lsb
|
||||||
|
Date: August 2008
|
||||||
|
Kernel Version: 2.6.26
|
||||||
|
Contact: Harrison Metzger <harrisonmetz@gmail.com>
|
||||||
|
Description: Controls the devices display mode.
|
||||||
|
For a 6 character display the values are
|
||||||
|
MSB 0x06; LSB 0x3F, and
|
||||||
|
for an 8 character display the values are
|
||||||
|
MSB 0x08; LSB 0xFF.
|
||||||
|
|
||||||
|
Where: /sys/bus/usb/.../textmode
|
||||||
|
Date: August 2008
|
||||||
|
Kernel Version: 2.6.26
|
||||||
|
Contact: Harrison Metzger <harrisonmetz@gmail.com>
|
||||||
|
Description: Controls the way the device interprets its text buffer.
|
||||||
|
raw: each character controls its segment manually
|
||||||
|
hex: each character is between 0-15
|
||||||
|
ascii: each character is between '0'-'9' and 'A'-'F'.
|
||||||
|
|
||||||
|
Where: /sys/bus/usb/.../text
|
||||||
|
Date: August 2008
|
||||||
|
Kernel Version: 2.6.26
|
||||||
|
Contact: Harrison Metzger <harrisonmetz@gmail.com>
|
||||||
|
Description: The text (or data) for the device to display
|
||||||
|
|
||||||
|
Where: /sys/bus/usb/.../decimals
|
||||||
|
Date: August 2008
|
||||||
|
Kernel Version: 2.6.26
|
||||||
|
Contact: Harrison Metzger <harrisonmetz@gmail.com>
|
||||||
|
Description: Controls the decimal places on the device.
|
||||||
|
To set the nth decimal place, give this field
|
||||||
|
the value of 10 ** n. Assume this field has
|
||||||
|
the value k and has 1 or more decimal places set,
|
||||||
|
to set the mth place (where m is not already set),
|
||||||
|
change this fields value to k + 10 ** m.
|
|
@ -557,6 +557,9 @@ Near-term plans include converting all of them, except for "gadgetfs".
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
!Edrivers/usb/gadget/f_acm.c
|
!Edrivers/usb/gadget/f_acm.c
|
||||||
|
!Edrivers/usb/gadget/f_ecm.c
|
||||||
|
!Edrivers/usb/gadget/f_subset.c
|
||||||
|
!Edrivers/usb/gadget/f_obex.c
|
||||||
!Edrivers/usb/gadget/f_serial.c
|
!Edrivers/usb/gadget/f_serial.c
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
|
@ -2571,6 +2571,9 @@ Your cooperation is appreciated.
|
||||||
160 = /dev/usb/legousbtower0 1st USB Legotower device
|
160 = /dev/usb/legousbtower0 1st USB Legotower device
|
||||||
...
|
...
|
||||||
175 = /dev/usb/legousbtower15 16th USB Legotower device
|
175 = /dev/usb/legousbtower15 16th USB Legotower device
|
||||||
|
176 = /dev/usb/usbtmc1 First USB TMC device
|
||||||
|
...
|
||||||
|
192 = /dev/usb/usbtmc16 16th USB TMC device
|
||||||
240 = /dev/usb/dabusb0 First daubusb device
|
240 = /dev/usb/dabusb0 First daubusb device
|
||||||
...
|
...
|
||||||
243 = /dev/usb/dabusb3 Fourth dabusb device
|
243 = /dev/usb/dabusb3 Fourth dabusb device
|
||||||
|
|
|
@ -2,19 +2,24 @@
|
||||||
Ext4 Filesystem
|
Ext4 Filesystem
|
||||||
===============
|
===============
|
||||||
|
|
||||||
This is a development version of the ext4 filesystem, an advanced level
|
Ext4 is an an advanced level of the ext3 filesystem which incorporates
|
||||||
of the ext3 filesystem which incorporates scalability and reliability
|
scalability and reliability enhancements for supporting large filesystems
|
||||||
enhancements for supporting large filesystems (64 bit) in keeping with
|
(64 bit) in keeping with increasing disk capacities and state-of-the-art
|
||||||
increasing disk capacities and state-of-the-art feature requirements.
|
feature requirements.
|
||||||
|
|
||||||
Mailing list: linux-ext4@vger.kernel.org
|
Mailing list: linux-ext4@vger.kernel.org
|
||||||
|
Web site: http://ext4.wiki.kernel.org
|
||||||
|
|
||||||
|
|
||||||
1. Quick usage instructions:
|
1. Quick usage instructions:
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
|
Note: More extensive information for getting started with ext4 can be
|
||||||
|
found at the ext4 wiki site at the URL:
|
||||||
|
http://ext4.wiki.kernel.org/index.php/Ext4_Howto
|
||||||
|
|
||||||
- Compile and install the latest version of e2fsprogs (as of this
|
- Compile and install the latest version of e2fsprogs (as of this
|
||||||
writing version 1.41) from:
|
writing version 1.41.3) from:
|
||||||
|
|
||||||
http://sourceforge.net/project/showfiles.php?group_id=2406
|
http://sourceforge.net/project/showfiles.php?group_id=2406
|
||||||
|
|
||||||
|
@ -36,11 +41,9 @@ Mailing list: linux-ext4@vger.kernel.org
|
||||||
|
|
||||||
# mke2fs -t ext4 /dev/hda1
|
# mke2fs -t ext4 /dev/hda1
|
||||||
|
|
||||||
Or configure an existing ext3 filesystem to support extents and set
|
Or to configure an existing ext3 filesystem to support extents:
|
||||||
the test_fs flag to indicate that it's ok for an in-development
|
|
||||||
filesystem to touch this filesystem:
|
|
||||||
|
|
||||||
# tune2fs -O extents -E test_fs /dev/hda1
|
# tune2fs -O extents /dev/hda1
|
||||||
|
|
||||||
If the filesystem was created with 128 byte inodes, it can be
|
If the filesystem was created with 128 byte inodes, it can be
|
||||||
converted to use 256 byte for greater efficiency via:
|
converted to use 256 byte for greater efficiency via:
|
||||||
|
@ -104,8 +107,8 @@ exist yet so I'm not sure they're in the near-term roadmap.
|
||||||
The big performance win will come with mballoc, delalloc and flex_bg
|
The big performance win will come with mballoc, delalloc and flex_bg
|
||||||
grouping of bitmaps and inode tables. Some test results available here:
|
grouping of bitmaps and inode tables. Some test results available here:
|
||||||
|
|
||||||
- http://www.bullopensource.org/ext4/20080530/ffsb-write-2.6.26-rc2.html
|
- http://www.bullopensource.org/ext4/20080818-ffsb/ffsb-write-2.6.27-rc1.html
|
||||||
- http://www.bullopensource.org/ext4/20080530/ffsb-readwrite-2.6.26-rc2.html
|
- http://www.bullopensource.org/ext4/20080818-ffsb/ffsb-readwrite-2.6.27-rc1.html
|
||||||
|
|
||||||
3. Options
|
3. Options
|
||||||
==========
|
==========
|
||||||
|
@ -214,9 +217,6 @@ noreservation
|
||||||
bsddf (*) Make 'df' act like BSD.
|
bsddf (*) Make 'df' act like BSD.
|
||||||
minixdf Make 'df' act like Minix.
|
minixdf Make 'df' act like Minix.
|
||||||
|
|
||||||
check=none Don't do extra checking of bitmaps on mount.
|
|
||||||
nocheck
|
|
||||||
|
|
||||||
debug Extra debugging information is sent to syslog.
|
debug Extra debugging information is sent to syslog.
|
||||||
|
|
||||||
errors=remount-ro(*) Remount the filesystem read-only on an error.
|
errors=remount-ro(*) Remount the filesystem read-only on an error.
|
||||||
|
@ -253,8 +253,6 @@ nobh (a) cache disk block mapping information
|
||||||
"nobh" option tries to avoid associating buffer
|
"nobh" option tries to avoid associating buffer
|
||||||
heads (supported only for "writeback" mode).
|
heads (supported only for "writeback" mode).
|
||||||
|
|
||||||
mballoc (*) Use the multiple block allocator for block allocation
|
|
||||||
nomballoc disabled multiple block allocator for block allocation.
|
|
||||||
stripe=n Number of filesystem blocks that mballoc will try
|
stripe=n Number of filesystem blocks that mballoc will try
|
||||||
to use for allocation size and alignment. For RAID5/6
|
to use for allocation size and alignment. For RAID5/6
|
||||||
systems this should be the number of data
|
systems this should be the number of data
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
Kernel driver adt7470
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Supported chips:
|
||||||
|
* Analog Devices ADT7470
|
||||||
|
Prefix: 'adt7470'
|
||||||
|
Addresses scanned: I2C 0x2C, 0x2E, 0x2F
|
||||||
|
Datasheet: Publicly available at the Analog Devices website
|
||||||
|
|
||||||
|
Author: Darrick J. Wong
|
||||||
|
|
||||||
|
Description
|
||||||
|
-----------
|
||||||
|
|
||||||
|
This driver implements support for the Analog Devices ADT7470 chip. There may
|
||||||
|
be other chips that implement this interface.
|
||||||
|
|
||||||
|
The ADT7470 uses the 2-wire interface compatible with the SMBus 2.0
|
||||||
|
specification. Using an analog to digital converter it measures up to ten (10)
|
||||||
|
external temperatures. It has four (4) 16-bit counters for measuring fan speed.
|
||||||
|
There are four (4) PWM outputs that can be used to control fan speed.
|
||||||
|
|
||||||
|
A sophisticated control system for the PWM outputs is designed into the ADT7470
|
||||||
|
that allows fan speed to be adjusted automatically based on any of the ten
|
||||||
|
temperature sensors. Each PWM output is individually adjustable and
|
||||||
|
programmable. Once configured, the ADT7470 will adjust the PWM outputs in
|
||||||
|
response to the measured temperatures with further host intervention. This
|
||||||
|
feature can also be disabled for manual control of the PWM's.
|
||||||
|
|
||||||
|
Each of the measured inputs (temperature, fan speed) has corresponding high/low
|
||||||
|
limit values. The ADT7470 will signal an ALARM if any measured value exceeds
|
||||||
|
either limit.
|
||||||
|
|
||||||
|
The ADT7470 DOES NOT sample all inputs continuously. A single pin on the
|
||||||
|
ADT7470 is connected to a multitude of thermal diodes, but the chip must be
|
||||||
|
instructed explicitly to read the multitude of diodes. If you want to use
|
||||||
|
automatic fan control mode, you must manually read any of the temperature
|
||||||
|
sensors or the fan control algorithm will not run. The chip WILL NOT DO THIS
|
||||||
|
AUTOMATICALLY; this must be done from userspace. This may be a bug in the chip
|
||||||
|
design, given that many other AD chips take care of this. The driver will not
|
||||||
|
read the registers more often than once every 5 seconds. Further,
|
||||||
|
configuration data is only read once per minute.
|
||||||
|
|
||||||
|
Special Features
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The ADT7470 has a 8-bit ADC and is capable of measuring temperatures with 1
|
||||||
|
degC resolution.
|
||||||
|
|
||||||
|
The Analog Devices datasheet is very detailed and describes a procedure for
|
||||||
|
determining an optimal configuration for the automatic PWM control.
|
||||||
|
|
||||||
|
Configuration Notes
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Besides standard interfaces driver adds the following:
|
||||||
|
|
||||||
|
* PWM Control
|
||||||
|
|
||||||
|
* pwm#_auto_point1_pwm and pwm#_auto_point1_temp and
|
||||||
|
* pwm#_auto_point2_pwm and pwm#_auto_point2_temp -
|
||||||
|
|
||||||
|
point1: Set the pwm speed at a lower temperature bound.
|
||||||
|
point2: Set the pwm speed at a higher temperature bound.
|
||||||
|
|
||||||
|
The ADT7470 will scale the pwm between the lower and higher pwm speed when
|
||||||
|
the temperature is between the two temperature boundaries. PWM values range
|
||||||
|
from 0 (off) to 255 (full speed). Fan speed will be set to maximum when the
|
||||||
|
temperature sensor associated with the PWM control exceeds
|
||||||
|
pwm#_auto_point2_temp.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
|
||||||
|
As stated above, the temperature inputs must be read periodically from
|
||||||
|
userspace in order for the automatic pwm algorithm to run.
|
|
@ -136,10 +136,10 @@ once-only alarms.
|
||||||
The IT87xx only updates its values each 1.5 seconds; reading it more often
|
The IT87xx only updates its values each 1.5 seconds; reading it more often
|
||||||
will do no harm, but will return 'old' values.
|
will do no harm, but will return 'old' values.
|
||||||
|
|
||||||
To change sensor N to a thermistor, 'echo 2 > tempN_type' where N is 1, 2,
|
To change sensor N to a thermistor, 'echo 4 > tempN_type' where N is 1, 2,
|
||||||
or 3. To change sensor N to a thermal diode, 'echo 3 > tempN_type'.
|
or 3. To change sensor N to a thermal diode, 'echo 3 > tempN_type'.
|
||||||
Give 0 for unused sensor. Any other value is invalid. To configure this at
|
Give 0 for unused sensor. Any other value is invalid. To configure this at
|
||||||
startup, consult lm_sensors's /etc/sensors.conf. (2 = thermistor;
|
startup, consult lm_sensors's /etc/sensors.conf. (4 = thermistor;
|
||||||
3 = thermal diode)
|
3 = thermal diode)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -163,16 +163,6 @@ configured individually according to the following options.
|
||||||
* pwm#_auto_pwm_min - this specifies the PWM value for temp#_auto_temp_off
|
* pwm#_auto_pwm_min - this specifies the PWM value for temp#_auto_temp_off
|
||||||
temperature. (PWM value from 0 to 255)
|
temperature. (PWM value from 0 to 255)
|
||||||
|
|
||||||
* pwm#_auto_pwm_freq - select base frequency of PWM output. You can select
|
|
||||||
in range of 10.0 to 94.0 Hz in .1 Hz units.
|
|
||||||
(Values 100 to 940).
|
|
||||||
|
|
||||||
The pwm#_auto_pwm_freq can be set to one of the following 8 values. Setting the
|
|
||||||
frequency to a value not on this list, will result in the next higher frequency
|
|
||||||
being selected. The actual device frequency may vary slightly from this
|
|
||||||
specification as designed by the manufacturer. Consult the datasheet for more
|
|
||||||
details. (PWM Frequency values: 100, 150, 230, 300, 380, 470, 620, 940)
|
|
||||||
|
|
||||||
* pwm#_auto_pwm_minctl - this flags selects for temp#_auto_temp_off temperature
|
* pwm#_auto_pwm_minctl - this flags selects for temp#_auto_temp_off temperature
|
||||||
the bahaviour of fans. Write 1 to let fans spinning at
|
the bahaviour of fans. Write 1 to let fans spinning at
|
||||||
pwm#_auto_pwm_min or write 0 to let them off.
|
pwm#_auto_pwm_min or write 0 to let them off.
|
||||||
|
|
|
@ -65,11 +65,10 @@ The LM87 has four pins which can serve one of two possible functions,
|
||||||
depending on the hardware configuration.
|
depending on the hardware configuration.
|
||||||
|
|
||||||
Some functions share pins, so not all functions are available at the same
|
Some functions share pins, so not all functions are available at the same
|
||||||
time. Which are depends on the hardware setup. This driver assumes that
|
time. Which are depends on the hardware setup. This driver normally
|
||||||
the BIOS configured the chip correctly. In that respect, it differs from
|
assumes that firmware configured the chip correctly. Where this is not
|
||||||
the original driver (from lm_sensors for Linux 2.4), which would force the
|
the case, platform code must set the I2C client's platform_data to point
|
||||||
LM87 to an arbitrary, compile-time chosen mode, regardless of the actual
|
to a u8 value to be written to the channel register.
|
||||||
chipset wiring.
|
|
||||||
|
|
||||||
For reference, here is the list of exclusive functions:
|
For reference, here is the list of exclusive functions:
|
||||||
- in0+in5 (default) or temp3
|
- in0+in5 (default) or temp3
|
||||||
|
|
|
@ -11,7 +11,7 @@ Supported chips:
|
||||||
Prefix: 'lm99'
|
Prefix: 'lm99'
|
||||||
Addresses scanned: I2C 0x4c and 0x4d
|
Addresses scanned: I2C 0x4c and 0x4d
|
||||||
Datasheet: Publicly available at the National Semiconductor website
|
Datasheet: Publicly available at the National Semiconductor website
|
||||||
http://www.national.com/pf/LM/LM89.html
|
http://www.national.com/mpf/LM/LM89.html
|
||||||
* National Semiconductor LM99
|
* National Semiconductor LM99
|
||||||
Prefix: 'lm99'
|
Prefix: 'lm99'
|
||||||
Addresses scanned: I2C 0x4c and 0x4d
|
Addresses scanned: I2C 0x4c and 0x4d
|
||||||
|
@ -21,18 +21,32 @@ Supported chips:
|
||||||
Prefix: 'lm86'
|
Prefix: 'lm86'
|
||||||
Addresses scanned: I2C 0x4c
|
Addresses scanned: I2C 0x4c
|
||||||
Datasheet: Publicly available at the National Semiconductor website
|
Datasheet: Publicly available at the National Semiconductor website
|
||||||
http://www.national.com/pf/LM/LM86.html
|
http://www.national.com/mpf/LM/LM86.html
|
||||||
* Analog Devices ADM1032
|
* Analog Devices ADM1032
|
||||||
Prefix: 'adm1032'
|
Prefix: 'adm1032'
|
||||||
Addresses scanned: I2C 0x4c and 0x4d
|
Addresses scanned: I2C 0x4c and 0x4d
|
||||||
Datasheet: Publicly available at the Analog Devices website
|
Datasheet: Publicly available at the ON Semiconductor website
|
||||||
http://www.analog.com/en/prod/0,2877,ADM1032,00.html
|
http://www.onsemi.com/PowerSolutions/product.do?id=ADM1032
|
||||||
* Analog Devices ADT7461
|
* Analog Devices ADT7461
|
||||||
Prefix: 'adt7461'
|
Prefix: 'adt7461'
|
||||||
Addresses scanned: I2C 0x4c and 0x4d
|
Addresses scanned: I2C 0x4c and 0x4d
|
||||||
Datasheet: Publicly available at the Analog Devices website
|
Datasheet: Publicly available at the ON Semiconductor website
|
||||||
http://www.analog.com/en/prod/0,2877,ADT7461,00.html
|
http://www.onsemi.com/PowerSolutions/product.do?id=ADT7461
|
||||||
Note: Only if in ADM1032 compatibility mode
|
* Maxim MAX6646
|
||||||
|
Prefix: 'max6646'
|
||||||
|
Addresses scanned: I2C 0x4d
|
||||||
|
Datasheet: Publicly available at the Maxim website
|
||||||
|
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3497
|
||||||
|
* Maxim MAX6647
|
||||||
|
Prefix: 'max6646'
|
||||||
|
Addresses scanned: I2C 0x4e
|
||||||
|
Datasheet: Publicly available at the Maxim website
|
||||||
|
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3497
|
||||||
|
* Maxim MAX6649
|
||||||
|
Prefix: 'max6646'
|
||||||
|
Addresses scanned: I2C 0x4c
|
||||||
|
Datasheet: Publicly available at the Maxim website
|
||||||
|
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3497
|
||||||
* Maxim MAX6657
|
* Maxim MAX6657
|
||||||
Prefix: 'max6657'
|
Prefix: 'max6657'
|
||||||
Addresses scanned: I2C 0x4c
|
Addresses scanned: I2C 0x4c
|
||||||
|
@ -70,25 +84,21 @@ Description
|
||||||
|
|
||||||
The LM90 is a digital temperature sensor. It senses its own temperature as
|
The LM90 is a digital temperature sensor. It senses its own temperature as
|
||||||
well as the temperature of up to one external diode. It is compatible
|
well as the temperature of up to one external diode. It is compatible
|
||||||
with many other devices such as the LM86, the LM89, the LM99, the ADM1032,
|
with many other devices, many of which are supported by this driver.
|
||||||
the MAX6657, MAX6658, MAX6659, MAX6680 and the MAX6681 all of which are
|
|
||||||
supported by this driver.
|
|
||||||
|
|
||||||
Note that there is no easy way to differentiate between the MAX6657,
|
Note that there is no easy way to differentiate between the MAX6657,
|
||||||
MAX6658 and MAX6659 variants. The extra address and features of the
|
MAX6658 and MAX6659 variants. The extra address and features of the
|
||||||
MAX6659 are not supported by this driver. The MAX6680 and MAX6681 only
|
MAX6659 are not supported by this driver. The MAX6680 and MAX6681 only
|
||||||
differ in their pinout, therefore they obviously can't (and don't need to)
|
differ in their pinout, therefore they obviously can't (and don't need to)
|
||||||
be distinguished. Additionally, the ADT7461 is supported if found in
|
be distinguished.
|
||||||
ADM1032 compatibility mode.
|
|
||||||
|
|
||||||
The specificity of this family of chipsets over the ADM1021/LM84
|
The specificity of this family of chipsets over the ADM1021/LM84
|
||||||
family is that it features critical limits with hysteresis, and an
|
family is that it features critical limits with hysteresis, and an
|
||||||
increased resolution of the remote temperature measurement.
|
increased resolution of the remote temperature measurement.
|
||||||
|
|
||||||
The different chipsets of the family are not strictly identical, although
|
The different chipsets of the family are not strictly identical, although
|
||||||
very similar. This driver doesn't handle any specific feature for now,
|
very similar. For reference, here comes a non-exhaustive list of specific
|
||||||
with the exception of SMBus PEC. For reference, here comes a non-exhaustive
|
features:
|
||||||
list of specific features:
|
|
||||||
|
|
||||||
LM90:
|
LM90:
|
||||||
* Filter and alert configuration register at 0xBF.
|
* Filter and alert configuration register at 0xBF.
|
||||||
|
@ -114,9 +124,11 @@ ADT7461:
|
||||||
* Lower resolution for remote temperature
|
* Lower resolution for remote temperature
|
||||||
|
|
||||||
MAX6657 and MAX6658:
|
MAX6657 and MAX6658:
|
||||||
|
* Better local resolution
|
||||||
* Remote sensor type selection
|
* Remote sensor type selection
|
||||||
|
|
||||||
MAX6659:
|
MAX6659:
|
||||||
|
* Better local resolution
|
||||||
* Selectable address
|
* Selectable address
|
||||||
* Second critical temperature limit
|
* Second critical temperature limit
|
||||||
* Remote sensor type selection
|
* Remote sensor type selection
|
||||||
|
@ -127,7 +139,8 @@ MAX6680 and MAX6681:
|
||||||
|
|
||||||
All temperature values are given in degrees Celsius. Resolution
|
All temperature values are given in degrees Celsius. Resolution
|
||||||
is 1.0 degree for the local temperature, 0.125 degree for the remote
|
is 1.0 degree for the local temperature, 0.125 degree for the remote
|
||||||
temperature.
|
temperature, except for the MAX6657, MAX6658 and MAX6659 which have a
|
||||||
|
resolution of 0.125 degree for both temperatures.
|
||||||
|
|
||||||
Each sensor has its own high and low limits, plus a critical limit.
|
Each sensor has its own high and low limits, plus a critical limit.
|
||||||
Additionally, there is a relative hysteresis value common to both critical
|
Additionally, there is a relative hysteresis value common to both critical
|
||||||
|
|
|
@ -5,12 +5,7 @@ Supported chips:
|
||||||
* National Semiconductor PC87360, PC87363, PC87364, PC87365 and PC87366
|
* National Semiconductor PC87360, PC87363, PC87364, PC87365 and PC87366
|
||||||
Prefixes: 'pc87360', 'pc87363', 'pc87364', 'pc87365', 'pc87366'
|
Prefixes: 'pc87360', 'pc87363', 'pc87364', 'pc87365', 'pc87366'
|
||||||
Addresses scanned: none, address read from Super I/O config space
|
Addresses scanned: none, address read from Super I/O config space
|
||||||
Datasheets:
|
Datasheets: No longer available
|
||||||
http://www.national.com/pf/PC/PC87360.html
|
|
||||||
http://www.national.com/pf/PC/PC87363.html
|
|
||||||
http://www.national.com/pf/PC/PC87364.html
|
|
||||||
http://www.national.com/pf/PC/PC87365.html
|
|
||||||
http://www.national.com/pf/PC/PC87366.html
|
|
||||||
|
|
||||||
Authors: Jean Delvare <khali@linux-fr.org>
|
Authors: Jean Delvare <khali@linux-fr.org>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ Supported chips:
|
||||||
* National Semiconductor PC87427
|
* National Semiconductor PC87427
|
||||||
Prefix: 'pc87427'
|
Prefix: 'pc87427'
|
||||||
Addresses scanned: none, address read from Super I/O config space
|
Addresses scanned: none, address read from Super I/O config space
|
||||||
Datasheet: http://www.winbond.com.tw/E-WINBONDHTM/partner/apc_007.html
|
Datasheet: No longer available
|
||||||
|
|
||||||
Author: Jean Delvare <khali@linux-fr.org>
|
Author: Jean Delvare <khali@linux-fr.org>
|
||||||
|
|
||||||
|
|
|
@ -353,7 +353,7 @@ in6=255
|
||||||
|
|
||||||
# PWM
|
# PWM
|
||||||
|
|
||||||
Additional info about PWM on the AS99127F (may apply to other Asus
|
* Additional info about PWM on the AS99127F (may apply to other Asus
|
||||||
chips as well) by Jean Delvare as of 2004-04-09:
|
chips as well) by Jean Delvare as of 2004-04-09:
|
||||||
|
|
||||||
AS99127F revision 2 seems to have two PWM registers at 0x59 and 0x5A,
|
AS99127F revision 2 seems to have two PWM registers at 0x59 and 0x5A,
|
||||||
|
@ -396,7 +396,7 @@ Please contact us if you can figure out how it is supposed to work. As
|
||||||
long as we don't know more, the w83781d driver doesn't handle PWM on
|
long as we don't know more, the w83781d driver doesn't handle PWM on
|
||||||
AS99127F chips at all.
|
AS99127F chips at all.
|
||||||
|
|
||||||
Additional info about PWM on the AS99127F rev.1 by Hector Martin:
|
* Additional info about PWM on the AS99127F rev.1 by Hector Martin:
|
||||||
|
|
||||||
I've been fiddling around with the (in)famous 0x59 register and
|
I've been fiddling around with the (in)famous 0x59 register and
|
||||||
found out the following values do work as a form of coarse pwm:
|
found out the following values do work as a form of coarse pwm:
|
||||||
|
@ -418,3 +418,36 @@ change.
|
||||||
My mobo is an ASUS A7V266-E. This behavior is similar to what I got
|
My mobo is an ASUS A7V266-E. This behavior is similar to what I got
|
||||||
with speedfan under Windows, where 0-15% would be off, 15-2x% (can't
|
with speedfan under Windows, where 0-15% would be off, 15-2x% (can't
|
||||||
remember the exact value) would be 70% and higher would be full on.
|
remember the exact value) would be 70% and higher would be full on.
|
||||||
|
|
||||||
|
* Additional info about PWM on the AS99127F rev.1 from lm-sensors
|
||||||
|
ticket #2350:
|
||||||
|
|
||||||
|
I conducted some experiment on Asus P3B-F motherboard with AS99127F
|
||||||
|
(Ver. 1).
|
||||||
|
|
||||||
|
I confirm that 0x59 register control the CPU_Fan Header on this
|
||||||
|
motherboard, and 0x5a register control PWR_Fan.
|
||||||
|
|
||||||
|
In order to reduce the dependency of specific fan, the measurement is
|
||||||
|
conducted with a digital scope without fan connected. I found out that
|
||||||
|
P3B-F actually output variable DC voltage on fan header center pin,
|
||||||
|
looks like PWM is filtered on this motherboard.
|
||||||
|
|
||||||
|
Here are some of measurements:
|
||||||
|
|
||||||
|
0x80 20 mV
|
||||||
|
0x81 20 mV
|
||||||
|
0x82 232 mV
|
||||||
|
0x83 1.2 V
|
||||||
|
0x84 2.31 V
|
||||||
|
0x85 3.44 V
|
||||||
|
0x86 4.62 V
|
||||||
|
0x87 5.81 V
|
||||||
|
0x88 7.01 V
|
||||||
|
9x89 8.22 V
|
||||||
|
0x8a 9.42 V
|
||||||
|
0x8b 10.6 V
|
||||||
|
0x8c 11.9 V
|
||||||
|
0x8d 12.4 V
|
||||||
|
0x8e 12.4 V
|
||||||
|
0x8f 12.4 V
|
||||||
|
|
|
@ -58,29 +58,35 @@ internal state that allows no clean access (Bank with ID register is not
|
||||||
currently selected). If you know the address of the chip, use a 'force'
|
currently selected). If you know the address of the chip, use a 'force'
|
||||||
parameter; this will put it into a more well-behaved state first.
|
parameter; this will put it into a more well-behaved state first.
|
||||||
|
|
||||||
The driver implements three temperature sensors, five fan rotation speed
|
The driver implements three temperature sensors, ten voltage sensors,
|
||||||
sensors, and ten voltage sensors.
|
five fan rotation speed sensors and manual PWM control of each fan.
|
||||||
|
|
||||||
Temperatures are measured in degrees Celsius and measurement resolution is 1
|
Temperatures are measured in degrees Celsius and measurement resolution is 1
|
||||||
degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
|
degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
|
||||||
the temperature gets higher than the Overtemperature Shutdown value; it stays
|
the temperature gets higher than the Overtemperature Shutdown value; it stays
|
||||||
on until the temperature falls below the Hysteresis value.
|
on until the temperature falls below the Hysteresis value.
|
||||||
|
|
||||||
|
Voltage sensors (also known as IN sensors) report their values in millivolts.
|
||||||
|
An alarm is triggered if the voltage has crossed a programmable minimum
|
||||||
|
or maximum limit.
|
||||||
|
|
||||||
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
|
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
|
||||||
triggered if the rotation speed has dropped below a programmable limit. Fan
|
triggered if the rotation speed has dropped below a programmable limit. Fan
|
||||||
readings can be divided by a programmable divider (1, 2, 4, 8, 16,
|
readings can be divided by a programmable divider (1, 2, 4, 8, 16,
|
||||||
32, 64 or 128 for all fans) to give the readings more range or accuracy.
|
32, 64 or 128 for all fans) to give the readings more range or accuracy.
|
||||||
|
|
||||||
Voltage sensors (also known as IN sensors) report their values in millivolts.
|
Each fan controlled is controlled by PWM. The PWM duty cycle can be read and
|
||||||
An alarm is triggered if the voltage has crossed a programmable minimum
|
set for each fan separately. Valid values range from 0 (stop) to 255 (full).
|
||||||
or maximum limit.
|
PWM 1-3 support Thermal Cruise mode, in which the PWMs are automatically
|
||||||
|
regulated to keep respectively temp 1-3 at a certain target temperature.
|
||||||
|
See below for the description of the sysfs-interface.
|
||||||
|
|
||||||
The w83791d has a global bit used to enable beeping from the speaker when an
|
The w83791d has a global bit used to enable beeping from the speaker when an
|
||||||
alarm is triggered as well as a bitmask to enable or disable the beep for
|
alarm is triggered as well as a bitmask to enable or disable the beep for
|
||||||
specific alarms. You need both the global beep enable bit and the
|
specific alarms. You need both the global beep enable bit and the
|
||||||
corresponding beep bit to be on for a triggered alarm to sound a beep.
|
corresponding beep bit to be on for a triggered alarm to sound a beep.
|
||||||
|
|
||||||
The sysfs interface to the gloabal enable is via the sysfs beep_enable file.
|
The sysfs interface to the global enable is via the sysfs beep_enable file.
|
||||||
This file is used for both legacy and new code.
|
This file is used for both legacy and new code.
|
||||||
|
|
||||||
The sysfs interface to the beep bitmask has migrated from the original legacy
|
The sysfs interface to the beep bitmask has migrated from the original legacy
|
||||||
|
@ -105,6 +111,27 @@ going forward.
|
||||||
The driver reads the hardware chip values at most once every three seconds.
|
The driver reads the hardware chip values at most once every three seconds.
|
||||||
User mode code requesting values more often will receive cached values.
|
User mode code requesting values more often will receive cached values.
|
||||||
|
|
||||||
|
/sys files
|
||||||
|
----------
|
||||||
|
The sysfs-interface is documented in the 'sysfs-interface' file. Only
|
||||||
|
chip-specific options are documented here.
|
||||||
|
|
||||||
|
pwm[1-3]_enable - this file controls mode of fan/temperature control for
|
||||||
|
fan 1-3. Fan/PWM 4-5 only support manual mode.
|
||||||
|
* 1 Manual mode
|
||||||
|
* 2 Thermal Cruise mode
|
||||||
|
* 3 Fan Speed Cruise mode (no further support)
|
||||||
|
|
||||||
|
temp[1-3]_target - defines the target temperature for Thermal Cruise mode.
|
||||||
|
Unit: millidegree Celsius
|
||||||
|
RW
|
||||||
|
|
||||||
|
temp[1-3]_tolerance - temperature tolerance for Thermal Cruise mode.
|
||||||
|
Specifies an interval around the target temperature
|
||||||
|
in which the fan speed is not changed.
|
||||||
|
Unit: millidegree Celsius
|
||||||
|
RW
|
||||||
|
|
||||||
Alarms bitmap vs. beep_mask bitmask
|
Alarms bitmap vs. beep_mask bitmask
|
||||||
------------------------------------
|
------------------------------------
|
||||||
For legacy code using the alarms and beep_mask files:
|
For legacy code using the alarms and beep_mask files:
|
||||||
|
@ -132,7 +159,3 @@ tart2 : alarms: 0x020000 beep_mask: 0x080000 <== mismatch
|
||||||
tart3 : alarms: 0x040000 beep_mask: 0x100000 <== mismatch
|
tart3 : alarms: 0x040000 beep_mask: 0x100000 <== mismatch
|
||||||
case_open : alarms: 0x001000 beep_mask: 0x001000
|
case_open : alarms: 0x001000 beep_mask: 0x001000
|
||||||
global_enable: alarms: -------- beep_mask: 0x800000 (modified via beep_enable)
|
global_enable: alarms: -------- beep_mask: 0x800000 (modified via beep_enable)
|
||||||
|
|
||||||
W83791D TODO:
|
|
||||||
---------------
|
|
||||||
Provide a patch for smart-fan control (still need appropriate motherboard/fans)
|
|
||||||
|
|
|
@ -92,6 +92,7 @@ Code Seq# Include File Comments
|
||||||
'J' 00-1F drivers/scsi/gdth_ioctl.h
|
'J' 00-1F drivers/scsi/gdth_ioctl.h
|
||||||
'K' all linux/kd.h
|
'K' all linux/kd.h
|
||||||
'L' 00-1F linux/loop.h
|
'L' 00-1F linux/loop.h
|
||||||
|
'L' 20-2F driver/usb/misc/vstusb.h
|
||||||
'L' E0-FF linux/ppdd.h encrypted disk device driver
|
'L' E0-FF linux/ppdd.h encrypted disk device driver
|
||||||
<http://linux01.gwdg.de/~alatham/ppdd.html>
|
<http://linux01.gwdg.de/~alatham/ppdd.html>
|
||||||
'M' all linux/soundcard.h
|
'M' all linux/soundcard.h
|
||||||
|
@ -110,6 +111,8 @@ Code Seq# Include File Comments
|
||||||
'W' 00-1F linux/wanrouter.h conflict!
|
'W' 00-1F linux/wanrouter.h conflict!
|
||||||
'X' all linux/xfs_fs.h
|
'X' all linux/xfs_fs.h
|
||||||
'Y' all linux/cyclades.h
|
'Y' all linux/cyclades.h
|
||||||
|
'[' 00-07 linux/usb/usbtmc.h USB Test and Measurement Devices
|
||||||
|
<mailto:gregkh@suse.de>
|
||||||
'a' all ATM on linux
|
'a' all ATM on linux
|
||||||
<http://lrcwww.epfl.ch/linux-atm/magic.html>
|
<http://lrcwww.epfl.ch/linux-atm/magic.html>
|
||||||
'b' 00-FF bit3 vme host bridge
|
'b' 00-FF bit3 vme host bridge
|
||||||
|
|
|
@ -2253,6 +2253,25 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||||
autosuspended. Devices for which the delay is set
|
autosuspended. Devices for which the delay is set
|
||||||
to a negative value won't be autosuspended at all.
|
to a negative value won't be autosuspended at all.
|
||||||
|
|
||||||
|
usbcore.usbfs_snoop=
|
||||||
|
[USB] Set to log all usbfs traffic (default 0 = off).
|
||||||
|
|
||||||
|
usbcore.blinkenlights=
|
||||||
|
[USB] Set to cycle leds on hubs (default 0 = off).
|
||||||
|
|
||||||
|
usbcore.old_scheme_first=
|
||||||
|
[USB] Start with the old device initialization
|
||||||
|
scheme (default 0 = off).
|
||||||
|
|
||||||
|
usbcore.use_both_schemes=
|
||||||
|
[USB] Try the other device initialization scheme
|
||||||
|
if the first one fails (default 1 = enabled).
|
||||||
|
|
||||||
|
usbcore.initial_descriptor_timeout=
|
||||||
|
[USB] Specifies timeout for the initial 64-byte
|
||||||
|
USB_REQ_GET_DESCRIPTOR request in milliseconds
|
||||||
|
(default 5000 = 5.0 seconds).
|
||||||
|
|
||||||
usbhid.mousepoll=
|
usbhid.mousepoll=
|
||||||
[USBHID] The interval which mice are to be polled at.
|
[USBHID] The interval which mice are to be polled at.
|
||||||
|
|
||||||
|
|
|
@ -369,4 +369,5 @@ can be ORed together:
|
||||||
2 - A module was force loaded by insmod -f.
|
2 - A module was force loaded by insmod -f.
|
||||||
Set by modutils >= 2.4.9 and module-init-tools.
|
Set by modutils >= 2.4.9 and module-init-tools.
|
||||||
4 - Unsafe SMP processors: SMP with CPUs not designed for SMP.
|
4 - Unsafe SMP processors: SMP with CPUs not designed for SMP.
|
||||||
|
64 - A module from drivers/staging was loaded.
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,11 @@ Therefore no guarantee is made that the URBs have been unlinked when
|
||||||
the call returns. They may be unlinked later but will be unlinked in
|
the call returns. They may be unlinked later but will be unlinked in
|
||||||
finite time.
|
finite time.
|
||||||
|
|
||||||
|
usb_scuttle_anchored_urbs()
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
All URBs of an anchor are unanchored en masse.
|
||||||
|
|
||||||
usb_wait_anchor_empty_timeout()
|
usb_wait_anchor_empty_timeout()
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
|
@ -59,4 +64,16 @@ This function waits for all URBs associated with an anchor to finish
|
||||||
or a timeout, whichever comes first. Its return value will tell you
|
or a timeout, whichever comes first. Its return value will tell you
|
||||||
whether the timeout was reached.
|
whether the timeout was reached.
|
||||||
|
|
||||||
|
usb_anchor_empty()
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Returns true if no URBs are associated with an anchor. Locking
|
||||||
|
is the caller's responsibility.
|
||||||
|
|
||||||
|
usb_get_from_anchor()
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Returns the oldest anchored URB of an anchor. The URB is unanchored
|
||||||
|
and returned with a reference. As you may mix URBs to several
|
||||||
|
destinations in one anchor you have no guarantee the chronologically
|
||||||
|
first submitted URB is returned.
|
|
@ -0,0 +1,46 @@
|
||||||
|
USB 7-Segment Numeric Display
|
||||||
|
Manufactured by Delcom Engineering
|
||||||
|
|
||||||
|
Device Information
|
||||||
|
------------------
|
||||||
|
USB VENDOR_ID 0x0fc5
|
||||||
|
USB PRODUCT_ID 0x1227
|
||||||
|
Both the 6 character and 8 character displays have PRODUCT_ID,
|
||||||
|
and according to Delcom Engineering no queryable information
|
||||||
|
can be obtained from the device to tell them apart.
|
||||||
|
|
||||||
|
Device Modes
|
||||||
|
------------
|
||||||
|
By default, the driver assumes the display is only 6 characters
|
||||||
|
The mode for 6 characters is:
|
||||||
|
MSB 0x06; LSB 0x3f
|
||||||
|
For the 8 character display:
|
||||||
|
MSB 0x08; LSB 0xff
|
||||||
|
The device can accept "text" either in raw, hex, or ascii textmode.
|
||||||
|
raw controls each segment manually,
|
||||||
|
hex expects a value between 0-15 per character,
|
||||||
|
ascii expects a value between '0'-'9' and 'A'-'F'.
|
||||||
|
The default is ascii.
|
||||||
|
|
||||||
|
Device Operation
|
||||||
|
----------------
|
||||||
|
1. Turn on the device:
|
||||||
|
echo 1 > /sys/bus/usb/.../powered
|
||||||
|
2. Set the device's mode:
|
||||||
|
echo $mode_msb > /sys/bus/usb/.../mode_msb
|
||||||
|
echo $mode_lsb > /sys/bus/usb/.../mode_lsb
|
||||||
|
3. Set the textmode:
|
||||||
|
echo $textmode > /sys/bus/usb/.../textmode
|
||||||
|
4. set the text (for example):
|
||||||
|
echo "123ABC" > /sys/bus/usb/.../text (ascii)
|
||||||
|
echo "A1B2" > /sys/bus/usb/.../text (ascii)
|
||||||
|
echo -ne "\x01\x02\x03" > /sys/bus/usb/.../text (hex)
|
||||||
|
5. Set the decimal places.
|
||||||
|
The device has either 6 or 8 decimal points.
|
||||||
|
to set the nth decimal place calculate 10 ** n
|
||||||
|
and echo it in to /sys/bus/usb/.../decimals
|
||||||
|
To set multiple decimals points sum up each power.
|
||||||
|
For example, to set the 0th and 3rd decimal place
|
||||||
|
echo 1001 > /sys/bus/usb/.../decimals
|
||||||
|
|
||||||
|
|
|
@ -350,12 +350,12 @@ without holding the mutex.
|
||||||
|
|
||||||
There also are a couple of utility routines drivers can use:
|
There also are a couple of utility routines drivers can use:
|
||||||
|
|
||||||
usb_autopm_enable() sets pm_usage_cnt to 1 and then calls
|
usb_autopm_enable() sets pm_usage_cnt to 0 and then calls
|
||||||
usb_autopm_set_interface(), which will attempt an autoresume.
|
|
||||||
|
|
||||||
usb_autopm_disable() sets pm_usage_cnt to 0 and then calls
|
|
||||||
usb_autopm_set_interface(), which will attempt an autosuspend.
|
usb_autopm_set_interface(), which will attempt an autosuspend.
|
||||||
|
|
||||||
|
usb_autopm_disable() sets pm_usage_cnt to 1 and then calls
|
||||||
|
usb_autopm_set_interface(), which will attempt an autoresume.
|
||||||
|
|
||||||
The conventional usage pattern is that a driver calls
|
The conventional usage pattern is that a driver calls
|
||||||
usb_autopm_get_interface() in its open routine and
|
usb_autopm_get_interface() in its open routine and
|
||||||
usb_autopm_put_interface() in its close or release routine. But
|
usb_autopm_put_interface() in its close or release routine. But
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
0 -> Unknown board (au0828)
|
0 -> Unknown board (au0828)
|
||||||
1 -> Hauppauge HVR950Q (au0828) [2040:7200,2040:7210,2040:7217,2040:721b,2040:721f,2040:7280,0fd9:0008]
|
1 -> Hauppauge HVR950Q (au0828) [2040:7200,2040:7210,2040:7217,2040:721b,2040:721e,2040:721f,2040:7280,0fd9:0008]
|
||||||
2 -> Hauppauge HVR850 (au0828) [2040:7240]
|
2 -> Hauppauge HVR850 (au0828) [2040:7240]
|
||||||
3 -> DViCO FusionHDTV USB (au0828) [0fe9:d620]
|
3 -> DViCO FusionHDTV USB (au0828) [0fe9:d620]
|
||||||
4 -> Hauppauge HVR950Q rev xxF8 (au0828) [2040:7201,2040:7211,2040:7281]
|
4 -> Hauppauge HVR950Q rev xxF8 (au0828) [2040:7201,2040:7211,2040:7281]
|
||||||
|
|
|
@ -75,3 +75,4 @@ tuner=73 - Samsung TCPG 6121P30A
|
||||||
tuner=75 - Philips TEA5761 FM Radio
|
tuner=75 - Philips TEA5761 FM Radio
|
||||||
tuner=76 - Xceive 5000 tuner
|
tuner=76 - Xceive 5000 tuner
|
||||||
tuner=77 - TCL tuner MF02GIP-5N-E
|
tuner=77 - TCL tuner MF02GIP-5N-E
|
||||||
|
tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner
|
||||||
|
|
|
@ -3937,7 +3937,7 @@ M: jbglaw@lug-owl.de
|
||||||
L: linux-kernel@vger.kernel.org
|
L: linux-kernel@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
|
||||||
STABLE BRANCH:
|
STABLE BRANCH
|
||||||
P: Greg Kroah-Hartman
|
P: Greg Kroah-Hartman
|
||||||
M: greg@kroah.com
|
M: greg@kroah.com
|
||||||
P: Chris Wright
|
P: Chris Wright
|
||||||
|
@ -3945,6 +3945,13 @@ M: chrisw@sous-sol.org
|
||||||
L: stable@kernel.org
|
L: stable@kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
|
||||||
|
STAGING SUBSYSTEM
|
||||||
|
P: Greg Kroah-Hartman
|
||||||
|
M: gregkh@suse.de
|
||||||
|
L: linux-kernel@vger.kernel.org
|
||||||
|
T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
|
||||||
|
S: Maintained
|
||||||
|
|
||||||
STARFIRE/DURALAN NETWORK DRIVER
|
STARFIRE/DURALAN NETWORK DRIVER
|
||||||
P: Ion Badulescu
|
P: Ion Badulescu
|
||||||
M: ionut@cs.columbia.edu
|
M: ionut@cs.columbia.edu
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <linux/mv643xx_eth.h>
|
#include <linux/mv643xx_eth.h>
|
||||||
#include <linux/ata_platform.h>
|
#include <linux/ata_platform.h>
|
||||||
#include <linux/spi/orion_spi.h>
|
#include <linux/spi/orion_spi.h>
|
||||||
|
#include <net/dsa.h>
|
||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
#include <asm/timex.h>
|
#include <asm/timex.h>
|
||||||
#include <asm/mach/map.h>
|
#include <asm/mach/map.h>
|
||||||
|
@ -151,6 +152,40 @@ void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Ethernet switch
|
||||||
|
****************************************************************************/
|
||||||
|
static struct resource kirkwood_switch_resources[] = {
|
||||||
|
{
|
||||||
|
.start = 0,
|
||||||
|
.end = 0,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device kirkwood_switch_device = {
|
||||||
|
.name = "dsa",
|
||||||
|
.id = 0,
|
||||||
|
.num_resources = 0,
|
||||||
|
.resource = kirkwood_switch_resources,
|
||||||
|
};
|
||||||
|
|
||||||
|
void __init kirkwood_ge00_switch_init(struct dsa_platform_data *d, int irq)
|
||||||
|
{
|
||||||
|
if (irq != NO_IRQ) {
|
||||||
|
kirkwood_switch_resources[0].start = irq;
|
||||||
|
kirkwood_switch_resources[0].end = irq;
|
||||||
|
kirkwood_switch_device.num_resources = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->mii_bus = &kirkwood_ge00_shared.dev;
|
||||||
|
d->netdev = &kirkwood_ge00.dev;
|
||||||
|
kirkwood_switch_device.dev.platform_data = d;
|
||||||
|
|
||||||
|
platform_device_register(&kirkwood_switch_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* SoC RTC
|
* SoC RTC
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#ifndef __ARCH_KIRKWOOD_COMMON_H
|
#ifndef __ARCH_KIRKWOOD_COMMON_H
|
||||||
#define __ARCH_KIRKWOOD_COMMON_H
|
#define __ARCH_KIRKWOOD_COMMON_H
|
||||||
|
|
||||||
|
struct dsa_platform_data;
|
||||||
struct mv643xx_eth_platform_data;
|
struct mv643xx_eth_platform_data;
|
||||||
struct mv_sata_platform_data;
|
struct mv_sata_platform_data;
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@ void kirkwood_pcie_id(u32 *dev, u32 *rev);
|
||||||
|
|
||||||
void kirkwood_ehci_init(void);
|
void kirkwood_ehci_init(void);
|
||||||
void kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data);
|
void kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data);
|
||||||
|
void kirkwood_ge00_switch_init(struct dsa_platform_data *d, int irq);
|
||||||
void kirkwood_pcie_init(void);
|
void kirkwood_pcie_init(void);
|
||||||
void kirkwood_rtc_init(void);
|
void kirkwood_rtc_init(void);
|
||||||
void kirkwood_sata_init(struct mv_sata_platform_data *sata_data);
|
void kirkwood_sata_init(struct mv_sata_platform_data *sata_data);
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <linux/ata_platform.h>
|
#include <linux/ata_platform.h>
|
||||||
#include <linux/mv643xx_eth.h>
|
#include <linux/mv643xx_eth.h>
|
||||||
#include <linux/ethtool.h>
|
#include <linux/ethtool.h>
|
||||||
|
#include <net/dsa.h>
|
||||||
#include <asm/mach-types.h>
|
#include <asm/mach-types.h>
|
||||||
#include <asm/mach/arch.h>
|
#include <asm/mach/arch.h>
|
||||||
#include <asm/mach/pci.h>
|
#include <asm/mach/pci.h>
|
||||||
|
@ -74,6 +75,15 @@ static struct mv643xx_eth_platform_data rd88f6281_ge00_data = {
|
||||||
.duplex = DUPLEX_FULL,
|
.duplex = DUPLEX_FULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct dsa_platform_data rd88f6281_switch_data = {
|
||||||
|
.port_names[0] = "lan1",
|
||||||
|
.port_names[1] = "lan2",
|
||||||
|
.port_names[2] = "lan3",
|
||||||
|
.port_names[3] = "lan4",
|
||||||
|
.port_names[4] = "wan",
|
||||||
|
.port_names[5] = "cpu",
|
||||||
|
};
|
||||||
|
|
||||||
static struct mv_sata_platform_data rd88f6281_sata_data = {
|
static struct mv_sata_platform_data rd88f6281_sata_data = {
|
||||||
.n_ports = 2,
|
.n_ports = 2,
|
||||||
};
|
};
|
||||||
|
@ -87,6 +97,7 @@ static void __init rd88f6281_init(void)
|
||||||
|
|
||||||
kirkwood_ehci_init();
|
kirkwood_ehci_init();
|
||||||
kirkwood_ge00_init(&rd88f6281_ge00_data);
|
kirkwood_ge00_init(&rd88f6281_ge00_data);
|
||||||
|
kirkwood_ge00_switch_init(&rd88f6281_switch_data, NO_IRQ);
|
||||||
kirkwood_rtc_init();
|
kirkwood_rtc_init();
|
||||||
kirkwood_sata_init(&rd88f6281_sata_data);
|
kirkwood_sata_init(&rd88f6281_sata_data);
|
||||||
kirkwood_uart0_init();
|
kirkwood_uart0_init();
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/ata_platform.h>
|
#include <linux/ata_platform.h>
|
||||||
#include <linux/mv643xx_eth.h>
|
#include <linux/mv643xx_eth.h>
|
||||||
|
#include <linux/ethtool.h>
|
||||||
#include <mach/mv78xx0.h>
|
#include <mach/mv78xx0.h>
|
||||||
#include <asm/mach-types.h>
|
#include <asm/mach-types.h>
|
||||||
#include <asm/mach/arch.h>
|
#include <asm/mach/arch.h>
|
||||||
|
@ -28,10 +29,14 @@ static struct mv643xx_eth_platform_data db78x00_ge01_data = {
|
||||||
|
|
||||||
static struct mv643xx_eth_platform_data db78x00_ge10_data = {
|
static struct mv643xx_eth_platform_data db78x00_ge10_data = {
|
||||||
.phy_addr = MV643XX_ETH_PHY_NONE,
|
.phy_addr = MV643XX_ETH_PHY_NONE,
|
||||||
|
.speed = SPEED_1000,
|
||||||
|
.duplex = DUPLEX_FULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct mv643xx_eth_platform_data db78x00_ge11_data = {
|
static struct mv643xx_eth_platform_data db78x00_ge11_data = {
|
||||||
.phy_addr = MV643XX_ETH_PHY_NONE,
|
.phy_addr = MV643XX_ETH_PHY_NONE,
|
||||||
|
.speed = SPEED_1000,
|
||||||
|
.duplex = DUPLEX_FULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct mv_sata_platform_data db78x00_sata_data = {
|
static struct mv_sata_platform_data db78x00_sata_data = {
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <linux/mv643xx_i2c.h>
|
#include <linux/mv643xx_i2c.h>
|
||||||
#include <linux/ata_platform.h>
|
#include <linux/ata_platform.h>
|
||||||
#include <linux/spi/orion_spi.h>
|
#include <linux/spi/orion_spi.h>
|
||||||
|
#include <net/dsa.h>
|
||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
#include <asm/timex.h>
|
#include <asm/timex.h>
|
||||||
|
@ -197,6 +198,40 @@ void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Ethernet switch
|
||||||
|
****************************************************************************/
|
||||||
|
static struct resource orion5x_switch_resources[] = {
|
||||||
|
{
|
||||||
|
.start = 0,
|
||||||
|
.end = 0,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device orion5x_switch_device = {
|
||||||
|
.name = "dsa",
|
||||||
|
.id = 0,
|
||||||
|
.num_resources = 0,
|
||||||
|
.resource = orion5x_switch_resources,
|
||||||
|
};
|
||||||
|
|
||||||
|
void __init orion5x_eth_switch_init(struct dsa_platform_data *d, int irq)
|
||||||
|
{
|
||||||
|
if (irq != NO_IRQ) {
|
||||||
|
orion5x_switch_resources[0].start = irq;
|
||||||
|
orion5x_switch_resources[0].end = irq;
|
||||||
|
orion5x_switch_device.num_resources = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->mii_bus = &orion5x_eth_shared.dev;
|
||||||
|
d->netdev = &orion5x_eth.dev;
|
||||||
|
orion5x_switch_device.dev.platform_data = d;
|
||||||
|
|
||||||
|
platform_device_register(&orion5x_switch_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* I2C
|
* I2C
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -275,7 +310,8 @@ void __init orion5x_sata_init(struct mv_sata_platform_data *sata_data)
|
||||||
* SPI
|
* SPI
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
static struct orion_spi_info orion5x_spi_plat_data = {
|
static struct orion_spi_info orion5x_spi_plat_data = {
|
||||||
.tclk = 0,
|
.tclk = 0,
|
||||||
|
.enable_clock_fix = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct resource orion5x_spi_resources[] = {
|
static struct resource orion5x_spi_resources[] = {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef __ARCH_ORION5X_COMMON_H
|
#ifndef __ARCH_ORION5X_COMMON_H
|
||||||
#define __ARCH_ORION5X_COMMON_H
|
#define __ARCH_ORION5X_COMMON_H
|
||||||
|
|
||||||
|
struct dsa_platform_data;
|
||||||
struct mv643xx_eth_platform_data;
|
struct mv643xx_eth_platform_data;
|
||||||
struct mv_sata_platform_data;
|
struct mv_sata_platform_data;
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@ void orion5x_setup_pcie_wa_win(u32 base, u32 size);
|
||||||
void orion5x_ehci0_init(void);
|
void orion5x_ehci0_init(void);
|
||||||
void orion5x_ehci1_init(void);
|
void orion5x_ehci1_init(void);
|
||||||
void orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data);
|
void orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data);
|
||||||
|
void orion5x_eth_switch_init(struct dsa_platform_data *d, int irq);
|
||||||
void orion5x_i2c_init(void);
|
void orion5x_i2c_init(void);
|
||||||
void orion5x_sata_init(struct mv_sata_platform_data *sata_data);
|
void orion5x_sata_init(struct mv_sata_platform_data *sata_data);
|
||||||
void orion5x_spi_init(void);
|
void orion5x_spi_init(void);
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <linux/mtd/physmap.h>
|
#include <linux/mtd/physmap.h>
|
||||||
#include <linux/mv643xx_eth.h>
|
#include <linux/mv643xx_eth.h>
|
||||||
#include <linux/ethtool.h>
|
#include <linux/ethtool.h>
|
||||||
|
#include <net/dsa.h>
|
||||||
#include <asm/mach-types.h>
|
#include <asm/mach-types.h>
|
||||||
#include <asm/gpio.h>
|
#include <asm/gpio.h>
|
||||||
#include <asm/leds.h>
|
#include <asm/leds.h>
|
||||||
|
@ -93,6 +94,15 @@ static struct mv643xx_eth_platform_data rd88f5181l_fxo_eth_data = {
|
||||||
.duplex = DUPLEX_FULL,
|
.duplex = DUPLEX_FULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct dsa_platform_data rd88f5181l_fxo_switch_data = {
|
||||||
|
.port_names[0] = "lan2",
|
||||||
|
.port_names[1] = "lan1",
|
||||||
|
.port_names[2] = "wan",
|
||||||
|
.port_names[3] = "cpu",
|
||||||
|
.port_names[5] = "lan4",
|
||||||
|
.port_names[7] = "lan3",
|
||||||
|
};
|
||||||
|
|
||||||
static void __init rd88f5181l_fxo_init(void)
|
static void __init rd88f5181l_fxo_init(void)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -107,6 +117,7 @@ static void __init rd88f5181l_fxo_init(void)
|
||||||
*/
|
*/
|
||||||
orion5x_ehci0_init();
|
orion5x_ehci0_init();
|
||||||
orion5x_eth_init(&rd88f5181l_fxo_eth_data);
|
orion5x_eth_init(&rd88f5181l_fxo_eth_data);
|
||||||
|
orion5x_eth_switch_init(&rd88f5181l_fxo_switch_data, NO_IRQ);
|
||||||
orion5x_uart0_init();
|
orion5x_uart0_init();
|
||||||
|
|
||||||
orion5x_setup_dev_boot_win(RD88F5181L_FXO_NOR_BOOT_BASE,
|
orion5x_setup_dev_boot_win(RD88F5181L_FXO_NOR_BOOT_BASE,
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <linux/mv643xx_eth.h>
|
#include <linux/mv643xx_eth.h>
|
||||||
#include <linux/ethtool.h>
|
#include <linux/ethtool.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
|
#include <net/dsa.h>
|
||||||
#include <asm/mach-types.h>
|
#include <asm/mach-types.h>
|
||||||
#include <asm/gpio.h>
|
#include <asm/gpio.h>
|
||||||
#include <asm/leds.h>
|
#include <asm/leds.h>
|
||||||
|
@ -94,6 +95,15 @@ static struct mv643xx_eth_platform_data rd88f5181l_ge_eth_data = {
|
||||||
.duplex = DUPLEX_FULL,
|
.duplex = DUPLEX_FULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct dsa_platform_data rd88f5181l_ge_switch_data = {
|
||||||
|
.port_names[0] = "lan2",
|
||||||
|
.port_names[1] = "lan1",
|
||||||
|
.port_names[2] = "wan",
|
||||||
|
.port_names[3] = "cpu",
|
||||||
|
.port_names[5] = "lan4",
|
||||||
|
.port_names[7] = "lan3",
|
||||||
|
};
|
||||||
|
|
||||||
static struct i2c_board_info __initdata rd88f5181l_ge_i2c_rtc = {
|
static struct i2c_board_info __initdata rd88f5181l_ge_i2c_rtc = {
|
||||||
I2C_BOARD_INFO("ds1338", 0x68),
|
I2C_BOARD_INFO("ds1338", 0x68),
|
||||||
};
|
};
|
||||||
|
@ -112,6 +122,7 @@ static void __init rd88f5181l_ge_init(void)
|
||||||
*/
|
*/
|
||||||
orion5x_ehci0_init();
|
orion5x_ehci0_init();
|
||||||
orion5x_eth_init(&rd88f5181l_ge_eth_data);
|
orion5x_eth_init(&rd88f5181l_ge_eth_data);
|
||||||
|
orion5x_eth_switch_init(&rd88f5181l_ge_switch_data, gpio_to_irq(8));
|
||||||
orion5x_i2c_init();
|
orion5x_i2c_init();
|
||||||
orion5x_uart0_init();
|
orion5x_uart0_init();
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <linux/spi/orion_spi.h>
|
#include <linux/spi/orion_spi.h>
|
||||||
#include <linux/spi/flash.h>
|
#include <linux/spi/flash.h>
|
||||||
#include <linux/ethtool.h>
|
#include <linux/ethtool.h>
|
||||||
|
#include <net/dsa.h>
|
||||||
#include <asm/mach-types.h>
|
#include <asm/mach-types.h>
|
||||||
#include <asm/gpio.h>
|
#include <asm/gpio.h>
|
||||||
#include <asm/leds.h>
|
#include <asm/leds.h>
|
||||||
|
@ -34,6 +35,15 @@ static struct mv643xx_eth_platform_data rd88f6183ap_ge_eth_data = {
|
||||||
.duplex = DUPLEX_FULL,
|
.duplex = DUPLEX_FULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct dsa_platform_data rd88f6183ap_ge_switch_data = {
|
||||||
|
.port_names[0] = "lan1",
|
||||||
|
.port_names[1] = "lan2",
|
||||||
|
.port_names[2] = "lan3",
|
||||||
|
.port_names[3] = "lan4",
|
||||||
|
.port_names[4] = "wan",
|
||||||
|
.port_names[5] = "cpu",
|
||||||
|
};
|
||||||
|
|
||||||
static struct mtd_partition rd88f6183ap_ge_partitions[] = {
|
static struct mtd_partition rd88f6183ap_ge_partitions[] = {
|
||||||
{
|
{
|
||||||
.name = "kernel",
|
.name = "kernel",
|
||||||
|
@ -79,6 +89,7 @@ static void __init rd88f6183ap_ge_init(void)
|
||||||
*/
|
*/
|
||||||
orion5x_ehci0_init();
|
orion5x_ehci0_init();
|
||||||
orion5x_eth_init(&rd88f6183ap_ge_eth_data);
|
orion5x_eth_init(&rd88f6183ap_ge_eth_data);
|
||||||
|
orion5x_eth_switch_init(&rd88f6183ap_ge_switch_data, gpio_to_irq(3));
|
||||||
spi_register_board_info(rd88f6183ap_ge_spi_slave_info,
|
spi_register_board_info(rd88f6183ap_ge_spi_slave_info,
|
||||||
ARRAY_SIZE(rd88f6183ap_ge_spi_slave_info));
|
ARRAY_SIZE(rd88f6183ap_ge_spi_slave_info));
|
||||||
orion5x_spi_init();
|
orion5x_spi_init();
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <linux/mtd/physmap.h>
|
#include <linux/mtd/physmap.h>
|
||||||
#include <linux/mv643xx_eth.h>
|
#include <linux/mv643xx_eth.h>
|
||||||
#include <linux/ethtool.h>
|
#include <linux/ethtool.h>
|
||||||
|
#include <net/dsa.h>
|
||||||
#include <asm/mach-types.h>
|
#include <asm/mach-types.h>
|
||||||
#include <asm/gpio.h>
|
#include <asm/gpio.h>
|
||||||
#include <asm/mach/arch.h>
|
#include <asm/mach/arch.h>
|
||||||
|
@ -105,6 +106,15 @@ static struct mv643xx_eth_platform_data wrt350n_v2_eth_data = {
|
||||||
.duplex = DUPLEX_FULL,
|
.duplex = DUPLEX_FULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct dsa_platform_data wrt350n_v2_switch_data = {
|
||||||
|
.port_names[0] = "lan2",
|
||||||
|
.port_names[1] = "lan1",
|
||||||
|
.port_names[2] = "wan",
|
||||||
|
.port_names[3] = "cpu",
|
||||||
|
.port_names[5] = "lan3",
|
||||||
|
.port_names[7] = "lan4",
|
||||||
|
};
|
||||||
|
|
||||||
static void __init wrt350n_v2_init(void)
|
static void __init wrt350n_v2_init(void)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -119,6 +129,7 @@ static void __init wrt350n_v2_init(void)
|
||||||
*/
|
*/
|
||||||
orion5x_ehci0_init();
|
orion5x_ehci0_init();
|
||||||
orion5x_eth_init(&wrt350n_v2_eth_data);
|
orion5x_eth_init(&wrt350n_v2_eth_data);
|
||||||
|
orion5x_eth_switch_init(&wrt350n_v2_switch_data, NO_IRQ);
|
||||||
orion5x_uart0_init();
|
orion5x_uart0_init();
|
||||||
|
|
||||||
orion5x_setup_dev_boot_win(WRT350N_V2_NOR_BOOT_BASE,
|
orion5x_setup_dev_boot_win(WRT350N_V2_NOR_BOOT_BASE,
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
# License. See the file "COPYING" in the main directory of this archive
|
# License. See the file "COPYING" in the main directory of this archive
|
||||||
# for more details.
|
# for more details.
|
||||||
|
|
||||||
|
KBUILD_DEFCONFIG := etrax-100lx_v2_defconfig
|
||||||
|
|
||||||
arch-y := v10
|
arch-y := v10
|
||||||
arch-$(CONFIG_ETRAX_ARCH_V10) := v10
|
arch-$(CONFIG_ETRAX_ARCH_V10) := v10
|
||||||
arch-$(CONFIG_ETRAX_ARCH_V32) := v32
|
arch-$(CONFIG_ETRAX_ARCH_V32) := v32
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
asflags-y += $(LINUXINCLUDE)
|
asflags-y += $(LINUXINCLUDE)
|
||||||
ccflags-y += -O2 $(LINUXINCLUDE)
|
ccflags-y += -O2 $(LINUXINCLUDE)
|
||||||
ldflags-y += -T $(srctree)/$(obj)/decompress.ld
|
ldflags-y += -T $(srctree)/$(src)/decompress.lds
|
||||||
OBJECTS = $(obj)/head.o $(obj)/misc.o
|
OBJECTS = $(obj)/head.o $(obj)/misc.o
|
||||||
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
ccflags-y += -O2 $(LINUXINCLUDE)
|
ccflags-y += -O2 $(LINUXINCLUDE)
|
||||||
asflags-y += $(LINUXINCLUDE)
|
asflags-y += $(LINUXINCLUDE)
|
||||||
ldflags-y += -T $(srctree)/$(obj)/rescue.ld
|
ldflags-y += -T $(srctree)/$(src)/rescue.lds
|
||||||
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
||||||
obj-$(CONFIG_ETRAX_AXISFLASHMAP) = head.o
|
obj-$(CONFIG_ETRAX_AXISFLASHMAP) = head.o
|
||||||
OBJECT := $(obj)/head.o
|
OBJECT := $(obj)/head.o
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
asflags-y += -I $(srctree)/include/asm/mach/ -I $(srctree)/include/asm/arch
|
asflags-y += -I $(srctree)/include/asm/mach/ -I $(srctree)/include/asm/arch
|
||||||
ccflags-y += -O2 -I $(srctree)/include/asm/mach/ -I $(srctree)/include/asm/arch
|
ccflags-y += -O2 -I $(srctree)/include/asm/mach/ -I $(srctree)/include/asm/arch
|
||||||
ldflags-y += -T $(srctree)/$(obj)/decompress.ld
|
ldflags-y += -T $(srctree)/$(src)/decompress.lds
|
||||||
OBJECTS = $(obj)/head.o $(obj)/misc.o
|
OBJECTS = $(obj)/head.o $(obj)/misc.o
|
||||||
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ ccflags-y += -O2 -I $(srctree)/include/asm/arch/mach/ \
|
||||||
-I $(srctree)/include/asm/arch
|
-I $(srctree)/include/asm/arch
|
||||||
asflags-y += -I $(srctree)/include/asm/arch/mach/ -I $(srctree)/include/asm/arch
|
asflags-y += -I $(srctree)/include/asm/arch/mach/ -I $(srctree)/include/asm/arch
|
||||||
LD = gcc-cris -mlinux -march=v32 -nostdlib
|
LD = gcc-cris -mlinux -march=v32 -nostdlib
|
||||||
ldflags-y += -T $(srctree)/$(obj)/rescue.ld
|
ldflags-y += -T $(srctree)/$(src)/rescue.lds
|
||||||
LDPOSTFLAGS = -lgcc
|
LDPOSTFLAGS = -lgcc
|
||||||
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
||||||
obj-$(CONFIG_ETRAX_AXISFLASHMAP) = head.o
|
obj-$(CONFIG_ETRAX_AXISFLASHMAP) = head.o
|
||||||
|
|
|
@ -137,6 +137,7 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
|
||||||
|
|
||||||
return (void*) vaddr;
|
return (void*) vaddr;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(kmap_atomic_pfn); /* temporarily in use by i915 GEM until vmap */
|
||||||
|
|
||||||
struct page *kmap_atomic_to_page(void *ptr)
|
struct page *kmap_atomic_to_page(void *ptr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -257,7 +257,6 @@ void __generic_unplug_device(struct request_queue *q)
|
||||||
|
|
||||||
q->request_fn(q);
|
q->request_fn(q);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__generic_unplug_device);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* generic_unplug_device - fire a request queue
|
* generic_unplug_device - fire a request queue
|
||||||
|
@ -325,6 +324,9 @@ EXPORT_SYMBOL(blk_unplug);
|
||||||
|
|
||||||
static void blk_invoke_request_fn(struct request_queue *q)
|
static void blk_invoke_request_fn(struct request_queue *q)
|
||||||
{
|
{
|
||||||
|
if (unlikely(blk_queue_stopped(q)))
|
||||||
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* one level of recursion is ok and is much faster than kicking
|
* one level of recursion is ok and is much faster than kicking
|
||||||
* the unplug handling
|
* the unplug handling
|
||||||
|
@ -399,8 +401,13 @@ void blk_sync_queue(struct request_queue *q)
|
||||||
EXPORT_SYMBOL(blk_sync_queue);
|
EXPORT_SYMBOL(blk_sync_queue);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* blk_run_queue - run a single device queue
|
* __blk_run_queue - run a single device queue
|
||||||
* @q: The queue to run
|
* @q: The queue to run
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* See @blk_run_queue. This variant must be called with the queue lock
|
||||||
|
* held and interrupts disabled.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
void __blk_run_queue(struct request_queue *q)
|
void __blk_run_queue(struct request_queue *q)
|
||||||
{
|
{
|
||||||
|
@ -418,6 +425,12 @@ EXPORT_SYMBOL(__blk_run_queue);
|
||||||
/**
|
/**
|
||||||
* blk_run_queue - run a single device queue
|
* blk_run_queue - run a single device queue
|
||||||
* @q: The queue to run
|
* @q: The queue to run
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Invoke request handling on this queue, if it has pending work to do.
|
||||||
|
* May be used to restart queueing when a request has completed. Also
|
||||||
|
* See @blk_start_queueing.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
void blk_run_queue(struct request_queue *q)
|
void blk_run_queue(struct request_queue *q)
|
||||||
{
|
{
|
||||||
|
@ -501,6 +514,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
|
||||||
init_timer(&q->unplug_timer);
|
init_timer(&q->unplug_timer);
|
||||||
setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
|
setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
|
||||||
INIT_LIST_HEAD(&q->timeout_list);
|
INIT_LIST_HEAD(&q->timeout_list);
|
||||||
|
INIT_WORK(&q->unplug_work, blk_unplug_work);
|
||||||
|
|
||||||
kobject_init(&q->kobj, &blk_queue_ktype);
|
kobject_init(&q->kobj, &blk_queue_ktype);
|
||||||
|
|
||||||
|
@ -884,7 +898,8 @@ EXPORT_SYMBOL(blk_get_request);
|
||||||
*
|
*
|
||||||
* This is basically a helper to remove the need to know whether a queue
|
* This is basically a helper to remove the need to know whether a queue
|
||||||
* is plugged or not if someone just wants to initiate dispatch of requests
|
* is plugged or not if someone just wants to initiate dispatch of requests
|
||||||
* for this queue.
|
* for this queue. Should be used to start queueing on a device outside
|
||||||
|
* of ->request_fn() context. Also see @blk_run_queue.
|
||||||
*
|
*
|
||||||
* The queue lock must be held with interrupts disabled.
|
* The queue lock must be held with interrupts disabled.
|
||||||
*/
|
*/
|
||||||
|
@ -1003,8 +1018,9 @@ static void part_round_stats_single(int cpu, struct hd_struct *part,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* part_round_stats() - Round off the performance stats on a struct
|
* part_round_stats() - Round off the performance stats on a struct disk_stats.
|
||||||
* disk_stats.
|
* @cpu: cpu number for stats access
|
||||||
|
* @part: target partition
|
||||||
*
|
*
|
||||||
* The average IO queue length and utilisation statistics are maintained
|
* The average IO queue length and utilisation statistics are maintained
|
||||||
* by observing the current state of the queue length and the amount of
|
* by observing the current state of the queue length and the amount of
|
||||||
|
@ -1075,8 +1091,15 @@ void init_request_from_bio(struct request *req, struct bio *bio)
|
||||||
/*
|
/*
|
||||||
* inherit FAILFAST from bio (for read-ahead, and explicit FAILFAST)
|
* inherit FAILFAST from bio (for read-ahead, and explicit FAILFAST)
|
||||||
*/
|
*/
|
||||||
if (bio_rw_ahead(bio) || bio_failfast(bio))
|
if (bio_rw_ahead(bio))
|
||||||
req->cmd_flags |= REQ_FAILFAST;
|
req->cmd_flags |= (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
|
||||||
|
REQ_FAILFAST_DRIVER);
|
||||||
|
if (bio_failfast_dev(bio))
|
||||||
|
req->cmd_flags |= REQ_FAILFAST_DEV;
|
||||||
|
if (bio_failfast_transport(bio))
|
||||||
|
req->cmd_flags |= REQ_FAILFAST_TRANSPORT;
|
||||||
|
if (bio_failfast_driver(bio))
|
||||||
|
req->cmd_flags |= REQ_FAILFAST_DRIVER;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* REQ_BARRIER implies no merging, but lets make it explicit
|
* REQ_BARRIER implies no merging, but lets make it explicit
|
||||||
|
|
|
@ -77,12 +77,20 @@ void blk_recalc_rq_segments(struct request *rq)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
new_segment:
|
new_segment:
|
||||||
|
if (nr_phys_segs == 1 && seg_size > rq->bio->bi_seg_front_size)
|
||||||
|
rq->bio->bi_seg_front_size = seg_size;
|
||||||
|
|
||||||
nr_phys_segs++;
|
nr_phys_segs++;
|
||||||
bvprv = bv;
|
bvprv = bv;
|
||||||
seg_size = bv->bv_len;
|
seg_size = bv->bv_len;
|
||||||
highprv = high;
|
highprv = high;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nr_phys_segs == 1 && seg_size > rq->bio->bi_seg_front_size)
|
||||||
|
rq->bio->bi_seg_front_size = seg_size;
|
||||||
|
if (seg_size > rq->biotail->bi_seg_back_size)
|
||||||
|
rq->biotail->bi_seg_back_size = seg_size;
|
||||||
|
|
||||||
rq->nr_phys_segments = nr_phys_segs;
|
rq->nr_phys_segments = nr_phys_segs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +114,8 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
|
||||||
if (!test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags))
|
if (!test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (bio->bi_size + nxt->bi_size > q->max_segment_size)
|
if (bio->bi_seg_back_size + nxt->bi_seg_front_size >
|
||||||
|
q->max_segment_size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!bio_has_data(bio))
|
if (!bio_has_data(bio))
|
||||||
|
@ -309,6 +318,8 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
|
||||||
struct request *next)
|
struct request *next)
|
||||||
{
|
{
|
||||||
int total_phys_segments;
|
int total_phys_segments;
|
||||||
|
unsigned int seg_size =
|
||||||
|
req->biotail->bi_seg_back_size + next->bio->bi_seg_front_size;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First check if the either of the requests are re-queued
|
* First check if the either of the requests are re-queued
|
||||||
|
@ -324,8 +335,13 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
total_phys_segments = req->nr_phys_segments + next->nr_phys_segments;
|
total_phys_segments = req->nr_phys_segments + next->nr_phys_segments;
|
||||||
if (blk_phys_contig_segment(q, req->biotail, next->bio))
|
if (blk_phys_contig_segment(q, req->biotail, next->bio)) {
|
||||||
|
if (req->nr_phys_segments == 1)
|
||||||
|
req->bio->bi_seg_front_size = seg_size;
|
||||||
|
if (next->nr_phys_segments == 1)
|
||||||
|
next->biotail->bi_seg_back_size = seg_size;
|
||||||
total_phys_segments--;
|
total_phys_segments--;
|
||||||
|
}
|
||||||
|
|
||||||
if (total_phys_segments > q->max_phys_segments)
|
if (total_phys_segments > q->max_phys_segments)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -141,8 +141,6 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
|
||||||
if (q->unplug_delay == 0)
|
if (q->unplug_delay == 0)
|
||||||
q->unplug_delay = 1;
|
q->unplug_delay = 1;
|
||||||
|
|
||||||
INIT_WORK(&q->unplug_work, blk_unplug_work);
|
|
||||||
|
|
||||||
q->unplug_timer.function = blk_unplug_timeout;
|
q->unplug_timer.function = blk_unplug_timeout;
|
||||||
q->unplug_timer.data = (unsigned long)q;
|
q->unplug_timer.data = (unsigned long)q;
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ void blk_unplug_timeout(unsigned long data);
|
||||||
void blk_rq_timed_out_timer(unsigned long data);
|
void blk_rq_timed_out_timer(unsigned long data);
|
||||||
void blk_delete_timer(struct request *);
|
void blk_delete_timer(struct request *);
|
||||||
void blk_add_timer(struct request *);
|
void blk_add_timer(struct request *);
|
||||||
|
void __generic_unplug_device(struct request_queue *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal atomic flags for request handling
|
* Internal atomic flags for request handling
|
||||||
|
|
|
@ -612,7 +612,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where)
|
||||||
* processing.
|
* processing.
|
||||||
*/
|
*/
|
||||||
blk_remove_plug(q);
|
blk_remove_plug(q);
|
||||||
q->request_fn(q);
|
blk_start_queueing(q);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ELEVATOR_INSERT_SORT:
|
case ELEVATOR_INSERT_SORT:
|
||||||
|
@ -950,7 +950,7 @@ void elv_completed_request(struct request_queue *q, struct request *rq)
|
||||||
blk_ordered_cur_seq(q) == QUEUE_ORDSEQ_DRAIN &&
|
blk_ordered_cur_seq(q) == QUEUE_ORDSEQ_DRAIN &&
|
||||||
blk_ordered_req_seq(first_rq) > QUEUE_ORDSEQ_DRAIN) {
|
blk_ordered_req_seq(first_rq) > QUEUE_ORDSEQ_DRAIN) {
|
||||||
blk_ordered_complete_seq(q, QUEUE_ORDSEQ_DRAIN, 0);
|
blk_ordered_complete_seq(q, QUEUE_ORDSEQ_DRAIN, 0);
|
||||||
q->request_fn(q);
|
blk_start_queueing(q);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1109,8 +1109,7 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
|
||||||
elv_drain_elevator(q);
|
elv_drain_elevator(q);
|
||||||
|
|
||||||
while (q->rq.elvpriv) {
|
while (q->rq.elvpriv) {
|
||||||
blk_remove_plug(q);
|
blk_start_queueing(q);
|
||||||
q->request_fn(q);
|
|
||||||
spin_unlock_irq(q->queue_lock);
|
spin_unlock_irq(q->queue_lock);
|
||||||
msleep(10);
|
msleep(10);
|
||||||
spin_lock_irq(q->queue_lock);
|
spin_lock_irq(q->queue_lock);
|
||||||
|
@ -1166,15 +1165,10 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name,
|
||||||
size_t count)
|
size_t count)
|
||||||
{
|
{
|
||||||
char elevator_name[ELV_NAME_MAX];
|
char elevator_name[ELV_NAME_MAX];
|
||||||
size_t len;
|
|
||||||
struct elevator_type *e;
|
struct elevator_type *e;
|
||||||
|
|
||||||
elevator_name[sizeof(elevator_name) - 1] = '\0';
|
strlcpy(elevator_name, name, sizeof(elevator_name));
|
||||||
strncpy(elevator_name, name, sizeof(elevator_name) - 1);
|
strstrip(elevator_name);
|
||||||
len = strlen(elevator_name);
|
|
||||||
|
|
||||||
if (len && elevator_name[len - 1] == '\n')
|
|
||||||
elevator_name[len - 1] = '\0';
|
|
||||||
|
|
||||||
e = elevator_get(elevator_name);
|
e = elevator_get(elevator_name);
|
||||||
if (!e) {
|
if (!e) {
|
||||||
|
|
|
@ -358,7 +358,6 @@ static int blk_mangle_minor(int minor)
|
||||||
/**
|
/**
|
||||||
* blk_alloc_devt - allocate a dev_t for a partition
|
* blk_alloc_devt - allocate a dev_t for a partition
|
||||||
* @part: partition to allocate dev_t for
|
* @part: partition to allocate dev_t for
|
||||||
* @gfp_mask: memory allocation flag
|
|
||||||
* @devt: out parameter for resulting dev_t
|
* @devt: out parameter for resulting dev_t
|
||||||
*
|
*
|
||||||
* Allocate a dev_t for block device.
|
* Allocate a dev_t for block device.
|
||||||
|
@ -535,7 +534,7 @@ void unlink_gendisk(struct gendisk *disk)
|
||||||
/**
|
/**
|
||||||
* get_gendisk - get partitioning information for a given device
|
* get_gendisk - get partitioning information for a given device
|
||||||
* @devt: device to get partitioning information for
|
* @devt: device to get partitioning information for
|
||||||
* @part: returned partition index
|
* @partno: returned partition index
|
||||||
*
|
*
|
||||||
* This function gets the structure containing partitioning
|
* This function gets the structure containing partitioning
|
||||||
* information for the given device @devt.
|
* information for the given device @devt.
|
||||||
|
|
|
@ -101,4 +101,6 @@ source "drivers/auxdisplay/Kconfig"
|
||||||
source "drivers/uio/Kconfig"
|
source "drivers/uio/Kconfig"
|
||||||
|
|
||||||
source "drivers/xen/Kconfig"
|
source "drivers/xen/Kconfig"
|
||||||
|
|
||||||
|
source "drivers/staging/Kconfig"
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -99,3 +99,4 @@ obj-$(CONFIG_OF) += of/
|
||||||
obj-$(CONFIG_SSB) += ssb/
|
obj-$(CONFIG_SSB) += ssb/
|
||||||
obj-$(CONFIG_VIRTIO) += virtio/
|
obj-$(CONFIG_VIRTIO) += virtio/
|
||||||
obj-$(CONFIG_REGULATOR) += regulator/
|
obj-$(CONFIG_REGULATOR) += regulator/
|
||||||
|
obj-$(CONFIG_STAGING) += staging/
|
||||||
|
|
|
@ -349,8 +349,6 @@ struct ub_dev {
|
||||||
|
|
||||||
struct work_struct reset_work;
|
struct work_struct reset_work;
|
||||||
wait_queue_head_t reset_wait;
|
wait_queue_head_t reset_wait;
|
||||||
|
|
||||||
int sg_stat[6];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -685,7 +683,6 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
urq->nsg = n_elem;
|
urq->nsg = n_elem;
|
||||||
sc->sg_stat[n_elem < 5 ? n_elem : 5]++;
|
|
||||||
|
|
||||||
if (blk_pc_request(rq)) {
|
if (blk_pc_request(rq)) {
|
||||||
ub_cmd_build_packet(sc, lun, cmd, urq);
|
ub_cmd_build_packet(sc, lun, cmd, urq);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#
|
#
|
||||||
menuconfig DRM
|
menuconfig DRM
|
||||||
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
|
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
|
||||||
depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG
|
depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && SHMEM
|
||||||
help
|
help
|
||||||
Kernel-level support for the Direct Rendering Infrastructure (DRI)
|
Kernel-level support for the Direct Rendering Infrastructure (DRI)
|
||||||
introduced in XFree86 4.0. If you say Y here, you need to select
|
introduced in XFree86 4.0. If you say Y here, you need to select
|
||||||
|
@ -87,6 +87,7 @@ config DRM_MGA
|
||||||
config DRM_SIS
|
config DRM_SIS
|
||||||
tristate "SiS video cards"
|
tristate "SiS video cards"
|
||||||
depends on DRM && AGP
|
depends on DRM && AGP
|
||||||
|
depends on FB_SIS || FB_SIS=n
|
||||||
help
|
help
|
||||||
Choose this option if you have a SiS 630 or compatible video
|
Choose this option if you have a SiS 630 or compatible video
|
||||||
chipset. If M is selected the module will be called sis. AGP
|
chipset. If M is selected the module will be called sis. AGP
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
|
|
||||||
ccflags-y := -Iinclude/drm
|
ccflags-y := -Iinclude/drm
|
||||||
|
|
||||||
drm-y := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
|
drm-y := drm_auth.o drm_bufs.o drm_cache.o \
|
||||||
drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \
|
drm_context.o drm_dma.o drm_drawable.o \
|
||||||
|
drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
|
||||||
drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
|
drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
|
||||||
drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
|
drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
|
||||||
drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o
|
drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
#include "drmP.h"
|
#include "drmP.h"
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <asm/agp.h>
|
||||||
|
|
||||||
#if __OS_HAS_AGP
|
#if __OS_HAS_AGP
|
||||||
|
|
||||||
|
@ -452,4 +453,53 @@ int drm_agp_unbind_memory(DRM_AGP_MEM * handle)
|
||||||
return agp_unbind_memory(handle);
|
return agp_unbind_memory(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __OS_HAS_AGP */
|
/**
|
||||||
|
* Binds a collection of pages into AGP memory at the given offset, returning
|
||||||
|
* the AGP memory structure containing them.
|
||||||
|
*
|
||||||
|
* No reference is held on the pages during this time -- it is up to the
|
||||||
|
* caller to handle that.
|
||||||
|
*/
|
||||||
|
DRM_AGP_MEM *
|
||||||
|
drm_agp_bind_pages(struct drm_device *dev,
|
||||||
|
struct page **pages,
|
||||||
|
unsigned long num_pages,
|
||||||
|
uint32_t gtt_offset,
|
||||||
|
u32 type)
|
||||||
|
{
|
||||||
|
DRM_AGP_MEM *mem;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
DRM_DEBUG("\n");
|
||||||
|
|
||||||
|
mem = drm_agp_allocate_memory(dev->agp->bridge, num_pages,
|
||||||
|
type);
|
||||||
|
if (mem == NULL) {
|
||||||
|
DRM_ERROR("Failed to allocate memory for %ld pages\n",
|
||||||
|
num_pages);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num_pages; i++)
|
||||||
|
mem->memory[i] = phys_to_gart(page_to_phys(pages[i]));
|
||||||
|
mem->page_count = num_pages;
|
||||||
|
|
||||||
|
mem->is_flushed = true;
|
||||||
|
ret = drm_agp_bind_memory(mem, gtt_offset / PAGE_SIZE);
|
||||||
|
if (ret != 0) {
|
||||||
|
DRM_ERROR("Failed to bind AGP memory: %d\n", ret);
|
||||||
|
agp_free_memory(mem);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_agp_bind_pages);
|
||||||
|
|
||||||
|
void drm_agp_chipset_flush(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
agp_flush_chipset(dev->agp->bridge);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_agp_chipset_flush);
|
||||||
|
|
||||||
|
#endif /* __OS_HAS_AGP */
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/**************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006-2007 Tungsten Graphics, Inc., Cedar Park, TX., USA
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sub license, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the
|
||||||
|
* next paragraph) shall be included in all copies or substantial portions
|
||||||
|
* of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
|
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
/*
|
||||||
|
* Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drmP.h"
|
||||||
|
|
||||||
|
#if defined(CONFIG_X86)
|
||||||
|
static void
|
||||||
|
drm_clflush_page(struct page *page)
|
||||||
|
{
|
||||||
|
uint8_t *page_virtual;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (unlikely(page == NULL))
|
||||||
|
return;
|
||||||
|
|
||||||
|
page_virtual = kmap_atomic(page, KM_USER0);
|
||||||
|
for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size)
|
||||||
|
clflush(page_virtual + i);
|
||||||
|
kunmap_atomic(page_virtual, KM_USER0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
drm_clflush_pages(struct page *pages[], unsigned long num_pages)
|
||||||
|
{
|
||||||
|
|
||||||
|
#if defined(CONFIG_X86)
|
||||||
|
if (cpu_has_clflush) {
|
||||||
|
unsigned long i;
|
||||||
|
|
||||||
|
mb();
|
||||||
|
for (i = 0; i < num_pages; ++i)
|
||||||
|
drm_clflush_page(*pages++);
|
||||||
|
mb();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wbinvd();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_clflush_pages);
|
|
@ -116,7 +116,13 @@ static struct drm_ioctl_desc drm_ioctls[] = {
|
||||||
|
|
||||||
DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0),
|
DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0),
|
||||||
|
|
||||||
|
DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0),
|
||||||
|
|
||||||
DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||||
|
|
||||||
|
DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, 0),
|
||||||
|
DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH),
|
||||||
|
DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH),
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
|
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
|
||||||
|
|
|
@ -246,7 +246,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
|
||||||
memset(priv, 0, sizeof(*priv));
|
memset(priv, 0, sizeof(*priv));
|
||||||
filp->private_data = priv;
|
filp->private_data = priv;
|
||||||
priv->filp = filp;
|
priv->filp = filp;
|
||||||
priv->uid = current->euid;
|
priv->uid = current_euid();
|
||||||
priv->pid = task_pid_nr(current);
|
priv->pid = task_pid_nr(current);
|
||||||
priv->minor = idr_find(&drm_minors_idr, minor_id);
|
priv->minor = idr_find(&drm_minors_idr, minor_id);
|
||||||
priv->ioctl_count = 0;
|
priv->ioctl_count = 0;
|
||||||
|
@ -256,6 +256,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
|
||||||
|
|
||||||
INIT_LIST_HEAD(&priv->lhead);
|
INIT_LIST_HEAD(&priv->lhead);
|
||||||
|
|
||||||
|
if (dev->driver->driver_features & DRIVER_GEM)
|
||||||
|
drm_gem_open(dev, priv);
|
||||||
|
|
||||||
if (dev->driver->open) {
|
if (dev->driver->open) {
|
||||||
ret = dev->driver->open(dev, priv);
|
ret = dev->driver->open(dev, priv);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -400,6 +403,9 @@ int drm_release(struct inode *inode, struct file *filp)
|
||||||
dev->driver->reclaim_buffers(dev, file_priv);
|
dev->driver->reclaim_buffers(dev, file_priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dev->driver->driver_features & DRIVER_GEM)
|
||||||
|
drm_gem_release(dev, file_priv);
|
||||||
|
|
||||||
drm_fasync(-1, filp, 0);
|
drm_fasync(-1, filp, 0);
|
||||||
|
|
||||||
mutex_lock(&dev->ctxlist_mutex);
|
mutex_lock(&dev->ctxlist_mutex);
|
||||||
|
|
|
@ -0,0 +1,421 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2008 Intel Corporation
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Eric Anholt <eric@anholt.net>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/file.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mman.h>
|
||||||
|
#include <linux/pagemap.h>
|
||||||
|
#include "drmP.h"
|
||||||
|
|
||||||
|
/** @file drm_gem.c
|
||||||
|
*
|
||||||
|
* This file provides some of the base ioctls and library routines for
|
||||||
|
* the graphics memory manager implemented by each device driver.
|
||||||
|
*
|
||||||
|
* Because various devices have different requirements in terms of
|
||||||
|
* synchronization and migration strategies, implementing that is left up to
|
||||||
|
* the driver, and all that the general API provides should be generic --
|
||||||
|
* allocating objects, reading/writing data with the cpu, freeing objects.
|
||||||
|
* Even there, platform-dependent optimizations for reading/writing data with
|
||||||
|
* the CPU mean we'll likely hook those out to driver-specific calls. However,
|
||||||
|
* the DRI2 implementation wants to have at least allocate/mmap be generic.
|
||||||
|
*
|
||||||
|
* The goal was to have swap-backed object allocation managed through
|
||||||
|
* struct file. However, file descriptors as handles to a struct file have
|
||||||
|
* two major failings:
|
||||||
|
* - Process limits prevent more than 1024 or so being used at a time by
|
||||||
|
* default.
|
||||||
|
* - Inability to allocate high fds will aggravate the X Server's select()
|
||||||
|
* handling, and likely that of many GL client applications as well.
|
||||||
|
*
|
||||||
|
* This led to a plan of using our own integer IDs (called handles, following
|
||||||
|
* DRM terminology) to mimic fds, and implement the fd syscalls we need as
|
||||||
|
* ioctls. The objects themselves will still include the struct file so
|
||||||
|
* that we can transition to fds if the required kernel infrastructure shows
|
||||||
|
* up at a later date, and as our interface with shmfs for memory allocation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the GEM device fields
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
drm_gem_init(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
spin_lock_init(&dev->object_name_lock);
|
||||||
|
idr_init(&dev->object_name_idr);
|
||||||
|
atomic_set(&dev->object_count, 0);
|
||||||
|
atomic_set(&dev->object_memory, 0);
|
||||||
|
atomic_set(&dev->pin_count, 0);
|
||||||
|
atomic_set(&dev->pin_memory, 0);
|
||||||
|
atomic_set(&dev->gtt_count, 0);
|
||||||
|
atomic_set(&dev->gtt_memory, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate a GEM object of the specified size with shmfs backing store
|
||||||
|
*/
|
||||||
|
struct drm_gem_object *
|
||||||
|
drm_gem_object_alloc(struct drm_device *dev, size_t size)
|
||||||
|
{
|
||||||
|
struct drm_gem_object *obj;
|
||||||
|
|
||||||
|
BUG_ON((size & (PAGE_SIZE - 1)) != 0);
|
||||||
|
|
||||||
|
obj = kcalloc(1, sizeof(*obj), GFP_KERNEL);
|
||||||
|
|
||||||
|
obj->dev = dev;
|
||||||
|
obj->filp = shmem_file_setup("drm mm object", size, 0);
|
||||||
|
if (IS_ERR(obj->filp)) {
|
||||||
|
kfree(obj);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
kref_init(&obj->refcount);
|
||||||
|
kref_init(&obj->handlecount);
|
||||||
|
obj->size = size;
|
||||||
|
if (dev->driver->gem_init_object != NULL &&
|
||||||
|
dev->driver->gem_init_object(obj) != 0) {
|
||||||
|
fput(obj->filp);
|
||||||
|
kfree(obj);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
atomic_inc(&dev->object_count);
|
||||||
|
atomic_add(obj->size, &dev->object_memory);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_gem_object_alloc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the mapping from handle to filp for this object.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
drm_gem_handle_delete(struct drm_file *filp, int handle)
|
||||||
|
{
|
||||||
|
struct drm_device *dev;
|
||||||
|
struct drm_gem_object *obj;
|
||||||
|
|
||||||
|
/* This is gross. The idr system doesn't let us try a delete and
|
||||||
|
* return an error code. It just spews if you fail at deleting.
|
||||||
|
* So, we have to grab a lock around finding the object and then
|
||||||
|
* doing the delete on it and dropping the refcount, or the user
|
||||||
|
* could race us to double-decrement the refcount and cause a
|
||||||
|
* use-after-free later. Given the frequency of our handle lookups,
|
||||||
|
* we may want to use ida for number allocation and a hash table
|
||||||
|
* for the pointers, anyway.
|
||||||
|
*/
|
||||||
|
spin_lock(&filp->table_lock);
|
||||||
|
|
||||||
|
/* Check if we currently have a reference on the object */
|
||||||
|
obj = idr_find(&filp->object_idr, handle);
|
||||||
|
if (obj == NULL) {
|
||||||
|
spin_unlock(&filp->table_lock);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
dev = obj->dev;
|
||||||
|
|
||||||
|
/* Release reference and decrement refcount. */
|
||||||
|
idr_remove(&filp->object_idr, handle);
|
||||||
|
spin_unlock(&filp->table_lock);
|
||||||
|
|
||||||
|
mutex_lock(&dev->struct_mutex);
|
||||||
|
drm_gem_object_handle_unreference(obj);
|
||||||
|
mutex_unlock(&dev->struct_mutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a handle for this object. This adds a handle reference
|
||||||
|
* to the object, which includes a regular reference count. Callers
|
||||||
|
* will likely want to dereference the object afterwards.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
drm_gem_handle_create(struct drm_file *file_priv,
|
||||||
|
struct drm_gem_object *obj,
|
||||||
|
int *handlep)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the user-visible handle using idr.
|
||||||
|
*/
|
||||||
|
again:
|
||||||
|
/* ensure there is space available to allocate a handle */
|
||||||
|
if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* do the allocation under our spinlock */
|
||||||
|
spin_lock(&file_priv->table_lock);
|
||||||
|
ret = idr_get_new_above(&file_priv->object_idr, obj, 1, handlep);
|
||||||
|
spin_unlock(&file_priv->table_lock);
|
||||||
|
if (ret == -EAGAIN)
|
||||||
|
goto again;
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
drm_gem_object_handle_reference(obj);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_gem_handle_create);
|
||||||
|
|
||||||
|
/** Returns a reference to the object named by the handle. */
|
||||||
|
struct drm_gem_object *
|
||||||
|
drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
|
||||||
|
int handle)
|
||||||
|
{
|
||||||
|
struct drm_gem_object *obj;
|
||||||
|
|
||||||
|
spin_lock(&filp->table_lock);
|
||||||
|
|
||||||
|
/* Check if we currently have a reference on the object */
|
||||||
|
obj = idr_find(&filp->object_idr, handle);
|
||||||
|
if (obj == NULL) {
|
||||||
|
spin_unlock(&filp->table_lock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_gem_object_reference(obj);
|
||||||
|
|
||||||
|
spin_unlock(&filp->table_lock);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_gem_object_lookup);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases the handle to an mm object.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
drm_gem_close_ioctl(struct drm_device *dev, void *data,
|
||||||
|
struct drm_file *file_priv)
|
||||||
|
{
|
||||||
|
struct drm_gem_close *args = data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!(dev->driver->driver_features & DRIVER_GEM))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
ret = drm_gem_handle_delete(file_priv, args->handle);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a global name for an object, returning the name.
|
||||||
|
*
|
||||||
|
* Note that the name does not hold a reference; when the object
|
||||||
|
* is freed, the name goes away.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
drm_gem_flink_ioctl(struct drm_device *dev, void *data,
|
||||||
|
struct drm_file *file_priv)
|
||||||
|
{
|
||||||
|
struct drm_gem_flink *args = data;
|
||||||
|
struct drm_gem_object *obj;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!(dev->driver->driver_features & DRIVER_GEM))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
|
||||||
|
if (obj == NULL)
|
||||||
|
return -EBADF;
|
||||||
|
|
||||||
|
again:
|
||||||
|
if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
spin_lock(&dev->object_name_lock);
|
||||||
|
if (obj->name) {
|
||||||
|
args->name = obj->name;
|
||||||
|
spin_unlock(&dev->object_name_lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ret = idr_get_new_above(&dev->object_name_idr, obj, 1,
|
||||||
|
&obj->name);
|
||||||
|
spin_unlock(&dev->object_name_lock);
|
||||||
|
if (ret == -EAGAIN)
|
||||||
|
goto again;
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
mutex_lock(&dev->struct_mutex);
|
||||||
|
drm_gem_object_unreference(obj);
|
||||||
|
mutex_unlock(&dev->struct_mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Leave the reference from the lookup around as the
|
||||||
|
* name table now holds one
|
||||||
|
*/
|
||||||
|
args->name = (uint64_t) obj->name;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open an object using the global name, returning a handle and the size.
|
||||||
|
*
|
||||||
|
* This handle (of course) holds a reference to the object, so the object
|
||||||
|
* will not go away until the handle is deleted.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
drm_gem_open_ioctl(struct drm_device *dev, void *data,
|
||||||
|
struct drm_file *file_priv)
|
||||||
|
{
|
||||||
|
struct drm_gem_open *args = data;
|
||||||
|
struct drm_gem_object *obj;
|
||||||
|
int ret;
|
||||||
|
int handle;
|
||||||
|
|
||||||
|
if (!(dev->driver->driver_features & DRIVER_GEM))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
spin_lock(&dev->object_name_lock);
|
||||||
|
obj = idr_find(&dev->object_name_idr, (int) args->name);
|
||||||
|
if (obj)
|
||||||
|
drm_gem_object_reference(obj);
|
||||||
|
spin_unlock(&dev->object_name_lock);
|
||||||
|
if (!obj)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
ret = drm_gem_handle_create(file_priv, obj, &handle);
|
||||||
|
mutex_lock(&dev->struct_mutex);
|
||||||
|
drm_gem_object_unreference(obj);
|
||||||
|
mutex_unlock(&dev->struct_mutex);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
args->handle = handle;
|
||||||
|
args->size = obj->size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called at device open time, sets up the structure for handling refcounting
|
||||||
|
* of mm objects.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
|
||||||
|
{
|
||||||
|
idr_init(&file_private->object_idr);
|
||||||
|
spin_lock_init(&file_private->table_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called at device close to release the file's
|
||||||
|
* handle references on objects.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
drm_gem_object_release_handle(int id, void *ptr, void *data)
|
||||||
|
{
|
||||||
|
struct drm_gem_object *obj = ptr;
|
||||||
|
|
||||||
|
drm_gem_object_handle_unreference(obj);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called at close time when the filp is going away.
|
||||||
|
*
|
||||||
|
* Releases any remaining references on objects by this filp.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
|
||||||
|
{
|
||||||
|
mutex_lock(&dev->struct_mutex);
|
||||||
|
idr_for_each(&file_private->object_idr,
|
||||||
|
&drm_gem_object_release_handle, NULL);
|
||||||
|
|
||||||
|
idr_destroy(&file_private->object_idr);
|
||||||
|
mutex_unlock(&dev->struct_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after the last reference to the object has been lost.
|
||||||
|
*
|
||||||
|
* Frees the object
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
drm_gem_object_free(struct kref *kref)
|
||||||
|
{
|
||||||
|
struct drm_gem_object *obj = (struct drm_gem_object *) kref;
|
||||||
|
struct drm_device *dev = obj->dev;
|
||||||
|
|
||||||
|
BUG_ON(!mutex_is_locked(&dev->struct_mutex));
|
||||||
|
|
||||||
|
if (dev->driver->gem_free_object != NULL)
|
||||||
|
dev->driver->gem_free_object(obj);
|
||||||
|
|
||||||
|
fput(obj->filp);
|
||||||
|
atomic_dec(&dev->object_count);
|
||||||
|
atomic_sub(obj->size, &dev->object_memory);
|
||||||
|
kfree(obj);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_gem_object_free);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after the last handle to the object has been closed
|
||||||
|
*
|
||||||
|
* Removes any name for the object. Note that this must be
|
||||||
|
* called before drm_gem_object_free or we'll be touching
|
||||||
|
* freed memory
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
drm_gem_object_handle_free(struct kref *kref)
|
||||||
|
{
|
||||||
|
struct drm_gem_object *obj = container_of(kref,
|
||||||
|
struct drm_gem_object,
|
||||||
|
handlecount);
|
||||||
|
struct drm_device *dev = obj->dev;
|
||||||
|
|
||||||
|
/* Remove any name for this object */
|
||||||
|
spin_lock(&dev->object_name_lock);
|
||||||
|
if (obj->name) {
|
||||||
|
idr_remove(&dev->object_name_idr, obj->name);
|
||||||
|
spin_unlock(&dev->object_name_lock);
|
||||||
|
/*
|
||||||
|
* The object name held a reference to this object, drop
|
||||||
|
* that now.
|
||||||
|
*/
|
||||||
|
drm_gem_object_unreference(obj);
|
||||||
|
} else
|
||||||
|
spin_unlock(&dev->object_name_lock);
|
||||||
|
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_gem_object_handle_free);
|
||||||
|
|
|
@ -63,7 +63,7 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
|
||||||
p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
|
p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
p->irq = dev->irq;
|
p->irq = dev->pdev->irq;
|
||||||
|
|
||||||
DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
|
DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
|
||||||
p->irq);
|
p->irq);
|
||||||
|
@ -71,25 +71,137 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vblank_disable_fn(unsigned long arg)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = (struct drm_device *)arg;
|
||||||
|
unsigned long irqflags;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!dev->vblank_disable_allowed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < dev->num_crtcs; i++) {
|
||||||
|
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||||
|
if (atomic_read(&dev->vblank_refcount[i]) == 0 &&
|
||||||
|
dev->vblank_enabled[i]) {
|
||||||
|
DRM_DEBUG("disabling vblank on crtc %d\n", i);
|
||||||
|
dev->last_vblank[i] =
|
||||||
|
dev->driver->get_vblank_counter(dev, i);
|
||||||
|
dev->driver->disable_vblank(dev, i);
|
||||||
|
dev->vblank_enabled[i] = 0;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drm_vblank_cleanup(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
/* Bail if the driver didn't call drm_vblank_init() */
|
||||||
|
if (dev->num_crtcs == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
del_timer(&dev->vblank_disable_timer);
|
||||||
|
|
||||||
|
vblank_disable_fn((unsigned long)dev);
|
||||||
|
|
||||||
|
drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs,
|
||||||
|
DRM_MEM_DRIVER);
|
||||||
|
drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs,
|
||||||
|
DRM_MEM_DRIVER);
|
||||||
|
drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) *
|
||||||
|
dev->num_crtcs, DRM_MEM_DRIVER);
|
||||||
|
drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) *
|
||||||
|
dev->num_crtcs, DRM_MEM_DRIVER);
|
||||||
|
drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) *
|
||||||
|
dev->num_crtcs, DRM_MEM_DRIVER);
|
||||||
|
drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs,
|
||||||
|
DRM_MEM_DRIVER);
|
||||||
|
drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) *
|
||||||
|
dev->num_crtcs, DRM_MEM_DRIVER);
|
||||||
|
|
||||||
|
dev->num_crtcs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int drm_vblank_init(struct drm_device *dev, int num_crtcs)
|
||||||
|
{
|
||||||
|
int i, ret = -ENOMEM;
|
||||||
|
|
||||||
|
setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,
|
||||||
|
(unsigned long)dev);
|
||||||
|
spin_lock_init(&dev->vbl_lock);
|
||||||
|
atomic_set(&dev->vbl_signal_pending, 0);
|
||||||
|
dev->num_crtcs = num_crtcs;
|
||||||
|
|
||||||
|
dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs,
|
||||||
|
DRM_MEM_DRIVER);
|
||||||
|
if (!dev->vbl_queue)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs,
|
||||||
|
DRM_MEM_DRIVER);
|
||||||
|
if (!dev->vbl_sigs)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs,
|
||||||
|
DRM_MEM_DRIVER);
|
||||||
|
if (!dev->_vblank_count)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs,
|
||||||
|
DRM_MEM_DRIVER);
|
||||||
|
if (!dev->vblank_refcount)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int),
|
||||||
|
DRM_MEM_DRIVER);
|
||||||
|
if (!dev->vblank_enabled)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER);
|
||||||
|
if (!dev->last_vblank)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
dev->vblank_inmodeset = drm_calloc(num_crtcs, sizeof(int),
|
||||||
|
DRM_MEM_DRIVER);
|
||||||
|
if (!dev->vblank_inmodeset)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* Zero per-crtc vblank stuff */
|
||||||
|
for (i = 0; i < num_crtcs; i++) {
|
||||||
|
init_waitqueue_head(&dev->vbl_queue[i]);
|
||||||
|
INIT_LIST_HEAD(&dev->vbl_sigs[i]);
|
||||||
|
atomic_set(&dev->_vblank_count[i], 0);
|
||||||
|
atomic_set(&dev->vblank_refcount[i], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->vblank_disable_allowed = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
drm_vblank_cleanup(dev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_vblank_init);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Install IRQ handler.
|
* Install IRQ handler.
|
||||||
*
|
*
|
||||||
* \param dev DRM device.
|
* \param dev DRM device.
|
||||||
* \param irq IRQ number.
|
|
||||||
*
|
*
|
||||||
* Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver
|
* Initializes the IRQ related data. Installs the handler, calling the driver
|
||||||
* \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions
|
* \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions
|
||||||
* before and after the installation.
|
* before and after the installation.
|
||||||
*/
|
*/
|
||||||
static int drm_irq_install(struct drm_device * dev)
|
int drm_irq_install(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret = 0;
|
||||||
unsigned long sh_flags = 0;
|
unsigned long sh_flags = 0;
|
||||||
|
|
||||||
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
|
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (dev->irq == 0)
|
if (dev->pdev->irq == 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&dev->struct_mutex);
|
mutex_lock(&dev->struct_mutex);
|
||||||
|
@ -107,18 +219,7 @@ static int drm_irq_install(struct drm_device * dev)
|
||||||
dev->irq_enabled = 1;
|
dev->irq_enabled = 1;
|
||||||
mutex_unlock(&dev->struct_mutex);
|
mutex_unlock(&dev->struct_mutex);
|
||||||
|
|
||||||
DRM_DEBUG("irq=%d\n", dev->irq);
|
DRM_DEBUG("irq=%d\n", dev->pdev->irq);
|
||||||
|
|
||||||
if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) {
|
|
||||||
init_waitqueue_head(&dev->vbl_queue);
|
|
||||||
|
|
||||||
spin_lock_init(&dev->vbl_lock);
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&dev->vbl_sigs);
|
|
||||||
INIT_LIST_HEAD(&dev->vbl_sigs2);
|
|
||||||
|
|
||||||
dev->vbl_pending = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Before installing handler */
|
/* Before installing handler */
|
||||||
dev->driver->irq_preinstall(dev);
|
dev->driver->irq_preinstall(dev);
|
||||||
|
@ -127,8 +228,9 @@ static int drm_irq_install(struct drm_device * dev)
|
||||||
if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
|
if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
|
||||||
sh_flags = IRQF_SHARED;
|
sh_flags = IRQF_SHARED;
|
||||||
|
|
||||||
ret = request_irq(dev->irq, dev->driver->irq_handler,
|
ret = request_irq(drm_dev_to_irq(dev), dev->driver->irq_handler,
|
||||||
sh_flags, dev->devname, dev);
|
sh_flags, dev->devname, dev);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
mutex_lock(&dev->struct_mutex);
|
mutex_lock(&dev->struct_mutex);
|
||||||
dev->irq_enabled = 0;
|
dev->irq_enabled = 0;
|
||||||
|
@ -137,10 +239,16 @@ static int drm_irq_install(struct drm_device * dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* After installing handler */
|
/* After installing handler */
|
||||||
dev->driver->irq_postinstall(dev);
|
ret = dev->driver->irq_postinstall(dev);
|
||||||
|
if (ret < 0) {
|
||||||
|
mutex_lock(&dev->struct_mutex);
|
||||||
|
dev->irq_enabled = 0;
|
||||||
|
mutex_unlock(&dev->struct_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(drm_irq_install);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uninstall the IRQ handler.
|
* Uninstall the IRQ handler.
|
||||||
|
@ -164,17 +272,18 @@ int drm_irq_uninstall(struct drm_device * dev)
|
||||||
if (!irq_enabled)
|
if (!irq_enabled)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
DRM_DEBUG("irq=%d\n", dev->irq);
|
DRM_DEBUG("irq=%d\n", dev->pdev->irq);
|
||||||
|
|
||||||
dev->driver->irq_uninstall(dev);
|
dev->driver->irq_uninstall(dev);
|
||||||
|
|
||||||
free_irq(dev->irq, dev);
|
free_irq(dev->pdev->irq, dev);
|
||||||
|
|
||||||
|
drm_vblank_cleanup(dev);
|
||||||
|
|
||||||
dev->locked_tasklet_func = NULL;
|
dev->locked_tasklet_func = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(drm_irq_uninstall);
|
EXPORT_SYMBOL(drm_irq_uninstall);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -201,7 +310,7 @@ int drm_control(struct drm_device *dev, void *data,
|
||||||
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
|
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
|
||||||
return 0;
|
return 0;
|
||||||
if (dev->if_version < DRM_IF_VERSION(1, 2) &&
|
if (dev->if_version < DRM_IF_VERSION(1, 2) &&
|
||||||
ctl->irq != dev->irq)
|
ctl->irq != dev->pdev->irq)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return drm_irq_install(dev);
|
return drm_irq_install(dev);
|
||||||
case DRM_UNINST_HANDLER:
|
case DRM_UNINST_HANDLER:
|
||||||
|
@ -213,6 +322,174 @@ int drm_control(struct drm_device *dev, void *data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_vblank_count - retrieve "cooked" vblank counter value
|
||||||
|
* @dev: DRM device
|
||||||
|
* @crtc: which counter to retrieve
|
||||||
|
*
|
||||||
|
* Fetches the "cooked" vblank count value that represents the number of
|
||||||
|
* vblank events since the system was booted, including lost events due to
|
||||||
|
* modesetting activity.
|
||||||
|
*/
|
||||||
|
u32 drm_vblank_count(struct drm_device *dev, int crtc)
|
||||||
|
{
|
||||||
|
return atomic_read(&dev->_vblank_count[crtc]);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_vblank_count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_update_vblank_count - update the master vblank counter
|
||||||
|
* @dev: DRM device
|
||||||
|
* @crtc: counter to update
|
||||||
|
*
|
||||||
|
* Call back into the driver to update the appropriate vblank counter
|
||||||
|
* (specified by @crtc). Deal with wraparound, if it occurred, and
|
||||||
|
* update the last read value so we can deal with wraparound on the next
|
||||||
|
* call if necessary.
|
||||||
|
*
|
||||||
|
* Only necessary when going from off->on, to account for frames we
|
||||||
|
* didn't get an interrupt for.
|
||||||
|
*
|
||||||
|
* Note: caller must hold dev->vbl_lock since this reads & writes
|
||||||
|
* device vblank fields.
|
||||||
|
*/
|
||||||
|
static void drm_update_vblank_count(struct drm_device *dev, int crtc)
|
||||||
|
{
|
||||||
|
u32 cur_vblank, diff;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupts were disabled prior to this call, so deal with counter
|
||||||
|
* wrap if needed.
|
||||||
|
* NOTE! It's possible we lost a full dev->max_vblank_count events
|
||||||
|
* here if the register is small or we had vblank interrupts off for
|
||||||
|
* a long time.
|
||||||
|
*/
|
||||||
|
cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
|
||||||
|
diff = cur_vblank - dev->last_vblank[crtc];
|
||||||
|
if (cur_vblank < dev->last_vblank[crtc]) {
|
||||||
|
diff += dev->max_vblank_count;
|
||||||
|
|
||||||
|
DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n",
|
||||||
|
crtc, dev->last_vblank[crtc], cur_vblank, diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n",
|
||||||
|
crtc, diff);
|
||||||
|
|
||||||
|
atomic_add(diff, &dev->_vblank_count[crtc]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_vblank_get - get a reference count on vblank events
|
||||||
|
* @dev: DRM device
|
||||||
|
* @crtc: which CRTC to own
|
||||||
|
*
|
||||||
|
* Acquire a reference count on vblank events to avoid having them disabled
|
||||||
|
* while in use.
|
||||||
|
*
|
||||||
|
* RETURNS
|
||||||
|
* Zero on success, nonzero on failure.
|
||||||
|
*/
|
||||||
|
int drm_vblank_get(struct drm_device *dev, int crtc)
|
||||||
|
{
|
||||||
|
unsigned long irqflags;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||||
|
/* Going from 0->1 means we have to enable interrupts again */
|
||||||
|
if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 &&
|
||||||
|
!dev->vblank_enabled[crtc]) {
|
||||||
|
ret = dev->driver->enable_vblank(dev, crtc);
|
||||||
|
DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
|
||||||
|
if (ret)
|
||||||
|
atomic_dec(&dev->vblank_refcount[crtc]);
|
||||||
|
else {
|
||||||
|
dev->vblank_enabled[crtc] = 1;
|
||||||
|
drm_update_vblank_count(dev, crtc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_vblank_get);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_vblank_put - give up ownership of vblank events
|
||||||
|
* @dev: DRM device
|
||||||
|
* @crtc: which counter to give up
|
||||||
|
*
|
||||||
|
* Release ownership of a given vblank counter, turning off interrupts
|
||||||
|
* if possible.
|
||||||
|
*/
|
||||||
|
void drm_vblank_put(struct drm_device *dev, int crtc)
|
||||||
|
{
|
||||||
|
/* Last user schedules interrupt disable */
|
||||||
|
if (atomic_dec_and_test(&dev->vblank_refcount[crtc]))
|
||||||
|
mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_vblank_put);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_modeset_ctl - handle vblank event counter changes across mode switch
|
||||||
|
* @DRM_IOCTL_ARGS: standard ioctl arguments
|
||||||
|
*
|
||||||
|
* Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET
|
||||||
|
* ioctls around modesetting so that any lost vblank events are accounted for.
|
||||||
|
*
|
||||||
|
* Generally the counter will reset across mode sets. If interrupts are
|
||||||
|
* enabled around this call, we don't have to do anything since the counter
|
||||||
|
* will have already been incremented.
|
||||||
|
*/
|
||||||
|
int drm_modeset_ctl(struct drm_device *dev, void *data,
|
||||||
|
struct drm_file *file_priv)
|
||||||
|
{
|
||||||
|
struct drm_modeset_ctl *modeset = data;
|
||||||
|
unsigned long irqflags;
|
||||||
|
int crtc, ret = 0;
|
||||||
|
|
||||||
|
/* If drm_vblank_init() hasn't been called yet, just no-op */
|
||||||
|
if (!dev->num_crtcs)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
crtc = modeset->crtc;
|
||||||
|
if (crtc >= dev->num_crtcs) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To avoid all the problems that might happen if interrupts
|
||||||
|
* were enabled/disabled around or between these calls, we just
|
||||||
|
* have the kernel take a reference on the CRTC (just once though
|
||||||
|
* to avoid corrupting the count if multiple, mismatch calls occur),
|
||||||
|
* so that interrupts remain enabled in the interim.
|
||||||
|
*/
|
||||||
|
switch (modeset->cmd) {
|
||||||
|
case _DRM_PRE_MODESET:
|
||||||
|
if (!dev->vblank_inmodeset[crtc]) {
|
||||||
|
dev->vblank_inmodeset[crtc] = 1;
|
||||||
|
drm_vblank_get(dev, crtc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case _DRM_POST_MODESET:
|
||||||
|
if (dev->vblank_inmodeset[crtc]) {
|
||||||
|
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||||
|
dev->vblank_disable_allowed = 1;
|
||||||
|
dev->vblank_inmodeset[crtc] = 0;
|
||||||
|
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||||
|
drm_vblank_put(dev, crtc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for VBLANK.
|
* Wait for VBLANK.
|
||||||
*
|
*
|
||||||
|
@ -232,14 +509,14 @@ int drm_control(struct drm_device *dev, void *data,
|
||||||
*
|
*
|
||||||
* If a signal is not requested, then calls vblank_wait().
|
* If a signal is not requested, then calls vblank_wait().
|
||||||
*/
|
*/
|
||||||
int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
int drm_wait_vblank(struct drm_device *dev, void *data,
|
||||||
|
struct drm_file *file_priv)
|
||||||
{
|
{
|
||||||
union drm_wait_vblank *vblwait = data;
|
union drm_wait_vblank *vblwait = data;
|
||||||
struct timeval now;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
unsigned int flags, seq;
|
unsigned int flags, seq, crtc;
|
||||||
|
|
||||||
if ((!dev->irq) || (!dev->irq_enabled))
|
if ((!dev->pdev->irq) || (!dev->irq_enabled))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (vblwait->request.type &
|
if (vblwait->request.type &
|
||||||
|
@ -251,13 +528,17 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
|
||||||
}
|
}
|
||||||
|
|
||||||
flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
|
flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
|
||||||
|
crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
|
||||||
|
|
||||||
if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
|
if (crtc >= dev->num_crtcs)
|
||||||
DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2
|
ret = drm_vblank_get(dev, crtc);
|
||||||
: &dev->vbl_received);
|
if (ret) {
|
||||||
|
DRM_ERROR("failed to acquire vblank counter, %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
seq = drm_vblank_count(dev, crtc);
|
||||||
|
|
||||||
switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {
|
switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {
|
||||||
case _DRM_VBLANK_RELATIVE:
|
case _DRM_VBLANK_RELATIVE:
|
||||||
|
@ -266,7 +547,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
|
||||||
case _DRM_VBLANK_ABSOLUTE:
|
case _DRM_VBLANK_ABSOLUTE:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & _DRM_VBLANK_NEXTONMISS) &&
|
if ((flags & _DRM_VBLANK_NEXTONMISS) &&
|
||||||
|
@ -276,8 +558,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
|
||||||
|
|
||||||
if (flags & _DRM_VBLANK_SIGNAL) {
|
if (flags & _DRM_VBLANK_SIGNAL) {
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
struct list_head *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
|
struct list_head *vbl_sigs = &dev->vbl_sigs[crtc];
|
||||||
? &dev->vbl_sigs2 : &dev->vbl_sigs;
|
|
||||||
struct drm_vbl_sig *vbl_sig;
|
struct drm_vbl_sig *vbl_sig;
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||||
|
@ -298,22 +579,29 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev->vbl_pending >= 100) {
|
if (atomic_read(&dev->vbl_signal_pending) >= 100) {
|
||||||
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||||
return -EBUSY;
|
ret = -EBUSY;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->vbl_pending++;
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||||
|
|
||||||
if (!
|
vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig),
|
||||||
(vbl_sig =
|
DRM_MEM_DRIVER);
|
||||||
drm_alloc(sizeof(struct drm_vbl_sig), DRM_MEM_DRIVER))) {
|
if (!vbl_sig) {
|
||||||
return -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset((void *)vbl_sig, 0, sizeof(*vbl_sig));
|
ret = drm_vblank_get(dev, crtc);
|
||||||
|
if (ret) {
|
||||||
|
drm_free(vbl_sig, sizeof(struct drm_vbl_sig),
|
||||||
|
DRM_MEM_DRIVER);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic_inc(&dev->vbl_signal_pending);
|
||||||
|
|
||||||
vbl_sig->sequence = vblwait->request.sequence;
|
vbl_sig->sequence = vblwait->request.sequence;
|
||||||
vbl_sig->info.si_signo = vblwait->request.signal;
|
vbl_sig->info.si_signo = vblwait->request.signal;
|
||||||
|
@ -327,20 +615,29 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
|
||||||
|
|
||||||
vblwait->reply.sequence = seq;
|
vblwait->reply.sequence = seq;
|
||||||
} else {
|
} else {
|
||||||
if (flags & _DRM_VBLANK_SECONDARY) {
|
DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
|
||||||
if (dev->driver->vblank_wait2)
|
vblwait->request.sequence, crtc);
|
||||||
ret = dev->driver->vblank_wait2(dev, &vblwait->request.sequence);
|
DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
|
||||||
} else if (dev->driver->vblank_wait)
|
((drm_vblank_count(dev, crtc)
|
||||||
ret =
|
- vblwait->request.sequence) <= (1 << 23)));
|
||||||
dev->driver->vblank_wait(dev,
|
|
||||||
&vblwait->request.sequence);
|
|
||||||
|
|
||||||
do_gettimeofday(&now);
|
if (ret != -EINTR) {
|
||||||
vblwait->reply.tval_sec = now.tv_sec;
|
struct timeval now;
|
||||||
vblwait->reply.tval_usec = now.tv_usec;
|
|
||||||
|
do_gettimeofday(&now);
|
||||||
|
|
||||||
|
vblwait->reply.tval_sec = now.tv_sec;
|
||||||
|
vblwait->reply.tval_usec = now.tv_usec;
|
||||||
|
vblwait->reply.sequence = drm_vblank_count(dev, crtc);
|
||||||
|
DRM_DEBUG("returning %d to client\n",
|
||||||
|
vblwait->reply.sequence);
|
||||||
|
} else {
|
||||||
|
DRM_DEBUG("vblank wait interrupted by signal\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
drm_vblank_put(dev, crtc);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,44 +645,57 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
|
||||||
* Send the VBLANK signals.
|
* Send the VBLANK signals.
|
||||||
*
|
*
|
||||||
* \param dev DRM device.
|
* \param dev DRM device.
|
||||||
|
* \param crtc CRTC where the vblank event occurred
|
||||||
*
|
*
|
||||||
* Sends a signal for each task in drm_device::vbl_sigs and empties the list.
|
* Sends a signal for each task in drm_device::vbl_sigs and empties the list.
|
||||||
*
|
*
|
||||||
* If a signal is not requested, then calls vblank_wait().
|
* If a signal is not requested, then calls vblank_wait().
|
||||||
*/
|
*/
|
||||||
void drm_vbl_send_signals(struct drm_device * dev)
|
static void drm_vbl_send_signals(struct drm_device *dev, int crtc)
|
||||||
{
|
{
|
||||||
|
struct drm_vbl_sig *vbl_sig, *tmp;
|
||||||
|
struct list_head *vbl_sigs;
|
||||||
|
unsigned int vbl_seq;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->vbl_lock, flags);
|
spin_lock_irqsave(&dev->vbl_lock, flags);
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
vbl_sigs = &dev->vbl_sigs[crtc];
|
||||||
struct drm_vbl_sig *vbl_sig, *tmp;
|
vbl_seq = drm_vblank_count(dev, crtc);
|
||||||
struct list_head *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
|
|
||||||
unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 :
|
|
||||||
&dev->vbl_received);
|
|
||||||
|
|
||||||
list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
|
list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
|
||||||
if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
|
if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
|
||||||
vbl_sig->info.si_code = vbl_seq;
|
vbl_sig->info.si_code = vbl_seq;
|
||||||
send_sig_info(vbl_sig->info.si_signo,
|
send_sig_info(vbl_sig->info.si_signo,
|
||||||
&vbl_sig->info, vbl_sig->task);
|
&vbl_sig->info, vbl_sig->task);
|
||||||
|
|
||||||
list_del(&vbl_sig->head);
|
list_del(&vbl_sig->head);
|
||||||
|
|
||||||
drm_free(vbl_sig, sizeof(*vbl_sig),
|
drm_free(vbl_sig, sizeof(*vbl_sig),
|
||||||
DRM_MEM_DRIVER);
|
DRM_MEM_DRIVER);
|
||||||
|
atomic_dec(&dev->vbl_signal_pending);
|
||||||
dev->vbl_pending--;
|
drm_vblank_put(dev, crtc);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dev->vbl_lock, flags);
|
spin_unlock_irqrestore(&dev->vbl_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(drm_vbl_send_signals);
|
/**
|
||||||
|
* drm_handle_vblank - handle a vblank event
|
||||||
|
* @dev: DRM device
|
||||||
|
* @crtc: where this event occurred
|
||||||
|
*
|
||||||
|
* Drivers should call this routine in their vblank interrupt handlers to
|
||||||
|
* update the vblank counter and send any signals that may be pending.
|
||||||
|
*/
|
||||||
|
void drm_handle_vblank(struct drm_device *dev, int crtc)
|
||||||
|
{
|
||||||
|
atomic_inc(&dev->_vblank_count[crtc]);
|
||||||
|
DRM_WAKEUP(&dev->vbl_queue[crtc]);
|
||||||
|
drm_vbl_send_signals(dev, crtc);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_handle_vblank);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tasklet wrapper function.
|
* Tasklet wrapper function.
|
||||||
|
|
|
@ -133,6 +133,7 @@ int drm_free_agp(DRM_AGP_MEM * handle, int pages)
|
||||||
{
|
{
|
||||||
return drm_agp_free_memory(handle) ? 0 : -EINVAL;
|
return drm_agp_free_memory(handle) ? 0 : -EINVAL;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(drm_free_agp);
|
||||||
|
|
||||||
/** Wrapper around agp_bind_memory() */
|
/** Wrapper around agp_bind_memory() */
|
||||||
int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start)
|
int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start)
|
||||||
|
@ -145,6 +146,7 @@ int drm_unbind_agp(DRM_AGP_MEM * handle)
|
||||||
{
|
{
|
||||||
return drm_agp_unbind_memory(handle);
|
return drm_agp_unbind_memory(handle);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(drm_unbind_agp);
|
||||||
|
|
||||||
#else /* __OS_HAS_AGP */
|
#else /* __OS_HAS_AGP */
|
||||||
static inline void *agp_remap(unsigned long offset, unsigned long size,
|
static inline void *agp_remap(unsigned long offset, unsigned long size,
|
||||||
|
|
|
@ -169,6 +169,7 @@ struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(drm_mm_get_block);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Put a block. Merge with the previous and / or next block if they are free.
|
* Put a block. Merge with the previous and / or next block if they are free.
|
||||||
|
@ -217,6 +218,7 @@ void drm_mm_put_block(struct drm_mm_node * cur)
|
||||||
drm_free(cur, sizeof(*cur), DRM_MEM_MM);
|
drm_free(cur, sizeof(*cur), DRM_MEM_MM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(drm_mm_put_block);
|
||||||
|
|
||||||
struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm,
|
struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm,
|
||||||
unsigned long size,
|
unsigned long size,
|
||||||
|
@ -265,6 +267,7 @@ int drm_mm_clean(struct drm_mm * mm)
|
||||||
|
|
||||||
return (head->next->next == head);
|
return (head->next->next == head);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(drm_mm_search_free);
|
||||||
|
|
||||||
int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
|
int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
|
||||||
{
|
{
|
||||||
|
@ -273,7 +276,7 @@ int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
|
||||||
|
|
||||||
return drm_mm_create_tail_node(mm, start, size);
|
return drm_mm_create_tail_node(mm, start, size);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(drm_mm_init);
|
||||||
|
|
||||||
void drm_mm_takedown(struct drm_mm * mm)
|
void drm_mm_takedown(struct drm_mm * mm)
|
||||||
{
|
{
|
||||||
|
|
|
@ -49,6 +49,10 @@ static int drm_queues_info(char *buf, char **start, off_t offset,
|
||||||
int request, int *eof, void *data);
|
int request, int *eof, void *data);
|
||||||
static int drm_bufs_info(char *buf, char **start, off_t offset,
|
static int drm_bufs_info(char *buf, char **start, off_t offset,
|
||||||
int request, int *eof, void *data);
|
int request, int *eof, void *data);
|
||||||
|
static int drm_gem_name_info(char *buf, char **start, off_t offset,
|
||||||
|
int request, int *eof, void *data);
|
||||||
|
static int drm_gem_object_info(char *buf, char **start, off_t offset,
|
||||||
|
int request, int *eof, void *data);
|
||||||
#if DRM_DEBUG_CODE
|
#if DRM_DEBUG_CODE
|
||||||
static int drm_vma_info(char *buf, char **start, off_t offset,
|
static int drm_vma_info(char *buf, char **start, off_t offset,
|
||||||
int request, int *eof, void *data);
|
int request, int *eof, void *data);
|
||||||
|
@ -60,13 +64,16 @@ static int drm_vma_info(char *buf, char **start, off_t offset,
|
||||||
static struct drm_proc_list {
|
static struct drm_proc_list {
|
||||||
const char *name; /**< file name */
|
const char *name; /**< file name */
|
||||||
int (*f) (char *, char **, off_t, int, int *, void *); /**< proc callback*/
|
int (*f) (char *, char **, off_t, int, int *, void *); /**< proc callback*/
|
||||||
|
u32 driver_features; /**< Required driver features for this entry */
|
||||||
} drm_proc_list[] = {
|
} drm_proc_list[] = {
|
||||||
{"name", drm_name_info},
|
{"name", drm_name_info, 0},
|
||||||
{"mem", drm_mem_info},
|
{"mem", drm_mem_info, 0},
|
||||||
{"vm", drm_vm_info},
|
{"vm", drm_vm_info, 0},
|
||||||
{"clients", drm_clients_info},
|
{"clients", drm_clients_info, 0},
|
||||||
{"queues", drm_queues_info},
|
{"queues", drm_queues_info, 0},
|
||||||
{"bufs", drm_bufs_info},
|
{"bufs", drm_bufs_info, 0},
|
||||||
|
{"gem_names", drm_gem_name_info, DRIVER_GEM},
|
||||||
|
{"gem_objects", drm_gem_object_info, DRIVER_GEM},
|
||||||
#if DRM_DEBUG_CODE
|
#if DRM_DEBUG_CODE
|
||||||
{"vma", drm_vma_info},
|
{"vma", drm_vma_info},
|
||||||
#endif
|
#endif
|
||||||
|
@ -90,8 +97,9 @@ static struct drm_proc_list {
|
||||||
int drm_proc_init(struct drm_minor *minor, int minor_id,
|
int drm_proc_init(struct drm_minor *minor, int minor_id,
|
||||||
struct proc_dir_entry *root)
|
struct proc_dir_entry *root)
|
||||||
{
|
{
|
||||||
|
struct drm_device *dev = minor->dev;
|
||||||
struct proc_dir_entry *ent;
|
struct proc_dir_entry *ent;
|
||||||
int i, j;
|
int i, j, ret;
|
||||||
char name[64];
|
char name[64];
|
||||||
|
|
||||||
sprintf(name, "%d", minor_id);
|
sprintf(name, "%d", minor_id);
|
||||||
|
@ -102,23 +110,42 @@ int drm_proc_init(struct drm_minor *minor, int minor_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < DRM_PROC_ENTRIES; i++) {
|
for (i = 0; i < DRM_PROC_ENTRIES; i++) {
|
||||||
|
u32 features = drm_proc_list[i].driver_features;
|
||||||
|
|
||||||
|
if (features != 0 &&
|
||||||
|
(dev->driver->driver_features & features) != features)
|
||||||
|
continue;
|
||||||
|
|
||||||
ent = create_proc_entry(drm_proc_list[i].name,
|
ent = create_proc_entry(drm_proc_list[i].name,
|
||||||
S_IFREG | S_IRUGO, minor->dev_root);
|
S_IFREG | S_IRUGO, minor->dev_root);
|
||||||
if (!ent) {
|
if (!ent) {
|
||||||
DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
|
DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
|
||||||
name, drm_proc_list[i].name);
|
name, drm_proc_list[i].name);
|
||||||
for (j = 0; j < i; j++)
|
ret = -1;
|
||||||
remove_proc_entry(drm_proc_list[i].name,
|
goto fail;
|
||||||
minor->dev_root);
|
|
||||||
remove_proc_entry(name, root);
|
|
||||||
minor->dev_root = NULL;
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
ent->read_proc = drm_proc_list[i].f;
|
ent->read_proc = drm_proc_list[i].f;
|
||||||
ent->data = minor;
|
ent->data = minor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dev->driver->proc_init) {
|
||||||
|
ret = dev->driver->proc_init(minor);
|
||||||
|
if (ret) {
|
||||||
|
DRM_ERROR("DRM: Driver failed to initialize "
|
||||||
|
"/proc/dri.\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
fail:
|
||||||
|
|
||||||
|
for (j = 0; j < i; j++)
|
||||||
|
remove_proc_entry(drm_proc_list[i].name,
|
||||||
|
minor->dev_root);
|
||||||
|
remove_proc_entry(name, root);
|
||||||
|
minor->dev_root = NULL;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,12 +160,16 @@ int drm_proc_init(struct drm_minor *minor, int minor_id,
|
||||||
*/
|
*/
|
||||||
int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root)
|
int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root)
|
||||||
{
|
{
|
||||||
|
struct drm_device *dev = minor->dev;
|
||||||
int i;
|
int i;
|
||||||
char name[64];
|
char name[64];
|
||||||
|
|
||||||
if (!root || !minor->dev_root)
|
if (!root || !minor->dev_root)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (dev->driver->proc_cleanup)
|
||||||
|
dev->driver->proc_cleanup(minor);
|
||||||
|
|
||||||
for (i = 0; i < DRM_PROC_ENTRIES; i++)
|
for (i = 0; i < DRM_PROC_ENTRIES; i++)
|
||||||
remove_proc_entry(drm_proc_list[i].name, minor->dev_root);
|
remove_proc_entry(drm_proc_list[i].name, minor->dev_root);
|
||||||
sprintf(name, "%d", minor->index);
|
sprintf(name, "%d", minor->index);
|
||||||
|
@ -480,6 +511,84 @@ static int drm_clients_info(char *buf, char **start, off_t offset,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct drm_gem_name_info_data {
|
||||||
|
int len;
|
||||||
|
char *buf;
|
||||||
|
int eof;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int drm_gem_one_name_info(int id, void *ptr, void *data)
|
||||||
|
{
|
||||||
|
struct drm_gem_object *obj = ptr;
|
||||||
|
struct drm_gem_name_info_data *nid = data;
|
||||||
|
|
||||||
|
DRM_INFO("name %d size %d\n", obj->name, obj->size);
|
||||||
|
if (nid->eof)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
nid->len += sprintf(&nid->buf[nid->len],
|
||||||
|
"%6d%9d%8d%9d\n",
|
||||||
|
obj->name, obj->size,
|
||||||
|
atomic_read(&obj->handlecount.refcount),
|
||||||
|
atomic_read(&obj->refcount.refcount));
|
||||||
|
if (nid->len > DRM_PROC_LIMIT) {
|
||||||
|
nid->eof = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drm_gem_name_info(char *buf, char **start, off_t offset,
|
||||||
|
int request, int *eof, void *data)
|
||||||
|
{
|
||||||
|
struct drm_minor *minor = (struct drm_minor *) data;
|
||||||
|
struct drm_device *dev = minor->dev;
|
||||||
|
struct drm_gem_name_info_data nid;
|
||||||
|
|
||||||
|
if (offset > DRM_PROC_LIMIT) {
|
||||||
|
*eof = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nid.len = sprintf(buf, " name size handles refcount\n");
|
||||||
|
nid.buf = buf;
|
||||||
|
nid.eof = 0;
|
||||||
|
idr_for_each(&dev->object_name_idr, drm_gem_one_name_info, &nid);
|
||||||
|
|
||||||
|
*start = &buf[offset];
|
||||||
|
*eof = 0;
|
||||||
|
if (nid.len > request + offset)
|
||||||
|
return request;
|
||||||
|
*eof = 1;
|
||||||
|
return nid.len - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drm_gem_object_info(char *buf, char **start, off_t offset,
|
||||||
|
int request, int *eof, void *data)
|
||||||
|
{
|
||||||
|
struct drm_minor *minor = (struct drm_minor *) data;
|
||||||
|
struct drm_device *dev = minor->dev;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (offset > DRM_PROC_LIMIT) {
|
||||||
|
*eof = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*start = &buf[offset];
|
||||||
|
*eof = 0;
|
||||||
|
DRM_PROC_PRINT("%d objects\n", atomic_read(&dev->object_count));
|
||||||
|
DRM_PROC_PRINT("%d object bytes\n", atomic_read(&dev->object_memory));
|
||||||
|
DRM_PROC_PRINT("%d pinned\n", atomic_read(&dev->pin_count));
|
||||||
|
DRM_PROC_PRINT("%d pin bytes\n", atomic_read(&dev->pin_memory));
|
||||||
|
DRM_PROC_PRINT("%d gtt bytes\n", atomic_read(&dev->gtt_memory));
|
||||||
|
DRM_PROC_PRINT("%d gtt total\n", dev->gtt_total);
|
||||||
|
if (len > request + offset)
|
||||||
|
return request;
|
||||||
|
*eof = 1;
|
||||||
|
return len - offset;
|
||||||
|
}
|
||||||
|
|
||||||
#if DRM_DEBUG_CODE
|
#if DRM_DEBUG_CODE
|
||||||
|
|
||||||
static int drm__vma_info(char *buf, char **start, off_t offset, int request,
|
static int drm__vma_info(char *buf, char **start, off_t offset, int request,
|
||||||
|
|
|
@ -107,7 +107,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
|
||||||
#ifdef __alpha__
|
#ifdef __alpha__
|
||||||
dev->hose = pdev->sysdata;
|
dev->hose = pdev->sysdata;
|
||||||
#endif
|
#endif
|
||||||
dev->irq = pdev->irq;
|
|
||||||
|
|
||||||
if (drm_ht_create(&dev->map_hash, 12)) {
|
if (drm_ht_create(&dev->map_hash, 12)) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -152,6 +151,15 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
|
||||||
goto error_out_unreg;
|
goto error_out_unreg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (driver->driver_features & DRIVER_GEM) {
|
||||||
|
retcode = drm_gem_init(dev);
|
||||||
|
if (retcode) {
|
||||||
|
DRM_ERROR("Cannot initialize graphics execution "
|
||||||
|
"manager (GEM)\n");
|
||||||
|
goto error_out_unreg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error_out_unreg:
|
error_out_unreg:
|
||||||
|
@ -317,6 +325,7 @@ int drm_put_dev(struct drm_device * dev)
|
||||||
int drm_put_minor(struct drm_minor **minor_p)
|
int drm_put_minor(struct drm_minor **minor_p)
|
||||||
{
|
{
|
||||||
struct drm_minor *minor = *minor_p;
|
struct drm_minor *minor = *minor_p;
|
||||||
|
|
||||||
DRM_DEBUG("release secondary minor %d\n", minor->index);
|
DRM_DEBUG("release secondary minor %d\n", minor->index);
|
||||||
|
|
||||||
if (minor->type == DRM_MINOR_LEGACY)
|
if (minor->type == DRM_MINOR_LEGACY)
|
||||||
|
|
|
@ -184,7 +184,7 @@ int drm_sysfs_device_add(struct drm_minor *minor)
|
||||||
err_out_files:
|
err_out_files:
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
for (j = 0; j < i; j++)
|
for (j = 0; j < i; j++)
|
||||||
device_remove_file(&minor->kdev, &device_attrs[i]);
|
device_remove_file(&minor->kdev, &device_attrs[j]);
|
||||||
device_unregister(&minor->kdev);
|
device_unregister(&minor->kdev);
|
||||||
err_out:
|
err_out:
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,12 @@
|
||||||
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
||||||
|
|
||||||
ccflags-y := -Iinclude/drm
|
ccflags-y := -Iinclude/drm
|
||||||
i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o
|
i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_opregion.o \
|
||||||
|
i915_suspend.o \
|
||||||
|
i915_gem.o \
|
||||||
|
i915_gem_debug.o \
|
||||||
|
i915_gem_proc.o \
|
||||||
|
i915_gem_tiling.o
|
||||||
|
|
||||||
i915-$(CONFIG_COMPAT) += i915_ioc32.o
|
i915-$(CONFIG_COMPAT) += i915_ioc32.o
|
||||||
|
|
||||||
|
|
|
@ -40,40 +40,96 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
|
||||||
{
|
{
|
||||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
|
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
|
||||||
u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
|
u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
|
||||||
|
u32 last_acthd = I915_READ(acthd_reg);
|
||||||
|
u32 acthd;
|
||||||
|
u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < 10000; i++) {
|
for (i = 0; i < 100000; i++) {
|
||||||
ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
|
ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
|
||||||
|
acthd = I915_READ(acthd_reg);
|
||||||
ring->space = ring->head - (ring->tail + 8);
|
ring->space = ring->head - (ring->tail + 8);
|
||||||
if (ring->space < 0)
|
if (ring->space < 0)
|
||||||
ring->space += ring->Size;
|
ring->space += ring->Size;
|
||||||
if (ring->space >= n)
|
if (ring->space >= n)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
|
if (dev_priv->sarea_priv)
|
||||||
|
dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
|
||||||
|
|
||||||
if (ring->head != last_head)
|
if (ring->head != last_head)
|
||||||
i = 0;
|
i = 0;
|
||||||
|
if (acthd != last_acthd)
|
||||||
|
i = 0;
|
||||||
|
|
||||||
last_head = ring->head;
|
last_head = ring->head;
|
||||||
|
last_acthd = acthd;
|
||||||
|
msleep_interruptible(10);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the hardware status page for devices that need a physical address
|
||||||
|
* in the register.
|
||||||
|
*/
|
||||||
|
static int i915_init_phys_hws(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
|
/* Program Hardware Status Page */
|
||||||
|
dev_priv->status_page_dmah =
|
||||||
|
drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff);
|
||||||
|
|
||||||
|
if (!dev_priv->status_page_dmah) {
|
||||||
|
DRM_ERROR("Can not allocate hardware status page\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;
|
||||||
|
dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
|
||||||
|
|
||||||
|
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
|
||||||
|
|
||||||
|
I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
|
||||||
|
DRM_DEBUG("Enabled hardware status page\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees the hardware status page, whether it's a physical address or a virtual
|
||||||
|
* address set up by the X Server.
|
||||||
|
*/
|
||||||
|
static void i915_free_hws(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
|
if (dev_priv->status_page_dmah) {
|
||||||
|
drm_pci_free(dev, dev_priv->status_page_dmah);
|
||||||
|
dev_priv->status_page_dmah = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev_priv->status_gfx_addr) {
|
||||||
|
dev_priv->status_gfx_addr = 0;
|
||||||
|
drm_core_ioremapfree(&dev_priv->hws_map, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Need to rewrite hardware status page */
|
||||||
|
I915_WRITE(HWS_PGA, 0x1ffff000);
|
||||||
|
}
|
||||||
|
|
||||||
void i915_kernel_lost_context(struct drm_device * dev)
|
void i915_kernel_lost_context(struct drm_device * dev)
|
||||||
{
|
{
|
||||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
|
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
|
||||||
|
|
||||||
ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
|
ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
|
||||||
ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
|
ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
|
||||||
ring->space = ring->head - (ring->tail + 8);
|
ring->space = ring->head - (ring->tail + 8);
|
||||||
if (ring->space < 0)
|
if (ring->space < 0)
|
||||||
ring->space += ring->Size;
|
ring->space += ring->Size;
|
||||||
|
|
||||||
if (ring->head == ring->tail)
|
if (ring->head == ring->tail && dev_priv->sarea_priv)
|
||||||
dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
|
dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,28 +140,19 @@ static int i915_dma_cleanup(struct drm_device * dev)
|
||||||
* may not have been called from userspace and after dev_private
|
* may not have been called from userspace and after dev_private
|
||||||
* is freed, it's too late.
|
* is freed, it's too late.
|
||||||
*/
|
*/
|
||||||
if (dev->irq)
|
if (dev->irq_enabled)
|
||||||
drm_irq_uninstall(dev);
|
drm_irq_uninstall(dev);
|
||||||
|
|
||||||
if (dev_priv->ring.virtual_start) {
|
if (dev_priv->ring.virtual_start) {
|
||||||
drm_core_ioremapfree(&dev_priv->ring.map, dev);
|
drm_core_ioremapfree(&dev_priv->ring.map, dev);
|
||||||
dev_priv->ring.virtual_start = 0;
|
dev_priv->ring.virtual_start = NULL;
|
||||||
dev_priv->ring.map.handle = 0;
|
dev_priv->ring.map.handle = NULL;
|
||||||
dev_priv->ring.map.size = 0;
|
dev_priv->ring.map.size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev_priv->status_page_dmah) {
|
/* Clear the HWS virtual address at teardown */
|
||||||
drm_pci_free(dev, dev_priv->status_page_dmah);
|
if (I915_NEED_GFX_HWS(dev))
|
||||||
dev_priv->status_page_dmah = NULL;
|
i915_free_hws(dev);
|
||||||
/* Need to rewrite hardware status page */
|
|
||||||
I915_WRITE(0x02080, 0x1ffff000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dev_priv->status_gfx_addr) {
|
|
||||||
dev_priv->status_gfx_addr = 0;
|
|
||||||
drm_core_ioremapfree(&dev_priv->hws_map, dev);
|
|
||||||
I915_WRITE(0x2080, 0x1ffff000);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -121,34 +168,34 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
|
|
||||||
if (!dev_priv->mmio_map) {
|
|
||||||
i915_dma_cleanup(dev);
|
|
||||||
DRM_ERROR("can not find mmio map!\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_priv->sarea_priv = (drm_i915_sarea_t *)
|
dev_priv->sarea_priv = (drm_i915_sarea_t *)
|
||||||
((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);
|
((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);
|
||||||
|
|
||||||
dev_priv->ring.Start = init->ring_start;
|
if (init->ring_size != 0) {
|
||||||
dev_priv->ring.End = init->ring_end;
|
if (dev_priv->ring.ring_obj != NULL) {
|
||||||
dev_priv->ring.Size = init->ring_size;
|
i915_dma_cleanup(dev);
|
||||||
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
|
DRM_ERROR("Client tried to initialize ringbuffer in "
|
||||||
|
"GEM mode\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
dev_priv->ring.map.offset = init->ring_start;
|
dev_priv->ring.Size = init->ring_size;
|
||||||
dev_priv->ring.map.size = init->ring_size;
|
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
|
||||||
dev_priv->ring.map.type = 0;
|
|
||||||
dev_priv->ring.map.flags = 0;
|
|
||||||
dev_priv->ring.map.mtrr = 0;
|
|
||||||
|
|
||||||
drm_core_ioremap(&dev_priv->ring.map, dev);
|
dev_priv->ring.map.offset = init->ring_start;
|
||||||
|
dev_priv->ring.map.size = init->ring_size;
|
||||||
|
dev_priv->ring.map.type = 0;
|
||||||
|
dev_priv->ring.map.flags = 0;
|
||||||
|
dev_priv->ring.map.mtrr = 0;
|
||||||
|
|
||||||
if (dev_priv->ring.map.handle == NULL) {
|
drm_core_ioremap(&dev_priv->ring.map, dev);
|
||||||
i915_dma_cleanup(dev);
|
|
||||||
DRM_ERROR("can not ioremap virtual address for"
|
if (dev_priv->ring.map.handle == NULL) {
|
||||||
" ring buffer\n");
|
i915_dma_cleanup(dev);
|
||||||
return -ENOMEM;
|
DRM_ERROR("can not ioremap virtual address for"
|
||||||
|
" ring buffer\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
|
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
|
||||||
|
@ -159,34 +206,10 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
|
||||||
dev_priv->current_page = 0;
|
dev_priv->current_page = 0;
|
||||||
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
|
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
|
||||||
|
|
||||||
/* We are using separate values as placeholders for mechanisms for
|
|
||||||
* private backbuffer/depthbuffer usage.
|
|
||||||
*/
|
|
||||||
dev_priv->use_mi_batchbuffer_start = 0;
|
|
||||||
if (IS_I965G(dev)) /* 965 doesn't support older method */
|
|
||||||
dev_priv->use_mi_batchbuffer_start = 1;
|
|
||||||
|
|
||||||
/* Allow hardware batchbuffers unless told otherwise.
|
/* Allow hardware batchbuffers unless told otherwise.
|
||||||
*/
|
*/
|
||||||
dev_priv->allow_batchbuffer = 1;
|
dev_priv->allow_batchbuffer = 1;
|
||||||
|
|
||||||
/* Program Hardware Status Page */
|
|
||||||
if (!I915_NEED_GFX_HWS(dev)) {
|
|
||||||
dev_priv->status_page_dmah =
|
|
||||||
drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff);
|
|
||||||
|
|
||||||
if (!dev_priv->status_page_dmah) {
|
|
||||||
i915_dma_cleanup(dev);
|
|
||||||
DRM_ERROR("Can not allocate hardware status page\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;
|
|
||||||
dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
|
|
||||||
|
|
||||||
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
|
|
||||||
I915_WRITE(0x02080, dev_priv->dma_status_page);
|
|
||||||
}
|
|
||||||
DRM_DEBUG("Enabled hardware status page\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,11 +224,6 @@ static int i915_dma_resume(struct drm_device * dev)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dev_priv->mmio_map) {
|
|
||||||
DRM_ERROR("can not find mmio map!\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dev_priv->ring.map.handle == NULL) {
|
if (dev_priv->ring.map.handle == NULL) {
|
||||||
DRM_ERROR("can not ioremap virtual address for"
|
DRM_ERROR("can not ioremap virtual address for"
|
||||||
" ring buffer\n");
|
" ring buffer\n");
|
||||||
|
@ -220,9 +238,9 @@ static int i915_dma_resume(struct drm_device * dev)
|
||||||
DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
|
DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
|
||||||
|
|
||||||
if (dev_priv->status_gfx_addr != 0)
|
if (dev_priv->status_gfx_addr != 0)
|
||||||
I915_WRITE(0x02080, dev_priv->status_gfx_addr);
|
I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
|
||||||
else
|
else
|
||||||
I915_WRITE(0x02080, dev_priv->dma_status_page);
|
I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
|
||||||
DRM_DEBUG("Enabled hardware status page\n");
|
DRM_DEBUG("Enabled hardware status page\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -367,9 +385,10 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i915_emit_box(struct drm_device * dev,
|
int
|
||||||
struct drm_clip_rect __user * boxes,
|
i915_emit_box(struct drm_device *dev,
|
||||||
int i, int DR1, int DR4)
|
struct drm_clip_rect __user *boxes,
|
||||||
|
int i, int DR1, int DR4)
|
||||||
{
|
{
|
||||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
struct drm_clip_rect box;
|
struct drm_clip_rect box;
|
||||||
|
@ -415,14 +434,15 @@ static void i915_emit_breadcrumb(struct drm_device *dev)
|
||||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
RING_LOCALS;
|
RING_LOCALS;
|
||||||
|
|
||||||
dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
|
dev_priv->counter++;
|
||||||
|
|
||||||
if (dev_priv->counter > 0x7FFFFFFFUL)
|
if (dev_priv->counter > 0x7FFFFFFFUL)
|
||||||
dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
|
dev_priv->counter = 0;
|
||||||
|
if (dev_priv->sarea_priv)
|
||||||
|
dev_priv->sarea_priv->last_enqueue = dev_priv->counter;
|
||||||
|
|
||||||
BEGIN_LP_RING(4);
|
BEGIN_LP_RING(4);
|
||||||
OUT_RING(CMD_STORE_DWORD_IDX);
|
OUT_RING(MI_STORE_DWORD_INDEX);
|
||||||
OUT_RING(20);
|
OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
|
||||||
OUT_RING(dev_priv->counter);
|
OUT_RING(dev_priv->counter);
|
||||||
OUT_RING(0);
|
OUT_RING(0);
|
||||||
ADVANCE_LP_RING();
|
ADVANCE_LP_RING();
|
||||||
|
@ -486,7 +506,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev_priv->use_mi_batchbuffer_start) {
|
if (!IS_I830(dev) && !IS_845G(dev)) {
|
||||||
BEGIN_LP_RING(2);
|
BEGIN_LP_RING(2);
|
||||||
if (IS_I965G(dev)) {
|
if (IS_I965G(dev)) {
|
||||||
OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
|
OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
|
||||||
|
@ -516,6 +536,9 @@ static int i915_dispatch_flip(struct drm_device * dev)
|
||||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
RING_LOCALS;
|
RING_LOCALS;
|
||||||
|
|
||||||
|
if (!dev_priv->sarea_priv)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
|
DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
|
||||||
__func__,
|
__func__,
|
||||||
dev_priv->current_page,
|
dev_priv->current_page,
|
||||||
|
@ -524,7 +547,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
|
||||||
i915_kernel_lost_context(dev);
|
i915_kernel_lost_context(dev);
|
||||||
|
|
||||||
BEGIN_LP_RING(2);
|
BEGIN_LP_RING(2);
|
||||||
OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
|
OUT_RING(MI_FLUSH | MI_READ_FLUSH);
|
||||||
OUT_RING(0);
|
OUT_RING(0);
|
||||||
ADVANCE_LP_RING();
|
ADVANCE_LP_RING();
|
||||||
|
|
||||||
|
@ -549,8 +572,8 @@ static int i915_dispatch_flip(struct drm_device * dev)
|
||||||
dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
|
dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
|
||||||
|
|
||||||
BEGIN_LP_RING(4);
|
BEGIN_LP_RING(4);
|
||||||
OUT_RING(CMD_STORE_DWORD_IDX);
|
OUT_RING(MI_STORE_DWORD_INDEX);
|
||||||
OUT_RING(20);
|
OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
|
||||||
OUT_RING(dev_priv->counter);
|
OUT_RING(dev_priv->counter);
|
||||||
OUT_RING(0);
|
OUT_RING(0);
|
||||||
ADVANCE_LP_RING();
|
ADVANCE_LP_RING();
|
||||||
|
@ -570,9 +593,15 @@ static int i915_quiescent(struct drm_device * dev)
|
||||||
static int i915_flush_ioctl(struct drm_device *dev, void *data,
|
static int i915_flush_ioctl(struct drm_device *dev, void *data,
|
||||||
struct drm_file *file_priv)
|
struct drm_file *file_priv)
|
||||||
{
|
{
|
||||||
LOCK_TEST_WITH_RETURN(dev, file_priv);
|
int ret;
|
||||||
|
|
||||||
return i915_quiescent(dev);
|
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||||
|
|
||||||
|
mutex_lock(&dev->struct_mutex);
|
||||||
|
ret = i915_quiescent(dev);
|
||||||
|
mutex_unlock(&dev->struct_mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i915_batchbuffer(struct drm_device *dev, void *data,
|
static int i915_batchbuffer(struct drm_device *dev, void *data,
|
||||||
|
@ -593,16 +622,19 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
|
||||||
DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
|
DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
|
||||||
batch->start, batch->used, batch->num_cliprects);
|
batch->start, batch->used, batch->num_cliprects);
|
||||||
|
|
||||||
LOCK_TEST_WITH_RETURN(dev, file_priv);
|
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||||
|
|
||||||
if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
|
if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
|
||||||
batch->num_cliprects *
|
batch->num_cliprects *
|
||||||
sizeof(struct drm_clip_rect)))
|
sizeof(struct drm_clip_rect)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
mutex_lock(&dev->struct_mutex);
|
||||||
ret = i915_dispatch_batchbuffer(dev, batch);
|
ret = i915_dispatch_batchbuffer(dev, batch);
|
||||||
|
mutex_unlock(&dev->struct_mutex);
|
||||||
|
|
||||||
sarea_priv->last_dispatch = (int)hw_status[5];
|
if (sarea_priv)
|
||||||
|
sarea_priv->last_dispatch = (int)hw_status[5];
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,7 +651,7 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
|
||||||
DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
|
DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
|
||||||
cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
|
cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
|
||||||
|
|
||||||
LOCK_TEST_WITH_RETURN(dev, file_priv);
|
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||||
|
|
||||||
if (cmdbuf->num_cliprects &&
|
if (cmdbuf->num_cliprects &&
|
||||||
DRM_VERIFYAREA_READ(cmdbuf->cliprects,
|
DRM_VERIFYAREA_READ(cmdbuf->cliprects,
|
||||||
|
@ -629,24 +661,33 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_lock(&dev->struct_mutex);
|
||||||
ret = i915_dispatch_cmdbuffer(dev, cmdbuf);
|
ret = i915_dispatch_cmdbuffer(dev, cmdbuf);
|
||||||
|
mutex_unlock(&dev->struct_mutex);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
|
DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
sarea_priv->last_dispatch = (int)hw_status[5];
|
if (sarea_priv)
|
||||||
|
sarea_priv->last_dispatch = (int)hw_status[5];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i915_flip_bufs(struct drm_device *dev, void *data,
|
static int i915_flip_bufs(struct drm_device *dev, void *data,
|
||||||
struct drm_file *file_priv)
|
struct drm_file *file_priv)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
DRM_DEBUG("%s\n", __func__);
|
DRM_DEBUG("%s\n", __func__);
|
||||||
|
|
||||||
LOCK_TEST_WITH_RETURN(dev, file_priv);
|
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||||
|
|
||||||
return i915_dispatch_flip(dev);
|
mutex_lock(&dev->struct_mutex);
|
||||||
|
ret = i915_dispatch_flip(dev);
|
||||||
|
mutex_unlock(&dev->struct_mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i915_getparam(struct drm_device *dev, void *data,
|
static int i915_getparam(struct drm_device *dev, void *data,
|
||||||
|
@ -663,7 +704,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
|
||||||
|
|
||||||
switch (param->param) {
|
switch (param->param) {
|
||||||
case I915_PARAM_IRQ_ACTIVE:
|
case I915_PARAM_IRQ_ACTIVE:
|
||||||
value = dev->irq ? 1 : 0;
|
value = dev->pdev->irq ? 1 : 0;
|
||||||
break;
|
break;
|
||||||
case I915_PARAM_ALLOW_BATCHBUFFER:
|
case I915_PARAM_ALLOW_BATCHBUFFER:
|
||||||
value = dev_priv->allow_batchbuffer ? 1 : 0;
|
value = dev_priv->allow_batchbuffer ? 1 : 0;
|
||||||
|
@ -671,6 +712,12 @@ static int i915_getparam(struct drm_device *dev, void *data,
|
||||||
case I915_PARAM_LAST_DISPATCH:
|
case I915_PARAM_LAST_DISPATCH:
|
||||||
value = READ_BREADCRUMB(dev_priv);
|
value = READ_BREADCRUMB(dev_priv);
|
||||||
break;
|
break;
|
||||||
|
case I915_PARAM_CHIPSET_ID:
|
||||||
|
value = dev->pci_device;
|
||||||
|
break;
|
||||||
|
case I915_PARAM_HAS_GEM:
|
||||||
|
value = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
DRM_ERROR("Unknown parameter %d\n", param->param);
|
DRM_ERROR("Unknown parameter %d\n", param->param);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -697,8 +744,6 @@ static int i915_setparam(struct drm_device *dev, void *data,
|
||||||
|
|
||||||
switch (param->param) {
|
switch (param->param) {
|
||||||
case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
|
case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
|
||||||
if (!IS_I965G(dev))
|
|
||||||
dev_priv->use_mi_batchbuffer_start = param->value;
|
|
||||||
break;
|
break;
|
||||||
case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
|
case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
|
||||||
dev_priv->tex_lru_log_granularity = param->value;
|
dev_priv->tex_lru_log_granularity = param->value;
|
||||||
|
@ -749,8 +794,8 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
|
||||||
dev_priv->hw_status_page = dev_priv->hws_map.handle;
|
dev_priv->hw_status_page = dev_priv->hws_map.handle;
|
||||||
|
|
||||||
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
|
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
|
||||||
I915_WRITE(0x02080, dev_priv->status_gfx_addr);
|
I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
|
||||||
DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n",
|
DRM_DEBUG("load hws HWS_PGA with gfx mem 0x%x\n",
|
||||||
dev_priv->status_gfx_addr);
|
dev_priv->status_gfx_addr);
|
||||||
DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page);
|
DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -776,14 +821,38 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
||||||
memset(dev_priv, 0, sizeof(drm_i915_private_t));
|
memset(dev_priv, 0, sizeof(drm_i915_private_t));
|
||||||
|
|
||||||
dev->dev_private = (void *)dev_priv;
|
dev->dev_private = (void *)dev_priv;
|
||||||
|
dev_priv->dev = dev;
|
||||||
|
|
||||||
/* Add register map (needed for suspend/resume) */
|
/* Add register map (needed for suspend/resume) */
|
||||||
base = drm_get_resource_start(dev, mmio_bar);
|
base = drm_get_resource_start(dev, mmio_bar);
|
||||||
size = drm_get_resource_len(dev, mmio_bar);
|
size = drm_get_resource_len(dev, mmio_bar);
|
||||||
|
|
||||||
ret = drm_addmap(dev, base, size, _DRM_REGISTERS,
|
dev_priv->regs = ioremap(base, size);
|
||||||
_DRM_KERNEL | _DRM_DRIVER,
|
|
||||||
&dev_priv->mmio_map);
|
i915_gem_load(dev);
|
||||||
|
|
||||||
|
/* Init HWS */
|
||||||
|
if (!I915_NEED_GFX_HWS(dev)) {
|
||||||
|
ret = i915_init_phys_hws(dev);
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* On the 945G/GM, the chipset reports the MSI capability on the
|
||||||
|
* integrated graphics even though the support isn't actually there
|
||||||
|
* according to the published specs. It doesn't appear to function
|
||||||
|
* correctly in testing on 945G.
|
||||||
|
* This may be a side effect of MSI having been made available for PEG
|
||||||
|
* and the registers being closely associated.
|
||||||
|
*/
|
||||||
|
if (!IS_I945G(dev) && !IS_I945GM(dev))
|
||||||
|
if (pci_enable_msi(dev->pdev))
|
||||||
|
DRM_ERROR("failed to enable MSI\n");
|
||||||
|
|
||||||
|
intel_opregion_init(dev);
|
||||||
|
|
||||||
|
spin_lock_init(&dev_priv->user_irq_lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -791,8 +860,15 @@ int i915_driver_unload(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
if (dev_priv->mmio_map)
|
if (dev->pdev->msi_enabled)
|
||||||
drm_rmmap(dev, dev_priv->mmio_map);
|
pci_disable_msi(dev->pdev);
|
||||||
|
|
||||||
|
i915_free_hws(dev);
|
||||||
|
|
||||||
|
if (dev_priv->regs != NULL)
|
||||||
|
iounmap(dev_priv->regs);
|
||||||
|
|
||||||
|
intel_opregion_free(dev);
|
||||||
|
|
||||||
drm_free(dev->dev_private, sizeof(drm_i915_private_t),
|
drm_free(dev->dev_private, sizeof(drm_i915_private_t),
|
||||||
DRM_MEM_DRIVER);
|
DRM_MEM_DRIVER);
|
||||||
|
@ -800,6 +876,25 @@ int i915_driver_unload(struct drm_device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
|
||||||
|
{
|
||||||
|
struct drm_i915_file_private *i915_file_priv;
|
||||||
|
|
||||||
|
DRM_DEBUG("\n");
|
||||||
|
i915_file_priv = (struct drm_i915_file_private *)
|
||||||
|
drm_alloc(sizeof(*i915_file_priv), DRM_MEM_FILES);
|
||||||
|
|
||||||
|
if (!i915_file_priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
file_priv->driver_priv = i915_file_priv;
|
||||||
|
|
||||||
|
i915_file_priv->mm.last_gem_seqno = 0;
|
||||||
|
i915_file_priv->mm.last_gem_throttle_seqno = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void i915_driver_lastclose(struct drm_device * dev)
|
void i915_driver_lastclose(struct drm_device * dev)
|
||||||
{
|
{
|
||||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
|
@ -807,6 +902,8 @@ void i915_driver_lastclose(struct drm_device * dev)
|
||||||
if (!dev_priv)
|
if (!dev_priv)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
i915_gem_lastclose(dev);
|
||||||
|
|
||||||
if (dev_priv->agp_heap)
|
if (dev_priv->agp_heap)
|
||||||
i915_mem_takedown(&(dev_priv->agp_heap));
|
i915_mem_takedown(&(dev_priv->agp_heap));
|
||||||
|
|
||||||
|
@ -819,6 +916,13 @@ void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
|
||||||
i915_mem_release(dev, file_priv, dev_priv->agp_heap);
|
i915_mem_release(dev, file_priv, dev_priv->agp_heap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
|
||||||
|
{
|
||||||
|
struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
|
||||||
|
|
||||||
|
drm_free(i915_file_priv, sizeof(*i915_file_priv), DRM_MEM_FILES);
|
||||||
|
}
|
||||||
|
|
||||||
struct drm_ioctl_desc i915_ioctls[] = {
|
struct drm_ioctl_desc i915_ioctls[] = {
|
||||||
DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||||
DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH),
|
DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH),
|
||||||
|
@ -836,7 +940,23 @@ struct drm_ioctl_desc i915_ioctls[] = {
|
||||||
DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE, i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ),
|
DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE, i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ),
|
||||||
DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH ),
|
DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH ),
|
||||||
DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH),
|
DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH),
|
||||||
DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH),
|
DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||||
|
DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||||
|
DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH),
|
||||||
|
DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
|
||||||
|
DRM_IOCTL_DEF(DRM_I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
|
||||||
|
DRM_IOCTL_DEF(DRM_I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH),
|
||||||
|
DRM_IOCTL_DEF(DRM_I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH),
|
||||||
|
DRM_IOCTL_DEF(DRM_I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||||
|
DRM_IOCTL_DEF(DRM_I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||||
|
DRM_IOCTL_DEF(DRM_I915_GEM_CREATE, i915_gem_create_ioctl, 0),
|
||||||
|
DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, 0),
|
||||||
|
DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, 0),
|
||||||
|
DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, 0),
|
||||||
|
DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, 0),
|
||||||
|
DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, 0),
|
||||||
|
DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, 0),
|
||||||
|
DRM_IOCTL_DEF(DRM_I915_GEM_GET_TILING, i915_gem_get_tiling, 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
|
int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
|
||||||
|
|
|
@ -38,211 +38,9 @@ static struct pci_device_id pciidlist[] = {
|
||||||
i915_PCI_IDS
|
i915_PCI_IDS
|
||||||
};
|
};
|
||||||
|
|
||||||
enum pipe {
|
|
||||||
PIPE_A = 0,
|
|
||||||
PIPE_B,
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe)
|
|
||||||
{
|
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
||||||
|
|
||||||
if (pipe == PIPE_A)
|
|
||||||
return (I915_READ(DPLL_A) & DPLL_VCO_ENABLE);
|
|
||||||
else
|
|
||||||
return (I915_READ(DPLL_B) & DPLL_VCO_ENABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void i915_save_palette(struct drm_device *dev, enum pipe pipe)
|
|
||||||
{
|
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
||||||
unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
|
|
||||||
u32 *array;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!i915_pipe_enabled(dev, pipe))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (pipe == PIPE_A)
|
|
||||||
array = dev_priv->save_palette_a;
|
|
||||||
else
|
|
||||||
array = dev_priv->save_palette_b;
|
|
||||||
|
|
||||||
for(i = 0; i < 256; i++)
|
|
||||||
array[i] = I915_READ(reg + (i << 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void i915_restore_palette(struct drm_device *dev, enum pipe pipe)
|
|
||||||
{
|
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
||||||
unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
|
|
||||||
u32 *array;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!i915_pipe_enabled(dev, pipe))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (pipe == PIPE_A)
|
|
||||||
array = dev_priv->save_palette_a;
|
|
||||||
else
|
|
||||||
array = dev_priv->save_palette_b;
|
|
||||||
|
|
||||||
for(i = 0; i < 256; i++)
|
|
||||||
I915_WRITE(reg + (i << 2), array[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static u8 i915_read_indexed(u16 index_port, u16 data_port, u8 reg)
|
|
||||||
{
|
|
||||||
outb(reg, index_port);
|
|
||||||
return inb(data_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
static u8 i915_read_ar(u16 st01, u8 reg, u16 palette_enable)
|
|
||||||
{
|
|
||||||
inb(st01);
|
|
||||||
outb(palette_enable | reg, VGA_AR_INDEX);
|
|
||||||
return inb(VGA_AR_DATA_READ);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void i915_write_ar(u8 st01, u8 reg, u8 val, u16 palette_enable)
|
|
||||||
{
|
|
||||||
inb(st01);
|
|
||||||
outb(palette_enable | reg, VGA_AR_INDEX);
|
|
||||||
outb(val, VGA_AR_DATA_WRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void i915_write_indexed(u16 index_port, u16 data_port, u8 reg, u8 val)
|
|
||||||
{
|
|
||||||
outb(reg, index_port);
|
|
||||||
outb(val, data_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void i915_save_vga(struct drm_device *dev)
|
|
||||||
{
|
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
||||||
int i;
|
|
||||||
u16 cr_index, cr_data, st01;
|
|
||||||
|
|
||||||
/* VGA color palette registers */
|
|
||||||
dev_priv->saveDACMASK = inb(VGA_DACMASK);
|
|
||||||
/* DACCRX automatically increments during read */
|
|
||||||
outb(0, VGA_DACRX);
|
|
||||||
/* Read 3 bytes of color data from each index */
|
|
||||||
for (i = 0; i < 256 * 3; i++)
|
|
||||||
dev_priv->saveDACDATA[i] = inb(VGA_DACDATA);
|
|
||||||
|
|
||||||
/* MSR bits */
|
|
||||||
dev_priv->saveMSR = inb(VGA_MSR_READ);
|
|
||||||
if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
|
|
||||||
cr_index = VGA_CR_INDEX_CGA;
|
|
||||||
cr_data = VGA_CR_DATA_CGA;
|
|
||||||
st01 = VGA_ST01_CGA;
|
|
||||||
} else {
|
|
||||||
cr_index = VGA_CR_INDEX_MDA;
|
|
||||||
cr_data = VGA_CR_DATA_MDA;
|
|
||||||
st01 = VGA_ST01_MDA;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* CRT controller regs */
|
|
||||||
i915_write_indexed(cr_index, cr_data, 0x11,
|
|
||||||
i915_read_indexed(cr_index, cr_data, 0x11) &
|
|
||||||
(~0x80));
|
|
||||||
for (i = 0; i <= 0x24; i++)
|
|
||||||
dev_priv->saveCR[i] =
|
|
||||||
i915_read_indexed(cr_index, cr_data, i);
|
|
||||||
/* Make sure we don't turn off CR group 0 writes */
|
|
||||||
dev_priv->saveCR[0x11] &= ~0x80;
|
|
||||||
|
|
||||||
/* Attribute controller registers */
|
|
||||||
inb(st01);
|
|
||||||
dev_priv->saveAR_INDEX = inb(VGA_AR_INDEX);
|
|
||||||
for (i = 0; i <= 0x14; i++)
|
|
||||||
dev_priv->saveAR[i] = i915_read_ar(st01, i, 0);
|
|
||||||
inb(st01);
|
|
||||||
outb(dev_priv->saveAR_INDEX, VGA_AR_INDEX);
|
|
||||||
inb(st01);
|
|
||||||
|
|
||||||
/* Graphics controller registers */
|
|
||||||
for (i = 0; i < 9; i++)
|
|
||||||
dev_priv->saveGR[i] =
|
|
||||||
i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, i);
|
|
||||||
|
|
||||||
dev_priv->saveGR[0x10] =
|
|
||||||
i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x10);
|
|
||||||
dev_priv->saveGR[0x11] =
|
|
||||||
i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x11);
|
|
||||||
dev_priv->saveGR[0x18] =
|
|
||||||
i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x18);
|
|
||||||
|
|
||||||
/* Sequencer registers */
|
|
||||||
for (i = 0; i < 8; i++)
|
|
||||||
dev_priv->saveSR[i] =
|
|
||||||
i915_read_indexed(VGA_SR_INDEX, VGA_SR_DATA, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void i915_restore_vga(struct drm_device *dev)
|
|
||||||
{
|
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
||||||
int i;
|
|
||||||
u16 cr_index, cr_data, st01;
|
|
||||||
|
|
||||||
/* MSR bits */
|
|
||||||
outb(dev_priv->saveMSR, VGA_MSR_WRITE);
|
|
||||||
if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
|
|
||||||
cr_index = VGA_CR_INDEX_CGA;
|
|
||||||
cr_data = VGA_CR_DATA_CGA;
|
|
||||||
st01 = VGA_ST01_CGA;
|
|
||||||
} else {
|
|
||||||
cr_index = VGA_CR_INDEX_MDA;
|
|
||||||
cr_data = VGA_CR_DATA_MDA;
|
|
||||||
st01 = VGA_ST01_MDA;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sequencer registers, don't write SR07 */
|
|
||||||
for (i = 0; i < 7; i++)
|
|
||||||
i915_write_indexed(VGA_SR_INDEX, VGA_SR_DATA, i,
|
|
||||||
dev_priv->saveSR[i]);
|
|
||||||
|
|
||||||
/* CRT controller regs */
|
|
||||||
/* Enable CR group 0 writes */
|
|
||||||
i915_write_indexed(cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]);
|
|
||||||
for (i = 0; i <= 0x24; i++)
|
|
||||||
i915_write_indexed(cr_index, cr_data, i, dev_priv->saveCR[i]);
|
|
||||||
|
|
||||||
/* Graphics controller regs */
|
|
||||||
for (i = 0; i < 9; i++)
|
|
||||||
i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, i,
|
|
||||||
dev_priv->saveGR[i]);
|
|
||||||
|
|
||||||
i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x10,
|
|
||||||
dev_priv->saveGR[0x10]);
|
|
||||||
i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x11,
|
|
||||||
dev_priv->saveGR[0x11]);
|
|
||||||
i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x18,
|
|
||||||
dev_priv->saveGR[0x18]);
|
|
||||||
|
|
||||||
/* Attribute controller registers */
|
|
||||||
inb(st01);
|
|
||||||
for (i = 0; i <= 0x14; i++)
|
|
||||||
i915_write_ar(st01, i, dev_priv->saveAR[i], 0);
|
|
||||||
inb(st01); /* switch back to index mode */
|
|
||||||
outb(dev_priv->saveAR_INDEX | 0x20, VGA_AR_INDEX);
|
|
||||||
inb(st01);
|
|
||||||
|
|
||||||
/* VGA color palette registers */
|
|
||||||
outb(dev_priv->saveDACMASK, VGA_DACMASK);
|
|
||||||
/* DACCRX automatically increments during read */
|
|
||||||
outb(0, VGA_DACWX);
|
|
||||||
/* Read 3 bytes of color data from each index */
|
|
||||||
for (i = 0; i < 256 * 3; i++)
|
|
||||||
outb(dev_priv->saveDACDATA[i], VGA_DACDATA);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int i915_suspend(struct drm_device *dev, pm_message_t state)
|
static int i915_suspend(struct drm_device *dev, pm_message_t state)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!dev || !dev_priv) {
|
if (!dev || !dev_priv) {
|
||||||
printk(KERN_ERR "dev: %p, dev_priv: %p\n", dev, dev_priv);
|
printk(KERN_ERR "dev: %p, dev_priv: %p\n", dev, dev_priv);
|
||||||
|
@ -254,122 +52,10 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
pci_save_state(dev->pdev);
|
pci_save_state(dev->pdev);
|
||||||
pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
|
|
||||||
|
|
||||||
/* Display arbitration control */
|
i915_save_state(dev);
|
||||||
dev_priv->saveDSPARB = I915_READ(DSPARB);
|
|
||||||
|
|
||||||
/* Pipe & plane A info */
|
intel_opregion_free(dev);
|
||||||
dev_priv->savePIPEACONF = I915_READ(PIPEACONF);
|
|
||||||
dev_priv->savePIPEASRC = I915_READ(PIPEASRC);
|
|
||||||
dev_priv->saveFPA0 = I915_READ(FPA0);
|
|
||||||
dev_priv->saveFPA1 = I915_READ(FPA1);
|
|
||||||
dev_priv->saveDPLL_A = I915_READ(DPLL_A);
|
|
||||||
if (IS_I965G(dev))
|
|
||||||
dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD);
|
|
||||||
dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A);
|
|
||||||
dev_priv->saveHBLANK_A = I915_READ(HBLANK_A);
|
|
||||||
dev_priv->saveHSYNC_A = I915_READ(HSYNC_A);
|
|
||||||
dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A);
|
|
||||||
dev_priv->saveVBLANK_A = I915_READ(VBLANK_A);
|
|
||||||
dev_priv->saveVSYNC_A = I915_READ(VSYNC_A);
|
|
||||||
dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
|
|
||||||
|
|
||||||
dev_priv->saveDSPACNTR = I915_READ(DSPACNTR);
|
|
||||||
dev_priv->saveDSPASTRIDE = I915_READ(DSPASTRIDE);
|
|
||||||
dev_priv->saveDSPASIZE = I915_READ(DSPASIZE);
|
|
||||||
dev_priv->saveDSPAPOS = I915_READ(DSPAPOS);
|
|
||||||
dev_priv->saveDSPABASE = I915_READ(DSPABASE);
|
|
||||||
if (IS_I965G(dev)) {
|
|
||||||
dev_priv->saveDSPASURF = I915_READ(DSPASURF);
|
|
||||||
dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF);
|
|
||||||
}
|
|
||||||
i915_save_palette(dev, PIPE_A);
|
|
||||||
dev_priv->savePIPEASTAT = I915_READ(I915REG_PIPEASTAT);
|
|
||||||
|
|
||||||
/* Pipe & plane B info */
|
|
||||||
dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF);
|
|
||||||
dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC);
|
|
||||||
dev_priv->saveFPB0 = I915_READ(FPB0);
|
|
||||||
dev_priv->saveFPB1 = I915_READ(FPB1);
|
|
||||||
dev_priv->saveDPLL_B = I915_READ(DPLL_B);
|
|
||||||
if (IS_I965G(dev))
|
|
||||||
dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD);
|
|
||||||
dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B);
|
|
||||||
dev_priv->saveHBLANK_B = I915_READ(HBLANK_B);
|
|
||||||
dev_priv->saveHSYNC_B = I915_READ(HSYNC_B);
|
|
||||||
dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B);
|
|
||||||
dev_priv->saveVBLANK_B = I915_READ(VBLANK_B);
|
|
||||||
dev_priv->saveVSYNC_B = I915_READ(VSYNC_B);
|
|
||||||
dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
|
|
||||||
|
|
||||||
dev_priv->saveDSPBCNTR = I915_READ(DSPBCNTR);
|
|
||||||
dev_priv->saveDSPBSTRIDE = I915_READ(DSPBSTRIDE);
|
|
||||||
dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE);
|
|
||||||
dev_priv->saveDSPBPOS = I915_READ(DSPBPOS);
|
|
||||||
dev_priv->saveDSPBBASE = I915_READ(DSPBBASE);
|
|
||||||
if (IS_I965GM(dev) || IS_IGD_GM(dev)) {
|
|
||||||
dev_priv->saveDSPBSURF = I915_READ(DSPBSURF);
|
|
||||||
dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF);
|
|
||||||
}
|
|
||||||
i915_save_palette(dev, PIPE_B);
|
|
||||||
dev_priv->savePIPEBSTAT = I915_READ(I915REG_PIPEBSTAT);
|
|
||||||
|
|
||||||
/* CRT state */
|
|
||||||
dev_priv->saveADPA = I915_READ(ADPA);
|
|
||||||
|
|
||||||
/* LVDS state */
|
|
||||||
dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL);
|
|
||||||
dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
|
|
||||||
dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
|
|
||||||
if (IS_I965G(dev))
|
|
||||||
dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
|
|
||||||
if (IS_MOBILE(dev) && !IS_I830(dev))
|
|
||||||
dev_priv->saveLVDS = I915_READ(LVDS);
|
|
||||||
if (!IS_I830(dev) && !IS_845G(dev))
|
|
||||||
dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL);
|
|
||||||
dev_priv->saveLVDSPP_ON = I915_READ(LVDSPP_ON);
|
|
||||||
dev_priv->saveLVDSPP_OFF = I915_READ(LVDSPP_OFF);
|
|
||||||
dev_priv->savePP_CYCLE = I915_READ(PP_CYCLE);
|
|
||||||
|
|
||||||
/* FIXME: save TV & SDVO state */
|
|
||||||
|
|
||||||
/* FBC state */
|
|
||||||
dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
|
|
||||||
dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE);
|
|
||||||
dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2);
|
|
||||||
dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL);
|
|
||||||
|
|
||||||
/* Interrupt state */
|
|
||||||
dev_priv->saveIIR = I915_READ(I915REG_INT_IDENTITY_R);
|
|
||||||
dev_priv->saveIER = I915_READ(I915REG_INT_ENABLE_R);
|
|
||||||
dev_priv->saveIMR = I915_READ(I915REG_INT_MASK_R);
|
|
||||||
|
|
||||||
/* VGA state */
|
|
||||||
dev_priv->saveVCLK_DIVISOR_VGA0 = I915_READ(VCLK_DIVISOR_VGA0);
|
|
||||||
dev_priv->saveVCLK_DIVISOR_VGA1 = I915_READ(VCLK_DIVISOR_VGA1);
|
|
||||||
dev_priv->saveVCLK_POST_DIV = I915_READ(VCLK_POST_DIV);
|
|
||||||
dev_priv->saveVGACNTRL = I915_READ(VGACNTRL);
|
|
||||||
|
|
||||||
/* Clock gating state */
|
|
||||||
dev_priv->saveD_STATE = I915_READ(D_STATE);
|
|
||||||
dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D);
|
|
||||||
|
|
||||||
/* Cache mode state */
|
|
||||||
dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
|
|
||||||
|
|
||||||
/* Memory Arbitration state */
|
|
||||||
dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE);
|
|
||||||
|
|
||||||
/* Scratch space */
|
|
||||||
for (i = 0; i < 16; i++) {
|
|
||||||
dev_priv->saveSWF0[i] = I915_READ(SWF0 + (i << 2));
|
|
||||||
dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2));
|
|
||||||
}
|
|
||||||
for (i = 0; i < 3; i++)
|
|
||||||
dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2));
|
|
||||||
|
|
||||||
i915_save_vga(dev);
|
|
||||||
|
|
||||||
if (state.event == PM_EVENT_SUSPEND) {
|
if (state.event == PM_EVENT_SUSPEND) {
|
||||||
/* Shut down the device */
|
/* Shut down the device */
|
||||||
|
@ -382,155 +68,15 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
|
||||||
|
|
||||||
static int i915_resume(struct drm_device *dev)
|
static int i915_resume(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
pci_set_power_state(dev->pdev, PCI_D0);
|
pci_set_power_state(dev->pdev, PCI_D0);
|
||||||
pci_restore_state(dev->pdev);
|
pci_restore_state(dev->pdev);
|
||||||
if (pci_enable_device(dev->pdev))
|
if (pci_enable_device(dev->pdev))
|
||||||
return -1;
|
return -1;
|
||||||
pci_set_master(dev->pdev);
|
pci_set_master(dev->pdev);
|
||||||
|
|
||||||
pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB);
|
i915_restore_state(dev);
|
||||||
|
|
||||||
I915_WRITE(DSPARB, dev_priv->saveDSPARB);
|
intel_opregion_init(dev);
|
||||||
|
|
||||||
/* Pipe & plane A info */
|
|
||||||
/* Prime the clock */
|
|
||||||
if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
|
|
||||||
I915_WRITE(DPLL_A, dev_priv->saveDPLL_A &
|
|
||||||
~DPLL_VCO_ENABLE);
|
|
||||||
udelay(150);
|
|
||||||
}
|
|
||||||
I915_WRITE(FPA0, dev_priv->saveFPA0);
|
|
||||||
I915_WRITE(FPA1, dev_priv->saveFPA1);
|
|
||||||
/* Actually enable it */
|
|
||||||
I915_WRITE(DPLL_A, dev_priv->saveDPLL_A);
|
|
||||||
udelay(150);
|
|
||||||
if (IS_I965G(dev))
|
|
||||||
I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
|
|
||||||
udelay(150);
|
|
||||||
|
|
||||||
/* Restore mode */
|
|
||||||
I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A);
|
|
||||||
I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A);
|
|
||||||
I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A);
|
|
||||||
I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A);
|
|
||||||
I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A);
|
|
||||||
I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A);
|
|
||||||
I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
|
|
||||||
|
|
||||||
/* Restore plane info */
|
|
||||||
I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE);
|
|
||||||
I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS);
|
|
||||||
I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
|
|
||||||
I915_WRITE(DSPABASE, dev_priv->saveDSPABASE);
|
|
||||||
I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
|
|
||||||
if (IS_I965G(dev)) {
|
|
||||||
I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
|
|
||||||
I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF);
|
|
||||||
|
|
||||||
i915_restore_palette(dev, PIPE_A);
|
|
||||||
/* Enable the plane */
|
|
||||||
I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR);
|
|
||||||
I915_WRITE(DSPABASE, I915_READ(DSPABASE));
|
|
||||||
|
|
||||||
/* Pipe & plane B info */
|
|
||||||
if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
|
|
||||||
I915_WRITE(DPLL_B, dev_priv->saveDPLL_B &
|
|
||||||
~DPLL_VCO_ENABLE);
|
|
||||||
udelay(150);
|
|
||||||
}
|
|
||||||
I915_WRITE(FPB0, dev_priv->saveFPB0);
|
|
||||||
I915_WRITE(FPB1, dev_priv->saveFPB1);
|
|
||||||
/* Actually enable it */
|
|
||||||
I915_WRITE(DPLL_B, dev_priv->saveDPLL_B);
|
|
||||||
udelay(150);
|
|
||||||
if (IS_I965G(dev))
|
|
||||||
I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
|
|
||||||
udelay(150);
|
|
||||||
|
|
||||||
/* Restore mode */
|
|
||||||
I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B);
|
|
||||||
I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B);
|
|
||||||
I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B);
|
|
||||||
I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B);
|
|
||||||
I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B);
|
|
||||||
I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B);
|
|
||||||
I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
|
|
||||||
|
|
||||||
/* Restore plane info */
|
|
||||||
I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE);
|
|
||||||
I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS);
|
|
||||||
I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
|
|
||||||
I915_WRITE(DSPBBASE, dev_priv->saveDSPBBASE);
|
|
||||||
I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
|
|
||||||
if (IS_I965G(dev)) {
|
|
||||||
I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
|
|
||||||
I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF);
|
|
||||||
|
|
||||||
i915_restore_palette(dev, PIPE_B);
|
|
||||||
/* Enable the plane */
|
|
||||||
I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
|
|
||||||
I915_WRITE(DSPBBASE, I915_READ(DSPBBASE));
|
|
||||||
|
|
||||||
/* CRT state */
|
|
||||||
I915_WRITE(ADPA, dev_priv->saveADPA);
|
|
||||||
|
|
||||||
/* LVDS state */
|
|
||||||
if (IS_I965G(dev))
|
|
||||||
I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2);
|
|
||||||
if (IS_MOBILE(dev) && !IS_I830(dev))
|
|
||||||
I915_WRITE(LVDS, dev_priv->saveLVDS);
|
|
||||||
if (!IS_I830(dev) && !IS_845G(dev))
|
|
||||||
I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL);
|
|
||||||
|
|
||||||
I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
|
|
||||||
I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
|
|
||||||
I915_WRITE(LVDSPP_ON, dev_priv->saveLVDSPP_ON);
|
|
||||||
I915_WRITE(LVDSPP_OFF, dev_priv->saveLVDSPP_OFF);
|
|
||||||
I915_WRITE(PP_CYCLE, dev_priv->savePP_CYCLE);
|
|
||||||
I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
|
|
||||||
|
|
||||||
/* FIXME: restore TV & SDVO state */
|
|
||||||
|
|
||||||
/* FBC info */
|
|
||||||
I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE);
|
|
||||||
I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE);
|
|
||||||
I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2);
|
|
||||||
I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL);
|
|
||||||
|
|
||||||
/* VGA state */
|
|
||||||
I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL);
|
|
||||||
I915_WRITE(VCLK_DIVISOR_VGA0, dev_priv->saveVCLK_DIVISOR_VGA0);
|
|
||||||
I915_WRITE(VCLK_DIVISOR_VGA1, dev_priv->saveVCLK_DIVISOR_VGA1);
|
|
||||||
I915_WRITE(VCLK_POST_DIV, dev_priv->saveVCLK_POST_DIV);
|
|
||||||
udelay(150);
|
|
||||||
|
|
||||||
/* Clock gating state */
|
|
||||||
I915_WRITE (D_STATE, dev_priv->saveD_STATE);
|
|
||||||
I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D);
|
|
||||||
|
|
||||||
/* Cache mode state */
|
|
||||||
I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
|
|
||||||
|
|
||||||
/* Memory arbitration state */
|
|
||||||
I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000);
|
|
||||||
|
|
||||||
for (i = 0; i < 16; i++) {
|
|
||||||
I915_WRITE(SWF0 + (i << 2), dev_priv->saveSWF0[i]);
|
|
||||||
I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]);
|
|
||||||
}
|
|
||||||
for (i = 0; i < 3; i++)
|
|
||||||
I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
|
|
||||||
|
|
||||||
i915_restore_vga(dev);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -541,17 +87,19 @@ static struct drm_driver driver = {
|
||||||
*/
|
*/
|
||||||
.driver_features =
|
.driver_features =
|
||||||
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/
|
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/
|
||||||
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL |
|
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM,
|
||||||
DRIVER_IRQ_VBL2,
|
|
||||||
.load = i915_driver_load,
|
.load = i915_driver_load,
|
||||||
.unload = i915_driver_unload,
|
.unload = i915_driver_unload,
|
||||||
|
.open = i915_driver_open,
|
||||||
.lastclose = i915_driver_lastclose,
|
.lastclose = i915_driver_lastclose,
|
||||||
.preclose = i915_driver_preclose,
|
.preclose = i915_driver_preclose,
|
||||||
|
.postclose = i915_driver_postclose,
|
||||||
.suspend = i915_suspend,
|
.suspend = i915_suspend,
|
||||||
.resume = i915_resume,
|
.resume = i915_resume,
|
||||||
.device_is_agp = i915_driver_device_is_agp,
|
.device_is_agp = i915_driver_device_is_agp,
|
||||||
.vblank_wait = i915_driver_vblank_wait,
|
.get_vblank_counter = i915_get_vblank_counter,
|
||||||
.vblank_wait2 = i915_driver_vblank_wait2,
|
.enable_vblank = i915_enable_vblank,
|
||||||
|
.disable_vblank = i915_disable_vblank,
|
||||||
.irq_preinstall = i915_driver_irq_preinstall,
|
.irq_preinstall = i915_driver_irq_preinstall,
|
||||||
.irq_postinstall = i915_driver_irq_postinstall,
|
.irq_postinstall = i915_driver_irq_postinstall,
|
||||||
.irq_uninstall = i915_driver_irq_uninstall,
|
.irq_uninstall = i915_driver_irq_uninstall,
|
||||||
|
@ -559,6 +107,10 @@ static struct drm_driver driver = {
|
||||||
.reclaim_buffers = drm_core_reclaim_buffers,
|
.reclaim_buffers = drm_core_reclaim_buffers,
|
||||||
.get_map_ofs = drm_core_get_map_ofs,
|
.get_map_ofs = drm_core_get_map_ofs,
|
||||||
.get_reg_ofs = drm_core_get_reg_ofs,
|
.get_reg_ofs = drm_core_get_reg_ofs,
|
||||||
|
.proc_init = i915_gem_proc_init,
|
||||||
|
.proc_cleanup = i915_gem_proc_cleanup,
|
||||||
|
.gem_init_object = i915_gem_init_object,
|
||||||
|
.gem_free_object = i915_gem_free_object,
|
||||||
.ioctls = i915_ioctls,
|
.ioctls = i915_ioctls,
|
||||||
.fops = {
|
.fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2008 Intel Corporation
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Keith Packard <keithp@keithp.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drmP.h"
|
||||||
|
#include "drm.h"
|
||||||
|
#include "i915_drm.h"
|
||||||
|
#include "i915_drv.h"
|
||||||
|
|
||||||
|
#if WATCH_INACTIVE
|
||||||
|
void
|
||||||
|
i915_verify_inactive(struct drm_device *dev, char *file, int line)
|
||||||
|
{
|
||||||
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
|
struct drm_gem_object *obj;
|
||||||
|
struct drm_i915_gem_object *obj_priv;
|
||||||
|
|
||||||
|
list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
|
||||||
|
obj = obj_priv->obj;
|
||||||
|
if (obj_priv->pin_count || obj_priv->active ||
|
||||||
|
(obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
|
||||||
|
I915_GEM_DOMAIN_GTT)))
|
||||||
|
DRM_ERROR("inactive %p (p %d a %d w %x) %s:%d\n",
|
||||||
|
obj,
|
||||||
|
obj_priv->pin_count, obj_priv->active,
|
||||||
|
obj->write_domain, file, line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* WATCH_INACTIVE */
|
||||||
|
|
||||||
|
|
||||||
|
#if WATCH_BUF | WATCH_EXEC | WATCH_PWRITE
|
||||||
|
static void
|
||||||
|
i915_gem_dump_page(struct page *page, uint32_t start, uint32_t end,
|
||||||
|
uint32_t bias, uint32_t mark)
|
||||||
|
{
|
||||||
|
uint32_t *mem = kmap_atomic(page, KM_USER0);
|
||||||
|
int i;
|
||||||
|
for (i = start; i < end; i += 4)
|
||||||
|
DRM_INFO("%08x: %08x%s\n",
|
||||||
|
(int) (bias + i), mem[i / 4],
|
||||||
|
(bias + i == mark) ? " ********" : "");
|
||||||
|
kunmap_atomic(mem, KM_USER0);
|
||||||
|
/* give syslog time to catch up */
|
||||||
|
msleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
i915_gem_dump_object(struct drm_gem_object *obj, int len,
|
||||||
|
const char *where, uint32_t mark)
|
||||||
|
{
|
||||||
|
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||||
|
int page;
|
||||||
|
|
||||||
|
DRM_INFO("%s: object at offset %08x\n", where, obj_priv->gtt_offset);
|
||||||
|
for (page = 0; page < (len + PAGE_SIZE-1) / PAGE_SIZE; page++) {
|
||||||
|
int page_len, chunk, chunk_len;
|
||||||
|
|
||||||
|
page_len = len - page * PAGE_SIZE;
|
||||||
|
if (page_len > PAGE_SIZE)
|
||||||
|
page_len = PAGE_SIZE;
|
||||||
|
|
||||||
|
for (chunk = 0; chunk < page_len; chunk += 128) {
|
||||||
|
chunk_len = page_len - chunk;
|
||||||
|
if (chunk_len > 128)
|
||||||
|
chunk_len = 128;
|
||||||
|
i915_gem_dump_page(obj_priv->page_list[page],
|
||||||
|
chunk, chunk + chunk_len,
|
||||||
|
obj_priv->gtt_offset +
|
||||||
|
page * PAGE_SIZE,
|
||||||
|
mark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if WATCH_LRU
|
||||||
|
void
|
||||||
|
i915_dump_lru(struct drm_device *dev, const char *where)
|
||||||
|
{
|
||||||
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
|
struct drm_i915_gem_object *obj_priv;
|
||||||
|
|
||||||
|
DRM_INFO("active list %s {\n", where);
|
||||||
|
list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
|
||||||
|
list)
|
||||||
|
{
|
||||||
|
DRM_INFO(" %p: %08x\n", obj_priv,
|
||||||
|
obj_priv->last_rendering_seqno);
|
||||||
|
}
|
||||||
|
DRM_INFO("}\n");
|
||||||
|
DRM_INFO("flushing list %s {\n", where);
|
||||||
|
list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
|
||||||
|
list)
|
||||||
|
{
|
||||||
|
DRM_INFO(" %p: %08x\n", obj_priv,
|
||||||
|
obj_priv->last_rendering_seqno);
|
||||||
|
}
|
||||||
|
DRM_INFO("}\n");
|
||||||
|
DRM_INFO("inactive %s {\n", where);
|
||||||
|
list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
|
||||||
|
DRM_INFO(" %p: %08x\n", obj_priv,
|
||||||
|
obj_priv->last_rendering_seqno);
|
||||||
|
}
|
||||||
|
DRM_INFO("}\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if WATCH_COHERENCY
|
||||||
|
void
|
||||||
|
i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = obj->dev;
|
||||||
|
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||||
|
int page;
|
||||||
|
uint32_t *gtt_mapping;
|
||||||
|
uint32_t *backing_map = NULL;
|
||||||
|
int bad_count = 0;
|
||||||
|
|
||||||
|
DRM_INFO("%s: checking coherency of object %p@0x%08x (%d, %dkb):\n",
|
||||||
|
__func__, obj, obj_priv->gtt_offset, handle,
|
||||||
|
obj->size / 1024);
|
||||||
|
|
||||||
|
gtt_mapping = ioremap(dev->agp->base + obj_priv->gtt_offset,
|
||||||
|
obj->size);
|
||||||
|
if (gtt_mapping == NULL) {
|
||||||
|
DRM_ERROR("failed to map GTT space\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (page = 0; page < obj->size / PAGE_SIZE; page++) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
backing_map = kmap_atomic(obj_priv->page_list[page], KM_USER0);
|
||||||
|
|
||||||
|
if (backing_map == NULL) {
|
||||||
|
DRM_ERROR("failed to map backing page\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < PAGE_SIZE / 4; i++) {
|
||||||
|
uint32_t cpuval = backing_map[i];
|
||||||
|
uint32_t gttval = readl(gtt_mapping +
|
||||||
|
page * 1024 + i);
|
||||||
|
|
||||||
|
if (cpuval != gttval) {
|
||||||
|
DRM_INFO("incoherent CPU vs GPU at 0x%08x: "
|
||||||
|
"0x%08x vs 0x%08x\n",
|
||||||
|
(int)(obj_priv->gtt_offset +
|
||||||
|
page * PAGE_SIZE + i * 4),
|
||||||
|
cpuval, gttval);
|
||||||
|
if (bad_count++ >= 8) {
|
||||||
|
DRM_INFO("...\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kunmap_atomic(backing_map, KM_USER0);
|
||||||
|
backing_map = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (backing_map != NULL)
|
||||||
|
kunmap_atomic(backing_map, KM_USER0);
|
||||||
|
iounmap(gtt_mapping);
|
||||||
|
|
||||||
|
/* give syslog time to catch up */
|
||||||
|
msleep(1);
|
||||||
|
|
||||||
|
/* Directly flush the object, since we just loaded values with the CPU
|
||||||
|
* from the backing pages and we don't want to disturb the cache
|
||||||
|
* management that we're trying to observe.
|
||||||
|
*/
|
||||||
|
|
||||||
|
i915_gem_clflush_object(obj);
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,292 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2008 Intel Corporation
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Eric Anholt <eric@anholt.net>
|
||||||
|
* Keith Packard <keithp@keithp.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drmP.h"
|
||||||
|
#include "drm.h"
|
||||||
|
#include "i915_drm.h"
|
||||||
|
#include "i915_drv.h"
|
||||||
|
|
||||||
|
static int i915_gem_active_info(char *buf, char **start, off_t offset,
|
||||||
|
int request, int *eof, void *data)
|
||||||
|
{
|
||||||
|
struct drm_minor *minor = (struct drm_minor *) data;
|
||||||
|
struct drm_device *dev = minor->dev;
|
||||||
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
|
struct drm_i915_gem_object *obj_priv;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (offset > DRM_PROC_LIMIT) {
|
||||||
|
*eof = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*start = &buf[offset];
|
||||||
|
*eof = 0;
|
||||||
|
DRM_PROC_PRINT("Active:\n");
|
||||||
|
list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
|
||||||
|
list)
|
||||||
|
{
|
||||||
|
struct drm_gem_object *obj = obj_priv->obj;
|
||||||
|
if (obj->name) {
|
||||||
|
DRM_PROC_PRINT(" %p(%d): %08x %08x %d\n",
|
||||||
|
obj, obj->name,
|
||||||
|
obj->read_domains, obj->write_domain,
|
||||||
|
obj_priv->last_rendering_seqno);
|
||||||
|
} else {
|
||||||
|
DRM_PROC_PRINT(" %p: %08x %08x %d\n",
|
||||||
|
obj,
|
||||||
|
obj->read_domains, obj->write_domain,
|
||||||
|
obj_priv->last_rendering_seqno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (len > request + offset)
|
||||||
|
return request;
|
||||||
|
*eof = 1;
|
||||||
|
return len - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int i915_gem_flushing_info(char *buf, char **start, off_t offset,
|
||||||
|
int request, int *eof, void *data)
|
||||||
|
{
|
||||||
|
struct drm_minor *minor = (struct drm_minor *) data;
|
||||||
|
struct drm_device *dev = minor->dev;
|
||||||
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
|
struct drm_i915_gem_object *obj_priv;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (offset > DRM_PROC_LIMIT) {
|
||||||
|
*eof = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*start = &buf[offset];
|
||||||
|
*eof = 0;
|
||||||
|
DRM_PROC_PRINT("Flushing:\n");
|
||||||
|
list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
|
||||||
|
list)
|
||||||
|
{
|
||||||
|
struct drm_gem_object *obj = obj_priv->obj;
|
||||||
|
if (obj->name) {
|
||||||
|
DRM_PROC_PRINT(" %p(%d): %08x %08x %d\n",
|
||||||
|
obj, obj->name,
|
||||||
|
obj->read_domains, obj->write_domain,
|
||||||
|
obj_priv->last_rendering_seqno);
|
||||||
|
} else {
|
||||||
|
DRM_PROC_PRINT(" %p: %08x %08x %d\n", obj,
|
||||||
|
obj->read_domains, obj->write_domain,
|
||||||
|
obj_priv->last_rendering_seqno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (len > request + offset)
|
||||||
|
return request;
|
||||||
|
*eof = 1;
|
||||||
|
return len - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int i915_gem_inactive_info(char *buf, char **start, off_t offset,
|
||||||
|
int request, int *eof, void *data)
|
||||||
|
{
|
||||||
|
struct drm_minor *minor = (struct drm_minor *) data;
|
||||||
|
struct drm_device *dev = minor->dev;
|
||||||
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
|
struct drm_i915_gem_object *obj_priv;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (offset > DRM_PROC_LIMIT) {
|
||||||
|
*eof = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*start = &buf[offset];
|
||||||
|
*eof = 0;
|
||||||
|
DRM_PROC_PRINT("Inactive:\n");
|
||||||
|
list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list,
|
||||||
|
list)
|
||||||
|
{
|
||||||
|
struct drm_gem_object *obj = obj_priv->obj;
|
||||||
|
if (obj->name) {
|
||||||
|
DRM_PROC_PRINT(" %p(%d): %08x %08x %d\n",
|
||||||
|
obj, obj->name,
|
||||||
|
obj->read_domains, obj->write_domain,
|
||||||
|
obj_priv->last_rendering_seqno);
|
||||||
|
} else {
|
||||||
|
DRM_PROC_PRINT(" %p: %08x %08x %d\n", obj,
|
||||||
|
obj->read_domains, obj->write_domain,
|
||||||
|
obj_priv->last_rendering_seqno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (len > request + offset)
|
||||||
|
return request;
|
||||||
|
*eof = 1;
|
||||||
|
return len - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int i915_gem_request_info(char *buf, char **start, off_t offset,
|
||||||
|
int request, int *eof, void *data)
|
||||||
|
{
|
||||||
|
struct drm_minor *minor = (struct drm_minor *) data;
|
||||||
|
struct drm_device *dev = minor->dev;
|
||||||
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
|
struct drm_i915_gem_request *gem_request;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (offset > DRM_PROC_LIMIT) {
|
||||||
|
*eof = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*start = &buf[offset];
|
||||||
|
*eof = 0;
|
||||||
|
DRM_PROC_PRINT("Request:\n");
|
||||||
|
list_for_each_entry(gem_request, &dev_priv->mm.request_list,
|
||||||
|
list)
|
||||||
|
{
|
||||||
|
DRM_PROC_PRINT(" %d @ %d %08x\n",
|
||||||
|
gem_request->seqno,
|
||||||
|
(int) (jiffies - gem_request->emitted_jiffies),
|
||||||
|
gem_request->flush_domains);
|
||||||
|
}
|
||||||
|
if (len > request + offset)
|
||||||
|
return request;
|
||||||
|
*eof = 1;
|
||||||
|
return len - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int i915_gem_seqno_info(char *buf, char **start, off_t offset,
|
||||||
|
int request, int *eof, void *data)
|
||||||
|
{
|
||||||
|
struct drm_minor *minor = (struct drm_minor *) data;
|
||||||
|
struct drm_device *dev = minor->dev;
|
||||||
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (offset > DRM_PROC_LIMIT) {
|
||||||
|
*eof = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*start = &buf[offset];
|
||||||
|
*eof = 0;
|
||||||
|
DRM_PROC_PRINT("Current sequence: %d\n", i915_get_gem_seqno(dev));
|
||||||
|
DRM_PROC_PRINT("Waiter sequence: %d\n",
|
||||||
|
dev_priv->mm.waiting_gem_seqno);
|
||||||
|
DRM_PROC_PRINT("IRQ sequence: %d\n", dev_priv->mm.irq_gem_seqno);
|
||||||
|
if (len > request + offset)
|
||||||
|
return request;
|
||||||
|
*eof = 1;
|
||||||
|
return len - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int i915_interrupt_info(char *buf, char **start, off_t offset,
|
||||||
|
int request, int *eof, void *data)
|
||||||
|
{
|
||||||
|
struct drm_minor *minor = (struct drm_minor *) data;
|
||||||
|
struct drm_device *dev = minor->dev;
|
||||||
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (offset > DRM_PROC_LIMIT) {
|
||||||
|
*eof = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*start = &buf[offset];
|
||||||
|
*eof = 0;
|
||||||
|
DRM_PROC_PRINT("Interrupt enable: %08x\n",
|
||||||
|
I915_READ(IER));
|
||||||
|
DRM_PROC_PRINT("Interrupt identity: %08x\n",
|
||||||
|
I915_READ(IIR));
|
||||||
|
DRM_PROC_PRINT("Interrupt mask: %08x\n",
|
||||||
|
I915_READ(IMR));
|
||||||
|
DRM_PROC_PRINT("Pipe A stat: %08x\n",
|
||||||
|
I915_READ(PIPEASTAT));
|
||||||
|
DRM_PROC_PRINT("Pipe B stat: %08x\n",
|
||||||
|
I915_READ(PIPEBSTAT));
|
||||||
|
DRM_PROC_PRINT("Interrupts received: %d\n",
|
||||||
|
atomic_read(&dev_priv->irq_received));
|
||||||
|
DRM_PROC_PRINT("Current sequence: %d\n",
|
||||||
|
i915_get_gem_seqno(dev));
|
||||||
|
DRM_PROC_PRINT("Waiter sequence: %d\n",
|
||||||
|
dev_priv->mm.waiting_gem_seqno);
|
||||||
|
DRM_PROC_PRINT("IRQ sequence: %d\n",
|
||||||
|
dev_priv->mm.irq_gem_seqno);
|
||||||
|
if (len > request + offset)
|
||||||
|
return request;
|
||||||
|
*eof = 1;
|
||||||
|
return len - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct drm_proc_list {
|
||||||
|
/** file name */
|
||||||
|
const char *name;
|
||||||
|
/** proc callback*/
|
||||||
|
int (*f) (char *, char **, off_t, int, int *, void *);
|
||||||
|
} i915_gem_proc_list[] = {
|
||||||
|
{"i915_gem_active", i915_gem_active_info},
|
||||||
|
{"i915_gem_flushing", i915_gem_flushing_info},
|
||||||
|
{"i915_gem_inactive", i915_gem_inactive_info},
|
||||||
|
{"i915_gem_request", i915_gem_request_info},
|
||||||
|
{"i915_gem_seqno", i915_gem_seqno_info},
|
||||||
|
{"i915_gem_interrupt", i915_interrupt_info},
|
||||||
|
};
|
||||||
|
|
||||||
|
#define I915_GEM_PROC_ENTRIES ARRAY_SIZE(i915_gem_proc_list)
|
||||||
|
|
||||||
|
int i915_gem_proc_init(struct drm_minor *minor)
|
||||||
|
{
|
||||||
|
struct proc_dir_entry *ent;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < I915_GEM_PROC_ENTRIES; i++) {
|
||||||
|
ent = create_proc_entry(i915_gem_proc_list[i].name,
|
||||||
|
S_IFREG | S_IRUGO, minor->dev_root);
|
||||||
|
if (!ent) {
|
||||||
|
DRM_ERROR("Cannot create /proc/dri/.../%s\n",
|
||||||
|
i915_gem_proc_list[i].name);
|
||||||
|
for (j = 0; j < i; j++)
|
||||||
|
remove_proc_entry(i915_gem_proc_list[i].name,
|
||||||
|
minor->dev_root);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ent->read_proc = i915_gem_proc_list[i].f;
|
||||||
|
ent->data = minor;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void i915_gem_proc_cleanup(struct drm_minor *minor)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!minor->dev_root)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < I915_GEM_PROC_ENTRIES; i++)
|
||||||
|
remove_proc_entry(i915_gem_proc_list[i].name, minor->dev_root);
|
||||||
|
}
|
|
@ -0,0 +1,257 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2008 Intel Corporation
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Eric Anholt <eric@anholt.net>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drmP.h"
|
||||||
|
#include "drm.h"
|
||||||
|
#include "i915_drm.h"
|
||||||
|
#include "i915_drv.h"
|
||||||
|
|
||||||
|
/** @file i915_gem_tiling.c
|
||||||
|
*
|
||||||
|
* Support for managing tiling state of buffer objects.
|
||||||
|
*
|
||||||
|
* The idea behind tiling is to increase cache hit rates by rearranging
|
||||||
|
* pixel data so that a group of pixel accesses are in the same cacheline.
|
||||||
|
* Performance improvement from doing this on the back/depth buffer are on
|
||||||
|
* the order of 30%.
|
||||||
|
*
|
||||||
|
* Intel architectures make this somewhat more complicated, though, by
|
||||||
|
* adjustments made to addressing of data when the memory is in interleaved
|
||||||
|
* mode (matched pairs of DIMMS) to improve memory bandwidth.
|
||||||
|
* For interleaved memory, the CPU sends every sequential 64 bytes
|
||||||
|
* to an alternate memory channel so it can get the bandwidth from both.
|
||||||
|
*
|
||||||
|
* The GPU also rearranges its accesses for increased bandwidth to interleaved
|
||||||
|
* memory, and it matches what the CPU does for non-tiled. However, when tiled
|
||||||
|
* it does it a little differently, since one walks addresses not just in the
|
||||||
|
* X direction but also Y. So, along with alternating channels when bit
|
||||||
|
* 6 of the address flips, it also alternates when other bits flip -- Bits 9
|
||||||
|
* (every 512 bytes, an X tile scanline) and 10 (every two X tile scanlines)
|
||||||
|
* are common to both the 915 and 965-class hardware.
|
||||||
|
*
|
||||||
|
* The CPU also sometimes XORs in higher bits as well, to improve
|
||||||
|
* bandwidth doing strided access like we do so frequently in graphics. This
|
||||||
|
* is called "Channel XOR Randomization" in the MCH documentation. The result
|
||||||
|
* is that the CPU is XORing in either bit 11 or bit 17 to bit 6 of its address
|
||||||
|
* decode.
|
||||||
|
*
|
||||||
|
* All of this bit 6 XORing has an effect on our memory management,
|
||||||
|
* as we need to make sure that the 3d driver can correctly address object
|
||||||
|
* contents.
|
||||||
|
*
|
||||||
|
* If we don't have interleaved memory, all tiling is safe and no swizzling is
|
||||||
|
* required.
|
||||||
|
*
|
||||||
|
* When bit 17 is XORed in, we simply refuse to tile at all. Bit
|
||||||
|
* 17 is not just a page offset, so as we page an objet out and back in,
|
||||||
|
* individual pages in it will have different bit 17 addresses, resulting in
|
||||||
|
* each 64 bytes being swapped with its neighbor!
|
||||||
|
*
|
||||||
|
* Otherwise, if interleaved, we have to tell the 3d driver what the address
|
||||||
|
* swizzling it needs to do is, since it's writing with the CPU to the pages
|
||||||
|
* (bit 6 and potentially bit 11 XORed in), and the GPU is reading from the
|
||||||
|
* pages (bit 6, 9, and 10 XORed in), resulting in a cumulative bit swizzling
|
||||||
|
* required by the CPU of XORing in bit 6, 9, 10, and potentially 11, in order
|
||||||
|
* to match what the GPU expects.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects bit 6 swizzling of address lookup between IGD access and CPU
|
||||||
|
* access through main memory.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
|
uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||||
|
uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||||
|
|
||||||
|
if (!IS_I9XX(dev)) {
|
||||||
|
/* As far as we know, the 865 doesn't have these bit 6
|
||||||
|
* swizzling issues.
|
||||||
|
*/
|
||||||
|
swizzle_x = I915_BIT_6_SWIZZLE_NONE;
|
||||||
|
swizzle_y = I915_BIT_6_SWIZZLE_NONE;
|
||||||
|
} else if ((!IS_I965G(dev) && !IS_G33(dev)) || IS_I965GM(dev) ||
|
||||||
|
IS_GM45(dev)) {
|
||||||
|
uint32_t dcc;
|
||||||
|
|
||||||
|
/* On 915-945 and GM965, channel interleave by the CPU is
|
||||||
|
* determined by DCC. The CPU will alternate based on bit 6
|
||||||
|
* in interleaved mode, and the GPU will then also alternate
|
||||||
|
* on bit 6, 9, and 10 for X, but the CPU may also optionally
|
||||||
|
* alternate based on bit 17 (XOR not disabled and XOR
|
||||||
|
* bit == 17).
|
||||||
|
*/
|
||||||
|
dcc = I915_READ(DCC);
|
||||||
|
switch (dcc & DCC_ADDRESSING_MODE_MASK) {
|
||||||
|
case DCC_ADDRESSING_MODE_SINGLE_CHANNEL:
|
||||||
|
case DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC:
|
||||||
|
swizzle_x = I915_BIT_6_SWIZZLE_NONE;
|
||||||
|
swizzle_y = I915_BIT_6_SWIZZLE_NONE;
|
||||||
|
break;
|
||||||
|
case DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED:
|
||||||
|
if (IS_I915G(dev) || IS_I915GM(dev) ||
|
||||||
|
dcc & DCC_CHANNEL_XOR_DISABLE) {
|
||||||
|
swizzle_x = I915_BIT_6_SWIZZLE_9_10;
|
||||||
|
swizzle_y = I915_BIT_6_SWIZZLE_9;
|
||||||
|
} else if (IS_I965GM(dev) || IS_GM45(dev)) {
|
||||||
|
/* GM965 only does bit 11-based channel
|
||||||
|
* randomization
|
||||||
|
*/
|
||||||
|
swizzle_x = I915_BIT_6_SWIZZLE_9_10_11;
|
||||||
|
swizzle_y = I915_BIT_6_SWIZZLE_9_11;
|
||||||
|
} else {
|
||||||
|
/* Bit 17 or perhaps other swizzling */
|
||||||
|
swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||||
|
swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (dcc == 0xffffffff) {
|
||||||
|
DRM_ERROR("Couldn't read from MCHBAR. "
|
||||||
|
"Disabling tiling.\n");
|
||||||
|
swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||||
|
swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* The 965, G33, and newer, have a very flexible memory
|
||||||
|
* configuration. It will enable dual-channel mode
|
||||||
|
* (interleaving) on as much memory as it can, and the GPU
|
||||||
|
* will additionally sometimes enable different bit 6
|
||||||
|
* swizzling for tiled objects from the CPU.
|
||||||
|
*
|
||||||
|
* Here's what I found on the G965:
|
||||||
|
* slot fill memory size swizzling
|
||||||
|
* 0A 0B 1A 1B 1-ch 2-ch
|
||||||
|
* 512 0 0 0 512 0 O
|
||||||
|
* 512 0 512 0 16 1008 X
|
||||||
|
* 512 0 0 512 16 1008 X
|
||||||
|
* 0 512 0 512 16 1008 X
|
||||||
|
* 1024 1024 1024 0 2048 1024 O
|
||||||
|
*
|
||||||
|
* We could probably detect this based on either the DRB
|
||||||
|
* matching, which was the case for the swizzling required in
|
||||||
|
* the table above, or from the 1-ch value being less than
|
||||||
|
* the minimum size of a rank.
|
||||||
|
*/
|
||||||
|
if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) {
|
||||||
|
swizzle_x = I915_BIT_6_SWIZZLE_NONE;
|
||||||
|
swizzle_y = I915_BIT_6_SWIZZLE_NONE;
|
||||||
|
} else {
|
||||||
|
swizzle_x = I915_BIT_6_SWIZZLE_9_10;
|
||||||
|
swizzle_y = I915_BIT_6_SWIZZLE_9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_priv->mm.bit_6_swizzle_x = swizzle_x;
|
||||||
|
dev_priv->mm.bit_6_swizzle_y = swizzle_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the tiling mode of an object, returning the required swizzling of
|
||||||
|
* bit 6 of addresses in the object.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
i915_gem_set_tiling(struct drm_device *dev, void *data,
|
||||||
|
struct drm_file *file_priv)
|
||||||
|
{
|
||||||
|
struct drm_i915_gem_set_tiling *args = data;
|
||||||
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
|
struct drm_gem_object *obj;
|
||||||
|
struct drm_i915_gem_object *obj_priv;
|
||||||
|
|
||||||
|
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
|
||||||
|
if (obj == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
obj_priv = obj->driver_private;
|
||||||
|
|
||||||
|
mutex_lock(&dev->struct_mutex);
|
||||||
|
|
||||||
|
if (args->tiling_mode == I915_TILING_NONE) {
|
||||||
|
obj_priv->tiling_mode = I915_TILING_NONE;
|
||||||
|
args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
|
||||||
|
} else {
|
||||||
|
if (args->tiling_mode == I915_TILING_X)
|
||||||
|
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
|
||||||
|
else
|
||||||
|
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
|
||||||
|
/* If we can't handle the swizzling, make it untiled. */
|
||||||
|
if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) {
|
||||||
|
args->tiling_mode = I915_TILING_NONE;
|
||||||
|
args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj_priv->tiling_mode = args->tiling_mode;
|
||||||
|
|
||||||
|
mutex_unlock(&dev->struct_mutex);
|
||||||
|
|
||||||
|
drm_gem_object_unreference(obj);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current tiling mode and required bit 6 swizzling for the object.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
i915_gem_get_tiling(struct drm_device *dev, void *data,
|
||||||
|
struct drm_file *file_priv)
|
||||||
|
{
|
||||||
|
struct drm_i915_gem_get_tiling *args = data;
|
||||||
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
|
struct drm_gem_object *obj;
|
||||||
|
struct drm_i915_gem_object *obj_priv;
|
||||||
|
|
||||||
|
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
|
||||||
|
if (obj == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
obj_priv = obj->driver_private;
|
||||||
|
|
||||||
|
mutex_lock(&dev->struct_mutex);
|
||||||
|
|
||||||
|
args->tiling_mode = obj_priv->tiling_mode;
|
||||||
|
switch (obj_priv->tiling_mode) {
|
||||||
|
case I915_TILING_X:
|
||||||
|
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
|
||||||
|
break;
|
||||||
|
case I915_TILING_Y:
|
||||||
|
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
|
||||||
|
break;
|
||||||
|
case I915_TILING_NONE:
|
||||||
|
args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRM_ERROR("unknown tiling mode\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&dev->struct_mutex);
|
||||||
|
|
||||||
|
drm_gem_object_unreference(obj);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -31,12 +31,92 @@
|
||||||
#include "i915_drm.h"
|
#include "i915_drm.h"
|
||||||
#include "i915_drv.h"
|
#include "i915_drv.h"
|
||||||
|
|
||||||
#define USER_INT_FLAG (1<<1)
|
|
||||||
#define VSYNC_PIPEB_FLAG (1<<5)
|
|
||||||
#define VSYNC_PIPEA_FLAG (1<<7)
|
|
||||||
|
|
||||||
#define MAX_NOPID ((u32)~0)
|
#define MAX_NOPID ((u32)~0)
|
||||||
|
|
||||||
|
/** These are the interrupts used by the driver */
|
||||||
|
#define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT | \
|
||||||
|
I915_ASLE_INTERRUPT | \
|
||||||
|
I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
|
||||||
|
I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
|
||||||
|
|
||||||
|
void
|
||||||
|
i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
|
||||||
|
{
|
||||||
|
if ((dev_priv->irq_mask_reg & mask) != 0) {
|
||||||
|
dev_priv->irq_mask_reg &= ~mask;
|
||||||
|
I915_WRITE(IMR, dev_priv->irq_mask_reg);
|
||||||
|
(void) I915_READ(IMR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask)
|
||||||
|
{
|
||||||
|
if ((dev_priv->irq_mask_reg & mask) != mask) {
|
||||||
|
dev_priv->irq_mask_reg |= mask;
|
||||||
|
I915_WRITE(IMR, dev_priv->irq_mask_reg);
|
||||||
|
(void) I915_READ(IMR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* i915_get_pipe - return the the pipe associated with a given plane
|
||||||
|
* @dev: DRM device
|
||||||
|
* @plane: plane to look for
|
||||||
|
*
|
||||||
|
* The Intel Mesa & 2D drivers call the vblank routines with a plane number
|
||||||
|
* rather than a pipe number, since they may not always be equal. This routine
|
||||||
|
* maps the given @plane back to a pipe number.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
i915_get_pipe(struct drm_device *dev, int plane)
|
||||||
|
{
|
||||||
|
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||||
|
u32 dspcntr;
|
||||||
|
|
||||||
|
dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR);
|
||||||
|
|
||||||
|
return dspcntr & DISPPLANE_SEL_PIPE_MASK ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* i915_get_plane - return the the plane associated with a given pipe
|
||||||
|
* @dev: DRM device
|
||||||
|
* @pipe: pipe to look for
|
||||||
|
*
|
||||||
|
* The Intel Mesa & 2D drivers call the vblank routines with a plane number
|
||||||
|
* rather than a plane number, since they may not always be equal. This routine
|
||||||
|
* maps the given @pipe back to a plane number.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
i915_get_plane(struct drm_device *dev, int pipe)
|
||||||
|
{
|
||||||
|
if (i915_get_pipe(dev, 0) == pipe)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* i915_pipe_enabled - check if a pipe is enabled
|
||||||
|
* @dev: DRM device
|
||||||
|
* @pipe: pipe to check
|
||||||
|
*
|
||||||
|
* Reading certain registers when the pipe is disabled can hang the chip.
|
||||||
|
* Use this routine to make sure the PLL is running and the pipe is active
|
||||||
|
* before reading such registers if unsure.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
i915_pipe_enabled(struct drm_device *dev, int pipe)
|
||||||
|
{
|
||||||
|
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||||
|
unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;
|
||||||
|
|
||||||
|
if (I915_READ(pipeconf) & PIPEACONF_ENABLE)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emit blits for scheduled buffer swaps.
|
* Emit blits for scheduled buffer swaps.
|
||||||
*
|
*
|
||||||
|
@ -48,8 +128,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
struct list_head *list, *tmp, hits, *hit;
|
struct list_head *list, *tmp, hits, *hit;
|
||||||
int nhits, nrects, slice[2], upper[2], lower[2], i;
|
int nhits, nrects, slice[2], upper[2], lower[2], i;
|
||||||
unsigned counter[2] = { atomic_read(&dev->vbl_received),
|
unsigned counter[2];
|
||||||
atomic_read(&dev->vbl_received2) };
|
|
||||||
struct drm_drawable_info *drw;
|
struct drm_drawable_info *drw;
|
||||||
drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
|
drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
|
||||||
u32 cpp = dev_priv->cpp;
|
u32 cpp = dev_priv->cpp;
|
||||||
|
@ -71,6 +150,9 @@ static void i915_vblank_tasklet(struct drm_device *dev)
|
||||||
src_pitch >>= 2;
|
src_pitch >>= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
counter[0] = drm_vblank_count(dev, 0);
|
||||||
|
counter[1] = drm_vblank_count(dev, 1);
|
||||||
|
|
||||||
DRM_DEBUG("\n");
|
DRM_DEBUG("\n");
|
||||||
|
|
||||||
INIT_LIST_HEAD(&hits);
|
INIT_LIST_HEAD(&hits);
|
||||||
|
@ -83,12 +165,14 @@ static void i915_vblank_tasklet(struct drm_device *dev)
|
||||||
list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
|
list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
|
||||||
drm_i915_vbl_swap_t *vbl_swap =
|
drm_i915_vbl_swap_t *vbl_swap =
|
||||||
list_entry(list, drm_i915_vbl_swap_t, head);
|
list_entry(list, drm_i915_vbl_swap_t, head);
|
||||||
|
int pipe = i915_get_pipe(dev, vbl_swap->plane);
|
||||||
|
|
||||||
if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
|
if ((counter[pipe] - vbl_swap->sequence) > (1<<23))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
list_del(list);
|
list_del(list);
|
||||||
dev_priv->swaps_pending--;
|
dev_priv->swaps_pending--;
|
||||||
|
drm_vblank_put(dev, pipe);
|
||||||
|
|
||||||
spin_unlock(&dev_priv->swaps_lock);
|
spin_unlock(&dev_priv->swaps_lock);
|
||||||
spin_lock(&dev->drw_lock);
|
spin_lock(&dev->drw_lock);
|
||||||
|
@ -181,7 +265,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
|
||||||
drm_i915_vbl_swap_t *swap_hit =
|
drm_i915_vbl_swap_t *swap_hit =
|
||||||
list_entry(hit, drm_i915_vbl_swap_t, head);
|
list_entry(hit, drm_i915_vbl_swap_t, head);
|
||||||
struct drm_clip_rect *rect;
|
struct drm_clip_rect *rect;
|
||||||
int num_rects, pipe;
|
int num_rects, plane;
|
||||||
unsigned short top, bottom;
|
unsigned short top, bottom;
|
||||||
|
|
||||||
drw = drm_get_drawable_info(dev, swap_hit->drw_id);
|
drw = drm_get_drawable_info(dev, swap_hit->drw_id);
|
||||||
|
@ -190,9 +274,9 @@ static void i915_vblank_tasklet(struct drm_device *dev)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
rect = drw->rects;
|
rect = drw->rects;
|
||||||
pipe = swap_hit->pipe;
|
plane = swap_hit->plane;
|
||||||
top = upper[pipe];
|
top = upper[plane];
|
||||||
bottom = lower[pipe];
|
bottom = lower[plane];
|
||||||
|
|
||||||
for (num_rects = drw->num_rects; num_rects--; rect++) {
|
for (num_rects = drw->num_rects; num_rects--; rect++) {
|
||||||
int y1 = max(rect->y1, top);
|
int y1 = max(rect->y1, top);
|
||||||
|
@ -229,61 +313,139 @@ static void i915_vblank_tasklet(struct drm_device *dev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
|
||||||
|
{
|
||||||
|
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||||
|
unsigned long high_frame;
|
||||||
|
unsigned long low_frame;
|
||||||
|
u32 high1, high2, low, count;
|
||||||
|
int pipe;
|
||||||
|
|
||||||
|
pipe = i915_get_pipe(dev, plane);
|
||||||
|
high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
|
||||||
|
low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
|
||||||
|
|
||||||
|
if (!i915_pipe_enabled(dev, pipe)) {
|
||||||
|
DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* High & low register fields aren't synchronized, so make sure
|
||||||
|
* we get a low value that's stable across two reads of the high
|
||||||
|
* register.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
|
||||||
|
PIPE_FRAME_HIGH_SHIFT);
|
||||||
|
low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
|
||||||
|
PIPE_FRAME_LOW_SHIFT);
|
||||||
|
high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
|
||||||
|
PIPE_FRAME_HIGH_SHIFT);
|
||||||
|
} while (high1 != high2);
|
||||||
|
|
||||||
|
count = (high1 << 8) | low;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
i915_gem_vblank_work_handler(struct work_struct *work)
|
||||||
|
{
|
||||||
|
drm_i915_private_t *dev_priv;
|
||||||
|
struct drm_device *dev;
|
||||||
|
|
||||||
|
dev_priv = container_of(work, drm_i915_private_t,
|
||||||
|
mm.vblank_work);
|
||||||
|
dev = dev_priv->dev;
|
||||||
|
|
||||||
|
mutex_lock(&dev->struct_mutex);
|
||||||
|
i915_vblank_tasklet(dev);
|
||||||
|
mutex_unlock(&dev->struct_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = (struct drm_device *) arg;
|
struct drm_device *dev = (struct drm_device *) arg;
|
||||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||||
u16 temp;
|
u32 iir;
|
||||||
u32 pipea_stats, pipeb_stats;
|
u32 pipea_stats, pipeb_stats;
|
||||||
|
int vblank = 0;
|
||||||
|
|
||||||
pipea_stats = I915_READ(I915REG_PIPEASTAT);
|
atomic_inc(&dev_priv->irq_received);
|
||||||
pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
|
|
||||||
|
|
||||||
temp = I915_READ16(I915REG_INT_IDENTITY_R);
|
if (dev->pdev->msi_enabled)
|
||||||
|
I915_WRITE(IMR, ~0);
|
||||||
|
iir = I915_READ(IIR);
|
||||||
|
|
||||||
temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG);
|
if (iir == 0) {
|
||||||
|
if (dev->pdev->msi_enabled) {
|
||||||
DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
|
I915_WRITE(IMR, dev_priv->irq_mask_reg);
|
||||||
|
(void) I915_READ(IMR);
|
||||||
if (temp == 0)
|
}
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
|
/*
|
||||||
(void) I915_READ16(I915REG_INT_IDENTITY_R);
|
* Clear the PIPE(A|B)STAT regs before the IIR otherwise
|
||||||
DRM_READMEMORYBARRIER();
|
* we may get extra interrupts.
|
||||||
|
*/
|
||||||
|
if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
|
||||||
|
pipea_stats = I915_READ(PIPEASTAT);
|
||||||
|
if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A))
|
||||||
|
pipea_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
|
||||||
|
PIPE_VBLANK_INTERRUPT_ENABLE);
|
||||||
|
else if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
|
||||||
|
PIPE_VBLANK_INTERRUPT_STATUS)) {
|
||||||
|
vblank++;
|
||||||
|
drm_handle_vblank(dev, i915_get_plane(dev, 0));
|
||||||
|
}
|
||||||
|
|
||||||
dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
|
I915_WRITE(PIPEASTAT, pipea_stats);
|
||||||
|
}
|
||||||
|
if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) {
|
||||||
|
pipeb_stats = I915_READ(PIPEBSTAT);
|
||||||
|
/* Ack the event */
|
||||||
|
I915_WRITE(PIPEBSTAT, pipeb_stats);
|
||||||
|
|
||||||
if (temp & USER_INT_FLAG)
|
/* The vblank interrupt gets enabled even if we didn't ask for
|
||||||
|
it, so make sure it's shut down again */
|
||||||
|
if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B))
|
||||||
|
pipeb_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
|
||||||
|
PIPE_VBLANK_INTERRUPT_ENABLE);
|
||||||
|
else if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
|
||||||
|
PIPE_VBLANK_INTERRUPT_STATUS)) {
|
||||||
|
vblank++;
|
||||||
|
drm_handle_vblank(dev, i915_get_plane(dev, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS)
|
||||||
|
opregion_asle_intr(dev);
|
||||||
|
I915_WRITE(PIPEBSTAT, pipeb_stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
I915_WRITE(IIR, iir);
|
||||||
|
if (dev->pdev->msi_enabled)
|
||||||
|
I915_WRITE(IMR, dev_priv->irq_mask_reg);
|
||||||
|
(void) I915_READ(IIR); /* Flush posted writes */
|
||||||
|
|
||||||
|
if (dev_priv->sarea_priv)
|
||||||
|
dev_priv->sarea_priv->last_dispatch =
|
||||||
|
READ_BREADCRUMB(dev_priv);
|
||||||
|
|
||||||
|
if (iir & I915_USER_INTERRUPT) {
|
||||||
|
dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
|
||||||
DRM_WAKEUP(&dev_priv->irq_queue);
|
DRM_WAKEUP(&dev_priv->irq_queue);
|
||||||
|
}
|
||||||
|
|
||||||
if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
|
if (iir & I915_ASLE_INTERRUPT)
|
||||||
int vblank_pipe = dev_priv->vblank_pipe;
|
opregion_asle_intr(dev);
|
||||||
|
|
||||||
if ((vblank_pipe &
|
if (vblank && dev_priv->swaps_pending > 0) {
|
||||||
(DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
|
if (dev_priv->ring.ring_obj == NULL)
|
||||||
== (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
|
|
||||||
if (temp & VSYNC_PIPEA_FLAG)
|
|
||||||
atomic_inc(&dev->vbl_received);
|
|
||||||
if (temp & VSYNC_PIPEB_FLAG)
|
|
||||||
atomic_inc(&dev->vbl_received2);
|
|
||||||
} else if (((temp & VSYNC_PIPEA_FLAG) &&
|
|
||||||
(vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
|
|
||||||
((temp & VSYNC_PIPEB_FLAG) &&
|
|
||||||
(vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
|
|
||||||
atomic_inc(&dev->vbl_received);
|
|
||||||
|
|
||||||
DRM_WAKEUP(&dev->vbl_queue);
|
|
||||||
drm_vbl_send_signals(dev);
|
|
||||||
|
|
||||||
if (dev_priv->swaps_pending > 0)
|
|
||||||
drm_locked_tasklet(dev, i915_vblank_tasklet);
|
drm_locked_tasklet(dev, i915_vblank_tasklet);
|
||||||
I915_WRITE(I915REG_PIPEASTAT,
|
else
|
||||||
pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
|
schedule_work(&dev_priv->mm.vblank_work);
|
||||||
I915_VBLANK_CLEAR);
|
|
||||||
I915_WRITE(I915REG_PIPEBSTAT,
|
|
||||||
pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE|
|
|
||||||
I915_VBLANK_CLEAR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
@ -298,23 +460,45 @@ static int i915_emit_irq(struct drm_device * dev)
|
||||||
|
|
||||||
DRM_DEBUG("\n");
|
DRM_DEBUG("\n");
|
||||||
|
|
||||||
dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
|
dev_priv->counter++;
|
||||||
|
|
||||||
if (dev_priv->counter > 0x7FFFFFFFUL)
|
if (dev_priv->counter > 0x7FFFFFFFUL)
|
||||||
dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
|
dev_priv->counter = 1;
|
||||||
|
if (dev_priv->sarea_priv)
|
||||||
|
dev_priv->sarea_priv->last_enqueue = dev_priv->counter;
|
||||||
|
|
||||||
BEGIN_LP_RING(6);
|
BEGIN_LP_RING(6);
|
||||||
OUT_RING(CMD_STORE_DWORD_IDX);
|
OUT_RING(MI_STORE_DWORD_INDEX);
|
||||||
OUT_RING(20);
|
OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
|
||||||
OUT_RING(dev_priv->counter);
|
OUT_RING(dev_priv->counter);
|
||||||
OUT_RING(0);
|
OUT_RING(0);
|
||||||
OUT_RING(0);
|
OUT_RING(0);
|
||||||
OUT_RING(GFX_OP_USER_INTERRUPT);
|
OUT_RING(MI_USER_INTERRUPT);
|
||||||
ADVANCE_LP_RING();
|
ADVANCE_LP_RING();
|
||||||
|
|
||||||
return dev_priv->counter;
|
return dev_priv->counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void i915_user_irq_get(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||||
|
|
||||||
|
spin_lock(&dev_priv->user_irq_lock);
|
||||||
|
if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1))
|
||||||
|
i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
|
||||||
|
spin_unlock(&dev_priv->user_irq_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void i915_user_irq_put(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||||
|
|
||||||
|
spin_lock(&dev_priv->user_irq_lock);
|
||||||
|
BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
|
||||||
|
if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0))
|
||||||
|
i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
|
||||||
|
spin_unlock(&dev_priv->user_irq_lock);
|
||||||
|
}
|
||||||
|
|
||||||
static int i915_wait_irq(struct drm_device * dev, int irq_nr)
|
static int i915_wait_irq(struct drm_device * dev, int irq_nr)
|
||||||
{
|
{
|
||||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||||
|
@ -323,55 +507,34 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
|
||||||
DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr,
|
DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr,
|
||||||
READ_BREADCRUMB(dev_priv));
|
READ_BREADCRUMB(dev_priv));
|
||||||
|
|
||||||
if (READ_BREADCRUMB(dev_priv) >= irq_nr)
|
if (READ_BREADCRUMB(dev_priv) >= irq_nr) {
|
||||||
|
if (dev_priv->sarea_priv) {
|
||||||
|
dev_priv->sarea_priv->last_dispatch =
|
||||||
|
READ_BREADCRUMB(dev_priv);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
|
if (dev_priv->sarea_priv)
|
||||||
|
dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
|
||||||
|
|
||||||
|
i915_user_irq_get(dev);
|
||||||
DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
|
DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
|
||||||
READ_BREADCRUMB(dev_priv) >= irq_nr);
|
READ_BREADCRUMB(dev_priv) >= irq_nr);
|
||||||
|
i915_user_irq_put(dev);
|
||||||
|
|
||||||
if (ret == -EBUSY) {
|
if (ret == -EBUSY) {
|
||||||
DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
|
DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
|
||||||
READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
|
READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
|
if (dev_priv->sarea_priv)
|
||||||
return ret;
|
dev_priv->sarea_priv->last_dispatch =
|
||||||
}
|
READ_BREADCRUMB(dev_priv);
|
||||||
|
|
||||||
static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence,
|
|
||||||
atomic_t *counter)
|
|
||||||
{
|
|
||||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
|
||||||
unsigned int cur_vblank;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (!dev_priv) {
|
|
||||||
DRM_ERROR("called with no initialization\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
|
|
||||||
(((cur_vblank = atomic_read(counter))
|
|
||||||
- *sequence) <= (1<<23)));
|
|
||||||
|
|
||||||
*sequence = cur_vblank;
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
|
|
||||||
{
|
|
||||||
return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
|
|
||||||
}
|
|
||||||
|
|
||||||
int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
|
|
||||||
{
|
|
||||||
return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Needs the lock as it touches the ring.
|
/* Needs the lock as it touches the ring.
|
||||||
*/
|
*/
|
||||||
int i915_irq_emit(struct drm_device *dev, void *data,
|
int i915_irq_emit(struct drm_device *dev, void *data,
|
||||||
|
@ -381,14 +544,15 @@ int i915_irq_emit(struct drm_device *dev, void *data,
|
||||||
drm_i915_irq_emit_t *emit = data;
|
drm_i915_irq_emit_t *emit = data;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
LOCK_TEST_WITH_RETURN(dev, file_priv);
|
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||||
|
|
||||||
if (!dev_priv) {
|
if (!dev_priv) {
|
||||||
DRM_ERROR("called with no initialization\n");
|
DRM_ERROR("called with no initialization\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
mutex_lock(&dev->struct_mutex);
|
||||||
result = i915_emit_irq(dev);
|
result = i915_emit_irq(dev);
|
||||||
|
mutex_unlock(&dev->struct_mutex);
|
||||||
|
|
||||||
if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
|
if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
|
||||||
DRM_ERROR("copy_to_user\n");
|
DRM_ERROR("copy_to_user\n");
|
||||||
|
@ -414,18 +578,74 @@ int i915_irq_wait(struct drm_device *dev, void *data,
|
||||||
return i915_wait_irq(dev, irqwait->irq_seq);
|
return i915_wait_irq(dev, irqwait->irq_seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void i915_enable_interrupt (struct drm_device *dev)
|
int i915_enable_vblank(struct drm_device *dev, int plane)
|
||||||
{
|
{
|
||||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||||
u16 flag;
|
int pipe = i915_get_pipe(dev, plane);
|
||||||
|
u32 pipestat_reg = 0;
|
||||||
|
u32 pipestat;
|
||||||
|
|
||||||
flag = 0;
|
switch (pipe) {
|
||||||
if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
|
case 0:
|
||||||
flag |= VSYNC_PIPEA_FLAG;
|
pipestat_reg = PIPEASTAT;
|
||||||
if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
|
i915_enable_irq(dev_priv, I915_DISPLAY_PIPE_A_EVENT_INTERRUPT);
|
||||||
flag |= VSYNC_PIPEB_FLAG;
|
break;
|
||||||
|
case 1:
|
||||||
|
pipestat_reg = PIPEBSTAT;
|
||||||
|
i915_enable_irq(dev_priv, I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRM_ERROR("tried to enable vblank on non-existent pipe %d\n",
|
||||||
|
pipe);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag);
|
if (pipestat_reg) {
|
||||||
|
pipestat = I915_READ(pipestat_reg);
|
||||||
|
if (IS_I965G(dev))
|
||||||
|
pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE;
|
||||||
|
else
|
||||||
|
pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE;
|
||||||
|
/* Clear any stale interrupt status */
|
||||||
|
pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS |
|
||||||
|
PIPE_VBLANK_INTERRUPT_STATUS);
|
||||||
|
I915_WRITE(pipestat_reg, pipestat);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void i915_disable_vblank(struct drm_device *dev, int plane)
|
||||||
|
{
|
||||||
|
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||||
|
int pipe = i915_get_pipe(dev, plane);
|
||||||
|
u32 pipestat_reg = 0;
|
||||||
|
u32 pipestat;
|
||||||
|
|
||||||
|
switch (pipe) {
|
||||||
|
case 0:
|
||||||
|
pipestat_reg = PIPEASTAT;
|
||||||
|
i915_disable_irq(dev_priv, I915_DISPLAY_PIPE_A_EVENT_INTERRUPT);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
pipestat_reg = PIPEBSTAT;
|
||||||
|
i915_disable_irq(dev_priv, I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRM_ERROR("tried to disable vblank on non-existent pipe %d\n",
|
||||||
|
pipe);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pipestat_reg) {
|
||||||
|
pipestat = I915_READ(pipestat_reg);
|
||||||
|
pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
|
||||||
|
PIPE_VBLANK_INTERRUPT_ENABLE);
|
||||||
|
/* Clear any stale interrupt status */
|
||||||
|
pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS |
|
||||||
|
PIPE_VBLANK_INTERRUPT_STATUS);
|
||||||
|
I915_WRITE(pipestat_reg, pipestat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the vblank monitor pipe
|
/* Set the vblank monitor pipe
|
||||||
|
@ -434,22 +654,12 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data,
|
||||||
struct drm_file *file_priv)
|
struct drm_file *file_priv)
|
||||||
{
|
{
|
||||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
drm_i915_vblank_pipe_t *pipe = data;
|
|
||||||
|
|
||||||
if (!dev_priv) {
|
if (!dev_priv) {
|
||||||
DRM_ERROR("called with no initialization\n");
|
DRM_ERROR("called with no initialization\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
|
|
||||||
DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_priv->vblank_pipe = pipe->pipe;
|
|
||||||
|
|
||||||
i915_enable_interrupt (dev);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,19 +668,13 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data,
|
||||||
{
|
{
|
||||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
drm_i915_vblank_pipe_t *pipe = data;
|
drm_i915_vblank_pipe_t *pipe = data;
|
||||||
u16 flag;
|
|
||||||
|
|
||||||
if (!dev_priv) {
|
if (!dev_priv) {
|
||||||
DRM_ERROR("called with no initialization\n");
|
DRM_ERROR("called with no initialization\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
flag = I915_READ(I915REG_INT_ENABLE_R);
|
pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
|
||||||
pipe->pipe = 0;
|
|
||||||
if (flag & VSYNC_PIPEA_FLAG)
|
|
||||||
pipe->pipe |= DRM_I915_VBLANK_PIPE_A;
|
|
||||||
if (flag & VSYNC_PIPEB_FLAG)
|
|
||||||
pipe->pipe |= DRM_I915_VBLANK_PIPE_B;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -484,11 +688,12 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
|
||||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
drm_i915_vblank_swap_t *swap = data;
|
drm_i915_vblank_swap_t *swap = data;
|
||||||
drm_i915_vbl_swap_t *vbl_swap;
|
drm_i915_vbl_swap_t *vbl_swap;
|
||||||
unsigned int pipe, seqtype, curseq;
|
unsigned int pipe, seqtype, curseq, plane;
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
struct list_head *list;
|
struct list_head *list;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!dev_priv) {
|
if (!dev_priv || !dev_priv->sarea_priv) {
|
||||||
DRM_ERROR("%s called with no initialization\n", __func__);
|
DRM_ERROR("%s called with no initialization\n", __func__);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -504,7 +709,8 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
|
plane = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
|
||||||
|
pipe = i915_get_pipe(dev, plane);
|
||||||
|
|
||||||
seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
|
seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
|
||||||
|
|
||||||
|
@ -523,7 +729,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
|
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
|
||||||
|
|
||||||
curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
|
/*
|
||||||
|
* We take the ref here and put it when the swap actually completes
|
||||||
|
* in the tasklet.
|
||||||
|
*/
|
||||||
|
ret = drm_vblank_get(dev, pipe);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
curseq = drm_vblank_count(dev, pipe);
|
||||||
|
|
||||||
if (seqtype == _DRM_VBLANK_RELATIVE)
|
if (seqtype == _DRM_VBLANK_RELATIVE)
|
||||||
swap->sequence += curseq;
|
swap->sequence += curseq;
|
||||||
|
@ -533,6 +746,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
|
||||||
swap->sequence = curseq + 1;
|
swap->sequence = curseq + 1;
|
||||||
} else {
|
} else {
|
||||||
DRM_DEBUG("Missed target sequence\n");
|
DRM_DEBUG("Missed target sequence\n");
|
||||||
|
drm_vblank_put(dev, pipe);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -543,7 +757,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
|
||||||
vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
|
vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
|
||||||
|
|
||||||
if (vbl_swap->drw_id == swap->drawable &&
|
if (vbl_swap->drw_id == swap->drawable &&
|
||||||
vbl_swap->pipe == pipe &&
|
vbl_swap->plane == plane &&
|
||||||
vbl_swap->sequence == swap->sequence) {
|
vbl_swap->sequence == swap->sequence) {
|
||||||
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
|
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
|
||||||
DRM_DEBUG("Already scheduled\n");
|
DRM_DEBUG("Already scheduled\n");
|
||||||
|
@ -555,6 +769,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
|
||||||
|
|
||||||
if (dev_priv->swaps_pending >= 100) {
|
if (dev_priv->swaps_pending >= 100) {
|
||||||
DRM_DEBUG("Too many swaps queued\n");
|
DRM_DEBUG("Too many swaps queued\n");
|
||||||
|
drm_vblank_put(dev, pipe);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,13 +777,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
|
||||||
|
|
||||||
if (!vbl_swap) {
|
if (!vbl_swap) {
|
||||||
DRM_ERROR("Failed to allocate memory to queue swap\n");
|
DRM_ERROR("Failed to allocate memory to queue swap\n");
|
||||||
|
drm_vblank_put(dev, pipe);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
DRM_DEBUG("\n");
|
DRM_DEBUG("\n");
|
||||||
|
|
||||||
vbl_swap->drw_id = swap->drawable;
|
vbl_swap->drw_id = swap->drawable;
|
||||||
vbl_swap->pipe = pipe;
|
vbl_swap->plane = plane;
|
||||||
vbl_swap->sequence = swap->sequence;
|
vbl_swap->sequence = swap->sequence;
|
||||||
|
|
||||||
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
|
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
|
||||||
|
@ -587,37 +803,63 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
|
||||||
{
|
{
|
||||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||||
|
|
||||||
I915_WRITE16(I915REG_HWSTAM, 0xfffe);
|
I915_WRITE(HWSTAM, 0xeffe);
|
||||||
I915_WRITE16(I915REG_INT_MASK_R, 0x0);
|
I915_WRITE(IMR, 0xffffffff);
|
||||||
I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
|
I915_WRITE(IER, 0x0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void i915_driver_irq_postinstall(struct drm_device * dev)
|
int i915_driver_irq_postinstall(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||||
|
int ret, num_pipes = 2;
|
||||||
|
|
||||||
spin_lock_init(&dev_priv->swaps_lock);
|
spin_lock_init(&dev_priv->swaps_lock);
|
||||||
INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
|
INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
|
||||||
dev_priv->swaps_pending = 0;
|
dev_priv->swaps_pending = 0;
|
||||||
|
|
||||||
if (!dev_priv->vblank_pipe)
|
/* Set initial unmasked IRQs to just the selected vblank pipes. */
|
||||||
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
|
dev_priv->irq_mask_reg = ~0;
|
||||||
i915_enable_interrupt(dev);
|
|
||||||
|
ret = drm_vblank_init(dev, num_pipes);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
|
||||||
|
dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
|
||||||
|
dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
|
||||||
|
|
||||||
|
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
|
||||||
|
|
||||||
|
dev_priv->irq_mask_reg &= I915_INTERRUPT_ENABLE_MASK;
|
||||||
|
|
||||||
|
I915_WRITE(IMR, dev_priv->irq_mask_reg);
|
||||||
|
I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK);
|
||||||
|
(void) I915_READ(IER);
|
||||||
|
|
||||||
|
opregion_enable_asle(dev);
|
||||||
DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
|
DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void i915_driver_irq_uninstall(struct drm_device * dev)
|
void i915_driver_irq_uninstall(struct drm_device * dev)
|
||||||
{
|
{
|
||||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||||
u16 temp;
|
u32 temp;
|
||||||
|
|
||||||
if (!dev_priv)
|
if (!dev_priv)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
I915_WRITE16(I915REG_HWSTAM, 0xffff);
|
dev_priv->vblank_pipe = 0;
|
||||||
I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
|
|
||||||
I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
|
|
||||||
|
|
||||||
temp = I915_READ16(I915REG_INT_IDENTITY_R);
|
I915_WRITE(HWSTAM, 0xffffffff);
|
||||||
I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
|
I915_WRITE(IMR, 0xffffffff);
|
||||||
|
I915_WRITE(IER, 0x0);
|
||||||
|
|
||||||
|
temp = I915_READ(PIPEASTAT);
|
||||||
|
I915_WRITE(PIPEASTAT, temp);
|
||||||
|
temp = I915_READ(PIPEBSTAT);
|
||||||
|
I915_WRITE(PIPEBSTAT, temp);
|
||||||
|
temp = I915_READ(IIR);
|
||||||
|
I915_WRITE(IIR, temp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,371 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2008 Intel Corporation <hong.liu@intel.com>
|
||||||
|
* Copyright 2008 Red Hat <mjg@redhat.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sub license, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the
|
||||||
|
* next paragraph) shall be included in all copies or substantial
|
||||||
|
* portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NON-INFRINGEMENT. IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/acpi.h>
|
||||||
|
|
||||||
|
#include "drmP.h"
|
||||||
|
#include "i915_drm.h"
|
||||||
|
#include "i915_drv.h"
|
||||||
|
|
||||||
|
#define PCI_ASLE 0xe4
|
||||||
|
#define PCI_LBPC 0xf4
|
||||||
|
#define PCI_ASLS 0xfc
|
||||||
|
|
||||||
|
#define OPREGION_SZ (8*1024)
|
||||||
|
#define OPREGION_HEADER_OFFSET 0
|
||||||
|
#define OPREGION_ACPI_OFFSET 0x100
|
||||||
|
#define OPREGION_SWSCI_OFFSET 0x200
|
||||||
|
#define OPREGION_ASLE_OFFSET 0x300
|
||||||
|
#define OPREGION_VBT_OFFSET 0x1000
|
||||||
|
|
||||||
|
#define OPREGION_SIGNATURE "IntelGraphicsMem"
|
||||||
|
#define MBOX_ACPI (1<<0)
|
||||||
|
#define MBOX_SWSCI (1<<1)
|
||||||
|
#define MBOX_ASLE (1<<2)
|
||||||
|
|
||||||
|
struct opregion_header {
|
||||||
|
u8 signature[16];
|
||||||
|
u32 size;
|
||||||
|
u32 opregion_ver;
|
||||||
|
u8 bios_ver[32];
|
||||||
|
u8 vbios_ver[16];
|
||||||
|
u8 driver_ver[16];
|
||||||
|
u32 mboxes;
|
||||||
|
u8 reserved[164];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* OpRegion mailbox #1: public ACPI methods */
|
||||||
|
struct opregion_acpi {
|
||||||
|
u32 drdy; /* driver readiness */
|
||||||
|
u32 csts; /* notification status */
|
||||||
|
u32 cevt; /* current event */
|
||||||
|
u8 rsvd1[20];
|
||||||
|
u32 didl[8]; /* supported display devices ID list */
|
||||||
|
u32 cpdl[8]; /* currently presented display list */
|
||||||
|
u32 cadl[8]; /* currently active display list */
|
||||||
|
u32 nadl[8]; /* next active devices list */
|
||||||
|
u32 aslp; /* ASL sleep time-out */
|
||||||
|
u32 tidx; /* toggle table index */
|
||||||
|
u32 chpd; /* current hotplug enable indicator */
|
||||||
|
u32 clid; /* current lid state*/
|
||||||
|
u32 cdck; /* current docking state */
|
||||||
|
u32 sxsw; /* Sx state resume */
|
||||||
|
u32 evts; /* ASL supported events */
|
||||||
|
u32 cnot; /* current OS notification */
|
||||||
|
u32 nrdy; /* driver status */
|
||||||
|
u8 rsvd2[60];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* OpRegion mailbox #2: SWSCI */
|
||||||
|
struct opregion_swsci {
|
||||||
|
u32 scic; /* SWSCI command|status|data */
|
||||||
|
u32 parm; /* command parameters */
|
||||||
|
u32 dslp; /* driver sleep time-out */
|
||||||
|
u8 rsvd[244];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* OpRegion mailbox #3: ASLE */
|
||||||
|
struct opregion_asle {
|
||||||
|
u32 ardy; /* driver readiness */
|
||||||
|
u32 aslc; /* ASLE interrupt command */
|
||||||
|
u32 tche; /* technology enabled indicator */
|
||||||
|
u32 alsi; /* current ALS illuminance reading */
|
||||||
|
u32 bclp; /* backlight brightness to set */
|
||||||
|
u32 pfit; /* panel fitting state */
|
||||||
|
u32 cblv; /* current brightness level */
|
||||||
|
u16 bclm[20]; /* backlight level duty cycle mapping table */
|
||||||
|
u32 cpfm; /* current panel fitting mode */
|
||||||
|
u32 epfm; /* enabled panel fitting modes */
|
||||||
|
u8 plut[74]; /* panel LUT and identifier */
|
||||||
|
u32 pfmb; /* PWM freq and min brightness */
|
||||||
|
u8 rsvd[102];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* ASLE irq request bits */
|
||||||
|
#define ASLE_SET_ALS_ILLUM (1 << 0)
|
||||||
|
#define ASLE_SET_BACKLIGHT (1 << 1)
|
||||||
|
#define ASLE_SET_PFIT (1 << 2)
|
||||||
|
#define ASLE_SET_PWM_FREQ (1 << 3)
|
||||||
|
#define ASLE_REQ_MSK 0xf
|
||||||
|
|
||||||
|
/* response bits of ASLE irq request */
|
||||||
|
#define ASLE_ALS_ILLUM_FAIL (2<<10)
|
||||||
|
#define ASLE_BACKLIGHT_FAIL (2<<12)
|
||||||
|
#define ASLE_PFIT_FAIL (2<<14)
|
||||||
|
#define ASLE_PWM_FREQ_FAIL (2<<16)
|
||||||
|
|
||||||
|
/* ASLE backlight brightness to set */
|
||||||
|
#define ASLE_BCLP_VALID (1<<31)
|
||||||
|
#define ASLE_BCLP_MSK (~(1<<31))
|
||||||
|
|
||||||
|
/* ASLE panel fitting request */
|
||||||
|
#define ASLE_PFIT_VALID (1<<31)
|
||||||
|
#define ASLE_PFIT_CENTER (1<<0)
|
||||||
|
#define ASLE_PFIT_STRETCH_TEXT (1<<1)
|
||||||
|
#define ASLE_PFIT_STRETCH_GFX (1<<2)
|
||||||
|
|
||||||
|
/* PWM frequency and minimum brightness */
|
||||||
|
#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
|
||||||
|
#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
|
||||||
|
#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
|
||||||
|
#define ASLE_PFMB_PWM_VALID (1<<31)
|
||||||
|
|
||||||
|
#define ASLE_CBLV_VALID (1<<31)
|
||||||
|
|
||||||
|
static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
struct opregion_asle *asle = dev_priv->opregion.asle;
|
||||||
|
u32 blc_pwm_ctl, blc_pwm_ctl2;
|
||||||
|
|
||||||
|
if (!(bclp & ASLE_BCLP_VALID))
|
||||||
|
return ASLE_BACKLIGHT_FAIL;
|
||||||
|
|
||||||
|
bclp &= ASLE_BCLP_MSK;
|
||||||
|
if (bclp < 0 || bclp > 255)
|
||||||
|
return ASLE_BACKLIGHT_FAIL;
|
||||||
|
|
||||||
|
blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
|
||||||
|
blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
|
||||||
|
blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2);
|
||||||
|
|
||||||
|
if (blc_pwm_ctl2 & BLM_COMBINATION_MODE)
|
||||||
|
pci_write_config_dword(dev->pdev, PCI_LBPC, bclp);
|
||||||
|
else
|
||||||
|
I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | ((bclp * 0x101)-1));
|
||||||
|
|
||||||
|
asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
|
||||||
|
{
|
||||||
|
/* alsi is the current ALS reading in lux. 0 indicates below sensor
|
||||||
|
range, 0xffff indicates above sensor range. 1-0xfffe are valid */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
if (pfmb & ASLE_PFMB_PWM_VALID) {
|
||||||
|
u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
|
||||||
|
u32 pwm = pfmb & ASLE_PFMB_PWM_MASK;
|
||||||
|
blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK;
|
||||||
|
pwm = pwm >> 9;
|
||||||
|
/* FIXME - what do we do with the PWM? */
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
|
||||||
|
{
|
||||||
|
/* Panel fitting is currently controlled by the X code, so this is a
|
||||||
|
noop until modesetting support works fully */
|
||||||
|
if (!(pfit & ASLE_PFIT_VALID))
|
||||||
|
return ASLE_PFIT_FAIL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void opregion_asle_intr(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
struct opregion_asle *asle = dev_priv->opregion.asle;
|
||||||
|
u32 asle_stat = 0;
|
||||||
|
u32 asle_req;
|
||||||
|
|
||||||
|
if (!asle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
asle_req = asle->aslc & ASLE_REQ_MSK;
|
||||||
|
|
||||||
|
if (!asle_req) {
|
||||||
|
DRM_DEBUG("non asle set request??\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asle_req & ASLE_SET_ALS_ILLUM)
|
||||||
|
asle_stat |= asle_set_als_illum(dev, asle->alsi);
|
||||||
|
|
||||||
|
if (asle_req & ASLE_SET_BACKLIGHT)
|
||||||
|
asle_stat |= asle_set_backlight(dev, asle->bclp);
|
||||||
|
|
||||||
|
if (asle_req & ASLE_SET_PFIT)
|
||||||
|
asle_stat |= asle_set_pfit(dev, asle->pfit);
|
||||||
|
|
||||||
|
if (asle_req & ASLE_SET_PWM_FREQ)
|
||||||
|
asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
|
||||||
|
|
||||||
|
asle->aslc = asle_stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ASLE_ALS_EN (1<<0)
|
||||||
|
#define ASLE_BLC_EN (1<<1)
|
||||||
|
#define ASLE_PFIT_EN (1<<2)
|
||||||
|
#define ASLE_PFMB_EN (1<<3)
|
||||||
|
|
||||||
|
void opregion_enable_asle(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
struct opregion_asle *asle = dev_priv->opregion.asle;
|
||||||
|
|
||||||
|
if (asle) {
|
||||||
|
u32 pipeb_stats = I915_READ(PIPEBSTAT);
|
||||||
|
if (IS_MOBILE(dev)) {
|
||||||
|
/* Many devices trigger events with a write to the
|
||||||
|
legacy backlight controller, so we need to ensure
|
||||||
|
that it's able to generate interrupts */
|
||||||
|
I915_WRITE(PIPEBSTAT, pipeb_stats |=
|
||||||
|
I915_LEGACY_BLC_EVENT_ENABLE);
|
||||||
|
i915_enable_irq(dev_priv, I915_ASLE_INTERRUPT |
|
||||||
|
I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
|
||||||
|
} else
|
||||||
|
i915_enable_irq(dev_priv, I915_ASLE_INTERRUPT);
|
||||||
|
|
||||||
|
asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
|
||||||
|
ASLE_PFMB_EN;
|
||||||
|
asle->ardy = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ACPI_EV_DISPLAY_SWITCH (1<<0)
|
||||||
|
#define ACPI_EV_LID (1<<1)
|
||||||
|
#define ACPI_EV_DOCK (1<<2)
|
||||||
|
|
||||||
|
static struct intel_opregion *system_opregion;
|
||||||
|
|
||||||
|
int intel_opregion_video_event(struct notifier_block *nb, unsigned long val,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
/* The only video events relevant to opregion are 0x80. These indicate
|
||||||
|
either a docking event, lid switch or display switch request. In
|
||||||
|
Linux, these are handled by the dock, button and video drivers.
|
||||||
|
We might want to fix the video driver to be opregion-aware in
|
||||||
|
future, but right now we just indicate to the firmware that the
|
||||||
|
request has been handled */
|
||||||
|
|
||||||
|
struct opregion_acpi *acpi;
|
||||||
|
|
||||||
|
if (!system_opregion)
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
|
||||||
|
acpi = system_opregion->acpi;
|
||||||
|
acpi->csts = 0;
|
||||||
|
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct notifier_block intel_opregion_notifier = {
|
||||||
|
.notifier_call = intel_opregion_video_event,
|
||||||
|
};
|
||||||
|
|
||||||
|
int intel_opregion_init(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
struct intel_opregion *opregion = &dev_priv->opregion;
|
||||||
|
void *base;
|
||||||
|
u32 asls, mboxes;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
pci_read_config_dword(dev->pdev, PCI_ASLS, &asls);
|
||||||
|
DRM_DEBUG("graphic opregion physical addr: 0x%x\n", asls);
|
||||||
|
if (asls == 0) {
|
||||||
|
DRM_DEBUG("ACPI OpRegion not supported!\n");
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
base = ioremap(asls, OPREGION_SZ);
|
||||||
|
if (!base)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
opregion->header = base;
|
||||||
|
if (memcmp(opregion->header->signature, OPREGION_SIGNATURE, 16)) {
|
||||||
|
DRM_DEBUG("opregion signature mismatch\n");
|
||||||
|
err = -EINVAL;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
mboxes = opregion->header->mboxes;
|
||||||
|
if (mboxes & MBOX_ACPI) {
|
||||||
|
DRM_DEBUG("Public ACPI methods supported\n");
|
||||||
|
opregion->acpi = base + OPREGION_ACPI_OFFSET;
|
||||||
|
} else {
|
||||||
|
DRM_DEBUG("Public ACPI methods not supported\n");
|
||||||
|
err = -ENOTSUPP;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
opregion->enabled = 1;
|
||||||
|
|
||||||
|
if (mboxes & MBOX_SWSCI) {
|
||||||
|
DRM_DEBUG("SWSCI supported\n");
|
||||||
|
opregion->swsci = base + OPREGION_SWSCI_OFFSET;
|
||||||
|
}
|
||||||
|
if (mboxes & MBOX_ASLE) {
|
||||||
|
DRM_DEBUG("ASLE supported\n");
|
||||||
|
opregion->asle = base + OPREGION_ASLE_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notify BIOS we are ready to handle ACPI video ext notifs.
|
||||||
|
* Right now, all the events are handled by the ACPI video module.
|
||||||
|
* We don't actually need to do anything with them. */
|
||||||
|
opregion->acpi->csts = 0;
|
||||||
|
opregion->acpi->drdy = 1;
|
||||||
|
|
||||||
|
system_opregion = opregion;
|
||||||
|
register_acpi_notifier(&intel_opregion_notifier);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
iounmap(opregion->header);
|
||||||
|
opregion->header = NULL;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void intel_opregion_free(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
struct intel_opregion *opregion = &dev_priv->opregion;
|
||||||
|
|
||||||
|
if (!opregion->enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
opregion->acpi->drdy = 0;
|
||||||
|
|
||||||
|
system_opregion = NULL;
|
||||||
|
unregister_acpi_notifier(&intel_opregion_notifier);
|
||||||
|
|
||||||
|
/* just clear all opregion memory pointers now */
|
||||||
|
iounmap(opregion->header);
|
||||||
|
opregion->header = NULL;
|
||||||
|
opregion->acpi = NULL;
|
||||||
|
opregion->swsci = NULL;
|
||||||
|
opregion->asle = NULL;
|
||||||
|
|
||||||
|
opregion->enabled = 0;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,509 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright 2008 (c) Intel Corporation
|
||||||
|
* Jesse Barnes <jbarnes@virtuousgeek.org>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sub license, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the
|
||||||
|
* next paragraph) shall be included in all copies or substantial portions
|
||||||
|
* of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
|
||||||
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drmP.h"
|
||||||
|
#include "drm.h"
|
||||||
|
#include "i915_drm.h"
|
||||||
|
#include "i915_drv.h"
|
||||||
|
|
||||||
|
static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
if (pipe == PIPE_A)
|
||||||
|
return (I915_READ(DPLL_A) & DPLL_VCO_ENABLE);
|
||||||
|
else
|
||||||
|
return (I915_READ(DPLL_B) & DPLL_VCO_ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i915_save_palette(struct drm_device *dev, enum pipe pipe)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
|
||||||
|
u32 *array;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!i915_pipe_enabled(dev, pipe))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pipe == PIPE_A)
|
||||||
|
array = dev_priv->save_palette_a;
|
||||||
|
else
|
||||||
|
array = dev_priv->save_palette_b;
|
||||||
|
|
||||||
|
for(i = 0; i < 256; i++)
|
||||||
|
array[i] = I915_READ(reg + (i << 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i915_restore_palette(struct drm_device *dev, enum pipe pipe)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
|
||||||
|
u32 *array;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!i915_pipe_enabled(dev, pipe))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pipe == PIPE_A)
|
||||||
|
array = dev_priv->save_palette_a;
|
||||||
|
else
|
||||||
|
array = dev_priv->save_palette_b;
|
||||||
|
|
||||||
|
for(i = 0; i < 256; i++)
|
||||||
|
I915_WRITE(reg + (i << 2), array[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 i915_read_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
I915_WRITE8(index_port, reg);
|
||||||
|
return I915_READ8(data_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 i915_read_ar(struct drm_device *dev, u16 st01, u8 reg, u16 palette_enable)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
I915_READ8(st01);
|
||||||
|
I915_WRITE8(VGA_AR_INDEX, palette_enable | reg);
|
||||||
|
return I915_READ8(VGA_AR_DATA_READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i915_write_ar(struct drm_device *dev, u16 st01, u8 reg, u8 val, u16 palette_enable)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
I915_READ8(st01);
|
||||||
|
I915_WRITE8(VGA_AR_INDEX, palette_enable | reg);
|
||||||
|
I915_WRITE8(VGA_AR_DATA_WRITE, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i915_write_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg, u8 val)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
I915_WRITE8(index_port, reg);
|
||||||
|
I915_WRITE8(data_port, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i915_save_vga(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
int i;
|
||||||
|
u16 cr_index, cr_data, st01;
|
||||||
|
|
||||||
|
/* VGA color palette registers */
|
||||||
|
dev_priv->saveDACMASK = I915_READ8(VGA_DACMASK);
|
||||||
|
/* DACCRX automatically increments during read */
|
||||||
|
I915_WRITE8(VGA_DACRX, 0);
|
||||||
|
/* Read 3 bytes of color data from each index */
|
||||||
|
for (i = 0; i < 256 * 3; i++)
|
||||||
|
dev_priv->saveDACDATA[i] = I915_READ8(VGA_DACDATA);
|
||||||
|
|
||||||
|
/* MSR bits */
|
||||||
|
dev_priv->saveMSR = I915_READ8(VGA_MSR_READ);
|
||||||
|
if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
|
||||||
|
cr_index = VGA_CR_INDEX_CGA;
|
||||||
|
cr_data = VGA_CR_DATA_CGA;
|
||||||
|
st01 = VGA_ST01_CGA;
|
||||||
|
} else {
|
||||||
|
cr_index = VGA_CR_INDEX_MDA;
|
||||||
|
cr_data = VGA_CR_DATA_MDA;
|
||||||
|
st01 = VGA_ST01_MDA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CRT controller regs */
|
||||||
|
i915_write_indexed(dev, cr_index, cr_data, 0x11,
|
||||||
|
i915_read_indexed(dev, cr_index, cr_data, 0x11) &
|
||||||
|
(~0x80));
|
||||||
|
for (i = 0; i <= 0x24; i++)
|
||||||
|
dev_priv->saveCR[i] =
|
||||||
|
i915_read_indexed(dev, cr_index, cr_data, i);
|
||||||
|
/* Make sure we don't turn off CR group 0 writes */
|
||||||
|
dev_priv->saveCR[0x11] &= ~0x80;
|
||||||
|
|
||||||
|
/* Attribute controller registers */
|
||||||
|
I915_READ8(st01);
|
||||||
|
dev_priv->saveAR_INDEX = I915_READ8(VGA_AR_INDEX);
|
||||||
|
for (i = 0; i <= 0x14; i++)
|
||||||
|
dev_priv->saveAR[i] = i915_read_ar(dev, st01, i, 0);
|
||||||
|
I915_READ8(st01);
|
||||||
|
I915_WRITE8(VGA_AR_INDEX, dev_priv->saveAR_INDEX);
|
||||||
|
I915_READ8(st01);
|
||||||
|
|
||||||
|
/* Graphics controller registers */
|
||||||
|
for (i = 0; i < 9; i++)
|
||||||
|
dev_priv->saveGR[i] =
|
||||||
|
i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i);
|
||||||
|
|
||||||
|
dev_priv->saveGR[0x10] =
|
||||||
|
i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10);
|
||||||
|
dev_priv->saveGR[0x11] =
|
||||||
|
i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11);
|
||||||
|
dev_priv->saveGR[0x18] =
|
||||||
|
i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18);
|
||||||
|
|
||||||
|
/* Sequencer registers */
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
dev_priv->saveSR[i] =
|
||||||
|
i915_read_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i915_restore_vga(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
int i;
|
||||||
|
u16 cr_index, cr_data, st01;
|
||||||
|
|
||||||
|
/* MSR bits */
|
||||||
|
I915_WRITE8(VGA_MSR_WRITE, dev_priv->saveMSR);
|
||||||
|
if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
|
||||||
|
cr_index = VGA_CR_INDEX_CGA;
|
||||||
|
cr_data = VGA_CR_DATA_CGA;
|
||||||
|
st01 = VGA_ST01_CGA;
|
||||||
|
} else {
|
||||||
|
cr_index = VGA_CR_INDEX_MDA;
|
||||||
|
cr_data = VGA_CR_DATA_MDA;
|
||||||
|
st01 = VGA_ST01_MDA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sequencer registers, don't write SR07 */
|
||||||
|
for (i = 0; i < 7; i++)
|
||||||
|
i915_write_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i,
|
||||||
|
dev_priv->saveSR[i]);
|
||||||
|
|
||||||
|
/* CRT controller regs */
|
||||||
|
/* Enable CR group 0 writes */
|
||||||
|
i915_write_indexed(dev, cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]);
|
||||||
|
for (i = 0; i <= 0x24; i++)
|
||||||
|
i915_write_indexed(dev, cr_index, cr_data, i, dev_priv->saveCR[i]);
|
||||||
|
|
||||||
|
/* Graphics controller regs */
|
||||||
|
for (i = 0; i < 9; i++)
|
||||||
|
i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i,
|
||||||
|
dev_priv->saveGR[i]);
|
||||||
|
|
||||||
|
i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10,
|
||||||
|
dev_priv->saveGR[0x10]);
|
||||||
|
i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11,
|
||||||
|
dev_priv->saveGR[0x11]);
|
||||||
|
i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18,
|
||||||
|
dev_priv->saveGR[0x18]);
|
||||||
|
|
||||||
|
/* Attribute controller registers */
|
||||||
|
I915_READ8(st01); /* switch back to index mode */
|
||||||
|
for (i = 0; i <= 0x14; i++)
|
||||||
|
i915_write_ar(dev, st01, i, dev_priv->saveAR[i], 0);
|
||||||
|
I915_READ8(st01); /* switch back to index mode */
|
||||||
|
I915_WRITE8(VGA_AR_INDEX, dev_priv->saveAR_INDEX | 0x20);
|
||||||
|
I915_READ8(st01);
|
||||||
|
|
||||||
|
/* VGA color palette registers */
|
||||||
|
I915_WRITE8(VGA_DACMASK, dev_priv->saveDACMASK);
|
||||||
|
/* DACCRX automatically increments during read */
|
||||||
|
I915_WRITE8(VGA_DACWX, 0);
|
||||||
|
/* Read 3 bytes of color data from each index */
|
||||||
|
for (i = 0; i < 256 * 3; i++)
|
||||||
|
I915_WRITE8(VGA_DACDATA, dev_priv->saveDACDATA[i]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int i915_save_state(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
|
||||||
|
|
||||||
|
/* Display arbitration control */
|
||||||
|
dev_priv->saveDSPARB = I915_READ(DSPARB);
|
||||||
|
|
||||||
|
/* Pipe & plane A info */
|
||||||
|
dev_priv->savePIPEACONF = I915_READ(PIPEACONF);
|
||||||
|
dev_priv->savePIPEASRC = I915_READ(PIPEASRC);
|
||||||
|
dev_priv->saveFPA0 = I915_READ(FPA0);
|
||||||
|
dev_priv->saveFPA1 = I915_READ(FPA1);
|
||||||
|
dev_priv->saveDPLL_A = I915_READ(DPLL_A);
|
||||||
|
if (IS_I965G(dev))
|
||||||
|
dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD);
|
||||||
|
dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A);
|
||||||
|
dev_priv->saveHBLANK_A = I915_READ(HBLANK_A);
|
||||||
|
dev_priv->saveHSYNC_A = I915_READ(HSYNC_A);
|
||||||
|
dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A);
|
||||||
|
dev_priv->saveVBLANK_A = I915_READ(VBLANK_A);
|
||||||
|
dev_priv->saveVSYNC_A = I915_READ(VSYNC_A);
|
||||||
|
dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
|
||||||
|
|
||||||
|
dev_priv->saveDSPACNTR = I915_READ(DSPACNTR);
|
||||||
|
dev_priv->saveDSPASTRIDE = I915_READ(DSPASTRIDE);
|
||||||
|
dev_priv->saveDSPASIZE = I915_READ(DSPASIZE);
|
||||||
|
dev_priv->saveDSPAPOS = I915_READ(DSPAPOS);
|
||||||
|
dev_priv->saveDSPAADDR = I915_READ(DSPAADDR);
|
||||||
|
if (IS_I965G(dev)) {
|
||||||
|
dev_priv->saveDSPASURF = I915_READ(DSPASURF);
|
||||||
|
dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF);
|
||||||
|
}
|
||||||
|
i915_save_palette(dev, PIPE_A);
|
||||||
|
dev_priv->savePIPEASTAT = I915_READ(PIPEASTAT);
|
||||||
|
|
||||||
|
/* Pipe & plane B info */
|
||||||
|
dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF);
|
||||||
|
dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC);
|
||||||
|
dev_priv->saveFPB0 = I915_READ(FPB0);
|
||||||
|
dev_priv->saveFPB1 = I915_READ(FPB1);
|
||||||
|
dev_priv->saveDPLL_B = I915_READ(DPLL_B);
|
||||||
|
if (IS_I965G(dev))
|
||||||
|
dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD);
|
||||||
|
dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B);
|
||||||
|
dev_priv->saveHBLANK_B = I915_READ(HBLANK_B);
|
||||||
|
dev_priv->saveHSYNC_B = I915_READ(HSYNC_B);
|
||||||
|
dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B);
|
||||||
|
dev_priv->saveVBLANK_B = I915_READ(VBLANK_B);
|
||||||
|
dev_priv->saveVSYNC_B = I915_READ(VSYNC_B);
|
||||||
|
dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
|
||||||
|
|
||||||
|
dev_priv->saveDSPBCNTR = I915_READ(DSPBCNTR);
|
||||||
|
dev_priv->saveDSPBSTRIDE = I915_READ(DSPBSTRIDE);
|
||||||
|
dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE);
|
||||||
|
dev_priv->saveDSPBPOS = I915_READ(DSPBPOS);
|
||||||
|
dev_priv->saveDSPBADDR = I915_READ(DSPBADDR);
|
||||||
|
if (IS_I965GM(dev) || IS_GM45(dev)) {
|
||||||
|
dev_priv->saveDSPBSURF = I915_READ(DSPBSURF);
|
||||||
|
dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF);
|
||||||
|
}
|
||||||
|
i915_save_palette(dev, PIPE_B);
|
||||||
|
dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT);
|
||||||
|
|
||||||
|
/* CRT state */
|
||||||
|
dev_priv->saveADPA = I915_READ(ADPA);
|
||||||
|
|
||||||
|
/* LVDS state */
|
||||||
|
dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL);
|
||||||
|
dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
|
||||||
|
dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
|
||||||
|
if (IS_I965G(dev))
|
||||||
|
dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
|
||||||
|
if (IS_MOBILE(dev) && !IS_I830(dev))
|
||||||
|
dev_priv->saveLVDS = I915_READ(LVDS);
|
||||||
|
if (!IS_I830(dev) && !IS_845G(dev))
|
||||||
|
dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL);
|
||||||
|
dev_priv->savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS);
|
||||||
|
dev_priv->savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS);
|
||||||
|
dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR);
|
||||||
|
|
||||||
|
/* FIXME: save TV & SDVO state */
|
||||||
|
|
||||||
|
/* FBC state */
|
||||||
|
dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
|
||||||
|
dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE);
|
||||||
|
dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2);
|
||||||
|
dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL);
|
||||||
|
|
||||||
|
/* Interrupt state */
|
||||||
|
dev_priv->saveIIR = I915_READ(IIR);
|
||||||
|
dev_priv->saveIER = I915_READ(IER);
|
||||||
|
dev_priv->saveIMR = I915_READ(IMR);
|
||||||
|
|
||||||
|
/* VGA state */
|
||||||
|
dev_priv->saveVGA0 = I915_READ(VGA0);
|
||||||
|
dev_priv->saveVGA1 = I915_READ(VGA1);
|
||||||
|
dev_priv->saveVGA_PD = I915_READ(VGA_PD);
|
||||||
|
dev_priv->saveVGACNTRL = I915_READ(VGACNTRL);
|
||||||
|
|
||||||
|
/* Clock gating state */
|
||||||
|
dev_priv->saveD_STATE = I915_READ(D_STATE);
|
||||||
|
dev_priv->saveCG_2D_DIS = I915_READ(CG_2D_DIS);
|
||||||
|
|
||||||
|
/* Cache mode state */
|
||||||
|
dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
|
||||||
|
|
||||||
|
/* Memory Arbitration state */
|
||||||
|
dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE);
|
||||||
|
|
||||||
|
/* Scratch space */
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
dev_priv->saveSWF0[i] = I915_READ(SWF00 + (i << 2));
|
||||||
|
dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2));
|
||||||
|
}
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2));
|
||||||
|
|
||||||
|
i915_save_vga(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i915_restore_state(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB);
|
||||||
|
|
||||||
|
I915_WRITE(DSPARB, dev_priv->saveDSPARB);
|
||||||
|
|
||||||
|
/* Pipe & plane A info */
|
||||||
|
/* Prime the clock */
|
||||||
|
if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
|
||||||
|
I915_WRITE(DPLL_A, dev_priv->saveDPLL_A &
|
||||||
|
~DPLL_VCO_ENABLE);
|
||||||
|
DRM_UDELAY(150);
|
||||||
|
}
|
||||||
|
I915_WRITE(FPA0, dev_priv->saveFPA0);
|
||||||
|
I915_WRITE(FPA1, dev_priv->saveFPA1);
|
||||||
|
/* Actually enable it */
|
||||||
|
I915_WRITE(DPLL_A, dev_priv->saveDPLL_A);
|
||||||
|
DRM_UDELAY(150);
|
||||||
|
if (IS_I965G(dev))
|
||||||
|
I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
|
||||||
|
DRM_UDELAY(150);
|
||||||
|
|
||||||
|
/* Restore mode */
|
||||||
|
I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A);
|
||||||
|
I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A);
|
||||||
|
I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A);
|
||||||
|
I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A);
|
||||||
|
I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A);
|
||||||
|
I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A);
|
||||||
|
I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
|
||||||
|
|
||||||
|
/* Restore plane info */
|
||||||
|
I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE);
|
||||||
|
I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS);
|
||||||
|
I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
|
||||||
|
I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR);
|
||||||
|
I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
|
||||||
|
if (IS_I965G(dev)) {
|
||||||
|
I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
|
||||||
|
I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF);
|
||||||
|
|
||||||
|
i915_restore_palette(dev, PIPE_A);
|
||||||
|
/* Enable the plane */
|
||||||
|
I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR);
|
||||||
|
I915_WRITE(DSPAADDR, I915_READ(DSPAADDR));
|
||||||
|
|
||||||
|
/* Pipe & plane B info */
|
||||||
|
if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
|
||||||
|
I915_WRITE(DPLL_B, dev_priv->saveDPLL_B &
|
||||||
|
~DPLL_VCO_ENABLE);
|
||||||
|
DRM_UDELAY(150);
|
||||||
|
}
|
||||||
|
I915_WRITE(FPB0, dev_priv->saveFPB0);
|
||||||
|
I915_WRITE(FPB1, dev_priv->saveFPB1);
|
||||||
|
/* Actually enable it */
|
||||||
|
I915_WRITE(DPLL_B, dev_priv->saveDPLL_B);
|
||||||
|
DRM_UDELAY(150);
|
||||||
|
if (IS_I965G(dev))
|
||||||
|
I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
|
||||||
|
DRM_UDELAY(150);
|
||||||
|
|
||||||
|
/* Restore mode */
|
||||||
|
I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B);
|
||||||
|
I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B);
|
||||||
|
I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B);
|
||||||
|
I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B);
|
||||||
|
I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B);
|
||||||
|
I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B);
|
||||||
|
I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
|
||||||
|
|
||||||
|
/* Restore plane info */
|
||||||
|
I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE);
|
||||||
|
I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS);
|
||||||
|
I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
|
||||||
|
I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR);
|
||||||
|
I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
|
||||||
|
if (IS_I965G(dev)) {
|
||||||
|
I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
|
||||||
|
I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF);
|
||||||
|
|
||||||
|
i915_restore_palette(dev, PIPE_B);
|
||||||
|
/* Enable the plane */
|
||||||
|
I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
|
||||||
|
I915_WRITE(DSPBADDR, I915_READ(DSPBADDR));
|
||||||
|
|
||||||
|
/* CRT state */
|
||||||
|
I915_WRITE(ADPA, dev_priv->saveADPA);
|
||||||
|
|
||||||
|
/* LVDS state */
|
||||||
|
if (IS_I965G(dev))
|
||||||
|
I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2);
|
||||||
|
if (IS_MOBILE(dev) && !IS_I830(dev))
|
||||||
|
I915_WRITE(LVDS, dev_priv->saveLVDS);
|
||||||
|
if (!IS_I830(dev) && !IS_845G(dev))
|
||||||
|
I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL);
|
||||||
|
|
||||||
|
I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
|
||||||
|
I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
|
||||||
|
I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON_DELAYS);
|
||||||
|
I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS);
|
||||||
|
I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR);
|
||||||
|
I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
|
||||||
|
|
||||||
|
/* FIXME: restore TV & SDVO state */
|
||||||
|
|
||||||
|
/* FBC info */
|
||||||
|
I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE);
|
||||||
|
I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE);
|
||||||
|
I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2);
|
||||||
|
I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL);
|
||||||
|
|
||||||
|
/* VGA state */
|
||||||
|
I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL);
|
||||||
|
I915_WRITE(VGA0, dev_priv->saveVGA0);
|
||||||
|
I915_WRITE(VGA1, dev_priv->saveVGA1);
|
||||||
|
I915_WRITE(VGA_PD, dev_priv->saveVGA_PD);
|
||||||
|
DRM_UDELAY(150);
|
||||||
|
|
||||||
|
/* Clock gating state */
|
||||||
|
I915_WRITE (D_STATE, dev_priv->saveD_STATE);
|
||||||
|
I915_WRITE (CG_2D_DIS, dev_priv->saveCG_2D_DIS);
|
||||||
|
|
||||||
|
/* Cache mode state */
|
||||||
|
I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
|
||||||
|
|
||||||
|
/* Memory arbitration state */
|
||||||
|
I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000);
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
I915_WRITE(SWF00 + (i << 2), dev_priv->saveSWF0[i]);
|
||||||
|
I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]);
|
||||||
|
}
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
|
||||||
|
|
||||||
|
i915_restore_vga(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -45,15 +45,16 @@ static struct pci_device_id pciidlist[] = {
|
||||||
static struct drm_driver driver = {
|
static struct drm_driver driver = {
|
||||||
.driver_features =
|
.driver_features =
|
||||||
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA |
|
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA |
|
||||||
DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
|
DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
|
||||||
DRIVER_IRQ_VBL,
|
|
||||||
.dev_priv_size = sizeof(drm_mga_buf_priv_t),
|
.dev_priv_size = sizeof(drm_mga_buf_priv_t),
|
||||||
.load = mga_driver_load,
|
.load = mga_driver_load,
|
||||||
.unload = mga_driver_unload,
|
.unload = mga_driver_unload,
|
||||||
.lastclose = mga_driver_lastclose,
|
.lastclose = mga_driver_lastclose,
|
||||||
.dma_quiescent = mga_driver_dma_quiescent,
|
.dma_quiescent = mga_driver_dma_quiescent,
|
||||||
.device_is_agp = mga_driver_device_is_agp,
|
.device_is_agp = mga_driver_device_is_agp,
|
||||||
.vblank_wait = mga_driver_vblank_wait,
|
.get_vblank_counter = mga_get_vblank_counter,
|
||||||
|
.enable_vblank = mga_enable_vblank,
|
||||||
|
.disable_vblank = mga_disable_vblank,
|
||||||
.irq_preinstall = mga_driver_irq_preinstall,
|
.irq_preinstall = mga_driver_irq_preinstall,
|
||||||
.irq_postinstall = mga_driver_irq_postinstall,
|
.irq_postinstall = mga_driver_irq_postinstall,
|
||||||
.irq_uninstall = mga_driver_irq_uninstall,
|
.irq_uninstall = mga_driver_irq_uninstall,
|
||||||
|
@ -64,20 +65,20 @@ static struct drm_driver driver = {
|
||||||
.ioctls = mga_ioctls,
|
.ioctls = mga_ioctls,
|
||||||
.dma_ioctl = mga_dma_buffers,
|
.dma_ioctl = mga_dma_buffers,
|
||||||
.fops = {
|
.fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.open = drm_open,
|
.open = drm_open,
|
||||||
.release = drm_release,
|
.release = drm_release,
|
||||||
.ioctl = drm_ioctl,
|
.ioctl = drm_ioctl,
|
||||||
.mmap = drm_mmap,
|
.mmap = drm_mmap,
|
||||||
.poll = drm_poll,
|
.poll = drm_poll,
|
||||||
.fasync = drm_fasync,
|
.fasync = drm_fasync,
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
.compat_ioctl = mga_compat_ioctl,
|
.compat_ioctl = mga_compat_ioctl,
|
||||||
#endif
|
#endif
|
||||||
},
|
},
|
||||||
.pci_driver = {
|
.pci_driver = {
|
||||||
.name = DRIVER_NAME,
|
.name = DRIVER_NAME,
|
||||||
.id_table = pciidlist,
|
.id_table = pciidlist,
|
||||||
},
|
},
|
||||||
|
|
||||||
.name = DRIVER_NAME,
|
.name = DRIVER_NAME,
|
||||||
|
|
|
@ -120,6 +120,7 @@ typedef struct drm_mga_private {
|
||||||
u32 clear_cmd;
|
u32 clear_cmd;
|
||||||
u32 maccess;
|
u32 maccess;
|
||||||
|
|
||||||
|
atomic_t vbl_received; /**< Number of vblanks received. */
|
||||||
wait_queue_head_t fence_queue;
|
wait_queue_head_t fence_queue;
|
||||||
atomic_t last_fence_retired;
|
atomic_t last_fence_retired;
|
||||||
u32 next_fence_to_post;
|
u32 next_fence_to_post;
|
||||||
|
@ -181,11 +182,14 @@ extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv);
|
||||||
extern int mga_warp_init(drm_mga_private_t * dev_priv);
|
extern int mga_warp_init(drm_mga_private_t * dev_priv);
|
||||||
|
|
||||||
/* mga_irq.c */
|
/* mga_irq.c */
|
||||||
|
extern int mga_enable_vblank(struct drm_device *dev, int crtc);
|
||||||
|
extern void mga_disable_vblank(struct drm_device *dev, int crtc);
|
||||||
|
extern u32 mga_get_vblank_counter(struct drm_device *dev, int crtc);
|
||||||
extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence);
|
extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence);
|
||||||
extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
|
extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
|
||||||
extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
|
extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
|
||||||
extern void mga_driver_irq_preinstall(struct drm_device * dev);
|
extern void mga_driver_irq_preinstall(struct drm_device * dev);
|
||||||
extern void mga_driver_irq_postinstall(struct drm_device * dev);
|
extern int mga_driver_irq_postinstall(struct drm_device *dev);
|
||||||
extern void mga_driver_irq_uninstall(struct drm_device * dev);
|
extern void mga_driver_irq_uninstall(struct drm_device * dev);
|
||||||
extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
|
extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
|
||||||
unsigned long arg);
|
unsigned long arg);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/* mga_irq.c -- IRQ handling for radeon -*- linux-c -*-
|
/* mga_irq.c -- IRQ handling for radeon -*- linux-c -*-
|
||||||
*
|
*/
|
||||||
|
/*
|
||||||
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
|
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* The Weather Channel (TM) funded Tungsten Graphics to develop the
|
* The Weather Channel (TM) funded Tungsten Graphics to develop the
|
||||||
|
@ -35,6 +36,18 @@
|
||||||
#include "mga_drm.h"
|
#include "mga_drm.h"
|
||||||
#include "mga_drv.h"
|
#include "mga_drv.h"
|
||||||
|
|
||||||
|
u32 mga_get_vblank_counter(struct drm_device *dev, int crtc)
|
||||||
|
{
|
||||||
|
const drm_mga_private_t *const dev_priv =
|
||||||
|
(drm_mga_private_t *) dev->dev_private;
|
||||||
|
|
||||||
|
if (crtc != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return atomic_read(&dev_priv->vbl_received);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
|
irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = (struct drm_device *) arg;
|
struct drm_device *dev = (struct drm_device *) arg;
|
||||||
|
@ -47,9 +60,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
|
||||||
/* VBLANK interrupt */
|
/* VBLANK interrupt */
|
||||||
if (status & MGA_VLINEPEN) {
|
if (status & MGA_VLINEPEN) {
|
||||||
MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR);
|
MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR);
|
||||||
atomic_inc(&dev->vbl_received);
|
atomic_inc(&dev_priv->vbl_received);
|
||||||
DRM_WAKEUP(&dev->vbl_queue);
|
drm_handle_vblank(dev, 0);
|
||||||
drm_vbl_send_signals(dev);
|
|
||||||
handled = 1;
|
handled = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +70,7 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
|
||||||
const u32 prim_start = MGA_READ(MGA_PRIMADDRESS);
|
const u32 prim_start = MGA_READ(MGA_PRIMADDRESS);
|
||||||
const u32 prim_end = MGA_READ(MGA_PRIMEND);
|
const u32 prim_end = MGA_READ(MGA_PRIMEND);
|
||||||
|
|
||||||
|
|
||||||
MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR);
|
MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR);
|
||||||
|
|
||||||
/* In addition to clearing the interrupt-pending bit, we
|
/* In addition to clearing the interrupt-pending bit, we
|
||||||
|
@ -72,28 +85,39 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
|
||||||
handled = 1;
|
handled = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handled) {
|
if (handled)
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
|
int mga_enable_vblank(struct drm_device *dev, int crtc)
|
||||||
{
|
{
|
||||||
unsigned int cur_vblank;
|
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
/* Assume that the user has missed the current sequence number
|
if (crtc != 0) {
|
||||||
* by about a day rather than she wants to wait for years
|
DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
|
||||||
* using vertical blanks...
|
crtc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mga_disable_vblank(struct drm_device *dev, int crtc)
|
||||||
|
{
|
||||||
|
if (crtc != 0) {
|
||||||
|
DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
|
||||||
|
crtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have
|
||||||
|
* a nice hardware counter that tracks the number of refreshes when
|
||||||
|
* the interrupt is disabled, and the kernel doesn't know the refresh
|
||||||
|
* rate to calculate an estimate.
|
||||||
*/
|
*/
|
||||||
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
|
/* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
|
||||||
(((cur_vblank = atomic_read(&dev->vbl_received))
|
|
||||||
- *sequence) <= (1 << 23)));
|
|
||||||
|
|
||||||
*sequence = cur_vblank;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence)
|
int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence)
|
||||||
|
@ -125,14 +149,22 @@ void mga_driver_irq_preinstall(struct drm_device * dev)
|
||||||
MGA_WRITE(MGA_ICLEAR, ~0);
|
MGA_WRITE(MGA_ICLEAR, ~0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mga_driver_irq_postinstall(struct drm_device * dev)
|
int mga_driver_irq_postinstall(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
|
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = drm_vblank_init(dev, 1);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
DRM_INIT_WAITQUEUE(&dev_priv->fence_queue);
|
DRM_INIT_WAITQUEUE(&dev_priv->fence_queue);
|
||||||
|
|
||||||
/* Turn on vertical blank interrupt and soft trap interrupt. */
|
/* Turn on soft trap interrupt. Vertical blank interrupts are enabled
|
||||||
MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
|
* in mga_enable_vblank.
|
||||||
|
*/
|
||||||
|
MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mga_driver_irq_uninstall(struct drm_device * dev)
|
void mga_driver_irq_uninstall(struct drm_device * dev)
|
||||||
|
|
|
@ -1022,7 +1022,7 @@ static int mga_getparam(struct drm_device *dev, void *data, struct drm_file *fil
|
||||||
|
|
||||||
switch (param->param) {
|
switch (param->param) {
|
||||||
case MGA_PARAM_IRQ_NR:
|
case MGA_PARAM_IRQ_NR:
|
||||||
value = dev->irq;
|
value = drm_dev_to_irq(dev);
|
||||||
break;
|
break;
|
||||||
case MGA_PARAM_CARD_TYPE:
|
case MGA_PARAM_CARD_TYPE:
|
||||||
value = dev_priv->chipset;
|
value = dev_priv->chipset;
|
||||||
|
|
|
@ -43,12 +43,13 @@ static struct pci_device_id pciidlist[] = {
|
||||||
static struct drm_driver driver = {
|
static struct drm_driver driver = {
|
||||||
.driver_features =
|
.driver_features =
|
||||||
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
|
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
|
||||||
DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
|
DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
|
||||||
DRIVER_IRQ_VBL,
|
|
||||||
.dev_priv_size = sizeof(drm_r128_buf_priv_t),
|
.dev_priv_size = sizeof(drm_r128_buf_priv_t),
|
||||||
.preclose = r128_driver_preclose,
|
.preclose = r128_driver_preclose,
|
||||||
.lastclose = r128_driver_lastclose,
|
.lastclose = r128_driver_lastclose,
|
||||||
.vblank_wait = r128_driver_vblank_wait,
|
.get_vblank_counter = r128_get_vblank_counter,
|
||||||
|
.enable_vblank = r128_enable_vblank,
|
||||||
|
.disable_vblank = r128_disable_vblank,
|
||||||
.irq_preinstall = r128_driver_irq_preinstall,
|
.irq_preinstall = r128_driver_irq_preinstall,
|
||||||
.irq_postinstall = r128_driver_irq_postinstall,
|
.irq_postinstall = r128_driver_irq_postinstall,
|
||||||
.irq_uninstall = r128_driver_irq_uninstall,
|
.irq_uninstall = r128_driver_irq_uninstall,
|
||||||
|
@ -59,21 +60,20 @@ static struct drm_driver driver = {
|
||||||
.ioctls = r128_ioctls,
|
.ioctls = r128_ioctls,
|
||||||
.dma_ioctl = r128_cce_buffers,
|
.dma_ioctl = r128_cce_buffers,
|
||||||
.fops = {
|
.fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.open = drm_open,
|
.open = drm_open,
|
||||||
.release = drm_release,
|
.release = drm_release,
|
||||||
.ioctl = drm_ioctl,
|
.ioctl = drm_ioctl,
|
||||||
.mmap = drm_mmap,
|
.mmap = drm_mmap,
|
||||||
.poll = drm_poll,
|
.poll = drm_poll,
|
||||||
.fasync = drm_fasync,
|
.fasync = drm_fasync,
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
.compat_ioctl = r128_compat_ioctl,
|
.compat_ioctl = r128_compat_ioctl,
|
||||||
#endif
|
#endif
|
||||||
},
|
},
|
||||||
|
|
||||||
.pci_driver = {
|
.pci_driver = {
|
||||||
.name = DRIVER_NAME,
|
.name = DRIVER_NAME,
|
||||||
.id_table = pciidlist,
|
.id_table = pciidlist,
|
||||||
},
|
},
|
||||||
|
|
||||||
.name = DRIVER_NAME,
|
.name = DRIVER_NAME,
|
||||||
|
@ -87,6 +87,7 @@ static struct drm_driver driver = {
|
||||||
static int __init r128_init(void)
|
static int __init r128_init(void)
|
||||||
{
|
{
|
||||||
driver.num_ioctls = r128_max_ioctl;
|
driver.num_ioctls = r128_max_ioctl;
|
||||||
|
|
||||||
return drm_init(&driver);
|
return drm_init(&driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
* Rickard E. (Rik) Faith <faith@valinux.com>
|
* Rickard E. (Rik) Faith <faith@valinux.com>
|
||||||
* Kevin E. Martin <martin@valinux.com>
|
* Kevin E. Martin <martin@valinux.com>
|
||||||
* Gareth Hughes <gareth@valinux.com>
|
* Gareth Hughes <gareth@valinux.com>
|
||||||
* Michel Dänzer <daenzerm@student.ethz.ch>
|
* Michel D<EFBFBD>zer <daenzerm@student.ethz.ch>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __R128_DRV_H__
|
#ifndef __R128_DRV_H__
|
||||||
|
@ -97,6 +97,8 @@ typedef struct drm_r128_private {
|
||||||
u32 crtc_offset;
|
u32 crtc_offset;
|
||||||
u32 crtc_offset_cntl;
|
u32 crtc_offset_cntl;
|
||||||
|
|
||||||
|
atomic_t vbl_received;
|
||||||
|
|
||||||
u32 color_fmt;
|
u32 color_fmt;
|
||||||
unsigned int front_offset;
|
unsigned int front_offset;
|
||||||
unsigned int front_pitch;
|
unsigned int front_pitch;
|
||||||
|
@ -149,11 +151,12 @@ extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n);
|
||||||
extern int r128_do_cce_idle(drm_r128_private_t * dev_priv);
|
extern int r128_do_cce_idle(drm_r128_private_t * dev_priv);
|
||||||
extern int r128_do_cleanup_cce(struct drm_device * dev);
|
extern int r128_do_cleanup_cce(struct drm_device * dev);
|
||||||
|
|
||||||
extern int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
|
extern int r128_enable_vblank(struct drm_device *dev, int crtc);
|
||||||
|
extern void r128_disable_vblank(struct drm_device *dev, int crtc);
|
||||||
|
extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc);
|
||||||
extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS);
|
extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS);
|
||||||
extern void r128_driver_irq_preinstall(struct drm_device * dev);
|
extern void r128_driver_irq_preinstall(struct drm_device * dev);
|
||||||
extern void r128_driver_irq_postinstall(struct drm_device * dev);
|
extern int r128_driver_irq_postinstall(struct drm_device *dev);
|
||||||
extern void r128_driver_irq_uninstall(struct drm_device * dev);
|
extern void r128_driver_irq_uninstall(struct drm_device * dev);
|
||||||
extern void r128_driver_lastclose(struct drm_device * dev);
|
extern void r128_driver_lastclose(struct drm_device * dev);
|
||||||
extern void r128_driver_preclose(struct drm_device * dev,
|
extern void r128_driver_preclose(struct drm_device * dev,
|
||||||
|
|
|
@ -35,6 +35,16 @@
|
||||||
#include "r128_drm.h"
|
#include "r128_drm.h"
|
||||||
#include "r128_drv.h"
|
#include "r128_drv.h"
|
||||||
|
|
||||||
|
u32 r128_get_vblank_counter(struct drm_device *dev, int crtc)
|
||||||
|
{
|
||||||
|
const drm_r128_private_t *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
if (crtc != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return atomic_read(&dev_priv->vbl_received);
|
||||||
|
}
|
||||||
|
|
||||||
irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
|
irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = (struct drm_device *) arg;
|
struct drm_device *dev = (struct drm_device *) arg;
|
||||||
|
@ -46,30 +56,38 @@ irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
|
||||||
/* VBLANK interrupt */
|
/* VBLANK interrupt */
|
||||||
if (status & R128_CRTC_VBLANK_INT) {
|
if (status & R128_CRTC_VBLANK_INT) {
|
||||||
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
|
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
|
||||||
atomic_inc(&dev->vbl_received);
|
atomic_inc(&dev_priv->vbl_received);
|
||||||
DRM_WAKEUP(&dev->vbl_queue);
|
drm_handle_vblank(dev, 0);
|
||||||
drm_vbl_send_signals(dev);
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
|
int r128_enable_vblank(struct drm_device *dev, int crtc)
|
||||||
{
|
{
|
||||||
unsigned int cur_vblank;
|
drm_r128_private_t *dev_priv = dev->dev_private;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
/* Assume that the user has missed the current sequence number
|
if (crtc != 0) {
|
||||||
* by about a day rather than she wants to wait for years
|
DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
|
||||||
* using vertical blanks...
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void r128_disable_vblank(struct drm_device *dev, int crtc)
|
||||||
|
{
|
||||||
|
if (crtc != 0)
|
||||||
|
DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: implement proper interrupt disable by using the vblank
|
||||||
|
* counter register (if available)
|
||||||
|
*
|
||||||
|
* R128_WRITE(R128_GEN_INT_CNTL,
|
||||||
|
* R128_READ(R128_GEN_INT_CNTL) & ~R128_CRTC_VBLANK_INT_EN);
|
||||||
*/
|
*/
|
||||||
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
|
|
||||||
(((cur_vblank = atomic_read(&dev->vbl_received))
|
|
||||||
- *sequence) <= (1 << 23)));
|
|
||||||
|
|
||||||
*sequence = cur_vblank;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void r128_driver_irq_preinstall(struct drm_device * dev)
|
void r128_driver_irq_preinstall(struct drm_device * dev)
|
||||||
|
@ -82,12 +100,9 @@ void r128_driver_irq_preinstall(struct drm_device * dev)
|
||||||
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
|
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void r128_driver_irq_postinstall(struct drm_device * dev)
|
int r128_driver_irq_postinstall(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
|
return drm_vblank_init(dev, 1);
|
||||||
|
|
||||||
/* Turn on VBL interrupt */
|
|
||||||
R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void r128_driver_irq_uninstall(struct drm_device * dev)
|
void r128_driver_irq_uninstall(struct drm_device * dev)
|
||||||
|
|
|
@ -1629,7 +1629,7 @@ static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *fi
|
||||||
|
|
||||||
switch (param->param) {
|
switch (param->param) {
|
||||||
case R128_PARAM_IRQ_NR:
|
case R128_PARAM_IRQ_NR:
|
||||||
value = dev->irq;
|
value = drm_dev_to_irq(dev);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
|
@ -71,7 +71,8 @@ static u32 RS690_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
|
||||||
|
|
||||||
static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
|
static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
|
||||||
{
|
{
|
||||||
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
|
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
|
||||||
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
|
||||||
return RS690_READ_MCIND(dev_priv, addr);
|
return RS690_READ_MCIND(dev_priv, addr);
|
||||||
else
|
else
|
||||||
return RS480_READ_MCIND(dev_priv, addr);
|
return RS480_READ_MCIND(dev_priv, addr);
|
||||||
|
@ -82,7 +83,8 @@ u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
|
||||||
|
|
||||||
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
|
||||||
return R500_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION);
|
return R500_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION);
|
||||||
else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
|
else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
|
||||||
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
|
||||||
return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION);
|
return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION);
|
||||||
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
|
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
|
||||||
return R500_READ_MCIND(dev_priv, R520_MC_FB_LOCATION);
|
return R500_READ_MCIND(dev_priv, R520_MC_FB_LOCATION);
|
||||||
|
@ -94,7 +96,8 @@ static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc)
|
||||||
{
|
{
|
||||||
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
|
||||||
R500_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc);
|
R500_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc);
|
||||||
else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
|
else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
|
||||||
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
|
||||||
RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc);
|
RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc);
|
||||||
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
|
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
|
||||||
R500_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc);
|
R500_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc);
|
||||||
|
@ -106,7 +109,8 @@ static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_lo
|
||||||
{
|
{
|
||||||
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
|
||||||
R500_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc);
|
R500_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc);
|
||||||
else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
|
else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
|
||||||
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
|
||||||
RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc);
|
RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc);
|
||||||
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
|
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
|
||||||
R500_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc);
|
R500_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc);
|
||||||
|
@ -122,15 +126,17 @@ static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
|
||||||
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) {
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) {
|
||||||
R500_WRITE_MCIND(RV515_MC_AGP_BASE, agp_base_lo);
|
R500_WRITE_MCIND(RV515_MC_AGP_BASE, agp_base_lo);
|
||||||
R500_WRITE_MCIND(RV515_MC_AGP_BASE_2, agp_base_hi);
|
R500_WRITE_MCIND(RV515_MC_AGP_BASE_2, agp_base_hi);
|
||||||
} else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
|
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
|
||||||
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
|
||||||
RS690_WRITE_MCIND(RS690_MC_AGP_BASE, agp_base_lo);
|
RS690_WRITE_MCIND(RS690_MC_AGP_BASE, agp_base_lo);
|
||||||
RS690_WRITE_MCIND(RS690_MC_AGP_BASE_2, agp_base_hi);
|
RS690_WRITE_MCIND(RS690_MC_AGP_BASE_2, agp_base_hi);
|
||||||
} else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) {
|
} else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) {
|
||||||
R500_WRITE_MCIND(R520_MC_AGP_BASE, agp_base_lo);
|
R500_WRITE_MCIND(R520_MC_AGP_BASE, agp_base_lo);
|
||||||
R500_WRITE_MCIND(R520_MC_AGP_BASE_2, agp_base_hi);
|
R500_WRITE_MCIND(R520_MC_AGP_BASE_2, agp_base_hi);
|
||||||
} else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480) {
|
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
|
||||||
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
|
||||||
RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo);
|
RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo);
|
||||||
RADEON_WRITE(RS480_AGP_BASE_2, 0);
|
RADEON_WRITE(RS480_AGP_BASE_2, agp_base_hi);
|
||||||
} else {
|
} else {
|
||||||
RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo);
|
RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo);
|
||||||
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R200)
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R200)
|
||||||
|
@ -347,6 +353,7 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
|
||||||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R350) ||
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R350) ||
|
||||||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV350) ||
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV350) ||
|
||||||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV380) ||
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV380) ||
|
||||||
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
|
||||||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
|
||||||
DRM_INFO("Loading R300 Microcode\n");
|
DRM_INFO("Loading R300 Microcode\n");
|
||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++) {
|
||||||
|
@ -356,6 +363,7 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
|
||||||
R300_cp_microcode[i][0]);
|
R300_cp_microcode[i][0]);
|
||||||
}
|
}
|
||||||
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
|
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
|
||||||
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R423) ||
|
||||||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV410)) {
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV410)) {
|
||||||
DRM_INFO("Loading R400 Microcode\n");
|
DRM_INFO("Loading R400 Microcode\n");
|
||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++) {
|
||||||
|
@ -364,8 +372,9 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
|
||||||
RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
|
RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
|
||||||
R420_cp_microcode[i][0]);
|
R420_cp_microcode[i][0]);
|
||||||
}
|
}
|
||||||
} else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
|
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
|
||||||
DRM_INFO("Loading RS690 Microcode\n");
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
|
||||||
|
DRM_INFO("Loading RS690/RS740 Microcode\n");
|
||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++) {
|
||||||
RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
|
RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
|
||||||
RS690_cp_microcode[i][1]);
|
RS690_cp_microcode[i][1]);
|
||||||
|
@ -626,8 +635,6 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
|
||||||
dev_priv->ring.size_l2qw);
|
dev_priv->ring.size_l2qw);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Start with assuming that writeback doesn't work */
|
|
||||||
dev_priv->writeback_works = 0;
|
|
||||||
|
|
||||||
/* Initialize the scratch register pointer. This will cause
|
/* Initialize the scratch register pointer. This will cause
|
||||||
* the scratch register values to be written out to memory
|
* the scratch register values to be written out to memory
|
||||||
|
@ -646,8 +653,18 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
|
||||||
RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7);
|
RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7);
|
||||||
|
|
||||||
/* Turn on bus mastering */
|
/* Turn on bus mastering */
|
||||||
tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
|
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
|
||||||
RADEON_WRITE(RADEON_BUS_CNTL, tmp);
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
|
||||||
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
|
||||||
|
/* rs400, rs690/rs740 */
|
||||||
|
tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RS400_BUS_MASTER_DIS;
|
||||||
|
RADEON_WRITE(RADEON_BUS_CNTL, tmp);
|
||||||
|
} else if (!(((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV380) ||
|
||||||
|
((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R423))) {
|
||||||
|
/* r1xx, r2xx, r300, r(v)350, r420/r481, rs480 */
|
||||||
|
tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
|
||||||
|
RADEON_WRITE(RADEON_BUS_CNTL, tmp);
|
||||||
|
} /* PCIE cards appears to not need this */
|
||||||
|
|
||||||
dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0;
|
dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0;
|
||||||
RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
|
RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
|
||||||
|
@ -674,6 +691,9 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv)
|
||||||
{
|
{
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
|
/* Start with assuming that writeback doesn't work */
|
||||||
|
dev_priv->writeback_works = 0;
|
||||||
|
|
||||||
/* Writeback doesn't seem to work everywhere, test it here and possibly
|
/* Writeback doesn't seem to work everywhere, test it here and possibly
|
||||||
* enable it if it appears to work
|
* enable it if it appears to work
|
||||||
*/
|
*/
|
||||||
|
@ -719,7 +739,8 @@ static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on)
|
||||||
dev_priv->gart_size);
|
dev_priv->gart_size);
|
||||||
|
|
||||||
temp = IGP_READ_MCIND(dev_priv, RS480_MC_MISC_CNTL);
|
temp = IGP_READ_MCIND(dev_priv, RS480_MC_MISC_CNTL);
|
||||||
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
|
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
|
||||||
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
|
||||||
IGP_WRITE_MCIND(RS480_MC_MISC_CNTL, (RS480_GART_INDEX_REG_EN |
|
IGP_WRITE_MCIND(RS480_MC_MISC_CNTL, (RS480_GART_INDEX_REG_EN |
|
||||||
RS690_BLOCK_GFX_D3_EN));
|
RS690_BLOCK_GFX_D3_EN));
|
||||||
else
|
else
|
||||||
|
@ -812,6 +833,7 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
|
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
|
||||||
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740) ||
|
||||||
(dev_priv->flags & RADEON_IS_IGPGART)) {
|
(dev_priv->flags & RADEON_IS_IGPGART)) {
|
||||||
radeon_set_igpgart(dev_priv, on);
|
radeon_set_igpgart(dev_priv, on);
|
||||||
return;
|
return;
|
||||||
|
@ -1286,7 +1308,7 @@ static int radeon_do_resume_cp(struct drm_device * dev)
|
||||||
radeon_cp_init_ring_buffer(dev, dev_priv);
|
radeon_cp_init_ring_buffer(dev, dev_priv);
|
||||||
|
|
||||||
radeon_do_engine_reset(dev);
|
radeon_do_engine_reset(dev);
|
||||||
radeon_enable_interrupt(dev);
|
radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
|
||||||
|
|
||||||
DRM_DEBUG("radeon_do_resume_cp() complete\n");
|
DRM_DEBUG("radeon_do_resume_cp() complete\n");
|
||||||
|
|
||||||
|
@ -1708,6 +1730,7 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
|
||||||
case CHIP_R300:
|
case CHIP_R300:
|
||||||
case CHIP_R350:
|
case CHIP_R350:
|
||||||
case CHIP_R420:
|
case CHIP_R420:
|
||||||
|
case CHIP_R423:
|
||||||
case CHIP_RV410:
|
case CHIP_RV410:
|
||||||
case CHIP_RV515:
|
case CHIP_RV515:
|
||||||
case CHIP_R520:
|
case CHIP_R520:
|
||||||
|
|
|
@ -52,6 +52,28 @@ static int dri_library_name(struct drm_device *dev, char *buf)
|
||||||
"r300"));
|
"r300"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int radeon_suspend(struct drm_device *dev, pm_message_t state)
|
||||||
|
{
|
||||||
|
drm_radeon_private_t *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
/* Disable *all* interrupts */
|
||||||
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
|
||||||
|
RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
|
||||||
|
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int radeon_resume(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
drm_radeon_private_t *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
/* Restore interrupt registers */
|
||||||
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
|
||||||
|
RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg);
|
||||||
|
RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct pci_device_id pciidlist[] = {
|
static struct pci_device_id pciidlist[] = {
|
||||||
radeon_PCI_IDS
|
radeon_PCI_IDS
|
||||||
};
|
};
|
||||||
|
@ -59,8 +81,7 @@ static struct pci_device_id pciidlist[] = {
|
||||||
static struct drm_driver driver = {
|
static struct drm_driver driver = {
|
||||||
.driver_features =
|
.driver_features =
|
||||||
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
|
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
|
||||||
DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED |
|
DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED,
|
||||||
DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2,
|
|
||||||
.dev_priv_size = sizeof(drm_radeon_buf_priv_t),
|
.dev_priv_size = sizeof(drm_radeon_buf_priv_t),
|
||||||
.load = radeon_driver_load,
|
.load = radeon_driver_load,
|
||||||
.firstopen = radeon_driver_firstopen,
|
.firstopen = radeon_driver_firstopen,
|
||||||
|
@ -69,8 +90,11 @@ static struct drm_driver driver = {
|
||||||
.postclose = radeon_driver_postclose,
|
.postclose = radeon_driver_postclose,
|
||||||
.lastclose = radeon_driver_lastclose,
|
.lastclose = radeon_driver_lastclose,
|
||||||
.unload = radeon_driver_unload,
|
.unload = radeon_driver_unload,
|
||||||
.vblank_wait = radeon_driver_vblank_wait,
|
.suspend = radeon_suspend,
|
||||||
.vblank_wait2 = radeon_driver_vblank_wait2,
|
.resume = radeon_resume,
|
||||||
|
.get_vblank_counter = radeon_get_vblank_counter,
|
||||||
|
.enable_vblank = radeon_enable_vblank,
|
||||||
|
.disable_vblank = radeon_disable_vblank,
|
||||||
.dri_library_name = dri_library_name,
|
.dri_library_name = dri_library_name,
|
||||||
.irq_preinstall = radeon_driver_irq_preinstall,
|
.irq_preinstall = radeon_driver_irq_preinstall,
|
||||||
.irq_postinstall = radeon_driver_irq_postinstall,
|
.irq_postinstall = radeon_driver_irq_postinstall,
|
||||||
|
|
|
@ -122,9 +122,12 @@ enum radeon_family {
|
||||||
CHIP_RV350,
|
CHIP_RV350,
|
||||||
CHIP_RV380,
|
CHIP_RV380,
|
||||||
CHIP_R420,
|
CHIP_R420,
|
||||||
|
CHIP_R423,
|
||||||
CHIP_RV410,
|
CHIP_RV410,
|
||||||
|
CHIP_RS400,
|
||||||
CHIP_RS480,
|
CHIP_RS480,
|
||||||
CHIP_RS690,
|
CHIP_RS690,
|
||||||
|
CHIP_RS740,
|
||||||
CHIP_RV515,
|
CHIP_RV515,
|
||||||
CHIP_R520,
|
CHIP_R520,
|
||||||
CHIP_RV530,
|
CHIP_RV530,
|
||||||
|
@ -378,17 +381,17 @@ extern void radeon_mem_release(struct drm_file *file_priv,
|
||||||
struct mem_block *heap);
|
struct mem_block *heap);
|
||||||
|
|
||||||
/* radeon_irq.c */
|
/* radeon_irq.c */
|
||||||
|
extern void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state);
|
||||||
extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv);
|
extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv);
|
||||||
extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv);
|
extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv);
|
||||||
|
|
||||||
extern void radeon_do_release(struct drm_device * dev);
|
extern void radeon_do_release(struct drm_device * dev);
|
||||||
extern int radeon_driver_vblank_wait(struct drm_device * dev,
|
extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc);
|
||||||
unsigned int *sequence);
|
extern int radeon_enable_vblank(struct drm_device *dev, int crtc);
|
||||||
extern int radeon_driver_vblank_wait2(struct drm_device * dev,
|
extern void radeon_disable_vblank(struct drm_device *dev, int crtc);
|
||||||
unsigned int *sequence);
|
|
||||||
extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS);
|
extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS);
|
||||||
extern void radeon_driver_irq_preinstall(struct drm_device * dev);
|
extern void radeon_driver_irq_preinstall(struct drm_device * dev);
|
||||||
extern void radeon_driver_irq_postinstall(struct drm_device * dev);
|
extern int radeon_driver_irq_postinstall(struct drm_device *dev);
|
||||||
extern void radeon_driver_irq_uninstall(struct drm_device * dev);
|
extern void radeon_driver_irq_uninstall(struct drm_device * dev);
|
||||||
extern void radeon_enable_interrupt(struct drm_device *dev);
|
extern void radeon_enable_interrupt(struct drm_device *dev);
|
||||||
extern int radeon_vblank_crtc_get(struct drm_device *dev);
|
extern int radeon_vblank_crtc_get(struct drm_device *dev);
|
||||||
|
@ -397,19 +400,22 @@ extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value);
|
||||||
extern int radeon_driver_load(struct drm_device *dev, unsigned long flags);
|
extern int radeon_driver_load(struct drm_device *dev, unsigned long flags);
|
||||||
extern int radeon_driver_unload(struct drm_device *dev);
|
extern int radeon_driver_unload(struct drm_device *dev);
|
||||||
extern int radeon_driver_firstopen(struct drm_device *dev);
|
extern int radeon_driver_firstopen(struct drm_device *dev);
|
||||||
extern void radeon_driver_preclose(struct drm_device * dev, struct drm_file *file_priv);
|
extern void radeon_driver_preclose(struct drm_device *dev,
|
||||||
extern void radeon_driver_postclose(struct drm_device * dev, struct drm_file * filp);
|
struct drm_file *file_priv);
|
||||||
|
extern void radeon_driver_postclose(struct drm_device *dev,
|
||||||
|
struct drm_file *file_priv);
|
||||||
extern void radeon_driver_lastclose(struct drm_device * dev);
|
extern void radeon_driver_lastclose(struct drm_device * dev);
|
||||||
extern int radeon_driver_open(struct drm_device * dev, struct drm_file * filp_priv);
|
extern int radeon_driver_open(struct drm_device *dev,
|
||||||
|
struct drm_file *file_priv);
|
||||||
extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
|
extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
|
||||||
unsigned long arg);
|
unsigned long arg);
|
||||||
|
|
||||||
/* r300_cmdbuf.c */
|
/* r300_cmdbuf.c */
|
||||||
extern void r300_init_reg_flags(struct drm_device *dev);
|
extern void r300_init_reg_flags(struct drm_device *dev);
|
||||||
|
|
||||||
extern int r300_do_cp_cmdbuf(struct drm_device * dev,
|
extern int r300_do_cp_cmdbuf(struct drm_device *dev,
|
||||||
struct drm_file *file_priv,
|
struct drm_file *file_priv,
|
||||||
drm_radeon_kcmd_buffer_t * cmdbuf);
|
drm_radeon_kcmd_buffer_t *cmdbuf);
|
||||||
|
|
||||||
/* Flags for stats.boxes
|
/* Flags for stats.boxes
|
||||||
*/
|
*/
|
||||||
|
@ -434,8 +440,31 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
|
||||||
# define RADEON_SCISSOR_1_ENABLE (1 << 29)
|
# define RADEON_SCISSOR_1_ENABLE (1 << 29)
|
||||||
# define RADEON_SCISSOR_2_ENABLE (1 << 30)
|
# define RADEON_SCISSOR_2_ENABLE (1 << 30)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PCIE radeons (rv370/rv380, rv410, r423/r430/r480, r5xx)
|
||||||
|
* don't have an explicit bus mastering disable bit. It's handled
|
||||||
|
* by the PCI D-states. PMI_BM_DIS disables D-state bus master
|
||||||
|
* handling, not bus mastering itself.
|
||||||
|
*/
|
||||||
#define RADEON_BUS_CNTL 0x0030
|
#define RADEON_BUS_CNTL 0x0030
|
||||||
|
/* r1xx, r2xx, r300, r(v)350, r420/r481, rs480 */
|
||||||
# define RADEON_BUS_MASTER_DIS (1 << 6)
|
# define RADEON_BUS_MASTER_DIS (1 << 6)
|
||||||
|
/* rs400, rs690/rs740 */
|
||||||
|
# define RS400_BUS_MASTER_DIS (1 << 14)
|
||||||
|
# define RS400_MSI_REARM (1 << 20)
|
||||||
|
/* see RS480_MSI_REARM in AIC_CNTL for rs480 */
|
||||||
|
|
||||||
|
#define RADEON_BUS_CNTL1 0x0034
|
||||||
|
# define RADEON_PMI_BM_DIS (1 << 2)
|
||||||
|
# define RADEON_PMI_INT_DIS (1 << 3)
|
||||||
|
|
||||||
|
#define RV370_BUS_CNTL 0x004c
|
||||||
|
# define RV370_PMI_BM_DIS (1 << 5)
|
||||||
|
# define RV370_PMI_INT_DIS (1 << 6)
|
||||||
|
|
||||||
|
#define RADEON_MSI_REARM_EN 0x0160
|
||||||
|
/* rv370/rv380, rv410, r423/r430/r480, r5xx */
|
||||||
|
# define RV370_MSI_REARM_EN (1 << 0)
|
||||||
|
|
||||||
#define RADEON_CLOCK_CNTL_DATA 0x000c
|
#define RADEON_CLOCK_CNTL_DATA 0x000c
|
||||||
# define RADEON_PLL_WR_EN (1 << 7)
|
# define RADEON_PLL_WR_EN (1 << 7)
|
||||||
|
@ -623,6 +652,7 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
|
||||||
# define RADEON_SW_INT_TEST (1 << 25)
|
# define RADEON_SW_INT_TEST (1 << 25)
|
||||||
# define RADEON_SW_INT_TEST_ACK (1 << 25)
|
# define RADEON_SW_INT_TEST_ACK (1 << 25)
|
||||||
# define RADEON_SW_INT_FIRE (1 << 26)
|
# define RADEON_SW_INT_FIRE (1 << 26)
|
||||||
|
# define R500_DISPLAY_INT_STATUS (1 << 0)
|
||||||
|
|
||||||
#define RADEON_HOST_PATH_CNTL 0x0130
|
#define RADEON_HOST_PATH_CNTL 0x0130
|
||||||
# define RADEON_HDP_SOFT_RESET (1 << 26)
|
# define RADEON_HDP_SOFT_RESET (1 << 26)
|
||||||
|
@ -907,6 +937,7 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
|
||||||
|
|
||||||
#define RADEON_AIC_CNTL 0x01d0
|
#define RADEON_AIC_CNTL 0x01d0
|
||||||
# define RADEON_PCIGART_TRANSLATE_EN (1 << 0)
|
# define RADEON_PCIGART_TRANSLATE_EN (1 << 0)
|
||||||
|
# define RS480_MSI_REARM (1 << 3)
|
||||||
#define RADEON_AIC_STAT 0x01d4
|
#define RADEON_AIC_STAT 0x01d4
|
||||||
#define RADEON_AIC_PT_BASE 0x01d8
|
#define RADEON_AIC_PT_BASE 0x01d8
|
||||||
#define RADEON_AIC_LO_ADDR 0x01dc
|
#define RADEON_AIC_LO_ADDR 0x01dc
|
||||||
|
@ -1116,6 +1147,9 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
|
||||||
|
|
||||||
#define R200_VAP_PVS_CNTL_1 0x22D0
|
#define R200_VAP_PVS_CNTL_1 0x22D0
|
||||||
|
|
||||||
|
#define RADEON_CRTC_CRNT_FRAME 0x0214
|
||||||
|
#define RADEON_CRTC2_CRNT_FRAME 0x0314
|
||||||
|
|
||||||
#define R500_D1CRTC_STATUS 0x609c
|
#define R500_D1CRTC_STATUS 0x609c
|
||||||
#define R500_D2CRTC_STATUS 0x689c
|
#define R500_D2CRTC_STATUS 0x689c
|
||||||
#define R500_CRTC_V_BLANK (1<<0)
|
#define R500_CRTC_V_BLANK (1<<0)
|
||||||
|
@ -1200,7 +1234,8 @@ do { \
|
||||||
|
|
||||||
#define IGP_WRITE_MCIND(addr, val) \
|
#define IGP_WRITE_MCIND(addr, val) \
|
||||||
do { \
|
do { \
|
||||||
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) \
|
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) || \
|
||||||
|
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) \
|
||||||
RS690_WRITE_MCIND(addr, val); \
|
RS690_WRITE_MCIND(addr, val); \
|
||||||
else \
|
else \
|
||||||
RS480_WRITE_MCIND(addr, val); \
|
RS480_WRITE_MCIND(addr, val); \
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Keith Whitwell <keith@tungstengraphics.com>
|
* Keith Whitwell <keith@tungstengraphics.com>
|
||||||
* Michel Dänzer <michel@daenzer.net>
|
* Michel D<EFBFBD>zer <michel@daenzer.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "drmP.h"
|
#include "drmP.h"
|
||||||
|
@ -35,12 +35,128 @@
|
||||||
#include "radeon_drm.h"
|
#include "radeon_drm.h"
|
||||||
#include "radeon_drv.h"
|
#include "radeon_drv.h"
|
||||||
|
|
||||||
static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv,
|
void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state)
|
||||||
u32 mask)
|
|
||||||
{
|
{
|
||||||
u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask;
|
drm_radeon_private_t *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
if (state)
|
||||||
|
dev_priv->irq_enable_reg |= mask;
|
||||||
|
else
|
||||||
|
dev_priv->irq_enable_reg &= ~mask;
|
||||||
|
|
||||||
|
RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void r500_vbl_irq_set_state(struct drm_device *dev, u32 mask, int state)
|
||||||
|
{
|
||||||
|
drm_radeon_private_t *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
if (state)
|
||||||
|
dev_priv->r500_disp_irq_reg |= mask;
|
||||||
|
else
|
||||||
|
dev_priv->r500_disp_irq_reg &= ~mask;
|
||||||
|
|
||||||
|
RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
int radeon_enable_vblank(struct drm_device *dev, int crtc)
|
||||||
|
{
|
||||||
|
drm_radeon_private_t *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
|
||||||
|
switch (crtc) {
|
||||||
|
case 0:
|
||||||
|
r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 1);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
|
||||||
|
crtc);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (crtc) {
|
||||||
|
case 0:
|
||||||
|
radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
|
||||||
|
crtc);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void radeon_disable_vblank(struct drm_device *dev, int crtc)
|
||||||
|
{
|
||||||
|
drm_radeon_private_t *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
|
||||||
|
switch (crtc) {
|
||||||
|
case 0:
|
||||||
|
r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 0);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
|
||||||
|
crtc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (crtc) {
|
||||||
|
case 0:
|
||||||
|
radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
|
||||||
|
crtc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r500_disp_int)
|
||||||
|
{
|
||||||
|
u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS);
|
||||||
|
u32 irq_mask = RADEON_SW_INT_TEST;
|
||||||
|
|
||||||
|
*r500_disp_int = 0;
|
||||||
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
|
||||||
|
/* vbl interrupts in a different place */
|
||||||
|
|
||||||
|
if (irqs & R500_DISPLAY_INT_STATUS) {
|
||||||
|
/* if a display interrupt */
|
||||||
|
u32 disp_irq;
|
||||||
|
|
||||||
|
disp_irq = RADEON_READ(R500_DISP_INTERRUPT_STATUS);
|
||||||
|
|
||||||
|
*r500_disp_int = disp_irq;
|
||||||
|
if (disp_irq & R500_D1_VBLANK_INTERRUPT)
|
||||||
|
RADEON_WRITE(R500_D1MODE_VBLANK_STATUS, R500_VBLANK_ACK);
|
||||||
|
if (disp_irq & R500_D2_VBLANK_INTERRUPT)
|
||||||
|
RADEON_WRITE(R500_D2MODE_VBLANK_STATUS, R500_VBLANK_ACK);
|
||||||
|
}
|
||||||
|
irq_mask |= R500_DISPLAY_INT_STATUS;
|
||||||
|
} else
|
||||||
|
irq_mask |= RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT;
|
||||||
|
|
||||||
|
irqs &= irq_mask;
|
||||||
|
|
||||||
if (irqs)
|
if (irqs)
|
||||||
RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
|
RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
|
||||||
|
|
||||||
return irqs;
|
return irqs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,44 +184,33 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
|
||||||
drm_radeon_private_t *dev_priv =
|
drm_radeon_private_t *dev_priv =
|
||||||
(drm_radeon_private_t *) dev->dev_private;
|
(drm_radeon_private_t *) dev->dev_private;
|
||||||
u32 stat;
|
u32 stat;
|
||||||
|
u32 r500_disp_int;
|
||||||
|
|
||||||
/* Only consider the bits we're interested in - others could be used
|
/* Only consider the bits we're interested in - others could be used
|
||||||
* outside the DRM
|
* outside the DRM
|
||||||
*/
|
*/
|
||||||
stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
|
stat = radeon_acknowledge_irqs(dev_priv, &r500_disp_int);
|
||||||
RADEON_CRTC_VBLANK_STAT |
|
|
||||||
RADEON_CRTC2_VBLANK_STAT));
|
|
||||||
if (!stat)
|
if (!stat)
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
stat &= dev_priv->irq_enable_reg;
|
stat &= dev_priv->irq_enable_reg;
|
||||||
|
|
||||||
/* SW interrupt */
|
/* SW interrupt */
|
||||||
if (stat & RADEON_SW_INT_TEST) {
|
if (stat & RADEON_SW_INT_TEST)
|
||||||
DRM_WAKEUP(&dev_priv->swi_queue);
|
DRM_WAKEUP(&dev_priv->swi_queue);
|
||||||
}
|
|
||||||
|
|
||||||
/* VBLANK interrupt */
|
/* VBLANK interrupt */
|
||||||
if (stat & (RADEON_CRTC_VBLANK_STAT|RADEON_CRTC2_VBLANK_STAT)) {
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
|
||||||
int vblank_crtc = dev_priv->vblank_crtc;
|
if (r500_disp_int & R500_D1_VBLANK_INTERRUPT)
|
||||||
|
drm_handle_vblank(dev, 0);
|
||||||
if ((vblank_crtc &
|
if (r500_disp_int & R500_D2_VBLANK_INTERRUPT)
|
||||||
(DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) ==
|
drm_handle_vblank(dev, 1);
|
||||||
(DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) {
|
} else {
|
||||||
if (stat & RADEON_CRTC_VBLANK_STAT)
|
if (stat & RADEON_CRTC_VBLANK_STAT)
|
||||||
atomic_inc(&dev->vbl_received);
|
drm_handle_vblank(dev, 0);
|
||||||
if (stat & RADEON_CRTC2_VBLANK_STAT)
|
if (stat & RADEON_CRTC2_VBLANK_STAT)
|
||||||
atomic_inc(&dev->vbl_received2);
|
drm_handle_vblank(dev, 1);
|
||||||
} else if (((stat & RADEON_CRTC_VBLANK_STAT) &&
|
|
||||||
(vblank_crtc & DRM_RADEON_VBLANK_CRTC1)) ||
|
|
||||||
((stat & RADEON_CRTC2_VBLANK_STAT) &&
|
|
||||||
(vblank_crtc & DRM_RADEON_VBLANK_CRTC2)))
|
|
||||||
atomic_inc(&dev->vbl_received);
|
|
||||||
|
|
||||||
DRM_WAKEUP(&dev->vbl_queue);
|
|
||||||
drm_vbl_send_signals(dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,54 +249,31 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int radeon_driver_vblank_do_wait(struct drm_device * dev,
|
u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
|
||||||
unsigned int *sequence, int crtc)
|
|
||||||
{
|
{
|
||||||
drm_radeon_private_t *dev_priv =
|
drm_radeon_private_t *dev_priv = dev->dev_private;
|
||||||
(drm_radeon_private_t *) dev->dev_private;
|
|
||||||
unsigned int cur_vblank;
|
|
||||||
int ret = 0;
|
|
||||||
int ack = 0;
|
|
||||||
atomic_t *counter;
|
|
||||||
if (!dev_priv) {
|
if (!dev_priv) {
|
||||||
DRM_ERROR("called with no initialization\n");
|
DRM_ERROR("called with no initialization\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crtc == DRM_RADEON_VBLANK_CRTC1) {
|
if (crtc < 0 || crtc > 1) {
|
||||||
counter = &dev->vbl_received;
|
DRM_ERROR("Invalid crtc %d\n", crtc);
|
||||||
ack |= RADEON_CRTC_VBLANK_STAT;
|
|
||||||
} else if (crtc == DRM_RADEON_VBLANK_CRTC2) {
|
|
||||||
counter = &dev->vbl_received2;
|
|
||||||
ack |= RADEON_CRTC2_VBLANK_STAT;
|
|
||||||
} else
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
radeon_acknowledge_irqs(dev_priv, ack);
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
|
||||||
|
if (crtc == 0)
|
||||||
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
|
return RADEON_READ(R500_D1CRTC_FRAME_COUNT);
|
||||||
|
else
|
||||||
/* Assume that the user has missed the current sequence number
|
return RADEON_READ(R500_D2CRTC_FRAME_COUNT);
|
||||||
* by about a day rather than she wants to wait for years
|
} else {
|
||||||
* using vertical blanks...
|
if (crtc == 0)
|
||||||
*/
|
return RADEON_READ(RADEON_CRTC_CRNT_FRAME);
|
||||||
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
|
else
|
||||||
(((cur_vblank = atomic_read(counter))
|
return RADEON_READ(RADEON_CRTC2_CRNT_FRAME);
|
||||||
- *sequence) <= (1 << 23)));
|
}
|
||||||
|
|
||||||
*sequence = cur_vblank;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int radeon_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
|
|
||||||
{
|
|
||||||
return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int radeon_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
|
|
||||||
{
|
|
||||||
return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Needs the lock as it touches the ring.
|
/* Needs the lock as it touches the ring.
|
||||||
|
@ -234,46 +316,41 @@ int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_pr
|
||||||
return radeon_wait_irq(dev, irqwait->irq_seq);
|
return radeon_wait_irq(dev, irqwait->irq_seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
void radeon_enable_interrupt(struct drm_device *dev)
|
|
||||||
{
|
|
||||||
drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
|
|
||||||
|
|
||||||
dev_priv->irq_enable_reg = RADEON_SW_INT_ENABLE;
|
|
||||||
if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC1)
|
|
||||||
dev_priv->irq_enable_reg |= RADEON_CRTC_VBLANK_MASK;
|
|
||||||
|
|
||||||
if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC2)
|
|
||||||
dev_priv->irq_enable_reg |= RADEON_CRTC2_VBLANK_MASK;
|
|
||||||
|
|
||||||
RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
|
|
||||||
dev_priv->irq_enabled = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* drm_dma.h hooks
|
/* drm_dma.h hooks
|
||||||
*/
|
*/
|
||||||
void radeon_driver_irq_preinstall(struct drm_device * dev)
|
void radeon_driver_irq_preinstall(struct drm_device * dev)
|
||||||
{
|
{
|
||||||
drm_radeon_private_t *dev_priv =
|
drm_radeon_private_t *dev_priv =
|
||||||
(drm_radeon_private_t *) dev->dev_private;
|
(drm_radeon_private_t *) dev->dev_private;
|
||||||
|
u32 dummy;
|
||||||
|
|
||||||
/* Disable *all* interrupts */
|
/* Disable *all* interrupts */
|
||||||
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
|
||||||
|
RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
|
||||||
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
|
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
|
||||||
|
|
||||||
/* Clear bits if they're already high */
|
/* Clear bits if they're already high */
|
||||||
radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
|
radeon_acknowledge_irqs(dev_priv, &dummy);
|
||||||
RADEON_CRTC_VBLANK_STAT |
|
|
||||||
RADEON_CRTC2_VBLANK_STAT));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void radeon_driver_irq_postinstall(struct drm_device * dev)
|
int radeon_driver_irq_postinstall(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
drm_radeon_private_t *dev_priv =
|
drm_radeon_private_t *dev_priv =
|
||||||
(drm_radeon_private_t *) dev->dev_private;
|
(drm_radeon_private_t *) dev->dev_private;
|
||||||
|
int ret;
|
||||||
|
|
||||||
atomic_set(&dev_priv->swi_emitted, 0);
|
atomic_set(&dev_priv->swi_emitted, 0);
|
||||||
DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
|
DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
|
||||||
|
|
||||||
radeon_enable_interrupt(dev);
|
ret = drm_vblank_init(dev, 2);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
dev->max_vblank_count = 0x001fffff;
|
||||||
|
|
||||||
|
radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void radeon_driver_irq_uninstall(struct drm_device * dev)
|
void radeon_driver_irq_uninstall(struct drm_device * dev)
|
||||||
|
@ -285,6 +362,8 @@ void radeon_driver_irq_uninstall(struct drm_device * dev)
|
||||||
|
|
||||||
dev_priv->irq_enabled = 0;
|
dev_priv->irq_enabled = 0;
|
||||||
|
|
||||||
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
|
||||||
|
RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
|
||||||
/* Disable *all* interrupts */
|
/* Disable *all* interrupts */
|
||||||
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
|
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
|
||||||
}
|
}
|
||||||
|
@ -293,18 +372,8 @@ void radeon_driver_irq_uninstall(struct drm_device * dev)
|
||||||
int radeon_vblank_crtc_get(struct drm_device *dev)
|
int radeon_vblank_crtc_get(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
|
drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
|
||||||
u32 flag;
|
|
||||||
u32 value;
|
|
||||||
|
|
||||||
flag = RADEON_READ(RADEON_GEN_INT_CNTL);
|
return dev_priv->vblank_crtc;
|
||||||
value = 0;
|
|
||||||
|
|
||||||
if (flag & RADEON_CRTC_VBLANK_MASK)
|
|
||||||
value |= DRM_RADEON_VBLANK_CRTC1;
|
|
||||||
|
|
||||||
if (flag & RADEON_CRTC2_VBLANK_MASK)
|
|
||||||
value |= DRM_RADEON_VBLANK_CRTC2;
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value)
|
int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value)
|
||||||
|
@ -315,6 +384,5 @@ int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
dev_priv->vblank_crtc = (unsigned int)value;
|
dev_priv->vblank_crtc = (unsigned int)value;
|
||||||
radeon_enable_interrupt(dev);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2997,7 +2997,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
|
||||||
value = GET_SCRATCH(2);
|
value = GET_SCRATCH(2);
|
||||||
break;
|
break;
|
||||||
case RADEON_PARAM_IRQ_NR:
|
case RADEON_PARAM_IRQ_NR:
|
||||||
value = dev->irq;
|
value = drm_dev_to_irq(dev);
|
||||||
break;
|
break;
|
||||||
case RADEON_PARAM_GART_BASE:
|
case RADEON_PARAM_GART_BASE:
|
||||||
value = dev_priv->gart_vm_start;
|
value = dev_priv->gart_vm_start;
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
#define AGP_TYPE 1
|
#define AGP_TYPE 1
|
||||||
|
|
||||||
|
|
||||||
#if defined(CONFIG_FB_SIS)
|
#if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
|
||||||
/* fb management via fb device */
|
/* fb management via fb device */
|
||||||
|
|
||||||
#define SIS_MM_ALIGN_SHIFT 0
|
#define SIS_MM_ALIGN_SHIFT 0
|
||||||
|
@ -57,7 +57,7 @@ static void *sis_sman_mm_allocate(void *private, unsigned long size,
|
||||||
if (req.size == 0)
|
if (req.size == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
else
|
else
|
||||||
return (void *)~req.offset;
|
return (void *)(unsigned long)~req.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sis_sman_mm_free(void *private, void *ref)
|
static void sis_sman_mm_free(void *private, void *ref)
|
||||||
|
@ -75,12 +75,12 @@ static unsigned long sis_sman_mm_offset(void *private, void *ref)
|
||||||
return ~((unsigned long)ref);
|
return ~((unsigned long)ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* CONFIG_FB_SIS */
|
#else /* CONFIG_FB_SIS[_MODULE] */
|
||||||
|
|
||||||
#define SIS_MM_ALIGN_SHIFT 4
|
#define SIS_MM_ALIGN_SHIFT 4
|
||||||
#define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1)
|
#define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1)
|
||||||
|
|
||||||
#endif /* CONFIG_FB_SIS */
|
#endif /* CONFIG_FB_SIS[_MODULE] */
|
||||||
|
|
||||||
static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||||
{
|
{
|
||||||
|
@ -89,7 +89,7 @@ static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
mutex_lock(&dev->struct_mutex);
|
mutex_lock(&dev->struct_mutex);
|
||||||
#if defined(CONFIG_FB_SIS)
|
#if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
|
||||||
{
|
{
|
||||||
struct drm_sman_mm sman_mm;
|
struct drm_sman_mm sman_mm;
|
||||||
sman_mm.private = (void *)0xFFFFFFFF;
|
sman_mm.private = (void *)0xFFFFFFFF;
|
||||||
|
|
|
@ -40,11 +40,13 @@ static struct pci_device_id pciidlist[] = {
|
||||||
static struct drm_driver driver = {
|
static struct drm_driver driver = {
|
||||||
.driver_features =
|
.driver_features =
|
||||||
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ |
|
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ |
|
||||||
DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
|
DRIVER_IRQ_SHARED,
|
||||||
.load = via_driver_load,
|
.load = via_driver_load,
|
||||||
.unload = via_driver_unload,
|
.unload = via_driver_unload,
|
||||||
.context_dtor = via_final_context,
|
.context_dtor = via_final_context,
|
||||||
.vblank_wait = via_driver_vblank_wait,
|
.get_vblank_counter = via_get_vblank_counter,
|
||||||
|
.enable_vblank = via_enable_vblank,
|
||||||
|
.disable_vblank = via_disable_vblank,
|
||||||
.irq_preinstall = via_driver_irq_preinstall,
|
.irq_preinstall = via_driver_irq_preinstall,
|
||||||
.irq_postinstall = via_driver_irq_postinstall,
|
.irq_postinstall = via_driver_irq_postinstall,
|
||||||
.irq_uninstall = via_driver_irq_uninstall,
|
.irq_uninstall = via_driver_irq_uninstall,
|
||||||
|
@ -59,17 +61,17 @@ static struct drm_driver driver = {
|
||||||
.get_reg_ofs = drm_core_get_reg_ofs,
|
.get_reg_ofs = drm_core_get_reg_ofs,
|
||||||
.ioctls = via_ioctls,
|
.ioctls = via_ioctls,
|
||||||
.fops = {
|
.fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.open = drm_open,
|
.open = drm_open,
|
||||||
.release = drm_release,
|
.release = drm_release,
|
||||||
.ioctl = drm_ioctl,
|
.ioctl = drm_ioctl,
|
||||||
.mmap = drm_mmap,
|
.mmap = drm_mmap,
|
||||||
.poll = drm_poll,
|
.poll = drm_poll,
|
||||||
.fasync = drm_fasync,
|
.fasync = drm_fasync,
|
||||||
},
|
},
|
||||||
.pci_driver = {
|
.pci_driver = {
|
||||||
.name = DRIVER_NAME,
|
.name = DRIVER_NAME,
|
||||||
.id_table = pciidlist,
|
.id_table = pciidlist,
|
||||||
},
|
},
|
||||||
|
|
||||||
.name = DRIVER_NAME,
|
.name = DRIVER_NAME,
|
||||||
|
|
|
@ -75,6 +75,7 @@ typedef struct drm_via_private {
|
||||||
struct timeval last_vblank;
|
struct timeval last_vblank;
|
||||||
int last_vblank_valid;
|
int last_vblank_valid;
|
||||||
unsigned usec_per_vblank;
|
unsigned usec_per_vblank;
|
||||||
|
atomic_t vbl_received;
|
||||||
drm_via_state_t hc_state;
|
drm_via_state_t hc_state;
|
||||||
char pci_buf[VIA_PCI_BUF_SIZE];
|
char pci_buf[VIA_PCI_BUF_SIZE];
|
||||||
const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
|
const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
|
||||||
|
@ -130,21 +131,24 @@ extern int via_init_context(struct drm_device * dev, int context);
|
||||||
extern int via_final_context(struct drm_device * dev, int context);
|
extern int via_final_context(struct drm_device * dev, int context);
|
||||||
|
|
||||||
extern int via_do_cleanup_map(struct drm_device * dev);
|
extern int via_do_cleanup_map(struct drm_device * dev);
|
||||||
extern int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
|
extern u32 via_get_vblank_counter(struct drm_device *dev, int crtc);
|
||||||
|
extern int via_enable_vblank(struct drm_device *dev, int crtc);
|
||||||
|
extern void via_disable_vblank(struct drm_device *dev, int crtc);
|
||||||
|
|
||||||
extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS);
|
extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS);
|
||||||
extern void via_driver_irq_preinstall(struct drm_device * dev);
|
extern void via_driver_irq_preinstall(struct drm_device * dev);
|
||||||
extern void via_driver_irq_postinstall(struct drm_device * dev);
|
extern int via_driver_irq_postinstall(struct drm_device *dev);
|
||||||
extern void via_driver_irq_uninstall(struct drm_device * dev);
|
extern void via_driver_irq_uninstall(struct drm_device * dev);
|
||||||
|
|
||||||
extern int via_dma_cleanup(struct drm_device * dev);
|
extern int via_dma_cleanup(struct drm_device * dev);
|
||||||
extern void via_init_command_verifier(void);
|
extern void via_init_command_verifier(void);
|
||||||
extern int via_driver_dma_quiescent(struct drm_device * dev);
|
extern int via_driver_dma_quiescent(struct drm_device * dev);
|
||||||
extern void via_init_futex(drm_via_private_t * dev_priv);
|
extern void via_init_futex(drm_via_private_t *dev_priv);
|
||||||
extern void via_cleanup_futex(drm_via_private_t * dev_priv);
|
extern void via_cleanup_futex(drm_via_private_t *dev_priv);
|
||||||
extern void via_release_futex(drm_via_private_t * dev_priv, int context);
|
extern void via_release_futex(drm_via_private_t *dev_priv, int context);
|
||||||
|
|
||||||
extern void via_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv);
|
extern void via_reclaim_buffers_locked(struct drm_device *dev,
|
||||||
|
struct drm_file *file_priv);
|
||||||
extern void via_lastclose(struct drm_device *dev);
|
extern void via_lastclose(struct drm_device *dev);
|
||||||
|
|
||||||
extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq);
|
extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq);
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
#define VIA_REG_INTERRUPT 0x200
|
#define VIA_REG_INTERRUPT 0x200
|
||||||
|
|
||||||
/* VIA_REG_INTERRUPT */
|
/* VIA_REG_INTERRUPT */
|
||||||
#define VIA_IRQ_GLOBAL (1 << 31)
|
#define VIA_IRQ_GLOBAL (1 << 31)
|
||||||
#define VIA_IRQ_VBLANK_ENABLE (1 << 19)
|
#define VIA_IRQ_VBLANK_ENABLE (1 << 19)
|
||||||
#define VIA_IRQ_VBLANK_PENDING (1 << 3)
|
#define VIA_IRQ_VBLANK_PENDING (1 << 3)
|
||||||
#define VIA_IRQ_HQV0_ENABLE (1 << 11)
|
#define VIA_IRQ_HQV0_ENABLE (1 << 11)
|
||||||
|
@ -68,16 +68,15 @@
|
||||||
|
|
||||||
static maskarray_t via_pro_group_a_irqs[] = {
|
static maskarray_t via_pro_group_a_irqs[] = {
|
||||||
{VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010,
|
{VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010,
|
||||||
0x00000000},
|
0x00000000 },
|
||||||
{VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010,
|
{VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010,
|
||||||
0x00000000},
|
0x00000000 },
|
||||||
{VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
|
{VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
|
||||||
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
|
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
|
||||||
{VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
|
{VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
|
||||||
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
|
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
|
||||||
};
|
};
|
||||||
static int via_num_pro_group_a =
|
static int via_num_pro_group_a = ARRAY_SIZE(via_pro_group_a_irqs);
|
||||||
sizeof(via_pro_group_a_irqs) / sizeof(maskarray_t);
|
|
||||||
static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3};
|
static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3};
|
||||||
|
|
||||||
static maskarray_t via_unichrome_irqs[] = {
|
static maskarray_t via_unichrome_irqs[] = {
|
||||||
|
@ -86,14 +85,24 @@ static maskarray_t via_unichrome_irqs[] = {
|
||||||
{VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
|
{VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
|
||||||
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}
|
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}
|
||||||
};
|
};
|
||||||
static int via_num_unichrome = sizeof(via_unichrome_irqs) / sizeof(maskarray_t);
|
static int via_num_unichrome = ARRAY_SIZE(via_unichrome_irqs);
|
||||||
static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
|
static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
|
||||||
|
|
||||||
|
|
||||||
static unsigned time_diff(struct timeval *now, struct timeval *then)
|
static unsigned time_diff(struct timeval *now, struct timeval *then)
|
||||||
{
|
{
|
||||||
return (now->tv_usec >= then->tv_usec) ?
|
return (now->tv_usec >= then->tv_usec) ?
|
||||||
now->tv_usec - then->tv_usec :
|
now->tv_usec - then->tv_usec :
|
||||||
1000000 - (then->tv_usec - now->tv_usec);
|
1000000 - (then->tv_usec - now->tv_usec);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 via_get_vblank_counter(struct drm_device *dev, int crtc)
|
||||||
|
{
|
||||||
|
drm_via_private_t *dev_priv = dev->dev_private;
|
||||||
|
if (crtc != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return atomic_read(&dev_priv->vbl_received);
|
||||||
}
|
}
|
||||||
|
|
||||||
irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
|
irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
|
||||||
|
@ -108,23 +117,22 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
|
||||||
|
|
||||||
status = VIA_READ(VIA_REG_INTERRUPT);
|
status = VIA_READ(VIA_REG_INTERRUPT);
|
||||||
if (status & VIA_IRQ_VBLANK_PENDING) {
|
if (status & VIA_IRQ_VBLANK_PENDING) {
|
||||||
atomic_inc(&dev->vbl_received);
|
atomic_inc(&dev_priv->vbl_received);
|
||||||
if (!(atomic_read(&dev->vbl_received) & 0x0F)) {
|
if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) {
|
||||||
do_gettimeofday(&cur_vblank);
|
do_gettimeofday(&cur_vblank);
|
||||||
if (dev_priv->last_vblank_valid) {
|
if (dev_priv->last_vblank_valid) {
|
||||||
dev_priv->usec_per_vblank =
|
dev_priv->usec_per_vblank =
|
||||||
time_diff(&cur_vblank,
|
time_diff(&cur_vblank,
|
||||||
&dev_priv->last_vblank) >> 4;
|
&dev_priv->last_vblank) >> 4;
|
||||||
}
|
}
|
||||||
dev_priv->last_vblank = cur_vblank;
|
dev_priv->last_vblank = cur_vblank;
|
||||||
dev_priv->last_vblank_valid = 1;
|
dev_priv->last_vblank_valid = 1;
|
||||||
}
|
}
|
||||||
if (!(atomic_read(&dev->vbl_received) & 0xFF)) {
|
if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) {
|
||||||
DRM_DEBUG("US per vblank is: %u\n",
|
DRM_DEBUG("US per vblank is: %u\n",
|
||||||
dev_priv->usec_per_vblank);
|
dev_priv->usec_per_vblank);
|
||||||
}
|
}
|
||||||
DRM_WAKEUP(&dev->vbl_queue);
|
drm_handle_vblank(dev, 0);
|
||||||
drm_vbl_send_signals(dev);
|
|
||||||
handled = 1;
|
handled = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +153,7 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
|
||||||
/* Acknowlege interrupts */
|
/* Acknowlege interrupts */
|
||||||
VIA_WRITE(VIA_REG_INTERRUPT, status);
|
VIA_WRITE(VIA_REG_INTERRUPT, status);
|
||||||
|
|
||||||
|
|
||||||
if (handled)
|
if (handled)
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
else
|
else
|
||||||
|
@ -163,31 +172,34 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
|
int via_enable_vblank(struct drm_device *dev, int crtc)
|
||||||
{
|
{
|
||||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
drm_via_private_t *dev_priv = dev->dev_private;
|
||||||
unsigned int cur_vblank;
|
u32 status;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
DRM_DEBUG("\n");
|
if (crtc != 0) {
|
||||||
if (!dev_priv) {
|
DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
|
||||||
DRM_ERROR("called with no initialization\n");
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
viadrv_acknowledge_irqs(dev_priv);
|
status = VIA_READ(VIA_REG_INTERRUPT);
|
||||||
|
VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE);
|
||||||
|
|
||||||
/* Assume that the user has missed the current sequence number
|
VIA_WRITE8(0x83d4, 0x11);
|
||||||
* by about a day rather than she wants to wait for years
|
VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
|
||||||
* using vertical blanks...
|
|
||||||
*/
|
|
||||||
|
|
||||||
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
|
return 0;
|
||||||
(((cur_vblank = atomic_read(&dev->vbl_received)) -
|
}
|
||||||
*sequence) <= (1 << 23)));
|
|
||||||
|
|
||||||
*sequence = cur_vblank;
|
void via_disable_vblank(struct drm_device *dev, int crtc)
|
||||||
return ret;
|
{
|
||||||
|
drm_via_private_t *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
VIA_WRITE8(0x83d4, 0x11);
|
||||||
|
VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);
|
||||||
|
|
||||||
|
if (crtc != 0)
|
||||||
|
DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -239,6 +251,7 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* drm_dma.h hooks
|
* drm_dma.h hooks
|
||||||
*/
|
*/
|
||||||
|
@ -292,23 +305,25 @@ void via_driver_irq_preinstall(struct drm_device * dev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void via_driver_irq_postinstall(struct drm_device * dev)
|
int via_driver_irq_postinstall(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||||
u32 status;
|
u32 status;
|
||||||
|
|
||||||
DRM_DEBUG("\n");
|
DRM_DEBUG("via_driver_irq_postinstall\n");
|
||||||
if (dev_priv) {
|
if (!dev_priv)
|
||||||
status = VIA_READ(VIA_REG_INTERRUPT);
|
return -EINVAL;
|
||||||
VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
|
|
||||||
| dev_priv->irq_enable_mask);
|
|
||||||
|
|
||||||
/* Some magic, oh for some data sheets ! */
|
drm_vblank_init(dev, 1);
|
||||||
|
status = VIA_READ(VIA_REG_INTERRUPT);
|
||||||
|
VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
|
||||||
|
| dev_priv->irq_enable_mask);
|
||||||
|
|
||||||
VIA_WRITE8(0x83d4, 0x11);
|
/* Some magic, oh for some data sheets ! */
|
||||||
VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
|
VIA_WRITE8(0x83d4, 0x11);
|
||||||
|
VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
|
||||||
|
|
||||||
}
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void via_driver_irq_uninstall(struct drm_device * dev)
|
void via_driver_irq_uninstall(struct drm_device * dev)
|
||||||
|
@ -339,9 +354,6 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||||
drm_via_irq_t *cur_irq = dev_priv->via_irqs;
|
drm_via_irq_t *cur_irq = dev_priv->via_irqs;
|
||||||
int force_sequence;
|
int force_sequence;
|
||||||
|
|
||||||
if (!dev->irq)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (irqwait->request.irq >= dev_priv->num_irqs) {
|
if (irqwait->request.irq >= dev_priv->num_irqs) {
|
||||||
DRM_ERROR("Trying to wait on unknown irq %d\n",
|
DRM_ERROR("Trying to wait on unknown irq %d\n",
|
||||||
irqwait->request.irq);
|
irqwait->request.irq);
|
||||||
|
@ -352,7 +364,8 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||||
|
|
||||||
switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) {
|
switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) {
|
||||||
case VIA_IRQ_RELATIVE:
|
case VIA_IRQ_RELATIVE:
|
||||||
irqwait->request.sequence += atomic_read(&cur_irq->irq_received);
|
irqwait->request.sequence +=
|
||||||
|
atomic_read(&cur_irq->irq_received);
|
||||||
irqwait->request.type &= ~_DRM_VBLANK_RELATIVE;
|
irqwait->request.type &= ~_DRM_VBLANK_RELATIVE;
|
||||||
case VIA_IRQ_ABSOLUTE:
|
case VIA_IRQ_ABSOLUTE:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -93,8 +93,7 @@ int via_final_context(struct drm_device *dev, int context)
|
||||||
/* Last context, perform cleanup */
|
/* Last context, perform cleanup */
|
||||||
if (dev->ctx_count == 1 && dev->dev_private) {
|
if (dev->ctx_count == 1 && dev->dev_private) {
|
||||||
DRM_DEBUG("Last Context\n");
|
DRM_DEBUG("Last Context\n");
|
||||||
if (dev->irq)
|
drm_irq_uninstall(dev);
|
||||||
drm_irq_uninstall(dev);
|
|
||||||
via_cleanup_futex(dev_priv);
|
via_cleanup_futex(dev_priv);
|
||||||
via_do_cleanup_map(dev);
|
via_do_cleanup_map(dev);
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue