forked from Minki/linux
Merge branch 'perf/urgent' into perf/core, to pick up fixes
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
42ebd27bcb
1
.mailmap
1
.mailmap
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
97
Documentation/devicetree/bindings/arm/marvell,kirkwood.txt
Normal file
97
Documentation/devicetree/bindings/arm/marvell,kirkwood.txt
Normal 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"
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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>;
|
||||
|
@ -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.
|
||||
|
@ -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週間毎ですが、差し迫っ
|
||||
た問題がなければもう少し長くなることもあります。セキュリティ関連の問題
|
||||
の場合はこれに対してだいたいの場合、すぐにリリースがされます。
|
||||
|
@ -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 のアドレスに送られる。
|
||||
|
||||
レビューサイクル-
|
||||
|
@ -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=
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
@ -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.
|
@ -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?
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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文件具体描述了可被稳定
|
||||
|
67
Documentation/zh_CN/io_ordering.txt
Normal file
67
Documentation/zh_CN/io_ordering.txt
Normal 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芯片清刷未处理的写操作,
|
||||
再处理后面的读操作,防止引发数据不一致问题。
|
@ -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
|
||||
|
@ -42,7 +42,7 @@ Documentation/stable_kernel_rules.txt 的中文翻译
|
||||
|
||||
向稳定版代码树提交补丁的过程:
|
||||
|
||||
- 在确认了补丁符合以上的规则后,将补丁发送到stable@kernel.org。
|
||||
- 在确认了补丁符合以上的规则后,将补丁发送到stable@vger.kernel.org。
|
||||
- 如果补丁被接受到队列里,发送者会收到一个ACK回复,如果没有被接受,收
|
||||
到的是NAK回复。回复需要几天的时间,这取决于开发者的时间安排。
|
||||
- 被接受的补丁会被加到稳定版本队列里,等待其他开发者的审查。
|
||||
|
@ -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
|
||||
|
2
Makefile
2
Makefile
@ -1,7 +1,7 @@
|
||||
VERSION = 3
|
||||
PATCHLEVEL = 15
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc1
|
||||
EXTRAVERSION = -rc2
|
||||
NAME = Shuffling Zombie Juror
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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)");
|
||||
|
@ -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))
|
||||
|
@ -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 */
|
||||
|
@ -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? */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -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");
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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(¶virt_ticketlocks_enabled);
|
||||
return 0;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) || \
|
||||
|
@ -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---
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 = {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
426
drivers/gpu/drm/drm_probe_helper.c
Normal file
426
drivers/gpu/drm/drm_probe_helper.c
Normal 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);
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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, "
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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.. */
|
||||
|
@ -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,
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user