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:
|
||||
PowerTOP <power@bughost.org>
|
||||
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>
|
||||
|
||||
!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
|
||||
|
||||
</sect1>
|
||||
|
|
|
@ -2571,6 +2571,9 @@ Your cooperation is appreciated.
|
|||
160 = /dev/usb/legousbtower0 1st 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
|
||||
...
|
||||
243 = /dev/usb/dabusb3 Fourth dabusb device
|
||||
|
|
|
@ -2,19 +2,24 @@
|
|||
Ext4 Filesystem
|
||||
===============
|
||||
|
||||
This is a development version of the ext4 filesystem, an advanced level
|
||||
of the ext3 filesystem which incorporates scalability and reliability
|
||||
enhancements for supporting large filesystems (64 bit) in keeping with
|
||||
increasing disk capacities and state-of-the-art feature requirements.
|
||||
Ext4 is an an advanced level of the ext3 filesystem which incorporates
|
||||
scalability and reliability enhancements for supporting large filesystems
|
||||
(64 bit) in keeping with increasing disk capacities and state-of-the-art
|
||||
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:
|
||||
===========================
|
||||
|
||||
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
|
||||
writing version 1.41) from:
|
||||
writing version 1.41.3) from:
|
||||
|
||||
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
|
||||
|
||||
Or configure an existing ext3 filesystem to support extents and set
|
||||
the test_fs flag to indicate that it's ok for an in-development
|
||||
filesystem to touch this filesystem:
|
||||
Or to configure an existing ext3 filesystem to support extents:
|
||||
|
||||
# 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
|
||||
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
|
||||
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/20080530/ffsb-readwrite-2.6.26-rc2.html
|
||||
- http://www.bullopensource.org/ext4/20080818-ffsb/ffsb-write-2.6.27-rc1.html
|
||||
- http://www.bullopensource.org/ext4/20080818-ffsb/ffsb-readwrite-2.6.27-rc1.html
|
||||
|
||||
3. Options
|
||||
==========
|
||||
|
@ -214,9 +217,6 @@ noreservation
|
|||
bsddf (*) Make 'df' act like BSD.
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
to use for allocation size and alignment. For RAID5/6
|
||||
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
|
||||
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'.
|
||||
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)
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
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
|
||||
the bahaviour of fans. Write 1 to let fans spinning at
|
||||
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.
|
||||
|
||||
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
|
||||
the BIOS configured the chip correctly. In that respect, it differs from
|
||||
the original driver (from lm_sensors for Linux 2.4), which would force the
|
||||
LM87 to an arbitrary, compile-time chosen mode, regardless of the actual
|
||||
chipset wiring.
|
||||
time. Which are depends on the hardware setup. This driver normally
|
||||
assumes that firmware configured the chip correctly. Where this is not
|
||||
the case, platform code must set the I2C client's platform_data to point
|
||||
to a u8 value to be written to the channel register.
|
||||
|
||||
For reference, here is the list of exclusive functions:
|
||||
- in0+in5 (default) or temp3
|
||||
|
|
|
@ -11,7 +11,7 @@ Supported chips:
|
|||
Prefix: 'lm99'
|
||||
Addresses scanned: I2C 0x4c and 0x4d
|
||||
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
|
||||
Prefix: 'lm99'
|
||||
Addresses scanned: I2C 0x4c and 0x4d
|
||||
|
@ -21,18 +21,32 @@ Supported chips:
|
|||
Prefix: 'lm86'
|
||||
Addresses scanned: I2C 0x4c
|
||||
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
|
||||
Prefix: 'adm1032'
|
||||
Addresses scanned: I2C 0x4c and 0x4d
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
http://www.analog.com/en/prod/0,2877,ADM1032,00.html
|
||||
Datasheet: Publicly available at the ON Semiconductor website
|
||||
http://www.onsemi.com/PowerSolutions/product.do?id=ADM1032
|
||||
* Analog Devices ADT7461
|
||||
Prefix: 'adt7461'
|
||||
Addresses scanned: I2C 0x4c and 0x4d
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
http://www.analog.com/en/prod/0,2877,ADT7461,00.html
|
||||
Note: Only if in ADM1032 compatibility mode
|
||||
Datasheet: Publicly available at the ON Semiconductor website
|
||||
http://www.onsemi.com/PowerSolutions/product.do?id=ADT7461
|
||||
* 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
|
||||
Prefix: 'max6657'
|
||||
Addresses scanned: I2C 0x4c
|
||||
|
@ -70,25 +84,21 @@ Description
|
|||
|
||||
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
|
||||
with many other devices such as the LM86, the LM89, the LM99, the ADM1032,
|
||||
the MAX6657, MAX6658, MAX6659, MAX6680 and the MAX6681 all of which are
|
||||
supported by this driver.
|
||||
with many other devices, many of which are supported by this driver.
|
||||
|
||||
Note that there is no easy way to differentiate between the MAX6657,
|
||||
MAX6658 and MAX6659 variants. The extra address and features of the
|
||||
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)
|
||||
be distinguished. Additionally, the ADT7461 is supported if found in
|
||||
ADM1032 compatibility mode.
|
||||
be distinguished.
|
||||
|
||||
The specificity of this family of chipsets over the ADM1021/LM84
|
||||
family is that it features critical limits with hysteresis, and an
|
||||
increased resolution of the remote temperature measurement.
|
||||
|
||||
The different chipsets of the family are not strictly identical, although
|
||||
very similar. This driver doesn't handle any specific feature for now,
|
||||
with the exception of SMBus PEC. For reference, here comes a non-exhaustive
|
||||
list of specific features:
|
||||
very similar. For reference, here comes a non-exhaustive list of specific
|
||||
features:
|
||||
|
||||
LM90:
|
||||
* Filter and alert configuration register at 0xBF.
|
||||
|
@ -114,9 +124,11 @@ ADT7461:
|
|||
* Lower resolution for remote temperature
|
||||
|
||||
MAX6657 and MAX6658:
|
||||
* Better local resolution
|
||||
* Remote sensor type selection
|
||||
|
||||
MAX6659:
|
||||
* Better local resolution
|
||||
* Selectable address
|
||||
* Second critical temperature limit
|
||||
* Remote sensor type selection
|
||||
|
@ -127,7 +139,8 @@ MAX6680 and MAX6681:
|
|||
|
||||
All temperature values are given in degrees Celsius. Resolution
|
||||
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.
|
||||
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
|
||||
Prefixes: 'pc87360', 'pc87363', 'pc87364', 'pc87365', 'pc87366'
|
||||
Addresses scanned: none, address read from Super I/O config space
|
||||
Datasheets:
|
||||
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
|
||||
Datasheets: No longer available
|
||||
|
||||
Authors: Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ Supported chips:
|
|||
* National Semiconductor PC87427
|
||||
Prefix: 'pc87427'
|
||||
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>
|
||||
|
||||
|
|
|
@ -353,7 +353,7 @@ in6=255
|
|||
|
||||
# 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:
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
* 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'
|
||||
parameter; this will put it into a more well-behaved state first.
|
||||
|
||||
The driver implements three temperature sensors, five fan rotation speed
|
||||
sensors, and ten voltage sensors.
|
||||
The driver implements three temperature sensors, 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
|
||||
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
|
||||
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
|
||||
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,
|
||||
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.
|
||||
An alarm is triggered if the voltage has crossed a programmable minimum
|
||||
or maximum limit.
|
||||
Each fan controlled is controlled by PWM. The PWM duty cycle can be read and
|
||||
set for each fan separately. Valid values range from 0 (stop) to 255 (full).
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
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.
|
||||
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
|
||||
------------------------------------
|
||||
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
|
||||
case_open : alarms: 0x001000 beep_mask: 0x001000
|
||||
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
|
||||
'K' all linux/kd.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
|
||||
<http://linux01.gwdg.de/~alatham/ppdd.html>
|
||||
'M' all linux/soundcard.h
|
||||
|
@ -110,6 +111,8 @@ Code Seq# Include File Comments
|
|||
'W' 00-1F linux/wanrouter.h conflict!
|
||||
'X' all linux/xfs_fs.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
|
||||
<http://lrcwww.epfl.ch/linux-atm/magic.html>
|
||||
'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
|
||||
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] 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.
|
||||
Set by modutils >= 2.4.9 and module-init-tools.
|
||||
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
|
||||
finite time.
|
||||
|
||||
usb_scuttle_anchored_urbs()
|
||||
---------------------------
|
||||
|
||||
All URBs of an anchor are unanchored en masse.
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
usb_autopm_enable() sets pm_usage_cnt to 1 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_enable() sets pm_usage_cnt to 0 and then calls
|
||||
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
|
||||
usb_autopm_get_interface() in its open routine and
|
||||
usb_autopm_put_interface() in its close or release routine. But
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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]
|
||||
3 -> DViCO FusionHDTV USB (au0828) [0fe9:d620]
|
||||
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=76 - Xceive 5000 tuner
|
||||
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
|
||||
S: Maintained
|
||||
|
||||
STABLE BRANCH:
|
||||
STABLE BRANCH
|
||||
P: Greg Kroah-Hartman
|
||||
M: greg@kroah.com
|
||||
P: Chris Wright
|
||||
|
@ -3945,6 +3945,13 @@ M: chrisw@sous-sol.org
|
|||
L: stable@kernel.org
|
||||
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
|
||||
P: Ion Badulescu
|
||||
M: ionut@cs.columbia.edu
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/mv643xx_eth.h>
|
||||
#include <linux/ata_platform.h>
|
||||
#include <linux/spi/orion_spi.h>
|
||||
#include <net/dsa.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/timex.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
|
||||
****************************************************************************/
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#ifndef __ARCH_KIRKWOOD_COMMON_H
|
||||
#define __ARCH_KIRKWOOD_COMMON_H
|
||||
|
||||
struct dsa_platform_data;
|
||||
struct mv643xx_eth_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_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_rtc_init(void);
|
||||
void kirkwood_sata_init(struct mv_sata_platform_data *sata_data);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/ata_platform.h>
|
||||
#include <linux/mv643xx_eth.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <net/dsa.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/pci.h>
|
||||
|
@ -74,6 +75,15 @@ static struct mv643xx_eth_platform_data rd88f6281_ge00_data = {
|
|||
.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 = {
|
||||
.n_ports = 2,
|
||||
};
|
||||
|
@ -87,6 +97,7 @@ static void __init rd88f6281_init(void)
|
|||
|
||||
kirkwood_ehci_init();
|
||||
kirkwood_ge00_init(&rd88f6281_ge00_data);
|
||||
kirkwood_ge00_switch_init(&rd88f6281_switch_data, NO_IRQ);
|
||||
kirkwood_rtc_init();
|
||||
kirkwood_sata_init(&rd88f6281_sata_data);
|
||||
kirkwood_uart0_init();
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/ata_platform.h>
|
||||
#include <linux/mv643xx_eth.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <mach/mv78xx0.h>
|
||||
#include <asm/mach-types.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 = {
|
||||
.phy_addr = MV643XX_ETH_PHY_NONE,
|
||||
.speed = SPEED_1000,
|
||||
.duplex = DUPLEX_FULL,
|
||||
};
|
||||
|
||||
static struct mv643xx_eth_platform_data db78x00_ge11_data = {
|
||||
.phy_addr = MV643XX_ETH_PHY_NONE,
|
||||
.speed = SPEED_1000,
|
||||
.duplex = DUPLEX_FULL,
|
||||
};
|
||||
|
||||
static struct mv_sata_platform_data db78x00_sata_data = {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/mv643xx_i2c.h>
|
||||
#include <linux/ata_platform.h>
|
||||
#include <linux/spi/orion_spi.h>
|
||||
#include <net/dsa.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/setup.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
|
||||
****************************************************************************/
|
||||
|
@ -275,7 +310,8 @@ void __init orion5x_sata_init(struct mv_sata_platform_data *sata_data)
|
|||
* SPI
|
||||
****************************************************************************/
|
||||
static struct orion_spi_info orion5x_spi_plat_data = {
|
||||
.tclk = 0,
|
||||
.tclk = 0,
|
||||
.enable_clock_fix = 1,
|
||||
};
|
||||
|
||||
static struct resource orion5x_spi_resources[] = {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef __ARCH_ORION5X_COMMON_H
|
||||
#define __ARCH_ORION5X_COMMON_H
|
||||
|
||||
struct dsa_platform_data;
|
||||
struct mv643xx_eth_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_ehci1_init(void);
|
||||
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_sata_init(struct mv_sata_platform_data *sata_data);
|
||||
void orion5x_spi_init(void);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/mv643xx_eth.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <net/dsa.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/leds.h>
|
||||
|
@ -93,6 +94,15 @@ static struct mv643xx_eth_platform_data rd88f5181l_fxo_eth_data = {
|
|||
.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)
|
||||
{
|
||||
/*
|
||||
|
@ -107,6 +117,7 @@ static void __init rd88f5181l_fxo_init(void)
|
|||
*/
|
||||
orion5x_ehci0_init();
|
||||
orion5x_eth_init(&rd88f5181l_fxo_eth_data);
|
||||
orion5x_eth_switch_init(&rd88f5181l_fxo_switch_data, NO_IRQ);
|
||||
orion5x_uart0_init();
|
||||
|
||||
orion5x_setup_dev_boot_win(RD88F5181L_FXO_NOR_BOOT_BASE,
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/mv643xx_eth.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <net/dsa.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/leds.h>
|
||||
|
@ -94,6 +95,15 @@ static struct mv643xx_eth_platform_data rd88f5181l_ge_eth_data = {
|
|||
.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 = {
|
||||
I2C_BOARD_INFO("ds1338", 0x68),
|
||||
};
|
||||
|
@ -112,6 +122,7 @@ static void __init rd88f5181l_ge_init(void)
|
|||
*/
|
||||
orion5x_ehci0_init();
|
||||
orion5x_eth_init(&rd88f5181l_ge_eth_data);
|
||||
orion5x_eth_switch_init(&rd88f5181l_ge_switch_data, gpio_to_irq(8));
|
||||
orion5x_i2c_init();
|
||||
orion5x_uart0_init();
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/spi/orion_spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <net/dsa.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/leds.h>
|
||||
|
@ -34,6 +35,15 @@ static struct mv643xx_eth_platform_data rd88f6183ap_ge_eth_data = {
|
|||
.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[] = {
|
||||
{
|
||||
.name = "kernel",
|
||||
|
@ -79,6 +89,7 @@ static void __init rd88f6183ap_ge_init(void)
|
|||
*/
|
||||
orion5x_ehci0_init();
|
||||
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,
|
||||
ARRAY_SIZE(rd88f6183ap_ge_spi_slave_info));
|
||||
orion5x_spi_init();
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/mv643xx_eth.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <net/dsa.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
@ -105,6 +106,15 @@ static struct mv643xx_eth_platform_data wrt350n_v2_eth_data = {
|
|||
.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)
|
||||
{
|
||||
/*
|
||||
|
@ -119,6 +129,7 @@ static void __init wrt350n_v2_init(void)
|
|||
*/
|
||||
orion5x_ehci0_init();
|
||||
orion5x_eth_init(&wrt350n_v2_eth_data);
|
||||
orion5x_eth_switch_init(&wrt350n_v2_switch_data, NO_IRQ);
|
||||
orion5x_uart0_init();
|
||||
|
||||
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
|
||||
# for more details.
|
||||
|
||||
KBUILD_DEFCONFIG := etrax-100lx_v2_defconfig
|
||||
|
||||
arch-y := v10
|
||||
arch-$(CONFIG_ETRAX_ARCH_V10) := v10
|
||||
arch-$(CONFIG_ETRAX_ARCH_V32) := v32
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
asflags-y += $(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
|
||||
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
ccflags-y += -O2 $(LINUXINCLUDE)
|
||||
asflags-y += $(LINUXINCLUDE)
|
||||
ldflags-y += -T $(srctree)/$(obj)/rescue.ld
|
||||
ldflags-y += -T $(srctree)/$(src)/rescue.lds
|
||||
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
||||
obj-$(CONFIG_ETRAX_AXISFLASHMAP) = head.o
|
||||
OBJECT := $(obj)/head.o
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
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
|
||||
ldflags-y += -T $(srctree)/$(obj)/decompress.ld
|
||||
ldflags-y += -T $(srctree)/$(src)/decompress.lds
|
||||
OBJECTS = $(obj)/head.o $(obj)/misc.o
|
||||
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ ccflags-y += -O2 -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
|
||||
ldflags-y += -T $(srctree)/$(obj)/rescue.ld
|
||||
ldflags-y += -T $(srctree)/$(src)/rescue.lds
|
||||
LDPOSTFLAGS = -lgcc
|
||||
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
||||
obj-$(CONFIG_ETRAX_AXISFLASHMAP) = head.o
|
||||
|
|
|
@ -137,6 +137,7 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
|
|||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -257,7 +257,6 @@ void __generic_unplug_device(struct request_queue *q)
|
|||
|
||||
q->request_fn(q);
|
||||
}
|
||||
EXPORT_SYMBOL(__generic_unplug_device);
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (unlikely(blk_queue_stopped(q)))
|
||||
return;
|
||||
|
||||
/*
|
||||
* one level of recursion is ok and is much faster than kicking
|
||||
* the unplug handling
|
||||
|
@ -399,8 +401,13 @@ void blk_sync_queue(struct request_queue *q)
|
|||
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
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
|
@ -418,6 +425,12 @@ EXPORT_SYMBOL(__blk_run_queue);
|
|||
/**
|
||||
* blk_run_queue - run a single device queue
|
||||
* @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)
|
||||
{
|
||||
|
@ -501,6 +514,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
|
|||
init_timer(&q->unplug_timer);
|
||||
setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
|
||||
INIT_LIST_HEAD(&q->timeout_list);
|
||||
INIT_WORK(&q->unplug_work, blk_unplug_work);
|
||||
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
|
@ -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
|
||||
* disk_stats.
|
||||
* part_round_stats() - Round off the performance stats on a struct disk_stats.
|
||||
* @cpu: cpu number for stats access
|
||||
* @part: target partition
|
||||
*
|
||||
* The average IO queue length and utilisation statistics are maintained
|
||||
* 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)
|
||||
*/
|
||||
if (bio_rw_ahead(bio) || bio_failfast(bio))
|
||||
req->cmd_flags |= REQ_FAILFAST;
|
||||
if (bio_rw_ahead(bio))
|
||||
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
|
||||
|
|
|
@ -77,12 +77,20 @@ void blk_recalc_rq_segments(struct request *rq)
|
|||
continue;
|
||||
}
|
||||
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++;
|
||||
bvprv = bv;
|
||||
seg_size = bv->bv_len;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
|
@ -324,8 +335,13 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
|
|||
return 0;
|
||||
|
||||
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--;
|
||||
}
|
||||
|
||||
if (total_phys_segments > q->max_phys_segments)
|
||||
return 0;
|
||||
|
|
|
@ -141,8 +141,6 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
|
|||
if (q->unplug_delay == 0)
|
||||
q->unplug_delay = 1;
|
||||
|
||||
INIT_WORK(&q->unplug_work, blk_unplug_work);
|
||||
|
||||
q->unplug_timer.function = blk_unplug_timeout;
|
||||
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_delete_timer(struct request *);
|
||||
void blk_add_timer(struct request *);
|
||||
void __generic_unplug_device(struct request_queue *);
|
||||
|
||||
/*
|
||||
* Internal atomic flags for request handling
|
||||
|
|
|
@ -612,7 +612,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where)
|
|||
* processing.
|
||||
*/
|
||||
blk_remove_plug(q);
|
||||
q->request_fn(q);
|
||||
blk_start_queueing(q);
|
||||
break;
|
||||
|
||||
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_req_seq(first_rq) > QUEUE_ORDSEQ_DRAIN) {
|
||||
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);
|
||||
|
||||
while (q->rq.elvpriv) {
|
||||
blk_remove_plug(q);
|
||||
q->request_fn(q);
|
||||
blk_start_queueing(q);
|
||||
spin_unlock_irq(q->queue_lock);
|
||||
msleep(10);
|
||||
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)
|
||||
{
|
||||
char elevator_name[ELV_NAME_MAX];
|
||||
size_t len;
|
||||
struct elevator_type *e;
|
||||
|
||||
elevator_name[sizeof(elevator_name) - 1] = '\0';
|
||||
strncpy(elevator_name, name, sizeof(elevator_name) - 1);
|
||||
len = strlen(elevator_name);
|
||||
|
||||
if (len && elevator_name[len - 1] == '\n')
|
||||
elevator_name[len - 1] = '\0';
|
||||
strlcpy(elevator_name, name, sizeof(elevator_name));
|
||||
strstrip(elevator_name);
|
||||
|
||||
e = elevator_get(elevator_name);
|
||||
if (!e) {
|
||||
|
|
|
@ -358,7 +358,6 @@ static int blk_mangle_minor(int minor)
|
|||
/**
|
||||
* blk_alloc_devt - allocate a dev_t for a partition
|
||||
* @part: partition to allocate dev_t for
|
||||
* @gfp_mask: memory allocation flag
|
||||
* @devt: out parameter for resulting dev_t
|
||||
*
|
||||
* 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
|
||||
* @devt: device to get partitioning information for
|
||||
* @part: returned partition index
|
||||
* @partno: returned partition index
|
||||
*
|
||||
* This function gets the structure containing partitioning
|
||||
* information for the given device @devt.
|
||||
|
|
|
@ -101,4 +101,6 @@ source "drivers/auxdisplay/Kconfig"
|
|||
source "drivers/uio/Kconfig"
|
||||
|
||||
source "drivers/xen/Kconfig"
|
||||
|
||||
source "drivers/staging/Kconfig"
|
||||
endmenu
|
||||
|
|
|
@ -99,3 +99,4 @@ obj-$(CONFIG_OF) += of/
|
|||
obj-$(CONFIG_SSB) += ssb/
|
||||
obj-$(CONFIG_VIRTIO) += virtio/
|
||||
obj-$(CONFIG_REGULATOR) += regulator/
|
||||
obj-$(CONFIG_STAGING) += staging/
|
||||
|
|
|
@ -349,8 +349,6 @@ struct ub_dev {
|
|||
|
||||
struct work_struct reset_work;
|
||||
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;
|
||||
}
|
||||
urq->nsg = n_elem;
|
||||
sc->sg_stat[n_elem < 5 ? n_elem : 5]++;
|
||||
|
||||
if (blk_pc_request(rq)) {
|
||||
ub_cmd_build_packet(sc, lun, cmd, urq);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#
|
||||
menuconfig DRM
|
||||
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
|
||||
Kernel-level support for the Direct Rendering Infrastructure (DRI)
|
||||
introduced in XFree86 4.0. If you say Y here, you need to select
|
||||
|
@ -87,6 +87,7 @@ config DRM_MGA
|
|||
config DRM_SIS
|
||||
tristate "SiS video cards"
|
||||
depends on DRM && AGP
|
||||
depends on FB_SIS || FB_SIS=n
|
||||
help
|
||||
Choose this option if you have a SiS 630 or compatible video
|
||||
chipset. If M is selected the module will be called sis. AGP
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
|
||||
ccflags-y := -Iinclude/drm
|
||||
|
||||
drm-y := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
|
||||
drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \
|
||||
drm-y := drm_auth.o drm_bufs.o drm_cache.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_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
|
||||
drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include "drmP.h"
|
||||
#include <linux/module.h>
|
||||
#include <asm/agp.h>
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
|
||||
|
@ -452,4 +453,53 @@ int drm_agp_unbind_memory(DRM_AGP_MEM * 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_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_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 )
|
||||
|
|
|
@ -246,7 +246,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
|
|||
memset(priv, 0, sizeof(*priv));
|
||||
filp->private_data = priv;
|
||||
priv->filp = filp;
|
||||
priv->uid = current->euid;
|
||||
priv->uid = current_euid();
|
||||
priv->pid = task_pid_nr(current);
|
||||
priv->minor = idr_find(&drm_minors_idr, minor_id);
|
||||
priv->ioctl_count = 0;
|
||||
|
@ -256,6 +256,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
|
|||
|
||||
INIT_LIST_HEAD(&priv->lhead);
|
||||
|
||||
if (dev->driver->driver_features & DRIVER_GEM)
|
||||
drm_gem_open(dev, priv);
|
||||
|
||||
if (dev->driver->open) {
|
||||
ret = dev->driver->open(dev, priv);
|
||||
if (ret < 0)
|
||||
|
@ -400,6 +403,9 @@ int drm_release(struct inode *inode, struct file *filp)
|
|||
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);
|
||||
|
||||
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))
|
||||
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,
|
||||
p->irq);
|
||||
|
@ -71,25 +71,137 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
|
|||
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.
|
||||
*
|
||||
* \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
|
||||
* 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;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->irq == 0)
|
||||
if (dev->pdev->irq == 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
@ -107,18 +219,7 @@ static int drm_irq_install(struct drm_device * dev)
|
|||
dev->irq_enabled = 1;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
DRM_DEBUG("irq=%d\n", dev->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;
|
||||
}
|
||||
DRM_DEBUG("irq=%d\n", dev->pdev->irq);
|
||||
|
||||
/* Before installing handler */
|
||||
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))
|
||||
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);
|
||||
|
||||
if (ret < 0) {
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
dev->irq_enabled = 0;
|
||||
|
@ -137,10 +239,16 @@ static int drm_irq_install(struct drm_device * dev)
|
|||
}
|
||||
|
||||
/* 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.
|
||||
|
@ -164,17 +272,18 @@ int drm_irq_uninstall(struct drm_device * dev)
|
|||
if (!irq_enabled)
|
||||
return -EINVAL;
|
||||
|
||||
DRM_DEBUG("irq=%d\n", dev->irq);
|
||||
DRM_DEBUG("irq=%d\n", dev->pdev->irq);
|
||||
|
||||
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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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))
|
||||
return 0;
|
||||
if (dev->if_version < DRM_IF_VERSION(1, 2) &&
|
||||
ctl->irq != dev->irq)
|
||||
ctl->irq != dev->pdev->irq)
|
||||
return -EINVAL;
|
||||
return drm_irq_install(dev);
|
||||
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.
|
||||
*
|
||||
|
@ -232,14 +509,14 @@ int drm_control(struct drm_device *dev, void *data,
|
|||
*
|
||||
* 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;
|
||||
struct timeval now;
|
||||
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;
|
||||
|
||||
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;
|
||||
crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
|
||||
|
||||
if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
|
||||
DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
|
||||
if (crtc >= dev->num_crtcs)
|
||||
return -EINVAL;
|
||||
|
||||
seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2
|
||||
: &dev->vbl_received);
|
||||
ret = drm_vblank_get(dev, crtc);
|
||||
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) {
|
||||
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:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
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) {
|
||||
unsigned long irqflags;
|
||||
struct list_head *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
|
||||
? &dev->vbl_sigs2 : &dev->vbl_sigs;
|
||||
struct list_head *vbl_sigs = &dev->vbl_sigs[crtc];
|
||||
struct drm_vbl_sig *vbl_sig;
|
||||
|
||||
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);
|
||||
return -EBUSY;
|
||||
ret = -EBUSY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
dev->vbl_pending++;
|
||||
|
||||
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||
|
||||
if (!
|
||||
(vbl_sig =
|
||||
drm_alloc(sizeof(struct drm_vbl_sig), DRM_MEM_DRIVER))) {
|
||||
return -ENOMEM;
|
||||
vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig),
|
||||
DRM_MEM_DRIVER);
|
||||
if (!vbl_sig) {
|
||||
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->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;
|
||||
} else {
|
||||
if (flags & _DRM_VBLANK_SECONDARY) {
|
||||
if (dev->driver->vblank_wait2)
|
||||
ret = dev->driver->vblank_wait2(dev, &vblwait->request.sequence);
|
||||
} else if (dev->driver->vblank_wait)
|
||||
ret =
|
||||
dev->driver->vblank_wait(dev,
|
||||
&vblwait->request.sequence);
|
||||
DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
|
||||
vblwait->request.sequence, crtc);
|
||||
DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
|
||||
((drm_vblank_count(dev, crtc)
|
||||
- vblwait->request.sequence) <= (1 << 23)));
|
||||
|
||||
do_gettimeofday(&now);
|
||||
vblwait->reply.tval_sec = now.tv_sec;
|
||||
vblwait->reply.tval_usec = now.tv_usec;
|
||||
if (ret != -EINTR) {
|
||||
struct timeval now;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -348,44 +645,57 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
|
|||
* Send the VBLANK signals.
|
||||
*
|
||||
* \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.
|
||||
*
|
||||
* 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;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&dev->vbl_lock, flags);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
struct drm_vbl_sig *vbl_sig, *tmp;
|
||||
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);
|
||||
vbl_sigs = &dev->vbl_sigs[crtc];
|
||||
vbl_seq = drm_vblank_count(dev, crtc);
|
||||
|
||||
list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
|
||||
if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
|
||||
vbl_sig->info.si_code = vbl_seq;
|
||||
send_sig_info(vbl_sig->info.si_signo,
|
||||
&vbl_sig->info, vbl_sig->task);
|
||||
list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
|
||||
if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
|
||||
vbl_sig->info.si_code = vbl_seq;
|
||||
send_sig_info(vbl_sig->info.si_signo,
|
||||
&vbl_sig->info, vbl_sig->task);
|
||||
|
||||
list_del(&vbl_sig->head);
|
||||
list_del(&vbl_sig->head);
|
||||
|
||||
drm_free(vbl_sig, sizeof(*vbl_sig),
|
||||
DRM_MEM_DRIVER);
|
||||
|
||||
dev->vbl_pending--;
|
||||
}
|
||||
}
|
||||
drm_free(vbl_sig, sizeof(*vbl_sig),
|
||||
DRM_MEM_DRIVER);
|
||||
atomic_dec(&dev->vbl_signal_pending);
|
||||
drm_vblank_put(dev, crtc);
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
|
|
|
@ -133,6 +133,7 @@ int drm_free_agp(DRM_AGP_MEM * handle, int pages)
|
|||
{
|
||||
return drm_agp_free_memory(handle) ? 0 : -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_free_agp);
|
||||
|
||||
/** Wrapper around agp_bind_memory() */
|
||||
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);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_unbind_agp);
|
||||
|
||||
#else /* __OS_HAS_AGP */
|
||||
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;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mm_get_block);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mm_put_block);
|
||||
|
||||
struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm,
|
||||
unsigned long size,
|
||||
|
@ -265,6 +267,7 @@ int drm_mm_clean(struct drm_mm * mm)
|
|||
|
||||
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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_mm_init);
|
||||
|
||||
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);
|
||||
static int drm_bufs_info(char *buf, char **start, off_t offset,
|
||||
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
|
||||
static int drm_vma_info(char *buf, char **start, off_t offset,
|
||||
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 {
|
||||
const char *name; /**< file name */
|
||||
int (*f) (char *, char **, off_t, int, int *, void *); /**< proc callback*/
|
||||
u32 driver_features; /**< Required driver features for this entry */
|
||||
} drm_proc_list[] = {
|
||||
{"name", drm_name_info},
|
||||
{"mem", drm_mem_info},
|
||||
{"vm", drm_vm_info},
|
||||
{"clients", drm_clients_info},
|
||||
{"queues", drm_queues_info},
|
||||
{"bufs", drm_bufs_info},
|
||||
{"name", drm_name_info, 0},
|
||||
{"mem", drm_mem_info, 0},
|
||||
{"vm", drm_vm_info, 0},
|
||||
{"clients", drm_clients_info, 0},
|
||||
{"queues", drm_queues_info, 0},
|
||||
{"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
|
||||
{"vma", drm_vma_info},
|
||||
#endif
|
||||
|
@ -90,8 +97,9 @@ static struct drm_proc_list {
|
|||
int drm_proc_init(struct drm_minor *minor, int minor_id,
|
||||
struct proc_dir_entry *root)
|
||||
{
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct proc_dir_entry *ent;
|
||||
int i, j;
|
||||
int i, j, ret;
|
||||
char name[64];
|
||||
|
||||
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++) {
|
||||
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,
|
||||
S_IFREG | S_IRUGO, minor->dev_root);
|
||||
if (!ent) {
|
||||
DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
|
||||
name, drm_proc_list[i].name);
|
||||
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 -1;
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
ent->read_proc = drm_proc_list[i].f;
|
||||
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;
|
||||
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)
|
||||
{
|
||||
struct drm_device *dev = minor->dev;
|
||||
int i;
|
||||
char name[64];
|
||||
|
||||
if (!root || !minor->dev_root)
|
||||
return 0;
|
||||
|
||||
if (dev->driver->proc_cleanup)
|
||||
dev->driver->proc_cleanup(minor);
|
||||
|
||||
for (i = 0; i < DRM_PROC_ENTRIES; i++)
|
||||
remove_proc_entry(drm_proc_list[i].name, minor->dev_root);
|
||||
sprintf(name, "%d", minor->index);
|
||||
|
@ -480,6 +511,84 @@ static int drm_clients_info(char *buf, char **start, off_t offset,
|
|||
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
|
||||
|
||||
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__
|
||||
dev->hose = pdev->sysdata;
|
||||
#endif
|
||||
dev->irq = pdev->irq;
|
||||
|
||||
if (drm_ht_create(&dev->map_hash, 12)) {
|
||||
return -ENOMEM;
|
||||
|
@ -152,6 +151,15 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
|
|||
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;
|
||||
|
||||
error_out_unreg:
|
||||
|
@ -317,6 +325,7 @@ int drm_put_dev(struct drm_device * dev)
|
|||
int drm_put_minor(struct drm_minor **minor_p)
|
||||
{
|
||||
struct drm_minor *minor = *minor_p;
|
||||
|
||||
DRM_DEBUG("release secondary minor %d\n", minor->index);
|
||||
|
||||
if (minor->type == DRM_MINOR_LEGACY)
|
||||
|
|
|
@ -184,7 +184,7 @@ int drm_sysfs_device_add(struct drm_minor *minor)
|
|||
err_out_files:
|
||||
if (i > 0)
|
||||
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);
|
||||
err_out:
|
||||
|
||||
|
|
|
@ -3,7 +3,12 @@
|
|||
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -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_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;
|
||||
|
||||
for (i = 0; i < 10000; i++) {
|
||||
ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
|
||||
for (i = 0; i < 100000; i++) {
|
||||
ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
|
||||
acthd = I915_READ(acthd_reg);
|
||||
ring->space = ring->head - (ring->tail + 8);
|
||||
if (ring->space < 0)
|
||||
ring->space += ring->Size;
|
||||
if (ring->space >= n)
|
||||
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)
|
||||
i = 0;
|
||||
if (acthd != last_acthd)
|
||||
i = 0;
|
||||
|
||||
last_head = ring->head;
|
||||
last_acthd = acthd;
|
||||
msleep_interruptible(10);
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
|
||||
|
||||
ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
|
||||
ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
|
||||
ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
|
||||
ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
|
||||
ring->space = ring->head - (ring->tail + 8);
|
||||
if (ring->space < 0)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -84,28 +140,19 @@ static int i915_dma_cleanup(struct drm_device * dev)
|
|||
* may not have been called from userspace and after dev_private
|
||||
* is freed, it's too late.
|
||||
*/
|
||||
if (dev->irq)
|
||||
if (dev->irq_enabled)
|
||||
drm_irq_uninstall(dev);
|
||||
|
||||
if (dev_priv->ring.virtual_start) {
|
||||
drm_core_ioremapfree(&dev_priv->ring.map, dev);
|
||||
dev_priv->ring.virtual_start = 0;
|
||||
dev_priv->ring.map.handle = 0;
|
||||
dev_priv->ring.virtual_start = NULL;
|
||||
dev_priv->ring.map.handle = NULL;
|
||||
dev_priv->ring.map.size = 0;
|
||||
}
|
||||
|
||||
if (dev_priv->status_page_dmah) {
|
||||
drm_pci_free(dev, dev_priv->status_page_dmah);
|
||||
dev_priv->status_page_dmah = NULL;
|
||||
/* 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);
|
||||
}
|
||||
/* Clear the HWS virtual address at teardown */
|
||||
if (I915_NEED_GFX_HWS(dev))
|
||||
i915_free_hws(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -121,34 +168,34 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
|
|||
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 *)
|
||||
((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);
|
||||
|
||||
dev_priv->ring.Start = init->ring_start;
|
||||
dev_priv->ring.End = init->ring_end;
|
||||
dev_priv->ring.Size = init->ring_size;
|
||||
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
|
||||
if (init->ring_size != 0) {
|
||||
if (dev_priv->ring.ring_obj != NULL) {
|
||||
i915_dma_cleanup(dev);
|
||||
DRM_ERROR("Client tried to initialize ringbuffer in "
|
||||
"GEM mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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;
|
||||
dev_priv->ring.Size = init->ring_size;
|
||||
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
|
||||
|
||||
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) {
|
||||
i915_dma_cleanup(dev);
|
||||
DRM_ERROR("can not ioremap virtual address for"
|
||||
" ring buffer\n");
|
||||
return -ENOMEM;
|
||||
drm_core_ioremap(&dev_priv->ring.map, dev);
|
||||
|
||||
if (dev_priv->ring.map.handle == NULL) {
|
||||
i915_dma_cleanup(dev);
|
||||
DRM_ERROR("can not ioremap virtual address for"
|
||||
" ring buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
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->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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -201,11 +224,6 @@ static int i915_dma_resume(struct drm_device * dev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!dev_priv->mmio_map) {
|
||||
DRM_ERROR("can not find mmio map!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dev_priv->ring.map.handle == NULL) {
|
||||
DRM_ERROR("can not ioremap virtual address for"
|
||||
" 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);
|
||||
|
||||
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
|
||||
I915_WRITE(0x02080, dev_priv->dma_status_page);
|
||||
I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
|
||||
DRM_DEBUG("Enabled hardware status page\n");
|
||||
|
||||
return 0;
|
||||
|
@ -367,9 +385,10 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int i915_emit_box(struct drm_device * dev,
|
||||
struct drm_clip_rect __user * boxes,
|
||||
int i, int DR1, int DR4)
|
||||
int
|
||||
i915_emit_box(struct drm_device *dev,
|
||||
struct drm_clip_rect __user *boxes,
|
||||
int i, int DR1, int DR4)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
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;
|
||||
RING_LOCALS;
|
||||
|
||||
dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
|
||||
|
||||
dev_priv->counter++;
|
||||
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);
|
||||
OUT_RING(CMD_STORE_DWORD_IDX);
|
||||
OUT_RING(20);
|
||||
OUT_RING(MI_STORE_DWORD_INDEX);
|
||||
OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
|
||||
OUT_RING(dev_priv->counter);
|
||||
OUT_RING(0);
|
||||
ADVANCE_LP_RING();
|
||||
|
@ -486,7 +506,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (dev_priv->use_mi_batchbuffer_start) {
|
||||
if (!IS_I830(dev) && !IS_845G(dev)) {
|
||||
BEGIN_LP_RING(2);
|
||||
if (IS_I965G(dev)) {
|
||||
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;
|
||||
RING_LOCALS;
|
||||
|
||||
if (!dev_priv->sarea_priv)
|
||||
return -EINVAL;
|
||||
|
||||
DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
|
||||
__func__,
|
||||
dev_priv->current_page,
|
||||
|
@ -524,7 +547,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
|
|||
i915_kernel_lost_context(dev);
|
||||
|
||||
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);
|
||||
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++;
|
||||
|
||||
BEGIN_LP_RING(4);
|
||||
OUT_RING(CMD_STORE_DWORD_IDX);
|
||||
OUT_RING(20);
|
||||
OUT_RING(MI_STORE_DWORD_INDEX);
|
||||
OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
|
||||
OUT_RING(dev_priv->counter);
|
||||
OUT_RING(0);
|
||||
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,
|
||||
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,
|
||||
|
@ -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",
|
||||
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,
|
||||
batch->num_cliprects *
|
||||
sizeof(struct drm_clip_rect)))
|
||||
return -EFAULT;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
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 &&
|
||||
DRM_VERIFYAREA_READ(cmdbuf->cliprects,
|
||||
|
@ -629,24 +661,33 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
|
|||
return -EFAULT;
|
||||
}
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = i915_dispatch_cmdbuffer(dev, cmdbuf);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
if (ret) {
|
||||
DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
sarea_priv->last_dispatch = (int)hw_status[5];
|
||||
if (sarea_priv)
|
||||
sarea_priv->last_dispatch = (int)hw_status[5];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_flip_bufs(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
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,
|
||||
|
@ -663,7 +704,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
|
|||
|
||||
switch (param->param) {
|
||||
case I915_PARAM_IRQ_ACTIVE:
|
||||
value = dev->irq ? 1 : 0;
|
||||
value = dev->pdev->irq ? 1 : 0;
|
||||
break;
|
||||
case I915_PARAM_ALLOW_BATCHBUFFER:
|
||||
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:
|
||||
value = READ_BREADCRUMB(dev_priv);
|
||||
break;
|
||||
case I915_PARAM_CHIPSET_ID:
|
||||
value = dev->pci_device;
|
||||
break;
|
||||
case I915_PARAM_HAS_GEM:
|
||||
value = 1;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Unknown parameter %d\n", param->param);
|
||||
return -EINVAL;
|
||||
|
@ -697,8 +744,6 @@ static int i915_setparam(struct drm_device *dev, void *data,
|
|||
|
||||
switch (param->param) {
|
||||
case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
|
||||
if (!IS_I965G(dev))
|
||||
dev_priv->use_mi_batchbuffer_start = param->value;
|
||||
break;
|
||||
case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
|
||||
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;
|
||||
|
||||
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
|
||||
I915_WRITE(0x02080, dev_priv->status_gfx_addr);
|
||||
DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n",
|
||||
I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
|
||||
DRM_DEBUG("load hws HWS_PGA with gfx mem 0x%x\n",
|
||||
dev_priv->status_gfx_addr);
|
||||
DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page);
|
||||
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));
|
||||
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
dev_priv->dev = dev;
|
||||
|
||||
/* Add register map (needed for suspend/resume) */
|
||||
base = drm_get_resource_start(dev, mmio_bar);
|
||||
size = drm_get_resource_len(dev, mmio_bar);
|
||||
|
||||
ret = drm_addmap(dev, base, size, _DRM_REGISTERS,
|
||||
_DRM_KERNEL | _DRM_DRIVER,
|
||||
&dev_priv->mmio_map);
|
||||
dev_priv->regs = ioremap(base, size);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -791,8 +860,15 @@ int i915_driver_unload(struct drm_device *dev)
|
|||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (dev_priv->mmio_map)
|
||||
drm_rmmap(dev, dev_priv->mmio_map);
|
||||
if (dev->pdev->msi_enabled)
|
||||
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_MEM_DRIVER);
|
||||
|
@ -800,6 +876,25 @@ int i915_driver_unload(struct drm_device *dev)
|
|||
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)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
|
@ -807,6 +902,8 @@ void i915_driver_lastclose(struct drm_device * dev)
|
|||
if (!dev_priv)
|
||||
return;
|
||||
|
||||
i915_gem_lastclose(dev);
|
||||
|
||||
if (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);
|
||||
}
|
||||
|
||||
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[] = {
|
||||
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),
|
||||
|
@ -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_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_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);
|
||||
|
|
|
@ -38,211 +38,9 @@ static struct pci_device_id pciidlist[] = {
|
|||
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)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int i;
|
||||
|
||||
if (!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;
|
||||
|
||||
pci_save_state(dev->pdev);
|
||||
pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
|
||||
|
||||
/* Display arbitration control */
|
||||
dev_priv->saveDSPARB = I915_READ(DSPARB);
|
||||
i915_save_state(dev);
|
||||
|
||||
/* 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->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);
|
||||
intel_opregion_free(dev);
|
||||
|
||||
if (state.event == PM_EVENT_SUSPEND) {
|
||||
/* 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)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int i;
|
||||
|
||||
pci_set_power_state(dev->pdev, PCI_D0);
|
||||
pci_restore_state(dev->pdev);
|
||||
if (pci_enable_device(dev->pdev))
|
||||
return -1;
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
intel_opregion_init(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -541,17 +87,19 @@ static struct drm_driver driver = {
|
|||
*/
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/
|
||||
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL |
|
||||
DRIVER_IRQ_VBL2,
|
||||
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM,
|
||||
.load = i915_driver_load,
|
||||
.unload = i915_driver_unload,
|
||||
.open = i915_driver_open,
|
||||
.lastclose = i915_driver_lastclose,
|
||||
.preclose = i915_driver_preclose,
|
||||
.postclose = i915_driver_postclose,
|
||||
.suspend = i915_suspend,
|
||||
.resume = i915_resume,
|
||||
.device_is_agp = i915_driver_device_is_agp,
|
||||
.vblank_wait = i915_driver_vblank_wait,
|
||||
.vblank_wait2 = i915_driver_vblank_wait2,
|
||||
.get_vblank_counter = i915_get_vblank_counter,
|
||||
.enable_vblank = i915_enable_vblank,
|
||||
.disable_vblank = i915_disable_vblank,
|
||||
.irq_preinstall = i915_driver_irq_preinstall,
|
||||
.irq_postinstall = i915_driver_irq_postinstall,
|
||||
.irq_uninstall = i915_driver_irq_uninstall,
|
||||
|
@ -559,6 +107,10 @@ static struct drm_driver driver = {
|
|||
.reclaim_buffers = drm_core_reclaim_buffers,
|
||||
.get_map_ofs = drm_core_get_map_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,
|
||||
.fops = {
|
||||
.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_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)
|
||||
|
||||
/** 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.
|
||||
*
|
||||
|
@ -48,8 +128,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
|
|||
unsigned long irqflags;
|
||||
struct list_head *list, *tmp, hits, *hit;
|
||||
int nhits, nrects, slice[2], upper[2], lower[2], i;
|
||||
unsigned counter[2] = { atomic_read(&dev->vbl_received),
|
||||
atomic_read(&dev->vbl_received2) };
|
||||
unsigned counter[2];
|
||||
struct drm_drawable_info *drw;
|
||||
drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
|
||||
u32 cpp = dev_priv->cpp;
|
||||
|
@ -71,6 +150,9 @@ static void i915_vblank_tasklet(struct drm_device *dev)
|
|||
src_pitch >>= 2;
|
||||
}
|
||||
|
||||
counter[0] = drm_vblank_count(dev, 0);
|
||||
counter[1] = drm_vblank_count(dev, 1);
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
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) {
|
||||
drm_i915_vbl_swap_t *vbl_swap =
|
||||
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;
|
||||
|
||||
list_del(list);
|
||||
dev_priv->swaps_pending--;
|
||||
drm_vblank_put(dev, pipe);
|
||||
|
||||
spin_unlock(&dev_priv->swaps_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 =
|
||||
list_entry(hit, drm_i915_vbl_swap_t, head);
|
||||
struct drm_clip_rect *rect;
|
||||
int num_rects, pipe;
|
||||
int num_rects, plane;
|
||||
unsigned short top, bottom;
|
||||
|
||||
drw = drm_get_drawable_info(dev, swap_hit->drw_id);
|
||||
|
@ -190,9 +274,9 @@ static void i915_vblank_tasklet(struct drm_device *dev)
|
|||
continue;
|
||||
|
||||
rect = drw->rects;
|
||||
pipe = swap_hit->pipe;
|
||||
top = upper[pipe];
|
||||
bottom = lower[pipe];
|
||||
plane = swap_hit->plane;
|
||||
top = upper[plane];
|
||||
bottom = lower[plane];
|
||||
|
||||
for (num_rects = drw->num_rects; num_rects--; rect++) {
|
||||
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)
|
||||
{
|
||||
struct drm_device *dev = (struct drm_device *) arg;
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
u16 temp;
|
||||
u32 iir;
|
||||
u32 pipea_stats, pipeb_stats;
|
||||
int vblank = 0;
|
||||
|
||||
pipea_stats = I915_READ(I915REG_PIPEASTAT);
|
||||
pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
|
||||
atomic_inc(&dev_priv->irq_received);
|
||||
|
||||
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);
|
||||
|
||||
DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
|
||||
|
||||
if (temp == 0)
|
||||
if (iir == 0) {
|
||||
if (dev->pdev->msi_enabled) {
|
||||
I915_WRITE(IMR, dev_priv->irq_mask_reg);
|
||||
(void) I915_READ(IMR);
|
||||
}
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
|
||||
(void) I915_READ16(I915REG_INT_IDENTITY_R);
|
||||
DRM_READMEMORYBARRIER();
|
||||
/*
|
||||
* Clear the PIPE(A|B)STAT regs before the IIR otherwise
|
||||
* 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);
|
||||
}
|
||||
|
||||
if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
|
||||
int vblank_pipe = dev_priv->vblank_pipe;
|
||||
if (iir & I915_ASLE_INTERRUPT)
|
||||
opregion_asle_intr(dev);
|
||||
|
||||
if ((vblank_pipe &
|
||||
(DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
|
||||
== (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)
|
||||
if (vblank && dev_priv->swaps_pending > 0) {
|
||||
if (dev_priv->ring.ring_obj == NULL)
|
||||
drm_locked_tasklet(dev, i915_vblank_tasklet);
|
||||
I915_WRITE(I915REG_PIPEASTAT,
|
||||
pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
|
||||
I915_VBLANK_CLEAR);
|
||||
I915_WRITE(I915REG_PIPEBSTAT,
|
||||
pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE|
|
||||
I915_VBLANK_CLEAR);
|
||||
else
|
||||
schedule_work(&dev_priv->mm.vblank_work);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
@ -298,23 +460,45 @@ static int i915_emit_irq(struct drm_device * dev)
|
|||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
|
||||
|
||||
dev_priv->counter++;
|
||||
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);
|
||||
OUT_RING(CMD_STORE_DWORD_IDX);
|
||||
OUT_RING(20);
|
||||
OUT_RING(MI_STORE_DWORD_INDEX);
|
||||
OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
|
||||
OUT_RING(dev_priv->counter);
|
||||
OUT_RING(0);
|
||||
OUT_RING(0);
|
||||
OUT_RING(GFX_OP_USER_INTERRUPT);
|
||||
OUT_RING(MI_USER_INTERRUPT);
|
||||
ADVANCE_LP_RING();
|
||||
|
||||
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)
|
||||
{
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
READ_BREADCRUMB(dev_priv) >= irq_nr);
|
||||
i915_user_irq_put(dev);
|
||||
|
||||
if (ret == -EBUSY) {
|
||||
DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
|
||||
READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
|
||||
}
|
||||
|
||||
dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
if (dev_priv->sarea_priv)
|
||||
dev_priv->sarea_priv->last_dispatch =
|
||||
READ_BREADCRUMB(dev_priv);
|
||||
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
int result;
|
||||
|
||||
LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||
|
||||
if (!dev_priv) {
|
||||
DRM_ERROR("called with no initialization\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
result = i915_emit_irq(dev);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
u16 flag;
|
||||
int pipe = i915_get_pipe(dev, plane);
|
||||
u32 pipestat_reg = 0;
|
||||
u32 pipestat;
|
||||
|
||||
flag = 0;
|
||||
if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
|
||||
flag |= VSYNC_PIPEA_FLAG;
|
||||
if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
|
||||
flag |= VSYNC_PIPEB_FLAG;
|
||||
switch (pipe) {
|
||||
case 0:
|
||||
pipestat_reg = PIPEASTAT;
|
||||
i915_enable_irq(dev_priv, I915_DISPLAY_PIPE_A_EVENT_INTERRUPT);
|
||||
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
|
||||
|
@ -434,22 +654,12 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data,
|
|||
struct drm_file *file_priv)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
drm_i915_vblank_pipe_t *pipe = data;
|
||||
|
||||
if (!dev_priv) {
|
||||
DRM_ERROR("called with no initialization\n");
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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_vblank_pipe_t *pipe = data;
|
||||
u16 flag;
|
||||
|
||||
if (!dev_priv) {
|
||||
DRM_ERROR("called with no initialization\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
flag = I915_READ(I915REG_INT_ENABLE_R);
|
||||
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;
|
||||
pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
|
||||
|
||||
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_vblank_swap_t *swap = data;
|
||||
drm_i915_vbl_swap_t *vbl_swap;
|
||||
unsigned int pipe, seqtype, curseq;
|
||||
unsigned int pipe, seqtype, curseq, plane;
|
||||
unsigned long irqflags;
|
||||
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__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -504,7 +709,8 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
|
|||
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);
|
||||
|
||||
|
@ -523,7 +729,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
|
|||
|
||||
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)
|
||||
swap->sequence += curseq;
|
||||
|
@ -533,6 +746,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
|
|||
swap->sequence = curseq + 1;
|
||||
} else {
|
||||
DRM_DEBUG("Missed target sequence\n");
|
||||
drm_vblank_put(dev, pipe);
|
||||
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);
|
||||
|
||||
if (vbl_swap->drw_id == swap->drawable &&
|
||||
vbl_swap->pipe == pipe &&
|
||||
vbl_swap->plane == plane &&
|
||||
vbl_swap->sequence == swap->sequence) {
|
||||
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
|
||||
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) {
|
||||
DRM_DEBUG("Too many swaps queued\n");
|
||||
drm_vblank_put(dev, pipe);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
|
@ -562,13 +777,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
|
|||
|
||||
if (!vbl_swap) {
|
||||
DRM_ERROR("Failed to allocate memory to queue swap\n");
|
||||
drm_vblank_put(dev, pipe);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
vbl_swap->drw_id = swap->drawable;
|
||||
vbl_swap->pipe = pipe;
|
||||
vbl_swap->plane = plane;
|
||||
vbl_swap->sequence = swap->sequence;
|
||||
|
||||
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;
|
||||
|
||||
I915_WRITE16(I915REG_HWSTAM, 0xfffe);
|
||||
I915_WRITE16(I915REG_INT_MASK_R, 0x0);
|
||||
I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
|
||||
I915_WRITE(HWSTAM, 0xeffe);
|
||||
I915_WRITE(IMR, 0xffffffff);
|
||||
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;
|
||||
int ret, num_pipes = 2;
|
||||
|
||||
spin_lock_init(&dev_priv->swaps_lock);
|
||||
INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
|
||||
dev_priv->swaps_pending = 0;
|
||||
|
||||
if (!dev_priv->vblank_pipe)
|
||||
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
|
||||
i915_enable_interrupt(dev);
|
||||
/* Set initial unmasked IRQs to just the selected vblank pipes. */
|
||||
dev_priv->irq_mask_reg = ~0;
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void i915_driver_irq_uninstall(struct drm_device * dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
u16 temp;
|
||||
u32 temp;
|
||||
|
||||
if (!dev_priv)
|
||||
return;
|
||||
|
||||
I915_WRITE16(I915REG_HWSTAM, 0xffff);
|
||||
I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
|
||||
I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
|
||||
dev_priv->vblank_pipe = 0;
|
||||
|
||||
temp = I915_READ16(I915REG_INT_IDENTITY_R);
|
||||
I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
|
||||
I915_WRITE(HWSTAM, 0xffffffff);
|
||||
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 = {
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA |
|
||||
DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
|
||||
DRIVER_IRQ_VBL,
|
||||
DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
|
||||
.dev_priv_size = sizeof(drm_mga_buf_priv_t),
|
||||
.load = mga_driver_load,
|
||||
.unload = mga_driver_unload,
|
||||
.lastclose = mga_driver_lastclose,
|
||||
.dma_quiescent = mga_driver_dma_quiescent,
|
||||
.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_postinstall = mga_driver_irq_postinstall,
|
||||
.irq_uninstall = mga_driver_irq_uninstall,
|
||||
|
@ -64,20 +65,20 @@ static struct drm_driver driver = {
|
|||
.ioctls = mga_ioctls,
|
||||
.dma_ioctl = mga_dma_buffers,
|
||||
.fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.ioctl = drm_ioctl,
|
||||
.mmap = drm_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.ioctl = drm_ioctl,
|
||||
.mmap = drm_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = mga_compat_ioctl,
|
||||
.compat_ioctl = mga_compat_ioctl,
|
||||
#endif
|
||||
},
|
||||
},
|
||||
.pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
},
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
|
|
|
@ -120,6 +120,7 @@ typedef struct drm_mga_private {
|
|||
u32 clear_cmd;
|
||||
u32 maccess;
|
||||
|
||||
atomic_t vbl_received; /**< Number of vblanks received. */
|
||||
wait_queue_head_t fence_queue;
|
||||
atomic_t last_fence_retired;
|
||||
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);
|
||||
|
||||
/* 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_vblank_wait(struct drm_device * dev, unsigned int *sequence);
|
||||
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_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 long mga_compat_ioctl(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* mga_irq.c -- IRQ handling for radeon -*- linux-c -*-
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
|
||||
*
|
||||
* The Weather Channel (TM) funded Tungsten Graphics to develop the
|
||||
|
@ -35,6 +36,18 @@
|
|||
#include "mga_drm.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)
|
||||
{
|
||||
struct drm_device *dev = (struct drm_device *) arg;
|
||||
|
@ -47,9 +60,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
|
|||
/* VBLANK interrupt */
|
||||
if (status & MGA_VLINEPEN) {
|
||||
MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR);
|
||||
atomic_inc(&dev->vbl_received);
|
||||
DRM_WAKEUP(&dev->vbl_queue);
|
||||
drm_vbl_send_signals(dev);
|
||||
atomic_inc(&dev_priv->vbl_received);
|
||||
drm_handle_vblank(dev, 0);
|
||||
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_end = MGA_READ(MGA_PRIMEND);
|
||||
|
||||
|
||||
MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR);
|
||||
|
||||
/* In addition to clearing the interrupt-pending bit, we
|
||||
|
@ -72,28 +85,39 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
|
|||
handled = 1;
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
if (handled)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
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;
|
||||
int ret = 0;
|
||||
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
|
||||
|
||||
/* Assume that the user has missed the current sequence number
|
||||
* by about a day rather than she wants to wait for years
|
||||
* using vertical blanks...
|
||||
if (crtc != 0) {
|
||||
DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
|
||||
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,
|
||||
(((cur_vblank = atomic_read(&dev->vbl_received))
|
||||
- *sequence) <= (1 << 23)));
|
||||
|
||||
*sequence = cur_vblank;
|
||||
|
||||
return ret;
|
||||
/* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
int ret;
|
||||
|
||||
ret = drm_vblank_init(dev, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
DRM_INIT_WAITQUEUE(&dev_priv->fence_queue);
|
||||
|
||||
/* Turn on vertical blank interrupt and soft trap interrupt. */
|
||||
MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
|
||||
/* Turn on soft trap interrupt. Vertical blank interrupts are enabled
|
||||
* in mga_enable_vblank.
|
||||
*/
|
||||
MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
case MGA_PARAM_IRQ_NR:
|
||||
value = dev->irq;
|
||||
value = drm_dev_to_irq(dev);
|
||||
break;
|
||||
case MGA_PARAM_CARD_TYPE:
|
||||
value = dev_priv->chipset;
|
||||
|
|
|
@ -43,12 +43,13 @@ static struct pci_device_id pciidlist[] = {
|
|||
static struct drm_driver driver = {
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
|
||||
DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
|
||||
DRIVER_IRQ_VBL,
|
||||
DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
|
||||
.dev_priv_size = sizeof(drm_r128_buf_priv_t),
|
||||
.preclose = r128_driver_preclose,
|
||||
.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_postinstall = r128_driver_irq_postinstall,
|
||||
.irq_uninstall = r128_driver_irq_uninstall,
|
||||
|
@ -59,21 +60,20 @@ static struct drm_driver driver = {
|
|||
.ioctls = r128_ioctls,
|
||||
.dma_ioctl = r128_cce_buffers,
|
||||
.fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.ioctl = drm_ioctl,
|
||||
.mmap = drm_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.ioctl = drm_ioctl,
|
||||
.mmap = drm_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = r128_compat_ioctl,
|
||||
.compat_ioctl = r128_compat_ioctl,
|
||||
#endif
|
||||
},
|
||||
|
||||
.pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
},
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
|
@ -87,6 +87,7 @@ static struct drm_driver driver = {
|
|||
static int __init r128_init(void)
|
||||
{
|
||||
driver.num_ioctls = r128_max_ioctl;
|
||||
|
||||
return drm_init(&driver);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
* Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* Kevin E. Martin <martin@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__
|
||||
|
@ -97,6 +97,8 @@ typedef struct drm_r128_private {
|
|||
u32 crtc_offset;
|
||||
u32 crtc_offset_cntl;
|
||||
|
||||
atomic_t vbl_received;
|
||||
|
||||
u32 color_fmt;
|
||||
unsigned int front_offset;
|
||||
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_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 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_lastclose(struct drm_device * dev);
|
||||
extern void r128_driver_preclose(struct drm_device * dev,
|
||||
|
|
|
@ -35,6 +35,16 @@
|
|||
#include "r128_drm.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)
|
||||
{
|
||||
struct drm_device *dev = (struct drm_device *) arg;
|
||||
|
@ -46,30 +56,38 @@ irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
|
|||
/* VBLANK interrupt */
|
||||
if (status & R128_CRTC_VBLANK_INT) {
|
||||
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
|
||||
atomic_inc(&dev->vbl_received);
|
||||
DRM_WAKEUP(&dev->vbl_queue);
|
||||
drm_vbl_send_signals(dev);
|
||||
atomic_inc(&dev_priv->vbl_received);
|
||||
drm_handle_vblank(dev, 0);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
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;
|
||||
int ret = 0;
|
||||
drm_r128_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
/* Assume that the user has missed the current sequence number
|
||||
* by about a day rather than she wants to wait for years
|
||||
* using vertical blanks...
|
||||
if (crtc != 0) {
|
||||
DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
|
||||
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)
|
||||
|
@ -82,12 +100,9 @@ void r128_driver_irq_preinstall(struct drm_device * dev)
|
|||
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;
|
||||
|
||||
/* Turn on VBL interrupt */
|
||||
R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
|
||||
return drm_vblank_init(dev, 1);
|
||||
}
|
||||
|
||||
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) {
|
||||
case R128_PARAM_IRQ_NR:
|
||||
value = dev->irq;
|
||||
value = drm_dev_to_irq(dev);
|
||||
break;
|
||||
default:
|
||||
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)
|
||||
{
|
||||
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);
|
||||
else
|
||||
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)
|
||||
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);
|
||||
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
|
||||
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)
|
||||
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);
|
||||
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
|
||||
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)
|
||||
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);
|
||||
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
|
||||
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) {
|
||||
R500_WRITE_MCIND(RV515_MC_AGP_BASE, agp_base_lo);
|
||||
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_2, agp_base_hi);
|
||||
} 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_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(RS480_AGP_BASE_2, 0);
|
||||
RADEON_WRITE(RS480_AGP_BASE_2, agp_base_hi);
|
||||
} else {
|
||||
RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo);
|
||||
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_RV350) ||
|
||||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV380) ||
|
||||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
|
||||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
|
||||
DRM_INFO("Loading R300 Microcode\n");
|
||||
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]);
|
||||
}
|
||||
} 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)) {
|
||||
DRM_INFO("Loading R400 Microcode\n");
|
||||
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,
|
||||
R420_cp_microcode[i][0]);
|
||||
}
|
||||
} else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
|
||||
DRM_INFO("Loading RS690 Microcode\n");
|
||||
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
|
||||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
|
||||
DRM_INFO("Loading RS690/RS740 Microcode\n");
|
||||
for (i = 0; i < 256; i++) {
|
||||
RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
|
||||
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);
|
||||
#endif
|
||||
|
||||
/* Start with assuming that writeback doesn't work */
|
||||
dev_priv->writeback_works = 0;
|
||||
|
||||
/* Initialize the scratch register pointer. This will cause
|
||||
* 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);
|
||||
|
||||
/* Turn on bus mastering */
|
||||
tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
|
||||
RADEON_WRITE(RADEON_BUS_CNTL, tmp);
|
||||
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
|
||||
((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;
|
||||
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;
|
||||
|
||||
/* 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
|
||||
* 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);
|
||||
|
||||
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 |
|
||||
RS690_BLOCK_GFX_D3_EN));
|
||||
else
|
||||
|
@ -812,6 +833,7 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
|
|||
u32 tmp;
|
||||
|
||||
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
|
||||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740) ||
|
||||
(dev_priv->flags & RADEON_IS_IGPGART)) {
|
||||
radeon_set_igpgart(dev_priv, on);
|
||||
return;
|
||||
|
@ -1286,7 +1308,7 @@ static int radeon_do_resume_cp(struct drm_device * dev)
|
|||
radeon_cp_init_ring_buffer(dev, dev_priv);
|
||||
|
||||
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");
|
||||
|
||||
|
@ -1708,6 +1730,7 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
case CHIP_R300:
|
||||
case CHIP_R350:
|
||||
case CHIP_R420:
|
||||
case CHIP_R423:
|
||||
case CHIP_RV410:
|
||||
case CHIP_RV515:
|
||||
case CHIP_R520:
|
||||
|
|
|
@ -52,6 +52,28 @@ static int dri_library_name(struct drm_device *dev, char *buf)
|
|||
"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[] = {
|
||||
radeon_PCI_IDS
|
||||
};
|
||||
|
@ -59,8 +81,7 @@ static struct pci_device_id pciidlist[] = {
|
|||
static struct drm_driver driver = {
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
|
||||
DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED |
|
||||
DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2,
|
||||
DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED,
|
||||
.dev_priv_size = sizeof(drm_radeon_buf_priv_t),
|
||||
.load = radeon_driver_load,
|
||||
.firstopen = radeon_driver_firstopen,
|
||||
|
@ -69,8 +90,11 @@ static struct drm_driver driver = {
|
|||
.postclose = radeon_driver_postclose,
|
||||
.lastclose = radeon_driver_lastclose,
|
||||
.unload = radeon_driver_unload,
|
||||
.vblank_wait = radeon_driver_vblank_wait,
|
||||
.vblank_wait2 = radeon_driver_vblank_wait2,
|
||||
.suspend = radeon_suspend,
|
||||
.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,
|
||||
.irq_preinstall = radeon_driver_irq_preinstall,
|
||||
.irq_postinstall = radeon_driver_irq_postinstall,
|
||||
|
|
|
@ -122,9 +122,12 @@ enum radeon_family {
|
|||
CHIP_RV350,
|
||||
CHIP_RV380,
|
||||
CHIP_R420,
|
||||
CHIP_R423,
|
||||
CHIP_RV410,
|
||||
CHIP_RS400,
|
||||
CHIP_RS480,
|
||||
CHIP_RS690,
|
||||
CHIP_RS740,
|
||||
CHIP_RV515,
|
||||
CHIP_R520,
|
||||
CHIP_RV530,
|
||||
|
@ -378,17 +381,17 @@ extern void radeon_mem_release(struct drm_file *file_priv,
|
|||
struct mem_block *heap);
|
||||
|
||||
/* 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_wait(struct drm_device *dev, void *data, struct drm_file *file_priv);
|
||||
|
||||
extern void radeon_do_release(struct drm_device * dev);
|
||||
extern int radeon_driver_vblank_wait(struct drm_device * dev,
|
||||
unsigned int *sequence);
|
||||
extern int radeon_driver_vblank_wait2(struct drm_device * dev,
|
||||
unsigned int *sequence);
|
||||
extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc);
|
||||
extern int radeon_enable_vblank(struct drm_device *dev, int crtc);
|
||||
extern void radeon_disable_vblank(struct drm_device *dev, int crtc);
|
||||
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_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_enable_interrupt(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_unload(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_postclose(struct drm_device * dev, struct drm_file * filp);
|
||||
extern void radeon_driver_preclose(struct drm_device *dev,
|
||||
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 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,
|
||||
unsigned long arg);
|
||||
|
||||
/* r300_cmdbuf.c */
|
||||
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,
|
||||
drm_radeon_kcmd_buffer_t * cmdbuf);
|
||||
drm_radeon_kcmd_buffer_t *cmdbuf);
|
||||
|
||||
/* 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_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
|
||||
/* r1xx, r2xx, r300, r(v)350, r420/r481, rs480 */
|
||||
# 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_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_ACK (1 << 25)
|
||||
# define RADEON_SW_INT_FIRE (1 << 26)
|
||||
# define R500_DISPLAY_INT_STATUS (1 << 0)
|
||||
|
||||
#define RADEON_HOST_PATH_CNTL 0x0130
|
||||
# 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_PCIGART_TRANSLATE_EN (1 << 0)
|
||||
# define RS480_MSI_REARM (1 << 3)
|
||||
#define RADEON_AIC_STAT 0x01d4
|
||||
#define RADEON_AIC_PT_BASE 0x01d8
|
||||
#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 RADEON_CRTC_CRNT_FRAME 0x0214
|
||||
#define RADEON_CRTC2_CRNT_FRAME 0x0314
|
||||
|
||||
#define R500_D1CRTC_STATUS 0x609c
|
||||
#define R500_D2CRTC_STATUS 0x689c
|
||||
#define R500_CRTC_V_BLANK (1<<0)
|
||||
|
@ -1200,7 +1234,8 @@ do { \
|
|||
|
||||
#define IGP_WRITE_MCIND(addr, val) \
|
||||
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); \
|
||||
else \
|
||||
RS480_WRITE_MCIND(addr, val); \
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
*
|
||||
* Authors:
|
||||
* Keith Whitwell <keith@tungstengraphics.com>
|
||||
* Michel Dänzer <michel@daenzer.net>
|
||||
* Michel D<EFBFBD>zer <michel@daenzer.net>
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
|
@ -35,12 +35,128 @@
|
|||
#include "radeon_drm.h"
|
||||
#include "radeon_drv.h"
|
||||
|
||||
static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv,
|
||||
u32 mask)
|
||||
void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state)
|
||||
{
|
||||
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)
|
||||
RADEON_WRITE(RADEON_GEN_INT_STATUS, 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->dev_private;
|
||||
u32 stat;
|
||||
u32 r500_disp_int;
|
||||
|
||||
/* Only consider the bits we're interested in - others could be used
|
||||
* outside the DRM
|
||||
*/
|
||||
stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
|
||||
RADEON_CRTC_VBLANK_STAT |
|
||||
RADEON_CRTC2_VBLANK_STAT));
|
||||
stat = radeon_acknowledge_irqs(dev_priv, &r500_disp_int);
|
||||
if (!stat)
|
||||
return IRQ_NONE;
|
||||
|
||||
stat &= dev_priv->irq_enable_reg;
|
||||
|
||||
/* SW interrupt */
|
||||
if (stat & RADEON_SW_INT_TEST) {
|
||||
if (stat & RADEON_SW_INT_TEST)
|
||||
DRM_WAKEUP(&dev_priv->swi_queue);
|
||||
}
|
||||
|
||||
/* VBLANK interrupt */
|
||||
if (stat & (RADEON_CRTC_VBLANK_STAT|RADEON_CRTC2_VBLANK_STAT)) {
|
||||
int vblank_crtc = dev_priv->vblank_crtc;
|
||||
|
||||
if ((vblank_crtc &
|
||||
(DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) ==
|
||||
(DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) {
|
||||
if (stat & RADEON_CRTC_VBLANK_STAT)
|
||||
atomic_inc(&dev->vbl_received);
|
||||
if (stat & RADEON_CRTC2_VBLANK_STAT)
|
||||
atomic_inc(&dev->vbl_received2);
|
||||
} 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);
|
||||
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
|
||||
if (r500_disp_int & R500_D1_VBLANK_INTERRUPT)
|
||||
drm_handle_vblank(dev, 0);
|
||||
if (r500_disp_int & R500_D2_VBLANK_INTERRUPT)
|
||||
drm_handle_vblank(dev, 1);
|
||||
} else {
|
||||
if (stat & RADEON_CRTC_VBLANK_STAT)
|
||||
drm_handle_vblank(dev, 0);
|
||||
if (stat & RADEON_CRTC2_VBLANK_STAT)
|
||||
drm_handle_vblank(dev, 1);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -144,54 +249,31 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int radeon_driver_vblank_do_wait(struct drm_device * dev,
|
||||
unsigned int *sequence, int crtc)
|
||||
u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
|
||||
{
|
||||
drm_radeon_private_t *dev_priv =
|
||||
(drm_radeon_private_t *) dev->dev_private;
|
||||
unsigned int cur_vblank;
|
||||
int ret = 0;
|
||||
int ack = 0;
|
||||
atomic_t *counter;
|
||||
drm_radeon_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
if (!dev_priv) {
|
||||
DRM_ERROR("called with no initialization\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (crtc == DRM_RADEON_VBLANK_CRTC1) {
|
||||
counter = &dev->vbl_received;
|
||||
ack |= RADEON_CRTC_VBLANK_STAT;
|
||||
} else if (crtc == DRM_RADEON_VBLANK_CRTC2) {
|
||||
counter = &dev->vbl_received2;
|
||||
ack |= RADEON_CRTC2_VBLANK_STAT;
|
||||
} else
|
||||
if (crtc < 0 || crtc > 1) {
|
||||
DRM_ERROR("Invalid crtc %d\n", crtc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
radeon_acknowledge_irqs(dev_priv, ack);
|
||||
|
||||
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
|
||||
|
||||
/* Assume that the user has missed the current sequence number
|
||||
* by about a day rather than she wants to wait for years
|
||||
* using vertical blanks...
|
||||
*/
|
||||
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
|
||||
(((cur_vblank = atomic_read(counter))
|
||||
- *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);
|
||||
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
|
||||
if (crtc == 0)
|
||||
return RADEON_READ(R500_D1CRTC_FRAME_COUNT);
|
||||
else
|
||||
return RADEON_READ(R500_D2CRTC_FRAME_COUNT);
|
||||
} else {
|
||||
if (crtc == 0)
|
||||
return RADEON_READ(RADEON_CRTC_CRNT_FRAME);
|
||||
else
|
||||
return RADEON_READ(RADEON_CRTC2_CRNT_FRAME);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
void radeon_driver_irq_preinstall(struct drm_device * dev)
|
||||
{
|
||||
drm_radeon_private_t *dev_priv =
|
||||
(drm_radeon_private_t *) dev->dev_private;
|
||||
u32 dummy;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Clear bits if they're already high */
|
||||
radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
|
||||
RADEON_CRTC_VBLANK_STAT |
|
||||
RADEON_CRTC2_VBLANK_STAT));
|
||||
radeon_acknowledge_irqs(dev_priv, &dummy);
|
||||
}
|
||||
|
||||
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->dev_private;
|
||||
int ret;
|
||||
|
||||
atomic_set(&dev_priv->swi_emitted, 0);
|
||||
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)
|
||||
|
@ -285,6 +362,8 @@ void radeon_driver_irq_uninstall(struct drm_device * dev)
|
|||
|
||||
dev_priv->irq_enabled = 0;
|
||||
|
||||
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
|
||||
RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
|
||||
/* Disable *all* interrupts */
|
||||
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)
|
||||
{
|
||||
drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
|
||||
u32 flag;
|
||||
u32 value;
|
||||
|
||||
flag = RADEON_READ(RADEON_GEN_INT_CNTL);
|
||||
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;
|
||||
return dev_priv->vblank_crtc;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
dev_priv->vblank_crtc = (unsigned int)value;
|
||||
radeon_enable_interrupt(dev);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -2997,7 +2997,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
|
|||
value = GET_SCRATCH(2);
|
||||
break;
|
||||
case RADEON_PARAM_IRQ_NR:
|
||||
value = dev->irq;
|
||||
value = drm_dev_to_irq(dev);
|
||||
break;
|
||||
case RADEON_PARAM_GART_BASE:
|
||||
value = dev_priv->gart_vm_start;
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#define AGP_TYPE 1
|
||||
|
||||
|
||||
#if defined(CONFIG_FB_SIS)
|
||||
#if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
|
||||
/* fb management via fb device */
|
||||
|
||||
#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)
|
||||
return NULL;
|
||||
else
|
||||
return (void *)~req.offset;
|
||||
return (void *)(unsigned long)~req.offset;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#else /* CONFIG_FB_SIS */
|
||||
#else /* CONFIG_FB_SIS[_MODULE] */
|
||||
|
||||
#define SIS_MM_ALIGN_SHIFT 4
|
||||
#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)
|
||||
{
|
||||
|
@ -89,7 +89,7 @@ static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file
|
|||
int ret;
|
||||
|
||||
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;
|
||||
sman_mm.private = (void *)0xFFFFFFFF;
|
||||
|
|
|
@ -40,11 +40,13 @@ static struct pci_device_id pciidlist[] = {
|
|||
static struct drm_driver driver = {
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ |
|
||||
DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
|
||||
DRIVER_IRQ_SHARED,
|
||||
.load = via_driver_load,
|
||||
.unload = via_driver_unload,
|
||||
.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_postinstall = via_driver_irq_postinstall,
|
||||
.irq_uninstall = via_driver_irq_uninstall,
|
||||
|
@ -59,17 +61,17 @@ static struct drm_driver driver = {
|
|||
.get_reg_ofs = drm_core_get_reg_ofs,
|
||||
.ioctls = via_ioctls,
|
||||
.fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.ioctl = drm_ioctl,
|
||||
.mmap = drm_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
},
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.ioctl = drm_ioctl,
|
||||
.mmap = drm_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
},
|
||||
.pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
},
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
|
|
|
@ -75,6 +75,7 @@ typedef struct drm_via_private {
|
|||
struct timeval last_vblank;
|
||||
int last_vblank_valid;
|
||||
unsigned usec_per_vblank;
|
||||
atomic_t vbl_received;
|
||||
drm_via_state_t hc_state;
|
||||
char pci_buf[VIA_PCI_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_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 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 int via_dma_cleanup(struct drm_device * dev);
|
||||
extern void via_init_command_verifier(void);
|
||||
extern int via_driver_dma_quiescent(struct drm_device * dev);
|
||||
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_release_futex(drm_via_private_t * dev_priv, int context);
|
||||
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_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_dmablit_handler(struct drm_device *dev, int engine, int from_irq);
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
#define VIA_REG_INTERRUPT 0x200
|
||||
|
||||
/* 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_PENDING (1 << 3)
|
||||
#define VIA_IRQ_HQV0_ENABLE (1 << 11)
|
||||
|
@ -68,16 +68,15 @@
|
|||
|
||||
static maskarray_t via_pro_group_a_irqs[] = {
|
||||
{VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010,
|
||||
0x00000000},
|
||||
0x00000000 },
|
||||
{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_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
|
||||
{VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
|
||||
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
|
||||
};
|
||||
static int via_num_pro_group_a =
|
||||
sizeof(via_pro_group_a_irqs) / sizeof(maskarray_t);
|
||||
static int via_num_pro_group_a = ARRAY_SIZE(via_pro_group_a_irqs);
|
||||
static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3};
|
||||
|
||||
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_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 unsigned time_diff(struct timeval *now, struct timeval *then)
|
||||
{
|
||||
return (now->tv_usec >= then->tv_usec) ?
|
||||
now->tv_usec - then->tv_usec :
|
||||
1000000 - (then->tv_usec - now->tv_usec);
|
||||
now->tv_usec - then->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)
|
||||
|
@ -108,23 +117,22 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
|
|||
|
||||
status = VIA_READ(VIA_REG_INTERRUPT);
|
||||
if (status & VIA_IRQ_VBLANK_PENDING) {
|
||||
atomic_inc(&dev->vbl_received);
|
||||
if (!(atomic_read(&dev->vbl_received) & 0x0F)) {
|
||||
atomic_inc(&dev_priv->vbl_received);
|
||||
if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) {
|
||||
do_gettimeofday(&cur_vblank);
|
||||
if (dev_priv->last_vblank_valid) {
|
||||
dev_priv->usec_per_vblank =
|
||||
time_diff(&cur_vblank,
|
||||
&dev_priv->last_vblank) >> 4;
|
||||
time_diff(&cur_vblank,
|
||||
&dev_priv->last_vblank) >> 4;
|
||||
}
|
||||
dev_priv->last_vblank = cur_vblank;
|
||||
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",
|
||||
dev_priv->usec_per_vblank);
|
||||
}
|
||||
DRM_WAKEUP(&dev->vbl_queue);
|
||||
drm_vbl_send_signals(dev);
|
||||
drm_handle_vblank(dev, 0);
|
||||
handled = 1;
|
||||
}
|
||||
|
||||
|
@ -145,6 +153,7 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
|
|||
/* Acknowlege interrupts */
|
||||
VIA_WRITE(VIA_REG_INTERRUPT, status);
|
||||
|
||||
|
||||
if (handled)
|
||||
return IRQ_HANDLED;
|
||||
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;
|
||||
unsigned int cur_vblank;
|
||||
int ret = 0;
|
||||
drm_via_private_t *dev_priv = dev->dev_private;
|
||||
u32 status;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
if (!dev_priv) {
|
||||
DRM_ERROR("called with no initialization\n");
|
||||
if (crtc != 0) {
|
||||
DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
|
||||
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
|
||||
* by about a day rather than she wants to wait for years
|
||||
* using vertical blanks...
|
||||
*/
|
||||
VIA_WRITE8(0x83d4, 0x11);
|
||||
VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
|
||||
|
||||
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
|
||||
(((cur_vblank = atomic_read(&dev->vbl_received)) -
|
||||
*sequence) <= (1 << 23)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sequence = cur_vblank;
|
||||
return ret;
|
||||
void via_disable_vblank(struct drm_device *dev, int crtc)
|
||||
{
|
||||
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
|
||||
|
@ -239,6 +251,7 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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;
|
||||
u32 status;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
if (dev_priv) {
|
||||
status = VIA_READ(VIA_REG_INTERRUPT);
|
||||
VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
|
||||
| dev_priv->irq_enable_mask);
|
||||
DRM_DEBUG("via_driver_irq_postinstall\n");
|
||||
if (!dev_priv)
|
||||
return -EINVAL;
|
||||
|
||||
/* 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);
|
||||
VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
|
||||
/* Some magic, oh for some data sheets ! */
|
||||
VIA_WRITE8(0x83d4, 0x11);
|
||||
VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
int force_sequence;
|
||||
|
||||
if (!dev->irq)
|
||||
return -EINVAL;
|
||||
|
||||
if (irqwait->request.irq >= dev_priv->num_irqs) {
|
||||
DRM_ERROR("Trying to wait on unknown irq %d\n",
|
||||
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) {
|
||||
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;
|
||||
case VIA_IRQ_ABSOLUTE:
|
||||
break;
|
||||
|
|
|
@ -93,8 +93,7 @@ int via_final_context(struct drm_device *dev, int context)
|
|||
/* Last context, perform cleanup */
|
||||
if (dev->ctx_count == 1 && dev->dev_private) {
|
||||
DRM_DEBUG("Last Context\n");
|
||||
if (dev->irq)
|
||||
drm_irq_uninstall(dev);
|
||||
drm_irq_uninstall(dev);
|
||||
via_cleanup_futex(dev_priv);
|
||||
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