Merge branch 'perf/urgent' into perf/core, to pick up fixes

Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Ingo Molnar 2014-04-25 10:04:22 +02:00
commit 42ebd27bcb
864 changed files with 6803 additions and 26151 deletions

View File

@ -99,6 +99,7 @@ Sachin P Sant <ssant@in.ibm.com>
Sam Ravnborg <sam@mars.ravnborg.org>
Sascha Hauer <s.hauer@pengutronix.de>
S.Çağlar Onur <caglar@pardus.org.tr>
Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com>
Simon Kelley <simon@thekelleys.org.uk>
Stéphane Witzmann <stephane.witzmann@ubpmes.univ-bpclermont.fr>
Stephen Hemminger <shemminger@osdl.org>

View File

@ -276,7 +276,7 @@ X!Isound/sound_firmware.c
</para>
<sect1><title>Frame Buffer Memory</title>
!Edrivers/video/fbmem.c
!Edrivers/video/fbdev/core/fbmem.c
</sect1>
<!--
<sect1><title>Frame Buffer Console</title>
@ -284,7 +284,7 @@ X!Edrivers/video/console/fbcon.c
</sect1>
-->
<sect1><title>Frame Buffer Colormap</title>
!Edrivers/video/fbcmap.c
!Edrivers/video/fbdev/core/fbcmap.c
</sect1>
<!-- FIXME:
drivers/video/fbgen.c has no docs, which stuffs up the sgml. Comment
@ -294,11 +294,11 @@ X!Idrivers/video/fbgen.c
</sect1>
KAO -->
<sect1><title>Frame Buffer Video Mode Database</title>
!Idrivers/video/modedb.c
!Edrivers/video/modedb.c
!Idrivers/video/fbdev/core/modedb.c
!Edrivers/video/fbdev/core/modedb.c
</sect1>
<sect1><title>Frame Buffer Macintosh Video Mode Database</title>
!Edrivers/video/macmodes.c
!Edrivers/video/fbdev/macmodes.c
</sect1>
<sect1><title>Frame Buffer Fonts</title>
<para>

View File

@ -2285,6 +2285,11 @@ void intel_crt_init(struct drm_device *dev)
<sect2>
<title>Modeset Helper Functions Reference</title>
!Edrivers/gpu/drm/drm_crtc_helper.c
</sect2>
<sect2>
<title>Output Probing Helper Functions Reference</title>
!Pdrivers/gpu/drm/drm_probe_helper.c output probing helper overview
!Edrivers/gpu/drm/drm_probe_helper.c
</sect2>
<sect2>
<title>fbdev Helper Functions Reference</title>

View File

@ -0,0 +1,97 @@
Marvell Kirkwood SoC Family Device Tree Bindings
------------------------------------------------
Boards with a SoC of the Marvell Kirkwook family, eg 88f6281
* Required root node properties:
compatible: must contain "marvell,kirkwood"
In addition, the above compatible shall be extended with the specific
SoC. Currently known SoC compatibles are:
"marvell,kirkwood-88f6192"
"marvell,kirkwood-88f6281"
"marvell,kirkwood-88f6282"
"marvell,kirkwood-88f6283"
"marvell,kirkwood-88f6702"
"marvell,kirkwood-98DX4122"
And in addition, the compatible shall be extended with the specific
board. Currently known boards are:
"buffalo,lschlv2"
"buffalo,lsxhl"
"buffalo,lsxl"
"dlink,dns-320"
"dlink,dns-320-a1"
"dlink,dns-325"
"dlink,dns-325-a1"
"dlink,dns-kirkwood"
"excito,b3"
"globalscale,dreamplug-003-ds2001"
"globalscale,guruplug"
"globalscale,guruplug-server-plus"
"globalscale,sheevaplug"
"globalscale,sheevaplug"
"globalscale,sheevaplug-esata"
"globalscale,sheevaplug-esata-rev13"
"iom,iconnect"
"iom,iconnect-1.1"
"iom,ix2-200"
"keymile,km_kirkwood"
"lacie,cloudbox"
"lacie,inetspace_v2"
"lacie,laplug"
"lacie,netspace_lite_v2"
"lacie,netspace_max_v2"
"lacie,netspace_mini_v2"
"lacie,netspace_v2"
"marvell,db-88f6281-bp"
"marvell,db-88f6282-bp"
"marvell,mv88f6281gtw-ge"
"marvell,rd88f6281"
"marvell,rd88f6281"
"marvell,rd88f6281-a0"
"marvell,rd88f6281-a1"
"mpl,cec4"
"mpl,cec4-10"
"netgear,readynas"
"netgear,readynas"
"netgear,readynas-duo-v2"
"netgear,readynas-nv+-v2"
"plathome,openblocks-a6"
"plathome,openblocks-a7"
"raidsonic,ib-nas6210"
"raidsonic,ib-nas6210-b"
"raidsonic,ib-nas6220"
"raidsonic,ib-nas6220-b"
"raidsonic,ib-nas62x0"
"seagate,dockstar"
"seagate,goflexnet"
"synology,ds109"
"synology,ds110jv10"
"synology,ds110jv20"
"synology,ds110jv30"
"synology,ds111"
"synology,ds209"
"synology,ds210jv10"
"synology,ds210jv20"
"synology,ds212"
"synology,ds212jv10"
"synology,ds212jv20"
"synology,ds212pv10"
"synology,ds409"
"synology,ds409slim"
"synology,ds410j"
"synology,ds411"
"synology,ds411j"
"synology,ds411slim"
"synology,ds413jv10"
"synology,rs212"
"synology,rs409"
"synology,rs411"
"synology,rs812"
"usi,topkick"
"usi,topkick-1281P2"
"zyxel,nsa310"
"zyxel,nsa310a"

View File

@ -13,8 +13,22 @@ ad,ad7414 SMBus/I2C Digital Temperature Sensor in 6-Pin SOT with SMBus Alert an
ad,adm9240 ADM9240: Complete System Hardware Monitor for uProcessor-Based Systems
adi,adt7461 +/-1C TDM Extended Temp Range I.C
adt7461 +/-1C TDM Extended Temp Range I.C
adi,adt7473 +/-1C TDM Extended Temp Range I.C
adi,adt7475 +/-1C TDM Extended Temp Range I.C
adi,adt7476 +/-1C TDM Extended Temp Range I.C
adi,adt7490 +/-1C TDM Extended Temp Range I.C
at,24c08 i2c serial eeprom (24cxx)
atmel,24c00 i2c serial eeprom (24cxx)
atmel,24c01 i2c serial eeprom (24cxx)
atmel,24c02 i2c serial eeprom (24cxx)
atmel,24c04 i2c serial eeprom (24cxx)
atmel,24c16 i2c serial eeprom (24cxx)
atmel,24c32 i2c serial eeprom (24cxx)
atmel,24c64 i2c serial eeprom (24cxx)
atmel,24c128 i2c serial eeprom (24cxx)
atmel,24c256 i2c serial eeprom (24cxx)
atmel,24c512 i2c serial eeprom (24cxx)
atmel,24c1024 i2c serial eeprom (24cxx)
atmel,at97sc3204t i2c trusted platform module (TPM)
capella,cm32181 CM32181: Ambient Light Sensor
catalyst,24c32 i2c serial eeprom
@ -46,8 +60,10 @@ maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator
maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
mc,rv3029c2 Real Time Clock Module with I2C-Bus
national,lm63 Temperature sensor with integrated fan control
national,lm75 I2C TEMP SENSOR
national,lm80 Serial Interface ACPI-Compatible Microprocessor System Hardware Monitor
national,lm85 Temperature sensor with integrated fan control
national,lm92 ±0.33°C Accurate, 12-Bit + Sign Temperature Sensor and Thermal Window Comparator with Two-Wire Interface
nuvoton,npct501 i2c trusted platform module (TPM)
nxp,pca9556 Octal SMBus and I2C registered interface

View File

@ -10,7 +10,7 @@ The following properties are common to the Ethernet controllers:
- max-frame-size: number, maximum transfer unit (IEEE defined MTU), rather than
the maximum frame size (there's contradiction in ePAPR).
- phy-mode: string, operation mode of the PHY interface; supported values are
"mii", "gmii", "sgmii", "tbi", "rev-mii", "rmii", "rgmii", "rgmii-id",
"mii", "gmii", "sgmii", "qsgmii", "tbi", "rev-mii", "rmii", "rgmii", "rgmii-id",
"rgmii-rxid", "rgmii-txid", "rtbi", "smii", "xgmii"; this is now a de-facto
standard property;
- phy-connection-type: the same as "phy-mode" property but described in ePAPR;

View File

@ -1,7 +1,7 @@
* Energymicro efm32 UART
Required properties:
- compatible : Should be "efm32,uart"
- compatible : Should be "energymicro,efm32-uart"
- reg : Address and length of the register set
- interrupts : Should contain uart interrupt
@ -13,7 +13,7 @@ Optional properties:
Example:
uart@0x4000c400 {
compatible = "efm32,uart";
compatible = "energymicro,efm32-uart";
reg = <0x4000c400 0x400>;
interrupts = <15>;
efm32,location = <0>;

View File

@ -22,6 +22,7 @@ auo AU Optronics Corporation
avago Avago Technologies
bosch Bosch Sensortec GmbH
brcm Broadcom Corporation
buffalo Buffalo, Inc.
calxeda Calxeda
capella Capella Microsystems, Inc
cavium Cavium, Inc.
@ -33,15 +34,18 @@ cortina Cortina Systems, Inc.
crystalfontz Crystalfontz America, Inc.
dallas Maxim Integrated Products (formerly Dallas Semiconductor)
davicom DAVICOM Semiconductor, Inc.
dlink D-Link Systems, Inc.
denx Denx Software Engineering
digi Digi International Inc.
dlink D-Link Corporation
dmo Data Modul AG
ebv EBV Elektronik
edt Emerging Display Technologies
emmicro EM Microelectronic
epfl Ecole Polytechnique Fédérale de Lausanne
epson Seiko Epson Corp.
est ESTeem Wireless Modems
eukrea Eukréa Electromatique
excito Excito
fsl Freescale Semiconductor
GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
@ -53,13 +57,17 @@ haoyu Haoyu Microelectronic Co. Ltd.
hisilicon Hisilicon Limited.
honeywell Honeywell
hp Hewlett Packard
i2se I2SE GmbH
ibm International Business Machines (IBM)
idt Integrated Device Technologies, Inc.
iom Iomega Corporation
img Imagination Technologies Ltd.
intel Intel Corporation
intercontrol Inter Control Group
isee ISEE 2007 S.L.
isl Intersil
karo Ka-Ro electronics GmbH
keymile Keymile GmbH
lacie LaCie
lantiq Lantiq Semiconductor
lg LG Corporation
@ -70,9 +78,12 @@ maxim Maxim Integrated Products
microchip Microchip Technology Inc.
mosaixtech Mosaix Technologies, Inc.
moxa Moxa
mpl MPL AG
mxicy Macronix International Co., Ltd.
national National Semiconductor
neonode Neonode Inc.
netgear NETGEAR
newhaven Newhaven Display International
nintendo Nintendo
nokia Nokia
nvidia NVIDIA
@ -82,10 +93,12 @@ opencores OpenCores.org
panasonic Panasonic Corporation
phytec PHYTEC Messtechnik GmbH
picochip Picochip Ltd
plathome Plat'Home Co., Ltd.
powervr PowerVR (deprecated, use img)
qca Qualcomm Atheros, Inc.
qcom Qualcomm Technologies, Inc
qnap QNAP Systems, Inc.
raidsonic RaidSonic Technology GmbH
ralink Mediatek/Ralink Technology Corp.
ramtron Ramtron International
realtek Realtek Semiconductor Corp.
@ -95,6 +108,7 @@ rockchip Fuzhou Rockchip Electronics Co., Ltd
samsung Samsung Semiconductor
sbs Smart Battery System
schindler Schindler
seagate Seagate Technology PLC
sil Silicon Image
silabs Silicon Laboratories
simtek
@ -111,6 +125,7 @@ ti Texas Instruments
tlm Trusted Logic Mobility
toshiba Toshiba Corporation
toumaz Toumaz
usi Universal Scientifc Industrial Co., Ltd.
v3 V3 Semiconductor
via VIA Technologies, Inc.
voipac Voipac Technologies s.r.o.
@ -119,3 +134,4 @@ wlf Wolfson Microelectronics
wm Wondermedia Technologies, Inc.
xes Extreme Engineering Solutions (X-ES)
xlnx Xilinx
zyxel ZyXEL Communications Corp.

View File

@ -315,7 +315,7 @@ Andrew Morton が Linux-kernel メーリングリストにカーネルリリー
もし、3.x.y カーネルが存在しない場合には、番号が一番大きい 3.x が
最新の安定版カーネルです。
3.x.y は "stable" チーム <stable@kernel.org> でメンテされており、必
3.x.y は "stable" チーム <stable@vger.kernel.org> でメンテされており、必
要に応じてリリースされます。通常のリリース期間は 2週間毎ですが、差し迫っ
た問題がなければもう少し長くなることもあります。セキュリティ関連の問題
の場合はこれに対してだいたいの場合、すぐにリリースがされます。

View File

@ -50,16 +50,16 @@ linux-2.6.29/Documentation/stable_kernel_rules.txt
-stable ツリーにパッチを送付する手続き-
- 上記の規則に従っているかを確認した後に、stable@kernel.org にパッチ
- 上記の規則に従っているかを確認した後に、stable@vger.kernel.org にパッチ
を送る。
- 送信者はパッチがキューに受け付けられた際には ACK を、却下された場合
には NAK を受け取る。この反応は開発者たちのスケジュールによって、数
日かかる場合がある。
- もし受け取られたら、パッチは他の開発者たちと関連するサブシステムの
メンテナーによるレビューのために -stable キューに追加される。
- パッチに stable@kernel.org のアドレスが付加されているときには、それ
- パッチに stable@vger.kernel.org のアドレスが付加されているときには、それ
が Linus のツリーに入る時に自動的に stable チームに email される。
- セキュリティパッチはこのエイリアス (stable@kernel.org) に送られるべ
- セキュリティパッチはこのエイリアス (stable@vger.kernel.org) に送られるべ
きではなく、代わりに security@kernel.org のアドレスに送られる。
レビューサイクル-

View File

@ -804,13 +804,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
dhash_entries= [KNL]
Set number of hash buckets for dentry cache.
digi= [HW,SERIAL]
IO parameters + enable/disable command.
digiepca= [HW,SERIAL]
See drivers/char/README.epca and
Documentation/serial/digiepca.txt.
disable= [IPV6]
See Documentation/networking/ipv6.txt.
@ -2939,9 +2932,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
rhash_entries= [KNL,NET]
Set number of hash buckets for route cache
riscom8= [HW,SERIAL]
Format: <io_board1>[,<io_board2>[,...<io_boardN>]]
ro [KNL] Mount root device read-only on boot
root= [KNL] Root filesystem
@ -3083,9 +3073,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
sonypi.*= [HW] Sony Programmable I/O Control Device driver
See Documentation/laptops/sonypi.txt
specialix= [HW,SERIAL] Specialix multi-serial port adapter
See Documentation/serial/specialix.txt.
spia_io_base= [HW,MTD]
spia_fio_base=
spia_pedr=

View File

@ -63,8 +63,6 @@ Magic Name Number Structure File
PG_MAGIC 'P' pg_{read,write}_hdr include/linux/pg.h
CMAGIC 0x0111 user include/linux/a.out.h
MKISS_DRIVER_MAGIC 0x04bf mkiss_channel drivers/net/mkiss.h
RISCOM8_MAGIC 0x0907 riscom_port drivers/char/riscom8.h
SPECIALIX_MAGIC 0x0907 specialix_port drivers/char/specialix_io8.h
HDLC_MAGIC 0x239e n_hdlc drivers/char/n_hdlc.c
APM_BIOS_MAGIC 0x4101 apm_user arch/x86/kernel/apm_32.c
CYCLADES_MAGIC 0x4359 cyclades_port include/linux/cyclades.h
@ -82,7 +80,6 @@ STRIP_MAGIC 0x5303 strip drivers/net/strip.c
X25_ASY_MAGIC 0x5303 x25_asy drivers/net/x25_asy.h
SIXPACK_MAGIC 0x5304 sixpack drivers/net/hamradio/6pack.h
AX25_MAGIC 0x5316 ax_disp drivers/net/mkiss.h
ESP_MAGIC 0x53ee esp_struct drivers/char/esp.h
TTY_MAGIC 0x5401 tty_struct include/linux/tty.h
MGSL_MAGIC 0x5401 mgsl_info drivers/char/synclink.c
TTY_DRIVER_MAGIC 0x5402 tty_driver include/linux/tty_driver.h
@ -94,13 +91,10 @@ USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth drivers/usb/class/bluetty.c
RFCOMM_TTY_MAGIC 0x6d02 net/bluetooth/rfcomm/tty.c
USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port drivers/usb/serial/usb-serial.h
CG_MAGIC 0x00090255 ufs_cylinder_group include/linux/ufs_fs.h
A2232_MAGIC 0x000a2232 gs_port drivers/char/ser_a2232.h
RPORT_MAGIC 0x00525001 r_port drivers/char/rocket_int.h
LSEMAGIC 0x05091998 lse drivers/fc4/fc.c
GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str drivers/scsi/gdth_ioctl.h
RIEBL_MAGIC 0x09051990 drivers/net/atarilance.c
RIO_MAGIC 0x12345678 gs_port drivers/char/rio/rio_linux.c
SX_MAGIC 0x12345678 gs_port drivers/char/sx.h
NBD_REQUEST_MAGIC 0x12560953 nbd_request include/linux/nbd.h
RED_MAGIC2 0x170fc2a5 (any) mm/slab.c
BAYCOM_MAGIC 0x19730510 baycom_state drivers/net/baycom_epp.c
@ -116,7 +110,6 @@ ISDN_ASYNC_MAGIC 0x49344C01 modem_info include/linux/isdn.h
CTC_ASYNC_MAGIC 0x49344C01 ctc_tty_info drivers/s390/net/ctctty.c
ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s drivers/isdn/i4l/isdn_net_lib.h
SAVEKMSG_MAGIC2 0x4B4D5347 savekmsg arch/*/amiga/config.c
STLI_BOARDMAGIC 0x4bc6c825 stlibrd include/linux/istallion.h
CS_STATE_MAGIC 0x4c4f4749 cs_state sound/oss/cs46xx.c
SLAB_C_MAGIC 0x4f17a36d kmem_cache mm/slab.c
COW_MAGIC 0x4f4f4f4d cow_header_v1 arch/um/drivers/ubd_user.c
@ -127,10 +120,8 @@ SCC_MAGIC 0x52696368 gs_port drivers/char/scc.h
SAVEKMSG_MAGIC1 0x53415645 savekmsg arch/*/amiga/config.c
GDA_MAGIC 0x58464552 gda arch/mips/include/asm/sn/gda.h
RED_MAGIC1 0x5a2cf071 (any) mm/slab.c
STL_PORTMAGIC 0x5a7182c9 stlport include/linux/stallion.h
EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev drivers/atm/lanai.c
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state include/linux/hdlcdrv.h
EPCA_MAGIC 0x5c6df104 channel include/linux/epca.h
PCXX_MAGIC 0x5c6df104 channel drivers/char/pcxx.h
KV_MAGIC 0x5f4b565f kernel_vars_s arch/mips/include/asm/sn/klkernvars.h
I810_STATE_MAGIC 0x63657373 i810_state sound/oss/i810_audio.c
@ -142,17 +133,14 @@ SLOT_MAGIC 0x67267322 slot drivers/hotplug/acpiphp.h
LO_MAGIC 0x68797548 nbd_device include/linux/nbd.h
OPROFILE_MAGIC 0x6f70726f super_block drivers/oprofile/oprofilefs.h
M3_STATE_MAGIC 0x734d724d m3_state sound/oss/maestro3.c
STL_PANELMAGIC 0x7ef621a1 stlpanel include/linux/stallion.h
VMALLOC_MAGIC 0x87654320 snd_alloc_track sound/core/memory.c
KMALLOC_MAGIC 0x87654321 snd_alloc_track sound/core/memory.c
PWC_MAGIC 0x89DC10AB pwc_device drivers/usb/media/pwc.h
NBD_REPLY_MAGIC 0x96744668 nbd_reply include/linux/nbd.h
STL_BOARDMAGIC 0xa2267f52 stlbrd include/linux/stallion.h
ENI155_MAGIC 0xa54b872d midway_eprom drivers/atm/eni.h
SCI_MAGIC 0xbabeface gs_port drivers/char/sh-sci.h
CODA_MAGIC 0xC0DAC0DA coda_file_info fs/coda/coda_fs_i.h
DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram drivers/scsi/gdth.h
STLI_PORTMAGIC 0xe671c7a1 stliport include/linux/istallion.h
YAM_MAGIC 0xF10A7654 yam_port drivers/net/hamradio/yam.c
CCB_MAGIC 0xf2691ad2 ccb drivers/scsi/ncr53c8xx.c
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry drivers/scsi/arm/queue.c

View File

@ -2,23 +2,15 @@
- this file.
README.cycladesZ
- info on Cyclades-Z firmware loading.
digiepca.txt
- info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
driver
- intro to the low level serial driver.
moxa-smartio
- file with info on installing/using Moxa multiport serial driver.
n_gsm.txt
- GSM 0710 tty multiplexer howto.
riscom8.txt
- notes on using the RISCom/8 multi-port serial driver.
rocket.txt
- info on the Comtrol RocketPort multiport serial driver.
serial-rs485.txt
- info about RS485 structures and support in the kernel.
specialix.txt
- info on hardware/driver for specialix IO8+ multiport serial card.
sx.txt
- info on the Specialix SX/SI multiport serial driver.
tty.txt
- guide to the locking policies of the tty layer.

View File

@ -1,98 +0,0 @@
NOTE: This driver is obsolete. Digi provides a 2.6 driver (dgdm) at
http://www.digi.com for PCI cards. They no longer maintain this driver,
and have no 2.6 driver for ISA cards.
This driver requires a number of user-space tools. They can be acquired from
http://www.digi.com, but only works with 2.4 kernels.
The Digi Intl. epca driver.
----------------------------
The Digi Intl. epca driver for Linux supports the following boards:
Digi PC/Xem, PC/Xr, PC/Xe, PC/Xi, PC/Xeve
Digi EISA/Xem, PCI/Xem, PCI/Xr
Limitations:
------------
Currently the driver only autoprobes for supported PCI boards.
The Linux MAKEDEV command does not support generating the Digiboard
Devices. Users executing digiConfig to setup EISA and PC series cards
will have their device nodes automatically constructed (cud?? for ~CLOCAL,
and ttyD?? for CLOCAL). Users wishing to boot their board from the LILO
prompt, or those users booting PCI cards may use buildDIGI to construct
the necessary nodes.
Notes:
------
This driver may be configured via LILO. For users who have already configured
their driver using digiConfig, configuring from LILO will override previous
settings. Multiple boards may be configured by issuing multiple LILO command
lines. For examples see the bottom of this document.
Device names start at 0 and continue up. Beware of this as previous Digi
drivers started device names with 1.
PCI boards are auto-detected and configured by the driver. PCI boards will
be allocated device numbers (internally) beginning with the lowest PCI slot
first. In other words a PCI card in slot 3 will always have higher device
nodes than a PCI card in slot 1.
LILO config examples:
---------------------
Using LILO's APPEND command, a string of comma separated identifiers or
integers can be used to configure supported boards. The six values in order
are:
Enable/Disable this card or Override,
Type of card: PC/Xe (AccelePort) (0), PC/Xeve (1), PC/Xem or PC/Xr (2),
EISA/Xem (3), PC/64Xe (4), PC/Xi (5),
Enable/Disable alternate pin arrangement,
Number of ports on this card,
I/O Port where card is configured (in HEX if using string identifiers),
Base of memory window (in HEX if using string identifiers),
NOTE : PCI boards are auto-detected and configured. Do not attempt to
configure PCI boards with the LILO append command. If you wish to override
previous configuration data (As set by digiConfig), but you do not wish to
configure any specific card (Example if there are PCI cards in the system)
the following override command will accomplish this:
-> append="digi=2"
Samples:
append="digiepca=E,PC/Xe,D,16,200,D0000"
or
append="digi=1,0,0,16,512,851968"
Supporting Tools:
-----------------
Supporting tools include digiDload, digiConfig, buildPCI, and ditty. See
drivers/char/README.epca for more details. Note,
this driver REQUIRES that digiDload be executed prior to it being used.
Failure to do this will result in an ENODEV error.
Documentation:
--------------
Complete documentation for this product may be found in the tool package.
Sources of information and support:
-----------------------------------
Digi Intl. support site for this product:
-> http://www.digi.com
Acknowledgments:
----------------
Much of this work (And even text) was derived from a similar document
supporting the original public domain DigiBoard driver Copyright (C)
1994,1995 Troy De Jongh. Many thanks to Christoph Lameter
(christoph@lameter.com) and Mike McLagan (mike.mclagan@linux.org) who authored
and contributed to the original document.
Changelog:
----------
10-29-04: Update status of driver, remove dead links in document
James Nelson <james4765@gmail.com>
2000 (?) Original Document

View File

@ -1,36 +0,0 @@
* NOTE - this is an unmaintained driver. The original author cannot be located.
SDL Communications is now SBS Technologies, and does not have any
information on these ancient ISA cards on their website.
James Nelson <james4765@gmail.com> - 12-12-2004
This is the README for RISCom/8 multi-port serial driver
(C) 1994-1996 D.Gorodchanin
See file LICENSE for terms and conditions.
NOTE: English is not my native language.
I'm sorry for any mistakes in this text.
Misc. notes for RISCom/8 serial driver, in no particular order :)
1) This driver can support up to 4 boards at time.
Use string "riscom8=0xXXX,0xXXX,0xXXX,0xXXX" at LILO prompt, for
setting I/O base addresses for boards. If you compile driver
as module use modprobe options "iobase=0xXXX iobase1=0xXXX iobase2=..."
2) The driver partially supports famous 'setserial' program, you can use almost
any of its options, excluding port & irq settings.
3) There are some misc. defines at the beginning of riscom8.c, please read the
comments and try to change some of them in case of problems.
4) I consider the current state of the driver as BETA.
5) SDL Communications WWW page is http://www.sdlcomm.com.
6) You can use the MAKEDEV program to create RISCom/8 /dev/ttyL* entries.
7) Minor numbers for first board are 0-7, for second 8-15, etc.
22 Apr 1996.

View File

@ -1,383 +0,0 @@
specialix.txt -- specialix IO8+ multiport serial driver readme.
Copyright (C) 1997 Roger Wolff (R.E.Wolff@BitWizard.nl)
Specialix pays for the development and support of this driver.
Please DO contact io8-linux@specialix.co.uk if you require
support.
This driver was developed in the BitWizard linux device
driver service. If you require a linux device driver for your
product, please contact devices@BitWizard.nl for a quote.
This code is firmly based on the riscom/8 serial driver,
written by Dmitry Gorodchanin. The specialix IO8+ card
programming information was obtained from the CL-CD1865 Data
Book, and Specialix document number 6200059: IO8+ Hardware
Functional Specification, augmented by document number 6200088:
Merak Hardware Functional Specification. (IO8+/PCI is also
called Merak)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with this program; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
USA.
Intro
=====
This file contains some random information, that I like to have online
instead of in a manual that can get lost. Ever misplace your Linux
kernel sources? And the manual of one of the boards in your computer?
Addresses and interrupts
========================
Address dip switch settings:
The dip switch sets bits 2-9 of the IO address.
9 8 7 6 5 4 3 2
+-----------------+
0 | X X X X X X X |
| | = IoBase = 0x100
1 | X |
+-----------------+ ------ RS232 connectors ---->
| | |
edge connector
| | |
V V V
Base address 0x100 caused a conflict in one of my computers once. I
haven't the foggiest why. My Specialix card is now at 0x180. My
other computer runs just fine with the Specialix card at 0x100....
The card occupies 4 addresses, but actually only two are really used.
The PCI version doesn't have any dip switches. The BIOS assigns
an IO address.
The driver now still autoprobes at 0x100, 0x180, 0x250 and 0x260. If
that causes trouble for you, please report that. I'll remove
autoprobing then.
The driver will tell the card what IRQ to use, so you don't have to
change any jumpers to change the IRQ. Just use a command line
argument (irq=xx) to the insmod program to set the interrupt.
The BIOS assigns the IRQ on the PCI version. You have no say in what
IRQ to use in that case.
If your specialix cards are not at the default locations, you can use
the kernel command line argument "specialix=io0,irq0,io1,irq1...".
Here "io0" is the io address for the first card, and "irq0" is the
irq line that the first card should use. And so on.
Examples.
You use the driver as a module and have three cards at 0x100, 0x250
and 0x180. And some way or another you want them detected in that
order. Moreover irq 12 is taken (e.g. by your PS/2 mouse).
insmod specialix.o iobase=0x100,0x250,0x180 irq=9,11,15
The same three cards, but now in the kernel would require you to
add
specialix=0x100,9,0x250,11,0x180,15
to the command line. This would become
append="specialix=0x100,9,0x250,11,0x180,15"
in your /etc/lilo.conf file if you use lilo.
The Specialix driver is slightly odd: It allows you to have the second
or third card detected without having a first card. This has
advantages and disadvantages. A slot that isn't filled by an ISA card,
might be filled if a PCI card is detected. Thus if you have an ISA
card at 0x250 and a PCI card, you would get:
sx0: specialix IO8+ Board at 0x100 not found.
sx1: specialix IO8+ Board at 0x180 not found.
sx2: specialix IO8+ board detected at 0x250, IRQ 12, CD1865 Rev. B.
sx3: specialix IO8+ Board at 0x260 not found.
sx0: specialix IO8+ board detected at 0xd800, IRQ 9, CD1865 Rev. B.
This would happen if you don't give any probe hints to the driver.
If you would specify:
specialix=0x250,11
you'd get the following messages:
sx0: specialix IO8+ board detected at 0x250, IRQ 11, CD1865 Rev. B.
sx1: specialix IO8+ board detected at 0xd800, IRQ 9, CD1865 Rev. B.
ISA probing is aborted after the IO address you gave is exhausted, and
the PCI card is now detected as the second card. The ISA card is now
also forced to IRQ11....
Baud rates
==========
The rev 1.2 and below boards use a CL-CD1864. These chips can only
do 64kbit. The rev 1.3 and newer boards use a CL-CD1865. These chips
are officially capable of 115k2.
The Specialix card uses a 25MHz crystal (in times two mode, which in
fact is a divided by two mode). This is not enough to reach the rated
115k2 on all ports at the same time. With this clock rate you can only
do 37% of this rate. This means that at 115k2 on all ports you are
going to lose characters (The chip cannot handle that many incoming
bits at this clock rate.) (Yes, you read that correctly: there is a
limit to the number of -=bits=- per second that the chip can handle.)
If you near the "limit" you will first start to see a graceful
degradation in that the chip cannot keep the transmitter busy at all
times. However with a central clock this slow, you can also get it to
miss incoming characters. The driver will print a warning message when
you are outside the official specs. The messages usually show up in
the file /var/log/messages .
The specialix card cannot reliably do 115k2. If you use it, you have
to do "extensive testing" (*) to verify if it actually works.
When "mgetty" communicates with my modem at 115k2 it reports:
got: +++[0d]ATQ0V1H0[0d][0d][8a]O[cb][0d][8a]
^^^^ ^^^^ ^^^^
The three characters that have the "^^^" under them have suffered a
bit error in the highest bit. In conclusion: I've tested it, and found
that it simply DOESN'T work for me. I also suspect that this is also
caused by the baud rate being just a little bit out of tune.
I upgraded the crystal to 66Mhz on one of my Specialix cards. Works
great! Contact me for details. (Voids warranty, requires a steady hand
and more such restrictions....)
(*) Cirrus logic CD1864 databook, page 40.
Cables for the Specialix IO8+
=============================
The pinout of the connectors on the IO8+ is:
pin short direction long name
name
Pin 1 DCD input Data Carrier Detect
Pin 2 RXD input Receive
Pin 3 DTR/RTS output Data Terminal Ready/Ready To Send
Pin 4 GND - Ground
Pin 5 TXD output Transmit
Pin 6 CTS input Clear To Send
-- 6 5 4 3 2 1 --
| |
| |
| |
| |
+----- -----+
|__________|
clip
Front view of an RJ12 connector. Cable moves "into" the paper.
(the plug is ready to plug into your mouth this way...)
NULL cable. I don't know who is going to use these except for
testing purposes, but I tested the cards with this cable. (It
took quite a while to figure out, so I'm not going to delete
it. So there! :-)
This end goes This end needs
straight into the some twists in
RJ12 plug. the wiring.
IO8+ RJ12 IO8+ RJ12
1 DCD white -
- - 1 DCD
2 RXD black 5 TXD
3 DTR/RTS red 6 CTS
4 GND green 4 GND
5 TXD yellow 2 RXD
6 CTS blue 3 DTR/RTS
Same NULL cable, but now sorted on the second column.
1 DCD white -
- - 1 DCD
5 TXD yellow 2 RXD
6 CTS blue 3 DTR/RTS
4 GND green 4 GND
2 RXD black 5 TXD
3 DTR/RTS red 6 CTS
This is a modem cable usable for hardware handshaking:
RJ12 DB25 DB9
1 DCD white 8 DCD 1 DCD
2 RXD black 3 RXD 2 RXD
3 DTR/RTS red 4 RTS 7 RTS
4 GND green 7 GND 5 GND
5 TXD yellow 2 TXD 3 TXD
6 CTS blue 5 CTS 8 CTS
+---- 6 DSR 6 DSR
+---- 20 DTR 4 DTR
This is a modem cable usable for software handshaking:
It allows you to reset the modem using the DTR ioctls.
I (REW) have never tested this, "but xxxxxxxxxxxxx
says that it works." If you test this, please
tell me and I'll fill in your name on the xxx's.
RJ12 DB25 DB9
1 DCD white 8 DCD 1 DCD
2 RXD black 3 RXD 2 RXD
3 DTR/RTS red 20 DTR 4 DTR
4 GND green 7 GND 5 GND
5 TXD yellow 2 TXD 3 TXD
6 CTS blue 5 CTS 8 CTS
+---- 6 DSR 6 DSR
+---- 4 RTS 7 RTS
I bought a 6 wire flat cable. It was colored as indicated.
Check that yours is the same before you trust me on this.
Hardware handshaking issues.
============================
The driver can be told to operate in two different ways. The default
behaviour is specialix.sx_rtscts = 0 where the pin behaves as DTR when
hardware handshaking is off. It behaves as the RTS hardware
handshaking signal when hardware handshaking is selected.
When you use this, you have to use the appropriate cable. The
cable will either be compatible with hardware handshaking or with
software handshaking. So switching on the fly is not really an
option.
I actually prefer to use the "specialix.sx_rtscts=1" option.
This makes the DTR/RTS pin always an RTS pin, and ioctls to
change DTR are always ignored. I have a cable that is configured
for this.
Ports and devices
=================
Port 0 is the one furthest from the card-edge connector.
Devices:
You should make the devices as follows:
bash
cd /dev
for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 \
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
do
echo -n "$i "
mknod /dev/ttyW$i c 75 $i
mknod /dev/cuw$i c 76 $i
done
echo ""
If your system doesn't come with these devices preinstalled, bug your
linux-vendor about this. They have had ample time to get this
implemented by now.
You cannot have more than 4 boards in one computer. The card only
supports 4 different interrupts. If you really want this, contact me
about this and I'll give you a few tips (requires soldering iron)....
If you have enough PCI slots, you can probably use more than 4 PCI
versions of the card though....
The PCI version of the card cannot adhere to the mechanical part of
the PCI spec because the 8 serial connectors are simply too large. If
it doesn't fit in your computer, bring back the card.
------------------------------------------------------------------------
Fixed bugs and restrictions:
- During initialization, interrupts are blindly turned on.
Having a shadow variable would cause an extra memory
access on every IO instruction.
- The interrupt (on the card) should be disabled when we
don't allocate the Linux end of the interrupt. This allows
a different driver/card to use it while all ports are not in
use..... (a la standard serial port)
== An extra _off variant of the sx_in and sx_out macros are
now available. They don't set the interrupt enable bit.
These are used during initialization. Normal operation uses
the old variant which enables the interrupt line.
- RTS/DTR issue needs to be implemented according to
specialix' spec.
I kind of like the "determinism" of the current
implementation. Compile time flag?
== Ok. Compile time flag! Default is how Specialix likes it.
== Now a config time flag! Gets saved in your config file. Neat!
- Can you set the IO address from the lilo command line?
If you need this, bug me about it, I'll make it.
== Hah! No bugging needed. Fixed! :-)
- Cirrus logic hasn't gotten back to me yet why the CD1865 can
and the CD1864 can't do 115k2. I suspect that this is
because the CD1864 is not rated for 33MHz operation.
Therefore the CD1864 versions of the card can't do 115k2 on
all ports just like the CD1865 versions. The driver does
not block 115k2 on CD1864 cards.
== I called the Cirrus Logic representative here in Holland.
The CD1864 databook is identical to the CD1865 databook,
except for an extra warning at the end. Similar Bit errors
have been observed in testing at 115k2 on both an 1865 and
a 1864 chip. I see no reason why I would prohibit 115k2 on
1864 chips and not do it on 1865 chips. Actually there is
reason to prohibit it on BOTH chips. I print a warning.
If you use 115k2, you're on your own.
- A spiky CD may send spurious HUPs. Also in CLOCAL???
-- A fix for this turned out to be counter productive.
Different fix? Current behaviour is acceptable?
-- Maybe the current implementation is correct. If anybody
gets bitten by this, please report, and it will get fixed.
-- Testing revealed that when in CLOCAL, the problem doesn't
occur. As warned for in the CD1865 manual, the chip may
send modem intr's on a spike. We could filter those out,
but that would be a cludge anyway (You'd still risk getting
a spurious HUP when two spikes occur.).....
Bugs & restrictions:
- This is a difficult card to autoprobe.
You have to WRITE to the address register to even
read-probe a CD186x register. Disable autodetection?
-- Specialix: any suggestions?

View File

@ -1,294 +0,0 @@
sx.txt -- specialix SX/SI multiport serial driver readme.
Copyright (C) 1997 Roger Wolff (R.E.Wolff@BitWizard.nl)
Specialix pays for the development and support of this driver.
Please DO contact support@specialix.co.uk if you require
support.
This driver was developed in the BitWizard linux device
driver service. If you require a linux device driver for your
product, please contact devices@BitWizard.nl for a quote.
(History)
There used to be an SI driver by Simon Allan. This is a complete
rewrite from scratch. Just a few lines-of-code have been snatched.
(Sources)
Specialix document number 6210028: SX Host Card and Download Code
Software Functional Specification.
(Copying)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with this program; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
USA.
(Addendum)
I'd appreciate it that if you have fixes, that you send them
to me first.
Introduction
============
This file contains some random information, that I like to have online
instead of in a manual that can get lost. Ever misplace your Linux
kernel sources? And the manual of one of the boards in your computer?
Theory of operation
===================
An important thing to know is that the driver itself doesn't have the
firmware for the card. This means that you need the separate package
"sx_firmware". For now you can get the source at
ftp://ftp.bitwizard.nl/specialix/sx_firmware_<version>.tgz
The firmware load needs a "misc" device, so you'll need to enable the
"Support for user misc device modules" in your kernel configuration.
The misc device needs to be called "/dev/specialix_sxctl". It needs
misc major 10, and minor number 167 (assigned by HPA). The section
on creating device files below also creates this device.
After loading the sx.o module into your kernel, the driver will report
the number of cards detected, but because it doesn't have any
firmware, it will not be able to determine the number of ports. Only
when you then run "sx_firmware" will the firmware be downloaded and
the rest of the driver initialized. At that time the sx_firmware
program will report the number of ports installed.
In contrast with many other multi port serial cards, some of the data
structures are only allocated when the card knows the number of ports
that are connected. This means we won't waste memory for 120 port
descriptor structures when you only have 8 ports. If you experience
problems due to this, please report them: I haven't seen any.
Interrupts
==========
A multi port serial card, would generate a horrendous amount of
interrupts if it would interrupt the CPU for every received
character. Even more than 10 years ago, the trick not to use
interrupts but to poll the serial cards was invented.
The SX card allow us to do this two ways. First the card limits its
own interrupt rate to a rate that won't overwhelm the CPU. Secondly,
we could forget about the cards interrupt completely and use the
internal timer for this purpose.
Polling the card can take up to a few percent of your CPU. Using the
interrupts would be better if you have most of the ports idle. Using
timer-based polling is better if your card almost always has work to
do. You save the separate interrupt in that case.
In any case, it doesn't really matter all that much.
The most common problem with interrupts is that for ISA cards in a PCI
system the BIOS has to be told to configure that interrupt as "legacy
ISA". Otherwise the card can pull on the interrupt line all it wants
but the CPU won't see this.
If you can't get the interrupt to work, remember that polling mode is
more efficient (provided you actually use the card intensively).
Allowed Configurations
======================
Some configurations are disallowed. Even though at a glance they might
seem to work, they are known to lockup the bus between the host card
and the device concentrators. You should respect the drivers decision
not to support certain configurations. It's there for a reason.
Warning: Seriously technical stuff ahead. Executive summary: Don't use
SX cards except configured at a 64k boundary. Skip the next paragraph.
The SX cards can theoretically be placed at a 32k boundary. So for
instance you can put an SX card at 0xc8000-0xd7fff. This is not a
"recommended configuration". ISA cards have to tell the bus controller
how they like their timing. Due to timing issues they have to do this
based on which 64k window the address falls into. This means that the
32k window below and above the SX card have to use exactly the same
timing as the SX card. That reportedly works for other SX cards. But
you're still left with two useless 32k windows that should not be used
by anybody else.
Configuring the driver
======================
PCI cards are always detected. The driver auto-probes for ISA cards at
some sensible addresses. Please report if the auto-probe causes trouble
in your system, or when a card isn't detected.
I'm afraid I haven't implemented "kernel command line parameters" yet.
This means that if the default doesn't work for you, you shouldn't use
the compiled-into-the-kernel version of the driver. Use a module
instead. If you convince me that you need this, I'll make it for
you. Deal?
I'm afraid that the module parameters are a bit clumsy. If you have a
better idea, please tell me.
You can specify several parameters:
sx_poll: number of jiffies between timer-based polls.
Set this to "0" to disable timer based polls.
Initialization of cards without a working interrupt
will fail.
Set this to "1" if you want a polling driver.
(on Intel: 100 polls per second). If you don't use
fast baud rates, you might consider a value like "5".
(If you don't know how to do the math, use 1).
sx_slowpoll: Number of jiffies between timer-based polls.
Set this to "100" to poll once a second.
This should get the card out of a stall if the driver
ever misses an interrupt. I've never seen this happen,
and if it does, that's a bug. Tell me.
sx_maxints: Number of interrupts to request from the card.
The card normally limits interrupts to about 100 per
second to offload the host CPU. You can increase this
number to reduce latency on the card a little.
Note that if you give a very high number you can overload
your CPU as well as the CPU on the host card. This setting
is inaccurate and not recommended for SI cards (But it
works).
sx_irqmask: The mask of allowable IRQs to use. I suggest you set
this to 0 (disable IRQs all together) and use polling if
the assignment of IRQs becomes problematic. This is defined
as the sum of (1 << irq) 's that you want to allow. So
sx_irqmask of 8 (1 << 3) specifies that only irq 3 may
be used by the SX driver. If you want to specify to the
driver: "Either irq 11 or 12 is ok for you to use", then
specify (1 << 11) | (1 << 12) = 0x1800 .
sx_debug: You can enable different sorts of debug traces with this.
At "-1" all debugging traces are active. You'll get several
times more debugging output than you'll get characters
transmitted.
Baud rates
==========
Theoretically new SXDCs should be capable of more than 460k
baud. However the line drivers usually give up before that. Also the
CPU on the card may not be able to handle 8 channels going at full
blast at that speed. Moreover, the buffers are not large enough to
allow operation with 100 interrupts per second. You'll have to realize
that the card has a 256 byte buffer, so you'll have to increase the
number of interrupts per second if you have more than 256*100 bytes
per second to transmit. If you do any performance testing in this
area, I'd be glad to hear from you...
(Psst Linux users..... I think the Linux driver is more efficient than
the driver for other OSes. If you can and want to benchmark them
against each other, be my guest, and report your findings...... :-)
Ports and devices
=================
Port 0 is the top connector on the module closest to the host
card. Oh, the ports on the SXDCs and TAs are labelled from 1 to 8
instead of from 0 to 7, as they are numbered by linux. I'm stubborn in
this: I know for sure that I wouldn't be able to calculate which port
is which anymore if I would change that....
Devices:
You should make the device files as follows:
#!/bin/sh
# (I recommend that you cut-and-paste this into a file and run that)
cd /dev
t=0
mknod specialix_sxctl c 10 167
while [ $t -lt 64 ]
do
echo -n "$t "
mknod ttyX$t c 32 $t
mknod cux$t c 33 $t
t=`expr $t + 1`
done
echo ""
rm /etc/psdevtab
ps > /dev/null
This creates 64 devices. If you have more, increase the constant on
the line with "while". The devices start at 0, as is customary on
Linux. Specialix seems to like starting the numbering at 1.
If your system doesn't come with these devices pre-installed, bug your
linux-vendor about this. They should have these devices
"pre-installed" before the new millennium. The "ps" stuff at the end
is to "tell" ps that the new devices exist.
Officially the maximum number of cards per computer is 4. This driver
however supports as many cards in one machine as you want. You'll run
out of interrupts after a few, but you can switch to polled operation
then. At about 256 ports (More than 8 cards), we run out of minor
device numbers. Sorry. I suggest you buy a second computer.... (Or
switch to RIO).
------------------------------------------------------------------------
Fixed bugs and restrictions:
- Hangup processing.
-- Done.
- the write path in generic_serial (lockup / oops).
-- Done (Ugly: not the way I want it. Copied from serial.c).
- write buffer isn't flushed at close.
-- Done. I still seem to lose a few chars at close.
Sorry. I think that this is a firmware issue. (-> Specialix)
- drain hardware before changing termios
- Change debug on the fly.
- ISA free irq -1. (no firmware loaded).
- adding c8000 as a probe address. Added warning.
- Add a RAMtest for the RAM on the card.c
- Crash when opening a port "way" of the number of allowed ports.
(for example opening port 60 when there are only 24 ports attached)
- Sometimes the use-count strays a bit. After a few hours of
testing the use count is sometimes "3". If you are not like
me and can remember what you did to get it that way, I'd
appreciate an Email. Possibly fixed. Tell me if anyone still
sees this.
- TAs don't work right if you don't connect all the modem control
signals. SXDCs do. T225 firmware problem -> Specialix.
(Mostly fixed now, I think. Tell me if you encounter this!)
Bugs & restrictions:
- Arbitrary baud rates. Requires firmware update. (-> Specialix)
- Low latency (mostly firmware, -> Specialix)

View File

@ -39,7 +39,7 @@ Procedure for submitting patches to the -stable tree:
the stable tree without anything else needing to be done by the author
or subsystem maintainer.
- If the patch requires other patches as prerequisites which can be
cherry-picked than this can be specified in the following format in
cherry-picked, then this can be specified in the following format in
the sign-off area:
Cc: <stable@vger.kernel.org> # 3.3.x: a1f84a3: sched: Check for idle

View File

@ -174,7 +174,6 @@ Components of Memory Policies
allocation fails, the kernel will search other nodes, in order of
increasing distance from the preferred node based on information
provided by the platform firmware.
containing the cpu where the allocation takes place.
Internally, the Preferred policy uses a single node--the
preferred_node member of struct mempolicy. When the internal
@ -275,9 +274,9 @@ Components of Memory Policies
For example, consider a task that is attached to a cpuset with
mems 2-5 that sets an Interleave policy over the same set with
MPOL_F_RELATIVE_NODES. If the cpuset's mems change to 3-7, the
interleave now occurs over nodes 3,5-6. If the cpuset's mems
interleave now occurs over nodes 3,5-7. If the cpuset's mems
then change to 0,2-3,5, then the interleave occurs over nodes
0,3,5.
0,2-3,5.
Thanks to the consistent remapping, applications preparing
nodemasks to specify memory policies using this flag should

View File

@ -237,7 +237,7 @@ kernel.org网站的pub/linux/kernel/v2.6/目录下找到它。它的开发遵循
如果没有2.6.x.y版本内核存在那么最新的2.6.x版本内核就相当于是当前的稳定
版内核。
2.6.x.y版本由“稳定版”小组邮件地址<stable@kernel.org>)维护,一般隔周发
2.6.x.y版本由“稳定版”小组邮件地址<stable@vger.kernel.org>)维护,一般隔周发
布新版本。
内核源码中的Documentation/stable_kernel_rules.txt文件具体描述了可被稳定

View File

@ -0,0 +1,67 @@
Chinese translated version of Documentation/io_orderings.txt
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
communicating in English you can also ask the Chinese maintainer for
help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Chinese maintainer: Lin Yongting <linyongting@gmail.com>
---------------------------------------------------------------------
Documentation/io_ordering.txt 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
中文版维护者: 林永听 Lin Yongting <linyongting@gmail.com>
中文版翻译者: 林永听 Lin Yongting <linyongting@gmail.com>
中文版校译者: 林永听 Lin Yongting <linyongting@gmail.com>
以下为正文
---------------------------------------------------------------------
在某些平台上所谓的内存映射I/O是弱顺序。在这些平台上驱动开发者有责任
保证I/O内存映射地址的写操作按程序图意的顺序达到设备。通常读取一个“安全”
设备寄存器或桥寄存器触发IO芯片清刷未处理的写操作到达设备后才处理读操作
而达到保证目的。驱动程序通常在spinlock保护的临界区退出之前使用这种技术。
这也可以保证后面的写操作只在前面的写操作之后到达设备(这非常类似于内存
屏障操作mb()不过仅适用于I/O
假设一个设备驱动程的具体例子:
...
CPU A: spin_lock_irqsave(&dev_lock, flags)
CPU A: val = readl(my_status);
CPU A: ...
CPU A: writel(newval, ring_ptr);
CPU A: spin_unlock_irqrestore(&dev_lock, flags)
...
CPU B: spin_lock_irqsave(&dev_lock, flags)
CPU B: val = readl(my_status);
CPU B: ...
CPU B: writel(newval2, ring_ptr);
CPU B: spin_unlock_irqrestore(&dev_lock, flags)
...
上述例子中设备可能会先接收到newval2的值然后接收到newval的值问题就
发生了。不过很容易通过下面方法来修复:
...
CPU A: spin_lock_irqsave(&dev_lock, flags)
CPU A: val = readl(my_status);
CPU A: ...
CPU A: writel(newval, ring_ptr);
CPU A: (void)readl(safe_register); /* 配置寄存器?*/
CPU A: spin_unlock_irqrestore(&dev_lock, flags)
...
CPU B: spin_lock_irqsave(&dev_lock, flags)
CPU B: val = readl(my_status);
CPU B: ...
CPU B: writel(newval2, ring_ptr);
CPU B: (void)readl(safe_register); /* 配置寄存器?*/
CPU B: spin_unlock_irqrestore(&dev_lock, flags)
在解决方案中读取safe_register寄存器触发IO芯片清刷未处理的写操作
再处理后面的读操作,防止引发数据不一致问题。

View File

@ -63,8 +63,6 @@ struct tty_ldisc {
PG_MAGIC 'P' pg_{read,write}_hdr include/linux/pg.h
CMAGIC 0x0111 user include/linux/a.out.h
MKISS_DRIVER_MAGIC 0x04bf mkiss_channel drivers/net/mkiss.h
RISCOM8_MAGIC 0x0907 riscom_port drivers/char/riscom8.h
SPECIALIX_MAGIC 0x0907 specialix_port drivers/char/specialix_io8.h
HDLC_MAGIC 0x239e n_hdlc drivers/char/n_hdlc.c
APM_BIOS_MAGIC 0x4101 apm_user arch/x86/kernel/apm_32.c
CYCLADES_MAGIC 0x4359 cyclades_port include/linux/cyclades.h
@ -82,7 +80,6 @@ STRIP_MAGIC 0x5303 strip drivers/net/strip.c
X25_ASY_MAGIC 0x5303 x25_asy drivers/net/x25_asy.h
SIXPACK_MAGIC 0x5304 sixpack drivers/net/hamradio/6pack.h
AX25_MAGIC 0x5316 ax_disp drivers/net/mkiss.h
ESP_MAGIC 0x53ee esp_struct drivers/char/esp.h
TTY_MAGIC 0x5401 tty_struct include/linux/tty.h
MGSL_MAGIC 0x5401 mgsl_info drivers/char/synclink.c
TTY_DRIVER_MAGIC 0x5402 tty_driver include/linux/tty_driver.h
@ -94,13 +91,10 @@ USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth drivers/usb/class/bluetty.c
RFCOMM_TTY_MAGIC 0x6d02 net/bluetooth/rfcomm/tty.c
USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port drivers/usb/serial/usb-serial.h
CG_MAGIC 0x00090255 ufs_cylinder_group include/linux/ufs_fs.h
A2232_MAGIC 0x000a2232 gs_port drivers/char/ser_a2232.h
RPORT_MAGIC 0x00525001 r_port drivers/char/rocket_int.h
LSEMAGIC 0x05091998 lse drivers/fc4/fc.c
GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str drivers/scsi/gdth_ioctl.h
RIEBL_MAGIC 0x09051990 drivers/net/atarilance.c
RIO_MAGIC 0x12345678 gs_port drivers/char/rio/rio_linux.c
SX_MAGIC 0x12345678 gs_port drivers/char/sx.h
NBD_REQUEST_MAGIC 0x12560953 nbd_request include/linux/nbd.h
RED_MAGIC2 0x170fc2a5 (any) mm/slab.c
BAYCOM_MAGIC 0x19730510 baycom_state drivers/net/baycom_epp.c
@ -116,7 +110,6 @@ ISDN_ASYNC_MAGIC 0x49344C01 modem_info include/linux/isdn.h
CTC_ASYNC_MAGIC 0x49344C01 ctc_tty_info drivers/s390/net/ctctty.c
ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s drivers/isdn/i4l/isdn_net_lib.h
SAVEKMSG_MAGIC2 0x4B4D5347 savekmsg arch/*/amiga/config.c
STLI_BOARDMAGIC 0x4bc6c825 stlibrd include/linux/istallion.h
CS_STATE_MAGIC 0x4c4f4749 cs_state sound/oss/cs46xx.c
SLAB_C_MAGIC 0x4f17a36d kmem_cache mm/slab.c
COW_MAGIC 0x4f4f4f4d cow_header_v1 arch/um/drivers/ubd_user.c
@ -127,10 +120,8 @@ SCC_MAGIC 0x52696368 gs_port drivers/char/scc.h
SAVEKMSG_MAGIC1 0x53415645 savekmsg arch/*/amiga/config.c
GDA_MAGIC 0x58464552 gda arch/mips/include/asm/sn/gda.h
RED_MAGIC1 0x5a2cf071 (any) mm/slab.c
STL_PORTMAGIC 0x5a7182c9 stlport include/linux/stallion.h
EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev drivers/atm/lanai.c
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state include/linux/hdlcdrv.h
EPCA_MAGIC 0x5c6df104 channel include/linux/epca.h
PCXX_MAGIC 0x5c6df104 channel drivers/char/pcxx.h
KV_MAGIC 0x5f4b565f kernel_vars_s arch/mips/include/asm/sn/klkernvars.h
I810_STATE_MAGIC 0x63657373 i810_state sound/oss/i810_audio.c
@ -142,17 +133,14 @@ SLOT_MAGIC 0x67267322 slot drivers/hotplug/acpiphp.h
LO_MAGIC 0x68797548 nbd_device include/linux/nbd.h
OPROFILE_MAGIC 0x6f70726f super_block drivers/oprofile/oprofilefs.h
M3_STATE_MAGIC 0x734d724d m3_state sound/oss/maestro3.c
STL_PANELMAGIC 0x7ef621a1 stlpanel include/linux/stallion.h
VMALLOC_MAGIC 0x87654320 snd_alloc_track sound/core/memory.c
KMALLOC_MAGIC 0x87654321 snd_alloc_track sound/core/memory.c
PWC_MAGIC 0x89DC10AB pwc_device drivers/usb/media/pwc.h
NBD_REPLY_MAGIC 0x96744668 nbd_reply include/linux/nbd.h
STL_BOARDMAGIC 0xa2267f52 stlbrd include/linux/stallion.h
ENI155_MAGIC 0xa54b872d midway_eprom drivers/atm/eni.h
SCI_MAGIC 0xbabeface gs_port drivers/char/sh-sci.h
CODA_MAGIC 0xC0DAC0DA coda_file_info include/linux/coda_fs_i.h
DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram drivers/scsi/gdth.h
STLI_PORTMAGIC 0xe671c7a1 stliport include/linux/istallion.h
YAM_MAGIC 0xF10A7654 yam_port drivers/net/hamradio/yam.c
CCB_MAGIC 0xf2691ad2 ccb drivers/scsi/ncr53c8xx.c
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry drivers/scsi/arm/queue.c

View File

@ -42,7 +42,7 @@ Documentation/stable_kernel_rules.txt 的中文翻译
向稳定版代码树提交补丁的过程:
- 在确认了补丁符合以上的规则后将补丁发送到stable@kernel.org。
- 在确认了补丁符合以上的规则后将补丁发送到stable@vger.kernel.org。
- 如果补丁被接受到队列里发送者会收到一个ACK回复如果没有被接受
到的是NAK回复。回复需要几天的时间这取决于开发者的时间安排。
- 被接受的补丁会被加到稳定版本队列里,等待其他开发者的审查。

View File

@ -8315,7 +8315,7 @@ F: include/linux/compiler.h
SPEAR PLATFORM SUPPORT
M: Viresh Kumar <viresh.linux@gmail.com>
M: Shiraz Hashim <shiraz.hashim@st.com>
M: Shiraz Hashim <shiraz.linux.kernel@gmail.com>
L: spear-devel@list.st.com
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
W: http://www.st.com/spear

View File

@ -1,7 +1,7 @@
VERSION = 3
PATCHLEVEL = 15
SUBLEVEL = 0
EXTRAVERSION = -rc1
EXTRAVERSION = -rc2
NAME = Shuffling Zombie Juror
# *DOCUMENTATION*

View File

@ -1,37 +0,0 @@
/*
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_BARRIER_H
#define __ASM_BARRIER_H
#ifndef __ASSEMBLY__
/* TODO-vineetg: Need to see what this does, don't we need sync anywhere */
#define mb() __asm__ __volatile__ ("" : : : "memory")
#define rmb() mb()
#define wmb() mb()
#define set_mb(var, value) do { var = value; mb(); } while (0)
#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#define read_barrier_depends() mb()
/* TODO-vineetg verify the correctness of macros here */
#ifdef CONFIG_SMP
#define smp_mb() mb()
#define smp_rmb() rmb()
#define smp_wmb() wmb()
#else
#define smp_mb() barrier()
#define smp_rmb() barrier()
#define smp_wmb() barrier()
#endif
#define smp_read_barrier_depends() do { } while (0)
#endif
#endif

View File

@ -1,7 +1,7 @@
/*
* DTS file for SPEAr320 Evaluation Baord
*
* Copyright 2012 Shiraz Hashim <shiraz.hashim@st.com>
* Copyright 2012 Shiraz Hashim <shiraz.linux.kernel@gmail.com>
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License

View File

@ -3,7 +3,7 @@
*
* Picked from realview
* Copyright (c) 2012 ST Microelectronics Limited
* Shiraz Hashim <shiraz.hashim@st.com>
* Shiraz Hashim <shiraz.linux.kernel@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as

View File

@ -4,7 +4,7 @@
* based upon linux/arch/arm/mach-realview/platsmp.c
*
* Copyright (C) 2012 ST Microelectronics Ltd.
* Shiraz Hashim <shiraz.hashim@st.com>
* Shiraz Hashim <shiraz.linux.kernel@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as

View File

@ -2,7 +2,7 @@
* arch/arm/plat-spear/time.c
*
* Copyright (C) 2010 ST Microelectronics
* Shiraz Hashim<shiraz.hashim@st.com>
* Shiraz Hashim<shiraz.linux.kernel@gmail.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any

View File

@ -29,15 +29,15 @@ void (*flush_cache_range)(struct vm_area_struct *vma, unsigned long start,
void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page,
unsigned long pfn);
void (*flush_icache_range)(unsigned long start, unsigned long end);
EXPORT_SYMBOL_GPL(flush_icache_range);
void (*local_flush_icache_range)(unsigned long start, unsigned long end);
void (*__flush_cache_vmap)(void);
void (*__flush_cache_vunmap)(void);
void (*__flush_kernel_vmap_range)(unsigned long vaddr, int size);
void (*__invalidate_kernel_vmap_range)(unsigned long vaddr, int size);
EXPORT_SYMBOL_GPL(__flush_kernel_vmap_range);
void (*__invalidate_kernel_vmap_range)(unsigned long vaddr, int size);
/* MIPS specific cache operations */
void (*flush_cache_sigtramp)(unsigned long addr);

View File

@ -1,8 +1,7 @@
#ifndef _ASMPARISC_SHMPARAM_H
#define _ASMPARISC_SHMPARAM_H
#define __ARCH_FORCE_SHMLBA 1
#define SHMLBA 0x00400000 /* attach addr needs to be 4 Mb aligned */
#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */
#define SHM_COLOUR 0x00400000 /* shared mappings colouring */
#endif /* _ASMPARISC_SHMPARAM_H */

View File

@ -323,7 +323,8 @@ void flush_dcache_page(struct page *page)
* specifically accesses it, of course) */
flush_tlb_page(mpnt, addr);
if (old_addr == 0 || (old_addr & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) {
if (old_addr == 0 || (old_addr & (SHM_COLOUR - 1))
!= (addr & (SHM_COLOUR - 1))) {
__flush_cache_page(mpnt, addr, page_to_phys(page));
if (old_addr)
printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? (char *)mpnt->vm_file->f_path.dentry->d_name.name : "(null)");

View File

@ -45,7 +45,7 @@
static int get_offset(unsigned int last_mmap)
{
return (last_mmap & (SHMLBA-1)) >> PAGE_SHIFT;
return (last_mmap & (SHM_COLOUR-1)) >> PAGE_SHIFT;
}
static unsigned long shared_align_offset(unsigned int last_mmap,
@ -57,8 +57,8 @@ static unsigned long shared_align_offset(unsigned int last_mmap,
static inline unsigned long COLOR_ALIGN(unsigned long addr,
unsigned int last_mmap, unsigned long pgoff)
{
unsigned long base = (addr+SHMLBA-1) & ~(SHMLBA-1);
unsigned long off = (SHMLBA-1) &
unsigned long base = (addr+SHM_COLOUR-1) & ~(SHM_COLOUR-1);
unsigned long off = (SHM_COLOUR-1) &
(shared_align_offset(last_mmap, pgoff) << PAGE_SHIFT);
return base + off;
@ -101,7 +101,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
if (flags & MAP_FIXED) {
if ((flags & MAP_SHARED) && last_mmap &&
(addr - shared_align_offset(last_mmap, pgoff))
& (SHMLBA - 1))
& (SHM_COLOUR - 1))
return -EINVAL;
goto found_addr;
}
@ -122,7 +122,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
info.length = len;
info.low_limit = mm->mmap_legacy_base;
info.high_limit = mmap_upper_limit();
info.align_mask = last_mmap ? (PAGE_MASK & (SHMLBA - 1)) : 0;
info.align_mask = last_mmap ? (PAGE_MASK & (SHM_COLOUR - 1)) : 0;
info.align_offset = shared_align_offset(last_mmap, pgoff);
addr = vm_unmapped_area(&info);
@ -161,7 +161,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
if (flags & MAP_FIXED) {
if ((flags & MAP_SHARED) && last_mmap &&
(addr - shared_align_offset(last_mmap, pgoff))
& (SHMLBA - 1))
& (SHM_COLOUR - 1))
return -EINVAL;
goto found_addr;
}
@ -182,7 +182,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
info.length = len;
info.low_limit = PAGE_SIZE;
info.high_limit = mm->mmap_base;
info.align_mask = last_mmap ? (PAGE_MASK & (SHMLBA - 1)) : 0;
info.align_mask = last_mmap ? (PAGE_MASK & (SHM_COLOUR - 1)) : 0;
info.align_offset = shared_align_offset(last_mmap, pgoff);
addr = vm_unmapped_area(&info);
if (!(addr & ~PAGE_MASK))

View File

@ -392,7 +392,7 @@
ENTRY_COMP(vmsplice)
ENTRY_COMP(move_pages) /* 295 */
ENTRY_SAME(getcpu)
ENTRY_SAME(epoll_pwait)
ENTRY_COMP(epoll_pwait)
ENTRY_COMP(statfs64)
ENTRY_COMP(fstatfs64)
ENTRY_COMP(kexec_load) /* 300 */

View File

@ -470,7 +470,7 @@ static unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len)
return 0;
/* if a load or store fault occured we can get the faulty addr */
d = &__get_cpu_var(exception_data);
d = this_cpu_ptr(&exception_data);
fault_addr = d->fault_addr;
/* error in load or store? */

View File

@ -151,7 +151,7 @@ int fixup_exception(struct pt_regs *regs)
fix = search_exception_tables(regs->iaoq[0]);
if (fix) {
struct exception_data *d;
d = &__get_cpu_var(exception_data);
d = this_cpu_ptr(&exception_data);
d->fault_ip = regs->iaoq[0];
d->fault_space = regs->isr;
d->fault_addr = regs->ior;

View File

@ -208,7 +208,7 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus,
unsigned long in_devfn)
{
struct pci_controller* hose;
struct pci_bus *bus = NULL;
struct pci_bus *tmp_bus, *bus = NULL;
struct device_node *hose_node;
/* Argh ! Please forgive me for that hack, but that's the
@ -229,10 +229,12 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus,
* used on pre-domains setup. We return the first match
*/
list_for_each_entry(bus, &pci_root_buses, node) {
if (in_bus >= bus->number && in_bus <= bus->busn_res.end)
list_for_each_entry(tmp_bus, &pci_root_buses, node) {
if (in_bus >= tmp_bus->number &&
in_bus <= tmp_bus->busn_res.end) {
bus = tmp_bus;
break;
bus = NULL;
}
}
if (bus == NULL || bus->dev.of_node == NULL)
return -ENODEV;

View File

@ -232,6 +232,7 @@ int __node_distance(int a, int b)
return distance;
}
EXPORT_SYMBOL(__node_distance);
static void initialize_distance_lookup_table(int nid,
const __be32 *associativity)

View File

@ -136,6 +136,7 @@ extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg);
extern int os_get_ifname(int fd, char *namebuf);
extern int os_set_slip(int fd);
extern int os_mode_fd(int fd, int mode);
extern int os_fsync_file(int fd);
extern int os_seek_file(int fd, unsigned long long offset);
extern int os_open_file(const char *file, struct openflags flags, int mode);

View File

@ -103,6 +103,7 @@ void __init setup_physmem(unsigned long start, unsigned long reserve_end,
*/
os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
os_fsync_file(physmem_fd);
bootmap_size = init_bootmem(pfn, pfn + delta);
free_bootmem(__pa(reserve_end) + bootmap_size,

View File

@ -237,6 +237,12 @@ void os_close_file(int fd)
{
close(fd);
}
int os_fsync_file(int fd)
{
if (fsync(fd) < 0)
return -errno;
return 0;
}
int os_seek_file(int fd, unsigned long long offset)
{

View File

@ -151,6 +151,7 @@ int __init main(int argc, char **argv, char **envp)
#endif
do_uml_initcalls();
change_sig(SIGPIPE, 0);
ret = linux_main(argc, argv);
/*

View File

@ -12,337 +12,117 @@
#include <string.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/vfs.h>
#include <linux/magic.h>
#include <init.h>
#include <os.h>
/* Modified by which_tmpdir, which is called during early boot */
static char *default_tmpdir = "/tmp";
/*
* Modified when creating the physical memory file and when checking
* the tmp filesystem for usability, both happening during early boot.
*/
/* Set by make_tempfile() during early boot. */
static char *tempdir = NULL;
static void __init find_tempdir(void)
/* Check if dir is on tmpfs. Return 0 if yes, -1 if no or error. */
static int __init check_tmpfs(const char *dir)
{
const char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
int i;
char *dir = NULL;
struct statfs st;
if (tempdir != NULL)
/* We've already been called */
return;
for (i = 0; dirs[i]; i++) {
dir = getenv(dirs[i]);
if ((dir != NULL) && (*dir != '\0'))
break;
}
if ((dir == NULL) || (*dir == '\0'))
dir = default_tmpdir;
tempdir = malloc(strlen(dir) + 2);
if (tempdir == NULL) {
fprintf(stderr, "Failed to malloc tempdir, "
"errno = %d\n", errno);
return;
}
strcpy(tempdir, dir);
strcat(tempdir, "/");
}
/*
* Remove bytes from the front of the buffer and refill it so that if there's a
* partial string that we care about, it will be completed, and we can recognize
* it.
*/
static int pop(int fd, char *buf, size_t size, size_t npop)
{
ssize_t n;
size_t len = strlen(&buf[npop]);
memmove(buf, &buf[npop], len + 1);
n = read(fd, &buf[len], size - len - 1);
if (n < 0)
return -errno;
buf[len + n] = '\0';
return 1;
}
/*
* This will return 1, with the first character in buf being the
* character following the next instance of c in the file. This will
* read the file as needed. If there's an error, -errno is returned;
* if the end of the file is reached, 0 is returned.
*/
static int next(int fd, char *buf, size_t size, char c)
{
ssize_t n;
char *ptr;
while ((ptr = strchr(buf, c)) == NULL) {
n = read(fd, buf, size - 1);
if (n == 0)
return 0;
else if (n < 0)
return -errno;
buf[n] = '\0';
}
return pop(fd, buf, size, ptr - buf + 1);
}
/*
* Decode an octal-escaped and space-terminated path of the form used by
* /proc/mounts. May be used to decode a path in-place. "out" must be at least
* as large as the input. The output is always null-terminated. "len" gets the
* length of the output, excluding the trailing null. Returns 0 if a full path
* was successfully decoded, otherwise an error.
*/
static int decode_path(const char *in, char *out, size_t *len)
{
char *first = out;
int c;
int i;
int ret = -EINVAL;
while (1) {
switch (*in) {
case '\0':
goto out;
case ' ':
ret = 0;
goto out;
case '\\':
in++;
c = 0;
for (i = 0; i < 3; i++) {
if (*in < '0' || *in > '7')
goto out;
c = (c << 3) | (*in++ - '0');
}
*(unsigned char *)out++ = (unsigned char) c;
break;
default:
*out++ = *in++;
break;
}
}
out:
*out = '\0';
*len = out - first;
return ret;
}
/*
* Computes the length of s when encoded with three-digit octal escape sequences
* for the characters in chars.
*/
static size_t octal_encoded_length(const char *s, const char *chars)
{
size_t len = strlen(s);
while ((s = strpbrk(s, chars)) != NULL) {
len += 3;
s++;
}
return len;
}
enum {
OUTCOME_NOTHING_MOUNTED,
OUTCOME_TMPFS_MOUNT,
OUTCOME_NON_TMPFS_MOUNT,
};
/* Read a line of /proc/mounts data looking for a tmpfs mount at "path". */
static int read_mount(int fd, char *buf, size_t bufsize, const char *path,
int *outcome)
{
int found;
int match;
char *space;
size_t len;
enum {
MATCH_NONE,
MATCH_EXACT,
MATCH_PARENT,
};
found = next(fd, buf, bufsize, ' ');
if (found != 1)
return found;
/*
* If there's no following space in the buffer, then this path is
* truncated, so it can't be the one we're looking for.
*/
space = strchr(buf, ' ');
if (space) {
match = MATCH_NONE;
if (!decode_path(buf, buf, &len)) {
if (!strcmp(buf, path))
match = MATCH_EXACT;
else if (!strncmp(buf, path, len)
&& (path[len] == '/' || !strcmp(buf, "/")))
match = MATCH_PARENT;
}
found = pop(fd, buf, bufsize, space - buf + 1);
if (found != 1)
return found;
switch (match) {
case MATCH_EXACT:
if (!strncmp(buf, "tmpfs", strlen("tmpfs")))
*outcome = OUTCOME_TMPFS_MOUNT;
else
*outcome = OUTCOME_NON_TMPFS_MOUNT;
break;
case MATCH_PARENT:
/* This mount obscures any previous ones. */
*outcome = OUTCOME_NOTHING_MOUNTED;
break;
}
}
return next(fd, buf, bufsize, '\n');
}
/* which_tmpdir is called only during early boot */
static int checked_tmpdir = 0;
/*
* Look for a tmpfs mounted at /dev/shm. I couldn't find a cleaner
* way to do this than to parse /proc/mounts. statfs will return the
* same filesystem magic number and fs id for both /dev and /dev/shm
* when they are both tmpfs, so you can't tell if they are different
* filesystems. Also, there seems to be no other way of finding the
* mount point of a filesystem from within it.
*
* If a /dev/shm tmpfs entry is found, then we switch to using it.
* Otherwise, we stay with the default /tmp.
*/
static void which_tmpdir(void)
{
int fd;
int found;
int outcome;
char *path;
char *buf;
size_t bufsize;
if (checked_tmpdir)
return;
checked_tmpdir = 1;
printf("Checking for tmpfs mount on /dev/shm...");
path = realpath("/dev/shm", NULL);
if (!path) {
printf("failed to check real path, errno = %d\n", errno);
return;
}
printf("%s...", path);
/*
* The buffer needs to be able to fit the full octal-escaped path, a
* space, and a trailing null in order to successfully decode it.
*/
bufsize = octal_encoded_length(path, " \t\n\\") + 2;
if (bufsize < 128)
bufsize = 128;
buf = malloc(bufsize);
if (!buf) {
printf("malloc failed, errno = %d\n", errno);
goto out;
}
buf[0] = '\0';
fd = open("/proc/mounts", O_RDONLY);
if (fd < 0) {
printf("failed to open /proc/mounts, errno = %d\n", errno);
goto out1;
}
outcome = OUTCOME_NOTHING_MOUNTED;
while (1) {
found = read_mount(fd, buf, bufsize, path, &outcome);
if (found != 1)
break;
}
if (found < 0) {
printf("read returned errno %d\n", -found);
printf("Checking if %s is on tmpfs...", dir);
if (statfs(dir, &st) < 0) {
printf("%s\n", strerror(errno));
} else if (st.f_type != TMPFS_MAGIC) {
printf("no\n");
} else {
switch (outcome) {
case OUTCOME_TMPFS_MOUNT:
printf("OK\n");
default_tmpdir = "/dev/shm";
break;
case OUTCOME_NON_TMPFS_MOUNT:
printf("not tmpfs\n");
break;
default:
printf("nothing mounted on /dev/shm\n");
break;
}
printf("OK\n");
return 0;
}
close(fd);
out1:
free(buf);
out:
free(path);
return -1;
}
static int __init make_tempfile(const char *template, char **out_tempname,
int do_unlink)
/*
* Choose the tempdir to use. We want something on tmpfs so that our memory is
* not subject to the host's vm.dirty_ratio. If a tempdir is specified in the
* environment, we use that even if it's not on tmpfs, but we warn the user.
* Otherwise, we try common tmpfs locations, and if no tmpfs directory is found
* then we fall back to /tmp.
*/
static char * __init choose_tempdir(void)
{
static const char * const vars[] = {
"TMPDIR",
"TMP",
"TEMP",
NULL
};
static const char fallback_dir[] = "/tmp";
static const char * const tmpfs_dirs[] = {
"/dev/shm",
fallback_dir,
NULL
};
int i;
const char *dir;
printf("Checking environment variables for a tempdir...");
for (i = 0; vars[i]; i++) {
dir = getenv(vars[i]);
if ((dir != NULL) && (*dir != '\0')) {
printf("%s\n", dir);
if (check_tmpfs(dir) >= 0)
goto done;
else
goto warn;
}
}
printf("none found\n");
for (i = 0; tmpfs_dirs[i]; i++) {
dir = tmpfs_dirs[i];
if (check_tmpfs(dir) >= 0)
goto done;
}
dir = fallback_dir;
warn:
printf("Warning: tempdir %s is not on tmpfs\n", dir);
done:
/* Make a copy since getenv results may not remain valid forever. */
return strdup(dir);
}
/*
* Create an unlinked tempfile in a suitable tempdir. template must be the
* basename part of the template with a leading '/'.
*/
static int __init make_tempfile(const char *template)
{
char *tempname;
int fd;
which_tmpdir();
tempname = malloc(MAXPATHLEN);
if (tempdir == NULL) {
tempdir = choose_tempdir();
if (tempdir == NULL) {
fprintf(stderr, "Failed to choose tempdir: %s\n",
strerror(errno));
return -1;
}
}
tempname = malloc(strlen(tempdir) + strlen(template) + 1);
if (tempname == NULL)
return -1;
find_tempdir();
if ((tempdir == NULL) || (strlen(tempdir) >= MAXPATHLEN))
goto out;
if (template[0] != '/')
strcpy(tempname, tempdir);
else
tempname[0] = '\0';
strncat(tempname, template, MAXPATHLEN-1-strlen(tempname));
strcpy(tempname, tempdir);
strcat(tempname, template);
fd = mkstemp(tempname);
if (fd < 0) {
fprintf(stderr, "open - cannot create %s: %s\n", tempname,
strerror(errno));
goto out;
}
if (do_unlink && (unlink(tempname) < 0)) {
if (unlink(tempname) < 0) {
perror("unlink");
goto close;
}
if (out_tempname) {
*out_tempname = tempname;
} else
free(tempname);
free(tempname);
return fd;
close:
close(fd);
@ -351,14 +131,14 @@ out:
return -1;
}
#define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
#define TEMPNAME_TEMPLATE "/vm_file-XXXXXX"
static int __init create_tmp_file(unsigned long long len)
{
int fd, err;
char zero;
fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1);
fd = make_tempfile(TEMPNAME_TEMPLATE);
if (fd < 0)
exit(1);
@ -402,7 +182,6 @@ int __init create_mem_file(unsigned long long len)
return fd;
}
void __init check_tmpexec(void)
{
void *addr;
@ -410,14 +189,13 @@ void __init check_tmpexec(void)
addr = mmap(NULL, UM_KERN_PAGE_SIZE,
PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
printf("Checking PROT_EXEC mmap in %s...",tempdir);
fflush(stdout);
printf("Checking PROT_EXEC mmap in %s...", tempdir);
if (addr == MAP_FAILED) {
err = errno;
perror("failed");
printf("%s\n", strerror(err));
close(fd);
if (err == EPERM)
printf("%s must be not mounted noexec\n",tempdir);
printf("%s must be not mounted noexec\n", tempdir);
exit(1);
}
printf("OK\n");

View File

@ -598,7 +598,6 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
{
struct mce m;
int i;
unsigned long *v;
this_cpu_inc(mce_poll_count);
@ -618,8 +617,7 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
if (!(m.status & MCI_STATUS_VAL))
continue;
v = &get_cpu_var(mce_polled_error);
set_bit(0, v);
this_cpu_write(mce_polled_error, 1);
/*
* Uncorrected or signalled events are handled by the exception
* handler when it is enabled, so don't process those here.

View File

@ -42,7 +42,7 @@ static DEFINE_PER_CPU(mce_banks_t, mce_banks_owned);
* cmci_discover_lock protects against parallel discovery attempts
* which could race against each other.
*/
static DEFINE_RAW_SPINLOCK(cmci_discover_lock);
static DEFINE_SPINLOCK(cmci_discover_lock);
#define CMCI_THRESHOLD 1
#define CMCI_POLL_INTERVAL (30 * HZ)
@ -144,14 +144,14 @@ static void cmci_storm_disable_banks(void)
int bank;
u64 val;
raw_spin_lock_irqsave(&cmci_discover_lock, flags);
spin_lock_irqsave(&cmci_discover_lock, flags);
owned = __get_cpu_var(mce_banks_owned);
for_each_set_bit(bank, owned, MAX_NR_BANKS) {
rdmsrl(MSR_IA32_MCx_CTL2(bank), val);
val &= ~MCI_CTL2_CMCI_EN;
wrmsrl(MSR_IA32_MCx_CTL2(bank), val);
}
raw_spin_unlock_irqrestore(&cmci_discover_lock, flags);
spin_unlock_irqrestore(&cmci_discover_lock, flags);
}
static bool cmci_storm_detect(void)
@ -211,7 +211,7 @@ static void cmci_discover(int banks)
int i;
int bios_wrong_thresh = 0;
raw_spin_lock_irqsave(&cmci_discover_lock, flags);
spin_lock_irqsave(&cmci_discover_lock, flags);
for (i = 0; i < banks; i++) {
u64 val;
int bios_zero_thresh = 0;
@ -266,7 +266,7 @@ static void cmci_discover(int banks)
WARN_ON(!test_bit(i, __get_cpu_var(mce_poll_banks)));
}
}
raw_spin_unlock_irqrestore(&cmci_discover_lock, flags);
spin_unlock_irqrestore(&cmci_discover_lock, flags);
if (mca_cfg.bios_cmci_threshold && bios_wrong_thresh) {
pr_info_once(
"bios_cmci_threshold: Some banks do not have valid thresholds set\n");
@ -316,10 +316,10 @@ void cmci_clear(void)
if (!cmci_supported(&banks))
return;
raw_spin_lock_irqsave(&cmci_discover_lock, flags);
spin_lock_irqsave(&cmci_discover_lock, flags);
for (i = 0; i < banks; i++)
__cmci_disable_bank(i);
raw_spin_unlock_irqrestore(&cmci_discover_lock, flags);
spin_unlock_irqrestore(&cmci_discover_lock, flags);
}
static void cmci_rediscover_work_func(void *arg)
@ -360,9 +360,9 @@ void cmci_disable_bank(int bank)
if (!cmci_supported(&banks))
return;
raw_spin_lock_irqsave(&cmci_discover_lock, flags);
spin_lock_irqsave(&cmci_discover_lock, flags);
__cmci_disable_bank(bank);
raw_spin_unlock_irqrestore(&cmci_discover_lock, flags);
spin_unlock_irqrestore(&cmci_discover_lock, flags);
}
static void intel_init_cmci(void)

View File

@ -543,7 +543,8 @@ static int rapl_cpu_prepare(int cpu)
if (phys_id < 0)
return -1;
if (!rdmsrl_safe(MSR_RAPL_POWER_UNIT, &msr_rapl_power_unit_bits))
/* protect rdmsrl() to handle virtualization */
if (rdmsrl_safe(MSR_RAPL_POWER_UNIT, &msr_rapl_power_unit_bits))
return -1;
pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu));

View File

@ -9,12 +9,9 @@ SECTIONS
#ifdef BUILD_VDSO32
#include <asm/vdso32.h>
.hpet_sect : {
hpet_page = . - VDSO_OFFSET(VDSO_HPET_PAGE);
} :text :hpet_sect
hpet_page = . - VDSO_OFFSET(VDSO_HPET_PAGE);
.vvar_sect : {
vvar = . - VDSO_OFFSET(VDSO_VVAR_PAGE);
vvar = . - VDSO_OFFSET(VDSO_VVAR_PAGE);
/* Place all vvars at the offsets in asm/vvar.h. */
#define EMIT_VVAR(name, offset) vvar_ ## name = vvar + offset;
@ -22,7 +19,6 @@ SECTIONS
#include <asm/vvar.h>
#undef __VVAR_KERNEL_LDS
#undef EMIT_VVAR
} :text :vvar_sect
#endif
. = SIZEOF_HEADERS;
@ -61,7 +57,12 @@ SECTIONS
*/
. = ALIGN(0x100);
.text : { *(.text*) } :text =0x90909090
.text : { *(.text*) } :text =0x90909090,
/*
* The comma above works around a bug in gold:
* https://sourceware.org/bugzilla/show_bug.cgi?id=16804
*/
/DISCARD/ : {
*(.discard)
@ -84,8 +85,4 @@ PHDRS
dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
note PT_NOTE FLAGS(4); /* PF_R */
eh_frame_hdr PT_GNU_EH_FRAME;
#ifdef BUILD_VDSO32
vvar_sect PT_NULL FLAGS(4); /* PF_R */
hpet_sect PT_NULL FLAGS(4); /* PF_R */
#endif
}

View File

@ -441,10 +441,11 @@ static int xen_cpu_up(unsigned int cpu, struct task_struct *idle)
irq_ctx_init(cpu);
#else
clear_tsk_thread_flag(idle, TIF_FORK);
#endif
per_cpu(kernel_stack, cpu) =
(unsigned long)task_stack_page(idle) -
KERNEL_STACK_OFFSET + THREAD_SIZE;
#endif
xen_setup_runstate_info(cpu);
xen_setup_timer(cpu);
xen_init_lock_cpu(cpu);

View File

@ -274,7 +274,7 @@ void __init xen_init_spinlocks(void)
printk(KERN_DEBUG "xen: PV spinlocks disabled\n");
return;
}
printk(KERN_DEBUG "xen: PV spinlocks enabled\n");
pv_lock_ops.lock_spinning = PV_CALLEE_SAVE(xen_lock_spinning);
pv_lock_ops.unlock_kick = xen_unlock_kick;
}
@ -290,6 +290,9 @@ static __init int xen_init_spinlocks_jump(void)
if (!xen_pvspin)
return 0;
if (!xen_domain())
return 0;
static_key_slow_inc(&paravirt_ticketlocks_enabled);
return 0;
}

View File

@ -75,6 +75,17 @@ ENDPROC(xen_sysexit)
* stack state in whatever form its in, we keep things simple by only
* using a single register which is pushed/popped on the stack.
*/
.macro POP_FS
1:
popw %fs
.pushsection .fixup, "ax"
2: movw $0, (%esp)
jmp 1b
.popsection
_ASM_EXTABLE(1b,2b)
.endm
ENTRY(xen_iret)
/* test eflags for special cases */
testl $(X86_EFLAGS_VM | XEN_EFLAGS_NMI), 8(%esp)
@ -83,15 +94,13 @@ ENTRY(xen_iret)
push %eax
ESP_OFFSET=4 # bytes pushed onto stack
/*
* Store vcpu_info pointer for easy access. Do it this way to
* avoid having to reload %fs
*/
/* Store vcpu_info pointer for easy access */
#ifdef CONFIG_SMP
GET_THREAD_INFO(%eax)
movl %ss:TI_cpu(%eax), %eax
movl %ss:__per_cpu_offset(,%eax,4), %eax
mov %ss:xen_vcpu(%eax), %eax
pushw %fs
movl $(__KERNEL_PERCPU), %eax
movl %eax, %fs
movl %fs:xen_vcpu, %eax
POP_FS
#else
movl %ss:xen_vcpu, %eax
#endif

View File

@ -53,8 +53,8 @@ obj-y += gpu/
obj-$(CONFIG_CONNECTOR) += connector/
# i810fb and intelfb depend on char/agp/
obj-$(CONFIG_FB_I810) += video/i810/
obj-$(CONFIG_FB_INTEL) += video/intelfb/
obj-$(CONFIG_FB_I810) += video/fbdev/i810/
obj-$(CONFIG_FB_INTEL) += video/fbdev/intelfb/
obj-$(CONFIG_PARPORT) += parport/
obj-y += base/ block/ misc/ mfd/ nfc/

View File

@ -614,39 +614,6 @@ void device_remove_bin_file(struct device *dev,
}
EXPORT_SYMBOL_GPL(device_remove_bin_file);
/**
* device_schedule_callback_owner - helper to schedule a callback for a device
* @dev: device.
* @func: callback function to invoke later.
* @owner: module owning the callback routine
*
* Attribute methods must not unregister themselves or their parent device
* (which would amount to the same thing). Attempts to do so will deadlock,
* since unregistration is mutually exclusive with driver callbacks.
*
* Instead methods can call this routine, which will attempt to allocate
* and schedule a workqueue request to call back @func with @dev as its
* argument in the workqueue's process context. @dev will be pinned until
* @func returns.
*
* This routine is usually called via the inline device_schedule_callback(),
* which automatically sets @owner to THIS_MODULE.
*
* Returns 0 if the request was submitted, -ENOMEM if storage could not
* be allocated, -ENODEV if a reference to @owner isn't available.
*
* NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an
* underlying sysfs routine (since it is intended for use by attribute
* methods), and if sysfs isn't available you'll get nothing but -ENOSYS.
*/
int device_schedule_callback_owner(struct device *dev,
void (*func)(struct device *), struct module *owner)
{
return sysfs_schedule_callback(&dev->kobj,
(void (*)(void *)) func, dev, owner);
}
EXPORT_SYMBOL_GPL(device_schedule_callback_owner);
static void klist_children_get(struct klist_node *n)
{
struct device_private *p = to_device_private_parent(n);

View File

@ -187,8 +187,8 @@ static void driver_bound(struct device *dev)
return;
}
pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),
__func__, dev->driver->name);
pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->driver->name,
__func__, dev_name(dev));
klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);

View File

@ -39,8 +39,7 @@
static ssize_t show_##name(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
unsigned int cpu = dev->id; \
return sprintf(buf, "%d\n", topology_##name(cpu)); \
return sprintf(buf, "%d\n", topology_##name(dev->id)); \
}
#if defined(topology_thread_cpumask) || defined(topology_core_cpumask) || \

View File

@ -40,7 +40,7 @@ config SGI_MBCS
source "drivers/tty/serial/Kconfig"
config TTY_PRINTK
bool "TTY driver to output user messages via printk"
tristate "TTY driver to output user messages via printk"
depends on EXPERT && TTY
default n
---help---

View File

@ -50,6 +50,18 @@ config IPMI_SI
Currently, only KCS and SMIC are supported. If
you are using IPMI, you should probably say "y" here.
config IPMI_SI_PROBE_DEFAULTS
bool 'Probe for all possible IPMI system interfaces by default'
default n
depends on IPMI_SI
help
Modern systems will usually expose IPMI interfaces via a discoverable
firmware mechanism such as ACPI or DMI. Older systems do not, and so
the driver is forced to probe hardware manually. This may cause boot
delays. Say "n" here to disable this manual probing. IPMI will then
only be available on older systems if the "ipmi_si_intf.trydefaults=1"
boot argument is passed.
config IPMI_WATCHDOG
tristate 'IPMI Watchdog Timer'
help

View File

@ -352,7 +352,7 @@ static inline void write_all_bytes(struct si_sm_data *bt)
static inline int read_all_bytes(struct si_sm_data *bt)
{
unsigned char i;
unsigned int i;
/*
* length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode.

View File

@ -251,8 +251,9 @@ static inline int check_obf(struct si_sm_data *kcs, unsigned char status,
if (!GET_STATUS_OBF(status)) {
kcs->obf_timeout -= time;
if (kcs->obf_timeout < 0) {
start_error_recovery(kcs, "OBF not ready in time");
return 1;
kcs->obf_timeout = OBF_RETRY_TIMEOUT;
start_error_recovery(kcs, "OBF not ready in time");
return 1;
}
return 0;
}

View File

@ -55,6 +55,7 @@ static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
static int ipmi_init_msghandler(void);
static void smi_recv_tasklet(unsigned long);
static void handle_new_recv_msgs(ipmi_smi_t intf);
static void need_waiter(ipmi_smi_t intf);
static int initialized;
@ -73,14 +74,28 @@ static struct proc_dir_entry *proc_ipmi_root;
*/
#define MAX_MSG_TIMEOUT 60000
/* Call every ~1000 ms. */
#define IPMI_TIMEOUT_TIME 1000
/* How many jiffies does it take to get to the timeout time. */
#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
/*
* Request events from the queue every second (this is the number of
* IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
* future, IPMI will add a way to know immediately if an event is in
* the queue and this silliness can go away.
*/
#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
/*
* The main "user" data structure.
*/
struct ipmi_user {
struct list_head link;
/* Set to "0" when the user is destroyed. */
int valid;
/* Set to false when the user is destroyed. */
bool valid;
struct kref refcount;
@ -92,7 +107,7 @@ struct ipmi_user {
ipmi_smi_t intf;
/* Does this interface receive IPMI events? */
int gets_events;
bool gets_events;
};
struct cmd_rcvr {
@ -383,6 +398,9 @@ struct ipmi_smi {
unsigned int waiting_events_count; /* How many events in queue? */
char delivering_events;
char event_msg_printed;
atomic_t event_waiters;
unsigned int ticks_to_req_ev;
int last_needs_timer;
/*
* The event receiver for my BMC, only really used at panic
@ -395,7 +413,7 @@ struct ipmi_smi {
/* For handling of maintenance mode. */
int maintenance_mode;
int maintenance_mode_enable;
bool maintenance_mode_enable;
int auto_maintenance_timeout;
spinlock_t maintenance_mode_lock; /* Used in a timer... */
@ -451,7 +469,6 @@ static DEFINE_MUTEX(ipmi_interfaces_mutex);
static LIST_HEAD(smi_watchers);
static DEFINE_MUTEX(smi_watchers_mutex);
#define ipmi_inc_stat(intf, stat) \
atomic_inc(&(intf)->stats[IPMI_STAT_ ## stat])
#define ipmi_get_stat(intf, stat) \
@ -772,6 +789,7 @@ static int intf_next_seq(ipmi_smi_t intf,
*seq = i;
*seqid = intf->seq_table[i].seqid;
intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
need_waiter(intf);
} else {
rv = -EAGAIN;
}
@ -941,7 +959,7 @@ int ipmi_create_user(unsigned int if_num,
new_user->handler = handler;
new_user->handler_data = handler_data;
new_user->intf = intf;
new_user->gets_events = 0;
new_user->gets_events = false;
if (!try_module_get(intf->handlers->owner)) {
rv = -ENODEV;
@ -962,10 +980,15 @@ int ipmi_create_user(unsigned int if_num,
*/
mutex_unlock(&ipmi_interfaces_mutex);
new_user->valid = 1;
new_user->valid = true;
spin_lock_irqsave(&intf->seq_lock, flags);
list_add_rcu(&new_user->link, &intf->users);
spin_unlock_irqrestore(&intf->seq_lock, flags);
if (handler->ipmi_watchdog_pretimeout) {
/* User wants pretimeouts, so make sure to watch for them. */
if (atomic_inc_return(&intf->event_waiters) == 1)
need_waiter(intf);
}
*user = new_user;
return 0;
@ -1019,7 +1042,13 @@ int ipmi_destroy_user(ipmi_user_t user)
struct cmd_rcvr *rcvr;
struct cmd_rcvr *rcvrs = NULL;
user->valid = 0;
user->valid = false;
if (user->handler->ipmi_watchdog_pretimeout)
atomic_dec(&intf->event_waiters);
if (user->gets_events)
atomic_dec(&intf->event_waiters);
/* Remove the user from the interface's sequence table. */
spin_lock_irqsave(&intf->seq_lock, flags);
@ -1155,25 +1184,23 @@ int ipmi_set_maintenance_mode(ipmi_user_t user, int mode)
if (intf->maintenance_mode != mode) {
switch (mode) {
case IPMI_MAINTENANCE_MODE_AUTO:
intf->maintenance_mode = mode;
intf->maintenance_mode_enable
= (intf->auto_maintenance_timeout > 0);
break;
case IPMI_MAINTENANCE_MODE_OFF:
intf->maintenance_mode = mode;
intf->maintenance_mode_enable = 0;
intf->maintenance_mode_enable = false;
break;
case IPMI_MAINTENANCE_MODE_ON:
intf->maintenance_mode = mode;
intf->maintenance_mode_enable = 1;
intf->maintenance_mode_enable = true;
break;
default:
rv = -EINVAL;
goto out_unlock;
}
intf->maintenance_mode = mode;
maintenance_mode_update(intf);
}
@ -1184,7 +1211,7 @@ int ipmi_set_maintenance_mode(ipmi_user_t user, int mode)
}
EXPORT_SYMBOL(ipmi_set_maintenance_mode);
int ipmi_set_gets_events(ipmi_user_t user, int val)
int ipmi_set_gets_events(ipmi_user_t user, bool val)
{
unsigned long flags;
ipmi_smi_t intf = user->intf;
@ -1194,8 +1221,18 @@ int ipmi_set_gets_events(ipmi_user_t user, int val)
INIT_LIST_HEAD(&msgs);
spin_lock_irqsave(&intf->events_lock, flags);
if (user->gets_events == val)
goto out;
user->gets_events = val;
if (val) {
if (atomic_inc_return(&intf->event_waiters) == 1)
need_waiter(intf);
} else {
atomic_dec(&intf->event_waiters);
}
if (intf->delivering_events)
/*
* Another thread is delivering events for this, so
@ -1289,6 +1326,9 @@ int ipmi_register_for_cmd(ipmi_user_t user,
goto out_unlock;
}
if (atomic_inc_return(&intf->event_waiters) == 1)
need_waiter(intf);
list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
out_unlock:
@ -1330,6 +1370,7 @@ int ipmi_unregister_for_cmd(ipmi_user_t user,
mutex_unlock(&intf->cmd_rcvrs_mutex);
synchronize_rcu();
while (rcvrs) {
atomic_dec(&intf->event_waiters);
rcvr = rcvrs;
rcvrs = rcvr->next;
kfree(rcvr);
@ -1535,7 +1576,7 @@ static int i_ipmi_request(ipmi_user_t user,
= IPMI_MAINTENANCE_MODE_TIMEOUT;
if (!intf->maintenance_mode
&& !intf->maintenance_mode_enable) {
intf->maintenance_mode_enable = 1;
intf->maintenance_mode_enable = true;
maintenance_mode_update(intf);
}
spin_unlock_irqrestore(&intf->maintenance_mode_lock,
@ -2876,6 +2917,8 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
(unsigned long) intf);
atomic_set(&intf->watchdog_pretimeouts_to_deliver, 0);
spin_lock_init(&intf->events_lock);
atomic_set(&intf->event_waiters, 0);
intf->ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
INIT_LIST_HEAD(&intf->waiting_events);
intf->waiting_events_count = 0;
mutex_init(&intf->cmd_rcvrs_mutex);
@ -3965,7 +4008,8 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
struct list_head *timeouts, long timeout_period,
int slot, unsigned long *flags)
int slot, unsigned long *flags,
unsigned int *waiting_msgs)
{
struct ipmi_recv_msg *msg;
struct ipmi_smi_handlers *handlers;
@ -3977,8 +4021,10 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
return;
ent->timeout -= timeout_period;
if (ent->timeout > 0)
if (ent->timeout > 0) {
(*waiting_msgs)++;
return;
}
if (ent->retries_left == 0) {
/* The message has used all its retries. */
@ -3995,6 +4041,8 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
struct ipmi_smi_msg *smi_msg;
/* More retries, send again. */
(*waiting_msgs)++;
/*
* Start with the max timer, set to normal timer after
* the message is sent.
@ -4040,117 +4088,118 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
}
}
static void ipmi_timeout_handler(long timeout_period)
static unsigned int ipmi_timeout_handler(ipmi_smi_t intf, long timeout_period)
{
ipmi_smi_t intf;
struct list_head timeouts;
struct ipmi_recv_msg *msg, *msg2;
unsigned long flags;
int i;
unsigned int waiting_msgs = 0;
rcu_read_lock();
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
tasklet_schedule(&intf->recv_tasklet);
/*
* Go through the seq table and find any messages that
* have timed out, putting them in the timeouts
* list.
*/
INIT_LIST_HEAD(&timeouts);
spin_lock_irqsave(&intf->seq_lock, flags);
for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++)
check_msg_timeout(intf, &(intf->seq_table[i]),
&timeouts, timeout_period, i,
&flags, &waiting_msgs);
spin_unlock_irqrestore(&intf->seq_lock, flags);
/*
* Go through the seq table and find any messages that
* have timed out, putting them in the timeouts
* list.
*/
INIT_LIST_HEAD(&timeouts);
spin_lock_irqsave(&intf->seq_lock, flags);
for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++)
check_msg_timeout(intf, &(intf->seq_table[i]),
&timeouts, timeout_period, i,
&flags);
spin_unlock_irqrestore(&intf->seq_lock, flags);
list_for_each_entry_safe(msg, msg2, &timeouts, link)
deliver_err_response(msg, IPMI_TIMEOUT_COMPLETION_CODE);
list_for_each_entry_safe(msg, msg2, &timeouts, link)
deliver_err_response(msg, IPMI_TIMEOUT_COMPLETION_CODE);
/*
* Maintenance mode handling. Check the timeout
* optimistically before we claim the lock. It may
* mean a timeout gets missed occasionally, but that
* only means the timeout gets extended by one period
* in that case. No big deal, and it avoids the lock
* most of the time.
*/
/*
* Maintenance mode handling. Check the timeout
* optimistically before we claim the lock. It may
* mean a timeout gets missed occasionally, but that
* only means the timeout gets extended by one period
* in that case. No big deal, and it avoids the lock
* most of the time.
*/
if (intf->auto_maintenance_timeout > 0) {
spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
if (intf->auto_maintenance_timeout > 0) {
spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
if (intf->auto_maintenance_timeout > 0) {
intf->auto_maintenance_timeout
-= timeout_period;
if (!intf->maintenance_mode
&& (intf->auto_maintenance_timeout <= 0)) {
intf->maintenance_mode_enable = 0;
maintenance_mode_update(intf);
}
intf->auto_maintenance_timeout
-= timeout_period;
if (!intf->maintenance_mode
&& (intf->auto_maintenance_timeout <= 0)) {
intf->maintenance_mode_enable = false;
maintenance_mode_update(intf);
}
spin_unlock_irqrestore(&intf->maintenance_mode_lock,
flags);
}
spin_unlock_irqrestore(&intf->maintenance_mode_lock,
flags);
}
rcu_read_unlock();
tasklet_schedule(&intf->recv_tasklet);
return waiting_msgs;
}
static void ipmi_request_event(void)
static void ipmi_request_event(ipmi_smi_t intf)
{
ipmi_smi_t intf;
struct ipmi_smi_handlers *handlers;
rcu_read_lock();
/*
* Called from the timer, no need to check if handlers is
* valid.
*/
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
/* No event requests when in maintenance mode. */
if (intf->maintenance_mode_enable)
continue;
/* No event requests when in maintenance mode. */
if (intf->maintenance_mode_enable)
return;
handlers = intf->handlers;
if (handlers)
handlers->request_events(intf->send_info);
}
rcu_read_unlock();
handlers = intf->handlers;
if (handlers)
handlers->request_events(intf->send_info);
}
static struct timer_list ipmi_timer;
/* Call every ~1000 ms. */
#define IPMI_TIMEOUT_TIME 1000
/* How many jiffies does it take to get to the timeout time. */
#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
/*
* Request events from the queue every second (this is the number of
* IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
* future, IPMI will add a way to know immediately if an event is in
* the queue and this silliness can go away.
*/
#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
static atomic_t stop_operation;
static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
static void ipmi_timeout(unsigned long data)
{
ipmi_smi_t intf;
int nt = 0;
if (atomic_read(&stop_operation))
return;
ticks_to_req_ev--;
if (ticks_to_req_ev == 0) {
ipmi_request_event();
ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
rcu_read_lock();
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
int lnt = 0;
if (atomic_read(&intf->event_waiters)) {
intf->ticks_to_req_ev--;
if (intf->ticks_to_req_ev == 0) {
ipmi_request_event(intf);
intf->ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
}
lnt++;
}
lnt += ipmi_timeout_handler(intf, IPMI_TIMEOUT_TIME);
lnt = !!lnt;
if (lnt != intf->last_needs_timer &&
intf->handlers->set_need_watch)
intf->handlers->set_need_watch(intf->send_info, lnt);
intf->last_needs_timer = lnt;
nt += lnt;
}
rcu_read_unlock();
ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
if (nt)
mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
}
static void need_waiter(ipmi_smi_t intf)
{
/* Racy, but worst case we start the timer twice. */
if (!timer_pending(&ipmi_timer))
mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
}
static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);

View File

@ -217,7 +217,7 @@ struct smi_info {
unsigned char msg_flags;
/* Does the BMC have an event buffer? */
char has_event_buffer;
bool has_event_buffer;
/*
* If set to true, this will request events the next time the
@ -230,7 +230,7 @@ struct smi_info {
* call. Generally used after a panic to make sure stuff goes
* out.
*/
int run_to_completion;
bool run_to_completion;
/* The I/O port of an SI interface. */
int port;
@ -248,19 +248,25 @@ struct smi_info {
/* The timer for this si. */
struct timer_list si_timer;
/* This flag is set, if the timer is running (timer_pending() isn't enough) */
bool timer_running;
/* The time (in jiffies) the last timeout occurred at. */
unsigned long last_timeout_jiffies;
/* Used to gracefully stop the timer without race conditions. */
atomic_t stop_operation;
/* Are we waiting for the events, pretimeouts, received msgs? */
atomic_t need_watch;
/*
* The driver will disable interrupts when it gets into a
* situation where it cannot handle messages due to lack of
* memory. Once that situation clears up, it will re-enable
* interrupts.
*/
int interrupt_disabled;
bool interrupt_disabled;
/* From the get device id response... */
struct ipmi_device_id device_id;
@ -273,7 +279,7 @@ struct smi_info {
* True if we allocated the device, false if it came from
* someplace else (like PCI).
*/
int dev_registered;
bool dev_registered;
/* Slave address, could be reported from DMI. */
unsigned char slave_addr;
@ -297,19 +303,19 @@ struct smi_info {
static int force_kipmid[SI_MAX_PARMS];
static int num_force_kipmid;
#ifdef CONFIG_PCI
static int pci_registered;
static bool pci_registered;
#endif
#ifdef CONFIG_ACPI
static int pnp_registered;
static bool pnp_registered;
#endif
#ifdef CONFIG_PARISC
static int parisc_registered;
static bool parisc_registered;
#endif
static unsigned int kipmid_max_busy_us[SI_MAX_PARMS];
static int num_max_busy_us;
static int unload_when_empty = 1;
static bool unload_when_empty = true;
static int add_smi(struct smi_info *smi);
static int try_smi_init(struct smi_info *smi);
@ -434,6 +440,13 @@ static void start_clear_flags(struct smi_info *smi_info)
smi_info->si_state = SI_CLEARING_FLAGS;
}
static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
{
smi_info->last_timeout_jiffies = jiffies;
mod_timer(&smi_info->si_timer, new_val);
smi_info->timer_running = true;
}
/*
* When we have a situtaion where we run out of memory and cannot
* allocate messages, we just leave them in the BMC and run the system
@ -444,10 +457,9 @@ static inline void disable_si_irq(struct smi_info *smi_info)
{
if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
start_disable_irq(smi_info);
smi_info->interrupt_disabled = 1;
smi_info->interrupt_disabled = true;
if (!atomic_read(&smi_info->stop_operation))
mod_timer(&smi_info->si_timer,
jiffies + SI_TIMEOUT_JIFFIES);
smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES);
}
}
@ -455,7 +467,7 @@ static inline void enable_si_irq(struct smi_info *smi_info)
{
if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
start_enable_irq(smi_info);
smi_info->interrupt_disabled = 0;
smi_info->interrupt_disabled = false;
}
}
@ -700,7 +712,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
dev_warn(smi_info->dev,
"Maybe ok, but ipmi might run very slowly.\n");
} else
smi_info->interrupt_disabled = 0;
smi_info->interrupt_disabled = false;
smi_info->si_state = SI_NORMAL;
break;
}
@ -853,6 +865,19 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
return si_sm_result;
}
static void check_start_timer_thread(struct smi_info *smi_info)
{
if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) {
smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES);
if (smi_info->thread)
wake_up_process(smi_info->thread);
start_next_msg(smi_info);
smi_event_handler(smi_info, 0);
}
}
static void sender(void *send_info,
struct ipmi_smi_msg *msg,
int priority)
@ -906,27 +931,11 @@ static void sender(void *send_info,
else
list_add_tail(&msg->link, &smi_info->xmit_msgs);
if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) {
/*
* last_timeout_jiffies is updated here to avoid
* smi_timeout() handler passing very large time_diff
* value to smi_event_handler() that causes
* the send command to abort.
*/
smi_info->last_timeout_jiffies = jiffies;
mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
if (smi_info->thread)
wake_up_process(smi_info->thread);
start_next_msg(smi_info);
smi_event_handler(smi_info, 0);
}
check_start_timer_thread(smi_info);
spin_unlock_irqrestore(&smi_info->si_lock, flags);
}
static void set_run_to_completion(void *send_info, int i_run_to_completion)
static void set_run_to_completion(void *send_info, bool i_run_to_completion)
{
struct smi_info *smi_info = send_info;
enum si_sm_result result;
@ -1004,6 +1013,17 @@ static int ipmi_thread(void *data)
spin_lock_irqsave(&(smi_info->si_lock), flags);
smi_result = smi_event_handler(smi_info, 0);
/*
* If the driver is doing something, there is a possible
* race with the timer. If the timer handler see idle,
* and the thread here sees something else, the timer
* handler won't restart the timer even though it is
* required. So start it here if necessary.
*/
if (smi_result != SI_SM_IDLE && !smi_info->timer_running)
smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES);
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
busy_wait = ipmi_thread_busy_wait(smi_result, smi_info,
&busy_until);
@ -1011,9 +1031,15 @@ static int ipmi_thread(void *data)
; /* do nothing */
else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait)
schedule();
else if (smi_result == SI_SM_IDLE)
schedule_timeout_interruptible(100);
else
else if (smi_result == SI_SM_IDLE) {
if (atomic_read(&smi_info->need_watch)) {
schedule_timeout_interruptible(100);
} else {
/* Wait to be woken up when we are needed. */
__set_current_state(TASK_INTERRUPTIBLE);
schedule();
}
} else
schedule_timeout_interruptible(1);
}
return 0;
@ -1024,7 +1050,7 @@ static void poll(void *send_info)
{
struct smi_info *smi_info = send_info;
unsigned long flags = 0;
int run_to_completion = smi_info->run_to_completion;
bool run_to_completion = smi_info->run_to_completion;
/*
* Make sure there is some delay in the poll loop so we can
@ -1049,6 +1075,17 @@ static void request_events(void *send_info)
atomic_set(&smi_info->req_events, 1);
}
static void set_need_watch(void *send_info, bool enable)
{
struct smi_info *smi_info = send_info;
unsigned long flags;
atomic_set(&smi_info->need_watch, enable);
spin_lock_irqsave(&smi_info->si_lock, flags);
check_start_timer_thread(smi_info);
spin_unlock_irqrestore(&smi_info->si_lock, flags);
}
static int initialized;
static void smi_timeout(unsigned long data)
@ -1073,10 +1110,6 @@ static void smi_timeout(unsigned long data)
* SI_USEC_PER_JIFFY);
smi_result = smi_event_handler(smi_info, time_diff);
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
smi_info->last_timeout_jiffies = jiffies_now;
if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
/* Running with interrupts, only do long timeouts. */
timeout = jiffies + SI_TIMEOUT_JIFFIES;
@ -1098,7 +1131,10 @@ static void smi_timeout(unsigned long data)
do_mod_timer:
if (smi_result != SI_SM_IDLE)
mod_timer(&(smi_info->si_timer), timeout);
smi_mod_timer(smi_info, timeout);
else
smi_info->timer_running = false;
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
}
static irqreturn_t si_irq_handler(int irq, void *data)
@ -1146,8 +1182,7 @@ static int smi_start_processing(void *send_info,
/* Set up the timer that drives the interface. */
setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi);
new_smi->last_timeout_jiffies = jiffies;
mod_timer(&new_smi->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES);
/*
* Check if the user forcefully enabled the daemon.
@ -1188,7 +1223,7 @@ static int get_smi_info(void *send_info, struct ipmi_smi_info *data)
return 0;
}
static void set_maintenance_mode(void *send_info, int enable)
static void set_maintenance_mode(void *send_info, bool enable)
{
struct smi_info *smi_info = send_info;
@ -1202,6 +1237,7 @@ static struct ipmi_smi_handlers handlers = {
.get_smi_info = get_smi_info,
.sender = sender,
.request_events = request_events,
.set_need_watch = set_need_watch,
.set_maintenance_mode = set_maintenance_mode,
.set_run_to_completion = set_run_to_completion,
.poll = poll,
@ -1229,7 +1265,7 @@ static bool si_tryplatform = 1;
#ifdef CONFIG_PCI
static bool si_trypci = 1;
#endif
static bool si_trydefaults = 1;
static bool si_trydefaults = IS_ENABLED(CONFIG_IPMI_SI_PROBE_DEFAULTS);
static char *si_type[SI_MAX_PARMS];
#define MAX_SI_TYPE_STR 30
static char si_type_str[MAX_SI_TYPE_STR];
@ -1328,7 +1364,7 @@ module_param_array(force_kipmid, int, &num_force_kipmid, 0);
MODULE_PARM_DESC(force_kipmid, "Force the kipmi daemon to be enabled (1) or"
" disabled(0). Normally the IPMI driver auto-detects"
" this, but the value may be overridden by this parm.");
module_param(unload_when_empty, int, 0);
module_param(unload_when_empty, bool, 0);
MODULE_PARM_DESC(unload_when_empty, "Unload the module if no interfaces are"
" specified or found, default is 1. Setting to 0"
" is useful for hot add of devices using hotmod.");
@ -3336,18 +3372,19 @@ static int try_smi_init(struct smi_info *new_smi)
INIT_LIST_HEAD(&(new_smi->hp_xmit_msgs));
new_smi->curr_msg = NULL;
atomic_set(&new_smi->req_events, 0);
new_smi->run_to_completion = 0;
new_smi->run_to_completion = false;
for (i = 0; i < SI_NUM_STATS; i++)
atomic_set(&new_smi->stats[i], 0);
new_smi->interrupt_disabled = 1;
new_smi->interrupt_disabled = true;
atomic_set(&new_smi->stop_operation, 0);
atomic_set(&new_smi->need_watch, 0);
new_smi->intf_num = smi_num;
smi_num++;
rv = try_enable_event_buffer(new_smi);
if (rv == 0)
new_smi->has_event_buffer = 1;
new_smi->has_event_buffer = true;
/*
* Start clearing the flags before we enable interrupts or the
@ -3381,7 +3418,7 @@ static int try_smi_init(struct smi_info *new_smi)
rv);
goto out_err;
}
new_smi->dev_registered = 1;
new_smi->dev_registered = true;
}
rv = ipmi_register_smi(&handlers,
@ -3430,7 +3467,7 @@ static int try_smi_init(struct smi_info *new_smi)
wait_for_timer_and_thread(new_smi);
out_err:
new_smi->interrupt_disabled = 1;
new_smi->interrupt_disabled = true;
if (new_smi->intf) {
ipmi_unregister_smi(new_smi->intf);
@ -3466,7 +3503,7 @@ static int try_smi_init(struct smi_info *new_smi)
if (new_smi->dev_registered) {
platform_device_unregister(new_smi->pdev);
new_smi->dev_registered = 0;
new_smi->dev_registered = false;
}
return rv;
@ -3521,14 +3558,14 @@ static int init_ipmi_si(void)
printk(KERN_ERR PFX "Unable to register "
"PCI driver: %d\n", rv);
else
pci_registered = 1;
pci_registered = true;
}
#endif
#ifdef CONFIG_ACPI
if (si_tryacpi) {
pnp_register_driver(&ipmi_pnp_driver);
pnp_registered = 1;
pnp_registered = true;
}
#endif
@ -3544,7 +3581,7 @@ static int init_ipmi_si(void)
#ifdef CONFIG_PARISC
register_parisc_driver(&ipmi_parisc_driver);
parisc_registered = 1;
parisc_registered = true;
/* poking PC IO addresses will crash machine, don't do it */
si_trydefaults = 0;
#endif

View File

@ -15,7 +15,7 @@ config SYNCLINK_CS
This driver may be built as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called synclinkmp. If you want to do that, say M
The module will be called synclink_cs. If you want to do that, say M
here.
config CARDMAN_4000

View File

@ -17,7 +17,7 @@
#include <linux/device.h>
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/export.h>
#include <linux/module.h>
struct ttyprintk_port {
struct tty_port port;
@ -210,10 +210,19 @@ static int __init ttyprintk_init(void)
return 0;
error:
put_tty_driver(ttyprintk_driver);
tty_port_destroy(&tpk_port.port);
return ret;
}
static void __exit ttyprintk_exit(void)
{
tty_unregister_driver(ttyprintk_driver);
put_tty_driver(ttyprintk_driver);
tty_port_destroy(&tpk_port.port);
ttyprintk_driver = NULL;
return ret;
}
device_initcall(ttyprintk_init);
module_exit(ttyprintk_exit);
MODULE_LICENSE("GPL");

View File

@ -197,7 +197,7 @@ config AMCC_PPC440SPE_ADMA
config TIMB_DMA
tristate "Timberdale FPGA DMA support"
depends on MFD_TIMBERDALE || HAS_IOMEM
depends on MFD_TIMBERDALE
select DMA_ENGINE
help
Enable support for the Timberdale FPGA DMA engine.

View File

@ -182,11 +182,13 @@ static void edma_execute(struct edma_chan *echan)
echan->ecc->dummy_slot);
}
edma_resume(echan->ch_num);
if (edesc->processed <= MAX_NR_SG) {
dev_dbg(dev, "first transfer starting %d\n", echan->ch_num);
edma_start(echan->ch_num);
} else {
dev_dbg(dev, "chan: %d: completed %d elements, resuming\n",
echan->ch_num, edesc->processed);
edma_resume(echan->ch_num);
}
/*

View File

@ -968,7 +968,17 @@ static struct platform_driver fsl_edma_driver = {
.remove = fsl_edma_remove,
};
module_platform_driver(fsl_edma_driver);
static int __init fsl_edma_init(void)
{
return platform_driver_register(&fsl_edma_driver);
}
subsys_initcall(fsl_edma_init);
static void __exit fsl_edma_exit(void)
{
platform_driver_unregister(&fsl_edma_driver);
}
module_exit(fsl_edma_exit);
MODULE_ALIAS("platform:fsl-edma");
MODULE_DESCRIPTION("Freescale eDMA engine driver");

View File

@ -666,7 +666,7 @@ static struct dma_chan *of_dma_sirfsoc_xlate(struct of_phandle_args *dma_spec,
struct sirfsoc_dma *sdma = ofdma->of_dma_data;
unsigned int request = dma_spec->args[0];
if (request > SIRFSOC_DMA_CHANNELS)
if (request >= SIRFSOC_DMA_CHANNELS)
return NULL;
return dma_get_slave_channel(&sdma->channels[request].chan);

View File

@ -2,7 +2,7 @@
* SPEAr platform SPI chipselect abstraction over gpiolib
*
* Copyright (C) 2012 ST Microelectronics
* Shiraz Hashim <shiraz.hashim@st.com>
* Shiraz Hashim <shiraz.linux.kernel@gmail.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@ -205,6 +205,6 @@ static int __init spics_gpio_init(void)
}
subsys_initcall(spics_gpio_init);
MODULE_AUTHOR("Shiraz Hashim <shiraz.hashim@st.com>");
MODULE_AUTHOR("Shiraz Hashim <shiraz.linux.kernel@gmail.com>");
MODULE_DESCRIPTION("ST Microlectronics SPEAr SPI Chip Select Abstraction");
MODULE_LICENSE("GPL");

View File

@ -233,7 +233,7 @@ static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio)
{
struct gpio_chip *chip = acpi_gpio->chip;
if (!chip->dev || !chip->to_irq)
if (!chip->to_irq)
return;
INIT_LIST_HEAD(&acpi_gpio->events);
@ -253,7 +253,7 @@ static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio)
struct acpi_gpio_event *event, *ep;
struct gpio_chip *chip = acpi_gpio->chip;
if (!chip->dev || !chip->to_irq)
if (!chip->to_irq)
return;
list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) {
@ -451,7 +451,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
if (function == ACPI_WRITE)
gpiod_set_raw_value(desc, !!((1 << i) & *value));
else
*value |= gpiod_get_raw_value(desc) << i;
*value |= (u64)gpiod_get_raw_value(desc) << i;
}
out:
@ -501,6 +501,9 @@ void acpi_gpiochip_add(struct gpio_chip *chip)
acpi_handle handle;
acpi_status status;
if (!chip || !chip->dev)
return;
handle = ACPI_HANDLE(chip->dev);
if (!handle)
return;
@ -531,6 +534,9 @@ void acpi_gpiochip_remove(struct gpio_chip *chip)
acpi_handle handle;
acpi_status status;
if (!chip || !chip->dev)
return;
handle = ACPI_HANDLE(chip->dev);
if (!handle)
return;

View File

@ -1387,8 +1387,8 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
{
struct gpio_chip *chip = d->host_data;
irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler);
irq_set_chip_data(irq, chip);
irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else

View File

@ -23,7 +23,7 @@ drm-$(CONFIG_DRM_PANEL) += drm_panel.o
drm-usb-y := drm_usb.o
drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o
drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o
drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
drm_kms_helper-$(CONFIG_DRM_KMS_FB_HELPER) += drm_fb_helper.o
drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o

View File

@ -572,7 +572,7 @@ static u32 cbr_scan2(struct ast_private *ast)
for (loop = 0; loop < CBR_PASSNUM2; loop++) {
if ((data = cbr_test2(ast)) != 0) {
data2 &= data;
if (!data)
if (!data2)
return 0;
break;
}

View File

@ -1,5 +1,6 @@
#include <linux/io.h>
#include <linux/fb.h>
#include <linux/console.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
@ -87,8 +88,6 @@ struct bochs_device {
struct bochs_framebuffer gfb;
struct drm_fb_helper helper;
int size;
int x1, y1, x2, y2; /* dirty rect */
spinlock_t dirty_lock;
bool initialized;
} fb;
};

View File

@ -94,6 +94,49 @@ static struct drm_driver bochs_driver = {
.dumb_destroy = drm_gem_dumb_destroy,
};
/* ---------------------------------------------------------------------- */
/* pm interface */
static int bochs_pm_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
struct bochs_device *bochs = drm_dev->dev_private;
drm_kms_helper_poll_disable(drm_dev);
if (bochs->fb.initialized) {
console_lock();
fb_set_suspend(bochs->fb.helper.fbdev, 1);
console_unlock();
}
return 0;
}
static int bochs_pm_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
struct bochs_device *bochs = drm_dev->dev_private;
drm_helper_resume_force_mode(drm_dev);
if (bochs->fb.initialized) {
console_lock();
fb_set_suspend(bochs->fb.helper.fbdev, 0);
console_unlock();
}
drm_kms_helper_poll_enable(drm_dev);
return 0;
}
static const struct dev_pm_ops bochs_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(bochs_pm_suspend,
bochs_pm_resume)
};
/* ---------------------------------------------------------------------- */
/* pci interface */
@ -155,6 +198,7 @@ static struct pci_driver bochs_pci_driver = {
.id_table = bochs_pci_tbl,
.probe = bochs_pci_probe,
.remove = bochs_pci_remove,
.driver.pm = &bochs_pm_ops,
};
/* ---------------------------------------------------------------------- */

View File

@ -190,7 +190,6 @@ int bochs_fbdev_init(struct bochs_device *bochs)
int ret;
bochs->fb.helper.funcs = &bochs_fb_helper_funcs;
spin_lock_init(&bochs->fb.dirty_lock);
ret = drm_fb_helper_init(bochs->dev, &bochs->fb.helper,
1, 1);

View File

@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/console.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include "cirrus_drv.h"
@ -75,6 +76,41 @@ static void cirrus_pci_remove(struct pci_dev *pdev)
drm_put_dev(dev);
}
static int cirrus_pm_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
struct cirrus_device *cdev = drm_dev->dev_private;
drm_kms_helper_poll_disable(drm_dev);
if (cdev->mode_info.gfbdev) {
console_lock();
fb_set_suspend(cdev->mode_info.gfbdev->helper.fbdev, 1);
console_unlock();
}
return 0;
}
static int cirrus_pm_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
struct cirrus_device *cdev = drm_dev->dev_private;
drm_helper_resume_force_mode(drm_dev);
if (cdev->mode_info.gfbdev) {
console_lock();
fb_set_suspend(cdev->mode_info.gfbdev->helper.fbdev, 0);
console_unlock();
}
drm_kms_helper_poll_enable(drm_dev);
return 0;
}
static const struct file_operations cirrus_driver_fops = {
.owner = THIS_MODULE,
.open = drm_open,
@ -103,11 +139,17 @@ static struct drm_driver driver = {
.dumb_destroy = drm_gem_dumb_destroy,
};
static const struct dev_pm_ops cirrus_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(cirrus_pm_suspend,
cirrus_pm_resume)
};
static struct pci_driver cirrus_pci_driver = {
.name = DRIVER_NAME,
.id_table = pciidlist,
.probe = cirrus_pci_probe,
.remove = cirrus_pci_remove,
.driver.pm = &cirrus_pm_ops,
};
static int __init cirrus_init(void)

View File

@ -308,6 +308,9 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
WREG_HDR(hdr);
cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0);
/* Unblank (needed on S3 resume, vgabios doesn't do it then) */
outb(0x20, 0x3c0);
return 0;
}

View File

@ -72,147 +72,6 @@ void drm_helper_move_panel_connectors_to_head(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head);
static bool drm_kms_helper_poll = true;
module_param_named(poll, drm_kms_helper_poll, bool, 0600);
static void drm_mode_validate_flag(struct drm_connector *connector,
int flags)
{
struct drm_display_mode *mode;
if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE |
DRM_MODE_FLAG_3D_MASK))
return;
list_for_each_entry(mode, &connector->modes, head) {
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&
!(flags & DRM_MODE_FLAG_INTERLACE))
mode->status = MODE_NO_INTERLACE;
if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) &&
!(flags & DRM_MODE_FLAG_DBLSCAN))
mode->status = MODE_NO_DBLESCAN;
if ((mode->flags & DRM_MODE_FLAG_3D_MASK) &&
!(flags & DRM_MODE_FLAG_3D_MASK))
mode->status = MODE_NO_STEREO;
}
return;
}
/**
* drm_helper_probe_single_connector_modes - get complete set of display modes
* @connector: connector to probe
* @maxX: max width for modes
* @maxY: max height for modes
*
* Based on the helper callbacks implemented by @connector try to detect all
* valid modes. Modes will first be added to the connector's probed_modes list,
* then culled (based on validity and the @maxX, @maxY parameters) and put into
* the normal modes list.
*
* Intended to be use as a generic implementation of the ->fill_modes()
* @connector vfunc for drivers that use the crtc helpers for output mode
* filtering and detection.
*
* Returns:
* The number of modes found on @connector.
*/
int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
uint32_t maxX, uint32_t maxY)
{
struct drm_device *dev = connector->dev;
struct drm_display_mode *mode;
struct drm_connector_helper_funcs *connector_funcs =
connector->helper_private;
int count = 0;
int mode_flags = 0;
bool verbose_prune = true;
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
drm_get_connector_name(connector));
/* set all modes to the unverified state */
list_for_each_entry(mode, &connector->modes, head)
mode->status = MODE_UNVERIFIED;
if (connector->force) {
if (connector->force == DRM_FORCE_ON)
connector->status = connector_status_connected;
else
connector->status = connector_status_disconnected;
if (connector->funcs->force)
connector->funcs->force(connector);
} else {
connector->status = connector->funcs->detect(connector, true);
}
/* Re-enable polling in case the global poll config changed. */
if (drm_kms_helper_poll != dev->mode_config.poll_running)
drm_kms_helper_poll_enable(dev);
dev->mode_config.poll_running = drm_kms_helper_poll;
if (connector->status == connector_status_disconnected) {
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n",
connector->base.id, drm_get_connector_name(connector));
drm_mode_connector_update_edid_property(connector, NULL);
verbose_prune = false;
goto prune;
}
#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
count = drm_load_edid_firmware(connector);
if (count == 0)
#endif
count = (*connector_funcs->get_modes)(connector);
if (count == 0 && connector->status == connector_status_connected)
count = drm_add_modes_noedid(connector, 1024, 768);
if (count == 0)
goto prune;
drm_mode_connector_list_update(connector);
if (maxX && maxY)
drm_mode_validate_size(dev, &connector->modes, maxX, maxY);
if (connector->interlace_allowed)
mode_flags |= DRM_MODE_FLAG_INTERLACE;
if (connector->doublescan_allowed)
mode_flags |= DRM_MODE_FLAG_DBLSCAN;
if (connector->stereo_allowed)
mode_flags |= DRM_MODE_FLAG_3D_MASK;
drm_mode_validate_flag(connector, mode_flags);
list_for_each_entry(mode, &connector->modes, head) {
if (mode->status == MODE_OK)
mode->status = connector_funcs->mode_valid(connector,
mode);
}
prune:
drm_mode_prune_invalid(dev, &connector->modes, verbose_prune);
if (list_empty(&connector->modes))
return 0;
list_for_each_entry(mode, &connector->modes, head)
mode->vrefresh = drm_mode_vrefresh(mode);
drm_mode_sort(&connector->modes);
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id,
drm_get_connector_name(connector));
list_for_each_entry(mode, &connector->modes, head) {
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
drm_mode_debug_printmodeline(mode);
}
return count;
}
EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
/**
* drm_helper_encoder_in_use - check if a given encoder is in use
* @encoder: encoder to check
@ -1020,232 +879,3 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
drm_modeset_unlock_all(dev);
}
EXPORT_SYMBOL(drm_helper_resume_force_mode);
/**
* drm_kms_helper_hotplug_event - fire off KMS hotplug events
* @dev: drm_device whose connector state changed
*
* This function fires off the uevent for userspace and also calls the
* output_poll_changed function, which is most commonly used to inform the fbdev
* emulation code and allow it to update the fbcon output configuration.
*
* Drivers should call this from their hotplug handling code when a change is
* detected. Note that this function does not do any output detection of its
* own, like drm_helper_hpd_irq_event() does - this is assumed to be done by the
* driver already.
*
* This function must be called from process context with no mode
* setting locks held.
*/
void drm_kms_helper_hotplug_event(struct drm_device *dev)
{
/* send a uevent + call fbdev */
drm_sysfs_hotplug_event(dev);
if (dev->mode_config.funcs->output_poll_changed)
dev->mode_config.funcs->output_poll_changed(dev);
}
EXPORT_SYMBOL(drm_kms_helper_hotplug_event);
#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
static void output_poll_execute(struct work_struct *work)
{
struct delayed_work *delayed_work = to_delayed_work(work);
struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work);
struct drm_connector *connector;
enum drm_connector_status old_status;
bool repoll = false, changed = false;
if (!drm_kms_helper_poll)
return;
mutex_lock(&dev->mode_config.mutex);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
/* Ignore forced connectors. */
if (connector->force)
continue;
/* Ignore HPD capable connectors and connectors where we don't
* want any hotplug detection at all for polling. */
if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD)
continue;
repoll = true;
old_status = connector->status;
/* if we are connected and don't want to poll for disconnect
skip it */
if (old_status == connector_status_connected &&
!(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT))
continue;
connector->status = connector->funcs->detect(connector, false);
if (old_status != connector->status) {
const char *old, *new;
old = drm_get_connector_status_name(old_status);
new = drm_get_connector_status_name(connector->status);
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] "
"status updated from %s to %s\n",
connector->base.id,
drm_get_connector_name(connector),
old, new);
changed = true;
}
}
mutex_unlock(&dev->mode_config.mutex);
if (changed)
drm_kms_helper_hotplug_event(dev);
if (repoll)
schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD);
}
/**
* drm_kms_helper_poll_disable - disable output polling
* @dev: drm_device
*
* This function disables the output polling work.
*
* Drivers can call this helper from their device suspend implementation. It is
* not an error to call this even when output polling isn't enabled or arlready
* disabled.
*/
void drm_kms_helper_poll_disable(struct drm_device *dev)
{
if (!dev->mode_config.poll_enabled)
return;
cancel_delayed_work_sync(&dev->mode_config.output_poll_work);
}
EXPORT_SYMBOL(drm_kms_helper_poll_disable);
/**
* drm_kms_helper_poll_enable - re-enable output polling.
* @dev: drm_device
*
* This function re-enables the output polling work.
*
* Drivers can call this helper from their device resume implementation. It is
* an error to call this when the output polling support has not yet been set
* up.
*/
void drm_kms_helper_poll_enable(struct drm_device *dev)
{
bool poll = false;
struct drm_connector *connector;
if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll)
return;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT))
poll = true;
}
if (poll)
schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD);
}
EXPORT_SYMBOL(drm_kms_helper_poll_enable);
/**
* drm_kms_helper_poll_init - initialize and enable output polling
* @dev: drm_device
*
* This function intializes and then also enables output polling support for
* @dev. Drivers which do not have reliable hotplug support in hardware can use
* this helper infrastructure to regularly poll such connectors for changes in
* their connection state.
*
* Drivers can control which connectors are polled by setting the
* DRM_CONNECTOR_POLL_CONNECT and DRM_CONNECTOR_POLL_DISCONNECT flags. On
* connectors where probing live outputs can result in visual distortion drivers
* should not set the DRM_CONNECTOR_POLL_DISCONNECT flag to avoid this.
* Connectors which have no flag or only DRM_CONNECTOR_POLL_HPD set are
* completely ignored by the polling logic.
*
* Note that a connector can be both polled and probed from the hotplug handler,
* in case the hotplug interrupt is known to be unreliable.
*/
void drm_kms_helper_poll_init(struct drm_device *dev)
{
INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute);
dev->mode_config.poll_enabled = true;
drm_kms_helper_poll_enable(dev);
}
EXPORT_SYMBOL(drm_kms_helper_poll_init);
/**
* drm_kms_helper_poll_fini - disable output polling and clean it up
* @dev: drm_device
*/
void drm_kms_helper_poll_fini(struct drm_device *dev)
{
drm_kms_helper_poll_disable(dev);
}
EXPORT_SYMBOL(drm_kms_helper_poll_fini);
/**
* drm_helper_hpd_irq_event - hotplug processing
* @dev: drm_device
*
* Drivers can use this helper function to run a detect cycle on all connectors
* which have the DRM_CONNECTOR_POLL_HPD flag set in their &polled member. All
* other connectors are ignored, which is useful to avoid reprobing fixed
* panels.
*
* This helper function is useful for drivers which can't or don't track hotplug
* interrupts for each connector.
*
* Drivers which support hotplug interrupts for each connector individually and
* which have a more fine-grained detect logic should bypass this code and
* directly call drm_kms_helper_hotplug_event() in case the connector state
* changed.
*
* This function must be called from process context with no mode
* setting locks held.
*
* Note that a connector can be both polled and probed from the hotplug handler,
* in case the hotplug interrupt is known to be unreliable.
*/
bool drm_helper_hpd_irq_event(struct drm_device *dev)
{
struct drm_connector *connector;
enum drm_connector_status old_status;
bool changed = false;
if (!dev->mode_config.poll_enabled)
return false;
mutex_lock(&dev->mode_config.mutex);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
/* Only handle HPD capable connectors. */
if (!(connector->polled & DRM_CONNECTOR_POLL_HPD))
continue;
old_status = connector->status;
connector->status = connector->funcs->detect(connector, false);
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
connector->base.id,
drm_get_connector_name(connector),
drm_get_connector_status_name(old_status),
drm_get_connector_status_name(connector->status));
if (old_status != connector->status)
changed = true;
}
mutex_unlock(&dev->mode_config.mutex);
if (changed)
drm_kms_helper_hotplug_event(dev);
return changed;
}
EXPORT_SYMBOL(drm_helper_hpd_irq_event);

View File

@ -577,7 +577,9 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter)
/*
* Transfer a single I2C-over-AUX message and handle various error conditions,
* retrying the transaction as appropriate.
* retrying the transaction as appropriate. It is assumed that the
* aux->transfer function does not modify anything in the msg other than the
* reply field.
*/
static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
{
@ -665,11 +667,26 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
{
struct drm_dp_aux *aux = adapter->algo_data;
unsigned int i, j;
struct drm_dp_aux_msg msg;
int err = 0;
memset(&msg, 0, sizeof(msg));
for (i = 0; i < num; i++) {
struct drm_dp_aux_msg msg;
int err;
msg.address = msgs[i].addr;
msg.request = (msgs[i].flags & I2C_M_RD) ?
DP_AUX_I2C_READ :
DP_AUX_I2C_WRITE;
msg.request |= DP_AUX_I2C_MOT;
/* Send a bare address packet to start the transaction.
* Zero sized messages specify an address only (bare
* address) transaction.
*/
msg.buffer = NULL;
msg.size = 0;
err = drm_dp_i2c_do_msg(aux, &msg);
if (err < 0)
break;
/*
* Many hardware implementations support FIFOs larger than a
* single byte, but it has been empirically determined that
@ -678,30 +695,28 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
* transferred byte-by-byte.
*/
for (j = 0; j < msgs[i].len; j++) {
memset(&msg, 0, sizeof(msg));
msg.address = msgs[i].addr;
msg.request = (msgs[i].flags & I2C_M_RD) ?
DP_AUX_I2C_READ :
DP_AUX_I2C_WRITE;
/*
* All messages except the last one are middle-of-
* transfer messages.
*/
if ((i < num - 1) || (j < msgs[i].len - 1))
msg.request |= DP_AUX_I2C_MOT;
msg.buffer = msgs[i].buf + j;
msg.size = 1;
err = drm_dp_i2c_do_msg(aux, &msg);
if (err < 0)
return err;
break;
}
if (err < 0)
break;
}
if (err >= 0)
err = num;
/* Send a bare address packet to close out the transaction.
* Zero sized messages specify an address only (bare
* address) transaction.
*/
msg.request &= ~DP_AUX_I2C_MOT;
msg.buffer = NULL;
msg.size = 0;
(void)drm_dp_i2c_do_msg(aux, &msg);
return num;
return err;
}
static const struct i2c_algorithm drm_dp_i2c_algo = {

View File

@ -207,8 +207,6 @@ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node)
return 0;
}
WARN(1, "no hole found for node 0x%lx + 0x%lx\n",
node->start, node->size);
return -ENOSPC;
}
EXPORT_SYMBOL(drm_mm_reserve_node);

View File

@ -203,9 +203,9 @@ EXPORT_SYMBOL(drm_primary_helper_update);
*
* Provides a default plane disable handler for primary planes. This is handler
* is called in response to a userspace SetPlane operation on the plane with a
* NULL framebuffer parameter. We call the driver's modeset handler with a NULL
* framebuffer to disable the CRTC if no other planes are currently enabled.
* If other planes are still enabled on the same CRTC, we return -EBUSY.
* NULL framebuffer parameter. It unconditionally fails the disable call with
* -EINVAL the only way to disable the primary plane without driver support is
* to disable the entier CRTC. Which does not match the plane ->disable hook.
*
* Note that some hardware may be able to disable the primary plane without
* disabling the whole CRTC. Drivers for such hardware should provide their
@ -214,34 +214,11 @@ EXPORT_SYMBOL(drm_primary_helper_update);
* disabled primary plane).
*
* RETURNS:
* Zero on success, error code on failure
* Unconditionally returns -EINVAL.
*/
int drm_primary_helper_disable(struct drm_plane *plane)
{
struct drm_plane *p;
struct drm_mode_set set = {
.crtc = plane->crtc,
.fb = NULL,
};
if (plane->crtc == NULL || plane->fb == NULL)
/* Already disabled */
return 0;
list_for_each_entry(p, &plane->dev->mode_config.plane_list, head)
if (p != plane && p->fb) {
DRM_DEBUG_KMS("Cannot disable primary plane while other planes are still active on CRTC.\n");
return -EBUSY;
}
/*
* N.B. We call set_config() directly here rather than
* drm_mode_set_config_internal() since drm_mode_setplane() already
* handles the basic refcounting and we don't need the special
* cross-CRTC refcounting (no chance of stealing connectors from
* other CRTC's with this update).
*/
return plane->crtc->funcs->set_config(&set);
return -EINVAL;
}
EXPORT_SYMBOL(drm_primary_helper_disable);

View File

@ -0,0 +1,426 @@
/*
* Copyright (c) 2006-2008 Intel Corporation
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
*
* DRM core CRTC related functions
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*
* Authors:
* Keith Packard
* Eric Anholt <eric@anholt.net>
* Dave Airlie <airlied@linux.ie>
* Jesse Barnes <jesse.barnes@intel.com>
*/
#include <linux/export.h>
#include <linux/moduleparam.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_edid.h>
/**
* DOC: output probing helper overview
*
* This library provides some helper code for output probing. It provides an
* implementation of the core connector->fill_modes interface with
* drm_helper_probe_single_connector_modes.
*
* It also provides support for polling connectors with a work item and for
* generic hotplug interrupt handling where the driver doesn't or cannot keep
* track of a per-connector hpd interrupt.
*
* This helper library can be used independently of the modeset helper library.
* Drivers can also overwrite different parts e.g. use their own hotplug
* handling code to avoid probing unrelated outputs.
*/
static bool drm_kms_helper_poll = true;
module_param_named(poll, drm_kms_helper_poll, bool, 0600);
static void drm_mode_validate_flag(struct drm_connector *connector,
int flags)
{
struct drm_display_mode *mode;
if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE |
DRM_MODE_FLAG_3D_MASK))
return;
list_for_each_entry(mode, &connector->modes, head) {
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&
!(flags & DRM_MODE_FLAG_INTERLACE))
mode->status = MODE_NO_INTERLACE;
if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) &&
!(flags & DRM_MODE_FLAG_DBLSCAN))
mode->status = MODE_NO_DBLESCAN;
if ((mode->flags & DRM_MODE_FLAG_3D_MASK) &&
!(flags & DRM_MODE_FLAG_3D_MASK))
mode->status = MODE_NO_STEREO;
}
return;
}
/**
* drm_helper_probe_single_connector_modes - get complete set of display modes
* @connector: connector to probe
* @maxX: max width for modes
* @maxY: max height for modes
*
* Based on the helper callbacks implemented by @connector try to detect all
* valid modes. Modes will first be added to the connector's probed_modes list,
* then culled (based on validity and the @maxX, @maxY parameters) and put into
* the normal modes list.
*
* Intended to be use as a generic implementation of the ->fill_modes()
* @connector vfunc for drivers that use the crtc helpers for output mode
* filtering and detection.
*
* Returns:
* The number of modes found on @connector.
*/
int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
uint32_t maxX, uint32_t maxY)
{
struct drm_device *dev = connector->dev;
struct drm_display_mode *mode;
struct drm_connector_helper_funcs *connector_funcs =
connector->helper_private;
int count = 0;
int mode_flags = 0;
bool verbose_prune = true;
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
drm_get_connector_name(connector));
/* set all modes to the unverified state */
list_for_each_entry(mode, &connector->modes, head)
mode->status = MODE_UNVERIFIED;
if (connector->force) {
if (connector->force == DRM_FORCE_ON)
connector->status = connector_status_connected;
else
connector->status = connector_status_disconnected;
if (connector->funcs->force)
connector->funcs->force(connector);
} else {
connector->status = connector->funcs->detect(connector, true);
}
/* Re-enable polling in case the global poll config changed. */
if (drm_kms_helper_poll != dev->mode_config.poll_running)
drm_kms_helper_poll_enable(dev);
dev->mode_config.poll_running = drm_kms_helper_poll;
if (connector->status == connector_status_disconnected) {
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n",
connector->base.id, drm_get_connector_name(connector));
drm_mode_connector_update_edid_property(connector, NULL);
verbose_prune = false;
goto prune;
}
#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
count = drm_load_edid_firmware(connector);
if (count == 0)
#endif
count = (*connector_funcs->get_modes)(connector);
if (count == 0 && connector->status == connector_status_connected)
count = drm_add_modes_noedid(connector, 1024, 768);
if (count == 0)
goto prune;
drm_mode_connector_list_update(connector);
if (maxX && maxY)
drm_mode_validate_size(dev, &connector->modes, maxX, maxY);
if (connector->interlace_allowed)
mode_flags |= DRM_MODE_FLAG_INTERLACE;
if (connector->doublescan_allowed)
mode_flags |= DRM_MODE_FLAG_DBLSCAN;
if (connector->stereo_allowed)
mode_flags |= DRM_MODE_FLAG_3D_MASK;
drm_mode_validate_flag(connector, mode_flags);
list_for_each_entry(mode, &connector->modes, head) {
if (mode->status == MODE_OK)
mode->status = connector_funcs->mode_valid(connector,
mode);
}
prune:
drm_mode_prune_invalid(dev, &connector->modes, verbose_prune);
if (list_empty(&connector->modes))
return 0;
list_for_each_entry(mode, &connector->modes, head)
mode->vrefresh = drm_mode_vrefresh(mode);
drm_mode_sort(&connector->modes);
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id,
drm_get_connector_name(connector));
list_for_each_entry(mode, &connector->modes, head) {
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
drm_mode_debug_printmodeline(mode);
}
return count;
}
EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
/**
* drm_kms_helper_hotplug_event - fire off KMS hotplug events
* @dev: drm_device whose connector state changed
*
* This function fires off the uevent for userspace and also calls the
* output_poll_changed function, which is most commonly used to inform the fbdev
* emulation code and allow it to update the fbcon output configuration.
*
* Drivers should call this from their hotplug handling code when a change is
* detected. Note that this function does not do any output detection of its
* own, like drm_helper_hpd_irq_event() does - this is assumed to be done by the
* driver already.
*
* This function must be called from process context with no mode
* setting locks held.
*/
void drm_kms_helper_hotplug_event(struct drm_device *dev)
{
/* send a uevent + call fbdev */
drm_sysfs_hotplug_event(dev);
if (dev->mode_config.funcs->output_poll_changed)
dev->mode_config.funcs->output_poll_changed(dev);
}
EXPORT_SYMBOL(drm_kms_helper_hotplug_event);
#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
static void output_poll_execute(struct work_struct *work)
{
struct delayed_work *delayed_work = to_delayed_work(work);
struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work);
struct drm_connector *connector;
enum drm_connector_status old_status;
bool repoll = false, changed = false;
if (!drm_kms_helper_poll)
return;
mutex_lock(&dev->mode_config.mutex);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
/* Ignore forced connectors. */
if (connector->force)
continue;
/* Ignore HPD capable connectors and connectors where we don't
* want any hotplug detection at all for polling. */
if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD)
continue;
repoll = true;
old_status = connector->status;
/* if we are connected and don't want to poll for disconnect
skip it */
if (old_status == connector_status_connected &&
!(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT))
continue;
connector->status = connector->funcs->detect(connector, false);
if (old_status != connector->status) {
const char *old, *new;
old = drm_get_connector_status_name(old_status);
new = drm_get_connector_status_name(connector->status);
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] "
"status updated from %s to %s\n",
connector->base.id,
drm_get_connector_name(connector),
old, new);
changed = true;
}
}
mutex_unlock(&dev->mode_config.mutex);
if (changed)
drm_kms_helper_hotplug_event(dev);
if (repoll)
schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD);
}
/**
* drm_kms_helper_poll_disable - disable output polling
* @dev: drm_device
*
* This function disables the output polling work.
*
* Drivers can call this helper from their device suspend implementation. It is
* not an error to call this even when output polling isn't enabled or arlready
* disabled.
*/
void drm_kms_helper_poll_disable(struct drm_device *dev)
{
if (!dev->mode_config.poll_enabled)
return;
cancel_delayed_work_sync(&dev->mode_config.output_poll_work);
}
EXPORT_SYMBOL(drm_kms_helper_poll_disable);
/**
* drm_kms_helper_poll_enable - re-enable output polling.
* @dev: drm_device
*
* This function re-enables the output polling work.
*
* Drivers can call this helper from their device resume implementation. It is
* an error to call this when the output polling support has not yet been set
* up.
*/
void drm_kms_helper_poll_enable(struct drm_device *dev)
{
bool poll = false;
struct drm_connector *connector;
if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll)
return;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT))
poll = true;
}
if (poll)
schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD);
}
EXPORT_SYMBOL(drm_kms_helper_poll_enable);
/**
* drm_kms_helper_poll_init - initialize and enable output polling
* @dev: drm_device
*
* This function intializes and then also enables output polling support for
* @dev. Drivers which do not have reliable hotplug support in hardware can use
* this helper infrastructure to regularly poll such connectors for changes in
* their connection state.
*
* Drivers can control which connectors are polled by setting the
* DRM_CONNECTOR_POLL_CONNECT and DRM_CONNECTOR_POLL_DISCONNECT flags. On
* connectors where probing live outputs can result in visual distortion drivers
* should not set the DRM_CONNECTOR_POLL_DISCONNECT flag to avoid this.
* Connectors which have no flag or only DRM_CONNECTOR_POLL_HPD set are
* completely ignored by the polling logic.
*
* Note that a connector can be both polled and probed from the hotplug handler,
* in case the hotplug interrupt is known to be unreliable.
*/
void drm_kms_helper_poll_init(struct drm_device *dev)
{
INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute);
dev->mode_config.poll_enabled = true;
drm_kms_helper_poll_enable(dev);
}
EXPORT_SYMBOL(drm_kms_helper_poll_init);
/**
* drm_kms_helper_poll_fini - disable output polling and clean it up
* @dev: drm_device
*/
void drm_kms_helper_poll_fini(struct drm_device *dev)
{
drm_kms_helper_poll_disable(dev);
}
EXPORT_SYMBOL(drm_kms_helper_poll_fini);
/**
* drm_helper_hpd_irq_event - hotplug processing
* @dev: drm_device
*
* Drivers can use this helper function to run a detect cycle on all connectors
* which have the DRM_CONNECTOR_POLL_HPD flag set in their &polled member. All
* other connectors are ignored, which is useful to avoid reprobing fixed
* panels.
*
* This helper function is useful for drivers which can't or don't track hotplug
* interrupts for each connector.
*
* Drivers which support hotplug interrupts for each connector individually and
* which have a more fine-grained detect logic should bypass this code and
* directly call drm_kms_helper_hotplug_event() in case the connector state
* changed.
*
* This function must be called from process context with no mode
* setting locks held.
*
* Note that a connector can be both polled and probed from the hotplug handler,
* in case the hotplug interrupt is known to be unreliable.
*/
bool drm_helper_hpd_irq_event(struct drm_device *dev)
{
struct drm_connector *connector;
enum drm_connector_status old_status;
bool changed = false;
if (!dev->mode_config.poll_enabled)
return false;
mutex_lock(&dev->mode_config.mutex);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
/* Only handle HPD capable connectors. */
if (!(connector->polled & DRM_CONNECTOR_POLL_HPD))
continue;
old_status = connector->status;
connector->status = connector->funcs->detect(connector, false);
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
connector->base.id,
drm_get_connector_name(connector),
drm_get_connector_status_name(old_status),
drm_get_connector_status_name(connector->status));
if (old_status != connector->status)
changed = true;
}
mutex_unlock(&dev->mode_config.mutex);
if (changed)
drm_kms_helper_hotplug_event(dev);
return changed;
}
EXPORT_SYMBOL(drm_helper_hpd_irq_event);

View File

@ -1308,6 +1308,7 @@ struct intel_vbt_data {
struct {
u16 pwm_freq_hz;
bool present;
bool active_low_pwm;
} backlight;
@ -2431,20 +2432,18 @@ int i915_gem_context_open(struct drm_device *dev, struct drm_file *file);
int i915_gem_context_enable(struct drm_i915_private *dev_priv);
void i915_gem_context_close(struct drm_device *dev, struct drm_file *file);
int i915_switch_context(struct intel_ring_buffer *ring,
struct drm_file *file, struct i915_hw_context *to);
struct i915_hw_context *to);
struct i915_hw_context *
i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id);
void i915_gem_context_free(struct kref *ctx_ref);
static inline void i915_gem_context_reference(struct i915_hw_context *ctx)
{
if (ctx->obj && HAS_HW_CONTEXTS(ctx->obj->base.dev))
kref_get(&ctx->ref);
kref_get(&ctx->ref);
}
static inline void i915_gem_context_unreference(struct i915_hw_context *ctx)
{
if (ctx->obj && HAS_HW_CONTEXTS(ctx->obj->base.dev))
kref_put(&ctx->ref, i915_gem_context_free);
kref_put(&ctx->ref, i915_gem_context_free);
}
static inline bool i915_gem_context_is_default(const struct i915_hw_context *c)

View File

@ -2790,7 +2790,7 @@ int i915_gpu_idle(struct drm_device *dev)
/* Flush everything onto the inactive list. */
for_each_ring(ring, dev_priv, i) {
ret = i915_switch_context(ring, NULL, ring->default_context);
ret = i915_switch_context(ring, ring->default_context);
if (ret)
return ret;

View File

@ -96,9 +96,6 @@
#define GEN6_CONTEXT_ALIGN (64<<10)
#define GEN7_CONTEXT_ALIGN 4096
static int do_switch(struct intel_ring_buffer *ring,
struct i915_hw_context *to);
static void do_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt)
{
struct drm_device *dev = ppgtt->base.dev;
@ -185,13 +182,15 @@ void i915_gem_context_free(struct kref *ctx_ref)
typeof(*ctx), ref);
struct i915_hw_ppgtt *ppgtt = NULL;
/* We refcount even the aliasing PPGTT to keep the code symmetric */
if (USES_PPGTT(ctx->obj->base.dev))
ppgtt = ctx_to_ppgtt(ctx);
if (ctx->obj) {
/* We refcount even the aliasing PPGTT to keep the code symmetric */
if (USES_PPGTT(ctx->obj->base.dev))
ppgtt = ctx_to_ppgtt(ctx);
/* XXX: Free up the object before tearing down the address space, in
* case we're bound in the PPGTT */
drm_gem_object_unreference(&ctx->obj->base);
/* XXX: Free up the object before tearing down the address space, in
* case we're bound in the PPGTT */
drm_gem_object_unreference(&ctx->obj->base);
}
if (ppgtt)
kref_put(&ppgtt->ref, ppgtt_release);
@ -232,32 +231,32 @@ __create_hw_context(struct drm_device *dev,
return ERR_PTR(-ENOMEM);
kref_init(&ctx->ref);
ctx->obj = i915_gem_alloc_object(dev, dev_priv->hw_context_size);
INIT_LIST_HEAD(&ctx->link);
if (ctx->obj == NULL) {
kfree(ctx);
DRM_DEBUG_DRIVER("Context object allocated failed\n");
return ERR_PTR(-ENOMEM);
}
if (INTEL_INFO(dev)->gen >= 7) {
ret = i915_gem_object_set_cache_level(ctx->obj,
I915_CACHE_L3_LLC);
/* Failure shouldn't ever happen this early */
if (WARN_ON(ret))
goto err_out;
}
list_add_tail(&ctx->link, &dev_priv->context_list);
/* Default context will never have a file_priv */
if (file_priv == NULL)
return ctx;
if (dev_priv->hw_context_size) {
ctx->obj = i915_gem_alloc_object(dev, dev_priv->hw_context_size);
if (ctx->obj == NULL) {
ret = -ENOMEM;
goto err_out;
}
ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID, 0,
GFP_KERNEL);
if (ret < 0)
goto err_out;
if (INTEL_INFO(dev)->gen >= 7) {
ret = i915_gem_object_set_cache_level(ctx->obj,
I915_CACHE_L3_LLC);
/* Failure shouldn't ever happen this early */
if (WARN_ON(ret))
goto err_out;
}
}
/* Default context will never have a file_priv */
if (file_priv != NULL) {
ret = idr_alloc(&file_priv->context_idr, ctx,
DEFAULT_CONTEXT_ID, 0, GFP_KERNEL);
if (ret < 0)
goto err_out;
} else
ret = DEFAULT_CONTEXT_ID;
ctx->file_priv = file_priv;
ctx->id = ret;
@ -294,7 +293,7 @@ i915_gem_create_context(struct drm_device *dev,
if (IS_ERR(ctx))
return ctx;
if (is_global_default_ctx) {
if (is_global_default_ctx && ctx->obj) {
/* We may need to do things with the shrinker which
* require us to immediately switch back to the default
* context. This can cause a problem as pinning the
@ -342,7 +341,7 @@ i915_gem_create_context(struct drm_device *dev,
return ctx;
err_unpin:
if (is_global_default_ctx)
if (is_global_default_ctx && ctx->obj)
i915_gem_object_ggtt_unpin(ctx->obj);
err_destroy:
i915_gem_context_unreference(ctx);
@ -352,32 +351,22 @@ err_destroy:
void i915_gem_context_reset(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring;
int i;
if (!HAS_HW_CONTEXTS(dev))
return;
/* Prevent the hardware from restoring the last context (which hung) on
* the next switch */
for (i = 0; i < I915_NUM_RINGS; i++) {
struct i915_hw_context *dctx;
if (!(INTEL_INFO(dev)->ring_mask & (1<<i)))
continue;
struct intel_ring_buffer *ring = &dev_priv->ring[i];
struct i915_hw_context *dctx = ring->default_context;
/* Do a fake switch to the default context */
ring = &dev_priv->ring[i];
dctx = ring->default_context;
if (WARN_ON(!dctx))
if (ring->last_context == dctx)
continue;
if (!ring->last_context)
continue;
if (ring->last_context == dctx)
continue;
if (i == RCS) {
if (dctx->obj && i == RCS) {
WARN_ON(i915_gem_obj_ggtt_pin(dctx->obj,
get_context_alignment(dev), 0));
/* Fake a finish/inactive */
@ -394,44 +383,35 @@ void i915_gem_context_reset(struct drm_device *dev)
int i915_gem_context_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring;
struct i915_hw_context *ctx;
int i;
if (!HAS_HW_CONTEXTS(dev))
return 0;
/* Init should only be called once per module load. Eventually the
* restriction on the context_disabled check can be loosened. */
if (WARN_ON(dev_priv->ring[RCS].default_context))
return 0;
dev_priv->hw_context_size = round_up(get_context_size(dev), 4096);
if (dev_priv->hw_context_size > (1<<20)) {
DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size\n");
return -E2BIG;
if (HAS_HW_CONTEXTS(dev)) {
dev_priv->hw_context_size = round_up(get_context_size(dev), 4096);
if (dev_priv->hw_context_size > (1<<20)) {
DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size %d\n",
dev_priv->hw_context_size);
dev_priv->hw_context_size = 0;
}
}
dev_priv->ring[RCS].default_context =
i915_gem_create_context(dev, NULL, USES_PPGTT(dev));
if (IS_ERR_OR_NULL(dev_priv->ring[RCS].default_context)) {
DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %ld\n",
PTR_ERR(dev_priv->ring[RCS].default_context));
return PTR_ERR(dev_priv->ring[RCS].default_context);
ctx = i915_gem_create_context(dev, NULL, USES_PPGTT(dev));
if (IS_ERR(ctx)) {
DRM_ERROR("Failed to create default global context (error %ld)\n",
PTR_ERR(ctx));
return PTR_ERR(ctx);
}
for (i = RCS + 1; i < I915_NUM_RINGS; i++) {
if (!(INTEL_INFO(dev)->ring_mask & (1<<i)))
continue;
/* NB: RCS will hold a ref for all rings */
for (i = 0; i < I915_NUM_RINGS; i++)
dev_priv->ring[i].default_context = ctx;
ring = &dev_priv->ring[i];
/* NB: RCS will hold a ref for all rings */
ring->default_context = dev_priv->ring[RCS].default_context;
}
DRM_DEBUG_DRIVER("HW context support initialized\n");
DRM_DEBUG_DRIVER("%s context support initialized\n", dev_priv->hw_context_size ? "HW" : "fake");
return 0;
}
@ -441,33 +421,30 @@ void i915_gem_context_fini(struct drm_device *dev)
struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context;
int i;
if (!HAS_HW_CONTEXTS(dev))
return;
if (dctx->obj) {
/* The only known way to stop the gpu from accessing the hw context is
* to reset it. Do this as the very last operation to avoid confusing
* other code, leading to spurious errors. */
intel_gpu_reset(dev);
/* The only known way to stop the gpu from accessing the hw context is
* to reset it. Do this as the very last operation to avoid confusing
* other code, leading to spurious errors. */
intel_gpu_reset(dev);
/* When default context is created and switched to, base object refcount
* will be 2 (+1 from object creation and +1 from do_switch()).
* i915_gem_context_fini() will be called after gpu_idle() has switched
* to default context. So we need to unreference the base object once
* to offset the do_switch part, so that i915_gem_context_unreference()
* can then free the base object correctly. */
WARN_ON(!dev_priv->ring[RCS].last_context);
if (dev_priv->ring[RCS].last_context == dctx) {
/* Fake switch to NULL context */
WARN_ON(dctx->obj->active);
i915_gem_object_ggtt_unpin(dctx->obj);
i915_gem_context_unreference(dctx);
dev_priv->ring[RCS].last_context = NULL;
/* When default context is created and switched to, base object refcount
* will be 2 (+1 from object creation and +1 from do_switch()).
* i915_gem_context_fini() will be called after gpu_idle() has switched
* to default context. So we need to unreference the base object once
* to offset the do_switch part, so that i915_gem_context_unreference()
* can then free the base object correctly. */
WARN_ON(!dev_priv->ring[RCS].last_context);
if (dev_priv->ring[RCS].last_context == dctx) {
/* Fake switch to NULL context */
WARN_ON(dctx->obj->active);
i915_gem_object_ggtt_unpin(dctx->obj);
i915_gem_context_unreference(dctx);
dev_priv->ring[RCS].last_context = NULL;
}
}
for (i = 0; i < I915_NUM_RINGS; i++) {
struct intel_ring_buffer *ring = &dev_priv->ring[i];
if (!(INTEL_INFO(dev)->ring_mask & (1<<i)))
continue;
if (ring->last_context)
i915_gem_context_unreference(ring->last_context);
@ -478,7 +455,6 @@ void i915_gem_context_fini(struct drm_device *dev)
i915_gem_object_ggtt_unpin(dctx->obj);
i915_gem_context_unreference(dctx);
dev_priv->mm.aliasing_ppgtt = NULL;
}
int i915_gem_context_enable(struct drm_i915_private *dev_priv)
@ -486,9 +462,6 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv)
struct intel_ring_buffer *ring;
int ret, i;
if (!HAS_HW_CONTEXTS(dev_priv->dev))
return 0;
/* This is the only place the aliasing PPGTT gets enabled, which means
* it has to happen before we bail on reset */
if (dev_priv->mm.aliasing_ppgtt) {
@ -503,7 +476,7 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv)
BUG_ON(!dev_priv->ring[RCS].default_context);
for_each_ring(ring, dev_priv, i) {
ret = do_switch(ring, ring->default_context);
ret = i915_switch_context(ring, ring->default_context);
if (ret)
return ret;
}
@ -526,19 +499,6 @@ static int context_idr_cleanup(int id, void *p, void *data)
int i915_gem_context_open(struct drm_device *dev, struct drm_file *file)
{
struct drm_i915_file_private *file_priv = file->driver_priv;
struct drm_i915_private *dev_priv = dev->dev_private;
if (!HAS_HW_CONTEXTS(dev)) {
/* Cheat for hang stats */
file_priv->private_default_ctx =
kzalloc(sizeof(struct i915_hw_context), GFP_KERNEL);
if (file_priv->private_default_ctx == NULL)
return -ENOMEM;
file_priv->private_default_ctx->vm = &dev_priv->gtt.base;
return 0;
}
idr_init(&file_priv->context_idr);
@ -559,14 +519,10 @@ void i915_gem_context_close(struct drm_device *dev, struct drm_file *file)
{
struct drm_i915_file_private *file_priv = file->driver_priv;
if (!HAS_HW_CONTEXTS(dev)) {
kfree(file_priv->private_default_ctx);
return;
}
idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL);
i915_gem_context_unreference(file_priv->private_default_ctx);
idr_destroy(&file_priv->context_idr);
i915_gem_context_unreference(file_priv->private_default_ctx);
}
struct i915_hw_context *
@ -574,9 +530,6 @@ i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id)
{
struct i915_hw_context *ctx;
if (!HAS_HW_CONTEXTS(file_priv->dev_priv->dev))
return file_priv->private_default_ctx;
ctx = (struct i915_hw_context *)idr_find(&file_priv->context_idr, id);
if (!ctx)
return ERR_PTR(-ENOENT);
@ -758,7 +711,6 @@ unpin_out:
/**
* i915_switch_context() - perform a GPU context switch.
* @ring: ring for which we'll execute the context switch
* @file_priv: file_priv associated with the context, may be NULL
* @to: the context to switch to
*
* The context life cycle is simple. The context refcount is incremented and
@ -767,24 +719,30 @@ unpin_out:
* object while letting the normal object tracking destroy the backing BO.
*/
int i915_switch_context(struct intel_ring_buffer *ring,
struct drm_file *file,
struct i915_hw_context *to)
{
struct drm_i915_private *dev_priv = ring->dev->dev_private;
WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
BUG_ON(file && to == NULL);
/* We have the fake context */
if (!HAS_HW_CONTEXTS(ring->dev)) {
ring->last_context = to;
if (to->obj == NULL) { /* We have the fake context */
if (to != ring->last_context) {
i915_gem_context_reference(to);
if (ring->last_context)
i915_gem_context_unreference(ring->last_context);
ring->last_context = to;
}
return 0;
}
return do_switch(ring, to);
}
static bool hw_context_enabled(struct drm_device *dev)
{
return to_i915(dev)->hw_context_size;
}
int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
struct drm_file *file)
{
@ -793,7 +751,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
struct i915_hw_context *ctx;
int ret;
if (!HAS_HW_CONTEXTS(dev))
if (!hw_context_enabled(dev))
return -ENODEV;
ret = i915_mutex_lock_interruptible(dev);

View File

@ -1221,7 +1221,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
if (ret)
goto err;
ret = i915_switch_context(ring, file, ctx);
ret = i915_switch_context(ring, ctx);
if (ret)
goto err;

View File

@ -287,6 +287,9 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
const struct bdb_lfp_backlight_data *backlight_data;
const struct bdb_lfp_backlight_data_entry *entry;
/* Err to enabling backlight if no backlight block. */
dev_priv->vbt.backlight.present = true;
backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT);
if (!backlight_data)
return;
@ -299,6 +302,13 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
entry = &backlight_data->data[panel_type];
dev_priv->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM;
if (!dev_priv->vbt.backlight.present) {
DRM_DEBUG_KMS("PWM backlight not present in VBT (type %u)\n",
entry->type);
return;
}
dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz;
dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm;
DRM_DEBUG_KMS("VBT backlight PWM modulation frequency %u Hz, "

View File

@ -374,6 +374,9 @@ struct bdb_lvds_lfp_data {
struct bdb_lvds_lfp_data_entry data[16];
} __packed;
#define BDB_BACKLIGHT_TYPE_NONE 0
#define BDB_BACKLIGHT_TYPE_PWM 2
struct bdb_lfp_backlight_data_entry {
u8 type:2;
u8 active_low_pwm:1;

View File

@ -575,7 +575,8 @@ out:
return ret;
}
#define HEADER_SIZE 4
#define BARE_ADDRESS_SIZE 3
#define HEADER_SIZE (BARE_ADDRESS_SIZE + 1)
static ssize_t
intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
{
@ -592,7 +593,7 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
switch (msg->request & ~DP_AUX_I2C_MOT) {
case DP_AUX_NATIVE_WRITE:
case DP_AUX_I2C_WRITE:
txsize = HEADER_SIZE + msg->size;
txsize = msg->size ? HEADER_SIZE + msg->size : BARE_ADDRESS_SIZE;
rxsize = 1;
if (WARN_ON(txsize > 20))
@ -611,7 +612,7 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
case DP_AUX_NATIVE_READ:
case DP_AUX_I2C_READ:
txsize = HEADER_SIZE;
txsize = msg->size ? HEADER_SIZE : BARE_ADDRESS_SIZE;
rxsize = msg->size + 1;
if (WARN_ON(rxsize > 20))

View File

@ -1065,6 +1065,11 @@ int intel_panel_setup_backlight(struct drm_connector *connector)
unsigned long flags;
int ret;
if (!dev_priv->vbt.backlight.present) {
DRM_DEBUG_KMS("native backlight control not available per VBT\n");
return 0;
}
/* set level and max in panel struct */
spin_lock_irqsave(&dev_priv->backlight_lock, flags);
ret = dev_priv->display.setup_backlight(intel_connector);

View File

@ -1545,6 +1545,16 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);
if (IS_I915GM(dev) && enabled) {
struct intel_framebuffer *fb;
fb = to_intel_framebuffer(enabled->primary->fb);
/* self-refresh seems busted with untiled */
if (fb->obj->tiling_mode == I915_TILING_NONE)
enabled = NULL;
}
/*
* Overlay gets an aggressive default since video jitter is bad.
*/

View File

@ -109,7 +109,7 @@ nouveau_bios_shadow_pramin(struct nouveau_bios *bios)
return;
}
addr = (u64)(addr >> 8) << 8;
addr = (addr & 0xffffff00) << 8;
if (!addr) {
addr = (u64)nv_rd32(bios, 0x001700) << 16;
addr += 0xf0000;

View File

@ -33,6 +33,7 @@ struct omap_crtc {
int pipe;
enum omap_channel channel;
struct omap_overlay_manager_info info;
struct drm_encoder *current_encoder;
/*
* Temporary: eventually this will go away, but it is needed
@ -120,13 +121,25 @@ static void omap_crtc_start_update(struct omap_overlay_manager *mgr)
{
}
static void set_enabled(struct drm_crtc *crtc, bool enable);
static int omap_crtc_enable(struct omap_overlay_manager *mgr)
{
struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info);
dispc_mgr_set_timings(omap_crtc->channel,
&omap_crtc->timings);
set_enabled(&omap_crtc->base, true);
return 0;
}
static void omap_crtc_disable(struct omap_overlay_manager *mgr)
{
struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
set_enabled(&omap_crtc->base, false);
}
static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
@ -184,7 +197,6 @@ static void omap_crtc_destroy(struct drm_crtc *crtc)
WARN_ON(omap_crtc->apply_irq.registered);
omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
omap_crtc->plane->funcs->destroy(omap_crtc->plane);
drm_crtc_cleanup(crtc);
kfree(omap_crtc);
@ -338,17 +350,23 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct drm_plane *primary = crtc->primary;
struct drm_gem_object *bo;
unsigned long flags;
DBG("%d -> %d (event=%p)", primary->fb ? primary->fb->base.id : -1,
fb->base.id, event);
spin_lock_irqsave(&dev->event_lock, flags);
if (omap_crtc->old_fb) {
spin_unlock_irqrestore(&dev->event_lock, flags);
dev_err(dev->dev, "already a pending flip\n");
return -EINVAL;
}
omap_crtc->event = event;
primary->fb = fb;
omap_crtc->old_fb = primary->fb = fb;
spin_unlock_irqrestore(&dev->event_lock, flags);
/*
* Hold a reference temporarily until the crtc is updated
@ -528,38 +546,46 @@ static void set_enabled(struct drm_crtc *crtc, bool enable)
struct drm_device *dev = crtc->dev;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
enum omap_channel channel = omap_crtc->channel;
struct omap_irq_wait *wait = NULL;
struct omap_irq_wait *wait;
u32 framedone_irq, vsync_irq;
int ret;
if (dispc_mgr_is_enabled(channel) == enable)
return;
/* ignore sync-lost irqs during enable/disable */
/*
* Digit output produces some sync lost interrupts during the first
* frame when enabling, so we need to ignore those.
*/
omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
if (dispc_mgr_get_framedone_irq(channel)) {
if (!enable) {
wait = omap_irq_wait_init(dev,
dispc_mgr_get_framedone_irq(channel), 1);
}
framedone_irq = dispc_mgr_get_framedone_irq(channel);
vsync_irq = dispc_mgr_get_vsync_irq(channel);
if (enable) {
wait = omap_irq_wait_init(dev, vsync_irq, 1);
} else {
/*
* When we disable digit output, we need to wait until fields
* are done. Otherwise the DSS is still working, and turning
* off the clocks prevents DSS from going to OFF mode. And when
* enabling, we need to wait for the extra sync losts
* When we disable the digit output, we need to wait for
* FRAMEDONE to know that DISPC has finished with the output.
*
* OMAP2/3 does not have FRAMEDONE irq for digit output, and in
* that case we need to use vsync interrupt, and wait for both
* even and odd frames.
*/
wait = omap_irq_wait_init(dev,
dispc_mgr_get_vsync_irq(channel), 2);
if (framedone_irq)
wait = omap_irq_wait_init(dev, framedone_irq, 1);
else
wait = omap_irq_wait_init(dev, vsync_irq, 2);
}
dispc_mgr_enable(channel, enable);
if (wait) {
int ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
if (ret) {
dev_err(dev->dev, "%s: timeout waiting for %s\n",
omap_crtc->name, enable ? "enable" : "disable");
}
ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
if (ret) {
dev_err(dev->dev, "%s: timeout waiting for %s\n",
omap_crtc->name, enable ? "enable" : "disable");
}
omap_irq_register(crtc->dev, &omap_crtc->error_irq);
@ -586,8 +612,12 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
}
}
if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder)
omap_encoder_set_enabled(omap_crtc->current_encoder, false);
omap_crtc->current_encoder = encoder;
if (!omap_crtc->enabled) {
set_enabled(&omap_crtc->base, false);
if (encoder)
omap_encoder_set_enabled(encoder, false);
} else {
@ -596,13 +626,7 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
omap_encoder_update(encoder, omap_crtc->mgr,
&omap_crtc->timings);
omap_encoder_set_enabled(encoder, true);
omap_crtc->full_update = false;
}
dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info);
dispc_mgr_set_timings(omap_crtc->channel,
&omap_crtc->timings);
set_enabled(&omap_crtc->base, true);
}
omap_crtc->full_update = false;
@ -613,10 +637,30 @@ static void omap_crtc_post_apply(struct omap_drm_apply *apply)
/* nothing needed for post-apply */
}
void omap_crtc_flush(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
int loops = 0;
while (!list_empty(&omap_crtc->pending_applies) ||
!list_empty(&omap_crtc->queued_applies) ||
omap_crtc->event || omap_crtc->old_fb) {
if (++loops > 10) {
dev_err(crtc->dev->dev,
"omap_crtc_flush() timeout\n");
break;
}
schedule_timeout_uninterruptible(msecs_to_jiffies(20));
}
}
static const char *channel_names[] = {
[OMAP_DSS_CHANNEL_LCD] = "lcd",
[OMAP_DSS_CHANNEL_DIGIT] = "tv",
[OMAP_DSS_CHANNEL_LCD2] = "lcd2",
[OMAP_DSS_CHANNEL_LCD3] = "lcd3",
};
void omap_crtc_pre_init(void)

View File

@ -513,12 +513,18 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
static int dev_unload(struct drm_device *dev)
{
struct omap_drm_private *priv = dev->dev_private;
int i;
DBG("unload: dev=%p", dev);
drm_kms_helper_poll_fini(dev);
omap_fbdev_free(dev);
/* flush crtcs so the fbs get released */
for (i = 0; i < priv->num_crtcs; i++)
omap_crtc_flush(priv->crtcs[i]);
omap_modeset_free(dev);
omap_gem_deinit(dev);
@ -696,10 +702,11 @@ static int pdev_remove(struct platform_device *device)
{
DBG("");
drm_put_dev(platform_get_drvdata(device));
omap_disconnect_dssdevs();
omap_crtc_pre_uninit();
drm_put_dev(platform_get_drvdata(device));
return 0;
}
@ -726,18 +733,33 @@ static struct platform_driver pdev = {
static int __init omap_drm_init(void)
{
int r;
DBG("init");
if (platform_driver_register(&omap_dmm_driver)) {
/* we can continue on without DMM.. so not fatal */
dev_err(NULL, "DMM registration failed\n");
r = platform_driver_register(&omap_dmm_driver);
if (r) {
pr_err("DMM driver registration failed\n");
return r;
}
return platform_driver_register(&pdev);
r = platform_driver_register(&pdev);
if (r) {
pr_err("omapdrm driver registration failed\n");
platform_driver_unregister(&omap_dmm_driver);
return r;
}
return 0;
}
static void __exit omap_drm_fini(void)
{
DBG("fini");
platform_driver_unregister(&pdev);
platform_driver_unregister(&omap_dmm_driver);
}
/* need late_initcall() so we load after dss_driver's are loaded */

View File

@ -163,6 +163,7 @@ void omap_crtc_pre_init(void);
void omap_crtc_pre_uninit(void);
struct drm_crtc *omap_crtc_init(struct drm_device *dev,
struct drm_plane *plane, enum omap_channel channel, int id);
void omap_crtc_flush(struct drm_crtc *crtc);
struct drm_plane *omap_plane_init(struct drm_device *dev,
int plane_id, bool private_plane);

View File

@ -218,6 +218,20 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
info->rotation_type = OMAP_DSS_ROT_TILER;
info->screen_width = omap_gem_tiled_stride(plane->bo, orient);
} else {
switch (win->rotation & 0xf) {
case 0:
case BIT(DRM_ROTATE_0):
/* OK */
break;
default:
dev_warn(fb->dev->dev,
"rotation '%d' ignored for non-tiled fb\n",
win->rotation);
win->rotation = 0;
break;
}
info->paddr = get_linear_addr(plane, format, 0, x, y);
info->rotation_type = OMAP_DSS_ROT_DMA;
info->screen_width = plane->pitch;

View File

@ -371,6 +371,9 @@ void omap_fbdev_free(struct drm_device *dev)
fbdev = to_omap_fbdev(priv->fbdev);
/* release the ref taken in omap_fbdev_create() */
omap_gem_put_paddr(fbdev->bo);
/* this will free the backing object */
if (fbdev->fb) {
drm_framebuffer_unregister_private(fbdev->fb);

View File

@ -980,12 +980,9 @@ int omap_gem_resume(struct device *dev)
#ifdef CONFIG_DEBUG_FS
void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
{
struct drm_device *dev = obj->dev;
struct omap_gem_object *omap_obj = to_omap_bo(obj);
uint64_t off;
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
off = drm_vma_node_start(&obj->vma_node);
seq_printf(m, "%08x: %2d (%2d) %08llx %08Zx (%2d) %p %4d",
@ -1050,10 +1047,10 @@ static inline bool is_waiting(struct omap_gem_sync_waiter *waiter)
{
struct omap_gem_object *omap_obj = waiter->omap_obj;
if ((waiter->op & OMAP_GEM_READ) &&
(omap_obj->sync->read_complete < waiter->read_target))
(omap_obj->sync->write_complete < waiter->write_target))
return true;
if ((waiter->op & OMAP_GEM_WRITE) &&
(omap_obj->sync->write_complete < waiter->write_target))
(omap_obj->sync->read_complete < waiter->read_target))
return true;
return false;
}
@ -1229,6 +1226,8 @@ int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op,
}
spin_unlock(&sync_lock);
kfree(waiter);
}
/* no waiting.. */

View File

@ -225,6 +225,11 @@ int omap_plane_mode_set(struct drm_plane *plane,
omap_plane->apply_done_cb.arg = arg;
}
if (plane->fb)
drm_framebuffer_unreference(plane->fb);
drm_framebuffer_reference(fb);
plane->fb = fb;
plane->crtc = crtc;
@ -241,10 +246,13 @@ static int omap_plane_update(struct drm_plane *plane,
struct omap_plane *omap_plane = to_omap_plane(plane);
omap_plane->enabled = true;
if (plane->fb)
drm_framebuffer_unreference(plane->fb);
drm_framebuffer_reference(fb);
/* omap_plane_mode_set() takes adjusted src */
switch (omap_plane->win.rotation & 0xf) {
case BIT(DRM_ROTATE_90):
case BIT(DRM_ROTATE_270):
swap(src_w, src_h);
break;
}
return omap_plane_mode_set(plane, crtc, fb,
crtc_x, crtc_y, crtc_w, crtc_h,

View File

@ -142,7 +142,8 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
return recv_bytes;
}
#define HEADER_SIZE 4
#define BARE_ADDRESS_SIZE 3
#define HEADER_SIZE (BARE_ADDRESS_SIZE + 1)
static ssize_t
radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
@ -160,13 +161,19 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
tx_buf[0] = msg->address & 0xff;
tx_buf[1] = msg->address >> 8;
tx_buf[2] = msg->request << 4;
tx_buf[3] = msg->size - 1;
tx_buf[3] = msg->size ? (msg->size - 1) : 0;
switch (msg->request & ~DP_AUX_I2C_MOT) {
case DP_AUX_NATIVE_WRITE:
case DP_AUX_I2C_WRITE:
/* tx_size needs to be 4 even for bare address packets since the atom
* table needs the info in tx_buf[3].
*/
tx_size = HEADER_SIZE + msg->size;
tx_buf[3] |= tx_size << 4;
if (msg->size == 0)
tx_buf[3] |= BARE_ADDRESS_SIZE << 4;
else
tx_buf[3] |= tx_size << 4;
memcpy(tx_buf + HEADER_SIZE, msg->buffer, msg->size);
ret = radeon_process_aux_ch(chan,
tx_buf, tx_size, NULL, 0, delay, &ack);
@ -176,8 +183,14 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
break;
case DP_AUX_NATIVE_READ:
case DP_AUX_I2C_READ:
/* tx_size needs to be 4 even for bare address packets since the atom
* table needs the info in tx_buf[3].
*/
tx_size = HEADER_SIZE;
tx_buf[3] |= tx_size << 4;
if (msg->size == 0)
tx_buf[3] |= BARE_ADDRESS_SIZE << 4;
else
tx_buf[3] |= tx_size << 4;
ret = radeon_process_aux_ch(chan,
tx_buf, tx_size, msg->buffer, msg->size, delay, &ack);
break;
@ -186,7 +199,7 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
break;
}
if (ret > 0)
if (ret >= 0)
msg->reply = ack >> 4;
return ret;
@ -194,98 +207,15 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
void radeon_dp_aux_init(struct radeon_connector *radeon_connector)
{
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
dig_connector->dp_i2c_bus->aux.dev = radeon_connector->base.kdev;
dig_connector->dp_i2c_bus->aux.transfer = radeon_dp_aux_transfer;
}
int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
u8 write_byte, u8 *read_byte)
{
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
struct radeon_i2c_chan *auxch = i2c_get_adapdata(adapter);
u16 address = algo_data->address;
u8 msg[5];
u8 reply[2];
unsigned retry;
int msg_bytes;
int reply_bytes = 1;
int ret;
u8 ack;
/* Set up the address */
msg[0] = address;
msg[1] = address >> 8;
radeon_connector->ddc_bus->aux.dev = radeon_connector->base.kdev;
radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer;
ret = drm_dp_aux_register_i2c_bus(&radeon_connector->ddc_bus->aux);
if (!ret)
radeon_connector->ddc_bus->has_aux = true;
/* Set up the command byte */
if (mode & MODE_I2C_READ) {
msg[2] = DP_AUX_I2C_READ << 4;
msg_bytes = 4;
msg[3] = msg_bytes << 4;
} else {
msg[2] = DP_AUX_I2C_WRITE << 4;
msg_bytes = 5;
msg[3] = msg_bytes << 4;
msg[4] = write_byte;
}
/* special handling for start/stop */
if (mode & (MODE_I2C_START | MODE_I2C_STOP))
msg[3] = 3 << 4;
/* Set MOT bit for all but stop */
if ((mode & MODE_I2C_STOP) == 0)
msg[2] |= DP_AUX_I2C_MOT << 4;
for (retry = 0; retry < 7; retry++) {
ret = radeon_process_aux_ch(auxch,
msg, msg_bytes, reply, reply_bytes, 0, &ack);
if (ret == -EBUSY)
continue;
else if (ret < 0) {
DRM_DEBUG_KMS("aux_ch failed %d\n", ret);
return ret;
}
switch ((ack >> 4) & DP_AUX_NATIVE_REPLY_MASK) {
case DP_AUX_NATIVE_REPLY_ACK:
/* I2C-over-AUX Reply field is only valid
* when paired with AUX ACK.
*/
break;
case DP_AUX_NATIVE_REPLY_NACK:
DRM_DEBUG_KMS("aux_ch native nack\n");
return -EREMOTEIO;
case DP_AUX_NATIVE_REPLY_DEFER:
DRM_DEBUG_KMS("aux_ch native defer\n");
usleep_range(500, 600);
continue;
default:
DRM_ERROR("aux_ch invalid native reply 0x%02x\n", ack);
return -EREMOTEIO;
}
switch ((ack >> 4) & DP_AUX_I2C_REPLY_MASK) {
case DP_AUX_I2C_REPLY_ACK:
if (mode == MODE_I2C_READ)
*read_byte = reply[0];
return ret;
case DP_AUX_I2C_REPLY_NACK:
DRM_DEBUG_KMS("aux_i2c nack\n");
return -EREMOTEIO;
case DP_AUX_I2C_REPLY_DEFER:
DRM_DEBUG_KMS("aux_i2c defer\n");
usleep_range(400, 500);
break;
default:
DRM_ERROR("aux_i2c invalid reply 0x%02x\n", ack);
return -EREMOTEIO;
}
}
DRM_DEBUG_KMS("aux i2c too many retries, giving up\n");
return -EREMOTEIO;
WARN(ret, "drm_dp_aux_register_i2c_bus() failed with error %d\n", ret);
}
/***** general DP utility functions *****/
@ -420,12 +350,11 @@ static u8 radeon_dp_encoder_service(struct radeon_device *rdev,
u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector)
{
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
struct drm_device *dev = radeon_connector->base.dev;
struct radeon_device *rdev = dev->dev_private;
return radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_GET_SINK_TYPE, 0,
dig_connector->dp_i2c_bus->rec.i2c_id, 0);
radeon_connector->ddc_bus->rec.i2c_id, 0);
}
static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector)
@ -436,11 +365,11 @@ static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector)
if (!(dig_connector->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))
return;
if (drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_SINK_OUI, buf, 3))
if (drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_SINK_OUI, buf, 3))
DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n",
buf[0], buf[1], buf[2]);
if (drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_BRANCH_OUI, buf, 3))
if (drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_BRANCH_OUI, buf, 3))
DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n",
buf[0], buf[1], buf[2]);
}
@ -451,7 +380,7 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)
u8 msg[DP_DPCD_SIZE];
int ret, i;
ret = drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_DPCD_REV, msg,
ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_DPCD_REV, msg,
DP_DPCD_SIZE);
if (ret > 0) {
memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE);
@ -489,7 +418,7 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
if (dp_bridge != ENCODER_OBJECT_ID_NONE) {
/* DP bridge chips */
drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux,
drm_dp_dpcd_readb(&radeon_connector->ddc_bus->aux,
DP_EDP_CONFIGURATION_CAP, &tmp);
if (tmp & 1)
panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
@ -500,7 +429,7 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
} else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
/* eDP */
drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux,
drm_dp_dpcd_readb(&radeon_connector->ddc_bus->aux,
DP_EDP_CONFIGURATION_CAP, &tmp);
if (tmp & 1)
panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
@ -554,7 +483,8 @@ bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector)
u8 link_status[DP_LINK_STATUS_SIZE];
struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
if (drm_dp_dpcd_read_link_status(&dig->dp_i2c_bus->aux, link_status) <= 0)
if (drm_dp_dpcd_read_link_status(&radeon_connector->ddc_bus->aux, link_status)
<= 0)
return false;
if (drm_dp_channel_eq_ok(link_status, dig->dp_lane_count))
return false;
@ -574,7 +504,7 @@ void radeon_dp_set_rx_power_state(struct drm_connector *connector,
/* power up/down the sink */
if (dig_connector->dpcd[0] >= 0x11) {
drm_dp_dpcd_writeb(&dig_connector->dp_i2c_bus->aux,
drm_dp_dpcd_writeb(&radeon_connector->ddc_bus->aux,
DP_SET_POWER, power_state);
usleep_range(1000, 2000);
}
@ -878,7 +808,7 @@ void radeon_dp_link_train(struct drm_encoder *encoder,
else
dp_info.enc_id |= ATOM_DP_CONFIG_LINK_A;
drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux, DP_MAX_LANE_COUNT, &tmp);
drm_dp_dpcd_readb(&radeon_connector->ddc_bus->aux, DP_MAX_LANE_COUNT, &tmp);
if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED))
dp_info.tp3_supported = true;
else
@ -890,7 +820,7 @@ void radeon_dp_link_train(struct drm_encoder *encoder,
dp_info.connector = connector;
dp_info.dp_lane_count = dig_connector->dp_lane_count;
dp_info.dp_clock = dig_connector->dp_clock;
dp_info.aux = &dig_connector->dp_i2c_bus->aux;
dp_info.aux = &radeon_connector->ddc_bus->aux;
if (radeon_dp_link_train_init(&dp_info))
goto done;

Some files were not shown because too many files have changed in this diff Show More