aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2009-12-24 15:16:02 +0900
committerPaul Mundt <lethal@linux-sh.org>2009-12-24 15:16:02 +0900
commitf34548cb735b7a80bbbb0bdd09ad4c2173ba92d5 (patch)
treee53c9e39b3149221779c10595bc59fa02de4f45f /drivers
parent76382b5bdb77c29ab430e1b82ef1c604c8dd113b (diff)
parent32b53076c31ce9159740b744d5eb5d9505312add (diff)
Merge branch 'sh/g3-prep' into sh/for-2.6.33
Diffstat (limited to 'drivers')
-rw-r--r--drivers/accessibility/braille/braille_console.c1
-rw-r--r--drivers/ata/libata-scsi.c2
-rw-r--r--drivers/ata/libata-sff.c2
-rw-r--r--drivers/ata/pata_bf54x.c19
-rw-r--r--drivers/ata/pata_cmd64x.c118
-rw-r--r--drivers/ata/pata_hpt3x2n.c64
-rw-r--r--drivers/ata/pata_octeon_cf.c2
-rw-r--r--drivers/ata/sata_mv.c144
-rw-r--r--drivers/base/bus.c2
-rw-r--r--drivers/base/core.c16
-rw-r--r--drivers/base/devtmpfs.c19
-rw-r--r--drivers/base/driver.c4
-rw-r--r--drivers/base/memory.c19
-rw-r--r--drivers/base/platform.c1
-rw-r--r--drivers/base/power/main.c128
-rw-r--r--drivers/base/power/runtime.c45
-rw-r--r--drivers/bluetooth/btusb.c1
-rw-r--r--drivers/char/nozomi.c48
-rw-r--r--drivers/char/sonypi.c49
-rw-r--r--drivers/gpu/drm/drm_drv.c13
-rw-r--r--drivers/gpu/drm/drm_edid.c2
-rw-r--r--drivers/gpu/drm/drm_ioc32.c89
-rw-r--r--drivers/gpu/drm/drm_mm.c4
-rw-r--r--drivers/gpu/drm/i2c/ch7006_drv.c5
-rw-r--r--drivers/gpu/drm/i2c/ch7006_mode.c5
-rw-r--r--drivers/gpu/drm/i810/i810_dma.c2
-rw-r--r--drivers/gpu/drm/i810/i810_drv.c2
-rw-r--r--drivers/gpu/drm/i830/i830_dma.c2
-rw-r--r--drivers/gpu/drm/i830/i830_drv.c2
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c2
-rw-r--r--drivers/gpu/drm/i915/i915_ioc32.c23
-rw-r--r--drivers/gpu/drm/mga/mga_drv.c2
-rw-r--r--drivers/gpu/drm/mga/mga_ioc32.c13
-rw-r--r--drivers/gpu/drm/nouveau/Makefile5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c621
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c19
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c28
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h27
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c22
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_grctx.c161
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_grctx.h133
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ioc32.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c147
-rw-r--r--drivers/gpu/drm/nouveau/nv04_crtc.c10
-rw-r--r--drivers/gpu/drm/nouveau/nv04_dac.c8
-rw-r--r--drivers/gpu/drm/nouveau/nv04_dfp.c8
-rw-r--r--drivers/gpu/drm/nouveau/nv04_display.c11
-rw-r--r--drivers/gpu/drm/nouveau/nv04_graph.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv10_graph.c197
-rw-r--r--drivers/gpu/drm/nouveau/nv17_tv.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv40_graph.c212
-rw-r--r--drivers/gpu/drm/nouveau/nv40_grctx.c678
-rw-r--r--drivers/gpu/drm/nouveau/nv50_crtc.c22
-rw-r--r--drivers/gpu/drm/nouveau/nv50_cursor.c8
-rw-r--r--drivers/gpu/drm/nouveau/nv50_dac.c20
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c20
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fifo.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_graph.c10
-rw-r--r--drivers/gpu/drm/nouveau/nv50_sor.c16
-rw-r--r--drivers/gpu/drm/r128/r128_drv.c2
-rw-r--r--drivers/gpu/drm/r128/r128_ioc32.c16
-rw-r--r--drivers/gpu/drm/radeon/atom.c12
-rw-r--r--drivers/gpu/drm/radeon/atom.h1
-rw-r--r--drivers/gpu/drm/radeon/atombios.h199
-rw-r--r--drivers/gpu/drm/radeon/r100.c4
-rw-r--r--drivers/gpu/drm/radeon/r100_track.h4
-rw-r--r--drivers/gpu/drm/radeon/r300.c30
-rw-r--r--drivers/gpu/drm/radeon/r300_cmdbuf.c6
-rw-r--r--drivers/gpu/drm/radeon/r300_reg.h1
-rw-r--r--drivers/gpu/drm/radeon/r600_cs.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon.h4
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h7
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c105
-rw-r--r--drivers/gpu/drm/radeon/radeon_clocks.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_combios.c9
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c16
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c80
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c18
-rw-r--r--drivers/gpu/drm/radeon/radeon_fence.c9
-rw-r--r--drivers/gpu/drm/radeon/radeon_ioc32.c38
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_crtc.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_encoders.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h6
-rw-r--r--drivers/gpu/drm/radeon/radeon_test.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c4
-rw-r--r--drivers/gpu/drm/savage/savage_drv.c2
-rw-r--r--drivers/gpu/drm/sis/sis_drv.c2
-rw-r--r--drivers/gpu/drm/tdfx/tdfx_drv.c2
-rw-r--r--drivers/gpu/drm/via/via_drv.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c47
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h10
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c157
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c6
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_irq.c6
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c8
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c149
-rw-r--r--drivers/hid/hid-lg.h2
-rw-r--r--drivers/hwmon/Kconfig37
-rw-r--r--drivers/hwmon/Makefile3
-rw-r--r--drivers/hwmon/k10temp.c197
-rw-r--r--drivers/hwmon/lis3lv02d_i2c.c183
-rw-r--r--drivers/hwmon/sht15.c6
-rw-r--r--drivers/hwmon/smsc47m1.c153
-rw-r--r--drivers/hwmon/via-cputemp.c356
-rw-r--r--drivers/hwmon/w83627hf.c2
-rw-r--r--drivers/idle/i7300_idle.c15
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.h9
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_resource.c75
-rw-r--r--drivers/isdn/mISDN/l1oip_core.c2
-rw-r--r--drivers/leds/Kconfig33
-rw-r--r--drivers/leds/Makefile4
-rw-r--r--drivers/leds/leds-adp5520.c230
-rw-r--r--drivers/leds/leds-alix2.c115
-rw-r--r--drivers/leds/leds-cobalt-qube.c4
-rw-r--r--drivers/leds/leds-cobalt-raq.c2
-rw-r--r--drivers/leds/leds-lt3593.c217
-rw-r--r--drivers/leds/leds-pwm.c5
-rw-r--r--drivers/leds/leds-regulator.c242
-rw-r--r--drivers/leds/leds-ss4200.c556
-rw-r--r--drivers/media/video/cx23885/cx23888-ir.c44
-rw-r--r--drivers/media/video/meye.c60
-rw-r--r--drivers/media/video/meye.h4
-rw-r--r--drivers/message/fusion/mptbase.c6
-rw-r--r--drivers/misc/Kconfig1
-rw-r--r--drivers/misc/enclosure.c1
-rw-r--r--drivers/mmc/core/sdio.c5
-rw-r--r--drivers/mmc/core/sdio_bus.c7
-rw-r--r--drivers/mmc/host/Kconfig37
-rw-r--r--drivers/mmc/host/Makefile6
-rw-r--r--drivers/mmc/host/sdhci-of-core.c (renamed from drivers/mmc/host/sdhci-of.c)143
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c143
-rw-r--r--drivers/mmc/host/sdhci-of-hlwd.c65
-rw-r--r--drivers/mmc/host/sdhci-of.h42
-rw-r--r--drivers/mmc/host/sdhci.h4
-rw-r--r--drivers/mtd/maps/pxa2xx-flash.c13
-rw-r--r--drivers/mtd/nand/Kconfig8
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/excite_nandflash.c248
-rw-r--r--drivers/net/Kconfig2
-rw-r--r--drivers/net/Makefile2
-rw-r--r--drivers/net/bnx2.c12
-rw-r--r--drivers/net/can/at91_can.c2
-rw-r--r--drivers/net/davinci_emac.c2
-rw-r--r--drivers/net/e100.c2
-rw-r--r--drivers/net/e1000e/82571.c6
-rw-r--r--drivers/net/gianfar.c50
-rw-r--r--drivers/net/gianfar.h18
-rw-r--r--drivers/net/netxen/netxen_nic_main.c57
-rw-r--r--drivers/net/octeon/Kconfig10
-rw-r--r--drivers/net/octeon/Makefile2
-rw-r--r--drivers/net/octeon/octeon_mgmt.c1176
-rw-r--r--drivers/net/phy/Kconfig11
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/broadcom.c3
-rw-r--r--drivers/net/phy/mdio-octeon.c180
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h2
-rw-r--r--drivers/net/wireless/libertas/cmd.c4
-rw-r--r--drivers/net/wireless/libertas/dev.h4
-rw-r--r--drivers/net/wireless/libertas/main.c21
-rw-r--r--drivers/pcmcia/pxa2xx_base.c6
-rw-r--r--drivers/platform/x86/compal-laptop.c1
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c30
-rw-r--r--drivers/platform/x86/sony-laptop.c56
-rw-r--r--drivers/regulator/88pm8607.c685
-rw-r--r--drivers/regulator/Kconfig13
-rw-r--r--drivers/regulator/Makefile4
-rw-r--r--drivers/regulator/ab3100.c33
-rw-r--r--drivers/regulator/core.c248
-rw-r--r--drivers/regulator/da903x.c2
-rw-r--r--drivers/regulator/lp3971.c4
-rw-r--r--drivers/regulator/max8660.c510
-rw-r--r--drivers/regulator/mc13783-regulator.c245
-rw-r--r--drivers/regulator/mc13783.c410
-rw-r--r--drivers/regulator/twl-regulator.c147
-rw-r--r--drivers/regulator/wm831x-dcdc.c207
-rw-r--r--drivers/regulator/wm831x-ldo.c2
-rw-r--r--drivers/rtc/rtc-cmos.c3
-rw-r--r--drivers/rtc/rtc-ds1305.c2
-rw-r--r--drivers/rtc/rtc-ds1307.c2
-rw-r--r--drivers/rtc/rtc-ds1374.c2
-rw-r--r--drivers/s390/block/dasd_alias.c2
-rw-r--r--drivers/s390/block/dasd_diag.c42
-rw-r--r--drivers/s390/char/fs3270.c2
-rw-r--r--drivers/s390/char/tape_34xx.c1
-rw-r--r--drivers/s390/char/tape_3590.c3
-rw-r--r--drivers/s390/char/tape_block.c1
-rw-r--r--drivers/s390/char/tape_char.c3
-rw-r--r--drivers/s390/char/tape_class.c4
-rw-r--r--drivers/s390/char/tape_core.c2
-rw-r--r--drivers/s390/char/tape_proc.c3
-rw-r--r--drivers/s390/char/tape_std.c3
-rw-r--r--drivers/s390/cio/ccwreq.c3
-rw-r--r--drivers/s390/cio/device.c1
-rw-r--r--drivers/s390/cio/device_pgid.c29
-rw-r--r--drivers/s390/cio/fcx.c4
-rw-r--r--drivers/s390/cio/io_sch.h1
-rw-r--r--drivers/s390/cio/qdio_main.c3
-rw-r--r--drivers/s390/cio/qdio_perf.c2
-rw-r--r--drivers/s390/cio/qdio_perf.h1
-rw-r--r--drivers/s390/cio/qdio_setup.c10
-rw-r--r--drivers/scsi/3w-9xxx.c11
-rw-r--r--drivers/scsi/Kconfig10
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c12
-rw-r--r--drivers/scsi/bnx2i/bnx2i.h1
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c51
-rw-r--r--drivers/scsi/bnx2i/bnx2i_init.c16
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c2
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_offload.c24
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_pdu.c4
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c2
-rw-r--r--drivers/scsi/fcoe/fcoe.c137
-rw-r--r--drivers/scsi/hpsa.c3531
-rw-r--r--drivers/scsi/hpsa.h273
-rw-r--r--drivers/scsi/hpsa_cmd.h326
-rw-r--r--drivers/scsi/ipr.c1
-rw-r--r--drivers/scsi/libfc/fc_fcp.c65
-rw-r--r--drivers/scsi/libfc/fc_lport.c7
-rw-r--r--drivers/scsi/libfc/fc_rport.c1
-rw-r--r--drivers/scsi/libiscsi.c22
-rw-r--r--drivers/scsi/libiscsi_tcp.c36
-rw-r--r--drivers/scsi/libsrp.c17
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c16
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c14
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c5
-rw-r--r--drivers/scsi/mvsas/mv_init.c1
-rw-r--r--drivers/scsi/osd/osd_initiator.c88
-rw-r--r--drivers/scsi/pm8001/pm8001_ctl.h10
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c149
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.h3
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c19
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c57
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.h32
-rw-r--r--drivers/scsi/pmcraid.c34
-rw-r--r--drivers/scsi/pmcraid.h5
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h5
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c12
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c103
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c75
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/scsi_lib.c1
-rw-r--r--drivers/scsi/scsi_transport_fc.c17
-rw-r--r--drivers/scsi/sd.c107
-rw-r--r--drivers/scsi/sd.h2
-rw-r--r--drivers/scsi/st.c23
-rw-r--r--drivers/scsi/st.h1
-rw-r--r--drivers/serial/sh-sci.c20
-rw-r--r--drivers/serial/sh-sci.h118
-rw-r--r--drivers/spi/Kconfig28
-rw-r--r--drivers/spi/Makefile10
-rw-r--r--drivers/spi/atmel_spi.c6
-rw-r--r--drivers/spi/dw_spi.c944
-rw-r--r--drivers/spi/dw_spi_pci.c169
-rw-r--r--drivers/spi/spi_bfin5xx.c2
-rw-r--r--drivers/spi/spi_mpc8xxx.c2
-rw-r--r--drivers/spi/spi_s3c24xx.c244
-rw-r--r--drivers/spi/spi_s3c24xx_fiq.S116
-rw-r--r--drivers/spi/spi_s3c24xx_fiq.h26
-rw-r--r--drivers/spi/spi_s3c64xx.c1196
-rw-r--r--drivers/spi/spi_sh_sci.c2
-rw-r--r--drivers/spi/spi_txx9.c6
-rw-r--r--drivers/spi/spidev.c18
-rw-r--r--drivers/staging/Kconfig4
-rw-r--r--drivers/staging/Makefile2
-rw-r--r--drivers/staging/batman-adv/Kconfig1
-rw-r--r--drivers/staging/batman-adv/send.c4
-rw-r--r--drivers/staging/comedi/comedi.h2
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c7
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c5
-rw-r--r--drivers/staging/dst/Kconfig67
-rw-r--r--drivers/staging/dst/Makefile3
-rw-r--r--drivers/staging/dst/crypto.c733
-rw-r--r--drivers/staging/dst/dcore.c968
-rw-r--r--drivers/staging/dst/export.c660
-rw-r--r--drivers/staging/dst/state.c844
-rw-r--r--drivers/staging/dst/thread_pool.c348
-rw-r--r--drivers/staging/dst/trans.c337
-rw-r--r--drivers/staging/iio/ring_sw.h1
-rw-r--r--drivers/staging/octeon/Kconfig3
-rw-r--r--drivers/staging/octeon/ethernet-mdio.c204
-rw-r--r--drivers/staging/octeon/ethernet-mdio.h2
-rw-r--r--drivers/staging/octeon/ethernet-proc.c112
-rw-r--r--drivers/staging/octeon/ethernet-rgmii.c52
-rw-r--r--drivers/staging/octeon/ethernet-sgmii.c2
-rw-r--r--drivers/staging/octeon/ethernet-xaui.c2
-rw-r--r--drivers/staging/octeon/ethernet.c23
-rw-r--r--drivers/staging/octeon/octeon-ethernet.h6
-rw-r--r--drivers/staging/panel/Kconfig2
-rw-r--r--drivers/staging/panel/panel.c4
-rw-r--r--drivers/staging/pohmelfs/dir.c2
-rw-r--r--drivers/staging/ramzswap/TODO1
-rw-r--r--drivers/staging/ramzswap/ramzswap_drv.c28
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211.h10
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c14
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c2
-rw-r--r--drivers/staging/rtl8187se/r8180_core.c10
-rw-r--r--drivers/staging/rtl8187se/r8180_wx.c2
-rw-r--r--drivers/staging/rtl8192e/ieee80211.h12
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211.h12
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_module.c10
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c2
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c24
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c2
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c2
-rw-r--r--drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c6
-rw-r--r--drivers/staging/rtl8192e/r8192E_core.c14
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211.h8
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c6
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c16
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c2
-rw-r--r--drivers/staging/rtl8192su/r8192U_core.c10
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c6
-rw-r--r--drivers/staging/sm7xx/Kconfig15
-rw-r--r--drivers/staging/sm7xx/Makefile3
-rw-r--r--drivers/staging/sm7xx/TODO10
-rw-r--r--drivers/staging/sm7xx/smtc2d.c979
-rw-r--r--drivers/staging/sm7xx/smtc2d.h530
-rw-r--r--drivers/staging/sm7xx/smtcfb.c1253
-rw-r--r--drivers/staging/sm7xx/smtcfb.h793
-rw-r--r--drivers/staging/vt6655/Kconfig2
-rw-r--r--drivers/staging/vt6656/Kconfig2
-rw-r--r--drivers/staging/wlan-ng/prism2fw.c2
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/core/hcd.c4
-rw-r--r--drivers/usb/core/hub.c58
-rw-r--r--drivers/usb/core/sysfs.c6
-rw-r--r--drivers/usb/core/usb.c6
-rw-r--r--drivers/usb/early/ehci-dbgp.c2
-rw-r--r--drivers/usb/gadget/audio.c1
-rw-r--r--drivers/usb/gadget/f_audio.c15
-rw-r--r--drivers/usb/gadget/u_audio.c12
-rw-r--r--drivers/usb/gadget/u_audio.h2
-rw-r--r--drivers/usb/host/ehci-omap.c2
-rw-r--r--drivers/usb/host/fhci-sched.c10
-rw-r--r--drivers/usb/host/fhci-tds.c35
-rw-r--r--drivers/usb/host/fhci.h16
-rw-r--r--drivers/usb/misc/appledisplay.c5
-rw-r--r--drivers/usb/misc/emi62.c2
-rw-r--r--drivers/usb/musb/blackfin.c134
-rw-r--r--drivers/usb/musb/blackfin.h2
-rw-r--r--drivers/usb/musb/cppi_dma.c6
-rw-r--r--drivers/usb/musb/davinci.c2
-rw-r--r--drivers/usb/musb/musb_core.c14
-rw-r--r--drivers/usb/musb/musb_gadget.c13
-rw-r--r--drivers/usb/musb/musb_gadget_ep0.c14
-rw-r--r--drivers/usb/otg/isp1301_omap.c4
-rw-r--r--drivers/usb/serial/ftdi_sio.c1
-rw-r--r--drivers/usb/serial/ftdi_sio.h959
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h986
-rw-r--r--drivers/usb/serial/generic.c12
-rw-r--r--drivers/usb/serial/mos7840.c7
-rw-r--r--drivers/usb/serial/option.c5
-rw-r--r--drivers/usb/serial/usb-serial.c7
-rw-r--r--drivers/video/atafb.c3
-rw-r--r--drivers/video/backlight/adp5520_bl.c2
-rw-r--r--drivers/video/backlight/adx_bl.c2
-rw-r--r--drivers/video/backlight/atmel-pwm-bl.c2
-rw-r--r--drivers/video/backlight/backlight.c2
-rw-r--r--drivers/video/backlight/corgi_lcd.c2
-rw-r--r--drivers/video/backlight/cr_bllcd.c4
-rw-r--r--drivers/video/backlight/da903x_bl.c2
-rw-r--r--drivers/video/backlight/generic_bl.c2
-rw-r--r--drivers/video/backlight/hp680_bl.c2
-rw-r--r--drivers/video/backlight/jornada720_bl.c2
-rw-r--r--drivers/video/backlight/kb3886_bl.c2
-rw-r--r--drivers/video/backlight/locomolcd.c2
-rw-r--r--drivers/video/backlight/mbp_nvidia_bl.c20
-rw-r--r--drivers/video/backlight/omap1_bl.c2
-rw-r--r--drivers/video/backlight/progear_bl.c2
-rw-r--r--drivers/video/backlight/pwm_bl.c11
-rw-r--r--drivers/video/backlight/tosa_bl.c2
-rw-r--r--drivers/video/backlight/wm831x_bl.c2
-rw-r--r--drivers/video/omap/lcd_ldp.c4
-rw-r--r--drivers/video/omap/lcd_omap2evm.c10
-rw-r--r--drivers/video/omap/lcd_omap3beagle.c2
-rw-r--r--drivers/video/omap/lcd_omap3evm.c10
-rw-r--r--drivers/video/omap/lcd_overo.c2
-rw-r--r--drivers/video/via/viafbdev.c4
-rw-r--r--drivers/watchdog/Kconfig12
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/geodewdt.c40
-rw-r--r--drivers/watchdog/rm9k_wdt.c419
391 files changed, 22063 insertions, 9121 deletions
diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c
index d672cfe7ca5..cb423f5aef2 100644
--- a/drivers/accessibility/braille/braille_console.c
+++ b/drivers/accessibility/braille/braille_console.c
@@ -21,7 +21,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/autoconf.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 1683ebda900..f4ea5a8c325 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3022,7 +3022,7 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
case WRITE_16:
return ata_scsi_rw_xlat;
- case 0x93 /*WRITE_SAME_16*/:
+ case WRITE_SAME_16:
return ata_scsi_write_same_xlat;
case SYNCHRONIZE_CACHE:
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index efa8773bef5..741065c9da6 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -2275,7 +2275,7 @@ void ata_sff_drain_fifo(struct ata_queued_cmd *qc)
ap = qc->ap;
/* Drain up to 64K of data before we give up this recovery method */
for (count = 0; (ap->ops->sff_check_status(ap) & ATA_DRQ)
- && count < 32768; count++)
+ && count < 65536; count += 2)
ioread16(ap->ioaddr.data_addr);
/* Can become DEBUG later */
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
index c4b47a3e544..02c81f12c70 100644
--- a/drivers/ata/pata_bf54x.c
+++ b/drivers/ata/pata_bf54x.c
@@ -1557,6 +1557,25 @@ static unsigned short atapi_io_port[] = {
P_ATAPI_DMARQ,
P_ATAPI_INTRQ,
P_ATAPI_IORDY,
+ P_ATAPI_D0A,
+ P_ATAPI_D1A,
+ P_ATAPI_D2A,
+ P_ATAPI_D3A,
+ P_ATAPI_D4A,
+ P_ATAPI_D5A,
+ P_ATAPI_D6A,
+ P_ATAPI_D7A,
+ P_ATAPI_D8A,
+ P_ATAPI_D9A,
+ P_ATAPI_D10A,
+ P_ATAPI_D11A,
+ P_ATAPI_D12A,
+ P_ATAPI_D13A,
+ P_ATAPI_D14A,
+ P_ATAPI_D15A,
+ P_ATAPI_A0A,
+ P_ATAPI_A1A,
+ P_ATAPI_A2A,
0
};
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index dadfc358ba1..0efb1f58f25 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -31,7 +31,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_cmd64x"
-#define DRV_VERSION "0.3.1"
+#define DRV_VERSION "0.2.5"
/*
* CMD64x specific registers definition.
@@ -219,7 +219,7 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
regU |= udma_data[adev->dma_mode - XFER_UDMA_0] << shift;
/* Merge the control bits */
regU |= 1 << adev->devno; /* UDMA on */
- if (adev->dma_mode > 2) /* 15nS timing */
+ if (adev->dma_mode > XFER_UDMA_2) /* 15nS timing */
regU |= 4 << adev->devno;
} else {
regU &= ~ (1 << adev->devno); /* UDMA off */
@@ -254,109 +254,17 @@ static void cmd648_bmdma_stop(struct ata_queued_cmd *qc)
}
/**
- * cmd64x_bmdma_stop - DMA stop callback
+ * cmd646r1_dma_stop - DMA stop callback
* @qc: Command in progress
*
- * Track the completion of live DMA commands and clear the
- * host->private_data DMA tracking flag as we do.
+ * Stub for now while investigating the r1 quirk in the old driver.
*/
-static void cmd64x_bmdma_stop(struct ata_queued_cmd *qc)
+static void cmd646r1_bmdma_stop(struct ata_queued_cmd *qc)
{
- struct ata_port *ap = qc->ap;
ata_bmdma_stop(qc);
- WARN_ON(ap->host->private_data != ap);
- ap->host->private_data = NULL;
-}
-
-/**
- * cmd64x_qc_defer - Defer logic for chip limits
- * @qc: queued command
- *
- * Decide whether we can issue the command. Called under the host lock.
- */
-
-static int cmd64x_qc_defer(struct ata_queued_cmd *qc)
-{
- struct ata_host *host = qc->ap->host;
- struct ata_port *alt = host->ports[1 ^ qc->ap->port_no];
- int rc;
- int dma = 0;
-
- /* Apply the ATA rules first */
- rc = ata_std_qc_defer(qc);
- if (rc)
- return rc;
-
- if (qc->tf.protocol == ATAPI_PROT_DMA ||
- qc->tf.protocol == ATA_PROT_DMA)
- dma = 1;
-
- /* If the other port is not live then issue the command */
- if (alt == NULL || !alt->qc_active) {
- if (dma)
- host->private_data = qc->ap;
- return 0;
- }
- /* If there is a live DMA command then wait */
- if (host->private_data != NULL)
- return ATA_DEFER_PORT;
- if (dma)
- /* Cannot overlap our DMA command */
- return ATA_DEFER_PORT;
- return 0;
}
-/**
- * cmd64x_interrupt - ATA host interrupt handler
- * @irq: irq line (unused)
- * @dev_instance: pointer to our ata_host information structure
- *
- * Our interrupt handler for PCI IDE devices. Calls
- * ata_sff_host_intr() for each port that is flagging an IRQ. We cannot
- * use the defaults as we need to avoid touching status/altstatus during
- * a DMA.
- *
- * LOCKING:
- * Obtains host lock during operation.
- *
- * RETURNS:
- * IRQ_NONE or IRQ_HANDLED.
- */
-irqreturn_t cmd64x_interrupt(int irq, void *dev_instance)
-{
- struct ata_host *host = dev_instance;
- struct pci_dev *pdev = to_pci_dev(host->dev);
- unsigned int i;
- unsigned int handled = 0;
- unsigned long flags;
- static const u8 irq_reg[2] = { CFR, ARTTIM23 };
- static const u8 irq_mask[2] = { 1 << 2, 1 << 4 };
-
- /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
- spin_lock_irqsave(&host->lock, flags);
-
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap;
- u8 reg;
-
- pci_read_config_byte(pdev, irq_reg[i], &reg);
- ap = host->ports[i];
- if (ap && (reg & irq_mask[i]) &&
- !(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_queued_cmd *qc;
-
- qc = ata_qc_from_tag(ap, ap->link.active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
- (qc->flags & ATA_QCFLAG_ACTIVE))
- handled |= ata_sff_host_intr(ap, qc);
- }
- }
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- return IRQ_RETVAL(handled);
-}
static struct scsi_host_template cmd64x_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
@@ -365,8 +273,6 @@ static const struct ata_port_operations cmd64x_base_ops = {
.inherits = &ata_bmdma_port_ops,
.set_piomode = cmd64x_set_piomode,
.set_dmamode = cmd64x_set_dmamode,
- .bmdma_stop = cmd64x_bmdma_stop,
- .qc_defer = cmd64x_qc_defer,
};
static struct ata_port_operations cmd64x_port_ops = {
@@ -376,6 +282,7 @@ static struct ata_port_operations cmd64x_port_ops = {
static struct ata_port_operations cmd646r1_port_ops = {
.inherits = &cmd64x_base_ops,
+ .bmdma_stop = cmd646r1_bmdma_stop,
.cable_detect = ata_cable_40wire,
};
@@ -383,7 +290,6 @@ static struct ata_port_operations cmd648_port_ops = {
.inherits = &cmd64x_base_ops,
.bmdma_stop = cmd648_bmdma_stop,
.cable_detect = cmd648_cable_detect,
- .qc_defer = ata_std_qc_defer
};
static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -432,7 +338,6 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
const struct ata_port_info *ppi[] = { &cmd_info[id->driver_data], NULL };
u8 mrdmode;
int rc;
- struct ata_host *host;
rc = pcim_enable_device(pdev);
if (rc)
@@ -450,25 +355,20 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
ppi[0] = &cmd_info[3];
}
-
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
pci_read_config_byte(pdev, MRDMODE, &mrdmode);
mrdmode &= ~ 0x30; /* IRQ set up */
mrdmode |= 0x02; /* Memory read line enable */
pci_write_config_byte(pdev, MRDMODE, mrdmode);
+ /* Force PIO 0 here.. */
+
/* PPC specific fixup copied from old driver */
#ifdef CONFIG_PPC
pci_write_config_byte(pdev, UDIDETCR0, 0xF0);
#endif
- rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
- if (rc)
- return rc;
- /* We use this pointer to track the AP which has DMA running */
- host->private_data = NULL;
- pci_set_master(pdev);
- return ata_pci_sff_activate_host(host, cmd64x_interrupt, &cmd64x_sht);
+ return ata_pci_sff_init_one(pdev, ppi, &cmd64x_sht, NULL);
}
#ifdef CONFIG_PM
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index 9a09a1b11ca..dd26bc73bd9 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -8,7 +8,7 @@
* Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
* Portions Copyright (C) 2001 Sun Microsystems, Inc.
* Portions Copyright (C) 2003 Red Hat Inc
- * Portions Copyright (C) 2005-2007 MontaVista Software, Inc.
+ * Portions Copyright (C) 2005-2009 MontaVista Software, Inc.
*
*
* TODO
@@ -25,7 +25,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt3x2n"
-#define DRV_VERSION "0.3.7"
+#define DRV_VERSION "0.3.8"
enum {
HPT_PCI_FAST = (1 << 31),
@@ -264,7 +264,7 @@ static void hpt3x2n_bmdma_stop(struct ata_queued_cmd *qc)
static void hpt3x2n_set_clock(struct ata_port *ap, int source)
{
- void __iomem *bmdma = ap->ioaddr.bmdma_addr;
+ void __iomem *bmdma = ap->ioaddr.bmdma_addr - ap->port_no * 8;
/* Tristate the bus */
iowrite8(0x80, bmdma+0x73);
@@ -274,9 +274,9 @@ static void hpt3x2n_set_clock(struct ata_port *ap, int source)
iowrite8(source, bmdma+0x7B);
iowrite8(0xC0, bmdma+0x79);
- /* Reset state machines */
- iowrite8(0x37, bmdma+0x70);
- iowrite8(0x37, bmdma+0x74);
+ /* Reset state machines, avoid enabling the disabled channels */
+ iowrite8(ioread8(bmdma+0x70) | 0x32, bmdma+0x70);
+ iowrite8(ioread8(bmdma+0x74) | 0x32, bmdma+0x74);
/* Complete reset */
iowrite8(0x00, bmdma+0x79);
@@ -286,21 +286,10 @@ static void hpt3x2n_set_clock(struct ata_port *ap, int source)
iowrite8(0x00, bmdma+0x77);
}
-/* Check if our partner interface is busy */
-
-static int hpt3x2n_pair_idle(struct ata_port *ap)
-{
- struct ata_host *host = ap->host;
- struct ata_port *pair = host->ports[ap->port_no ^ 1];
-
- if (pair->hsm_task_state == HSM_ST_IDLE)
- return 1;
- return 0;
-}
-
static int hpt3x2n_use_dpll(struct ata_port *ap, int writing)
{
long flags = (long)ap->host->private_data;
+
/* See if we should use the DPLL */
if (writing)
return USE_DPLL; /* Needed for write */
@@ -309,20 +298,35 @@ static int hpt3x2n_use_dpll(struct ata_port *ap, int writing)
return 0;
}
+static int hpt3x2n_qc_defer(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_port *alt = ap->host->ports[ap->port_no ^ 1];
+ int rc, flags = (long)ap->host->private_data;
+ int dpll = hpt3x2n_use_dpll(ap, qc->tf.flags & ATA_TFLAG_WRITE);
+
+ /* First apply the usual rules */
+ rc = ata_std_qc_defer(qc);
+ if (rc != 0)
+ return rc;
+
+ if ((flags & USE_DPLL) != dpll && alt->qc_active)
+ return ATA_DEFER_PORT;
+ return 0;
+}
+
static unsigned int hpt3x2n_qc_issue(struct ata_queued_cmd *qc)
{
- struct ata_taskfile *tf = &qc->tf;
struct ata_port *ap = qc->ap;
int flags = (long)ap->host->private_data;
+ int dpll = hpt3x2n_use_dpll(ap, qc->tf.flags & ATA_TFLAG_WRITE);
- if (hpt3x2n_pair_idle(ap)) {
- int dpll = hpt3x2n_use_dpll(ap, (tf->flags & ATA_TFLAG_WRITE));
- if ((flags & USE_DPLL) != dpll) {
- if (dpll == 1)
- hpt3x2n_set_clock(ap, 0x21);
- else
- hpt3x2n_set_clock(ap, 0x23);
- }
+ if ((flags & USE_DPLL) != dpll) {
+ flags &= ~USE_DPLL;
+ flags |= dpll;
+ ap->host->private_data = (void *)(long)flags;
+
+ hpt3x2n_set_clock(ap, dpll ? 0x21 : 0x23);
}
return ata_sff_qc_issue(qc);
}
@@ -339,6 +343,8 @@ static struct ata_port_operations hpt3x2n_port_ops = {
.inherits = &ata_bmdma_port_ops,
.bmdma_stop = hpt3x2n_bmdma_stop,
+
+ .qc_defer = hpt3x2n_qc_defer,
.qc_issue = hpt3x2n_qc_issue,
.cable_detect = hpt3x2n_cable_detect,
@@ -454,7 +460,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
unsigned int f_low, f_high;
int adjust;
unsigned long iobase = pci_resource_start(dev, 4);
- void *hpriv = NULL;
+ void *hpriv = (void *)USE_DPLL;
int rc;
rc = pcim_enable_device(dev);
@@ -539,7 +545,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
/* Set our private data up. We only need a few flags so we use
it directly */
if (pci_mhz > 60) {
- hpriv = (void *)PCI66;
+ hpriv = (void *)(PCI66 | USE_DPLL);
/*
* On HPT371N, if ATA clock is 66 MHz we must set bit 2 in
* the MISC. register to stretch the UltraDMA Tss timing.
diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c
index d6f69561dc8..37ef416c124 100644
--- a/drivers/ata/pata_octeon_cf.c
+++ b/drivers/ata/pata_octeon_cf.c
@@ -853,7 +853,7 @@ static int __devinit octeon_cf_probe(struct platform_device *pdev)
return -EINVAL;
cs1 = devm_ioremap_nocache(&pdev->dev, res_cs1->start,
- res_cs0->end - res_cs1->start + 1);
+ resource_size(res_cs1));
if (!cs1)
return -ENOMEM;
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index a8a7be0d06f..df8ee325d3c 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -59,6 +59,7 @@
#include <linux/dmapool.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
+#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/ata_platform.h>
#include <linux/mbus.h>
@@ -538,6 +539,7 @@ struct mv_port_signal {
struct mv_host_priv {
u32 hp_flags;
+ unsigned int board_idx;
u32 main_irq_mask;
struct mv_port_signal signal[8];
const struct mv_hw_ops *ops;
@@ -548,6 +550,10 @@ struct mv_host_priv {
u32 irq_cause_offset;
u32 irq_mask_offset;
u32 unmask_all_irqs;
+
+#if defined(CONFIG_HAVE_CLK)
+ struct clk *clk;
+#endif
/*
* These consistent DMA memory pools give us guaranteed
* alignment for hardware-accessed data structures,
@@ -2775,7 +2781,7 @@ static void mv_port_intr(struct ata_port *ap, u32 port_cause)
struct mv_port_priv *pp;
int edma_was_enabled;
- if (!ap || (ap->flags & ATA_FLAG_DISABLED)) {
+ if (ap->flags & ATA_FLAG_DISABLED) {
mv_unexpected_intr(ap, 0);
return;
}
@@ -3393,7 +3399,7 @@ static void mv_soc_reset_hc_port(struct mv_host_priv *hpriv,
ZERO(0x024); /* respq outp */
ZERO(0x020); /* respq inp */
ZERO(0x02c); /* test control */
- writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
+ writel(0x800, port_mmio + EDMA_IORDY_TMOUT);
}
#undef ZERO
@@ -3854,7 +3860,6 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
/**
* mv_init_host - Perform some early initialization of the host.
* @host: ATA host to initialize
- * @board_idx: controller index
*
* If possible, do an early global reset of the host. Then do
* our port init and clear/unmask all/relevant host interrupts.
@@ -3862,13 +3867,13 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
* LOCKING:
* Inherited from caller.
*/
-static int mv_init_host(struct ata_host *host, unsigned int board_idx)
+static int mv_init_host(struct ata_host *host)
{
int rc = 0, n_hc, port, hc;
struct mv_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->base;
- rc = mv_chip_id(host, board_idx);
+ rc = mv_chip_id(host, hpriv->board_idx);
if (rc)
goto done;
@@ -3905,14 +3910,6 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
void __iomem *port_mmio = mv_port_base(mmio, port);
mv_port_init(&ap->ioaddr, port_mmio);
-
-#ifdef CONFIG_PCI
- if (!IS_SOC(hpriv)) {
- unsigned int offset = port_mmio - mmio;
- ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
- ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
- }
-#endif
}
for (hc = 0; hc < n_hc; hc++) {
@@ -4035,12 +4032,21 @@ static int mv_platform_probe(struct platform_device *pdev)
return -ENOMEM;
host->private_data = hpriv;
hpriv->n_ports = n_ports;
+ hpriv->board_idx = chip_soc;
host->iomap = NULL;
hpriv->base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
hpriv->base -= SATAHC0_REG_BASE;
+#if defined(CONFIG_HAVE_CLK)
+ hpriv->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(hpriv->clk))
+ dev_notice(&pdev->dev, "cannot get clkdev\n");
+ else
+ clk_enable(hpriv->clk);
+#endif
+
/*
* (Re-)program MBUS remapping windows if we are asked to.
*/
@@ -4049,12 +4055,12 @@ static int mv_platform_probe(struct platform_device *pdev)
rc = mv_create_dma_pools(hpriv, &pdev->dev);
if (rc)
- return rc;
+ goto err;
/* initialize adapter */
- rc = mv_init_host(host, chip_soc);
+ rc = mv_init_host(host);
if (rc)
- return rc;
+ goto err;
dev_printk(KERN_INFO, &pdev->dev,
"slots %u ports %d\n", (unsigned)MV_MAX_Q_DEPTH,
@@ -4062,6 +4068,15 @@ static int mv_platform_probe(struct platform_device *pdev)
return ata_host_activate(host, platform_get_irq(pdev, 0), mv_interrupt,
IRQF_SHARED, &mv6_sht);
+err:
+#if defined(CONFIG_HAVE_CLK)
+ if (!IS_ERR(hpriv->clk)) {
+ clk_disable(hpriv->clk);
+ clk_put(hpriv->clk);
+ }
+#endif
+
+ return rc;
}
/*
@@ -4076,14 +4091,66 @@ static int __devexit mv_platform_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ata_host *host = dev_get_drvdata(dev);
-
+#if defined(CONFIG_HAVE_CLK)
+ struct mv_host_priv *hpriv = host->private_data;
+#endif
ata_host_detach(host);
+
+#if defined(CONFIG_HAVE_CLK)
+ if (!IS_ERR(hpriv->clk)) {
+ clk_disable(hpriv->clk);
+ clk_put(hpriv->clk);
+ }
+#endif
return 0;
}
+#ifdef CONFIG_PM
+static int mv_platform_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ if (host)
+ return ata_host_suspend(host, state);
+ else
+ return 0;
+}
+
+static int mv_platform_resume(struct platform_device *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int ret;
+
+ if (host) {
+ struct mv_host_priv *hpriv = host->private_data;
+ const struct mv_sata_platform_data *mv_platform_data = \
+ pdev->dev.platform_data;
+ /*
+ * (Re-)program MBUS remapping windows if we are asked to.
+ */
+ if (mv_platform_data->dram != NULL)
+ mv_conf_mbus_windows(hpriv, mv_platform_data->dram);
+
+ /* initialize adapter */
+ ret = mv_init_host(host);
+ if (ret) {
+ printk(KERN_ERR DRV_NAME ": Error during HW init\n");
+ return ret;
+ }
+ ata_host_resume(host);
+ }
+
+ return 0;
+}
+#else
+#define mv_platform_suspend NULL
+#define mv_platform_resume NULL
+#endif
+
static struct platform_driver mv_platform_driver = {
.probe = mv_platform_probe,
.remove = __devexit_p(mv_platform_remove),
+ .suspend = mv_platform_suspend,
+ .resume = mv_platform_resume,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
@@ -4094,6 +4161,9 @@ static struct platform_driver mv_platform_driver = {
#ifdef CONFIG_PCI
static int mv_pci_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent);
+#ifdef CONFIG_PM
+static int mv_pci_device_resume(struct pci_dev *pdev);
+#endif
static struct pci_driver mv_pci_driver = {
@@ -4101,6 +4171,11 @@ static struct pci_driver mv_pci_driver = {
.id_table = mv_pci_tbl,
.probe = mv_pci_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = mv_pci_device_resume,
+#endif
+
};
/* move to PCI layer or libata core? */
@@ -4194,7 +4269,7 @@ static int mv_pci_init_one(struct pci_dev *pdev,
const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL };
struct ata_host *host;
struct mv_host_priv *hpriv;
- int n_ports, rc;
+ int n_ports, port, rc;
if (!printed_version++)
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
@@ -4208,6 +4283,7 @@ static int mv_pci_init_one(struct pci_dev *pdev,
return -ENOMEM;
host->private_data = hpriv;
hpriv->n_ports = n_ports;
+ hpriv->board_idx = board_idx;
/* acquire resources */
rc = pcim_enable_device(pdev);
@@ -4230,8 +4306,17 @@ static int mv_pci_init_one(struct pci_dev *pdev,
if (rc)
return rc;
+ for (port = 0; port < host->n_ports; port++) {
+ struct ata_port *ap = host->ports[port];
+ void __iomem *port_mmio = mv_port_base(hpriv->base, port);
+ unsigned int offset = port_mmio - hpriv->base;
+
+ ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
+ }
+
/* initialize adapter */
- rc = mv_init_host(host, board_idx);
+ rc = mv_init_host(host);
if (rc)
return rc;
@@ -4247,6 +4332,27 @@ static int mv_pci_init_one(struct pci_dev *pdev,
return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht);
}
+
+#ifdef CONFIG_PM
+static int mv_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
+
+ /* initialize adapter */
+ rc = mv_init_host(host);
+ if (rc)
+ return rc;
+
+ ata_host_resume(host);
+
+ return 0;
+}
+#endif
#endif
static int mv_platform_probe(struct platform_device *pdev);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 63c143e54a5..c0c5a43d9fb 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -703,9 +703,9 @@ int bus_add_driver(struct device_driver *drv)
return 0;
out_unregister:
+ kobject_put(&priv->kobj);
kfree(drv->p);
drv->p = NULL;
- kobject_put(&priv->kobj);
out_put_bus:
bus_put(bus);
return error;
diff --git a/drivers/base/core.c b/drivers/base/core.c
index f1290cbd135..28202577042 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -446,7 +446,8 @@ struct kset *devices_kset;
* @dev: device.
* @attr: device attribute descriptor.
*/
-int device_create_file(struct device *dev, struct device_attribute *attr)
+int device_create_file(struct device *dev,
+ const struct device_attribute *attr)
{
int error = 0;
if (dev)
@@ -459,7 +460,8 @@ int device_create_file(struct device *dev, struct device_attribute *attr)
* @dev: device.
* @attr: device attribute descriptor.
*/
-void device_remove_file(struct device *dev, struct device_attribute *attr)
+void device_remove_file(struct device *dev,
+ const struct device_attribute *attr)
{
if (dev)
sysfs_remove_file(&dev->kobj, &attr->attr);
@@ -470,7 +472,8 @@ void device_remove_file(struct device *dev, struct device_attribute *attr)
* @dev: device.
* @attr: device binary attribute descriptor.
*/
-int device_create_bin_file(struct device *dev, struct bin_attribute *attr)
+int device_create_bin_file(struct device *dev,
+ const struct bin_attribute *attr)
{
int error = -EINVAL;
if (dev)
@@ -484,7 +487,8 @@ EXPORT_SYMBOL_GPL(device_create_bin_file);
* @dev: device.
* @attr: device binary attribute descriptor.
*/
-void device_remove_bin_file(struct device *dev, struct bin_attribute *attr)
+void device_remove_bin_file(struct device *dev,
+ const struct bin_attribute *attr)
{
if (dev)
sysfs_remove_bin_file(&dev->kobj, attr);
@@ -905,8 +909,10 @@ int device_add(struct device *dev)
dev->init_name = NULL;
}
- if (!dev_name(dev))
+ if (!dev_name(dev)) {
+ error = -EINVAL;
goto name_error;
+ }
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index 50375bb8e51..090dd485130 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -32,7 +32,7 @@ static int dev_mount = 1;
static int dev_mount;
#endif
-static rwlock_t dirlock;
+static DEFINE_MUTEX(dirlock);
static int __init mount_param(char *str)
{
@@ -93,7 +93,7 @@ static int create_path(const char *nodepath)
{
int err;
- read_lock(&dirlock);
+ mutex_lock(&dirlock);
err = dev_mkdir(nodepath, 0755);
if (err == -ENOENT) {
char *path;
@@ -101,8 +101,10 @@ static int create_path(const char *nodepath)
/* parent directories do not exist, create them */
path = kstrdup(nodepath, GFP_KERNEL);
- if (!path)
- return -ENOMEM;
+ if (!path) {
+ err = -ENOMEM;
+ goto out;
+ }
s = path;
for (;;) {
s = strchr(s, '/');
@@ -117,7 +119,8 @@ static int create_path(const char *nodepath)
}
kfree(path);
}
- read_unlock(&dirlock);
+out:
+ mutex_unlock(&dirlock);
return err;
}
@@ -229,7 +232,7 @@ static int delete_path(const char *nodepath)
if (!path)
return -ENOMEM;
- write_lock(&dirlock);
+ mutex_lock(&dirlock);
for (;;) {
char *base;
@@ -241,7 +244,7 @@ static int delete_path(const char *nodepath)
if (err)
break;
}
- write_unlock(&dirlock);
+ mutex_unlock(&dirlock);
kfree(path);
return err;
@@ -352,8 +355,6 @@ int __init devtmpfs_init(void)
int err;
struct vfsmount *mnt;
- rwlock_init(&dirlock);
-
err = register_filesystem(&dev_fs_type);
if (err) {
printk(KERN_ERR "devtmpfs: unable to register devtmpfs "
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index f367885a764..90c9fff09ea 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -98,7 +98,7 @@ EXPORT_SYMBOL_GPL(driver_find_device);
* @attr: driver attribute descriptor.
*/
int driver_create_file(struct device_driver *drv,
- struct driver_attribute *attr)
+ const struct driver_attribute *attr)
{
int error;
if (drv)
@@ -115,7 +115,7 @@ EXPORT_SYMBOL_GPL(driver_create_file);
* @attr: driver attribute descriptor.
*/
void driver_remove_file(struct device_driver *drv,
- struct driver_attribute *attr)
+ const struct driver_attribute *attr)
{
if (drv)
sysfs_remove_file(&drv->p->kobj, &attr->attr);
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index c4c8f2e1dd1..d7d77d4a402 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -63,6 +63,20 @@ void unregister_memory_notifier(struct notifier_block *nb)
}
EXPORT_SYMBOL(unregister_memory_notifier);
+static ATOMIC_NOTIFIER_HEAD(memory_isolate_chain);
+
+int register_memory_isolate_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&memory_isolate_chain, nb);
+}
+EXPORT_SYMBOL(register_memory_isolate_notifier);
+
+void unregister_memory_isolate_notifier(struct notifier_block *nb)
+{
+ atomic_notifier_chain_unregister(&memory_isolate_chain, nb);
+}
+EXPORT_SYMBOL(unregister_memory_isolate_notifier);
+
/*
* register_memory - Setup a sysfs device for a memory block
*/
@@ -157,6 +171,11 @@ int memory_notify(unsigned long val, void *v)
return blocking_notifier_call_chain(&memory_chain, val, v);
}
+int memory_isolate_notify(unsigned long val, void *v)
+{
+ return atomic_notifier_call_chain(&memory_isolate_chain, val, v);
+}
+
/*
* MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is
* OK to have direct references to sparsemem variables in here.
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 9d2ee25deaf..58efaf2f125 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -441,6 +441,7 @@ error:
platform_device_put(pdev);
return ERR_PTR(retval);
}
+EXPORT_SYMBOL_GPL(platform_device_register_data);
static int platform_drv_probe(struct device *_dev)
{
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 1a216c114a0..48adf80926a 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -161,6 +161,32 @@ void device_pm_move_last(struct device *dev)
list_move_tail(&dev->power.entry, &dpm_list);
}
+static ktime_t initcall_debug_start(struct device *dev)
+{
+ ktime_t calltime = ktime_set(0, 0);
+
+ if (initcall_debug) {
+ pr_info("calling %s+ @ %i\n",
+ dev_name(dev), task_pid_nr(current));
+ calltime = ktime_get();
+ }
+
+ return calltime;
+}
+
+static void initcall_debug_report(struct device *dev, ktime_t calltime,
+ int error)
+{
+ ktime_t delta, rettime;
+
+ if (initcall_debug) {
+ rettime = ktime_get();
+ delta = ktime_sub(rettime, calltime);
+ pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),
+ error, (unsigned long long)ktime_to_ns(delta) >> 10);
+ }
+}
+
/**
* pm_op - Execute the PM operation appropriate for given PM event.
* @dev: Device to handle.
@@ -172,13 +198,9 @@ static int pm_op(struct device *dev,
pm_message_t state)
{
int error = 0;
- ktime_t calltime, delta, rettime;
+ ktime_t calltime;
- if (initcall_debug) {
- pr_info("calling %s+ @ %i\n",
- dev_name(dev), task_pid_nr(current));
- calltime = ktime_get();
- }
+ calltime = initcall_debug_start(dev);
switch (state.event) {
#ifdef CONFIG_SUSPEND
@@ -227,12 +249,7 @@ static int pm_op(struct device *dev,
error = -EINVAL;
}
- if (initcall_debug) {
- rettime = ktime_get();
- delta = ktime_sub(rettime, calltime);
- pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),
- error, (unsigned long long)ktime_to_ns(delta) >> 10);
- }
+ initcall_debug_report(dev, calltime, error);
return error;
}
@@ -309,8 +326,9 @@ static int pm_noirq_op(struct device *dev,
if (initcall_debug) {
rettime = ktime_get();
delta = ktime_sub(rettime, calltime);
- printk("initcall %s_i+ returned %d after %Ld usecs\n", dev_name(dev),
- error, (unsigned long long)ktime_to_ns(delta) >> 10);
+ printk("initcall %s_i+ returned %d after %Ld usecs\n",
+ dev_name(dev), error,
+ (unsigned long long)ktime_to_ns(delta) >> 10);
}
return error;
@@ -354,6 +372,23 @@ static void pm_dev_err(struct device *dev, pm_message_t state, char *info,
kobject_name(&dev->kobj), pm_verb(state.event), info, error);
}
+static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info)
+{
+ ktime_t calltime;
+ s64 usecs64;
+ int usecs;
+
+ calltime = ktime_get();
+ usecs64 = ktime_to_ns(ktime_sub(calltime, starttime));
+ do_div(usecs64, NSEC_PER_USEC);
+ usecs = usecs64;
+ if (usecs == 0)
+ usecs = 1;
+ pr_info("PM: %s%s%s of devices complete after %ld.%03ld msecs\n",
+ info ?: "", info ? " " : "", pm_verb(state.event),
+ usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC);
+}
+
/*------------------------- Resume routines -------------------------*/
/**
@@ -390,6 +425,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
void dpm_resume_noirq(pm_message_t state)
{
struct device *dev;
+ ktime_t starttime = ktime_get();
mutex_lock(&dpm_list_mtx);
transition_started = false;
@@ -403,11 +439,32 @@ void dpm_resume_noirq(pm_message_t state)
pm_dev_err(dev, state, " early", error);
}
mutex_unlock(&dpm_list_mtx);
+ dpm_show_time(starttime, state, "early");
resume_device_irqs();
}
EXPORT_SYMBOL_GPL(dpm_resume_noirq);
/**
+ * legacy_resume - Execute a legacy (bus or class) resume callback for device.
+ * dev: Device to resume.
+ * cb: Resume callback to execute.
+ */
+static int legacy_resume(struct device *dev, int (*cb)(struct device *dev))
+{
+ int error;
+ ktime_t calltime;
+
+ calltime = initcall_debug_start(dev);
+
+ error = cb(dev);
+ suspend_report_result(cb, error);
+
+ initcall_debug_report(dev, calltime, error);
+
+ return error;
+}
+
+/**
* device_resume - Execute "resume" callbacks for given device.
* @dev: Device to handle.
* @state: PM transition of the system being carried out.
@@ -427,7 +484,7 @@ static int device_resume(struct device *dev, pm_message_t state)
error = pm_op(dev, dev->bus->pm, state);
} else if (dev->bus->resume) {
pm_dev_dbg(dev, state, "legacy ");
- error = dev->bus->resume(dev);
+ error = legacy_resume(dev, dev->bus->resume);
}
if (error)
goto End;
@@ -448,7 +505,7 @@ static int device_resume(struct device *dev, pm_message_t state)
error = pm_op(dev, dev->class->pm, state);
} else if (dev->class->resume) {
pm_dev_dbg(dev, state, "legacy class ");
- error = dev->class->resume(dev);
+ error = legacy_resume(dev, dev->class->resume);
}
}
End:
@@ -468,6 +525,7 @@ static int device_resume(struct device *dev, pm_message_t state)
static void dpm_resume(pm_message_t state)
{
struct list_head list;
+ ktime_t starttime = ktime_get();
INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
@@ -496,6 +554,7 @@ static void dpm_resume(pm_message_t state)
}
list_splice(&list, &dpm_list);
mutex_unlock(&dpm_list_mtx);
+ dpm_show_time(starttime, state, NULL);
}
/**
@@ -548,7 +607,7 @@ static void dpm_complete(pm_message_t state)
mutex_unlock(&dpm_list_mtx);
device_complete(dev, state);
- pm_runtime_put_noidle(dev);
+ pm_runtime_put_sync(dev);
mutex_lock(&dpm_list_mtx);
}
@@ -628,6 +687,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
int dpm_suspend_noirq(pm_message_t state)
{
struct device *dev;
+ ktime_t starttime = ktime_get();
int error = 0;
suspend_device_irqs();
@@ -643,11 +703,34 @@ int dpm_suspend_noirq(pm_message_t state)
mutex_unlock(&dpm_list_mtx);
if (error)
dpm_resume_noirq(resume_event(state));
+ else
+ dpm_show_time(starttime, state, "late");
return error;
}
EXPORT_SYMBOL_GPL(dpm_suspend_noirq);
/**
+ * legacy_suspend - Execute a legacy (bus or class) suspend callback for device.
+ * dev: Device to suspend.
+ * cb: Suspend callback to execute.
+ */
+static int legacy_suspend(struct device *dev, pm_message_t state,
+ int (*cb)(struct device *dev, pm_message_t state))
+{
+ int error;
+ ktime_t calltime;
+
+ calltime = initcall_debug_start(dev);
+
+ error = cb(dev, state);
+ suspend_report_result(cb, error);
+
+ initcall_debug_report(dev, calltime, error);
+
+ return error;
+}
+
+/**
* device_suspend - Execute "suspend" callbacks for given device.
* @dev: Device to handle.
* @state: PM transition of the system being carried out.
@@ -664,8 +747,7 @@ static int device_suspend(struct device *dev, pm_message_t state)
error = pm_op(dev, dev->class->pm, state);
} else if (dev->class->suspend) {
pm_dev_dbg(dev, state, "legacy class ");
- error = dev->class->suspend(dev, state);
- suspend_report_result(dev->class->suspend, error);
+ error = legacy_suspend(dev, state, dev->class->suspend);
}
if (error)
goto End;
@@ -686,8 +768,7 @@ static int device_suspend(struct device *dev, pm_message_t state)
error = pm_op(dev, dev->bus->pm, state);
} else if (dev->bus->suspend) {
pm_dev_dbg(dev, state, "legacy ");
- error = dev->bus->suspend(dev, state);
- suspend_report_result(dev->bus->suspend, error);
+ error = legacy_suspend(dev, state, dev->bus->suspend);
}
}
End:
@@ -703,6 +784,7 @@ static int device_suspend(struct device *dev, pm_message_t state)
static int dpm_suspend(pm_message_t state)
{
struct list_head list;
+ ktime_t starttime = ktime_get();
int error = 0;
INIT_LIST_HEAD(&list);
@@ -728,6 +810,8 @@ static int dpm_suspend(pm_message_t state)
}
list_splice(&list, dpm_list.prev);
mutex_unlock(&dpm_list_mtx);
+ if (!error)
+ dpm_show_time(starttime, state, NULL);
return error;
}
@@ -796,7 +880,7 @@ static int dpm_prepare(pm_message_t state)
pm_runtime_get_noresume(dev);
if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) {
/* Wake-up requested during system sleep transition. */
- pm_runtime_put_noidle(dev);
+ pm_runtime_put_sync(dev);
error = -EBUSY;
} else {
error = device_prepare(dev, state);
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 40d7720a4b2..f8b044e8aef 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -85,6 +85,19 @@ static int __pm_runtime_idle(struct device *dev)
dev->bus->pm->runtime_idle(dev);
spin_lock_irq(&dev->power.lock);
+ } else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) {
+ spin_unlock_irq(&dev->power.lock);
+
+ dev->type->pm->runtime_idle(dev);
+
+ spin_lock_irq(&dev->power.lock);
+ } else if (dev->class && dev->class->pm
+ && dev->class->pm->runtime_idle) {
+ spin_unlock_irq(&dev->power.lock);
+
+ dev->class->pm->runtime_idle(dev);
+
+ spin_lock_irq(&dev->power.lock);
}
dev->power.idle_notification = false;
@@ -194,6 +207,22 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
spin_lock_irq(&dev->power.lock);
dev->power.runtime_error = retval;
+ } else if (dev->type && dev->type->pm
+ && dev->type->pm->runtime_suspend) {
+ spin_unlock_irq(&dev->power.lock);
+
+ retval = dev->type->pm->runtime_suspend(dev);
+
+ spin_lock_irq(&dev->power.lock);
+ dev->power.runtime_error = retval;
+ } else if (dev->class && dev->class->pm
+ && dev->class->pm->runtime_suspend) {
+ spin_unlock_irq(&dev->power.lock);
+
+ retval = dev->class->pm->runtime_suspend(dev);
+
+ spin_lock_irq(&dev->power.lock);
+ dev->power.runtime_error = retval;
} else {
retval = -ENOSYS;
}
@@ -359,6 +388,22 @@ int __pm_runtime_resume(struct device *dev, bool from_wq)
spin_lock_irq(&dev->power.lock);
dev->power.runtime_error = retval;
+ } else if (dev->type && dev->type->pm
+ && dev->type->pm->runtime_resume) {
+ spin_unlock_irq(&dev->power.lock);
+
+ retval = dev->type->pm->runtime_resume(dev);
+
+ spin_lock_irq(&dev->power.lock);
+ dev->power.runtime_error = retval;
+ } else if (dev->class && dev->class->pm
+ && dev->class->pm->runtime_resume) {
+ spin_unlock_irq(&dev->power.lock);
+
+ retval = dev->class->pm->runtime_resume(dev);
+
+ spin_lock_irq(&dev->power.lock);
+ dev->power.runtime_error = retval;
} else {
retval = -ENOSYS;
}
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 4d290599675..a699f09ddf7 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -307,6 +307,7 @@ static void btusb_bulk_complete(struct urb *urb)
return;
usb_anchor_urb(urb, &data->bulk_anchor);
+ usb_mark_last_busy(data->udev);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
index d3400b20444..7d73cd43034 100644
--- a/drivers/char/nozomi.c
+++ b/drivers/char/nozomi.c
@@ -358,7 +358,7 @@ struct port {
u8 update_flow_control;
struct ctrl_ul ctrl_ul;
struct ctrl_dl ctrl_dl;
- struct kfifo *fifo_ul;
+ struct kfifo fifo_ul;
void __iomem *dl_addr[2];
u32 dl_size[2];
u8 toggle_dl;
@@ -685,8 +685,6 @@ static int nozomi_read_config_table(struct nozomi *dc)
dump_table(dc);
for (i = PORT_MDM; i < MAX_PORT; i++) {
- dc->port[i].fifo_ul =
- kfifo_alloc(FIFO_BUFFER_SIZE_UL, GFP_ATOMIC, NULL);
memset(&dc->port[i].ctrl_dl, 0, sizeof(struct ctrl_dl));
memset(&dc->port[i].ctrl_ul, 0, sizeof(struct ctrl_ul));
}
@@ -798,7 +796,7 @@ static int send_data(enum port_type index, struct nozomi *dc)
struct tty_struct *tty = tty_port_tty_get(&port->port);
/* Get data from tty and place in buf for now */
- size = __kfifo_get(port->fifo_ul, dc->send_buf,
+ size = kfifo_out(&port->fifo_ul, dc->send_buf,
ul_size < SEND_BUF_MAX ? ul_size : SEND_BUF_MAX);
if (size == 0) {
@@ -988,11 +986,11 @@ static int receive_flow_control(struct nozomi *dc)
} else if (old_ctrl.CTS == 0 && ctrl_dl.CTS == 1) {
- if (__kfifo_len(dc->port[port].fifo_ul)) {
+ if (kfifo_len(&dc->port[port].fifo_ul)) {
DBG1("Enable interrupt (0x%04X) on port: %d",
enable_ier, port);
DBG1("Data in buffer [%d], enable transmit! ",
- __kfifo_len(dc->port[port].fifo_ul));
+ kfifo_len(&dc->port[port].fifo_ul));
enable_transmit_ul(port, dc);
} else {
DBG1("No data in buffer...");
@@ -1433,6 +1431,16 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
goto err_free_sbuf;
}
+ for (i = PORT_MDM; i < MAX_PORT; i++) {
+ if (kfifo_alloc(&dc->port[i].fifo_ul,
+ FIFO_BUFFER_SIZE_UL, GFP_ATOMIC)) {
+ dev_err(&pdev->dev,
+ "Could not allocate kfifo buffer\n");
+ ret = -ENOMEM;
+ goto err_free_kfifo;
+ }
+ }
+
spin_lock_init(&dc->spin_mutex);
nozomi_setup_private_data(dc);
@@ -1445,7 +1453,7 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
NOZOMI_NAME, dc);
if (unlikely(ret)) {
dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq);
- goto err_free_sbuf;
+ goto err_free_kfifo;
}
DBG1("base_addr: %p", dc->base_addr);
@@ -1464,13 +1472,28 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
dc->state = NOZOMI_STATE_ENABLED;
for (i = 0; i < MAX_PORT; i++) {
+ struct device *tty_dev;
+
mutex_init(&dc->port[i].tty_sem);
tty_port_init(&dc->port[i].port);
- tty_register_device(ntty_driver, dc->index_start + i,
+ tty_dev = tty_register_device(ntty_driver, dc->index_start + i,
&pdev->dev);
+
+ if (IS_ERR(tty_dev)) {
+ ret = PTR_ERR(tty_dev);
+ dev_err(&pdev->dev, "Could not allocate tty?\n");
+ goto err_free_tty;
+ }
}
+
return 0;
+err_free_tty:
+ for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i)
+ tty_unregister_device(ntty_driver, i);
+err_free_kfifo:
+ for (i = 0; i < MAX_PORT; i++)
+ kfifo_free(&dc->port[i].fifo_ul);
err_free_sbuf:
kfree(dc->send_buf);
iounmap(dc->base_addr);
@@ -1536,8 +1559,7 @@ static void __devexit nozomi_card_exit(struct pci_dev *pdev)
free_irq(pdev->irq, dc);
for (i = 0; i < MAX_PORT; i++)
- if (dc->port[i].fifo_ul)
- kfifo_free(dc->port[i].fifo_ul);
+ kfifo_free(&dc->port[i].fifo_ul);
kfree(dc->send_buf);
@@ -1673,7 +1695,7 @@ static int ntty_write(struct tty_struct *tty, const unsigned char *buffer,
goto exit;
}
- rval = __kfifo_put(port->fifo_ul, (unsigned char *)buffer, count);
+ rval = kfifo_in(&port->fifo_ul, (unsigned char *)buffer, count);
/* notify card */
if (unlikely(dc == NULL)) {
@@ -1721,7 +1743,7 @@ static int ntty_write_room(struct tty_struct *tty)
if (!port->port.count)
goto exit;
- room = port->fifo_ul->size - __kfifo_len(port->fifo_ul);
+ room = port->fifo_ul.size - kfifo_len(&port->fifo_ul);
exit:
mutex_unlock(&port->tty_sem);
@@ -1878,7 +1900,7 @@ static s32 ntty_chars_in_buffer(struct tty_struct *tty)
goto exit_in_buffer;
}
- rval = __kfifo_len(port->fifo_ul);
+ rval = kfifo_len(&port->fifo_ul);
exit_in_buffer:
return rval;
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 8c262aaf7c2..0798754a607 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -487,7 +487,7 @@ static struct sonypi_device {
int camera_power;
int bluetooth_power;
struct mutex lock;
- struct kfifo *fifo;
+ struct kfifo fifo;
spinlock_t fifo_lock;
wait_queue_head_t fifo_proc_list;
struct fasync_struct *fifo_async;
@@ -496,7 +496,7 @@ static struct sonypi_device {
struct input_dev *input_jog_dev;
struct input_dev *input_key_dev;
struct work_struct input_work;
- struct kfifo *input_fifo;
+ struct kfifo input_fifo;
spinlock_t input_fifo_lock;
} sonypi_device;
@@ -777,8 +777,9 @@ static void input_keyrelease(struct work_struct *work)
{
struct sonypi_keypress kp;
- while (kfifo_get(sonypi_device.input_fifo, (unsigned char *)&kp,
- sizeof(kp)) == sizeof(kp)) {
+ while (kfifo_out_locked(&sonypi_device.input_fifo, (unsigned char *)&kp,
+ sizeof(kp), &sonypi_device.input_fifo_lock)
+ == sizeof(kp)) {
msleep(10);
input_report_key(kp.dev, kp.key, 0);
input_sync(kp.dev);
@@ -827,8 +828,9 @@ static void sonypi_report_input_event(u8 event)
if (kp.dev) {
input_report_key(kp.dev, kp.key, 1);
input_sync(kp.dev);
- kfifo_put(sonypi_device.input_fifo,
- (unsigned char *)&kp, sizeof(kp));
+ kfifo_in_locked(&sonypi_device.input_fifo,
+ (unsigned char *)&kp, sizeof(kp),
+ &sonypi_device.input_fifo_lock);
schedule_work(&sonypi_device.input_work);
}
}
@@ -880,7 +882,8 @@ found:
acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event);
#endif
- kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event));
+ kfifo_in_locked(&sonypi_device.fifo, (unsigned char *)&event,
+ sizeof(event), &sonypi_device.fifo_lock);
kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN);
wake_up_interruptible(&sonypi_device.fifo_proc_list);
@@ -906,7 +909,7 @@ static int sonypi_misc_open(struct inode *inode, struct file *file)
mutex_lock(&sonypi_device.lock);
/* Flush input queue on first open */
if (!sonypi_device.open_count)
- kfifo_reset(sonypi_device.fifo);
+ kfifo_reset(&sonypi_device.fifo);
sonypi_device.open_count++;
mutex_unlock(&sonypi_device.lock);
unlock_kernel();
@@ -919,17 +922,18 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
ssize_t ret;
unsigned char c;
- if ((kfifo_len(sonypi_device.fifo) == 0) &&
+ if ((kfifo_len(&sonypi_device.fifo) == 0) &&
(file->f_flags & O_NONBLOCK))
return -EAGAIN;
ret = wait_event_interruptible(sonypi_device.fifo_proc_list,
- kfifo_len(sonypi_device.fifo) != 0);
+ kfifo_len(&sonypi_device.fifo) != 0);
if (ret)
return ret;
while (ret < count &&
- (kfifo_get(sonypi_device.fifo, &c, sizeof(c)) == sizeof(c))) {
+ (kfifo_out_locked(&sonypi_device.fifo, &c, sizeof(c),
+ &sonypi_device.fifo_lock) == sizeof(c))) {
if (put_user(c, buf++))
return -EFAULT;
ret++;
@@ -946,7 +950,7 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
{
poll_wait(file, &sonypi_device.fifo_proc_list, wait);
- if (kfifo_len(sonypi_device.fifo))
+ if (kfifo_len(&sonypi_device.fifo))
return POLLIN | POLLRDNORM;
return 0;
}
@@ -1313,11 +1317,10 @@ static int __devinit sonypi_probe(struct platform_device *dev)
"http://www.linux.it/~malattia/wiki/index.php/Sony_drivers\n");
spin_lock_init(&sonypi_device.fifo_lock);
- sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
- &sonypi_device.fifo_lock);
- if (IS_ERR(sonypi_device.fifo)) {
+ error = kfifo_alloc(&sonypi_device.fifo, SONYPI_BUF_SIZE, GFP_KERNEL);
+ if (error) {
printk(KERN_ERR "sonypi: kfifo_alloc failed\n");
- return PTR_ERR(sonypi_device.fifo);
+ return error;
}
init_waitqueue_head(&sonypi_device.fifo_proc_list);
@@ -1393,12 +1396,10 @@ static int __devinit sonypi_probe(struct platform_device *dev)
}
spin_lock_init(&sonypi_device.input_fifo_lock);
- sonypi_device.input_fifo =
- kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
- &sonypi_device.input_fifo_lock);
- if (IS_ERR(sonypi_device.input_fifo)) {
+ error = kfifo_alloc(&sonypi_device.input_fifo, SONYPI_BUF_SIZE,
+ GFP_KERNEL);
+ if (error) {
printk(KERN_ERR "sonypi: kfifo_alloc failed\n");
- error = PTR_ERR(sonypi_device.input_fifo);
goto err_inpdev_unregister;
}
@@ -1423,7 +1424,7 @@ static int __devinit sonypi_probe(struct platform_device *dev)
pci_disable_device(pcidev);
err_put_pcidev:
pci_dev_put(pcidev);
- kfifo_free(sonypi_device.fifo);
+ kfifo_free(&sonypi_device.fifo);
return error;
}
@@ -1438,7 +1439,7 @@ static int __devexit sonypi_remove(struct platform_device *dev)
if (useinput) {
input_unregister_device(sonypi_device.input_key_dev);
input_unregister_device(sonypi_device.input_jog_dev);
- kfifo_free(sonypi_device.input_fifo);
+ kfifo_free(&sonypi_device.input_fifo);
}
misc_deregister(&sonypi_misc_device);
@@ -1451,7 +1452,7 @@ static int __devexit sonypi_remove(struct platform_device *dev)
pci_dev_put(sonypi_device.dev);
}
- kfifo_free(sonypi_device.fifo);
+ kfifo_free(&sonypi_device.fifo);
return 0;
}
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index ff2f1042cb4..766c46875a2 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -434,11 +434,11 @@ static int drm_version(struct drm_device *dev, void *data,
* Looks up the ioctl function in the ::ioctls table, checking for root
* previleges if so required, and dispatches to the respective function.
*/
-int drm_ioctl(struct inode *inode, struct file *filp,
+long drm_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct drm_file *file_priv = filp->private_data;
- struct drm_device *dev = file_priv->minor->dev;
+ struct drm_device *dev;
struct drm_ioctl_desc *ioctl;
drm_ioctl_t *func;
unsigned int nr = DRM_IOCTL_NR(cmd);
@@ -446,6 +446,7 @@ int drm_ioctl(struct inode *inode, struct file *filp,
char stack_kdata[128];
char *kdata = NULL;
+ dev = file_priv->minor->dev;
atomic_inc(&dev->ioctl_count);
atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
++file_priv->ioctl_count;
@@ -501,7 +502,13 @@ int drm_ioctl(struct inode *inode, struct file *filp,
goto err_i1;
}
}
- retcode = func(dev, kdata, file_priv);
+ if (ioctl->flags & DRM_UNLOCKED)
+ retcode = func(dev, kdata, file_priv);
+ else {
+ lock_kernel();
+ retcode = func(dev, kdata, file_priv);
+ unlock_kernel();
+ }
if (cmd & IOC_OUT) {
if (copy_to_user((void __user *)arg, kdata,
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index c39b26f1abe..5c9f79877cb 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -913,7 +913,7 @@ static int drm_cvt_modes(struct drm_connector *connector,
const int rates[] = { 60, 85, 75, 60, 50 };
for (i = 0; i < 4; i++) {
- int width, height;
+ int uninitialized_var(width), height;
cvt = &(timing->data.other_data.data.cvt[i]);
height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 8) + 1) * 2;
diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c
index 282d9fdf9f4..d61d185cf04 100644
--- a/drivers/gpu/drm/drm_ioc32.c
+++ b/drivers/gpu/drm/drm_ioc32.c
@@ -104,7 +104,7 @@ static int compat_drm_version(struct file *file, unsigned int cmd,
&version->desc))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
+ err = drm_ioctl(file,
DRM_IOCTL_VERSION, (unsigned long)version);
if (err)
return err;
@@ -145,8 +145,7 @@ static int compat_drm_getunique(struct file *file, unsigned int cmd,
&u->unique))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_GET_UNIQUE, (unsigned long)u);
+ err = drm_ioctl(file, DRM_IOCTL_GET_UNIQUE, (unsigned long)u);
if (err)
return err;
@@ -174,8 +173,7 @@ static int compat_drm_setunique(struct file *file, unsigned int cmd,
&u->unique))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_SET_UNIQUE, (unsigned long)u);
+ return drm_ioctl(file, DRM_IOCTL_SET_UNIQUE, (unsigned long)u);
}
typedef struct drm_map32 {
@@ -205,8 +203,7 @@ static int compat_drm_getmap(struct file *file, unsigned int cmd,
if (__put_user(idx, &map->offset))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_GET_MAP, (unsigned long)map);
+ err = drm_ioctl(file, DRM_IOCTL_GET_MAP, (unsigned long)map);
if (err)
return err;
@@ -246,8 +243,7 @@ static int compat_drm_addmap(struct file *file, unsigned int cmd,
|| __put_user(m32.flags, &map->flags))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_ADD_MAP, (unsigned long)map);
+ err = drm_ioctl(file, DRM_IOCTL_ADD_MAP, (unsigned long)map);
if (err)
return err;
@@ -284,8 +280,7 @@ static int compat_drm_rmmap(struct file *file, unsigned int cmd,
if (__put_user((void *)(unsigned long)handle, &map->handle))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_RM_MAP, (unsigned long)map);
+ return drm_ioctl(file, DRM_IOCTL_RM_MAP, (unsigned long)map);
}
typedef struct drm_client32 {
@@ -314,8 +309,7 @@ static int compat_drm_getclient(struct file *file, unsigned int cmd,
if (__put_user(idx, &client->idx))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_GET_CLIENT, (unsigned long)client);
+ err = drm_ioctl(file, DRM_IOCTL_GET_CLIENT, (unsigned long)client);
if (err)
return err;
@@ -351,8 +345,7 @@ static int compat_drm_getstats(struct file *file, unsigned int cmd,
if (!access_ok(VERIFY_WRITE, stats, sizeof(*stats)))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_GET_STATS, (unsigned long)stats);
+ err = drm_ioctl(file, DRM_IOCTL_GET_STATS, (unsigned long)stats);
if (err)
return err;
@@ -395,8 +388,7 @@ static int compat_drm_addbufs(struct file *file, unsigned int cmd,
|| __put_user(agp_start, &buf->agp_start))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_ADD_BUFS, (unsigned long)buf);
+ err = drm_ioctl(file, DRM_IOCTL_ADD_BUFS, (unsigned long)buf);
if (err)
return err;
@@ -427,8 +419,7 @@ static int compat_drm_markbufs(struct file *file, unsigned int cmd,
|| __put_user(b32.high_mark, &buf->high_mark))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_MARK_BUFS, (unsigned long)buf);
+ return drm_ioctl(file, DRM_IOCTL_MARK_BUFS, (unsigned long)buf);
}
typedef struct drm_buf_info32 {
@@ -469,8 +460,7 @@ static int compat_drm_infobufs(struct file *file, unsigned int cmd,
|| __put_user(list, &request->list))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_INFO_BUFS, (unsigned long)request);
+ err = drm_ioctl(file, DRM_IOCTL_INFO_BUFS, (unsigned long)request);
if (err)
return err;
@@ -531,8 +521,7 @@ static int compat_drm_mapbufs(struct file *file, unsigned int cmd,
|| __put_user(list, &request->list))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_MAP_BUFS, (unsigned long)request);
+ err = drm_ioctl(file, DRM_IOCTL_MAP_BUFS, (unsigned long)request);
if (err)
return err;
@@ -578,8 +567,7 @@ static int compat_drm_freebufs(struct file *file, unsigned int cmd,
&request->list))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_FREE_BUFS, (unsigned long)request);
+ return drm_ioctl(file, DRM_IOCTL_FREE_BUFS, (unsigned long)request);
}
typedef struct drm_ctx_priv_map32 {
@@ -605,8 +593,7 @@ static int compat_drm_setsareactx(struct file *file, unsigned int cmd,
&request->handle))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_SET_SAREA_CTX, (unsigned long)request);
+ return drm_ioctl(file, DRM_IOCTL_SET_SAREA_CTX, (unsigned long)request);
}
static int compat_drm_getsareactx(struct file *file, unsigned int cmd,
@@ -628,8 +615,7 @@ static int compat_drm_getsareactx(struct file *file, unsigned int cmd,
if (__put_user(ctx_id, &request->ctx_id))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_GET_SAREA_CTX, (unsigned long)request);
+ err = drm_ioctl(file, DRM_IOCTL_GET_SAREA_CTX, (unsigned long)request);
if (err)
return err;
@@ -664,8 +650,7 @@ static int compat_drm_resctx(struct file *file, unsigned int cmd,
&res->contexts))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_RES_CTX, (unsigned long)res);
+ err = drm_ioctl(file, DRM_IOCTL_RES_CTX, (unsigned long)res);
if (err)
return err;
@@ -718,8 +703,7 @@ static int compat_drm_dma(struct file *file, unsigned int cmd,
&d->request_sizes))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_DMA, (unsigned long)d);
+ err = drm_ioctl(file, DRM_IOCTL_DMA, (unsigned long)d);
if (err)
return err;
@@ -751,8 +735,7 @@ static int compat_drm_agp_enable(struct file *file, unsigned int cmd,
if (put_user(m32.mode, &mode->mode))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_AGP_ENABLE, (unsigned long)mode);
+ return drm_ioctl(file, DRM_IOCTL_AGP_ENABLE, (unsigned long)mode);
}
typedef struct drm_agp_info32 {
@@ -781,8 +764,7 @@ static int compat_drm_agp_info(struct file *file, unsigned int cmd,
if (!access_ok(VERIFY_WRITE, info, sizeof(*info)))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_AGP_INFO, (unsigned long)info);
+ err = drm_ioctl(file, DRM_IOCTL_AGP_INFO, (unsigned long)info);
if (err)
return err;
@@ -827,16 +809,14 @@ static int compat_drm_agp_alloc(struct file *file, unsigned int cmd,
|| __put_user(req32.type, &request->type))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_AGP_ALLOC, (unsigned long)request);
+ err = drm_ioctl(file, DRM_IOCTL_AGP_ALLOC, (unsigned long)request);
if (err)
return err;
if (__get_user(req32.handle, &request->handle)
|| __get_user(req32.physical, &request->physical)
|| copy_to_user(argp, &req32, sizeof(req32))) {
- drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_AGP_FREE, (unsigned long)request);
+ drm_ioctl(file, DRM_IOCTL_AGP_FREE, (unsigned long)request);
return -EFAULT;
}
@@ -856,8 +836,7 @@ static int compat_drm_agp_free(struct file *file, unsigned int cmd,
|| __put_user(handle, &request->handle))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_AGP_FREE, (unsigned long)request);
+ return drm_ioctl(file, DRM_IOCTL_AGP_FREE, (unsigned long)request);
}
typedef struct drm_agp_binding32 {
@@ -881,8 +860,7 @@ static int compat_drm_agp_bind(struct file *file, unsigned int cmd,
|| __put_user(req32.offset, &request->offset))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_AGP_BIND, (unsigned long)request);
+ return drm_ioctl(file, DRM_IOCTL_AGP_BIND, (unsigned long)request);
}
static int compat_drm_agp_unbind(struct file *file, unsigned int cmd,
@@ -898,8 +876,7 @@ static int compat_drm_agp_unbind(struct file *file, unsigned int cmd,
|| __put_user(handle, &request->handle))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_AGP_UNBIND, (unsigned long)request);
+ return drm_ioctl(file, DRM_IOCTL_AGP_UNBIND, (unsigned long)request);
}
#endif /* __OS_HAS_AGP */
@@ -923,8 +900,7 @@ static int compat_drm_sg_alloc(struct file *file, unsigned int cmd,
|| __put_user(x, &request->size))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_SG_ALLOC, (unsigned long)request);
+ err = drm_ioctl(file, DRM_IOCTL_SG_ALLOC, (unsigned long)request);
if (err)
return err;
@@ -950,8 +926,7 @@ static int compat_drm_sg_free(struct file *file, unsigned int cmd,
|| __put_user(x << PAGE_SHIFT, &request->handle))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_SG_FREE, (unsigned long)request);
+ return drm_ioctl(file, DRM_IOCTL_SG_FREE, (unsigned long)request);
}
#if defined(CONFIG_X86) || defined(CONFIG_IA64)
@@ -981,8 +956,7 @@ static int compat_drm_update_draw(struct file *file, unsigned int cmd,
__put_user(update32.data, &request->data))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_UPDATE_DRAW, (unsigned long)request);
+ err = drm_ioctl(file, DRM_IOCTL_UPDATE_DRAW, (unsigned long)request);
return err;
}
#endif
@@ -1023,8 +997,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd,
|| __put_user(req32.request.signal, &request->request.signal))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_WAIT_VBLANK, (unsigned long)request);
+ err = drm_ioctl(file, DRM_IOCTL_WAIT_VBLANK, (unsigned long)request);
if (err)
return err;
@@ -1094,16 +1067,14 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
* than always failing.
*/
if (nr >= ARRAY_SIZE(drm_compat_ioctls))
- return drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ return drm_ioctl(filp, cmd, arg);
fn = drm_compat_ioctls[nr];
- lock_kernel(); /* XXX for now */
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
- unlock_kernel();
+ ret = drm_ioctl(filp, cmd, arg);
return ret;
}
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index d7d7eac3ddd..cdec3297712 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -358,7 +358,7 @@ struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
if (entry->size >= size + wasted) {
if (!best_match)
return entry;
- if (size < best_size) {
+ if (entry->size < best_size) {
best = entry;
best_size = entry->size;
}
@@ -408,7 +408,7 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm,
if (entry->size >= size + wasted) {
if (!best_match)
return entry;
- if (size < best_size) {
+ if (entry->size < best_size) {
best = entry;
best_size = entry->size;
}
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c
index 9422a74c8b5..81681a07a80 100644
--- a/drivers/gpu/drm/i2c/ch7006_drv.c
+++ b/drivers/gpu/drm/i2c/ch7006_drv.c
@@ -408,6 +408,11 @@ static int ch7006_probe(struct i2c_client *client, const struct i2c_device_id *i
ch7006_info(client, "Detected version ID: %x\n", val);
+ /* I don't know what this is for, but otherwise I get no
+ * signal.
+ */
+ ch7006_write(client, 0x3d, 0x0);
+
return 0;
fail:
diff --git a/drivers/gpu/drm/i2c/ch7006_mode.c b/drivers/gpu/drm/i2c/ch7006_mode.c
index 87f5445092e..e447dfb6389 100644
--- a/drivers/gpu/drm/i2c/ch7006_mode.c
+++ b/drivers/gpu/drm/i2c/ch7006_mode.c
@@ -427,11 +427,6 @@ void ch7006_state_load(struct i2c_client *client,
ch7006_load_reg(client, state, CH7006_SUBC_INC7);
ch7006_load_reg(client, state, CH7006_PLL_CONTROL);
ch7006_load_reg(client, state, CH7006_CALC_SUBC_INC0);
-
- /* I don't know what this is for, but otherwise I get no
- * signal.
- */
- ch7006_write(client, 0x3d, 0x0);
}
void ch7006_state_save(struct i2c_client *client,
diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c
index 7d1d88cdf2d..de32d22a8c3 100644
--- a/drivers/gpu/drm/i810/i810_dma.c
+++ b/drivers/gpu/drm/i810/i810_dma.c
@@ -115,7 +115,7 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
static const struct file_operations i810_buffer_fops = {
.open = drm_open,
.release = drm_release,
- .ioctl = drm_ioctl,
+ .unlocked_ioctl = drm_ioctl,
.mmap = i810_mmap_buffers,
.fasync = drm_fasync,
};
diff --git a/drivers/gpu/drm/i810/i810_drv.c b/drivers/gpu/drm/i810/i810_drv.c
index fabb9a81796..c1e02752e02 100644
--- a/drivers/gpu/drm/i810/i810_drv.c
+++ b/drivers/gpu/drm/i810/i810_drv.c
@@ -59,7 +59,7 @@ static struct drm_driver driver = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
- .ioctl = drm_ioctl,
+ .unlocked_ioctl = drm_ioctl,
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
diff --git a/drivers/gpu/drm/i830/i830_dma.c b/drivers/gpu/drm/i830/i830_dma.c
index 877bf6cb14a..06bd732e646 100644
--- a/drivers/gpu/drm/i830/i830_dma.c
+++ b/drivers/gpu/drm/i830/i830_dma.c
@@ -117,7 +117,7 @@ static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
static const struct file_operations i830_buffer_fops = {
.open = drm_open,
.release = drm_release,
- .ioctl = drm_ioctl,
+ .unlocked_ioctl = drm_ioctl,
.mmap = i830_mmap_buffers,
.fasync = drm_fasync,
};
diff --git a/drivers/gpu/drm/i830/i830_drv.c b/drivers/gpu/drm/i830/i830_drv.c
index 389597e4a62..44f990bed8f 100644
--- a/drivers/gpu/drm/i830/i830_drv.c
+++ b/drivers/gpu/drm/i830/i830_drv.c
@@ -70,7 +70,7 @@ static struct drm_driver driver = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
- .ioctl = drm_ioctl,
+ .unlocked_ioctl = drm_ioctl,
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 2fa21786205..24286ca168f 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -329,7 +329,7 @@ static struct drm_driver driver = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
- .ioctl = drm_ioctl,
+ .unlocked_ioctl = drm_ioctl,
.mmap = drm_gem_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
diff --git a/drivers/gpu/drm/i915/i915_ioc32.c b/drivers/gpu/drm/i915/i915_ioc32.c
index 1fe68a251b7..13b028994b2 100644
--- a/drivers/gpu/drm/i915/i915_ioc32.c
+++ b/drivers/gpu/drm/i915/i915_ioc32.c
@@ -66,8 +66,7 @@ static int compat_i915_batchbuffer(struct file *file, unsigned int cmd,
&batchbuffer->cliprects))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_I915_BATCHBUFFER,
+ return drm_ioctl(file, DRM_IOCTL_I915_BATCHBUFFER,
(unsigned long)batchbuffer);
}
@@ -102,8 +101,8 @@ static int compat_i915_cmdbuffer(struct file *file, unsigned int cmd,
&cmdbuffer->cliprects))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_I915_CMDBUFFER, (unsigned long)cmdbuffer);
+ return drm_ioctl(file, DRM_IOCTL_I915_CMDBUFFER,
+ (unsigned long)cmdbuffer);
}
typedef struct drm_i915_irq_emit32 {
@@ -125,8 +124,8 @@ static int compat_i915_irq_emit(struct file *file, unsigned int cmd,
&request->irq_seq))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_I915_IRQ_EMIT, (unsigned long)request);
+ return drm_ioctl(file, DRM_IOCTL_I915_IRQ_EMIT,
+ (unsigned long)request);
}
typedef struct drm_i915_getparam32 {
int param;
@@ -149,8 +148,8 @@ static int compat_i915_getparam(struct file *file, unsigned int cmd,
&request->value))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_I915_GETPARAM, (unsigned long)request);
+ return drm_ioctl(file, DRM_IOCTL_I915_GETPARAM,
+ (unsigned long)request);
}
typedef struct drm_i915_mem_alloc32 {
@@ -178,8 +177,8 @@ static int compat_i915_alloc(struct file *file, unsigned int cmd,
&request->region_offset))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_I915_ALLOC, (unsigned long)request);
+ return drm_ioctl(file, DRM_IOCTL_I915_ALLOC,
+ (unsigned long)request);
}
drm_ioctl_compat_t *i915_compat_ioctls[] = {
@@ -211,12 +210,10 @@ long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(i915_compat_ioctls))
fn = i915_compat_ioctls[nr - DRM_COMMAND_BASE];
- lock_kernel(); /* XXX for now */
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
- unlock_kernel();
+ ret = drm_ioctl(filp, cmd, arg);
return ret;
}
diff --git a/drivers/gpu/drm/mga/mga_drv.c b/drivers/gpu/drm/mga/mga_drv.c
index 97ee566ef74..ddfe16197b5 100644
--- a/drivers/gpu/drm/mga/mga_drv.c
+++ b/drivers/gpu/drm/mga/mga_drv.c
@@ -68,7 +68,7 @@ static struct drm_driver driver = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
- .ioctl = drm_ioctl,
+ .unlocked_ioctl = drm_ioctl,
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
diff --git a/drivers/gpu/drm/mga/mga_ioc32.c b/drivers/gpu/drm/mga/mga_ioc32.c
index 30d00478dde..c1f877b7bac 100644
--- a/drivers/gpu/drm/mga/mga_ioc32.c
+++ b/drivers/gpu/drm/mga/mga_ioc32.c
@@ -100,8 +100,7 @@ static int compat_mga_init(struct file *file, unsigned int cmd,
if (err)
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_MGA_INIT, (unsigned long)init);
+ return drm_ioctl(file, DRM_IOCTL_MGA_INIT, (unsigned long)init);
}
typedef struct drm_mga_getparam32 {
@@ -125,8 +124,7 @@ static int compat_mga_getparam(struct file *file, unsigned int cmd,
&getparam->value))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_MGA_GETPARAM, (unsigned long)getparam);
+ return drm_ioctl(file, DRM_IOCTL_MGA_GETPARAM, (unsigned long)getparam);
}
typedef struct drm_mga_drm_bootstrap32 {
@@ -166,8 +164,7 @@ static int compat_mga_dma_bootstrap(struct file *file, unsigned int cmd,
|| __put_user(dma_bootstrap32.agp_size, &dma_bootstrap->agp_size))
return -EFAULT;
- err = drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_MGA_DMA_BOOTSTRAP,
+ err = drm_ioctl(file, DRM_IOCTL_MGA_DMA_BOOTSTRAP,
(unsigned long)dma_bootstrap);
if (err)
return err;
@@ -220,12 +217,10 @@ long mga_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(mga_compat_ioctls))
fn = mga_compat_ioctls[nr - DRM_COMMAND_BASE];
- lock_kernel(); /* XXX for now */
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
- unlock_kernel();
+ ret = drm_ioctl(filp, cmd, arg);
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index 1d90d4d0144..48c290b5da8 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -8,14 +8,15 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nouveau_sgdma.o nouveau_dma.o \
nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \
nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \
- nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
- nouveau_dp.o \
+ nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
+ nouveau_dp.o nouveau_grctx.o \
nv04_timer.o \
nv04_mc.o nv40_mc.o nv50_mc.o \
nv04_fb.o nv10_fb.o nv40_fb.o \
nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \
nv04_graph.o nv10_graph.o nv20_graph.o \
nv40_graph.o nv50_graph.o \
+ nv40_grctx.o \
nv04_instmem.o nv50_instmem.o \
nv50_crtc.o nv50_dac.o nv50_sor.o \
nv50_cursor.o nv50_display.o nv50_fbcon.o \
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index 5eec5ed6948..ba143972769 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -181,43 +181,42 @@ struct methods {
const char desc[8];
void (*loadbios)(struct drm_device *, uint8_t *);
const bool rw;
- int score;
};
static struct methods nv04_methods[] = {
{ "PROM", load_vbios_prom, false },
{ "PRAMIN", load_vbios_pramin, true },
{ "PCIROM", load_vbios_pci, true },
- { }
};
static struct methods nv50_methods[] = {
{ "PRAMIN", load_vbios_pramin, true },
{ "PROM", load_vbios_prom, false },
{ "PCIROM", load_vbios_pci, true },
- { }
};
+#define METHODCNT 3
+
static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct methods *methods, *method;
+ struct methods *methods;
+ int i;
int testscore = 3;
+ int scores[METHODCNT];
if (nouveau_vbios) {
- method = nv04_methods;
- while (method->loadbios) {
- if (!strcasecmp(nouveau_vbios, method->desc))
+ methods = nv04_methods;
+ for (i = 0; i < METHODCNT; i++)
+ if (!strcasecmp(nouveau_vbios, methods[i].desc))
break;
- method++;
- }
- if (method->loadbios) {
+ if (i < METHODCNT) {
NV_INFO(dev, "Attempting to use BIOS image from %s\n",
- method->desc);
+ methods[i].desc);
- method->loadbios(dev, data);
- if (score_vbios(dev, data, method->rw))
+ methods[i].loadbios(dev, data);
+ if (score_vbios(dev, data, methods[i].rw))
return true;
}
@@ -229,28 +228,24 @@ static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
else
methods = nv50_methods;
- method = methods;
- while (method->loadbios) {
+ for (i = 0; i < METHODCNT; i++) {
NV_TRACE(dev, "Attempting to load BIOS image from %s\n",
- method->desc);
+ methods[i].desc);
data[0] = data[1] = 0; /* avoid reuse of previous image */
- method->loadbios(dev, data);
- method->score = score_vbios(dev, data, method->rw);
- if (method->score == testscore)
+ methods[i].loadbios(dev, data);
+ scores[i] = score_vbios(dev, data, methods[i].rw);
+ if (scores[i] == testscore)
return true;
- method++;
}
while (--testscore > 0) {
- method = methods;
- while (method->loadbios) {
- if (method->score == testscore) {
+ for (i = 0; i < METHODCNT; i++) {
+ if (scores[i] == testscore) {
NV_TRACE(dev, "Using BIOS image from %s\n",
- method->desc);
- method->loadbios(dev, data);
+ methods[i].desc);
+ methods[i].loadbios(dev, data);
return true;
}
- method++;
}
}
@@ -261,10 +256,7 @@ static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
struct init_tbl_entry {
char *name;
uint8_t id;
- int length;
- int length_offset;
- int length_multiplier;
- bool (*handler)(struct nvbios *, uint16_t, struct init_exec *);
+ int (*handler)(struct nvbios *, uint16_t, struct init_exec *);
};
struct bit_entry {
@@ -820,7 +812,7 @@ static uint32_t get_tmds_index_reg(struct drm_device *dev, uint8_t mlv)
}
}
-static bool
+static int
init_io_restrict_prog(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -852,9 +844,10 @@ init_io_restrict_prog(struct nvbios *bios, uint16_t offset,
uint32_t reg = ROM32(bios->data[offset + 7]);
uint8_t config;
uint32_t configval;
+ int len = 11 + count * 4;
if (!iexec->execute)
- return true;
+ return len;
BIOSLOG(bios, "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, "
"Shift: 0x%02X, Count: 0x%02X, Reg: 0x%08X\n",
@@ -865,7 +858,7 @@ init_io_restrict_prog(struct nvbios *bios, uint16_t offset,
NV_ERROR(bios->dev,
"0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
offset, config, count);
- return false;
+ return 0;
}
configval = ROM32(bios->data[offset + 11 + config * 4]);
@@ -874,10 +867,10 @@ init_io_restrict_prog(struct nvbios *bios, uint16_t offset,
bios_wr32(bios, reg, configval);
- return true;
+ return len;
}
-static bool
+static int
init_repeat(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -912,10 +905,10 @@ init_repeat(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
iexec->repeat = false;
- return true;
+ return 2;
}
-static bool
+static int
init_io_restrict_pll(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -951,9 +944,10 @@ init_io_restrict_pll(struct nvbios *bios, uint16_t offset,
uint32_t reg = ROM32(bios->data[offset + 8]);
uint8_t config;
uint16_t freq;
+ int len = 12 + count * 2;
if (!iexec->execute)
- return true;
+ return len;
BIOSLOG(bios, "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, "
"Shift: 0x%02X, IO Flag Condition: 0x%02X, "
@@ -966,7 +960,7 @@ init_io_restrict_pll(struct nvbios *bios, uint16_t offset,
NV_ERROR(bios->dev,
"0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
offset, config, count);
- return false;
+ return 0;
}
freq = ROM16(bios->data[offset + 12 + config * 2]);
@@ -986,10 +980,10 @@ init_io_restrict_pll(struct nvbios *bios, uint16_t offset,
setPLL(bios, reg, freq * 10);
- return true;
+ return len;
}
-static bool
+static int
init_end_repeat(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -1007,12 +1001,12 @@ init_end_repeat(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
* we're not in repeat mode
*/
if (iexec->repeat)
- return false;
+ return 0;
- return true;
+ return 1;
}
-static bool
+static int
init_copy(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -1041,7 +1035,7 @@ init_copy(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint8_t crtcdata;
if (!iexec->execute)
- return true;
+ return 11;
BIOSLOG(bios, "0x%04X: Reg: 0x%08X, Shift: 0x%02X, SrcMask: 0x%02X, "
"Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X\n",
@@ -1060,10 +1054,10 @@ init_copy(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
crtcdata |= (uint8_t)data;
bios_idxprt_wr(bios, crtcport, crtcindex, crtcdata);
- return true;
+ return 11;
}
-static bool
+static int
init_not(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -1079,10 +1073,10 @@ init_not(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
BIOSLOG(bios, "0x%04X: ------ Executing following commands ------\n", offset);
iexec->execute = !iexec->execute;
- return true;
+ return 1;
}
-static bool
+static int
init_io_flag_condition(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -1100,7 +1094,7 @@ init_io_flag_condition(struct nvbios *bios, uint16_t offset,
uint8_t cond = bios->data[offset + 1];
if (!iexec->execute)
- return true;
+ return 2;
if (io_flag_condition_met(bios, offset, cond))
BIOSLOG(bios, "0x%04X: Condition fulfilled -- continuing to execute\n", offset);
@@ -1109,10 +1103,10 @@ init_io_flag_condition(struct nvbios *bios, uint16_t offset,
iexec->execute = false;
}
- return true;
+ return 2;
}
-static bool
+static int
init_idx_addr_latched(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -1140,11 +1134,12 @@ init_idx_addr_latched(struct nvbios *bios, uint16_t offset,
uint32_t mask = ROM32(bios->data[offset + 9]);
uint32_t data = ROM32(bios->data[offset + 13]);
uint8_t count = bios->data[offset + 17];
+ int len = 18 + count * 2;
uint32_t value;
int i;
if (!iexec->execute)
- return true;
+ return len;
BIOSLOG(bios, "0x%04X: ControlReg: 0x%08X, DataReg: 0x%08X, "
"Mask: 0x%08X, Data: 0x%08X, Count: 0x%02X\n",
@@ -1164,10 +1159,10 @@ init_idx_addr_latched(struct nvbios *bios, uint16_t offset,
bios_wr32(bios, controlreg, value);
}
- return true;
+ return len;
}
-static bool
+static int
init_io_restrict_pll2(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -1196,25 +1191,26 @@ init_io_restrict_pll2(struct nvbios *bios, uint16_t offset,
uint8_t shift = bios->data[offset + 5];
uint8_t count = bios->data[offset + 6];
uint32_t reg = ROM32(bios->data[offset + 7]);
+ int len = 11 + count * 4;
uint8_t config;
uint32_t freq;
if (!iexec->execute)
- return true;
+ return len;
BIOSLOG(bios, "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, "
"Shift: 0x%02X, Count: 0x%02X, Reg: 0x%08X\n",
offset, crtcport, crtcindex, mask, shift, count, reg);
if (!reg)
- return true;
+ return len;
config = (bios_idxprt_rd(bios, crtcport, crtcindex) & mask) >> shift;
if (config > count) {
NV_ERROR(bios->dev,
"0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
offset, config, count);
- return false;
+ return 0;
}
freq = ROM32(bios->data[offset + 11 + config * 4]);
@@ -1224,10 +1220,10 @@ init_io_restrict_pll2(struct nvbios *bios, uint16_t offset,
setPLL(bios, reg, freq);
- return true;
+ return len;
}
-static bool
+static int
init_pll2(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -1244,16 +1240,16 @@ init_pll2(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint32_t freq = ROM32(bios->data[offset + 5]);
if (!iexec->execute)
- return true;
+ return 9;
BIOSLOG(bios, "0x%04X: Reg: 0x%04X, Freq: %dkHz\n",
offset, reg, freq);
setPLL(bios, reg, freq);
- return true;
+ return 9;
}
-static bool
+static int
init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -1277,12 +1273,13 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint8_t i2c_index = bios->data[offset + 1];
uint8_t i2c_address = bios->data[offset + 2];
uint8_t count = bios->data[offset + 3];
+ int len = 4 + count * 3;
struct nouveau_i2c_chan *chan;
struct i2c_msg msg;
int i;
if (!iexec->execute)
- return true;
+ return len;
BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X, "
"Count: 0x%02X\n",
@@ -1290,7 +1287,7 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
chan = init_i2c_device_find(bios->dev, i2c_index);
if (!chan)
- return false;
+ return 0;
for (i = 0; i < count; i++) {
uint8_t i2c_reg = bios->data[offset + 4 + i * 3];
@@ -1303,7 +1300,7 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
msg.len = 1;
msg.buf = &value;
if (i2c_transfer(&chan->adapter, &msg, 1) != 1)
- return false;
+ return 0;
BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, "
"Mask: 0x%02X, Data: 0x%02X\n",
@@ -1317,14 +1314,14 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
msg.len = 1;
msg.buf = &value;
if (i2c_transfer(&chan->adapter, &msg, 1) != 1)
- return false;
+ return 0;
}
}
- return true;
+ return len;
}
-static bool
+static int
init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -1346,12 +1343,13 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint8_t i2c_index = bios->data[offset + 1];
uint8_t i2c_address = bios->data[offset + 2];
uint8_t count = bios->data[offset + 3];
+ int len = 4 + count * 2;
struct nouveau_i2c_chan *chan;
struct i2c_msg msg;
int i;
if (!iexec->execute)
- return true;
+ return len;
BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X, "
"Count: 0x%02X\n",
@@ -1359,7 +1357,7 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
chan = init_i2c_device_find(bios->dev, i2c_index);
if (!chan)
- return false;
+ return 0;
for (i = 0; i < count; i++) {
uint8_t i2c_reg = bios->data[offset + 4 + i * 2];
@@ -1374,14 +1372,14 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
msg.len = 1;
msg.buf = &data;
if (i2c_transfer(&chan->adapter, &msg, 1) != 1)
- return false;
+ return 0;
}
}
- return true;
+ return len;
}
-static bool
+static int
init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -1401,13 +1399,14 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint8_t i2c_index = bios->data[offset + 1];
uint8_t i2c_address = bios->data[offset + 2];
uint8_t count = bios->data[offset + 3];
+ int len = 4 + count;
struct nouveau_i2c_chan *chan;
struct i2c_msg msg;
uint8_t data[256];
int i;
if (!iexec->execute)
- return true;
+ return len;
BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X, "
"Count: 0x%02X\n",
@@ -1415,7 +1414,7 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
chan = init_i2c_device_find(bios->dev, i2c_index);
if (!chan)
- return false;
+ return 0;
for (i = 0; i < count; i++) {
data[i] = bios->data[offset + 4 + i];
@@ -1429,13 +1428,13 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
msg.len = count;
msg.buf = data;
if (i2c_transfer(&chan->adapter, &msg, 1) != 1)
- return false;
+ return 0;
}
- return true;
+ return len;
}
-static bool
+static int
init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -1460,7 +1459,7 @@ init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint32_t reg, value;
if (!iexec->execute)
- return true;
+ return 5;
BIOSLOG(bios, "0x%04X: MagicLookupValue: 0x%02X, TMDSAddr: 0x%02X, "
"Mask: 0x%02X, Data: 0x%02X\n",
@@ -1468,7 +1467,7 @@ init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
reg = get_tmds_index_reg(bios->dev, mlv);
if (!reg)
- return false;
+ return 0;
bios_wr32(bios, reg,
tmdsaddr | NV_PRAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE);
@@ -1476,10 +1475,10 @@ init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
bios_wr32(bios, reg + 4, value);
bios_wr32(bios, reg, tmdsaddr);
- return true;
+ return 5;
}
-static bool
+static int
init_zm_tmds_group(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -1500,18 +1499,19 @@ init_zm_tmds_group(struct nvbios *bios, uint16_t offset,
uint8_t mlv = bios->data[offset + 1];
uint8_t count = bios->data[offset + 2];
+ int len = 3 + count * 2;
uint32_t reg;
int i;
if (!iexec->execute)
- return true;
+ return len;
BIOSLOG(bios, "0x%04X: MagicLookupValue: 0x%02X, Count: 0x%02X\n",
offset, mlv, count);
reg = get_tmds_index_reg(bios->dev, mlv);
if (!reg)
- return false;
+ return 0;
for (i = 0; i < count; i++) {
uint8_t tmdsaddr = bios->data[offset + 3 + i * 2];
@@ -1521,10 +1521,10 @@ init_zm_tmds_group(struct nvbios *bios, uint16_t offset,
bios_wr32(bios, reg, tmdsaddr);
}
- return true;
+ return len;
}
-static bool
+static int
init_cr_idx_adr_latch(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -1547,11 +1547,12 @@ init_cr_idx_adr_latch(struct nvbios *bios, uint16_t offset,
uint8_t crtcindex2 = bios->data[offset + 2];
uint8_t baseaddr = bios->data[offset + 3];
uint8_t count = bios->data[offset + 4];
+ int len = 5 + count;
uint8_t oldaddr, data;
int i;
if (!iexec->execute)
- return true;
+ return len;
BIOSLOG(bios, "0x%04X: Index1: 0x%02X, Index2: 0x%02X, "
"BaseAddr: 0x%02X, Count: 0x%02X\n",
@@ -1568,10 +1569,10 @@ init_cr_idx_adr_latch(struct nvbios *bios, uint16_t offset,
bios_idxprt_wr(bios, NV_CIO_CRX__COLOR, crtcindex1, oldaddr);
- return true;
+ return len;
}
-static bool
+static int
init_cr(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -1592,7 +1593,7 @@ init_cr(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint8_t value;
if (!iexec->execute)
- return true;
+ return 4;
BIOSLOG(bios, "0x%04X: Index: 0x%02X, Mask: 0x%02X, Data: 0x%02X\n",
offset, crtcindex, mask, data);
@@ -1601,10 +1602,10 @@ init_cr(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
value |= data;
bios_idxprt_wr(bios, NV_CIO_CRX__COLOR, crtcindex, value);
- return true;
+ return 4;
}
-static bool
+static int
init_zm_cr(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -1621,14 +1622,14 @@ init_zm_cr(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint8_t data = bios->data[offset + 2];
if (!iexec->execute)
- return true;
+ return 3;
bios_idxprt_wr(bios, NV_CIO_CRX__COLOR, crtcindex, data);
- return true;
+ return 3;
}
-static bool
+static int
init_zm_cr_group(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -1645,18 +1646,19 @@ init_zm_cr_group(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
*/
uint8_t count = bios->data[offset + 1];
+ int len = 2 + count * 2;
int i;
if (!iexec->execute)
- return true;
+ return len;
for (i = 0; i < count; i++)
init_zm_cr(bios, offset + 2 + 2 * i - 1, iexec);
- return true;
+ return len;
}
-static bool
+static int
init_condition_time(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -1680,7 +1682,7 @@ init_condition_time(struct nvbios *bios, uint16_t offset,
unsigned cnt;
if (!iexec->execute)
- return true;
+ return 3;
if (retries > 100)
retries = 100;
@@ -1711,10 +1713,10 @@ init_condition_time(struct nvbios *bios, uint16_t offset,
iexec->execute = false;
}
- return true;
+ return 3;
}
-static bool
+static int
init_zm_reg_sequence(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -1734,10 +1736,11 @@ init_zm_reg_sequence(struct nvbios *bios, uint16_t offset,
uint32_t basereg = ROM32(bios->data[offset + 1]);
uint32_t count = bios->data[offset + 5];
+ int len = 6 + count * 4;
int i;
if (!iexec->execute)
- return true;
+ return len;
BIOSLOG(bios, "0x%04X: BaseReg: 0x%08X, Count: 0x%02X\n",
offset, basereg, count);
@@ -1749,10 +1752,10 @@ init_zm_reg_sequence(struct nvbios *bios, uint16_t offset,
bios_wr32(bios, reg, data);
}
- return true;
+ return len;
}
-static bool
+static int
init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -1768,7 +1771,7 @@ init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint16_t sub_offset = ROM16(bios->data[offset + 1]);
if (!iexec->execute)
- return true;
+ return 3;
BIOSLOG(bios, "0x%04X: Executing subroutine at 0x%04X\n",
offset, sub_offset);
@@ -1777,10 +1780,10 @@ init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
BIOSLOG(bios, "0x%04X: End of 0x%04X subroutine\n", offset, sub_offset);
- return true;
+ return 3;
}
-static bool
+static int
init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -1808,7 +1811,7 @@ init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint32_t srcvalue, dstvalue;
if (!iexec->execute)
- return true;
+ return 22;
BIOSLOG(bios, "0x%04X: SrcReg: 0x%08X, Shift: 0x%02X, SrcMask: 0x%08X, "
"Xor: 0x%08X, DstReg: 0x%08X, DstMask: 0x%08X\n",
@@ -1827,10 +1830,10 @@ init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
bios_wr32(bios, dstreg, dstvalue | srcvalue);
- return true;
+ return 22;
}
-static bool
+static int
init_zm_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -1848,14 +1851,14 @@ init_zm_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint8_t data = bios->data[offset + 4];
if (!iexec->execute)
- return true;
+ return 5;
bios_idxprt_wr(bios, crtcport, crtcindex, data);
- return true;
+ return 5;
}
-static bool
+static int
init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -1904,7 +1907,7 @@ init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
if (dev_priv->card_type >= NV_50)
- return true;
+ return 1;
/*
* On every card I've seen, this step gets done for us earlier in
@@ -1922,10 +1925,10 @@ init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
/* write back the saved configuration value */
bios_wr32(bios, NV_PFB_CFG0, bios->state.saved_nv_pfb_cfg0);
- return true;
+ return 1;
}
-static bool
+static int
init_reset(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -1959,10 +1962,10 @@ init_reset(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
pci_nv_20 &= ~NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED; /* 0xfffffffe */
bios_wr32(bios, NV_PBUS_PCI_NV_20, pci_nv_20);
- return true;
+ return 13;
}
-static bool
+static int
init_configure_mem(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -1983,7 +1986,7 @@ init_configure_mem(struct nvbios *bios, uint16_t offset,
uint32_t reg, data;
if (bios->major_version > 2)
- return false;
+ return 0;
bios_idxprt_wr(bios, NV_VIO_SRX, NV_VIO_SR_CLOCK_INDEX, bios_idxprt_rd(
bios, NV_VIO_SRX, NV_VIO_SR_CLOCK_INDEX) | 0x20);
@@ -2015,10 +2018,10 @@ init_configure_mem(struct nvbios *bios, uint16_t offset,
bios_wr32(bios, reg, data);
}
- return true;
+ return 1;
}
-static bool
+static int
init_configure_clk(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -2038,7 +2041,7 @@ init_configure_clk(struct nvbios *bios, uint16_t offset,
int clock;
if (bios->major_version > 2)
- return false;
+ return 0;
clock = ROM16(bios->data[meminitoffs + 4]) * 10;
setPLL(bios, NV_PRAMDAC_NVPLL_COEFF, clock);
@@ -2048,10 +2051,10 @@ init_configure_clk(struct nvbios *bios, uint16_t offset,
clock *= 2;
setPLL(bios, NV_PRAMDAC_MPLL_COEFF, clock);
- return true;
+ return 1;
}
-static bool
+static int
init_configure_preinit(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -2071,15 +2074,15 @@ init_configure_preinit(struct nvbios *bios, uint16_t offset,
uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & (1 << 6));
if (bios->major_version > 2)
- return false;
+ return 0;
bios_idxprt_wr(bios, NV_CIO_CRX__COLOR,
NV_CIO_CRE_SCRATCH4__INDEX, cr3c);
- return true;
+ return 1;
}
-static bool
+static int
init_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2099,7 +2102,7 @@ init_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint8_t data = bios->data[offset + 4];
if (!iexec->execute)
- return true;
+ return 5;
BIOSLOG(bios, "0x%04X: Port: 0x%04X, Mask: 0x%02X, Data: 0x%02X\n",
offset, crtcport, mask, data);
@@ -2158,15 +2161,15 @@ init_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
for (i = 0; i < 2; i++)
bios_wr32(bios, 0x614108 + (i*0x800), bios_rd32(
bios, 0x614108 + (i*0x800)) & 0x0fffffff);
- return true;
+ return 5;
}
bios_port_wr(bios, crtcport, (bios_port_rd(bios, crtcport) & mask) |
data);
- return true;
+ return 5;
}
-static bool
+static int
init_sub(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2181,7 +2184,7 @@ init_sub(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint8_t sub = bios->data[offset + 1];
if (!iexec->execute)
- return true;
+ return 2;
BIOSLOG(bios, "0x%04X: Calling script %d\n", offset, sub);
@@ -2191,10 +2194,10 @@ init_sub(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
BIOSLOG(bios, "0x%04X: End of script %d\n", offset, sub);
- return true;
+ return 2;
}
-static bool
+static int
init_ram_condition(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -2215,7 +2218,7 @@ init_ram_condition(struct nvbios *bios, uint16_t offset,
uint8_t data;
if (!iexec->execute)
- return true;
+ return 3;
data = bios_rd32(bios, NV_PFB_BOOT_0) & mask;
@@ -2229,10 +2232,10 @@ init_ram_condition(struct nvbios *bios, uint16_t offset,
iexec->execute = false;
}
- return true;
+ return 3;
}
-static bool
+static int
init_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2251,17 +2254,17 @@ init_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint32_t data = ROM32(bios->data[offset + 9]);
if (!iexec->execute)
- return true;
+ return 13;
BIOSLOG(bios, "0x%04X: Reg: 0x%08X, Mask: 0x%08X, Data: 0x%08X\n",
offset, reg, mask, data);
bios_wr32(bios, reg, (bios_rd32(bios, reg) & mask) | data);
- return true;
+ return 13;
}
-static bool
+static int
init_macro(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2285,7 +2288,7 @@ init_macro(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
int i;
if (!iexec->execute)
- return true;
+ return 2;
BIOSLOG(bios, "0x%04X: Macro: 0x%02X, MacroTableIndex: 0x%02X, "
"Count: 0x%02X\n",
@@ -2300,10 +2303,10 @@ init_macro(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
bios_wr32(bios, reg, data);
}
- return true;
+ return 2;
}
-static bool
+static int
init_done(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2315,10 +2318,10 @@ init_done(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
*/
/* mild retval abuse to stop parsing this table */
- return false;
+ return 0;
}
-static bool
+static int
init_resume(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2330,15 +2333,15 @@ init_resume(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
*/
if (iexec->execute)
- return true;
+ return 1;
iexec->execute = true;
BIOSLOG(bios, "0x%04X: ---- Executing following commands ----\n", offset);
- return true;
+ return 1;
}
-static bool
+static int
init_time(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2353,7 +2356,7 @@ init_time(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
unsigned time = ROM16(bios->data[offset + 1]);
if (!iexec->execute)
- return true;
+ return 3;
BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X microseconds\n",
offset, time);
@@ -2363,10 +2366,10 @@ init_time(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
else
msleep((time + 900) / 1000);
- return true;
+ return 3;
}
-static bool
+static int
init_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2383,7 +2386,7 @@ init_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint8_t cond = bios->data[offset + 1];
if (!iexec->execute)
- return true;
+ return 2;
BIOSLOG(bios, "0x%04X: Condition: 0x%02X\n", offset, cond);
@@ -2394,10 +2397,10 @@ init_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
iexec->execute = false;
}
- return true;
+ return 2;
}
-static bool
+static int
init_io_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2414,7 +2417,7 @@ init_io_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint8_t cond = bios->data[offset + 1];
if (!iexec->execute)
- return true;
+ return 2;
BIOSLOG(bios, "0x%04X: IO condition: 0x%02X\n", offset, cond);
@@ -2425,10 +2428,10 @@ init_io_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
iexec->execute = false;
}
- return true;
+ return 2;
}
-static bool
+static int
init_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2451,7 +2454,7 @@ init_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint8_t value;
if (!iexec->execute)
- return true;
+ return 6;
BIOSLOG(bios, "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, "
"Data: 0x%02X\n",
@@ -2460,10 +2463,10 @@ init_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
value = (bios_idxprt_rd(bios, crtcport, crtcindex) & mask) | data;
bios_idxprt_wr(bios, crtcport, crtcindex, value);
- return true;
+ return 6;
}
-static bool
+static int
init_pll(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2481,16 +2484,16 @@ init_pll(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint16_t freq = ROM16(bios->data[offset + 5]);
if (!iexec->execute)
- return true;
+ return 7;
BIOSLOG(bios, "0x%04X: Reg: 0x%08X, Freq: %d0kHz\n", offset, reg, freq);
setPLL(bios, reg, freq * 10);
- return true;
+ return 7;
}
-static bool
+static int
init_zm_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2507,17 +2510,17 @@ init_zm_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint32_t value = ROM32(bios->data[offset + 5]);
if (!iexec->execute)
- return true;
+ return 9;
if (reg == 0x000200)
value |= 1;
bios_wr32(bios, reg, value);
- return true;
+ return 9;
}
-static bool
+static int
init_ram_restrict_pll(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -2543,14 +2546,15 @@ init_ram_restrict_pll(struct nvbios *bios, uint16_t offset,
uint8_t type = bios->data[offset + 1];
uint32_t freq = ROM32(bios->data[offset + 2 + (index * 4)]);
uint8_t *pll_limits = &bios->data[bios->pll_limit_tbl_ptr], *entry;
+ int len = 2 + bios->ram_restrict_group_count * 4;
int i;
if (!iexec->execute)
- return true;
+ return len;
if (!bios->pll_limit_tbl_ptr || (pll_limits[0] & 0xf0) != 0x30) {
NV_ERROR(dev, "PLL limits table not version 3.x\n");
- return true; /* deliberate, allow default clocks to remain */
+ return len; /* deliberate, allow default clocks to remain */
}
entry = pll_limits + pll_limits[1];
@@ -2563,15 +2567,15 @@ init_ram_restrict_pll(struct nvbios *bios, uint16_t offset,
offset, type, reg, freq);
setPLL(bios, reg, freq);
- return true;
+ return len;
}
}
NV_ERROR(dev, "PLL type 0x%02x not found in PLL limits table", type);
- return true;
+ return len;
}
-static bool
+static int
init_8c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2581,10 +2585,10 @@ init_8c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
*
*/
- return true;
+ return 1;
}
-static bool
+static int
init_8d(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2594,10 +2598,10 @@ init_8d(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
*
*/
- return true;
+ return 1;
}
-static bool
+static int
init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2615,14 +2619,17 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
const uint8_t *gpio_entry;
int i;
+ if (!iexec->execute)
+ return 1;
+
if (bios->bdcb.version != 0x40) {
NV_ERROR(bios->dev, "DCB table not version 4.0\n");
- return false;
+ return 0;
}
if (!bios->bdcb.gpio_table_ptr) {
NV_WARN(bios->dev, "Invalid pointer to INIT_8E table\n");
- return false;
+ return 0;
}
gpio_entry = gpio_table + gpio_table[1];
@@ -2660,13 +2667,10 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
bios_wr32(bios, r, v);
}
- return true;
+ return 1;
}
-/* hack to avoid moving the itbl_entry array before this function */
-int init_ram_restrict_zm_reg_group_blocklen;
-
-static bool
+static int
init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -2692,21 +2696,21 @@ init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset,
uint8_t regincrement = bios->data[offset + 5];
uint8_t count = bios->data[offset + 6];
uint32_t strap_ramcfg, data;
- uint16_t blocklen;
+ /* previously set by 'M' BIT table */
+ uint16_t blocklen = bios->ram_restrict_group_count * 4;
+ int len = 7 + count * blocklen;
uint8_t index;
int i;
- /* previously set by 'M' BIT table */
- blocklen = init_ram_restrict_zm_reg_group_blocklen;
if (!iexec->execute)
- return true;
+ return len;
if (!blocklen) {
NV_ERROR(bios->dev,
"0x%04X: Zero block length - has the M table "
"been parsed?\n", offset);
- return false;
+ return 0;
}
strap_ramcfg = (bios_rd32(bios, NV_PEXTDEV_BOOT_0) >> 2) & 0xf;
@@ -2724,10 +2728,10 @@ init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset,
reg += regincrement;
}
- return true;
+ return len;
}
-static bool
+static int
init_copy_zm_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2744,14 +2748,14 @@ init_copy_zm_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
uint32_t dstreg = ROM32(bios->data[offset + 5]);
if (!iexec->execute)
- return true;
+ return 9;
bios_wr32(bios, dstreg, bios_rd32(bios, srcreg));
- return true;
+ return 9;
}
-static bool
+static int
init_zm_reg_group_addr_latched(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -2769,20 +2773,21 @@ init_zm_reg_group_addr_latched(struct nvbios *bios, uint16_t offset,
uint32_t reg = ROM32(bios->data[offset + 1]);
uint8_t count = bios->data[offset + 5];
+ int len = 6 + count * 4;
int i;
if (!iexec->execute)
- return true;
+ return len;
for (i = 0; i < count; i++) {
uint32_t data = ROM32(bios->data[offset + 6 + 4 * i]);
bios_wr32(bios, reg, data);
}
- return true;
+ return len;
}
-static bool
+static int
init_reserved(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2793,10 +2798,10 @@ init_reserved(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
* Seemingly does nothing
*/
- return true;
+ return 1;
}
-static bool
+static int
init_96(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2829,13 +2834,13 @@ init_96(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
val <<= bios->data[offset + 16];
if (!iexec->execute)
- return true;
+ return 17;
bios_wr32(bios, reg, (bios_rd32(bios, reg) & mask) | val);
- return true;
+ return 17;
}
-static bool
+static int
init_97(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2859,13 +2864,13 @@ init_97(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
val = (val & mask) | ((val + add) & ~mask);
if (!iexec->execute)
- return true;
+ return 13;
bios_wr32(bios, reg, val);
- return true;
+ return 13;
}
-static bool
+static int
init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2883,32 +2888,33 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
struct drm_device *dev = bios->dev;
struct nouveau_i2c_chan *auxch;
uint32_t addr = ROM32(bios->data[offset + 1]);
- uint8_t len = bios->data[offset + 5];
+ uint8_t count = bios->data[offset + 5];
+ int len = 6 + count * 2;
int ret, i;
if (!bios->display.output) {
NV_ERROR(dev, "INIT_AUXCH: no active output\n");
- return false;
+ return 0;
}
auxch = init_i2c_device_find(dev, bios->display.output->i2c_index);
if (!auxch) {
NV_ERROR(dev, "INIT_AUXCH: couldn't get auxch %d\n",
bios->display.output->i2c_index);
- return false;
+ return 0;
}
if (!iexec->execute)
- return true;
+ return len;
offset += 6;
- for (i = 0; i < len; i++, offset += 2) {
+ for (i = 0; i < count; i++, offset += 2) {
uint8_t data;
ret = nouveau_dp_auxch(auxch, 9, addr, &data, 1);
if (ret) {
NV_ERROR(dev, "INIT_AUXCH: rd auxch fail %d\n", ret);
- return false;
+ return 0;
}
data &= bios->data[offset + 0];
@@ -2917,14 +2923,14 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
ret = nouveau_dp_auxch(auxch, 8, addr, &data, 1);
if (ret) {
NV_ERROR(dev, "INIT_AUXCH: wr auxch fail %d\n", ret);
- return false;
+ return 0;
}
}
- return true;
+ return len;
}
-static bool
+static int
init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2941,106 +2947,99 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
struct drm_device *dev = bios->dev;
struct nouveau_i2c_chan *auxch;
uint32_t addr = ROM32(bios->data[offset + 1]);
- uint8_t len = bios->data[offset + 5];
+ uint8_t count = bios->data[offset + 5];
+ int len = 6 + count;
int ret, i;
if (!bios->display.output) {
NV_ERROR(dev, "INIT_ZM_AUXCH: no active output\n");
- return false;
+ return 0;
}
auxch = init_i2c_device_find(dev, bios->display.output->i2c_index);
if (!auxch) {
NV_ERROR(dev, "INIT_ZM_AUXCH: couldn't get auxch %d\n",
bios->display.output->i2c_index);
- return false;
+ return 0;
}
if (!iexec->execute)
- return true;
+ return len;
offset += 6;
- for (i = 0; i < len; i++, offset++) {
+ for (i = 0; i < count; i++, offset++) {
ret = nouveau_dp_auxch(auxch, 8, addr, &bios->data[offset], 1);
if (ret) {
NV_ERROR(dev, "INIT_ZM_AUXCH: wr auxch fail %d\n", ret);
- return false;
+ return 0;
}
}
- return true;
+ return len;
}
static struct init_tbl_entry itbl_entry[] = {
/* command name , id , length , offset , mult , command handler */
/* INIT_PROG (0x31, 15, 10, 4) removed due to no example of use */
- { "INIT_IO_RESTRICT_PROG" , 0x32, 11 , 6 , 4 , init_io_restrict_prog },
- { "INIT_REPEAT" , 0x33, 2 , 0 , 0 , init_repeat },
- { "INIT_IO_RESTRICT_PLL" , 0x34, 12 , 7 , 2 , init_io_restrict_pll },
- { "INIT_END_REPEAT" , 0x36, 1 , 0 , 0 , init_end_repeat },
- { "INIT_COPY" , 0x37, 11 , 0 , 0 , init_copy },
- { "INIT_NOT" , 0x38, 1 , 0 , 0 , init_not },
- { "INIT_IO_FLAG_CONDITION" , 0x39, 2 , 0 , 0 , init_io_flag_condition },
- { "INIT_INDEX_ADDRESS_LATCHED" , 0x49, 18 , 17 , 2 , init_idx_addr_latched },
- { "INIT_IO_RESTRICT_PLL2" , 0x4A, 11 , 6 , 4 , init_io_restrict_pll2 },
- { "INIT_PLL2" , 0x4B, 9 , 0 , 0 , init_pll2 },
- { "INIT_I2C_BYTE" , 0x4C, 4 , 3 , 3 , init_i2c_byte },
- { "INIT_ZM_I2C_BYTE" , 0x4D, 4 , 3 , 2 , init_zm_i2c_byte },
- { "INIT_ZM_I2C" , 0x4E, 4 , 3 , 1 , init_zm_i2c },
- { "INIT_TMDS" , 0x4F, 5 , 0 , 0 , init_tmds },
- { "INIT_ZM_TMDS_GROUP" , 0x50, 3 , 2 , 2 , init_zm_tmds_group },
- { "INIT_CR_INDEX_ADDRESS_LATCHED" , 0x51, 5 , 4 , 1 , init_cr_idx_adr_latch },
- { "INIT_CR" , 0x52, 4 , 0 , 0 , init_cr },
- { "INIT_ZM_CR" , 0x53, 3 , 0 , 0 , init_zm_cr },
- { "INIT_ZM_CR_GROUP" , 0x54, 2 , 1 , 2 , init_zm_cr_group },
- { "INIT_CONDITION_TIME" , 0x56, 3 , 0 , 0 , init_condition_time },
- { "INIT_ZM_REG_SEQUENCE" , 0x58, 6 , 5 , 4 , init_zm_reg_sequence },
+ { "INIT_IO_RESTRICT_PROG" , 0x32, init_io_restrict_prog },
+ { "INIT_REPEAT" , 0x33, init_repeat },
+ { "INIT_IO_RESTRICT_PLL" , 0x34, init_io_restrict_pll },
+ { "INIT_END_REPEAT" , 0x36, init_end_repeat },
+ { "INIT_COPY" , 0x37, init_copy },
+ { "INIT_NOT" , 0x38, init_not },
+ { "INIT_IO_FLAG_CONDITION" , 0x39, init_io_flag_condition },
+ { "INIT_INDEX_ADDRESS_LATCHED" , 0x49, init_idx_addr_latched },
+ { "INIT_IO_RESTRICT_PLL2" , 0x4A, init_io_restrict_pll2 },
+ { "INIT_PLL2" , 0x4B, init_pll2 },
+ { "INIT_I2C_BYTE" , 0x4C, init_i2c_byte },
+ { "INIT_ZM_I2C_BYTE" , 0x4D, init_zm_i2c_byte },
+ { "INIT_ZM_I2C" , 0x4E, init_zm_i2c },
+ { "INIT_TMDS" , 0x4F, init_tmds },
+ { "INIT_ZM_TMDS_GROUP" , 0x50, init_zm_tmds_group },
+ { "INIT_CR_INDEX_ADDRESS_LATCHED" , 0x51, init_cr_idx_adr_latch },
+ { "INIT_CR" , 0x52, init_cr },
+ { "INIT_ZM_CR" , 0x53, init_zm_cr },
+ { "INIT_ZM_CR_GROUP" , 0x54, init_zm_cr_group },
+ { "INIT_CONDITION_TIME" , 0x56, init_condition_time },
+ { "INIT_ZM_REG_SEQUENCE" , 0x58, init_zm_reg_sequence },
/* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */
- { "INIT_SUB_DIRECT" , 0x5B, 3 , 0 , 0 , init_sub_direct },
- { "INIT_COPY_NV_REG" , 0x5F, 22 , 0 , 0 , init_copy_nv_reg },
- { "INIT_ZM_INDEX_IO" , 0x62, 5 , 0 , 0 , init_zm_index_io },
- { "INIT_COMPUTE_MEM" , 0x63, 1 , 0 , 0 , init_compute_mem },
- { "INIT_RESET" , 0x65, 13 , 0 , 0 , init_reset },
- { "INIT_CONFIGURE_MEM" , 0x66, 1 , 0 , 0 , init_configure_mem },
- { "INIT_CONFIGURE_CLK" , 0x67, 1 , 0 , 0 , init_configure_clk },
- { "INIT_CONFIGURE_PREINIT" , 0x68, 1 , 0 , 0 , init_configure_preinit },
- { "INIT_IO" , 0x69, 5 , 0 , 0 , init_io },
- { "INIT_SUB" , 0x6B, 2 , 0 , 0 , init_sub },
- { "INIT_RAM_CONDITION" , 0x6D, 3 , 0 , 0 , init_ram_condition },
- { "INIT_NV_REG" , 0x6E, 13 , 0 , 0 , init_nv_reg },
- { "INIT_MACRO" , 0x6F, 2 , 0 , 0 , init_macro },
- { "INIT_DONE" , 0x71, 1 , 0 , 0 , init_done },
- { "INIT_RESUME" , 0x72, 1 , 0 , 0 , init_resume },
+ { "INIT_SUB_DIRECT" , 0x5B, init_sub_direct },
+ { "INIT_COPY_NV_REG" , 0x5F, init_copy_nv_reg },
+ { "INIT_ZM_INDEX_IO" , 0x62, init_zm_index_io },
+ { "INIT_COMPUTE_MEM" , 0x63, init_compute_mem },
+ { "INIT_RESET" , 0x65, init_reset },
+ { "INIT_CONFIGURE_MEM" , 0x66, init_configure_mem },
+ { "INIT_CONFIGURE_CLK" , 0x67, init_configure_clk },
+ { "INIT_CONFIGURE_PREINIT" , 0x68, init_configure_preinit },
+ { "INIT_IO" , 0x69, init_io },
+ { "INIT_SUB" , 0x6B, init_sub },
+ { "INIT_RAM_CONDITION" , 0x6D, init_ram_condition },
+ { "INIT_NV_REG" , 0x6E, init_nv_reg },
+ { "INIT_MACRO" , 0x6F, init_macro },
+ { "INIT_DONE" , 0x71, init_done },
+ { "INIT_RESUME" , 0x72, init_resume },
/* INIT_RAM_CONDITION2 (0x73, 9, 0, 0) removed due to no example of use */
- { "INIT_TIME" , 0x74, 3 , 0 , 0 , init_time },
- { "INIT_CONDITION" , 0x75, 2 , 0 , 0 , init_condition },
- { "INIT_IO_CONDITION" , 0x76, 2 , 0 , 0 , init_io_condition },
- { "INIT_INDEX_IO" , 0x78, 6 , 0 , 0 , init_index_io },
- { "INIT_PLL" , 0x79, 7 , 0 , 0 , init_pll },
- { "INIT_ZM_REG" , 0x7A, 9 , 0 , 0 , init_zm_reg },
- /* INIT_RAM_RESTRICT_PLL's length is adjusted by the BIT M table */
- { "INIT_RAM_RESTRICT_PLL" , 0x87, 2 , 0 , 0 , init_ram_restrict_pll },
- { "INIT_8C" , 0x8C, 1 , 0 , 0 , init_8c },
- { "INIT_8D" , 0x8D, 1 , 0 , 0 , init_8d },
- { "INIT_GPIO" , 0x8E, 1 , 0 , 0 , init_gpio },
- /* INIT_RAM_RESTRICT_ZM_REG_GROUP's mult is loaded by M table in BIT */
- { "INIT_RAM_RESTRICT_ZM_REG_GROUP" , 0x8F, 7 , 6 , 0 , init_ram_restrict_zm_reg_group },
- { "INIT_COPY_ZM_REG" , 0x90, 9 , 0 , 0 , init_copy_zm_reg },
- { "INIT_ZM_REG_GROUP_ADDRESS_LATCHED" , 0x91, 6 , 5 , 4 , init_zm_reg_group_addr_latched },
- { "INIT_RESERVED" , 0x92, 1 , 0 , 0 , init_reserved },
- { "INIT_96" , 0x96, 17 , 0 , 0 , init_96 },
- { "INIT_97" , 0x97, 13 , 0 , 0 , init_97 },
- { "INIT_AUXCH" , 0x98, 6 , 5 , 2 , init_auxch },
- { "INIT_ZM_AUXCH" , 0x99, 6 , 5 , 1 , init_zm_auxch },
- { NULL , 0 , 0 , 0 , 0 , NULL }
+ { "INIT_TIME" , 0x74, init_time },
+ { "INIT_CONDITION" , 0x75, init_condition },
+ { "INIT_IO_CONDITION" , 0x76, init_io_condition },
+ { "INIT_INDEX_IO" , 0x78, init_index_io },
+ { "INIT_PLL" , 0x79, init_pll },
+ { "INIT_ZM_REG" , 0x7A, init_zm_reg },
+ { "INIT_RAM_RESTRICT_PLL" , 0x87, init_ram_restrict_pll },
+ { "INIT_8C" , 0x8C, init_8c },
+ { "INIT_8D" , 0x8D, init_8d },
+ { "INIT_GPIO" , 0x8E, init_gpio },
+ { "INIT_RAM_RESTRICT_ZM_REG_GROUP" , 0x8F, init_ram_restrict_zm_reg_group },
+ { "INIT_COPY_ZM_REG" , 0x90, init_copy_zm_reg },
+ { "INIT_ZM_REG_GROUP_ADDRESS_LATCHED" , 0x91, init_zm_reg_group_addr_latched },
+ { "INIT_RESERVED" , 0x92, init_reserved },
+ { "INIT_96" , 0x96, init_96 },
+ { "INIT_97" , 0x97, init_97 },
+ { "INIT_AUXCH" , 0x98, init_auxch },
+ { "INIT_ZM_AUXCH" , 0x99, init_zm_auxch },
+ { NULL , 0 , NULL }
};
-static unsigned int get_init_table_entry_length(struct nvbios *bios, unsigned int offset, int i)
-{
- /* Calculates the length of a given init table entry. */
- return itbl_entry[i].length + bios->data[offset + itbl_entry[i].length_offset]*itbl_entry[i].length_multiplier;
-}
-
#define MAX_TABLE_OPS 1000
static int
@@ -3056,7 +3055,7 @@ parse_init_table(struct nvbios *bios, unsigned int offset,
* is changed back to EXECUTE.
*/
- int count = 0, i;
+ int count = 0, i, res;
uint8_t id;
/*
@@ -3076,22 +3075,21 @@ parse_init_table(struct nvbios *bios, unsigned int offset,
offset, itbl_entry[i].id, itbl_entry[i].name);
/* execute eventual command handler */
- if (itbl_entry[i].handler)
- if (!(*itbl_entry[i].handler)(bios, offset, iexec))
- break;
+ res = (*itbl_entry[i].handler)(bios, offset, iexec);
+ if (!res)
+ break;
+ /*
+ * Add the offset of the current command including all data
+ * of that command. The offset will then be pointing on the
+ * next op code.
+ */
+ offset += res;
} else {
NV_ERROR(bios->dev,
"0x%04X: Init table command not found: "
"0x%02X\n", offset, id);
return -ENOENT;
}
-
- /*
- * Add the offset of the current command including all data
- * of that command. The offset will then be pointing on the
- * next op code.
- */
- offset += get_init_table_entry_length(bios, offset, i);
}
if (offset >= bios->length)
@@ -3854,7 +3852,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
* script tables is a pointer to the script to execute.
*/
- NV_DEBUG(dev, "Searching for output entry for %d %d %d\n",
+ NV_DEBUG_KMS(dev, "Searching for output entry for %d %d %d\n",
dcbent->type, dcbent->location, dcbent->or);
otable = bios_output_config_match(dev, dcbent, table[1] +
bios->display.script_table_ptr,
@@ -3884,7 +3882,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
if (pxclk == 0) {
script = ROM16(otable[6]);
if (!script) {
- NV_DEBUG(dev, "output script 0 not found\n");
+ NV_DEBUG_KMS(dev, "output script 0 not found\n");
return 1;
}
@@ -3894,7 +3892,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
if (pxclk == -1) {
script = ROM16(otable[8]);
if (!script) {
- NV_DEBUG(dev, "output script 1 not found\n");
+ NV_DEBUG_KMS(dev, "output script 1 not found\n");
return 1;
}
@@ -3907,7 +3905,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
else
script = 0;
if (!script) {
- NV_DEBUG(dev, "output script 2 not found\n");
+ NV_DEBUG_KMS(dev, "output script 2 not found\n");
return 1;
}
@@ -3931,7 +3929,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
if (script)
script = clkcmptable(bios, script, -pxclk);
if (!script) {
- NV_DEBUG(dev, "clock script 1 not found\n");
+ NV_DEBUG_KMS(dev, "clock script 1 not found\n");
return 1;
}
@@ -4606,10 +4604,6 @@ parse_bit_M_tbl_entry(struct drm_device *dev, struct nvbios *bios,
* stuff that we don't use - their use currently unknown
*/
- uint16_t rr_strap_xlat;
- uint8_t rr_group_count;
- int i;
-
/*
* Older bios versions don't have a sufficiently long table for
* what we want
@@ -4618,24 +4612,13 @@ parse_bit_M_tbl_entry(struct drm_device *dev, struct nvbios *bios,
return 0;
if (bitentry->id[1] < 2) {
- rr_group_count = bios->data[bitentry->offset + 2];
- rr_strap_xlat = ROM16(bios->data[bitentry->offset + 3]);
+ bios->ram_restrict_group_count = bios->data[bitentry->offset + 2];
+ bios->ram_restrict_tbl_ptr = ROM16(bios->data[bitentry->offset + 3]);
} else {
- rr_group_count = bios->data[bitentry->offset + 0];
- rr_strap_xlat = ROM16(bios->data[bitentry->offset + 1]);
+ bios->ram_restrict_group_count = bios->data[bitentry->offset + 0];
+ bios->ram_restrict_tbl_ptr = ROM16(bios->data[bitentry->offset + 1]);
}
- /* adjust length of INIT_87 */
- for (i = 0; itbl_entry[i].name && (itbl_entry[i].id != 0x87); i++);
- itbl_entry[i].length += rr_group_count * 4;
-
- /* set up multiplier for INIT_RAM_RESTRICT_ZM_REG_GROUP */
- for (; itbl_entry[i].name && (itbl_entry[i].id != 0x8f); i++);
- itbl_entry[i].length_multiplier = rr_group_count * 4;
-
- init_ram_restrict_zm_reg_group_blocklen = itbl_entry[i].length_multiplier;
- bios->ram_restrict_tbl_ptr = rr_strap_xlat;
-
return 0;
}
@@ -5234,7 +5217,7 @@ parse_dcb_connector_table(struct nvbios *bios)
int i;
if (!bios->bdcb.connector_table_ptr) {
- NV_DEBUG(dev, "No DCB connector table present\n");
+ NV_DEBUG_KMS(dev, "No DCB connector table present\n");
return;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
index 1d5f10bd78e..058e98c76d8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
@@ -227,6 +227,7 @@ struct nvbios {
uint16_t pll_limit_tbl_ptr;
uint16_t ram_restrict_tbl_ptr;
+ uint8_t ram_restrict_group_count;
uint16_t some_script_ptr; /* BIT I + 14 */
uint16_t init96_tbl_ptr; /* BIT I + 16 */
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index aa2dfbc3e35..0cad6d834eb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -154,6 +154,11 @@ nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t memtype)
nvbo->placement.busy_placement = nvbo->placements;
nvbo->placement.num_placement = n;
nvbo->placement.num_busy_placement = n;
+
+ if (nvbo->pin_refcnt) {
+ while (n--)
+ nvbo->placements[n] |= TTM_PL_FLAG_NO_EVICT;
+ }
}
int
@@ -400,10 +405,16 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
struct nouveau_bo *nvbo = nouveau_bo(bo);
switch (bo->mem.mem_type) {
+ case TTM_PL_VRAM:
+ nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT |
+ TTM_PL_FLAG_SYSTEM);
+ break;
default:
nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_SYSTEM);
break;
}
+
+ *pl = nvbo->placement;
}
@@ -455,11 +466,8 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, int no_wait,
int ret;
chan = nvbo->channel;
- if (!chan || nvbo->tile_flags || nvbo->no_vm) {
+ if (!chan || nvbo->tile_flags || nvbo->no_vm)
chan = dev_priv->channel;
- if (!chan)
- return -EINVAL;
- }
src_offset = old_mem->mm_node->start << PAGE_SHIFT;
dst_offset = new_mem->mm_node->start << PAGE_SHIFT;
@@ -625,7 +633,8 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
return ret;
}
- if (dev_priv->init_state != NOUVEAU_CARD_INIT_DONE)
+ if (dev_priv->init_state != NOUVEAU_CARD_INIT_DONE ||
+ !dev_priv->channel)
return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem);
if (old_mem->mem_type == TTM_PL_SYSTEM && !bo->ttm) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 032cf098fa1..5a10deb8bdb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -86,7 +86,7 @@ nouveau_connector_destroy(struct drm_connector *drm_connector)
struct nouveau_connector *connector = nouveau_connector(drm_connector);
struct drm_device *dev = connector->base.dev;
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
if (!connector)
return;
@@ -420,7 +420,7 @@ nouveau_connector_native_mode(struct nouveau_connector *connector)
/* Use preferred mode if there is one.. */
list_for_each_entry(mode, &connector->base.probed_modes, head) {
if (mode->type & DRM_MODE_TYPE_PREFERRED) {
- NV_DEBUG(dev, "native mode from preferred\n");
+ NV_DEBUG_KMS(dev, "native mode from preferred\n");
return drm_mode_duplicate(dev, mode);
}
}
@@ -445,7 +445,7 @@ nouveau_connector_native_mode(struct nouveau_connector *connector)
largest = mode;
}
- NV_DEBUG(dev, "native mode from largest: %dx%d@%d\n",
+ NV_DEBUG_KMS(dev, "native mode from largest: %dx%d@%d\n",
high_w, high_h, high_v);
return largest ? drm_mode_duplicate(dev, largest) : NULL;
}
@@ -725,7 +725,7 @@ nouveau_connector_create(struct drm_device *dev, int index, int type)
struct drm_encoder *encoder;
int ret;
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
if (!nv_connector)
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index de61f4640e1..9e2926c4857 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -187,7 +187,7 @@ nouveau_dp_link_train_adjust(struct drm_encoder *encoder, uint8_t *config)
if (ret)
return false;
- NV_DEBUG(dev, "\t\tadjust 0x%02x 0x%02x\n", request[0], request[1]);
+ NV_DEBUG_KMS(dev, "\t\tadjust 0x%02x 0x%02x\n", request[0], request[1]);
/* Keep all lanes at the same level.. */
for (i = 0; i < nv_encoder->dp.link_nr; i++) {
@@ -228,7 +228,7 @@ nouveau_dp_link_train_commit(struct drm_encoder *encoder, uint8_t *config)
int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1);
int dpe_headerlen, ret, i;
- NV_DEBUG(dev, "\t\tconfig 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ NV_DEBUG_KMS(dev, "\t\tconfig 0x%02x 0x%02x 0x%02x 0x%02x\n",
config[0], config[1], config[2], config[3]);
dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
@@ -276,12 +276,12 @@ nouveau_dp_link_train(struct drm_encoder *encoder)
bool cr_done, cr_max_vs, eq_done;
int ret = 0, i, tries, voltage;
- NV_DEBUG(dev, "link training!!\n");
+ NV_DEBUG_KMS(dev, "link training!!\n");
train:
cr_done = eq_done = false;
/* set link configuration */
- NV_DEBUG(dev, "\tbegin train: bw %d, lanes %d\n",
+ NV_DEBUG_KMS(dev, "\tbegin train: bw %d, lanes %d\n",
nv_encoder->dp.link_bw, nv_encoder->dp.link_nr);
ret = nouveau_dp_link_bw_set(encoder, nv_encoder->dp.link_bw);
@@ -297,7 +297,7 @@ train:
return false;
/* clock recovery */
- NV_DEBUG(dev, "\tbegin cr\n");
+ NV_DEBUG_KMS(dev, "\tbegin cr\n");
ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_1);
if (ret)
goto stop;
@@ -314,7 +314,7 @@ train:
ret = auxch_rd(encoder, DP_LANE0_1_STATUS, status, 2);
if (ret)
break;
- NV_DEBUG(dev, "\t\tstatus: 0x%02x 0x%02x\n",
+ NV_DEBUG_KMS(dev, "\t\tstatus: 0x%02x 0x%02x\n",
status[0], status[1]);
cr_done = true;
@@ -346,7 +346,7 @@ train:
goto stop;
/* channel equalisation */
- NV_DEBUG(dev, "\tbegin eq\n");
+ NV_DEBUG_KMS(dev, "\tbegin eq\n");
ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_2);
if (ret)
goto stop;
@@ -357,7 +357,7 @@ train:
ret = auxch_rd(encoder, DP_LANE0_1_STATUS, status, 3);
if (ret)
break;
- NV_DEBUG(dev, "\t\tstatus: 0x%02x 0x%02x\n",
+ NV_DEBUG_KMS(dev, "\t\tstatus: 0x%02x 0x%02x\n",
status[0], status[1]);
eq_done = true;
@@ -395,9 +395,9 @@ stop:
/* retry at a lower setting, if possible */
if (!ret && !(eq_done && cr_done)) {
- NV_DEBUG(dev, "\twe failed\n");
+ NV_DEBUG_KMS(dev, "\twe failed\n");
if (nv_encoder->dp.link_bw != DP_LINK_BW_1_62) {
- NV_DEBUG(dev, "retry link training at low rate\n");
+ NV_DEBUG_KMS(dev, "retry link training at low rate\n");
nv_encoder->dp.link_bw = DP_LINK_BW_1_62;
goto train;
}
@@ -418,7 +418,7 @@ nouveau_dp_detect(struct drm_encoder *encoder)
if (ret)
return false;
- NV_DEBUG(dev, "encoder: link_bw %d, link_nr %d\n"
+ NV_DEBUG_KMS(dev, "encoder: link_bw %d, link_nr %d\n"
"display: link_bw %d, link_nr %d version 0x%02x\n",
nv_encoder->dcb->dpconf.link_bw,
nv_encoder->dcb->dpconf.link_nr,
@@ -446,7 +446,7 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
uint32_t tmp, ctrl, stat = 0, data32[4] = {};
int ret = 0, i, index = auxch->rd;
- NV_DEBUG(dev, "ch %d cmd %d addr 0x%x len %d\n", index, cmd, addr, data_nr);
+ NV_DEBUG_KMS(dev, "ch %d cmd %d addr 0x%x len %d\n", index, cmd, addr, data_nr);
tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd));
nv_wr32(dev, NV50_AUXCH_CTRL(auxch->rd), tmp | 0x00100000);
@@ -472,7 +472,7 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
if (!(cmd & 1)) {
memcpy(data32, data, data_nr);
for (i = 0; i < 4; i++) {
- NV_DEBUG(dev, "wr %d: 0x%08x\n", i, data32[i]);
+ NV_DEBUG_KMS(dev, "wr %d: 0x%08x\n", i, data32[i]);
nv_wr32(dev, NV50_AUXCH_DATA_OUT(index, i), data32[i]);
}
}
@@ -504,7 +504,7 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
if (cmd & 1) {
for (i = 0; i < 4; i++) {
data32[i] = nv_rd32(dev, NV50_AUXCH_DATA_IN(index, i));
- NV_DEBUG(dev, "rd %d: 0x%08x\n", i, data32[i]);
+ NV_DEBUG_KMS(dev, "rd %d: 0x%08x\n", i, data32[i]);
}
memcpy(data, data32, data_nr);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 35249c35118..06eb993e088 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -35,6 +35,10 @@
#include "drm_pciids.h"
+MODULE_PARM_DESC(ctxfw, "Use external firmware blob for grctx init (NV40)");
+int nouveau_ctxfw = 0;
+module_param_named(ctxfw, nouveau_ctxfw, int, 0400);
+
MODULE_PARM_DESC(noagp, "Disable AGP");
int nouveau_noagp;
module_param_named(noagp, nouveau_noagp, int, 0400);
@@ -273,7 +277,7 @@ nouveau_pci_resume(struct pci_dev *pdev)
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
chan = dev_priv->fifos[i];
- if (!chan)
+ if (!chan || !chan->pushbuf_bo)
continue;
for (j = 0; j < NOUVEAU_DMA_SKIPS; j++)
@@ -341,7 +345,7 @@ static struct drm_driver driver = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
- .ioctl = drm_ioctl,
+ .unlocked_ioctl = drm_ioctl,
.mmap = nouveau_ttm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 88b4c7b77e7..5f8cbb79c49 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -54,6 +54,7 @@ struct nouveau_fpriv {
#include "nouveau_drm.h"
#include "nouveau_reg.h"
#include "nouveau_bios.h"
+struct nouveau_grctx;
#define MAX_NUM_DCB_ENTRIES 16
@@ -317,6 +318,7 @@ struct nouveau_pgraph_engine {
bool accel_blocked;
void *ctxprog;
void *ctxvals;
+ int grctx_size;
int (*init)(struct drm_device *);
void (*takedown)(struct drm_device *);
@@ -647,6 +649,7 @@ extern int nouveau_fbpercrtc;
extern char *nouveau_tv_norm;
extern int nouveau_reg_debug;
extern char *nouveau_vbios;
+extern int nouveau_ctxfw;
/* nouveau_state.c */
extern void nouveau_preclose(struct drm_device *dev, struct drm_file *);
@@ -959,9 +962,7 @@ extern int nv40_graph_create_context(struct nouveau_channel *);
extern void nv40_graph_destroy_context(struct nouveau_channel *);
extern int nv40_graph_load_context(struct nouveau_channel *);
extern int nv40_graph_unload_context(struct drm_device *);
-extern int nv40_grctx_init(struct drm_device *);
-extern void nv40_grctx_fini(struct drm_device *);
-extern void nv40_grctx_vals_load(struct drm_device *, struct nouveau_gpuobj *);
+extern void nv40_grctx_init(struct nouveau_grctx *);
/* nv50_graph.c */
extern struct nouveau_pgraph_object_class nv50_graph_grclass[];
@@ -975,6 +976,12 @@ extern int nv50_graph_load_context(struct nouveau_channel *);
extern int nv50_graph_unload_context(struct drm_device *);
extern void nv50_graph_context_switch(struct drm_device *);
+/* nouveau_grctx.c */
+extern int nouveau_grctx_prog_load(struct drm_device *);
+extern void nouveau_grctx_vals_load(struct drm_device *,
+ struct nouveau_gpuobj *);
+extern void nouveau_grctx_fini(struct drm_device *);
+
/* nv04_instmem.c */
extern int nv04_instmem_init(struct drm_device *);
extern void nv04_instmem_takedown(struct drm_device *);
@@ -1207,14 +1214,24 @@ static inline void nv_wo32(struct drm_device *dev, struct nouveau_gpuobj *obj,
pci_name(d->pdev), ##arg)
#ifndef NV_DEBUG_NOTRACE
#define NV_DEBUG(d, fmt, arg...) do { \
- if (drm_debug) { \
+ if (drm_debug & DRM_UT_DRIVER) { \
+ NV_PRINTK(KERN_DEBUG, d, "%s:%d - " fmt, __func__, \
+ __LINE__, ##arg); \
+ } \
+} while (0)
+#define NV_DEBUG_KMS(d, fmt, arg...) do { \
+ if (drm_debug & DRM_UT_KMS) { \
NV_PRINTK(KERN_DEBUG, d, "%s:%d - " fmt, __func__, \
__LINE__, ##arg); \
} \
} while (0)
#else
#define NV_DEBUG(d, fmt, arg...) do { \
- if (drm_debug) \
+ if (drm_debug & DRM_UT_DRIVER) \
+ NV_PRINTK(KERN_DEBUG, d, fmt, ##arg); \
+} while (0)
+#define NV_DEBUG_KMS(d, fmt, arg...) do { \
+ if (drm_debug & DRM_UT_KMS) \
NV_PRINTK(KERN_DEBUG, d, fmt, ##arg); \
} while (0)
#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 36e8c5e4503..84af25c238b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -58,7 +58,7 @@ nouveau_fbcon_sync(struct fb_info *info)
struct nouveau_channel *chan = dev_priv->channel;
int ret, i;
- if (!chan->accel_done ||
+ if (!chan || !chan->accel_done ||
info->state != FBINFO_STATE_RUNNING ||
info->flags & FBINFO_HWACCEL_DISABLED)
return 0;
@@ -318,14 +318,16 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
par->nouveau_fb = nouveau_fb;
par->dev = dev;
- switch (dev_priv->card_type) {
- case NV_50:
- nv50_fbcon_accel_init(info);
- break;
- default:
- nv04_fbcon_accel_init(info);
- break;
- };
+ if (dev_priv->channel) {
+ switch (dev_priv->card_type) {
+ case NV_50:
+ nv50_fbcon_accel_init(info);
+ break;
+ default:
+ nv04_fbcon_accel_init(info);
+ break;
+ };
+ }
nouveau_fbcon_zfill(dev);
@@ -347,7 +349,7 @@ out:
int
nouveau_fbcon_probe(struct drm_device *dev)
{
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
return drm_fb_helper_single_fb_probe(dev, 32, nouveau_fbcon_create);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.c b/drivers/gpu/drm/nouveau/nouveau_grctx.c
new file mode 100644
index 00000000000..419f4c2b3b8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_grctx.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2009 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <linux/firmware.h>
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+
+struct nouveau_ctxprog {
+ uint32_t signature;
+ uint8_t version;
+ uint16_t length;
+ uint32_t data[];
+} __attribute__ ((packed));
+
+struct nouveau_ctxvals {
+ uint32_t signature;
+ uint8_t version;
+ uint32_t length;
+ struct {
+ uint32_t offset;
+ uint32_t value;
+ } data[];
+} __attribute__ ((packed));
+
+int
+nouveau_grctx_prog_load(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ const int chipset = dev_priv->chipset;
+ const struct firmware *fw;
+ const struct nouveau_ctxprog *cp;
+ const struct nouveau_ctxvals *cv;
+ char name[32];
+ int ret, i;
+
+ if (pgraph->accel_blocked)
+ return -ENODEV;
+
+ if (!pgraph->ctxprog) {
+ sprintf(name, "nouveau/nv%02x.ctxprog", chipset);
+ ret = request_firmware(&fw, name, &dev->pdev->dev);
+ if (ret) {
+ NV_ERROR(dev, "No ctxprog for NV%02x\n", chipset);
+ return ret;
+ }
+
+ pgraph->ctxprog = kmalloc(fw->size, GFP_KERNEL);
+ if (!pgraph->ctxprog) {
+ NV_ERROR(dev, "OOM copying ctxprog\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+ memcpy(pgraph->ctxprog, fw->data, fw->size);
+
+ cp = pgraph->ctxprog;
+ if (le32_to_cpu(cp->signature) != 0x5043564e ||
+ cp->version != 0 ||
+ le16_to_cpu(cp->length) != ((fw->size - 7) / 4)) {
+ NV_ERROR(dev, "ctxprog invalid\n");
+ release_firmware(fw);
+ nouveau_grctx_fini(dev);
+ return -EINVAL;
+ }
+ release_firmware(fw);
+ }
+
+ if (!pgraph->ctxvals) {
+ sprintf(name, "nouveau/nv%02x.ctxvals", chipset);
+ ret = request_firmware(&fw, name, &dev->pdev->dev);
+ if (ret) {
+ NV_ERROR(dev, "No ctxvals for NV%02x\n", chipset);
+ nouveau_grctx_fini(dev);
+ return ret;
+ }
+
+ pgraph->ctxvals = kmalloc(fw->size, GFP_KERNEL);
+ if (!pgraph->ctxprog) {
+ NV_ERROR(dev, "OOM copying ctxprog\n");
+ release_firmware(fw);
+ nouveau_grctx_fini(dev);
+ return -ENOMEM;
+ }
+ memcpy(pgraph->ctxvals, fw->data, fw->size);
+
+ cv = (void *)pgraph->ctxvals;
+ if (le32_to_cpu(cv->signature) != 0x5643564e ||
+ cv->version != 0 ||
+ le32_to_cpu(cv->length) != ((fw->size - 9) / 8)) {
+ NV_ERROR(dev, "ctxvals invalid\n");
+ release_firmware(fw);
+ nouveau_grctx_fini(dev);
+ return -EINVAL;
+ }
+ release_firmware(fw);
+ }
+
+ cp = pgraph->ctxprog;
+
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+ for (i = 0; i < le16_to_cpu(cp->length); i++)
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA,
+ le32_to_cpu(cp->data[i]));
+
+ return 0;
+}
+
+void
+nouveau_grctx_fini(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+
+ if (pgraph->ctxprog) {
+ kfree(pgraph->ctxprog);
+ pgraph->ctxprog = NULL;
+ }
+
+ if (pgraph->ctxvals) {
+ kfree(pgraph->ctxprog);
+ pgraph->ctxvals = NULL;
+ }
+}
+
+void
+nouveau_grctx_vals_load(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ struct nouveau_ctxvals *cv = pgraph->ctxvals;
+ int i;
+
+ if (!cv)
+ return;
+
+ for (i = 0; i < le32_to_cpu(cv->length); i++)
+ nv_wo32(dev, ctx, le32_to_cpu(cv->data[i].offset),
+ le32_to_cpu(cv->data[i].value));
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.h b/drivers/gpu/drm/nouveau/nouveau_grctx.h
new file mode 100644
index 00000000000..5d39c4ce800
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_grctx.h
@@ -0,0 +1,133 @@
+#ifndef __NOUVEAU_GRCTX_H__
+#define __NOUVEAU_GRCTX_H__
+
+struct nouveau_grctx {
+ struct drm_device *dev;
+
+ enum {
+ NOUVEAU_GRCTX_PROG,
+ NOUVEAU_GRCTX_VALS
+ } mode;
+ void *data;
+
+ uint32_t ctxprog_max;
+ uint32_t ctxprog_len;
+ uint32_t ctxprog_reg;
+ int ctxprog_label[32];
+ uint32_t ctxvals_pos;
+ uint32_t ctxvals_base;
+};
+
+#ifdef CP_CTX
+static inline void
+cp_out(struct nouveau_grctx *ctx, uint32_t inst)
+{
+ uint32_t *ctxprog = ctx->data;
+
+ if (ctx->mode != NOUVEAU_GRCTX_PROG)
+ return;
+
+ BUG_ON(ctx->ctxprog_len == ctx->ctxprog_max);
+ ctxprog[ctx->ctxprog_len++] = inst;
+}
+
+static inline void
+cp_lsr(struct nouveau_grctx *ctx, uint32_t val)
+{
+ cp_out(ctx, CP_LOAD_SR | val);
+}
+
+static inline void
+cp_ctx(struct nouveau_grctx *ctx, uint32_t reg, uint32_t length)
+{
+ ctx->ctxprog_reg = (reg - 0x00400000) >> 2;
+
+ ctx->ctxvals_base = ctx->ctxvals_pos;
+ ctx->ctxvals_pos = ctx->ctxvals_base + length;
+
+ if (length > (CP_CTX_COUNT >> CP_CTX_COUNT_SHIFT)) {
+ cp_lsr(ctx, length);
+ length = 0;
+ }
+
+ cp_out(ctx, CP_CTX | (length << CP_CTX_COUNT_SHIFT) | ctx->ctxprog_reg);
+}
+
+static inline void
+cp_name(struct nouveau_grctx *ctx, int name)
+{
+ uint32_t *ctxprog = ctx->data;
+ int i;
+
+ if (ctx->mode != NOUVEAU_GRCTX_PROG)
+ return;
+
+ ctx->ctxprog_label[name] = ctx->ctxprog_len;
+ for (i = 0; i < ctx->ctxprog_len; i++) {
+ if ((ctxprog[i] & 0xfff00000) != 0xff400000)
+ continue;
+ if ((ctxprog[i] & CP_BRA_IP) != ((name) << CP_BRA_IP_SHIFT))
+ continue;
+ ctxprog[i] = (ctxprog[i] & 0x00ff00ff) |
+ (ctx->ctxprog_len << CP_BRA_IP_SHIFT);
+ }
+}
+
+static inline void
+_cp_bra(struct nouveau_grctx *ctx, u32 mod, int flag, int state, int name)
+{
+ int ip = 0;
+
+ if (mod != 2) {
+ ip = ctx->ctxprog_label[name] << CP_BRA_IP_SHIFT;
+ if (ip == 0)
+ ip = 0xff000000 | (name << CP_BRA_IP_SHIFT);
+ }
+
+ cp_out(ctx, CP_BRA | (mod << 18) | ip | flag |
+ (state ? 0 : CP_BRA_IF_CLEAR));
+}
+#define cp_bra(c,f,s,n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#ifdef CP_BRA_MOD
+#define cp_cal(c,f,s,n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#define cp_ret(c,f,s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
+#endif
+
+static inline void
+_cp_wait(struct nouveau_grctx *ctx, int flag, int state)
+{
+ cp_out(ctx, CP_WAIT | flag | (state ? CP_WAIT_SET : 0));
+}
+#define cp_wait(c,f,s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+
+static inline void
+_cp_set(struct nouveau_grctx *ctx, int flag, int state)
+{
+ cp_out(ctx, CP_SET | flag | (state ? CP_SET_1 : 0));
+}
+#define cp_set(c,f,s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+
+static inline void
+cp_pos(struct nouveau_grctx *ctx, int offset)
+{
+ ctx->ctxvals_pos = offset;
+ ctx->ctxvals_base = ctx->ctxvals_pos;
+
+ cp_lsr(ctx, ctx->ctxvals_pos);
+ cp_out(ctx, CP_SET_CONTEXT_POINTER);
+}
+
+static inline void
+gr_def(struct nouveau_grctx *ctx, uint32_t reg, uint32_t val)
+{
+ if (ctx->mode != NOUVEAU_GRCTX_VALS)
+ return;
+
+ reg = (reg - 0x00400000) / 4;
+ reg = (reg - ctx->ctxprog_reg) + ctx->ctxvals_base;
+
+ nv_wo32(ctx->dev, ctx->data, reg, val);
+}
+#endif
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_ioc32.c b/drivers/gpu/drm/nouveau/nouveau_ioc32.c
index a2c30f4611b..475ba810bba 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ioc32.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ioc32.c
@@ -61,12 +61,10 @@ long nouveau_compat_ioctl(struct file *filp, unsigned int cmd,
if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(mga_compat_ioctls))
fn = nouveau_compat_ioctls[nr - DRM_COMMAND_BASE];
#endif
- lock_kernel(); /* XXX for now */
if (fn != NULL)
ret = (*fn)(filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
- unlock_kernel();
+ ret = drm_ioctl(filp, cmd, arg);
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index 2ed41d339f6..e76ec2d207a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -299,12 +299,57 @@ nouveau_vga_set_decode(void *priv, bool state)
return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
}
+static int
+nouveau_card_init_channel(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *gpuobj;
+ int ret;
+
+ ret = nouveau_channel_alloc(dev, &dev_priv->channel,
+ (struct drm_file *)-2,
+ NvDmaFB, NvDmaTT);
+ if (ret)
+ return ret;
+
+ gpuobj = NULL;
+ ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY,
+ 0, nouveau_mem_fb_amount(dev),
+ NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM,
+ &gpuobj);
+ if (ret)
+ goto out_err;
+
+ ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaVRAM,
+ gpuobj, NULL);
+ if (ret)
+ goto out_err;
+
+ gpuobj = NULL;
+ ret = nouveau_gpuobj_gart_dma_new(dev_priv->channel, 0,
+ dev_priv->gart_info.aper_size,
+ NV_DMA_ACCESS_RW, &gpuobj, NULL);
+ if (ret)
+ goto out_err;
+
+ ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaGART,
+ gpuobj, NULL);
+ if (ret)
+ goto out_err;
+
+ return 0;
+out_err:
+ nouveau_gpuobj_del(dev, &gpuobj);
+ nouveau_channel_free(dev_priv->channel);
+ dev_priv->channel = NULL;
+ return ret;
+}
+
int
nouveau_card_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine;
- struct nouveau_gpuobj *gpuobj;
int ret;
NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state);
@@ -317,7 +362,7 @@ nouveau_card_init(struct drm_device *dev)
/* Initialise internal driver API hooks */
ret = nouveau_init_engine_ptrs(dev);
if (ret)
- return ret;
+ goto out;
engine = &dev_priv->engine;
dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED;
@@ -325,12 +370,12 @@ nouveau_card_init(struct drm_device *dev)
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
ret = nouveau_bios_init(dev);
if (ret)
- return ret;
+ goto out;
}
ret = nouveau_gpuobj_early_init(dev);
if (ret)
- return ret;
+ goto out_bios;
/* Initialise instance memory, must happen before mem_init so we
* know exactly how much VRAM we're able to use for "normal"
@@ -338,100 +383,68 @@ nouveau_card_init(struct drm_device *dev)
*/
ret = engine->instmem.init(dev);
if (ret)
- return ret;
+ goto out_gpuobj_early;
/* Setup the memory manager */
ret = nouveau_mem_init(dev);
if (ret)
- return ret;
+ goto out_instmem;
ret = nouveau_gpuobj_init(dev);
if (ret)
- return ret;
+ goto out_mem;
/* PMC */
ret = engine->mc.init(dev);
if (ret)
- return ret;
+ goto out_gpuobj;
/* PTIMER */
ret = engine->timer.init(dev);
if (ret)
- return ret;
+ goto out_mc;
/* PFB */
ret = engine->fb.init(dev);
if (ret)
- return ret;
+ goto out_timer;
/* PGRAPH */
ret = engine->graph.init(dev);
if (ret)
- return ret;
+ goto out_fb;
/* PFIFO */
ret = engine->fifo.init(dev);
if (ret)
- return ret;
+ goto out_graph;
/* this call irq_preinstall, register irq handler and
* call irq_postinstall
*/
ret = drm_irq_install(dev);
if (ret)
- return ret;
+ goto out_fifo;
ret = drm_vblank_init(dev, 0);
if (ret)
- return ret;
+ goto out_irq;
/* what about PVIDEO/PCRTC/PRAMDAC etc? */
- ret = nouveau_channel_alloc(dev, &dev_priv->channel,
- (struct drm_file *)-2,
- NvDmaFB, NvDmaTT);
- if (ret)
- return ret;
-
- gpuobj = NULL;
- ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY,
- 0, nouveau_mem_fb_amount(dev),
- NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM,
- &gpuobj);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaVRAM,
- gpuobj, NULL);
- if (ret) {
- nouveau_gpuobj_del(dev, &gpuobj);
- return ret;
- }
-
- gpuobj = NULL;
- ret = nouveau_gpuobj_gart_dma_new(dev_priv->channel, 0,
- dev_priv->gart_info.aper_size,
- NV_DMA_ACCESS_RW, &gpuobj, NULL);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaGART,
- gpuobj, NULL);
- if (ret) {
- nouveau_gpuobj_del(dev, &gpuobj);
- return ret;
+ if (!engine->graph.accel_blocked) {
+ ret = nouveau_card_init_channel(dev);
+ if (ret)
+ goto out_irq;
}
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- if (dev_priv->card_type >= NV_50) {
+ if (dev_priv->card_type >= NV_50)
ret = nv50_display_create(dev);
- if (ret)
- return ret;
- } else {
+ else
ret = nv04_display_create(dev);
- if (ret)
- return ret;
- }
+ if (ret)
+ goto out_irq;
}
ret = nouveau_backlight_init(dev);
@@ -444,6 +457,32 @@ nouveau_card_init(struct drm_device *dev)
drm_helper_initial_config(dev);
return 0;
+
+out_irq:
+ drm_irq_uninstall(dev);
+out_fifo:
+ engine->fifo.takedown(dev);
+out_graph:
+ engine->graph.takedown(dev);
+out_fb:
+ engine->fb.takedown(dev);
+out_timer:
+ engine->timer.takedown(dev);
+out_mc:
+ engine->mc.takedown(dev);
+out_gpuobj:
+ nouveau_gpuobj_takedown(dev);
+out_mem:
+ nouveau_mem_close(dev);
+out_instmem:
+ engine->instmem.takedown(dev);
+out_gpuobj_early:
+ nouveau_gpuobj_late_takedown(dev);
+out_bios:
+ nouveau_bios_takedown(dev);
+out:
+ vga_client_register(dev->pdev, NULL, NULL, NULL);
+ return ret;
}
static void nouveau_card_takedown(struct drm_device *dev)
diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
index b9136360605..d2f143ed97c 100644
--- a/drivers/gpu/drm/nouveau/nv04_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -143,10 +143,10 @@ static void nv_crtc_calc_state_ext(struct drm_crtc *crtc, struct drm_display_mod
state->pllsel |= nv_crtc->index ? PLLSEL_VPLL2_MASK : PLLSEL_VPLL1_MASK;
if (pv->NM2)
- NV_TRACE(dev, "vpll: n1 %d n2 %d m1 %d m2 %d log2p %d\n",
+ NV_DEBUG_KMS(dev, "vpll: n1 %d n2 %d m1 %d m2 %d log2p %d\n",
pv->N1, pv->N2, pv->M1, pv->M2, pv->log2P);
else
- NV_TRACE(dev, "vpll: n %d m %d log2p %d\n",
+ NV_DEBUG_KMS(dev, "vpll: n %d m %d log2p %d\n",
pv->N1, pv->M1, pv->log2P);
nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.offset);
@@ -160,7 +160,7 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode)
unsigned char seq1 = 0, crtc17 = 0;
unsigned char crtc1A;
- NV_TRACE(dev, "Setting dpms mode %d on CRTC %d\n", mode,
+ NV_DEBUG_KMS(dev, "Setting dpms mode %d on CRTC %d\n", mode,
nv_crtc->index);
if (nv_crtc->last_dpms == mode) /* Don't do unnecesary mode changes. */
@@ -603,7 +603,7 @@ nv_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct drm_nouveau_private *dev_priv = dev->dev_private;
- NV_DEBUG(dev, "CTRC mode on CRTC %d:\n", nv_crtc->index);
+ NV_DEBUG_KMS(dev, "CTRC mode on CRTC %d:\n", nv_crtc->index);
drm_mode_debug_printmodeline(adjusted_mode);
/* unlock must come after turning off FP_TG_CONTROL in output_prepare */
@@ -703,7 +703,7 @@ static void nv_crtc_destroy(struct drm_crtc *crtc)
{
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- NV_DEBUG(crtc->dev, "\n");
+ NV_DEBUG_KMS(crtc->dev, "\n");
if (!nv_crtc)
return;
diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c
index a5fa51714e8..d9f32879ba3 100644
--- a/drivers/gpu/drm/nouveau/nv04_dac.c
+++ b/drivers/gpu/drm/nouveau/nv04_dac.c
@@ -205,7 +205,7 @@ out:
NVWriteVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX, saved_seq1);
if (blue == 0x18) {
- NV_TRACE(dev, "Load detected on head A\n");
+ NV_INFO(dev, "Load detected on head A\n");
return connector_status_connected;
}
@@ -350,14 +350,10 @@ static void nv04_dac_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
int head = nouveau_crtc(encoder->crtc)->index;
- NV_TRACE(dev, "%s called for encoder %d\n", __func__,
- nv_encoder->dcb->index);
-
if (nv_gf4_disp_arch(dev)) {
struct drm_encoder *rebind;
uint32_t dac_offset = nv04_dac_output_offset(encoder);
@@ -466,7 +462,7 @@ static void nv04_dac_destroy(struct drm_encoder *encoder)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- NV_DEBUG(encoder->dev, "\n");
+ NV_DEBUG_KMS(encoder->dev, "\n");
drm_encoder_cleanup(encoder);
kfree(nv_encoder);
diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c
index e5b33339d59..483f875bdb6 100644
--- a/drivers/gpu/drm/nouveau/nv04_dfp.c
+++ b/drivers/gpu/drm/nouveau/nv04_dfp.c
@@ -261,7 +261,7 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *output_mode = &nv_encoder->mode;
uint32_t mode_ratio, panel_ratio;
- NV_DEBUG(dev, "Output mode on CRTC %d:\n", nv_crtc->index);
+ NV_DEBUG_KMS(dev, "Output mode on CRTC %d:\n", nv_crtc->index);
drm_mode_debug_printmodeline(output_mode);
/* Initialize the FP registers in this CRTC. */
@@ -413,7 +413,9 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)
struct dcb_entry *dcbe = nv_encoder->dcb;
int head = nouveau_crtc(encoder->crtc)->index;
- NV_TRACE(dev, "%s called for encoder %d\n", __func__, nv_encoder->dcb->index);
+ NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
+ drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
+ nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
if (dcbe->type == OUTPUT_TMDS)
run_tmds_table(dev, dcbe, head, nv_encoder->mode.clock);
@@ -550,7 +552,7 @@ static void nv04_dfp_destroy(struct drm_encoder *encoder)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- NV_DEBUG(encoder->dev, "\n");
+ NV_DEBUG_KMS(encoder->dev, "\n");
drm_encoder_cleanup(encoder);
kfree(nv_encoder);
diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c
index b47c757ff48..ef77215fa5b 100644
--- a/drivers/gpu/drm/nouveau/nv04_display.c
+++ b/drivers/gpu/drm/nouveau/nv04_display.c
@@ -99,10 +99,11 @@ nv04_display_create(struct drm_device *dev)
uint16_t connector[16] = { 0 };
int i, ret;
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
if (nv_two_heads(dev))
nv04_display_store_initial_head_owner(dev);
+ nouveau_hw_save_vga_fonts(dev, 1);
drm_mode_config_init(dev);
drm_mode_create_scaling_mode_property(dev);
@@ -203,8 +204,6 @@ nv04_display_create(struct drm_device *dev)
/* Save previous state */
NVLockVgaCrtcs(dev, false);
- nouveau_hw_save_vga_fonts(dev, 1);
-
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
crtc->funcs->save(crtc);
@@ -223,7 +222,7 @@ nv04_display_destroy(struct drm_device *dev)
struct drm_encoder *encoder;
struct drm_crtc *crtc;
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
/* Turn every CRTC off. */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
@@ -246,9 +245,9 @@ nv04_display_destroy(struct drm_device *dev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
crtc->funcs->restore(crtc);
- nouveau_hw_save_vga_fonts(dev, 0);
-
drm_mode_config_cleanup(dev);
+
+ nouveau_hw_save_vga_fonts(dev, 0);
}
void
diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c
index 396ee92118f..d561d773c0f 100644
--- a/drivers/gpu/drm/nouveau/nv04_graph.c
+++ b/drivers/gpu/drm/nouveau/nv04_graph.c
@@ -543,7 +543,7 @@ nv04_graph_mthd_set_operation(struct nouveau_channel *chan, int grclass,
nv_wi32(dev, instance, tmp);
nv_wr32(dev, NV04_PGRAPH_CTX_SWITCH1, tmp);
- nv_wr32(dev, NV04_PGRAPH_CTX_CACHE1 + subc, tmp);
+ nv_wr32(dev, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c
index 6bf6804bb0e..6870e0ee2e7 100644
--- a/drivers/gpu/drm/nouveau/nv10_graph.c
+++ b/drivers/gpu/drm/nouveau/nv10_graph.c
@@ -389,49 +389,50 @@ struct graph_state {
int nv10[ARRAY_SIZE(nv10_graph_ctx_regs)];
int nv17[ARRAY_SIZE(nv17_graph_ctx_regs)];
struct pipe_state pipe_state;
+ uint32_t lma_window[4];
};
+#define PIPE_SAVE(dev, state, addr) \
+ do { \
+ int __i; \
+ nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, addr); \
+ for (__i = 0; __i < ARRAY_SIZE(state); __i++) \
+ state[__i] = nv_rd32(dev, NV10_PGRAPH_PIPE_DATA); \
+ } while (0)
+
+#define PIPE_RESTORE(dev, state, addr) \
+ do { \
+ int __i; \
+ nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, addr); \
+ for (__i = 0; __i < ARRAY_SIZE(state); __i++) \
+ nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, state[__i]); \
+ } while (0)
+
static void nv10_graph_save_pipe(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct graph_state *pgraph_ctx = chan->pgraph_ctx;
- struct pipe_state *fifo_pipe_state = &pgraph_ctx->pipe_state;
- int i;
-#define PIPE_SAVE(addr) \
- do { \
- nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, addr); \
- for (i = 0; i < ARRAY_SIZE(fifo_pipe_state->pipe_##addr); i++) \
- fifo_pipe_state->pipe_##addr[i] = nv_rd32(dev, NV10_PGRAPH_PIPE_DATA); \
- } while (0)
-
- PIPE_SAVE(0x4400);
- PIPE_SAVE(0x0200);
- PIPE_SAVE(0x6400);
- PIPE_SAVE(0x6800);
- PIPE_SAVE(0x6c00);
- PIPE_SAVE(0x7000);
- PIPE_SAVE(0x7400);
- PIPE_SAVE(0x7800);
- PIPE_SAVE(0x0040);
- PIPE_SAVE(0x0000);
-
-#undef PIPE_SAVE
+ struct pipe_state *pipe = &pgraph_ctx->pipe_state;
+
+ PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400);
+ PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200);
+ PIPE_SAVE(dev, pipe->pipe_0x6400, 0x6400);
+ PIPE_SAVE(dev, pipe->pipe_0x6800, 0x6800);
+ PIPE_SAVE(dev, pipe->pipe_0x6c00, 0x6c00);
+ PIPE_SAVE(dev, pipe->pipe_0x7000, 0x7000);
+ PIPE_SAVE(dev, pipe->pipe_0x7400, 0x7400);
+ PIPE_SAVE(dev, pipe->pipe_0x7800, 0x7800);
+ PIPE_SAVE(dev, pipe->pipe_0x0040, 0x0040);
+ PIPE_SAVE(dev, pipe->pipe_0x0000, 0x0000);
}
static void nv10_graph_load_pipe(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct graph_state *pgraph_ctx = chan->pgraph_ctx;
- struct pipe_state *fifo_pipe_state = &pgraph_ctx->pipe_state;
- int i;
+ struct pipe_state *pipe = &pgraph_ctx->pipe_state;
uint32_t xfmode0, xfmode1;
-#define PIPE_RESTORE(addr) \
- do { \
- nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, addr); \
- for (i = 0; i < ARRAY_SIZE(fifo_pipe_state->pipe_##addr); i++) \
- nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, fifo_pipe_state->pipe_##addr[i]); \
- } while (0)
-
+ int i;
nouveau_wait_for_idle(dev);
/* XXX check haiku comments */
@@ -457,24 +458,22 @@ static void nv10_graph_load_pipe(struct nouveau_channel *chan)
nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000008);
- PIPE_RESTORE(0x0200);
+ PIPE_RESTORE(dev, pipe->pipe_0x0200, 0x0200);
nouveau_wait_for_idle(dev);
/* restore XFMODE */
nv_wr32(dev, NV10_PGRAPH_XFMODE0, xfmode0);
nv_wr32(dev, NV10_PGRAPH_XFMODE1, xfmode1);
- PIPE_RESTORE(0x6400);
- PIPE_RESTORE(0x6800);
- PIPE_RESTORE(0x6c00);
- PIPE_RESTORE(0x7000);
- PIPE_RESTORE(0x7400);
- PIPE_RESTORE(0x7800);
- PIPE_RESTORE(0x4400);
- PIPE_RESTORE(0x0000);
- PIPE_RESTORE(0x0040);
+ PIPE_RESTORE(dev, pipe->pipe_0x6400, 0x6400);
+ PIPE_RESTORE(dev, pipe->pipe_0x6800, 0x6800);
+ PIPE_RESTORE(dev, pipe->pipe_0x6c00, 0x6c00);
+ PIPE_RESTORE(dev, pipe->pipe_0x7000, 0x7000);
+ PIPE_RESTORE(dev, pipe->pipe_0x7400, 0x7400);
+ PIPE_RESTORE(dev, pipe->pipe_0x7800, 0x7800);
+ PIPE_RESTORE(dev, pipe->pipe_0x4400, 0x4400);
+ PIPE_RESTORE(dev, pipe->pipe_0x0000, 0x0000);
+ PIPE_RESTORE(dev, pipe->pipe_0x0040, 0x0040);
nouveau_wait_for_idle(dev);
-
-#undef PIPE_RESTORE
}
static void nv10_graph_create_pipe(struct nouveau_channel *chan)
@@ -832,6 +831,9 @@ int nv10_graph_init(struct drm_device *dev)
(1<<31));
if (dev_priv->chipset >= 0x17) {
nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x1f000000);
+ nv_wr32(dev, 0x400a10, 0x3ff3fb6);
+ nv_wr32(dev, 0x400838, 0x2f8684);
+ nv_wr32(dev, 0x40083c, 0x115f3f);
nv_wr32(dev, 0x004006b0, 0x40000020);
} else
nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00000000);
@@ -867,6 +869,115 @@ void nv10_graph_takedown(struct drm_device *dev)
{
}
+static int
+nv17_graph_mthd_lma_window(struct nouveau_channel *chan, int grclass,
+ int mthd, uint32_t data)
+{
+ struct drm_device *dev = chan->dev;
+ struct graph_state *ctx = chan->pgraph_ctx;
+ struct pipe_state *pipe = &ctx->pipe_state;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ uint32_t pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
+ uint32_t xfmode0, xfmode1;
+ int i;
+
+ ctx->lma_window[(mthd - 0x1638) / 4] = data;
+
+ if (mthd != 0x1644)
+ return 0;
+
+ nouveau_wait_for_idle(dev);
+
+ PIPE_SAVE(dev, pipe_0x0040, 0x0040);
+ PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200);
+
+ PIPE_RESTORE(dev, ctx->lma_window, 0x6790);
+
+ nouveau_wait_for_idle(dev);
+
+ xfmode0 = nv_rd32(dev, NV10_PGRAPH_XFMODE0);
+ xfmode1 = nv_rd32(dev, NV10_PGRAPH_XFMODE1);
+
+ PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400);
+ PIPE_SAVE(dev, pipe_0x64c0, 0x64c0);
+ PIPE_SAVE(dev, pipe_0x6ab0, 0x6ab0);
+ PIPE_SAVE(dev, pipe_0x6a80, 0x6a80);
+
+ nouveau_wait_for_idle(dev);
+
+ nv_wr32(dev, NV10_PGRAPH_XFMODE0, 0x10000000);
+ nv_wr32(dev, NV10_PGRAPH_XFMODE1, 0x00000000);
+ nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
+ for (i = 0; i < 4; i++)
+ nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+ for (i = 0; i < 4; i++)
+ nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+ nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
+ for (i = 0; i < 3; i++)
+ nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+
+ nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
+ for (i = 0; i < 3; i++)
+ nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+ nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
+ nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000008);
+
+ PIPE_RESTORE(dev, pipe->pipe_0x0200, 0x0200);
+
+ nouveau_wait_for_idle(dev);
+
+ PIPE_RESTORE(dev, pipe_0x0040, 0x0040);
+
+ nv_wr32(dev, NV10_PGRAPH_XFMODE0, xfmode0);
+ nv_wr32(dev, NV10_PGRAPH_XFMODE1, xfmode1);
+
+ PIPE_RESTORE(dev, pipe_0x64c0, 0x64c0);
+ PIPE_RESTORE(dev, pipe_0x6ab0, 0x6ab0);
+ PIPE_RESTORE(dev, pipe_0x6a80, 0x6a80);
+ PIPE_RESTORE(dev, pipe->pipe_0x4400, 0x4400);
+
+ nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0);
+ nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+ nouveau_wait_for_idle(dev);
+
+ pgraph->fifo_access(dev, true);
+
+ return 0;
+}
+
+static int
+nv17_graph_mthd_lma_enable(struct nouveau_channel *chan, int grclass,
+ int mthd, uint32_t data)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+
+ nouveau_wait_for_idle(dev);
+
+ nv_wr32(dev, NV10_PGRAPH_DEBUG_4,
+ nv_rd32(dev, NV10_PGRAPH_DEBUG_4) | 0x1 << 8);
+ nv_wr32(dev, 0x004006b0,
+ nv_rd32(dev, 0x004006b0) | 0x8 << 24);
+
+ pgraph->fifo_access(dev, true);
+
+ return 0;
+}
+
+static struct nouveau_pgraph_object_method nv17_graph_celsius_mthds[] = {
+ { 0x1638, nv17_graph_mthd_lma_window },
+ { 0x163c, nv17_graph_mthd_lma_window },
+ { 0x1640, nv17_graph_mthd_lma_window },
+ { 0x1644, nv17_graph_mthd_lma_window },
+ { 0x1658, nv17_graph_mthd_lma_enable },
+ {}
+};
+
struct nouveau_pgraph_object_class nv10_graph_grclass[] = {
{ 0x0030, false, NULL }, /* null */
{ 0x0039, false, NULL }, /* m2mf */
@@ -887,6 +998,6 @@ struct nouveau_pgraph_object_class nv10_graph_grclass[] = {
{ 0x0095, false, NULL }, /* multitex_tri */
{ 0x0056, false, NULL }, /* celcius (nv10) */
{ 0x0096, false, NULL }, /* celcius (nv11) */
- { 0x0099, false, NULL }, /* celcius (nv17) */
+ { 0x0099, false, nv17_graph_celsius_mthds }, /* celcius (nv17) */
{}
};
diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c
index 46cfd9c6047..81c01353a9f 100644
--- a/drivers/gpu/drm/nouveau/nv17_tv.c
+++ b/drivers/gpu/drm/nouveau/nv17_tv.c
@@ -219,7 +219,7 @@ static void nv17_tv_dpms(struct drm_encoder *encoder, int mode)
return;
nouveau_encoder(encoder)->last_dpms = mode;
- NV_TRACE(dev, "Setting dpms mode %d on TV encoder (output %d)\n",
+ NV_INFO(dev, "Setting dpms mode %d on TV encoder (output %d)\n",
mode, nouveau_encoder(encoder)->dcb->index);
regs->ptv_200 &= ~1;
@@ -619,7 +619,7 @@ static void nv17_tv_destroy(struct drm_encoder *encoder)
{
struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
- NV_DEBUG(encoder->dev, "\n");
+ NV_DEBUG_KMS(encoder->dev, "\n");
drm_encoder_cleanup(encoder);
kfree(tv_enc);
diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c
index 7e8547cb583..2b332bb55ac 100644
--- a/drivers/gpu/drm/nouveau/nv40_graph.c
+++ b/drivers/gpu/drm/nouveau/nv40_graph.c
@@ -24,36 +24,10 @@
*
*/
-#include <linux/firmware.h>
-
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
-
-MODULE_FIRMWARE("nouveau/nv40.ctxprog");
-MODULE_FIRMWARE("nouveau/nv40.ctxvals");
-MODULE_FIRMWARE("nouveau/nv41.ctxprog");
-MODULE_FIRMWARE("nouveau/nv41.ctxvals");
-MODULE_FIRMWARE("nouveau/nv42.ctxprog");
-MODULE_FIRMWARE("nouveau/nv42.ctxvals");
-MODULE_FIRMWARE("nouveau/nv43.ctxprog");
-MODULE_FIRMWARE("nouveau/nv43.ctxvals");
-MODULE_FIRMWARE("nouveau/nv44.ctxprog");
-MODULE_FIRMWARE("nouveau/nv44.ctxvals");
-MODULE_FIRMWARE("nouveau/nv46.ctxprog");
-MODULE_FIRMWARE("nouveau/nv46.ctxvals");
-MODULE_FIRMWARE("nouveau/nv47.ctxprog");
-MODULE_FIRMWARE("nouveau/nv47.ctxvals");
-MODULE_FIRMWARE("nouveau/nv49.ctxprog");
-MODULE_FIRMWARE("nouveau/nv49.ctxvals");
-MODULE_FIRMWARE("nouveau/nv4a.ctxprog");
-MODULE_FIRMWARE("nouveau/nv4a.ctxvals");
-MODULE_FIRMWARE("nouveau/nv4b.ctxprog");
-MODULE_FIRMWARE("nouveau/nv4b.ctxvals");
-MODULE_FIRMWARE("nouveau/nv4c.ctxprog");
-MODULE_FIRMWARE("nouveau/nv4c.ctxvals");
-MODULE_FIRMWARE("nouveau/nv4e.ctxprog");
-MODULE_FIRMWARE("nouveau/nv4e.ctxvals");
+#include "nouveau_grctx.h"
struct nouveau_channel *
nv40_graph_channel(struct drm_device *dev)
@@ -83,27 +57,30 @@ nv40_graph_create_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *ctx;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
int ret;
- /* Allocate a 175KiB block of PRAMIN to store the context. This
- * is massive overkill for a lot of chipsets, but it should be safe
- * until we're able to implement this properly (will happen at more
- * or less the same time we're able to write our own context programs.
- */
- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 175*1024, 16,
- NVOBJ_FLAG_ZERO_ALLOC,
- &chan->ramin_grctx);
+ ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
+ 16, NVOBJ_FLAG_ZERO_ALLOC,
+ &chan->ramin_grctx);
if (ret)
return ret;
- ctx = chan->ramin_grctx->gpuobj;
/* Initialise default context values */
dev_priv->engine.instmem.prepare_access(dev, true);
- nv40_grctx_vals_load(dev, ctx);
- nv_wo32(dev, ctx, 0, ctx->im_pramin->start);
- dev_priv->engine.instmem.finish_access(dev);
+ if (!pgraph->ctxprog) {
+ struct nouveau_grctx ctx = {};
+ ctx.dev = chan->dev;
+ ctx.mode = NOUVEAU_GRCTX_VALS;
+ ctx.data = chan->ramin_grctx->gpuobj;
+ nv40_grctx_init(&ctx);
+ } else {
+ nouveau_grctx_vals_load(dev, chan->ramin_grctx->gpuobj);
+ }
+ nv_wo32(dev, chan->ramin_grctx->gpuobj, 0,
+ chan->ramin_grctx->gpuobj->im_pramin->start);
+ dev_priv->engine.instmem.finish_access(dev);
return 0;
}
@@ -204,139 +181,6 @@ nv40_graph_unload_context(struct drm_device *dev)
return ret;
}
-struct nouveau_ctxprog {
- uint32_t signature;
- uint8_t version;
- uint16_t length;
- uint32_t data[];
-} __attribute__ ((packed));
-
-struct nouveau_ctxvals {
- uint32_t signature;
- uint8_t version;
- uint32_t length;
- struct {
- uint32_t offset;
- uint32_t value;
- } data[];
-} __attribute__ ((packed));
-
-int
-nv40_grctx_init(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- const int chipset = dev_priv->chipset;
- const struct firmware *fw;
- const struct nouveau_ctxprog *cp;
- const struct nouveau_ctxvals *cv;
- char name[32];
- int ret, i;
-
- pgraph->accel_blocked = true;
-
- if (!pgraph->ctxprog) {
- sprintf(name, "nouveau/nv%02x.ctxprog", chipset);
- ret = request_firmware(&fw, name, &dev->pdev->dev);
- if (ret) {
- NV_ERROR(dev, "No ctxprog for NV%02x\n", chipset);
- return ret;
- }
-
- pgraph->ctxprog = kmalloc(fw->size, GFP_KERNEL);
- if (!pgraph->ctxprog) {
- NV_ERROR(dev, "OOM copying ctxprog\n");
- release_firmware(fw);
- return -ENOMEM;
- }
- memcpy(pgraph->ctxprog, fw->data, fw->size);
-
- cp = pgraph->ctxprog;
- if (le32_to_cpu(cp->signature) != 0x5043564e ||
- cp->version != 0 ||
- le16_to_cpu(cp->length) != ((fw->size - 7) / 4)) {
- NV_ERROR(dev, "ctxprog invalid\n");
- release_firmware(fw);
- nv40_grctx_fini(dev);
- return -EINVAL;
- }
- release_firmware(fw);
- }
-
- if (!pgraph->ctxvals) {
- sprintf(name, "nouveau/nv%02x.ctxvals", chipset);
- ret = request_firmware(&fw, name, &dev->pdev->dev);
- if (ret) {
- NV_ERROR(dev, "No ctxvals for NV%02x\n", chipset);
- nv40_grctx_fini(dev);
- return ret;
- }
-
- pgraph->ctxvals = kmalloc(fw->size, GFP_KERNEL);
- if (!pgraph->ctxprog) {
- NV_ERROR(dev, "OOM copying ctxprog\n");
- release_firmware(fw);
- nv40_grctx_fini(dev);
- return -ENOMEM;
- }
- memcpy(pgraph->ctxvals, fw->data, fw->size);
-
- cv = (void *)pgraph->ctxvals;
- if (le32_to_cpu(cv->signature) != 0x5643564e ||
- cv->version != 0 ||
- le32_to_cpu(cv->length) != ((fw->size - 9) / 8)) {
- NV_ERROR(dev, "ctxvals invalid\n");
- release_firmware(fw);
- nv40_grctx_fini(dev);
- return -EINVAL;
- }
- release_firmware(fw);
- }
-
- cp = pgraph->ctxprog;
-
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
- for (i = 0; i < le16_to_cpu(cp->length); i++)
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA,
- le32_to_cpu(cp->data[i]));
-
- pgraph->accel_blocked = false;
- return 0;
-}
-
-void
-nv40_grctx_fini(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-
- if (pgraph->ctxprog) {
- kfree(pgraph->ctxprog);
- pgraph->ctxprog = NULL;
- }
-
- if (pgraph->ctxvals) {
- kfree(pgraph->ctxprog);
- pgraph->ctxvals = NULL;
- }
-}
-
-void
-nv40_grctx_vals_load(struct drm_device *dev, struct nouveau_gpuobj *ctx)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nouveau_ctxvals *cv = pgraph->ctxvals;
- int i;
-
- if (!cv)
- return;
-
- for (i = 0; i < le32_to_cpu(cv->length); i++)
- nv_wo32(dev, ctx, le32_to_cpu(cv->data[i].offset),
- le32_to_cpu(cv->data[i].value));
-}
-
/*
* G70 0x47
* G71 0x49
@@ -359,7 +203,26 @@ nv40_graph_init(struct drm_device *dev)
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
NV_PMC_ENABLE_PGRAPH);
- nv40_grctx_init(dev);
+ if (nouveau_ctxfw) {
+ nouveau_grctx_prog_load(dev);
+ dev_priv->engine.graph.grctx_size = 175 * 1024;
+ }
+
+ if (!dev_priv->engine.graph.ctxprog) {
+ struct nouveau_grctx ctx = {};
+ uint32_t cp[256];
+
+ ctx.dev = dev;
+ ctx.mode = NOUVEAU_GRCTX_PROG;
+ ctx.data = cp;
+ ctx.ctxprog_max = 256;
+ nv40_grctx_init(&ctx);
+ dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
+
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+ for (i = 0; i < ctx.ctxprog_len; i++)
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
+ }
/* No context present currently */
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
@@ -539,6 +402,7 @@ nv40_graph_init(struct drm_device *dev)
void nv40_graph_takedown(struct drm_device *dev)
{
+ nouveau_grctx_fini(dev);
}
struct nouveau_pgraph_object_class nv40_graph_grclass[] = {
diff --git a/drivers/gpu/drm/nouveau/nv40_grctx.c b/drivers/gpu/drm/nouveau/nv40_grctx.c
new file mode 100644
index 00000000000..11b11c31f54
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv40_grctx.c
@@ -0,0 +1,678 @@
+/*
+ * Copyright 2009 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+/* NVIDIA context programs handle a number of other conditions which are
+ * not implemented in our versions. It's not clear why NVIDIA context
+ * programs have this code, nor whether it's strictly necessary for
+ * correct operation. We'll implement additional handling if/when we
+ * discover it's necessary.
+ *
+ * - On context save, NVIDIA set 0x400314 bit 0 to 1 if the "3D state"
+ * flag is set, this gets saved into the context.
+ * - On context save, the context program for all cards load nsource
+ * into a flag register and check for ILLEGAL_MTHD. If it's set,
+ * opcode 0x60000d is called before resuming normal operation.
+ * - Some context programs check more conditions than the above. NV44
+ * checks: ((nsource & 0x0857) || (0x400718 & 0x0100) || (intr & 0x0001))
+ * and calls 0x60000d before resuming normal operation.
+ * - At the very beginning of NVIDIA's context programs, flag 9 is checked
+ * and if true 0x800001 is called with count=0, pos=0, the flag is cleared
+ * and then the ctxprog is aborted. It looks like a complicated NOP,
+ * its purpose is unknown.
+ * - In the section of code that loads the per-vs state, NVIDIA check
+ * flag 10. If it's set, they only transfer the small 0x300 byte block
+ * of state + the state for a single vs as opposed to the state for
+ * all vs units. It doesn't seem likely that it'll occur in normal
+ * operation, especially seeing as it appears NVIDIA may have screwed
+ * up the ctxprogs for some cards and have an invalid instruction
+ * rather than a cp_lsr(ctx, dwords_for_1_vs_unit) instruction.
+ * - There's a number of places where context offset 0 (where we place
+ * the PRAMIN offset of the context) is loaded into either 0x408000,
+ * 0x408004 or 0x408008. Not sure what's up there either.
+ * - The ctxprogs for some cards save 0x400a00 again during the cleanup
+ * path for auto-loadctx.
+ */
+
+#define CP_FLAG_CLEAR 0
+#define CP_FLAG_SET 1
+#define CP_FLAG_SWAP_DIRECTION ((0 * 32) + 0)
+#define CP_FLAG_SWAP_DIRECTION_LOAD 0
+#define CP_FLAG_SWAP_DIRECTION_SAVE 1
+#define CP_FLAG_USER_SAVE ((0 * 32) + 5)
+#define CP_FLAG_USER_SAVE_NOT_PENDING 0
+#define CP_FLAG_USER_SAVE_PENDING 1
+#define CP_FLAG_USER_LOAD ((0 * 32) + 6)
+#define CP_FLAG_USER_LOAD_NOT_PENDING 0
+#define CP_FLAG_USER_LOAD_PENDING 1
+#define CP_FLAG_STATUS ((3 * 32) + 0)
+#define CP_FLAG_STATUS_IDLE 0
+#define CP_FLAG_STATUS_BUSY 1
+#define CP_FLAG_AUTO_SAVE ((3 * 32) + 4)
+#define CP_FLAG_AUTO_SAVE_NOT_PENDING 0
+#define CP_FLAG_AUTO_SAVE_PENDING 1
+#define CP_FLAG_AUTO_LOAD ((3 * 32) + 5)
+#define CP_FLAG_AUTO_LOAD_NOT_PENDING 0
+#define CP_FLAG_AUTO_LOAD_PENDING 1
+#define CP_FLAG_UNK54 ((3 * 32) + 6)
+#define CP_FLAG_UNK54_CLEAR 0
+#define CP_FLAG_UNK54_SET 1
+#define CP_FLAG_ALWAYS ((3 * 32) + 8)
+#define CP_FLAG_ALWAYS_FALSE 0
+#define CP_FLAG_ALWAYS_TRUE 1
+#define CP_FLAG_UNK57 ((3 * 32) + 9)
+#define CP_FLAG_UNK57_CLEAR 0
+#define CP_FLAG_UNK57_SET 1
+
+#define CP_CTX 0x00100000
+#define CP_CTX_COUNT 0x000fc000
+#define CP_CTX_COUNT_SHIFT 14
+#define CP_CTX_REG 0x00003fff
+#define CP_LOAD_SR 0x00200000
+#define CP_LOAD_SR_VALUE 0x000fffff
+#define CP_BRA 0x00400000
+#define CP_BRA_IP 0x0000ff00
+#define CP_BRA_IP_SHIFT 8
+#define CP_BRA_IF_CLEAR 0x00000080
+#define CP_BRA_FLAG 0x0000007f
+#define CP_WAIT 0x00500000
+#define CP_WAIT_SET 0x00000080
+#define CP_WAIT_FLAG 0x0000007f
+#define CP_SET 0x00700000
+#define CP_SET_1 0x00000080
+#define CP_SET_FLAG 0x0000007f
+#define CP_NEXT_TO_SWAP 0x00600007
+#define CP_NEXT_TO_CURRENT 0x00600009
+#define CP_SET_CONTEXT_POINTER 0x0060000a
+#define CP_END 0x0060000e
+#define CP_LOAD_MAGIC_UNK01 0x00800001 /* unknown */
+#define CP_LOAD_MAGIC_NV44TCL 0x00800029 /* per-vs state (0x4497) */
+#define CP_LOAD_MAGIC_NV40TCL 0x00800041 /* per-vs state (0x4097) */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_grctx.h"
+
+/* TODO:
+ * - get vs count from 0x1540
+ * - document unimplemented bits compared to nvidia
+ * - nsource handling
+ * - R0 & 0x0200 handling
+ * - single-vs handling
+ * - 400314 bit 0
+ */
+
+static int
+nv40_graph_4097(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if ((dev_priv->chipset & 0xf0) == 0x60)
+ return 0;
+
+ return !!(0x0baf & (1 << dev_priv->chipset));
+}
+
+static int
+nv40_graph_vs_count(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ switch (dev_priv->chipset) {
+ case 0x47:
+ case 0x49:
+ case 0x4b:
+ return 8;
+ case 0x40:
+ return 6;
+ case 0x41:
+ case 0x42:
+ return 5;
+ case 0x43:
+ case 0x44:
+ case 0x46:
+ case 0x4a:
+ return 3;
+ case 0x4c:
+ case 0x4e:
+ case 0x67:
+ default:
+ return 1;
+ }
+}
+
+
+enum cp_label {
+ cp_check_load = 1,
+ cp_setup_auto_load,
+ cp_setup_load,
+ cp_setup_save,
+ cp_swap_state,
+ cp_swap_state3d_3_is_save,
+ cp_prepare_exit,
+ cp_exit,
+};
+
+static void
+nv40_graph_construct_general(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ int i;
+
+ cp_ctx(ctx, 0x4000a4, 1);
+ gr_def(ctx, 0x4000a4, 0x00000008);
+ cp_ctx(ctx, 0x400144, 58);
+ gr_def(ctx, 0x400144, 0x00000001);
+ cp_ctx(ctx, 0x400314, 1);
+ gr_def(ctx, 0x400314, 0x00000000);
+ cp_ctx(ctx, 0x400400, 10);
+ cp_ctx(ctx, 0x400480, 10);
+ cp_ctx(ctx, 0x400500, 19);
+ gr_def(ctx, 0x400514, 0x00040000);
+ gr_def(ctx, 0x400524, 0x55555555);
+ gr_def(ctx, 0x400528, 0x55555555);
+ gr_def(ctx, 0x40052c, 0x55555555);
+ gr_def(ctx, 0x400530, 0x55555555);
+ cp_ctx(ctx, 0x400560, 6);
+ gr_def(ctx, 0x400568, 0x0000ffff);
+ gr_def(ctx, 0x40056c, 0x0000ffff);
+ cp_ctx(ctx, 0x40057c, 5);
+ cp_ctx(ctx, 0x400710, 3);
+ gr_def(ctx, 0x400710, 0x20010001);
+ gr_def(ctx, 0x400714, 0x0f73ef00);
+ cp_ctx(ctx, 0x400724, 1);
+ gr_def(ctx, 0x400724, 0x02008821);
+ cp_ctx(ctx, 0x400770, 3);
+ if (dev_priv->chipset == 0x40) {
+ cp_ctx(ctx, 0x400814, 4);
+ cp_ctx(ctx, 0x400828, 5);
+ cp_ctx(ctx, 0x400840, 5);
+ gr_def(ctx, 0x400850, 0x00000040);
+ cp_ctx(ctx, 0x400858, 4);
+ gr_def(ctx, 0x400858, 0x00000040);
+ gr_def(ctx, 0x40085c, 0x00000040);
+ gr_def(ctx, 0x400864, 0x80000000);
+ cp_ctx(ctx, 0x40086c, 9);
+ gr_def(ctx, 0x40086c, 0x80000000);
+ gr_def(ctx, 0x400870, 0x80000000);
+ gr_def(ctx, 0x400874, 0x80000000);
+ gr_def(ctx, 0x400878, 0x80000000);
+ gr_def(ctx, 0x400888, 0x00000040);
+ gr_def(ctx, 0x40088c, 0x80000000);
+ cp_ctx(ctx, 0x4009c0, 8);
+ gr_def(ctx, 0x4009cc, 0x80000000);
+ gr_def(ctx, 0x4009dc, 0x80000000);
+ } else {
+ cp_ctx(ctx, 0x400840, 20);
+ if (!nv40_graph_4097(ctx->dev)) {
+ for (i = 0; i < 8; i++)
+ gr_def(ctx, 0x400860 + (i * 4), 0x00000001);
+ }
+ gr_def(ctx, 0x400880, 0x00000040);
+ gr_def(ctx, 0x400884, 0x00000040);
+ gr_def(ctx, 0x400888, 0x00000040);
+ cp_ctx(ctx, 0x400894, 11);
+ gr_def(ctx, 0x400894, 0x00000040);
+ if (nv40_graph_4097(ctx->dev)) {
+ for (i = 0; i < 8; i++)
+ gr_def(ctx, 0x4008a0 + (i * 4), 0x80000000);
+ }
+ cp_ctx(ctx, 0x4008e0, 2);
+ cp_ctx(ctx, 0x4008f8, 2);
+ if (dev_priv->chipset == 0x4c ||
+ (dev_priv->chipset & 0xf0) == 0x60)
+ cp_ctx(ctx, 0x4009f8, 1);
+ }
+ cp_ctx(ctx, 0x400a00, 73);
+ gr_def(ctx, 0x400b0c, 0x0b0b0b0c);
+ cp_ctx(ctx, 0x401000, 4);
+ cp_ctx(ctx, 0x405004, 1);
+ switch (dev_priv->chipset) {
+ case 0x47:
+ case 0x49:
+ case 0x4b:
+ cp_ctx(ctx, 0x403448, 1);
+ gr_def(ctx, 0x403448, 0x00001010);
+ break;
+ default:
+ cp_ctx(ctx, 0x403440, 1);
+ switch (dev_priv->chipset) {
+ case 0x40:
+ gr_def(ctx, 0x403440, 0x00000010);
+ break;
+ case 0x44:
+ case 0x46:
+ case 0x4a:
+ gr_def(ctx, 0x403440, 0x00003010);
+ break;
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x4c:
+ case 0x4e:
+ case 0x67:
+ default:
+ gr_def(ctx, 0x403440, 0x00001010);
+ break;
+ }
+ break;
+ }
+}
+
+static void
+nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ int i;
+
+ if (dev_priv->chipset == 0x40) {
+ cp_ctx(ctx, 0x401880, 51);
+ gr_def(ctx, 0x401940, 0x00000100);
+ } else
+ if (dev_priv->chipset == 0x46 || dev_priv->chipset == 0x47 ||
+ dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) {
+ cp_ctx(ctx, 0x401880, 32);
+ for (i = 0; i < 16; i++)
+ gr_def(ctx, 0x401880 + (i * 4), 0x00000111);
+ if (dev_priv->chipset == 0x46)
+ cp_ctx(ctx, 0x401900, 16);
+ cp_ctx(ctx, 0x401940, 3);
+ }
+ cp_ctx(ctx, 0x40194c, 18);
+ gr_def(ctx, 0x401954, 0x00000111);
+ gr_def(ctx, 0x401958, 0x00080060);
+ gr_def(ctx, 0x401974, 0x00000080);
+ gr_def(ctx, 0x401978, 0xffff0000);
+ gr_def(ctx, 0x40197c, 0x00000001);
+ gr_def(ctx, 0x401990, 0x46400000);
+ if (dev_priv->chipset == 0x40) {
+ cp_ctx(ctx, 0x4019a0, 2);
+ cp_ctx(ctx, 0x4019ac, 5);
+ } else {
+ cp_ctx(ctx, 0x4019a0, 1);
+ cp_ctx(ctx, 0x4019b4, 3);
+ }
+ gr_def(ctx, 0x4019bc, 0xffff0000);
+ switch (dev_priv->chipset) {
+ case 0x46:
+ case 0x47:
+ case 0x49:
+ case 0x4b:
+ cp_ctx(ctx, 0x4019c0, 18);
+ for (i = 0; i < 16; i++)
+ gr_def(ctx, 0x4019c0 + (i * 4), 0x88888888);
+ break;
+ }
+ cp_ctx(ctx, 0x401a08, 8);
+ gr_def(ctx, 0x401a10, 0x0fff0000);
+ gr_def(ctx, 0x401a14, 0x0fff0000);
+ gr_def(ctx, 0x401a1c, 0x00011100);
+ cp_ctx(ctx, 0x401a2c, 4);
+ cp_ctx(ctx, 0x401a44, 26);
+ for (i = 0; i < 16; i++)
+ gr_def(ctx, 0x401a44 + (i * 4), 0x07ff0000);
+ gr_def(ctx, 0x401a8c, 0x4b7fffff);
+ if (dev_priv->chipset == 0x40) {
+ cp_ctx(ctx, 0x401ab8, 3);
+ } else {
+ cp_ctx(ctx, 0x401ab8, 1);
+ cp_ctx(ctx, 0x401ac0, 1);
+ }
+ cp_ctx(ctx, 0x401ad0, 8);
+ gr_def(ctx, 0x401ad0, 0x30201000);
+ gr_def(ctx, 0x401ad4, 0x70605040);
+ gr_def(ctx, 0x401ad8, 0xb8a89888);
+ gr_def(ctx, 0x401adc, 0xf8e8d8c8);
+ cp_ctx(ctx, 0x401b10, dev_priv->chipset == 0x40 ? 2 : 1);
+ gr_def(ctx, 0x401b10, 0x40100000);
+ cp_ctx(ctx, 0x401b18, dev_priv->chipset == 0x40 ? 6 : 5);
+ gr_def(ctx, 0x401b28, dev_priv->chipset == 0x40 ?
+ 0x00000004 : 0x00000000);
+ cp_ctx(ctx, 0x401b30, 25);
+ gr_def(ctx, 0x401b34, 0x0000ffff);
+ gr_def(ctx, 0x401b68, 0x435185d6);
+ gr_def(ctx, 0x401b6c, 0x2155b699);
+ gr_def(ctx, 0x401b70, 0xfedcba98);
+ gr_def(ctx, 0x401b74, 0x00000098);
+ gr_def(ctx, 0x401b84, 0xffffffff);
+ gr_def(ctx, 0x401b88, 0x00ff7000);
+ gr_def(ctx, 0x401b8c, 0x0000ffff);
+ if (dev_priv->chipset != 0x44 && dev_priv->chipset != 0x4a &&
+ dev_priv->chipset != 0x4e)
+ cp_ctx(ctx, 0x401b94, 1);
+ cp_ctx(ctx, 0x401b98, 8);
+ gr_def(ctx, 0x401b9c, 0x00ff0000);
+ cp_ctx(ctx, 0x401bc0, 9);
+ gr_def(ctx, 0x401be0, 0x00ffff00);
+ cp_ctx(ctx, 0x401c00, 192);
+ for (i = 0; i < 16; i++) { /* fragment texture units */
+ gr_def(ctx, 0x401c40 + (i * 4), 0x00018488);
+ gr_def(ctx, 0x401c80 + (i * 4), 0x00028202);
+ gr_def(ctx, 0x401d00 + (i * 4), 0x0000aae4);
+ gr_def(ctx, 0x401d40 + (i * 4), 0x01012000);
+ gr_def(ctx, 0x401d80 + (i * 4), 0x00080008);
+ gr_def(ctx, 0x401e00 + (i * 4), 0x00100008);
+ }
+ for (i = 0; i < 4; i++) { /* vertex texture units */
+ gr_def(ctx, 0x401e90 + (i * 4), 0x0001bc80);
+ gr_def(ctx, 0x401ea0 + (i * 4), 0x00000202);
+ gr_def(ctx, 0x401ec0 + (i * 4), 0x00000008);
+ gr_def(ctx, 0x401ee0 + (i * 4), 0x00080008);
+ }
+ cp_ctx(ctx, 0x400f5c, 3);
+ gr_def(ctx, 0x400f5c, 0x00000002);
+ cp_ctx(ctx, 0x400f84, 1);
+}
+
+static void
+nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ int i;
+
+ cp_ctx(ctx, 0x402000, 1);
+ cp_ctx(ctx, 0x402404, dev_priv->chipset == 0x40 ? 1 : 2);
+ switch (dev_priv->chipset) {
+ case 0x40:
+ gr_def(ctx, 0x402404, 0x00000001);
+ break;
+ case 0x4c:
+ case 0x4e:
+ case 0x67:
+ gr_def(ctx, 0x402404, 0x00000020);
+ break;
+ case 0x46:
+ case 0x49:
+ case 0x4b:
+ gr_def(ctx, 0x402404, 0x00000421);
+ break;
+ default:
+ gr_def(ctx, 0x402404, 0x00000021);
+ }
+ if (dev_priv->chipset != 0x40)
+ gr_def(ctx, 0x402408, 0x030c30c3);
+ switch (dev_priv->chipset) {
+ case 0x44:
+ case 0x46:
+ case 0x4a:
+ case 0x4c:
+ case 0x4e:
+ case 0x67:
+ cp_ctx(ctx, 0x402440, 1);
+ gr_def(ctx, 0x402440, 0x00011001);
+ break;
+ default:
+ break;
+ }
+ cp_ctx(ctx, 0x402480, dev_priv->chipset == 0x40 ? 8 : 9);
+ gr_def(ctx, 0x402488, 0x3e020200);
+ gr_def(ctx, 0x40248c, 0x00ffffff);
+ switch (dev_priv->chipset) {
+ case 0x40:
+ gr_def(ctx, 0x402490, 0x60103f00);
+ break;
+ case 0x47:
+ gr_def(ctx, 0x402490, 0x40103f00);
+ break;
+ case 0x41:
+ case 0x42:
+ case 0x49:
+ case 0x4b:
+ gr_def(ctx, 0x402490, 0x20103f00);
+ break;
+ default:
+ gr_def(ctx, 0x402490, 0x0c103f00);
+ break;
+ }
+ gr_def(ctx, 0x40249c, dev_priv->chipset <= 0x43 ?
+ 0x00020000 : 0x00040000);
+ cp_ctx(ctx, 0x402500, 31);
+ gr_def(ctx, 0x402530, 0x00008100);
+ if (dev_priv->chipset == 0x40)
+ cp_ctx(ctx, 0x40257c, 6);
+ cp_ctx(ctx, 0x402594, 16);
+ cp_ctx(ctx, 0x402800, 17);
+ gr_def(ctx, 0x402800, 0x00000001);
+ switch (dev_priv->chipset) {
+ case 0x47:
+ case 0x49:
+ case 0x4b:
+ cp_ctx(ctx, 0x402864, 1);
+ gr_def(ctx, 0x402864, 0x00001001);
+ cp_ctx(ctx, 0x402870, 3);
+ gr_def(ctx, 0x402878, 0x00000003);
+ if (dev_priv->chipset != 0x47) { /* belong at end!! */
+ cp_ctx(ctx, 0x402900, 1);
+ cp_ctx(ctx, 0x402940, 1);
+ cp_ctx(ctx, 0x402980, 1);
+ cp_ctx(ctx, 0x4029c0, 1);
+ cp_ctx(ctx, 0x402a00, 1);
+ cp_ctx(ctx, 0x402a40, 1);
+ cp_ctx(ctx, 0x402a80, 1);
+ cp_ctx(ctx, 0x402ac0, 1);
+ }
+ break;
+ case 0x40:
+ cp_ctx(ctx, 0x402844, 1);
+ gr_def(ctx, 0x402844, 0x00000001);
+ cp_ctx(ctx, 0x402850, 1);
+ break;
+ default:
+ cp_ctx(ctx, 0x402844, 1);
+ gr_def(ctx, 0x402844, 0x00001001);
+ cp_ctx(ctx, 0x402850, 2);
+ gr_def(ctx, 0x402854, 0x00000003);
+ break;
+ }
+
+ cp_ctx(ctx, 0x402c00, 4);
+ gr_def(ctx, 0x402c00, dev_priv->chipset == 0x40 ?
+ 0x80800001 : 0x00888001);
+ switch (dev_priv->chipset) {
+ case 0x47:
+ case 0x49:
+ case 0x4b:
+ cp_ctx(ctx, 0x402c20, 40);
+ for (i = 0; i < 32; i++)
+ gr_def(ctx, 0x402c40 + (i * 4), 0xffffffff);
+ cp_ctx(ctx, 0x4030b8, 13);
+ gr_def(ctx, 0x4030dc, 0x00000005);
+ gr_def(ctx, 0x4030e8, 0x0000ffff);
+ break;
+ default:
+ cp_ctx(ctx, 0x402c10, 4);
+ if (dev_priv->chipset == 0x40)
+ cp_ctx(ctx, 0x402c20, 36);
+ else
+ if (dev_priv->chipset <= 0x42)
+ cp_ctx(ctx, 0x402c20, 24);
+ else
+ if (dev_priv->chipset <= 0x4a)
+ cp_ctx(ctx, 0x402c20, 16);
+ else
+ cp_ctx(ctx, 0x402c20, 8);
+ cp_ctx(ctx, 0x402cb0, dev_priv->chipset == 0x40 ? 12 : 13);
+ gr_def(ctx, 0x402cd4, 0x00000005);
+ if (dev_priv->chipset != 0x40)
+ gr_def(ctx, 0x402ce0, 0x0000ffff);
+ break;
+ }
+
+ cp_ctx(ctx, 0x403400, dev_priv->chipset == 0x40 ? 4 : 3);
+ cp_ctx(ctx, 0x403410, dev_priv->chipset == 0x40 ? 4 : 3);
+ cp_ctx(ctx, 0x403420, nv40_graph_vs_count(ctx->dev));
+ for (i = 0; i < nv40_graph_vs_count(ctx->dev); i++)
+ gr_def(ctx, 0x403420 + (i * 4), 0x00005555);
+
+ if (dev_priv->chipset != 0x40) {
+ cp_ctx(ctx, 0x403600, 1);
+ gr_def(ctx, 0x403600, 0x00000001);
+ }
+ cp_ctx(ctx, 0x403800, 1);
+
+ cp_ctx(ctx, 0x403c18, 1);
+ gr_def(ctx, 0x403c18, 0x00000001);
+ switch (dev_priv->chipset) {
+ case 0x46:
+ case 0x47:
+ case 0x49:
+ case 0x4b:
+ cp_ctx(ctx, 0x405018, 1);
+ gr_def(ctx, 0x405018, 0x08e00001);
+ cp_ctx(ctx, 0x405c24, 1);
+ gr_def(ctx, 0x405c24, 0x000e3000);
+ break;
+ }
+ if (dev_priv->chipset != 0x4e)
+ cp_ctx(ctx, 0x405800, 11);
+ cp_ctx(ctx, 0x407000, 1);
+}
+
+static void
+nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx)
+{
+ int len = nv40_graph_4097(ctx->dev) ? 0x0684 : 0x0084;
+
+ cp_out (ctx, 0x300000);
+ cp_lsr (ctx, len - 4);
+ cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_swap_state3d_3_is_save);
+ cp_lsr (ctx, len);
+ cp_name(ctx, cp_swap_state3d_3_is_save);
+ cp_out (ctx, 0x800001);
+
+ ctx->ctxvals_pos += len;
+}
+
+static void
+nv40_graph_construct_shader(struct nouveau_grctx *ctx)
+{
+ struct drm_device *dev = ctx->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *obj = ctx->data;
+ int vs, vs_nr, vs_len, vs_nr_b0, vs_nr_b1, b0_offset, b1_offset;
+ int offset, i;
+
+ vs_nr = nv40_graph_vs_count(ctx->dev);
+ vs_nr_b0 = 363;
+ vs_nr_b1 = dev_priv->chipset == 0x40 ? 128 : 64;
+ if (dev_priv->chipset == 0x40) {
+ b0_offset = 0x2200/4; /* 33a0 */
+ b1_offset = 0x55a0/4; /* 1500 */
+ vs_len = 0x6aa0/4;
+ } else
+ if (dev_priv->chipset == 0x41 || dev_priv->chipset == 0x42) {
+ b0_offset = 0x2200/4; /* 2200 */
+ b1_offset = 0x4400/4; /* 0b00 */
+ vs_len = 0x4f00/4;
+ } else {
+ b0_offset = 0x1d40/4; /* 2200 */
+ b1_offset = 0x3f40/4; /* 0b00 : 0a40 */
+ vs_len = nv40_graph_4097(dev) ? 0x4a40/4 : 0x4980/4;
+ }
+
+ cp_lsr(ctx, vs_len * vs_nr + 0x300/4);
+ cp_out(ctx, nv40_graph_4097(dev) ? 0x800041 : 0x800029);
+
+ offset = ctx->ctxvals_pos;
+ ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len));
+
+ if (ctx->mode != NOUVEAU_GRCTX_VALS)
+ return;
+
+ offset += 0x0280/4;
+ for (i = 0; i < 16; i++, offset += 2)
+ nv_wo32(dev, obj, offset, 0x3f800000);
+
+ for (vs = 0; vs < vs_nr; vs++, offset += vs_len) {
+ for (i = 0; i < vs_nr_b0 * 6; i += 6)
+ nv_wo32(dev, obj, offset + b0_offset + i, 0x00000001);
+ for (i = 0; i < vs_nr_b1 * 4; i += 4)
+ nv_wo32(dev, obj, offset + b1_offset + i, 0x3f800000);
+ }
+}
+
+void
+nv40_grctx_init(struct nouveau_grctx *ctx)
+{
+ /* decide whether we're loading/unloading the context */
+ cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save);
+ cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save);
+
+ cp_name(ctx, cp_check_load);
+ cp_bra (ctx, AUTO_LOAD, PENDING, cp_setup_auto_load);
+ cp_bra (ctx, USER_LOAD, PENDING, cp_setup_load);
+ cp_bra (ctx, ALWAYS, TRUE, cp_exit);
+
+ /* setup for context load */
+ cp_name(ctx, cp_setup_auto_load);
+ cp_wait(ctx, STATUS, IDLE);
+ cp_out (ctx, CP_NEXT_TO_SWAP);
+ cp_name(ctx, cp_setup_load);
+ cp_wait(ctx, STATUS, IDLE);
+ cp_set (ctx, SWAP_DIRECTION, LOAD);
+ cp_out (ctx, 0x00910880); /* ?? */
+ cp_out (ctx, 0x00901ffe); /* ?? */
+ cp_out (ctx, 0x01940000); /* ?? */
+ cp_lsr (ctx, 0x20);
+ cp_out (ctx, 0x0060000b); /* ?? */
+ cp_wait(ctx, UNK57, CLEAR);
+ cp_out (ctx, 0x0060000c); /* ?? */
+ cp_bra (ctx, ALWAYS, TRUE, cp_swap_state);
+
+ /* setup for context save */
+ cp_name(ctx, cp_setup_save);
+ cp_set (ctx, SWAP_DIRECTION, SAVE);
+
+ /* general PGRAPH state */
+ cp_name(ctx, cp_swap_state);
+ cp_pos (ctx, 0x00020/4);
+ nv40_graph_construct_general(ctx);
+ cp_wait(ctx, STATUS, IDLE);
+
+ /* 3D state, block 1 */
+ cp_bra (ctx, UNK54, CLEAR, cp_prepare_exit);
+ nv40_graph_construct_state3d(ctx);
+ cp_wait(ctx, STATUS, IDLE);
+
+ /* 3D state, block 2 */
+ nv40_graph_construct_state3d_2(ctx);
+
+ /* Some other block of "random" state */
+ nv40_graph_construct_state3d_3(ctx);
+
+ /* Per-vertex shader state */
+ cp_pos (ctx, ctx->ctxvals_pos);
+ nv40_graph_construct_shader(ctx);
+
+ /* pre-exit state updates */
+ cp_name(ctx, cp_prepare_exit);
+ cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_check_load);
+ cp_bra (ctx, USER_SAVE, PENDING, cp_exit);
+ cp_out (ctx, CP_NEXT_TO_CURRENT);
+
+ cp_name(ctx, cp_exit);
+ cp_set (ctx, USER_SAVE, NOT_PENDING);
+ cp_set (ctx, USER_LOAD, NOT_PENDING);
+ cp_out (ctx, CP_END);
+}
+
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index f8e28a1e44e..118d3285fd8 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -45,7 +45,7 @@ nv50_crtc_lut_load(struct drm_crtc *crtc)
void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
int i;
- NV_DEBUG(crtc->dev, "\n");
+ NV_DEBUG_KMS(crtc->dev, "\n");
for (i = 0; i < 256; i++) {
writew(nv_crtc->lut.r[i] >> 2, lut + 8*i + 0);
@@ -68,8 +68,8 @@ nv50_crtc_blank(struct nouveau_crtc *nv_crtc, bool blanked)
struct nouveau_channel *evo = dev_priv->evo;
int index = nv_crtc->index, ret;
- NV_DEBUG(dev, "index %d\n", nv_crtc->index);
- NV_DEBUG(dev, "%s\n", blanked ? "blanked" : "unblanked");
+ NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
+ NV_DEBUG_KMS(dev, "%s\n", blanked ? "blanked" : "unblanked");
if (blanked) {
nv_crtc->cursor.hide(nv_crtc, false);
@@ -139,7 +139,7 @@ nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool on, bool update)
struct nouveau_channel *evo = dev_priv->evo;
int ret;
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
ret = RING_SPACE(evo, 2 + (update ? 2 : 0));
if (ret) {
@@ -193,7 +193,7 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, int scaling_mode, bool update)
uint32_t outX, outY, horiz, vert;
int ret;
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
switch (scaling_mode) {
case DRM_MODE_SCALE_NONE:
@@ -301,7 +301,7 @@ nv50_crtc_destroy(struct drm_crtc *crtc)
struct drm_device *dev = crtc->dev;
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
if (!crtc)
return;
@@ -433,7 +433,7 @@ nv50_crtc_prepare(struct drm_crtc *crtc)
struct drm_device *dev = crtc->dev;
struct drm_encoder *encoder;
- NV_DEBUG(dev, "index %d\n", nv_crtc->index);
+ NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
/* Disconnect all unused encoders. */
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
@@ -458,7 +458,7 @@ nv50_crtc_commit(struct drm_crtc *crtc)
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
int ret;
- NV_DEBUG(dev, "index %d\n", nv_crtc->index);
+ NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
nv50_crtc_blank(nv_crtc, false);
@@ -497,7 +497,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
int ret, format;
- NV_DEBUG(dev, "index %d\n", nv_crtc->index);
+ NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
switch (drm_fb->depth) {
case 8:
@@ -612,7 +612,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
*nv_crtc->mode = *adjusted_mode;
- NV_DEBUG(dev, "index %d\n", nv_crtc->index);
+ NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
hsync_dur = adjusted_mode->hsync_end - adjusted_mode->hsync_start;
vsync_dur = adjusted_mode->vsync_end - adjusted_mode->vsync_start;
@@ -706,7 +706,7 @@ nv50_crtc_create(struct drm_device *dev, int index)
struct nouveau_crtc *nv_crtc = NULL;
int ret, i;
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL);
if (!nv_crtc)
diff --git a/drivers/gpu/drm/nouveau/nv50_cursor.c b/drivers/gpu/drm/nouveau/nv50_cursor.c
index e2e79a8f220..753e723adb3 100644
--- a/drivers/gpu/drm/nouveau/nv50_cursor.c
+++ b/drivers/gpu/drm/nouveau/nv50_cursor.c
@@ -41,7 +41,7 @@ nv50_cursor_show(struct nouveau_crtc *nv_crtc, bool update)
struct drm_device *dev = nv_crtc->base.dev;
int ret;
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
if (update && nv_crtc->cursor.visible)
return;
@@ -76,7 +76,7 @@ nv50_cursor_hide(struct nouveau_crtc *nv_crtc, bool update)
struct drm_device *dev = nv_crtc->base.dev;
int ret;
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
if (update && !nv_crtc->cursor.visible)
return;
@@ -116,7 +116,7 @@ nv50_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
static void
nv50_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
{
- NV_DEBUG(nv_crtc->base.dev, "\n");
+ NV_DEBUG_KMS(nv_crtc->base.dev, "\n");
if (offset == nv_crtc->cursor.offset)
return;
@@ -143,7 +143,7 @@ nv50_cursor_fini(struct nouveau_crtc *nv_crtc)
struct drm_device *dev = nv_crtc->base.dev;
int idx = nv_crtc->index;
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), 0);
if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx),
diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c
index fb5838e3be2..f08f042a8e1 100644
--- a/drivers/gpu/drm/nouveau/nv50_dac.c
+++ b/drivers/gpu/drm/nouveau/nv50_dac.c
@@ -44,7 +44,7 @@ nv50_dac_disconnect(struct nouveau_encoder *nv_encoder)
struct nouveau_channel *evo = dev_priv->evo;
int ret;
- NV_DEBUG(dev, "Disconnecting DAC %d\n", nv_encoder->or);
+ NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or);
ret = RING_SPACE(evo, 2);
if (ret) {
@@ -81,11 +81,11 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
/* Use bios provided value if possible. */
if (dev_priv->vbios->dactestval) {
load_pattern = dev_priv->vbios->dactestval;
- NV_DEBUG(dev, "Using bios provided load_pattern of %d\n",
+ NV_DEBUG_KMS(dev, "Using bios provided load_pattern of %d\n",
load_pattern);
} else {
load_pattern = 340;
- NV_DEBUG(dev, "Using default load_pattern of %d\n",
+ NV_DEBUG_KMS(dev, "Using default load_pattern of %d\n",
load_pattern);
}
@@ -103,9 +103,9 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
status = connector_status_connected;
if (status == connector_status_connected)
- NV_DEBUG(dev, "Load was detected on output with or %d\n", or);
+ NV_DEBUG_KMS(dev, "Load was detected on output with or %d\n", or);
else
- NV_DEBUG(dev, "Load was not detected on output with or %d\n", or);
+ NV_DEBUG_KMS(dev, "Load was not detected on output with or %d\n", or);
return status;
}
@@ -118,7 +118,7 @@ nv50_dac_dpms(struct drm_encoder *encoder, int mode)
uint32_t val;
int or = nv_encoder->or;
- NV_DEBUG(dev, "or %d mode %d\n", or, mode);
+ NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
/* wait for it to be done */
if (!nv_wait(NV50_PDISPLAY_DAC_DPMS_CTRL(or),
@@ -173,7 +173,7 @@ nv50_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nouveau_connector *connector;
- NV_DEBUG(encoder->dev, "or %d\n", nv_encoder->or);
+ NV_DEBUG_KMS(encoder->dev, "or %d\n", nv_encoder->or);
connector = nouveau_encoder_connector_get(nv_encoder);
if (!connector) {
@@ -213,7 +213,7 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
uint32_t mode_ctl = 0, mode_ctl2 = 0;
int ret;
- NV_DEBUG(dev, "or %d\n", nv_encoder->or);
+ NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or);
nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON);
@@ -264,7 +264,7 @@ nv50_dac_destroy(struct drm_encoder *encoder)
if (!encoder)
return;
- NV_DEBUG(encoder->dev, "\n");
+ NV_DEBUG_KMS(encoder->dev, "\n");
drm_encoder_cleanup(encoder);
kfree(nv_encoder);
@@ -280,7 +280,7 @@ nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry)
struct nouveau_encoder *nv_encoder;
struct drm_encoder *encoder;
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
NV_INFO(dev, "Detected a DAC output\n");
nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 12c5ee63495..a9263d92a23 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -188,7 +188,7 @@ nv50_display_init(struct drm_device *dev)
uint64_t start;
int ret, i;
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
nv_wr32(dev, 0x00610184, nv_rd32(dev, 0x00614004));
/*
@@ -232,7 +232,7 @@ nv50_display_init(struct drm_device *dev)
nv_wr32(dev, NV50_PDISPLAY_UNK_380, 0);
/* RAM is clamped to 256 MiB. */
ram_amount = nouveau_mem_fb_amount(dev);
- NV_DEBUG(dev, "ram_amount %d\n", ram_amount);
+ NV_DEBUG_KMS(dev, "ram_amount %d\n", ram_amount);
if (ram_amount > 256*1024*1024)
ram_amount = 256*1024*1024;
nv_wr32(dev, NV50_PDISPLAY_RAM_AMOUNT, ram_amount - 1);
@@ -398,7 +398,7 @@ static int nv50_display_disable(struct drm_device *dev)
struct drm_crtc *drm_crtc;
int ret, i;
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *crtc = nouveau_crtc(drm_crtc);
@@ -469,7 +469,7 @@ int nv50_display_create(struct drm_device *dev)
uint32_t connector[16] = {};
int ret, i;
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
/* init basic kernel modesetting */
drm_mode_config_init(dev);
@@ -573,7 +573,7 @@ int nv50_display_destroy(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
drm_mode_config_cleanup(dev);
@@ -617,7 +617,7 @@ nv50_display_irq_head(struct drm_device *dev, int *phead,
* CRTC separately, and submission will be blocked by the GPU
* until we handle each in turn.
*/
- NV_DEBUG(dev, "0x610030: 0x%08x\n", unk30);
+ NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
head = ffs((unk30 >> 9) & 3) - 1;
if (head < 0)
return -EINVAL;
@@ -661,7 +661,7 @@ nv50_display_irq_head(struct drm_device *dev, int *phead,
or = i;
}
- NV_DEBUG(dev, "type %d, or %d\n", type, or);
+ NV_DEBUG_KMS(dev, "type %d, or %d\n", type, or);
if (type == OUTPUT_ANY) {
NV_ERROR(dev, "unknown encoder!!\n");
return -1;
@@ -811,7 +811,7 @@ nv50_display_unk20_handler(struct drm_device *dev)
pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff;
script = nv50_display_script_select(dev, dcbent, pclk);
- NV_DEBUG(dev, "head %d pxclk: %dKHz\n", head, pclk);
+ NV_DEBUG_KMS(dev, "head %d pxclk: %dKHz\n", head, pclk);
if (dcbent->type != OUTPUT_DP)
nouveau_bios_run_display_table(dev, dcbent, 0, -2);
@@ -870,7 +870,7 @@ nv50_display_irq_handler_bh(struct work_struct *work)
uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0);
uint32_t intr1 = nv_rd32(dev, NV50_PDISPLAY_INTR_1);
- NV_DEBUG(dev, "PDISPLAY_INTR_BH 0x%08x 0x%08x\n", intr0, intr1);
+ NV_DEBUG_KMS(dev, "PDISPLAY_INTR_BH 0x%08x 0x%08x\n", intr0, intr1);
if (intr1 & NV50_PDISPLAY_INTR_1_CLK_UNK10)
nv50_display_unk10_handler(dev);
@@ -974,7 +974,7 @@ nv50_display_irq_handler(struct drm_device *dev)
uint32_t intr1 = nv_rd32(dev, NV50_PDISPLAY_INTR_1);
uint32_t clock;
- NV_DEBUG(dev, "PDISPLAY_INTR 0x%08x 0x%08x\n", intr0, intr1);
+ NV_DEBUG_KMS(dev, "PDISPLAY_INTR 0x%08x 0x%08x\n", intr0, intr1);
if (!intr0 && !(intr1 & ~delayed))
break;
diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c
index 77ae1aaa0bc..b7282284f08 100644
--- a/drivers/gpu/drm/nouveau/nv50_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv50_fifo.c
@@ -416,7 +416,7 @@ nv50_fifo_unload_context(struct drm_device *dev)
NV_DEBUG(dev, "\n");
chid = pfifo->channel_id(dev);
- if (chid < 0 || chid >= dev_priv->engine.fifo.channels)
+ if (chid < 1 || chid >= dev_priv->engine.fifo.channels - 1)
return 0;
chan = dev_priv->fifos[chid];
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
index 177d8229336..ca79f32be44 100644
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
@@ -107,9 +107,13 @@ nv50_graph_init_regs(struct drm_device *dev)
static int
nv50_graph_init_ctxctl(struct drm_device *dev)
{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
NV_DEBUG(dev, "\n");
- nv40_grctx_init(dev);
+ nouveau_grctx_prog_load(dev);
+ if (!dev_priv->engine.graph.ctxprog)
+ dev_priv->engine.graph.accel_blocked = true;
nv_wr32(dev, 0x400320, 4);
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0);
@@ -140,7 +144,7 @@ void
nv50_graph_takedown(struct drm_device *dev)
{
NV_DEBUG(dev, "\n");
- nv40_grctx_fini(dev);
+ nouveau_grctx_fini(dev);
}
void
@@ -207,7 +211,7 @@ nv50_graph_create_context(struct nouveau_channel *chan)
dev_priv->engine.instmem.finish_access(dev);
dev_priv->engine.instmem.prepare_access(dev, true);
- nv40_grctx_vals_load(dev, ctx);
+ nouveau_grctx_vals_load(dev, ctx);
nv_wo32(dev, ctx, 0x00000/4, chan->ramin->instance >> 12);
if ((dev_priv->chipset & 0xf0) == 0xa0)
nv_wo32(dev, ctx, 0x00004/4, 0x00000000);
diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
index 8c280463a66..e395c16d30f 100644
--- a/drivers/gpu/drm/nouveau/nv50_sor.c
+++ b/drivers/gpu/drm/nouveau/nv50_sor.c
@@ -44,7 +44,7 @@ nv50_sor_disconnect(struct nouveau_encoder *nv_encoder)
struct nouveau_channel *evo = dev_priv->evo;
int ret;
- NV_DEBUG(dev, "Disconnecting SOR %d\n", nv_encoder->or);
+ NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or);
ret = RING_SPACE(evo, 2);
if (ret) {
@@ -70,7 +70,7 @@ nv50_sor_dp_link_train(struct drm_encoder *encoder)
}
if (dpe->script0) {
- NV_DEBUG(dev, "SOR-%d: running DP script 0\n", nv_encoder->or);
+ NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or);
nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0),
nv_encoder->dcb);
}
@@ -79,7 +79,7 @@ nv50_sor_dp_link_train(struct drm_encoder *encoder)
NV_ERROR(dev, "SOR-%d: link training failed\n", nv_encoder->or);
if (dpe->script1) {
- NV_DEBUG(dev, "SOR-%d: running DP script 1\n", nv_encoder->or);
+ NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or);
nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1),
nv_encoder->dcb);
}
@@ -93,7 +93,7 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
uint32_t val;
int or = nv_encoder->or;
- NV_DEBUG(dev, "or %d mode %d\n", or, mode);
+ NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
/* wait for it to be done */
if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_CTRL(or),
@@ -142,7 +142,7 @@ nv50_sor_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nouveau_connector *connector;
- NV_DEBUG(encoder->dev, "or %d\n", nv_encoder->or);
+ NV_DEBUG_KMS(encoder->dev, "or %d\n", nv_encoder->or);
connector = nouveau_encoder_connector_get(nv_encoder);
if (!connector) {
@@ -182,7 +182,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
uint32_t mode_ctl = 0;
int ret;
- NV_DEBUG(dev, "or %d\n", nv_encoder->or);
+ NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or);
nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON);
@@ -246,7 +246,7 @@ nv50_sor_destroy(struct drm_encoder *encoder)
if (!encoder)
return;
- NV_DEBUG(encoder->dev, "\n");
+ NV_DEBUG_KMS(encoder->dev, "\n");
drm_encoder_cleanup(encoder);
@@ -265,7 +265,7 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
bool dum;
int type;
- NV_DEBUG(dev, "\n");
+ NV_DEBUG_KMS(dev, "\n");
switch (entry->type) {
case OUTPUT_TMDS:
diff --git a/drivers/gpu/drm/r128/r128_drv.c b/drivers/gpu/drm/r128/r128_drv.c
index 601f4c0e5da..b806fdcc717 100644
--- a/drivers/gpu/drm/r128/r128_drv.c
+++ b/drivers/gpu/drm/r128/r128_drv.c
@@ -64,7 +64,7 @@ static struct drm_driver driver = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
- .ioctl = drm_ioctl,
+ .unlocked_ioctl = drm_ioctl,
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
diff --git a/drivers/gpu/drm/r128/r128_ioc32.c b/drivers/gpu/drm/r128/r128_ioc32.c
index d3cb676eee8..51c99fc4dd3 100644
--- a/drivers/gpu/drm/r128/r128_ioc32.c
+++ b/drivers/gpu/drm/r128/r128_ioc32.c
@@ -95,8 +95,7 @@ static int compat_r128_init(struct file *file, unsigned int cmd,
&init->agp_textures_offset))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_R128_INIT, (unsigned long)init);
+ return drm_ioctl(file, DRM_IOCTL_R128_INIT, (unsigned long)init);
}
typedef struct drm_r128_depth32 {
@@ -129,8 +128,7 @@ static int compat_r128_depth(struct file *file, unsigned int cmd,
&depth->mask))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_R128_DEPTH, (unsigned long)depth);
+ return drm_ioctl(file, DRM_IOCTL_R128_DEPTH, (unsigned long)depth);
}
@@ -153,8 +151,7 @@ static int compat_r128_stipple(struct file *file, unsigned int cmd,
&stipple->mask))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_R128_STIPPLE, (unsigned long)stipple);
+ return drm_ioctl(file, DRM_IOCTL_R128_STIPPLE, (unsigned long)stipple);
}
typedef struct drm_r128_getparam32 {
@@ -178,8 +175,7 @@ static int compat_r128_getparam(struct file *file, unsigned int cmd,
&getparam->value))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_R128_GETPARAM, (unsigned long)getparam);
+ return drm_ioctl(file, DRM_IOCTL_R128_GETPARAM, (unsigned long)getparam);
}
drm_ioctl_compat_t *r128_compat_ioctls[] = {
@@ -210,12 +206,10 @@ long r128_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(r128_compat_ioctls))
fn = r128_compat_ioctls[nr - DRM_COMMAND_BASE];
- lock_kernel(); /* XXX for now */
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
- unlock_kernel();
+ ret = drm_ioctl(filp, cmd, arg);
return ret;
}
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c
index 6578d19dff9..388140a7e65 100644
--- a/drivers/gpu/drm/radeon/atom.c
+++ b/drivers/gpu/drm/radeon/atom.c
@@ -58,6 +58,7 @@ typedef struct {
} atom_exec_context;
int atom_debug = 0;
+static void atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params);
void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params);
static uint32_t atom_arg_mask[8] =
@@ -573,7 +574,7 @@ static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
else
SDEBUG(" table: %d\n", idx);
if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
- atom_execute_table(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
+ atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
}
static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
@@ -1040,7 +1041,7 @@ static struct {
atom_op_shr, ATOM_ARG_MC}, {
atom_op_debug, 0},};
-void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
+static void atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params)
{
int base = CU16(ctx->cmd_table + 4 + 2 * index);
int len, ws, ps, ptr;
@@ -1092,6 +1093,13 @@ void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
kfree(ectx.ws);
}
+void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
+{
+ mutex_lock(&ctx->mutex);
+ atom_execute_table_locked(ctx, index, params);
+ mutex_unlock(&ctx->mutex);
+}
+
static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
static void atom_index_iio(struct atom_context *ctx, int base)
diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h
index 6671848e5ea..47fd943f6d1 100644
--- a/drivers/gpu/drm/radeon/atom.h
+++ b/drivers/gpu/drm/radeon/atom.h
@@ -120,6 +120,7 @@ struct card_info {
struct atom_context {
struct card_info *card;
+ struct mutex mutex;
void *bios;
uint32_t cmd_table, data_table;
uint16_t *iio;
diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h
index 5f48515c77a..91ad0d1c1b1 100644
--- a/drivers/gpu/drm/radeon/atombios.h
+++ b/drivers/gpu/drm/radeon/atombios.h
@@ -4690,6 +4690,205 @@ typedef struct _ATOM_POWERPLAY_INFO_V3 {
ATOM_POWERMODE_INFO_V3 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK];
} ATOM_POWERPLAY_INFO_V3;
+/* New PPlib */
+/**************************************************************************/
+typedef struct _ATOM_PPLIB_THERMALCONTROLLER
+
+{
+ UCHAR ucType; // one of ATOM_PP_THERMALCONTROLLER_*
+ UCHAR ucI2cLine; // as interpreted by DAL I2C
+ UCHAR ucI2cAddress;
+ UCHAR ucFanParameters; // Fan Control Parameters.
+ UCHAR ucFanMinRPM; // Fan Minimum RPM (hundreds) -- for display purposes only.
+ UCHAR ucFanMaxRPM; // Fan Maximum RPM (hundreds) -- for display purposes only.
+ UCHAR ucReserved; // ----
+ UCHAR ucFlags; // to be defined
+} ATOM_PPLIB_THERMALCONTROLLER;
+
+#define ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK 0x0f
+#define ATOM_PP_FANPARAMETERS_NOFAN 0x80 // No fan is connected to this controller.
+
+#define ATOM_PP_THERMALCONTROLLER_NONE 0
+#define ATOM_PP_THERMALCONTROLLER_LM63 1 // Not used by PPLib
+#define ATOM_PP_THERMALCONTROLLER_ADM1032 2 // Not used by PPLib
+#define ATOM_PP_THERMALCONTROLLER_ADM1030 3 // Not used by PPLib
+#define ATOM_PP_THERMALCONTROLLER_MUA6649 4 // Not used by PPLib
+#define ATOM_PP_THERMALCONTROLLER_LM64 5
+#define ATOM_PP_THERMALCONTROLLER_F75375 6 // Not used by PPLib
+#define ATOM_PP_THERMALCONTROLLER_RV6xx 7
+#define ATOM_PP_THERMALCONTROLLER_RV770 8
+#define ATOM_PP_THERMALCONTROLLER_ADT7473 9
+
+typedef struct _ATOM_PPLIB_STATE
+{
+ UCHAR ucNonClockStateIndex;
+ UCHAR ucClockStateIndices[1]; // variable-sized
+} ATOM_PPLIB_STATE;
+
+//// ATOM_PPLIB_POWERPLAYTABLE::ulPlatformCaps
+#define ATOM_PP_PLATFORM_CAP_BACKBIAS 1
+#define ATOM_PP_PLATFORM_CAP_POWERPLAY 2
+#define ATOM_PP_PLATFORM_CAP_SBIOSPOWERSOURCE 4
+#define ATOM_PP_PLATFORM_CAP_ASPM_L0s 8
+#define ATOM_PP_PLATFORM_CAP_ASPM_L1 16
+#define ATOM_PP_PLATFORM_CAP_HARDWAREDC 32
+#define ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY 64
+#define ATOM_PP_PLATFORM_CAP_STEPVDDC 128
+#define ATOM_PP_PLATFORM_CAP_VOLTAGECONTROL 256
+#define ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL 512
+#define ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1 1024
+#define ATOM_PP_PLATFORM_CAP_HTLINKCONTROL 2048
+
+typedef struct _ATOM_PPLIB_POWERPLAYTABLE
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+
+ UCHAR ucDataRevision;
+
+ UCHAR ucNumStates;
+ UCHAR ucStateEntrySize;
+ UCHAR ucClockInfoSize;
+ UCHAR ucNonClockSize;
+
+ // offset from start of this table to array of ucNumStates ATOM_PPLIB_STATE structures
+ USHORT usStateArrayOffset;
+
+ // offset from start of this table to array of ASIC-specific structures,
+ // currently ATOM_PPLIB_CLOCK_INFO.
+ USHORT usClockInfoArrayOffset;
+
+ // offset from start of this table to array of ATOM_PPLIB_NONCLOCK_INFO
+ USHORT usNonClockInfoArrayOffset;
+
+ USHORT usBackbiasTime; // in microseconds
+ USHORT usVoltageTime; // in microseconds
+ USHORT usTableSize; //the size of this structure, or the extended structure
+
+ ULONG ulPlatformCaps; // See ATOM_PPLIB_CAPS_*
+
+ ATOM_PPLIB_THERMALCONTROLLER sThermalController;
+
+ USHORT usBootClockInfoOffset;
+ USHORT usBootNonClockInfoOffset;
+
+} ATOM_PPLIB_POWERPLAYTABLE;
+
+//// ATOM_PPLIB_NONCLOCK_INFO::usClassification
+#define ATOM_PPLIB_CLASSIFICATION_UI_MASK 0x0007
+#define ATOM_PPLIB_CLASSIFICATION_UI_SHIFT 0
+#define ATOM_PPLIB_CLASSIFICATION_UI_NONE 0
+#define ATOM_PPLIB_CLASSIFICATION_UI_BATTERY 1
+#define ATOM_PPLIB_CLASSIFICATION_UI_BALANCED 3
+#define ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE 5
+// 2, 4, 6, 7 are reserved
+
+#define ATOM_PPLIB_CLASSIFICATION_BOOT 0x0008
+#define ATOM_PPLIB_CLASSIFICATION_THERMAL 0x0010
+#define ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE 0x0020
+#define ATOM_PPLIB_CLASSIFICATION_REST 0x0040
+#define ATOM_PPLIB_CLASSIFICATION_FORCED 0x0080
+#define ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE 0x0100
+#define ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE 0x0200
+#define ATOM_PPLIB_CLASSIFICATION_UVDSTATE 0x0400
+#define ATOM_PPLIB_CLASSIFICATION_3DLOW 0x0800
+#define ATOM_PPLIB_CLASSIFICATION_ACPI 0x1000
+// remaining 3 bits are reserved
+
+//// ATOM_PPLIB_NONCLOCK_INFO::ulCapsAndSettings
+#define ATOM_PPLIB_SINGLE_DISPLAY_ONLY 0x00000001
+#define ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK 0x00000002
+
+// 0 is 2.5Gb/s, 1 is 5Gb/s
+#define ATOM_PPLIB_PCIE_LINK_SPEED_MASK 0x00000004
+#define ATOM_PPLIB_PCIE_LINK_SPEED_SHIFT 2
+
+// lanes - 1: 1, 2, 4, 8, 12, 16 permitted by PCIE spec
+#define ATOM_PPLIB_PCIE_LINK_WIDTH_MASK 0x000000F8
+#define ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT 3
+
+// lookup into reduced refresh-rate table
+#define ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK 0x00000F00
+#define ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT 8
+
+#define ATOM_PPLIB_LIMITED_REFRESHRATE_UNLIMITED 0
+#define ATOM_PPLIB_LIMITED_REFRESHRATE_50HZ 1
+// 2-15 TBD as needed.
+
+#define ATOM_PPLIB_SOFTWARE_DISABLE_LOADBALANCING 0x00001000
+#define ATOM_PPLIB_SOFTWARE_ENABLE_SLEEP_FOR_TIMESTAMPS 0x00002000
+#define ATOM_PPLIB_ENABLE_VARIBRIGHT 0x00008000
+
+#define ATOM_PPLIB_DISALLOW_ON_DC 0x00004000
+
+// Contained in an array starting at the offset
+// in ATOM_PPLIB_POWERPLAYTABLE::usNonClockInfoArrayOffset.
+// referenced from ATOM_PPLIB_STATE_INFO::ucNonClockStateIndex
+typedef struct _ATOM_PPLIB_NONCLOCK_INFO
+{
+ USHORT usClassification;
+ UCHAR ucMinTemperature;
+ UCHAR ucMaxTemperature;
+ ULONG ulCapsAndSettings;
+ UCHAR ucRequiredPower;
+ UCHAR ucUnused1[3];
+} ATOM_PPLIB_NONCLOCK_INFO;
+
+// Contained in an array starting at the offset
+// in ATOM_PPLIB_POWERPLAYTABLE::usClockInfoArrayOffset.
+// referenced from ATOM_PPLIB_STATE::ucClockStateIndices
+typedef struct _ATOM_PPLIB_R600_CLOCK_INFO
+{
+ USHORT usEngineClockLow;
+ UCHAR ucEngineClockHigh;
+
+ USHORT usMemoryClockLow;
+ UCHAR ucMemoryClockHigh;
+
+ USHORT usVDDC;
+ USHORT usUnused1;
+ USHORT usUnused2;
+
+ ULONG ulFlags; // ATOM_PPLIB_R600_FLAGS_*
+
+} ATOM_PPLIB_R600_CLOCK_INFO;
+
+// ulFlags in ATOM_PPLIB_R600_CLOCK_INFO
+#define ATOM_PPLIB_R600_FLAGS_PCIEGEN2 1
+#define ATOM_PPLIB_R600_FLAGS_UVDSAFE 2
+#define ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE 4
+#define ATOM_PPLIB_R600_FLAGS_MEMORY_ODT_OFF 8
+#define ATOM_PPLIB_R600_FLAGS_MEMORY_DLL_OFF 16
+
+typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO
+
+{
+ USHORT usLowEngineClockLow; // Low Engine clock in MHz (the same way as on the R600).
+ UCHAR ucLowEngineClockHigh;
+ USHORT usHighEngineClockLow; // High Engine clock in MHz.
+ UCHAR ucHighEngineClockHigh;
+ USHORT usMemoryClockLow; // For now one of the ATOM_PPLIB_RS780_SPMCLK_XXXX constants.
+ UCHAR ucMemoryClockHigh; // Currentyl unused.
+ UCHAR ucPadding; // For proper alignment and size.
+ USHORT usVDDC; // For the 780, use: None, Low, High, Variable
+ UCHAR ucMaxHTLinkWidth; // From SBIOS - {2, 4, 8, 16}
+ UCHAR ucMinHTLinkWidth; // From SBIOS - {2, 4, 8, 16}. Effective only if CDLW enabled. Minimum down stream width could be bigger as display BW requriement.
+ USHORT usHTLinkFreq; // See definition ATOM_PPLIB_RS780_HTLINKFREQ_xxx or in MHz(>=200).
+ ULONG ulFlags;
+} ATOM_PPLIB_RS780_CLOCK_INFO;
+
+#define ATOM_PPLIB_RS780_VOLTAGE_NONE 0
+#define ATOM_PPLIB_RS780_VOLTAGE_LOW 1
+#define ATOM_PPLIB_RS780_VOLTAGE_HIGH 2
+#define ATOM_PPLIB_RS780_VOLTAGE_VARIABLE 3
+
+#define ATOM_PPLIB_RS780_SPMCLK_NONE 0 // We cannot change the side port memory clock, leave it as it is.
+#define ATOM_PPLIB_RS780_SPMCLK_LOW 1
+#define ATOM_PPLIB_RS780_SPMCLK_HIGH 2
+
+#define ATOM_PPLIB_RS780_HTLINKFREQ_NONE 0
+#define ATOM_PPLIB_RS780_HTLINKFREQ_LOW 1
+#define ATOM_PPLIB_RS780_HTLINKFREQ_HIGH 2
+
/**************************************************************************/
/* Following definitions are for compatiblity issue in different SW components. */
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 84e5df766d3..71727460968 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -2881,6 +2881,10 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track)
for (i = 0; i < track->num_cb; i++) {
if (track->cb[i].robj == NULL) {
+ if (!(track->fastfill || track->color_channel_mask ||
+ track->blend_read_enable)) {
+ continue;
+ }
DRM_ERROR("[drm] No buffer for color buffer %d !\n", i);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/radeon/r100_track.h b/drivers/gpu/drm/radeon/r100_track.h
index 7188c3778ee..b27a6999d21 100644
--- a/drivers/gpu/drm/radeon/r100_track.h
+++ b/drivers/gpu/drm/radeon/r100_track.h
@@ -67,13 +67,15 @@ struct r100_cs_track {
unsigned immd_dwords;
unsigned num_arrays;
unsigned max_indx;
+ unsigned color_channel_mask;
struct r100_cs_track_array arrays[11];
struct r100_cs_track_cb cb[R300_MAX_CB];
struct r100_cs_track_cb zb;
struct r100_cs_track_texture textures[R300_TRACK_MAX_TEXTURE];
bool z_enabled;
bool separate_cube;
-
+ bool fastfill;
+ bool blend_read_enable;
};
int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track);
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 83490c2b506..3f2cc9e2e8d 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -887,6 +887,14 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
track->textures[i].cpp = 1;
track->textures[i].compress_format = R100_TRACK_COMP_DXT1;
break;
+ case R300_TX_FORMAT_ATI2N:
+ if (p->rdev->family < CHIP_R420) {
+ DRM_ERROR("Invalid texture format %u\n",
+ (idx_value & 0x1F));
+ return -EINVAL;
+ }
+ /* The same rules apply as for DXT3/5. */
+ /* Pass through. */
case R300_TX_FORMAT_DXT3:
case R300_TX_FORMAT_DXT5:
track->textures[i].cpp = 1;
@@ -951,6 +959,16 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
track->textures[i].width_11 = tmp;
tmp = ((idx_value >> 16) & 1) << 11;
track->textures[i].height_11 = tmp;
+
+ /* ATI1N */
+ if (idx_value & (1 << 14)) {
+ /* The same rules apply as for DXT1. */
+ track->textures[i].compress_format =
+ R100_TRACK_COMP_DXT1;
+ }
+ } else if (idx_value & (1 << 14)) {
+ DRM_ERROR("Forbidden bit TXFORMAT_MSB\n");
+ return -EINVAL;
}
break;
case 0x4480:
@@ -992,6 +1010,18 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
}
ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
break;
+ case 0x4e0c:
+ /* RB3D_COLOR_CHANNEL_MASK */
+ track->color_channel_mask = idx_value;
+ break;
+ case 0x4d1c:
+ /* ZB_BW_CNTL */
+ track->fastfill = !!(idx_value & (1 << 2));
+ break;
+ case 0x4e04:
+ /* RB3D_BLENDCNTL */
+ track->blend_read_enable = !!(idx_value & (1 << 2));
+ break;
case 0x4be8:
/* valid register only on RV530 */
if (p->rdev->family == CHIP_RV530)
diff --git a/drivers/gpu/drm/radeon/r300_cmdbuf.c b/drivers/gpu/drm/radeon/r300_cmdbuf.c
index cb2e470f97d..34bffa0e4b7 100644
--- a/drivers/gpu/drm/radeon/r300_cmdbuf.c
+++ b/drivers/gpu/drm/radeon/r300_cmdbuf.c
@@ -990,7 +990,7 @@ static inline int r300_emit_r500fp(drm_radeon_private_t *dev_priv,
int sz;
int addr;
int type;
- int clamp;
+ int isclamp;
int stride;
RING_LOCALS;
@@ -999,10 +999,10 @@ static inline int r300_emit_r500fp(drm_radeon_private_t *dev_priv,
addr = ((header.r500fp.adrhi_flags & 1) << 8) | header.r500fp.adrlo;
type = !!(header.r500fp.adrhi_flags & R500FP_CONSTANT_TYPE);
- clamp = !!(header.r500fp.adrhi_flags & R500FP_CONSTANT_CLAMP);
+ isclamp = !!(header.r500fp.adrhi_flags & R500FP_CONSTANT_CLAMP);
addr |= (type << 16);
- addr |= (clamp << 17);
+ addr |= (isclamp << 17);
stride = type ? 4 : 6;
diff --git a/drivers/gpu/drm/radeon/r300_reg.h b/drivers/gpu/drm/radeon/r300_reg.h
index 4b7afef35a6..1735a2b6958 100644
--- a/drivers/gpu/drm/radeon/r300_reg.h
+++ b/drivers/gpu/drm/radeon/r300_reg.h
@@ -900,6 +900,7 @@
# define R300_TX_FORMAT_FL_I32 0x1B
# define R300_TX_FORMAT_FL_I32A32 0x1C
# define R300_TX_FORMAT_FL_R32G32B32A32 0x1D
+# define R300_TX_FORMAT_ATI2N 0x1F
/* alpha modes, convenience mostly */
/* if you have alpha, pick constant appropriate to the
number of channels (1 for I8, 2 for I8A8, 4 for R8G8B8A8, etc */
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index 0d820764f34..44060b92d9e 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -170,7 +170,7 @@ static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p,
idx, relocs_chunk->length_dw);
return -EINVAL;
}
- *cs_reloc = &p->relocs[0];
+ *cs_reloc = p->relocs;
(*cs_reloc)->lobj.gpu_offset = (u64)relocs_chunk->kdata[idx + 3] << 32;
(*cs_reloc)->lobj.gpu_offset |= relocs_chunk->kdata[idx + 0];
return 0;
@@ -717,7 +717,7 @@ static int r600_cs_parser_relocs_legacy(struct radeon_cs_parser *p)
if (p->chunk_relocs_idx == -1) {
return 0;
}
- p->relocs = kcalloc(1, sizeof(struct radeon_cs_reloc), GFP_KERNEL);
+ p->relocs = kzalloc(sizeof(struct radeon_cs_reloc), GFP_KERNEL);
if (p->relocs == NULL) {
return -ENOMEM;
}
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index cd650fd3964..53b55608102 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -162,6 +162,7 @@ struct radeon_fence_driver {
struct list_head created;
struct list_head emited;
struct list_head signaled;
+ bool initialized;
};
struct radeon_fence {
@@ -202,8 +203,9 @@ struct radeon_surface_reg {
struct radeon_mman {
struct ttm_bo_global_ref bo_global_ref;
struct ttm_global_reference mem_global_ref;
- bool mem_global_referenced;
struct ttm_bo_device bdev;
+ bool mem_global_referenced;
+ bool initialized;
};
struct radeon_bo {
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 636116bedcb..eb29217bbf1 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -33,6 +33,7 @@
*/
uint32_t radeon_legacy_get_engine_clock(struct radeon_device *rdev);
void radeon_legacy_set_engine_clock(struct radeon_device *rdev, uint32_t eng_clock);
+uint32_t radeon_legacy_get_memory_clock(struct radeon_device *rdev);
void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable);
uint32_t radeon_atom_get_engine_clock(struct radeon_device *rdev);
@@ -106,7 +107,7 @@ static struct radeon_asic r100_asic = {
.copy = &r100_copy_blit,
.get_engine_clock = &radeon_legacy_get_engine_clock,
.set_engine_clock = &radeon_legacy_set_engine_clock,
- .get_memory_clock = NULL,
+ .get_memory_clock = &radeon_legacy_get_memory_clock,
.set_memory_clock = NULL,
.set_pcie_lanes = NULL,
.set_clock_gating = &radeon_legacy_set_clock_gating,
@@ -166,7 +167,7 @@ static struct radeon_asic r300_asic = {
.copy = &r100_copy_blit,
.get_engine_clock = &radeon_legacy_get_engine_clock,
.set_engine_clock = &radeon_legacy_set_engine_clock,
- .get_memory_clock = NULL,
+ .get_memory_clock = &radeon_legacy_get_memory_clock,
.set_memory_clock = NULL,
.set_pcie_lanes = &rv370_set_pcie_lanes,
.set_clock_gating = &radeon_legacy_set_clock_gating,
@@ -259,7 +260,7 @@ static struct radeon_asic rs400_asic = {
.copy = &r100_copy_blit,
.get_engine_clock = &radeon_legacy_get_engine_clock,
.set_engine_clock = &radeon_legacy_set_engine_clock,
- .get_memory_clock = NULL,
+ .get_memory_clock = &radeon_legacy_get_memory_clock,
.set_memory_clock = NULL,
.set_pcie_lanes = NULL,
.set_clock_gating = &radeon_legacy_set_clock_gating,
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 12a0c760e7f..321044bef71 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -745,8 +745,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
else
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
- (1 <<
- i),
+ (1 << i),
dac),
(1 << i));
}
@@ -758,32 +757,30 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
if (bios_connectors[j].valid && (i != j)) {
if (bios_connectors[i].line_mux ==
bios_connectors[j].line_mux) {
- if (((bios_connectors[i].
- devices &
- (ATOM_DEVICE_DFP_SUPPORT))
- && (bios_connectors[j].
- devices &
- (ATOM_DEVICE_CRT_SUPPORT)))
- ||
- ((bios_connectors[j].
- devices &
- (ATOM_DEVICE_DFP_SUPPORT))
- && (bios_connectors[i].
- devices &
- (ATOM_DEVICE_CRT_SUPPORT)))) {
- bios_connectors[i].
- devices |=
- bios_connectors[j].
- devices;
- bios_connectors[i].
- connector_type =
- DRM_MODE_CONNECTOR_DVII;
- if (bios_connectors[j].devices &
- (ATOM_DEVICE_DFP_SUPPORT))
+ /* make sure not to combine LVDS */
+ if (bios_connectors[i].devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+ bios_connectors[i].line_mux = 53;
+ bios_connectors[i].ddc_bus.valid = false;
+ continue;
+ }
+ if (bios_connectors[j].devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+ bios_connectors[j].line_mux = 53;
+ bios_connectors[j].ddc_bus.valid = false;
+ continue;
+ }
+ /* combine analog and digital for DVI-I */
+ if (((bios_connectors[i].devices & (ATOM_DEVICE_DFP_SUPPORT)) &&
+ (bios_connectors[j].devices & (ATOM_DEVICE_CRT_SUPPORT))) ||
+ ((bios_connectors[j].devices & (ATOM_DEVICE_DFP_SUPPORT)) &&
+ (bios_connectors[i].devices & (ATOM_DEVICE_CRT_SUPPORT)))) {
+ bios_connectors[i].devices |=
+ bios_connectors[j].devices;
+ bios_connectors[i].connector_type =
+ DRM_MODE_CONNECTOR_DVII;
+ if (bios_connectors[j].devices & (ATOM_DEVICE_DFP_SUPPORT))
bios_connectors[i].hpd =
bios_connectors[j].hpd;
- bios_connectors[j].
- valid = false;
+ bios_connectors[j].valid = false;
}
}
}
@@ -1234,6 +1231,61 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
return true;
}
+enum radeon_tv_std
+radeon_atombios_get_tv_info(struct radeon_device *rdev)
+{
+ struct radeon_mode_info *mode_info = &rdev->mode_info;
+ int index = GetIndexIntoMasterTable(DATA, AnalogTV_Info);
+ uint16_t data_offset;
+ uint8_t frev, crev;
+ struct _ATOM_ANALOG_TV_INFO *tv_info;
+ enum radeon_tv_std tv_std = TV_STD_NTSC;
+
+ atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset);
+
+ tv_info = (struct _ATOM_ANALOG_TV_INFO *)(mode_info->atom_context->bios + data_offset);
+
+ switch (tv_info->ucTV_BootUpDefaultStandard) {
+ case ATOM_TV_NTSC:
+ tv_std = TV_STD_NTSC;
+ DRM_INFO("Default TV standard: NTSC\n");
+ break;
+ case ATOM_TV_NTSCJ:
+ tv_std = TV_STD_NTSC_J;
+ DRM_INFO("Default TV standard: NTSC-J\n");
+ break;
+ case ATOM_TV_PAL:
+ tv_std = TV_STD_PAL;
+ DRM_INFO("Default TV standard: PAL\n");
+ break;
+ case ATOM_TV_PALM:
+ tv_std = TV_STD_PAL_M;
+ DRM_INFO("Default TV standard: PAL-M\n");
+ break;
+ case ATOM_TV_PALN:
+ tv_std = TV_STD_PAL_N;
+ DRM_INFO("Default TV standard: PAL-N\n");
+ break;
+ case ATOM_TV_PALCN:
+ tv_std = TV_STD_PAL_CN;
+ DRM_INFO("Default TV standard: PAL-CN\n");
+ break;
+ case ATOM_TV_PAL60:
+ tv_std = TV_STD_PAL_60;
+ DRM_INFO("Default TV standard: PAL-60\n");
+ break;
+ case ATOM_TV_SECAM:
+ tv_std = TV_STD_SECAM;
+ DRM_INFO("Default TV standard: SECAM\n");
+ break;
+ default:
+ tv_std = TV_STD_NTSC;
+ DRM_INFO("Unknown TV standard; defaulting to NTSC\n");
+ break;
+ }
+ return tv_std;
+}
+
struct radeon_encoder_tv_dac *
radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder)
{
@@ -1269,6 +1321,7 @@ radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder)
dac = dac_info->ucDAC2_NTSC_DAC_Adjustment;
tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
+ tv_dac->tv_std = radeon_atombios_get_tv_info(rdev);
}
return tv_dac;
}
diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c
index b062109efbe..812f24dbc2a 100644
--- a/drivers/gpu/drm/radeon/radeon_clocks.c
+++ b/drivers/gpu/drm/radeon/radeon_clocks.c
@@ -62,7 +62,7 @@ uint32_t radeon_legacy_get_engine_clock(struct radeon_device *rdev)
}
/* 10 khz */
-static uint32_t radeon_legacy_get_memory_clock(struct radeon_device *rdev)
+uint32_t radeon_legacy_get_memory_clock(struct radeon_device *rdev)
{
struct radeon_pll *mpll = &rdev->clock.mpll;
uint32_t fb_div, ref_div, post_div, mclk;
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index c5021a3445d..fd94dbca33a 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -634,11 +634,10 @@ struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct
return p_dac;
}
-static enum radeon_tv_std
-radeon_combios_get_tv_info(struct radeon_encoder *encoder)
+enum radeon_tv_std
+radeon_combios_get_tv_info(struct radeon_device *rdev)
{
- struct drm_device *dev = encoder->base.dev;
- struct radeon_device *rdev = dev->dev_private;
+ struct drm_device *dev = rdev->ddev;
uint16_t tv_info;
enum radeon_tv_std tv_std = TV_STD_NTSC;
@@ -779,7 +778,7 @@ struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct
tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
found = 1;
}
- tv_dac->tv_std = radeon_combios_get_tv_info(encoder);
+ tv_dac->tv_std = radeon_combios_get_tv_info(rdev);
}
if (!found) {
/* then check CRT table */
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 5eece186e03..20161567dbf 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -208,6 +208,18 @@ static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encode
drm_mode_set_name(mode);
DRM_DEBUG("Adding native panel mode %s\n", mode->name);
+ } else if (native_mode->hdisplay != 0 &&
+ native_mode->vdisplay != 0) {
+ /* mac laptops without an edid */
+ /* Note that this is not necessarily the exact panel mode,
+ * but an approximation based on the cvt formula. For these
+ * systems we should ideally read the mode info out of the
+ * registers or add a mode table, but this works and is much
+ * simpler.
+ */
+ mode = drm_cvt_mode(dev, native_mode->hdisplay, native_mode->vdisplay, 60, true, false, false);
+ mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
+ DRM_DEBUG("Adding cvt approximation of native panel mode %s\n", mode->name);
}
return mode;
}
@@ -1171,7 +1183,7 @@ radeon_add_atom_connector(struct drm_device *dev,
1);
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.tv_std_property,
- 1);
+ radeon_atombios_get_tv_info(rdev));
}
break;
case DRM_MODE_CONNECTOR_LVDS:
@@ -1315,7 +1327,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
1);
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.tv_std_property,
- 1);
+ radeon_combios_get_tv_info(rdev));
}
break;
case DRM_MODE_CONNECTOR_LVDS:
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 02bcdb1240c..7c6848096bc 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -391,6 +391,12 @@ int radeon_asic_init(struct radeon_device *rdev)
/* FIXME: not supported yet */
return -EINVAL;
}
+
+ if (rdev->flags & RADEON_IS_IGP) {
+ rdev->asic->get_memory_clock = NULL;
+ rdev->asic->set_memory_clock = NULL;
+ }
+
return 0;
}
@@ -481,6 +487,7 @@ int radeon_atombios_init(struct radeon_device *rdev)
atom_card_info->pll_write = cail_pll_write;
rdev->mode_info.atom_context = atom_parse(atom_card_info, rdev->bios);
+ mutex_init(&rdev->mode_info.atom_context->mutex);
radeon_atom_initialize_bios_scratch_regs(rdev->ddev);
atom_allocate_fb_scratch(rdev->mode_info.atom_context);
return 0;
@@ -539,9 +546,72 @@ void radeon_agp_disable(struct radeon_device *rdev)
}
}
-/*
- * Radeon device.
- */
+void radeon_check_arguments(struct radeon_device *rdev)
+{
+ /* vramlimit must be a power of two */
+ switch (radeon_vram_limit) {
+ case 0:
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ case 128:
+ case 256:
+ case 512:
+ case 1024:
+ case 2048:
+ case 4096:
+ break;
+ default:
+ dev_warn(rdev->dev, "vram limit (%d) must be a power of 2\n",
+ radeon_vram_limit);
+ radeon_vram_limit = 0;
+ break;
+ }
+ radeon_vram_limit = radeon_vram_limit << 20;
+ /* gtt size must be power of two and greater or equal to 32M */
+ switch (radeon_gart_size) {
+ case 4:
+ case 8:
+ case 16:
+ dev_warn(rdev->dev, "gart size (%d) too small forcing to 512M\n",
+ radeon_gart_size);
+ radeon_gart_size = 512;
+ break;
+ case 32:
+ case 64:
+ case 128:
+ case 256:
+ case 512:
+ case 1024:
+ case 2048:
+ case 4096:
+ break;
+ default:
+ dev_warn(rdev->dev, "gart size (%d) must be a power of 2\n",
+ radeon_gart_size);
+ radeon_gart_size = 512;
+ break;
+ }
+ rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
+ /* AGP mode can only be -1, 1, 2, 4, 8 */
+ switch (radeon_agpmode) {
+ case -1:
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ dev_warn(rdev->dev, "invalid AGP mode %d (valid mode: "
+ "-1, 0, 1, 2, 4, 8)\n", radeon_agpmode);
+ radeon_agpmode = 0;
+ break;
+ }
+}
+
int radeon_device_init(struct radeon_device *rdev,
struct drm_device *ddev,
struct pci_dev *pdev,
@@ -580,9 +650,9 @@ int radeon_device_init(struct radeon_device *rdev,
/* Set asic functions */
r = radeon_asic_init(rdev);
- if (r) {
+ if (r)
return r;
- }
+ radeon_check_arguments(rdev);
if (rdev->flags & RADEON_IS_AGP && radeon_agpmode == -1) {
radeon_agp_disable(rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index a133b833e45..91d72b70abc 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -739,7 +739,7 @@ static struct drm_prop_enum_list radeon_tv_std_enum_list[] =
{ TV_STD_SECAM, "secam" },
};
-int radeon_modeset_create_props(struct radeon_device *rdev)
+static int radeon_modeset_create_props(struct radeon_device *rdev)
{
int i, sz;
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index dbd56ef82f9..8ba3de7994d 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -196,7 +196,7 @@ static struct drm_driver driver_old = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
- .ioctl = drm_ioctl,
+ .unlocked_ioctl = drm_ioctl,
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
@@ -284,7 +284,7 @@ static struct drm_driver kms_driver = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
- .ioctl = drm_ioctl,
+ .unlocked_ioctl = drm_ioctl,
.mmap = radeon_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index 0d1d908e522..ccba95f83d1 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -233,6 +233,8 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
if (!ASIC_IS_AVIVO(rdev)) {
adjusted_mode->hdisplay = mode->hdisplay;
adjusted_mode->vdisplay = mode->vdisplay;
+ adjusted_mode->crtc_hdisplay = mode->hdisplay;
+ adjusted_mode->crtc_vdisplay = mode->vdisplay;
}
adjusted_mode->base.id = mode_id;
}
@@ -495,9 +497,9 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
- if (dig->lvds_misc & (1 << 0))
+ if (dig->lvds_misc & ATOM_PANEL_MISC_DUAL)
args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
- if (dig->lvds_misc & (1 << 1))
+ if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB)
args.v1.ucMisc |= (1 << 1);
} else {
if (dig_connector->linkb)
@@ -524,18 +526,18 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
args.v2.ucTemporal = 0;
args.v2.ucFRC = 0;
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
- if (dig->lvds_misc & (1 << 0))
+ if (dig->lvds_misc & ATOM_PANEL_MISC_DUAL)
args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
- if (dig->lvds_misc & (1 << 5)) {
+ if (dig->lvds_misc & ATOM_PANEL_MISC_SPATIAL) {
args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN;
- if (dig->lvds_misc & (1 << 1))
+ if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB)
args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH;
}
- if (dig->lvds_misc & (1 << 6)) {
+ if (dig->lvds_misc & ATOM_PANEL_MISC_TEMPORAL) {
args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN;
- if (dig->lvds_misc & (1 << 1))
+ if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB)
args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH;
- if (((dig->lvds_misc >> 2) & 0x3) == 2)
+ if (((dig->lvds_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2)
args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4;
}
} else {
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index cb4cd97ae39..4cdd8b4f754 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -324,7 +324,7 @@ int radeon_fence_driver_init(struct radeon_device *rdev)
write_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
r = radeon_scratch_get(rdev, &rdev->fence_drv.scratch_reg);
if (r) {
- DRM_ERROR("Fence failed to get a scratch register.");
+ dev_err(rdev->dev, "fence failed to get scratch register\n");
write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
return r;
}
@@ -335,9 +335,10 @@ int radeon_fence_driver_init(struct radeon_device *rdev)
INIT_LIST_HEAD(&rdev->fence_drv.signaled);
rdev->fence_drv.count_timeout = 0;
init_waitqueue_head(&rdev->fence_drv.queue);
+ rdev->fence_drv.initialized = true;
write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
if (radeon_debugfs_fence_init(rdev)) {
- DRM_ERROR("Failed to register debugfs file for fence !\n");
+ dev_err(rdev->dev, "fence debugfs file creation failed\n");
}
return 0;
}
@@ -346,11 +347,13 @@ void radeon_fence_driver_fini(struct radeon_device *rdev)
{
unsigned long irq_flags;
+ if (!rdev->fence_drv.initialized)
+ return;
wake_up_all(&rdev->fence_drv.queue);
write_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
radeon_scratch_free(rdev, rdev->fence_drv.scratch_reg);
write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
- DRM_INFO("radeon: fence finalized\n");
+ rdev->fence_drv.initialized = false;
}
diff --git a/drivers/gpu/drm/radeon/radeon_ioc32.c b/drivers/gpu/drm/radeon/radeon_ioc32.c
index a1bf11de308..48b7cea31e0 100644
--- a/drivers/gpu/drm/radeon/radeon_ioc32.c
+++ b/drivers/gpu/drm/radeon/radeon_ioc32.c
@@ -92,8 +92,7 @@ static int compat_radeon_cp_init(struct file *file, unsigned int cmd,
&init->gart_textures_offset))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_RADEON_CP_INIT, (unsigned long)init);
+ return drm_ioctl(file, DRM_IOCTL_RADEON_CP_INIT, (unsigned long)init);
}
typedef struct drm_radeon_clear32 {
@@ -125,8 +124,7 @@ static int compat_radeon_cp_clear(struct file *file, unsigned int cmd,
&clr->depth_boxes))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_RADEON_CLEAR, (unsigned long)clr);
+ return drm_ioctl(file, DRM_IOCTL_RADEON_CLEAR, (unsigned long)clr);
}
typedef struct drm_radeon_stipple32 {
@@ -149,8 +147,7 @@ static int compat_radeon_cp_stipple(struct file *file, unsigned int cmd,
&request->mask))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_RADEON_STIPPLE, (unsigned long)request);
+ return drm_ioctl(file, DRM_IOCTL_RADEON_STIPPLE, (unsigned long)request);
}
typedef struct drm_radeon_tex_image32 {
@@ -204,8 +201,7 @@ static int compat_radeon_cp_texture(struct file *file, unsigned int cmd,
&image->data))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_RADEON_TEXTURE, (unsigned long)request);
+ return drm_ioctl(file, DRM_IOCTL_RADEON_TEXTURE, (unsigned long)request);
}
typedef struct drm_radeon_vertex2_32 {
@@ -238,8 +234,7 @@ static int compat_radeon_cp_vertex2(struct file *file, unsigned int cmd,
&request->prim))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_RADEON_VERTEX2, (unsigned long)request);
+ return drm_ioctl(file, DRM_IOCTL_RADEON_VERTEX2, (unsigned long)request);
}
typedef struct drm_radeon_cmd_buffer32 {
@@ -268,8 +263,7 @@ static int compat_radeon_cp_cmdbuf(struct file *file, unsigned int cmd,
&request->boxes))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_RADEON_CMDBUF, (unsigned long)request);
+ return drm_ioctl(file, DRM_IOCTL_RADEON_CMDBUF, (unsigned long)request);
}
typedef struct drm_radeon_getparam32 {
@@ -293,8 +287,7 @@ static int compat_radeon_cp_getparam(struct file *file, unsigned int cmd,
&request->value))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_RADEON_GETPARAM, (unsigned long)request);
+ return drm_ioctl(file, DRM_IOCTL_RADEON_GETPARAM, (unsigned long)request);
}
typedef struct drm_radeon_mem_alloc32 {
@@ -322,8 +315,7 @@ static int compat_radeon_mem_alloc(struct file *file, unsigned int cmd,
&request->region_offset))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_RADEON_ALLOC, (unsigned long)request);
+ return drm_ioctl(file, DRM_IOCTL_RADEON_ALLOC, (unsigned long)request);
}
typedef struct drm_radeon_irq_emit32 {
@@ -345,8 +337,7 @@ static int compat_radeon_irq_emit(struct file *file, unsigned int cmd,
&request->irq_seq))
return -EFAULT;
- return drm_ioctl(file->f_path.dentry->d_inode, file,
- DRM_IOCTL_RADEON_IRQ_EMIT, (unsigned long)request);
+ return drm_ioctl(file, DRM_IOCTL_RADEON_IRQ_EMIT, (unsigned long)request);
}
/* The two 64-bit arches where alignof(u64)==4 in 32-bit code */
@@ -372,8 +363,7 @@ static int compat_radeon_cp_setparam(struct file *file, unsigned int cmd,
&request->value))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
- DRM_IOCTL_RADEON_SETPARAM, (unsigned long) request);
+ return drm_ioctl(file, DRM_IOCTL_RADEON_SETPARAM, (unsigned long) request);
}
#else
#define compat_radeon_cp_setparam NULL
@@ -413,12 +403,10 @@ long radeon_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(radeon_compat_ioctls))
fn = radeon_compat_ioctls[nr - DRM_COMMAND_BASE];
- lock_kernel(); /* XXX for now */
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
- unlock_kernel();
+ ret = drm_ioctl(filp, cmd, arg);
return ret;
}
@@ -431,9 +419,7 @@ long radeon_kms_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long
if (nr < DRM_COMMAND_BASE)
return drm_compat_ioctl(filp, cmd, arg);
- lock_kernel(); /* XXX for now */
- ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
- unlock_kernel();
+ ret = drm_ioctl(filp, cmd, arg);
return ret;
}
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
index b82ede98e15..cc27485a07a 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
@@ -43,8 +43,7 @@ static void radeon_overscan_setup(struct drm_crtc *crtc,
}
static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+ struct drm_display_mode *mode)
{
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
@@ -1059,7 +1058,7 @@ static int radeon_crtc_mode_set(struct drm_crtc *crtc,
radeon_set_pll(crtc, adjusted_mode);
radeon_overscan_setup(crtc, adjusted_mode);
if (radeon_crtc->crtc_id == 0) {
- radeon_legacy_rmx_mode_set(crtc, mode, adjusted_mode);
+ radeon_legacy_rmx_mode_set(crtc, adjusted_mode);
} else {
if (radeon_crtc->rmx_type != RMX_OFF) {
/* FIXME: only first crtc has rmx what should we
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
index df00515e81f..981508ff703 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
@@ -207,6 +207,8 @@ static bool radeon_legacy_mode_fixup(struct drm_encoder *encoder,
*adjusted_mode = *native_mode;
adjusted_mode->hdisplay = mode->hdisplay;
adjusted_mode->vdisplay = mode->vdisplay;
+ adjusted_mode->crtc_hdisplay = mode->hdisplay;
+ adjusted_mode->crtc_vdisplay = mode->vdisplay;
adjusted_mode->base.id = mode_id;
}
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 3dcbe130c42..402369db5ba 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -88,6 +88,7 @@ enum radeon_tv_std {
TV_STD_SCART_PAL,
TV_STD_SECAM,
TV_STD_PAL_CN,
+ TV_STD_PAL_N,
};
/* radeon gpio-based i2c
@@ -395,6 +396,11 @@ struct radeon_framebuffer {
struct drm_gem_object *obj;
};
+extern enum radeon_tv_std
+radeon_combios_get_tv_info(struct radeon_device *rdev);
+extern enum radeon_tv_std
+radeon_atombios_get_tv_info(struct radeon_device *rdev);
+
extern void radeon_connector_hotplug(struct drm_connector *connector);
extern bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector);
extern int radeon_dp_mode_valid_helper(struct radeon_connector *radeon_connector,
diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c
index 391c973ec4d..9f5e2f929da 100644
--- a/drivers/gpu/drm/radeon/radeon_test.c
+++ b/drivers/gpu/drm/radeon/radeon_test.c
@@ -42,8 +42,8 @@ void radeon_test_moves(struct radeon_device *rdev)
/* Number of tests =
* (Total GTT - IB pool - writeback page - ring buffer) / test size
*/
- n = (rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - RADEON_GPU_PAGE_SIZE -
- rdev->cp.ring_size) / size;
+ n = ((u32)(rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - RADEON_GPU_PAGE_SIZE -
+ rdev->cp.ring_size)) / size;
gtt_obj = kzalloc(n * sizeof(*gtt_obj), GFP_KERNEL);
if (!gtt_obj) {
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index d7fd160cc67..3b0c07b444a 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -494,6 +494,7 @@ int radeon_ttm_init(struct radeon_device *rdev)
DRM_ERROR("failed initializing buffer object driver(%d).\n", r);
return r;
}
+ rdev->mman.initialized = true;
r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_VRAM,
rdev->mc.real_vram_size >> PAGE_SHIFT);
if (r) {
@@ -541,6 +542,8 @@ void radeon_ttm_fini(struct radeon_device *rdev)
{
int r;
+ if (!rdev->mman.initialized)
+ return;
if (rdev->stollen_vga_memory) {
r = radeon_bo_reserve(rdev->stollen_vga_memory, false);
if (r == 0) {
@@ -554,6 +557,7 @@ void radeon_ttm_fini(struct radeon_device *rdev)
ttm_bo_device_release(&rdev->mman.bdev);
radeon_gart_fini(rdev);
radeon_ttm_global_fini(rdev);
+ rdev->mman.initialized = false;
DRM_INFO("radeon: ttm finalized\n");
}
diff --git a/drivers/gpu/drm/savage/savage_drv.c b/drivers/gpu/drm/savage/savage_drv.c
index eee52aa92a7..021de44c15a 100644
--- a/drivers/gpu/drm/savage/savage_drv.c
+++ b/drivers/gpu/drm/savage/savage_drv.c
@@ -50,7 +50,7 @@ static struct drm_driver driver = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
- .ioctl = drm_ioctl,
+ .unlocked_ioctl = drm_ioctl,
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c
index e725cc0b115..4fd1f067d38 100644
--- a/drivers/gpu/drm/sis/sis_drv.c
+++ b/drivers/gpu/drm/sis/sis_drv.c
@@ -80,7 +80,7 @@ static struct drm_driver driver = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
- .ioctl = drm_ioctl,
+ .unlocked_ioctl = drm_ioctl,
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
diff --git a/drivers/gpu/drm/tdfx/tdfx_drv.c b/drivers/gpu/drm/tdfx/tdfx_drv.c
index 012ff2e356b..ec5a43e6572 100644
--- a/drivers/gpu/drm/tdfx/tdfx_drv.c
+++ b/drivers/gpu/drm/tdfx/tdfx_drv.c
@@ -48,7 +48,7 @@ static struct drm_driver driver = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
- .ioctl = drm_ioctl,
+ .unlocked_ioctl = drm_ioctl,
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
diff --git a/drivers/gpu/drm/via/via_drv.c b/drivers/gpu/drm/via/via_drv.c
index bc2f5184300..7a1b210401e 100644
--- a/drivers/gpu/drm/via/via_drv.c
+++ b/drivers/gpu/drm/via/via_drv.c
@@ -58,7 +58,7 @@ static struct drm_driver driver = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
- .ioctl = drm_ioctl,
+ .unlocked_ioctl = drm_ioctl,
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 7b48bb3b63b..1db1ef30be2 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -103,37 +103,39 @@
*/
static struct drm_ioctl_desc vmw_ioctls[] = {
- VMW_IOCTL_DEF(DRM_IOCTL_VMW_GET_PARAM, vmw_getparam_ioctl, 0),
+ VMW_IOCTL_DEF(DRM_IOCTL_VMW_GET_PARAM, vmw_getparam_ioctl,
+ DRM_AUTH | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_ALLOC_DMABUF, vmw_dmabuf_alloc_ioctl,
- 0),
+ DRM_AUTH | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_DMABUF, vmw_dmabuf_unref_ioctl,
- 0),
+ DRM_AUTH | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_CURSOR_BYPASS,
- vmw_kms_cursor_bypass_ioctl, 0),
+ vmw_kms_cursor_bypass_ioctl,
+ DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_CONTROL_STREAM, vmw_overlay_ioctl,
- 0),
+ DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_CLAIM_STREAM, vmw_stream_claim_ioctl,
- 0),
+ DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_STREAM, vmw_stream_unref_ioctl,
- 0),
+ DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_CREATE_CONTEXT, vmw_context_define_ioctl,
- 0),
+ DRM_AUTH | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl,
- 0),
+ DRM_AUTH | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_CREATE_SURFACE, vmw_surface_define_ioctl,
- 0),
+ DRM_AUTH | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl,
- 0),
+ DRM_AUTH | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_REF_SURFACE, vmw_surface_reference_ioctl,
- 0),
+ DRM_AUTH | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_EXECBUF, vmw_execbuf_ioctl,
- 0),
+ DRM_AUTH | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_FIFO_DEBUG, vmw_fifo_debug_ioctl,
- 0),
+ DRM_AUTH | DRM_ROOT_ONLY | DRM_MASTER | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_FENCE_WAIT, vmw_fence_wait_ioctl,
- 0)
+ DRM_AUTH | DRM_UNLOCKED)
};
static struct pci_device_id vmw_pci_id_list[] = {
@@ -460,11 +462,9 @@ static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd,
struct drm_file *file_priv = filp->private_data;
struct drm_device *dev = file_priv->minor->dev;
unsigned int nr = DRM_IOCTL_NR(cmd);
- long ret;
/*
- * The driver private ioctls and TTM ioctls should be
- * thread-safe.
+ * Do extra checking on driver private ioctls.
*/
if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END)
@@ -477,18 +477,9 @@ static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd,
nr - DRM_COMMAND_BASE);
return -EINVAL;
}
- return drm_ioctl(filp->f_path.dentry->d_inode,
- filp, cmd, arg);
}
- /*
- * Not all old drm ioctls are thread-safe.
- */
-
- lock_kernel();
- ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
- unlock_kernel();
- return ret;
+ return drm_ioctl(filp, cmd, arg);
}
static int vmw_firstopen(struct drm_device *dev)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 43546d09d1b..e61bd85b697 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -123,6 +123,7 @@ struct vmw_sw_context{
uint32_t last_cid;
bool cid_valid;
uint32_t last_sid;
+ uint32_t sid_translation;
bool sid_valid;
struct ttm_object_file *tfile;
struct list_head validate_nodes;
@@ -317,9 +318,10 @@ extern void vmw_surface_res_free(struct vmw_resource *res);
extern int vmw_surface_init(struct vmw_private *dev_priv,
struct vmw_surface *srf,
void (*res_free) (struct vmw_resource *res));
-extern int vmw_user_surface_lookup(struct vmw_private *dev_priv,
- struct ttm_object_file *tfile,
- int sid, struct vmw_surface **out);
+extern int vmw_user_surface_lookup_handle(struct vmw_private *dev_priv,
+ struct ttm_object_file *tfile,
+ uint32_t handle,
+ struct vmw_surface **out);
extern int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
@@ -328,7 +330,7 @@ extern int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_surface_check(struct vmw_private *dev_priv,
struct ttm_object_file *tfile,
- int id);
+ uint32_t handle, int *id);
extern void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo);
extern int vmw_dmabuf_init(struct vmw_private *dev_priv,
struct vmw_dma_buffer *vmw_bo,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 7a39f3e6dc2..2e92da56740 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -73,21 +73,32 @@ static int vmw_cmd_cid_check(struct vmw_private *dev_priv,
static int vmw_cmd_sid_check(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
- uint32_t sid)
+ uint32_t *sid)
{
- if (unlikely((!sw_context->sid_valid || sid != sw_context->last_sid) &&
- sid != SVGA3D_INVALID_ID)) {
- int ret = vmw_surface_check(dev_priv, sw_context->tfile, sid);
+ if (*sid == SVGA3D_INVALID_ID)
+ return 0;
+
+ if (unlikely((!sw_context->sid_valid ||
+ *sid != sw_context->last_sid))) {
+ int real_id;
+ int ret = vmw_surface_check(dev_priv, sw_context->tfile,
+ *sid, &real_id);
if (unlikely(ret != 0)) {
- DRM_ERROR("Could ot find or use surface %u\n",
- (unsigned) sid);
+ DRM_ERROR("Could ot find or use surface 0x%08x "
+ "address 0x%08lx\n",
+ (unsigned int) *sid,
+ (unsigned long) sid);
return ret;
}
- sw_context->last_sid = sid;
+ sw_context->last_sid = *sid;
sw_context->sid_valid = true;
- }
+ *sid = real_id;
+ sw_context->sid_translation = real_id;
+ } else
+ *sid = sw_context->sid_translation;
+
return 0;
}
@@ -107,7 +118,8 @@ static int vmw_cmd_set_render_target_check(struct vmw_private *dev_priv,
return ret;
cmd = container_of(header, struct vmw_sid_cmd, header);
- return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.target.sid);
+ ret = vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.target.sid);
+ return ret;
}
static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv,
@@ -121,10 +133,10 @@ static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv,
int ret;
cmd = container_of(header, struct vmw_sid_cmd, header);
- ret = vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.src.sid);
+ ret = vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.src.sid);
if (unlikely(ret != 0))
return ret;
- return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.dest.sid);
+ return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.dest.sid);
}
static int vmw_cmd_stretch_blt_check(struct vmw_private *dev_priv,
@@ -138,10 +150,10 @@ static int vmw_cmd_stretch_blt_check(struct vmw_private *dev_priv,
int ret;
cmd = container_of(header, struct vmw_sid_cmd, header);
- ret = vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.src.sid);
+ ret = vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.src.sid);
if (unlikely(ret != 0))
return ret;
- return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.dest.sid);
+ return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.dest.sid);
}
static int vmw_cmd_blt_surf_screen_check(struct vmw_private *dev_priv,
@@ -154,7 +166,7 @@ static int vmw_cmd_blt_surf_screen_check(struct vmw_private *dev_priv,
} *cmd;
cmd = container_of(header, struct vmw_sid_cmd, header);
- return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.srcImage.sid);
+ return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.srcImage.sid);
}
static int vmw_cmd_present_check(struct vmw_private *dev_priv,
@@ -167,7 +179,7 @@ static int vmw_cmd_present_check(struct vmw_private *dev_priv,
} *cmd;
cmd = container_of(header, struct vmw_sid_cmd, header);
- return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.sid);
+ return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.sid);
}
static int vmw_cmd_dma(struct vmw_private *dev_priv,
@@ -187,12 +199,7 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv,
uint32_t cur_validate_node;
struct ttm_validate_buffer *val_buf;
-
cmd = container_of(header, struct vmw_dma_cmd, header);
- ret = vmw_cmd_sid_check(dev_priv, sw_context, cmd->dma.host.sid);
- if (unlikely(ret != 0))
- return ret;
-
handle = cmd->dma.guest.ptr.gmrId;
ret = vmw_user_dmabuf_lookup(sw_context->tfile, handle, &vmw_bo);
if (unlikely(ret != 0)) {
@@ -228,14 +235,23 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv,
++sw_context->cur_val_buf;
}
- ret = vmw_user_surface_lookup(dev_priv, sw_context->tfile,
- cmd->dma.host.sid, &srf);
+ ret = vmw_user_surface_lookup_handle(dev_priv, sw_context->tfile,
+ cmd->dma.host.sid, &srf);
if (ret) {
DRM_ERROR("could not find surface\n");
goto out_no_reloc;
}
+ /**
+ * Patch command stream with device SID.
+ */
+
+ cmd->dma.host.sid = srf->res.id;
vmw_kms_cursor_snoop(srf, sw_context->tfile, bo, header);
+ /**
+ * FIXME: May deadlock here when called from the
+ * command parsing code.
+ */
vmw_surface_unreference(&srf);
out_no_reloc:
@@ -243,6 +259,90 @@ out_no_reloc:
return ret;
}
+static int vmw_cmd_draw(struct vmw_private *dev_priv,
+ struct vmw_sw_context *sw_context,
+ SVGA3dCmdHeader *header)
+{
+ struct vmw_draw_cmd {
+ SVGA3dCmdHeader header;
+ SVGA3dCmdDrawPrimitives body;
+ } *cmd;
+ SVGA3dVertexDecl *decl = (SVGA3dVertexDecl *)(
+ (unsigned long)header + sizeof(*cmd));
+ SVGA3dPrimitiveRange *range;
+ uint32_t i;
+ uint32_t maxnum;
+ int ret;
+
+ ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
+ if (unlikely(ret != 0))
+ return ret;
+
+ cmd = container_of(header, struct vmw_draw_cmd, header);
+ maxnum = (header->size - sizeof(cmd->body)) / sizeof(*decl);
+
+ if (unlikely(cmd->body.numVertexDecls > maxnum)) {
+ DRM_ERROR("Illegal number of vertex declarations.\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < cmd->body.numVertexDecls; ++i, ++decl) {
+ ret = vmw_cmd_sid_check(dev_priv, sw_context,
+ &decl->array.surfaceId);
+ if (unlikely(ret != 0))
+ return ret;
+ }
+
+ maxnum = (header->size - sizeof(cmd->body) -
+ cmd->body.numVertexDecls * sizeof(*decl)) / sizeof(*range);
+ if (unlikely(cmd->body.numRanges > maxnum)) {
+ DRM_ERROR("Illegal number of index ranges.\n");
+ return -EINVAL;
+ }
+
+ range = (SVGA3dPrimitiveRange *) decl;
+ for (i = 0; i < cmd->body.numRanges; ++i, ++range) {
+ ret = vmw_cmd_sid_check(dev_priv, sw_context,
+ &range->indexArray.surfaceId);
+ if (unlikely(ret != 0))
+ return ret;
+ }
+ return 0;
+}
+
+
+static int vmw_cmd_tex_state(struct vmw_private *dev_priv,
+ struct vmw_sw_context *sw_context,
+ SVGA3dCmdHeader *header)
+{
+ struct vmw_tex_state_cmd {
+ SVGA3dCmdHeader header;
+ SVGA3dCmdSetTextureState state;
+ };
+
+ SVGA3dTextureState *last_state = (SVGA3dTextureState *)
+ ((unsigned long) header + header->size + sizeof(header));
+ SVGA3dTextureState *cur_state = (SVGA3dTextureState *)
+ ((unsigned long) header + sizeof(struct vmw_tex_state_cmd));
+ int ret;
+
+ ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
+ if (unlikely(ret != 0))
+ return ret;
+
+ for (; cur_state < last_state; ++cur_state) {
+ if (likely(cur_state->name != SVGA3D_TS_BIND_TEXTURE))
+ continue;
+
+ ret = vmw_cmd_sid_check(dev_priv, sw_context,
+ &cur_state->value);
+ if (unlikely(ret != 0))
+ return ret;
+ }
+
+ return 0;
+}
+
typedef int (*vmw_cmd_func) (struct vmw_private *,
struct vmw_sw_context *,
@@ -264,7 +364,7 @@ static vmw_cmd_func vmw_cmd_funcs[SVGA_3D_CMD_MAX] = {
VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERSTATE, &vmw_cmd_cid_check),
VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERTARGET,
&vmw_cmd_set_render_target_check),
- VMW_CMD_DEF(SVGA_3D_CMD_SETTEXTURESTATE, &vmw_cmd_cid_check),
+ VMW_CMD_DEF(SVGA_3D_CMD_SETTEXTURESTATE, &vmw_cmd_tex_state),
VMW_CMD_DEF(SVGA_3D_CMD_SETMATERIAL, &vmw_cmd_cid_check),
VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTDATA, &vmw_cmd_cid_check),
VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTENABLED, &vmw_cmd_cid_check),
@@ -276,7 +376,7 @@ static vmw_cmd_func vmw_cmd_funcs[SVGA_3D_CMD_MAX] = {
VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DESTROY, &vmw_cmd_cid_check),
VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER, &vmw_cmd_cid_check),
VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER_CONST, &vmw_cmd_cid_check),
- VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_cid_check),
+ VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_draw),
VMW_CMD_DEF(SVGA_3D_CMD_SETSCISSORRECT, &vmw_cmd_cid_check),
VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_QUERY, &vmw_cmd_cid_check),
VMW_CMD_DEF(SVGA_3D_CMD_END_QUERY, &vmw_cmd_cid_check),
@@ -291,6 +391,7 @@ static int vmw_cmd_check(struct vmw_private *dev_priv,
void *buf, uint32_t *size)
{
uint32_t cmd_id;
+ uint32_t size_remaining = *size;
SVGA3dCmdHeader *header = (SVGA3dCmdHeader *) buf;
int ret;
@@ -304,6 +405,9 @@ static int vmw_cmd_check(struct vmw_private *dev_priv,
*size = le32_to_cpu(header->size) + sizeof(SVGA3dCmdHeader);
cmd_id -= SVGA_3D_CMD_BASE;
+ if (unlikely(*size > size_remaining))
+ goto out_err;
+
if (unlikely(cmd_id >= SVGA_3D_CMD_MAX - SVGA_3D_CMD_BASE))
goto out_err;
@@ -326,6 +430,7 @@ static int vmw_cmd_check_all(struct vmw_private *dev_priv,
int ret;
while (cur_size > 0) {
+ size = cur_size;
ret = vmw_cmd_check(dev_priv, sw_context, buf, &size);
if (unlikely(ret != 0))
return ret;
@@ -386,7 +491,7 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
return 0;
ret = vmw_gmr_bind(dev_priv, bo);
- if (likely(ret == 0 || ret == -ERESTART))
+ if (likely(ret == 0 || ret == -ERESTARTSYS))
return ret;
@@ -429,7 +534,7 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex);
if (unlikely(ret != 0)) {
- ret = -ERESTART;
+ ret = -ERESTARTSYS;
goto out_no_cmd_mutex;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
index 76b0693e245..01feb48af33 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
@@ -191,7 +191,7 @@ static int vmw_fifo_wait_noirq(struct vmw_private *dev_priv,
}
schedule_timeout(1);
if (interruptible && signal_pending(current)) {
- ret = -ERESTART;
+ ret = -ERESTARTSYS;
break;
}
}
@@ -237,9 +237,7 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv,
(dev_priv->fifo_queue,
!vmw_fifo_is_full(dev_priv, bytes), timeout);
- if (unlikely(ret == -ERESTARTSYS))
- ret = -ERESTART;
- else if (unlikely(ret == 0))
+ if (unlikely(ret == 0))
ret = -EBUSY;
else if (likely(ret > 0))
ret = 0;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
index 9e0f0306eed..d40086fc864 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
@@ -155,7 +155,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
TASK_UNINTERRUPTIBLE);
}
if (interruptible && signal_pending(current)) {
- ret = -ERESTART;
+ ret = -ERESTARTSYS;
break;
}
}
@@ -218,9 +218,7 @@ int vmw_wait_fence(struct vmw_private *dev_priv,
vmw_fence_signaled(dev_priv, sequence),
timeout);
- if (unlikely(ret == -ERESTARTSYS))
- ret = -ERESTART;
- else if (unlikely(ret == 0))
+ if (unlikely(ret == 0))
ret = -EBUSY;
else if (likely(ret > 0))
ret = 0;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index e9403be446f..b1af76e371c 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -106,8 +106,8 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
int ret;
if (handle) {
- ret = vmw_user_surface_lookup(dev_priv, tfile,
- handle, &surface);
+ ret = vmw_user_surface_lookup_handle(dev_priv, tfile,
+ handle, &surface);
if (!ret) {
if (!surface->snooper.image) {
DRM_ERROR("surface not suitable for cursor\n");
@@ -704,8 +704,8 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
struct vmw_dma_buffer *bo = NULL;
int ret;
- ret = vmw_user_surface_lookup(dev_priv, tfile,
- mode_cmd->handle, &surface);
+ ret = vmw_user_surface_lookup_handle(dev_priv, tfile,
+ mode_cmd->handle, &surface);
if (ret)
goto try_dmabuf;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index a1ceed0c8e0..c012d5927f6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -488,28 +488,44 @@ static void vmw_user_surface_free(struct vmw_resource *res)
kfree(user_srf);
}
-int vmw_user_surface_lookup(struct vmw_private *dev_priv,
- struct ttm_object_file *tfile,
- int sid, struct vmw_surface **out)
+int vmw_user_surface_lookup_handle(struct vmw_private *dev_priv,
+ struct ttm_object_file *tfile,
+ uint32_t handle, struct vmw_surface **out)
{
struct vmw_resource *res;
struct vmw_surface *srf;
struct vmw_user_surface *user_srf;
+ struct ttm_base_object *base;
+ int ret = -EINVAL;
- res = vmw_resource_lookup(dev_priv, &dev_priv->surface_idr, sid);
- if (unlikely(res == NULL))
+ base = ttm_base_object_lookup(tfile, handle);
+ if (unlikely(base == NULL))
return -EINVAL;
- if (res->res_free != &vmw_user_surface_free)
- return -EINVAL;
+ if (unlikely(base->object_type != VMW_RES_SURFACE))
+ goto out_bad_resource;
- srf = container_of(res, struct vmw_surface, res);
- user_srf = container_of(srf, struct vmw_user_surface, srf);
- if (user_srf->base.tfile != tfile && !user_srf->base.shareable)
- return -EPERM;
+ user_srf = container_of(base, struct vmw_user_surface, base);
+ srf = &user_srf->srf;
+ res = &srf->res;
+
+ read_lock(&dev_priv->resource_lock);
+
+ if (!res->avail || res->res_free != &vmw_user_surface_free) {
+ read_unlock(&dev_priv->resource_lock);
+ goto out_bad_resource;
+ }
+
+ kref_get(&res->kref);
+ read_unlock(&dev_priv->resource_lock);
*out = srf;
- return 0;
+ ret = 0;
+
+out_bad_resource:
+ ttm_base_object_unref(&base);
+
+ return ret;
}
static void vmw_user_surface_base_release(struct ttm_base_object **p_base)
@@ -526,35 +542,10 @@ static void vmw_user_surface_base_release(struct ttm_base_object **p_base)
int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- struct vmw_private *dev_priv = vmw_priv(dev);
- struct vmw_resource *res;
- struct vmw_surface *srf;
- struct vmw_user_surface *user_srf;
struct drm_vmw_surface_arg *arg = (struct drm_vmw_surface_arg *)data;
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
- int ret = 0;
-
- res = vmw_resource_lookup(dev_priv, &dev_priv->surface_idr, arg->sid);
- if (unlikely(res == NULL))
- return -EINVAL;
-
- if (res->res_free != &vmw_user_surface_free) {
- ret = -EINVAL;
- goto out;
- }
- srf = container_of(res, struct vmw_surface, res);
- user_srf = container_of(srf, struct vmw_user_surface, srf);
- if (user_srf->base.tfile != tfile && !user_srf->base.shareable) {
- ret = -EPERM;
- goto out;
- }
-
- ttm_ref_object_base_unref(tfile, user_srf->base.hash.key,
- TTM_REF_USAGE);
-out:
- vmw_resource_unreference(&res);
- return ret;
+ return ttm_ref_object_base_unref(tfile, arg->sid, TTM_REF_USAGE);
}
int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
@@ -649,7 +640,10 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
}
srf->snooper.crtc = NULL;
- rep->sid = res->id;
+ rep->sid = user_srf->base.hash.key;
+ if (rep->sid == SVGA3D_INVALID_ID)
+ DRM_ERROR("Created bad Surface ID.\n");
+
vmw_resource_unreference(&res);
return 0;
out_err1:
@@ -662,39 +656,33 @@ out_err0:
int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- struct vmw_private *dev_priv = vmw_priv(dev);
union drm_vmw_surface_reference_arg *arg =
(union drm_vmw_surface_reference_arg *)data;
struct drm_vmw_surface_arg *req = &arg->req;
struct drm_vmw_surface_create_req *rep = &arg->rep;
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
- struct vmw_resource *res;
struct vmw_surface *srf;
struct vmw_user_surface *user_srf;
struct drm_vmw_size __user *user_sizes;
- int ret;
+ struct ttm_base_object *base;
+ int ret = -EINVAL;
- res = vmw_resource_lookup(dev_priv, &dev_priv->surface_idr, req->sid);
- if (unlikely(res == NULL))
+ base = ttm_base_object_lookup(tfile, req->sid);
+ if (unlikely(base == NULL)) {
+ DRM_ERROR("Could not find surface to reference.\n");
return -EINVAL;
-
- if (res->res_free != &vmw_user_surface_free) {
- ret = -EINVAL;
- goto out;
}
- srf = container_of(res, struct vmw_surface, res);
- user_srf = container_of(srf, struct vmw_user_surface, srf);
- if (user_srf->base.tfile != tfile && !user_srf->base.shareable) {
- DRM_ERROR("Tried to reference none shareable surface\n");
- ret = -EPERM;
- goto out;
- }
+ if (unlikely(base->object_type != VMW_RES_SURFACE))
+ goto out_bad_resource;
+
+ user_srf = container_of(base, struct vmw_user_surface, base);
+ srf = &user_srf->srf;
ret = ttm_ref_object_add(tfile, &user_srf->base, TTM_REF_USAGE, NULL);
if (unlikely(ret != 0)) {
DRM_ERROR("Could not add a reference to a surface.\n");
- goto out;
+ goto out_no_reference;
}
rep->flags = srf->flags;
@@ -706,40 +694,43 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
if (user_sizes)
ret = copy_to_user(user_sizes, srf->sizes,
srf->num_sizes * sizeof(*srf->sizes));
- if (unlikely(ret != 0)) {
+ if (unlikely(ret != 0))
DRM_ERROR("copy_to_user failed %p %u\n",
user_sizes, srf->num_sizes);
- /**
- * FIXME: Unreference surface here?
- */
- goto out;
- }
-out:
- vmw_resource_unreference(&res);
+out_bad_resource:
+out_no_reference:
+ ttm_base_object_unref(&base);
+
return ret;
}
int vmw_surface_check(struct vmw_private *dev_priv,
struct ttm_object_file *tfile,
- int id)
+ uint32_t handle, int *id)
{
- struct vmw_resource *res;
- int ret = 0;
+ struct ttm_base_object *base;
+ struct vmw_user_surface *user_srf;
- read_lock(&dev_priv->resource_lock);
- res = idr_find(&dev_priv->surface_idr, id);
- if (res && res->avail) {
- struct vmw_surface *srf =
- container_of(res, struct vmw_surface, res);
- struct vmw_user_surface *usrf =
- container_of(srf, struct vmw_user_surface, srf);
+ int ret = -EPERM;
- if (usrf->base.tfile != tfile && !usrf->base.shareable)
- ret = -EPERM;
- } else
- ret = -EINVAL;
- read_unlock(&dev_priv->resource_lock);
+ base = ttm_base_object_lookup(tfile, handle);
+ if (unlikely(base == NULL))
+ return -EINVAL;
+
+ if (unlikely(base->object_type != VMW_RES_SURFACE))
+ goto out_bad_surface;
+ user_srf = container_of(base, struct vmw_user_surface, base);
+ *id = user_srf->srf.res.id;
+ ret = 0;
+
+out_bad_surface:
+ /**
+ * FIXME: May deadlock here when called from the
+ * command parsing code.
+ */
+
+ ttm_base_object_unref(&base);
return ret;
}
diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h
index 27ae750ca87..bf31592eaf7 100644
--- a/drivers/hid/hid-lg.h
+++ b/drivers/hid/hid-lg.h
@@ -1,8 +1,6 @@
#ifndef __HID_LG_H
#define __HID_LG_H
-#include <linux/autoconf.h>
-
#ifdef CONFIG_LOGITECH_FF
int lgff_init(struct hid_device *hdev);
#else
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 95ccbe377f9..46c3c566307 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -228,6 +228,18 @@ config SENSORS_K8TEMP
This driver can also be built as a module. If so, the module
will be called k8temp.
+config SENSORS_K10TEMP
+ tristate "AMD Phenom/Sempron/Turion/Opteron temperature sensor"
+ depends on X86 && PCI
+ help
+ If you say yes here you get support for the temperature
+ sensor(s) inside your CPU. Supported are later revisions of
+ the AMD Family 10h and all revisions of the AMD Family 11h
+ microarchitectures.
+
+ This driver can also be built as a module. If so, the module
+ will be called k10temp.
+
config SENSORS_AMS
tristate "Apple Motion Sensor driver"
depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL
@@ -810,6 +822,14 @@ config SENSORS_TMP421
This driver can also be built as a module. If so, the module
will be called tmp421.
+config SENSORS_VIA_CPUTEMP
+ tristate "VIA CPU temperature sensor"
+ depends on X86
+ help
+ If you say yes here you get support for the temperature
+ sensor inside your CPU. Supported are all known variants of
+ the VIA C7 and Nano.
+
config SENSORS_VIA686A
tristate "VIA686A"
depends on PCI
@@ -998,6 +1018,23 @@ config SENSORS_LIS3_SPI
will be called lis3lv02d and a specific module for the SPI transport
is called lis3lv02d_spi.
+config SENSORS_LIS3_I2C
+ tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (I2C)"
+ depends on I2C && INPUT
+ select INPUT_POLLDEV
+ default n
+ help
+ This driver provides support for the LIS3LV02Dx accelerometer connected
+ via I2C. The accelerometer data is readable via
+ /sys/devices/platform/lis3lv02d.
+
+ This driver also provides an absolute input class device, allowing
+ the device to act as a pinball machine-esque joystick.
+
+ This driver can also be built as modules. If so, the core module
+ will be called lis3lv02d and a specific module for the I2C transport
+ is called lis3lv02d_i2c.
+
config SENSORS_APPLESMC
tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
depends on INPUT && X86
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 33c2ee10528..450c8e89427 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -53,8 +53,10 @@ obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
obj-$(CONFIG_SENSORS_IT87) += it87.o
obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o
+obj-$(CONFIG_SENSORS_K10TEMP) += k10temp.o
obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o
obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d.o lis3lv02d_spi.o
+obj-$(CONFIG_SENSORS_LIS3_I2C) += lis3lv02d.o lis3lv02d_i2c.o
obj-$(CONFIG_SENSORS_LM63) += lm63.o
obj-$(CONFIG_SENSORS_LM70) += lm70.o
obj-$(CONFIG_SENSORS_LM73) += lm73.o
@@ -87,6 +89,7 @@ obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
obj-$(CONFIG_SENSORS_THMC50) += thmc50.o
obj-$(CONFIG_SENSORS_TMP401) += tmp401.o
obj-$(CONFIG_SENSORS_TMP421) += tmp421.o
+obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
obj-$(CONFIG_SENSORS_VT1211) += vt1211.o
obj-$(CONFIG_SENSORS_VT8231) += vt8231.o
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
new file mode 100644
index 00000000000..d8a26d16d94
--- /dev/null
+++ b/drivers/hwmon/k10temp.c
@@ -0,0 +1,197 @@
+/*
+ * k10temp.c - AMD Family 10h/11h processor hardware monitoring
+ *
+ * Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ * This driver is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This driver 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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <asm/processor.h>
+
+MODULE_DESCRIPTION("AMD Family 10h/11h CPU core temperature monitor");
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_LICENSE("GPL");
+
+static bool force;
+module_param(force, bool, 0444);
+MODULE_PARM_DESC(force, "force loading on processors with erratum 319");
+
+#define REG_HARDWARE_THERMAL_CONTROL 0x64
+#define HTC_ENABLE 0x00000001
+
+#define REG_REPORTED_TEMPERATURE 0xa4
+
+#define REG_NORTHBRIDGE_CAPABILITIES 0xe8
+#define NB_CAP_HTC 0x00000400
+
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 regval;
+
+ pci_read_config_dword(to_pci_dev(dev),
+ REG_REPORTED_TEMPERATURE, &regval);
+ return sprintf(buf, "%u\n", (regval >> 21) * 125);
+}
+
+static ssize_t show_temp_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", 70 * 1000);
+}
+
+static ssize_t show_temp_crit(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int show_hyst = attr->index;
+ u32 regval;
+ int value;
+
+ pci_read_config_dword(to_pci_dev(dev),
+ REG_HARDWARE_THERMAL_CONTROL, &regval);
+ value = ((regval >> 16) & 0x7f) * 500 + 52000;
+ if (show_hyst)
+ value -= ((regval >> 24) & 0xf) * 500;
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "k10temp\n");
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
+static DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max, NULL);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit, NULL, 1);
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static bool __devinit has_erratum_319(void)
+{
+ /*
+ * Erratum 319: The thermal sensor of older Family 10h processors
+ * (B steppings) may be unreliable.
+ */
+ return boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model <= 2;
+}
+
+static int __devinit k10temp_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct device *hwmon_dev;
+ u32 reg_caps, reg_htc;
+ int err;
+
+ if (has_erratum_319() && !force) {
+ dev_err(&pdev->dev,
+ "unreliable CPU thermal sensor; monitoring disabled\n");
+ err = -ENODEV;
+ goto exit;
+ }
+
+ err = device_create_file(&pdev->dev, &dev_attr_temp1_input);
+ if (err)
+ goto exit;
+ err = device_create_file(&pdev->dev, &dev_attr_temp1_max);
+ if (err)
+ goto exit_remove;
+
+ pci_read_config_dword(pdev, REG_NORTHBRIDGE_CAPABILITIES, &reg_caps);
+ pci_read_config_dword(pdev, REG_HARDWARE_THERMAL_CONTROL, &reg_htc);
+ if ((reg_caps & NB_CAP_HTC) && (reg_htc & HTC_ENABLE)) {
+ err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_temp1_crit.dev_attr);
+ if (err)
+ goto exit_remove;
+ err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_temp1_crit_hyst.dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+
+ err = device_create_file(&pdev->dev, &dev_attr_name);
+ if (err)
+ goto exit_remove;
+
+ hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(hwmon_dev)) {
+ err = PTR_ERR(hwmon_dev);
+ goto exit_remove;
+ }
+ dev_set_drvdata(&pdev->dev, hwmon_dev);
+
+ if (has_erratum_319() && force)
+ dev_warn(&pdev->dev,
+ "unreliable CPU thermal sensor; check erratum 319\n");
+ return 0;
+
+exit_remove:
+ device_remove_file(&pdev->dev, &dev_attr_name);
+ device_remove_file(&pdev->dev, &dev_attr_temp1_input);
+ device_remove_file(&pdev->dev, &dev_attr_temp1_max);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp1_crit.dev_attr);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp1_crit_hyst.dev_attr);
+exit:
+ return err;
+}
+
+static void __devexit k10temp_remove(struct pci_dev *pdev)
+{
+ hwmon_device_unregister(dev_get_drvdata(&pdev->dev));
+ device_remove_file(&pdev->dev, &dev_attr_name);
+ device_remove_file(&pdev->dev, &dev_attr_temp1_input);
+ device_remove_file(&pdev->dev, &dev_attr_temp1_max);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp1_crit.dev_attr);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp1_crit_hyst.dev_attr);
+ dev_set_drvdata(&pdev->dev, NULL);
+}
+
+static struct pci_device_id k10temp_id_table[] = {
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) },
+ {}
+};
+MODULE_DEVICE_TABLE(pci, k10temp_id_table);
+
+static struct pci_driver k10temp_driver = {
+ .name = "k10temp",
+ .id_table = k10temp_id_table,
+ .probe = k10temp_probe,
+ .remove = __devexit_p(k10temp_remove),
+};
+
+static int __init k10temp_init(void)
+{
+ return pci_register_driver(&k10temp_driver);
+}
+
+static void __exit k10temp_exit(void)
+{
+ pci_unregister_driver(&k10temp_driver);
+}
+
+module_init(k10temp_init)
+module_exit(k10temp_exit)
diff --git a/drivers/hwmon/lis3lv02d_i2c.c b/drivers/hwmon/lis3lv02d_i2c.c
new file mode 100644
index 00000000000..dc1f5402c1d
--- /dev/null
+++ b/drivers/hwmon/lis3lv02d_i2c.c
@@ -0,0 +1,183 @@
+/*
+ * drivers/hwmon/lis3lv02d_i2c.c
+ *
+ * Implements I2C interface for lis3lv02d (STMicroelectronics) accelerometer.
+ * Driver is based on corresponding SPI driver written by Daniel Mack
+ * (lis3lv02d_spi.c (C) 2009 Daniel Mack <daniel@caiaq.de> ).
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include "lis3lv02d.h"
+
+#define DRV_NAME "lis3lv02d_i2c"
+
+static inline s32 lis3_i2c_write(struct lis3lv02d *lis3, int reg, u8 value)
+{
+ struct i2c_client *c = lis3->bus_priv;
+ return i2c_smbus_write_byte_data(c, reg, value);
+}
+
+static inline s32 lis3_i2c_read(struct lis3lv02d *lis3, int reg, u8 *v)
+{
+ struct i2c_client *c = lis3->bus_priv;
+ *v = i2c_smbus_read_byte_data(c, reg);
+ return 0;
+}
+
+static int lis3_i2c_init(struct lis3lv02d *lis3)
+{
+ u8 reg;
+ int ret;
+
+ /* power up the device */
+ ret = lis3->read(lis3, CTRL_REG1, &reg);
+ if (ret < 0)
+ return ret;
+
+ reg |= CTRL1_PD0;
+ return lis3->write(lis3, CTRL_REG1, reg);
+}
+
+/* Default axis mapping but it can be overwritten by platform data */
+static struct axis_conversion lis3lv02d_axis_map = { LIS3_DEV_X,
+ LIS3_DEV_Y,
+ LIS3_DEV_Z };
+
+static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
+
+ if (pdata) {
+ if (pdata->axis_x)
+ lis3lv02d_axis_map.x = pdata->axis_x;
+
+ if (pdata->axis_y)
+ lis3lv02d_axis_map.y = pdata->axis_y;
+
+ if (pdata->axis_z)
+ lis3lv02d_axis_map.z = pdata->axis_z;
+
+ if (pdata->setup_resources)
+ ret = pdata->setup_resources();
+
+ if (ret)
+ goto fail;
+ }
+
+ lis3_dev.pdata = pdata;
+ lis3_dev.bus_priv = client;
+ lis3_dev.init = lis3_i2c_init;
+ lis3_dev.read = lis3_i2c_read;
+ lis3_dev.write = lis3_i2c_write;
+ lis3_dev.irq = client->irq;
+ lis3_dev.ac = lis3lv02d_axis_map;
+
+ i2c_set_clientdata(client, &lis3_dev);
+ ret = lis3lv02d_init_device(&lis3_dev);
+fail:
+ return ret;
+}
+
+static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client)
+{
+ struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+ struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
+
+ if (pdata && pdata->release_resources)
+ pdata->release_resources();
+
+ lis3lv02d_joystick_disable();
+ lis3lv02d_poweroff(lis3);
+
+ return lis3lv02d_remove_fs(&lis3_dev);
+}
+
+#ifdef CONFIG_PM
+static int lis3lv02d_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+
+ if (!lis3->pdata->wakeup_flags)
+ lis3lv02d_poweroff(lis3);
+ return 0;
+}
+
+static int lis3lv02d_i2c_resume(struct i2c_client *client)
+{
+ struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+
+ if (!lis3->pdata->wakeup_flags)
+ lis3lv02d_poweron(lis3);
+ return 0;
+}
+
+static void lis3lv02d_i2c_shutdown(struct i2c_client *client)
+{
+ lis3lv02d_i2c_suspend(client, PMSG_SUSPEND);
+}
+#else
+#define lis3lv02d_i2c_suspend NULL
+#define lis3lv02d_i2c_resume NULL
+#define lis3lv02d_i2c_shutdown NULL
+#endif
+
+static const struct i2c_device_id lis3lv02d_id[] = {
+ {"lis3lv02d", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lis3lv02d_id);
+
+static struct i2c_driver lis3lv02d_i2c_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .suspend = lis3lv02d_i2c_suspend,
+ .shutdown = lis3lv02d_i2c_shutdown,
+ .resume = lis3lv02d_i2c_resume,
+ .probe = lis3lv02d_i2c_probe,
+ .remove = __devexit_p(lis3lv02d_i2c_remove),
+ .id_table = lis3lv02d_id,
+};
+
+static int __init lis3lv02d_init(void)
+{
+ return i2c_add_driver(&lis3lv02d_i2c_driver);
+}
+
+static void __exit lis3lv02d_exit(void)
+{
+ i2c_del_driver(&lis3lv02d_i2c_driver);
+}
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("lis3lv02d I2C interface");
+MODULE_LICENSE("GPL");
+
+module_init(lis3lv02d_init);
+module_exit(lis3lv02d_exit);
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
index ebe38b680ee..864a371f6eb 100644
--- a/drivers/hwmon/sht15.c
+++ b/drivers/hwmon/sht15.c
@@ -305,7 +305,7 @@ static inline int sht15_calc_temp(struct sht15_data *data)
int d1 = 0;
int i;
- for (i = 1; i < ARRAY_SIZE(temppoints) - 1; i++)
+ for (i = 1; i < ARRAY_SIZE(temppoints); i++)
/* Find pointer to interpolate */
if (data->supply_uV > temppoints[i - 1].vdd) {
d1 = (data->supply_uV/1000 - temppoints[i - 1].vdd)
@@ -332,12 +332,12 @@ static inline int sht15_calc_humid(struct sht15_data *data)
const int c1 = -4;
const int c2 = 40500; /* x 10 ^ -6 */
- const int c3 = 2800; /* x10 ^ -9 */
+ const int c3 = -2800; /* x10 ^ -9 */
RHlinear = c1*1000
+ c2 * data->val_humid/1000
+ (data->val_humid * data->val_humid * c3)/1000000;
- return (temp - 25000) * (10000 + 800 * data->val_humid)
+ return (temp - 25000) * (10000 + 80 * data->val_humid)
/ 1000000 + RHlinear;
}
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index 8ad50fdba00..9ca97818bd4 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -136,11 +136,11 @@ struct smsc47m1_data {
struct smsc47m1_sio_data {
enum chips type;
+ u8 activate; /* Remember initial device state */
};
-static int smsc47m1_probe(struct platform_device *pdev);
-static int __devexit smsc47m1_remove(struct platform_device *pdev);
+static int __exit smsc47m1_remove(struct platform_device *pdev);
static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
int init);
@@ -160,8 +160,7 @@ static struct platform_driver smsc47m1_driver = {
.owner = THIS_MODULE,
.name = DRVNAME,
},
- .probe = smsc47m1_probe,
- .remove = __devexit_p(smsc47m1_remove),
+ .remove = __exit_p(smsc47m1_remove),
};
static ssize_t get_fan(struct device *dev, struct device_attribute
@@ -470,24 +469,126 @@ static int __init smsc47m1_find(unsigned short *addr,
superio_select();
*addr = (superio_inb(SUPERIO_REG_BASE) << 8)
| superio_inb(SUPERIO_REG_BASE + 1);
- val = superio_inb(SUPERIO_REG_ACT);
- if (*addr == 0 || (val & 0x01) == 0) {
- pr_info(DRVNAME ": Device is disabled, will not use\n");
+ if (*addr == 0) {
+ pr_info(DRVNAME ": Device address not set, will not use\n");
superio_exit();
return -ENODEV;
}
+ /* Enable only if address is set (needed at least on the
+ * Compaq Presario S4000NX) */
+ sio_data->activate = superio_inb(SUPERIO_REG_ACT);
+ if ((sio_data->activate & 0x01) == 0) {
+ pr_info(DRVNAME ": Enabling device\n");
+ superio_outb(SUPERIO_REG_ACT, sio_data->activate | 0x01);
+ }
+
superio_exit();
return 0;
}
-static int __devinit smsc47m1_probe(struct platform_device *pdev)
+/* Restore device to its initial state */
+static void __init smsc47m1_restore(const struct smsc47m1_sio_data *sio_data)
+{
+ if ((sio_data->activate & 0x01) == 0) {
+ superio_enter();
+ superio_select();
+
+ pr_info(DRVNAME ": Disabling device\n");
+ superio_outb(SUPERIO_REG_ACT, sio_data->activate);
+
+ superio_exit();
+ }
+}
+
+#define CHECK 1
+#define REQUEST 2
+#define RELEASE 3
+
+/*
+ * This function can be used to:
+ * - test for resource conflicts with ACPI
+ * - request the resources
+ * - release the resources
+ * We only allocate the I/O ports we really need, to minimize the risk of
+ * conflicts with ACPI or with other drivers.
+ */
+static int smsc47m1_handle_resources(unsigned short address, enum chips type,
+ int action, struct device *dev)
+{
+ static const u8 ports_m1[] = {
+ /* register, region length */
+ 0x04, 1,
+ 0x33, 4,
+ 0x56, 7,
+ };
+
+ static const u8 ports_m2[] = {
+ /* register, region length */
+ 0x04, 1,
+ 0x09, 1,
+ 0x2c, 2,
+ 0x35, 4,
+ 0x56, 7,
+ 0x69, 4,
+ };
+
+ int i, ports_size, err;
+ const u8 *ports;
+
+ switch (type) {
+ case smsc47m1:
+ default:
+ ports = ports_m1;
+ ports_size = ARRAY_SIZE(ports_m1);
+ break;
+ case smsc47m2:
+ ports = ports_m2;
+ ports_size = ARRAY_SIZE(ports_m2);
+ break;
+ }
+
+ for (i = 0; i + 1 < ports_size; i += 2) {
+ unsigned short start = address + ports[i];
+ unsigned short len = ports[i + 1];
+
+ switch (action) {
+ case CHECK:
+ /* Only check for conflicts */
+ err = acpi_check_region(start, len, DRVNAME);
+ if (err)
+ return err;
+ break;
+ case REQUEST:
+ /* Request the resources */
+ if (!request_region(start, len, DRVNAME)) {
+ dev_err(dev, "Region 0x%hx-0x%hx already in "
+ "use!\n", start, start + len);
+
+ /* Undo all requests */
+ for (i -= 2; i >= 0; i -= 2)
+ release_region(address + ports[i],
+ ports[i + 1]);
+ return -EBUSY;
+ }
+ break;
+ case RELEASE:
+ /* Release the resources */
+ release_region(start, len);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int __init smsc47m1_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct smsc47m1_sio_data *sio_data = dev->platform_data;
struct smsc47m1_data *data;
struct resource *res;
- int err = 0;
+ int err;
int fan1, fan2, fan3, pwm1, pwm2, pwm3;
static const char *names[] = {
@@ -496,12 +597,10 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
};
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (!request_region(res->start, SMSC_EXTENT, DRVNAME)) {
- dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
- (unsigned long)res->start,
- (unsigned long)res->end);
- return -EBUSY;
- }
+ err = smsc47m1_handle_resources(res->start, sio_data->type,
+ REQUEST, dev);
+ if (err < 0)
+ return err;
if (!(data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) {
err = -ENOMEM;
@@ -637,11 +736,11 @@ error_free:
platform_set_drvdata(pdev, NULL);
kfree(data);
error_release:
- release_region(res->start, SMSC_EXTENT);
+ smsc47m1_handle_resources(res->start, sio_data->type, RELEASE, dev);
return err;
}
-static int __devexit smsc47m1_remove(struct platform_device *pdev)
+static int __exit smsc47m1_remove(struct platform_device *pdev)
{
struct smsc47m1_data *data = platform_get_drvdata(pdev);
struct resource *res;
@@ -650,7 +749,7 @@ static int __devexit smsc47m1_remove(struct platform_device *pdev)
sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- release_region(res->start, SMSC_EXTENT);
+ smsc47m1_handle_resources(res->start, data->type, RELEASE, &pdev->dev);
platform_set_drvdata(pdev, NULL);
kfree(data);
@@ -717,7 +816,7 @@ static int __init smsc47m1_device_add(unsigned short address,
};
int err;
- err = acpi_check_resource_conflict(&res);
+ err = smsc47m1_handle_resources(address, sio_data->type, CHECK, NULL);
if (err)
goto exit;
@@ -766,27 +865,29 @@ static int __init sm_smsc47m1_init(void)
if (smsc47m1_find(&address, &sio_data))
return -ENODEV;
- err = platform_driver_register(&smsc47m1_driver);
+ /* Sets global pdev as a side effect */
+ err = smsc47m1_device_add(address, &sio_data);
if (err)
goto exit;
- /* Sets global pdev as a side effect */
- err = smsc47m1_device_add(address, &sio_data);
+ err = platform_driver_probe(&smsc47m1_driver, smsc47m1_probe);
if (err)
- goto exit_driver;
+ goto exit_device;
return 0;
-exit_driver:
- platform_driver_unregister(&smsc47m1_driver);
+exit_device:
+ platform_device_unregister(pdev);
+ smsc47m1_restore(&sio_data);
exit:
return err;
}
static void __exit sm_smsc47m1_exit(void)
{
- platform_device_unregister(pdev);
platform_driver_unregister(&smsc47m1_driver);
+ smsc47m1_restore(pdev->dev.platform_data);
+ platform_device_unregister(pdev);
}
MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c
new file mode 100644
index 00000000000..7442cf75485
--- /dev/null
+++ b/drivers/hwmon/via-cputemp.c
@@ -0,0 +1,356 @@
+/*
+ * via-cputemp.c - Driver for VIA CPU core temperature monitoring
+ * Copyright (C) 2009 VIA Technologies, Inc.
+ *
+ * based on existing coretemp.c, which is
+ *
+ * Copyright (C) 2007 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/sysfs.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/cpu.h>
+#include <asm/msr.h>
+#include <asm/processor.h>
+
+#define DRVNAME "via_cputemp"
+
+enum { SHOW_TEMP, SHOW_LABEL, SHOW_NAME } SHOW;
+
+/*
+ * Functions declaration
+ */
+
+struct via_cputemp_data {
+ struct device *hwmon_dev;
+ const char *name;
+ u32 id;
+ u32 msr;
+};
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ int ret;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct via_cputemp_data *data = dev_get_drvdata(dev);
+
+ if (attr->index == SHOW_NAME)
+ ret = sprintf(buf, "%s\n", data->name);
+ else /* show label */
+ ret = sprintf(buf, "Core %d\n", data->id);
+ return ret;
+}
+
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct via_cputemp_data *data = dev_get_drvdata(dev);
+ u32 eax, edx;
+ int err;
+
+ err = rdmsr_safe_on_cpu(data->id, data->msr, &eax, &edx);
+ if (err)
+ return -EAGAIN;
+
+ return sprintf(buf, "%lu\n", ((unsigned long)eax & 0xffffff) * 1000);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL,
+ SHOW_TEMP);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL);
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME);
+
+static struct attribute *via_cputemp_attributes[] = {
+ &sensor_dev_attr_name.dev_attr.attr,
+ &sensor_dev_attr_temp1_label.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group via_cputemp_group = {
+ .attrs = via_cputemp_attributes,
+};
+
+static int __devinit via_cputemp_probe(struct platform_device *pdev)
+{
+ struct via_cputemp_data *data;
+ struct cpuinfo_x86 *c = &cpu_data(pdev->id);
+ int err;
+ u32 eax, edx;
+
+ data = kzalloc(sizeof(struct via_cputemp_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ dev_err(&pdev->dev, "Out of memory\n");
+ goto exit;
+ }
+
+ data->id = pdev->id;
+ data->name = "via_cputemp";
+
+ switch (c->x86_model) {
+ case 0xA:
+ /* C7 A */
+ case 0xD:
+ /* C7 D */
+ data->msr = 0x1169;
+ break;
+ case 0xF:
+ /* Nano */
+ data->msr = 0x1423;
+ break;
+ default:
+ err = -ENODEV;
+ goto exit_free;
+ }
+
+ /* test if we can access the TEMPERATURE MSR */
+ err = rdmsr_safe_on_cpu(data->id, data->msr, &eax, &edx);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Unable to access TEMPERATURE MSR, giving up\n");
+ goto exit_free;
+ }
+
+ platform_set_drvdata(pdev, data);
+
+ err = sysfs_create_group(&pdev->dev.kobj, &via_cputemp_group);
+ if (err)
+ goto exit_free;
+
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ dev_err(&pdev->dev, "Class registration failed (%d)\n",
+ err);
+ goto exit_remove;
+ }
+
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
+exit_free:
+ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+exit:
+ return err;
+}
+
+static int __devexit via_cputemp_remove(struct platform_device *pdev)
+{
+ struct via_cputemp_data *data = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
+ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+ return 0;
+}
+
+static struct platform_driver via_cputemp_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ },
+ .probe = via_cputemp_probe,
+ .remove = __devexit_p(via_cputemp_remove),
+};
+
+struct pdev_entry {
+ struct list_head list;
+ struct platform_device *pdev;
+ unsigned int cpu;
+};
+
+static LIST_HEAD(pdev_list);
+static DEFINE_MUTEX(pdev_list_mutex);
+
+static int __cpuinit via_cputemp_device_add(unsigned int cpu)
+{
+ int err;
+ struct platform_device *pdev;
+ struct pdev_entry *pdev_entry;
+
+ pdev = platform_device_alloc(DRVNAME, cpu);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ goto exit;
+ }
+
+ pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL);
+ if (!pdev_entry) {
+ err = -ENOMEM;
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto exit_device_free;
+ }
+
+ pdev_entry->pdev = pdev;
+ pdev_entry->cpu = cpu;
+ mutex_lock(&pdev_list_mutex);
+ list_add_tail(&pdev_entry->list, &pdev_list);
+ mutex_unlock(&pdev_list_mutex);
+
+ return 0;
+
+exit_device_free:
+ kfree(pdev_entry);
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static void via_cputemp_device_remove(unsigned int cpu)
+{
+ struct pdev_entry *p, *n;
+ mutex_lock(&pdev_list_mutex);
+ list_for_each_entry_safe(p, n, &pdev_list, list) {
+ if (p->cpu == cpu) {
+ platform_device_unregister(p->pdev);
+ list_del(&p->list);
+ kfree(p);
+ }
+ }
+ mutex_unlock(&pdev_list_mutex);
+}
+
+static int __cpuinit via_cputemp_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long) hcpu;
+
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_DOWN_FAILED:
+ via_cputemp_device_add(cpu);
+ break;
+ case CPU_DOWN_PREPARE:
+ via_cputemp_device_remove(cpu);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block via_cputemp_cpu_notifier __refdata = {
+ .notifier_call = via_cputemp_cpu_callback,
+};
+#endif /* !CONFIG_HOTPLUG_CPU */
+
+static int __init via_cputemp_init(void)
+{
+ int i, err;
+ struct pdev_entry *p, *n;
+
+ if (cpu_data(0).x86_vendor != X86_VENDOR_CENTAUR) {
+ printk(KERN_DEBUG DRVNAME ": Not a VIA CPU\n");
+ err = -ENODEV;
+ goto exit;
+ }
+
+ err = platform_driver_register(&via_cputemp_driver);
+ if (err)
+ goto exit;
+
+ for_each_online_cpu(i) {
+ struct cpuinfo_x86 *c = &cpu_data(i);
+
+ if (c->x86 != 6)
+ continue;
+
+ if (c->x86_model < 0x0a)
+ continue;
+
+ if (c->x86_model > 0x0f) {
+ printk(KERN_WARNING DRVNAME ": Unknown CPU "
+ "model 0x%x\n", c->x86_model);
+ continue;
+ }
+
+ err = via_cputemp_device_add(i);
+ if (err)
+ goto exit_devices_unreg;
+ }
+ if (list_empty(&pdev_list)) {
+ err = -ENODEV;
+ goto exit_driver_unreg;
+ }
+
+#ifdef CONFIG_HOTPLUG_CPU
+ register_hotcpu_notifier(&via_cputemp_cpu_notifier);
+#endif
+ return 0;
+
+exit_devices_unreg:
+ mutex_lock(&pdev_list_mutex);
+ list_for_each_entry_safe(p, n, &pdev_list, list) {
+ platform_device_unregister(p->pdev);
+ list_del(&p->list);
+ kfree(p);
+ }
+ mutex_unlock(&pdev_list_mutex);
+exit_driver_unreg:
+ platform_driver_unregister(&via_cputemp_driver);
+exit:
+ return err;
+}
+
+static void __exit via_cputemp_exit(void)
+{
+ struct pdev_entry *p, *n;
+#ifdef CONFIG_HOTPLUG_CPU
+ unregister_hotcpu_notifier(&via_cputemp_cpu_notifier);
+#endif
+ mutex_lock(&pdev_list_mutex);
+ list_for_each_entry_safe(p, n, &pdev_list, list) {
+ platform_device_unregister(p->pdev);
+ list_del(&p->list);
+ kfree(p);
+ }
+ mutex_unlock(&pdev_list_mutex);
+ platform_driver_unregister(&via_cputemp_driver);
+}
+
+MODULE_AUTHOR("Harald Welte <HaraldWelte@viatech.com>");
+MODULE_DESCRIPTION("VIA CPU temperature monitor");
+MODULE_LICENSE("GPL");
+
+module_init(via_cputemp_init)
+module_exit(via_cputemp_exit)
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index b257c722373..38e28052307 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -1135,6 +1135,7 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
"W83687THF",
};
+ sio_data->sioaddr = sioaddr;
superio_enter(sio_data);
val = force_id ? force_id : superio_inb(sio_data, DEVID);
switch (val) {
@@ -1177,7 +1178,6 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
}
err = 0;
- sio_data->sioaddr = sioaddr;
pr_info(DRVNAME ": Found %s chip at %#x\n",
names[sio_data->type], *addr);
diff --git a/drivers/idle/i7300_idle.c b/drivers/idle/i7300_idle.c
index 1f20a042a4f..dd253002cd5 100644
--- a/drivers/idle/i7300_idle.c
+++ b/drivers/idle/i7300_idle.c
@@ -81,7 +81,7 @@ static u8 i7300_idle_thrtctl_saved;
static u8 i7300_idle_thrtlow_saved;
static u32 i7300_idle_mc_saved;
-static cpumask_t idle_cpumask;
+static cpumask_var_t idle_cpumask;
static ktime_t start_ktime;
static unsigned long avg_idle_us;
@@ -459,9 +459,9 @@ static int i7300_idle_notifier(struct notifier_block *nb, unsigned long val,
spin_lock_irqsave(&i7300_idle_lock, flags);
if (val == IDLE_START) {
- cpu_set(smp_processor_id(), idle_cpumask);
+ cpumask_set_cpu(smp_processor_id(), idle_cpumask);
- if (cpus_weight(idle_cpumask) != num_online_cpus())
+ if (cpumask_weight(idle_cpumask) != num_online_cpus())
goto end;
now_ktime = ktime_get();
@@ -478,8 +478,8 @@ static int i7300_idle_notifier(struct notifier_block *nb, unsigned long val,
i7300_idle_ioat_start();
} else if (val == IDLE_END) {
- cpu_clear(smp_processor_id(), idle_cpumask);
- if (cpus_weight(idle_cpumask) == (num_online_cpus() - 1)) {
+ cpumask_clear_cpu(smp_processor_id(), idle_cpumask);
+ if (cpumask_weight(idle_cpumask) == (num_online_cpus() - 1)) {
/* First CPU coming out of idle */
u64 idle_duration_us;
@@ -553,7 +553,6 @@ struct debugfs_file_info {
static int __init i7300_idle_init(void)
{
spin_lock_init(&i7300_idle_lock);
- cpus_clear(idle_cpumask);
total_us = 0;
if (i7300_idle_platform_probe(&fbd_dev, &ioat_dev, forceload))
@@ -565,6 +564,9 @@ static int __init i7300_idle_init(void)
if (i7300_idle_ioat_init())
return -ENODEV;
+ if (!zalloc_cpumask_var(&idle_cpumask, GFP_KERNEL))
+ return -ENOMEM;
+
debugfs_dir = debugfs_create_dir("i7300_idle", NULL);
if (debugfs_dir) {
int i = 0;
@@ -589,6 +591,7 @@ static int __init i7300_idle_init(void)
static void __exit i7300_idle_exit(void)
{
idle_notifier_unregister(&i7300_idle_nb);
+ free_cpumask_var(idle_cpumask);
if (debugfs_dir) {
int i = 0;
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h
index bfd03bf8be5..f3d440cc68f 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h
@@ -34,6 +34,7 @@
#include <linux/list.h>
#include <linux/mutex.h>
+#include <linux/kfifo.h>
#include "t3_cpl.h"
#include "t3cdev.h"
@@ -75,13 +76,13 @@ struct cxio_hal_ctrl_qp {
};
struct cxio_hal_resource {
- struct kfifo *tpt_fifo;
+ struct kfifo tpt_fifo;
spinlock_t tpt_fifo_lock;
- struct kfifo *qpid_fifo;
+ struct kfifo qpid_fifo;
spinlock_t qpid_fifo_lock;
- struct kfifo *cqid_fifo;
+ struct kfifo cqid_fifo;
spinlock_t cqid_fifo_lock;
- struct kfifo *pdid_fifo;
+ struct kfifo pdid_fifo;
spinlock_t pdid_fifo_lock;
};
diff --git a/drivers/infiniband/hw/cxgb3/cxio_resource.c b/drivers/infiniband/hw/cxgb3/cxio_resource.c
index bd233c08765..31f9201b298 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_resource.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_resource.c
@@ -39,12 +39,12 @@
#include "cxio_resource.h"
#include "cxio_hal.h"
-static struct kfifo *rhdl_fifo;
+static struct kfifo rhdl_fifo;
static spinlock_t rhdl_fifo_lock;
#define RANDOM_SIZE 16
-static int __cxio_init_resource_fifo(struct kfifo **fifo,
+static int __cxio_init_resource_fifo(struct kfifo *fifo,
spinlock_t *fifo_lock,
u32 nr, u32 skip_low,
u32 skip_high,
@@ -55,12 +55,11 @@ static int __cxio_init_resource_fifo(struct kfifo **fifo,
u32 rarray[16];
spin_lock_init(fifo_lock);
- *fifo = kfifo_alloc(nr * sizeof(u32), GFP_KERNEL, fifo_lock);
- if (IS_ERR(*fifo))
+ if (kfifo_alloc(fifo, nr * sizeof(u32), GFP_KERNEL))
return -ENOMEM;
for (i = 0; i < skip_low + skip_high; i++)
- __kfifo_put(*fifo, (unsigned char *) &entry, sizeof(u32));
+ kfifo_in(fifo, (unsigned char *) &entry, sizeof(u32));
if (random) {
j = 0;
random_bytes = random32();
@@ -72,33 +71,35 @@ static int __cxio_init_resource_fifo(struct kfifo **fifo,
random_bytes = random32();
}
idx = (random_bytes >> (j * 2)) & 0xF;
- __kfifo_put(*fifo,
+ kfifo_in(fifo,
(unsigned char *) &rarray[idx],
sizeof(u32));
rarray[idx] = i;
j++;
}
for (i = 0; i < RANDOM_SIZE; i++)
- __kfifo_put(*fifo,
+ kfifo_in(fifo,
(unsigned char *) &rarray[i],
sizeof(u32));
} else
for (i = skip_low; i < nr - skip_high; i++)
- __kfifo_put(*fifo, (unsigned char *) &i, sizeof(u32));
+ kfifo_in(fifo, (unsigned char *) &i, sizeof(u32));
for (i = 0; i < skip_low + skip_high; i++)
- kfifo_get(*fifo, (unsigned char *) &entry, sizeof(u32));
+ if (kfifo_out_locked(fifo, (unsigned char *) &entry,
+ sizeof(u32), fifo_lock) != sizeof(u32))
+ break;
return 0;
}
-static int cxio_init_resource_fifo(struct kfifo **fifo, spinlock_t * fifo_lock,
+static int cxio_init_resource_fifo(struct kfifo *fifo, spinlock_t * fifo_lock,
u32 nr, u32 skip_low, u32 skip_high)
{
return (__cxio_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
skip_high, 0));
}
-static int cxio_init_resource_fifo_random(struct kfifo **fifo,
+static int cxio_init_resource_fifo_random(struct kfifo *fifo,
spinlock_t * fifo_lock,
u32 nr, u32 skip_low, u32 skip_high)
{
@@ -113,15 +114,13 @@ static int cxio_init_qpid_fifo(struct cxio_rdev *rdev_p)
spin_lock_init(&rdev_p->rscp->qpid_fifo_lock);
- rdev_p->rscp->qpid_fifo = kfifo_alloc(T3_MAX_NUM_QP * sizeof(u32),
- GFP_KERNEL,
- &rdev_p->rscp->qpid_fifo_lock);
- if (IS_ERR(rdev_p->rscp->qpid_fifo))
+ if (kfifo_alloc(&rdev_p->rscp->qpid_fifo, T3_MAX_NUM_QP * sizeof(u32),
+ GFP_KERNEL))
return -ENOMEM;
for (i = 16; i < T3_MAX_NUM_QP; i++)
if (!(i & rdev_p->qpmask))
- __kfifo_put(rdev_p->rscp->qpid_fifo,
+ kfifo_in(&rdev_p->rscp->qpid_fifo,
(unsigned char *) &i, sizeof(u32));
return 0;
}
@@ -134,7 +133,7 @@ int cxio_hal_init_rhdl_resource(u32 nr_rhdl)
void cxio_hal_destroy_rhdl_resource(void)
{
- kfifo_free(rhdl_fifo);
+ kfifo_free(&rhdl_fifo);
}
/* nr_* must be power of 2 */
@@ -167,11 +166,11 @@ int cxio_hal_init_resource(struct cxio_rdev *rdev_p,
goto pdid_err;
return 0;
pdid_err:
- kfifo_free(rscp->cqid_fifo);
+ kfifo_free(&rscp->cqid_fifo);
cqid_err:
- kfifo_free(rscp->qpid_fifo);
+ kfifo_free(&rscp->qpid_fifo);
qpid_err:
- kfifo_free(rscp->tpt_fifo);
+ kfifo_free(&rscp->tpt_fifo);
tpt_err:
return -ENOMEM;
}
@@ -179,33 +178,37 @@ tpt_err:
/*
* returns 0 if no resource available
*/
-static u32 cxio_hal_get_resource(struct kfifo *fifo)
+static u32 cxio_hal_get_resource(struct kfifo *fifo, spinlock_t * lock)
{
u32 entry;
- if (kfifo_get(fifo, (unsigned char *) &entry, sizeof(u32)))
+ if (kfifo_out_locked(fifo, (unsigned char *) &entry, sizeof(u32), lock))
return entry;
else
return 0; /* fifo emptry */
}
-static void cxio_hal_put_resource(struct kfifo *fifo, u32 entry)
+static void cxio_hal_put_resource(struct kfifo *fifo, spinlock_t * lock,
+ u32 entry)
{
- BUG_ON(kfifo_put(fifo, (unsigned char *) &entry, sizeof(u32)) == 0);
+ BUG_ON(
+ kfifo_in_locked(fifo, (unsigned char *) &entry, sizeof(u32), lock)
+ == 0);
}
u32 cxio_hal_get_stag(struct cxio_hal_resource *rscp)
{
- return cxio_hal_get_resource(rscp->tpt_fifo);
+ return cxio_hal_get_resource(&rscp->tpt_fifo, &rscp->tpt_fifo_lock);
}
void cxio_hal_put_stag(struct cxio_hal_resource *rscp, u32 stag)
{
- cxio_hal_put_resource(rscp->tpt_fifo, stag);
+ cxio_hal_put_resource(&rscp->tpt_fifo, &rscp->tpt_fifo_lock, stag);
}
u32 cxio_hal_get_qpid(struct cxio_hal_resource *rscp)
{
- u32 qpid = cxio_hal_get_resource(rscp->qpid_fifo);
+ u32 qpid = cxio_hal_get_resource(&rscp->qpid_fifo,
+ &rscp->qpid_fifo_lock);
PDBG("%s qpid 0x%x\n", __func__, qpid);
return qpid;
}
@@ -213,35 +216,35 @@ u32 cxio_hal_get_qpid(struct cxio_hal_resource *rscp)
void cxio_hal_put_qpid(struct cxio_hal_resource *rscp, u32 qpid)
{
PDBG("%s qpid 0x%x\n", __func__, qpid);
- cxio_hal_put_resource(rscp->qpid_fifo, qpid);
+ cxio_hal_put_resource(&rscp->qpid_fifo, &rscp->qpid_fifo_lock, qpid);
}
u32 cxio_hal_get_cqid(struct cxio_hal_resource *rscp)
{
- return cxio_hal_get_resource(rscp->cqid_fifo);
+ return cxio_hal_get_resource(&rscp->cqid_fifo, &rscp->cqid_fifo_lock);
}
void cxio_hal_put_cqid(struct cxio_hal_resource *rscp, u32 cqid)
{
- cxio_hal_put_resource(rscp->cqid_fifo, cqid);
+ cxio_hal_put_resource(&rscp->cqid_fifo, &rscp->cqid_fifo_lock, cqid);
}
u32 cxio_hal_get_pdid(struct cxio_hal_resource *rscp)
{
- return cxio_hal_get_resource(rscp->pdid_fifo);
+ return cxio_hal_get_resource(&rscp->pdid_fifo, &rscp->pdid_fifo_lock);
}
void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid)
{
- cxio_hal_put_resource(rscp->pdid_fifo, pdid);
+ cxio_hal_put_resource(&rscp->pdid_fifo, &rscp->pdid_fifo_lock, pdid);
}
void cxio_hal_destroy_resource(struct cxio_hal_resource *rscp)
{
- kfifo_free(rscp->tpt_fifo);
- kfifo_free(rscp->cqid_fifo);
- kfifo_free(rscp->qpid_fifo);
- kfifo_free(rscp->pdid_fifo);
+ kfifo_free(&rscp->tpt_fifo);
+ kfifo_free(&rscp->cqid_fifo);
+ kfifo_free(&rscp->qpid_fifo);
+ kfifo_free(&rscp->pdid_fifo);
kfree(rscp);
}
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c
index 7e5f30dbc0a..f1e8af54dff 100644
--- a/drivers/isdn/mISDN/l1oip_core.c
+++ b/drivers/isdn/mISDN/l1oip_core.c
@@ -661,7 +661,7 @@ l1oip_socket_thread(void *data)
size_t recvbuf_size = 1500;
int recvlen;
struct socket *socket = NULL;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
/* allocate buffer memory */
recvbuf = kmalloc(recvbuf_size, GFP_KERNEL);
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index e4f599f20e3..8a0e1ec95e4 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -229,6 +229,12 @@ config LEDS_PWM
help
This option enables support for pwm driven LEDs
+config LEDS_REGULATOR
+ tristate "REGULATOR driven LED support"
+ depends on LEDS_CLASS && REGULATOR
+ help
+ This option enables support for regulator driven LEDs.
+
config LEDS_BD2802
tristate "LED driver for BD2802 RGB LED"
depends on LEDS_CLASS && I2C
@@ -236,6 +242,33 @@ config LEDS_BD2802
This option enables support for BD2802GU RGB LED driver chips
accessed via the I2C bus.
+config LEDS_INTEL_SS4200
+ tristate "LED driver for Intel NAS SS4200 series"
+ depends on LEDS_CLASS && PCI && DMI
+ help
+ This option enables support for the Intel SS4200 series of
+ Network Attached Storage servers. You may control the hard
+ drive or power LEDs on the front panel. Using this driver
+ can stop the front LED from blinking after startup.
+
+config LEDS_LT3593
+ tristate "LED driver for LT3593 controllers"
+ depends on LEDS_CLASS && GENERIC_GPIO
+ help
+ This option enables support for LEDs driven by a Linear Technology
+ LT3593 controller. This controller uses a special one-wire pulse
+ coding protocol to set the brightness.
+
+config LEDS_ADP5520
+ tristate "LED Support for ADP5520/ADP5501 PMIC"
+ depends on LEDS_CLASS && PMIC_ADP5520
+ help
+ This option enables support for on-chip LED drivers found
+ on Analog Devices ADP5520/ADP5501 PMICs.
+
+ To compile this driver as a module, choose M here: the module will
+ be called leds-adp5520.
+
comment "LED Triggers"
config LEDS_TRIGGERS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 46d72704d60..9e63869d7c0 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -29,6 +29,10 @@ obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o
obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o
obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o
obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
+obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o
+obj-$(CONFIG_LEDS_INTEL_SS4200) += leds-ss4200.o
+obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o
+obj-$(CONFIG_LEDS_ADP5520) += leds-adp5520.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
diff --git a/drivers/leds/leds-adp5520.c b/drivers/leds/leds-adp5520.c
new file mode 100644
index 00000000000..a8f31590213
--- /dev/null
+++ b/drivers/leds/leds-adp5520.c
@@ -0,0 +1,230 @@
+/*
+ * LEDs driver for Analog Devices ADP5520/ADP5501 MFD PMICs
+ *
+ * Copyright 2009 Analog Devices Inc.
+ *
+ * Loosely derived from leds-da903x:
+ * Copyright (C) 2008 Compulab, Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ * Eric Miao <eric.miao@marvell.com>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+#include <linux/mfd/adp5520.h>
+
+struct adp5520_led {
+ struct led_classdev cdev;
+ struct work_struct work;
+ struct device *master;
+ enum led_brightness new_brightness;
+ int id;
+ int flags;
+};
+
+static void adp5520_led_work(struct work_struct *work)
+{
+ struct adp5520_led *led = container_of(work, struct adp5520_led, work);
+ adp5520_write(led->master, ADP5520_LED1_CURRENT + led->id - 1,
+ led->new_brightness >> 2);
+}
+
+static void adp5520_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct adp5520_led *led;
+
+ led = container_of(led_cdev, struct adp5520_led, cdev);
+ led->new_brightness = value;
+ schedule_work(&led->work);
+}
+
+static int adp5520_led_setup(struct adp5520_led *led)
+{
+ struct device *dev = led->master;
+ int flags = led->flags;
+ int ret = 0;
+
+ switch (led->id) {
+ case FLAG_ID_ADP5520_LED1_ADP5501_LED0:
+ ret |= adp5520_set_bits(dev, ADP5520_LED_TIME,
+ (flags >> ADP5520_FLAG_OFFT_SHIFT) &
+ ADP5520_FLAG_OFFT_MASK);
+ ret |= adp5520_set_bits(dev, ADP5520_LED_CONTROL,
+ ADP5520_LED1_EN);
+ break;
+ case FLAG_ID_ADP5520_LED2_ADP5501_LED1:
+ ret |= adp5520_set_bits(dev, ADP5520_LED_TIME,
+ ((flags >> ADP5520_FLAG_OFFT_SHIFT) &
+ ADP5520_FLAG_OFFT_MASK) << 2);
+ ret |= adp5520_clr_bits(dev, ADP5520_LED_CONTROL,
+ ADP5520_R3_MODE);
+ ret |= adp5520_set_bits(dev, ADP5520_LED_CONTROL,
+ ADP5520_LED2_EN);
+ break;
+ case FLAG_ID_ADP5520_LED3_ADP5501_LED2:
+ ret |= adp5520_set_bits(dev, ADP5520_LED_TIME,
+ ((flags >> ADP5520_FLAG_OFFT_SHIFT) &
+ ADP5520_FLAG_OFFT_MASK) << 4);
+ ret |= adp5520_clr_bits(dev, ADP5520_LED_CONTROL,
+ ADP5520_C3_MODE);
+ ret |= adp5520_set_bits(dev, ADP5520_LED_CONTROL,
+ ADP5520_LED3_EN);
+ break;
+ }
+
+ return ret;
+}
+
+static int __devinit adp5520_led_prepare(struct platform_device *pdev)
+{
+ struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data;
+ struct device *dev = pdev->dev.parent;
+ int ret = 0;
+
+ ret |= adp5520_write(dev, ADP5520_LED1_CURRENT, 0);
+ ret |= adp5520_write(dev, ADP5520_LED2_CURRENT, 0);
+ ret |= adp5520_write(dev, ADP5520_LED3_CURRENT, 0);
+ ret |= adp5520_write(dev, ADP5520_LED_TIME, pdata->led_on_time << 6);
+ ret |= adp5520_write(dev, ADP5520_LED_FADE, FADE_VAL(pdata->fade_in,
+ pdata->fade_out));
+
+ return ret;
+}
+
+static int __devinit adp5520_led_probe(struct platform_device *pdev)
+{
+ struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data;
+ struct adp5520_led *led, *led_dat;
+ struct led_info *cur_led;
+ int ret, i;
+
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "missing platform data\n");
+ return -ENODEV;
+ }
+
+ if (pdata->num_leds > ADP5520_01_MAXLEDS) {
+ dev_err(&pdev->dev, "can't handle more than %d LEDS\n",
+ ADP5520_01_MAXLEDS);
+ return -EFAULT;
+ }
+
+ led = kzalloc(sizeof(*led) * pdata->num_leds, GFP_KERNEL);
+ if (led == NULL) {
+ dev_err(&pdev->dev, "failed to alloc memory\n");
+ return -ENOMEM;
+ }
+
+ ret = adp5520_led_prepare(pdev);
+
+ if (ret) {
+ dev_err(&pdev->dev, "failed to write\n");
+ goto err_free;
+ }
+
+ for (i = 0; i < pdata->num_leds; ++i) {
+ cur_led = &pdata->leds[i];
+ led_dat = &led[i];
+
+ led_dat->cdev.name = cur_led->name;
+ led_dat->cdev.default_trigger = cur_led->default_trigger;
+ led_dat->cdev.brightness_set = adp5520_led_set;
+ led_dat->cdev.brightness = LED_OFF;
+
+ if (cur_led->flags & ADP5520_FLAG_LED_MASK)
+ led_dat->flags = cur_led->flags;
+ else
+ led_dat->flags = i + 1;
+
+ led_dat->id = led_dat->flags & ADP5520_FLAG_LED_MASK;
+
+ led_dat->master = pdev->dev.parent;
+ led_dat->new_brightness = LED_OFF;
+
+ INIT_WORK(&led_dat->work, adp5520_led_work);
+
+ ret = led_classdev_register(led_dat->master, &led_dat->cdev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register LED %d\n",
+ led_dat->id);
+ goto err;
+ }
+
+ ret = adp5520_led_setup(led_dat);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to write\n");
+ i++;
+ goto err;
+ }
+ }
+
+ platform_set_drvdata(pdev, led);
+ return 0;
+
+err:
+ if (i > 0) {
+ for (i = i - 1; i >= 0; i--) {
+ led_classdev_unregister(&led[i].cdev);
+ cancel_work_sync(&led[i].work);
+ }
+ }
+
+err_free:
+ kfree(led);
+ return ret;
+}
+
+static int __devexit adp5520_led_remove(struct platform_device *pdev)
+{
+ struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data;
+ struct adp5520_led *led;
+ int i;
+
+ led = platform_get_drvdata(pdev);
+
+ adp5520_clr_bits(led->master, ADP5520_LED_CONTROL,
+ ADP5520_LED1_EN | ADP5520_LED2_EN | ADP5520_LED3_EN);
+
+ for (i = 0; i < pdata->num_leds; i++) {
+ led_classdev_unregister(&led[i].cdev);
+ cancel_work_sync(&led[i].work);
+ }
+
+ kfree(led);
+ return 0;
+}
+
+static struct platform_driver adp5520_led_driver = {
+ .driver = {
+ .name = "adp5520-led",
+ .owner = THIS_MODULE,
+ },
+ .probe = adp5520_led_probe,
+ .remove = __devexit_p(adp5520_led_remove),
+};
+
+static int __init adp5520_led_init(void)
+{
+ return platform_driver_register(&adp5520_led_driver);
+}
+module_init(adp5520_led_init);
+
+static void __exit adp5520_led_exit(void)
+{
+ platform_driver_unregister(&adp5520_led_driver);
+}
+module_exit(adp5520_led_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("LEDS ADP5520(01) Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:adp5520-led");
diff --git a/drivers/leds/leds-alix2.c b/drivers/leds/leds-alix2.c
index 731d4eef342..f59ffadf512 100644
--- a/drivers/leds/leds-alix2.c
+++ b/drivers/leds/leds-alix2.c
@@ -11,11 +11,24 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/string.h>
+#include <linux/pci.h>
static int force = 0;
module_param(force, bool, 0444);
MODULE_PARM_DESC(force, "Assume system has ALIX.2/ALIX.3 style LEDs");
+#define MSR_LBAR_GPIO 0x5140000C
+#define CS5535_GPIO_SIZE 256
+
+static u32 gpio_base;
+
+static struct pci_device_id divil_pci[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
+ { } /* NULL entry */
+};
+MODULE_DEVICE_TABLE(pci, divil_pci);
+
struct alix_led {
struct led_classdev cdev;
unsigned short port;
@@ -30,9 +43,9 @@ static void alix_led_set(struct led_classdev *led_cdev,
container_of(led_cdev, struct alix_led, cdev);
if (brightness)
- outl(led_dev->on_value, led_dev->port);
+ outl(led_dev->on_value, gpio_base + led_dev->port);
else
- outl(led_dev->off_value, led_dev->port);
+ outl(led_dev->off_value, gpio_base + led_dev->port);
}
static struct alix_led alix_leds[] = {
@@ -41,7 +54,7 @@ static struct alix_led alix_leds[] = {
.name = "alix:1",
.brightness_set = alix_led_set,
},
- .port = 0x6100,
+ .port = 0x00,
.on_value = 1 << 22,
.off_value = 1 << 6,
},
@@ -50,7 +63,7 @@ static struct alix_led alix_leds[] = {
.name = "alix:2",
.brightness_set = alix_led_set,
},
- .port = 0x6180,
+ .port = 0x80,
.on_value = 1 << 25,
.off_value = 1 << 9,
},
@@ -59,7 +72,7 @@ static struct alix_led alix_leds[] = {
.name = "alix:3",
.brightness_set = alix_led_set,
},
- .port = 0x6180,
+ .port = 0x80,
.on_value = 1 << 27,
.off_value = 1 << 11,
},
@@ -101,64 +114,104 @@ static struct platform_driver alix_led_driver = {
},
};
-static int __init alix_present(void)
+static int __init alix_present(unsigned long bios_phys,
+ const char *alix_sig,
+ size_t alix_sig_len)
{
- const unsigned long bios_phys = 0x000f0000;
const size_t bios_len = 0x00010000;
- const char alix_sig[] = "PC Engines ALIX.";
- const size_t alix_sig_len = sizeof(alix_sig) - 1;
-
const char *bios_virt;
const char *scan_end;
const char *p;
- int ret = 0;
+ char name[64];
if (force) {
printk(KERN_NOTICE "%s: forced to skip BIOS test, "
"assume system has ALIX.2 style LEDs\n",
KBUILD_MODNAME);
- ret = 1;
- goto out;
+ return 1;
}
bios_virt = phys_to_virt(bios_phys);
scan_end = bios_virt + bios_len - (alix_sig_len + 2);
for (p = bios_virt; p < scan_end; p++) {
const char *tail;
+ char *a;
- if (memcmp(p, alix_sig, alix_sig_len) != 0) {
+ if (memcmp(p, alix_sig, alix_sig_len) != 0)
continue;
- }
+
+ memcpy(name, p, sizeof(name));
+
+ /* remove the first \0 character from string */
+ a = strchr(name, '\0');
+ if (a)
+ *a = ' ';
+
+ /* cut the string at a newline */
+ a = strchr(name, '\r');
+ if (a)
+ *a = '\0';
tail = p + alix_sig_len;
- if ((tail[0] == '2' || tail[0] == '3') && tail[1] == '\0') {
+ if ((tail[0] == '2' || tail[0] == '3')) {
printk(KERN_INFO
"%s: system is recognized as \"%s\"\n",
- KBUILD_MODNAME, p);
- ret = 1;
- break;
+ KBUILD_MODNAME, name);
+ return 1;
}
}
-out:
- return ret;
+ return 0;
}
static struct platform_device *pdev;
-static int __init alix_led_init(void)
+static int __init alix_pci_led_init(void)
{
- int ret;
+ u32 low, hi;
- if (!alix_present()) {
- ret = -ENODEV;
- goto out;
+ if (pci_dev_present(divil_pci) == 0) {
+ printk(KERN_WARNING KBUILD_MODNAME": DIVIL not found\n");
+ return -ENODEV;
}
- /* enable output on GPIO for LED 1,2,3 */
- outl(1 << 6, 0x6104);
- outl(1 << 9, 0x6184);
- outl(1 << 11, 0x6184);
+ /* Grab the GPIO I/O range */
+ rdmsr(MSR_LBAR_GPIO, low, hi);
+
+ /* Check the mask and whether GPIO is enabled (sanity check) */
+ if (hi != 0x0000f001) {
+ printk(KERN_WARNING KBUILD_MODNAME": GPIO not enabled\n");
+ return -ENODEV;
+ }
+
+ /* Mask off the IO base address */
+ gpio_base = low & 0x0000ff00;
+
+ if (!request_region(gpio_base, CS5535_GPIO_SIZE, KBUILD_MODNAME)) {
+ printk(KERN_ERR KBUILD_MODNAME": can't allocate I/O for GPIO\n");
+ return -ENODEV;
+ }
+
+ /* Set GPIO function to output */
+ outl(1 << 6, gpio_base + 0x04);
+ outl(1 << 9, gpio_base + 0x84);
+ outl(1 << 11, gpio_base + 0x84);
+
+ return 0;
+}
+
+static int __init alix_led_init(void)
+{
+ int ret = -ENODEV;
+ const char tinybios_sig[] = "PC Engines ALIX.";
+ const char coreboot_sig[] = "PC Engines\0ALIX.";
+
+ if (alix_present(0xf0000, tinybios_sig, sizeof(tinybios_sig) - 1) ||
+ alix_present(0x500, coreboot_sig, sizeof(coreboot_sig) - 1))
+ ret = alix_pci_led_init();
+
+ if (ret < 0)
+ return ret;
pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
if (!IS_ERR(pdev)) {
@@ -168,7 +221,6 @@ static int __init alix_led_init(void)
} else
ret = PTR_ERR(pdev);
-out:
return ret;
}
@@ -176,6 +228,7 @@ static void __exit alix_led_exit(void)
{
platform_device_unregister(pdev);
platform_driver_unregister(&alix_led_driver);
+ release_region(gpio_base, CS5535_GPIO_SIZE);
}
module_init(alix_led_init);
diff --git a/drivers/leds/leds-cobalt-qube.c b/drivers/leds/leds-cobalt-qube.c
index 8816806accd..da5fb016b1a 100644
--- a/drivers/leds/leds-cobalt-qube.c
+++ b/drivers/leds/leds-cobalt-qube.c
@@ -31,7 +31,7 @@ static struct led_classdev qube_front_led = {
.name = "qube::front",
.brightness = LED_FULL,
.brightness_set = qube_front_led_set,
- .default_trigger = "ide-disk",
+ .default_trigger = "default-on",
};
static int __devinit cobalt_qube_led_probe(struct platform_device *pdev)
@@ -43,7 +43,7 @@ static int __devinit cobalt_qube_led_probe(struct platform_device *pdev)
if (!res)
return -EBUSY;
- led_port = ioremap(res->start, res->end - res->start + 1);
+ led_port = ioremap(res->start, resource_size(res));
if (!led_port)
return -ENOMEM;
diff --git a/drivers/leds/leds-cobalt-raq.c b/drivers/leds/leds-cobalt-raq.c
index defc212105f..438d4838463 100644
--- a/drivers/leds/leds-cobalt-raq.c
+++ b/drivers/leds/leds-cobalt-raq.c
@@ -84,7 +84,7 @@ static int __devinit cobalt_raq_led_probe(struct platform_device *pdev)
if (!res)
return -EBUSY;
- led_port = ioremap(res->start, res->end - res->start + 1);
+ led_port = ioremap(res->start, resource_size(res));
if (!led_port)
return -ENOMEM;
diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c
new file mode 100644
index 00000000000..fee40a84195
--- /dev/null
+++ b/drivers/leds/leds-lt3593.c
@@ -0,0 +1,217 @@
+/*
+ * LEDs driver for LT3593 controllers
+ *
+ * See the datasheet at http://cds.linear.com/docs/Datasheet/3593f.pdf
+ *
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ * Based on leds-gpio.c,
+ *
+ * Copyright (C) 2007 8D Technologies inc.
+ * Raphael Assenat <raph@8d.com>
+ * Copyright (C) 2008 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+struct lt3593_led_data {
+ struct led_classdev cdev;
+ unsigned gpio;
+ struct work_struct work;
+ u8 new_level;
+};
+
+static void lt3593_led_work(struct work_struct *work)
+{
+ int pulses;
+ struct lt3593_led_data *led_dat =
+ container_of(work, struct lt3593_led_data, work);
+
+ /*
+ * The LT3593 resets its internal current level register to the maximum
+ * level on the first falling edge on the control pin. Each following
+ * falling edge decreases the current level by 625uA. Up to 32 pulses
+ * can be sent, so the maximum power reduction is 20mA.
+ * After a timeout of 128us, the value is taken from the register and
+ * applied is to the output driver.
+ */
+
+ if (led_dat->new_level == 0) {
+ gpio_set_value_cansleep(led_dat->gpio, 0);
+ return;
+ }
+
+ pulses = 32 - (led_dat->new_level * 32) / 255;
+
+ if (pulses == 0) {
+ gpio_set_value_cansleep(led_dat->gpio, 0);
+ mdelay(1);
+ gpio_set_value_cansleep(led_dat->gpio, 1);
+ return;
+ }
+
+ gpio_set_value_cansleep(led_dat->gpio, 1);
+
+ while (pulses--) {
+ gpio_set_value_cansleep(led_dat->gpio, 0);
+ udelay(1);
+ gpio_set_value_cansleep(led_dat->gpio, 1);
+ udelay(1);
+ }
+}
+
+static void lt3593_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct lt3593_led_data *led_dat =
+ container_of(led_cdev, struct lt3593_led_data, cdev);
+
+ led_dat->new_level = value;
+ schedule_work(&led_dat->work);
+}
+
+static int __devinit create_lt3593_led(const struct gpio_led *template,
+ struct lt3593_led_data *led_dat, struct device *parent)
+{
+ int ret, state;
+
+ /* skip leds on GPIOs that aren't available */
+ if (!gpio_is_valid(template->gpio)) {
+ printk(KERN_INFO "%s: skipping unavailable LT3593 LED at gpio %d (%s)\n",
+ KBUILD_MODNAME, template->gpio, template->name);
+ return 0;
+ }
+
+ ret = gpio_request(template->gpio, template->name);
+ if (ret < 0)
+ return ret;
+
+ led_dat->cdev.name = template->name;
+ led_dat->cdev.default_trigger = template->default_trigger;
+ led_dat->gpio = template->gpio;
+
+ led_dat->cdev.brightness_set = lt3593_led_set;
+
+ state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
+ led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
+
+ if (!template->retain_state_suspended)
+ led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
+
+ ret = gpio_direction_output(led_dat->gpio, state);
+ if (ret < 0)
+ goto err;
+
+ INIT_WORK(&led_dat->work, lt3593_led_work);
+
+ ret = led_classdev_register(parent, &led_dat->cdev);
+ if (ret < 0)
+ goto err;
+
+ printk(KERN_INFO "%s: registered LT3593 LED '%s' at GPIO %d\n",
+ KBUILD_MODNAME, template->name, template->gpio);
+
+ return 0;
+
+err:
+ gpio_free(led_dat->gpio);
+ return ret;
+}
+
+static void delete_lt3593_led(struct lt3593_led_data *led)
+{
+ if (!gpio_is_valid(led->gpio))
+ return;
+
+ led_classdev_unregister(&led->cdev);
+ cancel_work_sync(&led->work);
+ gpio_free(led->gpio);
+}
+
+static int __devinit lt3593_led_probe(struct platform_device *pdev)
+{
+ struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+ struct lt3593_led_data *leds_data;
+ int i, ret = 0;
+
+ if (!pdata)
+ return -EBUSY;
+
+ leds_data = kzalloc(sizeof(struct lt3593_led_data) * pdata->num_leds,
+ GFP_KERNEL);
+ if (!leds_data)
+ return -ENOMEM;
+
+ for (i = 0; i < pdata->num_leds; i++) {
+ ret = create_lt3593_led(&pdata->leds[i], &leds_data[i],
+ &pdev->dev);
+ if (ret < 0)
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, leds_data);
+
+ return 0;
+
+err:
+ for (i = i - 1; i >= 0; i--)
+ delete_lt3593_led(&leds_data[i]);
+
+ kfree(leds_data);
+
+ return ret;
+}
+
+static int __devexit lt3593_led_remove(struct platform_device *pdev)
+{
+ int i;
+ struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+ struct lt3593_led_data *leds_data;
+
+ leds_data = platform_get_drvdata(pdev);
+
+ for (i = 0; i < pdata->num_leds; i++)
+ delete_lt3593_led(&leds_data[i]);
+
+ kfree(leds_data);
+
+ return 0;
+}
+
+static struct platform_driver lt3593_led_driver = {
+ .probe = lt3593_led_probe,
+ .remove = __devexit_p(lt3593_led_remove),
+ .driver = {
+ .name = "leds-lt3593",
+ .owner = THIS_MODULE,
+ },
+};
+
+MODULE_ALIAS("platform:leds-lt3593");
+
+static int __init lt3593_led_init(void)
+{
+ return platform_driver_register(&lt3593_led_driver);
+}
+
+static void __exit lt3593_led_exit(void)
+{
+ platform_driver_unregister(&lt3593_led_driver);
+}
+
+module_init(lt3593_led_init);
+module_exit(lt3593_led_exit);
+
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
+MODULE_DESCRIPTION("LED driver for LT3593 controllers");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index cdfdc8714e1..88b1dd091cf 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -27,7 +27,6 @@ struct led_pwm_data {
struct pwm_device *pwm;
unsigned int active_low;
unsigned int period;
- unsigned int max_brightness;
};
static void led_pwm_set(struct led_classdev *led_cdev,
@@ -35,7 +34,7 @@ static void led_pwm_set(struct led_classdev *led_cdev,
{
struct led_pwm_data *led_dat =
container_of(led_cdev, struct led_pwm_data, cdev);
- unsigned int max = led_dat->max_brightness;
+ unsigned int max = led_dat->cdev.max_brightness;
unsigned int period = led_dat->period;
if (brightness == 0) {
@@ -77,10 +76,10 @@ static int led_pwm_probe(struct platform_device *pdev)
led_dat->cdev.name = cur_led->name;
led_dat->cdev.default_trigger = cur_led->default_trigger;
led_dat->active_low = cur_led->active_low;
- led_dat->max_brightness = cur_led->max_brightness;
led_dat->period = cur_led->pwm_period_ns;
led_dat->cdev.brightness_set = led_pwm_set;
led_dat->cdev.brightness = LED_OFF;
+ led_dat->cdev.max_brightness = cur_led->max_brightness;
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
diff --git a/drivers/leds/leds-regulator.c b/drivers/leds/leds-regulator.c
new file mode 100644
index 00000000000..7f00de3ef92
--- /dev/null
+++ b/drivers/leds/leds-regulator.c
@@ -0,0 +1,242 @@
+/*
+ * leds-regulator.c - LED class driver for regulator driven LEDs.
+ *
+ * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
+ *
+ * Inspired by leds-wm8350 driver.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/workqueue.h>
+#include <linux/leds.h>
+#include <linux/leds-regulator.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#define to_regulator_led(led_cdev) \
+ container_of(led_cdev, struct regulator_led, cdev)
+
+struct regulator_led {
+ struct led_classdev cdev;
+ enum led_brightness value;
+ int enabled;
+ struct mutex mutex;
+ struct work_struct work;
+
+ struct regulator *vcc;
+};
+
+static inline int led_regulator_get_max_brightness(struct regulator *supply)
+{
+ int ret;
+ int voltage = regulator_list_voltage(supply, 0);
+
+ if (voltage <= 0)
+ return 1;
+
+ /* even if regulator can't change voltages,
+ * we still assume it can change status
+ * and the LED can be turned on and off.
+ */
+ ret = regulator_set_voltage(supply, voltage, voltage);
+ if (ret < 0)
+ return 1;
+
+ return regulator_count_voltages(supply);
+}
+
+static int led_regulator_get_voltage(struct regulator *supply,
+ enum led_brightness brightness)
+{
+ if (brightness == 0)
+ return -EINVAL;
+
+ return regulator_list_voltage(supply, brightness - 1);
+}
+
+
+static void regulator_led_enable(struct regulator_led *led)
+{
+ int ret;
+
+ if (led->enabled)
+ return;
+
+ ret = regulator_enable(led->vcc);
+ if (ret != 0) {
+ dev_err(led->cdev.dev, "Failed to enable vcc: %d\n", ret);
+ return;
+ }
+
+ led->enabled = 1;
+}
+
+static void regulator_led_disable(struct regulator_led *led)
+{
+ int ret;
+
+ if (!led->enabled)
+ return;
+
+ ret = regulator_disable(led->vcc);
+ if (ret != 0) {
+ dev_err(led->cdev.dev, "Failed to disable vcc: %d\n", ret);
+ return;
+ }
+
+ led->enabled = 0;
+}
+
+static void regulator_led_set_value(struct regulator_led *led)
+{
+ int voltage;
+ int ret;
+
+ mutex_lock(&led->mutex);
+
+ if (led->value == LED_OFF) {
+ regulator_led_disable(led);
+ goto out;
+ }
+
+ if (led->cdev.max_brightness > 1) {
+ voltage = led_regulator_get_voltage(led->vcc, led->value);
+ dev_dbg(led->cdev.dev, "brightness: %d voltage: %d\n",
+ led->value, voltage);
+
+ ret = regulator_set_voltage(led->vcc, voltage, voltage);
+ if (ret != 0)
+ dev_err(led->cdev.dev, "Failed to set voltage %d: %d\n",
+ voltage, ret);
+ }
+
+ regulator_led_enable(led);
+
+out:
+ mutex_unlock(&led->mutex);
+}
+
+static void led_work(struct work_struct *work)
+{
+ struct regulator_led *led;
+
+ led = container_of(work, struct regulator_led, work);
+ regulator_led_set_value(led);
+}
+
+static void regulator_led_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct regulator_led *led = to_regulator_led(led_cdev);
+
+ led->value = value;
+ schedule_work(&led->work);
+}
+
+static int __devinit regulator_led_probe(struct platform_device *pdev)
+{
+ struct led_regulator_platform_data *pdata = pdev->dev.platform_data;
+ struct regulator_led *led;
+ struct regulator *vcc;
+ int ret = 0;
+
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -ENODEV;
+ }
+
+ vcc = regulator_get_exclusive(&pdev->dev, "vled");
+ if (IS_ERR(vcc)) {
+ dev_err(&pdev->dev, "Cannot get vcc for %s\n", pdata->name);
+ return PTR_ERR(vcc);
+ }
+
+ led = kzalloc(sizeof(*led), GFP_KERNEL);
+ if (led == NULL) {
+ ret = -ENOMEM;
+ goto err_vcc;
+ }
+
+ led->cdev.max_brightness = led_regulator_get_max_brightness(vcc);
+ if (pdata->brightness > led->cdev.max_brightness) {
+ dev_err(&pdev->dev, "Invalid default brightness %d\n",
+ pdata->brightness);
+ ret = -EINVAL;
+ goto err_led;
+ }
+ led->value = pdata->brightness;
+
+ led->cdev.brightness_set = regulator_led_brightness_set;
+ led->cdev.name = pdata->name;
+ led->cdev.flags |= LED_CORE_SUSPENDRESUME;
+ led->vcc = vcc;
+
+ mutex_init(&led->mutex);
+ INIT_WORK(&led->work, led_work);
+
+ platform_set_drvdata(pdev, led);
+
+ ret = led_classdev_register(&pdev->dev, &led->cdev);
+ if (ret < 0) {
+ cancel_work_sync(&led->work);
+ goto err_led;
+ }
+
+ /* to expose the default value to userspace */
+ led->cdev.brightness = led->value;
+
+ /* Set the default led status */
+ regulator_led_set_value(led);
+
+ return 0;
+
+err_led:
+ kfree(led);
+err_vcc:
+ regulator_put(vcc);
+ return ret;
+}
+
+static int __devexit regulator_led_remove(struct platform_device *pdev)
+{
+ struct regulator_led *led = platform_get_drvdata(pdev);
+
+ led_classdev_unregister(&led->cdev);
+ cancel_work_sync(&led->work);
+ regulator_led_disable(led);
+ regulator_put(led->vcc);
+ kfree(led);
+ return 0;
+}
+
+static struct platform_driver regulator_led_driver = {
+ .driver = {
+ .name = "leds-regulator",
+ .owner = THIS_MODULE,
+ },
+ .probe = regulator_led_probe,
+ .remove = __devexit_p(regulator_led_remove),
+};
+
+static int __init regulator_led_init(void)
+{
+ return platform_driver_register(&regulator_led_driver);
+}
+module_init(regulator_led_init);
+
+static void __exit regulator_led_exit(void)
+{
+ platform_driver_unregister(&regulator_led_driver);
+}
+module_exit(regulator_led_exit);
+
+MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
+MODULE_DESCRIPTION("Regulator driven LED driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:leds-regulator");
diff --git a/drivers/leds/leds-ss4200.c b/drivers/leds/leds-ss4200.c
new file mode 100644
index 00000000000..97f04984c1c
--- /dev/null
+++ b/drivers/leds/leds-ss4200.c
@@ -0,0 +1,556 @@
+/*
+ * SS4200-E Hardware API
+ * Copyright (c) 2009, Intel Corporation.
+ * Copyright IBM Corporation, 2009
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Author: Dave Hansen <dave@sr71.net>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/dmi.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+
+MODULE_AUTHOR("Rodney Girod <rgirod@confocus.com>, Dave Hansen <dave@sr71.net>");
+MODULE_DESCRIPTION("Intel NAS/Home Server ICH7 GPIO Driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * ICH7 LPC/GPIO PCI Config register offsets
+ */
+#define PMBASE 0x040
+#define GPIO_BASE 0x048
+#define GPIO_CTRL 0x04c
+#define GPIO_EN 0x010
+
+/*
+ * The ICH7 GPIO register block is 64 bytes in size.
+ */
+#define ICH7_GPIO_SIZE 64
+
+/*
+ * Define register offsets within the ICH7 register block.
+ */
+#define GPIO_USE_SEL 0x000
+#define GP_IO_SEL 0x004
+#define GP_LVL 0x00c
+#define GPO_BLINK 0x018
+#define GPI_INV 0x030
+#define GPIO_USE_SEL2 0x034
+#define GP_IO_SEL2 0x038
+#define GP_LVL2 0x03c
+
+/*
+ * PCI ID of the Intel ICH7 LPC Device within which the GPIO block lives.
+ */
+static struct pci_device_id ich7_lpc_pci_id[] =
+{
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_30) },
+ { } /* NULL entry */
+};
+
+MODULE_DEVICE_TABLE(pci, ich7_lpc_pci_id);
+
+static int __init ss4200_led_dmi_callback(const struct dmi_system_id *id)
+{
+ pr_info("detected '%s'\n", id->ident);
+ return 1;
+}
+
+static unsigned int __initdata nodetect;
+module_param_named(nodetect, nodetect, bool, 0);
+MODULE_PARM_DESC(nodetect, "Skip DMI-based hardware detection");
+
+/*
+ * struct nas_led_whitelist - List of known good models
+ *
+ * Contains the known good models this driver is compatible with.
+ * When adding a new model try to be as strict as possible. This
+ * makes it possible to keep the false positives (the model is
+ * detected as working, but in reality it is not) as low as
+ * possible.
+ */
+static struct dmi_system_id __initdata nas_led_whitelist[] = {
+ {
+ .callback = ss4200_led_dmi_callback,
+ .ident = "Intel SS4200-E",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "SS4200-E"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "1.00.00")
+ }
+ },
+};
+
+/*
+ * Base I/O address assigned to the Power Management register block
+ */
+static u32 g_pm_io_base;
+
+/*
+ * Base I/O address assigned to the ICH7 GPIO register block
+ */
+static u32 nas_gpio_io_base;
+
+/*
+ * When we successfully register a region, we are returned a resource.
+ * We use these to identify which regions we need to release on our way
+ * back out.
+ */
+static struct resource *gp_gpio_resource;
+
+struct nasgpio_led {
+ char *name;
+ u32 gpio_bit;
+ struct led_classdev led_cdev;
+};
+
+/*
+ * gpio_bit(s) are the ICH7 GPIO bit assignments
+ */
+static struct nasgpio_led nasgpio_leds[] = {
+ { .name = "hdd1:blue:sata", .gpio_bit = 0 },
+ { .name = "hdd1:amber:sata", .gpio_bit = 1 },
+ { .name = "hdd2:blue:sata", .gpio_bit = 2 },
+ { .name = "hdd2:amber:sata", .gpio_bit = 3 },
+ { .name = "hdd3:blue:sata", .gpio_bit = 4 },
+ { .name = "hdd3:amber:sata", .gpio_bit = 5 },
+ { .name = "hdd4:blue:sata", .gpio_bit = 6 },
+ { .name = "hdd4:amber:sata", .gpio_bit = 7 },
+ { .name = "power:blue:power", .gpio_bit = 27},
+ { .name = "power:amber:power", .gpio_bit = 28},
+};
+
+#define NAS_RECOVERY 0x00000400 /* GPIO10 */
+
+static struct nasgpio_led *
+led_classdev_to_nasgpio_led(struct led_classdev *led_cdev)
+{
+ return container_of(led_cdev, struct nasgpio_led, led_cdev);
+}
+
+static struct nasgpio_led *get_led_named(char *name)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++) {
+ if (strcmp(nasgpio_leds[i].name, name))
+ continue;
+ return &nasgpio_leds[i];
+ }
+ return NULL;
+}
+
+/*
+ * This protects access to the gpio ports.
+ */
+static DEFINE_SPINLOCK(nasgpio_gpio_lock);
+
+/*
+ * There are two gpio ports, one for blinking and the other
+ * for power. @port tells us if we're doing blinking or
+ * power control.
+ *
+ * Caller must hold nasgpio_gpio_lock
+ */
+static void __nasgpio_led_set_attr(struct led_classdev *led_cdev,
+ u32 port, u32 value)
+{
+ struct nasgpio_led *led = led_classdev_to_nasgpio_led(led_cdev);
+ u32 gpio_out;
+
+ gpio_out = inl(nas_gpio_io_base + port);
+ if (value)
+ gpio_out |= (1<<led->gpio_bit);
+ else
+ gpio_out &= ~(1<<led->gpio_bit);
+
+ outl(gpio_out, nas_gpio_io_base + port);
+}
+
+static void nasgpio_led_set_attr(struct led_classdev *led_cdev,
+ u32 port, u32 value)
+{
+ spin_lock(&nasgpio_gpio_lock);
+ __nasgpio_led_set_attr(led_cdev, port, value);
+ spin_unlock(&nasgpio_gpio_lock);
+}
+
+u32 nasgpio_led_get_attr(struct led_classdev *led_cdev, u32 port)
+{
+ struct nasgpio_led *led = led_classdev_to_nasgpio_led(led_cdev);
+ u32 gpio_in;
+
+ spin_lock(&nasgpio_gpio_lock);
+ gpio_in = inl(nas_gpio_io_base + port);
+ spin_unlock(&nasgpio_gpio_lock);
+ if (gpio_in & (1<<led->gpio_bit))
+ return 1;
+ return 0;
+}
+
+/*
+ * There is actual brightness control in the hardware,
+ * but it is via smbus commands and not implemented
+ * in this driver.
+ */
+static void nasgpio_led_set_brightness(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ u32 setting = 0;
+ if (brightness >= LED_HALF)
+ setting = 1;
+ /*
+ * Hold the lock across both operations. This ensures
+ * consistency so that both the "turn off blinking"
+ * and "turn light off" operations complete as a set.
+ */
+ spin_lock(&nasgpio_gpio_lock);
+ /*
+ * LED class documentation asks that past blink state
+ * be disabled when brightness is turned to zero.
+ */
+ if (brightness == 0)
+ __nasgpio_led_set_attr(led_cdev, GPO_BLINK, 0);
+ __nasgpio_led_set_attr(led_cdev, GP_LVL, setting);
+ spin_unlock(&nasgpio_gpio_lock);
+}
+
+static int nasgpio_led_set_blink(struct led_classdev *led_cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ u32 setting = 1;
+ if (!(*delay_on == 0 && *delay_off == 0) &&
+ !(*delay_on == 500 && *delay_off == 500))
+ return -EINVAL;
+ /*
+ * These are very approximate.
+ */
+ *delay_on = 500;
+ *delay_off = 500;
+
+ nasgpio_led_set_attr(led_cdev, GPO_BLINK, setting);
+
+ return 0;
+}
+
+
+/*
+ * Initialize the ICH7 GPIO registers for NAS usage. The BIOS should have
+ * already taken care of this, but we will do so in a non destructive manner
+ * so that we have what we need whether the BIOS did it or not.
+ */
+static int __devinit ich7_gpio_init(struct device *dev)
+{
+ int i;
+ u32 config_data = 0;
+ u32 all_nas_led = 0;
+
+ for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++)
+ all_nas_led |= (1<<nasgpio_leds[i].gpio_bit);
+
+ spin_lock(&nasgpio_gpio_lock);
+ /*
+ * We need to enable all of the GPIO lines used by the NAS box,
+ * so we will read the current Use Selection and add our usage
+ * to it. This should be benign with regard to the original
+ * BIOS configuration.
+ */
+ config_data = inl(nas_gpio_io_base + GPIO_USE_SEL);
+ dev_dbg(dev, ": Data read from GPIO_USE_SEL = 0x%08x\n", config_data);
+ config_data |= all_nas_led + NAS_RECOVERY;
+ outl(config_data, nas_gpio_io_base + GPIO_USE_SEL);
+ config_data = inl(nas_gpio_io_base + GPIO_USE_SEL);
+ dev_dbg(dev, ": GPIO_USE_SEL = 0x%08x\n\n", config_data);
+
+ /*
+ * The LED GPIO outputs need to be configured for output, so we
+ * will ensure that all LED lines are cleared for output and the
+ * RECOVERY line ready for input. This too should be benign with
+ * regard to BIOS configuration.
+ */
+ config_data = inl(nas_gpio_io_base + GP_IO_SEL);
+ dev_dbg(dev, ": Data read from GP_IO_SEL = 0x%08x\n",
+ config_data);
+ config_data &= ~all_nas_led;
+ config_data |= NAS_RECOVERY;
+ outl(config_data, nas_gpio_io_base + GP_IO_SEL);
+ config_data = inl(nas_gpio_io_base + GP_IO_SEL);
+ dev_dbg(dev, ": GP_IO_SEL = 0x%08x\n", config_data);
+
+ /*
+ * In our final system, the BIOS will initialize the state of all
+ * of the LEDs. For now, we turn them all off (or Low).
+ */
+ config_data = inl(nas_gpio_io_base + GP_LVL);
+ dev_dbg(dev, ": Data read from GP_LVL = 0x%08x\n", config_data);
+ /*
+ * In our final system, the BIOS will initialize the blink state of all
+ * of the LEDs. For now, we turn blink off for all of them.
+ */
+ config_data = inl(nas_gpio_io_base + GPO_BLINK);
+ dev_dbg(dev, ": Data read from GPO_BLINK = 0x%08x\n", config_data);
+
+ /*
+ * At this moment, I am unsure if anything needs to happen with GPI_INV
+ */
+ config_data = inl(nas_gpio_io_base + GPI_INV);
+ dev_dbg(dev, ": Data read from GPI_INV = 0x%08x\n", config_data);
+
+ spin_unlock(&nasgpio_gpio_lock);
+ return 0;
+}
+
+static void ich7_lpc_cleanup(struct device *dev)
+{
+ /*
+ * If we were given exclusive use of the GPIO
+ * I/O Address range, we must return it.
+ */
+ if (gp_gpio_resource) {
+ dev_dbg(dev, ": Releasing GPIO I/O addresses\n");
+ release_region(nas_gpio_io_base, ICH7_GPIO_SIZE);
+ gp_gpio_resource = NULL;
+ }
+}
+
+/*
+ * The OS has determined that the LPC of the Intel ICH7 Southbridge is present
+ * so we can retrive the required operational information and prepare the GPIO.
+ */
+static struct pci_dev *nas_gpio_pci_dev;
+static int __devinit ich7_lpc_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ int status;
+ u32 gc = 0;
+
+ status = pci_enable_device(dev);
+ if (status) {
+ dev_err(&dev->dev, "pci_enable_device failed\n");
+ return -EIO;
+ }
+
+ nas_gpio_pci_dev = dev;
+ status = pci_read_config_dword(dev, PMBASE, &g_pm_io_base);
+ if (status)
+ goto out;
+ g_pm_io_base &= 0x00000ff80;
+
+ status = pci_read_config_dword(dev, GPIO_CTRL, &gc);
+ if (!(GPIO_EN & gc)) {
+ status = -EEXIST;
+ dev_info(&dev->dev,
+ "ERROR: The LPC GPIO Block has not been enabled.\n");
+ goto out;
+ }
+
+ status = pci_read_config_dword(dev, GPIO_BASE, &nas_gpio_io_base);
+ if (0 > status) {
+ dev_info(&dev->dev, "Unable to read GPIOBASE.\n");
+ goto out;
+ }
+ dev_dbg(&dev->dev, ": GPIOBASE = 0x%08x\n", nas_gpio_io_base);
+ nas_gpio_io_base &= 0x00000ffc0;
+
+ /*
+ * Insure that we have exclusive access to the GPIO I/O address range.
+ */
+ gp_gpio_resource = request_region(nas_gpio_io_base, ICH7_GPIO_SIZE,
+ KBUILD_MODNAME);
+ if (NULL == gp_gpio_resource) {
+ dev_info(&dev->dev,
+ "ERROR Unable to register GPIO I/O addresses.\n");
+ status = -1;
+ goto out;
+ }
+
+ /*
+ * Initialize the GPIO for NAS/Home Server Use
+ */
+ ich7_gpio_init(&dev->dev);
+
+out:
+ if (status) {
+ ich7_lpc_cleanup(&dev->dev);
+ pci_disable_device(dev);
+ }
+ return status;
+}
+
+static void ich7_lpc_remove(struct pci_dev *dev)
+{
+ ich7_lpc_cleanup(&dev->dev);
+ pci_disable_device(dev);
+}
+
+/*
+ * pci_driver structure passed to the PCI modules
+ */
+static struct pci_driver nas_gpio_pci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ich7_lpc_pci_id,
+ .probe = ich7_lpc_probe,
+ .remove = ich7_lpc_remove,
+};
+
+static struct led_classdev *get_classdev_for_led_nr(int nr)
+{
+ struct nasgpio_led *nas_led = &nasgpio_leds[nr];
+ struct led_classdev *led = &nas_led->led_cdev;
+ return led;
+}
+
+
+static void set_power_light_amber_noblink(void)
+{
+ struct nasgpio_led *amber = get_led_named("power:amber:power");
+ struct nasgpio_led *blue = get_led_named("power:blue:power");
+
+ if (!amber || !blue)
+ return;
+ /*
+ * LED_OFF implies disabling future blinking
+ */
+ pr_debug("setting blue off and amber on\n");
+
+ nasgpio_led_set_brightness(&blue->led_cdev, LED_OFF);
+ nasgpio_led_set_brightness(&amber->led_cdev, LED_FULL);
+}
+
+static ssize_t nas_led_blink_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led = dev_get_drvdata(dev);
+ int blinking = 0;
+ if (nasgpio_led_get_attr(led, GPO_BLINK))
+ blinking = 1;
+ return sprintf(buf, "%u\n", blinking);
+}
+
+static ssize_t nas_led_blink_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ struct led_classdev *led = dev_get_drvdata(dev);
+ unsigned long blink_state;
+
+ ret = strict_strtoul(buf, 10, &blink_state);
+ if (ret)
+ return ret;
+
+ nasgpio_led_set_attr(led, GPO_BLINK, blink_state);
+
+ return size;
+}
+
+static DEVICE_ATTR(blink, 0644, nas_led_blink_show, nas_led_blink_store);
+
+static int register_nasgpio_led(int led_nr)
+{
+ int ret;
+ struct nasgpio_led *nas_led = &nasgpio_leds[led_nr];
+ struct led_classdev *led = get_classdev_for_led_nr(led_nr);
+
+ led->name = nas_led->name;
+ led->brightness = LED_OFF;
+ if (nasgpio_led_get_attr(led, GP_LVL))
+ led->brightness = LED_FULL;
+ led->brightness_set = nasgpio_led_set_brightness;
+ led->blink_set = nasgpio_led_set_blink;
+ ret = led_classdev_register(&nas_gpio_pci_dev->dev, led);
+ if (ret)
+ return ret;
+ ret = device_create_file(led->dev, &dev_attr_blink);
+ if (ret)
+ led_classdev_unregister(led);
+ return ret;
+}
+
+static void unregister_nasgpio_led(int led_nr)
+{
+ struct led_classdev *led = get_classdev_for_led_nr(led_nr);
+ led_classdev_unregister(led);
+ device_remove_file(led->dev, &dev_attr_blink);
+}
+/*
+ * module load/initialization
+ */
+static int __init nas_gpio_init(void)
+{
+ int i;
+ int ret = 0;
+ int nr_devices = 0;
+
+ nr_devices = dmi_check_system(nas_led_whitelist);
+ if (nodetect) {
+ pr_info("skipping hardware autodetection\n");
+ pr_info("Please send 'dmidecode' output to dave@sr71.net\n");
+ nr_devices++;
+ }
+
+ if (nr_devices <= 0) {
+ pr_info("no LED devices found\n");
+ return -ENODEV;
+ }
+
+ pr_info("registering PCI driver\n");
+ ret = pci_register_driver(&nas_gpio_pci_driver);
+ if (ret)
+ return ret;
+ for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++) {
+ ret = register_nasgpio_led(i);
+ if (ret)
+ goto out_err;
+ }
+ /*
+ * When the system powers on, the BIOS leaves the power
+ * light blue and blinking. This will turn it solid
+ * amber once the driver is loaded.
+ */
+ set_power_light_amber_noblink();
+ return 0;
+out_err:
+ for (; i >= 0; i--)
+ unregister_nasgpio_led(i);
+ pci_unregister_driver(&nas_gpio_pci_driver);
+ return ret;
+}
+
+/*
+ * module unload
+ */
+static void __exit nas_gpio_exit(void)
+{
+ int i;
+ pr_info("Unregistering driver\n");
+ for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++)
+ unregister_nasgpio_led(i);
+ pci_unregister_driver(&nas_gpio_pci_driver);
+}
+
+module_init(nas_gpio_init);
+module_exit(nas_gpio_exit);
diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c
index 3ccc8afeccf..2bf57a4527d 100644
--- a/drivers/media/video/cx23885/cx23888-ir.c
+++ b/drivers/media/video/cx23885/cx23888-ir.c
@@ -124,15 +124,12 @@ struct cx23888_ir_state {
atomic_t rxclk_divider;
atomic_t rx_invert;
- struct kfifo *rx_kfifo;
+ struct kfifo rx_kfifo;
spinlock_t rx_kfifo_lock;
struct v4l2_subdev_ir_parameters tx_params;
struct mutex tx_params_lock;
atomic_t txclk_divider;
-
- struct kfifo *tx_kfifo;
- spinlock_t tx_kfifo_lock;
};
static inline struct cx23888_ir_state *to_state(struct v4l2_subdev *sd)
@@ -522,6 +519,7 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
{
struct cx23888_ir_state *state = to_state(sd);
struct cx23885_dev *dev = state->dev;
+ unsigned long flags;
u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG);
u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG);
@@ -594,8 +592,9 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
if (i == 0)
break;
j = i * sizeof(u32);
- k = kfifo_put(state->rx_kfifo,
- (unsigned char *) rx_data, j);
+ k = kfifo_in_locked(&state->rx_kfifo,
+ (unsigned char *) rx_data, j,
+ &state->rx_kfifo_lock);
if (k != j)
kror++; /* rx_kfifo over run */
}
@@ -631,8 +630,11 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl);
*handled = true;
}
- if (kfifo_len(state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2)
+
+ spin_lock_irqsave(&state->rx_kfifo_lock, flags);
+ if (kfifo_len(&state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2)
events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ;
+ spin_unlock_irqrestore(&state->rx_kfifo_lock, flags);
if (events)
v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events);
@@ -657,7 +659,7 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
return 0;
}
- n = kfifo_get(state->rx_kfifo, buf, n);
+ n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock);
n /= sizeof(u32);
*num = n * sizeof(u32);
@@ -785,7 +787,12 @@ static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd,
o->interrupt_enable = p->interrupt_enable;
o->enable = p->enable;
if (p->enable) {
- kfifo_reset(state->rx_kfifo);
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->rx_kfifo_lock, flags);
+ kfifo_reset(&state->rx_kfifo);
+ /* reset tx_fifo too if there is one... */
+ spin_unlock_irqrestore(&state->rx_kfifo_lock, flags);
if (p->interrupt_enable)
irqenable_rx(dev, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE);
control_rx_enable(dev, p->enable);
@@ -892,7 +899,6 @@ static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd,
o->interrupt_enable = p->interrupt_enable;
o->enable = p->enable;
if (p->enable) {
- kfifo_reset(state->tx_kfifo);
if (p->interrupt_enable)
irqenable_tx(dev, IRQEN_TSE);
control_tx_enable(dev, p->enable);
@@ -1168,18 +1174,8 @@ int cx23888_ir_probe(struct cx23885_dev *dev)
return -ENOMEM;
spin_lock_init(&state->rx_kfifo_lock);
- state->rx_kfifo = kfifo_alloc(CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL,
- &state->rx_kfifo_lock);
- if (state->rx_kfifo == NULL)
- return -ENOMEM;
-
- spin_lock_init(&state->tx_kfifo_lock);
- state->tx_kfifo = kfifo_alloc(CX23888_IR_TX_KFIFO_SIZE, GFP_KERNEL,
- &state->tx_kfifo_lock);
- if (state->tx_kfifo == NULL) {
- kfifo_free(state->rx_kfifo);
+ if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL))
return -ENOMEM;
- }
state->dev = dev;
state->id = V4L2_IDENT_CX23888_IR;
@@ -1211,8 +1207,7 @@ int cx23888_ir_probe(struct cx23885_dev *dev)
sizeof(struct v4l2_subdev_ir_parameters));
v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params);
} else {
- kfifo_free(state->rx_kfifo);
- kfifo_free(state->tx_kfifo);
+ kfifo_free(&state->rx_kfifo);
}
return ret;
}
@@ -1231,8 +1226,7 @@ int cx23888_ir_remove(struct cx23885_dev *dev)
state = to_state(sd);
v4l2_device_unregister_subdev(sd);
- kfifo_free(state->rx_kfifo);
- kfifo_free(state->tx_kfifo);
+ kfifo_free(&state->rx_kfifo);
kfree(state);
/* Nothing more to free() as state held the actual v4l2_subdev object */
return 0;
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 6ffa64cd1c6..b421858ccf9 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -800,8 +800,8 @@ again:
return IRQ_HANDLED;
if (meye.mchip_mode == MCHIP_HIC_MODE_CONT_OUT) {
- if (kfifo_get(meye.grabq, (unsigned char *)&reqnr,
- sizeof(int)) != sizeof(int)) {
+ if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr,
+ sizeof(int), &meye.grabq_lock) != sizeof(int)) {
mchip_free_frame();
return IRQ_HANDLED;
}
@@ -811,7 +811,8 @@ again:
meye.grab_buffer[reqnr].state = MEYE_BUF_DONE;
do_gettimeofday(&meye.grab_buffer[reqnr].timestamp);
meye.grab_buffer[reqnr].sequence = sequence++;
- kfifo_put(meye.doneq, (unsigned char *)&reqnr, sizeof(int));
+ kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr,
+ sizeof(int), &meye.doneq_lock);
wake_up_interruptible(&meye.proc_list);
} else {
int size;
@@ -820,8 +821,8 @@ again:
mchip_free_frame();
goto again;
}
- if (kfifo_get(meye.grabq, (unsigned char *)&reqnr,
- sizeof(int)) != sizeof(int)) {
+ if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr,
+ sizeof(int), &meye.grabq_lock) != sizeof(int)) {
mchip_free_frame();
goto again;
}
@@ -831,7 +832,8 @@ again:
meye.grab_buffer[reqnr].state = MEYE_BUF_DONE;
do_gettimeofday(&meye.grab_buffer[reqnr].timestamp);
meye.grab_buffer[reqnr].sequence = sequence++;
- kfifo_put(meye.doneq, (unsigned char *)&reqnr, sizeof(int));
+ kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr,
+ sizeof(int), &meye.doneq_lock);
wake_up_interruptible(&meye.proc_list);
}
mchip_free_frame();
@@ -859,8 +861,8 @@ static int meye_open(struct file *file)
for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
- kfifo_reset(meye.grabq);
- kfifo_reset(meye.doneq);
+ kfifo_reset(&meye.grabq);
+ kfifo_reset(&meye.doneq);
return 0;
}
@@ -933,7 +935,8 @@ static int meyeioc_qbuf_capt(int *nb)
mchip_cont_compression_start();
meye.grab_buffer[*nb].state = MEYE_BUF_USING;
- kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int));
+ kfifo_in_locked(&meye.grabq, (unsigned char *)nb, sizeof(int),
+ &meye.grabq_lock);
mutex_unlock(&meye.lock);
return 0;
@@ -965,7 +968,9 @@ static int meyeioc_sync(struct file *file, void *fh, int *i)
/* fall through */
case MEYE_BUF_DONE:
meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
- kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
+ if (kfifo_out_locked(&meye.doneq, (unsigned char *)&unused,
+ sizeof(int), &meye.doneq_lock) != sizeof(int))
+ break;
}
*i = meye.grab_buffer[*i].size;
mutex_unlock(&meye.lock);
@@ -1452,7 +1457,8 @@ static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
buf->flags |= V4L2_BUF_FLAG_QUEUED;
buf->flags &= ~V4L2_BUF_FLAG_DONE;
meye.grab_buffer[buf->index].state = MEYE_BUF_USING;
- kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int));
+ kfifo_in_locked(&meye.grabq, (unsigned char *)&buf->index,
+ sizeof(int), &meye.grabq_lock);
mutex_unlock(&meye.lock);
return 0;
@@ -1467,19 +1473,19 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
mutex_lock(&meye.lock);
- if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
+ if (kfifo_len(&meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
mutex_unlock(&meye.lock);
return -EAGAIN;
}
if (wait_event_interruptible(meye.proc_list,
- kfifo_len(meye.doneq) != 0) < 0) {
+ kfifo_len(&meye.doneq) != 0) < 0) {
mutex_unlock(&meye.lock);
return -EINTR;
}
- if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr,
- sizeof(int))) {
+ if (!kfifo_out_locked(&meye.doneq, (unsigned char *)&reqnr,
+ sizeof(int), &meye.doneq_lock)) {
mutex_unlock(&meye.lock);
return -EBUSY;
}
@@ -1529,8 +1535,8 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
{
mutex_lock(&meye.lock);
mchip_hic_stop();
- kfifo_reset(meye.grabq);
- kfifo_reset(meye.doneq);
+ kfifo_reset(&meye.grabq);
+ kfifo_reset(&meye.doneq);
for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
@@ -1572,7 +1578,7 @@ static unsigned int meye_poll(struct file *file, poll_table *wait)
mutex_lock(&meye.lock);
poll_wait(file, &meye.proc_list, wait);
- if (kfifo_len(meye.doneq))
+ if (kfifo_len(&meye.doneq))
res = POLLIN | POLLRDNORM;
mutex_unlock(&meye.lock);
return res;
@@ -1745,16 +1751,14 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
}
spin_lock_init(&meye.grabq_lock);
- meye.grabq = kfifo_alloc(sizeof(int) * MEYE_MAX_BUFNBRS, GFP_KERNEL,
- &meye.grabq_lock);
- if (IS_ERR(meye.grabq)) {
+ if (kfifo_alloc(&meye.grabq, sizeof(int) * MEYE_MAX_BUFNBRS,
+ GFP_KERNEL)) {
printk(KERN_ERR "meye: fifo allocation failed\n");
goto outkfifoalloc1;
}
spin_lock_init(&meye.doneq_lock);
- meye.doneq = kfifo_alloc(sizeof(int) * MEYE_MAX_BUFNBRS, GFP_KERNEL,
- &meye.doneq_lock);
- if (IS_ERR(meye.doneq)) {
+ if (kfifo_alloc(&meye.doneq, sizeof(int) * MEYE_MAX_BUFNBRS,
+ GFP_KERNEL)) {
printk(KERN_ERR "meye: fifo allocation failed\n");
goto outkfifoalloc2;
}
@@ -1868,9 +1872,9 @@ outregions:
outenabledev:
sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);
outsonypienable:
- kfifo_free(meye.doneq);
+ kfifo_free(&meye.doneq);
outkfifoalloc2:
- kfifo_free(meye.grabq);
+ kfifo_free(&meye.grabq);
outkfifoalloc1:
vfree(meye.grab_temp);
outvmalloc:
@@ -1901,8 +1905,8 @@ static void __devexit meye_remove(struct pci_dev *pcidev)
sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);
- kfifo_free(meye.doneq);
- kfifo_free(meye.grabq);
+ kfifo_free(&meye.doneq);
+ kfifo_free(&meye.grabq);
vfree(meye.grab_temp);
diff --git a/drivers/media/video/meye.h b/drivers/media/video/meye.h
index 5f70a106ba2..1321ad5d659 100644
--- a/drivers/media/video/meye.h
+++ b/drivers/media/video/meye.h
@@ -303,9 +303,9 @@ struct meye {
struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS];
int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */
struct mutex lock; /* mutex for open/mmap... */
- struct kfifo *grabq; /* queue for buffers to be grabbed */
+ struct kfifo grabq; /* queue for buffers to be grabbed */
spinlock_t grabq_lock; /* lock protecting the queue */
- struct kfifo *doneq; /* queue for grabbed buffers */
+ struct kfifo doneq; /* queue for grabbed buffers */
spinlock_t doneq_lock; /* lock protecting the queue */
wait_queue_head_t proc_list; /* wait queue */
struct video_device *video_dev; /* video device parameters */
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 610e914abe6..85bc6a685e3 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -1587,7 +1587,7 @@ mpt_mapresources(MPT_ADAPTER *ioc)
{
u8 __iomem *mem;
int ii;
- unsigned long mem_phys;
+ resource_size_t mem_phys;
unsigned long port;
u32 msize;
u32 psize;
@@ -1677,8 +1677,8 @@ mpt_mapresources(MPT_ADAPTER *ioc)
return -EINVAL;
}
ioc->memmap = mem;
- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
- ioc->name, mem, mem_phys));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %llx\n",
+ ioc->name, mem, (unsigned long long)mem_phys));
ioc->mem_phys = mem_phys;
ioc->chip = (SYSIF_REGS __iomem *)mem;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 1a7a9fc50ea..e3551d20464 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -203,6 +203,7 @@ config CS5535_MFGPT
config CS5535_MFGPT_DEFAULT_IRQ
int
+ depends on CS5535_MFGPT
default 7
help
MFGPTs on the CS5535 require an interrupt. The selected IRQ
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c
index e9eae4a7840..1eac626e710 100644
--- a/drivers/misc/enclosure.c
+++ b/drivers/misc/enclosure.c
@@ -391,6 +391,7 @@ static const char *const enclosure_status [] = {
[ENCLOSURE_STATUS_NOT_INSTALLED] = "not installed",
[ENCLOSURE_STATUS_UNKNOWN] = "unknown",
[ENCLOSURE_STATUS_UNAVAILABLE] = "unavailable",
+ [ENCLOSURE_STATUS_MAX] = NULL,
};
static const char *const enclosure_type [] = {
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index cdb845b68ab..06b64085a35 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -516,7 +516,8 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
* The number of functions on the card is encoded inside
* the ocr.
*/
- card->sdio_funcs = funcs = (ocr & 0x70000000) >> 28;
+ funcs = (ocr & 0x70000000) >> 28;
+ card->sdio_funcs = 0;
/*
* If needed, disconnect card detection pull-up resistor.
@@ -528,7 +529,7 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
/*
* Initialize (but don't add) all present functions.
*/
- for (i = 0;i < funcs;i++) {
+ for (i = 0; i < funcs; i++, card->sdio_funcs++) {
err = sdio_init_func(host->card, i + 1);
if (err)
goto remove;
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index d37464e296a..9e060c87e64 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -248,12 +248,15 @@ int sdio_add_func(struct sdio_func *func)
/*
* Unregister a SDIO function with the driver model, and
* (eventually) free it.
+ * This function can be called through error paths where sdio_add_func() was
+ * never executed (because a failure occurred at an earlier point).
*/
void sdio_remove_func(struct sdio_func *func)
{
- if (sdio_func_present(func))
- device_del(&func->dev);
+ if (!sdio_func_present(func))
+ return;
+ device_del(&func->dev);
put_device(&func->dev);
}
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 9d405b18178..ce1d28884e2 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -44,6 +44,19 @@ config MMC_SDHCI_IO_ACCESSORS
This is silent Kconfig symbol that is selected by the drivers that
need to overwrite SDHCI IO memory accessors.
+config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
+ bool
+ select MMC_SDHCI_IO_ACCESSORS
+ help
+ This option is selected by drivers running on big endian hosts
+ and performing I/O to a SDHCI controller through a bus that
+ implements a hardware byte swapper using a 32-bit datum.
+ This endian mapping mode is called "data invariance" and
+ has the effect of scrambling the addresses and formats of data
+ accessed in sizes other than the datum size.
+
+ This is the case for the Freescale eSDHC and Nintendo Wii SDHCI.
+
config MMC_SDHCI_PCI
tristate "SDHCI support on PCI bus"
depends on MMC_SDHCI && PCI
@@ -75,11 +88,29 @@ config MMC_RICOH_MMC
config MMC_SDHCI_OF
tristate "SDHCI support on OpenFirmware platforms"
depends on MMC_SDHCI && PPC_OF
- select MMC_SDHCI_IO_ACCESSORS
help
This selects the OF support for Secure Digital Host Controller
- Interfaces. So far, only the Freescale eSDHC controller is known
- to exist on OF platforms.
+ Interfaces.
+
+ If unsure, say N.
+
+config MMC_SDHCI_OF_ESDHC
+ bool "SDHCI OF support for the Freescale eSDHC controller"
+ depends on MMC_SDHCI_OF
+ select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
+ help
+ This selects the Freescale eSDHC controller support.
+
+ If unsure, say N.
+
+config MMC_SDHCI_OF_HLWD
+ bool "SDHCI OF support for the Nintendo Wii SDHCI controllers"
+ depends on MMC_SDHCI_OF
+ select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
+ help
+ This selects the Secure Digital Host Controller Interface (SDHCI)
+ found in the "Hollywood" chipset of the Nintendo Wii video game
+ console.
If unsure, say N.
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index ded4d8cdd9d..3d253dd4240 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -13,7 +13,6 @@ obj-$(CONFIG_MMC_MXC) += mxcmmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
obj-$(CONFIG_MMC_RICOH_MMC) += ricoh_mmc.o
-obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o
obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o
obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
@@ -37,6 +36,11 @@ obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
+obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o
+sdhci-of-y := sdhci-of-core.o
+sdhci-of-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
+sdhci-of-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
+
ifeq ($(CONFIG_CB710_DEBUG),y)
CFLAGS-cb710-mmc += -DDEBUG
endif
diff --git a/drivers/mmc/host/sdhci-of.c b/drivers/mmc/host/sdhci-of-core.c
index 01ab916c280..55e33135edb 100644
--- a/drivers/mmc/host/sdhci-of.c
+++ b/drivers/mmc/host/sdhci-of-core.c
@@ -22,62 +22,37 @@
#include <linux/of_platform.h>
#include <linux/mmc/host.h>
#include <asm/machdep.h>
+#include "sdhci-of.h"
#include "sdhci.h"
-struct sdhci_of_data {
- unsigned int quirks;
- struct sdhci_ops ops;
-};
-
-struct sdhci_of_host {
- unsigned int clock;
- u16 xfer_mode_shadow;
-};
+#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
/*
- * Ops and quirks for the Freescale eSDHC controller.
+ * These accessors are designed for big endian hosts doing I/O to
+ * little endian controllers incorporating a 32-bit hardware byte swapper.
*/
-#define ESDHC_DMA_SYSCTL 0x40c
-#define ESDHC_DMA_SNOOP 0x00000040
-
-#define ESDHC_SYSTEM_CONTROL 0x2c
-#define ESDHC_CLOCK_MASK 0x0000fff0
-#define ESDHC_PREDIV_SHIFT 8
-#define ESDHC_DIVIDER_SHIFT 4
-#define ESDHC_CLOCK_PEREN 0x00000004
-#define ESDHC_CLOCK_HCKEN 0x00000002
-#define ESDHC_CLOCK_IPGEN 0x00000001
-
-#define ESDHC_HOST_CONTROL_RES 0x05
-
-static u32 esdhc_readl(struct sdhci_host *host, int reg)
+u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg)
{
return in_be32(host->ioaddr + reg);
}
-static u16 esdhc_readw(struct sdhci_host *host, int reg)
+u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg)
{
- u16 ret;
-
- if (unlikely(reg == SDHCI_HOST_VERSION))
- ret = in_be16(host->ioaddr + reg);
- else
- ret = in_be16(host->ioaddr + (reg ^ 0x2));
- return ret;
+ return in_be16(host->ioaddr + (reg ^ 0x2));
}
-static u8 esdhc_readb(struct sdhci_host *host, int reg)
+u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg)
{
return in_8(host->ioaddr + (reg ^ 0x3));
}
-static void esdhc_writel(struct sdhci_host *host, u32 val, int reg)
+void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg)
{
out_be32(host->ioaddr + reg, val);
}
-static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
+void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg)
{
struct sdhci_of_host *of_host = sdhci_priv(host);
int base = reg & ~0x3;
@@ -92,106 +67,21 @@ static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
of_host->xfer_mode_shadow = val;
return;
case SDHCI_COMMAND:
- esdhc_writel(host, val << 16 | of_host->xfer_mode_shadow,
- SDHCI_TRANSFER_MODE);
+ sdhci_be32bs_writel(host, val << 16 | of_host->xfer_mode_shadow,
+ SDHCI_TRANSFER_MODE);
return;
- case SDHCI_BLOCK_SIZE:
- /*
- * Two last DMA bits are reserved, and first one is used for
- * non-standard blksz of 4096 bytes that we don't support
- * yet. So clear the DMA boundary bits.
- */
- val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
- /* fall through */
}
clrsetbits_be32(host->ioaddr + base, 0xffff << shift, val << shift);
}
-static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
+void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
{
int base = reg & ~0x3;
int shift = (reg & 0x3) * 8;
- /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
- if (reg == SDHCI_HOST_CONTROL)
- val &= ~ESDHC_HOST_CONTROL_RES;
-
clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift);
}
-
-static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
-{
- int pre_div = 2;
- int div = 1;
-
- clrbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
- ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK);
-
- if (clock == 0)
- goto out;
-
- while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
- pre_div *= 2;
-
- while (host->max_clk / pre_div / div > clock && div < 16)
- div++;
-
- dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
- clock, host->max_clk / pre_div / div);
-
- pre_div >>= 1;
- div--;
-
- setbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
- ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN |
- div << ESDHC_DIVIDER_SHIFT | pre_div << ESDHC_PREDIV_SHIFT);
- mdelay(100);
-out:
- host->clock = clock;
-}
-
-static int esdhc_enable_dma(struct sdhci_host *host)
-{
- setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
- return 0;
-}
-
-static unsigned int esdhc_get_max_clock(struct sdhci_host *host)
-{
- struct sdhci_of_host *of_host = sdhci_priv(host);
-
- return of_host->clock;
-}
-
-static unsigned int esdhc_get_min_clock(struct sdhci_host *host)
-{
- struct sdhci_of_host *of_host = sdhci_priv(host);
-
- return of_host->clock / 256 / 16;
-}
-
-static struct sdhci_of_data sdhci_esdhc = {
- .quirks = SDHCI_QUIRK_FORCE_BLK_SZ_2048 |
- SDHCI_QUIRK_BROKEN_CARD_DETECTION |
- SDHCI_QUIRK_NO_BUSY_IRQ |
- SDHCI_QUIRK_NONSTANDARD_CLOCK |
- SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
- SDHCI_QUIRK_PIO_NEEDS_DELAY |
- SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET |
- SDHCI_QUIRK_NO_CARD_NO_RESET,
- .ops = {
- .readl = esdhc_readl,
- .readw = esdhc_readw,
- .readb = esdhc_readb,
- .writel = esdhc_writel,
- .writew = esdhc_writew,
- .writeb = esdhc_writeb,
- .set_clock = esdhc_set_clock,
- .enable_dma = esdhc_enable_dma,
- .get_max_clock = esdhc_get_max_clock,
- .get_min_clock = esdhc_get_min_clock,
- },
-};
+#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
#ifdef CONFIG_PM
@@ -301,9 +191,14 @@ static int __devexit sdhci_of_remove(struct of_device *ofdev)
}
static const struct of_device_id sdhci_of_match[] = {
+#ifdef CONFIG_MMC_SDHCI_OF_ESDHC
{ .compatible = "fsl,mpc8379-esdhc", .data = &sdhci_esdhc, },
{ .compatible = "fsl,mpc8536-esdhc", .data = &sdhci_esdhc, },
{ .compatible = "fsl,esdhc", .data = &sdhci_esdhc, },
+#endif
+#ifdef CONFIG_MMC_SDHCI_OF_HLWD
+ { .compatible = "nintendo,hollywood-sdhci", .data = &sdhci_hlwd, },
+#endif
{ .compatible = "generic-sdhci", },
{},
};
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
new file mode 100644
index 00000000000..d5b11a17e64
--- /dev/null
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -0,0 +1,143 @@
+/*
+ * Freescale eSDHC controller driver.
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ * Copyright (c) 2009 MontaVista Software, Inc.
+ *
+ * Authors: Xiaobo Xie <X.Xie@freescale.com>
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/mmc/host.h>
+#include "sdhci-of.h"
+#include "sdhci.h"
+
+/*
+ * Ops and quirks for the Freescale eSDHC controller.
+ */
+
+#define ESDHC_DMA_SYSCTL 0x40c
+#define ESDHC_DMA_SNOOP 0x00000040
+
+#define ESDHC_SYSTEM_CONTROL 0x2c
+#define ESDHC_CLOCK_MASK 0x0000fff0
+#define ESDHC_PREDIV_SHIFT 8
+#define ESDHC_DIVIDER_SHIFT 4
+#define ESDHC_CLOCK_PEREN 0x00000004
+#define ESDHC_CLOCK_HCKEN 0x00000002
+#define ESDHC_CLOCK_IPGEN 0x00000001
+
+#define ESDHC_HOST_CONTROL_RES 0x05
+
+static u16 esdhc_readw(struct sdhci_host *host, int reg)
+{
+ u16 ret;
+
+ if (unlikely(reg == SDHCI_HOST_VERSION))
+ ret = in_be16(host->ioaddr + reg);
+ else
+ ret = sdhci_be32bs_readw(host, reg);
+ return ret;
+}
+
+static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
+{
+ if (reg == SDHCI_BLOCK_SIZE) {
+ /*
+ * Two last DMA bits are reserved, and first one is used for
+ * non-standard blksz of 4096 bytes that we don't support
+ * yet. So clear the DMA boundary bits.
+ */
+ val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
+ }
+ sdhci_be32bs_writew(host, val, reg);
+}
+
+static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+ /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
+ if (reg == SDHCI_HOST_CONTROL)
+ val &= ~ESDHC_HOST_CONTROL_RES;
+ sdhci_be32bs_writeb(host, val, reg);
+}
+
+static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ int pre_div = 2;
+ int div = 1;
+
+ clrbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
+ ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK);
+
+ if (clock == 0)
+ goto out;
+
+ while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
+ pre_div *= 2;
+
+ while (host->max_clk / pre_div / div > clock && div < 16)
+ div++;
+
+ dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
+ clock, host->max_clk / pre_div / div);
+
+ pre_div >>= 1;
+ div--;
+
+ setbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
+ ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN |
+ div << ESDHC_DIVIDER_SHIFT | pre_div << ESDHC_PREDIV_SHIFT);
+ mdelay(100);
+out:
+ host->clock = clock;
+}
+
+static int esdhc_enable_dma(struct sdhci_host *host)
+{
+ setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
+ return 0;
+}
+
+static unsigned int esdhc_get_max_clock(struct sdhci_host *host)
+{
+ struct sdhci_of_host *of_host = sdhci_priv(host);
+
+ return of_host->clock;
+}
+
+static unsigned int esdhc_get_min_clock(struct sdhci_host *host)
+{
+ struct sdhci_of_host *of_host = sdhci_priv(host);
+
+ return of_host->clock / 256 / 16;
+}
+
+struct sdhci_of_data sdhci_esdhc = {
+ .quirks = SDHCI_QUIRK_FORCE_BLK_SZ_2048 |
+ SDHCI_QUIRK_BROKEN_CARD_DETECTION |
+ SDHCI_QUIRK_NO_BUSY_IRQ |
+ SDHCI_QUIRK_NONSTANDARD_CLOCK |
+ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
+ SDHCI_QUIRK_PIO_NEEDS_DELAY |
+ SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET |
+ SDHCI_QUIRK_NO_CARD_NO_RESET,
+ .ops = {
+ .readl = sdhci_be32bs_readl,
+ .readw = esdhc_readw,
+ .readb = sdhci_be32bs_readb,
+ .writel = sdhci_be32bs_writel,
+ .writew = esdhc_writew,
+ .writeb = esdhc_writeb,
+ .set_clock = esdhc_set_clock,
+ .enable_dma = esdhc_enable_dma,
+ .get_max_clock = esdhc_get_max_clock,
+ .get_min_clock = esdhc_get_min_clock,
+ },
+};
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
new file mode 100644
index 00000000000..35117f3ed75
--- /dev/null
+++ b/drivers/mmc/host/sdhci-of-hlwd.c
@@ -0,0 +1,65 @@
+/*
+ * drivers/mmc/host/sdhci-of-hlwd.c
+ *
+ * Nintendo Wii Secure Digital Host Controller Interface.
+ * Copyright (C) 2009 The GameCube Linux Team
+ * Copyright (C) 2009 Albert Herranz
+ *
+ * Based on sdhci-of-esdhc.c
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ * Copyright (c) 2009 MontaVista Software, Inc.
+ *
+ * Authors: Xiaobo Xie <X.Xie@freescale.com>
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/mmc/host.h>
+#include "sdhci-of.h"
+#include "sdhci.h"
+
+/*
+ * Ops and quirks for the Nintendo Wii SDHCI controllers.
+ */
+
+/*
+ * We need a small delay after each write, or things go horribly wrong.
+ */
+#define SDHCI_HLWD_WRITE_DELAY 5 /* usecs */
+
+static void sdhci_hlwd_writel(struct sdhci_host *host, u32 val, int reg)
+{
+ sdhci_be32bs_writel(host, val, reg);
+ udelay(SDHCI_HLWD_WRITE_DELAY);
+}
+
+static void sdhci_hlwd_writew(struct sdhci_host *host, u16 val, int reg)
+{
+ sdhci_be32bs_writew(host, val, reg);
+ udelay(SDHCI_HLWD_WRITE_DELAY);
+}
+
+static void sdhci_hlwd_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+ sdhci_be32bs_writeb(host, val, reg);
+ udelay(SDHCI_HLWD_WRITE_DELAY);
+}
+
+struct sdhci_of_data sdhci_hlwd = {
+ .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
+ SDHCI_QUIRK_32BIT_DMA_SIZE,
+ .ops = {
+ .readl = sdhci_be32bs_readl,
+ .readw = sdhci_be32bs_readw,
+ .readb = sdhci_be32bs_readb,
+ .writel = sdhci_hlwd_writel,
+ .writew = sdhci_hlwd_writew,
+ .writeb = sdhci_hlwd_writeb,
+ },
+};
diff --git a/drivers/mmc/host/sdhci-of.h b/drivers/mmc/host/sdhci-of.h
new file mode 100644
index 00000000000..ad09ad9915d
--- /dev/null
+++ b/drivers/mmc/host/sdhci-of.h
@@ -0,0 +1,42 @@
+/*
+ * OpenFirmware bindings for Secure Digital Host Controller Interface.
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ * Copyright (c) 2009 MontaVista Software, Inc.
+ *
+ * Authors: Xiaobo Xie <X.Xie@freescale.com>
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * 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.
+ */
+
+#ifndef __SDHCI_OF_H
+#define __SDHCI_OF_H
+
+#include <linux/types.h>
+#include "sdhci.h"
+
+struct sdhci_of_data {
+ unsigned int quirks;
+ struct sdhci_ops ops;
+};
+
+struct sdhci_of_host {
+ unsigned int clock;
+ u16 xfer_mode_shadow;
+};
+
+extern u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg);
+extern u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg);
+extern u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg);
+extern void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg);
+extern void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg);
+extern void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg);
+
+extern struct sdhci_of_data sdhci_esdhc;
+extern struct sdhci_of_data sdhci_hlwd;
+
+#endif /* __SDHCI_OF_H */
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index ce5f1d73dc0..842f46f9428 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -8,6 +8,8 @@
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*/
+#ifndef __SDHCI_H
+#define __SDHCI_H
#include <linux/scatterlist.h>
#include <linux/compiler.h>
@@ -408,3 +410,5 @@ extern void sdhci_remove_host(struct sdhci_host *host, int dead);
extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state);
extern int sdhci_resume_host(struct sdhci_host *host);
#endif
+
+#endif /* __SDHCI_H */
diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c
index 74fa075c838..b13f6417b5b 100644
--- a/drivers/mtd/maps/pxa2xx-flash.c
+++ b/drivers/mtd/maps/pxa2xx-flash.c
@@ -20,14 +20,23 @@
#include <asm/io.h>
#include <mach/hardware.h>
-#include <asm/cacheflush.h>
#include <asm/mach/flash.h>
+#define CACHELINESIZE 32
+
static void pxa2xx_map_inval_cache(struct map_info *map, unsigned long from,
ssize_t len)
{
- flush_ioremap_region(map->phys, map->cached, from, len);
+ unsigned long start = (unsigned long)map->cached + from;
+ unsigned long end = start + len;
+
+ start &= ~(CACHELINESIZE - 1);
+ while (start < end) {
+ /* invalidate D cache line */
+ asm volatile ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start));
+ start += CACHELINESIZE;
+ }
}
struct pxa2xx_flash_info {
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7678538344f..677cd53f18c 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -291,14 +291,6 @@ config MTD_NAND_SHARPSL
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
depends on ARCH_PXA
-config MTD_NAND_BASLER_EXCITE
- tristate "Support for NAND Flash on Basler eXcite"
- depends on BASLER_EXCITE
- help
- This enables the driver for the NAND flash device found on the
- Basler eXcite Smart Camera. If built as a module, the driver
- will be named excite_nandflash.
-
config MTD_NAND_CAFE
tristate "NAND support for OLPC CAFÉ chip"
depends on PCI
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 460a1f39a8d..1407bd14401 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -27,7 +27,6 @@ obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o
obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o
obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
-obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o
obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
diff --git a/drivers/mtd/nand/excite_nandflash.c b/drivers/mtd/nand/excite_nandflash.c
deleted file mode 100644
index af6a6a5399e..00000000000
--- a/drivers/mtd/nand/excite_nandflash.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
-* Copyright (C) 2005 - 2007 by Basler Vision Technologies AG
-* Author: Thomas Koeller <thomas.koeller.qbaslerweb.com>
-* Original code by Thies Moeller <thies.moeller@baslerweb.com>
-*
-* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/rm9k-ocd.h>
-
-#include <excite_nandflash.h>
-
-#define EXCITE_NANDFLASH_VERSION "0.1"
-
-/* I/O register offsets */
-#define EXCITE_NANDFLASH_DATA_BYTE 0x00
-#define EXCITE_NANDFLASH_STATUS_BYTE 0x0c
-#define EXCITE_NANDFLASH_ADDR_BYTE 0x10
-#define EXCITE_NANDFLASH_CMD_BYTE 0x14
-
-/* prefix for debug output */
-static const char module_id[] = "excite_nandflash";
-
-/*
- * partition definition
- */
-static const struct mtd_partition partition_info[] = {
- {
- .name = "eXcite RootFS",
- .offset = 0,
- .size = MTDPART_SIZ_FULL
- }
-};
-
-static inline const struct resource *
-excite_nand_get_resource(struct platform_device *d, unsigned long flags,
- const char *basename)
-{
- char buf[80];
-
- if (snprintf(buf, sizeof buf, "%s_%u", basename, d->id) >= sizeof buf)
- return NULL;
- return platform_get_resource_byname(d, flags, buf);
-}
-
-static inline void __iomem *
-excite_nand_map_regs(struct platform_device *d, const char *basename)
-{
- void *result = NULL;
- const struct resource *const r =
- excite_nand_get_resource(d, IORESOURCE_MEM, basename);
-
- if (r)
- result = ioremap_nocache(r->start, r->end + 1 - r->start);
- return result;
-}
-
-/* controller and mtd information */
-struct excite_nand_drvdata {
- struct mtd_info board_mtd;
- struct nand_chip board_chip;
- void __iomem *regs;
- void __iomem *tgt;
-};
-
-/* Control function */
-static void excite_nand_control(struct mtd_info *mtd, int cmd,
- unsigned int ctrl)
-{
- struct excite_nand_drvdata * const d =
- container_of(mtd, struct excite_nand_drvdata, board_mtd);
-
- switch (ctrl) {
- case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
- d->tgt = d->regs + EXCITE_NANDFLASH_CMD_BYTE;
- break;
- case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
- d->tgt = d->regs + EXCITE_NANDFLASH_ADDR_BYTE;
- break;
- case NAND_CTRL_CHANGE | NAND_NCE:
- d->tgt = d->regs + EXCITE_NANDFLASH_DATA_BYTE;
- break;
- }
-
- if (cmd != NAND_CMD_NONE)
- __raw_writeb(cmd, d->tgt);
-}
-
-/* Return 0 if flash is busy, 1 if ready */
-static int excite_nand_devready(struct mtd_info *mtd)
-{
- struct excite_nand_drvdata * const drvdata =
- container_of(mtd, struct excite_nand_drvdata, board_mtd);
-
- return __raw_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS_BYTE);
-}
-
-/*
- * Called by device layer to remove the driver.
- * The binding to the mtd and all allocated
- * resources are released.
- */
-static int __devexit excite_nand_remove(struct platform_device *dev)
-{
- struct excite_nand_drvdata * const this = platform_get_drvdata(dev);
-
- platform_set_drvdata(dev, NULL);
-
- if (unlikely(!this)) {
- printk(KERN_ERR "%s: called %s without private data!!",
- module_id, __func__);
- return -EINVAL;
- }
-
- /* first thing we need to do is release our mtd
- * then go through freeing the resource used
- */
- nand_release(&this->board_mtd);
-
- /* free the common resources */
- iounmap(this->regs);
- kfree(this);
-
- DEBUG(MTD_DEBUG_LEVEL1, "%s: removed\n", module_id);
- return 0;
-}
-
-/*
- * Called by device layer when it finds a device matching
- * one our driver can handle. This code checks to see if
- * it can allocate all necessary resources then calls the
- * nand layer to look for devices.
-*/
-static int __init excite_nand_probe(struct platform_device *pdev)
-{
- struct excite_nand_drvdata *drvdata; /* private driver data */
- struct nand_chip *board_chip; /* private flash chip data */
- struct mtd_info *board_mtd; /* mtd info for this board */
- int scan_res;
-
- drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
- if (unlikely(!drvdata)) {
- printk(KERN_ERR "%s: no memory for drvdata\n",
- module_id);
- return -ENOMEM;
- }
-
- /* bind private data into driver */
- platform_set_drvdata(pdev, drvdata);
-
- /* allocate and map the resource */
- drvdata->regs =
- excite_nand_map_regs(pdev, EXCITE_NANDFLASH_RESOURCE_REGS);
-
- if (unlikely(!drvdata->regs)) {
- printk(KERN_ERR "%s: cannot reserve register region\n",
- module_id);
- kfree(drvdata);
- return -ENXIO;
- }
-
- drvdata->tgt = drvdata->regs + EXCITE_NANDFLASH_DATA_BYTE;
-
- /* initialise our chip */
- board_chip = &drvdata->board_chip;
- board_chip->IO_ADDR_R = board_chip->IO_ADDR_W =
- drvdata->regs + EXCITE_NANDFLASH_DATA_BYTE;
- board_chip->cmd_ctrl = excite_nand_control;
- board_chip->dev_ready = excite_nand_devready;
- board_chip->chip_delay = 25;
- board_chip->ecc.mode = NAND_ECC_SOFT;
-
- /* link chip to mtd */
- board_mtd = &drvdata->board_mtd;
- board_mtd->priv = board_chip;
-
- DEBUG(MTD_DEBUG_LEVEL2, "%s: device scan\n", module_id);
- scan_res = nand_scan(&drvdata->board_mtd, 1);
-
- if (likely(!scan_res)) {
- DEBUG(MTD_DEBUG_LEVEL2, "%s: register partitions\n", module_id);
- add_mtd_partitions(&drvdata->board_mtd, partition_info,
- ARRAY_SIZE(partition_info));
- } else {
- iounmap(drvdata->regs);
- kfree(drvdata);
- printk(KERN_ERR "%s: device scan failed\n", module_id);
- return -EIO;
- }
- return 0;
-}
-
-static struct platform_driver excite_nand_driver = {
- .driver = {
- .name = "excite_nand",
- .owner = THIS_MODULE,
- },
- .probe = excite_nand_probe,
- .remove = __devexit_p(excite_nand_remove)
-};
-
-static int __init excite_nand_init(void)
-{
- pr_info("Basler eXcite nand flash driver Version "
- EXCITE_NANDFLASH_VERSION "\n");
- return platform_driver_register(&excite_nand_driver);
-}
-
-static void __exit excite_nand_exit(void)
-{
- platform_driver_unregister(&excite_nand_driver);
-}
-
-module_init(excite_nand_init);
-module_exit(excite_nand_exit);
-
-MODULE_AUTHOR("Thomas Koeller <thomas.koeller@baslerweb.com>");
-MODULE_DESCRIPTION("Basler eXcite NAND-Flash driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(EXCITE_NANDFLASH_VERSION)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index a5be9ac6405..e58a65391ad 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1953,6 +1953,8 @@ config BCM63XX_ENET
source "drivers/net/fs_enet/Kconfig"
+source "drivers/net/octeon/Kconfig"
+
endif # NET_ETHERNET
#
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 246323d7f16..ad1346dd9da 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -285,3 +285,5 @@ obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
obj-$(CONFIG_SFC) += sfc/
obj-$(CONFIG_WIMAX) += wimax/
+
+obj-$(CONFIG_OCTEON_MGMT_ETHERNET) += octeon/
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 4bfc8081292..65df1de447e 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -653,12 +653,20 @@ static void
bnx2_netif_stop(struct bnx2 *bp)
{
bnx2_cnic_stop(bp);
- bnx2_disable_int_sync(bp);
if (netif_running(bp->dev)) {
+ int i;
+
bnx2_napi_disable(bp);
netif_tx_disable(bp->dev);
- bp->dev->trans_start = jiffies; /* prevent tx timeout */
+ /* prevent tx timeout */
+ for (i = 0; i < bp->dev->num_tx_queues; i++) {
+ struct netdev_queue *txq;
+
+ txq = netdev_get_tx_queue(bp->dev, i);
+ txq->trans_start = jiffies;
+ }
}
+ bnx2_disable_int_sync(bp);
}
static void
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index d0ec17878ff..166cc7e579c 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -1037,7 +1037,7 @@ static int __init at91_can_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
- if (!res || !irq) {
+ if (!res || irq <= 0) {
err = -ENODEV;
goto exit_put;
}
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index 8edac8915ea..34e03104c3c 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -2272,7 +2272,7 @@ static int emac_mii_reset(struct mii_bus *bus)
unsigned int clk_div;
int mdio_bus_freq = emac_bus_frequency;
- if (mdio_max_freq & mdio_bus_freq)
+ if (mdio_max_freq && mdio_bus_freq)
clk_div = ((mdio_bus_freq / mdio_max_freq) - 1);
else
clk_div = 0xFF;
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 929701ca07d..839fb2b136d 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1829,6 +1829,7 @@ static int e100_alloc_cbs(struct nic *nic)
&nic->cbs_dma_addr);
if (!nic->cbs)
return -ENOMEM;
+ memset(nic->cbs, 0, count * sizeof(struct cb));
for (cb = nic->cbs, i = 0; i < count; cb++, i++) {
cb->next = (i + 1 < count) ? cb + 1 : nic->cbs;
@@ -1837,7 +1838,6 @@ static int e100_alloc_cbs(struct nic *nic)
cb->dma_addr = nic->cbs_dma_addr + i * sizeof(struct cb);
cb->link = cpu_to_le32(nic->cbs_dma_addr +
((i+1) % count) * sizeof(struct cb));
- cb->skb = NULL;
}
nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = nic->cbs;
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index c1a42cfc80b..b979464091b 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/e1000e/82571.c
@@ -1290,7 +1290,6 @@ static s32 e1000_setup_link_82571(struct e1000_hw *hw)
static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw)
{
u32 ctrl;
- u32 led_ctrl;
s32 ret_val;
ctrl = er32(CTRL);
@@ -1305,11 +1304,6 @@ static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw)
break;
case e1000_phy_igp_2:
ret_val = e1000e_copper_link_setup_igp(hw);
- /* Setup activity LED */
- led_ctrl = er32(LEDCTL);
- led_ctrl &= IGP_ACTIVITY_LED_MASK;
- led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
- ew32(LEDCTL, led_ctrl);
break;
default:
return -E1000_ERR_PHY;
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 6850dc0a7b9..e0620d08464 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -357,8 +357,11 @@ static void gfar_init_mac(struct net_device *ndev)
/* Configure the coalescing support */
gfar_configure_coalescing(priv, 0xFF, 0xFF);
- if (priv->rx_filer_enable)
+ if (priv->rx_filer_enable) {
rctrl |= RCTRL_FILREN;
+ /* Program the RIR0 reg with the required distribution */
+ gfar_write(&regs->rir0, DEFAULT_RIR0);
+ }
if (priv->rx_csum_enable)
rctrl |= RCTRL_CHECKSUMMING;
@@ -414,6 +417,36 @@ static void gfar_init_mac(struct net_device *ndev)
gfar_write(&regs->fifo_tx_starve_shutoff, priv->fifo_starve_off);
}
+static struct net_device_stats *gfar_get_stats(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ struct netdev_queue *txq;
+ unsigned long rx_packets = 0, rx_bytes = 0, rx_dropped = 0;
+ unsigned long tx_packets = 0, tx_bytes = 0;
+ int i = 0;
+
+ for (i = 0; i < priv->num_rx_queues; i++) {
+ rx_packets += priv->rx_queue[i]->stats.rx_packets;
+ rx_bytes += priv->rx_queue[i]->stats.rx_bytes;
+ rx_dropped += priv->rx_queue[i]->stats.rx_dropped;
+ }
+
+ dev->stats.rx_packets = rx_packets;
+ dev->stats.rx_bytes = rx_bytes;
+ dev->stats.rx_dropped = rx_dropped;
+
+ for (i = 0; i < priv->num_tx_queues; i++) {
+ txq = netdev_get_tx_queue(dev, i);
+ tx_bytes += txq->tx_bytes;
+ tx_packets += txq->tx_packets;
+ }
+
+ dev->stats.tx_bytes = tx_bytes;
+ dev->stats.tx_packets = tx_packets;
+
+ return &dev->stats;
+}
+
static const struct net_device_ops gfar_netdev_ops = {
.ndo_open = gfar_enet_open,
.ndo_start_xmit = gfar_start_xmit,
@@ -423,6 +456,7 @@ static const struct net_device_ops gfar_netdev_ops = {
.ndo_tx_timeout = gfar_timeout,
.ndo_do_ioctl = gfar_ioctl,
.ndo_select_queue = gfar_select_queue,
+ .ndo_get_stats = gfar_get_stats,
.ndo_vlan_rx_register = gfar_vlan_rx_register,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
@@ -1022,6 +1056,9 @@ static int gfar_probe(struct of_device *ofdev,
priv->rx_queue[i]->rxic = DEFAULT_RXIC;
}
+ /* enable filer if using multiple RX queues*/
+ if(priv->num_rx_queues > 1)
+ priv->rx_filer_enable = 1;
/* Enable most messages by default */
priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
@@ -1937,7 +1974,8 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
/* Update transmit stats */
- dev->stats.tx_bytes += skb->len;
+ txq->tx_bytes += skb->len;
+ txq->tx_packets ++;
txbdp = txbdp_start = tx_queue->cur_tx;
@@ -2295,8 +2333,6 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
tx_queue->skb_dirtytx = skb_dirtytx;
tx_queue->dirty_tx = bdp;
- dev->stats.tx_packets += howmany;
-
return howmany;
}
@@ -2510,14 +2546,14 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
}
} else {
/* Increment the number of packets */
- dev->stats.rx_packets++;
+ rx_queue->stats.rx_packets++;
howmany++;
if (likely(skb)) {
pkt_len = bdp->length - ETH_FCS_LEN;
/* Remove the FCS from the packet length */
skb_put(skb, pkt_len);
- dev->stats.rx_bytes += pkt_len;
+ rx_queue->stats.rx_bytes += pkt_len;
gfar_process_frame(dev, skb, amount_pull);
@@ -2525,7 +2561,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
if (netif_msg_rx_err(priv))
printk(KERN_WARNING
"%s: Missing skb!\n", dev->name);
- dev->stats.rx_dropped++;
+ rx_queue->stats.rx_dropped++;
priv->extra_stats.rx_skbmissing++;
}
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index cbb451011cb..3d72dc43dca 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -333,7 +333,7 @@ extern const char gfar_driver_version[];
#define IMASK_BSY 0x20000000
#define IMASK_EBERR 0x10000000
#define IMASK_MSRO 0x04000000
-#define IMASK_GRSC 0x02000000
+#define IMASK_GTSC 0x02000000
#define IMASK_BABT 0x01000000
#define IMASK_TXC 0x00800000
#define IMASK_TXEEN 0x00400000
@@ -344,7 +344,7 @@ extern const char gfar_driver_version[];
#define IMASK_XFUN 0x00010000
#define IMASK_RXB0 0x00008000
#define IMASK_MAG 0x00000800
-#define IMASK_GTSC 0x00000100
+#define IMASK_GRSC 0x00000100
#define IMASK_RXFEN0 0x00000080
#define IMASK_FIR 0x00000008
#define IMASK_FIQ 0x00000004
@@ -401,6 +401,10 @@ extern const char gfar_driver_version[];
#define FPR_FILER_MASK 0xFFFFFFFF
#define MAX_FILER_IDX 0xFF
+/* This default RIR value directly corresponds
+ * to the 3-bit hash value generated */
+#define DEFAULT_RIR0 0x05397700
+
/* RQFCR register bits */
#define RQFCR_GPI 0x80000000
#define RQFCR_HASHTBL_Q 0x00000000
@@ -936,6 +940,15 @@ struct gfar_priv_tx_q {
unsigned short txtime;
};
+/*
+ * Per RX queue stats
+ */
+struct rx_q_stats {
+ unsigned long rx_packets;
+ unsigned long rx_bytes;
+ unsigned long rx_dropped;
+};
+
/**
* struct gfar_priv_rx_q - per rx queue structure
* @rxlock: per queue rx spin lock
@@ -958,6 +971,7 @@ struct gfar_priv_rx_q {
struct rxbd8 *cur_rx;
struct net_device *dev;
struct gfar_priv_grp *grp;
+ struct rx_q_stats stats;
u16 skb_currx;
u16 qindex;
unsigned int rx_ring_size;
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index f4996846a23..6cae26a5bd6 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -57,7 +57,9 @@ static int use_msi = 1;
static int use_msi_x = 1;
-static unsigned long auto_fw_reset = AUTO_FW_RESET_ENABLED;
+static int auto_fw_reset = AUTO_FW_RESET_ENABLED;
+module_param(auto_fw_reset, int, 0644);
+MODULE_PARM_DESC(auto_fw_reset,"Auto firmware reset (0=disabled, 1=enabled");
static int __devinit netxen_nic_probe(struct pci_dev *pdev,
const struct pci_device_id *ent);
@@ -2534,42 +2536,6 @@ static struct bin_attribute bin_attr_mem = {
.write = netxen_sysfs_write_mem,
};
-#ifdef CONFIG_MODULES
-static ssize_t
-netxen_store_auto_fw_reset(struct module_attribute *mattr,
- struct module *mod, const char *buf, size_t count)
-
-{
- unsigned long new;
-
- if (strict_strtoul(buf, 16, &new))
- return -EINVAL;
-
- if ((new == AUTO_FW_RESET_ENABLED) || (new == AUTO_FW_RESET_DISABLED)) {
- auto_fw_reset = new;
- return count;
- }
-
- return -EINVAL;
-}
-
-static ssize_t
-netxen_show_auto_fw_reset(struct module_attribute *mattr,
- struct module *mod, char *buf)
-
-{
- if (auto_fw_reset == AUTO_FW_RESET_ENABLED)
- return sprintf(buf, "enabled\n");
- else
- return sprintf(buf, "disabled\n");
-}
-
-static struct module_attribute mod_attr_fw_reset = {
- .attr = {.name = "auto_fw_reset", .mode = (S_IRUGO | S_IWUSR)},
- .show = netxen_show_auto_fw_reset,
- .store = netxen_store_auto_fw_reset,
-};
-#endif
static void
netxen_create_sysfs_entries(struct netxen_adapter *adapter)
@@ -2775,23 +2741,12 @@ static struct pci_driver netxen_driver = {
static int __init netxen_init_module(void)
{
-#ifdef CONFIG_MODULES
- struct module *mod = THIS_MODULE;
-#endif
-
printk(KERN_INFO "%s\n", netxen_nic_driver_string);
#ifdef CONFIG_INET
register_netdevice_notifier(&netxen_netdev_cb);
register_inetaddr_notifier(&netxen_inetaddr_cb);
#endif
-
-#ifdef CONFIG_MODULES
- if (sysfs_create_file(&mod->mkobj.kobj, &mod_attr_fw_reset.attr))
- printk(KERN_ERR "%s: Failed to create auto_fw_reset "
- "sysfs entry.", netxen_nic_driver_name);
-#endif
-
return pci_register_driver(&netxen_driver);
}
@@ -2799,12 +2754,6 @@ module_init(netxen_init_module);
static void __exit netxen_exit_module(void)
{
-#ifdef CONFIG_MODULES
- struct module *mod = THIS_MODULE;
-
- sysfs_remove_file(&mod->mkobj.kobj, &mod_attr_fw_reset.attr);
-#endif
-
pci_unregister_driver(&netxen_driver);
#ifdef CONFIG_INET
diff --git a/drivers/net/octeon/Kconfig b/drivers/net/octeon/Kconfig
new file mode 100644
index 00000000000..1e56bbf3f5c
--- /dev/null
+++ b/drivers/net/octeon/Kconfig
@@ -0,0 +1,10 @@
+config OCTEON_MGMT_ETHERNET
+ tristate "Octeon Management port ethernet driver (CN5XXX, CN6XXX)"
+ depends on CPU_CAVIUM_OCTEON
+ select PHYLIB
+ select MDIO_OCTEON
+ default y
+ help
+ This option enables the ethernet driver for the management
+ port on Cavium Networks' Octeon CN57XX, CN56XX, CN55XX,
+ CN54XX, CN52XX, and CN6XXX chips.
diff --git a/drivers/net/octeon/Makefile b/drivers/net/octeon/Makefile
new file mode 100644
index 00000000000..906edecacfd
--- /dev/null
+++ b/drivers/net/octeon/Makefile
@@ -0,0 +1,2 @@
+
+obj-$(CONFIG_OCTEON_MGMT_ETHERNET) += octeon_mgmt.o
diff --git a/drivers/net/octeon/octeon_mgmt.c b/drivers/net/octeon/octeon_mgmt.c
new file mode 100644
index 00000000000..050538bf155
--- /dev/null
+++ b/drivers/net/octeon/octeon_mgmt.c
@@ -0,0 +1,1176 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Cavium Networks
+ */
+
+#include <linux/capability.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/phy.h>
+#include <linux/spinlock.h>
+
+#include <asm/octeon/octeon.h>
+#include <asm/octeon/cvmx-mixx-defs.h>
+#include <asm/octeon/cvmx-agl-defs.h>
+
+#define DRV_NAME "octeon_mgmt"
+#define DRV_VERSION "2.0"
+#define DRV_DESCRIPTION \
+ "Cavium Networks Octeon MII (management) port Network Driver"
+
+#define OCTEON_MGMT_NAPI_WEIGHT 16
+
+/*
+ * Ring sizes that are powers of two allow for more efficient modulo
+ * opertions.
+ */
+#define OCTEON_MGMT_RX_RING_SIZE 512
+#define OCTEON_MGMT_TX_RING_SIZE 128
+
+/* Allow 8 bytes for vlan and FCS. */
+#define OCTEON_MGMT_RX_HEADROOM (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN)
+
+union mgmt_port_ring_entry {
+ u64 d64;
+ struct {
+ u64 reserved_62_63:2;
+ /* Length of the buffer/packet in bytes */
+ u64 len:14;
+ /* For TX, signals that the packet should be timestamped */
+ u64 tstamp:1;
+ /* The RX error code */
+ u64 code:7;
+#define RING_ENTRY_CODE_DONE 0xf
+#define RING_ENTRY_CODE_MORE 0x10
+ /* Physical address of the buffer */
+ u64 addr:40;
+ } s;
+};
+
+struct octeon_mgmt {
+ struct net_device *netdev;
+ int port;
+ int irq;
+ u64 *tx_ring;
+ dma_addr_t tx_ring_handle;
+ unsigned int tx_next;
+ unsigned int tx_next_clean;
+ unsigned int tx_current_fill;
+ /* The tx_list lock also protects the ring related variables */
+ struct sk_buff_head tx_list;
+
+ /* RX variables only touched in napi_poll. No locking necessary. */
+ u64 *rx_ring;
+ dma_addr_t rx_ring_handle;
+ unsigned int rx_next;
+ unsigned int rx_next_fill;
+ unsigned int rx_current_fill;
+ struct sk_buff_head rx_list;
+
+ spinlock_t lock;
+ unsigned int last_duplex;
+ unsigned int last_link;
+ struct device *dev;
+ struct napi_struct napi;
+ struct tasklet_struct tx_clean_tasklet;
+ struct phy_device *phydev;
+};
+
+static void octeon_mgmt_set_rx_irq(struct octeon_mgmt *p, int enable)
+{
+ int port = p->port;
+ union cvmx_mixx_intena mix_intena;
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->lock, flags);
+ mix_intena.u64 = cvmx_read_csr(CVMX_MIXX_INTENA(port));
+ mix_intena.s.ithena = enable ? 1 : 0;
+ cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64);
+ spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static void octeon_mgmt_set_tx_irq(struct octeon_mgmt *p, int enable)
+{
+ int port = p->port;
+ union cvmx_mixx_intena mix_intena;
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->lock, flags);
+ mix_intena.u64 = cvmx_read_csr(CVMX_MIXX_INTENA(port));
+ mix_intena.s.othena = enable ? 1 : 0;
+ cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64);
+ spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static inline void octeon_mgmt_enable_rx_irq(struct octeon_mgmt *p)
+{
+ octeon_mgmt_set_rx_irq(p, 1);
+}
+
+static inline void octeon_mgmt_disable_rx_irq(struct octeon_mgmt *p)
+{
+ octeon_mgmt_set_rx_irq(p, 0);
+}
+
+static inline void octeon_mgmt_enable_tx_irq(struct octeon_mgmt *p)
+{
+ octeon_mgmt_set_tx_irq(p, 1);
+}
+
+static inline void octeon_mgmt_disable_tx_irq(struct octeon_mgmt *p)
+{
+ octeon_mgmt_set_tx_irq(p, 0);
+}
+
+static unsigned int ring_max_fill(unsigned int ring_size)
+{
+ return ring_size - 8;
+}
+
+static unsigned int ring_size_to_bytes(unsigned int ring_size)
+{
+ return ring_size * sizeof(union mgmt_port_ring_entry);
+}
+
+static void octeon_mgmt_rx_fill_ring(struct net_device *netdev)
+{
+ struct octeon_mgmt *p = netdev_priv(netdev);
+ int port = p->port;
+
+ while (p->rx_current_fill < ring_max_fill(OCTEON_MGMT_RX_RING_SIZE)) {
+ unsigned int size;
+ union mgmt_port_ring_entry re;
+ struct sk_buff *skb;
+
+ /* CN56XX pass 1 needs 8 bytes of padding. */
+ size = netdev->mtu + OCTEON_MGMT_RX_HEADROOM + 8 + NET_IP_ALIGN;
+
+ skb = netdev_alloc_skb(netdev, size);
+ if (!skb)
+ break;
+ skb_reserve(skb, NET_IP_ALIGN);
+ __skb_queue_tail(&p->rx_list, skb);
+
+ re.d64 = 0;
+ re.s.len = size;
+ re.s.addr = dma_map_single(p->dev, skb->data,
+ size,
+ DMA_FROM_DEVICE);
+
+ /* Put it in the ring. */
+ p->rx_ring[p->rx_next_fill] = re.d64;
+ dma_sync_single_for_device(p->dev, p->rx_ring_handle,
+ ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE),
+ DMA_BIDIRECTIONAL);
+ p->rx_next_fill =
+ (p->rx_next_fill + 1) % OCTEON_MGMT_RX_RING_SIZE;
+ p->rx_current_fill++;
+ /* Ring the bell. */
+ cvmx_write_csr(CVMX_MIXX_IRING2(port), 1);
+ }
+}
+
+static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p)
+{
+ int port = p->port;
+ union cvmx_mixx_orcnt mix_orcnt;
+ union mgmt_port_ring_entry re;
+ struct sk_buff *skb;
+ int cleaned = 0;
+ unsigned long flags;
+
+ mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port));
+ while (mix_orcnt.s.orcnt) {
+ dma_sync_single_for_cpu(p->dev, p->tx_ring_handle,
+ ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE),
+ DMA_BIDIRECTIONAL);
+
+ spin_lock_irqsave(&p->tx_list.lock, flags);
+
+ re.d64 = p->tx_ring[p->tx_next_clean];
+ p->tx_next_clean =
+ (p->tx_next_clean + 1) % OCTEON_MGMT_TX_RING_SIZE;
+ skb = __skb_dequeue(&p->tx_list);
+
+ mix_orcnt.u64 = 0;
+ mix_orcnt.s.orcnt = 1;
+
+ /* Acknowledge to hardware that we have the buffer. */
+ cvmx_write_csr(CVMX_MIXX_ORCNT(port), mix_orcnt.u64);
+ p->tx_current_fill--;
+
+ spin_unlock_irqrestore(&p->tx_list.lock, flags);
+
+ dma_unmap_single(p->dev, re.s.addr, re.s.len,
+ DMA_TO_DEVICE);
+ dev_kfree_skb_any(skb);
+ cleaned++;
+
+ mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port));
+ }
+
+ if (cleaned && netif_queue_stopped(p->netdev))
+ netif_wake_queue(p->netdev);
+}
+
+static void octeon_mgmt_clean_tx_tasklet(unsigned long arg)
+{
+ struct octeon_mgmt *p = (struct octeon_mgmt *)arg;
+ octeon_mgmt_clean_tx_buffers(p);
+ octeon_mgmt_enable_tx_irq(p);
+}
+
+static void octeon_mgmt_update_rx_stats(struct net_device *netdev)
+{
+ struct octeon_mgmt *p = netdev_priv(netdev);
+ int port = p->port;
+ unsigned long flags;
+ u64 drop, bad;
+
+ /* These reads also clear the count registers. */
+ drop = cvmx_read_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_DRP(port));
+ bad = cvmx_read_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_BAD(port));
+
+ if (drop || bad) {
+ /* Do an atomic update. */
+ spin_lock_irqsave(&p->lock, flags);
+ netdev->stats.rx_errors += bad;
+ netdev->stats.rx_dropped += drop;
+ spin_unlock_irqrestore(&p->lock, flags);
+ }
+}
+
+static void octeon_mgmt_update_tx_stats(struct net_device *netdev)
+{
+ struct octeon_mgmt *p = netdev_priv(netdev);
+ int port = p->port;
+ unsigned long flags;
+
+ union cvmx_agl_gmx_txx_stat0 s0;
+ union cvmx_agl_gmx_txx_stat1 s1;
+
+ /* These reads also clear the count registers. */
+ s0.u64 = cvmx_read_csr(CVMX_AGL_GMX_TXX_STAT0(port));
+ s1.u64 = cvmx_read_csr(CVMX_AGL_GMX_TXX_STAT1(port));
+
+ if (s0.s.xsdef || s0.s.xscol || s1.s.scol || s1.s.mcol) {
+ /* Do an atomic update. */
+ spin_lock_irqsave(&p->lock, flags);
+ netdev->stats.tx_errors += s0.s.xsdef + s0.s.xscol;
+ netdev->stats.collisions += s1.s.scol + s1.s.mcol;
+ spin_unlock_irqrestore(&p->lock, flags);
+ }
+}
+
+/*
+ * Dequeue a receive skb and its corresponding ring entry. The ring
+ * entry is returned, *pskb is updated to point to the skb.
+ */
+static u64 octeon_mgmt_dequeue_rx_buffer(struct octeon_mgmt *p,
+ struct sk_buff **pskb)
+{
+ union mgmt_port_ring_entry re;
+
+ dma_sync_single_for_cpu(p->dev, p->rx_ring_handle,
+ ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE),
+ DMA_BIDIRECTIONAL);
+
+ re.d64 = p->rx_ring[p->rx_next];
+ p->rx_next = (p->rx_next + 1) % OCTEON_MGMT_RX_RING_SIZE;
+ p->rx_current_fill--;
+ *pskb = __skb_dequeue(&p->rx_list);
+
+ dma_unmap_single(p->dev, re.s.addr,
+ ETH_FRAME_LEN + OCTEON_MGMT_RX_HEADROOM,
+ DMA_FROM_DEVICE);
+
+ return re.d64;
+}
+
+
+static int octeon_mgmt_receive_one(struct octeon_mgmt *p)
+{
+ int port = p->port;
+ struct net_device *netdev = p->netdev;
+ union cvmx_mixx_ircnt mix_ircnt;
+ union mgmt_port_ring_entry re;
+ struct sk_buff *skb;
+ struct sk_buff *skb2;
+ struct sk_buff *skb_new;
+ union mgmt_port_ring_entry re2;
+ int rc = 1;
+
+
+ re.d64 = octeon_mgmt_dequeue_rx_buffer(p, &skb);
+ if (likely(re.s.code == RING_ENTRY_CODE_DONE)) {
+ /* A good packet, send it up. */
+ skb_put(skb, re.s.len);
+good:
+ skb->protocol = eth_type_trans(skb, netdev);
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += skb->len;
+ netdev->last_rx = jiffies;
+ netif_receive_skb(skb);
+ rc = 0;
+ } else if (re.s.code == RING_ENTRY_CODE_MORE) {
+ /*
+ * Packet split across skbs. This can happen if we
+ * increase the MTU. Buffers that are already in the
+ * rx ring can then end up being too small. As the rx
+ * ring is refilled, buffers sized for the new MTU
+ * will be used and we should go back to the normal
+ * non-split case.
+ */
+ skb_put(skb, re.s.len);
+ do {
+ re2.d64 = octeon_mgmt_dequeue_rx_buffer(p, &skb2);
+ if (re2.s.code != RING_ENTRY_CODE_MORE
+ && re2.s.code != RING_ENTRY_CODE_DONE)
+ goto split_error;
+ skb_put(skb2, re2.s.len);
+ skb_new = skb_copy_expand(skb, 0, skb2->len,
+ GFP_ATOMIC);
+ if (!skb_new)
+ goto split_error;
+ if (skb_copy_bits(skb2, 0, skb_tail_pointer(skb_new),
+ skb2->len))
+ goto split_error;
+ skb_put(skb_new, skb2->len);
+ dev_kfree_skb_any(skb);
+ dev_kfree_skb_any(skb2);
+ skb = skb_new;
+ } while (re2.s.code == RING_ENTRY_CODE_MORE);
+ goto good;
+ } else {
+ /* Some other error, discard it. */
+ dev_kfree_skb_any(skb);
+ /*
+ * Error statistics are accumulated in
+ * octeon_mgmt_update_rx_stats.
+ */
+ }
+ goto done;
+split_error:
+ /* Discard the whole mess. */
+ dev_kfree_skb_any(skb);
+ dev_kfree_skb_any(skb2);
+ while (re2.s.code == RING_ENTRY_CODE_MORE) {
+ re2.d64 = octeon_mgmt_dequeue_rx_buffer(p, &skb2);
+ dev_kfree_skb_any(skb2);
+ }
+ netdev->stats.rx_errors++;
+
+done:
+ /* Tell the hardware we processed a packet. */
+ mix_ircnt.u64 = 0;
+ mix_ircnt.s.ircnt = 1;
+ cvmx_write_csr(CVMX_MIXX_IRCNT(port), mix_ircnt.u64);
+ return rc;
+
+}
+
+static int octeon_mgmt_receive_packets(struct octeon_mgmt *p, int budget)
+{
+ int port = p->port;
+ unsigned int work_done = 0;
+ union cvmx_mixx_ircnt mix_ircnt;
+ int rc;
+
+
+ mix_ircnt.u64 = cvmx_read_csr(CVMX_MIXX_IRCNT(port));
+ while (work_done < budget && mix_ircnt.s.ircnt) {
+
+ rc = octeon_mgmt_receive_one(p);
+ if (!rc)
+ work_done++;
+
+ /* Check for more packets. */
+ mix_ircnt.u64 = cvmx_read_csr(CVMX_MIXX_IRCNT(port));
+ }
+
+ octeon_mgmt_rx_fill_ring(p->netdev);
+
+ return work_done;
+}
+
+static int octeon_mgmt_napi_poll(struct napi_struct *napi, int budget)
+{
+ struct octeon_mgmt *p = container_of(napi, struct octeon_mgmt, napi);
+ struct net_device *netdev = p->netdev;
+ unsigned int work_done = 0;
+
+ work_done = octeon_mgmt_receive_packets(p, budget);
+
+ if (work_done < budget) {
+ /* We stopped because no more packets were available. */
+ napi_complete(napi);
+ octeon_mgmt_enable_rx_irq(p);
+ }
+ octeon_mgmt_update_rx_stats(netdev);
+
+ return work_done;
+}
+
+/* Reset the hardware to clean state. */
+static void octeon_mgmt_reset_hw(struct octeon_mgmt *p)
+{
+ union cvmx_mixx_ctl mix_ctl;
+ union cvmx_mixx_bist mix_bist;
+ union cvmx_agl_gmx_bist agl_gmx_bist;
+
+ mix_ctl.u64 = 0;
+ cvmx_write_csr(CVMX_MIXX_CTL(p->port), mix_ctl.u64);
+ do {
+ mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(p->port));
+ } while (mix_ctl.s.busy);
+ mix_ctl.s.reset = 1;
+ cvmx_write_csr(CVMX_MIXX_CTL(p->port), mix_ctl.u64);
+ cvmx_read_csr(CVMX_MIXX_CTL(p->port));
+ cvmx_wait(64);
+
+ mix_bist.u64 = cvmx_read_csr(CVMX_MIXX_BIST(p->port));
+ if (mix_bist.u64)
+ dev_warn(p->dev, "MIX failed BIST (0x%016llx)\n",
+ (unsigned long long)mix_bist.u64);
+
+ agl_gmx_bist.u64 = cvmx_read_csr(CVMX_AGL_GMX_BIST);
+ if (agl_gmx_bist.u64)
+ dev_warn(p->dev, "AGL failed BIST (0x%016llx)\n",
+ (unsigned long long)agl_gmx_bist.u64);
+}
+
+struct octeon_mgmt_cam_state {
+ u64 cam[6];
+ u64 cam_mask;
+ int cam_index;
+};
+
+static void octeon_mgmt_cam_state_add(struct octeon_mgmt_cam_state *cs,
+ unsigned char *addr)
+{
+ int i;
+
+ for (i = 0; i < 6; i++)
+ cs->cam[i] |= (u64)addr[i] << (8 * (cs->cam_index));
+ cs->cam_mask |= (1ULL << cs->cam_index);
+ cs->cam_index++;
+}
+
+static void octeon_mgmt_set_rx_filtering(struct net_device *netdev)
+{
+ struct octeon_mgmt *p = netdev_priv(netdev);
+ int port = p->port;
+ int i;
+ union cvmx_agl_gmx_rxx_adr_ctl adr_ctl;
+ union cvmx_agl_gmx_prtx_cfg agl_gmx_prtx;
+ unsigned long flags;
+ unsigned int prev_packet_enable;
+ unsigned int cam_mode = 1; /* 1 - Accept on CAM match */
+ unsigned int multicast_mode = 1; /* 1 - Reject all multicast. */
+ struct octeon_mgmt_cam_state cam_state;
+ struct dev_addr_list *list;
+ struct list_head *pos;
+ int available_cam_entries;
+
+ memset(&cam_state, 0, sizeof(cam_state));
+
+ if ((netdev->flags & IFF_PROMISC) || netdev->dev_addrs.count > 7) {
+ cam_mode = 0;
+ available_cam_entries = 8;
+ } else {
+ /*
+ * One CAM entry for the primary address, leaves seven
+ * for the secondary addresses.
+ */
+ available_cam_entries = 7 - netdev->dev_addrs.count;
+ }
+
+ if (netdev->flags & IFF_MULTICAST) {
+ if (cam_mode == 0 || (netdev->flags & IFF_ALLMULTI)
+ || netdev->mc_count > available_cam_entries)
+ multicast_mode = 2; /* 1 - Accept all multicast. */
+ else
+ multicast_mode = 0; /* 0 - Use CAM. */
+ }
+
+ if (cam_mode == 1) {
+ /* Add primary address. */
+ octeon_mgmt_cam_state_add(&cam_state, netdev->dev_addr);
+ list_for_each(pos, &netdev->dev_addrs.list) {
+ struct netdev_hw_addr *hw_addr;
+ hw_addr = list_entry(pos, struct netdev_hw_addr, list);
+ octeon_mgmt_cam_state_add(&cam_state, hw_addr->addr);
+ list = list->next;
+ }
+ }
+ if (multicast_mode == 0) {
+ i = netdev->mc_count;
+ list = netdev->mc_list;
+ while (i--) {
+ octeon_mgmt_cam_state_add(&cam_state, list->da_addr);
+ list = list->next;
+ }
+ }
+
+
+ spin_lock_irqsave(&p->lock, flags);
+
+ /* Disable packet I/O. */
+ agl_gmx_prtx.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
+ prev_packet_enable = agl_gmx_prtx.s.en;
+ agl_gmx_prtx.s.en = 0;
+ cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64);
+
+
+ adr_ctl.u64 = 0;
+ adr_ctl.s.cam_mode = cam_mode;
+ adr_ctl.s.mcst = multicast_mode;
+ adr_ctl.s.bcst = 1; /* Allow broadcast */
+
+ cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CTL(port), adr_ctl.u64);
+
+ cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM0(port), cam_state.cam[0]);
+ cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM1(port), cam_state.cam[1]);
+ cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM2(port), cam_state.cam[2]);
+ cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM3(port), cam_state.cam[3]);
+ cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM4(port), cam_state.cam[4]);
+ cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM5(port), cam_state.cam[5]);
+ cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM_EN(port), cam_state.cam_mask);
+
+ /* Restore packet I/O. */
+ agl_gmx_prtx.s.en = prev_packet_enable;
+ cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64);
+
+ spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static int octeon_mgmt_set_mac_address(struct net_device *netdev, void *addr)
+{
+ struct sockaddr *sa = addr;
+
+ if (!is_valid_ether_addr(sa->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(netdev->dev_addr, sa->sa_data, ETH_ALEN);
+
+ octeon_mgmt_set_rx_filtering(netdev);
+
+ return 0;
+}
+
+static int octeon_mgmt_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct octeon_mgmt *p = netdev_priv(netdev);
+ int port = p->port;
+ int size_without_fcs = new_mtu + OCTEON_MGMT_RX_HEADROOM;
+
+ /*
+ * Limit the MTU to make sure the ethernet packets are between
+ * 64 bytes and 16383 bytes.
+ */
+ if (size_without_fcs < 64 || size_without_fcs > 16383) {
+ dev_warn(p->dev, "MTU must be between %d and %d.\n",
+ 64 - OCTEON_MGMT_RX_HEADROOM,
+ 16383 - OCTEON_MGMT_RX_HEADROOM);
+ return -EINVAL;
+ }
+
+ netdev->mtu = new_mtu;
+
+ cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_MAX(port), size_without_fcs);
+ cvmx_write_csr(CVMX_AGL_GMX_RXX_JABBER(port),
+ (size_without_fcs + 7) & 0xfff8);
+
+ return 0;
+}
+
+static irqreturn_t octeon_mgmt_interrupt(int cpl, void *dev_id)
+{
+ struct net_device *netdev = dev_id;
+ struct octeon_mgmt *p = netdev_priv(netdev);
+ int port = p->port;
+ union cvmx_mixx_isr mixx_isr;
+
+ mixx_isr.u64 = cvmx_read_csr(CVMX_MIXX_ISR(port));
+
+ /* Clear any pending interrupts */
+ cvmx_write_csr(CVMX_MIXX_ISR(port),
+ cvmx_read_csr(CVMX_MIXX_ISR(port)));
+ cvmx_read_csr(CVMX_MIXX_ISR(port));
+
+ if (mixx_isr.s.irthresh) {
+ octeon_mgmt_disable_rx_irq(p);
+ napi_schedule(&p->napi);
+ }
+ if (mixx_isr.s.orthresh) {
+ octeon_mgmt_disable_tx_irq(p);
+ tasklet_schedule(&p->tx_clean_tasklet);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int octeon_mgmt_ioctl(struct net_device *netdev,
+ struct ifreq *rq, int cmd)
+{
+ struct octeon_mgmt *p = netdev_priv(netdev);
+
+ if (!netif_running(netdev))
+ return -EINVAL;
+
+ if (!p->phydev)
+ return -EINVAL;
+
+ return phy_mii_ioctl(p->phydev, if_mii(rq), cmd);
+}
+
+static void octeon_mgmt_adjust_link(struct net_device *netdev)
+{
+ struct octeon_mgmt *p = netdev_priv(netdev);
+ int port = p->port;
+ union cvmx_agl_gmx_prtx_cfg prtx_cfg;
+ unsigned long flags;
+ int link_changed = 0;
+
+ spin_lock_irqsave(&p->lock, flags);
+ if (p->phydev->link) {
+ if (!p->last_link)
+ link_changed = 1;
+ if (p->last_duplex != p->phydev->duplex) {
+ p->last_duplex = p->phydev->duplex;
+ prtx_cfg.u64 =
+ cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
+ prtx_cfg.s.duplex = p->phydev->duplex;
+ cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port),
+ prtx_cfg.u64);
+ }
+ } else {
+ if (p->last_link)
+ link_changed = -1;
+ }
+ p->last_link = p->phydev->link;
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ if (link_changed != 0) {
+ if (link_changed > 0) {
+ netif_carrier_on(netdev);
+ pr_info("%s: Link is up - %d/%s\n", netdev->name,
+ p->phydev->speed,
+ DUPLEX_FULL == p->phydev->duplex ?
+ "Full" : "Half");
+ } else {
+ netif_carrier_off(netdev);
+ pr_info("%s: Link is down\n", netdev->name);
+ }
+ }
+}
+
+static int octeon_mgmt_init_phy(struct net_device *netdev)
+{
+ struct octeon_mgmt *p = netdev_priv(netdev);
+ char phy_id[20];
+
+ if (octeon_is_simulation()) {
+ /* No PHYs in the simulator. */
+ netif_carrier_on(netdev);
+ return 0;
+ }
+
+ snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "0", p->port);
+
+ p->phydev = phy_connect(netdev, phy_id, octeon_mgmt_adjust_link, 0,
+ PHY_INTERFACE_MODE_MII);
+
+ if (IS_ERR(p->phydev)) {
+ p->phydev = NULL;
+ return -1;
+ }
+
+ phy_start_aneg(p->phydev);
+
+ return 0;
+}
+
+static int octeon_mgmt_open(struct net_device *netdev)
+{
+ struct octeon_mgmt *p = netdev_priv(netdev);
+ int port = p->port;
+ union cvmx_mixx_ctl mix_ctl;
+ union cvmx_agl_gmx_inf_mode agl_gmx_inf_mode;
+ union cvmx_mixx_oring1 oring1;
+ union cvmx_mixx_iring1 iring1;
+ union cvmx_agl_gmx_prtx_cfg prtx_cfg;
+ union cvmx_agl_gmx_rxx_frm_ctl rxx_frm_ctl;
+ union cvmx_mixx_irhwm mix_irhwm;
+ union cvmx_mixx_orhwm mix_orhwm;
+ union cvmx_mixx_intena mix_intena;
+ struct sockaddr sa;
+
+ /* Allocate ring buffers. */
+ p->tx_ring = kzalloc(ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE),
+ GFP_KERNEL);
+ if (!p->tx_ring)
+ return -ENOMEM;
+ p->tx_ring_handle =
+ dma_map_single(p->dev, p->tx_ring,
+ ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE),
+ DMA_BIDIRECTIONAL);
+ p->tx_next = 0;
+ p->tx_next_clean = 0;
+ p->tx_current_fill = 0;
+
+
+ p->rx_ring = kzalloc(ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE),
+ GFP_KERNEL);
+ if (!p->rx_ring)
+ goto err_nomem;
+ p->rx_ring_handle =
+ dma_map_single(p->dev, p->rx_ring,
+ ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE),
+ DMA_BIDIRECTIONAL);
+
+ p->rx_next = 0;
+ p->rx_next_fill = 0;
+ p->rx_current_fill = 0;
+
+ octeon_mgmt_reset_hw(p);
+
+ mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port));
+
+ /* Bring it out of reset if needed. */
+ if (mix_ctl.s.reset) {
+ mix_ctl.s.reset = 0;
+ cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64);
+ do {
+ mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port));
+ } while (mix_ctl.s.reset);
+ }
+
+ agl_gmx_inf_mode.u64 = 0;
+ agl_gmx_inf_mode.s.en = 1;
+ cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64);
+
+ oring1.u64 = 0;
+ oring1.s.obase = p->tx_ring_handle >> 3;
+ oring1.s.osize = OCTEON_MGMT_TX_RING_SIZE;
+ cvmx_write_csr(CVMX_MIXX_ORING1(port), oring1.u64);
+
+ iring1.u64 = 0;
+ iring1.s.ibase = p->rx_ring_handle >> 3;
+ iring1.s.isize = OCTEON_MGMT_RX_RING_SIZE;
+ cvmx_write_csr(CVMX_MIXX_IRING1(port), iring1.u64);
+
+ /* Disable packet I/O. */
+ prtx_cfg.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
+ prtx_cfg.s.en = 0;
+ cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), prtx_cfg.u64);
+
+ memcpy(sa.sa_data, netdev->dev_addr, ETH_ALEN);
+ octeon_mgmt_set_mac_address(netdev, &sa);
+
+ octeon_mgmt_change_mtu(netdev, netdev->mtu);
+
+ /*
+ * Enable the port HW. Packets are not allowed until
+ * cvmx_mgmt_port_enable() is called.
+ */
+ mix_ctl.u64 = 0;
+ mix_ctl.s.crc_strip = 1; /* Strip the ending CRC */
+ mix_ctl.s.en = 1; /* Enable the port */
+ mix_ctl.s.nbtarb = 0; /* Arbitration mode */
+ /* MII CB-request FIFO programmable high watermark */
+ mix_ctl.s.mrq_hwm = 1;
+ cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64);
+
+ if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)
+ || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {
+ /*
+ * Force compensation values, as they are not
+ * determined properly by HW
+ */
+ union cvmx_agl_gmx_drv_ctl drv_ctl;
+
+ drv_ctl.u64 = cvmx_read_csr(CVMX_AGL_GMX_DRV_CTL);
+ if (port) {
+ drv_ctl.s.byp_en1 = 1;
+ drv_ctl.s.nctl1 = 6;
+ drv_ctl.s.pctl1 = 6;
+ } else {
+ drv_ctl.s.byp_en = 1;
+ drv_ctl.s.nctl = 6;
+ drv_ctl.s.pctl = 6;
+ }
+ cvmx_write_csr(CVMX_AGL_GMX_DRV_CTL, drv_ctl.u64);
+ }
+
+ octeon_mgmt_rx_fill_ring(netdev);
+
+ /* Clear statistics. */
+ /* Clear on read. */
+ cvmx_write_csr(CVMX_AGL_GMX_RXX_STATS_CTL(port), 1);
+ cvmx_write_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_DRP(port), 0);
+ cvmx_write_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_BAD(port), 0);
+
+ cvmx_write_csr(CVMX_AGL_GMX_TXX_STATS_CTL(port), 1);
+ cvmx_write_csr(CVMX_AGL_GMX_TXX_STAT0(port), 0);
+ cvmx_write_csr(CVMX_AGL_GMX_TXX_STAT1(port), 0);
+
+ /* Clear any pending interrupts */
+ cvmx_write_csr(CVMX_MIXX_ISR(port), cvmx_read_csr(CVMX_MIXX_ISR(port)));
+
+ if (request_irq(p->irq, octeon_mgmt_interrupt, 0, netdev->name,
+ netdev)) {
+ dev_err(p->dev, "request_irq(%d) failed.\n", p->irq);
+ goto err_noirq;
+ }
+
+ /* Interrupt every single RX packet */
+ mix_irhwm.u64 = 0;
+ mix_irhwm.s.irhwm = 0;
+ cvmx_write_csr(CVMX_MIXX_IRHWM(port), mix_irhwm.u64);
+
+ /* Interrupt when we have 5 or more packets to clean. */
+ mix_orhwm.u64 = 0;
+ mix_orhwm.s.orhwm = 5;
+ cvmx_write_csr(CVMX_MIXX_ORHWM(port), mix_orhwm.u64);
+
+ /* Enable receive and transmit interrupts */
+ mix_intena.u64 = 0;
+ mix_intena.s.ithena = 1;
+ mix_intena.s.othena = 1;
+ cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64);
+
+
+ /* Enable packet I/O. */
+
+ rxx_frm_ctl.u64 = 0;
+ rxx_frm_ctl.s.pre_align = 1;
+ /*
+ * When set, disables the length check for non-min sized pkts
+ * with padding in the client data.
+ */
+ rxx_frm_ctl.s.pad_len = 1;
+ /* When set, disables the length check for VLAN pkts */
+ rxx_frm_ctl.s.vlan_len = 1;
+ /* When set, PREAMBLE checking is less strict */
+ rxx_frm_ctl.s.pre_free = 1;
+ /* Control Pause Frames can match station SMAC */
+ rxx_frm_ctl.s.ctl_smac = 0;
+ /* Control Pause Frames can match globally assign Multicast address */
+ rxx_frm_ctl.s.ctl_mcst = 1;
+ /* Forward pause information to TX block */
+ rxx_frm_ctl.s.ctl_bck = 1;
+ /* Drop Control Pause Frames */
+ rxx_frm_ctl.s.ctl_drp = 1;
+ /* Strip off the preamble */
+ rxx_frm_ctl.s.pre_strp = 1;
+ /*
+ * This port is configured to send PREAMBLE+SFD to begin every
+ * frame. GMX checks that the PREAMBLE is sent correctly.
+ */
+ rxx_frm_ctl.s.pre_chk = 1;
+ cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_CTL(port), rxx_frm_ctl.u64);
+
+ /* Enable the AGL block */
+ agl_gmx_inf_mode.u64 = 0;
+ agl_gmx_inf_mode.s.en = 1;
+ cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64);
+
+ /* Configure the port duplex and enables */
+ prtx_cfg.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
+ prtx_cfg.s.tx_en = 1;
+ prtx_cfg.s.rx_en = 1;
+ prtx_cfg.s.en = 1;
+ p->last_duplex = 1;
+ prtx_cfg.s.duplex = p->last_duplex;
+ cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), prtx_cfg.u64);
+
+ p->last_link = 0;
+ netif_carrier_off(netdev);
+
+ if (octeon_mgmt_init_phy(netdev)) {
+ dev_err(p->dev, "Cannot initialize PHY.\n");
+ goto err_noirq;
+ }
+
+ netif_wake_queue(netdev);
+ napi_enable(&p->napi);
+
+ return 0;
+err_noirq:
+ octeon_mgmt_reset_hw(p);
+ dma_unmap_single(p->dev, p->rx_ring_handle,
+ ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE),
+ DMA_BIDIRECTIONAL);
+ kfree(p->rx_ring);
+err_nomem:
+ dma_unmap_single(p->dev, p->tx_ring_handle,
+ ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE),
+ DMA_BIDIRECTIONAL);
+ kfree(p->tx_ring);
+ return -ENOMEM;
+}
+
+static int octeon_mgmt_stop(struct net_device *netdev)
+{
+ struct octeon_mgmt *p = netdev_priv(netdev);
+
+ napi_disable(&p->napi);
+ netif_stop_queue(netdev);
+
+ if (p->phydev)
+ phy_disconnect(p->phydev);
+
+ netif_carrier_off(netdev);
+
+ octeon_mgmt_reset_hw(p);
+
+
+ free_irq(p->irq, netdev);
+
+ /* dma_unmap is a nop on Octeon, so just free everything. */
+ skb_queue_purge(&p->tx_list);
+ skb_queue_purge(&p->rx_list);
+
+ dma_unmap_single(p->dev, p->rx_ring_handle,
+ ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE),
+ DMA_BIDIRECTIONAL);
+ kfree(p->rx_ring);
+
+ dma_unmap_single(p->dev, p->tx_ring_handle,
+ ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE),
+ DMA_BIDIRECTIONAL);
+ kfree(p->tx_ring);
+
+
+ return 0;
+}
+
+static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct octeon_mgmt *p = netdev_priv(netdev);
+ int port = p->port;
+ union mgmt_port_ring_entry re;
+ unsigned long flags;
+
+ re.d64 = 0;
+ re.s.len = skb->len;
+ re.s.addr = dma_map_single(p->dev, skb->data,
+ skb->len,
+ DMA_TO_DEVICE);
+
+ spin_lock_irqsave(&p->tx_list.lock, flags);
+
+ if (unlikely(p->tx_current_fill >=
+ ring_max_fill(OCTEON_MGMT_TX_RING_SIZE))) {
+ spin_unlock_irqrestore(&p->tx_list.lock, flags);
+
+ dma_unmap_single(p->dev, re.s.addr, re.s.len,
+ DMA_TO_DEVICE);
+
+ netif_stop_queue(netdev);
+ return NETDEV_TX_BUSY;
+ }
+
+ __skb_queue_tail(&p->tx_list, skb);
+
+ /* Put it in the ring. */
+ p->tx_ring[p->tx_next] = re.d64;
+ p->tx_next = (p->tx_next + 1) % OCTEON_MGMT_TX_RING_SIZE;
+ p->tx_current_fill++;
+
+ spin_unlock_irqrestore(&p->tx_list.lock, flags);
+
+ dma_sync_single_for_device(p->dev, p->tx_ring_handle,
+ ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE),
+ DMA_BIDIRECTIONAL);
+
+ netdev->stats.tx_packets++;
+ netdev->stats.tx_bytes += skb->len;
+
+ /* Ring the bell. */
+ cvmx_write_csr(CVMX_MIXX_ORING2(port), 1);
+
+ netdev->trans_start = jiffies;
+ octeon_mgmt_clean_tx_buffers(p);
+ octeon_mgmt_update_tx_stats(netdev);
+ return NETDEV_TX_OK;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void octeon_mgmt_poll_controller(struct net_device *netdev)
+{
+ struct octeon_mgmt *p = netdev_priv(netdev);
+
+ octeon_mgmt_receive_packets(p, 16);
+ octeon_mgmt_update_rx_stats(netdev);
+ return;
+}
+#endif
+
+static void octeon_mgmt_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *info)
+{
+ strncpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strncpy(info->version, DRV_VERSION, sizeof(info->version));
+ strncpy(info->fw_version, "N/A", sizeof(info->fw_version));
+ strncpy(info->bus_info, "N/A", sizeof(info->bus_info));
+ info->n_stats = 0;
+ info->testinfo_len = 0;
+ info->regdump_len = 0;
+ info->eedump_len = 0;
+}
+
+static int octeon_mgmt_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *cmd)
+{
+ struct octeon_mgmt *p = netdev_priv(netdev);
+
+ if (p->phydev)
+ return phy_ethtool_gset(p->phydev, cmd);
+
+ return -EINVAL;
+}
+
+static int octeon_mgmt_set_settings(struct net_device *netdev,
+ struct ethtool_cmd *cmd)
+{
+ struct octeon_mgmt *p = netdev_priv(netdev);
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (p->phydev)
+ return phy_ethtool_sset(p->phydev, cmd);
+
+ return -EINVAL;
+}
+
+static const struct ethtool_ops octeon_mgmt_ethtool_ops = {
+ .get_drvinfo = octeon_mgmt_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_settings = octeon_mgmt_get_settings,
+ .set_settings = octeon_mgmt_set_settings
+};
+
+static const struct net_device_ops octeon_mgmt_ops = {
+ .ndo_open = octeon_mgmt_open,
+ .ndo_stop = octeon_mgmt_stop,
+ .ndo_start_xmit = octeon_mgmt_xmit,
+ .ndo_set_rx_mode = octeon_mgmt_set_rx_filtering,
+ .ndo_set_multicast_list = octeon_mgmt_set_rx_filtering,
+ .ndo_set_mac_address = octeon_mgmt_set_mac_address,
+ .ndo_do_ioctl = octeon_mgmt_ioctl,
+ .ndo_change_mtu = octeon_mgmt_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = octeon_mgmt_poll_controller,
+#endif
+};
+
+static int __init octeon_mgmt_probe(struct platform_device *pdev)
+{
+ struct resource *res_irq;
+ struct net_device *netdev;
+ struct octeon_mgmt *p;
+ int i;
+
+ netdev = alloc_etherdev(sizeof(struct octeon_mgmt));
+ if (netdev == NULL)
+ return -ENOMEM;
+
+ dev_set_drvdata(&pdev->dev, netdev);
+ p = netdev_priv(netdev);
+ netif_napi_add(netdev, &p->napi, octeon_mgmt_napi_poll,
+ OCTEON_MGMT_NAPI_WEIGHT);
+
+ p->netdev = netdev;
+ p->dev = &pdev->dev;
+
+ p->port = pdev->id;
+ snprintf(netdev->name, IFNAMSIZ, "mgmt%d", p->port);
+
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res_irq)
+ goto err;
+
+ p->irq = res_irq->start;
+ spin_lock_init(&p->lock);
+
+ skb_queue_head_init(&p->tx_list);
+ skb_queue_head_init(&p->rx_list);
+ tasklet_init(&p->tx_clean_tasklet,
+ octeon_mgmt_clean_tx_tasklet, (unsigned long)p);
+
+ netdev->netdev_ops = &octeon_mgmt_ops;
+ netdev->ethtool_ops = &octeon_mgmt_ethtool_ops;
+
+
+ /* The mgmt ports get the first N MACs. */
+ for (i = 0; i < 6; i++)
+ netdev->dev_addr[i] = octeon_bootinfo->mac_addr_base[i];
+ netdev->dev_addr[5] += p->port;
+
+ if (p->port >= octeon_bootinfo->mac_addr_count)
+ dev_err(&pdev->dev,
+ "Error %s: Using MAC outside of the assigned range: "
+ "%02x:%02x:%02x:%02x:%02x:%02x\n", netdev->name,
+ netdev->dev_addr[0], netdev->dev_addr[1],
+ netdev->dev_addr[2], netdev->dev_addr[3],
+ netdev->dev_addr[4], netdev->dev_addr[5]);
+
+ if (register_netdev(netdev))
+ goto err;
+
+ dev_info(&pdev->dev, "Version " DRV_VERSION "\n");
+ return 0;
+err:
+ free_netdev(netdev);
+ return -ENOENT;
+}
+
+static int __exit octeon_mgmt_remove(struct platform_device *pdev)
+{
+ struct net_device *netdev = dev_get_drvdata(&pdev->dev);
+
+ unregister_netdev(netdev);
+ free_netdev(netdev);
+ return 0;
+}
+
+static struct platform_driver octeon_mgmt_driver = {
+ .driver = {
+ .name = "octeon_mgmt",
+ .owner = THIS_MODULE,
+ },
+ .probe = octeon_mgmt_probe,
+ .remove = __exit_p(octeon_mgmt_remove),
+};
+
+extern void octeon_mdiobus_force_mod_depencency(void);
+
+static int __init octeon_mgmt_mod_init(void)
+{
+ /* Force our mdiobus driver module to be loaded first. */
+ octeon_mdiobus_force_mod_depencency();
+ return platform_driver_register(&octeon_mgmt_driver);
+}
+
+static void __exit octeon_mgmt_mod_exit(void)
+{
+ platform_driver_unregister(&octeon_mgmt_driver);
+}
+
+module_init(octeon_mgmt_mod_init);
+module_exit(octeon_mgmt_mod_exit);
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_AUTHOR("David Daney");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index d5d8e1c5bc9..fc5938ba3d7 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -115,4 +115,15 @@ config MDIO_GPIO
To compile this driver as a module, choose M here: the module
will be called mdio-gpio.
+config MDIO_OCTEON
+ tristate "Support for MDIO buses on Octeon SOCs"
+ depends on CPU_CAVIUM_OCTEON
+ default y
+ help
+
+ This module provides a driver for the Octeon MDIO busses.
+ It is required by the Octeon Ethernet device drivers.
+
+ If in doubt, say Y.
+
endif # PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index edfaac48cbd..1342585af38 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
obj-$(CONFIG_NATIONAL_PHY) += national.o
obj-$(CONFIG_STE10XP) += ste10Xp.o
+obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index f63c96a4ecb..c13cf64095b 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -326,7 +326,8 @@ error:
static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
{
- u32 val, orig;
+ u32 orig;
+ int val;
bool clk125en = true;
/* Abort if we are using an untested phy. */
diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c
new file mode 100644
index 00000000000..61a4461cbda
--- /dev/null
+++ b/drivers/net/phy/mdio-octeon.c
@@ -0,0 +1,180 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Cavium Networks
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/phy.h>
+
+#include <asm/octeon/octeon.h>
+#include <asm/octeon/cvmx-smix-defs.h>
+
+#define DRV_VERSION "1.0"
+#define DRV_DESCRIPTION "Cavium Networks Octeon SMI/MDIO driver"
+
+struct octeon_mdiobus {
+ struct mii_bus *mii_bus;
+ int unit;
+ int phy_irq[PHY_MAX_ADDR];
+};
+
+static int octeon_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum)
+{
+ struct octeon_mdiobus *p = bus->priv;
+ union cvmx_smix_cmd smi_cmd;
+ union cvmx_smix_rd_dat smi_rd;
+ int timeout = 1000;
+
+ smi_cmd.u64 = 0;
+ smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_22_READ */
+ smi_cmd.s.phy_adr = phy_id;
+ smi_cmd.s.reg_adr = regnum;
+ cvmx_write_csr(CVMX_SMIX_CMD(p->unit), smi_cmd.u64);
+
+ do {
+ /*
+ * Wait 1000 clocks so we don't saturate the RSL bus
+ * doing reads.
+ */
+ cvmx_wait(1000);
+ smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(p->unit));
+ } while (smi_rd.s.pending && --timeout);
+
+ if (smi_rd.s.val)
+ return smi_rd.s.dat;
+ else
+ return -EIO;
+}
+
+static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id,
+ int regnum, u16 val)
+{
+ struct octeon_mdiobus *p = bus->priv;
+ union cvmx_smix_cmd smi_cmd;
+ union cvmx_smix_wr_dat smi_wr;
+ int timeout = 1000;
+
+ smi_wr.u64 = 0;
+ smi_wr.s.dat = val;
+ cvmx_write_csr(CVMX_SMIX_WR_DAT(p->unit), smi_wr.u64);
+
+ smi_cmd.u64 = 0;
+ smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_22_WRITE */
+ smi_cmd.s.phy_adr = phy_id;
+ smi_cmd.s.reg_adr = regnum;
+ cvmx_write_csr(CVMX_SMIX_CMD(p->unit), smi_cmd.u64);
+
+ do {
+ /*
+ * Wait 1000 clocks so we don't saturate the RSL bus
+ * doing reads.
+ */
+ cvmx_wait(1000);
+ smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(p->unit));
+ } while (smi_wr.s.pending && --timeout);
+
+ if (timeout <= 0)
+ return -EIO;
+
+ return 0;
+}
+
+static int __init octeon_mdiobus_probe(struct platform_device *pdev)
+{
+ struct octeon_mdiobus *bus;
+ int i;
+ int err = -ENOENT;
+
+ bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
+ if (!bus)
+ return -ENOMEM;
+
+ /* The platform_device id is our unit number. */
+ bus->unit = pdev->id;
+
+ bus->mii_bus = mdiobus_alloc();
+
+ if (!bus->mii_bus)
+ goto err;
+
+ /*
+ * Standard Octeon evaluation boards don't support phy
+ * interrupts, we need to poll.
+ */
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ bus->phy_irq[i] = PHY_POLL;
+
+ bus->mii_bus->priv = bus;
+ bus->mii_bus->irq = bus->phy_irq;
+ bus->mii_bus->name = "mdio-octeon";
+ snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%x", bus->unit);
+ bus->mii_bus->parent = &pdev->dev;
+
+ bus->mii_bus->read = octeon_mdiobus_read;
+ bus->mii_bus->write = octeon_mdiobus_write;
+
+ dev_set_drvdata(&pdev->dev, bus);
+
+ err = mdiobus_register(bus->mii_bus);
+ if (err)
+ goto err_register;
+
+ dev_info(&pdev->dev, "Version " DRV_VERSION "\n");
+
+ return 0;
+err_register:
+ mdiobus_free(bus->mii_bus);
+
+err:
+ devm_kfree(&pdev->dev, bus);
+ return err;
+}
+
+static int __exit octeon_mdiobus_remove(struct platform_device *pdev)
+{
+ struct octeon_mdiobus *bus;
+
+ bus = dev_get_drvdata(&pdev->dev);
+
+ mdiobus_unregister(bus->mii_bus);
+ mdiobus_free(bus->mii_bus);
+ return 0;
+}
+
+static struct platform_driver octeon_mdiobus_driver = {
+ .driver = {
+ .name = "mdio-octeon",
+ .owner = THIS_MODULE,
+ },
+ .probe = octeon_mdiobus_probe,
+ .remove = __exit_p(octeon_mdiobus_remove),
+};
+
+void octeon_mdiobus_force_mod_depencency(void)
+{
+ /* Let ethernet drivers force us to be loaded. */
+}
+EXPORT_SYMBOL(octeon_mdiobus_force_mod_depencency);
+
+static int __init octeon_mdiobus_mod_init(void)
+{
+ return platform_driver_register(&octeon_mdiobus_driver);
+}
+
+static void __exit octeon_mdiobus_mod_exit(void)
+{
+ platform_driver_unregister(&octeon_mdiobus_driver);
+}
+
+module_init(octeon_mdiobus_mod_init);
+module_exit(octeon_mdiobus_mod_exit);
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("David Daney");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 675b7df632f..27ca859e745 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -63,7 +63,7 @@
#ifndef __iwl_core_h__
#define __iwl_core_h__
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
/************************
* forward declarations *
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index b9b371bfa30..42611bea76a 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -1365,7 +1365,7 @@ static void lbs_send_confirmsleep(struct lbs_private *priv)
priv->dnld_sent = DNLD_RES_RECEIVED;
/* If nothing to do, go back to sleep (?) */
- if (!__kfifo_len(priv->event_fifo) && !priv->resp_len[priv->resp_idx])
+ if (!kfifo_len(&priv->event_fifo) && !priv->resp_len[priv->resp_idx])
priv->psstate = PS_STATE_SLEEP;
spin_unlock_irqrestore(&priv->driver_lock, flags);
@@ -1439,7 +1439,7 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv)
}
/* Pending events or command responses? */
- if (__kfifo_len(priv->event_fifo) || priv->resp_len[priv->resp_idx]) {
+ if (kfifo_len(&priv->event_fifo) || priv->resp_len[priv->resp_idx]) {
allowed = 0;
lbs_deb_host("pending events or command responses\n");
}
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 6a8d2b291d8..05bb298dfae 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -10,7 +10,7 @@
#include "scan.h"
#include "assoc.h"
-
+#include <linux/kfifo.h>
/** sleep_params */
struct sleep_params {
@@ -120,7 +120,7 @@ struct lbs_private {
u32 resp_len[2];
/* Events sent from hardware to driver */
- struct kfifo *event_fifo;
+ struct kfifo event_fifo;
/** thread to service interrupts */
struct task_struct *main_thread;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index db38a5a719f..c2975c8e2f2 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -459,7 +459,7 @@ static int lbs_thread(void *data)
else if (!list_empty(&priv->cmdpendingq) &&
!(priv->wakeup_dev_required))
shouldsleep = 0; /* We have a command to send */
- else if (__kfifo_len(priv->event_fifo))
+ else if (kfifo_len(&priv->event_fifo))
shouldsleep = 0; /* We have an event to process */
else
shouldsleep = 1; /* No command */
@@ -511,10 +511,13 @@ static int lbs_thread(void *data)
/* Process hardware events, e.g. card removed, link lost */
spin_lock_irq(&priv->driver_lock);
- while (__kfifo_len(priv->event_fifo)) {
+ while (kfifo_len(&priv->event_fifo)) {
u32 event;
- __kfifo_get(priv->event_fifo, (unsigned char *) &event,
- sizeof(event));
+
+ if (kfifo_out(&priv->event_fifo,
+ (unsigned char *) &event, sizeof(event)) !=
+ sizeof(event))
+ break;
spin_unlock_irq(&priv->driver_lock);
lbs_process_event(priv, event);
spin_lock_irq(&priv->driver_lock);
@@ -883,10 +886,9 @@ static int lbs_init_adapter(struct lbs_private *priv)
priv->resp_len[0] = priv->resp_len[1] = 0;
/* Create the event FIFO */
- priv->event_fifo = kfifo_alloc(sizeof(u32) * 16, GFP_KERNEL, NULL);
- if (IS_ERR(priv->event_fifo)) {
+ ret = kfifo_alloc(&priv->event_fifo, sizeof(u32) * 16, GFP_KERNEL);
+ if (ret) {
lbs_pr_err("Out of memory allocating event FIFO buffer\n");
- ret = -ENOMEM;
goto out;
}
@@ -901,8 +903,7 @@ static void lbs_free_adapter(struct lbs_private *priv)
lbs_deb_enter(LBS_DEB_MAIN);
lbs_free_cmd_buffer(priv);
- if (priv->event_fifo)
- kfifo_free(priv->event_fifo);
+ kfifo_free(&priv->event_fifo);
del_timer(&priv->command_timer);
del_timer(&priv->auto_deepsleep_timer);
kfree(priv->networks);
@@ -1177,7 +1178,7 @@ void lbs_queue_event(struct lbs_private *priv, u32 event)
if (priv->psstate == PS_STATE_SLEEP)
priv->psstate = PS_STATE_AWAKE;
- __kfifo_put(priv->event_fifo, (unsigned char *) &event, sizeof(u32));
+ kfifo_in(&priv->event_fifo, (unsigned char *) &event, sizeof(u32));
wake_up_interruptible(&priv->waitq);
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
index 3aabf1e3798..76e640bccde 100644
--- a/drivers/pcmcia/pxa2xx_base.c
+++ b/drivers/pcmcia/pxa2xx_base.c
@@ -291,7 +291,7 @@ static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev)
skt->nr = ops->first + i;
skt->ops = ops;
skt->socket.owner = ops->owner;
- skt->socket.dev.parent = dev;
+ skt->socket.dev.parent = &dev->dev;
skt->socket.pci_irq = NO_IRQ;
ret = pxa2xx_drv_pcmcia_add_one(skt);
@@ -304,8 +304,8 @@ static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev)
soc_pcmcia_remove_one(&sinfo->skt[i]);
kfree(sinfo);
} else {
- pxa2xx_configure_sockets(dev);
- dev_set_drvdata(dev, sinfo);
+ pxa2xx_configure_sockets(&dev->dev);
+ dev_set_drvdata(&dev->dev, sinfo);
}
return ret;
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index 11003bba10d..1a387e79f71 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -51,7 +51,6 @@
#include <linux/dmi.h>
#include <linux/backlight.h>
#include <linux/platform_device.h>
-#include <linux/autoconf.h>
#define COMPAL_DRIVER_VERSION "0.2.6"
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index bcd4ba8be7d..b66029bd75d 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -164,7 +164,7 @@ struct fujitsu_hotkey_t {
struct input_dev *input;
char phys[32];
struct platform_device *pf_device;
- struct kfifo *fifo;
+ struct kfifo fifo;
spinlock_t fifo_lock;
int rfkill_supported;
int rfkill_state;
@@ -824,12 +824,10 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
/* kfifo */
spin_lock_init(&fujitsu_hotkey->fifo_lock);
- fujitsu_hotkey->fifo =
- kfifo_alloc(RINGBUFFERSIZE * sizeof(int), GFP_KERNEL,
- &fujitsu_hotkey->fifo_lock);
- if (IS_ERR(fujitsu_hotkey->fifo)) {
+ error = kfifo_alloc(&fujitsu_hotkey->fifo, RINGBUFFERSIZE * sizeof(int),
+ GFP_KERNEL);
+ if (error) {
printk(KERN_ERR "kfifo_alloc failed\n");
- error = PTR_ERR(fujitsu_hotkey->fifo);
goto err_stop;
}
@@ -934,7 +932,7 @@ err_unregister_input_dev:
err_free_input_dev:
input_free_device(input);
err_free_fifo:
- kfifo_free(fujitsu_hotkey->fifo);
+ kfifo_free(&fujitsu_hotkey->fifo);
err_stop:
return result;
}
@@ -956,7 +954,7 @@ static int acpi_fujitsu_hotkey_remove(struct acpi_device *device, int type)
input_free_device(input);
- kfifo_free(fujitsu_hotkey->fifo);
+ kfifo_free(&fujitsu_hotkey->fifo);
fujitsu_hotkey->acpi_handle = NULL;
@@ -1008,9 +1006,10 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
vdbg_printk(FUJLAPTOP_DBG_TRACE,
"Push keycode into ringbuffer [%d]\n",
keycode);
- status = kfifo_put(fujitsu_hotkey->fifo,
+ status = kfifo_in_locked(&fujitsu_hotkey->fifo,
(unsigned char *)&keycode,
- sizeof(keycode));
+ sizeof(keycode),
+ &fujitsu_hotkey->fifo_lock);
if (status != sizeof(keycode)) {
vdbg_printk(FUJLAPTOP_DBG_WARN,
"Could not push keycode [0x%x]\n",
@@ -1021,11 +1020,12 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
}
} else if (keycode == 0) {
while ((status =
- kfifo_get
- (fujitsu_hotkey->fifo, (unsigned char *)
- &keycode_r,
- sizeof
- (keycode_r))) == sizeof(keycode_r)) {
+ kfifo_out_locked(
+ &fujitsu_hotkey->fifo,
+ (unsigned char *) &keycode_r,
+ sizeof(keycode_r),
+ &fujitsu_hotkey->fifo_lock))
+ == sizeof(keycode_r)) {
input_report_key(input, keycode_r, 0);
input_sync(input);
vdbg_printk(FUJLAPTOP_DBG_TRACE,
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 7a2cc8a5c97..2896ca4cd9a 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -142,7 +142,7 @@ struct sony_laptop_input_s {
atomic_t users;
struct input_dev *jog_dev;
struct input_dev *key_dev;
- struct kfifo *fifo;
+ struct kfifo fifo;
spinlock_t fifo_lock;
struct workqueue_struct *wq;
};
@@ -300,8 +300,9 @@ static void do_sony_laptop_release_key(struct work_struct *work)
{
struct sony_laptop_keypress kp;
- while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp,
- sizeof(kp)) == sizeof(kp)) {
+ while (kfifo_out_locked(&sony_laptop_input.fifo, (unsigned char *)&kp,
+ sizeof(kp), &sony_laptop_input.fifo_lock)
+ == sizeof(kp)) {
msleep(10);
input_report_key(kp.dev, kp.key, 0);
input_sync(kp.dev);
@@ -362,8 +363,9 @@ static void sony_laptop_report_input_event(u8 event)
/* we emit the scancode so we can always remap the key */
input_event(kp.dev, EV_MSC, MSC_SCAN, event);
input_sync(kp.dev);
- kfifo_put(sony_laptop_input.fifo,
- (unsigned char *)&kp, sizeof(kp));
+ kfifo_in_locked(&sony_laptop_input.fifo,
+ (unsigned char *)&kp, sizeof(kp),
+ &sony_laptop_input.fifo_lock);
if (!work_pending(&sony_laptop_release_key_work))
queue_work(sony_laptop_input.wq,
@@ -385,12 +387,10 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
/* kfifo */
spin_lock_init(&sony_laptop_input.fifo_lock);
- sony_laptop_input.fifo =
- kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
- &sony_laptop_input.fifo_lock);
- if (IS_ERR(sony_laptop_input.fifo)) {
+ error =
+ kfifo_alloc(&sony_laptop_input.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
+ if (error) {
printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
- error = PTR_ERR(sony_laptop_input.fifo);
goto err_dec_users;
}
@@ -474,7 +474,7 @@ err_destroy_wq:
destroy_workqueue(sony_laptop_input.wq);
err_free_kfifo:
- kfifo_free(sony_laptop_input.fifo);
+ kfifo_free(&sony_laptop_input.fifo);
err_dec_users:
atomic_dec(&sony_laptop_input.users);
@@ -500,7 +500,7 @@ static void sony_laptop_remove_input(void)
}
destroy_workqueue(sony_laptop_input.wq);
- kfifo_free(sony_laptop_input.fifo);
+ kfifo_free(&sony_laptop_input.fifo);
}
/*********** Platform Device ***********/
@@ -2079,7 +2079,7 @@ static struct attribute_group spic_attribute_group = {
struct sonypi_compat_s {
struct fasync_struct *fifo_async;
- struct kfifo *fifo;
+ struct kfifo fifo;
spinlock_t fifo_lock;
wait_queue_head_t fifo_proc_list;
atomic_t open_count;
@@ -2104,12 +2104,12 @@ static int sonypi_misc_open(struct inode *inode, struct file *file)
/* Flush input queue on first open */
unsigned long flags;
- spin_lock_irqsave(sonypi_compat.fifo->lock, flags);
+ spin_lock_irqsave(&sonypi_compat.fifo_lock, flags);
if (atomic_inc_return(&sonypi_compat.open_count) == 1)
- __kfifo_reset(sonypi_compat.fifo);
+ kfifo_reset(&sonypi_compat.fifo);
- spin_unlock_irqrestore(sonypi_compat.fifo->lock, flags);
+ spin_unlock_irqrestore(&sonypi_compat.fifo_lock, flags);
return 0;
}
@@ -2120,17 +2120,18 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
ssize_t ret;
unsigned char c;
- if ((kfifo_len(sonypi_compat.fifo) == 0) &&
+ if ((kfifo_len(&sonypi_compat.fifo) == 0) &&
(file->f_flags & O_NONBLOCK))
return -EAGAIN;
ret = wait_event_interruptible(sonypi_compat.fifo_proc_list,
- kfifo_len(sonypi_compat.fifo) != 0);
+ kfifo_len(&sonypi_compat.fifo) != 0);
if (ret)
return ret;
while (ret < count &&
- (kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) {
+ (kfifo_out_locked(&sonypi_compat.fifo, &c, sizeof(c),
+ &sonypi_compat.fifo_lock) == sizeof(c))) {
if (put_user(c, buf++))
return -EFAULT;
ret++;
@@ -2147,7 +2148,7 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
{
poll_wait(file, &sonypi_compat.fifo_proc_list, wait);
- if (kfifo_len(sonypi_compat.fifo))
+ if (kfifo_len(&sonypi_compat.fifo))
return POLLIN | POLLRDNORM;
return 0;
}
@@ -2309,7 +2310,8 @@ static struct miscdevice sonypi_misc_device = {
static void sonypi_compat_report_event(u8 event)
{
- kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event));
+ kfifo_in_locked(&sonypi_compat.fifo, (unsigned char *)&event,
+ sizeof(event), &sonypi_compat.fifo_lock);
kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);
wake_up_interruptible(&sonypi_compat.fifo_proc_list);
}
@@ -2319,11 +2321,11 @@ static int sonypi_compat_init(void)
int error;
spin_lock_init(&sonypi_compat.fifo_lock);
- sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
- &sonypi_compat.fifo_lock);
- if (IS_ERR(sonypi_compat.fifo)) {
+ error =
+ kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
+ if (error) {
printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
- return PTR_ERR(sonypi_compat.fifo);
+ return error;
}
init_waitqueue_head(&sonypi_compat.fifo_proc_list);
@@ -2342,14 +2344,14 @@ static int sonypi_compat_init(void)
return 0;
err_free_kfifo:
- kfifo_free(sonypi_compat.fifo);
+ kfifo_free(&sonypi_compat.fifo);
return error;
}
static void sonypi_compat_exit(void)
{
misc_deregister(&sonypi_misc_device);
- kfifo_free(sonypi_compat.fifo);
+ kfifo_free(&sonypi_compat.fifo);
}
#else
static int sonypi_compat_init(void) { return 0; }
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
new file mode 100644
index 00000000000..04719551381
--- /dev/null
+++ b/drivers/regulator/88pm8607.c
@@ -0,0 +1,685 @@
+/*
+ * Regulators driver for Marvell 88PM8607
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/88pm8607.h>
+
+struct pm8607_regulator_info {
+ struct regulator_desc desc;
+ struct pm8607_chip *chip;
+ struct regulator_dev *regulator;
+
+ int min_uV;
+ int max_uV;
+ int step_uV;
+ int vol_reg;
+ int vol_shift;
+ int vol_nbits;
+ int update_reg;
+ int update_bit;
+ int enable_reg;
+ int enable_bit;
+ int slope_double;
+};
+
+static inline int check_range(struct pm8607_regulator_info *info,
+ int min_uV, int max_uV)
+{
+ if (max_uV < info->min_uV || min_uV > info->max_uV || min_uV > max_uV)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+ struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+ uint8_t chip_id = info->chip->chip_id;
+ int ret = -EINVAL;
+
+ switch (info->desc.id) {
+ case PM8607_ID_BUCK1:
+ ret = (index < 0x1d) ? (index * 25000 + 800000) :
+ ((index < 0x20) ? 1500000 :
+ ((index < 0x40) ? ((index - 0x20) * 25000) :
+ -EINVAL));
+ break;
+ case PM8607_ID_BUCK3:
+ ret = (index < 0x3d) ? (index * 25000) :
+ ((index < 0x40) ? 1500000 : -EINVAL);
+ if (ret < 0)
+ break;
+ if (info->slope_double)
+ ret <<= 1;
+ break;
+ case PM8607_ID_LDO1:
+ ret = (index == 0) ? 1800000 :
+ ((index == 1) ? 1200000 :
+ ((index == 2) ? 2800000 : -EINVAL));
+ break;
+ case PM8607_ID_LDO5:
+ ret = (index == 0) ? 2900000 :
+ ((index == 1) ? 3000000 :
+ ((index == 2) ? 3100000 : 3300000));
+ break;
+ case PM8607_ID_LDO7:
+ case PM8607_ID_LDO8:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 8) ? (index * 50000 + 2550000) :
+ -EINVAL);
+ break;
+ case PM8607_ID_LDO12:
+ ret = (index < 2) ? (index * 100000 + 1800000) :
+ ((index < 7) ? (index * 100000 + 2500000) :
+ ((index == 7) ? 3300000 : 1200000));
+ break;
+ case PM8607_ID_LDO2:
+ case PM8607_ID_LDO3:
+ case PM8607_ID_LDO9:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 8) ? (index * 50000 + 2550000) :
+ -EINVAL);
+ break;
+ case PM8607_CHIP_B0:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 7) ? (index * 50000 + 2550000) :
+ 3300000);
+ break;
+ }
+ break;
+ case PM8607_ID_LDO4:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 8) ? (index * 50000 + 2550000) :
+ -EINVAL);
+ break;
+ case PM8607_CHIP_B0:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 6) ? (index * 50000 + 2550000) :
+ ((index == 6) ? 2900000 : 3300000));
+ break;
+ }
+ break;
+ case PM8607_ID_LDO6:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 8) ? (index * 50000 + 2450000) :
+ -EINVAL);
+ break;
+ case PM8607_CHIP_B0:
+ ret = (index < 2) ? (index * 50000 + 1800000) :
+ ((index < 7) ? (index * 50000 + 2500000) :
+ 3300000);
+ break;
+ }
+ break;
+ case PM8607_ID_LDO10:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 8) ? (index * 50000 + 2550000) :
+ 1200000);
+ break;
+ case PM8607_CHIP_B0:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 7) ? (index * 50000 + 2550000) :
+ ((index == 7) ? 3300000 : 1200000));
+ break;
+ }
+ break;
+ case PM8607_ID_LDO14:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 8) ? (index * 50000 + 2550000) :
+ -EINVAL);
+ break;
+ case PM8607_CHIP_B0:
+ ret = (index < 2) ? (index * 50000 + 1800000) :
+ ((index < 7) ? (index * 50000 + 2600000) :
+ 3300000);
+ break;
+ }
+ break;
+ }
+ return ret;
+}
+
+static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+ struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+ uint8_t chip_id = info->chip->chip_id;
+ int val = -ENOENT;
+ int ret;
+
+ switch (info->desc.id) {
+ case PM8607_ID_BUCK1:
+ if (min_uV >= 800000) /* 800mV ~ 1500mV / 25mV */
+ val = (min_uV - 775001) / 25000;
+ else { /* 25mV ~ 775mV / 25mV */
+ val = (min_uV + 249999) / 25000;
+ val += 32;
+ }
+ break;
+ case PM8607_ID_BUCK3:
+ if (info->slope_double)
+ min_uV = min_uV >> 1;
+ val = (min_uV + 249999) / 25000; /* 0mV ~ 1500mV / 25mV */
+
+ break;
+ case PM8607_ID_LDO1:
+ if (min_uV > 1800000)
+ val = 2;
+ else if (min_uV > 1200000)
+ val = 0;
+ else
+ val = 1;
+ break;
+ case PM8607_ID_LDO5:
+ if (min_uV > 3100000)
+ val = 3;
+ else /* 2900mV ~ 3100mV / 100mV */
+ val = (min_uV - 2800001) / 100000;
+ break;
+ case PM8607_ID_LDO7:
+ case PM8607_ID_LDO8:
+ if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0; /* 1800mv */
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 3; /* 2700mV */
+ } else { /* 2700mV ~ 2900mV / 50mV */
+ if (min_uV <= 2900000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 3;
+ } else
+ val = -EINVAL;
+ }
+ break;
+ case PM8607_ID_LDO10:
+ if (min_uV > 2850000)
+ val = 7;
+ else if (min_uV <= 1200000)
+ val = 8;
+ else if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */
+ val = (min_uV - 1750001) / 50000;
+ else { /* 2700mV ~ 2850mV / 50mV */
+ val = (min_uV - 2650001) / 50000;
+ val += 3;
+ }
+ break;
+ case PM8607_ID_LDO12:
+ if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 100mV */
+ if (min_uV <= 1200000)
+ val = 8; /* 1200mV */
+ else if (min_uV <= 1800000)
+ val = 0; /* 1800mV */
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1700001) / 100000;
+ else
+ val = 2; /* 2700mV */
+ } else { /* 2700mV ~ 3100mV / 100mV */
+ if (min_uV <= 3100000) {
+ val = (min_uV - 2600001) / 100000;
+ val += 2;
+ } else if (min_uV <= 3300000)
+ val = 7;
+ else
+ val = -EINVAL;
+ }
+ break;
+ case PM8607_ID_LDO2:
+ case PM8607_ID_LDO3:
+ case PM8607_ID_LDO9:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 3; /* 2700mV */
+ else { /* 2700mV ~ 2900mV / 50mV */
+ if (min_uV <= 2900000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 3;
+ } else
+ val = -EINVAL;
+ }
+ break;
+ case PM8607_CHIP_B0:
+ if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 3; /* 2700mV */
+ } else { /* 2700mV ~ 2850mV / 50mV */
+ if (min_uV <= 2850000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 3;
+ } else if (min_uV <= 3300000)
+ val = 7;
+ else
+ val = -EINVAL;
+ }
+ break;
+ }
+ break;
+ case PM8607_ID_LDO4:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 3; /* 2700mV */
+ else { /* 2700mV ~ 2900mV / 50mV */
+ if (min_uV <= 2900000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 3;
+ } else
+ val = -EINVAL;
+ }
+ break;
+ case PM8607_CHIP_B0:
+ if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 3; /* 2700mV */
+ } else { /* 2700mV ~ 2800mV / 50mV */
+ if (min_uV <= 2850000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 3;
+ } else if (min_uV <= 2900000)
+ val = 6;
+ else if (min_uV <= 3300000)
+ val = 7;
+ else
+ val = -EINVAL;
+ }
+ break;
+ }
+ break;
+ case PM8607_ID_LDO6:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ if (min_uV < 2600000) { /* 1800mV ~ 1900mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 3; /* 2600mV */
+ } else { /* 2600mV ~ 2800mV / 50mV */
+ if (min_uV <= 2800000) {
+ val = (min_uV - 2550001) / 50000;
+ val += 3;
+ } else
+ val = -EINVAL;
+ }
+ break;
+ case PM8607_CHIP_B0:
+ if (min_uV < 2600000) { /* 1800mV ~ 1850mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1850000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 2; /* 2600mV */
+ } else { /* 2600mV ~ 2800mV / 50mV */
+ if (min_uV <= 2800000) {
+ val = (min_uV - 2550001) / 50000;
+ val += 2;
+ } else if (min_uV <= 3300000)
+ val = 7;
+ else
+ val = -EINVAL;
+ }
+ break;
+ }
+ break;
+ case PM8607_ID_LDO14:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 3; /* 2700mV */
+ } else { /* 2700mV ~ 2900mV / 50mV */
+ if (min_uV <= 2900000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 3;
+ } else
+ val = -EINVAL;
+ }
+ break;
+ case PM8607_CHIP_B0:
+ if (min_uV < 2700000) { /* 1800mV ~ 1850mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1850000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 2; /* 2700mV */
+ } else { /* 2700mV ~ 2900mV / 50mV */
+ if (min_uV <= 2900000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 2;
+ } else if (min_uV <= 3300000)
+ val = 7;
+ else
+ val = -EINVAL;
+ }
+ break;
+ }
+ break;
+ }
+ if (val >= 0) {
+ ret = pm8607_list_voltage(rdev, val);
+ if (ret > max_uV) {
+ pr_err("exceed voltage range (%d %d) uV",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+ } else
+ pr_err("invalid voltage range (%d %d) uV", min_uV, max_uV);
+ return val;
+}
+
+static int pm8607_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+ struct pm8607_chip *chip = info->chip;
+ uint8_t val, mask;
+ int ret;
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ ret = choose_voltage(rdev, min_uV, max_uV);
+ if (ret < 0)
+ return -EINVAL;
+ val = (uint8_t)(ret << info->vol_shift);
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+
+ ret = pm8607_set_bits(chip, info->vol_reg, mask, val);
+ if (ret)
+ return ret;
+ switch (info->desc.id) {
+ case PM8607_ID_BUCK1:
+ case PM8607_ID_BUCK3:
+ ret = pm8607_set_bits(chip, info->update_reg,
+ 1 << info->update_bit,
+ 1 << info->update_bit);
+ break;
+ }
+ return ret;
+}
+
+static int pm8607_get_voltage(struct regulator_dev *rdev)
+{
+ struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+ struct pm8607_chip *chip = info->chip;
+ uint8_t val, mask;
+ int ret;
+
+ ret = pm8607_reg_read(chip, info->vol_reg);
+ if (ret < 0)
+ return ret;
+
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ val = ((unsigned char)ret & mask) >> info->vol_shift;
+
+ return pm8607_list_voltage(rdev, val);
+}
+
+static int pm8607_enable(struct regulator_dev *rdev)
+{
+ struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+ struct pm8607_chip *chip = info->chip;
+
+ return pm8607_set_bits(chip, info->enable_reg,
+ 1 << info->enable_bit,
+ 1 << info->enable_bit);
+}
+
+static int pm8607_disable(struct regulator_dev *rdev)
+{
+ struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+ struct pm8607_chip *chip = info->chip;
+
+ return pm8607_set_bits(chip, info->enable_reg,
+ 1 << info->enable_bit, 0);
+}
+
+static int pm8607_is_enabled(struct regulator_dev *rdev)
+{
+ struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+ struct pm8607_chip *chip = info->chip;
+ int ret;
+
+ ret = pm8607_reg_read(chip, info->enable_reg);
+ if (ret < 0)
+ return ret;
+
+ return !!((unsigned char)ret & (1 << info->enable_bit));
+}
+
+static struct regulator_ops pm8607_regulator_ops = {
+ .set_voltage = pm8607_set_voltage,
+ .get_voltage = pm8607_get_voltage,
+ .enable = pm8607_enable,
+ .disable = pm8607_disable,
+ .is_enabled = pm8607_is_enabled,
+};
+
+#define PM8607_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
+{ \
+ .desc = { \
+ .name = "BUCK" #_id, \
+ .ops = &pm8607_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = PM8607_ID_BUCK##_id, \
+ .owner = THIS_MODULE, \
+ }, \
+ .min_uV = (min) * 1000, \
+ .max_uV = (max) * 1000, \
+ .step_uV = (step) * 1000, \
+ .vol_reg = PM8607_##vreg, \
+ .vol_shift = (0), \
+ .vol_nbits = (nbits), \
+ .update_reg = PM8607_##ureg, \
+ .update_bit = (ubit), \
+ .enable_reg = PM8607_##ereg, \
+ .enable_bit = (ebit), \
+ .slope_double = (0), \
+}
+
+#define PM8607_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \
+{ \
+ .desc = { \
+ .name = "LDO" #_id, \
+ .ops = &pm8607_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = PM8607_ID_LDO##_id, \
+ .owner = THIS_MODULE, \
+ }, \
+ .min_uV = (min) * 1000, \
+ .max_uV = (max) * 1000, \
+ .step_uV = (step) * 1000, \
+ .vol_reg = PM8607_##vreg, \
+ .vol_shift = (shift), \
+ .vol_nbits = (nbits), \
+ .enable_reg = PM8607_##ereg, \
+ .enable_bit = (ebit), \
+ .slope_double = (0), \
+}
+
+static struct pm8607_regulator_info pm8607_regulator_info[] = {
+ PM8607_DVC(1, 0, 1500, 25, BUCK1, 6, GO, 0, SUPPLIES_EN11, 0),
+ PM8607_DVC(3, 0, 1500, 25, BUCK3, 6, GO, 2, SUPPLIES_EN11, 2),
+
+ PM8607_LDO(1 , 1200, 2800, 0, LDO1 , 0, 2, SUPPLIES_EN11, 3),
+ PM8607_LDO(2 , 1800, 3300, 0, LDO2 , 0, 3, SUPPLIES_EN11, 4),
+ PM8607_LDO(3 , 1800, 3300, 0, LDO3 , 0, 3, SUPPLIES_EN11, 5),
+ PM8607_LDO(4 , 1800, 3300, 0, LDO4 , 0, 3, SUPPLIES_EN11, 6),
+ PM8607_LDO(5 , 2900, 3300, 0, LDO5 , 0, 2, SUPPLIES_EN11, 7),
+ PM8607_LDO(6 , 1800, 3300, 0, LDO6 , 0, 3, SUPPLIES_EN12, 0),
+ PM8607_LDO(7 , 1800, 2900, 0, LDO7 , 0, 3, SUPPLIES_EN12, 1),
+ PM8607_LDO(8 , 1800, 2900, 0, LDO8 , 0, 3, SUPPLIES_EN12, 2),
+ PM8607_LDO(9 , 1800, 3300, 0, LDO9 , 0, 3, SUPPLIES_EN12, 3),
+ PM8607_LDO(10, 1200, 3300, 0, LDO10, 0, 4, SUPPLIES_EN11, 4),
+ PM8607_LDO(12, 1200, 3300, 0, LDO12, 0, 4, SUPPLIES_EN11, 5),
+ PM8607_LDO(14, 1800, 3300, 0, LDO14, 0, 3, SUPPLIES_EN11, 6),
+};
+
+static inline struct pm8607_regulator_info *find_regulator_info(int id)
+{
+ struct pm8607_regulator_info *info;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
+ info = &pm8607_regulator_info[i];
+ if (info->desc.id == id)
+ return info;
+ }
+ return NULL;
+}
+
+static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
+{
+ struct pm8607_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct pm8607_platform_data *pdata = chip->dev->platform_data;
+ struct pm8607_regulator_info *info = NULL;
+
+ info = find_regulator_info(pdev->id);
+ if (info == NULL) {
+ dev_err(&pdev->dev, "invalid regulator ID specified\n");
+ return -EINVAL;
+ }
+
+ info->chip = chip;
+
+ info->regulator = regulator_register(&info->desc, &pdev->dev,
+ pdata->regulator[pdev->id], info);
+ if (IS_ERR(info->regulator)) {
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ info->desc.name);
+ return PTR_ERR(info->regulator);
+ }
+
+ /* check DVC ramp slope double */
+ if (info->desc.id == PM8607_ID_BUCK3)
+ if (info->chip->buck3_double)
+ info->slope_double = 1;
+
+ platform_set_drvdata(pdev, info);
+ return 0;
+}
+
+static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
+{
+ struct pm8607_regulator_info *info = platform_get_drvdata(pdev);
+
+ regulator_unregister(info->regulator);
+ return 0;
+}
+
+#define PM8607_REGULATOR_DRIVER(_name) \
+{ \
+ .driver = { \
+ .name = "88pm8607-" #_name, \
+ .owner = THIS_MODULE, \
+ }, \
+ .probe = pm8607_regulator_probe, \
+ .remove = __devexit_p(pm8607_regulator_remove), \
+}
+
+static struct platform_driver pm8607_regulator_driver[] = {
+ PM8607_REGULATOR_DRIVER(buck1),
+ PM8607_REGULATOR_DRIVER(buck2),
+ PM8607_REGULATOR_DRIVER(buck3),
+ PM8607_REGULATOR_DRIVER(ldo1),
+ PM8607_REGULATOR_DRIVER(ldo2),
+ PM8607_REGULATOR_DRIVER(ldo3),
+ PM8607_REGULATOR_DRIVER(ldo4),
+ PM8607_REGULATOR_DRIVER(ldo5),
+ PM8607_REGULATOR_DRIVER(ldo6),
+ PM8607_REGULATOR_DRIVER(ldo7),
+ PM8607_REGULATOR_DRIVER(ldo8),
+ PM8607_REGULATOR_DRIVER(ldo9),
+ PM8607_REGULATOR_DRIVER(ldo10),
+ PM8607_REGULATOR_DRIVER(ldo12),
+ PM8607_REGULATOR_DRIVER(ldo14),
+};
+
+static int __init pm8607_regulator_init(void)
+{
+ int i, count, ret;
+
+ count = ARRAY_SIZE(pm8607_regulator_driver);
+ for (i = 0; i < count; i++) {
+ ret = platform_driver_register(&pm8607_regulator_driver[i]);
+ if (ret != 0)
+ pr_err("Failed to register regulator driver: %d\n",
+ ret);
+ }
+ return 0;
+}
+subsys_initcall(pm8607_regulator_init);
+
+static void __exit pm8607_regulator_exit(void)
+{
+ int i, count;
+
+ count = ARRAY_SIZE(pm8607_regulator_driver);
+ for (i = 0; i < count; i++)
+ platform_driver_unregister(&pm8607_regulator_driver[i]);
+}
+module_exit(pm8607_regulator_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC");
+MODULE_ALIAS("platform:88pm8607-regulator");
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 7cfdd65bebb..262f62eec83 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -69,6 +69,13 @@ config REGULATOR_MAX1586
regulator via I2C bus. The provided regulator is suitable
for PXA27x chips to control VCC_CORE and VCC_USIM voltages.
+config REGULATOR_MAX8660
+ tristate "Maxim 8660/8661 voltage regulator"
+ depends on I2C
+ help
+ This driver controls a Maxim 8660/8661 voltage output
+ regulator via I2C bus.
+
config REGULATOR_TWL4030
bool "TI TWL4030/TWL5030/TWL6030/TPS695x0 PMIC"
depends on TWL4030_CORE
@@ -157,5 +164,11 @@ config REGULATOR_TPS6507X
three step-down converters and two general-purpose LDO voltage regulators.
It supports TI's software based Class-2 SmartReflex implementation.
+config REGULATOR_88PM8607
+ bool "Marvell 88PM8607 Power regulators"
+ depends on MFD_88PM8607=y
+ help
+ This driver supports 88PM8607 voltage regulator chips.
+
endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 9ae3cc44e66..b3c806c7941 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
+obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
@@ -20,10 +21,11 @@ obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
-obj-$(CONFIG_REGULATOR_MC13783) += mc13783.o
+obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
+obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c
index 49aeee823a2..b349db4504b 100644
--- a/drivers/regulator/ab3100.c
+++ b/drivers/regulator/ab3100.c
@@ -81,7 +81,7 @@ static const u8 ab3100_reg_init_order[AB3100_NUM_REGULATORS+2] = {
#define LDO_C_VOLTAGE 2650000
#define LDO_D_VOLTAGE 2650000
-static const int const ldo_e_buck_typ_voltages[] = {
+static const int ldo_e_buck_typ_voltages[] = {
1800000,
1400000,
1300000,
@@ -91,7 +91,7 @@ static const int const ldo_e_buck_typ_voltages[] = {
900000,
};
-static const int const ldo_f_typ_voltages[] = {
+static const int ldo_f_typ_voltages[] = {
1800000,
1400000,
1300000,
@@ -102,21 +102,21 @@ static const int const ldo_f_typ_voltages[] = {
2650000,
};
-static const int const ldo_g_typ_voltages[] = {
+static const int ldo_g_typ_voltages[] = {
2850000,
2750000,
1800000,
1500000,
};
-static const int const ldo_h_typ_voltages[] = {
+static const int ldo_h_typ_voltages[] = {
2750000,
1800000,
1500000,
1200000,
};
-static const int const ldo_k_typ_voltages[] = {
+static const int ldo_k_typ_voltages[] = {
2750000,
1800000,
};
@@ -241,24 +241,12 @@ static int ab3100_disable_regulator(struct regulator_dev *reg)
* LDO D is a special regulator. When it is disabled, the entire
* system is shut down. So this is handled specially.
*/
+ pr_info("Called ab3100_disable_regulator\n");
if (abreg->regreg == AB3100_LDO_D) {
- int i;
-
dev_info(&reg->dev, "disabling LDO D - shut down system\n");
- /*
- * Set regulators to default values, ignore any errors,
- * we're going DOWN
- */
- for (i = 0; i < ARRAY_SIZE(ab3100_reg_init_order); i++) {
- (void) ab3100_set_register_interruptible(abreg->ab3100,
- ab3100_reg_init_order[i],
- abreg->plfdata->reg_initvals[i]);
- }
-
/* Setting LDO D to 0x00 cuts the power to the SoC */
return ab3100_set_register_interruptible(abreg->ab3100,
AB3100_LDO_D, 0x00U);
-
}
/*
@@ -607,13 +595,6 @@ static int __init ab3100_regulators_probe(struct platform_device *pdev)
}
}
- if (err) {
- dev_err(&pdev->dev,
- "LDO D regulator initialization failed with error %d\n",
- err);
- return err;
- }
-
/* Register the regulators */
for (i = 0; i < AB3100_NUM_REGULATORS; i++) {
struct ab3100_regulator *reg = &ab3100_regulators[i];
@@ -688,7 +669,7 @@ static __init int ab3100_regulators_init(void)
static __exit void ab3100_regulators_exit(void)
{
- platform_driver_register(&ab3100_regulators_driver);
+ platform_driver_unregister(&ab3100_regulators_driver);
}
subsys_initcall(ab3100_regulators_init);
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index efe568deda1..686ef270ecf 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -66,6 +66,16 @@ static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
static void _notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data);
+static const char *rdev_get_name(struct regulator_dev *rdev)
+{
+ if (rdev->constraints && rdev->constraints->name)
+ return rdev->constraints->name;
+ else if (rdev->desc->name)
+ return rdev->desc->name;
+ else
+ return "";
+}
+
/* gets the regulator for a given consumer device */
static struct regulator *get_device_regulator(struct device *dev)
{
@@ -96,12 +106,12 @@ static int regulator_check_voltage(struct regulator_dev *rdev,
if (!rdev->constraints) {
printk(KERN_ERR "%s: no constraints for %s\n", __func__,
- rdev->desc->name);
+ rdev_get_name(rdev));
return -ENODEV;
}
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
printk(KERN_ERR "%s: operation not allowed for %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
return -EPERM;
}
@@ -124,12 +134,12 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,
if (!rdev->constraints) {
printk(KERN_ERR "%s: no constraints for %s\n", __func__,
- rdev->desc->name);
+ rdev_get_name(rdev));
return -ENODEV;
}
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) {
printk(KERN_ERR "%s: operation not allowed for %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
return -EPERM;
}
@@ -159,17 +169,17 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode)
if (!rdev->constraints) {
printk(KERN_ERR "%s: no constraints for %s\n", __func__,
- rdev->desc->name);
+ rdev_get_name(rdev));
return -ENODEV;
}
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) {
printk(KERN_ERR "%s: operation not allowed for %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
return -EPERM;
}
if (!(rdev->constraints->valid_modes_mask & mode)) {
printk(KERN_ERR "%s: invalid mode %x for %s\n",
- __func__, mode, rdev->desc->name);
+ __func__, mode, rdev_get_name(rdev));
return -EINVAL;
}
return 0;
@@ -180,12 +190,12 @@ static int regulator_check_drms(struct regulator_dev *rdev)
{
if (!rdev->constraints) {
printk(KERN_ERR "%s: no constraints for %s\n", __func__,
- rdev->desc->name);
+ rdev_get_name(rdev));
return -ENODEV;
}
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) {
printk(KERN_ERR "%s: operation not allowed for %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
return -EPERM;
}
return 0;
@@ -230,16 +240,8 @@ static ssize_t regulator_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
- const char *name;
- if (rdev->constraints && rdev->constraints->name)
- name = rdev->constraints->name;
- else if (rdev->desc->name)
- name = rdev->desc->name;
- else
- name = "";
-
- return sprintf(buf, "%s\n", name);
+ return sprintf(buf, "%s\n", rdev_get_name(rdev));
}
static ssize_t regulator_print_opmode(char *buf, int mode)
@@ -388,7 +390,7 @@ static ssize_t regulator_total_uA_show(struct device *dev,
mutex_lock(&rdev->mutex);
list_for_each_entry(regulator, &rdev->consumer_list, list)
- uA += regulator->uA_load;
+ uA += regulator->uA_load;
mutex_unlock(&rdev->mutex);
return sprintf(buf, "%d\n", uA);
}
@@ -563,7 +565,7 @@ static void drms_uA_update(struct regulator_dev *rdev)
/* calc total requested load */
list_for_each_entry(sibling, &rdev->consumer_list, list)
- current_uA += sibling->uA_load;
+ current_uA += sibling->uA_load;
/* now get the optimum mode for our new total regulator load */
mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV,
@@ -579,10 +581,29 @@ static int suspend_set_state(struct regulator_dev *rdev,
struct regulator_state *rstate)
{
int ret = 0;
+ bool can_set_state;
- /* enable & disable are mandatory for suspend control */
- if (!rdev->desc->ops->set_suspend_enable ||
- !rdev->desc->ops->set_suspend_disable) {
+ can_set_state = rdev->desc->ops->set_suspend_enable &&
+ rdev->desc->ops->set_suspend_disable;
+
+ /* If we have no suspend mode configration don't set anything;
+ * only warn if the driver actually makes the suspend mode
+ * configurable.
+ */
+ if (!rstate->enabled && !rstate->disabled) {
+ if (can_set_state)
+ printk(KERN_WARNING "%s: No configuration for %s\n",
+ __func__, rdev_get_name(rdev));
+ return 0;
+ }
+
+ if (rstate->enabled && rstate->disabled) {
+ printk(KERN_ERR "%s: invalid configuration for %s\n",
+ __func__, rdev_get_name(rdev));
+ return -EINVAL;
+ }
+
+ if (!can_set_state) {
printk(KERN_ERR "%s: no way to set suspend state\n",
__func__);
return -EINVAL;
@@ -641,25 +662,43 @@ static void print_constraints(struct regulator_dev *rdev)
{
struct regulation_constraints *constraints = rdev->constraints;
char buf[80];
- int count;
+ int count = 0;
+ int ret;
- if (rdev->desc->type == REGULATOR_VOLTAGE) {
+ if (constraints->min_uV && constraints->max_uV) {
if (constraints->min_uV == constraints->max_uV)
- count = sprintf(buf, "%d mV ",
- constraints->min_uV / 1000);
+ count += sprintf(buf + count, "%d mV ",
+ constraints->min_uV / 1000);
else
- count = sprintf(buf, "%d <--> %d mV ",
- constraints->min_uV / 1000,
- constraints->max_uV / 1000);
- } else {
+ count += sprintf(buf + count, "%d <--> %d mV ",
+ constraints->min_uV / 1000,
+ constraints->max_uV / 1000);
+ }
+
+ if (!constraints->min_uV ||
+ constraints->min_uV != constraints->max_uV) {
+ ret = _regulator_get_voltage(rdev);
+ if (ret > 0)
+ count += sprintf(buf + count, "at %d mV ", ret / 1000);
+ }
+
+ if (constraints->min_uA && constraints->max_uA) {
if (constraints->min_uA == constraints->max_uA)
- count = sprintf(buf, "%d mA ",
- constraints->min_uA / 1000);
+ count += sprintf(buf + count, "%d mA ",
+ constraints->min_uA / 1000);
else
- count = sprintf(buf, "%d <--> %d mA ",
- constraints->min_uA / 1000,
- constraints->max_uA / 1000);
+ count += sprintf(buf + count, "%d <--> %d mA ",
+ constraints->min_uA / 1000,
+ constraints->max_uA / 1000);
}
+
+ if (!constraints->min_uA ||
+ constraints->min_uA != constraints->max_uA) {
+ ret = _regulator_get_current_limit(rdev);
+ if (ret > 0)
+ count += sprintf(buf + count, "at %d uA ", ret / 1000);
+ }
+
if (constraints->valid_modes_mask & REGULATOR_MODE_FAST)
count += sprintf(buf + count, "fast ");
if (constraints->valid_modes_mask & REGULATOR_MODE_NORMAL)
@@ -669,33 +708,30 @@ static void print_constraints(struct regulator_dev *rdev)
if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY)
count += sprintf(buf + count, "standby");
- printk(KERN_INFO "regulator: %s: %s\n", rdev->desc->name, buf);
+ printk(KERN_INFO "regulator: %s: %s\n", rdev_get_name(rdev), buf);
}
-/**
- * set_machine_constraints - sets regulator constraints
- * @rdev: regulator source
- * @constraints: constraints to apply
- *
- * Allows platform initialisation code to define and constrain
- * regulator circuits e.g. valid voltage/current ranges, etc. NOTE:
- * Constraints *must* be set by platform code in order for some
- * regulator operations to proceed i.e. set_voltage, set_current_limit,
- * set_mode.
- */
-static int set_machine_constraints(struct regulator_dev *rdev,
+static int machine_constraints_voltage(struct regulator_dev *rdev,
struct regulation_constraints *constraints)
{
- int ret = 0;
- const char *name;
struct regulator_ops *ops = rdev->desc->ops;
+ const char *name = rdev_get_name(rdev);
+ int ret;
- if (constraints->name)
- name = constraints->name;
- else if (rdev->desc->name)
- name = rdev->desc->name;
- else
- name = "regulator";
+ /* do we need to apply the constraint voltage */
+ if (rdev->constraints->apply_uV &&
+ rdev->constraints->min_uV == rdev->constraints->max_uV &&
+ ops->set_voltage) {
+ ret = ops->set_voltage(rdev,
+ rdev->constraints->min_uV, rdev->constraints->max_uV);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: failed to apply %duV constraint to %s\n",
+ __func__,
+ rdev->constraints->min_uV, name);
+ rdev->constraints = NULL;
+ return ret;
+ }
+ }
/* constrain machine-level voltage specs to fit
* the actual range supported by this regulator.
@@ -719,14 +755,13 @@ static int set_machine_constraints(struct regulator_dev *rdev,
/* voltage constraints are optional */
if ((cmin == 0) && (cmax == 0))
- goto out;
+ return 0;
/* else require explicit machine-level constraints */
if (cmin <= 0 || cmax <= 0 || cmax < cmin) {
pr_err("%s: %s '%s' voltage constraints\n",
__func__, "invalid", name);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
/* initial: [cmin..cmax] valid, [min_uV..max_uV] not */
@@ -748,8 +783,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
if (max_uV < min_uV) {
pr_err("%s: %s '%s' voltage constraints\n",
__func__, "unsupportable", name);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
/* use regulator's subset of machine constraints */
@@ -767,22 +801,34 @@ static int set_machine_constraints(struct regulator_dev *rdev,
}
}
+ return 0;
+}
+
+/**
+ * set_machine_constraints - sets regulator constraints
+ * @rdev: regulator source
+ * @constraints: constraints to apply
+ *
+ * Allows platform initialisation code to define and constrain
+ * regulator circuits e.g. valid voltage/current ranges, etc. NOTE:
+ * Constraints *must* be set by platform code in order for some
+ * regulator operations to proceed i.e. set_voltage, set_current_limit,
+ * set_mode.
+ */
+static int set_machine_constraints(struct regulator_dev *rdev,
+ struct regulation_constraints *constraints)
+{
+ int ret = 0;
+ const char *name;
+ struct regulator_ops *ops = rdev->desc->ops;
+
rdev->constraints = constraints;
- /* do we need to apply the constraint voltage */
- if (rdev->constraints->apply_uV &&
- rdev->constraints->min_uV == rdev->constraints->max_uV &&
- ops->set_voltage) {
- ret = ops->set_voltage(rdev,
- rdev->constraints->min_uV, rdev->constraints->max_uV);
- if (ret < 0) {
- printk(KERN_ERR "%s: failed to apply %duV constraint to %s\n",
- __func__,
- rdev->constraints->min_uV, name);
- rdev->constraints = NULL;
- goto out;
- }
- }
+ name = rdev_get_name(rdev);
+
+ ret = machine_constraints_voltage(rdev, constraints);
+ if (ret != 0)
+ goto out;
/* do we need to setup our suspend state */
if (constraints->initial_state) {
@@ -903,7 +949,7 @@ static int set_consumer_device_supply(struct regulator_dev *rdev,
dev_name(&node->regulator->dev),
node->regulator->desc->name,
supply,
- dev_name(&rdev->dev), rdev->desc->name);
+ dev_name(&rdev->dev), rdev_get_name(rdev));
return -EBUSY;
}
@@ -1212,7 +1258,7 @@ static int _regulator_enable(struct regulator_dev *rdev)
ret = _regulator_enable(rdev->supply);
if (ret < 0) {
printk(KERN_ERR "%s: failed to enable %s: %d\n",
- __func__, rdev->desc->name, ret);
+ __func__, rdev_get_name(rdev), ret);
return ret;
}
}
@@ -1238,7 +1284,7 @@ static int _regulator_enable(struct regulator_dev *rdev)
}
} else if (ret < 0) {
printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n",
- __func__, rdev->desc->name, ret);
+ __func__, rdev_get_name(rdev), ret);
return ret;
}
/* Fallthrough on positive return values - already enabled */
@@ -1279,7 +1325,7 @@ static int _regulator_disable(struct regulator_dev *rdev)
if (WARN(rdev->use_count <= 0,
"unbalanced disables for %s\n",
- rdev->desc->name))
+ rdev_get_name(rdev)))
return -EIO;
/* are we the last user and permitted to disable ? */
@@ -1292,7 +1338,7 @@ static int _regulator_disable(struct regulator_dev *rdev)
ret = rdev->desc->ops->disable(rdev);
if (ret < 0) {
printk(KERN_ERR "%s: failed to disable %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
return ret;
}
}
@@ -1349,7 +1395,7 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
ret = rdev->desc->ops->disable(rdev);
if (ret < 0) {
printk(KERN_ERR "%s: failed to force disable %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
return ret;
}
/* notify other consumers that power has been forced off */
@@ -1766,7 +1812,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
output_uV = rdev->desc->ops->get_voltage(rdev);
if (output_uV <= 0) {
printk(KERN_ERR "%s: invalid output voltage found for %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
goto out;
}
@@ -1777,13 +1823,13 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
input_uV = rdev->constraints->input_uV;
if (input_uV <= 0) {
printk(KERN_ERR "%s: invalid input voltage found for %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
goto out;
}
/* calc total requested load for this regulator */
list_for_each_entry(consumer, &rdev->consumer_list, list)
- total_uA_load += consumer->uA_load;
+ total_uA_load += consumer->uA_load;
mode = rdev->desc->ops->get_optimum_mode(rdev,
input_uV, output_uV,
@@ -1791,7 +1837,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
ret = regulator_check_mode(rdev, mode);
if (ret < 0) {
printk(KERN_ERR "%s: failed to get optimum mode for %s @"
- " %d uA %d -> %d uV\n", __func__, rdev->desc->name,
+ " %d uA %d -> %d uV\n", __func__, rdev_get_name(rdev),
total_uA_load, input_uV, output_uV);
goto out;
}
@@ -1799,7 +1845,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
ret = rdev->desc->ops->set_mode(rdev, mode);
if (ret < 0) {
printk(KERN_ERR "%s: failed to set optimum mode %x for %s\n",
- __func__, mode, rdev->desc->name);
+ __func__, mode, rdev_get_name(rdev));
goto out;
}
ret = mode;
@@ -1852,9 +1898,9 @@ static void _notifier_call_chain(struct regulator_dev *rdev,
/* now notify regulator we supply */
list_for_each_entry(_rdev, &rdev->supply_list, slist) {
- mutex_lock(&_rdev->mutex);
- _notifier_call_chain(_rdev, event, data);
- mutex_unlock(&_rdev->mutex);
+ mutex_lock(&_rdev->mutex);
+ _notifier_call_chain(_rdev, event, data);
+ mutex_unlock(&_rdev->mutex);
}
}
@@ -1885,9 +1931,9 @@ int regulator_bulk_get(struct device *dev, int num_consumers,
consumers[i].consumer = regulator_get(dev,
consumers[i].supply);
if (IS_ERR(consumers[i].consumer)) {
- dev_err(dev, "Failed to get supply '%s'\n",
- consumers[i].supply);
ret = PTR_ERR(consumers[i].consumer);
+ dev_err(dev, "Failed to get supply '%s': %d\n",
+ consumers[i].supply, ret);
consumers[i].consumer = NULL;
goto err;
}
@@ -1930,8 +1976,8 @@ int regulator_bulk_enable(int num_consumers,
return 0;
err:
- printk(KERN_ERR "Failed to enable %s\n", consumers[i].supply);
- for (i = 0; i < num_consumers; i++)
+ printk(KERN_ERR "Failed to enable %s: %d\n", consumers[i].supply, ret);
+ for (--i; i >= 0; --i)
regulator_disable(consumers[i].consumer);
return ret;
@@ -1965,8 +2011,9 @@ int regulator_bulk_disable(int num_consumers,
return 0;
err:
- printk(KERN_ERR "Failed to disable %s\n", consumers[i].supply);
- for (i = 0; i < num_consumers; i++)
+ printk(KERN_ERR "Failed to disable %s: %d\n", consumers[i].supply,
+ ret);
+ for (--i; i >= 0; --i)
regulator_enable(consumers[i].consumer);
return ret;
@@ -2316,7 +2363,7 @@ int regulator_suspend_prepare(suspend_state_t state)
if (ret < 0) {
printk(KERN_ERR "%s: failed to prepare %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
goto out;
}
}
@@ -2429,12 +2476,7 @@ static int __init regulator_init_complete(void)
ops = rdev->desc->ops;
c = rdev->constraints;
- if (c && c->name)
- name = c->name;
- else if (rdev->desc->name)
- name = rdev->desc->name;
- else
- name = "regulator";
+ name = rdev_get_name(rdev);
if (!ops->disable || (c && c->always_on))
continue;
diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c
index aa224d936e0..f8c4661a7a8 100644
--- a/drivers/regulator/da903x.c
+++ b/drivers/regulator/da903x.c
@@ -331,7 +331,7 @@ static int da9034_get_ldo12_voltage(struct regulator_dev *rdev)
static int da9034_list_ldo12_voltage(struct regulator_dev *rdev,
unsigned selector)
{
- if (selector > ARRAY_SIZE(da9034_ldo12_data))
+ if (selector >= ARRAY_SIZE(da9034_ldo12_data))
return -EINVAL;
return da9034_ldo12_data[selector] * 1000;
}
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 7803a320543..76d08c282f9 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -446,8 +446,8 @@ static int setup_regulators(struct lp3971 *lp3971,
lp3971->rdev[i] = regulator_register(&regulators[id],
lp3971->dev, pdata->regulators[i].initdata, lp3971);
- err = IS_ERR(lp3971->rdev[i]);
- if (err) {
+ if (IS_ERR(lp3971->rdev[i])) {
+ err = PTR_ERR(lp3971->rdev[i]);
dev_err(lp3971->dev, "regulator init failed: %d\n",
err);
goto error;
diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c
new file mode 100644
index 00000000000..acc2fb7b608
--- /dev/null
+++ b/drivers/regulator/max8660.c
@@ -0,0 +1,510 @@
+/*
+ * max8660.c -- Voltage regulation for the Maxim 8660/8661
+ *
+ * based on max1586.c and wm8400-regulator.c
+ *
+ * Copyright (C) 2009 Wolfram Sang, Pengutronix e.K.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Some info:
+ *
+ * Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX8660-MAX8661.pdf
+ *
+ * This chip is a bit nasty because it is a write-only device. Thus, the driver
+ * uses shadow registers to keep track of its values. The main problem appears
+ * to be the initialization: When Linux boots up, we cannot know if the chip is
+ * in the default state or not, so we would have to pass such information in
+ * platform_data. As this adds a bit of complexity to the driver, this is left
+ * out for now until it is really needed.
+ *
+ * [A|S|M]DTV1 registers are currently not used, but [A|S|M]DTV2.
+ *
+ * If the driver is feature complete, it might be worth to check if one set of
+ * functions for V3-V7 is sufficient. For maximum flexibility during
+ * development, they are separated for now.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/max8660.h>
+
+#define MAX8660_DCDC_MIN_UV 725000
+#define MAX8660_DCDC_MAX_UV 1800000
+#define MAX8660_DCDC_STEP 25000
+#define MAX8660_DCDC_MAX_SEL 0x2b
+
+#define MAX8660_LDO5_MIN_UV 1700000
+#define MAX8660_LDO5_MAX_UV 2000000
+#define MAX8660_LDO5_STEP 25000
+#define MAX8660_LDO5_MAX_SEL 0x0c
+
+#define MAX8660_LDO67_MIN_UV 1800000
+#define MAX8660_LDO67_MAX_UV 3300000
+#define MAX8660_LDO67_STEP 100000
+#define MAX8660_LDO67_MAX_SEL 0x0f
+
+enum {
+ MAX8660_OVER1,
+ MAX8660_OVER2,
+ MAX8660_VCC1,
+ MAX8660_ADTV1,
+ MAX8660_ADTV2,
+ MAX8660_SDTV1,
+ MAX8660_SDTV2,
+ MAX8660_MDTV1,
+ MAX8660_MDTV2,
+ MAX8660_L12VCR,
+ MAX8660_FPWM,
+ MAX8660_N_REGS, /* not a real register */
+};
+
+struct max8660 {
+ struct i2c_client *client;
+ u8 shadow_regs[MAX8660_N_REGS]; /* as chip is write only */
+ struct regulator_dev *rdev[];
+};
+
+static int max8660_write(struct max8660 *max8660, u8 reg, u8 mask, u8 val)
+{
+ static const u8 max8660_addresses[MAX8660_N_REGS] =
+ { 0x10, 0x12, 0x20, 0x23, 0x24, 0x29, 0x2a, 0x32, 0x33, 0x39, 0x80 };
+
+ int ret;
+ u8 reg_val = (max8660->shadow_regs[reg] & mask) | val;
+ dev_vdbg(&max8660->client->dev, "Writing reg %02x with %02x\n",
+ max8660_addresses[reg], reg_val);
+
+ ret = i2c_smbus_write_byte_data(max8660->client,
+ max8660_addresses[reg], reg_val);
+ if (ret == 0)
+ max8660->shadow_regs[reg] = reg_val;
+
+ return ret;
+}
+
+
+/*
+ * DCDC functions
+ */
+
+static int max8660_dcdc_is_enabled(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 val = max8660->shadow_regs[MAX8660_OVER1];
+ u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4;
+ return !!(val & mask);
+}
+
+static int max8660_dcdc_enable(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 bit = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4;
+ return max8660_write(max8660, MAX8660_OVER1, 0xff, bit);
+}
+
+static int max8660_dcdc_disable(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? ~1 : ~4;
+ return max8660_write(max8660, MAX8660_OVER1, mask, 0);
+}
+
+static int max8660_dcdc_list(struct regulator_dev *rdev, unsigned selector)
+{
+ if (selector > MAX8660_DCDC_MAX_SEL)
+ return -EINVAL;
+ return MAX8660_DCDC_MIN_UV + selector * MAX8660_DCDC_STEP;
+}
+
+static int max8660_dcdc_get(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2;
+ u8 selector = max8660->shadow_regs[reg];
+ return MAX8660_DCDC_MIN_UV + selector * MAX8660_DCDC_STEP;
+}
+
+static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 reg, selector, bits;
+ int ret;
+
+ if (min_uV < MAX8660_DCDC_MIN_UV || min_uV > MAX8660_DCDC_MAX_UV)
+ return -EINVAL;
+ if (max_uV < MAX8660_DCDC_MIN_UV || max_uV > MAX8660_DCDC_MAX_UV)
+ return -EINVAL;
+
+ selector = (min_uV - (MAX8660_DCDC_MIN_UV - MAX8660_DCDC_STEP + 1))
+ / MAX8660_DCDC_STEP;
+
+ ret = max8660_dcdc_list(rdev, selector);
+ if (ret < 0 || ret > max_uV)
+ return -EINVAL;
+
+ reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2;
+ ret = max8660_write(max8660, reg, 0, selector);
+ if (ret)
+ return ret;
+
+ /* Select target voltage register and activate regulation */
+ bits = (rdev_get_id(rdev) == MAX8660_V3) ? 0x03 : 0x30;
+ return max8660_write(max8660, MAX8660_VCC1, 0xff, bits);
+}
+
+static struct regulator_ops max8660_dcdc_ops = {
+ .is_enabled = max8660_dcdc_is_enabled,
+ .list_voltage = max8660_dcdc_list,
+ .set_voltage = max8660_dcdc_set,
+ .get_voltage = max8660_dcdc_get,
+};
+
+
+/*
+ * LDO5 functions
+ */
+
+static int max8660_ldo5_list(struct regulator_dev *rdev, unsigned selector)
+{
+ if (selector > MAX8660_LDO5_MAX_SEL)
+ return -EINVAL;
+ return MAX8660_LDO5_MIN_UV + selector * MAX8660_LDO5_STEP;
+}
+
+static int max8660_ldo5_get(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 selector = max8660->shadow_regs[MAX8660_MDTV2];
+
+ return MAX8660_LDO5_MIN_UV + selector * MAX8660_LDO5_STEP;
+}
+
+static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 selector;
+ int ret;
+
+ if (min_uV < MAX8660_LDO5_MIN_UV || min_uV > MAX8660_LDO5_MAX_UV)
+ return -EINVAL;
+ if (max_uV < MAX8660_LDO5_MIN_UV || max_uV > MAX8660_LDO5_MAX_UV)
+ return -EINVAL;
+
+ selector = (min_uV - (MAX8660_LDO5_MIN_UV - MAX8660_LDO5_STEP + 1))
+ / MAX8660_LDO5_STEP;
+ ret = max8660_ldo5_list(rdev, selector);
+ if (ret < 0 || ret > max_uV)
+ return -EINVAL;
+
+ ret = max8660_write(max8660, MAX8660_MDTV2, 0, selector);
+ if (ret)
+ return ret;
+
+ /* Select target voltage register and activate regulation */
+ return max8660_write(max8660, MAX8660_VCC1, 0xff, 0xc0);
+}
+
+static struct regulator_ops max8660_ldo5_ops = {
+ .list_voltage = max8660_ldo5_list,
+ .set_voltage = max8660_ldo5_set,
+ .get_voltage = max8660_ldo5_get,
+};
+
+
+/*
+ * LDO67 functions
+ */
+
+static int max8660_ldo67_is_enabled(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 val = max8660->shadow_regs[MAX8660_OVER2];
+ u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4;
+ return !!(val & mask);
+}
+
+static int max8660_ldo67_enable(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 bit = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4;
+ return max8660_write(max8660, MAX8660_OVER2, 0xff, bit);
+}
+
+static int max8660_ldo67_disable(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? ~2 : ~4;
+ return max8660_write(max8660, MAX8660_OVER2, mask, 0);
+}
+
+static int max8660_ldo67_list(struct regulator_dev *rdev, unsigned selector)
+{
+ if (selector > MAX8660_LDO67_MAX_SEL)
+ return -EINVAL;
+ return MAX8660_LDO67_MIN_UV + selector * MAX8660_LDO67_STEP;
+}
+
+static int max8660_ldo67_get(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 shift = (rdev_get_id(rdev) == MAX8660_V6) ? 0 : 4;
+ u8 selector = (max8660->shadow_regs[MAX8660_L12VCR] >> shift) & 0xf;
+
+ return MAX8660_LDO67_MIN_UV + selector * MAX8660_LDO67_STEP;
+}
+
+static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 selector;
+ int ret;
+
+ if (min_uV < MAX8660_LDO67_MIN_UV || min_uV > MAX8660_LDO67_MAX_UV)
+ return -EINVAL;
+ if (max_uV < MAX8660_LDO67_MIN_UV || max_uV > MAX8660_LDO67_MAX_UV)
+ return -EINVAL;
+
+ selector = (min_uV - (MAX8660_LDO67_MIN_UV - MAX8660_LDO67_STEP + 1))
+ / MAX8660_LDO67_STEP;
+
+ ret = max8660_ldo67_list(rdev, selector);
+ if (ret < 0 || ret > max_uV)
+ return -EINVAL;
+
+ if (rdev_get_id(rdev) == MAX8660_V6)
+ return max8660_write(max8660, MAX8660_L12VCR, 0xf0, selector);
+ else
+ return max8660_write(max8660, MAX8660_L12VCR, 0x0f, selector << 4);
+}
+
+static struct regulator_ops max8660_ldo67_ops = {
+ .is_enabled = max8660_ldo67_is_enabled,
+ .enable = max8660_ldo67_enable,
+ .disable = max8660_ldo67_disable,
+ .list_voltage = max8660_ldo67_list,
+ .get_voltage = max8660_ldo67_get,
+ .set_voltage = max8660_ldo67_set,
+};
+
+static struct regulator_desc max8660_reg[] = {
+ {
+ .name = "V3(DCDC)",
+ .id = MAX8660_V3,
+ .ops = &max8660_dcdc_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = MAX8660_DCDC_MAX_SEL + 1,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "V4(DCDC)",
+ .id = MAX8660_V4,
+ .ops = &max8660_dcdc_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = MAX8660_DCDC_MAX_SEL + 1,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "V5(LDO)",
+ .id = MAX8660_V5,
+ .ops = &max8660_ldo5_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = MAX8660_LDO5_MAX_SEL + 1,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "V6(LDO)",
+ .id = MAX8660_V6,
+ .ops = &max8660_ldo67_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = MAX8660_LDO67_MAX_SEL + 1,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "V7(LDO)",
+ .id = MAX8660_V7,
+ .ops = &max8660_ldo67_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = MAX8660_LDO67_MAX_SEL + 1,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int max8660_probe(struct i2c_client *client,
+ const struct i2c_device_id *i2c_id)
+{
+ struct regulator_dev **rdev;
+ struct max8660_platform_data *pdata = client->dev.platform_data;
+ struct max8660 *max8660;
+ int boot_on, i, id, ret = -EINVAL;
+
+ if (pdata->num_subdevs > MAX8660_V_END) {
+ dev_err(&client->dev, "Too much regulators found!\n");
+ goto out;
+ }
+
+ max8660 = kzalloc(sizeof(struct max8660) +
+ sizeof(struct regulator_dev *) * MAX8660_V_END,
+ GFP_KERNEL);
+ if (!max8660) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ max8660->client = client;
+ rdev = max8660->rdev;
+
+ if (pdata->en34_is_high) {
+ /* Simulate always on */
+ max8660->shadow_regs[MAX8660_OVER1] = 5;
+ } else {
+ /* Otherwise devices can be toggled via software */
+ max8660_dcdc_ops.enable = max8660_dcdc_enable;
+ max8660_dcdc_ops.disable = max8660_dcdc_disable;
+ }
+
+ /*
+ * First, set up shadow registers to prevent glitches. As some
+ * registers are shared between regulators, everything must be properly
+ * set up for all regulators in advance.
+ */
+ max8660->shadow_regs[MAX8660_ADTV1] =
+ max8660->shadow_regs[MAX8660_ADTV2] =
+ max8660->shadow_regs[MAX8660_SDTV1] =
+ max8660->shadow_regs[MAX8660_SDTV2] = 0x1b;
+ max8660->shadow_regs[MAX8660_MDTV1] =
+ max8660->shadow_regs[MAX8660_MDTV2] = 0x04;
+
+ for (i = 0; i < pdata->num_subdevs; i++) {
+
+ if (!pdata->subdevs[i].platform_data)
+ goto err_free;
+
+ boot_on = pdata->subdevs[i].platform_data->constraints.boot_on;
+
+ switch (pdata->subdevs[i].id) {
+ case MAX8660_V3:
+ if (boot_on)
+ max8660->shadow_regs[MAX8660_OVER1] |= 1;
+ break;
+
+ case MAX8660_V4:
+ if (boot_on)
+ max8660->shadow_regs[MAX8660_OVER1] |= 4;
+ break;
+
+ case MAX8660_V5:
+ break;
+
+ case MAX8660_V6:
+ if (boot_on)
+ max8660->shadow_regs[MAX8660_OVER2] |= 2;
+ break;
+
+ case MAX8660_V7:
+ if (!strcmp(i2c_id->name, "max8661")) {
+ dev_err(&client->dev, "Regulator not on this chip!\n");
+ goto err_free;
+ }
+
+ if (boot_on)
+ max8660->shadow_regs[MAX8660_OVER2] |= 4;
+ break;
+
+ default:
+ dev_err(&client->dev, "invalid regulator %s\n",
+ pdata->subdevs[i].name);
+ goto err_free;
+ }
+ }
+
+ /* Finally register devices */
+ for (i = 0; i < pdata->num_subdevs; i++) {
+
+ id = pdata->subdevs[i].id;
+
+ rdev[i] = regulator_register(&max8660_reg[id], &client->dev,
+ pdata->subdevs[i].platform_data,
+ max8660);
+ if (IS_ERR(rdev[i])) {
+ ret = PTR_ERR(rdev[i]);
+ dev_err(&client->dev, "failed to register %s\n",
+ max8660_reg[id].name);
+ goto err_unregister;
+ }
+ }
+
+ i2c_set_clientdata(client, rdev);
+ dev_info(&client->dev, "Maxim 8660/8661 regulator driver loaded\n");
+ return 0;
+
+err_unregister:
+ while (--i >= 0)
+ regulator_unregister(rdev[i]);
+err_free:
+ kfree(max8660);
+out:
+ return ret;
+}
+
+static int max8660_remove(struct i2c_client *client)
+{
+ struct regulator_dev **rdev = i2c_get_clientdata(client);
+ int i;
+
+ for (i = 0; i < MAX8660_V_END; i++)
+ if (rdev[i])
+ regulator_unregister(rdev[i]);
+ kfree(rdev);
+ i2c_set_clientdata(client, NULL);
+
+ return 0;
+}
+
+static const struct i2c_device_id max8660_id[] = {
+ { "max8660", 0 },
+ { "max8661", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max8660_id);
+
+static struct i2c_driver max8660_driver = {
+ .probe = max8660_probe,
+ .remove = max8660_remove,
+ .driver = {
+ .name = "max8660",
+ },
+ .id_table = max8660_id,
+};
+
+static int __init max8660_init(void)
+{
+ return i2c_add_driver(&max8660_driver);
+}
+subsys_initcall(max8660_init);
+
+static void __exit max8660_exit(void)
+{
+ i2c_del_driver(&max8660_driver);
+}
+module_exit(max8660_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MAXIM 8660/8661 voltage regulator driver");
+MODULE_AUTHOR("Wolfram Sang");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c
new file mode 100644
index 00000000000..39c49530004
--- /dev/null
+++ b/drivers/regulator/mc13783-regulator.c
@@ -0,0 +1,245 @@
+/*
+ * Regulator Driver for Freescale MC13783 PMIC
+ *
+ * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ *
+ * 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.
+ */
+
+#include <linux/mfd/mc13783.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+
+#define MC13783_REG_SWITCHERS4 28
+#define MC13783_REG_SWITCHERS4_PLLEN (1 << 18)
+
+#define MC13783_REG_SWITCHERS5 29
+#define MC13783_REG_SWITCHERS5_SW3EN (1 << 20)
+
+#define MC13783_REG_REGULATORMODE0 32
+#define MC13783_REG_REGULATORMODE0_VAUDIOEN (1 << 0)
+#define MC13783_REG_REGULATORMODE0_VIOHIEN (1 << 3)
+#define MC13783_REG_REGULATORMODE0_VIOLOEN (1 << 6)
+#define MC13783_REG_REGULATORMODE0_VDIGEN (1 << 9)
+#define MC13783_REG_REGULATORMODE0_VGENEN (1 << 12)
+#define MC13783_REG_REGULATORMODE0_VRFDIGEN (1 << 15)
+#define MC13783_REG_REGULATORMODE0_VRFREFEN (1 << 18)
+#define MC13783_REG_REGULATORMODE0_VRFCPEN (1 << 21)
+
+#define MC13783_REG_REGULATORMODE1 33
+#define MC13783_REG_REGULATORMODE1_VSIMEN (1 << 0)
+#define MC13783_REG_REGULATORMODE1_VESIMEN (1 << 3)
+#define MC13783_REG_REGULATORMODE1_VCAMEN (1 << 6)
+#define MC13783_REG_REGULATORMODE1_VRFBGEN (1 << 9)
+#define MC13783_REG_REGULATORMODE1_VVIBEN (1 << 11)
+#define MC13783_REG_REGULATORMODE1_VRF1EN (1 << 12)
+#define MC13783_REG_REGULATORMODE1_VRF2EN (1 << 15)
+#define MC13783_REG_REGULATORMODE1_VMMC1EN (1 << 18)
+#define MC13783_REG_REGULATORMODE1_VMMC2EN (1 << 21)
+
+#define MC13783_REG_POWERMISC 34
+#define MC13783_REG_POWERMISC_GPO1EN (1 << 6)
+#define MC13783_REG_POWERMISC_GPO2EN (1 << 8)
+#define MC13783_REG_POWERMISC_GPO3EN (1 << 10)
+#define MC13783_REG_POWERMISC_GPO4EN (1 << 12)
+
+struct mc13783_regulator {
+ struct regulator_desc desc;
+ int reg;
+ int enable_bit;
+};
+
+static struct regulator_ops mc13783_regulator_ops;
+
+#define MC13783_DEFINE(prefix, _name, _reg) \
+ [MC13783_ ## prefix ## _ ## _name] = { \
+ .desc = { \
+ .name = #prefix "_" #_name, \
+ .ops = &mc13783_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MC13783_ ## prefix ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ }, \
+ .reg = MC13783_REG_ ## _reg, \
+ .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \
+ }
+
+#define MC13783_DEFINE_SW(_name, _reg) MC13783_DEFINE(SW, _name, _reg)
+#define MC13783_DEFINE_REGU(_name, _reg) MC13783_DEFINE(REGU, _name, _reg)
+
+static struct mc13783_regulator mc13783_regulators[] = {
+ MC13783_DEFINE_SW(SW3, SWITCHERS5),
+ MC13783_DEFINE_SW(PLL, SWITCHERS4),
+
+ MC13783_DEFINE_REGU(VAUDIO, REGULATORMODE0),
+ MC13783_DEFINE_REGU(VIOHI, REGULATORMODE0),
+ MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0),
+ MC13783_DEFINE_REGU(VDIG, REGULATORMODE0),
+ MC13783_DEFINE_REGU(VGEN, REGULATORMODE0),
+ MC13783_DEFINE_REGU(VRFDIG, REGULATORMODE0),
+ MC13783_DEFINE_REGU(VRFREF, REGULATORMODE0),
+ MC13783_DEFINE_REGU(VRFCP, REGULATORMODE0),
+ MC13783_DEFINE_REGU(VSIM, REGULATORMODE1),
+ MC13783_DEFINE_REGU(VESIM, REGULATORMODE1),
+ MC13783_DEFINE_REGU(VCAM, REGULATORMODE1),
+ MC13783_DEFINE_REGU(VRFBG, REGULATORMODE1),
+ MC13783_DEFINE_REGU(VVIB, REGULATORMODE1),
+ MC13783_DEFINE_REGU(VRF1, REGULATORMODE1),
+ MC13783_DEFINE_REGU(VRF2, REGULATORMODE1),
+ MC13783_DEFINE_REGU(VMMC1, REGULATORMODE1),
+ MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1),
+ MC13783_DEFINE_REGU(GPO1, POWERMISC),
+ MC13783_DEFINE_REGU(GPO2, POWERMISC),
+ MC13783_DEFINE_REGU(GPO3, POWERMISC),
+ MC13783_DEFINE_REGU(GPO4, POWERMISC),
+};
+
+struct mc13783_regulator_priv {
+ struct mc13783 *mc13783;
+ struct regulator_dev *regulators[];
+};
+
+static int mc13783_regulator_enable(struct regulator_dev *rdev)
+{
+ struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ int ret;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ mc13783_lock(priv->mc13783);
+ ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].reg,
+ mc13783_regulators[id].enable_bit,
+ mc13783_regulators[id].enable_bit);
+ mc13783_unlock(priv->mc13783);
+
+ return ret;
+}
+
+static int mc13783_regulator_disable(struct regulator_dev *rdev)
+{
+ struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ int ret;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ mc13783_lock(priv->mc13783);
+ ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].reg,
+ mc13783_regulators[id].enable_bit, 0);
+ mc13783_unlock(priv->mc13783);
+
+ return ret;
+}
+
+static int mc13783_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
+ int ret, id = rdev_get_id(rdev);
+ unsigned int val;
+
+ mc13783_lock(priv->mc13783);
+ ret = mc13783_reg_read(priv->mc13783, mc13783_regulators[id].reg, &val);
+ mc13783_unlock(priv->mc13783);
+
+ if (ret)
+ return ret;
+
+ return (val & mc13783_regulators[id].enable_bit) != 0;
+}
+
+static struct regulator_ops mc13783_regulator_ops = {
+ .enable = mc13783_regulator_enable,
+ .disable = mc13783_regulator_disable,
+ .is_enabled = mc13783_regulator_is_enabled,
+};
+
+static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
+{
+ struct mc13783_regulator_priv *priv;
+ struct mc13783 *mc13783 = dev_get_drvdata(pdev->dev.parent);
+ struct mc13783_regulator_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ struct mc13783_regulator_init_data *init_data;
+ int i, ret;
+
+ dev_dbg(&pdev->dev, "mc13783_regulator_probe id %d\n", pdev->id);
+
+ priv = kzalloc(sizeof(*priv) +
+ pdata->num_regulators * sizeof(priv->regulators[0]),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->mc13783 = mc13783;
+
+ for (i = 0; i < pdata->num_regulators; i++) {
+ init_data = &pdata->regulators[i];
+ priv->regulators[i] = regulator_register(
+ &mc13783_regulators[init_data->id].desc,
+ &pdev->dev, init_data->init_data, priv);
+
+ if (IS_ERR(priv->regulators[i])) {
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ mc13783_regulators[i].desc.name);
+ ret = PTR_ERR(priv->regulators[i]);
+ goto err;
+ }
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+err:
+ while (--i >= 0)
+ regulator_unregister(priv->regulators[i]);
+
+ kfree(priv);
+
+ return ret;
+}
+
+static int __devexit mc13783_regulator_remove(struct platform_device *pdev)
+{
+ struct mc13783_regulator_priv *priv = platform_get_drvdata(pdev);
+ struct mc13783_regulator_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ int i;
+
+ for (i = 0; i < pdata->num_regulators; i++)
+ regulator_unregister(priv->regulators[i]);
+
+ return 0;
+}
+
+static struct platform_driver mc13783_regulator_driver = {
+ .driver = {
+ .name = "mc13783-regulator",
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(mc13783_regulator_remove),
+ .probe = mc13783_regulator_probe,
+};
+
+static int __init mc13783_regulator_init(void)
+{
+ return platform_driver_register(&mc13783_regulator_driver);
+}
+subsys_initcall(mc13783_regulator_init);
+
+static void __exit mc13783_regulator_exit(void)
+{
+ platform_driver_unregister(&mc13783_regulator_driver);
+}
+module_exit(mc13783_regulator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de");
+MODULE_DESCRIPTION("Regulator Driver for Freescale MC13783 PMIC");
+MODULE_ALIAS("platform:mc13783-regulator");
diff --git a/drivers/regulator/mc13783.c b/drivers/regulator/mc13783.c
deleted file mode 100644
index 710211f6744..00000000000
--- a/drivers/regulator/mc13783.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * Regulator Driver for Freescale MC13783 PMIC
- *
- * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
- *
- * 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.
- */
-
-#include <linux/mfd/mc13783-private.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/driver.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/mc13783.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/err.h>
-
-struct mc13783_regulator {
- struct regulator_desc desc;
- int reg;
- int enable_bit;
-};
-
-static struct regulator_ops mc13783_regulator_ops;
-
-static struct mc13783_regulator mc13783_regulators[] = {
- [MC13783_SW_SW3] = {
- .desc = {
- .name = "SW_SW3",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_SW_SW3,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_SWITCHERS_5,
- .enable_bit = MC13783_SWCTRL_SW3_EN,
- },
- [MC13783_SW_PLL] = {
- .desc = {
- .name = "SW_PLL",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_SW_PLL,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_SWITCHERS_4,
- .enable_bit = MC13783_SWCTRL_PLL_EN,
- },
- [MC13783_REGU_VAUDIO] = {
- .desc = {
- .name = "REGU_VAUDIO",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VAUDIO,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_0,
- .enable_bit = MC13783_REGCTRL_VAUDIO_EN,
- },
- [MC13783_REGU_VIOHI] = {
- .desc = {
- .name = "REGU_VIOHI",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VIOHI,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_0,
- .enable_bit = MC13783_REGCTRL_VIOHI_EN,
- },
- [MC13783_REGU_VIOLO] = {
- .desc = {
- .name = "REGU_VIOLO",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VIOLO,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_0,
- .enable_bit = MC13783_REGCTRL_VIOLO_EN,
- },
- [MC13783_REGU_VDIG] = {
- .desc = {
- .name = "REGU_VDIG",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VDIG,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_0,
- .enable_bit = MC13783_REGCTRL_VDIG_EN,
- },
- [MC13783_REGU_VGEN] = {
- .desc = {
- .name = "REGU_VGEN",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VGEN,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_0,
- .enable_bit = MC13783_REGCTRL_VGEN_EN,
- },
- [MC13783_REGU_VRFDIG] = {
- .desc = {
- .name = "REGU_VRFDIG",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VRFDIG,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_0,
- .enable_bit = MC13783_REGCTRL_VRFDIG_EN,
- },
- [MC13783_REGU_VRFREF] = {
- .desc = {
- .name = "REGU_VRFREF",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VRFREF,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_0,
- .enable_bit = MC13783_REGCTRL_VRFREF_EN,
- },
- [MC13783_REGU_VRFCP] = {
- .desc = {
- .name = "REGU_VRFCP",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VRFCP,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_0,
- .enable_bit = MC13783_REGCTRL_VRFCP_EN,
- },
- [MC13783_REGU_VSIM] = {
- .desc = {
- .name = "REGU_VSIM",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VSIM,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_1,
- .enable_bit = MC13783_REGCTRL_VSIM_EN,
- },
- [MC13783_REGU_VESIM] = {
- .desc = {
- .name = "REGU_VESIM",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VESIM,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_1,
- .enable_bit = MC13783_REGCTRL_VESIM_EN,
- },
- [MC13783_REGU_VCAM] = {
- .desc = {
- .name = "REGU_VCAM",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VCAM,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_1,
- .enable_bit = MC13783_REGCTRL_VCAM_EN,
- },
- [MC13783_REGU_VRFBG] = {
- .desc = {
- .name = "REGU_VRFBG",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VRFBG,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_1,
- .enable_bit = MC13783_REGCTRL_VRFBG_EN,
- },
- [MC13783_REGU_VVIB] = {
- .desc = {
- .name = "REGU_VVIB",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VVIB,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_1,
- .enable_bit = MC13783_REGCTRL_VVIB_EN,
- },
- [MC13783_REGU_VRF1] = {
- .desc = {
- .name = "REGU_VRF1",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VRF1,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_1,
- .enable_bit = MC13783_REGCTRL_VRF1_EN,
- },
- [MC13783_REGU_VRF2] = {
- .desc = {
- .name = "REGU_VRF2",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VRF2,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_1,
- .enable_bit = MC13783_REGCTRL_VRF2_EN,
- },
- [MC13783_REGU_VMMC1] = {
- .desc = {
- .name = "REGU_VMMC1",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VMMC1,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_1,
- .enable_bit = MC13783_REGCTRL_VMMC1_EN,
- },
- [MC13783_REGU_VMMC2] = {
- .desc = {
- .name = "REGU_VMMC2",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_VMMC2,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_REGULATOR_MODE_1,
- .enable_bit = MC13783_REGCTRL_VMMC2_EN,
- },
- [MC13783_REGU_GPO1] = {
- .desc = {
- .name = "REGU_GPO1",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_GPO1,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_POWER_MISCELLANEOUS,
- .enable_bit = MC13783_REGCTRL_GPO1_EN,
- },
- [MC13783_REGU_GPO2] = {
- .desc = {
- .name = "REGU_GPO2",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_GPO2,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_POWER_MISCELLANEOUS,
- .enable_bit = MC13783_REGCTRL_GPO2_EN,
- },
- [MC13783_REGU_GPO3] = {
- .desc = {
- .name = "REGU_GPO3",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_GPO3,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_POWER_MISCELLANEOUS,
- .enable_bit = MC13783_REGCTRL_GPO3_EN,
- },
- [MC13783_REGU_GPO4] = {
- .desc = {
- .name = "REGU_GPO4",
- .ops = &mc13783_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .id = MC13783_REGU_GPO4,
- .owner = THIS_MODULE,
- },
- .reg = MC13783_REG_POWER_MISCELLANEOUS,
- .enable_bit = MC13783_REGCTRL_GPO4_EN,
- },
-};
-
-struct mc13783_priv {
- struct regulator_desc desc[ARRAY_SIZE(mc13783_regulators)];
- struct mc13783 *mc13783;
- struct regulator_dev *regulators[0];
-};
-
-static int mc13783_enable(struct regulator_dev *rdev)
-{
- struct mc13783_priv *priv = rdev_get_drvdata(rdev);
- int id = rdev_get_id(rdev);
-
- dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
-
- return mc13783_set_bits(priv->mc13783, mc13783_regulators[id].reg,
- mc13783_regulators[id].enable_bit,
- mc13783_regulators[id].enable_bit);
-}
-
-static int mc13783_disable(struct regulator_dev *rdev)
-{
- struct mc13783_priv *priv = rdev_get_drvdata(rdev);
- int id = rdev_get_id(rdev);
-
- dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
-
- return mc13783_set_bits(priv->mc13783, mc13783_regulators[id].reg,
- mc13783_regulators[id].enable_bit, 0);
-}
-
-static int mc13783_is_enabled(struct regulator_dev *rdev)
-{
- struct mc13783_priv *priv = rdev_get_drvdata(rdev);
- int ret, id = rdev_get_id(rdev);
- unsigned int val;
-
- ret = mc13783_reg_read(priv->mc13783, mc13783_regulators[id].reg, &val);
- if (ret)
- return ret;
-
- return (val & mc13783_regulators[id].enable_bit) != 0;
-}
-
-static struct regulator_ops mc13783_regulator_ops = {
- .enable = mc13783_enable,
- .disable = mc13783_disable,
- .is_enabled = mc13783_is_enabled,
-};
-
-static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
-{
- struct mc13783_priv *priv;
- struct mc13783 *mc13783 = dev_get_drvdata(pdev->dev.parent);
- struct mc13783_regulator_init_data *init_data;
- int i, ret;
-
- dev_dbg(&pdev->dev, "mc13783_regulator_probe id %d\n", pdev->id);
-
- priv = kzalloc(sizeof(*priv) + mc13783->num_regulators * sizeof(void *),
- GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->mc13783 = mc13783;
-
- for (i = 0; i < mc13783->num_regulators; i++) {
- init_data = &mc13783->regulators[i];
- priv->regulators[i] = regulator_register(
- &mc13783_regulators[init_data->id].desc,
- &pdev->dev, init_data->init_data, priv);
-
- if (IS_ERR(priv->regulators[i])) {
- dev_err(&pdev->dev, "failed to register regulator %s\n",
- mc13783_regulators[i].desc.name);
- ret = PTR_ERR(priv->regulators[i]);
- goto err;
- }
- }
-
- platform_set_drvdata(pdev, priv);
-
- return 0;
-err:
- while (--i >= 0)
- regulator_unregister(priv->regulators[i]);
-
- kfree(priv);
-
- return ret;
-}
-
-static int __devexit mc13783_regulator_remove(struct platform_device *pdev)
-{
- struct mc13783_priv *priv = platform_get_drvdata(pdev);
- struct mc13783 *mc13783 = priv->mc13783;
- int i;
-
- for (i = 0; i < mc13783->num_regulators; i++)
- regulator_unregister(priv->regulators[i]);
-
- return 0;
-}
-
-static struct platform_driver mc13783_regulator_driver = {
- .driver = {
- .name = "mc13783-regulator",
- .owner = THIS_MODULE,
- },
- .remove = __devexit_p(mc13783_regulator_remove),
-};
-
-static int __init mc13783_regulator_init(void)
-{
- return platform_driver_probe(&mc13783_regulator_driver,
- mc13783_regulator_probe);
-}
-subsys_initcall(mc13783_regulator_init);
-
-static void __exit mc13783_regulator_exit(void)
-{
- platform_driver_unregister(&mc13783_regulator_driver);
-}
-module_exit(mc13783_regulator_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de");
-MODULE_DESCRIPTION("Regulator Driver for Freescale MC13783 PMIC");
-MODULE_ALIAS("platform:mc13783-regulator");
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
index 7ea1c3a3108..7e674859bd5 100644
--- a/drivers/regulator/twl-regulator.c
+++ b/drivers/regulator/twl-regulator.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
+#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
@@ -40,6 +41,12 @@ struct twlreg_info {
u8 table_len;
const u16 *table;
+ /* regulator specific turn-on delay */
+ u16 delay;
+
+ /* State REMAP default configuration */
+ u8 remap;
+
/* chip constraints on regulator behavior */
u16 min_mV;
@@ -128,6 +135,7 @@ static int twlreg_enable(struct regulator_dev *rdev)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
int grp;
+ int ret;
grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
if (grp < 0)
@@ -138,7 +146,11 @@ static int twlreg_enable(struct regulator_dev *rdev)
else
grp |= P1_GRP_6030;
- return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
+ ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
+
+ udelay(info->delay);
+
+ return ret;
}
static int twlreg_disable(struct regulator_dev *rdev)
@@ -151,9 +163,9 @@ static int twlreg_disable(struct regulator_dev *rdev)
return grp;
if (twl_class_is_4030())
- grp &= ~P1_GRP_4030;
+ grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030);
else
- grp &= ~P1_GRP_6030;
+ grp &= ~(P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030);
return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
}
@@ -294,6 +306,18 @@ static const u16 VSIM_VSEL_table[] = {
static const u16 VDAC_VSEL_table[] = {
1200, 1300, 1800, 1800,
};
+static const u16 VDD1_VSEL_table[] = {
+ 800, 1450,
+};
+static const u16 VDD2_VSEL_table[] = {
+ 800, 1450, 1500,
+};
+static const u16 VIO_VSEL_table[] = {
+ 1800, 1850,
+};
+static const u16 VINTANA2_VSEL_table[] = {
+ 2500, 2750,
+};
static const u16 VAUX1_6030_VSEL_table[] = {
1000, 1300, 1800, 2500,
2800, 2900, 3000, 3000,
@@ -414,20 +438,30 @@ static struct regulator_ops twlfixed_ops = {
/*----------------------------------------------------------------------*/
-#define TWL4030_ADJUSTABLE_LDO(label, offset, num) \
- TWL_ADJUSTABLE_LDO(label, offset, num, TWL4030)
-#define TWL4030_FIXED_LDO(label, offset, mVolts, num) \
- TWL_FIXED_LDO(label, offset, mVolts, num, TWL4030)
-#define TWL6030_ADJUSTABLE_LDO(label, offset, num) \
- TWL_ADJUSTABLE_LDO(label, offset, num, TWL6030)
-#define TWL6030_FIXED_LDO(label, offset, mVolts, num) \
- TWL_FIXED_LDO(label, offset, mVolts, num, TWL6030)
-
-#define TWL_ADJUSTABLE_LDO(label, offset, num, family) { \
+#define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \
+ TWL_ADJUSTABLE_LDO(label, offset, num, turnon_delay, \
+ remap_conf, TWL4030)
+#define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
+ remap_conf) \
+ TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
+ remap_conf, TWL4030)
+#define TWL6030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, \
+ remap_conf) \
+ TWL_ADJUSTABLE_LDO(label, offset, num, turnon_delay, \
+ remap_conf, TWL6030)
+#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
+ remap_conf) \
+ TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
+ remap_conf, TWL6030)
+
+#define TWL_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf, \
+ family) { \
.base = offset, \
.id = num, \
.table_len = ARRAY_SIZE(label##_VSEL_table), \
.table = label##_VSEL_table, \
+ .delay = turnon_delay, \
+ .remap = remap_conf, \
.desc = { \
.name = #label, \
.id = family##_REG_##label, \
@@ -438,10 +472,13 @@ static struct regulator_ops twlfixed_ops = {
}, \
}
-#define TWL_FIXED_LDO(label, offset, mVolts, num, family) { \
+#define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \
+ family) { \
.base = offset, \
.id = num, \
.min_mV = mVolts, \
+ .delay = turnon_delay, \
+ .remap = remap_conf, \
.desc = { \
.name = #label, \
.id = family##_REG_##label, \
@@ -457,43 +494,41 @@ static struct regulator_ops twlfixed_ops = {
* software control over them after boot.
*/
static struct twlreg_info twl_regs[] = {
- TWL4030_ADJUSTABLE_LDO(VAUX1, 0x17, 1),
- TWL4030_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2),
- TWL4030_ADJUSTABLE_LDO(VAUX2, 0x1b, 2),
- TWL4030_ADJUSTABLE_LDO(VAUX3, 0x1f, 3),
- TWL4030_ADJUSTABLE_LDO(VAUX4, 0x23, 4),
- TWL4030_ADJUSTABLE_LDO(VMMC1, 0x27, 5),
- TWL4030_ADJUSTABLE_LDO(VMMC2, 0x2b, 6),
- /*
- TWL4030_ADJUSTABLE_LDO(VPLL1, 0x2f, 7),
- */
- TWL4030_ADJUSTABLE_LDO(VPLL2, 0x33, 8),
- TWL4030_ADJUSTABLE_LDO(VSIM, 0x37, 9),
- TWL4030_ADJUSTABLE_LDO(VDAC, 0x3b, 10),
- /*
- TWL4030_ADJUSTABLE_LDO(VINTANA1, 0x3f, 11),
- TWL4030_ADJUSTABLE_LDO(VINTANA2, 0x43, 12),
- TWL4030_ADJUSTABLE_LDO(VINTDIG, 0x47, 13),
- TWL4030_SMPS(VIO, 0x4b, 14),
- TWL4030_SMPS(VDD1, 0x55, 15),
- TWL4030_SMPS(VDD2, 0x63, 16),
- */
- TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17),
- TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18),
- TWL4030_FIXED_LDO(VUSB3V1, 0x77, 3100, 19),
+ TWL4030_ADJUSTABLE_LDO(VAUX1, 0x17, 1, 100, 0x08),
+ TWL4030_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2, 100, 0x08),
+ TWL4030_ADJUSTABLE_LDO(VAUX2, 0x1b, 2, 100, 0x08),
+ TWL4030_ADJUSTABLE_LDO(VAUX3, 0x1f, 3, 100, 0x08),
+ TWL4030_ADJUSTABLE_LDO(VAUX4, 0x23, 4, 100, 0x08),
+ TWL4030_ADJUSTABLE_LDO(VMMC1, 0x27, 5, 100, 0x08),
+ TWL4030_ADJUSTABLE_LDO(VMMC2, 0x2b, 6, 100, 0x08),
+ TWL4030_ADJUSTABLE_LDO(VPLL1, 0x2f, 7, 100, 0x00),
+ TWL4030_ADJUSTABLE_LDO(VPLL2, 0x33, 8, 100, 0x08),
+ TWL4030_ADJUSTABLE_LDO(VSIM, 0x37, 9, 100, 0x00),
+ TWL4030_ADJUSTABLE_LDO(VDAC, 0x3b, 10, 100, 0x08),
+ TWL4030_FIXED_LDO(VINTANA1, 0x3f, 1500, 11, 100, 0x08),
+ TWL4030_ADJUSTABLE_LDO(VINTANA2, 0x43, 12, 100, 0x08),
+ TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08),
+ TWL4030_ADJUSTABLE_LDO(VIO, 0x4b, 14, 1000, 0x08),
+ TWL4030_ADJUSTABLE_LDO(VDD1, 0x55, 15, 1000, 0x08),
+ TWL4030_ADJUSTABLE_LDO(VDD2, 0x63, 16, 1000, 0x08),
+ TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17, 100, 0x08),
+ TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18, 100, 0x08),
+ TWL4030_FIXED_LDO(VUSB3V1, 0x77, 3100, 19, 150, 0x08),
/* VUSBCP is managed *only* by the USB subchip */
/* 6030 REG with base as PMC Slave Misc : 0x0030 */
- TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1),
- TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 2),
- TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 3),
- TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 4),
- TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 5),
- TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 7),
- TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15),
- TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16),
- TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17),
- TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18)
+ /* Turnon-delay and remap configuration values for 6030 are not
+ verified since the specification is not public */
+ TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1, 0, 0x08),
+ TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 2, 0, 0x08),
+ TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 3, 0, 0x08),
+ TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 4, 0, 0x08),
+ TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 5, 0, 0x08),
+ TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 7, 0, 0x08),
+ TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x08),
+ TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x08),
+ TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x08),
+ TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x08)
};
static int twlreg_probe(struct platform_device *pdev)
@@ -525,6 +560,19 @@ static int twlreg_probe(struct platform_device *pdev)
c->valid_ops_mask &= REGULATOR_CHANGE_VOLTAGE
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS;
+ switch (pdev->id) {
+ case TWL4030_REG_VIO:
+ case TWL4030_REG_VDD1:
+ case TWL4030_REG_VDD2:
+ case TWL4030_REG_VPLL1:
+ case TWL4030_REG_VINTANA1:
+ case TWL4030_REG_VINTANA2:
+ case TWL4030_REG_VINTDIG:
+ c->always_on = true;
+ break;
+ default:
+ break;
+ }
rdev = regulator_register(&info->desc, &pdev->dev, initdata, info);
if (IS_ERR(rdev)) {
@@ -534,6 +582,9 @@ static int twlreg_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, rdev);
+ twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP,
+ info->remap);
+
/* NOTE: many regulators support short-circuit IRQs (presentable
* as REGULATOR_OVER_CURRENT notifications?) configured via:
* - SC_CONFIG
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index 2eefc1a0cf0..0a6577577e8 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -19,6 +19,8 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/regulator.h>
@@ -39,6 +41,7 @@
#define WM831X_DCDC_CONTROL_2 1
#define WM831X_DCDC_ON_CONFIG 2
#define WM831X_DCDC_SLEEP_CONTROL 3
+#define WM831X_DCDC_DVS_CONTROL 4
/*
* Shared
@@ -50,6 +53,10 @@ struct wm831x_dcdc {
int base;
struct wm831x *wm831x;
struct regulator_dev *regulator;
+ int dvs_gpio;
+ int dvs_gpio_state;
+ int on_vsel;
+ int dvs_vsel;
};
static int wm831x_dcdc_is_enabled(struct regulator_dev *rdev)
@@ -240,11 +247,9 @@ static int wm831x_buckv_list_voltage(struct regulator_dev *rdev,
return -EINVAL;
}
-static int wm831x_buckv_set_voltage_int(struct regulator_dev *rdev, int reg,
- int min_uV, int max_uV)
+static int wm831x_buckv_select_min_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
{
- struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = dcdc->wm831x;
u16 vsel;
if (min_uV < 600000)
@@ -257,39 +262,126 @@ static int wm831x_buckv_set_voltage_int(struct regulator_dev *rdev, int reg,
if (wm831x_buckv_list_voltage(rdev, vsel) > max_uV)
return -EINVAL;
- return wm831x_set_bits(wm831x, reg, WM831X_DC1_ON_VSEL_MASK, vsel);
+ return vsel;
+}
+
+static int wm831x_buckv_select_max_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ u16 vsel;
+
+ if (max_uV < 600000 || max_uV > 1800000)
+ return -EINVAL;
+
+ vsel = ((max_uV - 600000) / 12500) + 8;
+
+ if (wm831x_buckv_list_voltage(rdev, vsel) < min_uV ||
+ wm831x_buckv_list_voltage(rdev, vsel) < max_uV)
+ return -EINVAL;
+
+ return vsel;
+}
+
+static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state)
+{
+ struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+
+ if (state == dcdc->dvs_gpio_state)
+ return 0;
+
+ dcdc->dvs_gpio_state = state;
+ gpio_set_value(dcdc->dvs_gpio, state);
+
+ /* Should wait for DVS state change to be asserted if we have
+ * a GPIO for it, for now assume the device is configured
+ * for the fastest possible transition.
+ */
+
+ return 0;
}
static int wm831x_buckv_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV)
{
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
- u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
+ struct wm831x *wm831x = dcdc->wm831x;
+ int on_reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
+ int dvs_reg = dcdc->base + WM831X_DCDC_DVS_CONTROL;
+ int vsel, ret;
+
+ vsel = wm831x_buckv_select_min_voltage(rdev, min_uV, max_uV);
+ if (vsel < 0)
+ return vsel;
+
+ /* If this value is already set then do a GPIO update if we can */
+ if (dcdc->dvs_gpio && dcdc->on_vsel == vsel)
+ return wm831x_buckv_set_dvs(rdev, 0);
+
+ if (dcdc->dvs_gpio && dcdc->dvs_vsel == vsel)
+ return wm831x_buckv_set_dvs(rdev, 1);
+
+ /* Always set the ON status to the minimum voltage */
+ ret = wm831x_set_bits(wm831x, on_reg, WM831X_DC1_ON_VSEL_MASK, vsel);
+ if (ret < 0)
+ return ret;
+ dcdc->on_vsel = vsel;
+
+ if (!dcdc->dvs_gpio)
+ return ret;
+
+ /* Kick the voltage transition now */
+ ret = wm831x_buckv_set_dvs(rdev, 0);
+ if (ret < 0)
+ return ret;
+
+ /* Set the high voltage as the DVS voltage. This is optimised
+ * for CPUfreq usage, most processors will keep the maximum
+ * voltage constant and lower the minimum with the frequency. */
+ vsel = wm831x_buckv_select_max_voltage(rdev, min_uV, max_uV);
+ if (vsel < 0) {
+ /* This should never happen - at worst the same vsel
+ * should be chosen */
+ WARN_ON(vsel < 0);
+ return 0;
+ }
+
+ /* Don't bother if it's the same VSEL we're already using */
+ if (vsel == dcdc->on_vsel)
+ return 0;
- return wm831x_buckv_set_voltage_int(rdev, reg, min_uV, max_uV);
+ ret = wm831x_set_bits(wm831x, dvs_reg, WM831X_DC1_DVS_VSEL_MASK, vsel);
+ if (ret == 0)
+ dcdc->dvs_vsel = vsel;
+ else
+ dev_warn(wm831x->dev, "Failed to set DCDC DVS VSEL: %d\n",
+ ret);
+
+ return 0;
}
static int wm831x_buckv_set_suspend_voltage(struct regulator_dev *rdev,
- int uV)
+ int uV)
{
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+ struct wm831x *wm831x = dcdc->wm831x;
u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL;
+ int vsel;
+
+ vsel = wm831x_buckv_select_min_voltage(rdev, uV, uV);
+ if (vsel < 0)
+ return vsel;
- return wm831x_buckv_set_voltage_int(rdev, reg, uV, uV);
+ return wm831x_set_bits(wm831x, reg, WM831X_DC1_SLP_VSEL_MASK, vsel);
}
static int wm831x_buckv_get_voltage(struct regulator_dev *rdev)
{
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = dcdc->wm831x;
- u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
- int val;
- val = wm831x_reg_read(wm831x, reg);
- if (val < 0)
- return val;
-
- return wm831x_buckv_list_voltage(rdev, val & WM831X_DC1_ON_VSEL_MASK);
+ if (dcdc->dvs_gpio && dcdc->dvs_gpio_state)
+ return wm831x_buckv_list_voltage(rdev, dcdc->dvs_vsel);
+ else
+ return wm831x_buckv_list_voltage(rdev, dcdc->on_vsel);
}
/* Current limit options */
@@ -346,6 +438,64 @@ static struct regulator_ops wm831x_buckv_ops = {
.set_suspend_mode = wm831x_dcdc_set_suspend_mode,
};
+/*
+ * Set up DVS control. We just log errors since we can still run
+ * (with reduced performance) if we fail.
+ */
+static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc,
+ struct wm831x_buckv_pdata *pdata)
+{
+ struct wm831x *wm831x = dcdc->wm831x;
+ int ret;
+ u16 ctrl;
+
+ if (!pdata || !pdata->dvs_gpio)
+ return;
+
+ switch (pdata->dvs_control_src) {
+ case 1:
+ ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT;
+ break;
+ case 2:
+ ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT;
+ break;
+ default:
+ dev_err(wm831x->dev, "Invalid DVS control source %d for %s\n",
+ pdata->dvs_control_src, dcdc->name);
+ return;
+ }
+
+ ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL,
+ WM831X_DC1_DVS_SRC_MASK, ctrl);
+ if (ret < 0) {
+ dev_err(wm831x->dev, "Failed to set %s DVS source: %d\n",
+ dcdc->name, ret);
+ return;
+ }
+
+ ret = gpio_request(pdata->dvs_gpio, "DCDC DVS");
+ if (ret < 0) {
+ dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n",
+ dcdc->name, ret);
+ return;
+ }
+
+ /* gpiolib won't let us read the GPIO status so pick the higher
+ * of the two existing voltages so we take it as platform data.
+ */
+ dcdc->dvs_gpio_state = pdata->dvs_init_state;
+
+ ret = gpio_direction_output(pdata->dvs_gpio, dcdc->dvs_gpio_state);
+ if (ret < 0) {
+ dev_err(wm831x->dev, "Failed to enable %s DVS GPIO: %d\n",
+ dcdc->name, ret);
+ gpio_free(pdata->dvs_gpio);
+ return;
+ }
+
+ dcdc->dvs_gpio = pdata->dvs_gpio;
+}
+
static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
@@ -384,6 +534,23 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
dcdc->desc.ops = &wm831x_buckv_ops;
dcdc->desc.owner = THIS_MODULE;
+ ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG);
+ if (ret < 0) {
+ dev_err(wm831x->dev, "Failed to read ON VSEL: %d\n", ret);
+ goto err;
+ }
+ dcdc->on_vsel = ret & WM831X_DC1_ON_VSEL_MASK;
+
+ ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG);
+ if (ret < 0) {
+ dev_err(wm831x->dev, "Failed to read DVS VSEL: %d\n", ret);
+ goto err;
+ }
+ dcdc->dvs_vsel = ret & WM831X_DC1_DVS_VSEL_MASK;
+
+ if (pdata->dcdc[id])
+ wm831x_buckv_dvs_init(dcdc, pdata->dcdc[id]->driver_data);
+
dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
pdata->dcdc[id], dcdc);
if (IS_ERR(dcdc->regulator)) {
@@ -422,6 +589,8 @@ err_uv:
err_regulator:
regulator_unregister(dcdc->regulator);
err:
+ if (dcdc->dvs_gpio)
+ gpio_free(dcdc->dvs_gpio);
kfree(dcdc);
return ret;
}
@@ -434,6 +603,8 @@ static __devexit int wm831x_buckv_remove(struct platform_device *pdev)
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "HC"), dcdc);
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc);
regulator_unregister(dcdc->regulator);
+ if (dcdc->dvs_gpio)
+ gpio_free(dcdc->dvs_gpio);
kfree(dcdc);
return 0;
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c
index 902db56ce09..61e02ac2fda 100644
--- a/drivers/regulator/wm831x-ldo.c
+++ b/drivers/regulator/wm831x-ldo.c
@@ -470,7 +470,7 @@ static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev)
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
struct wm831x *wm831x = ldo->wm831x;
int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
- unsigned int ret;
+ int ret;
ret = wm831x_reg_read(wm831x, on_reg);
if (ret < 0)
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index eb154dc5716..c8c12325e69 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -686,7 +686,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
*/
#if defined(CONFIG_ATARI)
address_space = 64;
-#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__sparc__)
+#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) \
+ || defined(__sparc__) || defined(__mips__)
address_space = 128;
#else
#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c
index 259db7f3535..9630e7d3314 100644
--- a/drivers/rtc/rtc-ds1305.c
+++ b/drivers/rtc/rtc-ds1305.c
@@ -778,6 +778,8 @@ static int __devinit ds1305_probe(struct spi_device *spi)
spi->irq, status);
goto fail1;
}
+
+ device_set_wakeup_capable(&spi->dev, 1);
}
/* export NVRAM */
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 8a99da6f2f2..c4ec5c158aa 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -881,6 +881,8 @@ read_rtc:
"unable to request IRQ!\n");
goto exit_irq;
}
+
+ device_set_wakeup_capable(&client->dev, 1);
set_bit(HAS_ALARM, &ds1307->flags);
dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
}
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index 713f7bf5afb..5317bbcbc7a 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -383,6 +383,8 @@ static int ds1374_probe(struct i2c_client *client,
dev_err(&client->dev, "unable to request IRQ\n");
goto out_free;
}
+
+ device_set_wakeup_capable(&client->dev, 1);
}
ds1374->rtc = rtc_device_register(client->name, &client->dev,
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
index fd1231738ef..148b1dd2407 100644
--- a/drivers/s390/block/dasd_alias.c
+++ b/drivers/s390/block/dasd_alias.c
@@ -218,7 +218,7 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
spin_unlock_irqrestore(&aliastree.lock, flags);
newlcu = _allocate_lcu(uid);
if (IS_ERR(newlcu))
- return PTR_ERR(lcu);
+ return PTR_ERR(newlcu);
spin_lock_irqsave(&aliastree.lock, flags);
lcu = _find_lcu(server, uid);
if (!lcu) {
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index f64d0db881b..6e14863f5c7 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -8,7 +8,7 @@
*
*/
-#define KMSG_COMPONENT "dasd-diag"
+#define KMSG_COMPONENT "dasd"
#include <linux/stddef.h>
#include <linux/kernel.h>
@@ -146,16 +146,16 @@ dasd_diag_erp(struct dasd_device *device)
rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
if (rc == 4) {
if (!(device->features & DASD_FEATURE_READONLY)) {
- dev_warn(&device->cdev->dev,
- "The access mode of a DIAG device changed"
- " to read-only");
+ pr_warning("%s: The access mode of a DIAG device "
+ "changed to read-only\n",
+ dev_name(&device->cdev->dev));
device->features |= DASD_FEATURE_READONLY;
}
rc = 0;
}
if (rc)
- dev_warn(&device->cdev->dev, "DIAG ERP failed with "
- "rc=%d\n", rc);
+ pr_warning("%s: DIAG ERP failed with "
+ "rc=%d\n", dev_name(&device->cdev->dev), rc);
}
/* Start a given request at the device. Return zero on success, non-zero
@@ -371,8 +371,9 @@ dasd_diag_check_device(struct dasd_device *device)
private->pt_block = 2;
break;
default:
- dev_warn(&device->cdev->dev, "Device type %d is not supported "
- "in DIAG mode\n", private->rdc_data.vdev_class);
+ pr_warning("%s: Device type %d is not supported "
+ "in DIAG mode\n", dev_name(&device->cdev->dev),
+ private->rdc_data.vdev_class);
rc = -EOPNOTSUPP;
goto out;
}
@@ -413,8 +414,8 @@ dasd_diag_check_device(struct dasd_device *device)
private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;
rc = dia250(&private->iob, RW_BIO);
if (rc == 3) {
- dev_warn(&device->cdev->dev,
- "A 64-bit DIAG call failed\n");
+ pr_warning("%s: A 64-bit DIAG call failed\n",
+ dev_name(&device->cdev->dev));
rc = -EOPNOTSUPP;
goto out_label;
}
@@ -423,8 +424,9 @@ dasd_diag_check_device(struct dasd_device *device)
break;
}
if (bsize > PAGE_SIZE) {
- dev_warn(&device->cdev->dev, "Accessing the DASD failed because"
- " of an incorrect format (rc=%d)\n", rc);
+ pr_warning("%s: Accessing the DASD failed because of an "
+ "incorrect format (rc=%d)\n",
+ dev_name(&device->cdev->dev), rc);
rc = -EIO;
goto out_label;
}
@@ -442,18 +444,18 @@ dasd_diag_check_device(struct dasd_device *device)
block->s2b_shift++;
rc = mdsk_init_io(device, block->bp_block, 0, NULL);
if (rc && (rc != 4)) {
- dev_warn(&device->cdev->dev, "DIAG initialization "
- "failed with rc=%d\n", rc);
+ pr_warning("%s: DIAG initialization failed with rc=%d\n",
+ dev_name(&device->cdev->dev), rc);
rc = -EIO;
} else {
if (rc == 4)
device->features |= DASD_FEATURE_READONLY;
- dev_info(&device->cdev->dev,
- "New DASD with %ld byte/block, total size %ld KB%s\n",
- (unsigned long) block->bp_block,
- (unsigned long) (block->blocks <<
- block->s2b_shift) >> 1,
- (rc == 4) ? ", read-only device" : "");
+ pr_info("%s: New DASD with %ld byte/block, total size %ld "
+ "KB%s\n", dev_name(&device->cdev->dev),
+ (unsigned long) block->bp_block,
+ (unsigned long) (block->blocks <<
+ block->s2b_shift) >> 1,
+ (rc == 4) ? ", read-only device" : "");
rc = 0;
}
out_label:
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index 28e4649fa9e..247b2b93472 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -467,7 +467,7 @@ fs3270_open(struct inode *inode, struct file *filp)
if (IS_ERR(ib)) {
raw3270_put_view(&fp->view);
raw3270_del_view(&fp->view);
- rc = PTR_ERR(fp);
+ rc = PTR_ERR(ib);
goto out;
}
fp->rdbuf = ib;
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
index 3657fe103c2..cb70fa1cf53 100644
--- a/drivers/s390/char/tape_34xx.c
+++ b/drivers/s390/char/tape_34xx.c
@@ -9,6 +9,7 @@
*/
#define KMSG_COMPONENT "tape_34xx"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 0c72aadb839..9821c588661 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -9,6 +9,7 @@
*/
#define KMSG_COMPONENT "tape_3590"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/module.h>
#include <linux/init.h>
@@ -136,7 +137,7 @@ static void int_to_ext_kekl(struct tape3592_kekl *in,
out->type_on_tape = TAPE390_KEKL_TYPE_LABEL;
memcpy(out->label, in->label, sizeof(in->label));
EBCASC(out->label, sizeof(in->label));
- strstrip(out->label);
+ strim(out->label);
}
static void int_to_ext_kekl_pair(struct tape3592_kekl_pair *in,
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index 4799cc2f73c..96816149368 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -11,6 +11,7 @@
*/
#define KMSG_COMPONENT "tape"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/fs.h>
#include <linux/module.h>
diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c
index 23d773a0d11..2125ec7d95f 100644
--- a/drivers/s390/char/tape_char.c
+++ b/drivers/s390/char/tape_char.c
@@ -10,6 +10,9 @@
* Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
+#define KMSG_COMPONENT "tape"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
diff --git a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c
index ddc914ccea8..b2864e3edb6 100644
--- a/drivers/s390/char/tape_class.c
+++ b/drivers/s390/char/tape_class.c
@@ -7,6 +7,10 @@
* Author: Stefan Bader <shbader@de.ibm.com>
* Based on simple class device code by Greg K-H
*/
+
+#define KMSG_COMPONENT "tape"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include "tape_class.h"
MODULE_AUTHOR("Stefan Bader <shbader@de.ibm.com>");
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index f5d6802dc5d..81b094e480e 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -12,6 +12,8 @@
*/
#define KMSG_COMPONENT "tape"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/init.h> // for kernel parameters
#include <linux/kmod.h> // for requesting modules
diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c
index ebd820ccfb2..0ceb37984f7 100644
--- a/drivers/s390/char/tape_proc.c
+++ b/drivers/s390/char/tape_proc.c
@@ -11,6 +11,9 @@
* PROCFS Functions
*/
+#define KMSG_COMPONENT "tape"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/seq_file.h>
diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c
index 750354ad16e..03f07e5dd6e 100644
--- a/drivers/s390/char/tape_std.c
+++ b/drivers/s390/char/tape_std.c
@@ -11,6 +11,9 @@
* Stefan Bader <shbader@de.ibm.com>
*/
+#define KMSG_COMPONENT "tape"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/bio.h>
diff --git a/drivers/s390/cio/ccwreq.c b/drivers/s390/cio/ccwreq.c
index 9509e386093..7a28a3029a3 100644
--- a/drivers/s390/cio/ccwreq.c
+++ b/drivers/s390/cio/ccwreq.c
@@ -49,7 +49,6 @@ static u16 ccwreq_next_path(struct ccw_device *cdev)
*/
static void ccwreq_stop(struct ccw_device *cdev, int rc)
{
- struct subchannel *sch = to_subchannel(cdev->dev.parent);
struct ccw_request *req = &cdev->private->req;
if (req->done)
@@ -57,7 +56,6 @@ static void ccwreq_stop(struct ccw_device *cdev, int rc)
req->done = 1;
ccw_device_set_timeout(cdev, 0);
memset(&cdev->private->irb, 0, sizeof(struct irb));
- sch->lpm = sch->schib.pmcw.pam;
if (rc && rc != -ENODEV && req->drc)
rc = req->drc;
req->callback(cdev, req->data, rc);
@@ -80,7 +78,6 @@ static void ccwreq_do(struct ccw_device *cdev)
continue;
}
/* Perform start function. */
- sch->lpm = 0xff;
memset(&cdev->private->irb, 0, sizeof(struct irb));
rc = cio_start(sch, cp, (u8) req->mask);
if (rc == 0) {
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 73901c9e260..a6c7d5426fb 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1519,6 +1519,7 @@ static int ccw_device_console_enable(struct ccw_device *cdev,
sch->driver = &io_subchannel_driver;
/* Initialize the ccw_device structure. */
cdev->dev.parent= &sch->dev;
+ sch_set_cdev(sch, cdev);
io_subchannel_recog(cdev, sch);
/* Now wait for the async. recognition to come to an end. */
spin_lock_irq(cdev->ccwlock);
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index aad188e43b4..6facb5499a6 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -142,7 +142,7 @@ static void spid_do(struct ccw_device *cdev)
u8 fn;
/* Use next available path that is not already in correct state. */
- req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam & ~sch->vpm);
+ req->lpm = lpm_adjust(req->lpm, cdev->private->pgid_todo_mask);
if (!req->lpm)
goto out_nopath;
/* Channel program setup. */
@@ -254,15 +254,15 @@ static void pgid_analyze(struct ccw_device *cdev, struct pgid **p,
*p = first;
}
-static u8 pgid_to_vpm(struct ccw_device *cdev)
+static u8 pgid_to_donepm(struct ccw_device *cdev)
{
struct subchannel *sch = to_subchannel(cdev->dev.parent);
struct pgid *pgid;
int i;
int lpm;
- u8 vpm = 0;
+ u8 donepm = 0;
- /* Set VPM bits for paths which are already in the target state. */
+ /* Set bits for paths which are already in the target state. */
for (i = 0; i < 8; i++) {
lpm = 0x80 >> i;
if ((cdev->private->pgid_valid_mask & lpm) == 0)
@@ -282,10 +282,10 @@ static u8 pgid_to_vpm(struct ccw_device *cdev)
if (pgid->inf.ps.state3 != SNID_STATE3_SINGLE_PATH)
continue;
}
- vpm |= lpm;
+ donepm |= lpm;
}
- return vpm;
+ return donepm;
}
static void pgid_fill(struct ccw_device *cdev, struct pgid *pgid)
@@ -307,6 +307,7 @@ static void snid_done(struct ccw_device *cdev, int rc)
int mismatch = 0;
int reserved = 0;
int reset = 0;
+ u8 donepm;
if (rc)
goto out;
@@ -316,18 +317,20 @@ static void snid_done(struct ccw_device *cdev, int rc)
else if (mismatch)
rc = -EOPNOTSUPP;
else {
- sch->vpm = pgid_to_vpm(cdev);
+ donepm = pgid_to_donepm(cdev);
+ sch->vpm = donepm & sch->opm;
+ cdev->private->pgid_todo_mask &= ~donepm;
pgid_fill(cdev, pgid);
}
out:
CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x vpm=%02x "
- "mism=%d rsvd=%d reset=%d\n", id->ssid, id->devno, rc,
- cdev->private->pgid_valid_mask, sch->vpm, mismatch,
- reserved, reset);
+ "todo=%02x mism=%d rsvd=%d reset=%d\n", id->ssid,
+ id->devno, rc, cdev->private->pgid_valid_mask, sch->vpm,
+ cdev->private->pgid_todo_mask, mismatch, reserved, reset);
switch (rc) {
case 0:
/* Anything left to do? */
- if (sch->vpm == sch->schib.pmcw.pam) {
+ if (cdev->private->pgid_todo_mask == 0) {
verify_done(cdev, sch->vpm == 0 ? -EACCES : 0);
return;
}
@@ -411,6 +414,7 @@ static void verify_start(struct ccw_device *cdev)
struct ccw_dev_id *devid = &cdev->private->dev_id;
sch->vpm = 0;
+ sch->lpm = sch->schib.pmcw.pam;
/* Initialize request data. */
memset(req, 0, sizeof(*req));
req->timeout = PGID_TIMEOUT;
@@ -442,11 +446,14 @@ static void verify_start(struct ccw_device *cdev)
*/
void ccw_device_verify_start(struct ccw_device *cdev)
{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+
CIO_TRACE_EVENT(4, "vrfy");
CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
/* Initialize PGID data. */
memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid));
cdev->private->pgid_valid_mask = 0;
+ cdev->private->pgid_todo_mask = sch->schib.pmcw.pam;
/*
* Initialize pathgroup and multipath state with target values.
* They may change in the course of path verification.
diff --git a/drivers/s390/cio/fcx.c b/drivers/s390/cio/fcx.c
index 61677dfbdc9..ca5e9bb9d45 100644
--- a/drivers/s390/cio/fcx.c
+++ b/drivers/s390/cio/fcx.c
@@ -163,7 +163,7 @@ void tcw_finalize(struct tcw *tcw, int num_tidaws)
/* Add tcat to tccb. */
tccb = tcw_get_tccb(tcw);
tcat = (struct tccb_tcat *) &tccb->tca[tca_size(tccb)];
- memset(tcat, 0, sizeof(tcat));
+ memset(tcat, 0, sizeof(*tcat));
/* Calculate tcw input/output count and tcat transport count. */
count = calc_dcw_count(tccb);
if (tcw->w && (tcw->flags & TCW_FLAGS_OUTPUT_TIDA))
@@ -269,7 +269,7 @@ EXPORT_SYMBOL(tccb_init);
*/
void tsb_init(struct tsb *tsb)
{
- memset(tsb, 0, sizeof(tsb));
+ memset(tsb, 0, sizeof(*tsb));
}
EXPORT_SYMBOL(tsb_init);
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
index d72ae4c93af..b9ce712a7f2 100644
--- a/drivers/s390/cio/io_sch.h
+++ b/drivers/s390/cio/io_sch.h
@@ -150,6 +150,7 @@ struct ccw_device_private {
struct ccw_request req; /* internal I/O request */
int iretry;
u8 pgid_valid_mask; /* mask of valid PGIDs */
+ u8 pgid_todo_mask; /* mask of PGIDs to be adjusted */
struct {
unsigned int fast:1; /* post with "channel end" */
unsigned int repall:1; /* report every interrupt status */
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 4be6e84b959..b2275c5000e 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -486,7 +486,8 @@ static int get_inbound_buffer_frontier(struct qdio_q *q)
case SLSB_P_INPUT_PRIMED:
inbound_primed(q, count);
q->first_to_check = add_buf(q->first_to_check, count);
- atomic_sub(count, &q->nr_buf_used);
+ if (atomic_sub(count, &q->nr_buf_used) == 0)
+ qdio_perf_stat_inc(&perf_stats.inbound_queue_full);
break;
case SLSB_P_INPUT_ERROR:
announce_buffer_error(q, count);
diff --git a/drivers/s390/cio/qdio_perf.c b/drivers/s390/cio/qdio_perf.c
index 968e3c7c263..54f7c325a3e 100644
--- a/drivers/s390/cio/qdio_perf.c
+++ b/drivers/s390/cio/qdio_perf.c
@@ -64,6 +64,8 @@ static int qdio_perf_proc_show(struct seq_file *m, void *v)
(long)atomic_long_read(&perf_stats.fast_requeue));
seq_printf(m, "Number of outbound target full condition\t: %li\n",
(long)atomic_long_read(&perf_stats.outbound_target_full));
+ seq_printf(m, "Number of inbound queue full condition\t\t: %li\n",
+ (long)atomic_long_read(&perf_stats.inbound_queue_full));
seq_printf(m, "Number of outbound tasklet mod_timer calls\t: %li\n",
(long)atomic_long_read(&perf_stats.debug_tl_out_timer));
seq_printf(m, "Number of stop polling calls\t\t\t: %li\n",
diff --git a/drivers/s390/cio/qdio_perf.h b/drivers/s390/cio/qdio_perf.h
index ff4504ce1e3..12454231dc8 100644
--- a/drivers/s390/cio/qdio_perf.h
+++ b/drivers/s390/cio/qdio_perf.h
@@ -36,6 +36,7 @@ struct qdio_perf_stats {
atomic_long_t outbound_handler;
atomic_long_t fast_requeue;
atomic_long_t outbound_target_full;
+ atomic_long_t inbound_queue_full;
/* for debugging */
atomic_long_t debug_tl_out_timer;
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index 18d54fc21ce..8c2dea5fa2b 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -48,7 +48,6 @@ static void set_impl_params(struct qdio_irq *irq_ptr,
if (!irq_ptr)
return;
- WARN_ON((unsigned long)&irq_ptr->qib & 0xff);
irq_ptr->qib.pfmt = qib_param_field_format;
if (qib_param_field)
memcpy(irq_ptr->qib.parm, qib_param_field,
@@ -82,14 +81,12 @@ static int __qdio_allocate_qs(struct qdio_q **irq_ptr_qs, int nr_queues)
q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL);
if (!q)
return -ENOMEM;
- WARN_ON((unsigned long)q & 0xff);
q->slib = (struct slib *) __get_free_page(GFP_KERNEL);
if (!q->slib) {
kmem_cache_free(qdio_q_cache, q);
return -ENOMEM;
}
- WARN_ON((unsigned long)q->slib & 0x7ff);
irq_ptr_qs[i] = q;
}
return 0;
@@ -131,7 +128,7 @@ static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr,
/* fill in sbal */
for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) {
q->sbal[j] = *sbals_array++;
- WARN_ON((unsigned long)q->sbal[j] & 0xff);
+ BUG_ON((unsigned long)q->sbal[j] & 0xff);
}
/* fill in slib */
@@ -147,11 +144,6 @@ static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr,
/* fill in sl */
for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++)
q->sl->element[j].sbal = (unsigned long)q->sbal[j];
-
- DBF_EVENT("sl-slsb-sbal");
- DBF_HEX(q->sl, sizeof(void *));
- DBF_HEX(&q->slsb, sizeof(void *));
- DBF_HEX(q->sbal, sizeof(void *));
}
static void setup_queues(struct qdio_irq *irq_ptr,
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index 3bf75924741..84d3bbaa95e 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -76,6 +76,7 @@
Fix bug in twa_get_param() on 4GB+.
Use pci_resource_len() for ioremap().
2.26.02.012 - Add power management support.
+ 2.26.02.013 - Fix bug in twa_load_sgl().
*/
#include <linux/module.h>
@@ -100,7 +101,7 @@
#include "3w-9xxx.h"
/* Globals */
-#define TW_DRIVER_VERSION "2.26.02.012"
+#define TW_DRIVER_VERSION "2.26.02.013"
static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
static unsigned int twa_device_extension_count;
static int twa_major = -1;
@@ -1382,10 +1383,12 @@ static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_comm
newcommand = &full_command_packet->command.newcommand;
newcommand->request_id__lunl =
cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id));
- newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
- newcommand->sg_list[0].length = cpu_to_le32(length);
+ if (length) {
+ newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
+ newcommand->sg_list[0].length = cpu_to_le32(length);
+ }
newcommand->sgl_entries__lunh =
- cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), 1));
+ cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0));
} else {
oldcommand = &full_command_packet->command.oldcommand;
oldcommand->request_id = request_id;
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 36900c71a59..9191d1ea645 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -388,6 +388,16 @@ config BLK_DEV_3W_XXXX_RAID
Please read the comments at the top of
<file:drivers/scsi/3w-xxxx.c>.
+config SCSI_HPSA
+ tristate "HP Smart Array SCSI driver"
+ depends on PCI && SCSI
+ help
+ This driver supports HP Smart Array Controllers (circa 2009).
+ It is a SCSI alternative to the cciss driver, which is a block
+ driver. Anyone wishing to use HP Smart Array controllers who
+ would prefer the devices be presented to linux as SCSI devices,
+ rather than as generic block devices should say Y here.
+
config SCSI_3W_9XXX
tristate "3ware 9xxx SATA-RAID support"
depends on PCI && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 280d3c657d6..92a8c500b23 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -91,6 +91,7 @@ obj-$(CONFIG_SCSI_BFA_FC) += bfa/
obj-$(CONFIG_SCSI_PAS16) += pas16.o
obj-$(CONFIG_SCSI_T128) += t128.o
obj-$(CONFIG_SCSI_DMX3191D) += dmx3191d.o
+obj-$(CONFIG_SCSI_HPSA) += hpsa.o
obj-$(CONFIG_SCSI_DTC3280) += dtc.o
obj-$(CONFIG_SCSI_SYM53C8XX_2) += sym53c8xx_2/
obj-$(CONFIG_SCSI_ZALON) += zalon7xx.o
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
index 698a527d6cc..f008708f1b0 100644
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -135,11 +135,15 @@ int beiscsi_process_mcc(struct beiscsi_hba *phba)
while ((compl = be_mcc_compl_get(phba))) {
if (compl->flags & CQE_FLAGS_ASYNC_MASK) {
/* Interpret flags as an async trailer */
- BUG_ON(!is_link_state_evt(compl->flags));
+ if (is_link_state_evt(compl->flags))
+ /* Interpret compl as a async link evt */
+ beiscsi_async_link_state_process(phba,
+ (struct be_async_event_link_state *) compl);
+ else
+ SE_DEBUG(DBG_LVL_1,
+ " Unsupported Async Event, flags"
+ " = 0x%08x \n", compl->flags);
- /* Interpret compl as a async link evt */
- beiscsi_async_link_state_process(phba,
- (struct be_async_event_link_state *) compl);
} else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) {
status = be_mcc_compl_process(ctrl, compl);
atomic_dec(&phba->ctrl.mcc_obj.q.used);
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index 2b973f3c2eb..6cf9dc37d78 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -684,6 +684,7 @@ extern unsigned int error_mask1, error_mask2;
extern u64 iscsi_error_mask;
extern unsigned int en_tcp_dack;
extern unsigned int event_coal_div;
+extern unsigned int event_coal_min;
extern struct scsi_transport_template *bnx2i_scsi_xport_template;
extern struct iscsi_transport bnx2i_iscsi_transport;
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index 5c8d7630c13..1af578dec27 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -133,20 +133,38 @@ void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action)
{
struct bnx2i_5771x_cq_db *cq_db;
u16 cq_index;
+ u16 next_index;
+ u32 num_active_cmds;
+
+ /* Coalesce CQ entries only on 10G devices */
if (!test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
return;
+ /* Do not update CQ DB multiple times before firmware writes
+ * '0xFFFF' to CQDB->SQN field. Deviation may cause spurious
+ * interrupts and other unwanted results
+ */
+ cq_db = (struct bnx2i_5771x_cq_db *) ep->qp.cq_pgtbl_virt;
+ if (cq_db->sqn[0] && cq_db->sqn[0] != 0xFFFF)
+ return;
+
if (action == CNIC_ARM_CQE) {
- cq_index = ep->qp.cqe_exp_seq_sn +
- ep->num_active_cmds / event_coal_div;
- cq_index %= (ep->qp.cqe_size * 2 + 1);
- if (!cq_index) {
+ num_active_cmds = ep->num_active_cmds;
+ if (num_active_cmds <= event_coal_min)
+ next_index = 1;
+ else
+ next_index = event_coal_min +
+ (num_active_cmds - event_coal_min) / event_coal_div;
+ if (!next_index)
+ next_index = 1;
+ cq_index = ep->qp.cqe_exp_seq_sn + next_index - 1;
+ if (cq_index > ep->qp.cqe_size * 2)
+ cq_index -= ep->qp.cqe_size * 2;
+ if (!cq_index)
cq_index = 1;
- cq_db = (struct bnx2i_5771x_cq_db *)
- ep->qp.cq_pgtbl_virt;
- cq_db->sqn[0] = cq_index;
- }
+
+ cq_db->sqn[0] = cq_index;
}
}
@@ -366,6 +384,7 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn,
struct bnx2i_cmd *bnx2i_cmd;
struct bnx2i_tmf_request *tmfabort_wqe;
u32 dword;
+ u32 scsi_lun[2];
bnx2i_cmd = (struct bnx2i_cmd *)mtask->dd_data;
tmfabort_hdr = (struct iscsi_tm *)mtask->hdr;
@@ -376,27 +395,35 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn,
tmfabort_wqe->op_attr = 0;
tmfabort_wqe->op_attr =
ISCSI_TMF_REQUEST_ALWAYS_ONE | ISCSI_TM_FUNC_ABORT_TASK;
- tmfabort_wqe->lun[0] = be32_to_cpu(tmfabort_hdr->lun[0]);
- tmfabort_wqe->lun[1] = be32_to_cpu(tmfabort_hdr->lun[1]);
tmfabort_wqe->itt = (mtask->itt | (ISCSI_TASK_TYPE_MPATH << 14));
tmfabort_wqe->reserved2 = 0;
tmfabort_wqe->cmd_sn = be32_to_cpu(tmfabort_hdr->cmdsn);
ctask = iscsi_itt_to_task(conn, tmfabort_hdr->rtt);
- if (!ctask || ctask->sc)
+ if (!ctask || !ctask->sc)
/*
* the iscsi layer must have completed the cmd while this
* was starting up.
+ *
+ * Note: In the case of a SCSI cmd timeout, the task's sc
+ * is still active; hence ctask->sc != 0
+ * In this case, the task must be aborted
*/
return 0;
+
ref_sc = ctask->sc;
+ /* Retrieve LUN directly from the ref_sc */
+ int_to_scsilun(ref_sc->device->lun, (struct scsi_lun *) scsi_lun);
+ tmfabort_wqe->lun[0] = be32_to_cpu(scsi_lun[0]);
+ tmfabort_wqe->lun[1] = be32_to_cpu(scsi_lun[1]);
+
if (ref_sc->sc_data_direction == DMA_TO_DEVICE)
dword = (ISCSI_TASK_TYPE_WRITE << ISCSI_CMD_REQUEST_TYPE_SHIFT);
else
dword = (ISCSI_TASK_TYPE_READ << ISCSI_CMD_REQUEST_TYPE_SHIFT);
- tmfabort_wqe->ref_itt = (dword | tmfabort_hdr->rtt);
+ tmfabort_wqe->ref_itt = (dword | (tmfabort_hdr->rtt & ISCSI_ITT_MASK));
tmfabort_wqe->ref_cmd_sn = be32_to_cpu(tmfabort_hdr->refcmdsn);
tmfabort_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma;
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
index 0c4210d48ee..6d8172e781c 100644
--- a/drivers/scsi/bnx2i/bnx2i_init.c
+++ b/drivers/scsi/bnx2i/bnx2i_init.c
@@ -17,8 +17,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
static u32 adapter_count;
#define DRV_MODULE_NAME "bnx2i"
-#define DRV_MODULE_VERSION "2.0.1e"
-#define DRV_MODULE_RELDATE "June 22, 2009"
+#define DRV_MODULE_VERSION "2.1.0"
+#define DRV_MODULE_RELDATE "Dec 06, 2009"
static char version[] __devinitdata =
"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
@@ -32,6 +32,10 @@ MODULE_VERSION(DRV_MODULE_VERSION);
static DEFINE_MUTEX(bnx2i_dev_lock);
+unsigned int event_coal_min = 24;
+module_param(event_coal_min, int, 0664);
+MODULE_PARM_DESC(event_coal_min, "Event Coalescing Minimum Commands");
+
unsigned int event_coal_div = 1;
module_param(event_coal_div, int, 0664);
MODULE_PARM_DESC(event_coal_div, "Event Coalescing Divide Factor");
@@ -83,8 +87,12 @@ void bnx2i_identify_device(struct bnx2i_hba *hba)
set_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type);
hba->mail_queue_access = BNX2I_MQ_BIN_MODE;
} else if (hba->pci_did == PCI_DEVICE_ID_NX2_57710 ||
- hba->pci_did == PCI_DEVICE_ID_NX2_57711)
+ hba->pci_did == PCI_DEVICE_ID_NX2_57711 ||
+ hba->pci_did == PCI_DEVICE_ID_NX2_57711E)
set_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type);
+ else
+ printk(KERN_ALERT "bnx2i: unknown device, 0x%x\n",
+ hba->pci_did);
}
@@ -363,7 +371,7 @@ static int __init bnx2i_mod_init(void)
printk(KERN_INFO "%s", version);
- if (!is_power_of_2(sq_size))
+ if (sq_size && !is_power_of_2(sq_size))
sq_size = roundup_pow_of_two(sq_size);
mutex_init(&bnx2i_dev_lock);
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 132898c88d5..33b2294625b 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -485,7 +485,6 @@ static int bnx2i_setup_cmd_pool(struct bnx2i_hba *hba,
struct iscsi_task *task = session->cmds[i];
struct bnx2i_cmd *cmd = task->dd_data;
- /* Anil */
task->hdr = &cmd->hdr;
task->hdr_max = sizeof(struct iscsi_hdr);
@@ -765,7 +764,6 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
hba->pci_svid = hba->pcidev->subsystem_vendor;
hba->pci_func = PCI_FUNC(hba->pcidev->devfn);
hba->pci_devno = PCI_SLOT(hba->pcidev->devfn);
- bnx2i_identify_device(hba);
bnx2i_identify_device(hba);
bnx2i_setup_host_queue_size(hba, shost);
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.c b/drivers/scsi/cxgb3i/cxgb3i_offload.c
index c1d5be4adf9..26ffdcd5a43 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_offload.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_offload.c
@@ -291,7 +291,7 @@ static void act_open_req_arp_failure(struct t3cdev *dev, struct sk_buff *skb)
c3cn_hold(c3cn);
spin_lock_bh(&c3cn->lock);
if (c3cn->state == C3CN_STATE_CONNECTING)
- fail_act_open(c3cn, EHOSTUNREACH);
+ fail_act_open(c3cn, -EHOSTUNREACH);
spin_unlock_bh(&c3cn->lock);
c3cn_put(c3cn);
__kfree_skb(skb);
@@ -792,18 +792,18 @@ static int act_open_rpl_status_to_errno(int status)
{
switch (status) {
case CPL_ERR_CONN_RESET:
- return ECONNREFUSED;
+ return -ECONNREFUSED;
case CPL_ERR_ARP_MISS:
- return EHOSTUNREACH;
+ return -EHOSTUNREACH;
case CPL_ERR_CONN_TIMEDOUT:
- return ETIMEDOUT;
+ return -ETIMEDOUT;
case CPL_ERR_TCAM_FULL:
- return ENOMEM;
+ return -ENOMEM;
case CPL_ERR_CONN_EXIST:
cxgb3i_log_error("ACTIVE_OPEN_RPL: 4-tuple in use\n");
- return EADDRINUSE;
+ return -EADDRINUSE;
default:
- return EIO;
+ return -EIO;
}
}
@@ -817,7 +817,7 @@ static void act_open_retry_timer(unsigned long data)
spin_lock_bh(&c3cn->lock);
skb = alloc_skb(sizeof(struct cpl_act_open_req), GFP_ATOMIC);
if (!skb)
- fail_act_open(c3cn, ENOMEM);
+ fail_act_open(c3cn, -ENOMEM);
else {
skb->sk = (struct sock *)c3cn;
set_arp_failure_handler(skb, act_open_req_arp_failure);
@@ -966,14 +966,14 @@ static int abort_status_to_errno(struct s3_conn *c3cn, int abort_reason,
case CPL_ERR_BAD_SYN: /* fall through */
case CPL_ERR_CONN_RESET:
return c3cn->state > C3CN_STATE_ESTABLISHED ?
- EPIPE : ECONNRESET;
+ -EPIPE : -ECONNRESET;
case CPL_ERR_XMIT_TIMEDOUT:
case CPL_ERR_PERSIST_TIMEDOUT:
case CPL_ERR_FINWAIT2_TIMEDOUT:
case CPL_ERR_KEEPALIVE_TIMEDOUT:
- return ETIMEDOUT;
+ return -ETIMEDOUT;
default:
- return EIO;
+ return -EIO;
}
}
@@ -1563,7 +1563,7 @@ free_tid:
s3_free_atid(cdev, c3cn->tid);
c3cn->tid = 0;
out_err:
- return -1;
+ return -EINVAL;
}
diff --git a/drivers/scsi/cxgb3i/cxgb3i_pdu.c b/drivers/scsi/cxgb3i/cxgb3i_pdu.c
index 70910507117..1fe3b0f1f3c 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_pdu.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_pdu.c
@@ -388,8 +388,8 @@ int cxgb3i_conn_xmit_pdu(struct iscsi_task *task)
if (err > 0) {
int pdulen = err;
- cxgb3i_tx_debug("task 0x%p, skb 0x%p, len %u/%u, rv %d.\n",
- task, skb, skb->len, skb->data_len, err);
+ cxgb3i_tx_debug("task 0x%p, skb 0x%p, len %u/%u, rv %d.\n",
+ task, skb, skb->len, skb->data_len, err);
if (task->conn->hdrdgst_en)
pdulen += ISCSI_DIGEST_SIZE;
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 47cfe1c49c3..1a660191a90 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -748,6 +748,8 @@ static const struct scsi_dh_devlist rdac_dev_list[] = {
{"IBM", "1724"},
{"IBM", "1726"},
{"IBM", "1742"},
+ {"IBM", "1745"},
+ {"IBM", "1746"},
{"IBM", "1814"},
{"IBM", "1815"},
{"IBM", "1818"},
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index a30ffaa1222..10be9f36a4c 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -101,6 +101,8 @@ static int fcoe_cpu_callback(struct notifier_block *, unsigned long, void *);
static int fcoe_create(const char *, struct kernel_param *);
static int fcoe_destroy(const char *, struct kernel_param *);
+static int fcoe_enable(const char *, struct kernel_param *);
+static int fcoe_disable(const char *, struct kernel_param *);
static struct fc_seq *fcoe_elsct_send(struct fc_lport *,
u32 did, struct fc_frame *,
@@ -115,10 +117,16 @@ static void fcoe_get_lesb(struct fc_lport *, struct fc_els_lesb *);
module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR);
__MODULE_PARM_TYPE(create, "string");
-MODULE_PARM_DESC(create, "Create fcoe fcoe using net device passed in.");
+MODULE_PARM_DESC(create, " Creates fcoe instance on a ethernet interface");
module_param_call(destroy, fcoe_destroy, NULL, NULL, S_IWUSR);
__MODULE_PARM_TYPE(destroy, "string");
-MODULE_PARM_DESC(destroy, "Destroy fcoe fcoe");
+MODULE_PARM_DESC(destroy, " Destroys fcoe instance on a ethernet interface");
+module_param_call(enable, fcoe_enable, NULL, NULL, S_IWUSR);
+__MODULE_PARM_TYPE(enable, "string");
+MODULE_PARM_DESC(enable, " Enables fcoe on a ethernet interface.");
+module_param_call(disable, fcoe_disable, NULL, NULL, S_IWUSR);
+__MODULE_PARM_TYPE(disable, "string");
+MODULE_PARM_DESC(disable, " Disables fcoe on a ethernet interface.");
/* notification function for packets from net device */
static struct notifier_block fcoe_notifier = {
@@ -545,6 +553,23 @@ static void fcoe_queue_timer(ulong lport)
}
/**
+ * fcoe_get_wwn() - Get the world wide name from LLD if it supports it
+ * @netdev: the associated net device
+ * @wwn: the output WWN
+ * @type: the type of WWN (WWPN or WWNN)
+ *
+ * Returns: 0 for success
+ */
+static int fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type)
+{
+ const struct net_device_ops *ops = netdev->netdev_ops;
+
+ if (ops->ndo_fcoe_get_wwn)
+ return ops->ndo_fcoe_get_wwn(netdev, wwn, type);
+ return -EINVAL;
+}
+
+/**
* fcoe_netdev_config() - Set up net devive for SW FCoE
* @lport: The local port that is associated with the net device
* @netdev: The associated net device
@@ -611,9 +636,13 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
*/
if (netdev->priv_flags & IFF_802_1Q_VLAN)
vid = vlan_dev_vlan_id(netdev);
- wwnn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr, 1, 0);
+
+ if (fcoe_get_wwn(netdev, &wwnn, NETDEV_FCOE_WWNN))
+ wwnn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr, 1, 0);
fc_set_wwnn(lport, wwnn);
- wwpn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr, 2, vid);
+ if (fcoe_get_wwn(netdev, &wwpn, NETDEV_FCOE_WWPN))
+ wwpn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr,
+ 2, vid);
fc_set_wwpn(lport, wwpn);
}
@@ -1231,7 +1260,7 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
"CPU.\n");
spin_unlock_bh(&fps->fcoe_rx_list.lock);
- cpu = first_cpu(cpu_online_map);
+ cpu = cpumask_first(cpu_online_mask);
fps = &per_cpu(fcoe_percpu, cpu);
spin_lock_bh(&fps->fcoe_rx_list.lock);
if (!fps->thread) {
@@ -1838,6 +1867,104 @@ static struct net_device *fcoe_if_to_netdev(const char *buffer)
}
/**
+ * fcoe_disable() - Disables a FCoE interface
+ * @buffer: The name of the Ethernet interface to be disabled
+ * @kp: The associated kernel parameter
+ *
+ * Called from sysfs.
+ *
+ * Returns: 0 for success
+ */
+static int fcoe_disable(const char *buffer, struct kernel_param *kp)
+{
+ struct fcoe_interface *fcoe;
+ struct net_device *netdev;
+ int rc = 0;
+
+ mutex_lock(&fcoe_config_mutex);
+#ifdef CONFIG_FCOE_MODULE
+ /*
+ * Make sure the module has been initialized, and is not about to be
+ * removed. Module paramter sysfs files are writable before the
+ * module_init function is called and after module_exit.
+ */
+ if (THIS_MODULE->state != MODULE_STATE_LIVE) {
+ rc = -ENODEV;
+ goto out_nodev;
+ }
+#endif
+
+ netdev = fcoe_if_to_netdev(buffer);
+ if (!netdev) {
+ rc = -ENODEV;
+ goto out_nodev;
+ }
+
+ rtnl_lock();
+ fcoe = fcoe_hostlist_lookup_port(netdev);
+ rtnl_unlock();
+
+ if (fcoe)
+ fc_fabric_logoff(fcoe->ctlr.lp);
+ else
+ rc = -ENODEV;
+
+ dev_put(netdev);
+out_nodev:
+ mutex_unlock(&fcoe_config_mutex);
+ return rc;
+}
+
+/**
+ * fcoe_enable() - Enables a FCoE interface
+ * @buffer: The name of the Ethernet interface to be enabled
+ * @kp: The associated kernel parameter
+ *
+ * Called from sysfs.
+ *
+ * Returns: 0 for success
+ */
+static int fcoe_enable(const char *buffer, struct kernel_param *kp)
+{
+ struct fcoe_interface *fcoe;
+ struct net_device *netdev;
+ int rc = 0;
+
+ mutex_lock(&fcoe_config_mutex);
+#ifdef CONFIG_FCOE_MODULE
+ /*
+ * Make sure the module has been initialized, and is not about to be
+ * removed. Module paramter sysfs files are writable before the
+ * module_init function is called and after module_exit.
+ */
+ if (THIS_MODULE->state != MODULE_STATE_LIVE) {
+ rc = -ENODEV;
+ goto out_nodev;
+ }
+#endif
+
+ netdev = fcoe_if_to_netdev(buffer);
+ if (!netdev) {
+ rc = -ENODEV;
+ goto out_nodev;
+ }
+
+ rtnl_lock();
+ fcoe = fcoe_hostlist_lookup_port(netdev);
+ rtnl_unlock();
+
+ if (fcoe)
+ rc = fc_fabric_login(fcoe->ctlr.lp);
+ else
+ rc = -ENODEV;
+
+ dev_put(netdev);
+out_nodev:
+ mutex_unlock(&fcoe_config_mutex);
+ return rc;
+}
+
+/**
* fcoe_destroy() - Destroy a FCoE interface
* @buffer: The name of the Ethernet interface to be destroyed
* @kp: The associated kernel parameter
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
new file mode 100644
index 00000000000..bb96fdd58e2
--- /dev/null
+++ b/drivers/scsi/hpsa.c
@@ -0,0 +1,3531 @@
+/*
+ * Disk Array driver for HP Smart Array SAS controllers
+ * Copyright 2000, 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT. 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.
+ *
+ * Questions/Comments/Bugfixes to iss_storagedev@hp.com
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/timer.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/compat.h>
+#include <linux/blktrace_api.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/completion.h>
+#include <linux/moduleparam.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <linux/cciss_ioctl.h>
+#include <linux/string.h>
+#include <linux/bitmap.h>
+#include <asm/atomic.h>
+#include <linux/kthread.h>
+#include "hpsa_cmd.h"
+#include "hpsa.h"
+
+/* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */
+#define HPSA_DRIVER_VERSION "1.0.0"
+#define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
+
+/* How long to wait (in milliseconds) for board to go into simple mode */
+#define MAX_CONFIG_WAIT 30000
+#define MAX_IOCTL_CONFIG_WAIT 1000
+
+/*define how many times we will try a command because of bus resets */
+#define MAX_CMD_RETRIES 3
+
+/* Embedded module documentation macros - see modules.h */
+MODULE_AUTHOR("Hewlett-Packard Company");
+MODULE_DESCRIPTION("Driver for HP Smart Array Controller version " \
+ HPSA_DRIVER_VERSION);
+MODULE_SUPPORTED_DEVICE("HP Smart Array Controllers");
+MODULE_VERSION(HPSA_DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+static int hpsa_allow_any;
+module_param(hpsa_allow_any, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(hpsa_allow_any,
+ "Allow hpsa driver to access unknown HP Smart Array hardware");
+
+/* define the PCI info for the cards we can control */
+static const struct pci_device_id hpsa_pci_device_id[] = {
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3223},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3234},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x323D},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3241},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3243},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3245},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3247},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3249},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324a},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324b},
+ {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, hpsa_pci_device_id);
+
+/* board_id = Subsystem Device ID & Vendor ID
+ * product = Marketing Name for the board
+ * access = Address of the struct of function pointers
+ */
+static struct board_type products[] = {
+ {0x3223103C, "Smart Array P800", &SA5_access},
+ {0x3234103C, "Smart Array P400", &SA5_access},
+ {0x323d103c, "Smart Array P700M", &SA5_access},
+ {0x3241103C, "Smart Array P212", &SA5_access},
+ {0x3243103C, "Smart Array P410", &SA5_access},
+ {0x3245103C, "Smart Array P410i", &SA5_access},
+ {0x3247103C, "Smart Array P411", &SA5_access},
+ {0x3249103C, "Smart Array P812", &SA5_access},
+ {0x324a103C, "Smart Array P712m", &SA5_access},
+ {0x324b103C, "Smart Array P711m", &SA5_access},
+ {0xFFFF103C, "Unknown Smart Array", &SA5_access},
+};
+
+static int number_of_controllers;
+
+static irqreturn_t do_hpsa_intr(int irq, void *dev_id);
+static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg);
+static void start_io(struct ctlr_info *h);
+
+#ifdef CONFIG_COMPAT
+static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg);
+#endif
+
+static void cmd_free(struct ctlr_info *h, struct CommandList *c);
+static void cmd_special_free(struct ctlr_info *h, struct CommandList *c);
+static struct CommandList *cmd_alloc(struct ctlr_info *h);
+static struct CommandList *cmd_special_alloc(struct ctlr_info *h);
+static void fill_cmd(struct CommandList *c, __u8 cmd, struct ctlr_info *h,
+ void *buff, size_t size, __u8 page_code, unsigned char *scsi3addr,
+ int cmd_type);
+
+static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *));
+
+static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd);
+static int hpsa_slave_alloc(struct scsi_device *sdev);
+static void hpsa_slave_destroy(struct scsi_device *sdev);
+
+static ssize_t raid_level_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t lunid_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t unique_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno);
+static ssize_t host_store_rescan(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+static int check_for_unit_attention(struct ctlr_info *h,
+ struct CommandList *c);
+static void check_ioctl_unit_attention(struct ctlr_info *h,
+ struct CommandList *c);
+
+static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL);
+static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL);
+static DEVICE_ATTR(unique_id, S_IRUGO, unique_id_show, NULL);
+static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan);
+
+static struct device_attribute *hpsa_sdev_attrs[] = {
+ &dev_attr_raid_level,
+ &dev_attr_lunid,
+ &dev_attr_unique_id,
+ NULL,
+};
+
+static struct device_attribute *hpsa_shost_attrs[] = {
+ &dev_attr_rescan,
+ NULL,
+};
+
+static struct scsi_host_template hpsa_driver_template = {
+ .module = THIS_MODULE,
+ .name = "hpsa",
+ .proc_name = "hpsa",
+ .queuecommand = hpsa_scsi_queue_command,
+ .can_queue = 512,
+ .this_id = -1,
+ .sg_tablesize = MAXSGENTRIES,
+ .cmd_per_lun = 512,
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_device_reset_handler = hpsa_eh_device_reset_handler,
+ .ioctl = hpsa_ioctl,
+ .slave_alloc = hpsa_slave_alloc,
+ .slave_destroy = hpsa_slave_destroy,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = hpsa_compat_ioctl,
+#endif
+ .sdev_attrs = hpsa_sdev_attrs,
+ .shost_attrs = hpsa_shost_attrs,
+};
+
+static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
+{
+ unsigned long *priv = shost_priv(sdev->host);
+ return (struct ctlr_info *) *priv;
+}
+
+static struct task_struct *hpsa_scan_thread;
+static DEFINE_MUTEX(hpsa_scan_mutex);
+static LIST_HEAD(hpsa_scan_q);
+static int hpsa_scan_func(void *data);
+
+/**
+ * add_to_scan_list() - add controller to rescan queue
+ * @h: Pointer to the controller.
+ *
+ * Adds the controller to the rescan queue if not already on the queue.
+ *
+ * returns 1 if added to the queue, 0 if skipped (could be on the
+ * queue already, or the controller could be initializing or shutting
+ * down).
+ **/
+static int add_to_scan_list(struct ctlr_info *h)
+{
+ struct ctlr_info *test_h;
+ int found = 0;
+ int ret = 0;
+
+ if (h->busy_initializing)
+ return 0;
+
+ /*
+ * If we don't get the lock, it means the driver is unloading
+ * and there's no point in scheduling a new scan.
+ */
+ if (!mutex_trylock(&h->busy_shutting_down))
+ return 0;
+
+ mutex_lock(&hpsa_scan_mutex);
+ list_for_each_entry(test_h, &hpsa_scan_q, scan_list) {
+ if (test_h == h) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found && !h->busy_scanning) {
+ INIT_COMPLETION(h->scan_wait);
+ list_add_tail(&h->scan_list, &hpsa_scan_q);
+ ret = 1;
+ }
+ mutex_unlock(&hpsa_scan_mutex);
+ mutex_unlock(&h->busy_shutting_down);
+
+ return ret;
+}
+
+/**
+ * remove_from_scan_list() - remove controller from rescan queue
+ * @h: Pointer to the controller.
+ *
+ * Removes the controller from the rescan queue if present. Blocks if
+ * the controller is currently conducting a rescan. The controller
+ * can be in one of three states:
+ * 1. Doesn't need a scan
+ * 2. On the scan list, but not scanning yet (we remove it)
+ * 3. Busy scanning (and not on the list). In this case we want to wait for
+ * the scan to complete to make sure the scanning thread for this
+ * controller is completely idle.
+ **/
+static void remove_from_scan_list(struct ctlr_info *h)
+{
+ struct ctlr_info *test_h, *tmp_h;
+
+ mutex_lock(&hpsa_scan_mutex);
+ list_for_each_entry_safe(test_h, tmp_h, &hpsa_scan_q, scan_list) {
+ if (test_h == h) { /* state 2. */
+ list_del(&h->scan_list);
+ complete_all(&h->scan_wait);
+ mutex_unlock(&hpsa_scan_mutex);
+ return;
+ }
+ }
+ if (h->busy_scanning) { /* state 3. */
+ mutex_unlock(&hpsa_scan_mutex);
+ wait_for_completion(&h->scan_wait);
+ } else { /* state 1, nothing to do. */
+ mutex_unlock(&hpsa_scan_mutex);
+ }
+}
+
+/* hpsa_scan_func() - kernel thread used to rescan controllers
+ * @data: Ignored.
+ *
+ * A kernel thread used scan for drive topology changes on
+ * controllers. The thread processes only one controller at a time
+ * using a queue. Controllers are added to the queue using
+ * add_to_scan_list() and removed from the queue either after done
+ * processing or using remove_from_scan_list().
+ *
+ * returns 0.
+ **/
+static int hpsa_scan_func(__attribute__((unused)) void *data)
+{
+ struct ctlr_info *h;
+ int host_no;
+
+ while (1) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ if (kthread_should_stop())
+ break;
+
+ while (1) {
+ mutex_lock(&hpsa_scan_mutex);
+ if (list_empty(&hpsa_scan_q)) {
+ mutex_unlock(&hpsa_scan_mutex);
+ break;
+ }
+ h = list_entry(hpsa_scan_q.next, struct ctlr_info,
+ scan_list);
+ list_del(&h->scan_list);
+ h->busy_scanning = 1;
+ mutex_unlock(&hpsa_scan_mutex);
+ host_no = h->scsi_host ? h->scsi_host->host_no : -1;
+ hpsa_update_scsi_devices(h, host_no);
+ complete_all(&h->scan_wait);
+ mutex_lock(&hpsa_scan_mutex);
+ h->busy_scanning = 0;
+ mutex_unlock(&hpsa_scan_mutex);
+ }
+ }
+ return 0;
+}
+
+static int check_for_unit_attention(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ if (c->err_info->SenseInfo[2] != UNIT_ATTENTION)
+ return 0;
+
+ switch (c->err_info->SenseInfo[12]) {
+ case STATE_CHANGED:
+ dev_warn(&h->pdev->dev, "hpsa%d: a state change "
+ "detected, command retried\n", h->ctlr);
+ break;
+ case LUN_FAILED:
+ dev_warn(&h->pdev->dev, "hpsa%d: LUN failure "
+ "detected, action required\n", h->ctlr);
+ break;
+ case REPORT_LUNS_CHANGED:
+ dev_warn(&h->pdev->dev, "hpsa%d: report LUN data "
+ "changed\n", h->ctlr);
+ /*
+ * Here, we could call add_to_scan_list and wake up the scan thread,
+ * except that it's quite likely that we will get more than one
+ * REPORT_LUNS_CHANGED condition in quick succession, which means
+ * that those which occur after the first one will likely happen
+ * *during* the hpsa_scan_thread's rescan. And the rescan code is not
+ * robust enough to restart in the middle, undoing what it has already
+ * done, and it's not clear that it's even possible to do this, since
+ * part of what it does is notify the SCSI mid layer, which starts
+ * doing it's own i/o to read partition tables and so on, and the
+ * driver doesn't have visibility to know what might need undoing.
+ * In any event, if possible, it is horribly complicated to get right
+ * so we just don't do it for now.
+ *
+ * Note: this REPORT_LUNS_CHANGED condition only occurs on the MSA2012.
+ */
+ break;
+ case POWER_OR_RESET:
+ dev_warn(&h->pdev->dev, "hpsa%d: a power on "
+ "or device reset detected\n", h->ctlr);
+ break;
+ case UNIT_ATTENTION_CLEARED:
+ dev_warn(&h->pdev->dev, "hpsa%d: unit attention "
+ "cleared by another initiator\n", h->ctlr);
+ break;
+ default:
+ dev_warn(&h->pdev->dev, "hpsa%d: unknown "
+ "unit attention detected\n", h->ctlr);
+ break;
+ }
+ return 1;
+}
+
+static ssize_t host_store_rescan(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ctlr_info *h;
+ struct Scsi_Host *shost = class_to_shost(dev);
+ unsigned long *priv = shost_priv(shost);
+ h = (struct ctlr_info *) *priv;
+ if (add_to_scan_list(h)) {
+ wake_up_process(hpsa_scan_thread);
+ wait_for_completion_interruptible(&h->scan_wait);
+ }
+ return count;
+}
+
+/* Enqueuing and dequeuing functions for cmdlists. */
+static inline void addQ(struct hlist_head *list, struct CommandList *c)
+{
+ hlist_add_head(&c->list, list);
+}
+
+static void enqueue_cmd_and_start_io(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&h->lock, flags);
+ addQ(&h->reqQ, c);
+ h->Qdepth++;
+ start_io(h);
+ spin_unlock_irqrestore(&h->lock, flags);
+}
+
+static inline void removeQ(struct CommandList *c)
+{
+ if (WARN_ON(hlist_unhashed(&c->list)))
+ return;
+ hlist_del_init(&c->list);
+}
+
+static inline int is_hba_lunid(unsigned char scsi3addr[])
+{
+ return memcmp(scsi3addr, RAID_CTLR_LUNID, 8) == 0;
+}
+
+static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
+{
+ return (scsi3addr[3] & 0xC0) == 0x40;
+}
+
+static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
+ "UNKNOWN"
+};
+#define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 1)
+
+static ssize_t raid_level_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t l = 0;
+ int rlevel;
+ struct ctlr_info *h;
+ struct scsi_device *sdev;
+ struct hpsa_scsi_dev_t *hdev;
+ unsigned long flags;
+
+ sdev = to_scsi_device(dev);
+ h = sdev_to_hba(sdev);
+ spin_lock_irqsave(&h->lock, flags);
+ hdev = sdev->hostdata;
+ if (!hdev) {
+ spin_unlock_irqrestore(&h->lock, flags);
+ return -ENODEV;
+ }
+
+ /* Is this even a logical drive? */
+ if (!is_logical_dev_addr_mode(hdev->scsi3addr)) {
+ spin_unlock_irqrestore(&h->lock, flags);
+ l = snprintf(buf, PAGE_SIZE, "N/A\n");
+ return l;
+ }
+
+ rlevel = hdev->raid_level;
+ spin_unlock_irqrestore(&h->lock, flags);
+ if (rlevel < 0 || rlevel > RAID_UNKNOWN)
+ rlevel = RAID_UNKNOWN;
+ l = snprintf(buf, PAGE_SIZE, "RAID %s\n", raid_label[rlevel]);
+ return l;
+}
+
+static ssize_t lunid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ctlr_info *h;
+ struct scsi_device *sdev;
+ struct hpsa_scsi_dev_t *hdev;
+ unsigned long flags;
+ unsigned char lunid[8];
+
+ sdev = to_scsi_device(dev);
+ h = sdev_to_hba(sdev);
+ spin_lock_irqsave(&h->lock, flags);
+ hdev = sdev->hostdata;
+ if (!hdev) {
+ spin_unlock_irqrestore(&h->lock, flags);
+ return -ENODEV;
+ }
+ memcpy(lunid, hdev->scsi3addr, sizeof(lunid));
+ spin_unlock_irqrestore(&h->lock, flags);
+ return snprintf(buf, 20, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ lunid[0], lunid[1], lunid[2], lunid[3],
+ lunid[4], lunid[5], lunid[6], lunid[7]);
+}
+
+static ssize_t unique_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ctlr_info *h;
+ struct scsi_device *sdev;
+ struct hpsa_scsi_dev_t *hdev;
+ unsigned long flags;
+ unsigned char sn[16];
+
+ sdev = to_scsi_device(dev);
+ h = sdev_to_hba(sdev);
+ spin_lock_irqsave(&h->lock, flags);
+ hdev = sdev->hostdata;
+ if (!hdev) {
+ spin_unlock_irqrestore(&h->lock, flags);
+ return -ENODEV;
+ }
+ memcpy(sn, hdev->device_id, sizeof(sn));
+ spin_unlock_irqrestore(&h->lock, flags);
+ return snprintf(buf, 16 * 2 + 2,
+ "%02X%02X%02X%02X%02X%02X%02X%02X"
+ "%02X%02X%02X%02X%02X%02X%02X%02X\n",
+ sn[0], sn[1], sn[2], sn[3],
+ sn[4], sn[5], sn[6], sn[7],
+ sn[8], sn[9], sn[10], sn[11],
+ sn[12], sn[13], sn[14], sn[15]);
+}
+
+static int hpsa_find_target_lun(struct ctlr_info *h,
+ unsigned char scsi3addr[], int bus, int *target, int *lun)
+{
+ /* finds an unused bus, target, lun for a new physical device
+ * assumes h->devlock is held
+ */
+ int i, found = 0;
+ DECLARE_BITMAP(lun_taken, HPSA_MAX_SCSI_DEVS_PER_HBA);
+
+ memset(&lun_taken[0], 0, HPSA_MAX_SCSI_DEVS_PER_HBA >> 3);
+
+ for (i = 0; i < h->ndevices; i++) {
+ if (h->dev[i]->bus == bus && h->dev[i]->target != -1)
+ set_bit(h->dev[i]->target, lun_taken);
+ }
+
+ for (i = 0; i < HPSA_MAX_SCSI_DEVS_PER_HBA; i++) {
+ if (!test_bit(i, lun_taken)) {
+ /* *bus = 1; */
+ *target = i;
+ *lun = 0;
+ found = 1;
+ break;
+ }
+ }
+ return !found;
+}
+
+/* Add an entry into h->dev[] array. */
+static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno,
+ struct hpsa_scsi_dev_t *device,
+ struct hpsa_scsi_dev_t *added[], int *nadded)
+{
+ /* assumes h->devlock is held */
+ int n = h->ndevices;
+ int i;
+ unsigned char addr1[8], addr2[8];
+ struct hpsa_scsi_dev_t *sd;
+
+ if (n >= HPSA_MAX_SCSI_DEVS_PER_HBA) {
+ dev_err(&h->pdev->dev, "too many devices, some will be "
+ "inaccessible.\n");
+ return -1;
+ }
+
+ /* physical devices do not have lun or target assigned until now. */
+ if (device->lun != -1)
+ /* Logical device, lun is already assigned. */
+ goto lun_assigned;
+
+ /* If this device a non-zero lun of a multi-lun device
+ * byte 4 of the 8-byte LUN addr will contain the logical
+ * unit no, zero otherise.
+ */
+ if (device->scsi3addr[4] == 0) {
+ /* This is not a non-zero lun of a multi-lun device */
+ if (hpsa_find_target_lun(h, device->scsi3addr,
+ device->bus, &device->target, &device->lun) != 0)
+ return -1;
+ goto lun_assigned;
+ }
+
+ /* This is a non-zero lun of a multi-lun device.
+ * Search through our list and find the device which
+ * has the same 8 byte LUN address, excepting byte 4.
+ * Assign the same bus and target for this new LUN.
+ * Use the logical unit number from the firmware.
+ */
+ memcpy(addr1, device->scsi3addr, 8);
+ addr1[4] = 0;
+ for (i = 0; i < n; i++) {
+ sd = h->dev[i];
+ memcpy(addr2, sd->scsi3addr, 8);
+ addr2[4] = 0;
+ /* differ only in byte 4? */
+ if (memcmp(addr1, addr2, 8) == 0) {
+ device->bus = sd->bus;
+ device->target = sd->target;
+ device->lun = device->scsi3addr[4];
+ break;
+ }
+ }
+ if (device->lun == -1) {
+ dev_warn(&h->pdev->dev, "physical device with no LUN=0,"
+ " suspect firmware bug or unsupported hardware "
+ "configuration.\n");
+ return -1;
+ }
+
+lun_assigned:
+
+ h->dev[n] = device;
+ h->ndevices++;
+ added[*nadded] = device;
+ (*nadded)++;
+
+ /* initially, (before registering with scsi layer) we don't
+ * know our hostno and we don't want to print anything first
+ * time anyway (the scsi layer's inquiries will show that info)
+ */
+ /* if (hostno != -1) */
+ dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d added.\n",
+ scsi_device_type(device->devtype), hostno,
+ device->bus, device->target, device->lun);
+ return 0;
+}
+
+/* Remove an entry from h->dev[] array. */
+static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry,
+ struct hpsa_scsi_dev_t *removed[], int *nremoved)
+{
+ /* assumes h->devlock is held */
+ int i;
+ struct hpsa_scsi_dev_t *sd;
+
+ if (entry < 0 || entry >= HPSA_MAX_SCSI_DEVS_PER_HBA)
+ BUG();
+
+ sd = h->dev[entry];
+ removed[*nremoved] = h->dev[entry];
+ (*nremoved)++;
+
+ for (i = entry; i < h->ndevices-1; i++)
+ h->dev[i] = h->dev[i+1];
+ h->ndevices--;
+ dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d removed.\n",
+ scsi_device_type(sd->devtype), hostno, sd->bus, sd->target,
+ sd->lun);
+}
+
+#define SCSI3ADDR_EQ(a, b) ( \
+ (a)[7] == (b)[7] && \
+ (a)[6] == (b)[6] && \
+ (a)[5] == (b)[5] && \
+ (a)[4] == (b)[4] && \
+ (a)[3] == (b)[3] && \
+ (a)[2] == (b)[2] && \
+ (a)[1] == (b)[1] && \
+ (a)[0] == (b)[0])
+
+static void fixup_botched_add(struct ctlr_info *h,
+ struct hpsa_scsi_dev_t *added)
+{
+ /* called when scsi_add_device fails in order to re-adjust
+ * h->dev[] to match the mid layer's view.
+ */
+ unsigned long flags;
+ int i, j;
+
+ spin_lock_irqsave(&h->lock, flags);
+ for (i = 0; i < h->ndevices; i++) {
+ if (h->dev[i] == added) {
+ for (j = i; j < h->ndevices-1; j++)
+ h->dev[j] = h->dev[j+1];
+ h->ndevices--;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+ kfree(added);
+}
+
+static inline int device_is_the_same(struct hpsa_scsi_dev_t *dev1,
+ struct hpsa_scsi_dev_t *dev2)
+{
+ if ((is_logical_dev_addr_mode(dev1->scsi3addr) ||
+ (dev1->lun != -1 && dev2->lun != -1)) &&
+ dev1->devtype != 0x0C)
+ return (memcmp(dev1, dev2, sizeof(*dev1)) == 0);
+
+ /* we compare everything except lun and target as these
+ * are not yet assigned. Compare parts likely
+ * to differ first
+ */
+ if (memcmp(dev1->scsi3addr, dev2->scsi3addr,
+ sizeof(dev1->scsi3addr)) != 0)
+ return 0;
+ if (memcmp(dev1->device_id, dev2->device_id,
+ sizeof(dev1->device_id)) != 0)
+ return 0;
+ if (memcmp(dev1->model, dev2->model, sizeof(dev1->model)) != 0)
+ return 0;
+ if (memcmp(dev1->vendor, dev2->vendor, sizeof(dev1->vendor)) != 0)
+ return 0;
+ if (memcmp(dev1->revision, dev2->revision, sizeof(dev1->revision)) != 0)
+ return 0;
+ if (dev1->devtype != dev2->devtype)
+ return 0;
+ if (dev1->raid_level != dev2->raid_level)
+ return 0;
+ if (dev1->bus != dev2->bus)
+ return 0;
+ return 1;
+}
+
+/* Find needle in haystack. If exact match found, return DEVICE_SAME,
+ * and return needle location in *index. If scsi3addr matches, but not
+ * vendor, model, serial num, etc. return DEVICE_CHANGED, and return needle
+ * location in *index. If needle not found, return DEVICE_NOT_FOUND.
+ */
+static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
+ struct hpsa_scsi_dev_t *haystack[], int haystack_size,
+ int *index)
+{
+ int i;
+#define DEVICE_NOT_FOUND 0
+#define DEVICE_CHANGED 1
+#define DEVICE_SAME 2
+ for (i = 0; i < haystack_size; i++) {
+ if (SCSI3ADDR_EQ(needle->scsi3addr, haystack[i]->scsi3addr)) {
+ *index = i;
+ if (device_is_the_same(needle, haystack[i]))
+ return DEVICE_SAME;
+ else
+ return DEVICE_CHANGED;
+ }
+ }
+ *index = -1;
+ return DEVICE_NOT_FOUND;
+}
+
+static int adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
+ struct hpsa_scsi_dev_t *sd[], int nsds)
+{
+ /* sd contains scsi3 addresses and devtypes, and inquiry
+ * data. This function takes what's in sd to be the current
+ * reality and updates h->dev[] to reflect that reality.
+ */
+ int i, entry, device_change, changes = 0;
+ struct hpsa_scsi_dev_t *csd;
+ unsigned long flags;
+ struct hpsa_scsi_dev_t **added, **removed;
+ int nadded, nremoved;
+ struct Scsi_Host *sh = NULL;
+
+ added = kzalloc(sizeof(*added) * HPSA_MAX_SCSI_DEVS_PER_HBA,
+ GFP_KERNEL);
+ removed = kzalloc(sizeof(*removed) * HPSA_MAX_SCSI_DEVS_PER_HBA,
+ GFP_KERNEL);
+
+ if (!added || !removed) {
+ dev_warn(&h->pdev->dev, "out of memory in "
+ "adjust_hpsa_scsi_table\n");
+ goto free_and_out;
+ }
+
+ spin_lock_irqsave(&h->devlock, flags);
+
+ /* find any devices in h->dev[] that are not in
+ * sd[] and remove them from h->dev[], and for any
+ * devices which have changed, remove the old device
+ * info and add the new device info.
+ */
+ i = 0;
+ nremoved = 0;
+ nadded = 0;
+ while (i < h->ndevices) {
+ csd = h->dev[i];
+ device_change = hpsa_scsi_find_entry(csd, sd, nsds, &entry);
+ if (device_change == DEVICE_NOT_FOUND) {
+ changes++;
+ hpsa_scsi_remove_entry(h, hostno, i,
+ removed, &nremoved);
+ continue; /* remove ^^^, hence i not incremented */
+ } else if (device_change == DEVICE_CHANGED) {
+ changes++;
+ hpsa_scsi_remove_entry(h, hostno, i,
+ removed, &nremoved);
+ (void) hpsa_scsi_add_entry(h, hostno, sd[entry],
+ added, &nadded);
+ /* add can't fail, we just removed one. */
+ sd[entry] = NULL; /* prevent it from being freed */
+ }
+ i++;
+ }
+
+ /* Now, make sure every device listed in sd[] is also
+ * listed in h->dev[], adding them if they aren't found
+ */
+
+ for (i = 0; i < nsds; i++) {
+ if (!sd[i]) /* if already added above. */
+ continue;
+ device_change = hpsa_scsi_find_entry(sd[i], h->dev,
+ h->ndevices, &entry);
+ if (device_change == DEVICE_NOT_FOUND) {
+ changes++;
+ if (hpsa_scsi_add_entry(h, hostno, sd[i],
+ added, &nadded) != 0)
+ break;
+ sd[i] = NULL; /* prevent from being freed later. */
+ } else if (device_change == DEVICE_CHANGED) {
+ /* should never happen... */
+ changes++;
+ dev_warn(&h->pdev->dev,
+ "device unexpectedly changed.\n");
+ /* but if it does happen, we just ignore that device */
+ }
+ }
+ spin_unlock_irqrestore(&h->devlock, flags);
+
+ /* Don't notify scsi mid layer of any changes the first time through
+ * (or if there are no changes) scsi_scan_host will do it later the
+ * first time through.
+ */
+ if (hostno == -1 || !changes)
+ goto free_and_out;
+
+ sh = h->scsi_host;
+ /* Notify scsi mid layer of any removed devices */
+ for (i = 0; i < nremoved; i++) {
+ struct scsi_device *sdev =
+ scsi_device_lookup(sh, removed[i]->bus,
+ removed[i]->target, removed[i]->lun);
+ if (sdev != NULL) {
+ scsi_remove_device(sdev);
+ scsi_device_put(sdev);
+ } else {
+ /* We don't expect to get here.
+ * future cmds to this device will get selection
+ * timeout as if the device was gone.
+ */
+ dev_warn(&h->pdev->dev, "didn't find c%db%dt%dl%d "
+ " for removal.", hostno, removed[i]->bus,
+ removed[i]->target, removed[i]->lun);
+ }
+ kfree(removed[i]);
+ removed[i] = NULL;
+ }
+
+ /* Notify scsi mid layer of any added devices */
+ for (i = 0; i < nadded; i++) {
+ if (scsi_add_device(sh, added[i]->bus,
+ added[i]->target, added[i]->lun) == 0)
+ continue;
+ dev_warn(&h->pdev->dev, "scsi_add_device c%db%dt%dl%d failed, "
+ "device not added.\n", hostno, added[i]->bus,
+ added[i]->target, added[i]->lun);
+ /* now we have to remove it from h->dev,
+ * since it didn't get added to scsi mid layer
+ */
+ fixup_botched_add(h, added[i]);
+ }
+
+free_and_out:
+ kfree(added);
+ kfree(removed);
+ return 0;
+}
+
+/*
+ * Lookup bus/target/lun and retrun corresponding struct hpsa_scsi_dev_t *
+ * Assume's h->devlock is held.
+ */
+static struct hpsa_scsi_dev_t *lookup_hpsa_scsi_dev(struct ctlr_info *h,
+ int bus, int target, int lun)
+{
+ int i;
+ struct hpsa_scsi_dev_t *sd;
+
+ for (i = 0; i < h->ndevices; i++) {
+ sd = h->dev[i];
+ if (sd->bus == bus && sd->target == target && sd->lun == lun)
+ return sd;
+ }
+ return NULL;
+}
+
+/* link sdev->hostdata to our per-device structure. */
+static int hpsa_slave_alloc(struct scsi_device *sdev)
+{
+ struct hpsa_scsi_dev_t *sd;
+ unsigned long flags;
+ struct ctlr_info *h;
+
+ h = sdev_to_hba(sdev);
+ spin_lock_irqsave(&h->devlock, flags);
+ sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev),
+ sdev_id(sdev), sdev->lun);
+ if (sd != NULL)
+ sdev->hostdata = sd;
+ spin_unlock_irqrestore(&h->devlock, flags);
+ return 0;
+}
+
+static void hpsa_slave_destroy(struct scsi_device *sdev)
+{
+ return; /* nothing to do. */
+}
+
+static void hpsa_scsi_setup(struct ctlr_info *h)
+{
+ h->ndevices = 0;
+ h->scsi_host = NULL;
+ spin_lock_init(&h->devlock);
+ return;
+}
+
+static void complete_scsi_command(struct CommandList *cp,
+ int timeout, __u32 tag)
+{
+ struct scsi_cmnd *cmd;
+ struct ctlr_info *h;
+ struct ErrorInfo *ei;
+
+ unsigned char sense_key;
+ unsigned char asc; /* additional sense code */
+ unsigned char ascq; /* additional sense code qualifier */
+
+ ei = cp->err_info;
+ cmd = (struct scsi_cmnd *) cp->scsi_cmd;
+ h = cp->h;
+
+ scsi_dma_unmap(cmd); /* undo the DMA mappings */
+
+ cmd->result = (DID_OK << 16); /* host byte */
+ cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
+ cmd->result |= (ei->ScsiStatus << 1);
+
+ /* copy the sense data whether we need to or not. */
+ memcpy(cmd->sense_buffer, ei->SenseInfo,
+ ei->SenseLen > SCSI_SENSE_BUFFERSIZE ?
+ SCSI_SENSE_BUFFERSIZE :
+ ei->SenseLen);
+ scsi_set_resid(cmd, ei->ResidualCnt);
+
+ if (ei->CommandStatus == 0) {
+ cmd->scsi_done(cmd);
+ cmd_free(h, cp);
+ return;
+ }
+
+ /* an error has occurred */
+ switch (ei->CommandStatus) {
+
+ case CMD_TARGET_STATUS:
+ if (ei->ScsiStatus) {
+ /* Get sense key */
+ sense_key = 0xf & ei->SenseInfo[2];
+ /* Get additional sense code */
+ asc = ei->SenseInfo[12];
+ /* Get addition sense code qualifier */
+ ascq = ei->SenseInfo[13];
+ }
+
+ if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION) {
+ if (check_for_unit_attention(h, cp)) {
+ cmd->result = DID_SOFT_ERROR << 16;
+ break;
+ }
+ if (sense_key == ILLEGAL_REQUEST) {
+ /*
+ * SCSI REPORT_LUNS is commonly unsupported on
+ * Smart Array. Suppress noisy complaint.
+ */
+ if (cp->Request.CDB[0] == REPORT_LUNS)
+ break;
+
+ /* If ASC/ASCQ indicate Logical Unit
+ * Not Supported condition,
+ */
+ if ((asc == 0x25) && (ascq == 0x0)) {
+ dev_warn(&h->pdev->dev, "cp %p "
+ "has check condition\n", cp);
+ break;
+ }
+ }
+
+ if (sense_key == NOT_READY) {
+ /* If Sense is Not Ready, Logical Unit
+ * Not ready, Manual Intervention
+ * required
+ */
+ if ((asc == 0x04) && (ascq == 0x03)) {
+ cmd->result = DID_NO_CONNECT << 16;
+ dev_warn(&h->pdev->dev, "cp %p "
+ "has check condition: unit "
+ "not ready, manual "
+ "intervention required\n", cp);
+ break;
+ }
+ }
+
+
+ /* Must be some other type of check condition */
+ dev_warn(&h->pdev->dev, "cp %p has check condition: "
+ "unknown type: "
+ "Sense: 0x%x, ASC: 0x%x, ASCQ: 0x%x, "
+ "Returning result: 0x%x, "
+ "cmd=[%02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x]\n",
+ cp, sense_key, asc, ascq,
+ cmd->result,
+ cmd->cmnd[0], cmd->cmnd[1],
+ cmd->cmnd[2], cmd->cmnd[3],
+ cmd->cmnd[4], cmd->cmnd[5],
+ cmd->cmnd[6], cmd->cmnd[7],
+ cmd->cmnd[8], cmd->cmnd[9]);
+ break;
+ }
+
+
+ /* Problem was not a check condition
+ * Pass it up to the upper layers...
+ */
+ if (ei->ScsiStatus) {
+ dev_warn(&h->pdev->dev, "cp %p has status 0x%x "
+ "Sense: 0x%x, ASC: 0x%x, ASCQ: 0x%x, "
+ "Returning result: 0x%x\n",
+ cp, ei->ScsiStatus,
+ sense_key, asc, ascq,
+ cmd->result);
+ } else { /* scsi status is zero??? How??? */
+ dev_warn(&h->pdev->dev, "cp %p SCSI status was 0. "
+ "Returning no connection.\n", cp),
+
+ /* Ordinarily, this case should never happen,
+ * but there is a bug in some released firmware
+ * revisions that allows it to happen if, for
+ * example, a 4100 backplane loses power and
+ * the tape drive is in it. We assume that
+ * it's a fatal error of some kind because we
+ * can't show that it wasn't. We will make it
+ * look like selection timeout since that is
+ * the most common reason for this to occur,
+ * and it's severe enough.
+ */
+
+ cmd->result = DID_NO_CONNECT << 16;
+ }
+ break;
+
+ case CMD_DATA_UNDERRUN: /* let mid layer handle it. */
+ break;
+ case CMD_DATA_OVERRUN:
+ dev_warn(&h->pdev->dev, "cp %p has"
+ " completed with data overrun "
+ "reported\n", cp);
+ break;
+ case CMD_INVALID: {
+ /* print_bytes(cp, sizeof(*cp), 1, 0);
+ print_cmd(cp); */
+ /* We get CMD_INVALID if you address a non-existent device
+ * instead of a selection timeout (no response). You will
+ * see this if you yank out a drive, then try to access it.
+ * This is kind of a shame because it means that any other
+ * CMD_INVALID (e.g. driver bug) will get interpreted as a
+ * missing target. */
+ cmd->result = DID_NO_CONNECT << 16;
+ }
+ break;
+ case CMD_PROTOCOL_ERR:
+ dev_warn(&h->pdev->dev, "cp %p has "
+ "protocol error \n", cp);
+ break;
+ case CMD_HARDWARE_ERR:
+ cmd->result = DID_ERROR << 16;
+ dev_warn(&h->pdev->dev, "cp %p had hardware error\n", cp);
+ break;
+ case CMD_CONNECTION_LOST:
+ cmd->result = DID_ERROR << 16;
+ dev_warn(&h->pdev->dev, "cp %p had connection lost\n", cp);
+ break;
+ case CMD_ABORTED:
+ cmd->result = DID_ABORT << 16;
+ dev_warn(&h->pdev->dev, "cp %p was aborted with status 0x%x\n",
+ cp, ei->ScsiStatus);
+ break;
+ case CMD_ABORT_FAILED:
+ cmd->result = DID_ERROR << 16;
+ dev_warn(&h->pdev->dev, "cp %p reports abort failed\n", cp);
+ break;
+ case CMD_UNSOLICITED_ABORT:
+ cmd->result = DID_ABORT << 16;
+ dev_warn(&h->pdev->dev, "cp %p aborted do to an unsolicited "
+ "abort\n", cp);
+ break;
+ case CMD_TIMEOUT:
+ cmd->result = DID_TIME_OUT << 16;
+ dev_warn(&h->pdev->dev, "cp %p timedout\n", cp);
+ break;
+ default:
+ cmd->result = DID_ERROR << 16;
+ dev_warn(&h->pdev->dev, "cp %p returned unknown status %x\n",
+ cp, ei->CommandStatus);
+ }
+ cmd->scsi_done(cmd);
+ cmd_free(h, cp);
+}
+
+static int hpsa_scsi_detect(struct ctlr_info *h)
+{
+ struct Scsi_Host *sh;
+ int error;
+
+ sh = scsi_host_alloc(&hpsa_driver_template, sizeof(h));
+ if (sh == NULL)
+ goto fail;
+
+ sh->io_port = 0;
+ sh->n_io_port = 0;
+ sh->this_id = -1;
+ sh->max_channel = 3;
+ sh->max_cmd_len = MAX_COMMAND_SIZE;
+ sh->max_lun = HPSA_MAX_LUN;
+ sh->max_id = HPSA_MAX_LUN;
+ h->scsi_host = sh;
+ sh->hostdata[0] = (unsigned long) h;
+ sh->irq = h->intr[SIMPLE_MODE_INT];
+ sh->unique_id = sh->irq;
+ error = scsi_add_host(sh, &h->pdev->dev);
+ if (error)
+ goto fail_host_put;
+ scsi_scan_host(sh);
+ return 0;
+
+ fail_host_put:
+ dev_err(&h->pdev->dev, "hpsa_scsi_detect: scsi_add_host"
+ " failed for controller %d\n", h->ctlr);
+ scsi_host_put(sh);
+ return -1;
+ fail:
+ dev_err(&h->pdev->dev, "hpsa_scsi_detect: scsi_host_alloc"
+ " failed for controller %d\n", h->ctlr);
+ return -1;
+}
+
+static void hpsa_pci_unmap(struct pci_dev *pdev,
+ struct CommandList *c, int sg_used, int data_direction)
+{
+ int i;
+ union u64bit addr64;
+
+ for (i = 0; i < sg_used; i++) {
+ addr64.val32.lower = c->SG[i].Addr.lower;
+ addr64.val32.upper = c->SG[i].Addr.upper;
+ pci_unmap_single(pdev, (dma_addr_t) addr64.val, c->SG[i].Len,
+ data_direction);
+ }
+}
+
+static void hpsa_map_one(struct pci_dev *pdev,
+ struct CommandList *cp,
+ unsigned char *buf,
+ size_t buflen,
+ int data_direction)
+{
+ __u64 addr64;
+
+ if (buflen == 0 || data_direction == PCI_DMA_NONE) {
+ cp->Header.SGList = 0;
+ cp->Header.SGTotal = 0;
+ return;
+ }
+
+ addr64 = (__u64) pci_map_single(pdev, buf, buflen, data_direction);
+ cp->SG[0].Addr.lower =
+ (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[0].Addr.upper =
+ (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[0].Len = buflen;
+ cp->Header.SGList = (__u8) 1; /* no. SGs contig in this cmd */
+ cp->Header.SGTotal = (__u16) 1; /* total sgs in this cmd list */
+}
+
+static inline void hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ DECLARE_COMPLETION_ONSTACK(wait);
+
+ c->waiting = &wait;
+ enqueue_cmd_and_start_io(h, c);
+ wait_for_completion(&wait);
+}
+
+static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h,
+ struct CommandList *c, int data_direction)
+{
+ int retry_count = 0;
+
+ do {
+ memset(c->err_info, 0, sizeof(c->err_info));
+ hpsa_scsi_do_simple_cmd_core(h, c);
+ retry_count++;
+ } while (check_for_unit_attention(h, c) && retry_count <= 3);
+ hpsa_pci_unmap(h->pdev, c, 1, data_direction);
+}
+
+static void hpsa_scsi_interpret_error(struct CommandList *cp)
+{
+ struct ErrorInfo *ei;
+ struct device *d = &cp->h->pdev->dev;
+
+ ei = cp->err_info;
+ switch (ei->CommandStatus) {
+ case CMD_TARGET_STATUS:
+ dev_warn(d, "cmd %p has completed with errors\n", cp);
+ dev_warn(d, "cmd %p has SCSI Status = %x\n", cp,
+ ei->ScsiStatus);
+ if (ei->ScsiStatus == 0)
+ dev_warn(d, "SCSI status is abnormally zero. "
+ "(probably indicates selection timeout "
+ "reported incorrectly due to a known "
+ "firmware bug, circa July, 2001.)\n");
+ break;
+ case CMD_DATA_UNDERRUN: /* let mid layer handle it. */
+ dev_info(d, "UNDERRUN\n");
+ break;
+ case CMD_DATA_OVERRUN:
+ dev_warn(d, "cp %p has completed with data overrun\n", cp);
+ break;
+ case CMD_INVALID: {
+ /* controller unfortunately reports SCSI passthru's
+ * to non-existent targets as invalid commands.
+ */
+ dev_warn(d, "cp %p is reported invalid (probably means "
+ "target device no longer present)\n", cp);
+ /* print_bytes((unsigned char *) cp, sizeof(*cp), 1, 0);
+ print_cmd(cp); */
+ }
+ break;
+ case CMD_PROTOCOL_ERR:
+ dev_warn(d, "cp %p has protocol error \n", cp);
+ break;
+ case CMD_HARDWARE_ERR:
+ /* cmd->result = DID_ERROR << 16; */
+ dev_warn(d, "cp %p had hardware error\n", cp);
+ break;
+ case CMD_CONNECTION_LOST:
+ dev_warn(d, "cp %p had connection lost\n", cp);
+ break;
+ case CMD_ABORTED:
+ dev_warn(d, "cp %p was aborted\n", cp);
+ break;
+ case CMD_ABORT_FAILED:
+ dev_warn(d, "cp %p reports abort failed\n", cp);
+ break;
+ case CMD_UNSOLICITED_ABORT:
+ dev_warn(d, "cp %p aborted due to an unsolicited abort\n", cp);
+ break;
+ case CMD_TIMEOUT:
+ dev_warn(d, "cp %p timed out\n", cp);
+ break;
+ default:
+ dev_warn(d, "cp %p returned unknown status %x\n", cp,
+ ei->CommandStatus);
+ }
+}
+
+static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr,
+ unsigned char page, unsigned char *buf,
+ unsigned char bufsize)
+{
+ int rc = IO_OK;
+ struct CommandList *c;
+ struct ErrorInfo *ei;
+
+ c = cmd_special_alloc(h);
+
+ if (c == NULL) { /* trouble... */
+ dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ return -1;
+ }
+
+ fill_cmd(c, HPSA_INQUIRY, h, buf, bufsize, page, scsi3addr, TYPE_CMD);
+ hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE);
+ ei = c->err_info;
+ if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ hpsa_scsi_interpret_error(c);
+ rc = -1;
+ }
+ cmd_special_free(h, c);
+ return rc;
+}
+
+static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr)
+{
+ int rc = IO_OK;
+ struct CommandList *c;
+ struct ErrorInfo *ei;
+
+ c = cmd_special_alloc(h);
+
+ if (c == NULL) { /* trouble... */
+ dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ return -1;
+ }
+
+ fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, scsi3addr, TYPE_MSG);
+ hpsa_scsi_do_simple_cmd_core(h, c);
+ /* no unmap needed here because no data xfer. */
+
+ ei = c->err_info;
+ if (ei->CommandStatus != 0) {
+ hpsa_scsi_interpret_error(c);
+ rc = -1;
+ }
+ cmd_special_free(h, c);
+ return rc;
+}
+
+static void hpsa_get_raid_level(struct ctlr_info *h,
+ unsigned char *scsi3addr, unsigned char *raid_level)
+{
+ int rc;
+ unsigned char *buf;
+
+ *raid_level = RAID_UNKNOWN;
+ buf = kzalloc(64, GFP_KERNEL);
+ if (!buf)
+ return;
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr, 0xC1, buf, 64);
+ if (rc == 0)
+ *raid_level = buf[8];
+ if (*raid_level > RAID_UNKNOWN)
+ *raid_level = RAID_UNKNOWN;
+ kfree(buf);
+ return;
+}
+
+/* Get the device id from inquiry page 0x83 */
+static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr,
+ unsigned char *device_id, int buflen)
+{
+ int rc;
+ unsigned char *buf;
+
+ if (buflen > 16)
+ buflen = 16;
+ buf = kzalloc(64, GFP_KERNEL);
+ if (!buf)
+ return -1;
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr, 0x83, buf, 64);
+ if (rc == 0)
+ memcpy(device_id, &buf[8], buflen);
+ kfree(buf);
+ return rc != 0;
+}
+
+static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical,
+ struct ReportLUNdata *buf, int bufsize,
+ int extended_response)
+{
+ int rc = IO_OK;
+ struct CommandList *c;
+ unsigned char scsi3addr[8];
+ struct ErrorInfo *ei;
+
+ c = cmd_special_alloc(h);
+ if (c == NULL) { /* trouble... */
+ dev_err(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ return -1;
+ }
+
+ memset(&scsi3addr[0], 0, 8); /* address the controller */
+
+ fill_cmd(c, logical ? HPSA_REPORT_LOG : HPSA_REPORT_PHYS, h,
+ buf, bufsize, 0, scsi3addr, TYPE_CMD);
+ if (extended_response)
+ c->Request.CDB[1] = extended_response;
+ hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE);
+ ei = c->err_info;
+ if (ei->CommandStatus != 0 &&
+ ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ hpsa_scsi_interpret_error(c);
+ rc = -1;
+ }
+ cmd_special_free(h, c);
+ return rc;
+}
+
+static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h,
+ struct ReportLUNdata *buf,
+ int bufsize, int extended_response)
+{
+ return hpsa_scsi_do_report_luns(h, 0, buf, bufsize, extended_response);
+}
+
+static inline int hpsa_scsi_do_report_log_luns(struct ctlr_info *h,
+ struct ReportLUNdata *buf, int bufsize)
+{
+ return hpsa_scsi_do_report_luns(h, 1, buf, bufsize, 0);
+}
+
+static inline void hpsa_set_bus_target_lun(struct hpsa_scsi_dev_t *device,
+ int bus, int target, int lun)
+{
+ device->bus = bus;
+ device->target = target;
+ device->lun = lun;
+}
+
+static int hpsa_update_device_info(struct ctlr_info *h,
+ unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device)
+{
+#define OBDR_TAPE_INQ_SIZE 49
+ unsigned char *inq_buff = NULL;
+
+ inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
+ if (!inq_buff)
+ goto bail_out;
+
+ memset(inq_buff, 0, OBDR_TAPE_INQ_SIZE);
+ /* Do an inquiry to the device to see what it is. */
+ if (hpsa_scsi_do_inquiry(h, scsi3addr, 0, inq_buff,
+ (unsigned char) OBDR_TAPE_INQ_SIZE) != 0) {
+ /* Inquiry failed (msg printed already) */
+ dev_err(&h->pdev->dev,
+ "hpsa_update_device_info: inquiry failed\n");
+ goto bail_out;
+ }
+
+ /* As a side effect, record the firmware version number
+ * if we happen to be talking to the RAID controller.
+ */
+ if (is_hba_lunid(scsi3addr))
+ memcpy(h->firm_ver, &inq_buff[32], 4);
+
+ this_device->devtype = (inq_buff[0] & 0x1f);
+ memcpy(this_device->scsi3addr, scsi3addr, 8);
+ memcpy(this_device->vendor, &inq_buff[8],
+ sizeof(this_device->vendor));
+ memcpy(this_device->model, &inq_buff[16],
+ sizeof(this_device->model));
+ memcpy(this_device->revision, &inq_buff[32],
+ sizeof(this_device->revision));
+ memset(this_device->device_id, 0,
+ sizeof(this_device->device_id));
+ hpsa_get_device_id(h, scsi3addr, this_device->device_id,
+ sizeof(this_device->device_id));
+
+ if (this_device->devtype == TYPE_DISK &&
+ is_logical_dev_addr_mode(scsi3addr))
+ hpsa_get_raid_level(h, scsi3addr, &this_device->raid_level);
+ else
+ this_device->raid_level = RAID_UNKNOWN;
+
+ kfree(inq_buff);
+ return 0;
+
+bail_out:
+ kfree(inq_buff);
+ return 1;
+}
+
+static unsigned char *msa2xxx_model[] = {
+ "MSA2012",
+ "MSA2024",
+ "MSA2312",
+ "MSA2324",
+ NULL,
+};
+
+static int is_msa2xxx(struct ctlr_info *h, struct hpsa_scsi_dev_t *device)
+{
+ int i;
+
+ for (i = 0; msa2xxx_model[i]; i++)
+ if (strncmp(device->model, msa2xxx_model[i],
+ strlen(msa2xxx_model[i])) == 0)
+ return 1;
+ return 0;
+}
+
+/* Helper function to assign bus, target, lun mapping of devices.
+ * Puts non-msa2xxx logical volumes on bus 0, msa2xxx logical
+ * volumes on bus 1, physical devices on bus 2. and the hba on bus 3.
+ * Logical drive target and lun are assigned at this time, but
+ * physical device lun and target assignment are deferred (assigned
+ * in hpsa_find_target_lun, called by hpsa_scsi_add_entry.)
+ */
+static void figure_bus_target_lun(struct ctlr_info *h,
+ __u8 *lunaddrbytes, int *bus, int *target, int *lun,
+ struct hpsa_scsi_dev_t *device)
+{
+
+ __u32 lunid;
+
+ if (is_logical_dev_addr_mode(lunaddrbytes)) {
+ /* logical device */
+ memcpy(&lunid, lunaddrbytes, sizeof(lunid));
+ lunid = le32_to_cpu(lunid);
+
+ if (is_msa2xxx(h, device)) {
+ *bus = 1;
+ *target = (lunid >> 16) & 0x3fff;
+ *lun = lunid & 0x00ff;
+ } else {
+ *bus = 0;
+ *lun = 0;
+ *target = lunid & 0x3fff;
+ }
+ } else {
+ /* physical device */
+ if (is_hba_lunid(lunaddrbytes))
+ *bus = 3;
+ else
+ *bus = 2;
+ *target = -1;
+ *lun = -1; /* we will fill these in later. */
+ }
+}
+
+/*
+ * If there is no lun 0 on a target, linux won't find any devices.
+ * For the MSA2xxx boxes, we have to manually detect the enclosure
+ * which is at lun zero, as CCISS_REPORT_PHYSICAL_LUNS doesn't report
+ * it for some reason. *tmpdevice is the target we're adding,
+ * this_device is a pointer into the current element of currentsd[]
+ * that we're building up in update_scsi_devices(), below.
+ * lunzerobits is a bitmap that tracks which targets already have a
+ * lun 0 assigned.
+ * Returns 1 if an enclosure was added, 0 if not.
+ */
+static int add_msa2xxx_enclosure_device(struct ctlr_info *h,
+ struct hpsa_scsi_dev_t *tmpdevice,
+ struct hpsa_scsi_dev_t *this_device, __u8 *lunaddrbytes,
+ int bus, int target, int lun, unsigned long lunzerobits[],
+ int *nmsa2xxx_enclosures)
+{
+ unsigned char scsi3addr[8];
+
+ if (test_bit(target, lunzerobits))
+ return 0; /* There is already a lun 0 on this target. */
+
+ if (!is_logical_dev_addr_mode(lunaddrbytes))
+ return 0; /* It's the logical targets that may lack lun 0. */
+
+ if (!is_msa2xxx(h, tmpdevice))
+ return 0; /* It's only the MSA2xxx that have this problem. */
+
+ if (lun == 0) /* if lun is 0, then obviously we have a lun 0. */
+ return 0;
+
+ if (is_hba_lunid(scsi3addr))
+ return 0; /* Don't add the RAID controller here. */
+
+#define MAX_MSA2XXX_ENCLOSURES 32
+ if (*nmsa2xxx_enclosures >= MAX_MSA2XXX_ENCLOSURES) {
+ dev_warn(&h->pdev->dev, "Maximum number of MSA2XXX "
+ "enclosures exceeded. Check your hardware "
+ "configuration.");
+ return 0;
+ }
+
+ memset(scsi3addr, 0, 8);
+ scsi3addr[3] = target;
+ if (hpsa_update_device_info(h, scsi3addr, this_device))
+ return 0;
+ (*nmsa2xxx_enclosures)++;
+ hpsa_set_bus_target_lun(this_device, bus, target, 0);
+ set_bit(target, lunzerobits);
+ return 1;
+}
+
+/*
+ * Do CISS_REPORT_PHYS and CISS_REPORT_LOG. Data is returned in physdev,
+ * logdev. The number of luns in physdev and logdev are returned in
+ * *nphysicals and *nlogicals, respectively.
+ * Returns 0 on success, -1 otherwise.
+ */
+static int hpsa_gather_lun_info(struct ctlr_info *h,
+ int reportlunsize,
+ struct ReportLUNdata *physdev, __u32 *nphysicals,
+ struct ReportLUNdata *logdev, __u32 *nlogicals)
+{
+ if (hpsa_scsi_do_report_phys_luns(h, physdev, reportlunsize, 0)) {
+ dev_err(&h->pdev->dev, "report physical LUNs failed.\n");
+ return -1;
+ }
+ memcpy(nphysicals, &physdev->LUNListLength[0], sizeof(*nphysicals));
+ *nphysicals = be32_to_cpu(*nphysicals) / 8;
+#ifdef DEBUG
+ dev_info(&h->pdev->dev, "number of physical luns is %d\n", *nphysicals);
+#endif
+ if (*nphysicals > HPSA_MAX_PHYS_LUN) {
+ dev_warn(&h->pdev->dev, "maximum physical LUNs (%d) exceeded."
+ " %d LUNs ignored.\n", HPSA_MAX_PHYS_LUN,
+ *nphysicals - HPSA_MAX_PHYS_LUN);
+ *nphysicals = HPSA_MAX_PHYS_LUN;
+ }
+ if (hpsa_scsi_do_report_log_luns(h, logdev, reportlunsize)) {
+ dev_err(&h->pdev->dev, "report logical LUNs failed.\n");
+ return -1;
+ }
+ memcpy(nlogicals, &logdev->LUNListLength[0], sizeof(*nlogicals));
+ *nlogicals = be32_to_cpu(*nlogicals) / 8;
+#ifdef DEBUG
+ dev_info(&h->pdev->dev, "number of logical luns is %d\n", *nlogicals);
+#endif
+ /* Reject Logicals in excess of our max capability. */
+ if (*nlogicals > HPSA_MAX_LUN) {
+ dev_warn(&h->pdev->dev,
+ "maximum logical LUNs (%d) exceeded. "
+ "%d LUNs ignored.\n", HPSA_MAX_LUN,
+ *nlogicals - HPSA_MAX_LUN);
+ *nlogicals = HPSA_MAX_LUN;
+ }
+ if (*nlogicals + *nphysicals > HPSA_MAX_PHYS_LUN) {
+ dev_warn(&h->pdev->dev,
+ "maximum logical + physical LUNs (%d) exceeded. "
+ "%d LUNs ignored.\n", HPSA_MAX_PHYS_LUN,
+ *nphysicals + *nlogicals - HPSA_MAX_PHYS_LUN);
+ *nlogicals = HPSA_MAX_PHYS_LUN - *nphysicals;
+ }
+ return 0;
+}
+
+static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
+{
+ /* the idea here is we could get notified
+ * that some devices have changed, so we do a report
+ * physical luns and report logical luns cmd, and adjust
+ * our list of devices accordingly.
+ *
+ * The scsi3addr's of devices won't change so long as the
+ * adapter is not reset. That means we can rescan and
+ * tell which devices we already know about, vs. new
+ * devices, vs. disappearing devices.
+ */
+ struct ReportLUNdata *physdev_list = NULL;
+ struct ReportLUNdata *logdev_list = NULL;
+ unsigned char *inq_buff = NULL;
+ __u32 nphysicals = 0;
+ __u32 nlogicals = 0;
+ __u32 ndev_allocated = 0;
+ struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice;
+ int ncurrent = 0;
+ int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 8;
+ int i, nmsa2xxx_enclosures, ndevs_to_allocate;
+ int bus, target, lun;
+ DECLARE_BITMAP(lunzerobits, HPSA_MAX_TARGETS_PER_CTLR);
+
+ currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_SCSI_DEVS_PER_HBA,
+ GFP_KERNEL);
+ physdev_list = kzalloc(reportlunsize, GFP_KERNEL);
+ logdev_list = kzalloc(reportlunsize, GFP_KERNEL);
+ inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
+ tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL);
+
+ if (!currentsd || !physdev_list || !logdev_list ||
+ !inq_buff || !tmpdevice) {
+ dev_err(&h->pdev->dev, "out of memory\n");
+ goto out;
+ }
+ memset(lunzerobits, 0, sizeof(lunzerobits));
+
+ if (hpsa_gather_lun_info(h, reportlunsize, physdev_list, &nphysicals,
+ logdev_list, &nlogicals))
+ goto out;
+
+ /* We might see up to 32 MSA2xxx enclosures, actually 8 of them
+ * but each of them 4 times through different paths. The plus 1
+ * is for the RAID controller.
+ */
+ ndevs_to_allocate = nphysicals + nlogicals + MAX_MSA2XXX_ENCLOSURES + 1;
+
+ /* Allocate the per device structures */
+ for (i = 0; i < ndevs_to_allocate; i++) {
+ currentsd[i] = kzalloc(sizeof(*currentsd[i]), GFP_KERNEL);
+ if (!currentsd[i]) {
+ dev_warn(&h->pdev->dev, "out of memory at %s:%d\n",
+ __FILE__, __LINE__);
+ goto out;
+ }
+ ndev_allocated++;
+ }
+
+ /* adjust our table of devices */
+ nmsa2xxx_enclosures = 0;
+ for (i = 0; i < nphysicals + nlogicals + 1; i++) {
+ __u8 *lunaddrbytes;
+
+ /* Figure out where the LUN ID info is coming from */
+ if (i < nphysicals)
+ lunaddrbytes = &physdev_list->LUN[i][0];
+ else
+ if (i < nphysicals + nlogicals)
+ lunaddrbytes =
+ &logdev_list->LUN[i-nphysicals][0];
+ else /* jam in the RAID controller at the end */
+ lunaddrbytes = RAID_CTLR_LUNID;
+
+ /* skip masked physical devices. */
+ if (lunaddrbytes[3] & 0xC0 && i < nphysicals)
+ continue;
+
+ /* Get device type, vendor, model, device id */
+ if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice))
+ continue; /* skip it if we can't talk to it. */
+ figure_bus_target_lun(h, lunaddrbytes, &bus, &target, &lun,
+ tmpdevice);
+ this_device = currentsd[ncurrent];
+
+ /*
+ * For the msa2xxx boxes, we have to insert a LUN 0 which
+ * doesn't show up in CCISS_REPORT_PHYSICAL data, but there
+ * is nonetheless an enclosure device there. We have to
+ * present that otherwise linux won't find anything if
+ * there is no lun 0.
+ */
+ if (add_msa2xxx_enclosure_device(h, tmpdevice, this_device,
+ lunaddrbytes, bus, target, lun, lunzerobits,
+ &nmsa2xxx_enclosures)) {
+ ncurrent++;
+ this_device = currentsd[ncurrent];
+ }
+
+ *this_device = *tmpdevice;
+ hpsa_set_bus_target_lun(this_device, bus, target, lun);
+
+ switch (this_device->devtype) {
+ case TYPE_ROM: {
+ /* We don't *really* support actual CD-ROM devices,
+ * just "One Button Disaster Recovery" tape drive
+ * which temporarily pretends to be a CD-ROM drive.
+ * So we check that the device is really an OBDR tape
+ * device by checking for "$DR-10" in bytes 43-48 of
+ * the inquiry data.
+ */
+ char obdr_sig[7];
+#define OBDR_TAPE_SIG "$DR-10"
+ strncpy(obdr_sig, &inq_buff[43], 6);
+ obdr_sig[6] = '\0';
+ if (strncmp(obdr_sig, OBDR_TAPE_SIG, 6) != 0)
+ /* Not OBDR device, ignore it. */
+ break;
+ }
+ ncurrent++;
+ break;
+ case TYPE_DISK:
+ if (i < nphysicals)
+ break;
+ ncurrent++;
+ break;
+ case TYPE_TAPE:
+ case TYPE_MEDIUM_CHANGER:
+ ncurrent++;
+ break;
+ case TYPE_RAID:
+ /* Only present the Smartarray HBA as a RAID controller.
+ * If it's a RAID controller other than the HBA itself
+ * (an external RAID controller, MSA500 or similar)
+ * don't present it.
+ */
+ if (!is_hba_lunid(lunaddrbytes))
+ break;
+ ncurrent++;
+ break;
+ default:
+ break;
+ }
+ if (ncurrent >= HPSA_MAX_SCSI_DEVS_PER_HBA)
+ break;
+ }
+ adjust_hpsa_scsi_table(h, hostno, currentsd, ncurrent);
+out:
+ kfree(tmpdevice);
+ for (i = 0; i < ndev_allocated; i++)
+ kfree(currentsd[i]);
+ kfree(currentsd);
+ kfree(inq_buff);
+ kfree(physdev_list);
+ kfree(logdev_list);
+ return;
+}
+
+/* hpsa_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci
+ * dma mapping and fills in the scatter gather entries of the
+ * hpsa command, cp.
+ */
+static int hpsa_scatter_gather(struct pci_dev *pdev,
+ struct CommandList *cp,
+ struct scsi_cmnd *cmd)
+{
+ unsigned int len;
+ struct scatterlist *sg;
+ __u64 addr64;
+ int use_sg, i;
+
+ BUG_ON(scsi_sg_count(cmd) > MAXSGENTRIES);
+
+ use_sg = scsi_dma_map(cmd);
+ if (use_sg < 0)
+ return use_sg;
+
+ if (!use_sg)
+ goto sglist_finished;
+
+ scsi_for_each_sg(cmd, sg, use_sg, i) {
+ addr64 = (__u64) sg_dma_address(sg);
+ len = sg_dma_len(sg);
+ cp->SG[i].Addr.lower =
+ (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[i].Addr.upper =
+ (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[i].Len = len;
+ cp->SG[i].Ext = 0; /* we are not chaining */
+ }
+
+sglist_finished:
+
+ cp->Header.SGList = (__u8) use_sg; /* no. SGs contig in this cmd */
+ cp->Header.SGTotal = (__u16) use_sg; /* total sgs in this cmd list */
+ return 0;
+}
+
+
+static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
+{
+ struct ctlr_info *h;
+ struct hpsa_scsi_dev_t *dev;
+ unsigned char scsi3addr[8];
+ struct CommandList *c;
+ unsigned long flags;
+
+ /* Get the ptr to our adapter structure out of cmd->host. */
+ h = sdev_to_hba(cmd->device);
+ dev = cmd->device->hostdata;
+ if (!dev) {
+ cmd->result = DID_NO_CONNECT << 16;
+ done(cmd);
+ return 0;
+ }
+ memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr));
+
+ /* Need a lock as this is being allocated from the pool */
+ spin_lock_irqsave(&h->lock, flags);
+ c = cmd_alloc(h);
+ spin_unlock_irqrestore(&h->lock, flags);
+ if (c == NULL) { /* trouble... */
+ dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n");
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ /* Fill in the command list header */
+
+ cmd->scsi_done = done; /* save this for use by completion code */
+
+ /* save c in case we have to abort it */
+ cmd->host_scribble = (unsigned char *) c;
+
+ c->cmd_type = CMD_SCSI;
+ c->scsi_cmd = cmd;
+ c->Header.ReplyQueue = 0; /* unused in simple mode */
+ memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8);
+ c->Header.Tag.lower = c->busaddr; /* Use k. address of cmd as tag */
+
+ /* Fill in the request block... */
+
+ c->Request.Timeout = 0;
+ memset(c->Request.CDB, 0, sizeof(c->Request.CDB));
+ BUG_ON(cmd->cmd_len > sizeof(c->Request.CDB));
+ c->Request.CDBLen = cmd->cmd_len;
+ memcpy(c->Request.CDB, cmd->cmnd, cmd->cmd_len);
+ c->Request.Type.Type = TYPE_CMD;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ switch (cmd->sc_data_direction) {
+ case DMA_TO_DEVICE:
+ c->Request.Type.Direction = XFER_WRITE;
+ break;
+ case DMA_FROM_DEVICE:
+ c->Request.Type.Direction = XFER_READ;
+ break;
+ case DMA_NONE:
+ c->Request.Type.Direction = XFER_NONE;
+ break;
+ case DMA_BIDIRECTIONAL:
+ /* This can happen if a buggy application does a scsi passthru
+ * and sets both inlen and outlen to non-zero. ( see
+ * ../scsi/scsi_ioctl.c:scsi_ioctl_send_command() )
+ */
+
+ c->Request.Type.Direction = XFER_RSVD;
+ /* This is technically wrong, and hpsa controllers should
+ * reject it with CMD_INVALID, which is the most correct
+ * response, but non-fibre backends appear to let it
+ * slide by, and give the same results as if this field
+ * were set correctly. Either way is acceptable for
+ * our purposes here.
+ */
+
+ break;
+
+ default:
+ dev_err(&h->pdev->dev, "unknown data direction: %d\n",
+ cmd->sc_data_direction);
+ BUG();
+ break;
+ }
+
+ if (hpsa_scatter_gather(h->pdev, c, cmd) < 0) { /* Fill SG list */
+ cmd_free(h, c);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+ enqueue_cmd_and_start_io(h, c);
+ /* the cmd'll come back via intr handler in complete_scsi_command() */
+ return 0;
+}
+
+static void hpsa_unregister_scsi(struct ctlr_info *h)
+{
+ /* we are being forcibly unloaded, and may not refuse. */
+ scsi_remove_host(h->scsi_host);
+ scsi_host_put(h->scsi_host);
+ h->scsi_host = NULL;
+}
+
+static int hpsa_register_scsi(struct ctlr_info *h)
+{
+ int rc;
+
+ hpsa_update_scsi_devices(h, -1);
+ rc = hpsa_scsi_detect(h);
+ if (rc != 0)
+ dev_err(&h->pdev->dev, "hpsa_register_scsi: failed"
+ " hpsa_scsi_detect(), rc is %d\n", rc);
+ return rc;
+}
+
+static int wait_for_device_to_become_ready(struct ctlr_info *h,
+ unsigned char lunaddr[])
+{
+ int rc = 0;
+ int count = 0;
+ int waittime = 1; /* seconds */
+ struct CommandList *c;
+
+ c = cmd_special_alloc(h);
+ if (!c) {
+ dev_warn(&h->pdev->dev, "out of memory in "
+ "wait_for_device_to_become_ready.\n");
+ return IO_ERROR;
+ }
+
+ /* Send test unit ready until device ready, or give up. */
+ while (count < HPSA_TUR_RETRY_LIMIT) {
+
+ /* Wait for a bit. do this first, because if we send
+ * the TUR right away, the reset will just abort it.
+ */
+ msleep(1000 * waittime);
+ count++;
+
+ /* Increase wait time with each try, up to a point. */
+ if (waittime < HPSA_MAX_WAIT_INTERVAL_SECS)
+ waittime = waittime * 2;
+
+ /* Send the Test Unit Ready */
+ fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, lunaddr, TYPE_CMD);
+ hpsa_scsi_do_simple_cmd_core(h, c);
+ /* no unmap needed here because no data xfer. */
+
+ if (c->err_info->CommandStatus == CMD_SUCCESS)
+ break;
+
+ if (c->err_info->CommandStatus == CMD_TARGET_STATUS &&
+ c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION &&
+ (c->err_info->SenseInfo[2] == NO_SENSE ||
+ c->err_info->SenseInfo[2] == UNIT_ATTENTION))
+ break;
+
+ dev_warn(&h->pdev->dev, "waiting %d secs "
+ "for device to become ready.\n", waittime);
+ rc = 1; /* device not ready. */
+ }
+
+ if (rc)
+ dev_warn(&h->pdev->dev, "giving up on device.\n");
+ else
+ dev_warn(&h->pdev->dev, "device is ready.\n");
+
+ cmd_special_free(h, c);
+ return rc;
+}
+
+/* Need at least one of these error handlers to keep ../scsi/hosts.c from
+ * complaining. Doing a host- or bus-reset can't do anything good here.
+ */
+static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
+{
+ int rc;
+ struct ctlr_info *h;
+ struct hpsa_scsi_dev_t *dev;
+
+ /* find the controller to which the command to be aborted was sent */
+ h = sdev_to_hba(scsicmd->device);
+ if (h == NULL) /* paranoia */
+ return FAILED;
+ dev_warn(&h->pdev->dev, "resetting drive\n");
+
+ dev = scsicmd->device->hostdata;
+ if (!dev) {
+ dev_err(&h->pdev->dev, "hpsa_eh_device_reset_handler: "
+ "device lookup failed.\n");
+ return FAILED;
+ }
+ /* send a reset to the SCSI LUN which the command was sent to */
+ rc = hpsa_send_reset(h, dev->scsi3addr);
+ if (rc == 0 && wait_for_device_to_become_ready(h, dev->scsi3addr) == 0)
+ return SUCCESS;
+
+ dev_warn(&h->pdev->dev, "resetting device failed.\n");
+ return FAILED;
+}
+
+/*
+ * For operations that cannot sleep, a command block is allocated at init,
+ * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track
+ * which ones are free or in use. Lock must be held when calling this.
+ * cmd_free() is the complement.
+ */
+static struct CommandList *cmd_alloc(struct ctlr_info *h)
+{
+ struct CommandList *c;
+ int i;
+ union u64bit temp64;
+ dma_addr_t cmd_dma_handle, err_dma_handle;
+
+ do {
+ i = find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds);
+ if (i == h->nr_cmds)
+ return NULL;
+ } while (test_and_set_bit
+ (i & (BITS_PER_LONG - 1),
+ h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0);
+ c = h->cmd_pool + i;
+ memset(c, 0, sizeof(*c));
+ cmd_dma_handle = h->cmd_pool_dhandle
+ + i * sizeof(*c);
+ c->err_info = h->errinfo_pool + i;
+ memset(c->err_info, 0, sizeof(*c->err_info));
+ err_dma_handle = h->errinfo_pool_dhandle
+ + i * sizeof(*c->err_info);
+ h->nr_allocs++;
+
+ c->cmdindex = i;
+
+ INIT_HLIST_NODE(&c->list);
+ c->busaddr = (__u32) cmd_dma_handle;
+ temp64.val = (__u64) err_dma_handle;
+ c->ErrDesc.Addr.lower = temp64.val32.lower;
+ c->ErrDesc.Addr.upper = temp64.val32.upper;
+ c->ErrDesc.Len = sizeof(*c->err_info);
+
+ c->h = h;
+ return c;
+}
+
+/* For operations that can wait for kmalloc to possibly sleep,
+ * this routine can be called. Lock need not be held to call
+ * cmd_special_alloc. cmd_special_free() is the complement.
+ */
+static struct CommandList *cmd_special_alloc(struct ctlr_info *h)
+{
+ struct CommandList *c;
+ union u64bit temp64;
+ dma_addr_t cmd_dma_handle, err_dma_handle;
+
+ c = pci_alloc_consistent(h->pdev, sizeof(*c), &cmd_dma_handle);
+ if (c == NULL)
+ return NULL;
+ memset(c, 0, sizeof(*c));
+
+ c->cmdindex = -1;
+
+ c->err_info = pci_alloc_consistent(h->pdev, sizeof(*c->err_info),
+ &err_dma_handle);
+
+ if (c->err_info == NULL) {
+ pci_free_consistent(h->pdev,
+ sizeof(*c), c, cmd_dma_handle);
+ return NULL;
+ }
+ memset(c->err_info, 0, sizeof(*c->err_info));
+
+ INIT_HLIST_NODE(&c->list);
+ c->busaddr = (__u32) cmd_dma_handle;
+ temp64.val = (__u64) err_dma_handle;
+ c->ErrDesc.Addr.lower = temp64.val32.lower;
+ c->ErrDesc.Addr.upper = temp64.val32.upper;
+ c->ErrDesc.Len = sizeof(*c->err_info);
+
+ c->h = h;
+ return c;
+}
+
+static void cmd_free(struct ctlr_info *h, struct CommandList *c)
+{
+ int i;
+
+ i = c - h->cmd_pool;
+ clear_bit(i & (BITS_PER_LONG - 1),
+ h->cmd_pool_bits + (i / BITS_PER_LONG));
+ h->nr_frees++;
+}
+
+static void cmd_special_free(struct ctlr_info *h, struct CommandList *c)
+{
+ union u64bit temp64;
+
+ temp64.val32.lower = c->ErrDesc.Addr.lower;
+ temp64.val32.upper = c->ErrDesc.Addr.upper;
+ pci_free_consistent(h->pdev, sizeof(*c->err_info),
+ c->err_info, (dma_addr_t) temp64.val);
+ pci_free_consistent(h->pdev, sizeof(*c),
+ c, (dma_addr_t) c->busaddr);
+}
+
+#ifdef CONFIG_COMPAT
+
+static int do_ioctl(struct scsi_device *dev, int cmd, void *arg)
+{
+ int ret;
+
+ lock_kernel();
+ ret = hpsa_ioctl(dev, cmd, arg);
+ unlock_kernel();
+ return ret;
+}
+
+static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg);
+static int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
+ int cmd, void *arg);
+
+static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg)
+{
+ switch (cmd) {
+ case CCISS_GETPCIINFO:
+ case CCISS_GETINTINFO:
+ case CCISS_SETINTINFO:
+ case CCISS_GETNODENAME:
+ case CCISS_SETNODENAME:
+ case CCISS_GETHEARTBEAT:
+ case CCISS_GETBUSTYPES:
+ case CCISS_GETFIRMVER:
+ case CCISS_GETDRIVVER:
+ case CCISS_REVALIDVOLS:
+ case CCISS_DEREGDISK:
+ case CCISS_REGNEWDISK:
+ case CCISS_REGNEWD:
+ case CCISS_RESCANDISK:
+ case CCISS_GETLUNINFO:
+ return do_ioctl(dev, cmd, arg);
+
+ case CCISS_PASSTHRU32:
+ return hpsa_ioctl32_passthru(dev, cmd, arg);
+ case CCISS_BIG_PASSTHRU32:
+ return hpsa_ioctl32_big_passthru(dev, cmd, arg);
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg)
+{
+ IOCTL32_Command_struct __user *arg32 =
+ (IOCTL32_Command_struct __user *) arg;
+ IOCTL_Command_struct arg64;
+ IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64));
+ int err;
+ u32 cp;
+
+ err = 0;
+ err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
+ sizeof(arg64.LUN_info));
+ err |= copy_from_user(&arg64.Request, &arg32->Request,
+ sizeof(arg64.Request));
+ err |= copy_from_user(&arg64.error_info, &arg32->error_info,
+ sizeof(arg64.error_info));
+ err |= get_user(arg64.buf_size, &arg32->buf_size);
+ err |= get_user(cp, &arg32->buf);
+ arg64.buf = compat_ptr(cp);
+ err |= copy_to_user(p, &arg64, sizeof(arg64));
+
+ if (err)
+ return -EFAULT;
+
+ err = do_ioctl(dev, CCISS_PASSTHRU, (void *)p);
+ if (err)
+ return err;
+ err |= copy_in_user(&arg32->error_info, &p->error_info,
+ sizeof(arg32->error_info));
+ if (err)
+ return -EFAULT;
+ return err;
+}
+
+static int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
+ int cmd, void *arg)
+{
+ BIG_IOCTL32_Command_struct __user *arg32 =
+ (BIG_IOCTL32_Command_struct __user *) arg;
+ BIG_IOCTL_Command_struct arg64;
+ BIG_IOCTL_Command_struct __user *p =
+ compat_alloc_user_space(sizeof(arg64));
+ int err;
+ u32 cp;
+
+ err = 0;
+ err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
+ sizeof(arg64.LUN_info));
+ err |= copy_from_user(&arg64.Request, &arg32->Request,
+ sizeof(arg64.Request));
+ err |= copy_from_user(&arg64.error_info, &arg32->error_info,
+ sizeof(arg64.error_info));
+ err |= get_user(arg64.buf_size, &arg32->buf_size);
+ err |= get_user(arg64.malloc_size, &arg32->malloc_size);
+ err |= get_user(cp, &arg32->buf);
+ arg64.buf = compat_ptr(cp);
+ err |= copy_to_user(p, &arg64, sizeof(arg64));
+
+ if (err)
+ return -EFAULT;
+
+ err = do_ioctl(dev, CCISS_BIG_PASSTHRU, (void *)p);
+ if (err)
+ return err;
+ err |= copy_in_user(&arg32->error_info, &p->error_info,
+ sizeof(arg32->error_info));
+ if (err)
+ return -EFAULT;
+ return err;
+}
+#endif
+
+static int hpsa_getpciinfo_ioctl(struct ctlr_info *h, void __user *argp)
+{
+ struct hpsa_pci_info pciinfo;
+
+ if (!argp)
+ return -EINVAL;
+ pciinfo.domain = pci_domain_nr(h->pdev->bus);
+ pciinfo.bus = h->pdev->bus->number;
+ pciinfo.dev_fn = h->pdev->devfn;
+ pciinfo.board_id = h->board_id;
+ if (copy_to_user(argp, &pciinfo, sizeof(pciinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+static int hpsa_getdrivver_ioctl(struct ctlr_info *h, void __user *argp)
+{
+ DriverVer_type DriverVer;
+ unsigned char vmaj, vmin, vsubmin;
+ int rc;
+
+ rc = sscanf(HPSA_DRIVER_VERSION, "%hhu.%hhu.%hhu",
+ &vmaj, &vmin, &vsubmin);
+ if (rc != 3) {
+ dev_info(&h->pdev->dev, "driver version string '%s' "
+ "unrecognized.", HPSA_DRIVER_VERSION);
+ vmaj = 0;
+ vmin = 0;
+ vsubmin = 0;
+ }
+ DriverVer = (vmaj << 16) | (vmin << 8) | vsubmin;
+ if (!argp)
+ return -EINVAL;
+ if (copy_to_user(argp, &DriverVer, sizeof(DriverVer_type)))
+ return -EFAULT;
+ return 0;
+}
+
+static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
+{
+ IOCTL_Command_struct iocommand;
+ struct CommandList *c;
+ char *buff = NULL;
+ union u64bit temp64;
+
+ if (!argp)
+ return -EINVAL;
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ if (copy_from_user(&iocommand, argp, sizeof(iocommand)))
+ return -EFAULT;
+ if ((iocommand.buf_size < 1) &&
+ (iocommand.Request.Type.Direction != XFER_NONE)) {
+ return -EINVAL;
+ }
+ if (iocommand.buf_size > 0) {
+ buff = kmalloc(iocommand.buf_size, GFP_KERNEL);
+ if (buff == NULL)
+ return -EFAULT;
+ }
+ if (iocommand.Request.Type.Direction == XFER_WRITE) {
+ /* Copy the data into the buffer we created */
+ if (copy_from_user(buff, iocommand.buf, iocommand.buf_size)) {
+ kfree(buff);
+ return -EFAULT;
+ }
+ } else
+ memset(buff, 0, iocommand.buf_size);
+ c = cmd_special_alloc(h);
+ if (c == NULL) {
+ kfree(buff);
+ return -ENOMEM;
+ }
+ /* Fill in the command type */
+ c->cmd_type = CMD_IOCTL_PEND;
+ /* Fill in Command Header */
+ c->Header.ReplyQueue = 0; /* unused in simple mode */
+ if (iocommand.buf_size > 0) { /* buffer to fill */
+ c->Header.SGList = 1;
+ c->Header.SGTotal = 1;
+ } else { /* no buffers to fill */
+ c->Header.SGList = 0;
+ c->Header.SGTotal = 0;
+ }
+ memcpy(&c->Header.LUN, &iocommand.LUN_info, sizeof(c->Header.LUN));
+ /* use the kernel address the cmd block for tag */
+ c->Header.Tag.lower = c->busaddr;
+
+ /* Fill in Request block */
+ memcpy(&c->Request, &iocommand.Request,
+ sizeof(c->Request));
+
+ /* Fill in the scatter gather information */
+ if (iocommand.buf_size > 0) {
+ temp64.val = pci_map_single(h->pdev, buff,
+ iocommand.buf_size, PCI_DMA_BIDIRECTIONAL);
+ c->SG[0].Addr.lower = temp64.val32.lower;
+ c->SG[0].Addr.upper = temp64.val32.upper;
+ c->SG[0].Len = iocommand.buf_size;
+ c->SG[0].Ext = 0; /* we are not chaining*/
+ }
+ hpsa_scsi_do_simple_cmd_core(h, c);
+ hpsa_pci_unmap(h->pdev, c, 1, PCI_DMA_BIDIRECTIONAL);
+ check_ioctl_unit_attention(h, c);
+
+ /* Copy the error information out */
+ memcpy(&iocommand.error_info, c->err_info,
+ sizeof(iocommand.error_info));
+ if (copy_to_user(argp, &iocommand, sizeof(iocommand))) {
+ kfree(buff);
+ cmd_special_free(h, c);
+ return -EFAULT;
+ }
+
+ if (iocommand.Request.Type.Direction == XFER_READ) {
+ /* Copy the data out of the buffer we created */
+ if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) {
+ kfree(buff);
+ cmd_special_free(h, c);
+ return -EFAULT;
+ }
+ }
+ kfree(buff);
+ cmd_special_free(h, c);
+ return 0;
+}
+
+static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
+{
+ BIG_IOCTL_Command_struct *ioc;
+ struct CommandList *c;
+ unsigned char **buff = NULL;
+ int *buff_size = NULL;
+ union u64bit temp64;
+ BYTE sg_used = 0;
+ int status = 0;
+ int i;
+ __u32 left;
+ __u32 sz;
+ BYTE __user *data_ptr;
+
+ if (!argp)
+ return -EINVAL;
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ ioc = (BIG_IOCTL_Command_struct *)
+ kmalloc(sizeof(*ioc), GFP_KERNEL);
+ if (!ioc) {
+ status = -ENOMEM;
+ goto cleanup1;
+ }
+ if (copy_from_user(ioc, argp, sizeof(*ioc))) {
+ status = -EFAULT;
+ goto cleanup1;
+ }
+ if ((ioc->buf_size < 1) &&
+ (ioc->Request.Type.Direction != XFER_NONE)) {
+ status = -EINVAL;
+ goto cleanup1;
+ }
+ /* Check kmalloc limits using all SGs */
+ if (ioc->malloc_size > MAX_KMALLOC_SIZE) {
+ status = -EINVAL;
+ goto cleanup1;
+ }
+ if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {
+ status = -EINVAL;
+ goto cleanup1;
+ }
+ buff = kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
+ if (!buff) {
+ status = -ENOMEM;
+ goto cleanup1;
+ }
+ buff_size = kmalloc(MAXSGENTRIES * sizeof(int), GFP_KERNEL);
+ if (!buff_size) {
+ status = -ENOMEM;
+ goto cleanup1;
+ }
+ left = ioc->buf_size;
+ data_ptr = ioc->buf;
+ while (left) {
+ sz = (left > ioc->malloc_size) ? ioc->malloc_size : left;
+ buff_size[sg_used] = sz;
+ buff[sg_used] = kmalloc(sz, GFP_KERNEL);
+ if (buff[sg_used] == NULL) {
+ status = -ENOMEM;
+ goto cleanup1;
+ }
+ if (ioc->Request.Type.Direction == XFER_WRITE) {
+ if (copy_from_user(buff[sg_used], data_ptr, sz)) {
+ status = -ENOMEM;
+ goto cleanup1;
+ }
+ } else
+ memset(buff[sg_used], 0, sz);
+ left -= sz;
+ data_ptr += sz;
+ sg_used++;
+ }
+ c = cmd_special_alloc(h);
+ if (c == NULL) {
+ status = -ENOMEM;
+ goto cleanup1;
+ }
+ c->cmd_type = CMD_IOCTL_PEND;
+ c->Header.ReplyQueue = 0;
+
+ if (ioc->buf_size > 0) {
+ c->Header.SGList = sg_used;
+ c->Header.SGTotal = sg_used;
+ } else {
+ c->Header.SGList = 0;
+ c->Header.SGTotal = 0;
+ }
+ memcpy(&c->Header.LUN, &ioc->LUN_info, sizeof(c->Header.LUN));
+ c->Header.Tag.lower = c->busaddr;
+ memcpy(&c->Request, &ioc->Request, sizeof(c->Request));
+ if (ioc->buf_size > 0) {
+ int i;
+ for (i = 0; i < sg_used; i++) {
+ temp64.val = pci_map_single(h->pdev, buff[i],
+ buff_size[i], PCI_DMA_BIDIRECTIONAL);
+ c->SG[i].Addr.lower = temp64.val32.lower;
+ c->SG[i].Addr.upper = temp64.val32.upper;
+ c->SG[i].Len = buff_size[i];
+ /* we are not chaining */
+ c->SG[i].Ext = 0;
+ }
+ }
+ hpsa_scsi_do_simple_cmd_core(h, c);
+ hpsa_pci_unmap(h->pdev, c, sg_used, PCI_DMA_BIDIRECTIONAL);
+ check_ioctl_unit_attention(h, c);
+ /* Copy the error information out */
+ memcpy(&ioc->error_info, c->err_info, sizeof(ioc->error_info));
+ if (copy_to_user(argp, ioc, sizeof(*ioc))) {
+ cmd_special_free(h, c);
+ status = -EFAULT;
+ goto cleanup1;
+ }
+ if (ioc->Request.Type.Direction == XFER_READ) {
+ /* Copy the data out of the buffer we created */
+ BYTE __user *ptr = ioc->buf;
+ for (i = 0; i < sg_used; i++) {
+ if (copy_to_user(ptr, buff[i], buff_size[i])) {
+ cmd_special_free(h, c);
+ status = -EFAULT;
+ goto cleanup1;
+ }
+ ptr += buff_size[i];
+ }
+ }
+ cmd_special_free(h, c);
+ status = 0;
+cleanup1:
+ if (buff) {
+ for (i = 0; i < sg_used; i++)
+ kfree(buff[i]);
+ kfree(buff);
+ }
+ kfree(buff_size);
+ kfree(ioc);
+ return status;
+}
+
+static void check_ioctl_unit_attention(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ if (c->err_info->CommandStatus == CMD_TARGET_STATUS &&
+ c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION)
+ (void) check_for_unit_attention(h, c);
+}
+/*
+ * ioctl
+ */
+static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg)
+{
+ struct ctlr_info *h;
+ void __user *argp = (void __user *)arg;
+
+ h = sdev_to_hba(dev);
+
+ switch (cmd) {
+ case CCISS_DEREGDISK:
+ case CCISS_REGNEWDISK:
+ case CCISS_REGNEWD:
+ hpsa_update_scsi_devices(h, dev->host->host_no);
+ return 0;
+ case CCISS_GETPCIINFO:
+ return hpsa_getpciinfo_ioctl(h, argp);
+ case CCISS_GETDRIVVER:
+ return hpsa_getdrivver_ioctl(h, argp);
+ case CCISS_PASSTHRU:
+ return hpsa_passthru_ioctl(h, argp);
+ case CCISS_BIG_PASSTHRU:
+ return hpsa_big_passthru_ioctl(h, argp);
+ default:
+ return -ENOTTY;
+ }
+}
+
+static void fill_cmd(struct CommandList *c, __u8 cmd, struct ctlr_info *h,
+ void *buff, size_t size, __u8 page_code, unsigned char *scsi3addr,
+ int cmd_type)
+{
+ int pci_dir = XFER_NONE;
+
+ c->cmd_type = CMD_IOCTL_PEND;
+ c->Header.ReplyQueue = 0;
+ if (buff != NULL && size > 0) {
+ c->Header.SGList = 1;
+ c->Header.SGTotal = 1;
+ } else {
+ c->Header.SGList = 0;
+ c->Header.SGTotal = 0;
+ }
+ c->Header.Tag.lower = c->busaddr;
+ memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8);
+
+ c->Request.Type.Type = cmd_type;
+ if (cmd_type == TYPE_CMD) {
+ switch (cmd) {
+ case HPSA_INQUIRY:
+ /* are we trying to read a vital product page */
+ if (page_code != 0) {
+ c->Request.CDB[1] = 0x01;
+ c->Request.CDB[2] = page_code;
+ }
+ c->Request.CDBLen = 6;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_READ;
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = HPSA_INQUIRY;
+ c->Request.CDB[4] = size & 0xFF;
+ break;
+ case HPSA_REPORT_LOG:
+ case HPSA_REPORT_PHYS:
+ /* Talking to controller so It's a physical command
+ mode = 00 target = 0. Nothing to write.
+ */
+ c->Request.CDBLen = 12;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_READ;
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = cmd;
+ c->Request.CDB[6] = (size >> 24) & 0xFF; /* MSB */
+ c->Request.CDB[7] = (size >> 16) & 0xFF;
+ c->Request.CDB[8] = (size >> 8) & 0xFF;
+ c->Request.CDB[9] = size & 0xFF;
+ break;
+
+ case HPSA_READ_CAPACITY:
+ c->Request.CDBLen = 10;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_READ;
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = cmd;
+ break;
+ case HPSA_CACHE_FLUSH:
+ c->Request.CDBLen = 12;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_WRITE;
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = BMIC_WRITE;
+ c->Request.CDB[6] = BMIC_CACHE_FLUSH;
+ break;
+ case TEST_UNIT_READY:
+ c->Request.CDBLen = 6;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_NONE;
+ c->Request.Timeout = 0;
+ break;
+ default:
+ dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd);
+ BUG();
+ return;
+ }
+ } else if (cmd_type == TYPE_MSG) {
+ switch (cmd) {
+
+ case HPSA_DEVICE_RESET_MSG:
+ c->Request.CDBLen = 16;
+ c->Request.Type.Type = 1; /* It is a MSG not a CMD */
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_NONE;
+ c->Request.Timeout = 0; /* Don't time out */
+ c->Request.CDB[0] = 0x01; /* RESET_MSG is 0x01 */
+ c->Request.CDB[1] = 0x03; /* Reset target above */
+ /* If bytes 4-7 are zero, it means reset the */
+ /* LunID device */
+ c->Request.CDB[4] = 0x00;
+ c->Request.CDB[5] = 0x00;
+ c->Request.CDB[6] = 0x00;
+ c->Request.CDB[7] = 0x00;
+ break;
+
+ default:
+ dev_warn(&h->pdev->dev, "unknown message type %d\n",
+ cmd);
+ BUG();
+ }
+ } else {
+ dev_warn(&h->pdev->dev, "unknown command type %d\n", cmd_type);
+ BUG();
+ }
+
+ switch (c->Request.Type.Direction) {
+ case XFER_READ:
+ pci_dir = PCI_DMA_FROMDEVICE;
+ break;
+ case XFER_WRITE:
+ pci_dir = PCI_DMA_TODEVICE;
+ break;
+ case XFER_NONE:
+ pci_dir = PCI_DMA_NONE;
+ break;
+ default:
+ pci_dir = PCI_DMA_BIDIRECTIONAL;
+ }
+
+ hpsa_map_one(h->pdev, c, buff, size, pci_dir);
+
+ return;
+}
+
+/*
+ * Map (physical) PCI mem into (virtual) kernel space
+ */
+static void __iomem *remap_pci_mem(ulong base, ulong size)
+{
+ ulong page_base = ((ulong) base) & PAGE_MASK;
+ ulong page_offs = ((ulong) base) - page_base;
+ void __iomem *page_remapped = ioremap(page_base, page_offs + size);
+
+ return page_remapped ? (page_remapped + page_offs) : NULL;
+}
+
+/* Takes cmds off the submission queue and sends them to the hardware,
+ * then puts them on the queue of cmds waiting for completion.
+ */
+static void start_io(struct ctlr_info *h)
+{
+ struct CommandList *c;
+
+ while (!hlist_empty(&h->reqQ)) {
+ c = hlist_entry(h->reqQ.first, struct CommandList, list);
+ /* can't do anything if fifo is full */
+ if ((h->access.fifo_full(h))) {
+ dev_warn(&h->pdev->dev, "fifo full\n");
+ break;
+ }
+
+ /* Get the first entry from the Request Q */
+ removeQ(c);
+ h->Qdepth--;
+
+ /* Tell the controller execute command */
+ h->access.submit_command(h, c);
+
+ /* Put job onto the completed Q */
+ addQ(&h->cmpQ, c);
+ }
+}
+
+static inline unsigned long get_next_completion(struct ctlr_info *h)
+{
+ return h->access.command_completed(h);
+}
+
+static inline int interrupt_pending(struct ctlr_info *h)
+{
+ return h->access.intr_pending(h);
+}
+
+static inline long interrupt_not_for_us(struct ctlr_info *h)
+{
+ return ((h->access.intr_pending(h) == 0) ||
+ (h->interrupts_enabled == 0));
+}
+
+static inline int bad_tag(struct ctlr_info *h, __u32 tag_index,
+ __u32 raw_tag)
+{
+ if (unlikely(tag_index >= h->nr_cmds)) {
+ dev_warn(&h->pdev->dev, "bad tag 0x%08x ignored.\n", raw_tag);
+ return 1;
+ }
+ return 0;
+}
+
+static inline void finish_cmd(struct CommandList *c, __u32 raw_tag)
+{
+ removeQ(c);
+ if (likely(c->cmd_type == CMD_SCSI))
+ complete_scsi_command(c, 0, raw_tag);
+ else if (c->cmd_type == CMD_IOCTL_PEND)
+ complete(c->waiting);
+}
+
+static irqreturn_t do_hpsa_intr(int irq, void *dev_id)
+{
+ struct ctlr_info *h = dev_id;
+ struct CommandList *c;
+ unsigned long flags;
+ __u32 raw_tag, tag, tag_index;
+ struct hlist_node *tmp;
+
+ if (interrupt_not_for_us(h))
+ return IRQ_NONE;
+ spin_lock_irqsave(&h->lock, flags);
+ while (interrupt_pending(h)) {
+ while ((raw_tag = get_next_completion(h)) != FIFO_EMPTY) {
+ if (likely(HPSA_TAG_CONTAINS_INDEX(raw_tag))) {
+ tag_index = HPSA_TAG_TO_INDEX(raw_tag);
+ if (bad_tag(h, tag_index, raw_tag))
+ return IRQ_HANDLED;
+ c = h->cmd_pool + tag_index;
+ finish_cmd(c, raw_tag);
+ continue;
+ }
+ tag = HPSA_TAG_DISCARD_ERROR_BITS(raw_tag);
+ c = NULL;
+ hlist_for_each_entry(c, tmp, &h->cmpQ, list) {
+ if (c->busaddr == tag) {
+ finish_cmd(c, raw_tag);
+ break;
+ }
+ }
+ }
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+ return IRQ_HANDLED;
+}
+
+/* Send a message CDB to the firmware. */
+static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
+ unsigned char type)
+{
+ struct Command {
+ struct CommandListHeader CommandHeader;
+ struct RequestBlock Request;
+ struct ErrDescriptor ErrorDescriptor;
+ };
+ struct Command *cmd;
+ static const size_t cmd_sz = sizeof(*cmd) +
+ sizeof(cmd->ErrorDescriptor);
+ dma_addr_t paddr64;
+ uint32_t paddr32, tag;
+ void __iomem *vaddr;
+ int i, err;
+
+ vaddr = pci_ioremap_bar(pdev, 0);
+ if (vaddr == NULL)
+ return -ENOMEM;
+
+ /* The Inbound Post Queue only accepts 32-bit physical addresses for the
+ * CCISS commands, so they must be allocated from the lower 4GiB of
+ * memory.
+ */
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err) {
+ iounmap(vaddr);
+ return -ENOMEM;
+ }
+
+ cmd = pci_alloc_consistent(pdev, cmd_sz, &paddr64);
+ if (cmd == NULL) {
+ iounmap(vaddr);
+ return -ENOMEM;
+ }
+
+ /* This must fit, because of the 32-bit consistent DMA mask. Also,
+ * although there's no guarantee, we assume that the address is at
+ * least 4-byte aligned (most likely, it's page-aligned).
+ */
+ paddr32 = paddr64;
+
+ cmd->CommandHeader.ReplyQueue = 0;
+ cmd->CommandHeader.SGList = 0;
+ cmd->CommandHeader.SGTotal = 0;
+ cmd->CommandHeader.Tag.lower = paddr32;
+ cmd->CommandHeader.Tag.upper = 0;
+ memset(&cmd->CommandHeader.LUN.LunAddrBytes, 0, 8);
+
+ cmd->Request.CDBLen = 16;
+ cmd->Request.Type.Type = TYPE_MSG;
+ cmd->Request.Type.Attribute = ATTR_HEADOFQUEUE;
+ cmd->Request.Type.Direction = XFER_NONE;
+ cmd->Request.Timeout = 0; /* Don't time out */
+ cmd->Request.CDB[0] = opcode;
+ cmd->Request.CDB[1] = type;
+ memset(&cmd->Request.CDB[2], 0, 14); /* rest of the CDB is reserved */
+ cmd->ErrorDescriptor.Addr.lower = paddr32 + sizeof(*cmd);
+ cmd->ErrorDescriptor.Addr.upper = 0;
+ cmd->ErrorDescriptor.Len = sizeof(struct ErrorInfo);
+
+ writel(paddr32, vaddr + SA5_REQUEST_PORT_OFFSET);
+
+ for (i = 0; i < HPSA_MSG_SEND_RETRY_LIMIT; i++) {
+ tag = readl(vaddr + SA5_REPLY_PORT_OFFSET);
+ if (HPSA_TAG_DISCARD_ERROR_BITS(tag) == paddr32)
+ break;
+ msleep(HPSA_MSG_SEND_RETRY_INTERVAL_MSECS);
+ }
+
+ iounmap(vaddr);
+
+ /* we leak the DMA buffer here ... no choice since the controller could
+ * still complete the command.
+ */
+ if (i == HPSA_MSG_SEND_RETRY_LIMIT) {
+ dev_err(&pdev->dev, "controller message %02x:%02x timed out\n",
+ opcode, type);
+ return -ETIMEDOUT;
+ }
+
+ pci_free_consistent(pdev, cmd_sz, cmd, paddr64);
+
+ if (tag & HPSA_ERROR_BIT) {
+ dev_err(&pdev->dev, "controller message %02x:%02x failed\n",
+ opcode, type);
+ return -EIO;
+ }
+
+ dev_info(&pdev->dev, "controller message %02x:%02x succeeded\n",
+ opcode, type);
+ return 0;
+}
+
+#define hpsa_soft_reset_controller(p) hpsa_message(p, 1, 0)
+#define hpsa_noop(p) hpsa_message(p, 3, 0)
+
+static __devinit int hpsa_reset_msi(struct pci_dev *pdev)
+{
+/* the #defines are stolen from drivers/pci/msi.h. */
+#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
+#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
+
+ int pos;
+ u16 control = 0;
+
+ pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
+ if (pos) {
+ pci_read_config_word(pdev, msi_control_reg(pos), &control);
+ if (control & PCI_MSI_FLAGS_ENABLE) {
+ dev_info(&pdev->dev, "resetting MSI\n");
+ pci_write_config_word(pdev, msi_control_reg(pos),
+ control & ~PCI_MSI_FLAGS_ENABLE);
+ }
+ }
+
+ pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
+ if (pos) {
+ pci_read_config_word(pdev, msi_control_reg(pos), &control);
+ if (control & PCI_MSIX_FLAGS_ENABLE) {
+ dev_info(&pdev->dev, "resetting MSI-X\n");
+ pci_write_config_word(pdev, msi_control_reg(pos),
+ control & ~PCI_MSIX_FLAGS_ENABLE);
+ }
+ }
+
+ return 0;
+}
+
+/* This does a hard reset of the controller using PCI power management
+ * states.
+ */
+static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev)
+{
+ u16 pmcsr, saved_config_space[32];
+ int i, pos;
+
+ dev_info(&pdev->dev, "using PCI PM to reset controller\n");
+
+ /* This is very nearly the same thing as
+ *
+ * pci_save_state(pci_dev);
+ * pci_set_power_state(pci_dev, PCI_D3hot);
+ * pci_set_power_state(pci_dev, PCI_D0);
+ * pci_restore_state(pci_dev);
+ *
+ * but we can't use these nice canned kernel routines on
+ * kexec, because they also check the MSI/MSI-X state in PCI
+ * configuration space and do the wrong thing when it is
+ * set/cleared. Also, the pci_save/restore_state functions
+ * violate the ordering requirements for restoring the
+ * configuration space from the CCISS document (see the
+ * comment below). So we roll our own ....
+ */
+
+ for (i = 0; i < 32; i++)
+ pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
+
+ pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ if (pos == 0) {
+ dev_err(&pdev->dev,
+ "hpsa_reset_controller: PCI PM not supported\n");
+ return -ENODEV;
+ }
+
+ /* Quoting from the Open CISS Specification: "The Power
+ * Management Control/Status Register (CSR) controls the power
+ * state of the device. The normal operating state is D0,
+ * CSR=00h. The software off state is D3, CSR=03h. To reset
+ * the controller, place the interface device in D3 then to
+ * D0, this causes a secondary PCI reset which will reset the
+ * controller."
+ */
+
+ /* enter the D3hot power management state */
+ pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
+ pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+ pmcsr |= PCI_D3hot;
+ pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+
+ msleep(500);
+
+ /* enter the D0 power management state */
+ pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+ pmcsr |= PCI_D0;
+ pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+
+ msleep(500);
+
+ /* Restore the PCI configuration space. The Open CISS
+ * Specification says, "Restore the PCI Configuration
+ * Registers, offsets 00h through 60h. It is important to
+ * restore the command register, 16-bits at offset 04h,
+ * last. Do not restore the configuration status register,
+ * 16-bits at offset 06h." Note that the offset is 2*i.
+ */
+ for (i = 0; i < 32; i++) {
+ if (i == 2 || i == 3)
+ continue;
+ pci_write_config_word(pdev, 2*i, saved_config_space[i]);
+ }
+ wmb();
+ pci_write_config_word(pdev, 4, saved_config_space[2]);
+
+ return 0;
+}
+
+/*
+ * We cannot read the structure directly, for portability we must use
+ * the io functions.
+ * This is for debug only.
+ */
+#ifdef HPSA_DEBUG
+static void print_cfg_table(struct device *dev, struct CfgTable *tb)
+{
+ int i;
+ char temp_name[17];
+
+ dev_info(dev, "Controller Configuration information\n");
+ dev_info(dev, "------------------------------------\n");
+ for (i = 0; i < 4; i++)
+ temp_name[i] = readb(&(tb->Signature[i]));
+ temp_name[4] = '\0';
+ dev_info(dev, " Signature = %s\n", temp_name);
+ dev_info(dev, " Spec Number = %d\n", readl(&(tb->SpecValence)));
+ dev_info(dev, " Transport methods supported = 0x%x\n",
+ readl(&(tb->TransportSupport)));
+ dev_info(dev, " Transport methods active = 0x%x\n",
+ readl(&(tb->TransportActive)));
+ dev_info(dev, " Requested transport Method = 0x%x\n",
+ readl(&(tb->HostWrite.TransportRequest)));
+ dev_info(dev, " Coalesce Interrupt Delay = 0x%x\n",
+ readl(&(tb->HostWrite.CoalIntDelay)));
+ dev_info(dev, " Coalesce Interrupt Count = 0x%x\n",
+ readl(&(tb->HostWrite.CoalIntCount)));
+ dev_info(dev, " Max outstanding commands = 0x%d\n",
+ readl(&(tb->CmdsOutMax)));
+ dev_info(dev, " Bus Types = 0x%x\n", readl(&(tb->BusTypes)));
+ for (i = 0; i < 16; i++)
+ temp_name[i] = readb(&(tb->ServerName[i]));
+ temp_name[16] = '\0';
+ dev_info(dev, " Server Name = %s\n", temp_name);
+ dev_info(dev, " Heartbeat Counter = 0x%x\n\n\n",
+ readl(&(tb->HeartBeat)));
+}
+#endif /* HPSA_DEBUG */
+
+static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
+{
+ int i, offset, mem_type, bar_type;
+
+ if (pci_bar_addr == PCI_BASE_ADDRESS_0) /* looking for BAR zero? */
+ return 0;
+ offset = 0;
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ bar_type = pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE;
+ if (bar_type == PCI_BASE_ADDRESS_SPACE_IO)
+ offset += 4;
+ else {
+ mem_type = pci_resource_flags(pdev, i) &
+ PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+ switch (mem_type) {
+ case PCI_BASE_ADDRESS_MEM_TYPE_32:
+ case PCI_BASE_ADDRESS_MEM_TYPE_1M:
+ offset += 4; /* 32 bit */
+ break;
+ case PCI_BASE_ADDRESS_MEM_TYPE_64:
+ offset += 8;
+ break;
+ default: /* reserved in PCI 2.2 */
+ dev_warn(&pdev->dev,
+ "base address is invalid\n");
+ return -1;
+ break;
+ }
+ }
+ if (offset == pci_bar_addr - PCI_BASE_ADDRESS_0)
+ return i + 1;
+ }
+ return -1;
+}
+
+/* If MSI/MSI-X is supported by the kernel we will try to enable it on
+ * controllers that are capable. If not, we use IO-APIC mode.
+ */
+
+static void __devinit hpsa_interrupt_mode(struct ctlr_info *h,
+ struct pci_dev *pdev, __u32 board_id)
+{
+#ifdef CONFIG_PCI_MSI
+ int err;
+ struct msix_entry hpsa_msix_entries[4] = { {0, 0}, {0, 1},
+ {0, 2}, {0, 3}
+ };
+
+ /* Some boards advertise MSI but don't really support it */
+ if ((board_id == 0x40700E11) ||
+ (board_id == 0x40800E11) ||
+ (board_id == 0x40820E11) || (board_id == 0x40830E11))
+ goto default_int_mode;
+ if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
+ dev_info(&pdev->dev, "MSIX\n");
+ err = pci_enable_msix(pdev, hpsa_msix_entries, 4);
+ if (!err) {
+ h->intr[0] = hpsa_msix_entries[0].vector;
+ h->intr[1] = hpsa_msix_entries[1].vector;
+ h->intr[2] = hpsa_msix_entries[2].vector;
+ h->intr[3] = hpsa_msix_entries[3].vector;
+ h->msix_vector = 1;
+ return;
+ }
+ if (err > 0) {
+ dev_warn(&pdev->dev, "only %d MSI-X vectors "
+ "available\n", err);
+ goto default_int_mode;
+ } else {
+ dev_warn(&pdev->dev, "MSI-X init failed %d\n",
+ err);
+ goto default_int_mode;
+ }
+ }
+ if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
+ dev_info(&pdev->dev, "MSI\n");
+ if (!pci_enable_msi(pdev))
+ h->msi_vector = 1;
+ else
+ dev_warn(&pdev->dev, "MSI init failed\n");
+ }
+default_int_mode:
+#endif /* CONFIG_PCI_MSI */
+ /* if we get here we're going to use the default interrupt mode */
+ h->intr[SIMPLE_MODE_INT] = pdev->irq;
+ return;
+}
+
+static int hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
+{
+ ushort subsystem_vendor_id, subsystem_device_id, command;
+ __u32 board_id, scratchpad = 0;
+ __u64 cfg_offset;
+ __u32 cfg_base_addr;
+ __u64 cfg_base_addr_index;
+ int i, prod_index, err;
+
+ subsystem_vendor_id = pdev->subsystem_vendor;
+ subsystem_device_id = pdev->subsystem_device;
+ board_id = (((__u32) (subsystem_device_id << 16) & 0xffff0000) |
+ subsystem_vendor_id);
+
+ for (i = 0; i < ARRAY_SIZE(products); i++)
+ if (board_id == products[i].board_id)
+ break;
+
+ prod_index = i;
+
+ if (prod_index == ARRAY_SIZE(products)) {
+ prod_index--;
+ if (subsystem_vendor_id != PCI_VENDOR_ID_HP ||
+ !hpsa_allow_any) {
+ dev_warn(&pdev->dev, "unrecognized board ID:"
+ " 0x%08lx, ignoring.\n",
+ (unsigned long) board_id);
+ return -ENODEV;
+ }
+ }
+ /* check to see if controller has been disabled
+ * BEFORE trying to enable it
+ */
+ (void)pci_read_config_word(pdev, PCI_COMMAND, &command);
+ if (!(command & 0x02)) {
+ dev_warn(&pdev->dev, "controller appears to be disabled\n");
+ return -ENODEV;
+ }
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_warn(&pdev->dev, "unable to enable PCI device\n");
+ return err;
+ }
+
+ err = pci_request_regions(pdev, "hpsa");
+ if (err) {
+ dev_err(&pdev->dev, "cannot obtain PCI resources, aborting\n");
+ return err;
+ }
+
+ /* If the kernel supports MSI/MSI-X we will try to enable that,
+ * else we use the IO-APIC interrupt assigned to us by system ROM.
+ */
+ hpsa_interrupt_mode(h, pdev, board_id);
+
+ /* find the memory BAR */
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ if (pci_resource_flags(pdev, i) & IORESOURCE_MEM)
+ break;
+ }
+ if (i == DEVICE_COUNT_RESOURCE) {
+ dev_warn(&pdev->dev, "no memory BAR found\n");
+ err = -ENODEV;
+ goto err_out_free_res;
+ }
+
+ h->paddr = pci_resource_start(pdev, i); /* addressing mode bits
+ * already removed
+ */
+
+ h->vaddr = remap_pci_mem(h->paddr, 0x250);
+
+ /* Wait for the board to become ready. */
+ for (i = 0; i < HPSA_BOARD_READY_ITERATIONS; i++) {
+ scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
+ if (scratchpad == HPSA_FIRMWARE_READY)
+ break;
+ msleep(HPSA_BOARD_READY_POLL_INTERVAL_MSECS);
+ }
+ if (scratchpad != HPSA_FIRMWARE_READY) {
+ dev_warn(&pdev->dev, "board not ready, timed out.\n");
+ err = -ENODEV;
+ goto err_out_free_res;
+ }
+
+ /* get the address index number */
+ cfg_base_addr = readl(h->vaddr + SA5_CTCFG_OFFSET);
+ cfg_base_addr &= (__u32) 0x0000ffff;
+ cfg_base_addr_index = find_PCI_BAR_index(pdev, cfg_base_addr);
+ if (cfg_base_addr_index == -1) {
+ dev_warn(&pdev->dev, "cannot find cfg_base_addr_index\n");
+ err = -ENODEV;
+ goto err_out_free_res;
+ }
+
+ cfg_offset = readl(h->vaddr + SA5_CTMEM_OFFSET);
+ h->cfgtable = remap_pci_mem(pci_resource_start(pdev,
+ cfg_base_addr_index) + cfg_offset,
+ sizeof(h->cfgtable));
+ h->board_id = board_id;
+
+ /* Query controller for max supported commands: */
+ h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
+
+ h->product_name = products[prod_index].product_name;
+ h->access = *(products[prod_index].access);
+ /* Allow room for some ioctls */
+ h->nr_cmds = h->max_commands - 4;
+
+ if ((readb(&h->cfgtable->Signature[0]) != 'C') ||
+ (readb(&h->cfgtable->Signature[1]) != 'I') ||
+ (readb(&h->cfgtable->Signature[2]) != 'S') ||
+ (readb(&h->cfgtable->Signature[3]) != 'S')) {
+ dev_warn(&pdev->dev, "not a valid CISS config table\n");
+ err = -ENODEV;
+ goto err_out_free_res;
+ }
+#ifdef CONFIG_X86
+ {
+ /* Need to enable prefetch in the SCSI core for 6400 in x86 */
+ __u32 prefetch;
+ prefetch = readl(&(h->cfgtable->SCSI_Prefetch));
+ prefetch |= 0x100;
+ writel(prefetch, &(h->cfgtable->SCSI_Prefetch));
+ }
+#endif
+
+ /* Disabling DMA prefetch for the P600
+ * An ASIC bug may result in a prefetch beyond
+ * physical memory.
+ */
+ if (board_id == 0x3225103C) {
+ __u32 dma_prefetch;
+ dma_prefetch = readl(h->vaddr + I2O_DMA1_CFG);
+ dma_prefetch |= 0x8000;
+ writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
+ }
+
+ h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
+ /* Update the field, and then ring the doorbell */
+ writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
+ writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+
+ /* under certain very rare conditions, this can take awhile.
+ * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
+ * as we enter this code.)
+ */
+ for (i = 0; i < MAX_CONFIG_WAIT; i++) {
+ if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
+ break;
+ /* delay and try again */
+ msleep(10);
+ }
+
+#ifdef HPSA_DEBUG
+ print_cfg_table(&pdev->dev, h->cfgtable);
+#endif /* HPSA_DEBUG */
+
+ if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
+ dev_warn(&pdev->dev, "unable to get board into simple mode\n");
+ err = -ENODEV;
+ goto err_out_free_res;
+ }
+ return 0;
+
+err_out_free_res:
+ /*
+ * Deliberately omit pci_disable_device(): it does something nasty to
+ * Smart Array controllers that pci_enable_device does not undo
+ */
+ pci_release_regions(pdev);
+ return err;
+}
+
+static int __devinit hpsa_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int i;
+ int dac;
+ struct ctlr_info *h;
+
+ if (number_of_controllers == 0)
+ printk(KERN_INFO DRIVER_NAME "\n");
+ if (reset_devices) {
+ /* Reset the controller with a PCI power-cycle */
+ if (hpsa_hard_reset_controller(pdev) || hpsa_reset_msi(pdev))
+ return -ENODEV;
+
+ /* Some devices (notably the HP Smart Array 5i Controller)
+ need a little pause here */
+ msleep(HPSA_POST_RESET_PAUSE_MSECS);
+
+ /* Now try to get the controller to respond to a no-op */
+ for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
+ if (hpsa_noop(pdev) == 0)
+ break;
+ else
+ dev_warn(&pdev->dev, "no-op failed%s\n",
+ (i < 11 ? "; re-trying" : ""));
+ }
+ }
+
+ BUILD_BUG_ON(sizeof(struct CommandList) % 8);
+ h = kzalloc(sizeof(*h), GFP_KERNEL);
+ if (!h)
+ return -1;
+
+ h->busy_initializing = 1;
+ INIT_HLIST_HEAD(&h->cmpQ);
+ INIT_HLIST_HEAD(&h->reqQ);
+ mutex_init(&h->busy_shutting_down);
+ init_completion(&h->scan_wait);
+ if (hpsa_pci_init(h, pdev) != 0)
+ goto clean1;
+
+ sprintf(h->devname, "hpsa%d", number_of_controllers);
+ h->ctlr = number_of_controllers;
+ number_of_controllers++;
+ h->pdev = pdev;
+
+ /* configure PCI DMA stuff */
+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
+ dac = 1;
+ else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
+ dac = 0;
+ else {
+ dev_err(&pdev->dev, "no suitable DMA available\n");
+ goto clean1;
+ }
+
+ /* make sure the board interrupts are off */
+ h->access.set_intr_mask(h, HPSA_INTR_OFF);
+ if (request_irq(h->intr[SIMPLE_MODE_INT], do_hpsa_intr,
+ IRQF_DISABLED | IRQF_SHARED, h->devname, h)) {
+ dev_err(&pdev->dev, "unable to get irq %d for %s\n",
+ h->intr[SIMPLE_MODE_INT], h->devname);
+ goto clean2;
+ }
+
+ dev_info(&pdev->dev, "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n",
+ h->devname, pdev->device, pci_name(pdev),
+ h->intr[SIMPLE_MODE_INT], dac ? "" : " not");
+
+ h->cmd_pool_bits =
+ kmalloc(((h->nr_cmds + BITS_PER_LONG -
+ 1) / BITS_PER_LONG) * sizeof(unsigned long), GFP_KERNEL);
+ h->cmd_pool = pci_alloc_consistent(h->pdev,
+ h->nr_cmds * sizeof(*h->cmd_pool),
+ &(h->cmd_pool_dhandle));
+ h->errinfo_pool = pci_alloc_consistent(h->pdev,
+ h->nr_cmds * sizeof(*h->errinfo_pool),
+ &(h->errinfo_pool_dhandle));
+ if ((h->cmd_pool_bits == NULL)
+ || (h->cmd_pool == NULL)
+ || (h->errinfo_pool == NULL)) {
+ dev_err(&pdev->dev, "out of memory");
+ goto clean4;
+ }
+ spin_lock_init(&h->lock);
+
+ pci_set_drvdata(pdev, h);
+ memset(h->cmd_pool_bits, 0,
+ ((h->nr_cmds + BITS_PER_LONG -
+ 1) / BITS_PER_LONG) * sizeof(unsigned long));
+
+ hpsa_scsi_setup(h);
+
+ /* Turn the interrupts on so we can service requests */
+ h->access.set_intr_mask(h, HPSA_INTR_ON);
+
+ hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */
+ h->busy_initializing = 0;
+ return 1;
+
+clean4:
+ kfree(h->cmd_pool_bits);
+ if (h->cmd_pool)
+ pci_free_consistent(h->pdev,
+ h->nr_cmds * sizeof(struct CommandList),
+ h->cmd_pool, h->cmd_pool_dhandle);
+ if (h->errinfo_pool)
+ pci_free_consistent(h->pdev,
+ h->nr_cmds * sizeof(struct ErrorInfo),
+ h->errinfo_pool,
+ h->errinfo_pool_dhandle);
+ free_irq(h->intr[SIMPLE_MODE_INT], h);
+clean2:
+clean1:
+ h->busy_initializing = 0;
+ kfree(h);
+ return -1;
+}
+
+static void hpsa_flush_cache(struct ctlr_info *h)
+{
+ char *flush_buf;
+ struct CommandList *c;
+
+ flush_buf = kzalloc(4, GFP_KERNEL);
+ if (!flush_buf)
+ return;
+
+ c = cmd_special_alloc(h);
+ if (!c) {
+ dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ goto out_of_memory;
+ }
+ fill_cmd(c, HPSA_CACHE_FLUSH, h, flush_buf, 4, 0,
+ RAID_CTLR_LUNID, TYPE_CMD);
+ hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_TODEVICE);
+ if (c->err_info->CommandStatus != 0)
+ dev_warn(&h->pdev->dev,
+ "error flushing cache on controller\n");
+ cmd_special_free(h, c);
+out_of_memory:
+ kfree(flush_buf);
+}
+
+static void hpsa_shutdown(struct pci_dev *pdev)
+{
+ struct ctlr_info *h;
+
+ h = pci_get_drvdata(pdev);
+ /* Turn board interrupts off and send the flush cache command
+ * sendcmd will turn off interrupt, and send the flush...
+ * To write all data in the battery backed cache to disks
+ */
+ hpsa_flush_cache(h);
+ h->access.set_intr_mask(h, HPSA_INTR_OFF);
+ free_irq(h->intr[2], h);
+#ifdef CONFIG_PCI_MSI
+ if (h->msix_vector)
+ pci_disable_msix(h->pdev);
+ else if (h->msi_vector)
+ pci_disable_msi(h->pdev);
+#endif /* CONFIG_PCI_MSI */
+}
+
+static void __devexit hpsa_remove_one(struct pci_dev *pdev)
+{
+ struct ctlr_info *h;
+
+ if (pci_get_drvdata(pdev) == NULL) {
+ dev_err(&pdev->dev, "unable to remove device \n");
+ return;
+ }
+ h = pci_get_drvdata(pdev);
+ mutex_lock(&h->busy_shutting_down);
+ remove_from_scan_list(h);
+ hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */
+ hpsa_shutdown(pdev);
+ iounmap(h->vaddr);
+ pci_free_consistent(h->pdev,
+ h->nr_cmds * sizeof(struct CommandList),
+ h->cmd_pool, h->cmd_pool_dhandle);
+ pci_free_consistent(h->pdev,
+ h->nr_cmds * sizeof(struct ErrorInfo),
+ h->errinfo_pool, h->errinfo_pool_dhandle);
+ kfree(h->cmd_pool_bits);
+ /*
+ * Deliberately omit pci_disable_device(): it does something nasty to
+ * Smart Array controllers that pci_enable_device does not undo
+ */
+ pci_release_regions(pdev);
+ pci_set_drvdata(pdev, NULL);
+ mutex_unlock(&h->busy_shutting_down);
+ kfree(h);
+}
+
+static int hpsa_suspend(__attribute__((unused)) struct pci_dev *pdev,
+ __attribute__((unused)) pm_message_t state)
+{
+ return -ENOSYS;
+}
+
+static int hpsa_resume(__attribute__((unused)) struct pci_dev *pdev)
+{
+ return -ENOSYS;
+}
+
+static struct pci_driver hpsa_pci_driver = {
+ .name = "hpsa",
+ .probe = hpsa_init_one,
+ .remove = __devexit_p(hpsa_remove_one),
+ .id_table = hpsa_pci_device_id, /* id_table */
+ .shutdown = hpsa_shutdown,
+ .suspend = hpsa_suspend,
+ .resume = hpsa_resume,
+};
+
+/*
+ * This is it. Register the PCI driver information for the cards we control
+ * the OS will call our registered routines when it finds one of our cards.
+ */
+static int __init hpsa_init(void)
+{
+ int err;
+ /* Start the scan thread */
+ hpsa_scan_thread = kthread_run(hpsa_scan_func, NULL, "hpsa_scan");
+ if (IS_ERR(hpsa_scan_thread)) {
+ err = PTR_ERR(hpsa_scan_thread);
+ return -ENODEV;
+ }
+ err = pci_register_driver(&hpsa_pci_driver);
+ if (err)
+ kthread_stop(hpsa_scan_thread);
+ return err;
+}
+
+static void __exit hpsa_cleanup(void)
+{
+ pci_unregister_driver(&hpsa_pci_driver);
+ kthread_stop(hpsa_scan_thread);
+}
+
+module_init(hpsa_init);
+module_exit(hpsa_cleanup);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
new file mode 100644
index 00000000000..6bd1949144b
--- /dev/null
+++ b/drivers/scsi/hpsa.h
@@ -0,0 +1,273 @@
+/*
+ * Disk Array driver for HP Smart Array SAS controllers
+ * Copyright 2000, 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT. 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.
+ *
+ * Questions/Comments/Bugfixes to iss_storagedev@hp.com
+ *
+ */
+#ifndef HPSA_H
+#define HPSA_H
+
+#include <scsi/scsicam.h>
+
+#define IO_OK 0
+#define IO_ERROR 1
+
+struct ctlr_info;
+
+struct access_method {
+ void (*submit_command)(struct ctlr_info *h,
+ struct CommandList *c);
+ void (*set_intr_mask)(struct ctlr_info *h, unsigned long val);
+ unsigned long (*fifo_full)(struct ctlr_info *h);
+ unsigned long (*intr_pending)(struct ctlr_info *h);
+ unsigned long (*command_completed)(struct ctlr_info *h);
+};
+
+struct hpsa_scsi_dev_t {
+ int devtype;
+ int bus, target, lun; /* as presented to the OS */
+ unsigned char scsi3addr[8]; /* as presented to the HW */
+#define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0"
+ unsigned char device_id[16]; /* from inquiry pg. 0x83 */
+ unsigned char vendor[8]; /* bytes 8-15 of inquiry data */
+ unsigned char model[16]; /* bytes 16-31 of inquiry data */
+ unsigned char revision[4]; /* bytes 32-35 of inquiry data */
+ unsigned char raid_level; /* from inquiry page 0xC1 */
+};
+
+struct ctlr_info {
+ int ctlr;
+ char devname[8];
+ char *product_name;
+ char firm_ver[4]; /* Firmware version */
+ struct pci_dev *pdev;
+ __u32 board_id;
+ void __iomem *vaddr;
+ unsigned long paddr;
+ int nr_cmds; /* Number of commands allowed on this controller */
+ struct CfgTable __iomem *cfgtable;
+ int interrupts_enabled;
+ int major;
+ int max_commands;
+ int commands_outstanding;
+ int max_outstanding; /* Debug */
+ int usage_count; /* number of opens all all minor devices */
+# define DOORBELL_INT 0
+# define PERF_MODE_INT 1
+# define SIMPLE_MODE_INT 2
+# define MEMQ_MODE_INT 3
+ unsigned int intr[4];
+ unsigned int msix_vector;
+ unsigned int msi_vector;
+ struct access_method access;
+
+ /* queue and queue Info */
+ struct hlist_head reqQ;
+ struct hlist_head cmpQ;
+ unsigned int Qdepth;
+ unsigned int maxQsinceinit;
+ unsigned int maxSG;
+ spinlock_t lock;
+
+ /* pointers to command and error info pool */
+ struct CommandList *cmd_pool;
+ dma_addr_t cmd_pool_dhandle;
+ struct ErrorInfo *errinfo_pool;
+ dma_addr_t errinfo_pool_dhandle;
+ unsigned long *cmd_pool_bits;
+ int nr_allocs;
+ int nr_frees;
+ int busy_initializing;
+ int busy_scanning;
+ struct mutex busy_shutting_down;
+ struct list_head scan_list;
+ struct completion scan_wait;
+
+ struct Scsi_Host *scsi_host;
+ spinlock_t devlock; /* to protect hba[ctlr]->dev[]; */
+ int ndevices; /* number of used elements in .dev[] array. */
+#define HPSA_MAX_SCSI_DEVS_PER_HBA 256
+ struct hpsa_scsi_dev_t *dev[HPSA_MAX_SCSI_DEVS_PER_HBA];
+};
+#define HPSA_ABORT_MSG 0
+#define HPSA_DEVICE_RESET_MSG 1
+#define HPSA_BUS_RESET_MSG 2
+#define HPSA_HOST_RESET_MSG 3
+#define HPSA_MSG_SEND_RETRY_LIMIT 10
+#define HPSA_MSG_SEND_RETRY_INTERVAL_MSECS 1000
+
+/* Maximum time in seconds driver will wait for command completions
+ * when polling before giving up.
+ */
+#define HPSA_MAX_POLL_TIME_SECS (20)
+
+/* During SCSI error recovery, HPSA_TUR_RETRY_LIMIT defines
+ * how many times to retry TEST UNIT READY on a device
+ * while waiting for it to become ready before giving up.
+ * HPSA_MAX_WAIT_INTERVAL_SECS is the max wait interval
+ * between sending TURs while waiting for a device
+ * to become ready.
+ */
+#define HPSA_TUR_RETRY_LIMIT (20)
+#define HPSA_MAX_WAIT_INTERVAL_SECS (30)
+
+/* HPSA_BOARD_READY_WAIT_SECS is how long to wait for a board
+ * to become ready, in seconds, before giving up on it.
+ * HPSA_BOARD_READY_POLL_INTERVAL_MSECS * is how long to wait
+ * between polling the board to see if it is ready, in
+ * milliseconds. HPSA_BOARD_READY_POLL_INTERVAL and
+ * HPSA_BOARD_READY_ITERATIONS are derived from those.
+ */
+#define HPSA_BOARD_READY_WAIT_SECS (120)
+#define HPSA_BOARD_READY_POLL_INTERVAL_MSECS (100)
+#define HPSA_BOARD_READY_POLL_INTERVAL \
+ ((HPSA_BOARD_READY_POLL_INTERVAL_MSECS * HZ) / 1000)
+#define HPSA_BOARD_READY_ITERATIONS \
+ ((HPSA_BOARD_READY_WAIT_SECS * 1000) / \
+ HPSA_BOARD_READY_POLL_INTERVAL_MSECS)
+#define HPSA_POST_RESET_PAUSE_MSECS (3000)
+#define HPSA_POST_RESET_NOOP_RETRIES (12)
+
+/* Defining the diffent access_menthods */
+/*
+ * Memory mapped FIFO interface (SMART 53xx cards)
+ */
+#define SA5_DOORBELL 0x20
+#define SA5_REQUEST_PORT_OFFSET 0x40
+#define SA5_REPLY_INTR_MASK_OFFSET 0x34
+#define SA5_REPLY_PORT_OFFSET 0x44
+#define SA5_INTR_STATUS 0x30
+#define SA5_SCRATCHPAD_OFFSET 0xB0
+
+#define SA5_CTCFG_OFFSET 0xB4
+#define SA5_CTMEM_OFFSET 0xB8
+
+#define SA5_INTR_OFF 0x08
+#define SA5B_INTR_OFF 0x04
+#define SA5_INTR_PENDING 0x08
+#define SA5B_INTR_PENDING 0x04
+#define FIFO_EMPTY 0xffffffff
+#define HPSA_FIRMWARE_READY 0xffff0000 /* value in scratchpad register */
+
+#define HPSA_ERROR_BIT 0x02
+#define HPSA_TAG_CONTAINS_INDEX(tag) ((tag) & 0x04)
+#define HPSA_TAG_TO_INDEX(tag) ((tag) >> 3)
+#define HPSA_TAG_DISCARD_ERROR_BITS(tag) ((tag) & ~3)
+
+#define HPSA_INTR_ON 1
+#define HPSA_INTR_OFF 0
+/*
+ Send the command to the hardware
+*/
+static void SA5_submit_command(struct ctlr_info *h,
+ struct CommandList *c)
+{
+#ifdef HPSA_DEBUG
+ printk(KERN_WARNING "hpsa: Sending %x - down to controller\n",
+ c->busaddr);
+#endif /* HPSA_DEBUG */
+ writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
+ h->commands_outstanding++;
+ if (h->commands_outstanding > h->max_outstanding)
+ h->max_outstanding = h->commands_outstanding;
+}
+
+/*
+ * This card is the opposite of the other cards.
+ * 0 turns interrupts on...
+ * 0x08 turns them off...
+ */
+static void SA5_intr_mask(struct ctlr_info *h, unsigned long val)
+{
+ if (val) { /* Turn interrupts on */
+ h->interrupts_enabled = 1;
+ writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+ } else { /* Turn them off */
+ h->interrupts_enabled = 0;
+ writel(SA5_INTR_OFF,
+ h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+ }
+}
+/*
+ * Returns true if fifo is full.
+ *
+ */
+static unsigned long SA5_fifo_full(struct ctlr_info *h)
+{
+ if (h->commands_outstanding >= h->max_commands)
+ return 1;
+ else
+ return 0;
+
+}
+/*
+ * returns value read from hardware.
+ * returns FIFO_EMPTY if there is nothing to read
+ */
+static unsigned long SA5_completed(struct ctlr_info *h)
+{
+ unsigned long register_value
+ = readl(h->vaddr + SA5_REPLY_PORT_OFFSET);
+
+ if (register_value != FIFO_EMPTY)
+ h->commands_outstanding--;
+
+#ifdef HPSA_DEBUG
+ if (register_value != FIFO_EMPTY)
+ printk(KERN_INFO "hpsa: Read %lx back from board\n",
+ register_value);
+ else
+ printk(KERN_INFO "hpsa: FIFO Empty read\n");
+#endif
+
+ return register_value;
+}
+/*
+ * Returns true if an interrupt is pending..
+ */
+static unsigned long SA5_intr_pending(struct ctlr_info *h)
+{
+ unsigned long register_value =
+ readl(h->vaddr + SA5_INTR_STATUS);
+#ifdef HPSA_DEBUG
+ printk(KERN_INFO "hpsa: intr_pending %lx\n", register_value);
+#endif /* HPSA_DEBUG */
+ if (register_value & SA5_INTR_PENDING)
+ return 1;
+ return 0 ;
+}
+
+
+static struct access_method SA5_access = {
+ SA5_submit_command,
+ SA5_intr_mask,
+ SA5_fifo_full,
+ SA5_intr_pending,
+ SA5_completed,
+};
+
+struct board_type {
+ __u32 board_id;
+ char *product_name;
+ struct access_method *access;
+};
+
+
+/* end of old hpsa_scsi.h file */
+
+#endif /* HPSA_H */
+
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
new file mode 100644
index 00000000000..12d71387ed9
--- /dev/null
+++ b/drivers/scsi/hpsa_cmd.h
@@ -0,0 +1,326 @@
+/*
+ * Disk Array driver for HP Smart Array SAS controllers
+ * Copyright 2000, 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT. 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.
+ *
+ * Questions/Comments/Bugfixes to iss_storagedev@hp.com
+ *
+ */
+#ifndef HPSA_CMD_H
+#define HPSA_CMD_H
+
+/* general boundary defintions */
+#define SENSEINFOBYTES 32 /* may vary between hbas */
+#define MAXSGENTRIES 31
+#define MAXREPLYQS 256
+
+/* Command Status value */
+#define CMD_SUCCESS 0x0000
+#define CMD_TARGET_STATUS 0x0001
+#define CMD_DATA_UNDERRUN 0x0002
+#define CMD_DATA_OVERRUN 0x0003
+#define CMD_INVALID 0x0004
+#define CMD_PROTOCOL_ERR 0x0005
+#define CMD_HARDWARE_ERR 0x0006
+#define CMD_CONNECTION_LOST 0x0007
+#define CMD_ABORTED 0x0008
+#define CMD_ABORT_FAILED 0x0009
+#define CMD_UNSOLICITED_ABORT 0x000A
+#define CMD_TIMEOUT 0x000B
+#define CMD_UNABORTABLE 0x000C
+
+/* Unit Attentions ASC's as defined for the MSA2012sa */
+#define POWER_OR_RESET 0x29
+#define STATE_CHANGED 0x2a
+#define UNIT_ATTENTION_CLEARED 0x2f
+#define LUN_FAILED 0x3e
+#define REPORT_LUNS_CHANGED 0x3f
+
+/* Unit Attentions ASCQ's as defined for the MSA2012sa */
+
+ /* These ASCQ's defined for ASC = POWER_OR_RESET */
+#define POWER_ON_RESET 0x00
+#define POWER_ON_REBOOT 0x01
+#define SCSI_BUS_RESET 0x02
+#define MSA_TARGET_RESET 0x03
+#define CONTROLLER_FAILOVER 0x04
+#define TRANSCEIVER_SE 0x05
+#define TRANSCEIVER_LVD 0x06
+
+ /* These ASCQ's defined for ASC = STATE_CHANGED */
+#define RESERVATION_PREEMPTED 0x03
+#define ASYM_ACCESS_CHANGED 0x06
+#define LUN_CAPACITY_CHANGED 0x09
+
+/* transfer direction */
+#define XFER_NONE 0x00
+#define XFER_WRITE 0x01
+#define XFER_READ 0x02
+#define XFER_RSVD 0x03
+
+/* task attribute */
+#define ATTR_UNTAGGED 0x00
+#define ATTR_SIMPLE 0x04
+#define ATTR_HEADOFQUEUE 0x05
+#define ATTR_ORDERED 0x06
+#define ATTR_ACA 0x07
+
+/* cdb type */
+#define TYPE_CMD 0x00
+#define TYPE_MSG 0x01
+
+/* config space register offsets */
+#define CFG_VENDORID 0x00
+#define CFG_DEVICEID 0x02
+#define CFG_I2OBAR 0x10
+#define CFG_MEM1BAR 0x14
+
+/* i2o space register offsets */
+#define I2O_IBDB_SET 0x20
+#define I2O_IBDB_CLEAR 0x70
+#define I2O_INT_STATUS 0x30
+#define I2O_INT_MASK 0x34
+#define I2O_IBPOST_Q 0x40
+#define I2O_OBPOST_Q 0x44
+#define I2O_DMA1_CFG 0x214
+
+/* Configuration Table */
+#define CFGTBL_ChangeReq 0x00000001l
+#define CFGTBL_AccCmds 0x00000001l
+
+#define CFGTBL_Trans_Simple 0x00000002l
+
+#define CFGTBL_BusType_Ultra2 0x00000001l
+#define CFGTBL_BusType_Ultra3 0x00000002l
+#define CFGTBL_BusType_Fibre1G 0x00000100l
+#define CFGTBL_BusType_Fibre2G 0x00000200l
+struct vals32 {
+ __u32 lower;
+ __u32 upper;
+};
+
+union u64bit {
+ struct vals32 val32;
+ __u64 val;
+};
+
+/* FIXME this is a per controller value (barf!) */
+#define HPSA_MAX_TARGETS_PER_CTLR 16
+#define HPSA_MAX_LUN 256
+#define HPSA_MAX_PHYS_LUN 1024
+
+/* SCSI-3 Commands */
+#pragma pack(1)
+
+#define HPSA_INQUIRY 0x12
+struct InquiryData {
+ __u8 data_byte[36];
+};
+
+#define HPSA_REPORT_LOG 0xc2 /* Report Logical LUNs */
+#define HPSA_REPORT_PHYS 0xc3 /* Report Physical LUNs */
+struct ReportLUNdata {
+ __u8 LUNListLength[4];
+ __u32 reserved;
+ __u8 LUN[HPSA_MAX_LUN][8];
+};
+
+struct ReportExtendedLUNdata {
+ __u8 LUNListLength[4];
+ __u8 extended_response_flag;
+ __u8 reserved[3];
+ __u8 LUN[HPSA_MAX_LUN][24];
+};
+
+struct SenseSubsystem_info {
+ __u8 reserved[36];
+ __u8 portname[8];
+ __u8 reserved1[1108];
+};
+
+#define HPSA_READ_CAPACITY 0x25 /* Read Capacity */
+struct ReadCapdata {
+ __u8 total_size[4]; /* Total size in blocks */
+ __u8 block_size[4]; /* Size of blocks in bytes */
+};
+
+#if 0
+/* 12 byte commands not implemented in firmware yet. */
+#define HPSA_READ 0xa8
+#define HPSA_WRITE 0xaa
+#endif
+
+#define HPSA_READ 0x28 /* Read(10) */
+#define HPSA_WRITE 0x2a /* Write(10) */
+
+/* BMIC commands */
+#define BMIC_READ 0x26
+#define BMIC_WRITE 0x27
+#define BMIC_CACHE_FLUSH 0xc2
+#define HPSA_CACHE_FLUSH 0x01 /* C2 was already being used by HPSA */
+
+/* Command List Structure */
+union SCSI3Addr {
+ struct {
+ __u8 Dev;
+ __u8 Bus:6;
+ __u8 Mode:2; /* b00 */
+ } PeripDev;
+ struct {
+ __u8 DevLSB;
+ __u8 DevMSB:6;
+ __u8 Mode:2; /* b01 */
+ } LogDev;
+ struct {
+ __u8 Dev:5;
+ __u8 Bus:3;
+ __u8 Targ:6;
+ __u8 Mode:2; /* b10 */
+ } LogUnit;
+};
+
+struct PhysDevAddr {
+ __u32 TargetId:24;
+ __u32 Bus:6;
+ __u32 Mode:2;
+ /* 2 level target device addr */
+ union SCSI3Addr Target[2];
+};
+
+struct LogDevAddr {
+ __u32 VolId:30;
+ __u32 Mode:2;
+ __u8 reserved[4];
+};
+
+union LUNAddr {
+ __u8 LunAddrBytes[8];
+ union SCSI3Addr SCSI3Lun[4];
+ struct PhysDevAddr PhysDev;
+ struct LogDevAddr LogDev;
+};
+
+struct CommandListHeader {
+ __u8 ReplyQueue;
+ __u8 SGList;
+ __u16 SGTotal;
+ struct vals32 Tag;
+ union LUNAddr LUN;
+};
+
+struct RequestBlock {
+ __u8 CDBLen;
+ struct {
+ __u8 Type:3;
+ __u8 Attribute:3;
+ __u8 Direction:2;
+ } Type;
+ __u16 Timeout;
+ __u8 CDB[16];
+};
+
+struct ErrDescriptor {
+ struct vals32 Addr;
+ __u32 Len;
+};
+
+struct SGDescriptor {
+ struct vals32 Addr;
+ __u32 Len;
+ __u32 Ext;
+};
+
+union MoreErrInfo {
+ struct {
+ __u8 Reserved[3];
+ __u8 Type;
+ __u32 ErrorInfo;
+ } Common_Info;
+ struct {
+ __u8 Reserved[2];
+ __u8 offense_size; /* size of offending entry */
+ __u8 offense_num; /* byte # of offense 0-base */
+ __u32 offense_value;
+ } Invalid_Cmd;
+};
+struct ErrorInfo {
+ __u8 ScsiStatus;
+ __u8 SenseLen;
+ __u16 CommandStatus;
+ __u32 ResidualCnt;
+ union MoreErrInfo MoreErrInfo;
+ __u8 SenseInfo[SENSEINFOBYTES];
+};
+/* Command types */
+#define CMD_IOCTL_PEND 0x01
+#define CMD_SCSI 0x03
+
+struct ctlr_info; /* defined in hpsa.h */
+/* The size of this structure needs to be divisible by 8
+ * od on all architectures, because the controller uses 2
+ * lower bits of the address, and the driver uses 1 lower
+ * bit (3 bits total.)
+ */
+struct CommandList {
+ struct CommandListHeader Header;
+ struct RequestBlock Request;
+ struct ErrDescriptor ErrDesc;
+ struct SGDescriptor SG[MAXSGENTRIES];
+ /* information associated with the command */
+ __u32 busaddr; /* physical addr of this record */
+ struct ErrorInfo *err_info; /* pointer to the allocated mem */
+ struct ctlr_info *h;
+ int cmd_type;
+ long cmdindex;
+ struct hlist_node list;
+ struct CommandList *prev;
+ struct CommandList *next;
+ struct request *rq;
+ struct completion *waiting;
+ int retry_count;
+ void *scsi_cmd;
+};
+
+/* Configuration Table Structure */
+struct HostWrite {
+ __u32 TransportRequest;
+ __u32 Reserved;
+ __u32 CoalIntDelay;
+ __u32 CoalIntCount;
+};
+
+struct CfgTable {
+ __u8 Signature[4];
+ __u32 SpecValence;
+ __u32 TransportSupport;
+ __u32 TransportActive;
+ struct HostWrite HostWrite;
+ __u32 CmdsOutMax;
+ __u32 BusTypes;
+ __u32 Reserved;
+ __u8 ServerName[16];
+ __u32 HeartBeat;
+ __u32 SCSI_Prefetch;
+};
+
+struct hpsa_pci_info {
+ unsigned char bus;
+ unsigned char dev_fn;
+ unsigned short domain;
+ __u32 board_id;
+};
+
+#pragma pack()
+#endif /* HPSA_CMD_H */
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 8643f508936..9e52d16c7c3 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -6521,6 +6521,7 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
int rc;
ENTER;
+ ioa_cfg->pdev->state_saved = true;
rc = pci_restore_state(ioa_cfg->pdev);
if (rc != PCIBIOS_SUCCESSFUL) {
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index c4b58d042f6..881d5dfe8c7 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -68,18 +68,20 @@ struct kmem_cache *scsi_pkt_cachep;
/**
* struct fc_fcp_internal - FCP layer internal data
- * @scsi_pkt_pool: Memory pool to draw FCP packets from
+ * @scsi_pkt_pool: Memory pool to draw FCP packets from
+ * @scsi_queue_lock: Protects the scsi_pkt_queue
* @scsi_pkt_queue: Current FCP packets
* @last_can_queue_ramp_down_time: ramp down time
* @last_can_queue_ramp_up_time: ramp up time
* @max_can_queue: max can_queue size
*/
struct fc_fcp_internal {
- mempool_t *scsi_pkt_pool;
- struct list_head scsi_pkt_queue;
- unsigned long last_can_queue_ramp_down_time;
- unsigned long last_can_queue_ramp_up_time;
- int max_can_queue;
+ mempool_t *scsi_pkt_pool;
+ spinlock_t scsi_queue_lock;
+ struct list_head scsi_pkt_queue;
+ unsigned long last_can_queue_ramp_down_time;
+ unsigned long last_can_queue_ramp_up_time;
+ int max_can_queue;
};
#define fc_get_scsi_internal(x) ((struct fc_fcp_internal *)(x)->scsi_priv)
@@ -410,12 +412,14 @@ static inline struct fc_frame *fc_fcp_frame_alloc(struct fc_lport *lport,
unsigned long flags;
fp = fc_frame_alloc(lport, len);
- if (!fp) {
- spin_lock_irqsave(lport->host->host_lock, flags);
- fc_fcp_can_queue_ramp_down(lport);
- spin_unlock_irqrestore(lport->host->host_lock, flags);
- }
- return fp;
+ if (likely(fp))
+ return fp;
+
+ /* error case */
+ spin_lock_irqsave(lport->host->host_lock, flags);
+ fc_fcp_can_queue_ramp_down(lport);
+ spin_unlock_irqrestore(lport->host->host_lock, flags);
+ return NULL;
}
/**
@@ -990,7 +994,7 @@ static void fc_fcp_cleanup_each_cmd(struct fc_lport *lport, unsigned int id,
struct scsi_cmnd *sc_cmd;
unsigned long flags;
- spin_lock_irqsave(lport->host->host_lock, flags);
+ spin_lock_irqsave(&si->scsi_queue_lock, flags);
restart:
list_for_each_entry(fsp, &si->scsi_pkt_queue, list) {
sc_cmd = fsp->cmd;
@@ -1001,7 +1005,7 @@ restart:
continue;
fc_fcp_pkt_hold(fsp);
- spin_unlock_irqrestore(lport->host->host_lock, flags);
+ spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
if (!fc_fcp_lock_pkt(fsp)) {
fc_fcp_cleanup_cmd(fsp, error);
@@ -1010,14 +1014,14 @@ restart:
}
fc_fcp_pkt_release(fsp);
- spin_lock_irqsave(lport->host->host_lock, flags);
+ spin_lock_irqsave(&si->scsi_queue_lock, flags);
/*
* while we dropped the lock multiple pkts could
* have been released, so we have to start over.
*/
goto restart;
}
- spin_unlock_irqrestore(lport->host->host_lock, flags);
+ spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
}
/**
@@ -1035,11 +1039,12 @@ static void fc_fcp_abort_io(struct fc_lport *lport)
* @fsp: The FCP packet to send
*
* Return: Zero for success and -1 for failure
- * Locks: Called with the host lock and irqs disabled.
+ * Locks: Called without locks held
*/
static int fc_fcp_pkt_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp)
{
struct fc_fcp_internal *si = fc_get_scsi_internal(lport);
+ unsigned long flags;
int rc;
fsp->cmd->SCp.ptr = (char *)fsp;
@@ -1049,13 +1054,16 @@ static int fc_fcp_pkt_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp)
int_to_scsilun(fsp->cmd->device->lun,
(struct scsi_lun *)fsp->cdb_cmd.fc_lun);
memcpy(fsp->cdb_cmd.fc_cdb, fsp->cmd->cmnd, fsp->cmd->cmd_len);
- list_add_tail(&fsp->list, &si->scsi_pkt_queue);
- spin_unlock_irq(lport->host->host_lock);
+ spin_lock_irqsave(&si->scsi_queue_lock, flags);
+ list_add_tail(&fsp->list, &si->scsi_pkt_queue);
+ spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
rc = lport->tt.fcp_cmd_send(lport, fsp, fc_fcp_recv);
- spin_lock_irq(lport->host->host_lock);
- if (rc)
+ if (unlikely(rc)) {
+ spin_lock_irqsave(&si->scsi_queue_lock, flags);
list_del(&fsp->list);
+ spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
+ }
return rc;
}
@@ -1752,6 +1760,7 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
struct fcoe_dev_stats *stats;
lport = shost_priv(sc_cmd->device->host);
+ spin_unlock_irq(lport->host->host_lock);
rval = fc_remote_port_chkready(rport);
if (rval) {
@@ -1834,6 +1843,7 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
rc = SCSI_MLQUEUE_HOST_BUSY;
}
out:
+ spin_lock_irq(lport->host->host_lock);
return rc;
}
EXPORT_SYMBOL(fc_queuecommand);
@@ -1864,11 +1874,8 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
lport = fsp->lp;
si = fc_get_scsi_internal(lport);
- spin_lock_irqsave(lport->host->host_lock, flags);
- if (!fsp->cmd) {
- spin_unlock_irqrestore(lport->host->host_lock, flags);
+ if (!fsp->cmd)
return;
- }
/*
* if can_queue ramp down is done then try can_queue ramp up
@@ -1880,10 +1887,8 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
sc_cmd = fsp->cmd;
fsp->cmd = NULL;
- if (!sc_cmd->SCp.ptr) {
- spin_unlock_irqrestore(lport->host->host_lock, flags);
+ if (!sc_cmd->SCp.ptr)
return;
- }
CMD_SCSI_STATUS(sc_cmd) = fsp->cdb_status;
switch (fsp->status_code) {
@@ -1945,10 +1950,11 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
break;
}
+ spin_lock_irqsave(&si->scsi_queue_lock, flags);
list_del(&fsp->list);
+ spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
sc_cmd->SCp.ptr = NULL;
sc_cmd->scsi_done(sc_cmd);
- spin_unlock_irqrestore(lport->host->host_lock, flags);
/* release ref from initial allocation in queue command */
fc_fcp_pkt_release(fsp);
@@ -2216,6 +2222,7 @@ int fc_fcp_init(struct fc_lport *lport)
lport->scsi_priv = si;
si->max_can_queue = lport->host->can_queue;
INIT_LIST_HEAD(&si->scsi_pkt_queue);
+ spin_lock_init(&si->scsi_queue_lock);
si->scsi_pkt_pool = mempool_create_slab_pool(2, scsi_pkt_cachep);
if (!si->scsi_pkt_pool) {
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index 74338c83ad0..0b165024a21 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -537,7 +537,9 @@ int fc_fabric_login(struct fc_lport *lport)
int rc = -1;
mutex_lock(&lport->lp_mutex);
- if (lport->state == LPORT_ST_DISABLED) {
+ if (lport->state == LPORT_ST_DISABLED ||
+ lport->state == LPORT_ST_LOGO) {
+ fc_lport_state_enter(lport, LPORT_ST_RESET);
fc_lport_enter_reset(lport);
rc = 0;
}
@@ -967,6 +969,9 @@ static void fc_lport_enter_reset(struct fc_lport *lport)
FC_LPORT_DBG(lport, "Entered RESET state from %s state\n",
fc_lport_state(lport));
+ if (lport->state == LPORT_ST_DISABLED || lport->state == LPORT_ST_LOGO)
+ return;
+
if (lport->vport) {
if (lport->link_up)
fc_vport_set_state(lport->vport, FC_VPORT_INITIALIZING);
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 35ca0e72df4..02300523b23 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -310,6 +310,7 @@ static void fc_rport_work(struct work_struct *work)
restart = 1;
else
list_del(&rdata->peers);
+ rdata->event = RPORT_EV_NONE;
mutex_unlock(&rdata->rp_mutex);
mutex_unlock(&lport->disc.disc_mutex);
}
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index b7689f3d05f..c28a712fd4d 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -517,7 +517,7 @@ static void iscsi_free_task(struct iscsi_task *task)
if (conn->login_task == task)
return;
- __kfifo_put(session->cmdpool.queue, (void*)&task, sizeof(void*));
+ kfifo_in(&session->cmdpool.queue, (void*)&task, sizeof(void*));
if (sc) {
task->sc = NULL;
@@ -737,7 +737,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
- if (!__kfifo_get(session->cmdpool.queue,
+ if (!kfifo_out(&session->cmdpool.queue,
(void*)&task, sizeof(void*)))
return NULL;
}
@@ -1567,7 +1567,7 @@ static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
{
struct iscsi_task *task;
- if (!__kfifo_get(conn->session->cmdpool.queue,
+ if (!kfifo_out(&conn->session->cmdpool.queue,
(void *) &task, sizeof(void *)))
return NULL;
@@ -2461,12 +2461,7 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
if (q->pool == NULL)
return -ENOMEM;
- q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
- GFP_KERNEL, NULL);
- if (IS_ERR(q->queue)) {
- q->queue = NULL;
- goto enomem;
- }
+ kfifo_init(&q->queue, (void*)q->pool, max * sizeof(void*));
for (i = 0; i < max; i++) {
q->pool[i] = kzalloc(item_size, GFP_KERNEL);
@@ -2474,7 +2469,7 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
q->max = i;
goto enomem;
}
- __kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*));
+ kfifo_in(&q->queue, (void*)&q->pool[i], sizeof(void*));
}
if (items) {
@@ -2497,7 +2492,6 @@ void iscsi_pool_free(struct iscsi_pool *q)
for (i = 0; i < q->max; i++)
kfree(q->pool[i]);
kfree(q->pool);
- kfree(q->queue);
}
EXPORT_SYMBOL_GPL(iscsi_pool_free);
@@ -2825,7 +2819,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
/* allocate login_task used for the login/text sequences */
spin_lock_bh(&session->lock);
- if (!__kfifo_get(session->cmdpool.queue,
+ if (!kfifo_out(&session->cmdpool.queue,
(void*)&conn->login_task,
sizeof(void*))) {
spin_unlock_bh(&session->lock);
@@ -2845,7 +2839,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
return cls_conn;
login_task_data_alloc_fail:
- __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
+ kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
sizeof(void*));
login_task_alloc_fail:
iscsi_destroy_conn(cls_conn);
@@ -2908,7 +2902,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
free_pages((unsigned long) conn->data,
get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
kfree(conn->persistent_address);
- __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
+ kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
sizeof(void*));
if (session->leadconn == conn)
session->leadconn = NULL;
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index ca25ee5190b..db6856c138f 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -445,15 +445,15 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task)
return;
/* flush task's r2t queues */
- while (__kfifo_get(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
- __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
+ while (kfifo_out(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
+ kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
sizeof(void*));
ISCSI_DBG_TCP(task->conn, "pending r2t dropped\n");
}
r2t = tcp_task->r2t;
if (r2t != NULL) {
- __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
+ kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
sizeof(void*));
tcp_task->r2t = NULL;
}
@@ -541,7 +541,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
return 0;
}
- rc = __kfifo_get(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
+ rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
if (!rc) {
iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. "
"Target has sent more R2Ts than it "
@@ -554,7 +554,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
if (r2t->data_length == 0) {
iscsi_conn_printk(KERN_ERR, conn,
"invalid R2T with zero data len\n");
- __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
+ kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
sizeof(void*));
return ISCSI_ERR_DATALEN;
}
@@ -570,7 +570,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
"invalid R2T with data len %u at offset %u "
"and total length %d\n", r2t->data_length,
r2t->data_offset, scsi_out(task->sc)->length);
- __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
+ kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
sizeof(void*));
return ISCSI_ERR_DATALEN;
}
@@ -580,7 +580,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
r2t->sent = 0;
tcp_task->exp_datasn = r2tsn + 1;
- __kfifo_put(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
+ kfifo_in(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
conn->r2t_pdus_cnt++;
iscsi_requeue_task(task);
@@ -951,7 +951,7 @@ int iscsi_tcp_task_init(struct iscsi_task *task)
return conn->session->tt->init_pdu(task, 0, task->data_count);
}
- BUG_ON(__kfifo_len(tcp_task->r2tqueue));
+ BUG_ON(kfifo_len(&tcp_task->r2tqueue));
tcp_task->exp_datasn = 0;
/* Prepare PDU, optionally w/ immediate data */
@@ -982,7 +982,7 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
if (r2t->data_length <= r2t->sent) {
ISCSI_DBG_TCP(task->conn,
" done with r2t %p\n", r2t);
- __kfifo_put(tcp_task->r2tpool.queue,
+ kfifo_in(&tcp_task->r2tpool.queue,
(void *)&tcp_task->r2t,
sizeof(void *));
tcp_task->r2t = r2t = NULL;
@@ -990,8 +990,13 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
}
if (r2t == NULL) {
- __kfifo_get(tcp_task->r2tqueue,
- (void *)&tcp_task->r2t, sizeof(void *));
+ if (kfifo_out(&tcp_task->r2tqueue,
+ (void *)&tcp_task->r2t, sizeof(void *)) !=
+ sizeof(void *)) {
+ WARN_ONCE(1, "unexpected fifo state");
+ r2t = NULL;
+ }
+
r2t = tcp_task->r2t;
}
spin_unlock_bh(&session->lock);
@@ -1127,9 +1132,8 @@ int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session)
}
/* R2T xmit queue */
- tcp_task->r2tqueue = kfifo_alloc(
- session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL);
- if (tcp_task->r2tqueue == ERR_PTR(-ENOMEM)) {
+ if (kfifo_alloc(&tcp_task->r2tqueue,
+ session->max_r2t * 4 * sizeof(void*), GFP_KERNEL)) {
iscsi_pool_free(&tcp_task->r2tpool);
goto r2t_alloc_fail;
}
@@ -1142,7 +1146,7 @@ r2t_alloc_fail:
struct iscsi_task *task = session->cmds[i];
struct iscsi_tcp_task *tcp_task = task->dd_data;
- kfifo_free(tcp_task->r2tqueue);
+ kfifo_free(&tcp_task->r2tqueue);
iscsi_pool_free(&tcp_task->r2tpool);
}
return -ENOMEM;
@@ -1157,7 +1161,7 @@ void iscsi_tcp_r2tpool_free(struct iscsi_session *session)
struct iscsi_task *task = session->cmds[i];
struct iscsi_tcp_task *tcp_task = task->dd_data;
- kfifo_free(tcp_task->r2tqueue);
+ kfifo_free(&tcp_task->r2tqueue);
iscsi_pool_free(&tcp_task->r2tpool);
}
}
diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
index 9ad38e81e34..ab19b3b4be5 100644
--- a/drivers/scsi/libsrp.c
+++ b/drivers/scsi/libsrp.c
@@ -58,19 +58,15 @@ static int srp_iu_pool_alloc(struct srp_queue *q, size_t max,
goto free_pool;
spin_lock_init(&q->lock);
- q->queue = kfifo_init((void *) q->pool, max * sizeof(void *),
- GFP_KERNEL, &q->lock);
- if (IS_ERR(q->queue))
- goto free_item;
+ kfifo_init(&q->queue, (void *) q->pool, max * sizeof(void *));
for (i = 0, iue = q->items; i < max; i++) {
- __kfifo_put(q->queue, (void *) &iue, sizeof(void *));
+ kfifo_in(&q->queue, (void *) &iue, sizeof(void *));
iue->sbuf = ring[i];
iue++;
}
return 0;
-free_item:
kfree(q->items);
free_pool:
kfree(q->pool);
@@ -167,7 +163,11 @@ struct iu_entry *srp_iu_get(struct srp_target *target)
{
struct iu_entry *iue = NULL;
- kfifo_get(target->iu_queue.queue, (void *) &iue, sizeof(void *));
+ if (kfifo_out_locked(&target->iu_queue.queue, (void *) &iue,
+ sizeof(void *), &target->iu_queue.lock) != sizeof(void *)) {
+ WARN_ONCE(1, "unexpected fifo state");
+ return NULL;
+ }
if (!iue)
return iue;
iue->target = target;
@@ -179,7 +179,8 @@ EXPORT_SYMBOL_GPL(srp_iu_get);
void srp_iu_put(struct iu_entry *iue)
{
- kfifo_put(iue->target->iu_queue.queue, (void *) &iue, sizeof(void *));
+ kfifo_in_locked(&iue->target->iu_queue.queue, (void *) &iue,
+ sizeof(void *), &iue->target->iu_queue.lock);
}
EXPORT_SYMBOL_GPL(srp_iu_put);
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 226920d15ea..d4da6bdd0e7 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -4506,9 +4506,13 @@ lpfc_sli_pci_mem_setup(struct lpfc_hba *phba)
pdev = phba->pcidev;
/* Set the device DMA mask size */
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0
+ || pci_set_consistent_dma_mask(pdev,DMA_BIT_MASK(64)) != 0) {
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0
+ || pci_set_consistent_dma_mask(pdev,DMA_BIT_MASK(32)) != 0) {
return error;
+ }
+ }
/* Get the bus address of Bar0 and Bar2 and the number of bytes
* required by each mapping.
@@ -6021,9 +6025,13 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
pdev = phba->pcidev;
/* Set the device DMA mask size */
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0
+ || pci_set_consistent_dma_mask(pdev,DMA_BIT_MASK(64)) != 0) {
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0
+ || pci_set_consistent_dma_mask(pdev,DMA_BIT_MASK(32)) != 0) {
return error;
+ }
+ }
/* Get the bus address of SLI4 device Bar0, Bar1, and Bar2 and the
* number of bytes required by each mapping. They are actually
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 134c63ef6d3..99ff99e45be 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -2501,7 +2501,9 @@ static int megasas_init_mfi(struct megasas_instance *instance)
instance->base_addr = pci_resource_start(instance->pdev, 0);
}
- if (pci_request_regions(instance->pdev, "megasas: LSI")) {
+ if (pci_request_selected_regions(instance->pdev,
+ pci_select_bars(instance->pdev, IORESOURCE_MEM),
+ "megasas: LSI")) {
printk(KERN_DEBUG "megasas: IO memory region busy!\n");
return -EBUSY;
}
@@ -2642,7 +2644,8 @@ static int megasas_init_mfi(struct megasas_instance *instance)
iounmap(instance->reg_set);
fail_ioremap:
- pci_release_regions(instance->pdev);
+ pci_release_selected_regions(instance->pdev,
+ pci_select_bars(instance->pdev, IORESOURCE_MEM));
return -EINVAL;
}
@@ -2662,7 +2665,8 @@ static void megasas_release_mfi(struct megasas_instance *instance)
iounmap(instance->reg_set);
- pci_release_regions(instance->pdev);
+ pci_release_selected_regions(instance->pdev,
+ pci_select_bars(instance->pdev, IORESOURCE_MEM));
}
/**
@@ -2971,7 +2975,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
/*
* PCI prepping: enable device set bus mastering and dma mask
*/
- rval = pci_enable_device(pdev);
+ rval = pci_enable_device_mem(pdev);
if (rval) {
return rval;
@@ -3276,7 +3280,7 @@ megasas_resume(struct pci_dev *pdev)
/*
* PCI prepping: enable device set bus mastering and dma mask
*/
- rval = pci_enable_device(pdev);
+ rval = pci_enable_device_mem(pdev);
if (rval) {
printk(KERN_ERR "megasas: Enable device failed\n");
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 6422e258fd5..89d02401b9e 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -3583,6 +3583,11 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
mutex_init(&ioc->transport_cmds.mutex);
+ /* scsih internal command bits */
+ ioc->scsih_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
+ ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
+ mutex_init(&ioc->scsih_cmds.mutex);
+
/* task management internal command bits */
ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index c790d45876c..cae6b2cf492 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -657,6 +657,7 @@ static struct pci_device_id __devinitdata mvs_pci_table[] = {
{ PCI_VDEVICE(MARVELL, 0x9180), chip_9180 },
{ PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1300), chip_1300 },
{ PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1320), chip_1320 },
+ { PCI_VDEVICE(ADAPTEC2, 0x0450), chip_6440 },
{ } /* terminate list */
};
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 950202a70bc..24223473f57 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -432,30 +432,23 @@ static void _osd_free_seg(struct osd_request *or __unused,
seg->alloc_size = 0;
}
-static void _put_request(struct request *rq , bool is_async)
+static void _put_request(struct request *rq)
{
- if (is_async) {
- WARN_ON(rq->bio);
- __blk_put_request(rq->q, rq);
- } else {
- /*
- * If osd_finalize_request() was called but the request was not
- * executed through the block layer, then we must release BIOs.
- * TODO: Keep error code in or->async_error. Need to audit all
- * code paths.
- */
- if (unlikely(rq->bio))
- blk_end_request(rq, -ENOMEM, blk_rq_bytes(rq));
- else
- blk_put_request(rq);
- }
+ /*
+ * If osd_finalize_request() was called but the request was not
+ * executed through the block layer, then we must release BIOs.
+ * TODO: Keep error code in or->async_error. Need to audit all
+ * code paths.
+ */
+ if (unlikely(rq->bio))
+ blk_end_request(rq, -ENOMEM, blk_rq_bytes(rq));
+ else
+ blk_put_request(rq);
}
void osd_end_request(struct osd_request *or)
{
struct request *rq = or->request;
- /* IMPORTANT: make sure this agrees with osd_execute_request_async */
- bool is_async = (or->request->end_io_data == or);
_osd_free_seg(or, &or->set_attr);
_osd_free_seg(or, &or->enc_get_attr);
@@ -463,20 +456,34 @@ void osd_end_request(struct osd_request *or)
if (rq) {
if (rq->next_rq) {
- _put_request(rq->next_rq, is_async);
+ _put_request(rq->next_rq);
rq->next_rq = NULL;
}
- _put_request(rq, is_async);
+ _put_request(rq);
}
_osd_request_free(or);
}
EXPORT_SYMBOL(osd_end_request);
+static void _set_error_resid(struct osd_request *or, struct request *req,
+ int error)
+{
+ or->async_error = error;
+ or->req_errors = req->errors ? : error;
+ or->sense_len = req->sense_len;
+ if (or->out.req)
+ or->out.residual = or->out.req->resid_len;
+ if (or->in.req)
+ or->in.residual = or->in.req->resid_len;
+}
+
int osd_execute_request(struct osd_request *or)
{
- return or->async_error =
- blk_execute_rq(or->request->q, NULL, or->request, 0);
+ int error = blk_execute_rq(or->request->q, NULL, or->request, 0);
+
+ _set_error_resid(or, or->request, error);
+ return error;
}
EXPORT_SYMBOL(osd_execute_request);
@@ -484,15 +491,17 @@ static void osd_request_async_done(struct request *req, int error)
{
struct osd_request *or = req->end_io_data;
- or->async_error = error;
-
- if (unlikely(error)) {
- OSD_DEBUG("osd_request_async_done error recieved %d "
- "errors 0x%x\n", error, req->errors);
- if (!req->errors) /* don't miss out on this one */
- req->errors = error;
+ _set_error_resid(or, req, error);
+ if (req->next_rq) {
+ __blk_put_request(req->q, req->next_rq);
+ req->next_rq = NULL;
}
+ __blk_put_request(req->q, req);
+ or->request = NULL;
+ or->in.req = NULL;
+ or->out.req = NULL;
+
if (or->async_done)
or->async_done(or, or->async_private);
else
@@ -1489,21 +1498,18 @@ int osd_req_decode_sense_full(struct osd_request *or,
#endif
int ret;
- if (likely(!or->request->errors)) {
- osi->out_resid = 0;
- osi->in_resid = 0;
+ if (likely(!or->req_errors))
return 0;
- }
osi = osi ? : &local_osi;
memset(osi, 0, sizeof(*osi));
- ssdb = or->request->sense;
- sense_len = or->request->sense_len;
+ ssdb = (typeof(ssdb))or->sense;
+ sense_len = or->sense_len;
if ((sense_len < (int)sizeof(*ssdb) || !ssdb->sense_key)) {
OSD_ERR("Block-layer returned error(0x%x) but "
"sense_len(%u) || key(%d) is empty\n",
- or->request->errors, sense_len, ssdb->sense_key);
+ or->req_errors, sense_len, ssdb->sense_key);
goto analyze;
}
@@ -1525,7 +1531,7 @@ int osd_req_decode_sense_full(struct osd_request *or,
"additional_code=0x%x async_error=%d errors=0x%x\n",
osi->key, original_sense_len, sense_len,
osi->additional_code, or->async_error,
- or->request->errors);
+ or->req_errors);
if (original_sense_len < sense_len)
sense_len = original_sense_len;
@@ -1695,10 +1701,10 @@ analyze:
ret = -EIO;
}
- if (or->out.req)
- osi->out_resid = or->out.req->resid_len ?: or->out.total_bytes;
- if (or->in.req)
- osi->in_resid = or->in.req->resid_len ?: or->in.total_bytes;
+ if (!or->out.residual)
+ or->out.residual = or->out.total_bytes;
+ if (!or->in.residual)
+ or->in.residual = or->in.total_bytes;
return ret;
}
diff --git a/drivers/scsi/pm8001/pm8001_ctl.h b/drivers/scsi/pm8001/pm8001_ctl.h
index 22644de2639..63ad4aa0c42 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.h
+++ b/drivers/scsi/pm8001/pm8001_ctl.h
@@ -45,16 +45,6 @@
#define HEADER_LEN 28
#define SIZE_OFFSET 16
-struct pm8001_ioctl_payload {
- u32 signature;
- u16 major_function;
- u16 minor_function;
- u16 length;
- u16 status;
- u16 offset;
- u16 id;
- u8 func_specific[1];
-};
#define FLASH_OK 0x000000
#define FAIL_OPEN_BIOS_FILE 0x000100
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index a3de306b904..9b44c6f1b10 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -373,10 +373,7 @@ static int bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue)
static void __devinit
mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha, u32 SSCbit)
{
- u32 offset;
- u32 value;
- u32 i, j;
- u32 bit_cnt;
+ u32 value, offset, i;
#define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000
#define SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000
@@ -392,55 +389,35 @@ mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha, u32 SSCbit)
*/
if (-1 == bar4_shift(pm8001_ha, SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR))
return;
- /* set SSC bit of PHY 0 - 3 */
+
for (i = 0; i < 4; i++) {
offset = SAS2_SETTINGS_LOCAL_PHY_0_3_OFFSET + 0x4000 * i;
- value = pm8001_cr32(pm8001_ha, 2, offset);
- if (SSCbit) {
- value |= 0x00000001 << PHY_G3_WITH_SSC_BIT_SHIFT;
- value &= ~(0x00000001 << PHY_G3_WITHOUT_SSC_BIT_SHIFT);
- } else {
- value |= 0x00000001 << PHY_G3_WITHOUT_SSC_BIT_SHIFT;
- value &= ~(0x00000001 << PHY_G3_WITH_SSC_BIT_SHIFT);
- }
- bit_cnt = 0;
- for (j = 0; j < 31; j++)
- if ((value >> j) & 0x00000001)
- bit_cnt++;
- if (bit_cnt % 2)
- value &= ~(0x00000001 << SNW3_PHY_CAPABILITIES_PARITY);
- else
- value |= 0x00000001 << SNW3_PHY_CAPABILITIES_PARITY;
-
- pm8001_cw32(pm8001_ha, 2, offset, value);
+ pm8001_cw32(pm8001_ha, 2, offset, 0x80001501);
}
-
/* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */
if (-1 == bar4_shift(pm8001_ha, SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR))
return;
-
- /* set SSC bit of PHY 4 - 7 */
for (i = 4; i < 8; i++) {
offset = SAS2_SETTINGS_LOCAL_PHY_4_7_OFFSET + 0x4000 * (i-4);
- value = pm8001_cr32(pm8001_ha, 2, offset);
- if (SSCbit) {
- value |= 0x00000001 << PHY_G3_WITH_SSC_BIT_SHIFT;
- value &= ~(0x00000001 << PHY_G3_WITHOUT_SSC_BIT_SHIFT);
- } else {
- value |= 0x00000001 << PHY_G3_WITHOUT_SSC_BIT_SHIFT;
- value &= ~(0x00000001 << PHY_G3_WITH_SSC_BIT_SHIFT);
- }
- bit_cnt = 0;
- for (j = 0; j < 31; j++)
- if ((value >> j) & 0x00000001)
- bit_cnt++;
- if (bit_cnt % 2)
- value &= ~(0x00000001 << SNW3_PHY_CAPABILITIES_PARITY);
- else
- value |= 0x00000001 << SNW3_PHY_CAPABILITIES_PARITY;
-
- pm8001_cw32(pm8001_ha, 2, offset, value);
+ pm8001_cw32(pm8001_ha, 2, offset, 0x80001501);
}
+ /*************************************************************
+ Change the SSC upspreading value to 0x0 so that upspreading is disabled.
+ Device MABC SMOD0 Controls
+ Address: (via MEMBASE-III):
+ Using shifted destination address 0x0_0000: with Offset 0xD8
+
+ 31:28 R/W Reserved Do not change
+ 27:24 R/W SAS_SMOD_SPRDUP 0000
+ 23:20 R/W SAS_SMOD_SPRDDN 0000
+ 19:0 R/W Reserved Do not change
+ Upon power-up this register will read as 0x8990c016,
+ and I would like you to change the SAS_SMOD_SPRDUP bits to 0b0000
+ so that the written value will be 0x8090c016.
+ This will ensure only down-spreading SSC is enabled on the SPC.
+ *************************************************************/
+ value = pm8001_cr32(pm8001_ha, 2, 0xd8);
+ pm8001_cw32(pm8001_ha, 2, 0xd8, 0x8000C016);
/*set the shifted destination address to 0x0 to avoid error operation */
bar4_shift(pm8001_ha, 0x0);
@@ -1901,7 +1878,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
struct sas_task *t;
struct pm8001_ccb_info *ccb;
- unsigned long flags;
+ unsigned long flags = 0;
u32 param;
u32 status;
u32 tag;
@@ -2040,7 +2017,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
ts->stat = SAS_QUEUE_FULL;
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
mb();/*in order to force CPU ordering*/
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
return;
}
break;
@@ -2058,7 +2037,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
ts->stat = SAS_QUEUE_FULL;
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
mb();/*ditto*/
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
return;
}
break;
@@ -2084,7 +2065,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
ts->stat = SAS_QUEUE_FULL;
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
mb();/* ditto*/
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
return;
}
break;
@@ -2149,7 +2132,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
ts->stat = SAS_QUEUE_FULL;
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
mb();/*ditto*/
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
return;
}
break;
@@ -2171,7 +2156,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
ts->stat = SAS_QUEUE_FULL;
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
mb();/*ditto*/
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
return;
}
break;
@@ -2200,11 +2187,20 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
" resp 0x%x stat 0x%x but aborted by upper layer!\n",
t, status, ts->resp, ts->stat));
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- } else {
+ } else if (t->uldd_task) {
spin_unlock_irqrestore(&t->task_state_lock, flags);
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
mb();/* ditto */
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
+ } else if (!t->uldd_task) {
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ mb();/*ditto*/
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+ t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
}
}
@@ -2212,7 +2208,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
{
struct sas_task *t;
- unsigned long flags;
+ unsigned long flags = 0;
struct task_status_struct *ts;
struct pm8001_ccb_info *ccb;
struct pm8001_device *pm8001_dev;
@@ -2292,7 +2288,9 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
ts->stat = SAS_QUEUE_FULL;
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
mb();/*ditto*/
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
return;
}
break;
@@ -2401,11 +2399,20 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
" resp 0x%x stat 0x%x but aborted by upper layer!\n",
t, event, ts->resp, ts->stat));
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- } else {
+ } else if (t->uldd_task) {
spin_unlock_irqrestore(&t->task_state_lock, flags);
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/* in order to force CPU ordering */
+ mb();/* ditto */
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
+ } else if (!t->uldd_task) {
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ mb();/*ditto*/
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+ t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
}
}
@@ -2876,15 +2883,20 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
le32_to_cpu(pPayload->lr_evt_status_phyid_portid);
u8 link_rate =
(u8)((lr_evt_status_phyid_portid & 0xF0000000) >> 28);
+ u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F);
u8 phy_id =
(u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
+ u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate);
+ u8 portstate = (u8)(npip_portstate & 0x0000000F);
+ struct pm8001_port *port = &pm8001_ha->port[port_id];
struct sas_ha_struct *sas_ha = pm8001_ha->sas;
struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
unsigned long flags;
u8 deviceType = pPayload->sas_identify.dev_type;
-
+ port->port_state = portstate;
PM8001_MSG_DBG(pm8001_ha,
- pm8001_printk("HW_EVENT_SAS_PHY_UP \n"));
+ pm8001_printk("HW_EVENT_SAS_PHY_UP port id = %d, phy id = %d\n",
+ port_id, phy_id));
switch (deviceType) {
case SAS_PHY_UNUSED:
@@ -2895,16 +2907,19 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
PM8001_MSG_DBG(pm8001_ha, pm8001_printk("end device.\n"));
pm8001_chip_phy_ctl_req(pm8001_ha, phy_id,
PHY_NOTIFY_ENABLE_SPINUP);
+ port->port_attached = 1;
get_lrate_mode(phy, link_rate);
break;
case SAS_EDGE_EXPANDER_DEVICE:
PM8001_MSG_DBG(pm8001_ha,
pm8001_printk("expander device.\n"));
+ port->port_attached = 1;
get_lrate_mode(phy, link_rate);
break;
case SAS_FANOUT_EXPANDER_DEVICE:
PM8001_MSG_DBG(pm8001_ha,
pm8001_printk("fanout expander device.\n"));
+ port->port_attached = 1;
get_lrate_mode(phy, link_rate);
break;
default:
@@ -2946,11 +2961,20 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
le32_to_cpu(pPayload->lr_evt_status_phyid_portid);
u8 link_rate =
(u8)((lr_evt_status_phyid_portid & 0xF0000000) >> 28);
+ u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F);
u8 phy_id =
(u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
+ u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate);
+ u8 portstate = (u8)(npip_portstate & 0x0000000F);
+ struct pm8001_port *port = &pm8001_ha->port[port_id];
struct sas_ha_struct *sas_ha = pm8001_ha->sas;
struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
unsigned long flags;
+ PM8001_MSG_DBG(pm8001_ha,
+ pm8001_printk("HW_EVENT_SATA_PHY_UP port id = %d,"
+ " phy id = %d\n", port_id, phy_id));
+ port->port_state = portstate;
+ port->port_attached = 1;
get_lrate_mode(phy, link_rate);
phy->phy_type |= PORT_TYPE_SATA;
phy->phy_attached = 1;
@@ -2984,7 +3008,13 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb)
(u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate);
u8 portstate = (u8)(npip_portstate & 0x0000000F);
-
+ struct pm8001_port *port = &pm8001_ha->port[port_id];
+ struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
+ port->port_state = portstate;
+ phy->phy_type = 0;
+ phy->identify.device_type = 0;
+ phy->phy_attached = 0;
+ memset(&phy->dev_sas_addr, 0, SAS_ADDR_SIZE);
switch (portstate) {
case PORT_VALID:
break;
@@ -2993,26 +3023,30 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb)
pm8001_printk(" PortInvalid portID %d \n", port_id));
PM8001_MSG_DBG(pm8001_ha,
pm8001_printk(" Last phy Down and port invalid\n"));
+ port->port_attached = 0;
pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN,
port_id, phy_id, 0, 0);
break;
case PORT_IN_RESET:
PM8001_MSG_DBG(pm8001_ha,
- pm8001_printk(" PortInReset portID %d \n", port_id));
+ pm8001_printk(" Port In Reset portID %d \n", port_id));
break;
case PORT_NOT_ESTABLISHED:
PM8001_MSG_DBG(pm8001_ha,
pm8001_printk(" phy Down and PORT_NOT_ESTABLISHED\n"));
+ port->port_attached = 0;
break;
case PORT_LOSTCOMM:
PM8001_MSG_DBG(pm8001_ha,
pm8001_printk(" phy Down and PORT_LOSTCOMM\n"));
PM8001_MSG_DBG(pm8001_ha,
pm8001_printk(" Last phy Down and port invalid\n"));
+ port->port_attached = 0;
pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN,
port_id, phy_id, 0, 0);
break;
default:
+ port->port_attached = 0;
PM8001_MSG_DBG(pm8001_ha,
pm8001_printk(" phy Down and(default) = %x\n",
portstate));
@@ -3770,7 +3804,8 @@ static int pm8001_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,
u32 opc = OPC_INB_SSPINIIOSTART;
memset(&ssp_cmd, 0, sizeof(ssp_cmd));
memcpy(ssp_cmd.ssp_iu.lun, task->ssp_task.LUN, 8);
- ssp_cmd.dir_m_tlr = data_dir_flags[task->data_dir] << 8 | 0x0;/*0 for
+ ssp_cmd.dir_m_tlr =
+ cpu_to_le32(data_dir_flags[task->data_dir] << 8 | 0x0);/*0 for
SAS 1.1 compatible TLR*/
ssp_cmd.data_len = cpu_to_le32(task->total_xfer_len);
ssp_cmd.device_id = cpu_to_le32(pm8001_dev->device_id);
@@ -3841,7 +3876,7 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
}
}
if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag))
- ncg_tag = cpu_to_le32(hdr_tag);
+ ncg_tag = hdr_tag;
dir = data_dir_flags[task->data_dir] << 8;
sata_cmd.tag = cpu_to_le32(tag);
sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id);
@@ -3986,7 +4021,7 @@ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha,
((stp_sspsmp_sata & 0x03) * 0x10000000));
payload.firstburstsize_ITNexustimeout =
cpu_to_le32(ITNT | (firstBurstSize * 0x10000));
- memcpy(&payload.sas_addr_hi, pm8001_dev->sas_device->sas_addr,
+ memcpy(payload.sas_addr, pm8001_dev->sas_device->sas_addr,
SAS_ADDR_SIZE);
rc = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload);
return rc;
@@ -4027,7 +4062,7 @@ static int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha,
struct inbound_queue_table *circularQ;
int ret;
u32 opc = OPC_INB_LOCAL_PHY_CONTROL;
- memset((u8 *)&payload, 0, sizeof(payload));
+ memset(&payload, 0, sizeof(payload));
circularQ = &pm8001_ha->inbnd_q_tbl[0];
payload.tag = 1;
payload.phyop_phyid =
diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h
index 96e4daa68b8..833a5201eda 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.h
+++ b/drivers/scsi/pm8001/pm8001_hwi.h
@@ -242,8 +242,7 @@ struct reg_dev_req {
__le32 phyid_portid;
__le32 dtype_dlr_retry;
__le32 firstburstsize_ITNexustimeout;
- u32 sas_addr_hi;
- u32 sas_addr_low;
+ u8 sas_addr[SAS_ADDR_SIZE];
__le32 upper_device_id;
u32 reserved[8];
} __attribute__((packed, aligned(4)));
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 42ebe725d5a..c2f1032496c 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -200,8 +200,13 @@ static int __devinit pm8001_alloc(struct pm8001_hba_info *pm8001_ha)
{
int i;
spin_lock_init(&pm8001_ha->lock);
- for (i = 0; i < pm8001_ha->chip->n_phy; i++)
+ for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
pm8001_phy_init(pm8001_ha, i);
+ pm8001_ha->port[i].wide_port_phymap = 0;
+ pm8001_ha->port[i].port_attached = 0;
+ pm8001_ha->port[i].port_state = 0;
+ INIT_LIST_HEAD(&pm8001_ha->port[i].list);
+ }
pm8001_ha->tags = kzalloc(PM8001_MAX_CCB, GFP_KERNEL);
if (!pm8001_ha->tags)
@@ -511,19 +516,23 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
u8 i;
#ifdef PM8001_READ_VPD
DECLARE_COMPLETION_ONSTACK(completion);
+ struct pm8001_ioctl_payload payload;
pm8001_ha->nvmd_completion = &completion;
- PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, 0, 0);
+ payload.minor_function = 0;
+ payload.length = 128;
+ payload.func_specific = kzalloc(128, GFP_KERNEL);
+ PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload);
wait_for_completion(&completion);
for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
memcpy(&pm8001_ha->phy[i].dev_sas_addr, pm8001_ha->sas_addr,
SAS_ADDR_SIZE);
PM8001_INIT_DBG(pm8001_ha,
- pm8001_printk("phy %d sas_addr = %x \n", i,
- (u64)pm8001_ha->phy[i].dev_sas_addr));
+ pm8001_printk("phy %d sas_addr = %016llx \n", i,
+ pm8001_ha->phy[i].dev_sas_addr));
}
#else
for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
- pm8001_ha->phy[i].dev_sas_addr = 0x500e004010000004ULL;
+ pm8001_ha->phy[i].dev_sas_addr = 0x50010c600047f9d0ULL;
pm8001_ha->phy[i].dev_sas_addr =
cpu_to_be64((u64)
(*(u64 *)&pm8001_ha->phy[i].dev_sas_addr));
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index 1f767a0e727..7f9c83a7639 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -329,6 +329,23 @@ int pm8001_slave_configure(struct scsi_device *sdev)
}
return 0;
}
+ /* Find the local port id that's attached to this device */
+static int sas_find_local_port_id(struct domain_device *dev)
+{
+ struct domain_device *pdev = dev->parent;
+
+ /* Directly attached device */
+ if (!pdev)
+ return dev->port->id;
+ while (pdev) {
+ struct domain_device *pdev_p = pdev->parent;
+ if (!pdev_p)
+ return pdev->port->id;
+ pdev = pdev->parent;
+ }
+ return 0;
+}
+
/**
* pm8001_task_exec - queue the task(ssp, smp && ata) to the hardware.
* @task: the task to be execute.
@@ -346,11 +363,12 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
struct domain_device *dev = task->dev;
struct pm8001_hba_info *pm8001_ha;
struct pm8001_device *pm8001_dev;
+ struct pm8001_port *port = NULL;
struct sas_task *t = task;
struct pm8001_ccb_info *ccb;
u32 tag = 0xdeadbeef, rc, n_elem = 0;
u32 n = num;
- unsigned long flags = 0;
+ unsigned long flags = 0, flags_libsas = 0;
if (!dev->port) {
struct task_status_struct *tsm = &t->task_status;
@@ -379,6 +397,35 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
rc = SAS_PHY_DOWN;
goto out_done;
}
+ port = &pm8001_ha->port[sas_find_local_port_id(dev)];
+ if (!port->port_attached) {
+ if (sas_protocol_ata(t->task_proto)) {
+ struct task_status_struct *ts = &t->task_status;
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_PHY_DOWN;
+
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+ spin_unlock_irqrestore(dev->sata_dev.ap->lock,
+ flags_libsas);
+ t->task_done(t);
+ spin_lock_irqsave(dev->sata_dev.ap->lock,
+ flags_libsas);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
+ if (n > 1)
+ t = list_entry(t->list.next,
+ struct sas_task, list);
+ continue;
+ } else {
+ struct task_status_struct *ts = &t->task_status;
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_PHY_DOWN;
+ t->task_done(t);
+ if (n > 1)
+ t = list_entry(t->list.next,
+ struct sas_task, list);
+ continue;
+ }
+ }
rc = pm8001_tag_alloc(pm8001_ha, &tag);
if (rc)
goto err_out;
@@ -569,11 +616,11 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
spin_lock_irqsave(&pm8001_ha->lock, flags);
pm8001_device = pm8001_alloc_dev(pm8001_ha);
- pm8001_device->sas_device = dev;
if (!pm8001_device) {
res = -1;
goto found_out;
}
+ pm8001_device->sas_device = dev;
dev->lldd_dev = pm8001_device;
pm8001_device->dev_type = dev->dev_type;
pm8001_device->dcompletion = &completion;
@@ -609,7 +656,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
wait_for_completion(&completion);
if (dev->dev_type == SAS_END_DEV)
msleep(50);
- pm8001_ha->flags = PM8001F_RUN_TIME ;
+ pm8001_ha->flags |= PM8001F_RUN_TIME ;
return 0;
found_out:
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
@@ -772,7 +819,7 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha,
task->task_done = pm8001_task_done;
task->timer.data = (unsigned long)task;
task->timer.function = pm8001_tmf_timedout;
- task->timer.expires = jiffies + PM8001_TASK_TIMEOUT*HZ;
+ task->timer.expires = jiffies + PM8001_TASK_TIMEOUT * HZ;
add_timer(&task->timer);
res = pm8001_tag_alloc(pm8001_ha, &ccb_tag);
@@ -897,6 +944,8 @@ int pm8001_I_T_nexus_reset(struct domain_device *dev)
if (dev_is_sata(dev)) {
DECLARE_COMPLETION_ONSTACK(completion_setstate);
+ if (scsi_is_sas_phy_local(phy))
+ return 0;
rc = sas_phy_reset(phy, 1);
msleep(2000);
rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 30f2ede55a7..8e38ca8cd10 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -59,11 +59,11 @@
#define DRV_NAME "pm8001"
#define DRV_VERSION "0.1.36"
-#define PM8001_FAIL_LOGGING 0x01 /* libsas EH function logging */
+#define PM8001_FAIL_LOGGING 0x01 /* Error message logging */
#define PM8001_INIT_LOGGING 0x02 /* driver init logging */
#define PM8001_DISC_LOGGING 0x04 /* discovery layer logging */
#define PM8001_IO_LOGGING 0x08 /* I/O path logging */
-#define PM8001_EH_LOGGING 0x10 /* Error message logging */
+#define PM8001_EH_LOGGING 0x10 /* libsas EH function logging*/
#define PM8001_IOCTL_LOGGING 0x20 /* IOCTL message logging */
#define PM8001_MSG_LOGGING 0x40 /* misc message logging */
#define pm8001_printk(format, arg...) printk(KERN_INFO "%s %d:" format,\
@@ -100,6 +100,7 @@ do { \
#define PM8001_USE_TASKLET
#define PM8001_USE_MSIX
+#define PM8001_READ_VPD
#define DEV_IS_EXPANDER(type) ((type == EDGE_DEV) || (type == FANOUT_DEV))
@@ -111,7 +112,22 @@ extern const struct pm8001_dispatch pm8001_8001_dispatch;
struct pm8001_hba_info;
struct pm8001_ccb_info;
struct pm8001_device;
-struct pm8001_tmf_task;
+/* define task management IU */
+struct pm8001_tmf_task {
+ u8 tmf;
+ u32 tag_of_task_to_be_managed;
+};
+struct pm8001_ioctl_payload {
+ u32 signature;
+ u16 major_function;
+ u16 minor_function;
+ u16 length;
+ u16 status;
+ u16 offset;
+ u16 id;
+ u8 *func_specific;
+};
+
struct pm8001_dispatch {
char *name;
int (*chip_init)(struct pm8001_hba_info *pm8001_ha);
@@ -164,6 +180,10 @@ struct pm8001_chip_info {
struct pm8001_port {
struct asd_sas_port sas_port;
+ u8 port_attached;
+ u8 wide_port_phymap;
+ u8 port_state;
+ struct list_head list;
};
struct pm8001_phy {
@@ -386,11 +406,7 @@ struct pm8001_fw_image_header {
__be32 startup_entry;
} __attribute__((packed, aligned(4)));
-/* define task management IU */
-struct pm8001_tmf_task {
- u8 tmf;
- u32 tag_of_task_to_be_managed;
-};
+
/**
* FW Flash Update status values
*/
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index 34c6b896a91..e7d2688fbeb 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -1,7 +1,8 @@
/*
* pmcraid.c -- driver for PMC Sierra MaxRAID controller adapters
*
- * Written By: PMC Sierra Corporation
+ * Written By: Anil Ravindranath<anil_ravindranath@pmc-sierra.com>
+ * PMC-Sierra Inc
*
* Copyright (C) 2008, 2009 PMC Sierra Inc
*
@@ -79,7 +80,7 @@ DECLARE_BITMAP(pmcraid_minor, PMCRAID_MAX_ADAPTERS);
/*
* Module parameters
*/
-MODULE_AUTHOR("PMC Sierra Corporation, anil_ravindranath@pmc-sierra.com");
+MODULE_AUTHOR("Anil Ravindranath<anil_ravindranath@pmc-sierra.com>");
MODULE_DESCRIPTION("PMC Sierra MaxRAID Controller Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(PMCRAID_DRIVER_VERSION);
@@ -162,10 +163,10 @@ static int pmcraid_slave_alloc(struct scsi_device *scsi_dev)
spin_lock_irqsave(&pinstance->resource_lock, lock_flags);
list_for_each_entry(temp, &pinstance->used_res_q, queue) {
- /* do not expose VSETs with order-ids >= 240 */
+ /* do not expose VSETs with order-ids > MAX_VSET_TARGETS */
if (RES_IS_VSET(temp->cfg_entry)) {
target = temp->cfg_entry.unique_flags1;
- if (target >= PMCRAID_MAX_VSET_TARGETS)
+ if (target > PMCRAID_MAX_VSET_TARGETS)
continue;
bus = PMCRAID_VSET_BUS_ID;
lun = 0;
@@ -1210,7 +1211,7 @@ static int pmcraid_expose_resource(struct pmcraid_config_table_entry *cfgte)
int retval = 0;
if (cfgte->resource_type == RES_TYPE_VSET)
- retval = ((cfgte->unique_flags1 & 0xFF) < 0xFE);
+ retval = ((cfgte->unique_flags1 & 0x80) == 0);
else if (cfgte->resource_type == RES_TYPE_GSCSI)
retval = (RES_BUS(cfgte->resource_address) !=
PMCRAID_VIRTUAL_ENCL_BUS_ID);
@@ -1361,6 +1362,7 @@ static int pmcraid_notify_aen(struct pmcraid_instance *pinstance, u8 type)
* Return value:
* none
*/
+
static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance)
{
struct pmcraid_config_table_entry *cfg_entry;
@@ -1368,9 +1370,10 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance)
struct pmcraid_cmd *cmd;
struct pmcraid_cmd *cfgcmd;
struct pmcraid_resource_entry *res = NULL;
- u32 new_entry = 1;
unsigned long lock_flags;
unsigned long host_lock_flags;
+ u32 new_entry = 1;
+ u32 hidden_entry = 0;
int rc;
ccn_hcam = (struct pmcraid_hcam_ccn *)pinstance->ccn.hcam;
@@ -1406,9 +1409,15 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance)
}
/* If this resource is not going to be added to mid-layer, just notify
- * applications and return
+ * applications and return. If this notification is about hiding a VSET
+ * resource, check if it was exposed already.
*/
- if (!pmcraid_expose_resource(cfg_entry))
+ if (pinstance->ccn.hcam->notification_type ==
+ NOTIFICATION_TYPE_ENTRY_CHANGED &&
+ cfg_entry->resource_type == RES_TYPE_VSET &&
+ cfg_entry->unique_flags1 & 0x80) {
+ hidden_entry = 1;
+ } else if (!pmcraid_expose_resource(cfg_entry))
goto out_notify_apps;
spin_lock_irqsave(&pinstance->resource_lock, lock_flags);
@@ -1424,6 +1433,12 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance)
if (new_entry) {
+ if (hidden_entry) {
+ spin_unlock_irqrestore(&pinstance->resource_lock,
+ lock_flags);
+ goto out_notify_apps;
+ }
+
/* If there are more number of resources than what driver can
* manage, do not notify the applications about the CCN. Just
* ignore this notifications and re-register the same HCAM
@@ -1454,8 +1469,9 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance)
sizeof(struct pmcraid_config_table_entry));
if (pinstance->ccn.hcam->notification_type ==
- NOTIFICATION_TYPE_ENTRY_DELETED) {
+ NOTIFICATION_TYPE_ENTRY_DELETED || hidden_entry) {
if (res->scsi_dev) {
+ res->cfg_entry.unique_flags1 &= 0x7F;
res->change_detected = RES_CHANGE_DEL;
res->cfg_entry.resource_handle =
PMCRAID_INVALID_RES_HANDLE;
diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h
index 2752b56cad5..92f89d50850 100644
--- a/drivers/scsi/pmcraid.h
+++ b/drivers/scsi/pmcraid.h
@@ -1,6 +1,9 @@
/*
* pmcraid.h -- PMC Sierra MaxRAID controller driver header file
*
+ * Written By: Anil Ravindranath<anil_ravindranath@pmc-sierra.com>
+ * PMC-Sierra Inc
+ *
* Copyright (C) 2008, 2009 PMC Sierra Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -106,7 +109,7 @@
#define PMCRAID_VSET_LUN_ID 0x0
#define PMCRAID_PHYS_BUS_ID 0x0
#define PMCRAID_VIRTUAL_ENCL_BUS_ID 0x8
-#define PMCRAID_MAX_VSET_TARGETS 240
+#define PMCRAID_MAX_VSET_TARGETS 0x7F
#define PMCRAID_MAX_VSET_LUNS_PER_TARGET 8
#define PMCRAID_IOA_MAX_SECTORS 32767
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 6b9bf23c773..384afda7dbe 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1570,9 +1570,6 @@ typedef struct fc_port {
struct fc_rport *rport, *drport;
u32 supported_classes;
- unsigned long last_queue_full;
- unsigned long last_ramp_up;
-
uint16_t vp_idx;
} fc_port_t;
@@ -2265,6 +2262,7 @@ struct qla_hw_data {
uint32_t port0 :1;
uint32_t running_gold_fw :1;
uint32_t cpu_affinity_enabled :1;
+ uint32_t disable_msix_handshake :1;
} flags;
/* This spinlock is used to protect "io transactions", you must
@@ -2387,6 +2385,7 @@ struct qla_hw_data {
#define IS_QLA81XX(ha) (IS_QLA8001(ha))
#define IS_QLA2XXX_MIDTYPE(ha) (IS_QLA24XX(ha) || IS_QLA84XX(ha) || \
IS_QLA25XX(ha) || IS_QLA81XX(ha))
+#define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha))
#define IS_NOPOLLING_TYPE(ha) ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && \
(ha)->flags.msix_enabled)
#define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha))
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index e2185135850..0b6801fc638 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -72,8 +72,6 @@ extern int ql2xloginretrycount;
extern int ql2xfdmienable;
extern int ql2xallocfwdump;
extern int ql2xextended_error_logging;
-extern int ql2xqfullrampup;
-extern int ql2xqfulltracking;
extern int ql2xiidmaenable;
extern int ql2xmaxqueues;
extern int ql2xmultique_tag;
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index b74924b279e..73a793539d4 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -1442,7 +1442,17 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
icb->firmware_options_2 |=
__constant_cpu_to_le32(BIT_18);
- icb->firmware_options_2 &= __constant_cpu_to_le32(~BIT_22);
+ /* Use Disable MSIX Handshake mode for capable adapters */
+ if (IS_MSIX_NACK_CAPABLE(ha)) {
+ icb->firmware_options_2 &=
+ __constant_cpu_to_le32(~BIT_22);
+ ha->flags.disable_msix_handshake = 1;
+ qla_printk(KERN_INFO, ha,
+ "MSIX Handshake Disable Mode turned on\n");
+ } else {
+ icb->firmware_options_2 |=
+ __constant_cpu_to_le32(BIT_22);
+ }
icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_23);
WRT_REG_DWORD(&reg->isp25mq.req_q_in, 0);
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 804987397b7..1692a883f4d 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -811,78 +811,6 @@ skip_rio:
qla2x00_alert_all_vps(rsp, mb);
}
-static void
-qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, void *data)
-{
- fc_port_t *fcport = data;
- struct scsi_qla_host *vha = fcport->vha;
- struct qla_hw_data *ha = vha->hw;
- struct req_que *req = NULL;
-
- if (!ql2xqfulltracking)
- return;
-
- req = vha->req;
- if (!req)
- return;
- if (req->max_q_depth <= sdev->queue_depth)
- return;
-
- if (sdev->ordered_tags)
- scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
- sdev->queue_depth + 1);
- else
- scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
- sdev->queue_depth + 1);
-
- fcport->last_ramp_up = jiffies;
-
- DEBUG2(qla_printk(KERN_INFO, ha,
- "scsi(%ld:%d:%d:%d): Queue depth adjusted-up to %d.\n",
- fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
- sdev->queue_depth));
-}
-
-static void
-qla2x00_adjust_sdev_qdepth_down(struct scsi_device *sdev, void *data)
-{
- fc_port_t *fcport = data;
-
- if (!scsi_track_queue_full(sdev, sdev->queue_depth - 1))
- return;
-
- DEBUG2(qla_printk(KERN_INFO, fcport->vha->hw,
- "scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
- fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
- sdev->queue_depth));
-}
-
-static inline void
-qla2x00_ramp_up_queue_depth(scsi_qla_host_t *vha, struct req_que *req,
- srb_t *sp)
-{
- fc_port_t *fcport;
- struct scsi_device *sdev;
-
- if (!ql2xqfulltracking)
- return;
-
- sdev = sp->cmd->device;
- if (sdev->queue_depth >= req->max_q_depth)
- return;
-
- fcport = sp->fcport;
- if (time_before(jiffies,
- fcport->last_ramp_up + ql2xqfullrampup * HZ))
- return;
- if (time_before(jiffies,
- fcport->last_queue_full + ql2xqfullrampup * HZ))
- return;
-
- starget_for_each_device(sdev->sdev_target, fcport,
- qla2x00_adjust_sdev_qdepth_up);
-}
-
/**
* qla2x00_process_completed_request() - Process a Fast Post response.
* @ha: SCSI driver HA context
@@ -913,8 +841,6 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
/* Save ISP completion status */
sp->cmd->result = DID_OK << 16;
-
- qla2x00_ramp_up_queue_depth(vha, req, sp);
qla2x00_sp_compl(ha, sp);
} else {
DEBUG2(printk("scsi(%ld) Req:%d: Invalid ISP SCSI completion"
@@ -1435,13 +1361,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
"scsi(%ld): QUEUE FULL status detected "
"0x%x-0x%x.\n", vha->host_no, comp_status,
scsi_status));
-
- /* Adjust queue depth for all luns on the port. */
- if (!ql2xqfulltracking)
- break;
- fcport->last_queue_full = jiffies;
- starget_for_each_device(cp->device->sdev_target,
- fcport, qla2x00_adjust_sdev_qdepth_down);
break;
}
if (lscsi_status != SS_CHECK_CONDITION)
@@ -1516,17 +1435,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
"scsi(%ld): QUEUE FULL status detected "
"0x%x-0x%x.\n", vha->host_no, comp_status,
scsi_status));
-
- /*
- * Adjust queue depth for all luns on the
- * port.
- */
- if (!ql2xqfulltracking)
- break;
- fcport->last_queue_full = jiffies;
- starget_for_each_device(
- cp->device->sdev_target, fcport,
- qla2x00_adjust_sdev_qdepth_down);
break;
}
if (lscsi_status != SS_CHECK_CONDITION)
@@ -2020,7 +1928,7 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
vha = qla25xx_get_host(rsp);
qla24xx_process_response_queue(vha, rsp);
- if (!ha->mqenable) {
+ if (!ha->flags.disable_msix_handshake) {
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
RD_REG_DWORD_RELAXED(&reg->hccr);
}
@@ -2034,6 +1942,7 @@ qla25xx_msix_rsp_q(int irq, void *dev_id)
{
struct qla_hw_data *ha;
struct rsp_que *rsp;
+ struct device_reg_24xx __iomem *reg;
rsp = (struct rsp_que *) dev_id;
if (!rsp) {
@@ -2043,6 +1952,14 @@ qla25xx_msix_rsp_q(int irq, void *dev_id)
}
ha = rsp->hw;
+ /* Clear the interrupt, if enabled, for this response queue */
+ if (rsp->options & ~BIT_6) {
+ reg = &ha->iobase->isp24;
+ spin_lock_irq(&ha->hardware_lock);
+ WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
+ RD_REG_DWORD_RELAXED(&reg->hccr);
+ spin_unlock_irq(&ha->hardware_lock);
+ }
queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work);
return IRQ_HANDLED;
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index a47d34308a3..2a4c7f4e7b6 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -696,6 +696,10 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
/* Use alternate PCI devfn */
if (LSB(rsp->rid))
options |= BIT_5;
+ /* Enable MSIX handshake mode on for uncapable adapters */
+ if (!IS_MSIX_NACK_CAPABLE(ha))
+ options |= BIT_6;
+
rsp->options = options;
rsp->id = que_id;
reg = ISP_QUE_REG(ha, que_id);
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 41669357b18..2f873d23732 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -78,21 +78,6 @@ module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xmaxqdepth,
"Maximum queue depth to report for target devices.");
-int ql2xqfulltracking = 1;
-module_param(ql2xqfulltracking, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(ql2xqfulltracking,
- "Controls whether the driver tracks queue full status "
- "returns and dynamically adjusts a scsi device's queue "
- "depth. Default is 1, perform tracking. Set to 0 to "
- "disable dynamic tracking and adjustment of queue depth.");
-
-int ql2xqfullrampup = 120;
-module_param(ql2xqfullrampup, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(ql2xqfullrampup,
- "Number of seconds to wait to begin to ramp-up the queue "
- "depth for a device after a queue-full condition has been "
- "detected. Default is 120 seconds.");
-
int ql2xiidmaenable=1;
module_param(ql2xiidmaenable, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xiidmaenable,
@@ -1217,13 +1202,61 @@ qla2xxx_slave_destroy(struct scsi_device *sdev)
sdev->hostdata = NULL;
}
+static void qla2x00_handle_queue_full(struct scsi_device *sdev, int qdepth)
+{
+ fc_port_t *fcport = (struct fc_port *) sdev->hostdata;
+
+ if (!scsi_track_queue_full(sdev, qdepth))
+ return;
+
+ DEBUG2(qla_printk(KERN_INFO, fcport->vha->hw,
+ "scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
+ fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
+ sdev->queue_depth));
+}
+
+static void qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, int qdepth)
+{
+ fc_port_t *fcport = sdev->hostdata;
+ struct scsi_qla_host *vha = fcport->vha;
+ struct qla_hw_data *ha = vha->hw;
+ struct req_que *req = NULL;
+
+ req = vha->req;
+ if (!req)
+ return;
+
+ if (req->max_q_depth <= sdev->queue_depth || req->max_q_depth < qdepth)
+ return;
+
+ if (sdev->ordered_tags)
+ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, qdepth);
+ else
+ scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, qdepth);
+
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "scsi(%ld:%d:%d:%d): Queue depth adjusted-up to %d.\n",
+ fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
+ sdev->queue_depth));
+}
+
static int
qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
{
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
+ switch (reason) {
+ case SCSI_QDEPTH_DEFAULT:
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+ break;
+ case SCSI_QDEPTH_QFULL:
+ qla2x00_handle_queue_full(sdev, qdepth);
+ break;
+ case SCSI_QDEPTH_RAMP_UP:
+ qla2x00_adjust_sdev_qdepth_up(sdev, qdepth);
+ break;
+ default:
+ return EOPNOTSUPP;
+ }
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
return sdev->queue_depth;
}
@@ -2003,13 +2036,13 @@ skip_dpc:
DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
base_vha->host_no, ha));
- base_vha->flags.init_done = 1;
- base_vha->flags.online = 1;
-
ret = scsi_add_host(host, &pdev->dev);
if (ret)
goto probe_failed;
+ base_vha->flags.init_done = 1;
+ base_vha->flags.online = 1;
+
ha->isp_ops->enable_intrs(ha);
scsi_scan_host(host);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 807e0dbc67f..c482220f7ee 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.03.01-k7"
+#define QLA2XXX_VERSION "8.03.01-k8"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 3
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index e495d381394..d8927681ec8 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -859,6 +859,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
case 0x07: /* operation in progress */
case 0x08: /* Long write in progress */
case 0x09: /* self test in progress */
+ case 0x14: /* space allocation in progress */
action = ACTION_DELAYED_RETRY;
break;
default:
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 6531c91501b..ddfcecd5099 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -649,11 +649,22 @@ static __init int fc_transport_init(void)
return error;
error = transport_class_register(&fc_vport_class);
if (error)
- return error;
+ goto unreg_host_class;
error = transport_class_register(&fc_rport_class);
if (error)
- return error;
- return transport_class_register(&fc_transport_class);
+ goto unreg_vport_class;
+ error = transport_class_register(&fc_transport_class);
+ if (error)
+ goto unreg_rport_class;
+ return 0;
+
+unreg_rport_class:
+ transport_class_unregister(&fc_rport_class);
+unreg_vport_class:
+ transport_class_unregister(&fc_vport_class);
+unreg_host_class:
+ transport_class_unregister(&fc_host_class);
+ return error;
}
static void __exit fc_transport_exit(void)
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 9093c7261f3..255da53e5a0 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -264,6 +264,15 @@ sd_show_app_tag_own(struct device *dev, struct device_attribute *attr,
return snprintf(buf, 20, "%u\n", sdkp->ATO);
}
+static ssize_t
+sd_show_thin_provisioning(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_disk *sdkp = to_scsi_disk(dev);
+
+ return snprintf(buf, 20, "%u\n", sdkp->thin_provisioning);
+}
+
static struct device_attribute sd_disk_attrs[] = {
__ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type,
sd_store_cache_type),
@@ -274,6 +283,7 @@ static struct device_attribute sd_disk_attrs[] = {
sd_store_manage_start_stop),
__ATTR(protection_type, S_IRUGO, sd_show_protection_type, NULL),
__ATTR(app_tag_own, S_IRUGO, sd_show_app_tag_own, NULL),
+ __ATTR(thin_provisioning, S_IRUGO, sd_show_thin_provisioning, NULL),
__ATTR_NULL,
};
@@ -399,6 +409,57 @@ static void sd_prot_op(struct scsi_cmnd *scmd, unsigned int dif)
}
/**
+ * sd_prepare_discard - unmap blocks on thinly provisioned device
+ * @rq: Request to prepare
+ *
+ * Will issue either UNMAP or WRITE SAME(16) depending on preference
+ * indicated by target device.
+ **/
+static int sd_prepare_discard(struct request *rq)
+{
+ struct scsi_disk *sdkp = scsi_disk(rq->rq_disk);
+ struct bio *bio = rq->bio;
+ sector_t sector = bio->bi_sector;
+ unsigned int num = bio_sectors(bio);
+
+ if (sdkp->device->sector_size == 4096) {
+ sector >>= 3;
+ num >>= 3;
+ }
+
+ rq->cmd_type = REQ_TYPE_BLOCK_PC;
+ rq->timeout = SD_TIMEOUT;
+
+ memset(rq->cmd, 0, rq->cmd_len);
+
+ if (sdkp->unmap) {
+ char *buf = kmap_atomic(bio_page(bio), KM_USER0);
+
+ rq->cmd[0] = UNMAP;
+ rq->cmd[8] = 24;
+ rq->cmd_len = 10;
+
+ /* Ensure that data length matches payload */
+ rq->__data_len = bio->bi_size = bio->bi_io_vec->bv_len = 24;
+
+ put_unaligned_be16(6 + 16, &buf[0]);
+ put_unaligned_be16(16, &buf[2]);
+ put_unaligned_be64(sector, &buf[8]);
+ put_unaligned_be32(num, &buf[16]);
+
+ kunmap_atomic(buf, KM_USER0);
+ } else {
+ rq->cmd[0] = WRITE_SAME_16;
+ rq->cmd[1] = 0x8; /* UNMAP */
+ put_unaligned_be64(sector, &rq->cmd[2]);
+ put_unaligned_be32(num, &rq->cmd[10]);
+ rq->cmd_len = 16;
+ }
+
+ return BLKPREP_OK;
+}
+
+/**
* sd_init_command - build a scsi (read or write) command from
* information in the request structure.
* @SCpnt: pointer to mid-level's per scsi command structure that
@@ -418,6 +479,13 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
int ret, host_dif;
unsigned char protect;
+ /*
+ * Discard request come in as REQ_TYPE_FS but we turn them into
+ * block PC requests to make life easier.
+ */
+ if (blk_discard_rq(rq))
+ ret = sd_prepare_discard(rq);
+
if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
ret = scsi_setup_blk_pc_cmnd(sdp, rq);
goto out;
@@ -1432,6 +1500,19 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
sd_printk(KERN_NOTICE, sdkp,
"physical block alignment offset: %u\n", alignment);
+ if (buffer[14] & 0x80) { /* TPE */
+ struct request_queue *q = sdp->request_queue;
+
+ sdkp->thin_provisioning = 1;
+ q->limits.discard_granularity = sdkp->hw_sector_size;
+ q->limits.max_discard_sectors = 0xffffffff;
+
+ if (buffer[14] & 0x40) /* TPRZ */
+ q->limits.discard_zeroes_data = 1;
+
+ queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
+ }
+
sdkp->capacity = lba + 1;
return sector_size;
}
@@ -1863,6 +1944,7 @@ void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer)
*/
static void sd_read_block_limits(struct scsi_disk *sdkp)
{
+ struct request_queue *q = sdkp->disk->queue;
unsigned int sector_sz = sdkp->device->sector_size;
char *buffer;
@@ -1877,6 +1959,31 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
blk_queue_io_opt(sdkp->disk->queue,
get_unaligned_be32(&buffer[12]) * sector_sz);
+ /* Thin provisioning enabled and page length indicates TP support */
+ if (sdkp->thin_provisioning && buffer[3] == 0x3c) {
+ unsigned int lba_count, desc_count, granularity;
+
+ lba_count = get_unaligned_be32(&buffer[20]);
+ desc_count = get_unaligned_be32(&buffer[24]);
+
+ if (lba_count) {
+ q->limits.max_discard_sectors =
+ lba_count * sector_sz >> 9;
+
+ if (desc_count)
+ sdkp->unmap = 1;
+ }
+
+ granularity = get_unaligned_be32(&buffer[28]);
+
+ if (granularity)
+ q->limits.discard_granularity = granularity * sector_sz;
+
+ if (buffer[32] & 0x80)
+ q->limits.discard_alignment =
+ get_unaligned_be32(&buffer[32]) & ~(1 << 31);
+ }
+
kfree(buffer);
}
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index e374804d26f..43d3caf268e 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -60,6 +60,8 @@ struct scsi_disk {
unsigned RCD : 1; /* state of disk RCD bit, unused */
unsigned DPOFUA : 1; /* state of disk DPOFUA bit */
unsigned first_scan : 1;
+ unsigned thin_provisioning : 1;
+ unsigned unmap : 1;
};
#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index ad59abb4772..d04ea9a6f67 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -552,13 +552,15 @@ st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd
SRpnt->waiting = waiting;
if (STp->buffer->do_dio) {
+ mdata->page_order = 0;
mdata->nr_entries = STp->buffer->sg_segs;
mdata->pages = STp->buffer->mapped_pages;
} else {
+ mdata->page_order = STp->buffer->reserved_page_order;
mdata->nr_entries =
DIV_ROUND_UP(bytes, PAGE_SIZE << mdata->page_order);
- STp->buffer->map_data.pages = STp->buffer->reserved_pages;
- STp->buffer->map_data.offset = 0;
+ mdata->pages = STp->buffer->reserved_pages;
+ mdata->offset = 0;
}
memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd));
@@ -3719,7 +3721,7 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm
priority |= __GFP_ZERO;
if (STbuffer->frp_segs) {
- order = STbuffer->map_data.page_order;
+ order = STbuffer->reserved_page_order;
b_size = PAGE_SIZE << order;
} else {
for (b_size = PAGE_SIZE, order = 0;
@@ -3752,7 +3754,7 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm
segs++;
}
STbuffer->b_data = page_address(STbuffer->reserved_pages[0]);
- STbuffer->map_data.page_order = order;
+ STbuffer->reserved_page_order = order;
return 1;
}
@@ -3765,7 +3767,7 @@ static void clear_buffer(struct st_buffer * st_bp)
for (i=0; i < st_bp->frp_segs; i++)
memset(page_address(st_bp->reserved_pages[i]), 0,
- PAGE_SIZE << st_bp->map_data.page_order);
+ PAGE_SIZE << st_bp->reserved_page_order);
st_bp->cleared = 1;
}
@@ -3773,7 +3775,7 @@ static void clear_buffer(struct st_buffer * st_bp)
/* Release the extra buffer */
static void normalize_buffer(struct st_buffer * STbuffer)
{
- int i, order = STbuffer->map_data.page_order;
+ int i, order = STbuffer->reserved_page_order;
for (i = 0; i < STbuffer->frp_segs; i++) {
__free_pages(STbuffer->reserved_pages[i], order);
@@ -3781,7 +3783,7 @@ static void normalize_buffer(struct st_buffer * STbuffer)
}
STbuffer->frp_segs = 0;
STbuffer->sg_segs = 0;
- STbuffer->map_data.page_order = 0;
+ STbuffer->reserved_page_order = 0;
STbuffer->map_data.offset = 0;
}
@@ -3791,7 +3793,7 @@ static void normalize_buffer(struct st_buffer * STbuffer)
static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, int do_count)
{
int i, cnt, res, offset;
- int length = PAGE_SIZE << st_bp->map_data.page_order;
+ int length = PAGE_SIZE << st_bp->reserved_page_order;
for (i = 0, offset = st_bp->buffer_bytes;
i < st_bp->frp_segs && offset >= length; i++)
@@ -3823,7 +3825,7 @@ static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, in
static int from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count)
{
int i, cnt, res, offset;
- int length = PAGE_SIZE << st_bp->map_data.page_order;
+ int length = PAGE_SIZE << st_bp->reserved_page_order;
for (i = 0, offset = st_bp->read_pointer;
i < st_bp->frp_segs && offset >= length; i++)
@@ -3856,7 +3858,7 @@ static void move_buffer_data(struct st_buffer * st_bp, int offset)
{
int src_seg, dst_seg, src_offset = 0, dst_offset;
int count, total;
- int length = PAGE_SIZE << st_bp->map_data.page_order;
+ int length = PAGE_SIZE << st_bp->reserved_page_order;
if (offset == 0)
return;
@@ -4578,7 +4580,6 @@ static int sgl_map_user_pages(struct st_buffer *STbp,
}
mdata->offset = uaddr & ~PAGE_MASK;
- mdata->page_order = 0;
STbp->mapped_pages = pages;
return nr_pages;
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index 544dc6b1f54..f91a67c6d96 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -46,6 +46,7 @@ struct st_buffer {
struct st_request *last_SRpnt;
struct st_cmdstatus cmdstat;
struct page **reserved_pages;
+ int reserved_page_order;
struct page **mapped_pages;
struct rq_map_data map_data;
unsigned char *b_data;
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 68c7f6cfd72..37f0de9dd9c 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -222,9 +222,9 @@ static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
Set SCP6MD1,0 = {01} (output) */
__raw_writew((data & 0x0fcf) | 0x1000, SCPCR);
- data = ctrl_inb(SCPDR);
+ data = __raw_readb(SCPDR);
/* Set /RTS2 (bit6) = 0 */
- ctrl_outb(data & 0xbf, SCPDR);
+ __raw_writeb(data & 0xbf, SCPDR);
}
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
@@ -897,11 +897,21 @@ static void sci_shutdown(struct uart_port *port)
static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
- unsigned int status, baud, smr_val;
+ unsigned int status, baud, smr_val, max_baud;
int t = -1;
- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
- if (likely(baud))
+ /*
+ * earlyprintk comes here early on with port->uartclk set to zero.
+ * the clock framework is not up and running at this point so here
+ * we assume that 115200 is the maximum baud rate. please note that
+ * the baud rate is not programmed during earlyprintk - it is assumed
+ * that the previous boot loader has enabled required clocks and
+ * setup the baud rate generator hardware for us already.
+ */
+ max_baud = port->uartclk ? port->uartclk / 16 : 115200;
+
+ baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
+ if (likely(baud && port->uartclk))
t = SCBRR_VALUE(baud, port->uartclk);
do {
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index a32094eeb42..0efcded59ae 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -517,20 +517,20 @@ static const struct __attribute__((packed)) {
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xfffffe80)
- return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCI */
+ return __raw_readb(SCPDR)&0x01 ? 1 : 0; /* SCI */
if (port->mapbase == 0xa4000150)
- return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */
+ return __raw_readb(SCPDR)&0x10 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xa4000140)
- return ctrl_inb(SCPDR)&0x04 ? 1 : 0; /* IRDA */
+ return __raw_readb(SCPDR)&0x04 ? 1 : 0; /* IRDA */
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == SCIF0)
- return ctrl_inb(SCPDR)&0x04 ? 1 : 0; /* IRDA */
+ return __raw_readb(SCPDR)&0x04 ? 1 : 0; /* IRDA */
if (port->mapbase == SCIF2)
- return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */
+ return __raw_readb(SCPDR)&0x10 ? 1 : 0; /* SCIF */
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
@@ -557,68 +557,68 @@ static inline int sci_rxd_in(struct uart_port *port)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xffe00000)
- return ctrl_inb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */
+ return __raw_readb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */
if (port->mapbase == 0xffe80000)
- return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xffe80000)
- return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7757)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xfe4b0000)
- return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0;
+ return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0;
if (port->mapbase == 0xfe4c0000)
- return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0;
+ return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0;
if (port->mapbase == 0xfe4d0000)
- return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0;
+ return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xfe600000)
- return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xfe610000)
- return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xfe620000)
- return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xffe00000)
- return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffe10000)
- return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffe20000)
- return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffe30000)
- return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7366)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xffe00000)
- return ctrl_inb(SCPDR0) & 0x0001 ? 1 : 0; /* SCIF0 */
+ return __raw_readb(SCPDR0) & 0x0001 ? 1 : 0; /* SCIF0 */
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xffe00000)
- return ctrl_inb(PSDR) & 0x02 ? 1 : 0; /* SCIF0 */
+ return __raw_readb(PSDR) & 0x02 ? 1 : 0; /* SCIF0 */
if (port->mapbase == 0xffe10000)
- return ctrl_inb(PADR) & 0x40 ? 1 : 0; /* SCIF1 */
+ return __raw_readb(PADR) & 0x40 ? 1 : 0; /* SCIF1 */
if (port->mapbase == 0xffe20000)
- return ctrl_inb(PWDR) & 0x04 ? 1 : 0; /* SCIF2 */
+ return __raw_readb(PWDR) & 0x04 ? 1 : 0; /* SCIF2 */
return 1;
}
@@ -626,17 +626,17 @@ static inline int sci_rxd_in(struct uart_port *port)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xffe00000)
- return ctrl_inb(SCSPTR0) & 0x0008 ? 1 : 0; /* SCIF0 */
+ return __raw_readb(SCSPTR0) & 0x0008 ? 1 : 0; /* SCIF0 */
if (port->mapbase == 0xffe10000)
- return ctrl_inb(SCSPTR1) & 0x0020 ? 1 : 0; /* SCIF1 */
+ return __raw_readb(SCSPTR1) & 0x0020 ? 1 : 0; /* SCIF1 */
if (port->mapbase == 0xffe20000)
- return ctrl_inb(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF2 */
+ return __raw_readb(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF2 */
if (port->mapbase == 0xa4e30000)
- return ctrl_inb(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF3 */
+ return __raw_readb(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF3 */
if (port->mapbase == 0xa4e40000)
- return ctrl_inb(SCSPTR4) & 0x0001 ? 1 : 0; /* SCIF4 */
+ return __raw_readb(SCSPTR4) & 0x0001 ? 1 : 0; /* SCIF4 */
if (port->mapbase == 0xa4e50000)
- return ctrl_inb(SCSPTR5) & 0x0008 ? 1 : 0; /* SCIF5 */
+ return __raw_readb(SCSPTR5) & 0x0008 ? 1 : 0; /* SCIF5 */
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
@@ -645,9 +645,9 @@ static inline int sci_rxd_in(struct uart_port *port)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->type == PORT_SCIF)
- return ctrl_inw((port->mapbase + SCFSR)) & SCIF_BRK ? 1 : 0;
+ return __raw_readw((port->mapbase + SCFSR)) & SCIF_BRK ? 1 : 0;
if (port->type == PORT_SCIFA)
- return ctrl_inw((port->mapbase + SCASSR)) & SCIF_BRK ? 1 : 0;
+ return __raw_readw((port->mapbase + SCASSR)) & SCIF_BRK ? 1 : 0;
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
@@ -665,11 +665,11 @@ static inline int sci_rxd_in(struct uart_port *port)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xffe00000)
- return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffe08000)
- return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffe10000)
- return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF/IRDA */
+ return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF/IRDA */
return 1;
}
@@ -677,20 +677,20 @@ static inline int sci_rxd_in(struct uart_port *port)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xff923000)
- return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xff924000)
- return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xff925000)
- return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xffe00000)
- return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffe10000)
- return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \
@@ -698,17 +698,17 @@ static inline int sci_rxd_in(struct uart_port *port)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xffea0000)
- return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffeb0000)
- return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffec0000)
- return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffed0000)
- return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffee0000)
- return ctrl_inw(SCSPTR4) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR4) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffef0000)
- return ctrl_inw(SCSPTR5) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR5) & 0x0001 ? 1 : 0; /* SCIF */
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \
@@ -718,22 +718,22 @@ static inline int sci_rxd_in(struct uart_port *port)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xfffe8000)
- return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xfffe8800)
- return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xfffe9000)
- return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xfffe9800)
- return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
#if defined(CONFIG_CPU_SUBTYPE_SH7201)
if (port->mapbase == 0xfffeA000)
- return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xfffeA800)
- return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xfffeB000)
- return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xfffeB800)
- return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
#endif
return 1;
}
@@ -741,24 +741,24 @@ static inline int sci_rxd_in(struct uart_port *port)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xf8400000)
- return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xf8410000)
- return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xf8420000)
- return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SHX3)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xffc30000)
- return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffc40000)
- return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffc50000)
- return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffc60000)
- return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+ return __raw_readw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
return 1;
}
#endif
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 2d9d7035936..f55eb010733 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -216,6 +216,17 @@ config SPI_S3C24XX
help
SPI driver for Samsung S3C24XX series ARM SoCs
+config SPI_S3C24XX_FIQ
+ bool "S3C24XX driver with FIQ pseudo-DMA"
+ depends on SPI_S3C24XX
+ select FIQ
+ help
+ Enable FIQ support for the S3C24XX SPI driver to provide pseudo
+ DMA by using the fast-interrupt request framework, This allows
+ the driver to get DMA-like performance when there are either
+ no free DMA channels, or when doing transfers that required both
+ TX and RX data paths.
+
config SPI_S3C24XX_GPIO
tristate "Samsung S3C24XX series SPI by GPIO"
depends on ARCH_S3C2410 && EXPERIMENTAL
@@ -226,6 +237,13 @@ config SPI_S3C24XX_GPIO
the inbuilt hardware cannot provide the transfer mode, or
where the board is using non hardware connected pins.
+config SPI_S3C64XX
+ tristate "Samsung S3C64XX series type SPI"
+ depends on ARCH_S3C64XX && EXPERIMENTAL
+ select S3C64XX_DMA
+ help
+ SPI driver for Samsung S3C64XX and newer SoCs.
+
config SPI_SH_MSIOF
tristate "SuperH MSIOF SPI controller"
depends on SUPERH && HAVE_CLK
@@ -289,6 +307,16 @@ config SPI_NUC900
# Add new SPI master controllers in alphabetical order above this line
#
+config SPI_DESIGNWARE
+ bool "DesignWare SPI controller core support"
+ depends on SPI_MASTER
+ help
+ general driver for SPI controller core from DesignWare
+
+config SPI_DW_PCI
+ tristate "PCI interface driver for DW SPI core"
+ depends on SPI_DESIGNWARE && PCI
+
#
# There are lots of SPI device types, with sensors and memory
# being probably the most widely used ones.
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index ed8c1675b52..f3d2810ba11 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -16,6 +16,8 @@ obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o
obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
obj-$(CONFIG_SPI_AU1550) += au1550_spi.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
+obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o
+obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o
obj-$(CONFIG_SPI_GPIO) += spi_gpio.o
obj-$(CONFIG_SPI_IMX) += spi_imx.o
obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o
@@ -30,7 +32,8 @@ obj-$(CONFIG_SPI_MPC52xx) += mpc52xx_spi.o
obj-$(CONFIG_SPI_MPC8xxx) += spi_mpc8xxx.o
obj-$(CONFIG_SPI_PPC4xx) += spi_ppc4xx.o
obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
-obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
+obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx_hw.o
+obj-$(CONFIG_SPI_S3C64XX) += spi_s3c64xx.o
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
obj-$(CONFIG_SPI_XILINX_OF) += xilinx_spi_of.o
@@ -39,6 +42,11 @@ obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o
obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o
+
+# special build for s3c24xx spi driver with fiq support
+spi_s3c24xx_hw-y := spi_s3c24xx.o
+spi_s3c24xx_hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi_s3c24xx_fiq.o
+
# ... add above this line ...
# SPI protocol drivers (device/link on bus)
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index f5b3fdbb1e2..d21c24eaf0a 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -189,14 +189,14 @@ static void atmel_spi_next_xfer_data(struct spi_master *master,
/* use scratch buffer only when rx or tx data is unspecified */
if (xfer->rx_buf)
- *rx_dma = xfer->rx_dma + xfer->len - len;
+ *rx_dma = xfer->rx_dma + xfer->len - *plen;
else {
*rx_dma = as->buffer_dma;
if (len > BUFFER_SIZE)
len = BUFFER_SIZE;
}
if (xfer->tx_buf)
- *tx_dma = xfer->tx_dma + xfer->len - len;
+ *tx_dma = xfer->tx_dma + xfer->len - *plen;
else {
*tx_dma = as->buffer_dma;
if (len > BUFFER_SIZE)
@@ -788,7 +788,7 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
spin_lock_init(&as->lock);
INIT_LIST_HEAD(&as->queue);
as->pdev = pdev;
- as->regs = ioremap(regs->start, (regs->end - regs->start) + 1);
+ as->regs = ioremap(regs->start, resource_size(regs));
if (!as->regs)
goto out_free_buffer;
as->irq = irq;
diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c
new file mode 100644
index 00000000000..31620fae77b
--- /dev/null
+++ b/drivers/spi/dw_spi.c
@@ -0,0 +1,944 @@
+/*
+ * dw_spi.c - Designware SPI core controller driver (refer pxa2xx_spi.c)
+ *
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/highmem.h>
+#include <linux/delay.h>
+
+#include <linux/spi/dw_spi.h>
+#include <linux/spi/spi.h>
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#endif
+
+#define START_STATE ((void *)0)
+#define RUNNING_STATE ((void *)1)
+#define DONE_STATE ((void *)2)
+#define ERROR_STATE ((void *)-1)
+
+#define QUEUE_RUNNING 0
+#define QUEUE_STOPPED 1
+
+#define MRST_SPI_DEASSERT 0
+#define MRST_SPI_ASSERT 1
+
+/* Slave spi_dev related */
+struct chip_data {
+ u16 cr0;
+ u8 cs; /* chip select pin */
+ u8 n_bytes; /* current is a 1/2/4 byte op */
+ u8 tmode; /* TR/TO/RO/EEPROM */
+ u8 type; /* SPI/SSP/MicroWire */
+
+ u8 poll_mode; /* 1 means use poll mode */
+
+ u32 dma_width;
+ u32 rx_threshold;
+ u32 tx_threshold;
+ u8 enable_dma;
+ u8 bits_per_word;
+ u16 clk_div; /* baud rate divider */
+ u32 speed_hz; /* baud rate */
+ int (*write)(struct dw_spi *dws);
+ int (*read)(struct dw_spi *dws);
+ void (*cs_control)(u32 command);
+};
+
+#ifdef CONFIG_DEBUG_FS
+static int spi_show_regs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+#define SPI_REGS_BUFSIZE 1024
+static ssize_t spi_show_regs(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct dw_spi *dws;
+ char *buf;
+ u32 len = 0;
+ ssize_t ret;
+
+ dws = file->private_data;
+
+ buf = kzalloc(SPI_REGS_BUFSIZE, GFP_KERNEL);
+ if (!buf)
+ return 0;
+
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "MRST SPI0 registers:\n");
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "=================================\n");
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "CTRL0: \t\t0x%08x\n", dw_readl(dws, ctrl0));
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "CTRL1: \t\t0x%08x\n", dw_readl(dws, ctrl1));
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "SSIENR: \t0x%08x\n", dw_readl(dws, ssienr));
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "SER: \t\t0x%08x\n", dw_readl(dws, ser));
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "BAUDR: \t\t0x%08x\n", dw_readl(dws, baudr));
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "TXFTLR: \t0x%08x\n", dw_readl(dws, txfltr));
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "RXFTLR: \t0x%08x\n", dw_readl(dws, rxfltr));
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "TXFLR: \t\t0x%08x\n", dw_readl(dws, txflr));
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "RXFLR: \t\t0x%08x\n", dw_readl(dws, rxflr));
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "SR: \t\t0x%08x\n", dw_readl(dws, sr));
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "IMR: \t\t0x%08x\n", dw_readl(dws, imr));
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "ISR: \t\t0x%08x\n", dw_readl(dws, isr));
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "DMACR: \t\t0x%08x\n", dw_readl(dws, dmacr));
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "DMATDLR: \t0x%08x\n", dw_readl(dws, dmatdlr));
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "DMARDLR: \t0x%08x\n", dw_readl(dws, dmardlr));
+ len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
+ "=================================\n");
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations mrst_spi_regs_ops = {
+ .owner = THIS_MODULE,
+ .open = spi_show_regs_open,
+ .read = spi_show_regs,
+};
+
+static int mrst_spi_debugfs_init(struct dw_spi *dws)
+{
+ dws->debugfs = debugfs_create_dir("mrst_spi", NULL);
+ if (!dws->debugfs)
+ return -ENOMEM;
+
+ debugfs_create_file("registers", S_IFREG | S_IRUGO,
+ dws->debugfs, (void *)dws, &mrst_spi_regs_ops);
+ return 0;
+}
+
+static void mrst_spi_debugfs_remove(struct dw_spi *dws)
+{
+ if (dws->debugfs)
+ debugfs_remove_recursive(dws->debugfs);
+}
+
+#else
+static inline int mrst_spi_debugfs_init(struct dw_spi *dws)
+{
+}
+
+static inline void mrst_spi_debugfs_remove(struct dw_spi *dws)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static void wait_till_not_busy(struct dw_spi *dws)
+{
+ unsigned long end = jiffies + usecs_to_jiffies(1000);
+
+ while (time_before(jiffies, end)) {
+ if (!(dw_readw(dws, sr) & SR_BUSY))
+ return;
+ }
+ dev_err(&dws->master->dev,
+ "DW SPI: Stutus keeps busy for 1000us after a read/write!\n");
+}
+
+static void flush(struct dw_spi *dws)
+{
+ while (dw_readw(dws, sr) & SR_RF_NOT_EMPT)
+ dw_readw(dws, dr);
+
+ wait_till_not_busy(dws);
+}
+
+static void null_cs_control(u32 command)
+{
+}
+
+static int null_writer(struct dw_spi *dws)
+{
+ u8 n_bytes = dws->n_bytes;
+
+ if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL)
+ || (dws->tx == dws->tx_end))
+ return 0;
+ dw_writew(dws, dr, 0);
+ dws->tx += n_bytes;
+
+ wait_till_not_busy(dws);
+ return 1;
+}
+
+static int null_reader(struct dw_spi *dws)
+{
+ u8 n_bytes = dws->n_bytes;
+
+ while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT)
+ && (dws->rx < dws->rx_end)) {
+ dw_readw(dws, dr);
+ dws->rx += n_bytes;
+ }
+ wait_till_not_busy(dws);
+ return dws->rx == dws->rx_end;
+}
+
+static int u8_writer(struct dw_spi *dws)
+{
+ if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL)
+ || (dws->tx == dws->tx_end))
+ return 0;
+
+ dw_writew(dws, dr, *(u8 *)(dws->tx));
+ ++dws->tx;
+
+ wait_till_not_busy(dws);
+ return 1;
+}
+
+static int u8_reader(struct dw_spi *dws)
+{
+ while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT)
+ && (dws->rx < dws->rx_end)) {
+ *(u8 *)(dws->rx) = dw_readw(dws, dr);
+ ++dws->rx;
+ }
+
+ wait_till_not_busy(dws);
+ return dws->rx == dws->rx_end;
+}
+
+static int u16_writer(struct dw_spi *dws)
+{
+ if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL)
+ || (dws->tx == dws->tx_end))
+ return 0;
+
+ dw_writew(dws, dr, *(u16 *)(dws->tx));
+ dws->tx += 2;
+
+ wait_till_not_busy(dws);
+ return 1;
+}
+
+static int u16_reader(struct dw_spi *dws)
+{
+ u16 temp;
+
+ while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT)
+ && (dws->rx < dws->rx_end)) {
+ temp = dw_readw(dws, dr);
+ *(u16 *)(dws->rx) = temp;
+ dws->rx += 2;
+ }
+
+ wait_till_not_busy(dws);
+ return dws->rx == dws->rx_end;
+}
+
+static void *next_transfer(struct dw_spi *dws)
+{
+ struct spi_message *msg = dws->cur_msg;
+ struct spi_transfer *trans = dws->cur_transfer;
+
+ /* Move to next transfer */
+ if (trans->transfer_list.next != &msg->transfers) {
+ dws->cur_transfer =
+ list_entry(trans->transfer_list.next,
+ struct spi_transfer,
+ transfer_list);
+ return RUNNING_STATE;
+ } else
+ return DONE_STATE;
+}
+
+/*
+ * Note: first step is the protocol driver prepares
+ * a dma-capable memory, and this func just need translate
+ * the virt addr to physical
+ */
+static int map_dma_buffers(struct dw_spi *dws)
+{
+ if (!dws->cur_msg->is_dma_mapped || !dws->dma_inited
+ || !dws->cur_chip->enable_dma)
+ return 0;
+
+ if (dws->cur_transfer->tx_dma)
+ dws->tx_dma = dws->cur_transfer->tx_dma;
+
+ if (dws->cur_transfer->rx_dma)
+ dws->rx_dma = dws->cur_transfer->rx_dma;
+
+ return 1;
+}
+
+/* Caller already set message->status; dma and pio irqs are blocked */
+static void giveback(struct dw_spi *dws)
+{
+ struct spi_transfer *last_transfer;
+ unsigned long flags;
+ struct spi_message *msg;
+
+ spin_lock_irqsave(&dws->lock, flags);
+ msg = dws->cur_msg;
+ dws->cur_msg = NULL;
+ dws->cur_transfer = NULL;
+ dws->prev_chip = dws->cur_chip;
+ dws->cur_chip = NULL;
+ dws->dma_mapped = 0;
+ queue_work(dws->workqueue, &dws->pump_messages);
+ spin_unlock_irqrestore(&dws->lock, flags);
+
+ last_transfer = list_entry(msg->transfers.prev,
+ struct spi_transfer,
+ transfer_list);
+
+ if (!last_transfer->cs_change)
+ dws->cs_control(MRST_SPI_DEASSERT);
+
+ msg->state = NULL;
+ if (msg->complete)
+ msg->complete(msg->context);
+}
+
+static void int_error_stop(struct dw_spi *dws, const char *msg)
+{
+ /* Stop and reset hw */
+ flush(dws);
+ spi_enable_chip(dws, 0);
+
+ dev_err(&dws->master->dev, "%s\n", msg);
+ dws->cur_msg->state = ERROR_STATE;
+ tasklet_schedule(&dws->pump_transfers);
+}
+
+static void transfer_complete(struct dw_spi *dws)
+{
+ /* Update total byte transfered return count actual bytes read */
+ dws->cur_msg->actual_length += dws->len;
+
+ /* Move to next transfer */
+ dws->cur_msg->state = next_transfer(dws);
+
+ /* Handle end of message */
+ if (dws->cur_msg->state == DONE_STATE) {
+ dws->cur_msg->status = 0;
+ giveback(dws);
+ } else
+ tasklet_schedule(&dws->pump_transfers);
+}
+
+static irqreturn_t interrupt_transfer(struct dw_spi *dws)
+{
+ u16 irq_status, irq_mask = 0x3f;
+
+ irq_status = dw_readw(dws, isr) & irq_mask;
+ /* Error handling */
+ if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) {
+ dw_readw(dws, txoicr);
+ dw_readw(dws, rxoicr);
+ dw_readw(dws, rxuicr);
+ int_error_stop(dws, "interrupt_transfer: fifo overrun");
+ return IRQ_HANDLED;
+ }
+
+ /* INT comes from tx */
+ if (dws->tx && (irq_status & SPI_INT_TXEI)) {
+ while (dws->tx < dws->tx_end)
+ dws->write(dws);
+
+ if (dws->tx == dws->tx_end) {
+ spi_mask_intr(dws, SPI_INT_TXEI);
+ transfer_complete(dws);
+ }
+ }
+
+ /* INT comes from rx */
+ if (dws->rx && (irq_status & SPI_INT_RXFI)) {
+ if (dws->read(dws))
+ transfer_complete(dws);
+ }
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t dw_spi_irq(int irq, void *dev_id)
+{
+ struct dw_spi *dws = dev_id;
+
+ if (!dws->cur_msg) {
+ spi_mask_intr(dws, SPI_INT_TXEI);
+ /* Never fail */
+ return IRQ_HANDLED;
+ }
+
+ return dws->transfer_handler(dws);
+}
+
+/* Must be called inside pump_transfers() */
+static void poll_transfer(struct dw_spi *dws)
+{
+ if (dws->tx) {
+ while (dws->write(dws))
+ dws->read(dws);
+ }
+
+ dws->read(dws);
+ transfer_complete(dws);
+}
+
+static void dma_transfer(struct dw_spi *dws, int cs_change)
+{
+}
+
+static void pump_transfers(unsigned long data)
+{
+ struct dw_spi *dws = (struct dw_spi *)data;
+ struct spi_message *message = NULL;
+ struct spi_transfer *transfer = NULL;
+ struct spi_transfer *previous = NULL;
+ struct spi_device *spi = NULL;
+ struct chip_data *chip = NULL;
+ u8 bits = 0;
+ u8 imask = 0;
+ u8 cs_change = 0;
+ u16 clk_div = 0;
+ u32 speed = 0;
+ u32 cr0 = 0;
+
+ /* Get current state information */
+ message = dws->cur_msg;
+ transfer = dws->cur_transfer;
+ chip = dws->cur_chip;
+ spi = message->spi;
+
+ if (message->state == ERROR_STATE) {
+ message->status = -EIO;
+ goto early_exit;
+ }
+
+ /* Handle end of message */
+ if (message->state == DONE_STATE) {
+ message->status = 0;
+ goto early_exit;
+ }
+
+ /* Delay if requested at end of transfer*/
+ if (message->state == RUNNING_STATE) {
+ previous = list_entry(transfer->transfer_list.prev,
+ struct spi_transfer,
+ transfer_list);
+ if (previous->delay_usecs)
+ udelay(previous->delay_usecs);
+ }
+
+ dws->n_bytes = chip->n_bytes;
+ dws->dma_width = chip->dma_width;
+ dws->cs_control = chip->cs_control;
+
+ dws->rx_dma = transfer->rx_dma;
+ dws->tx_dma = transfer->tx_dma;
+ dws->tx = (void *)transfer->tx_buf;
+ dws->tx_end = dws->tx + transfer->len;
+ dws->rx = transfer->rx_buf;
+ dws->rx_end = dws->rx + transfer->len;
+ dws->write = dws->tx ? chip->write : null_writer;
+ dws->read = dws->rx ? chip->read : null_reader;
+ dws->cs_change = transfer->cs_change;
+ dws->len = dws->cur_transfer->len;
+ if (chip != dws->prev_chip)
+ cs_change = 1;
+
+ cr0 = chip->cr0;
+
+ /* Handle per transfer options for bpw and speed */
+ if (transfer->speed_hz) {
+ speed = chip->speed_hz;
+
+ if (transfer->speed_hz != speed) {
+ speed = transfer->speed_hz;
+ if (speed > dws->max_freq) {
+ printk(KERN_ERR "MRST SPI0: unsupported"
+ "freq: %dHz\n", speed);
+ message->status = -EIO;
+ goto early_exit;
+ }
+
+ /* clk_div doesn't support odd number */
+ clk_div = dws->max_freq / speed;
+ clk_div = (clk_div >> 1) << 1;
+
+ chip->speed_hz = speed;
+ chip->clk_div = clk_div;
+ }
+ }
+ if (transfer->bits_per_word) {
+ bits = transfer->bits_per_word;
+
+ switch (bits) {
+ case 8:
+ dws->n_bytes = 1;
+ dws->dma_width = 1;
+ dws->read = (dws->read != null_reader) ?
+ u8_reader : null_reader;
+ dws->write = (dws->write != null_writer) ?
+ u8_writer : null_writer;
+ break;
+ case 16:
+ dws->n_bytes = 2;
+ dws->dma_width = 2;
+ dws->read = (dws->read != null_reader) ?
+ u16_reader : null_reader;
+ dws->write = (dws->write != null_writer) ?
+ u16_writer : null_writer;
+ break;
+ default:
+ printk(KERN_ERR "MRST SPI0: unsupported bits:"
+ "%db\n", bits);
+ message->status = -EIO;
+ goto early_exit;
+ }
+
+ cr0 = (bits - 1)
+ | (chip->type << SPI_FRF_OFFSET)
+ | (spi->mode << SPI_MODE_OFFSET)
+ | (chip->tmode << SPI_TMOD_OFFSET);
+ }
+ message->state = RUNNING_STATE;
+
+ /* Check if current transfer is a DMA transaction */
+ dws->dma_mapped = map_dma_buffers(dws);
+
+ if (!dws->dma_mapped && !chip->poll_mode) {
+ if (dws->rx)
+ imask |= SPI_INT_RXFI;
+ if (dws->tx)
+ imask |= SPI_INT_TXEI;
+ dws->transfer_handler = interrupt_transfer;
+ }
+
+ /*
+ * Reprogram registers only if
+ * 1. chip select changes
+ * 2. clk_div is changed
+ * 3. control value changes
+ */
+ if (dw_readw(dws, ctrl0) != cr0 || cs_change || clk_div) {
+ spi_enable_chip(dws, 0);
+
+ if (dw_readw(dws, ctrl0) != cr0)
+ dw_writew(dws, ctrl0, cr0);
+
+ /* Set the interrupt mask, for poll mode just diable all int */
+ spi_mask_intr(dws, 0xff);
+ if (!chip->poll_mode)
+ spi_umask_intr(dws, imask);
+
+ spi_set_clk(dws, clk_div ? clk_div : chip->clk_div);
+ spi_chip_sel(dws, spi->chip_select);
+ spi_enable_chip(dws, 1);
+
+ if (cs_change)
+ dws->prev_chip = chip;
+ }
+
+ if (dws->dma_mapped)
+ dma_transfer(dws, cs_change);
+
+ if (chip->poll_mode)
+ poll_transfer(dws);
+
+ return;
+
+early_exit:
+ giveback(dws);
+ return;
+}
+
+static void pump_messages(struct work_struct *work)
+{
+ struct dw_spi *dws =
+ container_of(work, struct dw_spi, pump_messages);
+ unsigned long flags;
+
+ /* Lock queue and check for queue work */
+ spin_lock_irqsave(&dws->lock, flags);
+ if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) {
+ dws->busy = 0;
+ spin_unlock_irqrestore(&dws->lock, flags);
+ return;
+ }
+
+ /* Make sure we are not already running a message */
+ if (dws->cur_msg) {
+ spin_unlock_irqrestore(&dws->lock, flags);
+ return;
+ }
+
+ /* Extract head of queue */
+ dws->cur_msg = list_entry(dws->queue.next, struct spi_message, queue);
+ list_del_init(&dws->cur_msg->queue);
+
+ /* Initial message state*/
+ dws->cur_msg->state = START_STATE;
+ dws->cur_transfer = list_entry(dws->cur_msg->transfers.next,
+ struct spi_transfer,
+ transfer_list);
+ dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi);
+
+ /* Mark as busy and launch transfers */
+ tasklet_schedule(&dws->pump_transfers);
+
+ dws->busy = 1;
+ spin_unlock_irqrestore(&dws->lock, flags);
+}
+
+/* spi_device use this to queue in their spi_msg */
+static int dw_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+ struct dw_spi *dws = spi_master_get_devdata(spi->master);
+ unsigned long flags;
+
+ spin_lock_irqsave(&dws->lock, flags);
+
+ if (dws->run == QUEUE_STOPPED) {
+ spin_unlock_irqrestore(&dws->lock, flags);
+ return -ESHUTDOWN;
+ }
+
+ msg->actual_length = 0;
+ msg->status = -EINPROGRESS;
+ msg->state = START_STATE;
+
+ list_add_tail(&msg->queue, &dws->queue);
+
+ if (dws->run == QUEUE_RUNNING && !dws->busy) {
+
+ if (dws->cur_transfer || dws->cur_msg)
+ queue_work(dws->workqueue,
+ &dws->pump_messages);
+ else {
+ /* If no other data transaction in air, just go */
+ spin_unlock_irqrestore(&dws->lock, flags);
+ pump_messages(&dws->pump_messages);
+ return 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&dws->lock, flags);
+ return 0;
+}
+
+/* This may be called twice for each spi dev */
+static int dw_spi_setup(struct spi_device *spi)
+{
+ struct dw_spi_chip *chip_info = NULL;
+ struct chip_data *chip;
+
+ if (spi->bits_per_word != 8 && spi->bits_per_word != 16)
+ return -EINVAL;
+
+ /* Only alloc on first setup */
+ chip = spi_get_ctldata(spi);
+ if (!chip) {
+ chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->cs_control = null_cs_control;
+ chip->enable_dma = 0;
+ }
+
+ /*
+ * Protocol drivers may change the chip settings, so...
+ * if chip_info exists, use it
+ */
+ chip_info = spi->controller_data;
+
+ /* chip_info doesn't always exist */
+ if (chip_info) {
+ if (chip_info->cs_control)
+ chip->cs_control = chip_info->cs_control;
+
+ chip->poll_mode = chip_info->poll_mode;
+ chip->type = chip_info->type;
+
+ chip->rx_threshold = 0;
+ chip->tx_threshold = 0;
+
+ chip->enable_dma = chip_info->enable_dma;
+ }
+
+ if (spi->bits_per_word <= 8) {
+ chip->n_bytes = 1;
+ chip->dma_width = 1;
+ chip->read = u8_reader;
+ chip->write = u8_writer;
+ } else if (spi->bits_per_word <= 16) {
+ chip->n_bytes = 2;
+ chip->dma_width = 2;
+ chip->read = u16_reader;
+ chip->write = u16_writer;
+ } else {
+ /* Never take >16b case for MRST SPIC */
+ dev_err(&spi->dev, "invalid wordsize\n");
+ return -EINVAL;
+ }
+ chip->bits_per_word = spi->bits_per_word;
+
+ chip->speed_hz = spi->max_speed_hz;
+ if (chip->speed_hz)
+ chip->clk_div = 25000000 / chip->speed_hz;
+ else
+ chip->clk_div = 8; /* default value */
+
+ chip->tmode = 0; /* Tx & Rx */
+ /* Default SPI mode is SCPOL = 0, SCPH = 0 */
+ chip->cr0 = (chip->bits_per_word - 1)
+ | (chip->type << SPI_FRF_OFFSET)
+ | (spi->mode << SPI_MODE_OFFSET)
+ | (chip->tmode << SPI_TMOD_OFFSET);
+
+ spi_set_ctldata(spi, chip);
+ return 0;
+}
+
+static void dw_spi_cleanup(struct spi_device *spi)
+{
+ struct chip_data *chip = spi_get_ctldata(spi);
+ kfree(chip);
+}
+
+static int __init init_queue(struct dw_spi *dws)
+{
+ INIT_LIST_HEAD(&dws->queue);
+ spin_lock_init(&dws->lock);
+
+ dws->run = QUEUE_STOPPED;
+ dws->busy = 0;
+
+ tasklet_init(&dws->pump_transfers,
+ pump_transfers, (unsigned long)dws);
+
+ INIT_WORK(&dws->pump_messages, pump_messages);
+ dws->workqueue = create_singlethread_workqueue(
+ dev_name(dws->master->dev.parent));
+ if (dws->workqueue == NULL)
+ return -EBUSY;
+
+ return 0;
+}
+
+static int start_queue(struct dw_spi *dws)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dws->lock, flags);
+
+ if (dws->run == QUEUE_RUNNING || dws->busy) {
+ spin_unlock_irqrestore(&dws->lock, flags);
+ return -EBUSY;
+ }
+
+ dws->run = QUEUE_RUNNING;
+ dws->cur_msg = NULL;
+ dws->cur_transfer = NULL;
+ dws->cur_chip = NULL;
+ dws->prev_chip = NULL;
+ spin_unlock_irqrestore(&dws->lock, flags);
+
+ queue_work(dws->workqueue, &dws->pump_messages);
+
+ return 0;
+}
+
+static int stop_queue(struct dw_spi *dws)
+{
+ unsigned long flags;
+ unsigned limit = 50;
+ int status = 0;
+
+ spin_lock_irqsave(&dws->lock, flags);
+ dws->run = QUEUE_STOPPED;
+ while (!list_empty(&dws->queue) && dws->busy && limit--) {
+ spin_unlock_irqrestore(&dws->lock, flags);
+ msleep(10);
+ spin_lock_irqsave(&dws->lock, flags);
+ }
+
+ if (!list_empty(&dws->queue) || dws->busy)
+ status = -EBUSY;
+ spin_unlock_irqrestore(&dws->lock, flags);
+
+ return status;
+}
+
+static int destroy_queue(struct dw_spi *dws)
+{
+ int status;
+
+ status = stop_queue(dws);
+ if (status != 0)
+ return status;
+ destroy_workqueue(dws->workqueue);
+ return 0;
+}
+
+/* Restart the controller, disable all interrupts, clean rx fifo */
+static void spi_hw_init(struct dw_spi *dws)
+{
+ spi_enable_chip(dws, 0);
+ spi_mask_intr(dws, 0xff);
+ spi_enable_chip(dws, 1);
+ flush(dws);
+}
+
+int __devinit dw_spi_add_host(struct dw_spi *dws)
+{
+ struct spi_master *master;
+ int ret;
+
+ BUG_ON(dws == NULL);
+
+ master = spi_alloc_master(dws->parent_dev, 0);
+ if (!master) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ dws->master = master;
+ dws->type = SSI_MOTO_SPI;
+ dws->prev_chip = NULL;
+ dws->dma_inited = 0;
+ dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60);
+
+ ret = request_irq(dws->irq, dw_spi_irq, 0,
+ "dw_spi", dws);
+ if (ret < 0) {
+ dev_err(&master->dev, "can not get IRQ\n");
+ goto err_free_master;
+ }
+
+ master->mode_bits = SPI_CPOL | SPI_CPHA;
+ master->bus_num = dws->bus_num;
+ master->num_chipselect = dws->num_cs;
+ master->cleanup = dw_spi_cleanup;
+ master->setup = dw_spi_setup;
+ master->transfer = dw_spi_transfer;
+
+ dws->dma_inited = 0;
+
+ /* Basic HW init */
+ spi_hw_init(dws);
+
+ /* Initial and start queue */
+ ret = init_queue(dws);
+ if (ret) {
+ dev_err(&master->dev, "problem initializing queue\n");
+ goto err_diable_hw;
+ }
+ ret = start_queue(dws);
+ if (ret) {
+ dev_err(&master->dev, "problem starting queue\n");
+ goto err_diable_hw;
+ }
+
+ spi_master_set_devdata(master, dws);
+ ret = spi_register_master(master);
+ if (ret) {
+ dev_err(&master->dev, "problem registering spi master\n");
+ goto err_queue_alloc;
+ }
+
+ mrst_spi_debugfs_init(dws);
+ return 0;
+
+err_queue_alloc:
+ destroy_queue(dws);
+err_diable_hw:
+ spi_enable_chip(dws, 0);
+ free_irq(dws->irq, dws);
+err_free_master:
+ spi_master_put(master);
+exit:
+ return ret;
+}
+EXPORT_SYMBOL(dw_spi_add_host);
+
+void __devexit dw_spi_remove_host(struct dw_spi *dws)
+{
+ int status = 0;
+
+ if (!dws)
+ return;
+ mrst_spi_debugfs_remove(dws);
+
+ /* Remove the queue */
+ status = destroy_queue(dws);
+ if (status != 0)
+ dev_err(&dws->master->dev, "dw_spi_remove: workqueue will not "
+ "complete, message memory not freed\n");
+
+ spi_enable_chip(dws, 0);
+ /* Disable clk */
+ spi_set_clk(dws, 0);
+ free_irq(dws->irq, dws);
+
+ /* Disconnect from the SPI framework */
+ spi_unregister_master(dws->master);
+}
+
+int dw_spi_suspend_host(struct dw_spi *dws)
+{
+ int ret = 0;
+
+ ret = stop_queue(dws);
+ if (ret)
+ return ret;
+ spi_enable_chip(dws, 0);
+ spi_set_clk(dws, 0);
+ return ret;
+}
+EXPORT_SYMBOL(dw_spi_suspend_host);
+
+int dw_spi_resume_host(struct dw_spi *dws)
+{
+ int ret;
+
+ spi_hw_init(dws);
+ ret = start_queue(dws);
+ if (ret)
+ dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);
+ return ret;
+}
+EXPORT_SYMBOL(dw_spi_resume_host);
+
+MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
+MODULE_DESCRIPTION("Driver for DesignWare SPI controller core");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/dw_spi_pci.c b/drivers/spi/dw_spi_pci.c
new file mode 100644
index 00000000000..34ba6916173
--- /dev/null
+++ b/drivers/spi/dw_spi_pci.c
@@ -0,0 +1,169 @@
+/*
+ * mrst_spi_pci.c - PCI interface driver for DW SPI Core
+ *
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/spi/dw_spi.h>
+#include <linux/spi/spi.h>
+
+#define DRIVER_NAME "dw_spi_pci"
+
+struct dw_spi_pci {
+ struct pci_dev *pdev;
+ struct dw_spi dws;
+};
+
+static int __devinit spi_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct dw_spi_pci *dwpci;
+ struct dw_spi *dws;
+ int pci_bar = 0;
+ int ret;
+
+ printk(KERN_INFO "DW: found PCI SPI controller(ID: %04x:%04x)\n",
+ pdev->vendor, pdev->device);
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ dwpci = kzalloc(sizeof(struct dw_spi_pci), GFP_KERNEL);
+ if (!dwpci) {
+ ret = -ENOMEM;
+ goto err_disable;
+ }
+
+ dwpci->pdev = pdev;
+ dws = &dwpci->dws;
+
+ /* Get basic io resource and map it */
+ dws->paddr = pci_resource_start(pdev, pci_bar);
+ dws->iolen = pci_resource_len(pdev, pci_bar);
+
+ ret = pci_request_region(pdev, pci_bar, dev_name(&pdev->dev));
+ if (ret)
+ goto err_kfree;
+
+ dws->regs = ioremap_nocache((unsigned long)dws->paddr,
+ pci_resource_len(pdev, pci_bar));
+ if (!dws->regs) {
+ ret = -ENOMEM;
+ goto err_release_reg;
+ }
+
+ dws->parent_dev = &pdev->dev;
+ dws->bus_num = 0;
+ dws->num_cs = 4;
+ dws->max_freq = 25000000; /* for Moorestwon */
+ dws->irq = pdev->irq;
+
+ ret = dw_spi_add_host(dws);
+ if (ret)
+ goto err_unmap;
+
+ /* PCI hook and SPI hook use the same drv data */
+ pci_set_drvdata(pdev, dwpci);
+ return 0;
+
+err_unmap:
+ iounmap(dws->regs);
+err_release_reg:
+ pci_release_region(pdev, pci_bar);
+err_kfree:
+ kfree(dwpci);
+err_disable:
+ pci_disable_device(pdev);
+ return ret;
+}
+
+static void __devexit spi_pci_remove(struct pci_dev *pdev)
+{
+ struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
+
+ pci_set_drvdata(pdev, NULL);
+ iounmap(dwpci->dws.regs);
+ pci_release_region(pdev, 0);
+ kfree(dwpci);
+ pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM
+static int spi_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
+ int ret;
+
+ ret = dw_spi_suspend_host(&dwpci->dws);
+ if (ret)
+ return ret;
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return ret;
+}
+
+static int spi_resume(struct pci_dev *pdev)
+{
+ struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
+ int ret;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
+ return dw_spi_resume_host(&dwpci->dws);
+}
+#else
+#define spi_suspend NULL
+#define spi_resume NULL
+#endif
+
+static const struct pci_device_id pci_ids[] __devinitdata = {
+ /* Intel Moorestown platform SPI controller 0 */
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) },
+ {},
+};
+
+static struct pci_driver dw_spi_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pci_ids,
+ .probe = spi_pci_probe,
+ .remove = __devexit_p(spi_pci_remove),
+ .suspend = spi_suspend,
+ .resume = spi_resume,
+};
+
+static int __init mrst_spi_init(void)
+{
+ return pci_register_driver(&dw_spi_driver);
+}
+
+static void __exit mrst_spi_exit(void)
+{
+ pci_unregister_driver(&dw_spi_driver);
+}
+
+module_init(mrst_spi_init);
+module_exit(mrst_spi_exit);
+
+MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
+MODULE_DESCRIPTION("PCI interface driver for DW SPI Core");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 73e24ef5a2f..1d41058bbab 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -1294,7 +1294,7 @@ static int __init bfin_spi_probe(struct platform_device *pdev)
goto out_error_get_res;
}
- drv_data->regs_base = ioremap(res->start, (res->end - res->start + 1));
+ drv_data->regs_base = ioremap(res->start, resource_size(res));
if (drv_data->regs_base == NULL) {
dev_err(dev, "Cannot map IO\n");
status = -ENXIO;
diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c
index e9390d747bf..1fb2a6ea328 100644
--- a/drivers/spi/spi_mpc8xxx.c
+++ b/drivers/spi/spi_mpc8xxx.c
@@ -1013,7 +1013,7 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
init_completion(&mpc8xxx_spi->done);
- mpc8xxx_spi->base = ioremap(mem->start, mem->end - mem->start + 1);
+ mpc8xxx_spi->base = ioremap(mem->start, resource_size(mem));
if (mpc8xxx_spi->base == NULL) {
ret = -ENOMEM;
goto err_ioremap;
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index 276591569c8..c010733877a 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -1,7 +1,7 @@
/* linux/drivers/spi/spi_s3c24xx.c
*
* Copyright (c) 2006 Ben Dooks
- * Copyright (c) 2006 Simtec Electronics
+ * Copyright 2006-2009 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* This program is free software; you can redistribute it and/or modify
@@ -28,6 +28,11 @@
#include <plat/regs-spi.h>
#include <mach/spi.h>
+#include <plat/fiq.h>
+#include <asm/fiq.h>
+
+#include "spi_s3c24xx_fiq.h"
+
/**
* s3c24xx_spi_devstate - per device data
* @hz: Last frequency calculated for @sppre field.
@@ -42,6 +47,13 @@ struct s3c24xx_spi_devstate {
u8 sppre;
};
+enum spi_fiq_mode {
+ FIQ_MODE_NONE = 0,
+ FIQ_MODE_TX = 1,
+ FIQ_MODE_RX = 2,
+ FIQ_MODE_TXRX = 3,
+};
+
struct s3c24xx_spi {
/* bitbang has to be first */
struct spi_bitbang bitbang;
@@ -52,6 +64,11 @@ struct s3c24xx_spi {
int len;
int count;
+ struct fiq_handler fiq_handler;
+ enum spi_fiq_mode fiq_mode;
+ unsigned char fiq_inuse;
+ unsigned char fiq_claimed;
+
void (*set_cs)(struct s3c2410_spi_info *spi,
int cs, int pol);
@@ -67,6 +84,7 @@ struct s3c24xx_spi {
struct s3c2410_spi_info *pdata;
};
+
#define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT)
#define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP)
@@ -127,7 +145,7 @@ static int s3c24xx_spi_update_state(struct spi_device *spi,
}
if (spi->mode != cs->mode) {
- u8 spcon = SPCON_DEFAULT;
+ u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK;
if (spi->mode & SPI_CPHA)
spcon |= S3C2410_SPCON_CPHA_FMTB;
@@ -214,13 +232,196 @@ static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
return hw->tx ? hw->tx[count] : 0;
}
+#ifdef CONFIG_SPI_S3C24XX_FIQ
+/* Support for FIQ based pseudo-DMA to improve the transfer speed.
+ *
+ * This code uses the assembly helper in spi_s3c24xx_spi.S which is
+ * used by the FIQ core to move data between main memory and the peripheral
+ * block. Since this is code running on the processor, there is no problem
+ * with cache coherency of the buffers, so we can use any buffer we like.
+ */
+
+/**
+ * struct spi_fiq_code - FIQ code and header
+ * @length: The length of the code fragment, excluding this header.
+ * @ack_offset: The offset from @data to the word to place the IRQ ACK bit at.
+ * @data: The code itself to install as a FIQ handler.
+ */
+struct spi_fiq_code {
+ u32 length;
+ u32 ack_offset;
+ u8 data[0];
+};
+
+extern struct spi_fiq_code s3c24xx_spi_fiq_txrx;
+extern struct spi_fiq_code s3c24xx_spi_fiq_tx;
+extern struct spi_fiq_code s3c24xx_spi_fiq_rx;
+
+/**
+ * ack_bit - turn IRQ into IRQ acknowledgement bit
+ * @irq: The interrupt number
+ *
+ * Returns the bit to write to the interrupt acknowledge register.
+ */
+static inline u32 ack_bit(unsigned int irq)
+{
+ return 1 << (irq - IRQ_EINT0);
+}
+
+/**
+ * s3c24xx_spi_tryfiq - attempt to claim and setup FIQ for transfer
+ * @hw: The hardware state.
+ *
+ * Claim the FIQ handler (only one can be active at any one time) and
+ * then setup the correct transfer code for this transfer.
+ *
+ * This call updates all the necessary state information if sucessful,
+ * so the caller does not need to do anything more than start the transfer
+ * as normal, since the IRQ will have been re-routed to the FIQ handler.
+*/
+void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw)
+{
+ struct pt_regs regs;
+ enum spi_fiq_mode mode;
+ struct spi_fiq_code *code;
+ int ret;
+
+ if (!hw->fiq_claimed) {
+ /* try and claim fiq if we haven't got it, and if not
+ * then return and simply use another transfer method */
+
+ ret = claim_fiq(&hw->fiq_handler);
+ if (ret)
+ return;
+ }
+
+ if (hw->tx && !hw->rx)
+ mode = FIQ_MODE_TX;
+ else if (hw->rx && !hw->tx)
+ mode = FIQ_MODE_RX;
+ else
+ mode = FIQ_MODE_TXRX;
+
+ regs.uregs[fiq_rspi] = (long)hw->regs;
+ regs.uregs[fiq_rrx] = (long)hw->rx;
+ regs.uregs[fiq_rtx] = (long)hw->tx + 1;
+ regs.uregs[fiq_rcount] = hw->len - 1;
+ regs.uregs[fiq_rirq] = (long)S3C24XX_VA_IRQ;
+
+ set_fiq_regs(&regs);
+
+ if (hw->fiq_mode != mode) {
+ u32 *ack_ptr;
+
+ hw->fiq_mode = mode;
+
+ switch (mode) {
+ case FIQ_MODE_TX:
+ code = &s3c24xx_spi_fiq_tx;
+ break;
+ case FIQ_MODE_RX:
+ code = &s3c24xx_spi_fiq_rx;
+ break;
+ case FIQ_MODE_TXRX:
+ code = &s3c24xx_spi_fiq_txrx;
+ break;
+ default:
+ code = NULL;
+ }
+
+ BUG_ON(!code);
+
+ ack_ptr = (u32 *)&code->data[code->ack_offset];
+ *ack_ptr = ack_bit(hw->irq);
+
+ set_fiq_handler(&code->data, code->length);
+ }
+
+ s3c24xx_set_fiq(hw->irq, true);
+
+ hw->fiq_mode = mode;
+ hw->fiq_inuse = 1;
+}
+
+/**
+ * s3c24xx_spi_fiqop - FIQ core code callback
+ * @pw: Data registered with the handler
+ * @release: Whether this is a release or a return.
+ *
+ * Called by the FIQ code when another module wants to use the FIQ, so
+ * return whether we are currently using this or not and then update our
+ * internal state.
+ */
+static int s3c24xx_spi_fiqop(void *pw, int release)
+{
+ struct s3c24xx_spi *hw = pw;
+ int ret = 0;
+
+ if (release) {
+ if (hw->fiq_inuse)
+ ret = -EBUSY;
+
+ /* note, we do not need to unroute the FIQ, as the FIQ
+ * vector code de-routes it to signal the end of transfer */
+
+ hw->fiq_mode = FIQ_MODE_NONE;
+ hw->fiq_claimed = 0;
+ } else {
+ hw->fiq_claimed = 1;
+ }
+
+ return ret;
+}
+
+/**
+ * s3c24xx_spi_initfiq - setup the information for the FIQ core
+ * @hw: The hardware state.
+ *
+ * Setup the fiq_handler block to pass to the FIQ core.
+ */
+static inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *hw)
+{
+ hw->fiq_handler.dev_id = hw;
+ hw->fiq_handler.name = dev_name(hw->dev);
+ hw->fiq_handler.fiq_op = s3c24xx_spi_fiqop;
+}
+
+/**
+ * s3c24xx_spi_usefiq - return if we should be using FIQ.
+ * @hw: The hardware state.
+ *
+ * Return true if the platform data specifies whether this channel is
+ * allowed to use the FIQ.
+ */
+static inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *hw)
+{
+ return hw->pdata->use_fiq;
+}
+
+/**
+ * s3c24xx_spi_usingfiq - return if channel is using FIQ
+ * @spi: The hardware state.
+ *
+ * Return whether the channel is currently using the FIQ (separate from
+ * whether the FIQ is claimed).
+ */
+static inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *spi)
+{
+ return spi->fiq_inuse;
+}
+#else
+
+static inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *s) { }
+static inline void s3c24xx_spi_tryfiq(struct s3c24xx_spi *s) { }
+static inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *s) { return false; }
+static inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *s) { return false; }
+
+#endif /* CONFIG_SPI_S3C24XX_FIQ */
+
static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
{
struct s3c24xx_spi *hw = to_hw(spi);
- dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
- t->tx_buf, t->rx_buf, t->len);
-
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
hw->len = t->len;
@@ -228,11 +429,14 @@ static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
init_completion(&hw->done);
+ hw->fiq_inuse = 0;
+ if (s3c24xx_spi_usefiq(hw) && t->len >= 3)
+ s3c24xx_spi_tryfiq(hw);
+
/* send the first byte */
writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT);
wait_for_completion(&hw->done);
-
return hw->count;
}
@@ -254,17 +458,27 @@ static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
goto irq_done;
}
- hw->count++;
+ if (!s3c24xx_spi_usingfiq(hw)) {
+ hw->count++;
- if (hw->rx)
- hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);
+ if (hw->rx)
+ hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);
- count++;
+ count++;
+
+ if (count < hw->len)
+ writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);
+ else
+ complete(&hw->done);
+ } else {
+ hw->count = hw->len;
+ hw->fiq_inuse = 0;
+
+ if (hw->rx)
+ hw->rx[hw->len-1] = readb(hw->regs + S3C2410_SPRDAT);
- if (count < hw->len)
- writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);
- else
complete(&hw->done);
+ }
irq_done:
return IRQ_HANDLED;
@@ -322,6 +536,10 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, hw);
init_completion(&hw->done);
+ /* initialise fiq handler */
+
+ s3c24xx_spi_initfiq(hw);
+
/* setup the master state. */
/* the spi->mode bits understood by this driver: */
diff --git a/drivers/spi/spi_s3c24xx_fiq.S b/drivers/spi/spi_s3c24xx_fiq.S
new file mode 100644
index 00000000000..3793cae361d
--- /dev/null
+++ b/drivers/spi/spi_s3c24xx_fiq.S
@@ -0,0 +1,116 @@
+/* linux/drivers/spi/spi_s3c24xx_fiq.S
+ *
+ * Copyright 2009 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX SPI - FIQ pseudo-DMA transfer code
+ *
+ * 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.
+*/
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+#include <mach/map.h>
+#include <mach/regs-irq.h>
+#include <plat/regs-spi.h>
+
+#include "spi_s3c24xx_fiq.h"
+
+ .text
+
+ @ entry to these routines is as follows, with the register names
+ @ defined in fiq.h so that they can be shared with the C files which
+ @ setup the calling registers.
+ @
+ @ fiq_rirq The base of the IRQ registers to find S3C2410_SRCPND
+ @ fiq_rtmp Temporary register to hold tx/rx data
+ @ fiq_rspi The base of the SPI register block
+ @ fiq_rtx The tx buffer pointer
+ @ fiq_rrx The rx buffer pointer
+ @ fiq_rcount The number of bytes to move
+
+ @ each entry starts with a word entry of how long it is
+ @ and an offset to the irq acknowledgment word
+
+ENTRY(s3c24xx_spi_fiq_rx)
+s3c24xx_spi_fix_rx:
+ .word fiq_rx_end - fiq_rx_start
+ .word fiq_rx_irq_ack - fiq_rx_start
+fiq_rx_start:
+ ldr fiq_rtmp, fiq_rx_irq_ack
+ str fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ]
+
+ ldrb fiq_rtmp, [ fiq_rspi, # S3C2410_SPRDAT ]
+ strb fiq_rtmp, [ fiq_rrx ], #1
+
+ mov fiq_rtmp, #0xff
+ strb fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ]
+
+ subs fiq_rcount, fiq_rcount, #1
+ subnes pc, lr, #4 @@ return, still have work to do
+
+ @@ set IRQ controller so that next op will trigger IRQ
+ mov fiq_rtmp, #0
+ str fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD - S3C24XX_VA_IRQ ]
+ subs pc, lr, #4
+
+fiq_rx_irq_ack:
+ .word 0
+fiq_rx_end:
+
+ENTRY(s3c24xx_spi_fiq_txrx)
+s3c24xx_spi_fiq_txrx:
+ .word fiq_txrx_end - fiq_txrx_start
+ .word fiq_txrx_irq_ack - fiq_txrx_start
+fiq_txrx_start:
+
+ ldrb fiq_rtmp, [ fiq_rspi, # S3C2410_SPRDAT ]
+ strb fiq_rtmp, [ fiq_rrx ], #1
+
+ ldr fiq_rtmp, fiq_txrx_irq_ack
+ str fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ]
+
+ ldrb fiq_rtmp, [ fiq_rtx ], #1
+ strb fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ]
+
+ subs fiq_rcount, fiq_rcount, #1
+ subnes pc, lr, #4 @@ return, still have work to do
+
+ mov fiq_rtmp, #0
+ str fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD - S3C24XX_VA_IRQ ]
+ subs pc, lr, #4
+
+fiq_txrx_irq_ack:
+ .word 0
+
+fiq_txrx_end:
+
+ENTRY(s3c24xx_spi_fiq_tx)
+s3c24xx_spi_fix_tx:
+ .word fiq_tx_end - fiq_tx_start
+ .word fiq_tx_irq_ack - fiq_tx_start
+fiq_tx_start:
+ ldrb fiq_rtmp, [ fiq_rspi, # S3C2410_SPRDAT ]
+
+ ldr fiq_rtmp, fiq_tx_irq_ack
+ str fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ]
+
+ ldrb fiq_rtmp, [ fiq_rtx ], #1
+ strb fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ]
+
+ subs fiq_rcount, fiq_rcount, #1
+ subnes pc, lr, #4 @@ return, still have work to do
+
+ mov fiq_rtmp, #0
+ str fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD - S3C24XX_VA_IRQ ]
+ subs pc, lr, #4
+
+fiq_tx_irq_ack:
+ .word 0
+
+fiq_tx_end:
+
+ .end
diff --git a/drivers/spi/spi_s3c24xx_fiq.h b/drivers/spi/spi_s3c24xx_fiq.h
new file mode 100644
index 00000000000..a5950bb25b5
--- /dev/null
+++ b/drivers/spi/spi_s3c24xx_fiq.h
@@ -0,0 +1,26 @@
+/* linux/drivers/spi/spi_s3c24xx_fiq.h
+ *
+ * Copyright 2009 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX SPI - FIQ pseudo-DMA transfer support
+ *
+ * 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.
+*/
+
+/* We have R8 through R13 to play with */
+
+#ifdef __ASSEMBLY__
+#define __REG_NR(x) r##x
+#else
+#define __REG_NR(x) (x)
+#endif
+
+#define fiq_rspi __REG_NR(8)
+#define fiq_rtmp __REG_NR(9)
+#define fiq_rrx __REG_NR(10)
+#define fiq_rtx __REG_NR(11)
+#define fiq_rcount __REG_NR(12)
+#define fiq_rirq __REG_NR(13)
diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c
new file mode 100644
index 00000000000..88a456dba96
--- /dev/null
+++ b/drivers/spi/spi_s3c64xx.c
@@ -0,0 +1,1196 @@
+/* linux/drivers/spi/spi_s3c64xx.c
+ *
+ * Copyright (C) 2009 Samsung Electronics Ltd.
+ * Jaswinder Singh <jassi.brar@samsung.com>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+#include <mach/dma.h>
+#include <plat/spi.h>
+
+/* Registers and bit-fields */
+
+#define S3C64XX_SPI_CH_CFG 0x00
+#define S3C64XX_SPI_CLK_CFG 0x04
+#define S3C64XX_SPI_MODE_CFG 0x08
+#define S3C64XX_SPI_SLAVE_SEL 0x0C
+#define S3C64XX_SPI_INT_EN 0x10
+#define S3C64XX_SPI_STATUS 0x14
+#define S3C64XX_SPI_TX_DATA 0x18
+#define S3C64XX_SPI_RX_DATA 0x1C
+#define S3C64XX_SPI_PACKET_CNT 0x20
+#define S3C64XX_SPI_PENDING_CLR 0x24
+#define S3C64XX_SPI_SWAP_CFG 0x28
+#define S3C64XX_SPI_FB_CLK 0x2C
+
+#define S3C64XX_SPI_CH_HS_EN (1<<6) /* High Speed Enable */
+#define S3C64XX_SPI_CH_SW_RST (1<<5)
+#define S3C64XX_SPI_CH_SLAVE (1<<4)
+#define S3C64XX_SPI_CPOL_L (1<<3)
+#define S3C64XX_SPI_CPHA_B (1<<2)
+#define S3C64XX_SPI_CH_RXCH_ON (1<<1)
+#define S3C64XX_SPI_CH_TXCH_ON (1<<0)
+
+#define S3C64XX_SPI_CLKSEL_SRCMSK (3<<9)
+#define S3C64XX_SPI_CLKSEL_SRCSHFT 9
+#define S3C64XX_SPI_ENCLK_ENABLE (1<<8)
+#define S3C64XX_SPI_PSR_MASK 0xff
+
+#define S3C64XX_SPI_MODE_CH_TSZ_BYTE (0<<29)
+#define S3C64XX_SPI_MODE_CH_TSZ_HALFWORD (1<<29)
+#define S3C64XX_SPI_MODE_CH_TSZ_WORD (2<<29)
+#define S3C64XX_SPI_MODE_CH_TSZ_MASK (3<<29)
+#define S3C64XX_SPI_MODE_BUS_TSZ_BYTE (0<<17)
+#define S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD (1<<17)
+#define S3C64XX_SPI_MODE_BUS_TSZ_WORD (2<<17)
+#define S3C64XX_SPI_MODE_BUS_TSZ_MASK (3<<17)
+#define S3C64XX_SPI_MODE_RXDMA_ON (1<<2)
+#define S3C64XX_SPI_MODE_TXDMA_ON (1<<1)
+#define S3C64XX_SPI_MODE_4BURST (1<<0)
+
+#define S3C64XX_SPI_SLAVE_AUTO (1<<1)
+#define S3C64XX_SPI_SLAVE_SIG_INACT (1<<0)
+
+#define S3C64XX_SPI_ACT(c) writel(0, (c)->regs + S3C64XX_SPI_SLAVE_SEL)
+
+#define S3C64XX_SPI_DEACT(c) writel(S3C64XX_SPI_SLAVE_SIG_INACT, \
+ (c)->regs + S3C64XX_SPI_SLAVE_SEL)
+
+#define S3C64XX_SPI_INT_TRAILING_EN (1<<6)
+#define S3C64XX_SPI_INT_RX_OVERRUN_EN (1<<5)
+#define S3C64XX_SPI_INT_RX_UNDERRUN_EN (1<<4)
+#define S3C64XX_SPI_INT_TX_OVERRUN_EN (1<<3)
+#define S3C64XX_SPI_INT_TX_UNDERRUN_EN (1<<2)
+#define S3C64XX_SPI_INT_RX_FIFORDY_EN (1<<1)
+#define S3C64XX_SPI_INT_TX_FIFORDY_EN (1<<0)
+
+#define S3C64XX_SPI_ST_RX_OVERRUN_ERR (1<<5)
+#define S3C64XX_SPI_ST_RX_UNDERRUN_ERR (1<<4)
+#define S3C64XX_SPI_ST_TX_OVERRUN_ERR (1<<3)
+#define S3C64XX_SPI_ST_TX_UNDERRUN_ERR (1<<2)
+#define S3C64XX_SPI_ST_RX_FIFORDY (1<<1)
+#define S3C64XX_SPI_ST_TX_FIFORDY (1<<0)
+
+#define S3C64XX_SPI_PACKET_CNT_EN (1<<16)
+
+#define S3C64XX_SPI_PND_TX_UNDERRUN_CLR (1<<4)
+#define S3C64XX_SPI_PND_TX_OVERRUN_CLR (1<<3)
+#define S3C64XX_SPI_PND_RX_UNDERRUN_CLR (1<<2)
+#define S3C64XX_SPI_PND_RX_OVERRUN_CLR (1<<1)
+#define S3C64XX_SPI_PND_TRAILING_CLR (1<<0)
+
+#define S3C64XX_SPI_SWAP_RX_HALF_WORD (1<<7)
+#define S3C64XX_SPI_SWAP_RX_BYTE (1<<6)
+#define S3C64XX_SPI_SWAP_RX_BIT (1<<5)
+#define S3C64XX_SPI_SWAP_RX_EN (1<<4)
+#define S3C64XX_SPI_SWAP_TX_HALF_WORD (1<<3)
+#define S3C64XX_SPI_SWAP_TX_BYTE (1<<2)
+#define S3C64XX_SPI_SWAP_TX_BIT (1<<1)
+#define S3C64XX_SPI_SWAP_TX_EN (1<<0)
+
+#define S3C64XX_SPI_FBCLK_MSK (3<<0)
+
+#define S3C64XX_SPI_ST_TRLCNTZ(v, i) ((((v) >> (i)->rx_lvl_offset) & \
+ (((i)->fifo_lvl_mask + 1))) \
+ ? 1 : 0)
+
+#define S3C64XX_SPI_ST_TX_DONE(v, i) ((((v) >> (i)->rx_lvl_offset) & \
+ (((i)->fifo_lvl_mask + 1) << 1)) \
+ ? 1 : 0)
+#define TX_FIFO_LVL(v, i) (((v) >> 6) & (i)->fifo_lvl_mask)
+#define RX_FIFO_LVL(v, i) (((v) >> (i)->rx_lvl_offset) & (i)->fifo_lvl_mask)
+
+#define S3C64XX_SPI_MAX_TRAILCNT 0x3ff
+#define S3C64XX_SPI_TRAILCNT_OFF 19
+
+#define S3C64XX_SPI_TRAILCNT S3C64XX_SPI_MAX_TRAILCNT
+
+#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
+
+#define SUSPND (1<<0)
+#define SPIBUSY (1<<1)
+#define RXBUSY (1<<2)
+#define TXBUSY (1<<3)
+
+/**
+ * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver.
+ * @clk: Pointer to the spi clock.
+ * @master: Pointer to the SPI Protocol master.
+ * @workqueue: Work queue for the SPI xfer requests.
+ * @cntrlr_info: Platform specific data for the controller this driver manages.
+ * @tgl_spi: Pointer to the last CS left untoggled by the cs_change hint.
+ * @work: Work
+ * @queue: To log SPI xfer requests.
+ * @lock: Controller specific lock.
+ * @state: Set of FLAGS to indicate status.
+ * @rx_dmach: Controller's DMA channel for Rx.
+ * @tx_dmach: Controller's DMA channel for Tx.
+ * @sfr_start: BUS address of SPI controller regs.
+ * @regs: Pointer to ioremap'ed controller registers.
+ * @xfer_completion: To indicate completion of xfer task.
+ * @cur_mode: Stores the active configuration of the controller.
+ * @cur_bpw: Stores the active bits per word settings.
+ * @cur_speed: Stores the active xfer clock speed.
+ */
+struct s3c64xx_spi_driver_data {
+ void __iomem *regs;
+ struct clk *clk;
+ struct platform_device *pdev;
+ struct spi_master *master;
+ struct workqueue_struct *workqueue;
+ struct s3c64xx_spi_cntrlr_info *cntrlr_info;
+ struct spi_device *tgl_spi;
+ struct work_struct work;
+ struct list_head queue;
+ spinlock_t lock;
+ enum dma_ch rx_dmach;
+ enum dma_ch tx_dmach;
+ unsigned long sfr_start;
+ struct completion xfer_completion;
+ unsigned state;
+ unsigned cur_mode, cur_bpw;
+ unsigned cur_speed;
+};
+
+static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
+ .name = "samsung-spi-dma",
+};
+
+static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
+{
+ struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+ void __iomem *regs = sdd->regs;
+ unsigned long loops;
+ u32 val;
+
+ writel(0, regs + S3C64XX_SPI_PACKET_CNT);
+
+ val = readl(regs + S3C64XX_SPI_CH_CFG);
+ val |= S3C64XX_SPI_CH_SW_RST;
+ val &= ~S3C64XX_SPI_CH_HS_EN;
+ writel(val, regs + S3C64XX_SPI_CH_CFG);
+
+ /* Flush TxFIFO*/
+ loops = msecs_to_loops(1);
+ do {
+ val = readl(regs + S3C64XX_SPI_STATUS);
+ } while (TX_FIFO_LVL(val, sci) && loops--);
+
+ /* Flush RxFIFO*/
+ loops = msecs_to_loops(1);
+ do {
+ val = readl(regs + S3C64XX_SPI_STATUS);
+ if (RX_FIFO_LVL(val, sci))
+ readl(regs + S3C64XX_SPI_RX_DATA);
+ else
+ break;
+ } while (loops--);
+
+ val = readl(regs + S3C64XX_SPI_CH_CFG);
+ val &= ~S3C64XX_SPI_CH_SW_RST;
+ writel(val, regs + S3C64XX_SPI_CH_CFG);
+
+ val = readl(regs + S3C64XX_SPI_MODE_CFG);
+ val &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
+ writel(val, regs + S3C64XX_SPI_MODE_CFG);
+
+ val = readl(regs + S3C64XX_SPI_CH_CFG);
+ val &= ~(S3C64XX_SPI_CH_RXCH_ON | S3C64XX_SPI_CH_TXCH_ON);
+ writel(val, regs + S3C64XX_SPI_CH_CFG);
+}
+
+static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
+ struct spi_device *spi,
+ struct spi_transfer *xfer, int dma_mode)
+{
+ struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+ void __iomem *regs = sdd->regs;
+ u32 modecfg, chcfg;
+
+ modecfg = readl(regs + S3C64XX_SPI_MODE_CFG);
+ modecfg &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
+
+ chcfg = readl(regs + S3C64XX_SPI_CH_CFG);
+ chcfg &= ~S3C64XX_SPI_CH_TXCH_ON;
+
+ if (dma_mode) {
+ chcfg &= ~S3C64XX_SPI_CH_RXCH_ON;
+ } else {
+ /* Always shift in data in FIFO, even if xfer is Tx only,
+ * this helps setting PCKT_CNT value for generating clocks
+ * as exactly needed.
+ */
+ chcfg |= S3C64XX_SPI_CH_RXCH_ON;
+ writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
+ | S3C64XX_SPI_PACKET_CNT_EN,
+ regs + S3C64XX_SPI_PACKET_CNT);
+ }
+
+ if (xfer->tx_buf != NULL) {
+ sdd->state |= TXBUSY;
+ chcfg |= S3C64XX_SPI_CH_TXCH_ON;
+ if (dma_mode) {
+ modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
+ s3c2410_dma_config(sdd->tx_dmach, 1);
+ s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd,
+ xfer->tx_dma, xfer->len);
+ s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START);
+ } else {
+ unsigned char *buf = (unsigned char *) xfer->tx_buf;
+ int i = 0;
+ while (i < xfer->len)
+ writeb(buf[i++], regs + S3C64XX_SPI_TX_DATA);
+ }
+ }
+
+ if (xfer->rx_buf != NULL) {
+ sdd->state |= RXBUSY;
+
+ if (sci->high_speed && sdd->cur_speed >= 30000000UL
+ && !(sdd->cur_mode & SPI_CPHA))
+ chcfg |= S3C64XX_SPI_CH_HS_EN;
+
+ if (dma_mode) {
+ modecfg |= S3C64XX_SPI_MODE_RXDMA_ON;
+ chcfg |= S3C64XX_SPI_CH_RXCH_ON;
+ writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
+ | S3C64XX_SPI_PACKET_CNT_EN,
+ regs + S3C64XX_SPI_PACKET_CNT);
+ s3c2410_dma_config(sdd->rx_dmach, 1);
+ s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd,
+ xfer->rx_dma, xfer->len);
+ s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START);
+ }
+ }
+
+ writel(modecfg, regs + S3C64XX_SPI_MODE_CFG);
+ writel(chcfg, regs + S3C64XX_SPI_CH_CFG);
+}
+
+static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
+ struct spi_device *spi)
+{
+ struct s3c64xx_spi_csinfo *cs;
+
+ if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */
+ if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
+ /* Deselect the last toggled device */
+ cs = sdd->tgl_spi->controller_data;
+ cs->set_level(spi->mode & SPI_CS_HIGH ? 0 : 1);
+ }
+ sdd->tgl_spi = NULL;
+ }
+
+ cs = spi->controller_data;
+ cs->set_level(spi->mode & SPI_CS_HIGH ? 1 : 0);
+}
+
+static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
+ struct spi_transfer *xfer, int dma_mode)
+{
+ struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+ void __iomem *regs = sdd->regs;
+ unsigned long val;
+ int ms;
+
+ /* millisecs to xfer 'len' bytes @ 'cur_speed' */
+ ms = xfer->len * 8 * 1000 / sdd->cur_speed;
+ ms += 5; /* some tolerance */
+
+ if (dma_mode) {
+ val = msecs_to_jiffies(ms) + 10;
+ val = wait_for_completion_timeout(&sdd->xfer_completion, val);
+ } else {
+ val = msecs_to_loops(ms);
+ do {
+ val = readl(regs + S3C64XX_SPI_STATUS);
+ } while (RX_FIFO_LVL(val, sci) < xfer->len && --val);
+ }
+
+ if (!val)
+ return -EIO;
+
+ if (dma_mode) {
+ u32 status;
+
+ /*
+ * DmaTx returns after simply writing data in the FIFO,
+ * w/o waiting for real transmission on the bus to finish.
+ * DmaRx returns only after Dma read data from FIFO which
+ * needs bus transmission to finish, so we don't worry if
+ * Xfer involved Rx(with or without Tx).
+ */
+ if (xfer->rx_buf == NULL) {
+ val = msecs_to_loops(10);
+ status = readl(regs + S3C64XX_SPI_STATUS);
+ while ((TX_FIFO_LVL(status, sci)
+ || !S3C64XX_SPI_ST_TX_DONE(status, sci))
+ && --val) {
+ cpu_relax();
+ status = readl(regs + S3C64XX_SPI_STATUS);
+ }
+
+ if (!val)
+ return -EIO;
+ }
+ } else {
+ unsigned char *buf;
+ int i;
+
+ /* If it was only Tx */
+ if (xfer->rx_buf == NULL) {
+ sdd->state &= ~TXBUSY;
+ return 0;
+ }
+
+ i = 0;
+ buf = xfer->rx_buf;
+ while (i < xfer->len)
+ buf[i++] = readb(regs + S3C64XX_SPI_RX_DATA);
+
+ sdd->state &= ~RXBUSY;
+ }
+
+ return 0;
+}
+
+static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
+ struct spi_device *spi)
+{
+ struct s3c64xx_spi_csinfo *cs = spi->controller_data;
+
+ if (sdd->tgl_spi == spi)
+ sdd->tgl_spi = NULL;
+
+ cs->set_level(spi->mode & SPI_CS_HIGH ? 0 : 1);
+}
+
+static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
+{
+ struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+ void __iomem *regs = sdd->regs;
+ u32 val;
+
+ /* Disable Clock */
+ val = readl(regs + S3C64XX_SPI_CLK_CFG);
+ val &= ~S3C64XX_SPI_ENCLK_ENABLE;
+ writel(val, regs + S3C64XX_SPI_CLK_CFG);
+
+ /* Set Polarity and Phase */
+ val = readl(regs + S3C64XX_SPI_CH_CFG);
+ val &= ~(S3C64XX_SPI_CH_SLAVE |
+ S3C64XX_SPI_CPOL_L |
+ S3C64XX_SPI_CPHA_B);
+
+ if (sdd->cur_mode & SPI_CPOL)
+ val |= S3C64XX_SPI_CPOL_L;
+
+ if (sdd->cur_mode & SPI_CPHA)
+ val |= S3C64XX_SPI_CPHA_B;
+
+ writel(val, regs + S3C64XX_SPI_CH_CFG);
+
+ /* Set Channel & DMA Mode */
+ val = readl(regs + S3C64XX_SPI_MODE_CFG);
+ val &= ~(S3C64XX_SPI_MODE_BUS_TSZ_MASK
+ | S3C64XX_SPI_MODE_CH_TSZ_MASK);
+
+ switch (sdd->cur_bpw) {
+ case 32:
+ val |= S3C64XX_SPI_MODE_BUS_TSZ_WORD;
+ break;
+ case 16:
+ val |= S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD;
+ break;
+ default:
+ val |= S3C64XX_SPI_MODE_BUS_TSZ_BYTE;
+ break;
+ }
+ val |= S3C64XX_SPI_MODE_CH_TSZ_BYTE; /* Always 8bits wide */
+
+ writel(val, regs + S3C64XX_SPI_MODE_CFG);
+
+ /* Configure Clock */
+ val = readl(regs + S3C64XX_SPI_CLK_CFG);
+ val &= ~S3C64XX_SPI_PSR_MASK;
+ val |= ((clk_get_rate(sci->src_clk) / sdd->cur_speed / 2 - 1)
+ & S3C64XX_SPI_PSR_MASK);
+ writel(val, regs + S3C64XX_SPI_CLK_CFG);
+
+ /* Enable Clock */
+ val = readl(regs + S3C64XX_SPI_CLK_CFG);
+ val |= S3C64XX_SPI_ENCLK_ENABLE;
+ writel(val, regs + S3C64XX_SPI_CLK_CFG);
+}
+
+void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id,
+ int size, enum s3c2410_dma_buffresult res)
+{
+ struct s3c64xx_spi_driver_data *sdd = buf_id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sdd->lock, flags);
+
+ if (res == S3C2410_RES_OK)
+ sdd->state &= ~RXBUSY;
+ else
+ dev_err(&sdd->pdev->dev, "DmaAbrtRx-%d\n", size);
+
+ /* If the other done */
+ if (!(sdd->state & TXBUSY))
+ complete(&sdd->xfer_completion);
+
+ spin_unlock_irqrestore(&sdd->lock, flags);
+}
+
+void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id,
+ int size, enum s3c2410_dma_buffresult res)
+{
+ struct s3c64xx_spi_driver_data *sdd = buf_id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sdd->lock, flags);
+
+ if (res == S3C2410_RES_OK)
+ sdd->state &= ~TXBUSY;
+ else
+ dev_err(&sdd->pdev->dev, "DmaAbrtTx-%d \n", size);
+
+ /* If the other done */
+ if (!(sdd->state & RXBUSY))
+ complete(&sdd->xfer_completion);
+
+ spin_unlock_irqrestore(&sdd->lock, flags);
+}
+
+#define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
+
+static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
+ struct spi_message *msg)
+{
+ struct device *dev = &sdd->pdev->dev;
+ struct spi_transfer *xfer;
+
+ if (msg->is_dma_mapped)
+ return 0;
+
+ /* First mark all xfer unmapped */
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ xfer->rx_dma = XFER_DMAADDR_INVALID;
+ xfer->tx_dma = XFER_DMAADDR_INVALID;
+ }
+
+ /* Map until end or first fail */
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+
+ if (xfer->tx_buf != NULL) {
+ xfer->tx_dma = dma_map_single(dev, xfer->tx_buf,
+ xfer->len, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, xfer->tx_dma)) {
+ dev_err(dev, "dma_map_single Tx failed\n");
+ xfer->tx_dma = XFER_DMAADDR_INVALID;
+ return -ENOMEM;
+ }
+ }
+
+ if (xfer->rx_buf != NULL) {
+ xfer->rx_dma = dma_map_single(dev, xfer->rx_buf,
+ xfer->len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, xfer->rx_dma)) {
+ dev_err(dev, "dma_map_single Rx failed\n");
+ dma_unmap_single(dev, xfer->tx_dma,
+ xfer->len, DMA_TO_DEVICE);
+ xfer->tx_dma = XFER_DMAADDR_INVALID;
+ xfer->rx_dma = XFER_DMAADDR_INVALID;
+ return -ENOMEM;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
+ struct spi_message *msg)
+{
+ struct device *dev = &sdd->pdev->dev;
+ struct spi_transfer *xfer;
+
+ if (msg->is_dma_mapped)
+ return;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+
+ if (xfer->rx_buf != NULL
+ && xfer->rx_dma != XFER_DMAADDR_INVALID)
+ dma_unmap_single(dev, xfer->rx_dma,
+ xfer->len, DMA_FROM_DEVICE);
+
+ if (xfer->tx_buf != NULL
+ && xfer->tx_dma != XFER_DMAADDR_INVALID)
+ dma_unmap_single(dev, xfer->tx_dma,
+ xfer->len, DMA_TO_DEVICE);
+ }
+}
+
+static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
+ struct spi_message *msg)
+{
+ struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+ struct spi_device *spi = msg->spi;
+ struct s3c64xx_spi_csinfo *cs = spi->controller_data;
+ struct spi_transfer *xfer;
+ int status = 0, cs_toggle = 0;
+ u32 speed;
+ u8 bpw;
+
+ /* If Master's(controller) state differs from that needed by Slave */
+ if (sdd->cur_speed != spi->max_speed_hz
+ || sdd->cur_mode != spi->mode
+ || sdd->cur_bpw != spi->bits_per_word) {
+ sdd->cur_bpw = spi->bits_per_word;
+ sdd->cur_speed = spi->max_speed_hz;
+ sdd->cur_mode = spi->mode;
+ s3c64xx_spi_config(sdd);
+ }
+
+ /* Map all the transfers if needed */
+ if (s3c64xx_spi_map_mssg(sdd, msg)) {
+ dev_err(&spi->dev,
+ "Xfer: Unable to map message buffers!\n");
+ status = -ENOMEM;
+ goto out;
+ }
+
+ /* Configure feedback delay */
+ writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK);
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+
+ unsigned long flags;
+ int use_dma;
+
+ INIT_COMPLETION(sdd->xfer_completion);
+
+ /* Only BPW and Speed may change across transfers */
+ bpw = xfer->bits_per_word ? : spi->bits_per_word;
+ speed = xfer->speed_hz ? : spi->max_speed_hz;
+
+ if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
+ sdd->cur_bpw = bpw;
+ sdd->cur_speed = speed;
+ s3c64xx_spi_config(sdd);
+ }
+
+ /* Polling method for xfers not bigger than FIFO capacity */
+ if (xfer->len <= ((sci->fifo_lvl_mask >> 1) + 1))
+ use_dma = 0;
+ else
+ use_dma = 1;
+
+ spin_lock_irqsave(&sdd->lock, flags);
+
+ /* Pending only which is to be done */
+ sdd->state &= ~RXBUSY;
+ sdd->state &= ~TXBUSY;
+
+ enable_datapath(sdd, spi, xfer, use_dma);
+
+ /* Slave Select */
+ enable_cs(sdd, spi);
+
+ /* Start the signals */
+ S3C64XX_SPI_ACT(sdd);
+
+ spin_unlock_irqrestore(&sdd->lock, flags);
+
+ status = wait_for_xfer(sdd, xfer, use_dma);
+
+ /* Quiese the signals */
+ S3C64XX_SPI_DEACT(sdd);
+
+ if (status) {
+ dev_err(&spi->dev, "I/O Error: \
+ rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
+ xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0,
+ (sdd->state & RXBUSY) ? 'f' : 'p',
+ (sdd->state & TXBUSY) ? 'f' : 'p',
+ xfer->len);
+
+ if (use_dma) {
+ if (xfer->tx_buf != NULL
+ && (sdd->state & TXBUSY))
+ s3c2410_dma_ctrl(sdd->tx_dmach,
+ S3C2410_DMAOP_FLUSH);
+ if (xfer->rx_buf != NULL
+ && (sdd->state & RXBUSY))
+ s3c2410_dma_ctrl(sdd->rx_dmach,
+ S3C2410_DMAOP_FLUSH);
+ }
+
+ goto out;
+ }
+
+ if (xfer->delay_usecs)
+ udelay(xfer->delay_usecs);
+
+ if (xfer->cs_change) {
+ /* Hint that the next mssg is gonna be
+ for the same device */
+ if (list_is_last(&xfer->transfer_list,
+ &msg->transfers))
+ cs_toggle = 1;
+ else
+ disable_cs(sdd, spi);
+ }
+
+ msg->actual_length += xfer->len;
+
+ flush_fifo(sdd);
+ }
+
+out:
+ if (!cs_toggle || status)
+ disable_cs(sdd, spi);
+ else
+ sdd->tgl_spi = spi;
+
+ s3c64xx_spi_unmap_mssg(sdd, msg);
+
+ msg->status = status;
+
+ if (msg->complete)
+ msg->complete(msg->context);
+}
+
+static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
+{
+ if (s3c2410_dma_request(sdd->rx_dmach,
+ &s3c64xx_spi_dma_client, NULL) < 0) {
+ dev_err(&sdd->pdev->dev, "cannot get RxDMA\n");
+ return 0;
+ }
+ s3c2410_dma_set_buffdone_fn(sdd->rx_dmach, s3c64xx_spi_dma_rxcb);
+ s3c2410_dma_devconfig(sdd->rx_dmach, S3C2410_DMASRC_HW,
+ sdd->sfr_start + S3C64XX_SPI_RX_DATA);
+
+ if (s3c2410_dma_request(sdd->tx_dmach,
+ &s3c64xx_spi_dma_client, NULL) < 0) {
+ dev_err(&sdd->pdev->dev, "cannot get TxDMA\n");
+ s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
+ return 0;
+ }
+ s3c2410_dma_set_buffdone_fn(sdd->tx_dmach, s3c64xx_spi_dma_txcb);
+ s3c2410_dma_devconfig(sdd->tx_dmach, S3C2410_DMASRC_MEM,
+ sdd->sfr_start + S3C64XX_SPI_TX_DATA);
+
+ return 1;
+}
+
+static void s3c64xx_spi_work(struct work_struct *work)
+{
+ struct s3c64xx_spi_driver_data *sdd = container_of(work,
+ struct s3c64xx_spi_driver_data, work);
+ unsigned long flags;
+
+ /* Acquire DMA channels */
+ while (!acquire_dma(sdd))
+ msleep(10);
+
+ spin_lock_irqsave(&sdd->lock, flags);
+
+ while (!list_empty(&sdd->queue)
+ && !(sdd->state & SUSPND)) {
+
+ struct spi_message *msg;
+
+ msg = container_of(sdd->queue.next, struct spi_message, queue);
+
+ list_del_init(&msg->queue);
+
+ /* Set Xfer busy flag */
+ sdd->state |= SPIBUSY;
+
+ spin_unlock_irqrestore(&sdd->lock, flags);
+
+ handle_msg(sdd, msg);
+
+ spin_lock_irqsave(&sdd->lock, flags);
+
+ sdd->state &= ~SPIBUSY;
+ }
+
+ spin_unlock_irqrestore(&sdd->lock, flags);
+
+ /* Free DMA channels */
+ s3c2410_dma_free(sdd->tx_dmach, &s3c64xx_spi_dma_client);
+ s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
+}
+
+static int s3c64xx_spi_transfer(struct spi_device *spi,
+ struct spi_message *msg)
+{
+ struct s3c64xx_spi_driver_data *sdd;
+ unsigned long flags;
+
+ sdd = spi_master_get_devdata(spi->master);
+
+ spin_lock_irqsave(&sdd->lock, flags);
+
+ if (sdd->state & SUSPND) {
+ spin_unlock_irqrestore(&sdd->lock, flags);
+ return -ESHUTDOWN;
+ }
+
+ msg->status = -EINPROGRESS;
+ msg->actual_length = 0;
+
+ list_add_tail(&msg->queue, &sdd->queue);
+
+ queue_work(sdd->workqueue, &sdd->work);
+
+ spin_unlock_irqrestore(&sdd->lock, flags);
+
+ return 0;
+}
+
+/*
+ * Here we only check the validity of requested configuration
+ * and save the configuration in a local data-structure.
+ * The controller is actually configured only just before we
+ * get a message to transfer.
+ */
+static int s3c64xx_spi_setup(struct spi_device *spi)
+{
+ struct s3c64xx_spi_csinfo *cs = spi->controller_data;
+ struct s3c64xx_spi_driver_data *sdd;
+ struct s3c64xx_spi_cntrlr_info *sci;
+ struct spi_message *msg;
+ u32 psr, speed;
+ unsigned long flags;
+ int err = 0;
+
+ if (cs == NULL || cs->set_level == NULL) {
+ dev_err(&spi->dev, "No CS for SPI(%d)\n", spi->chip_select);
+ return -ENODEV;
+ }
+
+ sdd = spi_master_get_devdata(spi->master);
+ sci = sdd->cntrlr_info;
+
+ spin_lock_irqsave(&sdd->lock, flags);
+
+ list_for_each_entry(msg, &sdd->queue, queue) {
+ /* Is some mssg is already queued for this device */
+ if (msg->spi == spi) {
+ dev_err(&spi->dev,
+ "setup: attempt while mssg in queue!\n");
+ spin_unlock_irqrestore(&sdd->lock, flags);
+ return -EBUSY;
+ }
+ }
+
+ if (sdd->state & SUSPND) {
+ spin_unlock_irqrestore(&sdd->lock, flags);
+ dev_err(&spi->dev,
+ "setup: SPI-%d not active!\n", spi->master->bus_num);
+ return -ESHUTDOWN;
+ }
+
+ spin_unlock_irqrestore(&sdd->lock, flags);
+
+ if (spi->bits_per_word != 8
+ && spi->bits_per_word != 16
+ && spi->bits_per_word != 32) {
+ dev_err(&spi->dev, "setup: %dbits/wrd not supported!\n",
+ spi->bits_per_word);
+ err = -EINVAL;
+ goto setup_exit;
+ }
+
+ /* Check if we can provide the requested rate */
+ speed = clk_get_rate(sci->src_clk) / 2 / (0 + 1); /* Max possible */
+
+ if (spi->max_speed_hz > speed)
+ spi->max_speed_hz = speed;
+
+ psr = clk_get_rate(sci->src_clk) / 2 / spi->max_speed_hz - 1;
+ psr &= S3C64XX_SPI_PSR_MASK;
+ if (psr == S3C64XX_SPI_PSR_MASK)
+ psr--;
+
+ speed = clk_get_rate(sci->src_clk) / 2 / (psr + 1);
+ if (spi->max_speed_hz < speed) {
+ if (psr+1 < S3C64XX_SPI_PSR_MASK) {
+ psr++;
+ } else {
+ err = -EINVAL;
+ goto setup_exit;
+ }
+ }
+
+ speed = clk_get_rate(sci->src_clk) / 2 / (psr + 1);
+ if (spi->max_speed_hz >= speed)
+ spi->max_speed_hz = speed;
+ else
+ err = -EINVAL;
+
+setup_exit:
+
+ /* setup() returns with device de-selected */
+ disable_cs(sdd, spi);
+
+ return err;
+}
+
+static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
+{
+ struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+ void __iomem *regs = sdd->regs;
+ unsigned int val;
+
+ sdd->cur_speed = 0;
+
+ S3C64XX_SPI_DEACT(sdd);
+
+ /* Disable Interrupts - we use Polling if not DMA mode */
+ writel(0, regs + S3C64XX_SPI_INT_EN);
+
+ writel(sci->src_clk_nr << S3C64XX_SPI_CLKSEL_SRCSHFT,
+ regs + S3C64XX_SPI_CLK_CFG);
+ writel(0, regs + S3C64XX_SPI_MODE_CFG);
+ writel(0, regs + S3C64XX_SPI_PACKET_CNT);
+
+ /* Clear any irq pending bits */
+ writel(readl(regs + S3C64XX_SPI_PENDING_CLR),
+ regs + S3C64XX_SPI_PENDING_CLR);
+
+ writel(0, regs + S3C64XX_SPI_SWAP_CFG);
+
+ val = readl(regs + S3C64XX_SPI_MODE_CFG);
+ val &= ~S3C64XX_SPI_MODE_4BURST;
+ val &= ~(S3C64XX_SPI_MAX_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF);
+ val |= (S3C64XX_SPI_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF);
+ writel(val, regs + S3C64XX_SPI_MODE_CFG);
+
+ flush_fifo(sdd);
+}
+
+static int __init s3c64xx_spi_probe(struct platform_device *pdev)
+{
+ struct resource *mem_res, *dmatx_res, *dmarx_res;
+ struct s3c64xx_spi_driver_data *sdd;
+ struct s3c64xx_spi_cntrlr_info *sci;
+ struct spi_master *master;
+ int ret;
+
+ if (pdev->id < 0) {
+ dev_err(&pdev->dev,
+ "Invalid platform device id-%d\n", pdev->id);
+ return -ENODEV;
+ }
+
+ if (pdev->dev.platform_data == NULL) {
+ dev_err(&pdev->dev, "platform_data missing!\n");
+ return -ENODEV;
+ }
+
+ /* Check for availability of necessary resource */
+
+ dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (dmatx_res == NULL) {
+ dev_err(&pdev->dev, "Unable to get SPI-Tx dma resource\n");
+ return -ENXIO;
+ }
+
+ dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (dmarx_res == NULL) {
+ dev_err(&pdev->dev, "Unable to get SPI-Rx dma resource\n");
+ return -ENXIO;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (mem_res == NULL) {
+ dev_err(&pdev->dev, "Unable to get SPI MEM resource\n");
+ return -ENXIO;
+ }
+
+ master = spi_alloc_master(&pdev->dev,
+ sizeof(struct s3c64xx_spi_driver_data));
+ if (master == NULL) {
+ dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
+ return -ENOMEM;
+ }
+
+ sci = pdev->dev.platform_data;
+
+ platform_set_drvdata(pdev, master);
+
+ sdd = spi_master_get_devdata(master);
+ sdd->master = master;
+ sdd->cntrlr_info = sci;
+ sdd->pdev = pdev;
+ sdd->sfr_start = mem_res->start;
+ sdd->tx_dmach = dmatx_res->start;
+ sdd->rx_dmach = dmarx_res->start;
+
+ sdd->cur_bpw = 8;
+
+ master->bus_num = pdev->id;
+ master->setup = s3c64xx_spi_setup;
+ master->transfer = s3c64xx_spi_transfer;
+ master->num_chipselect = sci->num_cs;
+ master->dma_alignment = 8;
+ /* the spi->mode bits understood by this driver: */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+
+ if (request_mem_region(mem_res->start,
+ resource_size(mem_res), pdev->name) == NULL) {
+ dev_err(&pdev->dev, "Req mem region failed\n");
+ ret = -ENXIO;
+ goto err0;
+ }
+
+ sdd->regs = ioremap(mem_res->start, resource_size(mem_res));
+ if (sdd->regs == NULL) {
+ dev_err(&pdev->dev, "Unable to remap IO\n");
+ ret = -ENXIO;
+ goto err1;
+ }
+
+ if (sci->cfg_gpio == NULL || sci->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to config gpio\n");
+ ret = -EBUSY;
+ goto err2;
+ }
+
+ /* Setup clocks */
+ sdd->clk = clk_get(&pdev->dev, "spi");
+ if (IS_ERR(sdd->clk)) {
+ dev_err(&pdev->dev, "Unable to acquire clock 'spi'\n");
+ ret = PTR_ERR(sdd->clk);
+ goto err3;
+ }
+
+ if (clk_enable(sdd->clk)) {
+ dev_err(&pdev->dev, "Couldn't enable clock 'spi'\n");
+ ret = -EBUSY;
+ goto err4;
+ }
+
+ if (sci->src_clk_nr == S3C64XX_SPI_SRCCLK_PCLK)
+ sci->src_clk = sdd->clk;
+ else
+ sci->src_clk = clk_get(&pdev->dev, sci->src_clk_name);
+ if (IS_ERR(sci->src_clk)) {
+ dev_err(&pdev->dev,
+ "Unable to acquire clock '%s'\n", sci->src_clk_name);
+ ret = PTR_ERR(sci->src_clk);
+ goto err5;
+ }
+
+ if (sci->src_clk != sdd->clk && clk_enable(sci->src_clk)) {
+ dev_err(&pdev->dev, "Couldn't enable clock '%s'\n",
+ sci->src_clk_name);
+ ret = -EBUSY;
+ goto err6;
+ }
+
+ sdd->workqueue = create_singlethread_workqueue(
+ dev_name(master->dev.parent));
+ if (sdd->workqueue == NULL) {
+ dev_err(&pdev->dev, "Unable to create workqueue\n");
+ ret = -ENOMEM;
+ goto err7;
+ }
+
+ /* Setup Deufult Mode */
+ s3c64xx_spi_hwinit(sdd, pdev->id);
+
+ spin_lock_init(&sdd->lock);
+ init_completion(&sdd->xfer_completion);
+ INIT_WORK(&sdd->work, s3c64xx_spi_work);
+ INIT_LIST_HEAD(&sdd->queue);
+
+ if (spi_register_master(master)) {
+ dev_err(&pdev->dev, "cannot register SPI master\n");
+ ret = -EBUSY;
+ goto err8;
+ }
+
+ dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d \
+ with %d Slaves attached\n",
+ pdev->id, master->num_chipselect);
+ dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\
+ \tDMA=[Rx-%d, Tx-%d]\n",
+ mem_res->end, mem_res->start,
+ sdd->rx_dmach, sdd->tx_dmach);
+
+ return 0;
+
+err8:
+ destroy_workqueue(sdd->workqueue);
+err7:
+ if (sci->src_clk != sdd->clk)
+ clk_disable(sci->src_clk);
+err6:
+ if (sci->src_clk != sdd->clk)
+ clk_put(sci->src_clk);
+err5:
+ clk_disable(sdd->clk);
+err4:
+ clk_put(sdd->clk);
+err3:
+err2:
+ iounmap((void *) sdd->regs);
+err1:
+ release_mem_region(mem_res->start, resource_size(mem_res));
+err0:
+ platform_set_drvdata(pdev, NULL);
+ spi_master_put(master);
+
+ return ret;
+}
+
+static int s3c64xx_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
+ struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+ struct resource *mem_res;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sdd->lock, flags);
+ sdd->state |= SUSPND;
+ spin_unlock_irqrestore(&sdd->lock, flags);
+
+ while (sdd->state & SPIBUSY)
+ msleep(10);
+
+ spi_unregister_master(master);
+
+ destroy_workqueue(sdd->workqueue);
+
+ if (sci->src_clk != sdd->clk)
+ clk_disable(sci->src_clk);
+
+ if (sci->src_clk != sdd->clk)
+ clk_put(sci->src_clk);
+
+ clk_disable(sdd->clk);
+ clk_put(sdd->clk);
+
+ iounmap((void *) sdd->regs);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem_res->start, resource_size(mem_res));
+
+ platform_set_drvdata(pdev, NULL);
+ spi_master_put(master);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
+ struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+ struct s3c64xx_spi_csinfo *cs;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sdd->lock, flags);
+ sdd->state |= SUSPND;
+ spin_unlock_irqrestore(&sdd->lock, flags);
+
+ while (sdd->state & SPIBUSY)
+ msleep(10);
+
+ /* Disable the clock */
+ if (sci->src_clk != sdd->clk)
+ clk_disable(sci->src_clk);
+
+ clk_disable(sdd->clk);
+
+ sdd->cur_speed = 0; /* Output Clock is stopped */
+
+ return 0;
+}
+
+static int s3c64xx_spi_resume(struct platform_device *pdev)
+{
+ struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
+ struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+ unsigned long flags;
+
+ sci->cfg_gpio(pdev);
+
+ /* Enable the clock */
+ if (sci->src_clk != sdd->clk)
+ clk_enable(sci->src_clk);
+
+ clk_enable(sdd->clk);
+
+ s3c64xx_spi_hwinit(sdd, pdev->id);
+
+ spin_lock_irqsave(&sdd->lock, flags);
+ sdd->state &= ~SUSPND;
+ spin_unlock_irqrestore(&sdd->lock, flags);
+
+ return 0;
+}
+#else
+#define s3c64xx_spi_suspend NULL
+#define s3c64xx_spi_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver s3c64xx_spi_driver = {
+ .driver = {
+ .name = "s3c64xx-spi",
+ .owner = THIS_MODULE,
+ },
+ .remove = s3c64xx_spi_remove,
+ .suspend = s3c64xx_spi_suspend,
+ .resume = s3c64xx_spi_resume,
+};
+MODULE_ALIAS("platform:s3c64xx-spi");
+
+static int __init s3c64xx_spi_init(void)
+{
+ return platform_driver_probe(&s3c64xx_spi_driver, s3c64xx_spi_probe);
+}
+module_init(s3c64xx_spi_init);
+
+static void __exit s3c64xx_spi_exit(void)
+{
+ platform_driver_unregister(&s3c64xx_spi_driver);
+}
+module_exit(s3c64xx_spi_exit);
+
+MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>");
+MODULE_DESCRIPTION("S3C64XX SPI Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi_sh_sci.c b/drivers/spi/spi_sh_sci.c
index 7d36720eb98..a65c12ffa73 100644
--- a/drivers/spi/spi_sh_sci.c
+++ b/drivers/spi/spi_sh_sci.c
@@ -148,7 +148,7 @@ static int sh_sci_spi_probe(struct platform_device *dev)
ret = -ENOENT;
goto err1;
}
- sp->membase = ioremap(r->start, r->end - r->start + 1);
+ sp->membase = ioremap(r->start, resource_size(r));
if (!sp->membase) {
ret = -ENXIO;
goto err1;
diff --git a/drivers/spi/spi_txx9.c b/drivers/spi/spi_txx9.c
index 19f75627c3d..dfa024b633e 100644
--- a/drivers/spi/spi_txx9.c
+++ b/drivers/spi/spi_txx9.c
@@ -375,12 +375,10 @@ static int __init txx9spi_probe(struct platform_device *dev)
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res)
goto exit_busy;
- if (!devm_request_mem_region(&dev->dev,
- res->start, res->end - res->start + 1,
+ if (!devm_request_mem_region(&dev->dev, res->start, resource_size(res),
"spi_txx9"))
goto exit_busy;
- c->membase = devm_ioremap(&dev->dev,
- res->start, res->end - res->start + 1);
+ c->membase = devm_ioremap(&dev->dev, res->start, resource_size(res));
if (!c->membase)
goto exit_busy;
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 9c446e6003d..ea1bec3c9a1 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -53,7 +53,7 @@
#define SPIDEV_MAJOR 153 /* assigned */
#define N_SPI_MINORS 32 /* ... up to 256 */
-static unsigned long minors[N_SPI_MINORS / BITS_PER_LONG];
+static DECLARE_BITMAP(minors, N_SPI_MINORS);
/* Bit masks for spi_device.mode management. Note that incorrect
@@ -558,7 +558,7 @@ static struct class *spidev_class;
/*-------------------------------------------------------------------------*/
-static int spidev_probe(struct spi_device *spi)
+static int __devinit spidev_probe(struct spi_device *spi)
{
struct spidev_data *spidev;
int status;
@@ -607,7 +607,7 @@ static int spidev_probe(struct spi_device *spi)
return status;
}
-static int spidev_remove(struct spi_device *spi)
+static int __devexit spidev_remove(struct spi_device *spi)
{
struct spidev_data *spidev = spi_get_drvdata(spi);
@@ -629,7 +629,7 @@ static int spidev_remove(struct spi_device *spi)
return 0;
}
-static struct spi_driver spidev_spi = {
+static struct spi_driver spidev_spi_driver = {
.driver = {
.name = "spidev",
.owner = THIS_MODULE,
@@ -661,14 +661,14 @@ static int __init spidev_init(void)
spidev_class = class_create(THIS_MODULE, "spidev");
if (IS_ERR(spidev_class)) {
- unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
+ unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
return PTR_ERR(spidev_class);
}
- status = spi_register_driver(&spidev_spi);
+ status = spi_register_driver(&spidev_spi_driver);
if (status < 0) {
class_destroy(spidev_class);
- unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
+ unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
}
return status;
}
@@ -676,9 +676,9 @@ module_init(spidev_init);
static void __exit spidev_exit(void)
{
- spi_unregister_driver(&spidev_spi);
+ spi_unregister_driver(&spidev_spi_driver);
class_destroy(spidev_class);
- unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
+ unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
}
module_exit(spidev_exit);
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 093f57af32d..94eb86319ff 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -87,8 +87,6 @@ source "drivers/staging/frontier/Kconfig"
source "drivers/staging/dream/Kconfig"
-source "drivers/staging/dst/Kconfig"
-
source "drivers/staging/pohmelfs/Kconfig"
source "drivers/staging/b3dfg/Kconfig"
@@ -145,5 +143,7 @@ source "drivers/staging/wavelan/Kconfig"
source "drivers/staging/netwave/Kconfig"
+source "drivers/staging/sm7xx/Kconfig"
+
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 069864f4391..b5e67b889f6 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -26,7 +26,6 @@ obj-$(CONFIG_RTL8192E) += rtl8192e/
obj-$(CONFIG_INPUT_MIMIO) += mimio/
obj-$(CONFIG_TRANZPORT) += frontier/
obj-$(CONFIG_DREAM) += dream/
-obj-$(CONFIG_DST) += dst/
obj-$(CONFIG_POHMELFS) += pohmelfs/
obj-$(CONFIG_B3DFG) += b3dfg/
obj-$(CONFIG_IDE_PHISON) += phison/
@@ -53,3 +52,4 @@ obj-$(CONFIG_ARLAN) += arlan/
obj-$(CONFIG_WAVELAN) += wavelan/
obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan/
obj-$(CONFIG_PCMCIA_NETWAVE) += netwave/
+obj-$(CONFIG_FB_SM7XX) += sm7xx/
diff --git a/drivers/staging/batman-adv/Kconfig b/drivers/staging/batman-adv/Kconfig
index 7632f576006..1d74dabf951 100644
--- a/drivers/staging/batman-adv/Kconfig
+++ b/drivers/staging/batman-adv/Kconfig
@@ -4,6 +4,7 @@
config BATMAN_ADV
tristate "B.A.T.M.A.N. Advanced Meshing Protocol"
+ depends on PROC_FS && PACKET
default n
---help---
diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c
index d724798278d..eb617508cca 100644
--- a/drivers/staging/batman-adv/send.c
+++ b/drivers/staging/batman-adv/send.c
@@ -363,8 +363,10 @@ void add_bcast_packet_to_list(unsigned char *packet_buff, int packet_len)
return;
forw_packet->packet_buff = kmalloc(packet_len, GFP_ATOMIC);
- if (!forw_packet->packet_buff)
+ if (!forw_packet->packet_buff) {
+ kfree(forw_packet);
return;
+ }
forw_packet->packet_len = packet_len;
memcpy(forw_packet->packet_buff, packet_buff, forw_packet->packet_len);
diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h
index ccc5cdc008c..b559a9c2f85 100644
--- a/drivers/staging/comedi/comedi.h
+++ b/drivers/staging/comedi/comedi.h
@@ -451,7 +451,7 @@
#define COMEDI_CB_EOS 1 /* end of scan */
#define COMEDI_CB_EOA 2 /* end of acquisition */
-#define COMEDI_CB_BLOCK 4 /* DEPRECATED: convenient block size */
+#define COMEDI_CB_BLOCK 4 /* data has arrived: wakes up read() / write() */
#define COMEDI_CB_EOBUF 8 /* DEPRECATED: end of buffer */
#define COMEDI_CB_ERROR 16 /* card error during acquisition */
#define COMEDI_CB_OVERFLOW 32 /* buffer overflow/underflow */
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index 0d2c2eb23b2..bd397840dcb 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -849,8 +849,11 @@ static int jr3_pci_attach(struct comedi_device *dev,
}
devpriv->pci_enabled = 1;
- devpriv->iobase =
- ioremap(pci_resource_start(card, 0), sizeof(struct jr3_t));
+ devpriv->iobase = ioremap(pci_resource_start(card, 0),
+ offsetof(struct jr3_t, channel[devpriv->n_channels]));
+ if (!devpriv->iobase)
+ return -ENOMEM;
+
result = alloc_subdevices(dev, devpriv->n_channels);
if (result < 0)
goto out;
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index 06c02046629..9a1b559c4b0 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -1,4 +1,4 @@
-#define DRIVER_VERSION "v2.3"
+#define DRIVER_VERSION "v2.4"
#define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com"
#define DRIVER_DESC "Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com"
/*
@@ -81,6 +81,8 @@ sampling rate. If you sample two channels you get 4kHz and so on.
* 2.1: changed PWM API
* 2.2: added firmware kernel request to fix an udev problem
* 2.3: corrected a bug in bulk timeouts which were far too short
+ * 2.4: fixed a bug which causes the driver to hang when it ran out of data.
+ * Thanks to Jan-Matthias Braun and Ian to spot the bug and fix it.
*
*/
@@ -532,6 +534,7 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb)
}
}
/* tell comedi that data is there */
+ s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
comedi_event(this_usbduxsub->comedidev, s);
}
diff --git a/drivers/staging/dst/Kconfig b/drivers/staging/dst/Kconfig
deleted file mode 100644
index 448d342ac2a..00000000000
--- a/drivers/staging/dst/Kconfig
+++ /dev/null
@@ -1,67 +0,0 @@
-config DST
- tristate "Distributed storage"
- depends on NET && CRYPTO && SYSFS && BLK_DEV
- select CONNECTOR
- ---help---
- DST is a network block device storage, which can be used to organize
- exported storage on the remote nodes into the local block device.
-
- DST works on top of any network media and protocol; it is just a matter
- of configuration utility to understand the correct addresses. The most
- common example is TCP over IP, which allows to pass through firewalls and
- create remote backup storage in a different datacenter. DST requires
- single port to be enabled on the exporting node and outgoing connections
- on the local node.
-
- DST works with in-kernel client and server, which improves performance by
- eliminating unneded data copies and by not depending on the version
- of the external IO components. It requires userspace configuration utility
- though.
-
- DST uses transaction model, when each store has to be explicitly acked
- from the remote node to be considered as successfully written. There
- may be lots of in-flight transactions. When remote host does not ack
- the transaction it will be resent predefined number of times with specified
- timeouts between them. All those parameters are configurable. Transactions
- are marked as failed after all resends complete unsuccessfully; having
- long enough resend timeout and/or large number of resends allows not to
- return error to the higher (FS usually) layer in case of short network
- problems or remote node outages. In case of network RAID setup this means
- that storage will not degrade until transactions are marked as failed, and
- thus will not force checksum recalculation and data rebuild. In case of
- connection failure DST will try to reconnect to the remote node automatically.
- DST sends ping commands at idle time to detect if remote node is alive.
-
- Because of transactional model it is possible to use zero-copy sending
- without worry of data corruption (which in turn could be detected by the
- strong checksums though).
-
- DST may fully encrypt the data channel in case of untrusted channel and implement
- strong checksum of the transferred data. It is possible to configure algorithms
- and crypto keys; they should match on both sides of the network channel.
- Crypto processing does not introduce noticeble performance overhead, since DST
- uses configurable pool of threads to perform crypto processing.
-
- DST utilizes memory pool model of all its transaction allocations (it is the
- only additional allocation on the client) and server allocations (bio pools,
- while pages are allocated from the slab).
-
- At startup DST performs a simple negotiation with the export node to determine
- access permissions and size of the exported storage. It can be extended if
- new parameters should be autonegotiated.
-
- DST carries block IO flags in the protocol, which allows to transparently implement
- barriers and sync/flush operations. Those flags are used in the export node where
- IO against the local storage is performed, which means that sync write will be sync
- on the remote node too, which in turn improves data integrity and improved resistance
- to errors and data corruption during power outages or storage damages.
-
- Homepage: http://www.ioremap.net/projects/dst
- Userspace configuration utility and the latest releases: http://www.ioremap.net/archive/dst/
-
-config DST_DEBUG
- bool "DST debug"
- depends on DST
- ---help---
- This option will enable HEAVY debugging of the DST.
- Turn it on ONLY if you have to debug some really obscure problem.
diff --git a/drivers/staging/dst/Makefile b/drivers/staging/dst/Makefile
deleted file mode 100644
index 3a8b0cf9643..00000000000
--- a/drivers/staging/dst/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_DST) += nst.o
-
-nst-y := dcore.o state.o export.o thread_pool.o crypto.o trans.o
diff --git a/drivers/staging/dst/crypto.c b/drivers/staging/dst/crypto.c
deleted file mode 100644
index 351295c97a4..00000000000
--- a/drivers/staging/dst/crypto.c
+++ /dev/null
@@ -1,733 +0,0 @@
-/*
- * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
- * All rights reserved.
- *
- * 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.
- */
-
-#include <linux/bio.h>
-#include <linux/crypto.h>
-#include <linux/dst.h>
-#include <linux/kernel.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-
-/*
- * Tricky bastard, but IV can be more complex with time...
- */
-static inline u64 dst_gen_iv(struct dst_trans *t)
-{
- return t->gen;
-}
-
-/*
- * Crypto machinery: hash/cipher support for the given crypto controls.
- */
-static struct crypto_hash *dst_init_hash(struct dst_crypto_ctl *ctl, u8 *key)
-{
- int err;
- struct crypto_hash *hash;
-
- hash = crypto_alloc_hash(ctl->hash_algo, 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(hash)) {
- err = PTR_ERR(hash);
- dprintk("%s: failed to allocate hash '%s', err: %d.\n",
- __func__, ctl->hash_algo, err);
- goto err_out_exit;
- }
-
- ctl->crypto_attached_size = crypto_hash_digestsize(hash);
-
- if (!ctl->hash_keysize)
- return hash;
-
- err = crypto_hash_setkey(hash, key, ctl->hash_keysize);
- if (err) {
- dprintk("%s: failed to set key for hash '%s', err: %d.\n",
- __func__, ctl->hash_algo, err);
- goto err_out_free;
- }
-
- return hash;
-
-err_out_free:
- crypto_free_hash(hash);
-err_out_exit:
- return ERR_PTR(err);
-}
-
-static struct crypto_ablkcipher *dst_init_cipher(struct dst_crypto_ctl *ctl,
- u8 *key)
-{
- int err = -EINVAL;
- struct crypto_ablkcipher *cipher;
-
- if (!ctl->cipher_keysize)
- goto err_out_exit;
-
- cipher = crypto_alloc_ablkcipher(ctl->cipher_algo, 0, 0);
- if (IS_ERR(cipher)) {
- err = PTR_ERR(cipher);
- dprintk("%s: failed to allocate cipher '%s', err: %d.\n",
- __func__, ctl->cipher_algo, err);
- goto err_out_exit;
- }
-
- crypto_ablkcipher_clear_flags(cipher, ~0);
-
- err = crypto_ablkcipher_setkey(cipher, key, ctl->cipher_keysize);
- if (err) {
- dprintk("%s: failed to set key for cipher '%s', err: %d.\n",
- __func__, ctl->cipher_algo, err);
- goto err_out_free;
- }
-
- return cipher;
-
-err_out_free:
- crypto_free_ablkcipher(cipher);
-err_out_exit:
- return ERR_PTR(err);
-}
-
-/*
- * Crypto engine has a pool of pages to encrypt data into before sending
- * it over the network. This pool is freed/allocated here.
- */
-static void dst_crypto_pages_free(struct dst_crypto_engine *e)
-{
- unsigned int i;
-
- for (i = 0; i < e->page_num; ++i)
- __free_page(e->pages[i]);
- kfree(e->pages);
-}
-
-static int dst_crypto_pages_alloc(struct dst_crypto_engine *e, int num)
-{
- int i;
-
- e->pages = kmalloc(num * sizeof(struct page **), GFP_KERNEL);
- if (!e->pages)
- return -ENOMEM;
-
- for (i = 0; i < num; ++i) {
- e->pages[i] = alloc_page(GFP_KERNEL);
- if (!e->pages[i])
- goto err_out_free_pages;
- }
-
- e->page_num = num;
- return 0;
-
-err_out_free_pages:
- while (--i >= 0)
- __free_page(e->pages[i]);
-
- kfree(e->pages);
- return -ENOMEM;
-}
-
-/*
- * Initialize crypto engine for given node.
- * Setup cipher/hash, keys, pool of threads and private data.
- */
-static int dst_crypto_engine_init(struct dst_crypto_engine *e,
- struct dst_node *n)
-{
- int err;
- struct dst_crypto_ctl *ctl = &n->crypto;
-
- err = dst_crypto_pages_alloc(e, n->max_pages);
- if (err)
- goto err_out_exit;
-
- e->size = PAGE_SIZE;
- e->data = kmalloc(e->size, GFP_KERNEL);
- if (!e->data) {
- err = -ENOMEM;
- goto err_out_free_pages;
- }
-
- if (ctl->hash_algo[0]) {
- e->hash = dst_init_hash(ctl, n->hash_key);
- if (IS_ERR(e->hash)) {
- err = PTR_ERR(e->hash);
- e->hash = NULL;
- goto err_out_free;
- }
- }
-
- if (ctl->cipher_algo[0]) {
- e->cipher = dst_init_cipher(ctl, n->cipher_key);
- if (IS_ERR(e->cipher)) {
- err = PTR_ERR(e->cipher);
- e->cipher = NULL;
- goto err_out_free_hash;
- }
- }
-
- return 0;
-
-err_out_free_hash:
- crypto_free_hash(e->hash);
-err_out_free:
- kfree(e->data);
-err_out_free_pages:
- dst_crypto_pages_free(e);
-err_out_exit:
- return err;
-}
-
-static void dst_crypto_engine_exit(struct dst_crypto_engine *e)
-{
- if (e->hash)
- crypto_free_hash(e->hash);
- if (e->cipher)
- crypto_free_ablkcipher(e->cipher);
- dst_crypto_pages_free(e);
- kfree(e->data);
-}
-
-/*
- * Waiting for cipher processing to be completed.
- */
-struct dst_crypto_completion {
- struct completion complete;
- int error;
-};
-
-static void dst_crypto_complete(struct crypto_async_request *req, int err)
-{
- struct dst_crypto_completion *c = req->data;
-
- if (err == -EINPROGRESS)
- return;
-
- dprintk("%s: req: %p, err: %d.\n", __func__, req, err);
- c->error = err;
- complete(&c->complete);
-}
-
-static int dst_crypto_process(struct ablkcipher_request *req,
- struct scatterlist *sg_dst, struct scatterlist *sg_src,
- void *iv, int enc, unsigned long timeout)
-{
- struct dst_crypto_completion c;
- int err;
-
- init_completion(&c.complete);
- c.error = -EINPROGRESS;
-
- ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
- dst_crypto_complete, &c);
-
- ablkcipher_request_set_crypt(req, sg_src, sg_dst, sg_src->length, iv);
-
- if (enc)
- err = crypto_ablkcipher_encrypt(req);
- else
- err = crypto_ablkcipher_decrypt(req);
-
- switch (err) {
- case -EINPROGRESS:
- case -EBUSY:
- err = wait_for_completion_interruptible_timeout(&c.complete,
- timeout);
- if (!err)
- err = -ETIMEDOUT;
- else
- err = c.error;
- break;
- default:
- break;
- }
-
- return err;
-}
-
-/*
- * DST uses generic iteration approach for data crypto processing.
- * Single block IO request is switched into array of scatterlists,
- * which are submitted to the crypto processing iterator.
- *
- * Input and output iterator initialization are different, since
- * in output case we can not encrypt data in-place and need a
- * temporary storage, which is then being sent to the remote peer.
- */
-static int dst_trans_iter_out(struct bio *bio, struct dst_crypto_engine *e,
- int (*iterator) (struct dst_crypto_engine *e,
- struct scatterlist *dst,
- struct scatterlist *src))
-{
- struct bio_vec *bv;
- int err, i;
-
- sg_init_table(e->src, bio->bi_vcnt);
- sg_init_table(e->dst, bio->bi_vcnt);
-
- bio_for_each_segment(bv, bio, i) {
- sg_set_page(&e->src[i], bv->bv_page, bv->bv_len, bv->bv_offset);
- sg_set_page(&e->dst[i], e->pages[i], bv->bv_len, bv->bv_offset);
-
- err = iterator(e, &e->dst[i], &e->src[i]);
- if (err)
- return err;
- }
-
- return 0;
-}
-
-static int dst_trans_iter_in(struct bio *bio, struct dst_crypto_engine *e,
- int (*iterator) (struct dst_crypto_engine *e,
- struct scatterlist *dst,
- struct scatterlist *src))
-{
- struct bio_vec *bv;
- int err, i;
-
- sg_init_table(e->src, bio->bi_vcnt);
- sg_init_table(e->dst, bio->bi_vcnt);
-
- bio_for_each_segment(bv, bio, i) {
- sg_set_page(&e->src[i], bv->bv_page, bv->bv_len, bv->bv_offset);
- sg_set_page(&e->dst[i], bv->bv_page, bv->bv_len, bv->bv_offset);
-
- err = iterator(e, &e->dst[i], &e->src[i]);
- if (err)
- return err;
- }
-
- return 0;
-}
-
-static int dst_crypt_iterator(struct dst_crypto_engine *e,
- struct scatterlist *sg_dst, struct scatterlist *sg_src)
-{
- struct ablkcipher_request *req = e->data;
- u8 iv[32];
-
- memset(iv, 0, sizeof(iv));
-
- memcpy(iv, &e->iv, sizeof(e->iv));
-
- return dst_crypto_process(req, sg_dst, sg_src, iv, e->enc, e->timeout);
-}
-
-static int dst_crypt(struct dst_crypto_engine *e, struct bio *bio)
-{
- struct ablkcipher_request *req = e->data;
-
- memset(req, 0, sizeof(struct ablkcipher_request));
- ablkcipher_request_set_tfm(req, e->cipher);
-
- if (e->enc)
- return dst_trans_iter_out(bio, e, dst_crypt_iterator);
- else
- return dst_trans_iter_in(bio, e, dst_crypt_iterator);
-}
-
-static int dst_hash_iterator(struct dst_crypto_engine *e,
- struct scatterlist *sg_dst, struct scatterlist *sg_src)
-{
- return crypto_hash_update(e->data, sg_src, sg_src->length);
-}
-
-static int dst_hash(struct dst_crypto_engine *e, struct bio *bio, void *dst)
-{
- struct hash_desc *desc = e->data;
- int err;
-
- desc->tfm = e->hash;
- desc->flags = 0;
-
- err = crypto_hash_init(desc);
- if (err)
- return err;
-
- err = dst_trans_iter_in(bio, e, dst_hash_iterator);
- if (err)
- return err;
-
- err = crypto_hash_final(desc, dst);
- if (err)
- return err;
-
- return 0;
-}
-
-/*
- * Initialize/cleanup a crypto thread. The only thing it should
- * do is to allocate a pool of pages as temporary storage.
- * And to setup cipher and/or hash.
- */
-static void *dst_crypto_thread_init(void *data)
-{
- struct dst_node *n = data;
- struct dst_crypto_engine *e;
- int err = -ENOMEM;
-
- e = kzalloc(sizeof(struct dst_crypto_engine), GFP_KERNEL);
- if (!e)
- goto err_out_exit;
- e->src = kcalloc(2 * n->max_pages, sizeof(struct scatterlist),
- GFP_KERNEL);
- if (!e->src)
- goto err_out_free;
-
- e->dst = e->src + n->max_pages;
-
- err = dst_crypto_engine_init(e, n);
- if (err)
- goto err_out_free_all;
-
- return e;
-
-err_out_free_all:
- kfree(e->src);
-err_out_free:
- kfree(e);
-err_out_exit:
- return ERR_PTR(err);
-}
-
-static void dst_crypto_thread_cleanup(void *private)
-{
- struct dst_crypto_engine *e = private;
-
- dst_crypto_engine_exit(e);
- kfree(e->src);
- kfree(e);
-}
-
-/*
- * Initialize crypto engine for given node: store keys, create pool
- * of threads, initialize each one.
- *
- * Each thread has unique ID, but 0 and 1 are reserved for receiving and
- * accepting threads (if export node), so IDs could start from 2, but starting
- * them from 10 allows easily understand what this thread is for.
- */
-int dst_node_crypto_init(struct dst_node *n, struct dst_crypto_ctl *ctl)
-{
- void *key = (ctl + 1);
- int err = -ENOMEM, i;
- char name[32];
-
- if (ctl->hash_keysize) {
- n->hash_key = kmalloc(ctl->hash_keysize, GFP_KERNEL);
- if (!n->hash_key)
- goto err_out_exit;
- memcpy(n->hash_key, key, ctl->hash_keysize);
- }
-
- if (ctl->cipher_keysize) {
- n->cipher_key = kmalloc(ctl->cipher_keysize, GFP_KERNEL);
- if (!n->cipher_key)
- goto err_out_free_hash;
- memcpy(n->cipher_key, key, ctl->cipher_keysize);
- }
- memcpy(&n->crypto, ctl, sizeof(struct dst_crypto_ctl));
-
- for (i = 0; i < ctl->thread_num; ++i) {
- snprintf(name, sizeof(name), "%s-crypto-%d", n->name, i);
- /* Unique ids... */
- err = thread_pool_add_worker(n->pool, name, i + 10,
- dst_crypto_thread_init, dst_crypto_thread_cleanup, n);
- if (err)
- goto err_out_free_threads;
- }
-
- return 0;
-
-err_out_free_threads:
- while (--i >= 0)
- thread_pool_del_worker_id(n->pool, i+10);
-
- if (ctl->cipher_keysize)
- kfree(n->cipher_key);
- ctl->cipher_keysize = 0;
-err_out_free_hash:
- if (ctl->hash_keysize)
- kfree(n->hash_key);
- ctl->hash_keysize = 0;
-err_out_exit:
- return err;
-}
-
-void dst_node_crypto_exit(struct dst_node *n)
-{
- struct dst_crypto_ctl *ctl = &n->crypto;
-
- if (ctl->cipher_algo[0] || ctl->hash_algo[0]) {
- kfree(n->hash_key);
- kfree(n->cipher_key);
- }
-}
-
-/*
- * Thrad pool setup callback. Just stores a transaction in private data.
- */
-static int dst_trans_crypto_setup(void *crypto_engine, void *trans)
-{
- struct dst_crypto_engine *e = crypto_engine;
-
- e->private = trans;
- return 0;
-}
-
-#if 0
-static void dst_dump_bio(struct bio *bio)
-{
- u8 *p;
- struct bio_vec *bv;
- int i;
-
- bio_for_each_segment(bv, bio, i) {
- dprintk("%s: %llu/%u: size: %u, offset: %u, data: ",
- __func__, bio->bi_sector, bio->bi_size,
- bv->bv_len, bv->bv_offset);
-
- p = kmap(bv->bv_page) + bv->bv_offset;
- for (i = 0; i < bv->bv_len; ++i)
- printk(KERN_DEBUG "%02x ", p[i]);
- kunmap(bv->bv_page);
- printk("\n");
- }
-}
-#endif
-
-/*
- * Encrypt/hash data and send it to the network.
- */
-static int dst_crypto_process_sending(struct dst_crypto_engine *e,
- struct bio *bio, u8 *hash)
-{
- int err;
-
- if (e->cipher) {
- err = dst_crypt(e, bio);
- if (err)
- goto err_out_exit;
- }
-
- if (e->hash) {
- err = dst_hash(e, bio, hash);
- if (err)
- goto err_out_exit;
-
-#ifdef CONFIG_DST_DEBUG
- {
- unsigned int i;
-
- /* dst_dump_bio(bio); */
-
- printk(KERN_DEBUG "%s: bio: %llu/%u, rw: %lu, hash: ",
- __func__, (u64)bio->bi_sector,
- bio->bi_size, bio_data_dir(bio));
- for (i = 0; i < crypto_hash_digestsize(e->hash); ++i)
- printk("%02x ", hash[i]);
- printk("\n");
- }
-#endif
- }
-
- return 0;
-
-err_out_exit:
- return err;
-}
-
-/*
- * Check if received data is valid. Decipher if it is.
- */
-static int dst_crypto_process_receiving(struct dst_crypto_engine *e,
- struct bio *bio, u8 *hash, u8 *recv_hash)
-{
- int err;
-
- if (e->hash) {
- int mismatch;
-
- err = dst_hash(e, bio, hash);
- if (err)
- goto err_out_exit;
-
- mismatch = !!memcmp(recv_hash, hash,
- crypto_hash_digestsize(e->hash));
-#ifdef CONFIG_DST_DEBUG
- /* dst_dump_bio(bio); */
-
- printk(KERN_DEBUG "%s: bio: %llu/%u, rw: %lu, hash mismatch: %d",
- __func__, (u64)bio->bi_sector, bio->bi_size,
- bio_data_dir(bio), mismatch);
- if (mismatch) {
- unsigned int i;
-
- printk(", recv/calc: ");
- for (i = 0; i < crypto_hash_digestsize(e->hash); ++i)
- printk("%02x/%02x ", recv_hash[i], hash[i]);
-
- }
- printk("\n");
-#endif
- err = -1;
- if (mismatch)
- goto err_out_exit;
- }
-
- if (e->cipher) {
- err = dst_crypt(e, bio);
- if (err)
- goto err_out_exit;
- }
-
- return 0;
-
-err_out_exit:
- return err;
-}
-
-/*
- * Thread pool callback to encrypt data and send it to the netowork.
- */
-static int dst_trans_crypto_action(void *crypto_engine, void *schedule_data)
-{
- struct dst_crypto_engine *e = crypto_engine;
- struct dst_trans *t = schedule_data;
- struct bio *bio = t->bio;
- int err;
-
- dprintk("%s: t: %p, gen: %llu, cipher: %p, hash: %p.\n",
- __func__, t, t->gen, e->cipher, e->hash);
-
- e->enc = t->enc;
- e->iv = dst_gen_iv(t);
-
- if (bio_data_dir(bio) == WRITE) {
- err = dst_crypto_process_sending(e, bio, t->cmd.hash);
- if (err)
- goto err_out_exit;
-
- if (e->hash) {
- t->cmd.csize = crypto_hash_digestsize(e->hash);
- t->cmd.size += t->cmd.csize;
- }
-
- return dst_trans_send(t);
- } else {
- u8 *hash = e->data + e->size/2;
-
- err = dst_crypto_process_receiving(e, bio, hash, t->cmd.hash);
- if (err)
- goto err_out_exit;
-
- dst_trans_remove(t);
- dst_trans_put(t);
- }
-
- return 0;
-
-err_out_exit:
- t->error = err;
- dst_trans_put(t);
- return err;
-}
-
-/*
- * Schedule crypto processing for given transaction.
- */
-int dst_trans_crypto(struct dst_trans *t)
-{
- struct dst_node *n = t->n;
- int err;
-
- err = thread_pool_schedule(n->pool,
- dst_trans_crypto_setup, dst_trans_crypto_action,
- t, MAX_SCHEDULE_TIMEOUT);
- if (err)
- goto err_out_exit;
-
- return 0;
-
-err_out_exit:
- dst_trans_put(t);
- return err;
-}
-
-/*
- * Crypto machinery for the export node.
- */
-static int dst_export_crypto_setup(void *crypto_engine, void *bio)
-{
- struct dst_crypto_engine *e = crypto_engine;
-
- e->private = bio;
- return 0;
-}
-
-static int dst_export_crypto_action(void *crypto_engine, void *schedule_data)
-{
- struct dst_crypto_engine *e = crypto_engine;
- struct bio *bio = schedule_data;
- struct dst_export_priv *p = bio->bi_private;
- int err;
-
- dprintk("%s: e: %p, data: %p, bio: %llu/%u, dir: %lu.\n",
- __func__, e, e->data, (u64)bio->bi_sector,
- bio->bi_size, bio_data_dir(bio));
-
- e->enc = (bio_data_dir(bio) == READ);
- e->iv = p->cmd.id;
-
- if (bio_data_dir(bio) == WRITE) {
- u8 *hash = e->data + e->size/2;
-
- err = dst_crypto_process_receiving(e, bio, hash, p->cmd.hash);
- if (err)
- goto err_out_exit;
-
- generic_make_request(bio);
- } else {
- err = dst_crypto_process_sending(e, bio, p->cmd.hash);
- if (err)
- goto err_out_exit;
-
- if (e->hash) {
- p->cmd.csize = crypto_hash_digestsize(e->hash);
- p->cmd.size += p->cmd.csize;
- }
-
- err = dst_export_send_bio(bio);
- }
- return 0;
-
-err_out_exit:
- bio_put(bio);
- return err;
-}
-
-int dst_export_crypto(struct dst_node *n, struct bio *bio)
-{
- int err;
-
- err = thread_pool_schedule(n->pool,
- dst_export_crypto_setup, dst_export_crypto_action,
- bio, MAX_SCHEDULE_TIMEOUT);
- if (err)
- goto err_out_exit;
-
- return 0;
-
-err_out_exit:
- bio_put(bio);
- return err;
-}
diff --git a/drivers/staging/dst/dcore.c b/drivers/staging/dst/dcore.c
deleted file mode 100644
index c83ca7e3d04..00000000000
--- a/drivers/staging/dst/dcore.c
+++ /dev/null
@@ -1,968 +0,0 @@
-/*
- * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
- * All rights reserved.
- *
- * 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.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/blkdev.h>
-#include <linux/bio.h>
-#include <linux/buffer_head.h>
-#include <linux/connector.h>
-#include <linux/dst.h>
-#include <linux/device.h>
-#include <linux/jhash.h>
-#include <linux/idr.h>
-#include <linux/init.h>
-#include <linux/namei.h>
-#include <linux/slab.h>
-#include <linux/socket.h>
-
-#include <linux/in.h>
-#include <linux/in6.h>
-
-#include <net/sock.h>
-
-static int dst_major;
-
-static DEFINE_MUTEX(dst_hash_lock);
-static struct list_head *dst_hashtable;
-static unsigned int dst_hashtable_size = 128;
-module_param(dst_hashtable_size, uint, 0644);
-
-static char dst_name[] = "Dementianting goldfish";
-
-static DEFINE_IDR(dst_index_idr);
-static struct cb_id cn_dst_id = { CN_DST_IDX, CN_DST_VAL };
-
-/*
- * DST sysfs tree for device called 'storage':
- *
- * /sys/bus/dst/devices/storage/
- * /sys/bus/dst/devices/storage/type : 192.168.4.80:1025
- * /sys/bus/dst/devices/storage/size : 800
- * /sys/bus/dst/devices/storage/name : storage
- */
-
-static int dst_dev_match(struct device *dev, struct device_driver *drv)
-{
- return 1;
-}
-
-static struct bus_type dst_dev_bus_type = {
- .name = "dst",
- .match = &dst_dev_match,
-};
-
-static void dst_node_release(struct device *dev)
-{
- struct dst_info *info = container_of(dev, struct dst_info, device);
-
- kfree(info);
-}
-
-static struct device dst_node_dev = {
- .bus = &dst_dev_bus_type,
- .release = &dst_node_release
-};
-
-/*
- * Setting size of the node after it was changed.
- */
-static void dst_node_set_size(struct dst_node *n)
-{
- struct block_device *bdev;
-
- set_capacity(n->disk, n->size >> 9);
-
- bdev = bdget_disk(n->disk, 0);
- if (bdev) {
- mutex_lock(&bdev->bd_inode->i_mutex);
- i_size_write(bdev->bd_inode, n->size);
- mutex_unlock(&bdev->bd_inode->i_mutex);
- bdput(bdev);
- }
-}
-
-/*
- * Distributed storage request processing function.
- */
-static int dst_request(struct request_queue *q, struct bio *bio)
-{
- struct dst_node *n = q->queuedata;
- int err = -EIO;
-
- if (bio_empty_barrier(bio) && !blk_queue_discard(q)) {
- /*
- * This is a dirty^Wnice hack, but if we complete this
- * operation with -EOPNOTSUPP like intended, XFS
- * will stuck and freeze the machine. This may be
- * not particulary XFS problem though, but it is the
- * only FS which sends empty barrier at umount time
- * I worked with.
- *
- * Empty barriers are not allowed anyway, see 51fd77bd9f512
- * for example, although later it was changed to
- * bio_rw_flagged(bio, BIO_RW_DISCARD) only, which does not
- * work in this case.
- */
- /* err = -EOPNOTSUPP; */
- err = 0;
- goto end_io;
- }
-
- bio_get(bio);
-
- return dst_process_bio(n, bio);
-
-end_io:
- bio_endio(bio, err);
- return err;
-}
-
-/*
- * Open/close callbacks for appropriate block device.
- */
-static int dst_bdev_open(struct block_device *bdev, fmode_t mode)
-{
- struct dst_node *n = bdev->bd_disk->private_data;
-
- dst_node_get(n);
- return 0;
-}
-
-static int dst_bdev_release(struct gendisk *disk, fmode_t mode)
-{
- struct dst_node *n = disk->private_data;
-
- dst_node_put(n);
- return 0;
-}
-
-static struct block_device_operations dst_blk_ops = {
- .open = dst_bdev_open,
- .release = dst_bdev_release,
- .owner = THIS_MODULE,
-};
-
-/*
- * Block layer binding - disk is created when array is fully configured
- * by userspace request.
- */
-static int dst_node_create_disk(struct dst_node *n)
-{
- int err = -ENOMEM;
- u32 index = 0;
-
- n->queue = blk_init_queue(NULL, NULL);
- if (!n->queue)
- goto err_out_exit;
-
- n->queue->queuedata = n;
- blk_queue_make_request(n->queue, dst_request);
- blk_queue_max_phys_segments(n->queue, n->max_pages);
- blk_queue_max_hw_segments(n->queue, n->max_pages);
-
- err = -ENOMEM;
- n->disk = alloc_disk(1);
- if (!n->disk)
- goto err_out_free_queue;
-
- if (!(n->state->permissions & DST_PERM_WRITE)) {
- printk(KERN_INFO "DST node %s attached read-only.\n", n->name);
- set_disk_ro(n->disk, 1);
- }
-
- if (!idr_pre_get(&dst_index_idr, GFP_KERNEL))
- goto err_out_put;
-
- mutex_lock(&dst_hash_lock);
- err = idr_get_new(&dst_index_idr, NULL, &index);
- mutex_unlock(&dst_hash_lock);
- if (err)
- goto err_out_put;
-
- n->disk->major = dst_major;
- n->disk->first_minor = index;
- n->disk->fops = &dst_blk_ops;
- n->disk->queue = n->queue;
- n->disk->private_data = n;
- snprintf(n->disk->disk_name, sizeof(n->disk->disk_name),
- "dst-%s", n->name);
-
- return 0;
-
-err_out_put:
- put_disk(n->disk);
-err_out_free_queue:
- blk_cleanup_queue(n->queue);
-err_out_exit:
- return err;
-}
-
-/*
- * Sysfs machinery: show device's size.
- */
-static ssize_t dst_show_size(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct dst_info *info = container_of(dev, struct dst_info, device);
-
- return sprintf(buf, "%llu\n", info->size);
-}
-
-/*
- * Show local exported device.
- */
-static ssize_t dst_show_local(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct dst_info *info = container_of(dev, struct dst_info, device);
-
- return sprintf(buf, "%s\n", info->local);
-}
-
-/*
- * Shows type of the remote node - device major/minor number
- * for local nodes and address (af_inet ipv4/ipv6 only) for remote nodes.
- */
-static ssize_t dst_show_type(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct dst_info *info = container_of(dev, struct dst_info, device);
- int family = info->net.addr.sa_family;
-
- if (family == AF_INET) {
- struct sockaddr_in *sin = (struct sockaddr_in *)&info->net.addr;
- return sprintf(buf, "%u.%u.%u.%u:%d\n",
- NIPQUAD(sin->sin_addr.s_addr), ntohs(sin->sin_port));
- } else if (family == AF_INET6) {
- struct sockaddr_in6 *sin = (struct sockaddr_in6 *)
- &info->net.addr;
- return sprintf(buf,
- "%pi6:%d\n",
- &sin->sin6_addr, ntohs(sin->sin6_port));
- } else {
- int i, sz = PAGE_SIZE - 2; /* 0 symbol and '\n' below */
- int size, addrlen = info->net.addr.sa_data_len;
- unsigned char *a = (unsigned char *)&info->net.addr.sa_data;
- char *buf_orig = buf;
-
- size = snprintf(buf, sz, "family: %d, addrlen: %u, addr: ",
- family, addrlen);
- sz -= size;
- buf += size;
-
- for (i = 0; i < addrlen; ++i) {
- if (sz < 3)
- break;
-
- size = snprintf(buf, sz, "%02x ", a[i]);
- sz -= size;
- buf += size;
- }
- buf += sprintf(buf, "\n");
-
- return buf - buf_orig;
- }
- return 0;
-}
-
-static struct device_attribute dst_node_attrs[] = {
- __ATTR(size, 0444, dst_show_size, NULL),
- __ATTR(type, 0444, dst_show_type, NULL),
- __ATTR(local, 0444, dst_show_local, NULL),
-};
-
-static int dst_create_node_attributes(struct dst_node *n)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(dst_node_attrs); ++i) {
- err = device_create_file(&n->info->device,
- &dst_node_attrs[i]);
- if (err)
- goto err_out_remove_all;
- }
- return 0;
-
-err_out_remove_all:
- while (--i >= 0)
- device_remove_file(&n->info->device,
- &dst_node_attrs[i]);
-
- return err;
-}
-
-static void dst_remove_node_attributes(struct dst_node *n)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(dst_node_attrs); ++i)
- device_remove_file(&n->info->device,
- &dst_node_attrs[i]);
-}
-
-/*
- * Sysfs cleanup and initialization.
- * Shows number of useful parameters.
- */
-static void dst_node_sysfs_exit(struct dst_node *n)
-{
- if (n->info) {
- dst_remove_node_attributes(n);
- device_unregister(&n->info->device);
- n->info = NULL;
- }
-}
-
-static int dst_node_sysfs_init(struct dst_node *n)
-{
- int err;
-
- n->info = kzalloc(sizeof(struct dst_info), GFP_KERNEL);
- if (!n->info)
- return -ENOMEM;
-
- memcpy(&n->info->device, &dst_node_dev, sizeof(struct device));
- n->info->size = n->size;
-
- dev_set_name(&n->info->device, "dst-%s", n->name);
- err = device_register(&n->info->device);
- if (err) {
- dprintk(KERN_ERR "Failed to register node '%s', err: %d.\n",
- n->name, err);
- goto err_out_exit;
- }
-
- dst_create_node_attributes(n);
-
- return 0;
-
-err_out_exit:
- kfree(n->info);
- n->info = NULL;
- return err;
-}
-
-/*
- * DST node hash tables machinery.
- */
-static inline unsigned int dst_hash(char *str, unsigned int size)
-{
- return jhash(str, size, 0) % dst_hashtable_size;
-}
-
-static void dst_node_remove(struct dst_node *n)
-{
- mutex_lock(&dst_hash_lock);
- list_del_init(&n->node_entry);
- mutex_unlock(&dst_hash_lock);
-}
-
-static void dst_node_add(struct dst_node *n)
-{
- unsigned hash = dst_hash(n->name, sizeof(n->name));
-
- mutex_lock(&dst_hash_lock);
- list_add_tail(&n->node_entry, &dst_hashtable[hash]);
- mutex_unlock(&dst_hash_lock);
-}
-
-/*
- * Cleaning node when it is about to be freed.
- * There are still users of the socket though,
- * so connection cleanup should be protected.
- */
-static void dst_node_cleanup(struct dst_node *n)
-{
- struct dst_state *st = n->state;
-
- if (!st)
- return;
-
- if (n->queue) {
- blk_cleanup_queue(n->queue);
-
- mutex_lock(&dst_hash_lock);
- idr_remove(&dst_index_idr, n->disk->first_minor);
- mutex_unlock(&dst_hash_lock);
-
- put_disk(n->disk);
- }
-
- if (n->bdev) {
- sync_blockdev(n->bdev);
- close_bdev_exclusive(n->bdev, FMODE_READ|FMODE_WRITE);
- }
-
- dst_state_lock(st);
- st->need_exit = 1;
- dst_state_exit_connected(st);
- dst_state_unlock(st);
-
- wake_up(&st->thread_wait);
-
- dst_state_put(st);
- n->state = NULL;
-}
-
-/*
- * Free security attributes attached to given node.
- */
-static void dst_security_exit(struct dst_node *n)
-{
- struct dst_secure *s, *tmp;
-
- list_for_each_entry_safe(s, tmp, &n->security_list, sec_entry) {
- list_del(&s->sec_entry);
- kfree(s);
- }
-}
-
-/*
- * Free node when there are no more users.
- * Actually node has to be freed on behalf od userspace process,
- * since there are number of threads, which are embedded in the
- * node, so they can not exit and free node from there, that is
- * why there is a wakeup if reference counter is not equal to zero.
- */
-void dst_node_put(struct dst_node *n)
-{
- if (unlikely(!n))
- return;
-
- dprintk("%s: n: %p, refcnt: %d.\n",
- __func__, n, atomic_read(&n->refcnt));
-
- if (atomic_dec_and_test(&n->refcnt)) {
- dst_node_remove(n);
- n->trans_scan_timeout = 0;
- dst_node_cleanup(n);
- thread_pool_destroy(n->pool);
- dst_node_sysfs_exit(n);
- dst_node_crypto_exit(n);
- dst_security_exit(n);
- dst_node_trans_exit(n);
-
- kfree(n);
-
- dprintk("%s: freed n: %p.\n", __func__, n);
- } else {
- wake_up(&n->wait);
- }
-}
-
-/*
- * Setting up export device: lookup by the name, get its size
- * and setup listening socket, which will accept clients, which
- * will submit IO for given storage.
- */
-static int dst_setup_export(struct dst_node *n, struct dst_ctl *ctl,
- struct dst_export_ctl *le)
-{
- int err;
-
- snprintf(n->info->local, sizeof(n->info->local), "%s", le->device);
-
- n->bdev = open_bdev_exclusive(le->device, FMODE_READ|FMODE_WRITE, NULL);
- if (IS_ERR(n->bdev))
- return PTR_ERR(n->bdev);
-
- if (n->size != 0)
- n->size = min_t(loff_t, n->bdev->bd_inode->i_size, n->size);
- else
- n->size = n->bdev->bd_inode->i_size;
-
- n->info->size = n->size;
- err = dst_node_init_listened(n, le);
- if (err)
- goto err_out_cleanup;
-
- return 0;
-
-err_out_cleanup:
- close_bdev_exclusive(n->bdev, FMODE_READ|FMODE_WRITE);
- n->bdev = NULL;
-
- return err;
-}
-
-/* Empty thread pool callbacks for the network processing threads. */
-static inline void *dst_thread_network_init(void *data)
-{
- dprintk("%s: data: %p.\n", __func__, data);
- return data;
-}
-
-static inline void dst_thread_network_cleanup(void *data)
-{
- dprintk("%s: data: %p.\n", __func__, data);
-}
-
-/*
- * Allocate DST node and initialize some of its parameters.
- */
-static struct dst_node *dst_alloc_node(struct dst_ctl *ctl,
- int (*start)(struct dst_node *),
- int num)
-{
- struct dst_node *n;
- int err;
-
- n = kzalloc(sizeof(struct dst_node), GFP_KERNEL);
- if (!n)
- return NULL;
-
- INIT_LIST_HEAD(&n->node_entry);
-
- INIT_LIST_HEAD(&n->security_list);
- mutex_init(&n->security_lock);
-
- init_waitqueue_head(&n->wait);
-
- n->trans_scan_timeout = msecs_to_jiffies(ctl->trans_scan_timeout);
- if (!n->trans_scan_timeout)
- n->trans_scan_timeout = HZ;
-
- n->trans_max_retries = ctl->trans_max_retries;
- if (!n->trans_max_retries)
- n->trans_max_retries = 10;
-
- /*
- * Pretty much arbitrary default numbers.
- * 32 matches maximum number of pages in bio originated from ext3 (31).
- */
- n->max_pages = ctl->max_pages;
- if (!n->max_pages)
- n->max_pages = 32;
-
- if (n->max_pages > 1024)
- n->max_pages = 1024;
-
- n->start = start;
- n->size = ctl->size;
-
- atomic_set(&n->refcnt, 1);
- atomic_long_set(&n->gen, 0);
- snprintf(n->name, sizeof(n->name), "%s", ctl->name);
-
- err = dst_node_sysfs_init(n);
- if (err)
- goto err_out_free;
-
- n->pool = thread_pool_create(num, n->name, dst_thread_network_init,
- dst_thread_network_cleanup, n);
- if (IS_ERR(n->pool)) {
- err = PTR_ERR(n->pool);
- goto err_out_sysfs_exit;
- }
-
- dprintk("%s: n: %p, name: %s.\n", __func__, n, n->name);
-
- return n;
-
-err_out_sysfs_exit:
- dst_node_sysfs_exit(n);
-err_out_free:
- kfree(n);
- return NULL;
-}
-
-/*
- * Starting a node, connected to the remote server:
- * register block device and initialize transaction mechanism.
- * In revers order though.
- *
- * It will autonegotiate some parameters with the remote node
- * and update local if needed.
- *
- * Transaction initialization should be the last thing before
- * starting the node, since transaction should include not only
- * block IO, but also crypto related data (if any), which are
- * initialized separately.
- */
-static int dst_start_remote(struct dst_node *n)
-{
- int err;
-
- err = dst_node_trans_init(n, sizeof(struct dst_trans));
- if (err)
- return err;
-
- err = dst_node_create_disk(n);
- if (err)
- return err;
-
- dst_node_set_size(n);
- add_disk(n->disk);
-
- dprintk("DST: started remote node '%s', minor: %d.\n",
- n->name, n->disk->first_minor);
-
- return 0;
-}
-
-/*
- * Adding remote node and initialize connection.
- */
-static int dst_add_remote(struct dst_node *n, struct dst_ctl *ctl,
- void *data, unsigned int size)
-{
- int err;
- struct dst_network_ctl *rctl = data;
-
- if (n)
- return -EEXIST;
-
- if (size != sizeof(struct dst_network_ctl))
- return -EINVAL;
-
- n = dst_alloc_node(ctl, dst_start_remote, 1);
- if (!n)
- return -ENOMEM;
-
- memcpy(&n->info->net, rctl, sizeof(struct dst_network_ctl));
- err = dst_node_init_connected(n, rctl);
- if (err)
- goto err_out_free;
-
- dst_node_add(n);
-
- return 0;
-
-err_out_free:
- dst_node_put(n);
- return err;
-}
-
-/*
- * Adding export node: initializing block device and listening socket.
- */
-static int dst_add_export(struct dst_node *n, struct dst_ctl *ctl,
- void *data, unsigned int size)
-{
- int err;
- struct dst_export_ctl *le = data;
-
- if (n)
- return -EEXIST;
-
- if (size != sizeof(struct dst_export_ctl))
- return -EINVAL;
-
- n = dst_alloc_node(ctl, dst_start_export, 2);
- if (!n)
- return -EINVAL;
-
- err = dst_setup_export(n, ctl, le);
- if (err)
- goto err_out_free;
-
- dst_node_add(n);
-
- return 0;
-
-err_out_free:
- dst_node_put(n);
- return err;
-}
-
-static int dst_node_remove_unload(struct dst_node *n)
-{
- printk(KERN_INFO "STOPPED name: '%s', size: %llu.\n",
- n->name, n->size);
-
- if (n->disk)
- del_gendisk(n->disk);
-
- dst_node_remove(n);
- dst_node_sysfs_exit(n);
-
- /*
- * This is not a hack. Really.
- * Node's reference counter allows to implement fine grained
- * node freeing, but since all transactions (which hold node's
- * reference counter) are processed in the dedicated thread,
- * it is possible that reference will hit zero in that thread,
- * so we will not be able to exit thread and cleanup the node.
- *
- * So, we remove disk, so no new activity is possible, and
- * wait until all pending transaction are completed (either
- * in receiving thread or by timeout in workqueue), in this
- * case reference counter will be less or equal to 2 (once set in
- * dst_alloc_node() and then in connector message parser;
- * or when we force module unloading, and connector message
- * parser does not hold a reference, in this case reference
- * counter will be equal to 1),
- * and subsequent dst_node_put() calls will free the node.
- */
- dprintk("%s: going to sleep with %d refcnt.\n",
- __func__, atomic_read(&n->refcnt));
- wait_event(n->wait, atomic_read(&n->refcnt) <= 2);
-
- dst_node_put(n);
- return 0;
-}
-
-/*
- * Remove node from the hash table.
- */
-static int dst_del_node(struct dst_node *n, struct dst_ctl *ctl,
- void *data, unsigned int size)
-{
- if (!n)
- return -ENODEV;
-
- return dst_node_remove_unload(n);
-}
-
-/*
- * Initialize crypto processing for given node.
- */
-static int dst_crypto_init(struct dst_node *n, struct dst_ctl *ctl,
- void *data, unsigned int size)
-{
- struct dst_crypto_ctl *crypto = data;
-
- if (!n)
- return -ENODEV;
-
- if (size != sizeof(struct dst_crypto_ctl) + crypto->hash_keysize +
- crypto->cipher_keysize)
- return -EINVAL;
-
- if (n->trans_cache)
- return -EEXIST;
-
- return dst_node_crypto_init(n, crypto);
-}
-
-/*
- * Security attributes for given node.
- */
-static int dst_security_init(struct dst_node *n, struct dst_ctl *ctl,
- void *data, unsigned int size)
-{
- struct dst_secure *s;
-
- if (!n)
- return -ENODEV;
-
- if (size != sizeof(struct dst_secure_user))
- return -EINVAL;
-
- s = kmalloc(sizeof(struct dst_secure), GFP_KERNEL);
- if (!s)
- return -ENOMEM;
-
- memcpy(&s->sec, data, size);
-
- mutex_lock(&n->security_lock);
- list_add_tail(&s->sec_entry, &n->security_list);
- mutex_unlock(&n->security_lock);
-
- return 0;
-}
-
-/*
- * Kill'em all!
- */
-static int dst_start_node(struct dst_node *n, struct dst_ctl *ctl,
- void *data, unsigned int size)
-{
- int err;
-
- if (!n)
- return -ENODEV;
-
- if (n->trans_cache)
- return 0;
-
- err = n->start(n);
- if (err)
- return err;
-
- printk(KERN_INFO "STARTED name: '%s', size: %llu.\n", n->name, n->size);
- return 0;
-}
-
-typedef int (*dst_command_func)(struct dst_node *n, struct dst_ctl *ctl,
- void *data, unsigned int size);
-
-/*
- * List of userspace commands.
- */
-static dst_command_func dst_commands[] = {
- [DST_ADD_REMOTE] = &dst_add_remote,
- [DST_ADD_EXPORT] = &dst_add_export,
- [DST_DEL_NODE] = &dst_del_node,
- [DST_CRYPTO] = &dst_crypto_init,
- [DST_SECURITY] = &dst_security_init,
- [DST_START] = &dst_start_node,
-};
-
-/*
- * Configuration parser.
- */
-static void cn_dst_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
-{
- struct dst_ctl *ctl;
- int err;
- struct dst_ctl_ack ack;
- struct dst_node *n = NULL, *tmp;
- unsigned int hash;
-
- if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) {
- err = -EPERM;
- goto out;
- }
-
- if (msg->len < sizeof(struct dst_ctl)) {
- err = -EBADMSG;
- goto out;
- }
-
- ctl = (struct dst_ctl *)msg->data;
-
- if (ctl->cmd >= DST_CMD_MAX) {
- err = -EINVAL;
- goto out;
- }
- hash = dst_hash(ctl->name, sizeof(ctl->name));
-
- mutex_lock(&dst_hash_lock);
- list_for_each_entry(tmp, &dst_hashtable[hash], node_entry) {
- if (!memcmp(tmp->name, ctl->name, sizeof(tmp->name))) {
- n = tmp;
- dst_node_get(n);
- break;
- }
- }
- mutex_unlock(&dst_hash_lock);
-
- err = dst_commands[ctl->cmd](n, ctl, msg->data + sizeof(struct dst_ctl),
- msg->len - sizeof(struct dst_ctl));
-
- dst_node_put(n);
-out:
- memcpy(&ack.msg, msg, sizeof(struct cn_msg));
-
- ack.msg.ack = msg->ack + 1;
- ack.msg.len = sizeof(struct dst_ctl_ack) - sizeof(struct cn_msg);
-
- ack.error = err;
-
- cn_netlink_send(&ack.msg, 0, GFP_KERNEL);
-}
-
-/*
- * Global initialization: sysfs, hash table, block device registration,
- * connector and various caches.
- */
-static int __init dst_sysfs_init(void)
-{
- return bus_register(&dst_dev_bus_type);
-}
-
-static void dst_sysfs_exit(void)
-{
- bus_unregister(&dst_dev_bus_type);
-}
-
-static int __init dst_hashtable_init(void)
-{
- unsigned int i;
-
- dst_hashtable = kcalloc(dst_hashtable_size, sizeof(struct list_head),
- GFP_KERNEL);
- if (!dst_hashtable)
- return -ENOMEM;
-
- for (i = 0; i < dst_hashtable_size; ++i)
- INIT_LIST_HEAD(&dst_hashtable[i]);
-
- return 0;
-}
-
-static void dst_hashtable_exit(void)
-{
- unsigned int i;
- struct dst_node *n, *tmp;
-
- for (i = 0; i < dst_hashtable_size; ++i) {
- list_for_each_entry_safe(n, tmp, &dst_hashtable[i], node_entry) {
- dst_node_remove_unload(n);
- }
- }
-
- kfree(dst_hashtable);
-}
-
-static int __init dst_sys_init(void)
-{
- int err = -ENOMEM;
-
- err = dst_hashtable_init();
- if (err)
- goto err_out_exit;
-
- err = dst_export_init();
- if (err)
- goto err_out_hashtable_exit;
-
- err = register_blkdev(dst_major, DST_NAME);
- if (err < 0)
- goto err_out_export_exit;
- if (err)
- dst_major = err;
-
- err = dst_sysfs_init();
- if (err)
- goto err_out_unregister;
-
- err = cn_add_callback(&cn_dst_id, "DST", cn_dst_callback);
- if (err)
- goto err_out_sysfs_exit;
-
- printk(KERN_INFO "Distributed storage, '%s' release.\n", dst_name);
-
- return 0;
-
-err_out_sysfs_exit:
- dst_sysfs_exit();
-err_out_unregister:
- unregister_blkdev(dst_major, DST_NAME);
-err_out_export_exit:
- dst_export_exit();
-err_out_hashtable_exit:
- dst_hashtable_exit();
-err_out_exit:
- return err;
-}
-
-static void __exit dst_sys_exit(void)
-{
- cn_del_callback(&cn_dst_id);
- unregister_blkdev(dst_major, DST_NAME);
- dst_hashtable_exit();
- dst_sysfs_exit();
- dst_export_exit();
-}
-
-module_init(dst_sys_init);
-module_exit(dst_sys_exit);
-
-MODULE_DESCRIPTION("Distributed storage");
-MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/dst/export.c b/drivers/staging/dst/export.c
deleted file mode 100644
index c324230e8b6..00000000000
--- a/drivers/staging/dst/export.c
+++ /dev/null
@@ -1,660 +0,0 @@
-/*
- * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
- * All rights reserved.
- *
- * 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.
- */
-
-#include <linux/blkdev.h>
-#include <linux/bio.h>
-#include <linux/dst.h>
-#include <linux/in.h>
-#include <linux/in6.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/socket.h>
-
-#include <net/sock.h>
-
-/*
- * Export bioset is used for server block IO requests.
- */
-static struct bio_set *dst_bio_set;
-
-int __init dst_export_init(void)
-{
- int err = -ENOMEM;
-
- dst_bio_set = bioset_create(32, sizeof(struct dst_export_priv));
- if (!dst_bio_set)
- goto err_out_exit;
-
- return 0;
-
-err_out_exit:
- return err;
-}
-
-void dst_export_exit(void)
-{
- bioset_free(dst_bio_set);
-}
-
-/*
- * When client connects and autonegotiates with the server node,
- * its permissions are checked in a security attributes and sent
- * back.
- */
-static unsigned int dst_check_permissions(struct dst_state *main,
- struct dst_state *st)
-{
- struct dst_node *n = main->node;
- struct dst_secure *sentry;
- struct dst_secure_user *s;
- struct saddr *sa = &st->ctl.addr;
- unsigned int perm = 0;
-
- mutex_lock(&n->security_lock);
- list_for_each_entry(sentry, &n->security_list, sec_entry) {
- s = &sentry->sec;
-
- if (s->addr.sa_family != sa->sa_family)
- continue;
-
- if (s->addr.sa_data_len != sa->sa_data_len)
- continue;
-
- /*
- * This '2' below is a port field. This may be very wrong to do
- * in atalk for example though. If there will be any need
- * to extent protocol to something else, I can create
- * per-family helpers and use them instead of this memcmp.
- */
- if (memcmp(s->addr.sa_data + 2, sa->sa_data + 2,
- sa->sa_data_len - 2))
- continue;
-
- perm = s->permissions;
- }
- mutex_unlock(&n->security_lock);
-
- return perm;
-}
-
-/*
- * Accept new client: allocate appropriate network state and check permissions.
- */
-static struct dst_state *dst_accept_client(struct dst_state *st)
-{
- unsigned int revents = 0;
- unsigned int err_mask = POLLERR | POLLHUP | POLLRDHUP;
- unsigned int mask = err_mask | POLLIN;
- struct dst_node *n = st->node;
- int err = 0;
- struct socket *sock = NULL;
- struct dst_state *new;
-
- while (!err && !sock) {
- revents = dst_state_poll(st);
-
- if (!(revents & mask)) {
- DEFINE_WAIT(wait);
-
- for (;;) {
- prepare_to_wait(&st->thread_wait,
- &wait, TASK_INTERRUPTIBLE);
- if (!n->trans_scan_timeout || st->need_exit)
- break;
-
- revents = dst_state_poll(st);
-
- if (revents & mask)
- break;
-
- if (signal_pending(current))
- break;
-
- /*
- * Magic HZ? Polling check above is not safe in
- * all cases (like socket reset in BH context),
- * so it is simpler just to postpone it to the
- * process context instead of implementing
- * special locking there.
- */
- schedule_timeout(HZ);
- }
- finish_wait(&st->thread_wait, &wait);
- }
-
- err = -ECONNRESET;
- dst_state_lock(st);
-
- dprintk("%s: st: %p, revents: %x [err: %d, in: %d].\n",
- __func__, st, revents, revents & err_mask,
- revents & POLLIN);
-
- if (revents & err_mask) {
- dprintk("%s: revents: %x, socket: %p, err: %d.\n",
- __func__, revents, st->socket, err);
- err = -ECONNRESET;
- }
-
- if (!n->trans_scan_timeout || st->need_exit)
- err = -ENODEV;
-
- if (st->socket && (revents & POLLIN))
- err = kernel_accept(st->socket, &sock, 0);
-
- dst_state_unlock(st);
- }
-
- if (err)
- goto err_out_exit;
-
- new = dst_state_alloc(st->node);
- if (IS_ERR(new)) {
- err = -ENOMEM;
- goto err_out_release;
- }
- new->socket = sock;
-
- new->ctl.addr.sa_data_len = sizeof(struct sockaddr);
- err = kernel_getpeername(sock, (struct sockaddr *)&new->ctl.addr,
- (int *)&new->ctl.addr.sa_data_len);
- if (err)
- goto err_out_put;
-
- new->permissions = dst_check_permissions(st, new);
- if (new->permissions == 0) {
- err = -EPERM;
- dst_dump_addr(sock, (struct sockaddr *)&new->ctl.addr,
- "Client is not allowed to connect");
- goto err_out_put;
- }
-
- err = dst_poll_init(new);
- if (err)
- goto err_out_put;
-
- dst_dump_addr(sock, (struct sockaddr *)&new->ctl.addr,
- "Connected client");
-
- return new;
-
-err_out_put:
- dst_state_put(new);
-err_out_release:
- sock_release(sock);
-err_out_exit:
- return ERR_PTR(err);
-}
-
-/*
- * Each server's block request sometime finishes.
- * Usually it happens in hard irq context of the appropriate controller,
- * so to play good with all cases we just queue BIO into the queue
- * and wake up processing thread, which gets completed request and
- * send (encrypting if needed) it back to the client (if it was a read
- * request), or sends back reply that writing successfully completed.
- */
-static int dst_export_process_request_queue(struct dst_state *st)
-{
- unsigned long flags;
- struct dst_export_priv *p = NULL;
- struct bio *bio;
- int err = 0;
-
- while (!list_empty(&st->request_list)) {
- spin_lock_irqsave(&st->request_lock, flags);
- if (!list_empty(&st->request_list)) {
- p = list_first_entry(&st->request_list,
- struct dst_export_priv, request_entry);
- list_del(&p->request_entry);
- }
- spin_unlock_irqrestore(&st->request_lock, flags);
-
- if (!p)
- break;
-
- bio = p->bio;
-
- if (dst_need_crypto(st->node) && (bio_data_dir(bio) == READ))
- err = dst_export_crypto(st->node, bio);
- else
- err = dst_export_send_bio(bio);
-
- if (err)
- break;
- }
-
- return err;
-}
-
-/*
- * Cleanup export state.
- * It has to wait until all requests are finished,
- * and then free them all.
- */
-static void dst_state_cleanup_export(struct dst_state *st)
-{
- struct dst_export_priv *p;
- unsigned long flags;
-
- /*
- * This loop waits for all pending bios to be completed and freed.
- */
- while (atomic_read(&st->refcnt) > 1) {
- dprintk("%s: st: %p, refcnt: %d, list_empty: %d.\n",
- __func__, st, atomic_read(&st->refcnt),
- list_empty(&st->request_list));
- wait_event_timeout(st->thread_wait,
- (atomic_read(&st->refcnt) == 1) ||
- !list_empty(&st->request_list),
- HZ/2);
-
- while (!list_empty(&st->request_list)) {
- p = NULL;
- spin_lock_irqsave(&st->request_lock, flags);
- if (!list_empty(&st->request_list)) {
- p = list_first_entry(&st->request_list,
- struct dst_export_priv, request_entry);
- list_del(&p->request_entry);
- }
- spin_unlock_irqrestore(&st->request_lock, flags);
-
- if (p)
- bio_put(p->bio);
-
- dprintk("%s: st: %p, refcnt: %d, list_empty: %d, p: "
- "%p.\n", __func__, st, atomic_read(&st->refcnt),
- list_empty(&st->request_list), p);
- }
- }
-
- dst_state_put(st);
-}
-
-/*
- * Client accepting thread.
- * Not only accepts new connection, but also schedules receiving thread
- * and performs request completion described above.
- */
-static int dst_accept(void *init_data, void *schedule_data)
-{
- struct dst_state *main_st = schedule_data;
- struct dst_node *n = init_data;
- struct dst_state *st;
- int err;
-
- while (n->trans_scan_timeout && !main_st->need_exit) {
- dprintk("%s: main_st: %p, n: %p.\n", __func__, main_st, n);
- st = dst_accept_client(main_st);
- if (IS_ERR(st))
- continue;
-
- err = dst_state_schedule_receiver(st);
- if (!err) {
- while (n->trans_scan_timeout) {
- err = wait_event_interruptible_timeout(st->thread_wait,
- !list_empty(&st->request_list) ||
- !n->trans_scan_timeout ||
- st->need_exit,
- HZ);
-
- if (!n->trans_scan_timeout || st->need_exit)
- break;
-
- if (list_empty(&st->request_list))
- continue;
-
- err = dst_export_process_request_queue(st);
- if (err)
- break;
- }
-
- st->need_exit = 1;
- wake_up(&st->thread_wait);
- }
-
- dst_state_cleanup_export(st);
- }
-
- dprintk("%s: freeing listening socket st: %p.\n", __func__, main_st);
-
- dst_state_lock(main_st);
- dst_poll_exit(main_st);
- dst_state_socket_release(main_st);
- dst_state_unlock(main_st);
- dst_state_put(main_st);
- dprintk("%s: freed listening socket st: %p.\n", __func__, main_st);
-
- return 0;
-}
-
-int dst_start_export(struct dst_node *n)
-{
- if (list_empty(&n->security_list)) {
- printk(KERN_ERR "You are trying to export node '%s' "
- "without security attributes.\nNo clients will "
- "be allowed to connect. Exiting.\n", n->name);
- return -EINVAL;
- }
- return dst_node_trans_init(n, sizeof(struct dst_export_priv));
-}
-
-/*
- * Initialize listening state and schedule accepting thread.
- */
-int dst_node_init_listened(struct dst_node *n, struct dst_export_ctl *le)
-{
- struct dst_state *st;
- int err = -ENOMEM;
- struct dst_network_ctl *ctl = &le->ctl;
-
- memcpy(&n->info->net, ctl, sizeof(struct dst_network_ctl));
-
- st = dst_state_alloc(n);
- if (IS_ERR(st)) {
- err = PTR_ERR(st);
- goto err_out_exit;
- }
- memcpy(&st->ctl, ctl, sizeof(struct dst_network_ctl));
-
- err = dst_state_socket_create(st);
- if (err)
- goto err_out_put;
-
- st->socket->sk->sk_reuse = 1;
-
- err = kernel_bind(st->socket, (struct sockaddr *)&ctl->addr,
- ctl->addr.sa_data_len);
- if (err)
- goto err_out_socket_release;
-
- err = kernel_listen(st->socket, 1024);
- if (err)
- goto err_out_socket_release;
- n->state = st;
-
- err = dst_poll_init(st);
- if (err)
- goto err_out_socket_release;
-
- dst_state_get(st);
-
- err = thread_pool_schedule(n->pool, dst_thread_setup,
- dst_accept, st, MAX_SCHEDULE_TIMEOUT);
- if (err)
- goto err_out_poll_exit;
-
- return 0;
-
-err_out_poll_exit:
- dst_poll_exit(st);
-err_out_socket_release:
- dst_state_socket_release(st);
-err_out_put:
- dst_state_put(st);
-err_out_exit:
- n->state = NULL;
- return err;
-}
-
-/*
- * Free bio and related private data.
- * Also drop a reference counter for appropriate state,
- * which waits when there are no more block IOs in-flight.
- */
-static void dst_bio_destructor(struct bio *bio)
-{
- struct bio_vec *bv;
- struct dst_export_priv *priv = bio->bi_private;
- int i;
-
- bio_for_each_segment(bv, bio, i) {
- if (!bv->bv_page)
- break;
-
- __free_page(bv->bv_page);
- }
-
- if (priv)
- dst_state_put(priv->state);
- bio_free(bio, dst_bio_set);
-}
-
-/*
- * Block IO completion. Queue request to be sent back to
- * the client (or just confirmation).
- */
-static void dst_bio_end_io(struct bio *bio, int err)
-{
- struct dst_export_priv *p = bio->bi_private;
- struct dst_state *st = p->state;
- unsigned long flags;
-
- spin_lock_irqsave(&st->request_lock, flags);
- list_add_tail(&p->request_entry, &st->request_list);
- spin_unlock_irqrestore(&st->request_lock, flags);
-
- wake_up(&st->thread_wait);
-}
-
-/*
- * Allocate read request for the server.
- */
-static int dst_export_read_request(struct bio *bio, unsigned int total_size)
-{
- unsigned int size;
- struct page *page;
- int err;
-
- while (total_size) {
- err = -ENOMEM;
- page = alloc_page(GFP_KERNEL);
- if (!page)
- goto err_out_exit;
-
- size = min_t(unsigned int, PAGE_SIZE, total_size);
-
- err = bio_add_page(bio, page, size, 0);
- dprintk("%s: bio: %llu/%u, size: %u, err: %d.\n",
- __func__, (u64)bio->bi_sector, bio->bi_size,
- size, err);
- if (err <= 0)
- goto err_out_free_page;
-
- total_size -= size;
- }
-
- return 0;
-
-err_out_free_page:
- __free_page(page);
-err_out_exit:
- return err;
-}
-
-/*
- * Allocate write request for the server.
- * Should not only get pages, but also read data from the network.
- */
-static int dst_export_write_request(struct dst_state *st,
- struct bio *bio, unsigned int total_size)
-{
- unsigned int size;
- struct page *page;
- void *data;
- int err;
-
- while (total_size) {
- err = -ENOMEM;
- page = alloc_page(GFP_KERNEL);
- if (!page)
- goto err_out_exit;
-
- data = kmap(page);
- if (!data)
- goto err_out_free_page;
-
- size = min_t(unsigned int, PAGE_SIZE, total_size);
-
- err = dst_data_recv(st, data, size);
- if (err)
- goto err_out_unmap_page;
-
- err = bio_add_page(bio, page, size, 0);
- if (err <= 0)
- goto err_out_unmap_page;
-
- kunmap(page);
-
- total_size -= size;
- }
-
- return 0;
-
-err_out_unmap_page:
- kunmap(page);
-err_out_free_page:
- __free_page(page);
-err_out_exit:
- return err;
-}
-
-/*
- * Groovy, we've gotten an IO request from the client.
- * Allocate BIO from the bioset, private data from the mempool
- * and lots of pages for IO.
- */
-int dst_process_io(struct dst_state *st)
-{
- struct dst_node *n = st->node;
- struct dst_cmd *cmd = st->data;
- struct bio *bio;
- struct dst_export_priv *priv;
- int err = -ENOMEM;
-
- if (unlikely(!n->bdev)) {
- err = -EINVAL;
- goto err_out_exit;
- }
-
- bio = bio_alloc_bioset(GFP_KERNEL,
- PAGE_ALIGN(cmd->size) >> PAGE_SHIFT,
- dst_bio_set);
- if (!bio)
- goto err_out_exit;
-
- priv = (struct dst_export_priv *)(((void *)bio) -
- sizeof (struct dst_export_priv));
-
- priv->state = dst_state_get(st);
- priv->bio = bio;
-
- bio->bi_private = priv;
- bio->bi_end_io = dst_bio_end_io;
- bio->bi_destructor = dst_bio_destructor;
- bio->bi_bdev = n->bdev;
-
- /*
- * Server side is only interested in two low bits:
- * uptodate (set by itself actually) and rw block
- */
- bio->bi_flags |= cmd->flags & 3;
-
- bio->bi_rw = cmd->rw;
- bio->bi_size = 0;
- bio->bi_sector = cmd->sector;
-
- dst_bio_to_cmd(bio, &priv->cmd, DST_IO_RESPONSE, cmd->id);
-
- priv->cmd.flags = 0;
- priv->cmd.size = cmd->size;
-
- if (bio_data_dir(bio) == WRITE) {
- err = dst_recv_cdata(st, priv->cmd.hash);
- if (err)
- goto err_out_free;
-
- err = dst_export_write_request(st, bio, cmd->size);
- if (err)
- goto err_out_free;
-
- if (dst_need_crypto(n))
- return dst_export_crypto(n, bio);
- } else {
- err = dst_export_read_request(bio, cmd->size);
- if (err)
- goto err_out_free;
- }
-
- dprintk("%s: bio: %llu/%u, rw: %lu, dir: %lu, flags: %lx, phys: %d.\n",
- __func__, (u64)bio->bi_sector, bio->bi_size,
- bio->bi_rw, bio_data_dir(bio),
- bio->bi_flags, bio->bi_phys_segments);
-
- generic_make_request(bio);
-
- return 0;
-
-err_out_free:
- bio_put(bio);
-err_out_exit:
- return err;
-}
-
-/*
- * Ok, block IO is ready, let's send it back to the client...
- */
-int dst_export_send_bio(struct bio *bio)
-{
- struct dst_export_priv *p = bio->bi_private;
- struct dst_state *st = p->state;
- struct dst_cmd *cmd = &p->cmd;
- int err;
-
- dprintk("%s: id: %llu, bio: %llu/%u, csize: %u, flags: %lu, rw: %lu.\n",
- __func__, cmd->id, (u64)bio->bi_sector, bio->bi_size,
- cmd->csize, bio->bi_flags, bio->bi_rw);
-
- dst_convert_cmd(cmd);
-
- dst_state_lock(st);
- if (!st->socket) {
- err = -ECONNRESET;
- goto err_out_unlock;
- }
-
- if (bio_data_dir(bio) == WRITE) {
- /* ... or just confirmation that writing has completed. */
- cmd->size = cmd->csize = 0;
- err = dst_data_send_header(st->socket, cmd,
- sizeof(struct dst_cmd), 0);
- if (err)
- goto err_out_unlock;
- } else {
- err = dst_send_bio(st, cmd, bio);
- if (err)
- goto err_out_unlock;
- }
-
- dst_state_unlock(st);
-
- bio_put(bio);
- return 0;
-
-err_out_unlock:
- dst_state_unlock(st);
-
- bio_put(bio);
- return err;
-}
diff --git a/drivers/staging/dst/state.c b/drivers/staging/dst/state.c
deleted file mode 100644
index 02a05e6c48c..00000000000
--- a/drivers/staging/dst/state.c
+++ /dev/null
@@ -1,844 +0,0 @@
-/*
- * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
- * All rights reserved.
- *
- * 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.
- */
-
-#include <linux/buffer_head.h>
-#include <linux/blkdev.h>
-#include <linux/bio.h>
-#include <linux/connector.h>
-#include <linux/dst.h>
-#include <linux/device.h>
-#include <linux/in.h>
-#include <linux/in6.h>
-#include <linux/socket.h>
-#include <linux/slab.h>
-
-#include <net/sock.h>
-
-/*
- * Polling machinery.
- */
-
-struct dst_poll_helper {
- poll_table pt;
- struct dst_state *st;
-};
-
-static int dst_queue_wake(wait_queue_t *wait, unsigned mode,
- int sync, void *key)
-{
- struct dst_state *st = container_of(wait, struct dst_state, wait);
-
- wake_up(&st->thread_wait);
- return 1;
-}
-
-static void dst_queue_func(struct file *file, wait_queue_head_t *whead,
- poll_table *pt)
-{
- struct dst_state *st = container_of(pt, struct dst_poll_helper, pt)->st;
-
- st->whead = whead;
- init_waitqueue_func_entry(&st->wait, dst_queue_wake);
- add_wait_queue(whead, &st->wait);
-}
-
-void dst_poll_exit(struct dst_state *st)
-{
- if (st->whead) {
- remove_wait_queue(st->whead, &st->wait);
- st->whead = NULL;
- }
-}
-
-int dst_poll_init(struct dst_state *st)
-{
- struct dst_poll_helper ph;
-
- ph.st = st;
- init_poll_funcptr(&ph.pt, &dst_queue_func);
-
- st->socket->ops->poll(NULL, st->socket, &ph.pt);
- return 0;
-}
-
-/*
- * Header receiving function - may block.
- */
-static int dst_data_recv_header(struct socket *sock,
- void *data, unsigned int size, int block)
-{
- struct msghdr msg;
- struct kvec iov;
- int err;
-
- iov.iov_base = data;
- iov.iov_len = size;
-
- msg.msg_iov = (struct iovec *)&iov;
- msg.msg_iovlen = 1;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- msg.msg_flags = (block) ? MSG_WAITALL : MSG_DONTWAIT;
-
- err = kernel_recvmsg(sock, &msg, &iov, 1, iov.iov_len,
- msg.msg_flags);
- if (err != size)
- return -1;
-
- return 0;
-}
-
-/*
- * Header sending function - may block.
- */
-int dst_data_send_header(struct socket *sock,
- void *data, unsigned int size, int more)
-{
- struct msghdr msg;
- struct kvec iov;
- int err;
-
- iov.iov_base = data;
- iov.iov_len = size;
-
- msg.msg_iov = (struct iovec *)&iov;
- msg.msg_iovlen = 1;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- msg.msg_flags = MSG_WAITALL | (more ? MSG_MORE : 0);
-
- err = kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len);
- if (err != size) {
- dprintk("%s: size: %u, more: %d, err: %d.\n",
- __func__, size, more, err);
- return -1;
- }
-
- return 0;
-}
-
-/*
- * Block autoconfiguration: request size of the storage and permissions.
- */
-static int dst_request_remote_config(struct dst_state *st)
-{
- struct dst_node *n = st->node;
- int err = -EINVAL;
- struct dst_cmd *cmd = st->data;
-
- memset(cmd, 0, sizeof(struct dst_cmd));
- cmd->cmd = DST_CFG;
-
- dst_convert_cmd(cmd);
-
- err = dst_data_send_header(st->socket, cmd, sizeof(struct dst_cmd), 0);
- if (err)
- goto out;
-
- err = dst_data_recv_header(st->socket, cmd, sizeof(struct dst_cmd), 1);
- if (err)
- goto out;
-
- dst_convert_cmd(cmd);
-
- if (cmd->cmd != DST_CFG) {
- err = -EINVAL;
- dprintk("%s: checking result: cmd: %d, size reported: %llu.\n",
- __func__, cmd->cmd, cmd->sector);
- goto out;
- }
-
- if (n->size != 0)
- n->size = min_t(loff_t, n->size, cmd->sector);
- else
- n->size = cmd->sector;
-
- n->info->size = n->size;
- st->permissions = cmd->rw;
-
-out:
- dprintk("%s: n: %p, err: %d, size: %llu, permission: %x.\n",
- __func__, n, err, n->size, st->permissions);
- return err;
-}
-
-/*
- * Socket machinery.
- */
-
-#define DST_DEFAULT_TIMEO 20000
-
-int dst_state_socket_create(struct dst_state *st)
-{
- int err;
- struct socket *sock;
- struct dst_network_ctl *ctl = &st->ctl;
-
- err = sock_create(ctl->addr.sa_family, ctl->type, ctl->proto, &sock);
- if (err < 0)
- return err;
-
- sock->sk->sk_sndtimeo = sock->sk->sk_rcvtimeo =
- msecs_to_jiffies(DST_DEFAULT_TIMEO);
- sock->sk->sk_allocation = GFP_NOIO;
-
- st->socket = st->read_socket = sock;
- return 0;
-}
-
-void dst_state_socket_release(struct dst_state *st)
-{
- dprintk("%s: st: %p, socket: %p, n: %p.\n",
- __func__, st, st->socket, st->node);
- if (st->socket) {
- sock_release(st->socket);
- st->socket = NULL;
- st->read_socket = NULL;
- }
-}
-
-void dst_dump_addr(struct socket *sk, struct sockaddr *sa, char *str)
-{
- if (sk->ops->family == AF_INET) {
- struct sockaddr_in *sin = (struct sockaddr_in *)sa;
- printk(KERN_INFO "%s %u.%u.%u.%u:%d.\n", str,
- NIPQUAD(sin->sin_addr.s_addr), ntohs(sin->sin_port));
- } else if (sk->ops->family == AF_INET6) {
- struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
- printk(KERN_INFO "%s %pi6:%d",
- str, &sin->sin6_addr, ntohs(sin->sin6_port));
- }
-}
-
-void dst_state_exit_connected(struct dst_state *st)
-{
- if (st->socket) {
- dst_poll_exit(st);
- st->socket->ops->shutdown(st->socket, 2);
-
- dst_dump_addr(st->socket, (struct sockaddr *)&st->ctl.addr,
- "Disconnected peer");
- dst_state_socket_release(st);
- }
-}
-
-static int dst_state_init_connected(struct dst_state *st)
-{
- int err;
- struct dst_network_ctl *ctl = &st->ctl;
-
- err = dst_state_socket_create(st);
- if (err)
- goto err_out_exit;
-
- err = kernel_connect(st->socket, (struct sockaddr *)&st->ctl.addr,
- st->ctl.addr.sa_data_len, 0);
- if (err)
- goto err_out_release;
-
- err = dst_poll_init(st);
- if (err)
- goto err_out_release;
-
- dst_dump_addr(st->socket, (struct sockaddr *)&ctl->addr,
- "Connected to peer");
-
- return 0;
-
-err_out_release:
- dst_state_socket_release(st);
-err_out_exit:
- return err;
-}
-
-/*
- * State reset is used to reconnect to the remote peer.
- * May fail, but who cares, we will try again later.
- */
-static inline void dst_state_reset_nolock(struct dst_state *st)
-{
- dst_state_exit_connected(st);
- dst_state_init_connected(st);
-}
-
-static inline void dst_state_reset(struct dst_state *st)
-{
- dst_state_lock(st);
- dst_state_reset_nolock(st);
- dst_state_unlock(st);
-}
-
-/*
- * Basic network sending/receiving functions.
- * Blocked mode is used.
- */
-static int dst_data_recv_raw(struct dst_state *st, void *buf, u64 size)
-{
- struct msghdr msg;
- struct kvec iov;
- int err;
-
- BUG_ON(!size);
-
- iov.iov_base = buf;
- iov.iov_len = size;
-
- msg.msg_iov = (struct iovec *)&iov;
- msg.msg_iovlen = 1;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- msg.msg_flags = MSG_DONTWAIT;
-
- err = kernel_recvmsg(st->socket, &msg, &iov, 1, iov.iov_len,
- msg.msg_flags);
- if (err <= 0) {
- dprintk("%s: failed to recv data: size: %llu, err: %d.\n",
- __func__, size, err);
- if (err == 0)
- err = -ECONNRESET;
-
- dst_state_exit_connected(st);
- }
-
- return err;
-}
-
-/*
- * Ping command to early detect failed nodes.
- */
-static int dst_send_ping(struct dst_state *st)
-{
- struct dst_cmd *cmd = st->data;
- int err = -ECONNRESET;
-
- dst_state_lock(st);
- if (st->socket) {
- memset(cmd, 0, sizeof(struct dst_cmd));
-
- cmd->cmd = __cpu_to_be32(DST_PING);
-
- err = dst_data_send_header(st->socket, cmd,
- sizeof(struct dst_cmd), 0);
- }
- dprintk("%s: st: %p, socket: %p, err: %d.\n", __func__,
- st, st->socket, err);
- dst_state_unlock(st);
-
- return err;
-}
-
-/*
- * Receiving function, which should either return error or read
- * whole block request. If there was no traffic for a one second,
- * send a ping, since remote node may die.
- */
-int dst_data_recv(struct dst_state *st, void *data, unsigned int size)
-{
- unsigned int revents = 0;
- unsigned int err_mask = POLLERR | POLLHUP | POLLRDHUP;
- unsigned int mask = err_mask | POLLIN;
- struct dst_node *n = st->node;
- int err = 0;
-
- while (size && !err) {
- revents = dst_state_poll(st);
-
- if (!(revents & mask)) {
- DEFINE_WAIT(wait);
-
- for (;;) {
- prepare_to_wait(&st->thread_wait, &wait,
- TASK_INTERRUPTIBLE);
- if (!n->trans_scan_timeout || st->need_exit)
- break;
-
- revents = dst_state_poll(st);
-
- if (revents & mask)
- break;
-
- if (signal_pending(current))
- break;
-
- if (!schedule_timeout(HZ)) {
- err = dst_send_ping(st);
- if (err)
- return err;
- }
-
- continue;
- }
- finish_wait(&st->thread_wait, &wait);
- }
-
- err = -ECONNRESET;
- dst_state_lock(st);
-
- if (st->socket && (st->read_socket == st->socket) &&
- (revents & POLLIN)) {
- err = dst_data_recv_raw(st, data, size);
- if (err > 0) {
- data += err;
- size -= err;
- err = 0;
- }
- }
-
- if (revents & err_mask || !st->socket) {
- dprintk("%s: revents: %x, socket: %p, size: %u, "
- "err: %d.\n", __func__, revents,
- st->socket, size, err);
- err = -ECONNRESET;
- }
-
- dst_state_unlock(st);
-
- if (!n->trans_scan_timeout)
- err = -ENODEV;
- }
-
- return err;
-}
-
-/*
- * Send block autoconf reply.
- */
-static int dst_process_cfg(struct dst_state *st)
-{
- struct dst_node *n = st->node;
- struct dst_cmd *cmd = st->data;
- int err;
-
- cmd->sector = n->size;
- cmd->rw = st->permissions;
-
- dst_convert_cmd(cmd);
-
- dst_state_lock(st);
- err = dst_data_send_header(st->socket, cmd, sizeof(struct dst_cmd), 0);
- dst_state_unlock(st);
-
- return err;
-}
-
-/*
- * Receive block IO from the network.
- */
-static int dst_recv_bio(struct dst_state *st, struct bio *bio,
- unsigned int total_size)
-{
- struct bio_vec *bv;
- int i, err;
- void *data;
- unsigned int sz;
-
- bio_for_each_segment(bv, bio, i) {
- sz = min(total_size, bv->bv_len);
-
- dprintk("%s: bio: %llu/%u, total: %u, len: %u, sz: %u, "
- "off: %u.\n", __func__, (u64)bio->bi_sector,
- bio->bi_size, total_size, bv->bv_len, sz,
- bv->bv_offset);
-
- data = kmap(bv->bv_page) + bv->bv_offset;
- err = dst_data_recv(st, data, sz);
- kunmap(bv->bv_page);
-
- bv->bv_len = sz;
-
- if (err)
- return err;
-
- total_size -= sz;
- if (total_size == 0)
- break;
- }
-
- return 0;
-}
-
-/*
- * Our block IO has just completed and arrived: get it.
- */
-static int dst_process_io_response(struct dst_state *st)
-{
- struct dst_node *n = st->node;
- struct dst_cmd *cmd = st->data;
- struct dst_trans *t;
- int err = 0;
- struct bio *bio;
-
- mutex_lock(&n->trans_lock);
- t = dst_trans_search(n, cmd->id);
- mutex_unlock(&n->trans_lock);
-
- if (!t)
- goto err_out_exit;
-
- bio = t->bio;
-
- dprintk("%s: bio: %llu/%u, cmd_size: %u, csize: %u, dir: %lu.\n",
- __func__, (u64)bio->bi_sector, bio->bi_size, cmd->size,
- cmd->csize, bio_data_dir(bio));
-
- if (bio_data_dir(bio) == READ) {
- if (bio->bi_size != cmd->size - cmd->csize)
- goto err_out_exit;
-
- if (dst_need_crypto(n)) {
- err = dst_recv_cdata(st, t->cmd.hash);
- if (err)
- goto err_out_exit;
- }
-
- err = dst_recv_bio(st, t->bio, bio->bi_size);
- if (err)
- goto err_out_exit;
-
- if (dst_need_crypto(n))
- return dst_trans_crypto(t);
- } else {
- err = -EBADMSG;
- if (cmd->size || cmd->csize)
- goto err_out_exit;
- }
-
- dst_trans_remove(t);
- dst_trans_put(t);
-
- return 0;
-
-err_out_exit:
- return err;
-}
-
-/*
- * Receive crypto data.
- */
-int dst_recv_cdata(struct dst_state *st, void *cdata)
-{
- struct dst_cmd *cmd = st->data;
- struct dst_node *n = st->node;
- struct dst_crypto_ctl *c = &n->crypto;
- int err;
-
- if (cmd->csize != c->crypto_attached_size) {
- dprintk("%s: cmd: cmd: %u, sector: %llu, size: %u, "
- "csize: %u != digest size %u.\n",
- __func__, cmd->cmd, cmd->sector, cmd->size,
- cmd->csize, c->crypto_attached_size);
- err = -EINVAL;
- goto err_out_exit;
- }
-
- err = dst_data_recv(st, cdata, cmd->csize);
- if (err)
- goto err_out_exit;
-
- cmd->size -= cmd->csize;
- return 0;
-
-err_out_exit:
- return err;
-}
-
-/*
- * Receive the command and start its processing.
- */
-static int dst_recv_processing(struct dst_state *st)
-{
- int err = -EINTR;
- struct dst_cmd *cmd = st->data;
-
- /*
- * If socket will be reset after this statement, then
- * dst_data_recv() will just fail and loop will
- * start again, so it can be done without any locks.
- *
- * st->read_socket is needed to prevents state machine
- * breaking between this data reading and subsequent one
- * in protocol specific functions during connection reset.
- * In case of reset we have to read next command and do
- * not expect data for old command to magically appear in
- * new connection.
- */
- st->read_socket = st->socket;
- err = dst_data_recv(st, cmd, sizeof(struct dst_cmd));
- if (err)
- goto out_exit;
-
- dst_convert_cmd(cmd);
-
- dprintk("%s: cmd: %u, size: %u, csize: %u, id: %llu, "
- "sector: %llu, flags: %llx, rw: %llx.\n",
- __func__, cmd->cmd, cmd->size,
- cmd->csize, cmd->id, cmd->sector,
- cmd->flags, cmd->rw);
-
- /*
- * This should catch protocol breakage and random garbage
- * instead of commands.
- */
- if (unlikely(cmd->csize > st->size - sizeof(struct dst_cmd))) {
- err = -EBADMSG;
- goto out_exit;
- }
-
- err = -EPROTO;
- switch (cmd->cmd) {
- case DST_IO_RESPONSE:
- err = dst_process_io_response(st);
- break;
- case DST_IO:
- err = dst_process_io(st);
- break;
- case DST_CFG:
- err = dst_process_cfg(st);
- break;
- case DST_PING:
- err = 0;
- break;
- default:
- break;
- }
-
-out_exit:
- return err;
-}
-
-/*
- * Receiving thread. For the client node we should try to reconnect,
- * for accepted client we just drop the state and expect it to reconnect.
- */
-static int dst_recv(void *init_data, void *schedule_data)
-{
- struct dst_state *st = schedule_data;
- struct dst_node *n = init_data;
- int err = 0;
-
- dprintk("%s: start st: %p, n: %p, scan: %lu, need_exit: %d.\n",
- __func__, st, n, n->trans_scan_timeout, st->need_exit);
-
- while (n->trans_scan_timeout && !st->need_exit) {
- err = dst_recv_processing(st);
- if (err < 0) {
- if (!st->ctl.type)
- break;
-
- if (!n->trans_scan_timeout || st->need_exit)
- break;
-
- dst_state_reset(st);
- msleep(1000);
- }
- }
-
- st->need_exit = 1;
- wake_up(&st->thread_wait);
-
- dprintk("%s: freeing receiving socket st: %p.\n", __func__, st);
- dst_state_lock(st);
- dst_state_exit_connected(st);
- dst_state_unlock(st);
- dst_state_put(st);
-
- dprintk("%s: freed receiving socket st: %p.\n", __func__, st);
-
- return err;
-}
-
-/*
- * Network state dies here and borns couple of lines below.
- * This object is the main network state processing engine:
- * sending, receiving, reconnections, all network related
- * tasks are handled on behalf of the state.
- */
-static void dst_state_free(struct dst_state *st)
-{
- dprintk("%s: st: %p.\n", __func__, st);
- if (st->cleanup)
- st->cleanup(st);
- kfree(st->data);
- kfree(st);
-}
-
-struct dst_state *dst_state_alloc(struct dst_node *n)
-{
- struct dst_state *st;
- int err = -ENOMEM;
-
- st = kzalloc(sizeof(struct dst_state), GFP_KERNEL);
- if (!st)
- goto err_out_exit;
-
- st->node = n;
- st->need_exit = 0;
-
- st->size = PAGE_SIZE;
- st->data = kmalloc(st->size, GFP_KERNEL);
- if (!st->data)
- goto err_out_free;
-
- spin_lock_init(&st->request_lock);
- INIT_LIST_HEAD(&st->request_list);
-
- mutex_init(&st->state_lock);
- init_waitqueue_head(&st->thread_wait);
-
- /*
- * One for processing thread, another one for node itself.
- */
- atomic_set(&st->refcnt, 2);
-
- dprintk("%s: st: %p, n: %p.\n", __func__, st, st->node);
-
- return st;
-
-err_out_free:
- kfree(st);
-err_out_exit:
- return ERR_PTR(err);
-}
-
-int dst_state_schedule_receiver(struct dst_state *st)
-{
- return thread_pool_schedule_private(st->node->pool, dst_thread_setup,
- dst_recv, st, MAX_SCHEDULE_TIMEOUT, st->node);
-}
-
-/*
- * Initialize client's connection to the remote peer: allocate state,
- * connect and perform block IO autoconfiguration.
- */
-int dst_node_init_connected(struct dst_node *n, struct dst_network_ctl *r)
-{
- struct dst_state *st;
- int err = -ENOMEM;
-
- st = dst_state_alloc(n);
- if (IS_ERR(st)) {
- err = PTR_ERR(st);
- goto err_out_exit;
- }
- memcpy(&st->ctl, r, sizeof(struct dst_network_ctl));
-
- err = dst_state_init_connected(st);
- if (err)
- goto err_out_free_data;
-
- err = dst_request_remote_config(st);
- if (err)
- goto err_out_exit_connected;
- n->state = st;
-
- err = dst_state_schedule_receiver(st);
- if (err)
- goto err_out_exit_connected;
-
- return 0;
-
-err_out_exit_connected:
- dst_state_exit_connected(st);
-err_out_free_data:
- dst_state_free(st);
-err_out_exit:
- n->state = NULL;
- return err;
-}
-
-void dst_state_put(struct dst_state *st)
-{
- dprintk("%s: st: %p, refcnt: %d.\n",
- __func__, st, atomic_read(&st->refcnt));
- if (atomic_dec_and_test(&st->refcnt))
- dst_state_free(st);
-}
-
-/*
- * Send block IO to the network one by one using zero-copy ->sendpage().
- */
-int dst_send_bio(struct dst_state *st, struct dst_cmd *cmd, struct bio *bio)
-{
- struct bio_vec *bv;
- struct dst_crypto_ctl *c = &st->node->crypto;
- int err, i = 0;
- int flags = MSG_WAITALL;
-
- err = dst_data_send_header(st->socket, cmd,
- sizeof(struct dst_cmd) + c->crypto_attached_size, bio->bi_vcnt);
- if (err)
- goto err_out_exit;
-
- bio_for_each_segment(bv, bio, i) {
- if (i < bio->bi_vcnt - 1)
- flags |= MSG_MORE;
-
- err = kernel_sendpage(st->socket, bv->bv_page, bv->bv_offset,
- bv->bv_len, flags);
- if (err <= 0)
- goto err_out_exit;
- }
-
- return 0;
-
-err_out_exit:
- dprintk("%s: %d/%d, flags: %x, err: %d.\n",
- __func__, i, bio->bi_vcnt, flags, err);
- return err;
-}
-
-/*
- * Send transaction to the remote peer.
- */
-int dst_trans_send(struct dst_trans *t)
-{
- int err;
- struct dst_state *st = t->n->state;
- struct bio *bio = t->bio;
-
- dst_convert_cmd(&t->cmd);
-
- dst_state_lock(st);
- if (!st->socket) {
- err = dst_state_init_connected(st);
- if (err)
- goto err_out_unlock;
- }
-
- if (bio_data_dir(bio) == WRITE) {
- err = dst_send_bio(st, &t->cmd, t->bio);
- } else {
- err = dst_data_send_header(st->socket, &t->cmd,
- sizeof(struct dst_cmd), 0);
- }
- if (err)
- goto err_out_reset;
-
- dst_state_unlock(st);
- return 0;
-
-err_out_reset:
- dst_state_reset_nolock(st);
-err_out_unlock:
- dst_state_unlock(st);
-
- return err;
-}
diff --git a/drivers/staging/dst/thread_pool.c b/drivers/staging/dst/thread_pool.c
deleted file mode 100644
index 29a82b2602f..00000000000
--- a/drivers/staging/dst/thread_pool.c
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
- * All rights reserved.
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/dst.h>
-#include <linux/kthread.h>
-#include <linux/slab.h>
-
-/*
- * Thread pool abstraction allows to schedule a work to be performed
- * on behalf of kernel thread. One does not operate with threads itself,
- * instead user provides setup and cleanup callbacks for thread pool itself,
- * and action and cleanup callbacks for each submitted work.
- *
- * Each worker has private data initialized at creation time and data,
- * provided by user at scheduling time.
- *
- * When action is being performed, thread can not be used by other users,
- * instead they will sleep until there is free thread to pick their work.
- */
-struct thread_pool_worker {
- struct list_head worker_entry;
-
- struct task_struct *thread;
-
- struct thread_pool *pool;
-
- int error;
- int has_data;
- int need_exit;
- unsigned int id;
-
- wait_queue_head_t wait;
-
- void *private;
- void *schedule_data;
-
- int (*action)(void *private, void *schedule_data);
- void (*cleanup)(void *private);
-};
-
-static void thread_pool_exit_worker(struct thread_pool_worker *w)
-{
- kthread_stop(w->thread);
-
- w->cleanup(w->private);
- kfree(w);
-}
-
-/*
- * Called to mark thread as ready and allow users to schedule new work.
- */
-static void thread_pool_worker_make_ready(struct thread_pool_worker *w)
-{
- struct thread_pool *p = w->pool;
-
- mutex_lock(&p->thread_lock);
-
- if (!w->need_exit) {
- list_move_tail(&w->worker_entry, &p->ready_list);
- w->has_data = 0;
- mutex_unlock(&p->thread_lock);
-
- wake_up(&p->wait);
- } else {
- p->thread_num--;
- list_del(&w->worker_entry);
- mutex_unlock(&p->thread_lock);
-
- thread_pool_exit_worker(w);
- }
-}
-
-/*
- * Thread action loop: waits until there is new work.
- */
-static int thread_pool_worker_func(void *data)
-{
- struct thread_pool_worker *w = data;
-
- while (!kthread_should_stop()) {
- wait_event_interruptible(w->wait,
- kthread_should_stop() || w->has_data);
-
- if (kthread_should_stop())
- break;
-
- if (!w->has_data)
- continue;
-
- w->action(w->private, w->schedule_data);
- thread_pool_worker_make_ready(w);
- }
-
- return 0;
-}
-
-/*
- * Remove single worker without specifying which one.
- */
-void thread_pool_del_worker(struct thread_pool *p)
-{
- struct thread_pool_worker *w = NULL;
-
- while (!w && p->thread_num) {
- wait_event(p->wait, !list_empty(&p->ready_list) ||
- !p->thread_num);
-
- dprintk("%s: locking list_empty: %d, thread_num: %d.\n",
- __func__, list_empty(&p->ready_list),
- p->thread_num);
-
- mutex_lock(&p->thread_lock);
- if (!list_empty(&p->ready_list)) {
- w = list_first_entry(&p->ready_list,
- struct thread_pool_worker,
- worker_entry);
-
- dprintk("%s: deleting w: %p, thread_num: %d, "
- "list: %p [%p.%p].\n", __func__,
- w, p->thread_num, &p->ready_list,
- p->ready_list.prev, p->ready_list.next);
-
- p->thread_num--;
- list_del(&w->worker_entry);
- }
- mutex_unlock(&p->thread_lock);
- }
-
- if (w)
- thread_pool_exit_worker(w);
- dprintk("%s: deleted w: %p, thread_num: %d.\n",
- __func__, w, p->thread_num);
-}
-
-/*
- * Remove a worker with given ID.
- */
-void thread_pool_del_worker_id(struct thread_pool *p, unsigned int id)
-{
- struct thread_pool_worker *w;
- int found = 0;
-
- mutex_lock(&p->thread_lock);
- list_for_each_entry(w, &p->ready_list, worker_entry) {
- if (w->id == id) {
- found = 1;
- p->thread_num--;
- list_del(&w->worker_entry);
- break;
- }
- }
-
- if (!found) {
- list_for_each_entry(w, &p->active_list, worker_entry) {
- if (w->id == id) {
- w->need_exit = 1;
- break;
- }
- }
- }
- mutex_unlock(&p->thread_lock);
-
- if (found)
- thread_pool_exit_worker(w);
-}
-
-/*
- * Add new worker thread with given parameters.
- * If initialization callback fails, return error.
- */
-int thread_pool_add_worker(struct thread_pool *p,
- char *name,
- unsigned int id,
- void *(*init)(void *private),
- void (*cleanup)(void *private),
- void *private)
-{
- struct thread_pool_worker *w;
- int err = -ENOMEM;
-
- w = kzalloc(sizeof(struct thread_pool_worker), GFP_KERNEL);
- if (!w)
- goto err_out_exit;
-
- w->pool = p;
- init_waitqueue_head(&w->wait);
- w->cleanup = cleanup;
- w->id = id;
-
- w->thread = kthread_run(thread_pool_worker_func, w, "%s", name);
- if (IS_ERR(w->thread)) {
- err = PTR_ERR(w->thread);
- goto err_out_free;
- }
-
- w->private = init(private);
- if (IS_ERR(w->private)) {
- err = PTR_ERR(w->private);
- goto err_out_stop_thread;
- }
-
- mutex_lock(&p->thread_lock);
- list_add_tail(&w->worker_entry, &p->ready_list);
- p->thread_num++;
- mutex_unlock(&p->thread_lock);
-
- return 0;
-
-err_out_stop_thread:
- kthread_stop(w->thread);
-err_out_free:
- kfree(w);
-err_out_exit:
- return err;
-}
-
-/*
- * Destroy the whole pool.
- */
-void thread_pool_destroy(struct thread_pool *p)
-{
- while (p->thread_num) {
- dprintk("%s: num: %d.\n", __func__, p->thread_num);
- thread_pool_del_worker(p);
- }
-
- kfree(p);
-}
-
-/*
- * Create a pool with given number of threads.
- * They will have sequential IDs started from zero.
- */
-struct thread_pool *thread_pool_create(int num, char *name,
- void *(*init)(void *private),
- void (*cleanup)(void *private),
- void *private)
-{
- struct thread_pool_worker *w, *tmp;
- struct thread_pool *p;
- int err = -ENOMEM;
- int i;
-
- p = kzalloc(sizeof(struct thread_pool), GFP_KERNEL);
- if (!p)
- goto err_out_exit;
-
- init_waitqueue_head(&p->wait);
- mutex_init(&p->thread_lock);
- INIT_LIST_HEAD(&p->ready_list);
- INIT_LIST_HEAD(&p->active_list);
- p->thread_num = 0;
-
- for (i = 0; i < num; ++i) {
- err = thread_pool_add_worker(p, name, i, init,
- cleanup, private);
- if (err)
- goto err_out_free_all;
- }
-
- return p;
-
-err_out_free_all:
- list_for_each_entry_safe(w, tmp, &p->ready_list, worker_entry) {
- list_del(&w->worker_entry);
- thread_pool_exit_worker(w);
- }
- kfree(p);
-err_out_exit:
- return ERR_PTR(err);
-}
-
-/*
- * Schedule execution of the action on a given thread,
- * provided ID pointer has to match previously stored
- * private data.
- */
-int thread_pool_schedule_private(struct thread_pool *p,
- int (*setup)(void *private, void *data),
- int (*action)(void *private, void *data),
- void *data, long timeout, void *id)
-{
- struct thread_pool_worker *w, *tmp, *worker = NULL;
- int err = 0;
-
- while (!worker && !err) {
- timeout = wait_event_interruptible_timeout(p->wait,
- !list_empty(&p->ready_list),
- timeout);
-
- if (!timeout) {
- err = -ETIMEDOUT;
- break;
- }
-
- worker = NULL;
- mutex_lock(&p->thread_lock);
- list_for_each_entry_safe(w, tmp, &p->ready_list, worker_entry) {
- if (id && id != w->private)
- continue;
-
- worker = w;
-
- list_move_tail(&w->worker_entry, &p->active_list);
-
- err = setup(w->private, data);
- if (!err) {
- w->schedule_data = data;
- w->action = action;
- w->has_data = 1;
- wake_up(&w->wait);
- } else {
- list_move_tail(&w->worker_entry,
- &p->ready_list);
- }
-
- break;
- }
- mutex_unlock(&p->thread_lock);
- }
-
- return err;
-}
-
-/*
- * Schedule execution on arbitrary thread from the pool.
- */
-int thread_pool_schedule(struct thread_pool *p,
- int (*setup)(void *private, void *data),
- int (*action)(void *private, void *data),
- void *data, long timeout)
-{
- return thread_pool_schedule_private(p, setup,
- action, data, timeout, NULL);
-}
diff --git a/drivers/staging/dst/trans.c b/drivers/staging/dst/trans.c
deleted file mode 100644
index 1c36a6bc31d..00000000000
--- a/drivers/staging/dst/trans.c
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
- * All rights reserved.
- *
- * 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.
- */
-
-#include <linux/bio.h>
-#include <linux/dst.h>
-#include <linux/slab.h>
-#include <linux/mempool.h>
-
-/*
- * Transaction memory pool size.
- */
-static int dst_mempool_num = 32;
-module_param(dst_mempool_num, int, 0644);
-
-/*
- * Transaction tree management.
- */
-static inline int dst_trans_cmp(dst_gen_t gen, dst_gen_t new)
-{
- if (gen < new)
- return 1;
- if (gen > new)
- return -1;
- return 0;
-}
-
-struct dst_trans *dst_trans_search(struct dst_node *node, dst_gen_t gen)
-{
- struct rb_root *root = &node->trans_root;
- struct rb_node *n = root->rb_node;
- struct dst_trans *t, *ret = NULL;
- int cmp;
-
- while (n) {
- t = rb_entry(n, struct dst_trans, trans_entry);
-
- cmp = dst_trans_cmp(t->gen, gen);
- if (cmp < 0)
- n = n->rb_left;
- else if (cmp > 0)
- n = n->rb_right;
- else {
- ret = t;
- break;
- }
- }
-
- dprintk("%s: %s transaction: id: %llu.\n", __func__,
- (ret) ? "found" : "not found", gen);
-
- return ret;
-}
-
-static int dst_trans_insert(struct dst_trans *new)
-{
- struct rb_root *root = &new->n->trans_root;
- struct rb_node **n = &root->rb_node, *parent = NULL;
- struct dst_trans *ret = NULL, *t;
- int cmp;
-
- while (*n) {
- parent = *n;
-
- t = rb_entry(parent, struct dst_trans, trans_entry);
-
- cmp = dst_trans_cmp(t->gen, new->gen);
- if (cmp < 0)
- n = &parent->rb_left;
- else if (cmp > 0)
- n = &parent->rb_right;
- else {
- ret = t;
- break;
- }
- }
-
- new->send_time = jiffies;
- if (ret) {
- printk(KERN_DEBUG "%s: exist: old: gen: %llu, bio: %llu/%u, "
- "send_time: %lu, new: gen: %llu, bio: %llu/%u, "
- "send_time: %lu.\n", __func__,
- ret->gen, (u64)ret->bio->bi_sector,
- ret->bio->bi_size, ret->send_time,
- new->gen, (u64)new->bio->bi_sector,
- new->bio->bi_size, new->send_time);
- return -EEXIST;
- }
-
- rb_link_node(&new->trans_entry, parent, n);
- rb_insert_color(&new->trans_entry, root);
-
- dprintk("%s: inserted: gen: %llu, bio: %llu/%u, send_time: %lu.\n",
- __func__, new->gen, (u64)new->bio->bi_sector,
- new->bio->bi_size, new->send_time);
-
- return 0;
-}
-
-int dst_trans_remove_nolock(struct dst_trans *t)
-{
- struct dst_node *n = t->n;
-
- if (t->trans_entry.rb_parent_color) {
- rb_erase(&t->trans_entry, &n->trans_root);
- t->trans_entry.rb_parent_color = 0;
- }
- return 0;
-}
-
-int dst_trans_remove(struct dst_trans *t)
-{
- int ret;
- struct dst_node *n = t->n;
-
- mutex_lock(&n->trans_lock);
- ret = dst_trans_remove_nolock(t);
- mutex_unlock(&n->trans_lock);
-
- return ret;
-}
-
-/*
- * When transaction is completed and there are no more users,
- * we complete appriate block IO request with given error status.
- */
-void dst_trans_put(struct dst_trans *t)
-{
- if (atomic_dec_and_test(&t->refcnt)) {
- struct bio *bio = t->bio;
-
- dprintk("%s: completed t: %p, gen: %llu, bio: %p.\n",
- __func__, t, t->gen, bio);
-
- bio_endio(bio, t->error);
- bio_put(bio);
-
- dst_node_put(t->n);
- mempool_free(t, t->n->trans_pool);
- }
-}
-
-/*
- * Process given block IO request: allocate transaction, insert it into the tree
- * and send/schedule crypto processing.
- */
-int dst_process_bio(struct dst_node *n, struct bio *bio)
-{
- struct dst_trans *t;
- int err = -ENOMEM;
-
- t = mempool_alloc(n->trans_pool, GFP_NOFS);
- if (!t)
- goto err_out_exit;
-
- t->n = dst_node_get(n);
- t->bio = bio;
- t->error = 0;
- t->retries = 0;
- atomic_set(&t->refcnt, 1);
- t->gen = atomic_long_inc_return(&n->gen);
-
- t->enc = bio_data_dir(bio);
- dst_bio_to_cmd(bio, &t->cmd, DST_IO, t->gen);
-
- mutex_lock(&n->trans_lock);
- err = dst_trans_insert(t);
- mutex_unlock(&n->trans_lock);
- if (err)
- goto err_out_free;
-
- dprintk("%s: gen: %llu, bio: %llu/%u, dir/enc: %d, need_crypto: %d.\n",
- __func__, t->gen, (u64)bio->bi_sector,
- bio->bi_size, t->enc, dst_need_crypto(n));
-
- if (dst_need_crypto(n) && t->enc)
- dst_trans_crypto(t);
- else
- dst_trans_send(t);
-
- return 0;
-
-err_out_free:
- dst_node_put(n);
- mempool_free(t, n->trans_pool);
-err_out_exit:
- bio_endio(bio, err);
- bio_put(bio);
- return err;
-}
-
-/*
- * Scan for timeout/stale transactions.
- * Each transaction is being resent multiple times before error completion.
- */
-static void dst_trans_scan(struct work_struct *work)
-{
- struct dst_node *n = container_of(work, struct dst_node,
- trans_work.work);
- struct rb_node *rb_node;
- struct dst_trans *t;
- unsigned long timeout = n->trans_scan_timeout;
- int num = 10 * n->trans_max_retries;
-
- mutex_lock(&n->trans_lock);
-
- for (rb_node = rb_first(&n->trans_root); rb_node; ) {
- t = rb_entry(rb_node, struct dst_trans, trans_entry);
-
- if (timeout && time_after(t->send_time + timeout, jiffies)
- && t->retries == 0)
- break;
-#if 0
- dprintk("%s: t: %p, gen: %llu, n: %s, retries: %u, max: %u.\n",
- __func__, t, t->gen, n->name,
- t->retries, n->trans_max_retries);
-#endif
- if (--num == 0)
- break;
-
- dst_trans_get(t);
-
- rb_node = rb_next(rb_node);
-
- if (timeout && (++t->retries < n->trans_max_retries)) {
- dst_trans_send(t);
- } else {
- t->error = -ETIMEDOUT;
- dst_trans_remove_nolock(t);
- dst_trans_put(t);
- }
-
- dst_trans_put(t);
- }
-
- mutex_unlock(&n->trans_lock);
-
- /*
- * If no timeout specified then system is in the middle of exiting
- * process, so no need to reschedule scanning process again.
- */
- if (timeout) {
- if (!num)
- timeout = HZ;
- schedule_delayed_work(&n->trans_work, timeout);
- }
-}
-
-/*
- * Flush all transactions and mark them as timed out.
- * Destroy transaction pools.
- */
-void dst_node_trans_exit(struct dst_node *n)
-{
- struct dst_trans *t;
- struct rb_node *rb_node;
-
- if (!n->trans_cache)
- return;
-
- dprintk("%s: n: %p, cancelling the work.\n", __func__, n);
- cancel_delayed_work_sync(&n->trans_work);
- flush_scheduled_work();
- dprintk("%s: n: %p, work has been cancelled.\n", __func__, n);
-
- for (rb_node = rb_first(&n->trans_root); rb_node; ) {
- t = rb_entry(rb_node, struct dst_trans, trans_entry);
-
- dprintk("%s: t: %p, gen: %llu, n: %s.\n",
- __func__, t, t->gen, n->name);
-
- rb_node = rb_next(rb_node);
-
- t->error = -ETIMEDOUT;
- dst_trans_remove_nolock(t);
- dst_trans_put(t);
- }
-
- mempool_destroy(n->trans_pool);
- kmem_cache_destroy(n->trans_cache);
-}
-
-/*
- * Initialize transaction storage for given node.
- * Transaction stores not only control information,
- * but also network command and crypto data (if needed)
- * to reduce number of allocations. Thus transaction size
- * differs from node to node.
- */
-int dst_node_trans_init(struct dst_node *n, unsigned int size)
-{
- /*
- * We need this, since node with given name can be dropped from the
- * hash table, but be still alive, so subsequent creation of the node
- * with the same name may collide with existing cache name.
- */
-
- snprintf(n->cache_name, sizeof(n->cache_name), "%s-%p", n->name, n);
-
- n->trans_cache = kmem_cache_create(n->cache_name,
- size + n->crypto.crypto_attached_size,
- 0, 0, NULL);
- if (!n->trans_cache)
- goto err_out_exit;
-
- n->trans_pool = mempool_create_slab_pool(dst_mempool_num,
- n->trans_cache);
- if (!n->trans_pool)
- goto err_out_cache_destroy;
-
- mutex_init(&n->trans_lock);
- n->trans_root = RB_ROOT;
-
- INIT_DELAYED_WORK(&n->trans_work, dst_trans_scan);
- schedule_delayed_work(&n->trans_work, n->trans_scan_timeout);
-
- dprintk("%s: n: %p, size: %u, crypto: %u.\n",
- __func__, n, size, n->crypto.crypto_attached_size);
-
- return 0;
-
-err_out_cache_destroy:
- kmem_cache_destroy(n->trans_cache);
-err_out_exit:
- return -ENOMEM;
-}
diff --git a/drivers/staging/iio/ring_sw.h b/drivers/staging/iio/ring_sw.h
index f0b86f02cd8..fd677f00836 100644
--- a/drivers/staging/iio/ring_sw.h
+++ b/drivers/staging/iio/ring_sw.h
@@ -29,7 +29,6 @@
* driver requests - some may support multiple options */
-#include <linux/autoconf.h>
#include "iio.h"
#include "ring_generic.h"
diff --git a/drivers/staging/octeon/Kconfig b/drivers/staging/octeon/Kconfig
index 536e2382de5..638ad6b3589 100644
--- a/drivers/staging/octeon/Kconfig
+++ b/drivers/staging/octeon/Kconfig
@@ -1,7 +1,8 @@
config OCTEON_ETHERNET
tristate "Cavium Networks Octeon Ethernet support"
depends on CPU_CAVIUM_OCTEON
- select MII
+ select PHYLIB
+ select MDIO_OCTEON
help
This driver supports the builtin ethernet ports on Cavium
Networks' products in the Octeon family. This driver supports the
diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c
index 31a58e50892..05a5cc0f43e 100644
--- a/drivers/staging/octeon/ethernet-mdio.c
+++ b/drivers/staging/octeon/ethernet-mdio.c
@@ -26,7 +26,8 @@
**********************************************************************/
#include <linux/kernel.h>
#include <linux/ethtool.h>
-#include <linux/mii.h>
+#include <linux/phy.h>
+
#include <net/dst.h>
#include <asm/octeon/octeon.h>
@@ -34,86 +35,12 @@
#include "ethernet-defines.h"
#include "octeon-ethernet.h"
#include "ethernet-mdio.h"
+#include "ethernet-util.h"
#include "cvmx-helper-board.h"
#include "cvmx-smix-defs.h"
-DECLARE_MUTEX(mdio_sem);
-
-/**
- * Perform an MII read. Called by the generic MII routines
- *
- * @dev: Device to perform read for
- * @phy_id: The MII phy id
- * @location: Register location to read
- * Returns Result from the read or zero on failure
- */
-static int cvm_oct_mdio_read(struct net_device *dev, int phy_id, int location)
-{
- union cvmx_smix_cmd smi_cmd;
- union cvmx_smix_rd_dat smi_rd;
-
- smi_cmd.u64 = 0;
- smi_cmd.s.phy_op = 1;
- smi_cmd.s.phy_adr = phy_id;
- smi_cmd.s.reg_adr = location;
- cvmx_write_csr(CVMX_SMIX_CMD(0), smi_cmd.u64);
-
- do {
- if (!in_interrupt())
- yield();
- smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(0));
- } while (smi_rd.s.pending);
-
- if (smi_rd.s.val)
- return smi_rd.s.dat;
- else
- return 0;
-}
-
-static int cvm_oct_mdio_dummy_read(struct net_device *dev, int phy_id,
- int location)
-{
- return 0xffff;
-}
-
-/**
- * Perform an MII write. Called by the generic MII routines
- *
- * @dev: Device to perform write for
- * @phy_id: The MII phy id
- * @location: Register location to write
- * @val: Value to write
- */
-static void cvm_oct_mdio_write(struct net_device *dev, int phy_id, int location,
- int val)
-{
- union cvmx_smix_cmd smi_cmd;
- union cvmx_smix_wr_dat smi_wr;
-
- smi_wr.u64 = 0;
- smi_wr.s.dat = val;
- cvmx_write_csr(CVMX_SMIX_WR_DAT(0), smi_wr.u64);
-
- smi_cmd.u64 = 0;
- smi_cmd.s.phy_op = 0;
- smi_cmd.s.phy_adr = phy_id;
- smi_cmd.s.reg_adr = location;
- cvmx_write_csr(CVMX_SMIX_CMD(0), smi_cmd.u64);
-
- do {
- if (!in_interrupt())
- yield();
- smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(0));
- } while (smi_wr.s.pending);
-}
-
-static void cvm_oct_mdio_dummy_write(struct net_device *dev, int phy_id,
- int location, int val)
-{
-}
-
static void cvm_oct_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
@@ -125,49 +52,37 @@ static void cvm_oct_get_drvinfo(struct net_device *dev,
static int cvm_oct_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct octeon_ethernet *priv = netdev_priv(dev);
- int ret;
- down(&mdio_sem);
- ret = mii_ethtool_gset(&priv->mii_info, cmd);
- up(&mdio_sem);
+ if (priv->phydev)
+ return phy_ethtool_gset(priv->phydev, cmd);
- return ret;
+ return -EINVAL;
}
static int cvm_oct_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct octeon_ethernet *priv = netdev_priv(dev);
- int ret;
- down(&mdio_sem);
- ret = mii_ethtool_sset(&priv->mii_info, cmd);
- up(&mdio_sem);
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (priv->phydev)
+ return phy_ethtool_sset(priv->phydev, cmd);
- return ret;
+ return -EINVAL;
}
static int cvm_oct_nway_reset(struct net_device *dev)
{
struct octeon_ethernet *priv = netdev_priv(dev);
- int ret;
- down(&mdio_sem);
- ret = mii_nway_restart(&priv->mii_info);
- up(&mdio_sem);
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
- return ret;
-}
+ if (priv->phydev)
+ return phy_start_aneg(priv->phydev);
-static u32 cvm_oct_get_link(struct net_device *dev)
-{
- struct octeon_ethernet *priv = netdev_priv(dev);
- u32 ret;
-
- down(&mdio_sem);
- ret = mii_link_ok(&priv->mii_info);
- up(&mdio_sem);
-
- return ret;
+ return -EINVAL;
}
const struct ethtool_ops cvm_oct_ethtool_ops = {
@@ -175,7 +90,7 @@ const struct ethtool_ops cvm_oct_ethtool_ops = {
.get_settings = cvm_oct_get_settings,
.set_settings = cvm_oct_set_settings,
.nway_reset = cvm_oct_nway_reset,
- .get_link = cvm_oct_get_link,
+ .get_link = ethtool_op_get_link,
.get_sg = ethtool_op_get_sg,
.get_tx_csum = ethtool_op_get_tx_csum,
};
@@ -191,41 +106,78 @@ const struct ethtool_ops cvm_oct_ethtool_ops = {
int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct octeon_ethernet *priv = netdev_priv(dev);
- struct mii_ioctl_data *data = if_mii(rq);
- unsigned int duplex_chg;
- int ret;
- down(&mdio_sem);
- ret = generic_mii_ioctl(&priv->mii_info, data, cmd, &duplex_chg);
- up(&mdio_sem);
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ if (!priv->phydev)
+ return -EINVAL;
+
+ return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
+}
- return ret;
+static void cvm_oct_adjust_link(struct net_device *dev)
+{
+ struct octeon_ethernet *priv = netdev_priv(dev);
+ cvmx_helper_link_info_t link_info;
+
+ if (priv->last_link != priv->phydev->link) {
+ priv->last_link = priv->phydev->link;
+ link_info.u64 = 0;
+ link_info.s.link_up = priv->last_link ? 1 : 0;
+ link_info.s.full_duplex = priv->phydev->duplex ? 1 : 0;
+ link_info.s.speed = priv->phydev->speed;
+ cvmx_helper_link_set( priv->port, link_info);
+ if (priv->last_link) {
+ netif_carrier_on(dev);
+ if (priv->queue != -1)
+ DEBUGPRINT("%s: %u Mbps %s duplex, "
+ "port %2d, queue %2d\n",
+ dev->name, priv->phydev->speed,
+ priv->phydev->duplex ?
+ "Full" : "Half",
+ priv->port, priv->queue);
+ else
+ DEBUGPRINT("%s: %u Mbps %s duplex, "
+ "port %2d, POW\n",
+ dev->name, priv->phydev->speed,
+ priv->phydev->duplex ?
+ "Full" : "Half",
+ priv->port);
+ } else {
+ netif_carrier_off(dev);
+ DEBUGPRINT("%s: Link down\n", dev->name);
+ }
+ }
}
+
/**
- * Setup the MDIO device structures
+ * Setup the PHY
*
* @dev: Device to setup
*
* Returns Zero on success, negative on failure
*/
-int cvm_oct_mdio_setup_device(struct net_device *dev)
+int cvm_oct_phy_setup_device(struct net_device *dev)
{
struct octeon_ethernet *priv = netdev_priv(dev);
- int phy_id = cvmx_helper_board_get_mii_address(priv->port);
- if (phy_id != -1) {
- priv->mii_info.dev = dev;
- priv->mii_info.phy_id = phy_id;
- priv->mii_info.phy_id_mask = 0xff;
- priv->mii_info.supports_gmii = 1;
- priv->mii_info.reg_num_mask = 0x1f;
- priv->mii_info.mdio_read = cvm_oct_mdio_read;
- priv->mii_info.mdio_write = cvm_oct_mdio_write;
- } else {
- /* Supply dummy MDIO routines so the kernel won't crash
- if the user tries to read them */
- priv->mii_info.mdio_read = cvm_oct_mdio_dummy_read;
- priv->mii_info.mdio_write = cvm_oct_mdio_dummy_write;
+
+ int phy_addr = cvmx_helper_board_get_mii_address(priv->port);
+ if (phy_addr != -1) {
+ char phy_id[20];
+
+ snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "0", phy_addr);
+
+ priv->phydev = phy_connect(dev, phy_id, cvm_oct_adjust_link, 0,
+ PHY_INTERFACE_MODE_GMII);
+
+ if (IS_ERR(priv->phydev)) {
+ priv->phydev = NULL;
+ return -1;
+ }
+ priv->last_link = 0;
+ phy_start_aneg(priv->phydev);
}
return 0;
}
diff --git a/drivers/staging/octeon/ethernet-mdio.h b/drivers/staging/octeon/ethernet-mdio.h
index b3328aeec2d..55d0614a7cd 100644
--- a/drivers/staging/octeon/ethernet-mdio.h
+++ b/drivers/staging/octeon/ethernet-mdio.h
@@ -43,4 +43,4 @@
extern const struct ethtool_ops cvm_oct_ethtool_ops;
int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-int cvm_oct_mdio_setup_device(struct net_device *dev);
+int cvm_oct_phy_setup_device(struct net_device *dev);
diff --git a/drivers/staging/octeon/ethernet-proc.c b/drivers/staging/octeon/ethernet-proc.c
index 8fa88fc419b..16308d484d3 100644
--- a/drivers/staging/octeon/ethernet-proc.c
+++ b/drivers/staging/octeon/ethernet-proc.c
@@ -25,7 +25,6 @@
* Contact Cavium Networks for more information
**********************************************************************/
#include <linux/kernel.h>
-#include <linux/mii.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <net/dst.h>
@@ -38,112 +37,6 @@
#include "cvmx-helper.h"
#include "cvmx-pip.h"
-static unsigned long long cvm_oct_stats_read_switch(struct net_device *dev,
- int phy_id, int offset)
-{
- struct octeon_ethernet *priv = netdev_priv(dev);
-
- priv->mii_info.mdio_write(dev, phy_id, 0x1d, 0xcc00 | offset);
- return ((uint64_t) priv->mii_info.
- mdio_read(dev, phy_id,
- 0x1e) << 16) | (uint64_t) priv->mii_info.
- mdio_read(dev, phy_id, 0x1f);
-}
-
-static int cvm_oct_stats_switch_show(struct seq_file *m, void *v)
-{
- static const int ports[] = { 0, 1, 2, 3, 9, -1 };
- struct net_device *dev = cvm_oct_device[0];
- int index = 0;
-
- while (ports[index] != -1) {
-
- /* Latch port */
- struct octeon_ethernet *priv = netdev_priv(dev);
-
- priv->mii_info.mdio_write(dev, 0x1b, 0x1d,
- 0xdc00 | ports[index]);
- seq_printf(m, "\nSwitch Port %d\n", ports[index]);
- seq_printf(m, "InGoodOctets: %12llu\t"
- "OutOctets: %12llu\t"
- "64 Octets: %12llu\n",
- cvm_oct_stats_read_switch(dev, 0x1b,
- 0x00) |
- (cvm_oct_stats_read_switch(dev, 0x1b, 0x01) << 32),
- cvm_oct_stats_read_switch(dev, 0x1b,
- 0x0E) |
- (cvm_oct_stats_read_switch(dev, 0x1b, 0x0F) << 32),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x08));
-
- seq_printf(m, "InBadOctets: %12llu\t"
- "OutUnicast: %12llu\t"
- "65-127 Octets: %12llu\n",
- cvm_oct_stats_read_switch(dev, 0x1b, 0x02),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x10),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x09));
-
- seq_printf(m, "InUnicast: %12llu\t"
- "OutBroadcasts: %12llu\t"
- "128-255 Octets: %12llu\n",
- cvm_oct_stats_read_switch(dev, 0x1b, 0x04),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x13),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x0A));
-
- seq_printf(m, "InBroadcasts: %12llu\t"
- "OutMulticasts: %12llu\t"
- "256-511 Octets: %12llu\n",
- cvm_oct_stats_read_switch(dev, 0x1b, 0x06),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x12),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x0B));
-
- seq_printf(m, "InMulticasts: %12llu\t"
- "OutPause: %12llu\t"
- "512-1023 Octets:%12llu\n",
- cvm_oct_stats_read_switch(dev, 0x1b, 0x07),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x15),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x0C));
-
- seq_printf(m, "InPause: %12llu\t"
- "Excessive: %12llu\t"
- "1024-Max Octets:%12llu\n",
- cvm_oct_stats_read_switch(dev, 0x1b, 0x16),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x11),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x0D));
-
- seq_printf(m, "InUndersize: %12llu\t"
- "Collisions: %12llu\n",
- cvm_oct_stats_read_switch(dev, 0x1b, 0x18),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x1E));
-
- seq_printf(m, "InFragments: %12llu\t"
- "Deferred: %12llu\n",
- cvm_oct_stats_read_switch(dev, 0x1b, 0x19),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x05));
-
- seq_printf(m, "InOversize: %12llu\t"
- "Single: %12llu\n",
- cvm_oct_stats_read_switch(dev, 0x1b, 0x1A),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x14));
-
- seq_printf(m, "InJabber: %12llu\t"
- "Multiple: %12llu\n",
- cvm_oct_stats_read_switch(dev, 0x1b, 0x1B),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x17));
-
- seq_printf(m, "In RxErr: %12llu\t"
- "OutFCSErr: %12llu\n",
- cvm_oct_stats_read_switch(dev, 0x1b, 0x1C),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x03));
-
- seq_printf(m, "InFCSErr: %12llu\t"
- "Late: %12llu\n",
- cvm_oct_stats_read_switch(dev, 0x1b, 0x1D),
- cvm_oct_stats_read_switch(dev, 0x1b, 0x1F));
- index++;
- }
- return 0;
-}
-
/**
* User is reading /proc/octeon_ethernet_stats
*
@@ -215,11 +108,6 @@ static int cvm_oct_stats_show(struct seq_file *m, void *v)
}
}
- if (cvm_oct_device[0]) {
- priv = netdev_priv(cvm_oct_device[0]);
- if (priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
- cvm_oct_stats_switch_show(m, v);
- }
return 0;
}
diff --git a/drivers/staging/octeon/ethernet-rgmii.c b/drivers/staging/octeon/ethernet-rgmii.c
index fbaa465d2fa..3820f1ec11d 100644
--- a/drivers/staging/octeon/ethernet-rgmii.c
+++ b/drivers/staging/octeon/ethernet-rgmii.c
@@ -147,32 +147,36 @@ static void cvm_oct_rgmii_poll(struct net_device *dev)
cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
gmxx_rxx_int_reg.u64);
}
-
- link_info = cvmx_helper_link_autoconf(priv->port);
- priv->link_info = link_info.u64;
+ if (priv->phydev == NULL) {
+ link_info = cvmx_helper_link_autoconf(priv->port);
+ priv->link_info = link_info.u64;
+ }
spin_unlock_irqrestore(&global_register_lock, flags);
- /* Tell Linux */
- if (link_info.s.link_up) {
-
- if (!netif_carrier_ok(dev))
- netif_carrier_on(dev);
- if (priv->queue != -1)
- DEBUGPRINT
- ("%s: %u Mbps %s duplex, port %2d, queue %2d\n",
- dev->name, link_info.s.speed,
- (link_info.s.full_duplex) ? "Full" : "Half",
- priv->port, priv->queue);
- else
- DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, POW\n",
- dev->name, link_info.s.speed,
- (link_info.s.full_duplex) ? "Full" : "Half",
- priv->port);
- } else {
-
- if (netif_carrier_ok(dev))
- netif_carrier_off(dev);
- DEBUGPRINT("%s: Link down\n", dev->name);
+ if (priv->phydev == NULL) {
+ /* Tell core. */
+ if (link_info.s.link_up) {
+ if (!netif_carrier_ok(dev))
+ netif_carrier_on(dev);
+ if (priv->queue != -1)
+ DEBUGPRINT("%s: %u Mbps %s duplex, "
+ "port %2d, queue %2d\n",
+ dev->name, link_info.s.speed,
+ (link_info.s.full_duplex) ?
+ "Full" : "Half",
+ priv->port, priv->queue);
+ else
+ DEBUGPRINT("%s: %u Mbps %s duplex, "
+ "port %2d, POW\n",
+ dev->name, link_info.s.speed,
+ (link_info.s.full_duplex) ?
+ "Full" : "Half",
+ priv->port);
+ } else {
+ if (netif_carrier_ok(dev))
+ netif_carrier_off(dev);
+ DEBUGPRINT("%s: Link down\n", dev->name);
+ }
}
}
diff --git a/drivers/staging/octeon/ethernet-sgmii.c b/drivers/staging/octeon/ethernet-sgmii.c
index 2b54996bd85..6061d01eca2 100644
--- a/drivers/staging/octeon/ethernet-sgmii.c
+++ b/drivers/staging/octeon/ethernet-sgmii.c
@@ -113,7 +113,7 @@ int cvm_oct_sgmii_init(struct net_device *dev)
struct octeon_ethernet *priv = netdev_priv(dev);
cvm_oct_common_init(dev);
dev->netdev_ops->ndo_stop(dev);
- if (!octeon_is_simulation())
+ if (!octeon_is_simulation() && priv->phydev == NULL)
priv->poll = cvm_oct_sgmii_poll;
/* FIXME: Need autoneg logic */
diff --git a/drivers/staging/octeon/ethernet-xaui.c b/drivers/staging/octeon/ethernet-xaui.c
index 0c2e7cc40f3..ee3dc41b2c5 100644
--- a/drivers/staging/octeon/ethernet-xaui.c
+++ b/drivers/staging/octeon/ethernet-xaui.c
@@ -112,7 +112,7 @@ int cvm_oct_xaui_init(struct net_device *dev)
struct octeon_ethernet *priv = netdev_priv(dev);
cvm_oct_common_init(dev);
dev->netdev_ops->ndo_stop(dev);
- if (!octeon_is_simulation())
+ if (!octeon_is_simulation() && priv->phydev == NULL)
priv->poll = cvm_oct_xaui_poll;
return 0;
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c
index 492c5029992..4cfd4b136b3 100644
--- a/drivers/staging/octeon/ethernet.c
+++ b/drivers/staging/octeon/ethernet.c
@@ -30,7 +30,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
-#include <linux/mii.h>
+#include <linux/phy.h>
#include <net/dst.h>
@@ -132,8 +132,6 @@ static struct timer_list cvm_oct_poll_timer;
*/
struct net_device *cvm_oct_device[TOTAL_NUMBER_OF_PORTS];
-extern struct semaphore mdio_sem;
-
/**
* Periodic timer tick for slow management operations
*
@@ -160,13 +158,8 @@ static void cvm_do_timer(unsigned long arg)
goto out;
priv = netdev_priv(cvm_oct_device[port]);
- if (priv->poll) {
- /* skip polling if we don't get the lock */
- if (!down_trylock(&mdio_sem)) {
- priv->poll(cvm_oct_device[port]);
- up(&mdio_sem);
- }
- }
+ if (priv->poll)
+ priv->poll(cvm_oct_device[port]);
queues_per_port = cvmx_pko_get_num_queues(port);
/* Drain any pending packets in the free list */
@@ -524,7 +517,7 @@ int cvm_oct_common_init(struct net_device *dev)
dev->features |= NETIF_F_LLTX;
SET_ETHTOOL_OPS(dev, &cvm_oct_ethtool_ops);
- cvm_oct_mdio_setup_device(dev);
+ cvm_oct_phy_setup_device(dev);
dev->netdev_ops->ndo_set_mac_address(dev, &sa);
dev->netdev_ops->ndo_change_mtu(dev, dev->mtu);
@@ -540,7 +533,10 @@ int cvm_oct_common_init(struct net_device *dev)
void cvm_oct_common_uninit(struct net_device *dev)
{
- /* Currently nothing to do */
+ struct octeon_ethernet *priv = netdev_priv(dev);
+
+ if (priv->phydev)
+ phy_disconnect(priv->phydev);
}
static const struct net_device_ops cvm_oct_npi_netdev_ops = {
@@ -627,6 +623,8 @@ static const struct net_device_ops cvm_oct_pow_netdev_ops = {
#endif
};
+extern void octeon_mdiobus_force_mod_depencency(void);
+
/**
* Module/ driver initialization. Creates the linux network
* devices.
@@ -640,6 +638,7 @@ static int __init cvm_oct_init_module(void)
int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE;
int qos;
+ octeon_mdiobus_force_mod_depencency();
pr_notice("cavium-ethernet %s\n", OCTEON_ETHERNET_VERSION);
if (OCTEON_IS_MODEL(OCTEON_CN52XX))
diff --git a/drivers/staging/octeon/octeon-ethernet.h b/drivers/staging/octeon/octeon-ethernet.h
index 3aef9878fc0..402a15b9bb0 100644
--- a/drivers/staging/octeon/octeon-ethernet.h
+++ b/drivers/staging/octeon/octeon-ethernet.h
@@ -50,9 +50,9 @@ struct octeon_ethernet {
/* List of outstanding tx buffers per queue */
struct sk_buff_head tx_free_list[16];
/* Device statistics */
- struct net_device_stats stats
-; /* Generic MII info structure */
- struct mii_if_info mii_info;
+ struct net_device_stats stats;
+ struct phy_device *phydev;
+ unsigned int last_link;
/* Last negotiated link state */
uint64_t link_info;
/* Called periodically to check link status */
diff --git a/drivers/staging/panel/Kconfig b/drivers/staging/panel/Kconfig
index 3abe7c9d558..3defa0133f2 100644
--- a/drivers/staging/panel/Kconfig
+++ b/drivers/staging/panel/Kconfig
@@ -47,7 +47,7 @@ config PANEL_PROFILE
config PANEL_KEYPAD
depends on PANEL && PANEL_PROFILE="0"
int "Keypad type (0=none, 1=old 6 keys, 2=new 6 keys, 3=Nexcom 4 keys)"
- range 0 4
+ range 0 3
default 0
---help---
This enables and configures a keypad connected to the parallel port.
diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c
index 4ce399b6d23..95c93e82cce 100644
--- a/drivers/staging/panel/panel.c
+++ b/drivers/staging/panel/panel.c
@@ -55,7 +55,7 @@
#include <linux/list.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
#include <linux/io.h>
#include <asm/uaccess.h>
@@ -378,7 +378,7 @@ static unsigned char lcd_bits[LCD_PORTS][LCD_BITS][BIT_STATES];
#ifdef CONFIG_PANEL_LCD_CHARSET
#undef DEFAULT_LCD_CHARSET
-#define DEFAULT_LCD_CHARSET
+#define DEFAULT_LCD_CHARSET CONFIG_PANEL_LCD_CHARSET
#endif
#endif /* DEFAULT_PROFILE == 0 */
diff --git a/drivers/staging/pohmelfs/dir.c b/drivers/staging/pohmelfs/dir.c
index 6c5b261e9f0..aacd25bfb0c 100644
--- a/drivers/staging/pohmelfs/dir.c
+++ b/drivers/staging/pohmelfs/dir.c
@@ -722,8 +722,6 @@ static int pohmelfs_remove_entry(struct inode *dir, struct dentry *dentry)
if (inode->i_nlink)
inode_dec_link_count(inode);
}
- dprintk("%s: inode: %p, lock: %ld, unhashed: %d.\n",
- __func__, pi, inode->i_state & I_LOCK, hlist_unhashed(&inode->i_hash));
return err;
}
diff --git a/drivers/staging/ramzswap/TODO b/drivers/staging/ramzswap/TODO
index bac40d6cb9f..8d64e28fac0 100644
--- a/drivers/staging/ramzswap/TODO
+++ b/drivers/staging/ramzswap/TODO
@@ -1,6 +1,5 @@
TODO:
- Add support for swap notifiers
- - Remove CONFIG_ARM hack
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
Nitin Gupta <ngupta@vflare.org>
diff --git a/drivers/staging/ramzswap/ramzswap_drv.c b/drivers/staging/ramzswap/ramzswap_drv.c
index b839f05efbc..989fac5b01b 100644
--- a/drivers/staging/ramzswap/ramzswap_drv.c
+++ b/drivers/staging/ramzswap/ramzswap_drv.c
@@ -222,28 +222,6 @@ out:
return ret;
}
-static void ramzswap_flush_dcache_page(struct page *page)
-{
-#ifdef CONFIG_ARM
- int flag = 0;
- /*
- * Ugly hack to get flush_dcache_page() work on ARM.
- * page_mapping(page) == NULL after clearing this swap cache flag.
- * Without clearing this flag, flush_dcache_page() will simply set
- * "PG_dcache_dirty" bit and return.
- */
- if (PageSwapCache(page)) {
- flag = 1;
- ClearPageSwapCache(page);
- }
-#endif
- flush_dcache_page(page);
-#ifdef CONFIG_ARM
- if (flag)
- SetPageSwapCache(page);
-#endif
-}
-
void ramzswap_ioctl_get_stats(struct ramzswap *rzs,
struct ramzswap_ioctl_stats *s)
{
@@ -655,7 +633,7 @@ static int handle_zero_page(struct bio *bio)
memset(user_mem, 0, PAGE_SIZE);
kunmap_atomic(user_mem, KM_USER0);
- ramzswap_flush_dcache_page(page);
+ flush_dcache_page(page);
set_bit(BIO_UPTODATE, &bio->bi_flags);
bio_endio(bio, 0);
@@ -679,7 +657,7 @@ static int handle_uncompressed_page(struct ramzswap *rzs, struct bio *bio)
kunmap_atomic(user_mem, KM_USER0);
kunmap_atomic(cmem, KM_USER1);
- ramzswap_flush_dcache_page(page);
+ flush_dcache_page(page);
set_bit(BIO_UPTODATE, &bio->bi_flags);
bio_endio(bio, 0);
@@ -779,7 +757,7 @@ static int ramzswap_read(struct ramzswap *rzs, struct bio *bio)
goto out;
}
- ramzswap_flush_dcache_page(page);
+ flush_dcache_page(page);
set_bit(BIO_UPTODATE, &bio->bi_flags);
bio_endio(bio, 0);
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
index 3222c22152f..0d490c164db 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
@@ -1318,13 +1318,13 @@ extern int ieee80211_encrypt_fragment(
struct sk_buff *frag,
int hdr_len);
-extern int ieee80211_xmit(struct sk_buff *skb,
+extern int ieee80211_rtl_xmit(struct sk_buff *skb,
struct net_device *dev);
extern void ieee80211_txb_free(struct ieee80211_txb *);
/* ieee80211_rx.c */
-extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+extern int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
struct ieee80211_rx_stats *rx_stats);
extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
struct ieee80211_hdr_4addr *header,
@@ -1376,8 +1376,8 @@ extern void ieee80211_stop_protocol(struct ieee80211_device *ieee);
extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee);
extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee);
extern void ieee80211_reset_queue(struct ieee80211_device *ieee);
-extern void ieee80211_wake_queue(struct ieee80211_device *ieee);
-extern void ieee80211_stop_queue(struct ieee80211_device *ieee);
+extern void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee);
+extern void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee);
extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee);
extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee);
extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee);
@@ -1385,7 +1385,7 @@ extern int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct
extern void notify_wx_assoc_event(struct ieee80211_device *ieee);
extern void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success);
extern void SendDisassociation(struct ieee80211_device *ieee,u8* asSta,u8 asRsn);
-extern void ieee80211_start_scan(struct ieee80211_device *ieee);
+extern void ieee80211_rtl_start_scan(struct ieee80211_device *ieee);
//Add for RF power on power off by lizhaoming 080512
extern void SendDisassociation(struct ieee80211_device *ieee,
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
index f882dd8cf9b..9128c181bc7 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
@@ -469,7 +469,7 @@ drop:
/* All received frames are sent to this function. @skb contains the frame in
* IEEE 802.11 format, i.e., in the format it was sent over air.
* This function is called only as a tasklet (software IRQ). */
-int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
struct ieee80211_rx_stats *rx_stats)
{
struct net_device *dev = ieee->dev;
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
index 1fe19c39d70..c7c645af0eb 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
@@ -689,7 +689,7 @@ void ieee80211_stop_scan(struct ieee80211_device *ieee)
}
/* called with ieee->lock held */
-void ieee80211_start_scan(struct ieee80211_device *ieee)
+void ieee80211_rtl_start_scan(struct ieee80211_device *ieee)
{
if(IS_DOT11D_ENABLE(ieee) )
{
@@ -1196,7 +1196,7 @@ void ieee80211_associate_step1(struct ieee80211_device *ieee)
}
}
-void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen)
+void ieee80211_rtl_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen)
{
u8 *c;
struct sk_buff *skb;
@@ -1898,7 +1898,7 @@ associate_complete:
ieee80211_associate_step2(ieee);
}else{
- ieee80211_auth_challenge(ieee, challenge, chlen);
+ ieee80211_rtl_auth_challenge(ieee, challenge, chlen);
}
}else{
ieee->softmac_stats.rx_auth_rs_err++;
@@ -2047,7 +2047,7 @@ void ieee80211_reset_queue(struct ieee80211_device *ieee)
}
-void ieee80211_wake_queue(struct ieee80211_device *ieee)
+void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee)
{
unsigned long flags;
@@ -2089,7 +2089,7 @@ exit :
}
-void ieee80211_stop_queue(struct ieee80211_device *ieee)
+void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee)
{
//unsigned long flags;
//spin_lock_irqsave(&ieee->lock,flags);
@@ -2301,7 +2301,7 @@ void ieee80211_start_bss(struct ieee80211_device *ieee)
//#else
if (ieee->state == IEEE80211_NOLINK){
ieee->actscanning = true;
- ieee80211_start_scan(ieee);
+ ieee80211_rtl_start_scan(ieee);
}
//#endif
spin_unlock_irqrestore(&ieee->lock, flags);
@@ -2357,7 +2357,7 @@ void ieee80211_associate_retry_wq(struct work_struct *work)
if(ieee->state == IEEE80211_NOLINK){
ieee->beinretry = false;
ieee->actscanning = true;
- ieee80211_start_scan(ieee);
+ ieee80211_rtl_start_scan(ieee);
}
//YJ,add,080828, notify os here
if(ieee->state == IEEE80211_NOLINK)
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
index dde1f2e0cf3..69bd02164b0 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
@@ -304,7 +304,7 @@ ieee80211_classify(struct sk_buff *skb, struct ieee80211_network *network)
}
/* SKBs are added to the ieee->tx_queue. */
-int ieee80211_xmit(struct sk_buff *skb,
+int ieee80211_rtl_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct ieee80211_device *ieee = netdev_priv(dev);
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index 57c62b0a402..e0f13efdb15 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -1811,7 +1811,7 @@ void rtl8180_rx(struct net_device *dev)
if(priv->rx_skb->len > 4)
skb_trim(priv->rx_skb,priv->rx_skb->len-4);
#ifndef RX_DONT_PASS_UL
- if(!ieee80211_rx(priv->ieee80211,
+ if(!ieee80211_rtl_rx(priv->ieee80211,
priv->rx_skb, &stats)){
#endif // RX_DONT_PASS_UL
@@ -1917,11 +1917,11 @@ rate)
if (!check_nic_enought_desc(dev, priority)){
DMESGW("Error: no descriptor left by previous TX (avail %d) ",
get_curr_tx_free_desc(dev, priority));
- ieee80211_stop_queue(priv->ieee80211);
+ ieee80211_rtl_stop_queue(priv->ieee80211);
}
rtl8180_tx(dev, skb->data, skb->len, priority, morefrag,0,rate);
if (!check_nic_enought_desc(dev, priority))
- ieee80211_stop_queue(priv->ieee80211);
+ ieee80211_rtl_stop_queue(priv->ieee80211);
spin_unlock_irqrestore(&priv->tx_lock,flags);
}
@@ -3680,7 +3680,7 @@ static const struct net_device_ops rtl8180_netdev_ops = {
.ndo_set_mac_address = r8180_set_mac_adr,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
- .ndo_start_xmit = ieee80211_xmit,
+ .ndo_start_xmit = ieee80211_rtl_xmit,
};
static int __devinit rtl8180_pci_probe(struct pci_dev *pdev,
@@ -3900,7 +3900,7 @@ void rtl8180_try_wake_queue(struct net_device *dev, int pri)
spin_unlock_irqrestore(&priv->tx_lock,flags);
if(enough_desc)
- ieee80211_wake_queue(priv->ieee80211);
+ ieee80211_rtl_wake_queue(priv->ieee80211);
}
void rtl8180_tx_isr(struct net_device *dev, int pri,short error)
diff --git a/drivers/staging/rtl8187se/r8180_wx.c b/drivers/staging/rtl8187se/r8180_wx.c
index 536cb6e8e79..124cde356cb 100644
--- a/drivers/staging/rtl8187se/r8180_wx.c
+++ b/drivers/staging/rtl8187se/r8180_wx.c
@@ -377,7 +377,7 @@ static int r8180_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
// queue_work(priv->ieee80211->wq, &priv->ieee80211->wx_sync_scan_wq);
//printk("start scan============================>\n");
ieee80211_softmac_ips_scan_syncro(priv->ieee80211);
-//ieee80211_start_scan(priv->ieee80211);
+//ieee80211_rtl_start_scan(priv->ieee80211);
/* intentionally forget to up sem */
// up(&priv->ieee80211->wx_sem);
ret = 0;
diff --git a/drivers/staging/rtl8192e/ieee80211.h b/drivers/staging/rtl8192e/ieee80211.h
index 97137ddefff..3ba9e9e90bd 100644
--- a/drivers/staging/rtl8192e/ieee80211.h
+++ b/drivers/staging/rtl8192e/ieee80211.h
@@ -303,8 +303,8 @@ enum _ReasonCode{
#define ieee80211_rx_mgt ieee80211_rx_mgt_rsl
#define ieee80211_get_beacon ieee80211_get_beacon_rsl
-#define ieee80211_wake_queue ieee80211_wake_queue_rsl
-#define ieee80211_stop_queue ieee80211_stop_queue_rsl
+#define ieee80211_rtl_wake_queue ieee80211_rtl_wake_queue_rsl
+#define ieee80211_rtl_stop_queue ieee80211_rtl_stop_queue_rsl
#define ieee80211_reset_queue ieee80211_reset_queue_rsl
#define ieee80211_softmac_stop_protocol ieee80211_softmac_stop_protocol_rsl
#define ieee80211_softmac_start_protocol ieee80211_softmac_start_protocol_rsl
@@ -2435,13 +2435,13 @@ extern int ieee80211_encrypt_fragment(
struct sk_buff *frag,
int hdr_len);
-extern int ieee80211_xmit(struct sk_buff *skb,
+extern int ieee80211_rtl_xmit(struct sk_buff *skb,
struct net_device *dev);
extern void ieee80211_txb_free(struct ieee80211_txb *);
/* ieee80211_rx.c */
-extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+extern int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
struct ieee80211_rx_stats *rx_stats);
extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
struct ieee80211_hdr_4addr *header,
@@ -2502,8 +2502,8 @@ extern void ieee80211_stop_protocol(struct ieee80211_device *ieee);
extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee);
extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee);
extern void ieee80211_reset_queue(struct ieee80211_device *ieee);
-extern void ieee80211_wake_queue(struct ieee80211_device *ieee);
-extern void ieee80211_stop_queue(struct ieee80211_device *ieee);
+extern void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee);
+extern void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee);
extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee);
extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee);
extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee);
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211.h b/drivers/staging/rtl8192e/ieee80211/ieee80211.h
index 83c8452de37..aa76390487b 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211.h
@@ -333,8 +333,8 @@ enum _ReasonCode{
#define ieee80211_rx_mgt ieee80211_rx_mgt_rsl
#define ieee80211_get_beacon ieee80211_get_beacon_rsl
-#define ieee80211_wake_queue ieee80211_wake_queue_rsl
-#define ieee80211_stop_queue ieee80211_stop_queue_rsl
+#define ieee80211_rtl_wake_queue ieee80211_rtl_wake_queue_rsl
+#define ieee80211_rtl_stop_queue ieee80211_rtl_stop_queue_rsl
#define ieee80211_reset_queue ieee80211_reset_queue_rsl
#define ieee80211_softmac_stop_protocol ieee80211_softmac_stop_protocol_rsl
#define ieee80211_softmac_start_protocol ieee80211_softmac_start_protocol_rsl
@@ -2546,13 +2546,13 @@ extern int ieee80211_encrypt_fragment(
struct sk_buff *frag,
int hdr_len);
-extern int ieee80211_xmit(struct sk_buff *skb,
+extern int ieee80211_rtl_xmit(struct sk_buff *skb,
struct net_device *dev);
extern void ieee80211_txb_free(struct ieee80211_txb *);
/* ieee80211_rx.c */
-extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+extern int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
struct ieee80211_rx_stats *rx_stats);
extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
struct ieee80211_hdr_4addr *header,
@@ -2613,8 +2613,8 @@ extern void ieee80211_stop_protocol(struct ieee80211_device *ieee);
extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee);
extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee);
extern void ieee80211_reset_queue(struct ieee80211_device *ieee);
-extern void ieee80211_wake_queue(struct ieee80211_device *ieee);
-extern void ieee80211_stop_queue(struct ieee80211_device *ieee);
+extern void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee);
+extern void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee);
extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee);
extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee);
extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee);
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_module.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_module.c
index 2644155737a..f43a7db5c78 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_module.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_module.c
@@ -119,7 +119,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
ieee = (struct ieee80211_device *)dev->priv;
#endif
#if 0
- dev->hard_start_xmit = ieee80211_xmit;
+ dev->hard_start_xmit = ieee80211_rtl_xmit;
#endif
memset(ieee, 0, sizeof(struct ieee80211_device)+sizeof_priv);
@@ -333,7 +333,7 @@ extern void ieee80211_crypto_ccmp_exit(void);
extern int ieee80211_crypto_wep_init(void);
extern void ieee80211_crypto_wep_exit(void);
-int __init ieee80211_init(void)
+int __init ieee80211_rtl_init(void)
{
struct proc_dir_entry *e;
int retval;
@@ -389,7 +389,7 @@ int __init ieee80211_init(void)
return 0;
}
-void __exit ieee80211_exit(void)
+void __exit ieee80211_rtl_exit(void)
{
if (ieee80211_proc) {
remove_proc_entry("debug_level", ieee80211_proc);
@@ -412,8 +412,8 @@ module_param(debug, int, 0444);
MODULE_PARM_DESC(debug, "debug output mask");
-//module_exit(ieee80211_exit);
-//module_init(ieee80211_init);
+//module_exit(ieee80211_rtl_exit);
+//module_init(ieee80211_rtl_init);
#endif
#endif
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c
index 5dc478b8637..06d91715143 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c
@@ -923,7 +923,7 @@ u8 parse_subframe(struct sk_buff *skb,
/* All received frames are sent to this function. @skb contains the frame in
* IEEE 802.11 format, i.e., in the format it was sent over air.
* This function is called only as a tasklet (software IRQ). */
-int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
struct ieee80211_rx_stats *rx_stats)
{
struct net_device *dev = ieee->dev;
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c
index 593d2282518..6d1ddec39f0 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c
@@ -684,7 +684,7 @@ void ieee80211_stop_scan(struct ieee80211_device *ieee)
}
/* called with ieee->lock held */
-void ieee80211_start_scan(struct ieee80211_device *ieee)
+void ieee80211_rtl_start_scan(struct ieee80211_device *ieee)
{
#ifdef ENABLE_DOT11D
if(IS_DOT11D_ENABLE(ieee) )
@@ -1430,7 +1430,7 @@ void ieee80211_associate_step1(struct ieee80211_device *ieee)
}
}
-void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen)
+void ieee80211_rtl_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen)
{
u8 *c;
struct sk_buff *skb;
@@ -2262,7 +2262,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
ieee80211_associate_step2(ieee);
}else{
- ieee80211_auth_challenge(ieee, challenge, chlen);
+ ieee80211_rtl_auth_challenge(ieee, challenge, chlen);
}
}else{
ieee->softmac_stats.rx_auth_rs_err++;
@@ -2376,7 +2376,7 @@ void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *
* to check it any more.
* */
//printk("error:no descriptor left@queue_index %d\n", queue_index);
- //ieee80211_stop_queue(ieee);
+ //ieee80211_rtl_stop_queue(ieee);
#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE
skb_queue_tail(&ieee->skb_drv_aggQ[queue_index], txb->fragments[i]);
#else
@@ -2440,7 +2440,7 @@ void ieee80211_reset_queue(struct ieee80211_device *ieee)
}
-void ieee80211_wake_queue(struct ieee80211_device *ieee)
+void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee)
{
unsigned long flags;
@@ -2481,7 +2481,7 @@ exit :
}
-void ieee80211_stop_queue(struct ieee80211_device *ieee)
+void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee)
{
//unsigned long flags;
//spin_lock_irqsave(&ieee->lock,flags);
@@ -2706,7 +2706,7 @@ void ieee80211_start_bss(struct ieee80211_device *ieee)
if (ieee->state == IEEE80211_NOLINK){
ieee->actscanning = true;
- ieee80211_start_scan(ieee);
+ ieee80211_rtl_start_scan(ieee);
}
spin_unlock_irqrestore(&ieee->lock, flags);
}
@@ -2775,7 +2775,7 @@ void ieee80211_associate_retry_wq(struct ieee80211_device *ieee)
{
ieee->is_roaming= false;
ieee->actscanning = true;
- ieee80211_start_scan(ieee);
+ ieee80211_rtl_start_scan(ieee);
}
spin_unlock_irqrestore(&ieee->lock, flags);
@@ -3497,8 +3497,8 @@ void notify_wx_assoc_event(struct ieee80211_device *ieee)
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
//EXPORT_SYMBOL(ieee80211_get_beacon);
-//EXPORT_SYMBOL(ieee80211_wake_queue);
-//EXPORT_SYMBOL(ieee80211_stop_queue);
+//EXPORT_SYMBOL(ieee80211_rtl_wake_queue);
+//EXPORT_SYMBOL(ieee80211_rtl_stop_queue);
//EXPORT_SYMBOL(ieee80211_reset_queue);
//EXPORT_SYMBOL(ieee80211_softmac_stop_protocol);
//EXPORT_SYMBOL(ieee80211_softmac_start_protocol);
@@ -3518,8 +3518,8 @@ void notify_wx_assoc_event(struct ieee80211_device *ieee)
//EXPORT_SYMBOL(ieee80211_start_scan_syncro);
#else
EXPORT_SYMBOL_NOVERS(ieee80211_get_beacon);
-EXPORT_SYMBOL_NOVERS(ieee80211_wake_queue);
-EXPORT_SYMBOL_NOVERS(ieee80211_stop_queue);
+EXPORT_SYMBOL_NOVERS(ieee80211_rtl_wake_queue);
+EXPORT_SYMBOL_NOVERS(ieee80211_rtl_stop_queue);
EXPORT_SYMBOL_NOVERS(ieee80211_reset_queue);
EXPORT_SYMBOL_NOVERS(ieee80211_softmac_stop_protocol);
EXPORT_SYMBOL_NOVERS(ieee80211_softmac_start_protocol);
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c
index 103b33c093f..798fb4154c2 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c
@@ -604,7 +604,7 @@ void ieee80211_query_seqnum(struct ieee80211_device*ieee, struct sk_buff* skb, u
}
}
-int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
+int ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
struct ieee80211_device *ieee = netdev_priv(dev);
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c
index 4e34a1f4c66..3441b72dd8f 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c
@@ -976,7 +976,7 @@ int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
{
if (len != ie[1]+2)
{
- printk("len:%d, ie:%d\n", len, ie[1]);
+ printk("len:%zu, ie:%d\n", len, ie[1]);
return -EINVAL;
}
buf = kmalloc(len, GFP_KERNEL);
diff --git a/drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c
index 98b3bb6b6d6..e41e8a0c739 100644
--- a/drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c
+++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c
@@ -382,7 +382,7 @@ int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb)
if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9)
{
- IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
+ IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
return -1;
}
@@ -481,7 +481,7 @@ int ieee80211_rx_ADDBARsp( struct ieee80211_device* ieee, struct sk_buff *skb)
if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9)
{
- IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BARSP(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
+ IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BARSP(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
return -1;
}
rsp = ( struct ieee80211_hdr_3addr*)skb->data;
@@ -611,7 +611,7 @@ int ieee80211_rx_DELBA(struct ieee80211_device* ieee,struct sk_buff *skb)
if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 6)
{
- IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 6));
+ IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 6));
return -1;
}
diff --git a/drivers/staging/rtl8192e/r8192E_core.c b/drivers/staging/rtl8192e/r8192E_core.c
index ff8fe7e32a9..0ca5d8b4f74 100644
--- a/drivers/staging/rtl8192e/r8192E_core.c
+++ b/drivers/staging/rtl8192e/r8192E_core.c
@@ -5795,7 +5795,7 @@ static void rtl8192_rx(struct net_device *dev)
stats.fragoffset = 0;
stats.ntotalfrag = 1;
- if(!ieee80211_rx(priv->ieee80211, skb, &stats)){
+ if(!ieee80211_rtl_rx(priv->ieee80211, skb, &stats)){
dev_kfree_skb_any(skb);
} else {
priv->stats.rxok++;
@@ -5837,7 +5837,7 @@ static const struct net_device_ops rtl8192_netdev_ops = {
.ndo_do_ioctl = rtl8192_ioctl,
.ndo_set_multicast_list = r8192_set_multicast,
.ndo_set_mac_address = r8192_set_mac_adr,
- .ndo_start_xmit = ieee80211_xmit,
+ .ndo_start_xmit = ieee80211_rtl_xmit,
};
/****************************************************************************
@@ -6121,14 +6121,14 @@ static void __devexit rtl8192_pci_disconnect(struct pci_dev *pdev)
RT_TRACE(COMP_DOWN, "wlan driver removed\n");
}
-extern int ieee80211_init(void);
-extern void ieee80211_exit(void);
+extern int ieee80211_rtl_init(void);
+extern void ieee80211_rtl_exit(void);
static int __init rtl8192_pci_module_init(void)
{
int retval;
- retval = ieee80211_init();
+ retval = ieee80211_rtl_init();
if (retval)
return retval;
@@ -6153,7 +6153,7 @@ static void __exit rtl8192_pci_module_exit(void)
RT_TRACE(COMP_DOWN, "Exiting");
rtl8192_proc_module_remove();
- ieee80211_exit();
+ ieee80211_rtl_exit();
}
//warning message WB
@@ -6313,7 +6313,7 @@ void rtl8192_try_wake_queue(struct net_device *dev, int pri)
spin_unlock_irqrestore(&priv->tx_lock,flags);
if(enough_desc)
- ieee80211_wake_queue(priv->ieee80211);
+ ieee80211_rtl_wake_queue(priv->ieee80211);
#endif
}
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211.h b/drivers/staging/rtl8192su/ieee80211/ieee80211.h
index f22d024b1c3..9a4c858b066 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211.h
@@ -1721,13 +1721,13 @@ extern int ieee80211_encrypt_fragment(
struct sk_buff *frag,
int hdr_len);
-extern int rtl8192_ieee80211_xmit(struct sk_buff *skb,
+extern int rtl8192_ieee80211_rtl_xmit(struct sk_buff *skb,
struct net_device *dev);
extern void ieee80211_txb_free(struct ieee80211_txb *);
/* ieee80211_rx.c */
-extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+extern int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
struct ieee80211_rx_stats *rx_stats);
extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
struct ieee80211_hdr_4addr *header,
@@ -1783,8 +1783,8 @@ extern void ieee80211_stop_protocol(struct ieee80211_device *ieee);
extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee);
extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee);
extern void ieee80211_reset_queue(struct ieee80211_device *ieee);
-extern void ieee80211_wake_queue(struct ieee80211_device *ieee);
-extern void ieee80211_stop_queue(struct ieee80211_device *ieee);
+extern void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee);
+extern void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee);
extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee);
extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee);
extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee);
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c
index ac223cef1d3..fecfa120ff4 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c
@@ -208,7 +208,7 @@ static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee,
*
* Responsible for handling management control frames
*
- * Called by ieee80211_rx */
+ * Called by ieee80211_rtl_rx */
static inline int
ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,
struct ieee80211_rx_stats *rx_stats, u16 type,
@@ -289,7 +289,7 @@ static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee,
return 0;
}
-/* Called only as a tasklet (software IRQ), by ieee80211_rx */
+/* Called only as a tasklet (software IRQ), by ieee80211_rtl_rx */
static inline int
ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb,
struct ieee80211_crypt_data *crypt)
@@ -858,7 +858,7 @@ u8 parse_subframe(struct sk_buff *skb,
/* All received frames are sent to this function. @skb contains the frame in
* IEEE 802.11 format, i.e., in the format it was sent over air.
* This function is called only as a tasklet (software IRQ). */
-int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
struct ieee80211_rx_stats *rx_stats)
{
struct net_device *dev = ieee->dev;
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c
index 203c0a5cc8c..95d4f84dcf3 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c
@@ -610,7 +610,7 @@ void ieee80211_stop_scan(struct ieee80211_device *ieee)
}
/* called with ieee->lock held */
-void ieee80211_start_scan(struct ieee80211_device *ieee)
+void ieee80211_rtl_start_scan(struct ieee80211_device *ieee)
{
if(IS_DOT11D_ENABLE(ieee) )
{
@@ -1281,7 +1281,7 @@ void ieee80211_associate_step1(struct ieee80211_device *ieee)
}
}
-void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen)
+void ieee80211_rtl_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen)
{
u8 *c;
struct sk_buff *skb;
@@ -2054,7 +2054,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
ieee80211_associate_step2(ieee);
}else{
- ieee80211_auth_challenge(ieee, challenge, chlen);
+ ieee80211_rtl_auth_challenge(ieee, challenge, chlen);
}
}else{
ieee->softmac_stats.rx_auth_rs_err++;
@@ -2162,7 +2162,7 @@ void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *
* to check it any more.
* */
//printk("error:no descriptor left@queue_index %d, %d, %d\n", queue_index, skb_queue_len(&ieee->skb_waitQ[queue_index]), ieee->check_nic_enough_desc(ieee->dev,queue_index));
- //ieee80211_stop_queue(ieee);
+ //ieee80211_rtl_stop_queue(ieee);
skb_queue_tail(&ieee->skb_waitQ[queue_index], txb->fragments[i]);
}else{
ieee->softmac_data_hard_start_xmit(
@@ -2222,7 +2222,7 @@ void ieee80211_reset_queue(struct ieee80211_device *ieee)
}
-void ieee80211_wake_queue(struct ieee80211_device *ieee)
+void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee)
{
unsigned long flags;
@@ -2263,7 +2263,7 @@ exit :
}
-void ieee80211_stop_queue(struct ieee80211_device *ieee)
+void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee)
{
//unsigned long flags;
//spin_lock_irqsave(&ieee->lock,flags);
@@ -2479,7 +2479,7 @@ void ieee80211_start_bss(struct ieee80211_device *ieee)
if (ieee->state == IEEE80211_NOLINK){
ieee->actscanning = true;
- ieee80211_start_scan(ieee);
+ ieee80211_rtl_start_scan(ieee);
}
spin_unlock_irqrestore(&ieee->lock, flags);
}
@@ -2552,7 +2552,7 @@ void ieee80211_associate_retry_wq(struct work_struct *work)
if(ieee->state == IEEE80211_NOLINK)
{
ieee->actscanning = true;
- ieee80211_start_scan(ieee);
+ ieee80211_rtl_start_scan(ieee);
}
spin_unlock_irqrestore(&ieee->lock, flags);
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c
index 60621d6b2a6..4d54e1e62d2 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c
@@ -604,7 +604,7 @@ void ieee80211_query_seqnum(struct ieee80211_device*ieee, struct sk_buff* skb, u
}
}
-int rtl8192_ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
+int rtl8192_ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ieee80211_device *ieee = netdev_priv(dev);
struct ieee80211_txb *txb = NULL;
diff --git a/drivers/staging/rtl8192su/r8192U_core.c b/drivers/staging/rtl8192su/r8192U_core.c
index 66274d7666f..ccb9d5b8cd4 100644
--- a/drivers/staging/rtl8192su/r8192U_core.c
+++ b/drivers/staging/rtl8192su/r8192U_core.c
@@ -126,6 +126,8 @@ static struct usb_device_id rtl8192_usb_id_tbl[] = {
{USB_DEVICE(0x2001, 0x3301)},
/* Zinwell */
{USB_DEVICE(0x5a57, 0x0290)},
+ /* Guillemot */
+ {USB_DEVICE(0x06f8, 0xe031)},
//92SU
{USB_DEVICE(0x0bda, 0x8172)},
{}
@@ -1501,7 +1503,7 @@ static void rtl8192_rx_isr(struct urb *urb)
urb->context = skb;
skb_queue_tail(&priv->rx_queue, skb);
err = usb_submit_urb(urb, GFP_ATOMIC);
- if(err && err != EPERM)
+ if(err && err != -EPERM)
printk("can not submit rxurb, err is %x,URB status is %x\n",err,urb->status);
}
@@ -7155,7 +7157,7 @@ void rtl8192SU_rx_nomal(struct sk_buff* skb)
unicast_packet = true;
}
- if(!ieee80211_rx(priv->ieee80211,skb, &stats)) {
+ if(!ieee80211_rtl_rx(priv->ieee80211,skb, &stats)) {
dev_kfree_skb_any(skb);
} else {
// priv->stats.rxoktotal++; //YJ,test,090108
@@ -7426,7 +7428,7 @@ static const struct net_device_ops rtl8192_netdev_ops = {
.ndo_set_mac_address = r8192_set_mac_adr,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
- .ndo_start_xmit = rtl8192_ieee80211_xmit,
+ .ndo_start_xmit = rtl8192_ieee80211_rtl_xmit,
};
static int __devinit rtl8192_usb_probe(struct usb_interface *intf,
@@ -7619,7 +7621,7 @@ void rtl8192_try_wake_queue(struct net_device *dev, int pri)
spin_unlock_irqrestore(&priv->tx_lock,flags);
if(enough_desc)
- ieee80211_wake_queue(priv->ieee80211);
+ ieee80211_rtl_wake_queue(priv->ieee80211);
}
void EnableHWSecurityConfig8192(struct net_device *dev)
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
index d397f1d68eb..5f12d62658c 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
@@ -845,7 +845,7 @@ int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
{
if (len != ie[1]+2)
{
- printk("len:%d, ie:%d\n", len, ie[1]);
+ printk("len:%zu, ie:%d\n", len, ie[1]);
return -EINVAL;
}
buf = kmalloc(len, GFP_KERNEL);
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
index 26af43bb839..512a57aebde 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
@@ -340,7 +340,7 @@ int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb)
if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9)
{
- IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
+ IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
return -1;
}
@@ -439,7 +439,7 @@ int ieee80211_rx_ADDBARsp( struct ieee80211_device* ieee, struct sk_buff *skb)
if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9)
{
- IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BARSP(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
+ IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BARSP(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
return -1;
}
rsp = ( struct ieee80211_hdr_3addr*)skb->data;
@@ -569,7 +569,7 @@ int ieee80211_rx_DELBA(struct ieee80211_device* ieee,struct sk_buff *skb)
if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 6)
{
- IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 6));
+ IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 6));
return -1;
}
diff --git a/drivers/staging/sm7xx/Kconfig b/drivers/staging/sm7xx/Kconfig
new file mode 100644
index 00000000000..204dbfc3c38
--- /dev/null
+++ b/drivers/staging/sm7xx/Kconfig
@@ -0,0 +1,15 @@
+config FB_SM7XX
+ tristate "Silicon Motion SM7XX Frame Buffer Support"
+ depends on FB
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ Frame Buffer driver for the Silicon Motion SM7XX serial graphic card.
+
+config FB_SM7XX_ACCEL
+ bool "Siliconmotion Acceleration functions (EXPERIMENTAL)"
+ depends on FB_SM7XX && EXPERIMENTAL
+ help
+ This will compile the Trident frame buffer device with
+ acceleration functions.
diff --git a/drivers/staging/sm7xx/Makefile b/drivers/staging/sm7xx/Makefile
new file mode 100644
index 00000000000..f43cb910630
--- /dev/null
+++ b/drivers/staging/sm7xx/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_FB_SM7XX) += sm7xx.o
+
+sm7xx-y := smtcfb.o
diff --git a/drivers/staging/sm7xx/TODO b/drivers/staging/sm7xx/TODO
new file mode 100644
index 00000000000..1f61f5e11cf
--- /dev/null
+++ b/drivers/staging/sm7xx/TODO
@@ -0,0 +1,10 @@
+TODO:
+- Dual head support
+- use kernel coding style
+- checkpatch.pl clean
+- refine the code and remove unused code
+- use kernel framebuffer mode setting instead of hard code
+- move it to drivers/video/sm7xx/ or make it be drivers/video/sm7xxfb.c
+
+Please send any patches to Greg Kroah-Hartman <greg@kroah.com> and
+Teddy Wang <teddy.wang@siliconmotion.com.cn>.
diff --git a/drivers/staging/sm7xx/smtc2d.c b/drivers/staging/sm7xx/smtc2d.c
new file mode 100644
index 00000000000..133b86c6a67
--- /dev/null
+++ b/drivers/staging/sm7xx/smtc2d.c
@@ -0,0 +1,979 @@
+/*
+ * Silicon Motion SM7XX 2D drawing engine functions.
+ *
+ * Copyright (C) 2006 Silicon Motion Technology Corp.
+ * Author: Boyod boyod.yang@siliconmotion.com.cn
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzj@lemote.com
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Version 0.10.26192.21.01
+ * - Add PowerPC support
+ * - Add 2D support for Lynx -
+ * Verified on 2.6.19.2
+ * Boyod.yang <boyod.yang@siliconmotion.com.cn>
+ */
+
+unsigned char smtc_de_busy;
+
+void SMTC_write2Dreg(unsigned long nOffset, unsigned long nData)
+{
+ writel(nData, smtc_2DBaseAddress + nOffset);
+}
+
+unsigned long SMTC_read2Dreg(unsigned long nOffset)
+{
+ return readl(smtc_2DBaseAddress + nOffset);
+}
+
+void SMTC_write2Ddataport(unsigned long nOffset, unsigned long nData)
+{
+ writel(nData, smtc_2Ddataport + nOffset);
+}
+
+/**********************************************************************
+ *
+ * deInit
+ *
+ * Purpose
+ * Drawing engine initialization.
+ *
+ **********************************************************************/
+
+void deInit(unsigned int nModeWidth, unsigned int nModeHeight,
+ unsigned int bpp)
+{
+ /* Get current power configuration. */
+ unsigned char clock;
+ clock = smtc_seqr(0x21);
+
+ /* initialize global 'mutex lock' variable */
+ smtc_de_busy = 0;
+
+ /* Enable 2D Drawing Engine */
+ smtc_seqw(0x21, clock & 0xF8);
+
+ SMTC_write2Dreg(DE_CLIP_TL,
+ FIELD_VALUE(0, DE_CLIP_TL, TOP, 0) |
+ FIELD_SET(0, DE_CLIP_TL, STATUS, DISABLE) |
+ FIELD_SET(0, DE_CLIP_TL, INHIBIT, OUTSIDE) |
+ FIELD_VALUE(0, DE_CLIP_TL, LEFT, 0));
+
+ if (bpp >= 24) {
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION,
+ nModeWidth * 3) | FIELD_VALUE(0,
+ DE_PITCH,
+ SOURCE,
+ nModeWidth
+ * 3));
+ } else {
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION,
+ nModeWidth) | FIELD_VALUE(0,
+ DE_PITCH,
+ SOURCE,
+ nModeWidth));
+ }
+
+ SMTC_write2Dreg(DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ nModeWidth) | FIELD_VALUE(0,
+ DE_WINDOW_WIDTH,
+ SOURCE,
+ nModeWidth));
+
+ switch (bpp) {
+ case 8:
+ SMTC_write2Dreg(DE_STRETCH_FORMAT,
+ FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
+ NORMAL) | FIELD_VALUE(0,
+ DE_STRETCH_FORMAT,
+ PATTERN_Y,
+ 0) |
+ FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
+ 0) | FIELD_SET(0, DE_STRETCH_FORMAT,
+ PIXEL_FORMAT,
+ 8) | FIELD_SET(0,
+ DE_STRETCH_FORMAT,
+ ADDRESSING,
+ XY) |
+ FIELD_VALUE(0, DE_STRETCH_FORMAT,
+ SOURCE_HEIGHT, 3));
+ break;
+ case 24:
+ SMTC_write2Dreg(DE_STRETCH_FORMAT,
+ FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
+ NORMAL) | FIELD_VALUE(0,
+ DE_STRETCH_FORMAT,
+ PATTERN_Y,
+ 0) |
+ FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
+ 0) | FIELD_SET(0, DE_STRETCH_FORMAT,
+ PIXEL_FORMAT,
+ 24) | FIELD_SET(0,
+ DE_STRETCH_FORMAT,
+ ADDRESSING,
+ XY) |
+ FIELD_VALUE(0, DE_STRETCH_FORMAT,
+ SOURCE_HEIGHT, 3));
+ break;
+ case 16:
+ default:
+ SMTC_write2Dreg(DE_STRETCH_FORMAT,
+ FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
+ NORMAL) | FIELD_VALUE(0,
+ DE_STRETCH_FORMAT,
+ PATTERN_Y,
+ 0) |
+ FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
+ 0) | FIELD_SET(0, DE_STRETCH_FORMAT,
+ PIXEL_FORMAT,
+ 16) | FIELD_SET(0,
+ DE_STRETCH_FORMAT,
+ ADDRESSING,
+ XY) |
+ FIELD_VALUE(0, DE_STRETCH_FORMAT,
+ SOURCE_HEIGHT, 3));
+ break;
+ }
+
+ SMTC_write2Dreg(DE_MASKS,
+ FIELD_VALUE(0, DE_MASKS, BYTE_MASK, 0xFFFF) |
+ FIELD_VALUE(0, DE_MASKS, BIT_MASK, 0xFFFF));
+ SMTC_write2Dreg(DE_COLOR_COMPARE_MASK,
+ FIELD_VALUE(0, DE_COLOR_COMPARE_MASK, MASKS, \
+ 0xFFFFFF));
+ SMTC_write2Dreg(DE_COLOR_COMPARE,
+ FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR, 0xFFFFFF));
+}
+
+void deVerticalLine(unsigned long dst_base,
+ unsigned long dst_pitch,
+ unsigned long nX,
+ unsigned long nY,
+ unsigned long dst_height, unsigned long nColor)
+{
+ deWaitForNotBusy();
+
+ SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+ FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
+ dst_base));
+
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) |
+ FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch));
+
+ SMTC_write2Dreg(DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH,
+ SOURCE,
+ dst_pitch));
+
+ SMTC_write2Dreg(DE_FOREGROUND,
+ FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
+
+ SMTC_write2Dreg(DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_DESTINATION, X, nX) |
+ FIELD_VALUE(0, DE_DESTINATION, Y, nY));
+
+ SMTC_write2Dreg(DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X, 1) |
+ FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
+
+ SMTC_write2Dreg(DE_CONTROL,
+ FIELD_SET(0, DE_CONTROL, STATUS, START) |
+ FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
+ FIELD_SET(0, DE_CONTROL, MAJOR, Y) |
+ FIELD_SET(0, DE_CONTROL, STEP_X, NEGATIVE) |
+ FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) |
+ FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
+ FIELD_SET(0, DE_CONTROL, COMMAND, SHORT_STROKE) |
+ FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+ FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C));
+
+ smtc_de_busy = 1;
+}
+
+void deHorizontalLine(unsigned long dst_base,
+ unsigned long dst_pitch,
+ unsigned long nX,
+ unsigned long nY,
+ unsigned long dst_width, unsigned long nColor)
+{
+ deWaitForNotBusy();
+
+ SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+ FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
+ dst_base));
+
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) |
+ FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch));
+
+ SMTC_write2Dreg(DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH,
+ SOURCE,
+ dst_pitch));
+ SMTC_write2Dreg(DE_FOREGROUND,
+ FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
+ SMTC_write2Dreg(DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP,
+ DISABLE) | FIELD_VALUE(0, DE_DESTINATION, X,
+ nX) | FIELD_VALUE(0,
+ DE_DESTINATION,
+ Y,
+ nY));
+ SMTC_write2Dreg(DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X,
+ dst_width) | FIELD_VALUE(0, DE_DIMENSION,
+ Y_ET, 1));
+ SMTC_write2Dreg(DE_CONTROL,
+ FIELD_SET(0, DE_CONTROL, STATUS, START) | FIELD_SET(0,
+ DE_CONTROL,
+ DIRECTION,
+ RIGHT_TO_LEFT)
+ | FIELD_SET(0, DE_CONTROL, MAJOR, X) | FIELD_SET(0,
+ DE_CONTROL,
+ STEP_X,
+ POSITIVE)
+ | FIELD_SET(0, DE_CONTROL, STEP_Y,
+ NEGATIVE) | FIELD_SET(0, DE_CONTROL,
+ LAST_PIXEL,
+ OFF) | FIELD_SET(0,
+ DE_CONTROL,
+ COMMAND,
+ SHORT_STROKE)
+ | FIELD_SET(0, DE_CONTROL, ROP_SELECT,
+ ROP2) | FIELD_VALUE(0, DE_CONTROL, ROP,
+ 0x0C));
+
+ smtc_de_busy = 1;
+}
+
+void deLine(unsigned long dst_base,
+ unsigned long dst_pitch,
+ unsigned long nX1,
+ unsigned long nY1,
+ unsigned long nX2, unsigned long nY2, unsigned long nColor)
+{
+ unsigned long nCommand =
+ FIELD_SET(0, DE_CONTROL, STATUS, START) |
+ FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
+ FIELD_SET(0, DE_CONTROL, MAJOR, X) |
+ FIELD_SET(0, DE_CONTROL, STEP_X, POSITIVE) |
+ FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) |
+ FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
+ FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+ FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C);
+ unsigned long DeltaX;
+ unsigned long DeltaY;
+
+ /* Calculate delta X */
+ if (nX1 <= nX2)
+ DeltaX = nX2 - nX1;
+ else {
+ DeltaX = nX1 - nX2;
+ nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_X, NEGATIVE);
+ }
+
+ /* Calculate delta Y */
+ if (nY1 <= nY2)
+ DeltaY = nY2 - nY1;
+ else {
+ DeltaY = nY1 - nY2;
+ nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_Y, NEGATIVE);
+ }
+
+ /* Determine the major axis */
+ if (DeltaX < DeltaY)
+ nCommand = FIELD_SET(nCommand, DE_CONTROL, MAJOR, Y);
+
+ /* Vertical line? */
+ if (nX1 == nX2)
+ deVerticalLine(dst_base, dst_pitch, nX1, nY1, DeltaY, nColor);
+
+ /* Horizontal line? */
+ else if (nY1 == nY2)
+ deHorizontalLine(dst_base, dst_pitch, nX1, nY1, \
+ DeltaX, nColor);
+
+ /* Diagonal line? */
+ else if (DeltaX == DeltaY) {
+ deWaitForNotBusy();
+
+ SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+ FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE,
+ ADDRESS, dst_base));
+
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0,
+ DE_PITCH,
+ SOURCE,
+ dst_pitch));
+
+ SMTC_write2Dreg(DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0,
+ DE_WINDOW_WIDTH,
+ SOURCE,
+ dst_pitch));
+
+ SMTC_write2Dreg(DE_FOREGROUND,
+ FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
+
+ SMTC_write2Dreg(DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_DESTINATION, X, 1) |
+ FIELD_VALUE(0, DE_DESTINATION, Y, nY1));
+
+ SMTC_write2Dreg(DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X, 1) |
+ FIELD_VALUE(0, DE_DIMENSION, Y_ET, DeltaX));
+
+ SMTC_write2Dreg(DE_CONTROL,
+ FIELD_SET(nCommand, DE_CONTROL, COMMAND,
+ SHORT_STROKE));
+ }
+
+ /* Generic line */
+ else {
+ unsigned int k1, k2, et, w;
+ if (DeltaX < DeltaY) {
+ k1 = 2 * DeltaX;
+ et = k1 - DeltaY;
+ k2 = et - DeltaY;
+ w = DeltaY + 1;
+ } else {
+ k1 = 2 * DeltaY;
+ et = k1 - DeltaX;
+ k2 = et - DeltaX;
+ w = DeltaX + 1;
+ }
+
+ deWaitForNotBusy();
+
+ SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+ FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE,
+ ADDRESS, dst_base));
+
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0,
+ DE_PITCH,
+ SOURCE,
+ dst_pitch));
+
+ SMTC_write2Dreg(DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0,
+ DE_WINDOW_WIDTH,
+ SOURCE,
+ dst_pitch));
+
+ SMTC_write2Dreg(DE_FOREGROUND,
+ FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
+
+ SMTC_write2Dreg(DE_SOURCE,
+ FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_SOURCE, X_K1, k1) |
+ FIELD_VALUE(0, DE_SOURCE, Y_K2, k2));
+
+ SMTC_write2Dreg(DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_DESTINATION, X, nX1) |
+ FIELD_VALUE(0, DE_DESTINATION, Y, nY1));
+
+ SMTC_write2Dreg(DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X, w) |
+ FIELD_VALUE(0, DE_DIMENSION, Y_ET, et));
+
+ SMTC_write2Dreg(DE_CONTROL,
+ FIELD_SET(nCommand, DE_CONTROL, COMMAND,
+ LINE_DRAW));
+ }
+
+ smtc_de_busy = 1;
+}
+
+void deFillRect(unsigned long dst_base,
+ unsigned long dst_pitch,
+ unsigned long dst_X,
+ unsigned long dst_Y,
+ unsigned long dst_width,
+ unsigned long dst_height, unsigned long nColor)
+{
+ deWaitForNotBusy();
+
+ SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+ FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
+ dst_base));
+
+ if (dst_pitch) {
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0,
+ DE_PITCH,
+ SOURCE,
+ dst_pitch));
+
+ SMTC_write2Dreg(DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0,
+ DE_WINDOW_WIDTH,
+ SOURCE,
+ dst_pitch));
+ }
+
+ SMTC_write2Dreg(DE_FOREGROUND,
+ FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
+
+ SMTC_write2Dreg(DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_DESTINATION, X, dst_X) |
+ FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y));
+
+ SMTC_write2Dreg(DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X, dst_width) |
+ FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
+
+ SMTC_write2Dreg(DE_CONTROL,
+ FIELD_SET(0, DE_CONTROL, STATUS, START) |
+ FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
+ FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
+ FIELD_SET(0, DE_CONTROL, COMMAND, RECTANGLE_FILL) |
+ FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+ FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C));
+
+ smtc_de_busy = 1;
+}
+
+/**********************************************************************
+ *
+ * deRotatePattern
+ *
+ * Purpose
+ * Rotate the given pattern if necessary
+ *
+ * Parameters
+ * [in]
+ * pPattern - Pointer to DE_SURFACE structure containing
+ * pattern attributes
+ * patternX - X position (0-7) of pattern origin
+ * patternY - Y position (0-7) of pattern origin
+ *
+ * [out]
+ * pattern_dstaddr - Pointer to pre-allocated buffer containing
+ * rotated pattern
+ *
+ **********************************************************************/
+void deRotatePattern(unsigned char *pattern_dstaddr,
+ unsigned long pattern_src_addr,
+ unsigned long pattern_BPP,
+ unsigned long pattern_stride, int patternX, int patternY)
+{
+ unsigned int i;
+ unsigned long pattern[PATTERN_WIDTH * PATTERN_HEIGHT];
+ unsigned int x, y;
+ unsigned char *pjPatByte;
+
+ if (pattern_dstaddr != NULL) {
+ deWaitForNotBusy();
+
+ if (patternX || patternY) {
+ /* Rotate pattern */
+ pjPatByte = (unsigned char *)pattern;
+
+ switch (pattern_BPP) {
+ case 8:
+ {
+ for (y = 0; y < 8; y++) {
+ unsigned char *pjBuffer =
+ pattern_dstaddr +
+ ((patternY + y) & 7) * 8;
+ for (x = 0; x < 8; x++) {
+ pjBuffer[(patternX +
+ x) & 7] =
+ pjPatByte[x];
+ }
+ pjPatByte += pattern_stride;
+ }
+ break;
+ }
+
+ case 16:
+ {
+ for (y = 0; y < 8; y++) {
+ unsigned short *pjBuffer =
+ (unsigned short *)
+ pattern_dstaddr +
+ ((patternY + y) & 7) * 8;
+ for (x = 0; x < 8; x++) {
+ pjBuffer[(patternX +
+ x) & 7] =
+ ((unsigned short *)
+ pjPatByte)[x];
+ }
+ pjPatByte += pattern_stride;
+ }
+ break;
+ }
+
+ case 32:
+ {
+ for (y = 0; y < 8; y++) {
+ unsigned long *pjBuffer =
+ (unsigned long *)
+ pattern_dstaddr +
+ ((patternY + y) & 7) * 8;
+ for (x = 0; x < 8; x++) {
+ pjBuffer[(patternX +
+ x) & 7] =
+ ((unsigned long *)
+ pjPatByte)[x];
+ }
+ pjPatByte += pattern_stride;
+ }
+ break;
+ }
+ }
+ } else {
+ /*Don't rotate,just copy pattern into pattern_dstaddr*/
+ for (i = 0; i < (pattern_BPP * 2); i++) {
+ ((unsigned long *)pattern_dstaddr)[i] =
+ pattern[i];
+ }
+ }
+
+ }
+}
+
+/**********************************************************************
+ *
+ * deCopy
+ *
+ * Purpose
+ * Copy a rectangular area of the source surface to a destination surface
+ *
+ * Remarks
+ * Source bitmap must have the same color depth (BPP) as the destination
+ * bitmap.
+ *
+**********************************************************************/
+void deCopy(unsigned long dst_base,
+ unsigned long dst_pitch,
+ unsigned long dst_BPP,
+ unsigned long dst_X,
+ unsigned long dst_Y,
+ unsigned long dst_width,
+ unsigned long dst_height,
+ unsigned long src_base,
+ unsigned long src_pitch,
+ unsigned long src_X,
+ unsigned long src_Y, pTransparent pTransp, unsigned char nROP2)
+{
+ unsigned long nDirection = 0;
+ unsigned long nTransparent = 0;
+ /* Direction of ROP2 operation:
+ * 1 = Left to Right,
+ * (-1) = Right to Left
+ */
+ unsigned long opSign = 1;
+ /* xWidth is in pixels */
+ unsigned long xWidth = 192 / (dst_BPP / 8);
+ unsigned long de_ctrl = 0;
+
+ deWaitForNotBusy();
+
+ SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+ FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
+ dst_base));
+
+ SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE,
+ FIELD_VALUE(0, DE_WINDOW_SOURCE_BASE, ADDRESS,
+ src_base));
+
+ if (dst_pitch && src_pitch) {
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0,
+ DE_PITCH,
+ SOURCE,
+ src_pitch));
+
+ SMTC_write2Dreg(DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0,
+ DE_WINDOW_WIDTH,
+ SOURCE,
+ src_pitch));
+ }
+
+ /* Set transparent bits if necessary */
+ if (pTransp != NULL) {
+ nTransparent =
+ pTransp->match | pTransp->select | pTransp->control;
+
+ /* Set color compare register */
+ SMTC_write2Dreg(DE_COLOR_COMPARE,
+ FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR,
+ pTransp->color));
+ }
+
+ /* Determine direction of operation */
+ if (src_Y < dst_Y) {
+ /* +----------+
+ |S |
+ | +----------+
+ | | | |
+ | | | |
+ +---|------+ |
+ | D |
+ +----------+ */
+
+ nDirection = BOTTOM_TO_TOP;
+ } else if (src_Y > dst_Y) {
+ /* +----------+
+ |D |
+ | +----------+
+ | | | |
+ | | | |
+ +---|------+ |
+ | S |
+ +----------+ */
+
+ nDirection = TOP_TO_BOTTOM;
+ } else {
+ /* src_Y == dst_Y */
+
+ if (src_X <= dst_X) {
+ /* +------+---+------+
+ |S | | D|
+ | | | |
+ | | | |
+ | | | |
+ +------+---+------+ */
+
+ nDirection = RIGHT_TO_LEFT;
+ } else {
+ /* src_X > dst_X */
+
+ /* +------+---+------+
+ |D | | S|
+ | | | |
+ | | | |
+ | | | |
+ +------+---+------+ */
+
+ nDirection = LEFT_TO_RIGHT;
+ }
+ }
+
+ if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) {
+ src_X += dst_width - 1;
+ src_Y += dst_height - 1;
+ dst_X += dst_width - 1;
+ dst_Y += dst_height - 1;
+ opSign = (-1);
+ }
+
+ if (dst_BPP >= 24) {
+ src_X *= 3;
+ src_Y *= 3;
+ dst_X *= 3;
+ dst_Y *= 3;
+ dst_width *= 3;
+ if ((nDirection == BOTTOM_TO_TOP)
+ || (nDirection == RIGHT_TO_LEFT)) {
+ src_X += 2;
+ dst_X += 2;
+ }
+ }
+
+ /* Workaround for 192 byte hw bug */
+ if ((nROP2 != 0x0C) && ((dst_width * (dst_BPP / 8)) >= 192)) {
+ /*
+ * Perform the ROP2 operation in chunks of (xWidth *
+ * dst_height)
+ */
+ while (1) {
+ deWaitForNotBusy();
+
+ SMTC_write2Dreg(DE_SOURCE,
+ FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) |
+ FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y));
+
+ SMTC_write2Dreg(DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP,
+ DISABLE) | FIELD_VALUE(0,
+ DE_DESTINATION,
+ X,
+ dst_X)
+ | FIELD_VALUE(0, DE_DESTINATION, Y,
+ dst_Y));
+
+ SMTC_write2Dreg(DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X,
+ xWidth) | FIELD_VALUE(0,
+ DE_DIMENSION,
+ Y_ET,
+ dst_height));
+
+ de_ctrl =
+ FIELD_VALUE(0, DE_CONTROL, ROP,
+ nROP2) | nTransparent | FIELD_SET(0,
+ DE_CONTROL,
+ ROP_SELECT,
+ ROP2)
+ | FIELD_SET(0, DE_CONTROL, COMMAND,
+ BITBLT) | ((nDirection ==
+ 1) ? FIELD_SET(0,
+ DE_CONTROL,
+ DIRECTION,
+ RIGHT_TO_LEFT)
+ : FIELD_SET(0, DE_CONTROL,
+ DIRECTION,
+ LEFT_TO_RIGHT)) |
+ FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+ SMTC_write2Dreg(DE_CONTROL, de_ctrl);
+
+ src_X += (opSign * xWidth);
+ dst_X += (opSign * xWidth);
+ dst_width -= xWidth;
+
+ if (dst_width <= 0) {
+ /* ROP2 operation is complete */
+ break;
+ }
+
+ if (xWidth > dst_width)
+ xWidth = dst_width;
+ }
+ } else {
+ deWaitForNotBusy();
+ SMTC_write2Dreg(DE_SOURCE,
+ FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) |
+ FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y));
+
+ SMTC_write2Dreg(DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_DESTINATION, X, dst_X) |
+ FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y));
+
+ SMTC_write2Dreg(DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X, dst_width) |
+ FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
+
+ de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, nROP2) |
+ nTransparent |
+ FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+ FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
+ ((nDirection == 1) ? FIELD_SET(0, DE_CONTROL, DIRECTION,
+ RIGHT_TO_LEFT)
+ : FIELD_SET(0, DE_CONTROL, DIRECTION,
+ LEFT_TO_RIGHT)) | FIELD_SET(0, DE_CONTROL,
+ STATUS, START);
+ SMTC_write2Dreg(DE_CONTROL, de_ctrl);
+ }
+
+ smtc_de_busy = 1;
+}
+
+/*
+ * This function sets the pixel format that will apply to the 2D Engine.
+ */
+void deSetPixelFormat(unsigned long bpp)
+{
+ unsigned long de_format;
+
+ de_format = SMTC_read2Dreg(DE_STRETCH_FORMAT);
+
+ switch (bpp) {
+ case 8:
+ de_format =
+ FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 8);
+ break;
+ default:
+ case 16:
+ de_format =
+ FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 16);
+ break;
+ case 32:
+ de_format =
+ FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 32);
+ break;
+ }
+
+ SMTC_write2Dreg(DE_STRETCH_FORMAT, de_format);
+}
+
+/*
+ * System memory to Video memory monochrome expansion.
+ *
+ * Source is monochrome image in system memory. This function expands the
+ * monochrome data to color image in video memory.
+ */
+
+long deSystemMem2VideoMemMonoBlt(const char *pSrcbuf,
+ long srcDelta,
+ unsigned long startBit,
+ unsigned long dBase,
+ unsigned long dPitch,
+ unsigned long bpp,
+ unsigned long dx, unsigned long dy,
+ unsigned long width, unsigned long height,
+ unsigned long fColor,
+ unsigned long bColor,
+ unsigned long rop2) {
+ unsigned long bytePerPixel;
+ unsigned long ulBytesPerScan;
+ unsigned long ul4BytesPerScan;
+ unsigned long ulBytesRemain;
+ unsigned long de_ctrl = 0;
+ unsigned char ajRemain[4];
+ long i, j;
+
+ bytePerPixel = bpp / 8;
+
+ /* Just make sure the start bit is within legal range */
+ startBit &= 7;
+
+ ulBytesPerScan = (width + startBit + 7) / 8;
+ ul4BytesPerScan = ulBytesPerScan & ~3;
+ ulBytesRemain = ulBytesPerScan & 3;
+
+ if (smtc_de_busy)
+ deWaitForNotBusy();
+
+ /*
+ * 2D Source Base. Use 0 for HOST Blt.
+ */
+
+ SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE, 0);
+
+ /*
+ * 2D Destination Base.
+ *
+ * It is an address offset (128 bit aligned) from the beginning of
+ * frame buffer.
+ */
+
+ SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, dBase);
+
+ if (dPitch) {
+
+ /*
+ * Program pitch (distance between the 1st points of two
+ * adjacent lines).
+ *
+ * Note that input pitch is BYTE value, but the 2D Pitch
+ * register uses pixel values. Need Byte to pixel convertion.
+ */
+
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION,
+ dPitch /
+ bytePerPixel) | FIELD_VALUE(0,
+ DE_PITCH,
+ SOURCE,
+ dPitch /
+ bytePerPixel));
+
+ /* Screen Window width in Pixels.
+ *
+ * 2D engine uses this value to calculate the linear address in
+ * frame buffer for a given point.
+ */
+
+ SMTC_write2Dreg(DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ (dPitch /
+ bytePerPixel)) | FIELD_VALUE(0,
+ DE_WINDOW_WIDTH,
+ SOURCE,
+ (dPitch
+ /
+ bytePerPixel)));
+ }
+ /* Note: For 2D Source in Host Write, only X_K1 field is needed, and
+ * Y_K2 field is not used. For mono bitmap, use startBit for X_K1.
+ */
+
+ SMTC_write2Dreg(DE_SOURCE,
+ FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_SOURCE, X_K1, startBit) |
+ FIELD_VALUE(0, DE_SOURCE, Y_K2, 0));
+
+ SMTC_write2Dreg(DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_DESTINATION, X, dx) |
+ FIELD_VALUE(0, DE_DESTINATION, Y, dy));
+
+ SMTC_write2Dreg(DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X, width) |
+ FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+ SMTC_write2Dreg(DE_FOREGROUND, fColor);
+ SMTC_write2Dreg(DE_BACKGROUND, bColor);
+
+ if (bpp)
+ deSetPixelFormat(bpp);
+ /* Set the pixel format of the destination */
+
+ de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
+ FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+ FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) |
+ FIELD_SET(0, DE_CONTROL, HOST, MONO) |
+ FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+ SMTC_write2Dreg(DE_CONTROL, de_ctrl | deGetTransparency());
+
+ /* Write MONO data (line by line) to 2D Engine data port */
+ for (i = 0; i < height; i++) {
+ /* For each line, send the data in chunks of 4 bytes */
+ for (j = 0; j < (ul4BytesPerScan / 4); j++)
+ SMTC_write2Ddataport(0,
+ *(unsigned long *)(pSrcbuf +
+ (j * 4)));
+
+ if (ulBytesRemain) {
+ memcpy(ajRemain, pSrcbuf + ul4BytesPerScan,
+ ulBytesRemain);
+ SMTC_write2Ddataport(0, *(unsigned long *)ajRemain);
+ }
+
+ pSrcbuf += srcDelta;
+ }
+ smtc_de_busy = 1;
+
+ return 0;
+}
+
+/*
+ * This function gets the transparency status from DE_CONTROL register.
+ * It returns a double word with the transparent fields properly set,
+ * while other fields are 0.
+ */
+unsigned long deGetTransparency(void)
+{
+ unsigned long de_ctrl;
+
+ de_ctrl = SMTC_read2Dreg(DE_CONTROL);
+
+ de_ctrl &=
+ FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) |
+ FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT) |
+ FIELD_MASK(DE_CONTROL_TRANSPARENCY);
+
+ return de_ctrl;
+}
diff --git a/drivers/staging/sm7xx/smtc2d.h b/drivers/staging/sm7xx/smtc2d.h
new file mode 100644
index 00000000000..38d0c335322
--- /dev/null
+++ b/drivers/staging/sm7xx/smtc2d.h
@@ -0,0 +1,530 @@
+/*
+ * Silicon Motion SM712 2D drawing engine functions.
+ *
+ * Copyright (C) 2006 Silicon Motion Technology Corp.
+ * Author: Ge Wang, gewang@siliconmotion.com
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzj@lemote.com
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Internal macros */
+
+#define _F_START(f) (0 ? f)
+#define _F_END(f) (1 ? f)
+#define _F_SIZE(f) (1 + _F_END(f) - _F_START(f))
+#define _F_MASK(f) (((1ULL << _F_SIZE(f)) - 1) << _F_START(f))
+#define _F_NORMALIZE(v, f) (((v) & _F_MASK(f)) >> _F_START(f))
+#define _F_DENORMALIZE(v, f) (((v) << _F_START(f)) & _F_MASK(f))
+
+/* Global macros */
+
+#define FIELD_GET(x, reg, field) \
+( \
+ _F_NORMALIZE((x), reg ## _ ## field) \
+)
+
+#define FIELD_SET(x, reg, field, value) \
+( \
+ (x & ~_F_MASK(reg ## _ ## field)) \
+ | _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \
+)
+
+#define FIELD_VALUE(x, reg, field, value) \
+( \
+ (x & ~_F_MASK(reg ## _ ## field)) \
+ | _F_DENORMALIZE(value, reg ## _ ## field) \
+)
+
+#define FIELD_CLEAR(reg, field) \
+( \
+ ~_F_MASK(reg ## _ ## field) \
+)
+
+/* Field Macros */
+
+#define FIELD_START(field) (0 ? field)
+#define FIELD_END(field) (1 ? field)
+#define FIELD_SIZE(field) \
+ (1 + FIELD_END(field) - FIELD_START(field))
+
+#define FIELD_MASK(field) \
+ (((1 << (FIELD_SIZE(field)-1)) \
+ | ((1 << (FIELD_SIZE(field)-1)) - 1)) \
+ << FIELD_START(field))
+
+#define FIELD_NORMALIZE(reg, field) \
+ (((reg) & FIELD_MASK(field)) >> FIELD_START(field))
+
+#define FIELD_DENORMALIZE(field, value) \
+ (((value) << FIELD_START(field)) & FIELD_MASK(field))
+
+#define FIELD_INIT(reg, field, value) \
+ FIELD_DENORMALIZE(reg ## _ ## field, \
+ reg ## _ ## field ## _ ## value)
+
+#define FIELD_INIT_VAL(reg, field, value) \
+ (FIELD_DENORMALIZE(reg ## _ ## field, value))
+
+#define FIELD_VAL_SET(x, r, f, v) ({ \
+ x = (x & ~FIELD_MASK(r ## _ ## f)) \
+ | FIELD_DENORMALIZE(r ## _ ## f, r ## _ ## f ## _ ## v) \
+})
+
+#define RGB(r, g, b) ((unsigned long)(((r) << 16) | ((g) << 8) | (b)))
+
+/* Transparent info definition */
+typedef struct {
+ unsigned long match; /* Matching pixel is OPAQUE/TRANSPARENT */
+ unsigned long select; /* Transparency controlled by SRC/DST */
+ unsigned long control; /* ENABLE/DISABLE transparency */
+ unsigned long color; /* Transparent color */
+} Transparent, *pTransparent;
+
+#define PIXEL_DEPTH_1_BP 0 /* 1 bit per pixel */
+#define PIXEL_DEPTH_8_BPP 1 /* 8 bits per pixel */
+#define PIXEL_DEPTH_16_BPP 2 /* 16 bits per pixel */
+#define PIXEL_DEPTH_32_BPP 3 /* 32 bits per pixel */
+#define PIXEL_DEPTH_YUV422 8 /* 16 bits per pixel YUV422 */
+#define PIXEL_DEPTH_YUV420 9 /* 16 bits per pixel YUV420 */
+
+#define PATTERN_WIDTH 8
+#define PATTERN_HEIGHT 8
+
+#define TOP_TO_BOTTOM 0
+#define BOTTOM_TO_TOP 1
+#define RIGHT_TO_LEFT BOTTOM_TO_TOP
+#define LEFT_TO_RIGHT TOP_TO_BOTTOM
+
+/* Constants used in Transparent structure */
+#define MATCH_OPAQUE 0x00000000
+#define MATCH_TRANSPARENT 0x00000400
+#define SOURCE 0x00000000
+#define DESTINATION 0x00000200
+
+/* 2D registers. */
+
+#define DE_SOURCE 0x000000
+#define DE_SOURCE_WRAP 31 : 31
+#define DE_SOURCE_WRAP_DISABLE 0
+#define DE_SOURCE_WRAP_ENABLE 1
+#define DE_SOURCE_X_K1 29 : 16
+#define DE_SOURCE_Y_K2 15 : 0
+
+#define DE_DESTINATION 0x000004
+#define DE_DESTINATION_WRAP 31 : 31
+#define DE_DESTINATION_WRAP_DISABLE 0
+#define DE_DESTINATION_WRAP_ENABLE 1
+#define DE_DESTINATION_X 28 : 16
+#define DE_DESTINATION_Y 15 : 0
+
+#define DE_DIMENSION 0x000008
+#define DE_DIMENSION_X 28 : 16
+#define DE_DIMENSION_Y_ET 15 : 0
+
+#define DE_CONTROL 0x00000C
+#define DE_CONTROL_STATUS 31 : 31
+#define DE_CONTROL_STATUS_STOP 0
+#define DE_CONTROL_STATUS_START 1
+#define DE_CONTROL_PATTERN 30 : 30
+#define DE_CONTROL_PATTERN_MONO 0
+#define DE_CONTROL_PATTERN_COLOR 1
+#define DE_CONTROL_UPDATE_DESTINATION_X 29 : 29
+#define DE_CONTROL_UPDATE_DESTINATION_X_DISABLE 0
+#define DE_CONTROL_UPDATE_DESTINATION_X_ENABLE 1
+#define DE_CONTROL_QUICK_START 28 : 28
+#define DE_CONTROL_QUICK_START_DISABLE 0
+#define DE_CONTROL_QUICK_START_ENABLE 1
+#define DE_CONTROL_DIRECTION 27 : 27
+#define DE_CONTROL_DIRECTION_LEFT_TO_RIGHT 0
+#define DE_CONTROL_DIRECTION_RIGHT_TO_LEFT 1
+#define DE_CONTROL_MAJOR 26 : 26
+#define DE_CONTROL_MAJOR_X 0
+#define DE_CONTROL_MAJOR_Y 1
+#define DE_CONTROL_STEP_X 25 : 25
+#define DE_CONTROL_STEP_X_POSITIVE 1
+#define DE_CONTROL_STEP_X_NEGATIVE 0
+#define DE_CONTROL_STEP_Y 24 : 24
+#define DE_CONTROL_STEP_Y_POSITIVE 1
+#define DE_CONTROL_STEP_Y_NEGATIVE 0
+#define DE_CONTROL_STRETCH 23 : 23
+#define DE_CONTROL_STRETCH_DISABLE 0
+#define DE_CONTROL_STRETCH_ENABLE 1
+#define DE_CONTROL_HOST 22 : 22
+#define DE_CONTROL_HOST_COLOR 0
+#define DE_CONTROL_HOST_MONO 1
+#define DE_CONTROL_LAST_PIXEL 21 : 21
+#define DE_CONTROL_LAST_PIXEL_OFF 0
+#define DE_CONTROL_LAST_PIXEL_ON 1
+#define DE_CONTROL_COMMAND 20 : 16
+#define DE_CONTROL_COMMAND_BITBLT 0
+#define DE_CONTROL_COMMAND_RECTANGLE_FILL 1
+#define DE_CONTROL_COMMAND_DE_TILE 2
+#define DE_CONTROL_COMMAND_TRAPEZOID_FILL 3
+#define DE_CONTROL_COMMAND_ALPHA_BLEND 4
+#define DE_CONTROL_COMMAND_RLE_STRIP 5
+#define DE_CONTROL_COMMAND_SHORT_STROKE 6
+#define DE_CONTROL_COMMAND_LINE_DRAW 7
+#define DE_CONTROL_COMMAND_HOST_WRITE 8
+#define DE_CONTROL_COMMAND_HOST_READ 9
+#define DE_CONTROL_COMMAND_HOST_WRITE_BOTTOM_UP 10
+#define DE_CONTROL_COMMAND_ROTATE 11
+#define DE_CONTROL_COMMAND_FONT 12
+#define DE_CONTROL_COMMAND_TEXTURE_LOAD 15
+#define DE_CONTROL_ROP_SELECT 15 : 15
+#define DE_CONTROL_ROP_SELECT_ROP3 0
+#define DE_CONTROL_ROP_SELECT_ROP2 1
+#define DE_CONTROL_ROP2_SOURCE 14 : 14
+#define DE_CONTROL_ROP2_SOURCE_BITMAP 0
+#define DE_CONTROL_ROP2_SOURCE_PATTERN 1
+#define DE_CONTROL_MONO_DATA 13 : 12
+#define DE_CONTROL_MONO_DATA_NOT_PACKED 0
+#define DE_CONTROL_MONO_DATA_8_PACKED 1
+#define DE_CONTROL_MONO_DATA_16_PACKED 2
+#define DE_CONTROL_MONO_DATA_32_PACKED 3
+#define DE_CONTROL_REPEAT_ROTATE 11 : 11
+#define DE_CONTROL_REPEAT_ROTATE_DISABLE 0
+#define DE_CONTROL_REPEAT_ROTATE_ENABLE 1
+#define DE_CONTROL_TRANSPARENCY_MATCH 10 : 10
+#define DE_CONTROL_TRANSPARENCY_MATCH_OPAQUE 0
+#define DE_CONTROL_TRANSPARENCY_MATCH_TRANSPARENT 1
+#define DE_CONTROL_TRANSPARENCY_SELECT 9 : 9
+#define DE_CONTROL_TRANSPARENCY_SELECT_SOURCE 0
+#define DE_CONTROL_TRANSPARENCY_SELECT_DESTINATION 1
+#define DE_CONTROL_TRANSPARENCY 8 : 8
+#define DE_CONTROL_TRANSPARENCY_DISABLE 0
+#define DE_CONTROL_TRANSPARENCY_ENABLE 1
+#define DE_CONTROL_ROP 7 : 0
+
+/* Pseudo fields. */
+
+#define DE_CONTROL_SHORT_STROKE_DIR 27 : 24
+#define DE_CONTROL_SHORT_STROKE_DIR_225 0
+#define DE_CONTROL_SHORT_STROKE_DIR_135 1
+#define DE_CONTROL_SHORT_STROKE_DIR_315 2
+#define DE_CONTROL_SHORT_STROKE_DIR_45 3
+#define DE_CONTROL_SHORT_STROKE_DIR_270 4
+#define DE_CONTROL_SHORT_STROKE_DIR_90 5
+#define DE_CONTROL_SHORT_STROKE_DIR_180 8
+#define DE_CONTROL_SHORT_STROKE_DIR_0 10
+#define DE_CONTROL_ROTATION 25 : 24
+#define DE_CONTROL_ROTATION_0 0
+#define DE_CONTROL_ROTATION_270 1
+#define DE_CONTROL_ROTATION_90 2
+#define DE_CONTROL_ROTATION_180 3
+
+#define DE_PITCH 0x000010
+#define DE_PITCH_DESTINATION 28 : 16
+#define DE_PITCH_SOURCE 12 : 0
+
+#define DE_FOREGROUND 0x000014
+#define DE_FOREGROUND_COLOR 31 : 0
+
+#define DE_BACKGROUND 0x000018
+#define DE_BACKGROUND_COLOR 31 : 0
+
+#define DE_STRETCH_FORMAT 0x00001C
+#define DE_STRETCH_FORMAT_PATTERN_XY 30 : 30
+#define DE_STRETCH_FORMAT_PATTERN_XY_NORMAL 0
+#define DE_STRETCH_FORMAT_PATTERN_XY_OVERWRITE 1
+#define DE_STRETCH_FORMAT_PATTERN_Y 29 : 27
+#define DE_STRETCH_FORMAT_PATTERN_X 25 : 23
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT 21 : 20
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_8 0
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_16 1
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_24 3
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_32 2
+#define DE_STRETCH_FORMAT_ADDRESSING 19 : 16
+#define DE_STRETCH_FORMAT_ADDRESSING_XY 0
+#define DE_STRETCH_FORMAT_ADDRESSING_LINEAR 15
+#define DE_STRETCH_FORMAT_SOURCE_HEIGHT 11 : 0
+
+#define DE_COLOR_COMPARE 0x000020
+#define DE_COLOR_COMPARE_COLOR 23 : 0
+
+#define DE_COLOR_COMPARE_MASK 0x000024
+#define DE_COLOR_COMPARE_MASK_MASKS 23 : 0
+
+#define DE_MASKS 0x000028
+#define DE_MASKS_BYTE_MASK 31 : 16
+#define DE_MASKS_BIT_MASK 15 : 0
+
+#define DE_CLIP_TL 0x00002C
+#define DE_CLIP_TL_TOP 31 : 16
+#define DE_CLIP_TL_STATUS 13 : 13
+#define DE_CLIP_TL_STATUS_DISABLE 0
+#define DE_CLIP_TL_STATUS_ENABLE 1
+#define DE_CLIP_TL_INHIBIT 12 : 12
+#define DE_CLIP_TL_INHIBIT_OUTSIDE 0
+#define DE_CLIP_TL_INHIBIT_INSIDE 1
+#define DE_CLIP_TL_LEFT 11 : 0
+
+#define DE_CLIP_BR 0x000030
+#define DE_CLIP_BR_BOTTOM 31 : 16
+#define DE_CLIP_BR_RIGHT 12 : 0
+
+#define DE_MONO_PATTERN_LOW 0x000034
+#define DE_MONO_PATTERN_LOW_PATTERN 31 : 0
+
+#define DE_MONO_PATTERN_HIGH 0x000038
+#define DE_MONO_PATTERN_HIGH_PATTERN 31 : 0
+
+#define DE_WINDOW_WIDTH 0x00003C
+#define DE_WINDOW_WIDTH_DESTINATION 28 : 16
+#define DE_WINDOW_WIDTH_SOURCE 12 : 0
+
+#define DE_WINDOW_SOURCE_BASE 0x000040
+#define DE_WINDOW_SOURCE_BASE_EXT 27 : 27
+#define DE_WINDOW_SOURCE_BASE_EXT_LOCAL 0
+#define DE_WINDOW_SOURCE_BASE_EXT_EXTERNAL 1
+#define DE_WINDOW_SOURCE_BASE_CS 26 : 26
+#define DE_WINDOW_SOURCE_BASE_CS_0 0
+#define DE_WINDOW_SOURCE_BASE_CS_1 1
+#define DE_WINDOW_SOURCE_BASE_ADDRESS 25 : 0
+
+#define DE_WINDOW_DESTINATION_BASE 0x000044
+#define DE_WINDOW_DESTINATION_BASE_EXT 27 : 27
+#define DE_WINDOW_DESTINATION_BASE_EXT_LOCAL 0
+#define DE_WINDOW_DESTINATION_BASE_EXT_EXTERNAL 1
+#define DE_WINDOW_DESTINATION_BASE_CS 26 : 26
+#define DE_WINDOW_DESTINATION_BASE_CS_0 0
+#define DE_WINDOW_DESTINATION_BASE_CS_1 1
+#define DE_WINDOW_DESTINATION_BASE_ADDRESS 25 : 0
+
+#define DE_ALPHA 0x000048
+#define DE_ALPHA_VALUE 7 : 0
+
+#define DE_WRAP 0x00004C
+#define DE_WRAP_X 31 : 16
+#define DE_WRAP_Y 15 : 0
+
+#define DE_STATUS 0x000050
+#define DE_STATUS_CSC 1 : 1
+#define DE_STATUS_CSC_CLEAR 0
+#define DE_STATUS_CSC_NOT_ACTIVE 0
+#define DE_STATUS_CSC_ACTIVE 1
+#define DE_STATUS_2D 0 : 0
+#define DE_STATUS_2D_CLEAR 0
+#define DE_STATUS_2D_NOT_ACTIVE 0
+#define DE_STATUS_2D_ACTIVE 1
+
+/* Color Space Conversion registers. */
+
+#define CSC_Y_SOURCE_BASE 0x0000C8
+#define CSC_Y_SOURCE_BASE_EXT 27 : 27
+#define CSC_Y_SOURCE_BASE_EXT_LOCAL 0
+#define CSC_Y_SOURCE_BASE_EXT_EXTERNAL 1
+#define CSC_Y_SOURCE_BASE_CS 26 : 26
+#define CSC_Y_SOURCE_BASE_CS_0 0
+#define CSC_Y_SOURCE_BASE_CS_1 1
+#define CSC_Y_SOURCE_BASE_ADDRESS 25 : 0
+
+#define CSC_CONSTANTS 0x0000CC
+#define CSC_CONSTANTS_Y 31 : 24
+#define CSC_CONSTANTS_R 23 : 16
+#define CSC_CONSTANTS_G 15 : 8
+#define CSC_CONSTANTS_B 7 : 0
+
+#define CSC_Y_SOURCE_X 0x0000D0
+#define CSC_Y_SOURCE_X_INTEGER 26 : 16
+#define CSC_Y_SOURCE_X_FRACTION 15 : 3
+
+#define CSC_Y_SOURCE_Y 0x0000D4
+#define CSC_Y_SOURCE_Y_INTEGER 27 : 16
+#define CSC_Y_SOURCE_Y_FRACTION 15 : 3
+
+#define CSC_U_SOURCE_BASE 0x0000D8
+#define CSC_U_SOURCE_BASE_EXT 27 : 27
+#define CSC_U_SOURCE_BASE_EXT_LOCAL 0
+#define CSC_U_SOURCE_BASE_EXT_EXTERNAL 1
+#define CSC_U_SOURCE_BASE_CS 26 : 26
+#define CSC_U_SOURCE_BASE_CS_0 0
+#define CSC_U_SOURCE_BASE_CS_1 1
+#define CSC_U_SOURCE_BASE_ADDRESS 25 : 0
+
+#define CSC_V_SOURCE_BASE 0x0000DC
+#define CSC_V_SOURCE_BASE_EXT 27 : 27
+#define CSC_V_SOURCE_BASE_EXT_LOCAL 0
+#define CSC_V_SOURCE_BASE_EXT_EXTERNAL 1
+#define CSC_V_SOURCE_BASE_CS 26 : 26
+#define CSC_V_SOURCE_BASE_CS_0 0
+#define CSC_V_SOURCE_BASE_CS_1 1
+#define CSC_V_SOURCE_BASE_ADDRESS 25 : 0
+
+#define CSC_SOURCE_DIMENSION 0x0000E0
+#define CSC_SOURCE_DIMENSION_X 31 : 16
+#define CSC_SOURCE_DIMENSION_Y 15 : 0
+
+#define CSC_SOURCE_PITCH 0x0000E4
+#define CSC_SOURCE_PITCH_Y 31 : 16
+#define CSC_SOURCE_PITCH_UV 15 : 0
+
+#define CSC_DESTINATION 0x0000E8
+#define CSC_DESTINATION_WRAP 31 : 31
+#define CSC_DESTINATION_WRAP_DISABLE 0
+#define CSC_DESTINATION_WRAP_ENABLE 1
+#define CSC_DESTINATION_X 27 : 16
+#define CSC_DESTINATION_Y 11 : 0
+
+#define CSC_DESTINATION_DIMENSION 0x0000EC
+#define CSC_DESTINATION_DIMENSION_X 31 : 16
+#define CSC_DESTINATION_DIMENSION_Y 15 : 0
+
+#define CSC_DESTINATION_PITCH 0x0000F0
+#define CSC_DESTINATION_PITCH_X 31 : 16
+#define CSC_DESTINATION_PITCH_Y 15 : 0
+
+#define CSC_SCALE_FACTOR 0x0000F4
+#define CSC_SCALE_FACTOR_HORIZONTAL 31 : 16
+#define CSC_SCALE_FACTOR_VERTICAL 15 : 0
+
+#define CSC_DESTINATION_BASE 0x0000F8
+#define CSC_DESTINATION_BASE_EXT 27 : 27
+#define CSC_DESTINATION_BASE_EXT_LOCAL 0
+#define CSC_DESTINATION_BASE_EXT_EXTERNAL 1
+#define CSC_DESTINATION_BASE_CS 26 : 26
+#define CSC_DESTINATION_BASE_CS_0 0
+#define CSC_DESTINATION_BASE_CS_1 1
+#define CSC_DESTINATION_BASE_ADDRESS 25 : 0
+
+#define CSC_CONTROL 0x0000FC
+#define CSC_CONTROL_STATUS 31 : 31
+#define CSC_CONTROL_STATUS_STOP 0
+#define CSC_CONTROL_STATUS_START 1
+#define CSC_CONTROL_SOURCE_FORMAT 30 : 28
+#define CSC_CONTROL_SOURCE_FORMAT_YUV422 0
+#define CSC_CONTROL_SOURCE_FORMAT_YUV420I 1
+#define CSC_CONTROL_SOURCE_FORMAT_YUV420 2
+#define CSC_CONTROL_SOURCE_FORMAT_YVU9 3
+#define CSC_CONTROL_SOURCE_FORMAT_IYU1 4
+#define CSC_CONTROL_SOURCE_FORMAT_IYU2 5
+#define CSC_CONTROL_SOURCE_FORMAT_RGB565 6
+#define CSC_CONTROL_SOURCE_FORMAT_RGB8888 7
+#define CSC_CONTROL_DESTINATION_FORMAT 27 : 26
+#define CSC_CONTROL_DESTINATION_FORMAT_RGB565 0
+#define CSC_CONTROL_DESTINATION_FORMAT_RGB8888 1
+#define CSC_CONTROL_HORIZONTAL_FILTER 25 : 25
+#define CSC_CONTROL_HORIZONTAL_FILTER_DISABLE 0
+#define CSC_CONTROL_HORIZONTAL_FILTER_ENABLE 1
+#define CSC_CONTROL_VERTICAL_FILTER 24 : 24
+#define CSC_CONTROL_VERTICAL_FILTER_DISABLE 0
+#define CSC_CONTROL_VERTICAL_FILTER_ENABLE 1
+#define CSC_CONTROL_BYTE_ORDER 23 : 23
+#define CSC_CONTROL_BYTE_ORDER_YUYV 0
+#define CSC_CONTROL_BYTE_ORDER_UYVY 1
+
+#define DE_DATA_PORT_501 0x110000
+#define DE_DATA_PORT_712 0x400000
+#define DE_DATA_PORT_722 0x6000
+
+/* point to virtual Memory Map IO starting address */
+extern char *smtc_RegBaseAddress;
+/* point to virtual video memory starting address */
+extern char *smtc_VRAMBaseAddress;
+extern unsigned char smtc_de_busy;
+
+extern unsigned long memRead32(unsigned long nOffset);
+extern void memWrite32(unsigned long nOffset, unsigned long nData);
+extern unsigned long SMTC_read2Dreg(unsigned long nOffset);
+
+/* 2D functions */
+extern void deInit(unsigned int nModeWidth, unsigned int nModeHeight,
+ unsigned int bpp);
+
+extern void deWaitForNotBusy(void);
+
+extern void deVerticalLine(unsigned long dst_base,
+ unsigned long dst_pitch,
+ unsigned long nX,
+ unsigned long nY,
+ unsigned long dst_height,
+ unsigned long nColor);
+
+extern void deHorizontalLine(unsigned long dst_base,
+ unsigned long dst_pitch,
+ unsigned long nX,
+ unsigned long nY,
+ unsigned long dst_width,
+ unsigned long nColor);
+
+extern void deLine(unsigned long dst_base,
+ unsigned long dst_pitch,
+ unsigned long nX1,
+ unsigned long nY1,
+ unsigned long nX2,
+ unsigned long nY2,
+ unsigned long nColor);
+
+extern void deFillRect(unsigned long dst_base,
+ unsigned long dst_pitch,
+ unsigned long dst_X,
+ unsigned long dst_Y,
+ unsigned long dst_width,
+ unsigned long dst_height,
+ unsigned long nColor);
+
+extern void deRotatePattern(unsigned char *pattern_dstaddr,
+ unsigned long pattern_src_addr,
+ unsigned long pattern_BPP,
+ unsigned long pattern_stride,
+ int patternX,
+ int patternY);
+
+extern void deCopy(unsigned long dst_base,
+ unsigned long dst_pitch,
+ unsigned long dst_BPP,
+ unsigned long dst_X,
+ unsigned long dst_Y,
+ unsigned long dst_width,
+ unsigned long dst_height,
+ unsigned long src_base,
+ unsigned long src_pitch,
+ unsigned long src_X,
+ unsigned long src_Y,
+ pTransparent pTransp,
+ unsigned char nROP2);
+
+/*
+ * System memory to Video memory monochrome expansion.
+ *
+ * Source is monochrome image in system memory. This function expands the
+ * monochrome data to color image in video memory.
+ *
+ * @pSrcbuf: pointer to start of source buffer in system memory
+ * @srcDelta: Pitch value (in bytes) of the source buffer, +ive means top
+ * down and -ive mean button up
+ * @startBit: Mono data can start at any bit in a byte, this value should
+ * be 0 to 7
+ * @dBase: Address of destination : offset in frame buffer
+ * @dPitch: Pitch value of destination surface in BYTE
+ * @bpp: Color depth of destination surface
+ * @dx, dy: Starting coordinate of destination surface
+ * @width, height: width and height of rectange in pixel value
+ * @fColor,bColor: Foreground, Background color (corresponding to a 1, 0 in
+ * the monochrome data)
+ * @rop2: ROP value
+ */
+
+extern long deSystemMem2VideoMemMonoBlt(
+ const char *pSrcbuf,
+ long srcDelta,
+ unsigned long startBit,
+ unsigned long dBase,
+ unsigned long dPitch,
+ unsigned long bpp,
+ unsigned long dx, unsigned long dy,
+ unsigned long width, unsigned long height,
+ unsigned long fColor,
+ unsigned long bColor,
+ unsigned long rop2);
+
+extern unsigned long deGetTransparency(void);
+extern void deSetPixelFormat(unsigned long bpp);
diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c
new file mode 100644
index 00000000000..161dbc9c139
--- /dev/null
+++ b/drivers/staging/sm7xx/smtcfb.c
@@ -0,0 +1,1253 @@
+/*
+ * Silicon Motion SM7XX frame buffer device
+ *
+ * Copyright (C) 2006 Silicon Motion Technology Corp.
+ * Authors: Ge Wang, gewang@siliconmotion.com
+ * Boyod boyod.yang@siliconmotion.com.cn
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzj@lemote.com
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Version 0.10.26192.21.01
+ * - Add PowerPC/Big endian support
+ * - Add 2D support for Lynx
+ * - Verified on2.6.19.2 Boyod.yang <boyod.yang@siliconmotion.com.cn>
+ *
+ * Version 0.09.2621.00.01
+ * - Only support Linux Kernel's version 2.6.21.
+ * Boyod.yang <boyod.yang@siliconmotion.com.cn>
+ *
+ * Version 0.09
+ * - Only support Linux Kernel's version 2.6.12.
+ * Boyod.yang <boyod.yang@siliconmotion.com.cn>
+ */
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+
+#include <linux/io.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/console.h>
+#include <linux/screen_info.h>
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+struct screen_info smtc_screen_info;
+
+#include "smtcfb.h"
+#include "smtc2d.h"
+
+#ifdef DEBUG
+#define smdbg(format, arg...) printk(KERN_DEBUG format , ## arg)
+#else
+#define smdbg(format, arg...)
+#endif
+
+/*
+* Private structure
+*/
+struct smtcfb_info {
+ /*
+ * The following is a pointer to be passed into the
+ * functions below. The modules outside the main
+ * voyager.c driver have no knowledge as to what
+ * is within this structure.
+ */
+ struct fb_info fb;
+ struct display_switch *dispsw;
+ struct pci_dev *dev;
+ signed int currcon;
+
+ struct {
+ u8 red, green, blue;
+ } palette[NR_RGB];
+
+ u_int palette_size;
+};
+
+struct par_info {
+ /*
+ * Hardware
+ */
+ u16 chipID;
+ unsigned char __iomem *m_pMMIO;
+ char __iomem *m_pLFB;
+ char *m_pDPR;
+ char *m_pVPR;
+ char *m_pCPR;
+
+ u_int width;
+ u_int height;
+ u_int hz;
+ u_long BaseAddressInVRAM;
+ u8 chipRevID;
+};
+
+struct vesa_mode_table {
+ char mode_index[6];
+ u16 lfb_width;
+ u16 lfb_height;
+ u16 lfb_depth;
+};
+
+static struct vesa_mode_table vesa_mode[] = {
+ {"0x301", 640, 480, 8},
+ {"0x303", 800, 600, 8},
+ {"0x305", 1024, 768, 8},
+ {"0x307", 1280, 1024, 8},
+
+ {"0x311", 640, 480, 16},
+ {"0x314", 800, 600, 16},
+ {"0x317", 1024, 768, 16},
+ {"0x31A", 1280, 1024, 16},
+
+ {"0x312", 640, 480, 24},
+ {"0x315", 800, 600, 24},
+ {"0x318", 1024, 768, 24},
+ {"0x31B", 1280, 1024, 24},
+};
+
+char __iomem *smtc_RegBaseAddress; /* Memory Map IO starting address */
+char __iomem *smtc_VRAMBaseAddress; /* video memory starting address */
+
+char *smtc_2DBaseAddress; /* 2D engine starting address */
+char *smtc_2Ddataport; /* 2D data port offset */
+short smtc_2Dacceleration;
+
+static u32 colreg[17];
+static struct par_info hw; /* hardware information */
+
+u16 smtc_ChipIDs[] = {
+ 0x710,
+ 0x712,
+ 0x720
+};
+
+#define numSMTCchipIDs (sizeof(smtc_ChipIDs) / sizeof(u16))
+
+void deWaitForNotBusy(void)
+{
+ unsigned long i = 0x1000000;
+ while (i--) {
+ if ((smtc_seqr(0x16) & 0x18) == 0x10)
+ break;
+ }
+ smtc_de_busy = 0;
+}
+
+static void sm712_set_timing(struct smtcfb_info *sfb,
+ struct par_info *ppar_info)
+{
+ int i = 0, j = 0;
+ u32 m_nScreenStride;
+
+ smdbg("\nppar_info->width = %d ppar_info->height = %d"
+ "sfb->fb.var.bits_per_pixel = %d ppar_info->hz = %d\n",
+ ppar_info->width, ppar_info->height,
+ sfb->fb.var.bits_per_pixel, ppar_info->hz);
+
+ for (j = 0; j < numVGAModes; j++) {
+ if (VGAMode[j].mmSizeX == ppar_info->width &&
+ VGAMode[j].mmSizeY == ppar_info->height &&
+ VGAMode[j].bpp == sfb->fb.var.bits_per_pixel &&
+ VGAMode[j].hz == ppar_info->hz) {
+
+ smdbg("\nVGAMode[j].mmSizeX = %d VGAMode[j].mmSizeY ="
+ "%d VGAMode[j].bpp = %d"
+ "VGAMode[j].hz=%d\n",
+ VGAMode[j].mmSizeX, VGAMode[j].mmSizeY,
+ VGAMode[j].bpp, VGAMode[j].hz);
+
+ smdbg("VGAMode index=%d\n", j);
+
+ smtc_mmiowb(0x0, 0x3c6);
+
+ smtc_seqw(0, 0x1);
+
+ smtc_mmiowb(VGAMode[j].Init_MISC, 0x3c2);
+
+ /* init SEQ register SR00 - SR04 */
+ for (i = 0; i < SIZE_SR00_SR04; i++)
+ smtc_seqw(i, VGAMode[j].Init_SR00_SR04[i]);
+
+ /* init SEQ register SR10 - SR24 */
+ for (i = 0; i < SIZE_SR10_SR24; i++)
+ smtc_seqw(i + 0x10,
+ VGAMode[j].Init_SR10_SR24[i]);
+
+ /* init SEQ register SR30 - SR75 */
+ for (i = 0; i < SIZE_SR30_SR75; i++)
+ if (((i + 0x30) != 0x62) \
+ && ((i + 0x30) != 0x6a) \
+ && ((i + 0x30) != 0x6b))
+ smtc_seqw(i + 0x30,
+ VGAMode[j].Init_SR30_SR75[i]);
+
+ /* init SEQ register SR80 - SR93 */
+ for (i = 0; i < SIZE_SR80_SR93; i++)
+ smtc_seqw(i + 0x80,
+ VGAMode[j].Init_SR80_SR93[i]);
+
+ /* init SEQ register SRA0 - SRAF */
+ for (i = 0; i < SIZE_SRA0_SRAF; i++)
+ smtc_seqw(i + 0xa0,
+ VGAMode[j].Init_SRA0_SRAF[i]);
+
+ /* init Graphic register GR00 - GR08 */
+ for (i = 0; i < SIZE_GR00_GR08; i++)
+ smtc_grphw(i, VGAMode[j].Init_GR00_GR08[i]);
+
+ /* init Attribute register AR00 - AR14 */
+ for (i = 0; i < SIZE_AR00_AR14; i++)
+ smtc_attrw(i, VGAMode[j].Init_AR00_AR14[i]);
+
+ /* init CRTC register CR00 - CR18 */
+ for (i = 0; i < SIZE_CR00_CR18; i++)
+ smtc_crtcw(i, VGAMode[j].Init_CR00_CR18[i]);
+
+ /* init CRTC register CR30 - CR4D */
+ for (i = 0; i < SIZE_CR30_CR4D; i++)
+ smtc_crtcw(i + 0x30,
+ VGAMode[j].Init_CR30_CR4D[i]);
+
+ /* init CRTC register CR90 - CRA7 */
+ for (i = 0; i < SIZE_CR90_CRA7; i++)
+ smtc_crtcw(i + 0x90,
+ VGAMode[j].Init_CR90_CRA7[i]);
+ }
+ }
+ smtc_mmiowb(0x67, 0x3c2);
+
+ /* set VPR registers */
+ writel(0x0, ppar_info->m_pVPR + 0x0C);
+ writel(0x0, ppar_info->m_pVPR + 0x40);
+
+ /* set data width */
+ m_nScreenStride =
+ (ppar_info->width * sfb->fb.var.bits_per_pixel) / 64;
+ switch (sfb->fb.var.bits_per_pixel) {
+ case 8:
+ writel(0x0, ppar_info->m_pVPR + 0x0);
+ break;
+ case 16:
+ writel(0x00020000, ppar_info->m_pVPR + 0x0);
+ break;
+ case 24:
+ writel(0x00040000, ppar_info->m_pVPR + 0x0);
+ break;
+ case 32:
+ writel(0x00030000, ppar_info->m_pVPR + 0x0);
+ break;
+ }
+ writel((u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride),
+ ppar_info->m_pVPR + 0x10);
+
+}
+
+static void sm712_setpalette(int regno, unsigned red, unsigned green,
+ unsigned blue, struct fb_info *info)
+{
+ struct par_info *cur_par = (struct par_info *)info->par;
+
+ if (cur_par->BaseAddressInVRAM)
+ /*
+ * second display palette for dual head. Enable CRT RAM, 6-bit
+ * RAM
+ */
+ smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x20);
+ else
+ /* primary display palette. Enable LCD RAM only, 6-bit RAM */
+ smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
+ smtc_mmiowb(regno, dac_reg);
+ smtc_mmiowb(red >> 10, dac_val);
+ smtc_mmiowb(green >> 10, dac_val);
+ smtc_mmiowb(blue >> 10, dac_val);
+}
+
+static void smtc_set_timing(struct smtcfb_info *sfb, struct par_info
+ *ppar_info)
+{
+ switch (ppar_info->chipID) {
+ case 0x710:
+ case 0x712:
+ case 0x720:
+ sm712_set_timing(sfb, ppar_info);
+ break;
+ }
+}
+
+static struct fb_var_screeninfo smtcfb_var = {
+ .xres = 1024,
+ .yres = 600,
+ .xres_virtual = 1024,
+ .yres_virtual = 600,
+ .bits_per_pixel = 16,
+ .red = {16, 8, 0},
+ .green = {8, 8, 0},
+ .blue = {0, 8, 0},
+ .activate = FB_ACTIVATE_NOW,
+ .height = -1,
+ .width = -1,
+ .vmode = FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo smtcfb_fix = {
+ .id = "sm712fb",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .line_length = 800 * 3,
+ .accel = FB_ACCEL_SMI_LYNX,
+};
+
+/* chan_to_field
+ *
+ * convert a colour value into a field position
+ *
+ * from pxafb.c
+ */
+
+static inline unsigned int chan_to_field(unsigned int chan,
+ struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+static int smtcfb_blank(int blank_mode, struct fb_info *info)
+{
+ /* clear DPMS setting */
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ /* Screen On: HSync: On, VSync : On */
+ smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
+ smtc_seqw(0x6a, 0x16);
+ smtc_seqw(0x6b, 0x02);
+ smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
+ smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
+ smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
+ smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
+ smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
+ break;
+ case FB_BLANK_NORMAL:
+ /* Screen Off: HSync: On, VSync : On Soft blank */
+ smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
+ smtc_seqw(0x6a, 0x16);
+ smtc_seqw(0x6b, 0x02);
+ smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
+ smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
+ smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
+ smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ /* Screen On: HSync: On, VSync : Off */
+ smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
+ smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
+ smtc_seqw(0x6a, 0x0c);
+ smtc_seqw(0x6b, 0x02);
+ smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+ smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
+ smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
+ smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+ smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+ smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+ break;
+ case FB_BLANK_HSYNC_SUSPEND:
+ /* Screen On: HSync: Off, VSync : On */
+ smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
+ smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
+ smtc_seqw(0x6a, 0x0c);
+ smtc_seqw(0x6b, 0x02);
+ smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+ smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
+ smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
+ smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+ smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+ smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+ break;
+ case FB_BLANK_POWERDOWN:
+ /* Screen On: HSync: Off, VSync : Off */
+ smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
+ smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
+ smtc_seqw(0x6a, 0x0c);
+ smtc_seqw(0x6b, 0x02);
+ smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+ smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
+ smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
+ smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+ smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+ smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned trans, struct fb_info *info)
+{
+ struct smtcfb_info *sfb = (struct smtcfb_info *)info;
+ u32 val;
+
+ if (regno > 255)
+ return 1;
+
+ switch (sfb->fb.fix.visual) {
+ case FB_VISUAL_DIRECTCOLOR:
+ case FB_VISUAL_TRUECOLOR:
+ /*
+ * 16/32 bit true-colour, use pseuo-palette for 16 base color
+ */
+ if (regno < 16) {
+ if (sfb->fb.var.bits_per_pixel == 16) {
+ u32 *pal = sfb->fb.pseudo_palette;
+ val = chan_to_field(red, &sfb->fb.var.red);
+ val |= chan_to_field(green, \
+ &sfb->fb.var.green);
+ val |= chan_to_field(blue, &sfb->fb.var.blue);
+#ifdef __BIG_ENDIAN
+ pal[regno] =
+ ((red & 0xf800) >> 8) |
+ ((green & 0xe000) >> 13) |
+ ((green & 0x1c00) << 3) |
+ ((blue & 0xf800) >> 3);
+#else
+ pal[regno] = val;
+#endif
+ } else {
+ u32 *pal = sfb->fb.pseudo_palette;
+ val = chan_to_field(red, &sfb->fb.var.red);
+ val |= chan_to_field(green, \
+ &sfb->fb.var.green);
+ val |= chan_to_field(blue, &sfb->fb.var.blue);
+#ifdef __BIG_ENDIAN
+ val =
+ (val & 0xff00ff00 >> 8) |
+ (val & 0x00ff00ff << 8);
+#endif
+ pal[regno] = val;
+ }
+ }
+ break;
+
+ case FB_VISUAL_PSEUDOCOLOR:
+ /* color depth 8 bit */
+ sm712_setpalette(regno, red, green, blue, info);
+ break;
+
+ default:
+ return 1; /* unknown type */
+ }
+
+ return 0;
+
+}
+
+#ifdef __BIG_ENDIAN
+static ssize_t smtcfb_read(struct fb_info *info, char __user * buf, size_t
+ count, loff_t *ppos)
+{
+ unsigned long p = *ppos;
+
+ u32 *buffer, *dst;
+ u32 __iomem *src;
+ int c, i, cnt = 0, err = 0;
+ unsigned long total_size;
+
+ if (!info || !info->screen_base)
+ return -ENODEV;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return -EPERM;
+
+ total_size = info->screen_size;
+
+ if (total_size == 0)
+ total_size = info->fix.smem_len;
+
+ if (p >= total_size)
+ return 0;
+
+ if (count >= total_size)
+ count = total_size;
+
+ if (count + p > total_size)
+ count = total_size - p;
+
+ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ src = (u32 __iomem *) (info->screen_base + p);
+
+ if (info->fbops->fb_sync)
+ info->fbops->fb_sync(info);
+
+ while (count) {
+ c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+ dst = buffer;
+ for (i = c >> 2; i--;) {
+ *dst = fb_readl(src++);
+ *dst =
+ (*dst & 0xff00ff00 >> 8) |
+ (*dst & 0x00ff00ff << 8);
+ dst++;
+ }
+ if (c & 3) {
+ u8 *dst8 = (u8 *) dst;
+ u8 __iomem *src8 = (u8 __iomem *) src;
+
+ for (i = c & 3; i--;) {
+ if (i & 1) {
+ *dst8++ = fb_readb(++src8);
+ } else {
+ *dst8++ = fb_readb(--src8);
+ src8 += 2;
+ }
+ }
+ src = (u32 __iomem *) src8;
+ }
+
+ if (copy_to_user(buf, buffer, c)) {
+ err = -EFAULT;
+ break;
+ }
+ *ppos += c;
+ buf += c;
+ cnt += c;
+ count -= c;
+ }
+
+ kfree(buffer);
+
+ return (err) ? err : cnt;
+}
+
+static ssize_t
+smtcfb_write(struct fb_info *info, const char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned long p = *ppos;
+
+ u32 *buffer, *src;
+ u32 __iomem *dst;
+ int c, i, cnt = 0, err = 0;
+ unsigned long total_size;
+
+ if (!info || !info->screen_base)
+ return -ENODEV;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return -EPERM;
+
+ total_size = info->screen_size;
+
+ if (total_size == 0)
+ total_size = info->fix.smem_len;
+
+ if (p > total_size)
+ return -EFBIG;
+
+ if (count > total_size) {
+ err = -EFBIG;
+ count = total_size;
+ }
+
+ if (count + p > total_size) {
+ if (!err)
+ err = -ENOSPC;
+
+ count = total_size - p;
+ }
+
+ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ dst = (u32 __iomem *) (info->screen_base + p);
+
+ if (info->fbops->fb_sync)
+ info->fbops->fb_sync(info);
+
+ while (count) {
+ c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+ src = buffer;
+
+ if (copy_from_user(src, buf, c)) {
+ err = -EFAULT;
+ break;
+ }
+
+ for (i = c >> 2; i--;) {
+ fb_writel((*src & 0xff00ff00 >> 8) |
+ (*src & 0x00ff00ff << 8), dst++);
+ src++;
+ }
+ if (c & 3) {
+ u8 *src8 = (u8 *) src;
+ u8 __iomem *dst8 = (u8 __iomem *) dst;
+
+ for (i = c & 3; i--;) {
+ if (i & 1) {
+ fb_writeb(*src8++, ++dst8);
+ } else {
+ fb_writeb(*src8++, --dst8);
+ dst8 += 2;
+ }
+ }
+ dst = (u32 __iomem *) dst8;
+ }
+
+ *ppos += c;
+ buf += c;
+ cnt += c;
+ count -= c;
+ }
+
+ kfree(buffer);
+
+ return (cnt) ? cnt : err;
+}
+#endif /* ! __BIG_ENDIAN */
+
+#include "smtc2d.c"
+
+void smtcfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+ struct par_info *p = (struct par_info *)info->par;
+
+ if (smtc_2Dacceleration) {
+ if (!area->width || !area->height)
+ return;
+
+ deCopy(p->BaseAddressInVRAM, 0, info->var.bits_per_pixel,
+ area->dx, area->dy, area->width, area->height,
+ p->BaseAddressInVRAM, 0, area->sx, area->sy, 0, 0xC);
+
+ } else
+ cfb_copyarea(info, area);
+}
+
+void smtcfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ struct par_info *p = (struct par_info *)info->par;
+
+ if (smtc_2Dacceleration) {
+ if (!rect->width || !rect->height)
+ return;
+ if (info->var.bits_per_pixel >= 24)
+ deFillRect(p->BaseAddressInVRAM, 0, rect->dx * 3,
+ rect->dy * 3, rect->width * 3, rect->height,
+ rect->color);
+ else
+ deFillRect(p->BaseAddressInVRAM, 0, rect->dx, rect->dy,
+ rect->width, rect->height, rect->color);
+ } else
+ cfb_fillrect(info, rect);
+}
+
+void smtcfb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ struct par_info *p = (struct par_info *)info->par;
+ u32 bg_col = 0, fg_col = 0;
+
+ if ((smtc_2Dacceleration) && (image->depth == 1)) {
+ if (smtc_de_busy)
+ deWaitForNotBusy();
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ bg_col = image->bg_color;
+ fg_col = image->fg_color;
+ break;
+ case 16:
+ bg_col =
+ ((u32 *) (info->pseudo_palette))[image->bg_color];
+ fg_col =
+ ((u32 *) (info->pseudo_palette))[image->fg_color];
+ break;
+ case 32:
+ bg_col =
+ ((u32 *) (info->pseudo_palette))[image->bg_color];
+ fg_col =
+ ((u32 *) (info->pseudo_palette))[image->fg_color];
+ break;
+ }
+
+ deSystemMem2VideoMemMonoBlt(
+ image->data,
+ image->width / 8,
+ 0,
+ p->BaseAddressInVRAM,
+ 0,
+ 0,
+ image->dx, image->dy,
+ image->width, image->height,
+ fg_col, bg_col,
+ 0x0C);
+
+ } else
+ cfb_imageblit(info, image);
+}
+
+static struct fb_ops smtcfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_setcolreg = smtc_setcolreg,
+ .fb_blank = smtcfb_blank,
+ .fb_fillrect = smtcfb_fillrect,
+ .fb_imageblit = smtcfb_imageblit,
+ .fb_copyarea = smtcfb_copyarea,
+#ifdef __BIG_ENDIAN
+ .fb_read = smtcfb_read,
+ .fb_write = smtcfb_write,
+#endif
+
+};
+
+void smtcfb_setmode(struct smtcfb_info *sfb)
+{
+ switch (sfb->fb.var.bits_per_pixel) {
+ case 32:
+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+ sfb->fb.fix.line_length = sfb->fb.var.xres * 4;
+ sfb->fb.var.red.length = 8;
+ sfb->fb.var.green.length = 8;
+ sfb->fb.var.blue.length = 8;
+ sfb->fb.var.red.offset = 16;
+ sfb->fb.var.green.offset = 8;
+ sfb->fb.var.blue.offset = 0;
+
+ break;
+ case 8:
+ sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ sfb->fb.fix.line_length = sfb->fb.var.xres;
+ sfb->fb.var.red.offset = 5;
+ sfb->fb.var.red.length = 3;
+ sfb->fb.var.green.offset = 2;
+ sfb->fb.var.green.length = 3;
+ sfb->fb.var.blue.offset = 0;
+ sfb->fb.var.blue.length = 2;
+ break;
+ case 24:
+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+ sfb->fb.fix.line_length = sfb->fb.var.xres * 3;
+ sfb->fb.var.red.length = 8;
+ sfb->fb.var.green.length = 8;
+ sfb->fb.var.blue.length = 8;
+
+ sfb->fb.var.red.offset = 16;
+ sfb->fb.var.green.offset = 8;
+ sfb->fb.var.blue.offset = 0;
+
+ break;
+ case 16:
+ default:
+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+ sfb->fb.fix.line_length = sfb->fb.var.xres * 2;
+
+ sfb->fb.var.red.length = 5;
+ sfb->fb.var.green.length = 6;
+ sfb->fb.var.blue.length = 5;
+
+ sfb->fb.var.red.offset = 11;
+ sfb->fb.var.green.offset = 5;
+ sfb->fb.var.blue.offset = 0;
+
+ break;
+ }
+
+ hw.width = sfb->fb.var.xres;
+ hw.height = sfb->fb.var.yres;
+ hw.hz = 60;
+ smtc_set_timing(sfb, &hw);
+ if (smtc_2Dacceleration) {
+ printk("2D acceleration enabled!\n");
+ /* Init smtc drawing engine */
+ deInit(sfb->fb.var.xres, sfb->fb.var.yres,
+ sfb->fb.var.bits_per_pixel);
+ }
+}
+
+/*
+ * Alloc struct smtcfb_info and assign the default value
+ */
+static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *dev,
+ char *name)
+{
+ struct smtcfb_info *sfb;
+
+ sfb = kmalloc(sizeof(struct smtcfb_info), GFP_KERNEL);
+
+ if (!sfb)
+ return NULL;
+
+ memset(sfb, 0, sizeof(struct smtcfb_info));
+
+ sfb->currcon = -1;
+ sfb->dev = dev;
+
+ /*** Init sfb->fb with default value ***/
+ sfb->fb.flags = FBINFO_FLAG_DEFAULT;
+ sfb->fb.fbops = &smtcfb_ops;
+ sfb->fb.var = smtcfb_var;
+ sfb->fb.fix = smtcfb_fix;
+
+ strcpy(sfb->fb.fix.id, name);
+
+ sfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
+ sfb->fb.fix.type_aux = 0;
+ sfb->fb.fix.xpanstep = 0;
+ sfb->fb.fix.ypanstep = 0;
+ sfb->fb.fix.ywrapstep = 0;
+ sfb->fb.fix.accel = FB_ACCEL_SMI_LYNX;
+
+ sfb->fb.var.nonstd = 0;
+ sfb->fb.var.activate = FB_ACTIVATE_NOW;
+ sfb->fb.var.height = -1;
+ sfb->fb.var.width = -1;
+ /* text mode acceleration */
+ sfb->fb.var.accel_flags = FB_ACCELF_TEXT;
+ sfb->fb.var.vmode = FB_VMODE_NONINTERLACED;
+ sfb->fb.par = &hw;
+ sfb->fb.pseudo_palette = colreg;
+
+ return sfb;
+}
+
+/*
+ * Unmap in the memory mapped IO registers
+ */
+
+static void smtc_unmap_mmio(struct smtcfb_info *sfb)
+{
+ if (sfb && smtc_RegBaseAddress)
+ smtc_RegBaseAddress = NULL;
+}
+
+/*
+ * Map in the screen memory
+ */
+
+static int smtc_map_smem(struct smtcfb_info *sfb,
+ struct pci_dev *dev, u_long smem_len)
+{
+ if (sfb->fb.var.bits_per_pixel == 32) {
+#ifdef __BIG_ENDIAN
+ sfb->fb.fix.smem_start = pci_resource_start(dev, 0)
+ + 0x800000;
+#else
+ sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
+#endif
+ } else {
+ sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
+ }
+
+ sfb->fb.fix.smem_len = smem_len;
+
+ sfb->fb.screen_base = smtc_VRAMBaseAddress;
+
+ if (!sfb->fb.screen_base) {
+ printk(KERN_INFO "%s: unable to map screen memory\n",
+ sfb->fb.fix.id);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/*
+ * Unmap in the screen memory
+ *
+ */
+static void smtc_unmap_smem(struct smtcfb_info *sfb)
+{
+ if (sfb && sfb->fb.screen_base) {
+ iounmap(sfb->fb.screen_base);
+ sfb->fb.screen_base = NULL;
+ }
+}
+
+/*
+ * We need to wake up the LynxEM+, and make sure its in linear memory mode.
+ */
+static inline void sm7xx_init_hw(void)
+{
+ outb_p(0x18, 0x3c4);
+ outb_p(0x11, 0x3c5);
+}
+
+static void smtc_free_fb_info(struct smtcfb_info *sfb)
+{
+ if (sfb) {
+ fb_alloc_cmap(&sfb->fb.cmap, 0, 0);
+ kfree(sfb);
+ }
+}
+
+/*
+ * sm712vga_setup - process command line options, get vga parameter
+ * @options: string of options
+ * Returns zero.
+ *
+ */
+static int __init __maybe_unused sm712vga_setup(char *options)
+{
+ int index;
+
+ if (!options || !*options) {
+ smdbg("\n No vga parameter\n");
+ return -EINVAL;
+ }
+
+ smtc_screen_info.lfb_width = 0;
+ smtc_screen_info.lfb_height = 0;
+ smtc_screen_info.lfb_depth = 0;
+
+ smdbg("\nsm712vga_setup = %s\n", options);
+
+ for (index = 0;
+ index < (sizeof(vesa_mode) / sizeof(struct vesa_mode_table));
+ index++) {
+ if (strstr(options, vesa_mode[index].mode_index)) {
+ smtc_screen_info.lfb_width = vesa_mode[index].lfb_width;
+ smtc_screen_info.lfb_height =
+ vesa_mode[index].lfb_height;
+ smtc_screen_info.lfb_depth = vesa_mode[index].lfb_depth;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+__setup("vga=", sm712vga_setup);
+
+/* Jason (08/13/2009)
+ * Original init function changed to probe method to be used by pci_drv
+ * process used to detect chips replaced with kernel process in pci_drv
+ */
+static int __init smtcfb_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct smtcfb_info *sfb;
+ u_long smem_size = 0x00800000; /* default 8MB */
+ char name[16];
+ int err;
+ unsigned long pFramebufferPhysical;
+
+ printk(KERN_INFO
+ "Silicon Motion display driver " SMTC_LINUX_FB_VERSION "\n");
+
+ err = pci_enable_device(pdev); /* enable SMTC chip */
+
+ if (err)
+ return err;
+ err = -ENOMEM;
+
+ hw.chipID = ent->device;
+ sprintf(name, "sm%Xfb", hw.chipID);
+
+ sfb = smtc_alloc_fb_info(pdev, name);
+
+ if (!sfb)
+ goto failed;
+ /* Jason (08/13/2009)
+ * Store fb_info to be further used when suspending and resuming
+ */
+ pci_set_drvdata(pdev, sfb);
+
+ sm7xx_init_hw();
+
+ /*get mode parameter from smtc_screen_info */
+ if (smtc_screen_info.lfb_width != 0) {
+ sfb->fb.var.xres = smtc_screen_info.lfb_width;
+ sfb->fb.var.yres = smtc_screen_info.lfb_height;
+ sfb->fb.var.bits_per_pixel = smtc_screen_info.lfb_depth;
+ } else {
+ /* default resolution 1024x600 16bit mode */
+ sfb->fb.var.xres = SCREEN_X_RES;
+ sfb->fb.var.yres = SCREEN_Y_RES;
+ sfb->fb.var.bits_per_pixel = SCREEN_BPP;
+ }
+
+#ifdef __BIG_ENDIAN
+ if (sfb->fb.var.bits_per_pixel == 24)
+ sfb->fb.var.bits_per_pixel = (smtc_screen_info.lfb_depth = 32);
+#endif
+ /* Map address and memory detection */
+ pFramebufferPhysical = pci_resource_start(pdev, 0);
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &hw.chipRevID);
+
+ switch (hw.chipID) {
+ case 0x710:
+ case 0x712:
+ sfb->fb.fix.mmio_start = pFramebufferPhysical + 0x00400000;
+ sfb->fb.fix.mmio_len = 0x00400000;
+ smem_size = SM712_VIDEOMEMORYSIZE;
+#ifdef __BIG_ENDIAN
+ hw.m_pLFB = (smtc_VRAMBaseAddress =
+ ioremap(pFramebufferPhysical, 0x00c00000));
+#else
+ hw.m_pLFB = (smtc_VRAMBaseAddress =
+ ioremap(pFramebufferPhysical, 0x00800000));
+#endif
+ hw.m_pMMIO = (smtc_RegBaseAddress =
+ smtc_VRAMBaseAddress + 0x00700000);
+ smtc_2DBaseAddress = (hw.m_pDPR =
+ smtc_VRAMBaseAddress + 0x00408000);
+ smtc_2Ddataport = smtc_VRAMBaseAddress + DE_DATA_PORT_712;
+ hw.m_pVPR = hw.m_pLFB + 0x0040c000;
+#ifdef __BIG_ENDIAN
+ if (sfb->fb.var.bits_per_pixel == 32) {
+ smtc_VRAMBaseAddress += 0x800000;
+ hw.m_pLFB += 0x800000;
+ printk(KERN_INFO
+ "\nsmtc_VRAMBaseAddress=%p hw.m_pLFB=%p\n",
+ smtc_VRAMBaseAddress, hw.m_pLFB);
+ }
+#endif
+ if (!smtc_RegBaseAddress) {
+ printk(KERN_INFO
+ "%s: unable to map memory mapped IO\n",
+ sfb->fb.fix.id);
+ return -ENOMEM;
+ }
+
+ /* set MCLK = 14.31818 * (0x16 / 0x2) */
+ smtc_seqw(0x6a, 0x16);
+ smtc_seqw(0x6b, 0x02);
+ smtc_seqw(0x62, 0x3e);
+ /* enable PCI burst */
+ smtc_seqw(0x17, 0x20);
+ /* enable word swap */
+#ifdef __BIG_ENDIAN
+ if (sfb->fb.var.bits_per_pixel == 32)
+ smtc_seqw(0x17, 0x30);
+#endif
+#ifdef CONFIG_FB_SM7XX_ACCEL
+ smtc_2Dacceleration = 1;
+#endif
+ break;
+ case 0x720:
+ sfb->fb.fix.mmio_start = pFramebufferPhysical;
+ sfb->fb.fix.mmio_len = 0x00200000;
+ smem_size = SM722_VIDEOMEMORYSIZE;
+ smtc_2DBaseAddress = (hw.m_pDPR =
+ ioremap(pFramebufferPhysical, 0x00a00000));
+ hw.m_pLFB = (smtc_VRAMBaseAddress =
+ smtc_2DBaseAddress + 0x00200000);
+ hw.m_pMMIO = (smtc_RegBaseAddress =
+ smtc_2DBaseAddress + 0x000c0000);
+ smtc_2Ddataport = smtc_2DBaseAddress + DE_DATA_PORT_722;
+ hw.m_pVPR = smtc_2DBaseAddress + 0x800;
+
+ smtc_seqw(0x62, 0xff);
+ smtc_seqw(0x6a, 0x0d);
+ smtc_seqw(0x6b, 0x02);
+ smtc_2Dacceleration = 0;
+ break;
+ default:
+ printk(KERN_INFO
+ "No valid Silicon Motion display chip was detected!\n");
+
+ smtc_free_fb_info(sfb);
+ return err;
+ }
+
+ /* can support 32 bpp */
+ if (15 == sfb->fb.var.bits_per_pixel)
+ sfb->fb.var.bits_per_pixel = 16;
+
+ sfb->fb.var.xres_virtual = sfb->fb.var.xres;
+ sfb->fb.var.yres_virtual = sfb->fb.var.yres;
+ err = smtc_map_smem(sfb, pdev, smem_size);
+ if (err)
+ goto failed;
+
+ smtcfb_setmode(sfb);
+ /* Primary display starting from 0 postion */
+ hw.BaseAddressInVRAM = 0;
+ sfb->fb.par = &hw;
+
+ err = register_framebuffer(&sfb->fb);
+ if (err < 0)
+ goto failed;
+
+ printk(KERN_INFO "Silicon Motion SM%X Rev%X primary display mode"
+ "%dx%d-%d Init Complete.\n", hw.chipID, hw.chipRevID,
+ sfb->fb.var.xres, sfb->fb.var.yres,
+ sfb->fb.var.bits_per_pixel);
+
+ return 0;
+
+ failed:
+ printk(KERN_INFO "Silicon Motion, Inc. primary display init fail\n");
+
+ smtc_unmap_smem(sfb);
+ smtc_unmap_mmio(sfb);
+ smtc_free_fb_info(sfb);
+
+ return err;
+}
+
+
+/* Jason (08/11/2009) PCI_DRV wrapper essential structs */
+static struct pci_device_id smtcfb_pci_table[] = {
+ {0x126f, 0x710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x126f, 0x712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x126f, 0x720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0,}
+};
+
+
+/* Jason (08/14/2009)
+ * do some clean up when the driver module is removed
+ */
+static void __devexit smtcfb_pci_remove(struct pci_dev *pdev)
+{
+ struct smtcfb_info *sfb;
+
+ sfb = pci_get_drvdata(pdev);
+ pci_set_drvdata(pdev, NULL);
+ smtc_unmap_smem(sfb);
+ smtc_unmap_mmio(sfb);
+ unregister_framebuffer(&sfb->fb);
+ smtc_free_fb_info(sfb);
+}
+
+/* Jason (08/14/2009)
+ * suspend function, called when the suspend event is triggered
+ */
+static int __maybe_unused smtcfb_suspend(struct pci_dev *pdev, pm_message_t msg)
+{
+ struct smtcfb_info *sfb;
+ int retv;
+
+ sfb = pci_get_drvdata(pdev);
+
+ /* set the hw in sleep mode use externel clock and self memory refresh
+ * so that we can turn off internal PLLs later on
+ */
+ smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
+ smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
+
+ switch (msg.event) {
+ case PM_EVENT_FREEZE:
+ case PM_EVENT_PRETHAW:
+ pdev->dev.power.power_state = msg;
+ return 0;
+ }
+
+ /* when doing suspend, call fb apis and pci apis */
+ if (msg.event == PM_EVENT_SUSPEND) {
+ acquire_console_sem();
+ fb_set_suspend(&sfb->fb, 1);
+ release_console_sem();
+ retv = pci_save_state(pdev);
+ pci_disable_device(pdev);
+ retv = pci_choose_state(pdev, msg);
+ retv = pci_set_power_state(pdev, retv);
+ }
+
+ pdev->dev.power.power_state = msg;
+
+ /* additionaly turn off all function blocks including internal PLLs */
+ smtc_seqw(0x21, 0xff);
+
+ return 0;
+}
+
+static int __maybe_unused smtcfb_resume(struct pci_dev *pdev)
+{
+ struct smtcfb_info *sfb;
+ int retv;
+
+ sfb = pci_get_drvdata(pdev);
+
+ /* when resuming, restore pci data and fb cursor */
+ if (pdev->dev.power.power_state.event != PM_EVENT_FREEZE) {
+ retv = pci_set_power_state(pdev, PCI_D0);
+ retv = pci_restore_state(pdev);
+ if (pci_enable_device(pdev))
+ return -1;
+ pci_set_master(pdev);
+ }
+
+ /* reinit hardware */
+ sm7xx_init_hw();
+ switch (hw.chipID) {
+ case 0x710:
+ case 0x712:
+ /* set MCLK = 14.31818 * (0x16 / 0x2) */
+ smtc_seqw(0x6a, 0x16);
+ smtc_seqw(0x6b, 0x02);
+ smtc_seqw(0x62, 0x3e);
+ /* enable PCI burst */
+ smtc_seqw(0x17, 0x20);
+#ifdef __BIG_ENDIAN
+ if (sfb->fb.var.bits_per_pixel == 32)
+ smtc_seqw(0x17, 0x30);
+#endif
+ break;
+ case 0x720:
+ smtc_seqw(0x62, 0xff);
+ smtc_seqw(0x6a, 0x0d);
+ smtc_seqw(0x6b, 0x02);
+ break;
+ }
+
+ smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
+ smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
+
+ smtcfb_setmode(sfb);
+
+ acquire_console_sem();
+ fb_set_suspend(&sfb->fb, 0);
+ release_console_sem();
+
+ return 0;
+}
+
+/* Jason (08/13/2009)
+ * pci_driver struct used to wrap the original driver
+ * so that it can be registered into the kernel and
+ * the proper method would be called when suspending and resuming
+ */
+static struct pci_driver smtcfb_driver = {
+ .name = "smtcfb",
+ .id_table = smtcfb_pci_table,
+ .probe = smtcfb_pci_probe,
+ .remove = __devexit_p(smtcfb_pci_remove),
+#ifdef CONFIG_PM
+ .suspend = smtcfb_suspend,
+ .resume = smtcfb_resume,
+#endif
+};
+
+static int __init smtcfb_init(void)
+{
+ return pci_register_driver(&smtcfb_driver);
+}
+
+static void __exit smtcfb_exit(void)
+{
+ pci_unregister_driver(&smtcfb_driver);
+}
+
+module_init(smtcfb_init);
+module_exit(smtcfb_exit);
+
+MODULE_AUTHOR("Siliconmotion ");
+MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/sm7xx/smtcfb.h b/drivers/staging/sm7xx/smtcfb.h
new file mode 100644
index 00000000000..7f2c3413821
--- /dev/null
+++ b/drivers/staging/sm7xx/smtcfb.h
@@ -0,0 +1,793 @@
+/*
+ * Silicon Motion SM712 frame buffer device
+ *
+ * Copyright (C) 2006 Silicon Motion Technology Corp.
+ * Authors: Ge Wang, gewang@siliconmotion.com
+ * Boyod boyod.yang@siliconmotion.com.cn
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzj@lemote.com
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#define SMTC_LINUX_FB_VERSION "version 0.11.2619.21.01 July 27, 2008"
+
+#define NR_PALETTE 256
+#define NR_RGB 2
+
+#define FB_ACCEL_SMI_LYNX 88
+
+#ifdef __BIG_ENDIAN
+#define PC_VGA 0
+#else
+#define PC_VGA 1
+#endif
+
+#define SCREEN_X_RES 1024
+#define SCREEN_Y_RES 600
+#define SCREEN_BPP 16
+
+#ifndef FIELD_OFFSET
+#define FIELD_OFSFET(type, field) \
+ ((unsigned long) (PUCHAR) & (((type *)0)->field))
+#endif
+
+/*Assume SM712 graphics chip has 4MB VRAM */
+#define SM712_VIDEOMEMORYSIZE 0x00400000
+/*Assume SM722 graphics chip has 8MB VRAM */
+#define SM722_VIDEOMEMORYSIZE 0x00800000
+
+#define dac_reg (0x3c8)
+#define dac_val (0x3c9)
+
+extern char *smtc_RegBaseAddress;
+#define smtc_mmiowb(dat, reg) writeb(dat, smtc_RegBaseAddress + reg)
+#define smtc_mmioww(dat, reg) writew(dat, smtc_RegBaseAddress + reg)
+#define smtc_mmiowl(dat, reg) writel(dat, smtc_RegBaseAddress + reg)
+
+#define smtc_mmiorb(reg) readb(smtc_RegBaseAddress + reg)
+#define smtc_mmiorw(reg) readw(smtc_RegBaseAddress + reg)
+#define smtc_mmiorl(reg) readl(smtc_RegBaseAddress + reg)
+
+#define SIZE_SR00_SR04 (0x04 - 0x00 + 1)
+#define SIZE_SR10_SR24 (0x24 - 0x10 + 1)
+#define SIZE_SR30_SR75 (0x75 - 0x30 + 1)
+#define SIZE_SR80_SR93 (0x93 - 0x80 + 1)
+#define SIZE_SRA0_SRAF (0xAF - 0xA0 + 1)
+#define SIZE_GR00_GR08 (0x08 - 0x00 + 1)
+#define SIZE_AR00_AR14 (0x14 - 0x00 + 1)
+#define SIZE_CR00_CR18 (0x18 - 0x00 + 1)
+#define SIZE_CR30_CR4D (0x4D - 0x30 + 1)
+#define SIZE_CR90_CRA7 (0xA7 - 0x90 + 1)
+#define SIZE_VPR (0x6C + 1)
+#define SIZE_DPR (0x44 + 1)
+
+static inline void smtc_crtcw(int reg, int val)
+{
+ smtc_mmiowb(reg, 0x3d4);
+ smtc_mmiowb(val, 0x3d5);
+}
+
+static inline unsigned int smtc_crtcr(int reg)
+{
+ smtc_mmiowb(reg, 0x3d4);
+ return smtc_mmiorb(0x3d5);
+}
+
+static inline void smtc_grphw(int reg, int val)
+{
+ smtc_mmiowb(reg, 0x3ce);
+ smtc_mmiowb(val, 0x3cf);
+}
+
+static inline unsigned int smtc_grphr(int reg)
+{
+ smtc_mmiowb(reg, 0x3ce);
+ return smtc_mmiorb(0x3cf);
+}
+
+static inline void smtc_attrw(int reg, int val)
+{
+ smtc_mmiorb(0x3da);
+ smtc_mmiowb(reg, 0x3c0);
+ smtc_mmiorb(0x3c1);
+ smtc_mmiowb(val, 0x3c0);
+}
+
+static inline void smtc_seqw(int reg, int val)
+{
+ smtc_mmiowb(reg, 0x3c4);
+ smtc_mmiowb(val, 0x3c5);
+}
+
+static inline unsigned int smtc_seqr(int reg)
+{
+ smtc_mmiowb(reg, 0x3c4);
+ return smtc_mmiorb(0x3c5);
+}
+
+/* The next structure holds all information relevant for a specific video mode.
+ */
+
+struct ModeInit {
+ int mmSizeX;
+ int mmSizeY;
+ int bpp;
+ int hz;
+ unsigned char Init_MISC;
+ unsigned char Init_SR00_SR04[SIZE_SR00_SR04];
+ unsigned char Init_SR10_SR24[SIZE_SR10_SR24];
+ unsigned char Init_SR30_SR75[SIZE_SR30_SR75];
+ unsigned char Init_SR80_SR93[SIZE_SR80_SR93];
+ unsigned char Init_SRA0_SRAF[SIZE_SRA0_SRAF];
+ unsigned char Init_GR00_GR08[SIZE_GR00_GR08];
+ unsigned char Init_AR00_AR14[SIZE_AR00_AR14];
+ unsigned char Init_CR00_CR18[SIZE_CR00_CR18];
+ unsigned char Init_CR30_CR4D[SIZE_CR30_CR4D];
+ unsigned char Init_CR90_CRA7[SIZE_CR90_CRA7];
+};
+
+/**********************************************************************
+ SM712 Mode table.
+ **********************************************************************/
+struct ModeInit VGAMode[] = {
+ {
+ /* mode#0: 640 x 480 16Bpp 60Hz */
+ 640, 480, 16, 60,
+ /* Init_MISC */
+ 0xE3,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x00, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x30, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
+ },
+ },
+ {
+ /* mode#1: 640 x 480 24Bpp 60Hz */
+ 640, 480, 24, 60,
+ /* Init_MISC */
+ 0xE3,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x00, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x30, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
+ },
+ },
+ {
+ /* mode#0: 640 x 480 32Bpp 60Hz */
+ 640, 480, 32, 60,
+ /* Init_MISC */
+ 0xE3,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x00, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x30, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
+ },
+ },
+
+ { /* mode#2: 800 x 600 16Bpp 60Hz */
+ 800, 600, 16, 60,
+ /* Init_MISC */
+ 0x2B,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x30, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
+ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
+ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
+ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
+ },
+ { /* Init_SR80_SR93 */
+ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
+ },
+ },
+ { /* mode#3: 800 x 600 24Bpp 60Hz */
+ 800, 600, 24, 60,
+ 0x2B,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x30, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36,
+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
+ 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36,
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
+ 0x02, 0x45, 0x30, 0x30, 0x40, 0x20,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36,
+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
+ },
+ },
+ { /* mode#7: 800 x 600 32Bpp 60Hz */
+ 800, 600, 32, 60,
+ /* Init_MISC */
+ 0x2B,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x30, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
+ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
+ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
+ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
+ },
+ { /* Init_SR80_SR93 */
+ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
+ },
+ },
+ /* We use 1024x768 table to light 1024x600 panel for lemote */
+ { /* mode#4: 1024 x 600 16Bpp 60Hz */
+ 1024, 600, 16, 60,
+ /* Init_MISC */
+ 0xEB,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x00, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20,
+ 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x30, 0x02, 0x00, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22,
+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+ 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22,
+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02,
+ 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+ 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00,
+ 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+ },
+ },
+ { /* mode#5: 1024 x 768 24Bpp 60Hz */
+ 1024, 768, 24, 60,
+ /* Init_MISC */
+ 0xEB,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x30, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
+ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+ },
+ },
+ { /* mode#4: 1024 x 768 32Bpp 60Hz */
+ 1024, 768, 32, 60,
+ /* Init_MISC */
+ 0xEB,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x32, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
+ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+ },
+ },
+ { /* mode#6: 320 x 240 16Bpp 60Hz */
+ 320, 240, 16, 60,
+ /* Init_MISC */
+ 0xEB,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x32, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
+ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+ },
+ },
+
+ { /* mode#8: 320 x 240 32Bpp 60Hz */
+ 320, 240, 32, 60,
+ /* Init_MISC */
+ 0xEB,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x32, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
+ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+ },
+ },
+};
+
+#define numVGAModes (sizeof(VGAMode) / sizeof(struct ModeInit))
diff --git a/drivers/staging/vt6655/Kconfig b/drivers/staging/vt6655/Kconfig
index 825bbc4fc3f..061e730df2d 100644
--- a/drivers/staging/vt6655/Kconfig
+++ b/drivers/staging/vt6655/Kconfig
@@ -1,6 +1,6 @@
config VT6655
tristate "VIA Technologies VT6655 support"
- depends on PCI
+ depends on PCI && WLAN
select WIRELESS_EXT
select WEXT_PRIV
---help---
diff --git a/drivers/staging/vt6656/Kconfig b/drivers/staging/vt6656/Kconfig
index 87bcd269310..1055b526c53 100644
--- a/drivers/staging/vt6656/Kconfig
+++ b/drivers/staging/vt6656/Kconfig
@@ -1,6 +1,6 @@
config VT6656
tristate "VIA Technologies VT6656 support"
- depends on USB
+ depends on USB && WLAN
select WIRELESS_EXT
select WEXT_PRIV
---help---
diff --git a/drivers/staging/wlan-ng/prism2fw.c b/drivers/staging/wlan-ng/prism2fw.c
index 7d76a7f92a3..aaa70ed5771 100644
--- a/drivers/staging/wlan-ng/prism2fw.c
+++ b/drivers/staging/wlan-ng/prism2fw.c
@@ -439,7 +439,7 @@ void free_chunks(imgchunk_t *fchunk, unsigned int *nfchunks)
}
}
*nfchunks = 0;
- memset(fchunk, 0, sizeof(fchunk));
+ memset(fchunk, 0, sizeof(*fchunk));
}
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 473aa1a20de..be3c9b80bc9 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -44,5 +44,3 @@ obj-y += early/
obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
-
-obj-$(CONFIG_USB_ULPI) += otg/
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 6dac3b802d4..0495fa65122 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1597,7 +1597,9 @@ rescan:
}
/**
- * Check whether a new bandwidth setting exceeds the bus bandwidth.
+ * usb_hcd_alloc_bandwidth - check whether a new bandwidth setting exceeds
+ * the bus bandwidth
+ * @udev: target &usb_device
* @new_config: new configuration to install
* @cur_alt: the current alternate interface setting
* @new_alt: alternate interface setting that is being installed
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 06af970e106..0cec6caf6e9 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1658,12 +1658,12 @@ static inline void announce_device(struct usb_device *udev) { }
#endif
/**
- * usb_configure_device_otg - FIXME (usbcore-internal)
+ * usb_enumerate_device_otg - FIXME (usbcore-internal)
* @udev: newly addressed device (in ADDRESS state)
*
- * Do configuration for On-The-Go devices
+ * Finish enumeration for On-The-Go devices
*/
-static int usb_configure_device_otg(struct usb_device *udev)
+static int usb_enumerate_device_otg(struct usb_device *udev)
{
int err = 0;
@@ -1734,7 +1734,7 @@ fail:
/**
- * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal)
+ * usb_enumerate_device - Read device configs/intfs/otg (usbcore-internal)
* @udev: newly addressed device (in ADDRESS state)
*
* This is only called by usb_new_device() and usb_authorize_device()
@@ -1745,7 +1745,7 @@ fail:
* the string descriptors, as they will be errored out by the device
* until it has been authorized.
*/
-static int usb_configure_device(struct usb_device *udev)
+static int usb_enumerate_device(struct usb_device *udev)
{
int err;
@@ -1769,7 +1769,7 @@ static int usb_configure_device(struct usb_device *udev)
udev->descriptor.iManufacturer);
udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
}
- err = usb_configure_device_otg(udev);
+ err = usb_enumerate_device_otg(udev);
fail:
return err;
}
@@ -1779,8 +1779,8 @@ fail:
* usb_new_device - perform initial device setup (usbcore-internal)
* @udev: newly addressed device (in ADDRESS state)
*
- * This is called with devices which have been enumerated, but not yet
- * configured. The device descriptor is available, but not descriptors
+ * This is called with devices which have been detected but not fully
+ * enumerated. The device descriptor is available, but not descriptors
* for any device configuration. The caller must have locked either
* the parent hub (if udev is a normal device) or else the
* usb_bus_list_lock (if udev is a root hub). The parent's pointer to
@@ -1803,8 +1803,8 @@ int usb_new_device(struct usb_device *udev)
if (udev->parent)
usb_autoresume_device(udev->parent);
- usb_detect_quirks(udev); /* Determine quirks */
- err = usb_configure_device(udev); /* detect & probe dev/intfs */
+ usb_detect_quirks(udev);
+ err = usb_enumerate_device(udev); /* Read descriptors */
if (err < 0)
goto fail;
dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",
@@ -1849,21 +1849,23 @@ fail:
*/
int usb_deauthorize_device(struct usb_device *usb_dev)
{
- unsigned cnt;
usb_lock_device(usb_dev);
if (usb_dev->authorized == 0)
goto out_unauthorized;
+
usb_dev->authorized = 0;
usb_set_configuration(usb_dev, -1);
+
+ kfree(usb_dev->product);
usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ kfree(usb_dev->manufacturer);
usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ kfree(usb_dev->serial);
usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
- kfree(usb_dev->config);
- usb_dev->config = NULL;
- for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++)
- kfree(usb_dev->rawdescriptors[cnt]);
+
+ usb_destroy_configuration(usb_dev);
usb_dev->descriptor.bNumConfigurations = 0;
- kfree(usb_dev->rawdescriptors);
+
out_unauthorized:
usb_unlock_device(usb_dev);
return 0;
@@ -1873,15 +1875,11 @@ out_unauthorized:
int usb_authorize_device(struct usb_device *usb_dev)
{
int result = 0, c;
+
usb_lock_device(usb_dev);
if (usb_dev->authorized == 1)
goto out_authorized;
- kfree(usb_dev->product);
- usb_dev->product = NULL;
- kfree(usb_dev->manufacturer);
- usb_dev->manufacturer = NULL;
- kfree(usb_dev->serial);
- usb_dev->serial = NULL;
+
result = usb_autoresume_device(usb_dev);
if (result < 0) {
dev_err(&usb_dev->dev,
@@ -1894,10 +1892,18 @@ int usb_authorize_device(struct usb_device *usb_dev)
"authorization: %d\n", result);
goto error_device_descriptor;
}
+
+ kfree(usb_dev->product);
+ usb_dev->product = NULL;
+ kfree(usb_dev->manufacturer);
+ usb_dev->manufacturer = NULL;
+ kfree(usb_dev->serial);
+ usb_dev->serial = NULL;
+
usb_dev->authorized = 1;
- result = usb_configure_device(usb_dev);
+ result = usb_enumerate_device(usb_dev);
if (result < 0)
- goto error_configure;
+ goto error_enumerate;
/* Choose and set the configuration. This registers the interfaces
* with the driver core and lets interface drivers bind to them.
*/
@@ -1912,8 +1918,10 @@ int usb_authorize_device(struct usb_device *usb_dev)
}
}
dev_info(&usb_dev->dev, "authorized to connect\n");
-error_configure:
+
+error_enumerate:
error_device_descriptor:
+ usb_autosuspend_device(usb_dev);
error_autoresume:
out_authorized:
usb_unlock_device(usb_dev); // complements locktree
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 15477008b63..485edf937f2 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -82,9 +82,13 @@ static ssize_t show_##name(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_device *udev; \
+ int retval; \
\
udev = to_usb_device(dev); \
- return sprintf(buf, "%s\n", udev->name); \
+ usb_lock_device(udev); \
+ retval = sprintf(buf, "%s\n", udev->name); \
+ usb_unlock_device(udev); \
+ return retval; \
} \
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 2fb42043b30..0daff0d968b 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -66,9 +66,9 @@ MODULE_PARM_DESC(autosuspend, "default autosuspend delay");
/**
* usb_find_alt_setting() - Given a configuration, find the alternate setting
* for the given interface.
- * @config - the configuration to search (not necessarily the current config).
- * @iface_num - interface number to search in
- * @alt_num - alternate interface setting number to search for.
+ * @config: the configuration to search (not necessarily the current config).
+ * @iface_num: interface number to search in
+ * @alt_num: alternate interface setting number to search for.
*
* Search the configuration's interface cache for the given alt setting.
*/
diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c
index 1206a26ef89..2958a1271b2 100644
--- a/drivers/usb/early/ehci-dbgp.c
+++ b/drivers/usb/early/ehci-dbgp.c
@@ -613,7 +613,7 @@ err:
}
EXPORT_SYMBOL_GPL(dbgp_external_startup);
-static int __init ehci_reset_port(int port)
+static int ehci_reset_port(int port)
{
u32 portsc;
u32 delay_time, delay;
diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c
index 58f22032384..a62af7b5909 100644
--- a/drivers/usb/gadget/audio.c
+++ b/drivers/usb/gadget/audio.c
@@ -158,6 +158,7 @@ fail:
static int __exit audio_unbind(struct usb_composite_dev *cdev)
{
+ gaudio_cleanup();
return 0;
}
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c
index c43c89ffa2c..df77f6131c7 100644
--- a/drivers/usb/gadget/f_audio.c
+++ b/drivers/usb/gadget/f_audio.c
@@ -56,13 +56,16 @@ static struct usb_interface_descriptor ac_interface_desc __initdata = {
DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
+/* 1 input terminal, 1 output terminal and 1 feature unit */
+#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
+ + UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
/* B.3.2 Class-Specific AC Interface Descriptor */
static struct uac_ac_header_descriptor_2 ac_header_desc = {
.bLength = UAC_DT_AC_HEADER_LENGTH,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_HEADER,
.bcdADC = __constant_cpu_to_le16(0x0100),
- .wTotalLength = __constant_cpu_to_le16(UAC_DT_AC_HEADER_LENGTH),
+ .wTotalLength = __constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH),
.bInCollection = F_AUDIO_NUM_INTERFACES,
.baInterfaceNr = {
[0] = F_AUDIO_AC_INTERFACE,
@@ -252,12 +255,12 @@ static struct f_audio_buf *f_audio_buffer_alloc(int buf_size)
copy_buf = kzalloc(sizeof *copy_buf, GFP_ATOMIC);
if (!copy_buf)
- return (struct f_audio_buf *)-ENOMEM;
+ return ERR_PTR(-ENOMEM);
copy_buf->buf = kzalloc(buf_size, GFP_ATOMIC);
if (!copy_buf->buf) {
kfree(copy_buf);
- return (struct f_audio_buf *)-ENOMEM;
+ return ERR_PTR(-ENOMEM);
}
return copy_buf;
@@ -332,7 +335,7 @@ static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req)
list_add_tail(&copy_buf->list, &audio->play_queue);
schedule_work(&audio->playback_work);
copy_buf = f_audio_buffer_alloc(audio_buf_size);
- if (copy_buf < 0)
+ if (IS_ERR(copy_buf))
return -ENOMEM;
}
@@ -576,6 +579,8 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
usb_ep_enable(out_ep, audio->out_desc);
out_ep->driver_data = audio;
audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
+ if (IS_ERR(audio->copy_buf))
+ return -ENOMEM;
/*
* allocate a bunch of read buffers
@@ -787,7 +792,7 @@ int __init audio_bind_config(struct usb_configuration *c)
return status;
add_fail:
- gaudio_cleanup(&audio->card);
+ gaudio_cleanup();
setup_fail:
kfree(audio);
return status;
diff --git a/drivers/usb/gadget/u_audio.c b/drivers/usb/gadget/u_audio.c
index 8252595d619..35e0930f5bb 100644
--- a/drivers/usb/gadget/u_audio.c
+++ b/drivers/usb/gadget/u_audio.c
@@ -288,6 +288,7 @@ static int gaudio_close_snd_dev(struct gaudio *gau)
return 0;
}
+static struct gaudio *the_card;
/**
* gaudio_setup - setup ALSA interface and preparing for USB transfer
*
@@ -303,6 +304,9 @@ int __init gaudio_setup(struct gaudio *card)
if (ret)
ERROR(card, "we need at least one control device\n");
+ if (!the_card)
+ the_card = card;
+
return ret;
}
@@ -312,9 +316,11 @@ int __init gaudio_setup(struct gaudio *card)
*
* This is called to free all resources allocated by @gaudio_setup().
*/
-void gaudio_cleanup(struct gaudio *card)
+void gaudio_cleanup(void)
{
- if (card)
- gaudio_close_snd_dev(card);
+ if (the_card) {
+ gaudio_close_snd_dev(the_card);
+ the_card = NULL;
+ }
}
diff --git a/drivers/usb/gadget/u_audio.h b/drivers/usb/gadget/u_audio.h
index cc8d159c648..08ffce3298e 100644
--- a/drivers/usb/gadget/u_audio.h
+++ b/drivers/usb/gadget/u_audio.h
@@ -51,6 +51,6 @@ struct gaudio {
};
int gaudio_setup(struct gaudio *card);
-void gaudio_cleanup(struct gaudio *card);
+void gaudio_cleanup(void);
#endif /* __U_AUDIO_H */
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 12f1ad2fd0e..74d07f4e8b7 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -37,7 +37,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/gpio.h>
-#include <mach/usb.h>
+#include <plat/usb.h>
/*
* OMAP USBHOST Register addresses: VIRTUAL ADDRESSES
diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c
index 00a29855d0c..ff43747a614 100644
--- a/drivers/usb/host/fhci-sched.c
+++ b/drivers/usb/host/fhci-sched.c
@@ -37,7 +37,7 @@ static void recycle_frame(struct fhci_usb *usb, struct packet *pkt)
pkt->info = 0;
pkt->priv_data = NULL;
- cq_put(usb->ep0->empty_frame_Q, pkt);
+ cq_put(&usb->ep0->empty_frame_Q, pkt);
}
/* confirm submitted packet */
@@ -57,7 +57,7 @@ void fhci_transaction_confirm(struct fhci_usb *usb, struct packet *pkt)
if ((td->data + td->actual_len) && trans_len)
memcpy(td->data + td->actual_len, pkt->data,
trans_len);
- cq_put(usb->ep0->dummy_packets_Q, pkt->data);
+ cq_put(&usb->ep0->dummy_packets_Q, pkt->data);
}
recycle_frame(usb, pkt);
@@ -213,7 +213,7 @@ static int add_packet(struct fhci_usb *usb, struct ed *ed, struct td *td)
}
/* update frame object fields before transmitting */
- pkt = cq_get(usb->ep0->empty_frame_Q);
+ pkt = cq_get(&usb->ep0->empty_frame_Q);
if (!pkt) {
fhci_dbg(usb->fhci, "there is no empty frame\n");
return -1;
@@ -222,7 +222,7 @@ static int add_packet(struct fhci_usb *usb, struct ed *ed, struct td *td)
pkt->info = 0;
if (data == NULL) {
- data = cq_get(usb->ep0->dummy_packets_Q);
+ data = cq_get(&usb->ep0->dummy_packets_Q);
BUG_ON(!data);
pkt->info = PKT_DUMMY_PACKET;
}
@@ -246,7 +246,7 @@ static int add_packet(struct fhci_usb *usb, struct ed *ed, struct td *td)
list_del_init(&td->frame_lh);
td->status = USB_TD_OK;
if (pkt->info & PKT_DUMMY_PACKET)
- cq_put(usb->ep0->dummy_packets_Q, pkt->data);
+ cq_put(&usb->ep0->dummy_packets_Q, pkt->data);
recycle_frame(usb, pkt);
usb->actual_frame->total_bytes -= (len + PROTOCOL_OVERHEAD);
fhci_err(usb->fhci, "host transaction failed\n");
diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c
index b4033229031..d224ab467a4 100644
--- a/drivers/usb/host/fhci-tds.c
+++ b/drivers/usb/host/fhci-tds.c
@@ -106,33 +106,33 @@ void fhci_ep0_free(struct fhci_usb *usb)
cpm_muram_free(cpm_muram_offset(ep->td_base));
if (ep->conf_frame_Q) {
- size = cq_howmany(ep->conf_frame_Q);
+ size = cq_howmany(&ep->conf_frame_Q);
for (; size; size--) {
- struct packet *pkt = cq_get(ep->conf_frame_Q);
+ struct packet *pkt = cq_get(&ep->conf_frame_Q);
kfree(pkt);
}
- cq_delete(ep->conf_frame_Q);
+ cq_delete(&ep->conf_frame_Q);
}
if (ep->empty_frame_Q) {
- size = cq_howmany(ep->empty_frame_Q);
+ size = cq_howmany(&ep->empty_frame_Q);
for (; size; size--) {
- struct packet *pkt = cq_get(ep->empty_frame_Q);
+ struct packet *pkt = cq_get(&ep->empty_frame_Q);
kfree(pkt);
}
- cq_delete(ep->empty_frame_Q);
+ cq_delete(&ep->empty_frame_Q);
}
if (ep->dummy_packets_Q) {
- size = cq_howmany(ep->dummy_packets_Q);
+ size = cq_howmany(&ep->dummy_packets_Q);
for (; size; size--) {
- u8 *buff = cq_get(ep->dummy_packets_Q);
+ u8 *buff = cq_get(&ep->dummy_packets_Q);
kfree(buff);
}
- cq_delete(ep->dummy_packets_Q);
+ cq_delete(&ep->dummy_packets_Q);
}
kfree(ep);
@@ -175,10 +175,9 @@ u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem,
ep->td_base = cpm_muram_addr(ep_offset);
/* zero all queue pointers */
- ep->conf_frame_Q = cq_new(ring_len + 2);
- ep->empty_frame_Q = cq_new(ring_len + 2);
- ep->dummy_packets_Q = cq_new(ring_len + 2);
- if (!ep->conf_frame_Q || !ep->empty_frame_Q || !ep->dummy_packets_Q) {
+ if (cq_new(&ep->conf_frame_Q, ring_len + 2) ||
+ cq_new(&ep->empty_frame_Q, ring_len + 2) ||
+ cq_new(&ep->dummy_packets_Q, ring_len + 2)) {
err_for = "frame_queues";
goto err;
}
@@ -199,8 +198,8 @@ u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem,
err_for = "buffer";
goto err;
}
- cq_put(ep->empty_frame_Q, pkt);
- cq_put(ep->dummy_packets_Q, buff);
+ cq_put(&ep->empty_frame_Q, pkt);
+ cq_put(&ep->dummy_packets_Q, buff);
}
/* we put the endpoint parameter RAM right behind the TD ring */
@@ -319,7 +318,7 @@ static void fhci_td_transaction_confirm(struct fhci_usb *usb)
if ((buf == DUMMY2_BD_BUFFER) && !(td_status & ~TD_W))
continue;
- pkt = cq_get(ep->conf_frame_Q);
+ pkt = cq_get(&ep->conf_frame_Q);
if (!pkt)
fhci_err(usb->fhci, "no frame to confirm\n");
@@ -460,9 +459,9 @@ u32 fhci_host_transaction(struct fhci_usb *usb,
out_be16(&td->length, pkt->len);
/* put the frame to the confirmation queue */
- cq_put(ep->conf_frame_Q, pkt);
+ cq_put(&ep->conf_frame_Q, pkt);
- if (cq_howmany(ep->conf_frame_Q) == 1)
+ if (cq_howmany(&ep->conf_frame_Q) == 1)
out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO);
return 0;
diff --git a/drivers/usb/host/fhci.h b/drivers/usb/host/fhci.h
index 7116284ed21..72dae1c5ab3 100644
--- a/drivers/usb/host/fhci.h
+++ b/drivers/usb/host/fhci.h
@@ -423,9 +423,9 @@ struct endpoint {
struct usb_td __iomem *td_base; /* first TD in the ring */
struct usb_td __iomem *conf_td; /* next TD for confirm after transac */
struct usb_td __iomem *empty_td;/* next TD for new transaction req. */
- struct kfifo *empty_frame_Q; /* Empty frames list to use */
- struct kfifo *conf_frame_Q; /* frames passed to TDs,waiting for tx */
- struct kfifo *dummy_packets_Q;/* dummy packets for the CRC overun */
+ struct kfifo empty_frame_Q; /* Empty frames list to use */
+ struct kfifo conf_frame_Q; /* frames passed to TDs,waiting for tx */
+ struct kfifo dummy_packets_Q;/* dummy packets for the CRC overun */
bool already_pushed_dummy_bd;
};
@@ -493,9 +493,9 @@ static inline struct usb_hcd *fhci_to_hcd(struct fhci_hcd *fhci)
}
/* fifo of pointers */
-static inline struct kfifo *cq_new(int size)
+static inline int cq_new(struct kfifo *fifo, int size)
{
- return kfifo_alloc(size * sizeof(void *), GFP_KERNEL, NULL);
+ return kfifo_alloc(fifo, size * sizeof(void *), GFP_KERNEL);
}
static inline void cq_delete(struct kfifo *kfifo)
@@ -505,19 +505,19 @@ static inline void cq_delete(struct kfifo *kfifo)
static inline unsigned int cq_howmany(struct kfifo *kfifo)
{
- return __kfifo_len(kfifo) / sizeof(void *);
+ return kfifo_len(kfifo) / sizeof(void *);
}
static inline int cq_put(struct kfifo *kfifo, void *p)
{
- return __kfifo_put(kfifo, (void *)&p, sizeof(p));
+ return kfifo_in(kfifo, (void *)&p, sizeof(p));
}
static inline void *cq_get(struct kfifo *kfifo)
{
void *p = NULL;
- __kfifo_get(kfifo, (void *)&p, sizeof(p));
+ kfifo_out(kfifo, (void *)&p, sizeof(p));
return p;
}
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index 1d8e39a557d..1eb9e4162cc 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -60,6 +60,7 @@
static struct usb_device_id appledisplay_table [] = {
{ APPLEDISPLAY_DEVICE(0x9218) },
{ APPLEDISPLAY_DEVICE(0x9219) },
+ { APPLEDISPLAY_DEVICE(0x921c) },
{ APPLEDISPLAY_DEVICE(0x921d) },
/* Terminating entry */
@@ -72,8 +73,8 @@ struct appledisplay {
struct usb_device *udev; /* usb device */
struct urb *urb; /* usb request block */
struct backlight_device *bd; /* backlight device */
- char *urbdata; /* interrupt URB data buffer */
- char *msgdata; /* control message data buffer */
+ u8 *urbdata; /* interrupt URB data buffer */
+ u8 *msgdata; /* control message data buffer */
struct delayed_work work;
int button_pressed;
diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c
index 602ee05ba9f..59860b32853 100644
--- a/drivers/usb/misc/emi62.c
+++ b/drivers/usb/misc/emi62.c
@@ -167,7 +167,7 @@ static int emi62_load_firmware (struct usb_device *dev)
err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
- } while (i > 0);
+ } while (rec);
/* Assert reset (stop the CPU in the EMI) */
err = emi62_set_reset(dev,1);
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index fe4934d9602..ad26e656966 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -29,6 +29,8 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
{
void __iomem *fifo = hw_ep->fifo;
void __iomem *epio = hw_ep->regs;
+ u8 epnum = hw_ep->epnum;
+ u16 dma_reg = 0;
prefetch((u8 *)src);
@@ -39,67 +41,113 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
dump_fifo_data(src, len);
- if (unlikely((unsigned long)src & 0x01))
- outsw_8((unsigned long)fifo, src,
- len & 0x01 ? (len >> 1) + 1 : len >> 1);
- else
- outsw((unsigned long)fifo, src,
- len & 0x01 ? (len >> 1) + 1 : len >> 1);
-}
+ if (!ANOMALY_05000380 && epnum != 0) {
+ flush_dcache_range((unsigned int)src,
+ (unsigned int)(src + len));
+
+ /* Setup DMA address register */
+ dma_reg = (u16) ((u32) src & 0xFFFF);
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
+ SSYNC();
+
+ dma_reg = (u16) (((u32) src >> 16) & 0xFFFF);
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
+ SSYNC();
+
+ /* Setup DMA count register */
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_LOW), len);
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_HIGH), 0);
+ SSYNC();
+
+ /* Enable the DMA */
+ dma_reg = (epnum << 4) | DMA_ENA | INT_ENA | DIRECTION;
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);
+ SSYNC();
+
+ /* Wait for compelete */
+ while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))
+ cpu_relax();
+
+ /* acknowledge dma interrupt */
+ bfin_write_USB_DMA_INTERRUPT(1 << epnum);
+ SSYNC();
+
+ /* Reset DMA */
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), 0);
+ SSYNC();
+ } else {
+ SSYNC();
+
+ if (unlikely((unsigned long)src & 0x01))
+ outsw_8((unsigned long)fifo, src,
+ len & 0x01 ? (len >> 1) + 1 : len >> 1);
+ else
+ outsw((unsigned long)fifo, src,
+ len & 0x01 ? (len >> 1) + 1 : len >> 1);
+ }
+}
/*
* Unload an endpoint's FIFO
*/
void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
{
void __iomem *fifo = hw_ep->fifo;
-
-#ifdef CONFIG_BF52x
u8 epnum = hw_ep->epnum;
u16 dma_reg = 0;
- invalidate_dcache_range((unsigned int)dst,
- (unsigned int)(dst + len));
+ if (ANOMALY_05000467 && epnum != 0) {
- /* Setup DMA address register */
- dma_reg = (u16) ((u32) dst & 0xFFFF);
- bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
- SSYNC();
+ invalidate_dcache_range((unsigned int)dst,
+ (unsigned int)(dst + len));
- dma_reg = (u16) (((u32) dst >> 16) & 0xFFFF);
- bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
- SSYNC();
+ /* Setup DMA address register */
+ dma_reg = (u16) ((u32) dst & 0xFFFF);
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
+ SSYNC();
- /* Setup DMA count register */
- bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_LOW), len);
- bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_HIGH), 0);
- SSYNC();
+ dma_reg = (u16) (((u32) dst >> 16) & 0xFFFF);
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
+ SSYNC();
- /* Enable the DMA */
- dma_reg = (epnum << 4) | DMA_ENA | INT_ENA;
- bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);
- SSYNC();
+ /* Setup DMA count register */
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_LOW), len);
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_HIGH), 0);
+ SSYNC();
- /* Wait for compelete */
- while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))
- cpu_relax();
+ /* Enable the DMA */
+ dma_reg = (epnum << 4) | DMA_ENA | INT_ENA;
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);
+ SSYNC();
- /* acknowledge dma interrupt */
- bfin_write_USB_DMA_INTERRUPT(1 << epnum);
- SSYNC();
+ /* Wait for compelete */
+ while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))
+ cpu_relax();
- /* Reset DMA */
- bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), 0);
- SSYNC();
-#else
- if (unlikely((unsigned long)dst & 0x01))
- insw_8((unsigned long)fifo, dst,
- len & 0x01 ? (len >> 1) + 1 : len >> 1);
- else
- insw((unsigned long)fifo, dst,
- len & 0x01 ? (len >> 1) + 1 : len >> 1);
-#endif
+ /* acknowledge dma interrupt */
+ bfin_write_USB_DMA_INTERRUPT(1 << epnum);
+ SSYNC();
+ /* Reset DMA */
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), 0);
+ SSYNC();
+ } else {
+ SSYNC();
+ /* Read the last byte of packet with odd size from address fifo + 4
+ * to trigger 1 byte access to EP0 FIFO.
+ */
+ if (len == 1)
+ *dst = (u8)inw((unsigned long)fifo + 4);
+ else {
+ if (unlikely((unsigned long)dst & 0x01))
+ insw_8((unsigned long)fifo, dst, len >> 1);
+ else
+ insw((unsigned long)fifo, dst, len >> 1);
+
+ if (len & 0x01)
+ *(dst + len - 1) = (u8)inw((unsigned long)fifo + 4);
+ }
+ }
DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
'R', hw_ep->epnum, fifo, len, dst);
diff --git a/drivers/usb/musb/blackfin.h b/drivers/usb/musb/blackfin.h
index 10b7d7584f4..bd9352a2ef2 100644
--- a/drivers/usb/musb/blackfin.h
+++ b/drivers/usb/musb/blackfin.h
@@ -69,7 +69,6 @@ static void dump_fifo_data(u8 *buf, u16 len)
#define dump_fifo_data(buf, len) do {} while (0)
#endif
-#ifdef CONFIG_BF52x
#define USB_DMA_BASE USB_DMA_INTERRUPT
#define USB_DMAx_CTRL 0x04
@@ -79,7 +78,6 @@ static void dump_fifo_data(u8 *buf, u16 len)
#define USB_DMAx_COUNT_HIGH 0x14
#define USB_DMA_REG(ep, reg) (USB_DMA_BASE + 0x20 * ep + reg)
-#endif
/* Almost 1 second */
#define TIMER_DELAY (1 * HZ)
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index ef2332a9941..a44a450c860 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -1154,8 +1154,11 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
struct musb_hw_ep *hw_ep = NULL;
u32 rx, tx;
int i, index;
+ unsigned long flags;
cppi = container_of(musb->dma_controller, struct cppi, controller);
+ if (cppi->irq)
+ spin_lock_irqsave(&musb->lock, flags);
tibase = musb->ctrl_base;
@@ -1285,6 +1288,9 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
/* write to CPPI EOI register to re-enable interrupts */
musb_writel(tibase, DAVINCI_CPPI_EOI_REG, 0);
+ if (cppi->irq)
+ spin_unlock_irqrestore(&musb->lock, flags);
+
return IRQ_HANDLED;
}
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index e16ff605c45..66913811af5 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -42,7 +42,7 @@
#include "musb_core.h"
#ifdef CONFIG_MACH_DAVINCI_EVM
-#define GPIO_nVBUS_DRV 144
+#define GPIO_nVBUS_DRV 160
#endif
#include "davinci.h"
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index bfe08f4975a..5eb9318cff7 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1319,7 +1319,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
#endif
u8 reg;
char *type;
- char aInfo[78], aRevision[32], aDate[12];
+ char aInfo[90], aRevision[32], aDate[12];
void __iomem *mbase = musb->mregs;
int status = 0;
int i;
@@ -1521,6 +1521,14 @@ irqreturn_t musb_interrupt(struct musb *musb)
(devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral",
musb->int_usb, musb->int_tx, musb->int_rx);
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ if (is_otg_enabled(musb) || is_peripheral_enabled(musb))
+ if (!musb->gadget_driver) {
+ DBG(5, "No gadget driver loaded\n");
+ return IRQ_HANDLED;
+ }
+#endif
+
/* the core can interrupt us for multiple reasons; docs have
* a generic interrupt flowchart to follow
*/
@@ -2139,7 +2147,7 @@ static int __init musb_probe(struct platform_device *pdev)
return musb_init_controller(dev, irq, base);
}
-static int __devexit musb_remove(struct platform_device *pdev)
+static int __exit musb_remove(struct platform_device *pdev)
{
struct musb *musb = dev_to_musb(&pdev->dev);
void __iomem *ctrl_base = musb->ctrl_base;
@@ -2231,7 +2239,7 @@ static struct platform_driver musb_driver = {
.owner = THIS_MODULE,
.pm = MUSB_DEV_PM_OPS,
},
- .remove = __devexit_p(musb_remove),
+ .remove = __exit_p(musb_remove),
.shutdown = musb_shutdown,
};
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index c49b9ba025a..cbcf14a236e 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -309,7 +309,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
size_t request_size;
/* setup DMA, then program endpoint CSR */
- request_size = min(request->length,
+ request_size = min_t(size_t, request->length,
musb_ep->dma->max_len);
if (request_size < musb_ep->packet_sz)
musb_ep->dma->desired_mode = 0;
@@ -319,7 +319,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
use_dma = use_dma && c->channel_program(
musb_ep->dma, musb_ep->packet_sz,
musb_ep->dma->desired_mode,
- request->dma, request_size);
+ request->dma + request->actual, request_size);
if (use_dma) {
if (musb_ep->dma->desired_mode == 0) {
/*
@@ -515,12 +515,12 @@ void musb_g_tx(struct musb *musb, u8 epnum)
if (csr & MUSB_TXCSR_FIFONOTEMPTY)
return;
- if (!musb_ep->desc) {
+ request = musb_ep->desc ? next_request(musb_ep) : NULL;
+ if (!request) {
DBG(4, "%s idle now\n",
musb_ep->end_point.name);
return;
- } else
- request = next_request(musb_ep);
+ }
}
txstate(musb, to_musb_request(request));
@@ -746,6 +746,8 @@ void musb_g_rx(struct musb *musb, u8 epnum)
musb_ep_select(mbase, epnum);
request = next_request(musb_ep);
+ if (!request)
+ return;
csr = musb_readw(epio, MUSB_RXCSR);
dma = is_dma_capable() ? musb_ep->dma : NULL;
@@ -1731,6 +1733,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
spin_lock_irqsave(&musb->lock, flags);
otg_set_peripheral(musb->xceiv, &musb->g);
+ musb->xceiv->state = OTG_STATE_B_IDLE;
musb->is_active = 1;
/* FIXME this ignores the softconnect flag. Drivers are
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 8fba3f11e47..53d06451f82 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -664,7 +664,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
break;
default:
- ERR("SetupEnd came in a wrong ep0stage %s",
+ ERR("SetupEnd came in a wrong ep0stage %s\n",
decode_ep0stage(musb->ep0_state));
}
csr = musb_readw(regs, MUSB_CSR0);
@@ -787,12 +787,18 @@ setup:
handled = service_zero_data_request(
musb, &setup);
+ /*
+ * We're expecting no data in any case, so
+ * always set the DATAEND bit -- doing this
+ * here helps avoid SetupEnd interrupt coming
+ * in the idle stage when we're stalling...
+ */
+ musb->ackpend |= MUSB_CSR0_P_DATAEND;
+
/* status stage might be immediate */
- if (handled > 0) {
- musb->ackpend |= MUSB_CSR0_P_DATAEND;
+ if (handled > 0)
musb->ep0_state =
MUSB_EP0_STAGE_STATUSIN;
- }
break;
/* sequence #1 (IN to host), includes GET_STATUS
diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c
index d54460a8817..78a20970926 100644
--- a/drivers/usb/otg/isp1301_omap.c
+++ b/drivers/usb/otg/isp1301_omap.c
@@ -843,7 +843,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
static struct platform_device *otg_dev;
-static int otg_init(struct isp1301 *isp)
+static int isp1301_otg_init(struct isp1301 *isp)
{
u32 l;
@@ -1275,7 +1275,7 @@ static int __exit isp1301_remove(struct i2c_client *i2c)
static int isp1301_otg_enable(struct isp1301 *isp)
{
power_up(isp);
- otg_init(isp);
+ isp1301_otg_init(isp);
/* NOTE: since we don't change this, this provides
* a few more interrupts than are strictly needed.
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index f99498fca99..216f187582a 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -44,6 +44,7 @@
#include <linux/serial.h>
#include <linux/usb/serial.h>
#include "ftdi_sio.h"
+#include "ftdi_sio_ids.h"
/*
* Version Information
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 4586a24fafb..b0e0d64f822 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -1,7 +1,10 @@
/*
- * Definitions for the FTDI USB Single Port Serial Converter -
+ * Driver definitions for the FTDI USB Single Port Serial Converter -
* known as FTDI_SIO (Serial Input/Output application of the chipset)
*
+ * For USB vendor/product IDs (VID/PID), please see ftdi_sio_ids.h
+ *
+ *
* The example I have is known as the USC-1000 which is available from
* http://www.dse.co.nz - cat no XH4214 It looks similar to this:
* http://www.dansdata.com/usbser.htm but I can't be sure There are other
@@ -17,880 +20,7 @@
* Bill Ryder - bryder@sgi.com formerly of Silicon Graphics, Inc.- wrote the
* FTDI_SIO implementation.
*
- * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais
- * from Rudolf Gugler
- *
- */
-
-#define FTDI_VID 0x0403 /* Vendor Id */
-#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */
-#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
-#define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */
-#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */
-#define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */
-#define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */
-#define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */
-#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */
-#define FTDI_NF_RIC_PID 0x0001 /* Product Id */
-#define FTDI_USBX_707_PID 0xF857 /* ADSTech IR Blaster USBX-707 */
-
-/* Larsen and Brusgaard AltiTrack/USBtrack */
-#define LARSENBRUSGAARD_VID 0x0FD8
-#define LB_ALTITRACK_PID 0x0001
-
-/* www.canusb.com Lawicel CANUSB device */
-#define FTDI_CANUSB_PID 0xFFA8 /* Product Id */
-
-/* AlphaMicro Components AMC-232USB01 device */
-#define FTDI_AMC232_PID 0xFF00 /* Product Id */
-
-/* www.candapter.com Ewert Energy Systems CANdapter device */
-#define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */
-
-/* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */
-/* the VID is the standard ftdi vid (FTDI_VID) */
-#define FTDI_SCS_DEVICE_0_PID 0xD010 /* SCS PTC-IIusb */
-#define FTDI_SCS_DEVICE_1_PID 0xD011 /* SCS Tracker / DSP TNC */
-#define FTDI_SCS_DEVICE_2_PID 0xD012
-#define FTDI_SCS_DEVICE_3_PID 0xD013
-#define FTDI_SCS_DEVICE_4_PID 0xD014
-#define FTDI_SCS_DEVICE_5_PID 0xD015
-#define FTDI_SCS_DEVICE_6_PID 0xD016
-#define FTDI_SCS_DEVICE_7_PID 0xD017
-
-/* ACT Solutions HomePro ZWave interface (http://www.act-solutions.com/HomePro.htm) */
-#define FTDI_ACTZWAVE_PID 0xF2D0
-
-
-/* www.starting-point-systems.com µChameleon device */
-#define FTDI_MICRO_CHAMELEON_PID 0xCAA0 /* Product Id */
-
-/* www.irtrans.de device */
-#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */
-
-
-/* www.thoughttechnology.com/ TT-USB provide with procomp use ftdi_sio */
-#define FTDI_TTUSB_PID 0xFF20 /* Product Id */
-
-/* iPlus device */
-#define FTDI_IPLUS_PID 0xD070 /* Product Id */
-#define FTDI_IPLUS2_PID 0xD071 /* Product Id */
-
-/* DMX4ALL DMX Interfaces */
-#define FTDI_DMX4ALL 0xC850
-
-/* OpenDCC (www.opendcc.de) product id */
-#define FTDI_OPENDCC_PID 0xBFD8
-#define FTDI_OPENDCC_SNIFFER_PID 0xBFD9
-#define FTDI_OPENDCC_THROTTLE_PID 0xBFDA
-#define FTDI_OPENDCC_GATEWAY_PID 0xBFDB
-
-/* Sprog II (Andrew Crosland's SprogII DCC interface) */
-#define FTDI_SPROG_II 0xF0C8
-
-/* www.crystalfontz.com devices - thanx for providing free devices for evaluation ! */
-/* they use the ftdi chipset for the USB interface and the vendor id is the same */
-#define FTDI_XF_632_PID 0xFC08 /* 632: 16x2 Character Display */
-#define FTDI_XF_634_PID 0xFC09 /* 634: 20x4 Character Display */
-#define FTDI_XF_547_PID 0xFC0A /* 547: Two line Display */
-#define FTDI_XF_633_PID 0xFC0B /* 633: 16x2 Character Display with Keys */
-#define FTDI_XF_631_PID 0xFC0C /* 631: 20x2 Character Display */
-#define FTDI_XF_635_PID 0xFC0D /* 635: 20x4 Character Display */
-#define FTDI_XF_640_PID 0xFC0E /* 640: Two line Display */
-#define FTDI_XF_642_PID 0xFC0F /* 642: Two line Display */
-
-/* Video Networks Limited / Homechoice in the UK use an ftdi-based device for their 1Mb */
-/* broadband internet service. The following PID is exhibited by the usb device supplied */
-/* (the VID is the standard ftdi vid (FTDI_VID) */
-#define FTDI_VNHCPCUSB_D_PID 0xfe38 /* Product Id */
-
-/*
- * PCDJ use ftdi based dj-controllers. The following PID is for their DAC-2 device
- * http://www.pcdjhardware.com/DAC2.asp (PID sent by Wouter Paesen)
- * (the VID is the standard ftdi vid (FTDI_VID) */
-#define FTDI_PCDJ_DAC2_PID 0xFA88
-
-/*
- * The following are the values for the Matrix Orbital LCD displays,
- * which are the FT232BM ( similar to the 8U232AM )
- */
-#define FTDI_MTXORB_0_PID 0xFA00 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_1_PID 0xFA01 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_2_PID 0xFA02 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_3_PID 0xFA03 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_4_PID 0xFA04 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_5_PID 0xFA05 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_6_PID 0xFA06 /* Matrix Orbital Product Id */
-
-/* OOCDlink by Joern Kaipf <joernk@web.de>
- * (http://www.joernonline.de/dw/doku.php?id=start&idx=projects:oocdlink) */
-#define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */
-
-/*
- * The following are the values for the Matrix Orbital FTDI Range
- * Anything in this range will use an FT232RL.
- */
-#define MTXORB_VID 0x1B3D
-#define MTXORB_FTDI_RANGE_0100_PID 0x0100
-#define MTXORB_FTDI_RANGE_0101_PID 0x0101
-#define MTXORB_FTDI_RANGE_0102_PID 0x0102
-#define MTXORB_FTDI_RANGE_0103_PID 0x0103
-#define MTXORB_FTDI_RANGE_0104_PID 0x0104
-#define MTXORB_FTDI_RANGE_0105_PID 0x0105
-#define MTXORB_FTDI_RANGE_0106_PID 0x0106
-#define MTXORB_FTDI_RANGE_0107_PID 0x0107
-#define MTXORB_FTDI_RANGE_0108_PID 0x0108
-#define MTXORB_FTDI_RANGE_0109_PID 0x0109
-#define MTXORB_FTDI_RANGE_010A_PID 0x010A
-#define MTXORB_FTDI_RANGE_010B_PID 0x010B
-#define MTXORB_FTDI_RANGE_010C_PID 0x010C
-#define MTXORB_FTDI_RANGE_010D_PID 0x010D
-#define MTXORB_FTDI_RANGE_010E_PID 0x010E
-#define MTXORB_FTDI_RANGE_010F_PID 0x010F
-#define MTXORB_FTDI_RANGE_0110_PID 0x0110
-#define MTXORB_FTDI_RANGE_0111_PID 0x0111
-#define MTXORB_FTDI_RANGE_0112_PID 0x0112
-#define MTXORB_FTDI_RANGE_0113_PID 0x0113
-#define MTXORB_FTDI_RANGE_0114_PID 0x0114
-#define MTXORB_FTDI_RANGE_0115_PID 0x0115
-#define MTXORB_FTDI_RANGE_0116_PID 0x0116
-#define MTXORB_FTDI_RANGE_0117_PID 0x0117
-#define MTXORB_FTDI_RANGE_0118_PID 0x0118
-#define MTXORB_FTDI_RANGE_0119_PID 0x0119
-#define MTXORB_FTDI_RANGE_011A_PID 0x011A
-#define MTXORB_FTDI_RANGE_011B_PID 0x011B
-#define MTXORB_FTDI_RANGE_011C_PID 0x011C
-#define MTXORB_FTDI_RANGE_011D_PID 0x011D
-#define MTXORB_FTDI_RANGE_011E_PID 0x011E
-#define MTXORB_FTDI_RANGE_011F_PID 0x011F
-#define MTXORB_FTDI_RANGE_0120_PID 0x0120
-#define MTXORB_FTDI_RANGE_0121_PID 0x0121
-#define MTXORB_FTDI_RANGE_0122_PID 0x0122
-#define MTXORB_FTDI_RANGE_0123_PID 0x0123
-#define MTXORB_FTDI_RANGE_0124_PID 0x0124
-#define MTXORB_FTDI_RANGE_0125_PID 0x0125
-#define MTXORB_FTDI_RANGE_0126_PID 0x0126
-#define MTXORB_FTDI_RANGE_0127_PID 0x0127
-#define MTXORB_FTDI_RANGE_0128_PID 0x0128
-#define MTXORB_FTDI_RANGE_0129_PID 0x0129
-#define MTXORB_FTDI_RANGE_012A_PID 0x012A
-#define MTXORB_FTDI_RANGE_012B_PID 0x012B
-#define MTXORB_FTDI_RANGE_012C_PID 0x012C
-#define MTXORB_FTDI_RANGE_012D_PID 0x012D
-#define MTXORB_FTDI_RANGE_012E_PID 0x012E
-#define MTXORB_FTDI_RANGE_012F_PID 0x012F
-#define MTXORB_FTDI_RANGE_0130_PID 0x0130
-#define MTXORB_FTDI_RANGE_0131_PID 0x0131
-#define MTXORB_FTDI_RANGE_0132_PID 0x0132
-#define MTXORB_FTDI_RANGE_0133_PID 0x0133
-#define MTXORB_FTDI_RANGE_0134_PID 0x0134
-#define MTXORB_FTDI_RANGE_0135_PID 0x0135
-#define MTXORB_FTDI_RANGE_0136_PID 0x0136
-#define MTXORB_FTDI_RANGE_0137_PID 0x0137
-#define MTXORB_FTDI_RANGE_0138_PID 0x0138
-#define MTXORB_FTDI_RANGE_0139_PID 0x0139
-#define MTXORB_FTDI_RANGE_013A_PID 0x013A
-#define MTXORB_FTDI_RANGE_013B_PID 0x013B
-#define MTXORB_FTDI_RANGE_013C_PID 0x013C
-#define MTXORB_FTDI_RANGE_013D_PID 0x013D
-#define MTXORB_FTDI_RANGE_013E_PID 0x013E
-#define MTXORB_FTDI_RANGE_013F_PID 0x013F
-#define MTXORB_FTDI_RANGE_0140_PID 0x0140
-#define MTXORB_FTDI_RANGE_0141_PID 0x0141
-#define MTXORB_FTDI_RANGE_0142_PID 0x0142
-#define MTXORB_FTDI_RANGE_0143_PID 0x0143
-#define MTXORB_FTDI_RANGE_0144_PID 0x0144
-#define MTXORB_FTDI_RANGE_0145_PID 0x0145
-#define MTXORB_FTDI_RANGE_0146_PID 0x0146
-#define MTXORB_FTDI_RANGE_0147_PID 0x0147
-#define MTXORB_FTDI_RANGE_0148_PID 0x0148
-#define MTXORB_FTDI_RANGE_0149_PID 0x0149
-#define MTXORB_FTDI_RANGE_014A_PID 0x014A
-#define MTXORB_FTDI_RANGE_014B_PID 0x014B
-#define MTXORB_FTDI_RANGE_014C_PID 0x014C
-#define MTXORB_FTDI_RANGE_014D_PID 0x014D
-#define MTXORB_FTDI_RANGE_014E_PID 0x014E
-#define MTXORB_FTDI_RANGE_014F_PID 0x014F
-#define MTXORB_FTDI_RANGE_0150_PID 0x0150
-#define MTXORB_FTDI_RANGE_0151_PID 0x0151
-#define MTXORB_FTDI_RANGE_0152_PID 0x0152
-#define MTXORB_FTDI_RANGE_0153_PID 0x0153
-#define MTXORB_FTDI_RANGE_0154_PID 0x0154
-#define MTXORB_FTDI_RANGE_0155_PID 0x0155
-#define MTXORB_FTDI_RANGE_0156_PID 0x0156
-#define MTXORB_FTDI_RANGE_0157_PID 0x0157
-#define MTXORB_FTDI_RANGE_0158_PID 0x0158
-#define MTXORB_FTDI_RANGE_0159_PID 0x0159
-#define MTXORB_FTDI_RANGE_015A_PID 0x015A
-#define MTXORB_FTDI_RANGE_015B_PID 0x015B
-#define MTXORB_FTDI_RANGE_015C_PID 0x015C
-#define MTXORB_FTDI_RANGE_015D_PID 0x015D
-#define MTXORB_FTDI_RANGE_015E_PID 0x015E
-#define MTXORB_FTDI_RANGE_015F_PID 0x015F
-#define MTXORB_FTDI_RANGE_0160_PID 0x0160
-#define MTXORB_FTDI_RANGE_0161_PID 0x0161
-#define MTXORB_FTDI_RANGE_0162_PID 0x0162
-#define MTXORB_FTDI_RANGE_0163_PID 0x0163
-#define MTXORB_FTDI_RANGE_0164_PID 0x0164
-#define MTXORB_FTDI_RANGE_0165_PID 0x0165
-#define MTXORB_FTDI_RANGE_0166_PID 0x0166
-#define MTXORB_FTDI_RANGE_0167_PID 0x0167
-#define MTXORB_FTDI_RANGE_0168_PID 0x0168
-#define MTXORB_FTDI_RANGE_0169_PID 0x0169
-#define MTXORB_FTDI_RANGE_016A_PID 0x016A
-#define MTXORB_FTDI_RANGE_016B_PID 0x016B
-#define MTXORB_FTDI_RANGE_016C_PID 0x016C
-#define MTXORB_FTDI_RANGE_016D_PID 0x016D
-#define MTXORB_FTDI_RANGE_016E_PID 0x016E
-#define MTXORB_FTDI_RANGE_016F_PID 0x016F
-#define MTXORB_FTDI_RANGE_0170_PID 0x0170
-#define MTXORB_FTDI_RANGE_0171_PID 0x0171
-#define MTXORB_FTDI_RANGE_0172_PID 0x0172
-#define MTXORB_FTDI_RANGE_0173_PID 0x0173
-#define MTXORB_FTDI_RANGE_0174_PID 0x0174
-#define MTXORB_FTDI_RANGE_0175_PID 0x0175
-#define MTXORB_FTDI_RANGE_0176_PID 0x0176
-#define MTXORB_FTDI_RANGE_0177_PID 0x0177
-#define MTXORB_FTDI_RANGE_0178_PID 0x0178
-#define MTXORB_FTDI_RANGE_0179_PID 0x0179
-#define MTXORB_FTDI_RANGE_017A_PID 0x017A
-#define MTXORB_FTDI_RANGE_017B_PID 0x017B
-#define MTXORB_FTDI_RANGE_017C_PID 0x017C
-#define MTXORB_FTDI_RANGE_017D_PID 0x017D
-#define MTXORB_FTDI_RANGE_017E_PID 0x017E
-#define MTXORB_FTDI_RANGE_017F_PID 0x017F
-#define MTXORB_FTDI_RANGE_0180_PID 0x0180
-#define MTXORB_FTDI_RANGE_0181_PID 0x0181
-#define MTXORB_FTDI_RANGE_0182_PID 0x0182
-#define MTXORB_FTDI_RANGE_0183_PID 0x0183
-#define MTXORB_FTDI_RANGE_0184_PID 0x0184
-#define MTXORB_FTDI_RANGE_0185_PID 0x0185
-#define MTXORB_FTDI_RANGE_0186_PID 0x0186
-#define MTXORB_FTDI_RANGE_0187_PID 0x0187
-#define MTXORB_FTDI_RANGE_0188_PID 0x0188
-#define MTXORB_FTDI_RANGE_0189_PID 0x0189
-#define MTXORB_FTDI_RANGE_018A_PID 0x018A
-#define MTXORB_FTDI_RANGE_018B_PID 0x018B
-#define MTXORB_FTDI_RANGE_018C_PID 0x018C
-#define MTXORB_FTDI_RANGE_018D_PID 0x018D
-#define MTXORB_FTDI_RANGE_018E_PID 0x018E
-#define MTXORB_FTDI_RANGE_018F_PID 0x018F
-#define MTXORB_FTDI_RANGE_0190_PID 0x0190
-#define MTXORB_FTDI_RANGE_0191_PID 0x0191
-#define MTXORB_FTDI_RANGE_0192_PID 0x0192
-#define MTXORB_FTDI_RANGE_0193_PID 0x0193
-#define MTXORB_FTDI_RANGE_0194_PID 0x0194
-#define MTXORB_FTDI_RANGE_0195_PID 0x0195
-#define MTXORB_FTDI_RANGE_0196_PID 0x0196
-#define MTXORB_FTDI_RANGE_0197_PID 0x0197
-#define MTXORB_FTDI_RANGE_0198_PID 0x0198
-#define MTXORB_FTDI_RANGE_0199_PID 0x0199
-#define MTXORB_FTDI_RANGE_019A_PID 0x019A
-#define MTXORB_FTDI_RANGE_019B_PID 0x019B
-#define MTXORB_FTDI_RANGE_019C_PID 0x019C
-#define MTXORB_FTDI_RANGE_019D_PID 0x019D
-#define MTXORB_FTDI_RANGE_019E_PID 0x019E
-#define MTXORB_FTDI_RANGE_019F_PID 0x019F
-#define MTXORB_FTDI_RANGE_01A0_PID 0x01A0
-#define MTXORB_FTDI_RANGE_01A1_PID 0x01A1
-#define MTXORB_FTDI_RANGE_01A2_PID 0x01A2
-#define MTXORB_FTDI_RANGE_01A3_PID 0x01A3
-#define MTXORB_FTDI_RANGE_01A4_PID 0x01A4
-#define MTXORB_FTDI_RANGE_01A5_PID 0x01A5
-#define MTXORB_FTDI_RANGE_01A6_PID 0x01A6
-#define MTXORB_FTDI_RANGE_01A7_PID 0x01A7
-#define MTXORB_FTDI_RANGE_01A8_PID 0x01A8
-#define MTXORB_FTDI_RANGE_01A9_PID 0x01A9
-#define MTXORB_FTDI_RANGE_01AA_PID 0x01AA
-#define MTXORB_FTDI_RANGE_01AB_PID 0x01AB
-#define MTXORB_FTDI_RANGE_01AC_PID 0x01AC
-#define MTXORB_FTDI_RANGE_01AD_PID 0x01AD
-#define MTXORB_FTDI_RANGE_01AE_PID 0x01AE
-#define MTXORB_FTDI_RANGE_01AF_PID 0x01AF
-#define MTXORB_FTDI_RANGE_01B0_PID 0x01B0
-#define MTXORB_FTDI_RANGE_01B1_PID 0x01B1
-#define MTXORB_FTDI_RANGE_01B2_PID 0x01B2
-#define MTXORB_FTDI_RANGE_01B3_PID 0x01B3
-#define MTXORB_FTDI_RANGE_01B4_PID 0x01B4
-#define MTXORB_FTDI_RANGE_01B5_PID 0x01B5
-#define MTXORB_FTDI_RANGE_01B6_PID 0x01B6
-#define MTXORB_FTDI_RANGE_01B7_PID 0x01B7
-#define MTXORB_FTDI_RANGE_01B8_PID 0x01B8
-#define MTXORB_FTDI_RANGE_01B9_PID 0x01B9
-#define MTXORB_FTDI_RANGE_01BA_PID 0x01BA
-#define MTXORB_FTDI_RANGE_01BB_PID 0x01BB
-#define MTXORB_FTDI_RANGE_01BC_PID 0x01BC
-#define MTXORB_FTDI_RANGE_01BD_PID 0x01BD
-#define MTXORB_FTDI_RANGE_01BE_PID 0x01BE
-#define MTXORB_FTDI_RANGE_01BF_PID 0x01BF
-#define MTXORB_FTDI_RANGE_01C0_PID 0x01C0
-#define MTXORB_FTDI_RANGE_01C1_PID 0x01C1
-#define MTXORB_FTDI_RANGE_01C2_PID 0x01C2
-#define MTXORB_FTDI_RANGE_01C3_PID 0x01C3
-#define MTXORB_FTDI_RANGE_01C4_PID 0x01C4
-#define MTXORB_FTDI_RANGE_01C5_PID 0x01C5
-#define MTXORB_FTDI_RANGE_01C6_PID 0x01C6
-#define MTXORB_FTDI_RANGE_01C7_PID 0x01C7
-#define MTXORB_FTDI_RANGE_01C8_PID 0x01C8
-#define MTXORB_FTDI_RANGE_01C9_PID 0x01C9
-#define MTXORB_FTDI_RANGE_01CA_PID 0x01CA
-#define MTXORB_FTDI_RANGE_01CB_PID 0x01CB
-#define MTXORB_FTDI_RANGE_01CC_PID 0x01CC
-#define MTXORB_FTDI_RANGE_01CD_PID 0x01CD
-#define MTXORB_FTDI_RANGE_01CE_PID 0x01CE
-#define MTXORB_FTDI_RANGE_01CF_PID 0x01CF
-#define MTXORB_FTDI_RANGE_01D0_PID 0x01D0
-#define MTXORB_FTDI_RANGE_01D1_PID 0x01D1
-#define MTXORB_FTDI_RANGE_01D2_PID 0x01D2
-#define MTXORB_FTDI_RANGE_01D3_PID 0x01D3
-#define MTXORB_FTDI_RANGE_01D4_PID 0x01D4
-#define MTXORB_FTDI_RANGE_01D5_PID 0x01D5
-#define MTXORB_FTDI_RANGE_01D6_PID 0x01D6
-#define MTXORB_FTDI_RANGE_01D7_PID 0x01D7
-#define MTXORB_FTDI_RANGE_01D8_PID 0x01D8
-#define MTXORB_FTDI_RANGE_01D9_PID 0x01D9
-#define MTXORB_FTDI_RANGE_01DA_PID 0x01DA
-#define MTXORB_FTDI_RANGE_01DB_PID 0x01DB
-#define MTXORB_FTDI_RANGE_01DC_PID 0x01DC
-#define MTXORB_FTDI_RANGE_01DD_PID 0x01DD
-#define MTXORB_FTDI_RANGE_01DE_PID 0x01DE
-#define MTXORB_FTDI_RANGE_01DF_PID 0x01DF
-#define MTXORB_FTDI_RANGE_01E0_PID 0x01E0
-#define MTXORB_FTDI_RANGE_01E1_PID 0x01E1
-#define MTXORB_FTDI_RANGE_01E2_PID 0x01E2
-#define MTXORB_FTDI_RANGE_01E3_PID 0x01E3
-#define MTXORB_FTDI_RANGE_01E4_PID 0x01E4
-#define MTXORB_FTDI_RANGE_01E5_PID 0x01E5
-#define MTXORB_FTDI_RANGE_01E6_PID 0x01E6
-#define MTXORB_FTDI_RANGE_01E7_PID 0x01E7
-#define MTXORB_FTDI_RANGE_01E8_PID 0x01E8
-#define MTXORB_FTDI_RANGE_01E9_PID 0x01E9
-#define MTXORB_FTDI_RANGE_01EA_PID 0x01EA
-#define MTXORB_FTDI_RANGE_01EB_PID 0x01EB
-#define MTXORB_FTDI_RANGE_01EC_PID 0x01EC
-#define MTXORB_FTDI_RANGE_01ED_PID 0x01ED
-#define MTXORB_FTDI_RANGE_01EE_PID 0x01EE
-#define MTXORB_FTDI_RANGE_01EF_PID 0x01EF
-#define MTXORB_FTDI_RANGE_01F0_PID 0x01F0
-#define MTXORB_FTDI_RANGE_01F1_PID 0x01F1
-#define MTXORB_FTDI_RANGE_01F2_PID 0x01F2
-#define MTXORB_FTDI_RANGE_01F3_PID 0x01F3
-#define MTXORB_FTDI_RANGE_01F4_PID 0x01F4
-#define MTXORB_FTDI_RANGE_01F5_PID 0x01F5
-#define MTXORB_FTDI_RANGE_01F6_PID 0x01F6
-#define MTXORB_FTDI_RANGE_01F7_PID 0x01F7
-#define MTXORB_FTDI_RANGE_01F8_PID 0x01F8
-#define MTXORB_FTDI_RANGE_01F9_PID 0x01F9
-#define MTXORB_FTDI_RANGE_01FA_PID 0x01FA
-#define MTXORB_FTDI_RANGE_01FB_PID 0x01FB
-#define MTXORB_FTDI_RANGE_01FC_PID 0x01FC
-#define MTXORB_FTDI_RANGE_01FD_PID 0x01FD
-#define MTXORB_FTDI_RANGE_01FE_PID 0x01FE
-#define MTXORB_FTDI_RANGE_01FF_PID 0x01FF
-
-
-
-/* Interbiometrics USB I/O Board */
-/* Developed for Interbiometrics by Rudolf Gugler */
-#define INTERBIOMETRICS_VID 0x1209
-#define INTERBIOMETRICS_IOBOARD_PID 0x1002
-#define INTERBIOMETRICS_MINI_IOBOARD_PID 0x1006
-
-/*
- * The following are the values for the Perle Systems
- * UltraPort USB serial converters
- */
-#define FTDI_PERLE_ULTRAPORT_PID 0xF0C0 /* Perle UltraPort Product Id */
-
-/*
- * The following are the values for the Sealevel SeaLINK+ adapters.
- * (Original list sent by Tuan Hoang. Ian Abbott renamed the macros and
- * removed some PIDs that don't seem to match any existing products.)
- */
-#define SEALEVEL_VID 0x0c52 /* Sealevel Vendor ID */
-#define SEALEVEL_2101_PID 0x2101 /* SeaLINK+232 (2101/2105) */
-#define SEALEVEL_2102_PID 0x2102 /* SeaLINK+485 (2102) */
-#define SEALEVEL_2103_PID 0x2103 /* SeaLINK+232I (2103) */
-#define SEALEVEL_2104_PID 0x2104 /* SeaLINK+485I (2104) */
-#define SEALEVEL_2106_PID 0x9020 /* SeaLINK+422 (2106) */
-#define SEALEVEL_2201_1_PID 0x2211 /* SeaPORT+2/232 (2201) Port 1 */
-#define SEALEVEL_2201_2_PID 0x2221 /* SeaPORT+2/232 (2201) Port 2 */
-#define SEALEVEL_2202_1_PID 0x2212 /* SeaPORT+2/485 (2202) Port 1 */
-#define SEALEVEL_2202_2_PID 0x2222 /* SeaPORT+2/485 (2202) Port 2 */
-#define SEALEVEL_2203_1_PID 0x2213 /* SeaPORT+2 (2203) Port 1 */
-#define SEALEVEL_2203_2_PID 0x2223 /* SeaPORT+2 (2203) Port 2 */
-#define SEALEVEL_2401_1_PID 0x2411 /* SeaPORT+4/232 (2401) Port 1 */
-#define SEALEVEL_2401_2_PID 0x2421 /* SeaPORT+4/232 (2401) Port 2 */
-#define SEALEVEL_2401_3_PID 0x2431 /* SeaPORT+4/232 (2401) Port 3 */
-#define SEALEVEL_2401_4_PID 0x2441 /* SeaPORT+4/232 (2401) Port 4 */
-#define SEALEVEL_2402_1_PID 0x2412 /* SeaPORT+4/485 (2402) Port 1 */
-#define SEALEVEL_2402_2_PID 0x2422 /* SeaPORT+4/485 (2402) Port 2 */
-#define SEALEVEL_2402_3_PID 0x2432 /* SeaPORT+4/485 (2402) Port 3 */
-#define SEALEVEL_2402_4_PID 0x2442 /* SeaPORT+4/485 (2402) Port 4 */
-#define SEALEVEL_2403_1_PID 0x2413 /* SeaPORT+4 (2403) Port 1 */
-#define SEALEVEL_2403_2_PID 0x2423 /* SeaPORT+4 (2403) Port 2 */
-#define SEALEVEL_2403_3_PID 0x2433 /* SeaPORT+4 (2403) Port 3 */
-#define SEALEVEL_2403_4_PID 0x2443 /* SeaPORT+4 (2403) Port 4 */
-#define SEALEVEL_2801_1_PID 0X2811 /* SeaLINK+8/232 (2801) Port 1 */
-#define SEALEVEL_2801_2_PID 0X2821 /* SeaLINK+8/232 (2801) Port 2 */
-#define SEALEVEL_2801_3_PID 0X2831 /* SeaLINK+8/232 (2801) Port 3 */
-#define SEALEVEL_2801_4_PID 0X2841 /* SeaLINK+8/232 (2801) Port 4 */
-#define SEALEVEL_2801_5_PID 0X2851 /* SeaLINK+8/232 (2801) Port 5 */
-#define SEALEVEL_2801_6_PID 0X2861 /* SeaLINK+8/232 (2801) Port 6 */
-#define SEALEVEL_2801_7_PID 0X2871 /* SeaLINK+8/232 (2801) Port 7 */
-#define SEALEVEL_2801_8_PID 0X2881 /* SeaLINK+8/232 (2801) Port 8 */
-#define SEALEVEL_2802_1_PID 0X2812 /* SeaLINK+8/485 (2802) Port 1 */
-#define SEALEVEL_2802_2_PID 0X2822 /* SeaLINK+8/485 (2802) Port 2 */
-#define SEALEVEL_2802_3_PID 0X2832 /* SeaLINK+8/485 (2802) Port 3 */
-#define SEALEVEL_2802_4_PID 0X2842 /* SeaLINK+8/485 (2802) Port 4 */
-#define SEALEVEL_2802_5_PID 0X2852 /* SeaLINK+8/485 (2802) Port 5 */
-#define SEALEVEL_2802_6_PID 0X2862 /* SeaLINK+8/485 (2802) Port 6 */
-#define SEALEVEL_2802_7_PID 0X2872 /* SeaLINK+8/485 (2802) Port 7 */
-#define SEALEVEL_2802_8_PID 0X2882 /* SeaLINK+8/485 (2802) Port 8 */
-#define SEALEVEL_2803_1_PID 0X2813 /* SeaLINK+8 (2803) Port 1 */
-#define SEALEVEL_2803_2_PID 0X2823 /* SeaLINK+8 (2803) Port 2 */
-#define SEALEVEL_2803_3_PID 0X2833 /* SeaLINK+8 (2803) Port 3 */
-#define SEALEVEL_2803_4_PID 0X2843 /* SeaLINK+8 (2803) Port 4 */
-#define SEALEVEL_2803_5_PID 0X2853 /* SeaLINK+8 (2803) Port 5 */
-#define SEALEVEL_2803_6_PID 0X2863 /* SeaLINK+8 (2803) Port 6 */
-#define SEALEVEL_2803_7_PID 0X2873 /* SeaLINK+8 (2803) Port 7 */
-#define SEALEVEL_2803_8_PID 0X2883 /* SeaLINK+8 (2803) Port 8 */
-
-/*
- * The following are the values for two KOBIL chipcard terminals.
- */
-#define KOBIL_VID 0x0d46 /* KOBIL Vendor ID */
-#define KOBIL_CONV_B1_PID 0x2020 /* KOBIL Konverter for B1 */
-#define KOBIL_CONV_KAAN_PID 0x2021 /* KOBIL_Konverter for KAAN */
-
-/*
- * Icom ID-1 digital transceiver
- */
-
-#define ICOM_ID1_VID 0x0C26
-#define ICOM_ID1_PID 0x0004
-
-/*
- * ASK.fr devices
- */
-#define FTDI_ASK_RDR400_PID 0xC991 /* ASK RDR 400 series card reader */
-
-/*
- * FTDI USB UART chips used in construction projects from the
- * Elektor Electronics magazine (http://elektor-electronics.co.uk)
- */
-#define ELEKTOR_VID 0x0C7D
-#define ELEKTOR_FT323R_PID 0x0005 /* RFID-Reader, issue 09-2006 */
-
-/*
- * DSS-20 Sync Station for Sony Ericsson P800
- */
-#define FTDI_DSS20_PID 0xFC82
-
-/*
- * Home Electronics (www.home-electro.com) USB gadgets
- */
-#define FTDI_HE_TIRA1_PID 0xFA78 /* Tira-1 IR transceiver */
-
-/* USB-UIRT - An infrared receiver and transmitter using the 8U232AM chip */
-/* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */
-#define FTDI_USB_UIRT_PID 0xF850 /* Product Id */
-
-/* TNC-X USB-to-packet-radio adapter, versions prior to 3.0 (DLP module) */
-
-#define FTDI_TNC_X_PID 0xEBE0
-
-/*
- * ELV USB devices submitted by Christian Abt of ELV (www.elv.de).
- * All of these devices use FTDI's vendor ID (0x0403).
- *
- * The previously included PID for the UO 100 module was incorrect.
- * In fact, that PID was for ELV's UR 100 USB-RS232 converter (0xFB58).
- *
- * Armin Laeuger originally sent the PID for the UM 100 module.
- */
-#define FTDI_R2000KU_TRUE_RNG 0xFB80 /* R2000KU TRUE RNG */
-#define FTDI_ELV_UR100_PID 0xFB58 /* USB-RS232-Umsetzer (UR 100) */
-#define FTDI_ELV_UM100_PID 0xFB5A /* USB-Modul UM 100 */
-#define FTDI_ELV_UO100_PID 0xFB5B /* USB-Modul UO 100 */
-#define FTDI_ELV_ALC8500_PID 0xF06E /* ALC 8500 Expert */
-/* Additional ELV PIDs that default to using the FTDI D2XX drivers on
- * MS Windows, rather than the FTDI Virtual Com Port drivers.
- * Maybe these will be easier to use with the libftdi/libusb user-space
- * drivers, or possibly the Comedi drivers in some cases. */
-#define FTDI_ELV_CLI7000_PID 0xFB59 /* Computer-Light-Interface (CLI 7000) */
-#define FTDI_ELV_PPS7330_PID 0xFB5C /* Processor-Power-Supply (PPS 7330) */
-#define FTDI_ELV_TFM100_PID 0xFB5D /* Temperartur-Feuchte Messgeraet (TFM 100) */
-#define FTDI_ELV_UDF77_PID 0xFB5E /* USB DCF Funkurh (UDF 77) */
-#define FTDI_ELV_UIO88_PID 0xFB5F /* USB-I/O Interface (UIO 88) */
-#define FTDI_ELV_UAD8_PID 0xF068 /* USB-AD-Wandler (UAD 8) */
-#define FTDI_ELV_UDA7_PID 0xF069 /* USB-DA-Wandler (UDA 7) */
-#define FTDI_ELV_USI2_PID 0xF06A /* USB-Schrittmotoren-Interface (USI 2) */
-#define FTDI_ELV_T1100_PID 0xF06B /* Thermometer (T 1100) */
-#define FTDI_ELV_PCD200_PID 0xF06C /* PC-Datenlogger (PCD 200) */
-#define FTDI_ELV_ULA200_PID 0xF06D /* USB-LCD-Ansteuerung (ULA 200) */
-#define FTDI_ELV_FHZ1000PC_PID 0xF06F /* FHZ 1000 PC */
-#define FTDI_ELV_CSI8_PID 0xE0F0 /* Computer-Schalt-Interface (CSI 8) */
-#define FTDI_ELV_EM1000DL_PID 0xE0F1 /* PC-Datenlogger fuer Energiemonitor (EM 1000 DL) */
-#define FTDI_ELV_PCK100_PID 0xE0F2 /* PC-Kabeltester (PCK 100) */
-#define FTDI_ELV_RFP500_PID 0xE0F3 /* HF-Leistungsmesser (RFP 500) */
-#define FTDI_ELV_FS20SIG_PID 0xE0F4 /* Signalgeber (FS 20 SIG) */
-#define FTDI_ELV_WS300PC_PID 0xE0F6 /* PC-Wetterstation (WS 300 PC) */
-#define FTDI_ELV_FHZ1300PC_PID 0xE0E8 /* FHZ 1300 PC */
-#define FTDI_ELV_WS500_PID 0xE0E9 /* PC-Wetterstation (WS 500) */
-#define FTDI_ELV_HS485_PID 0xE0EA /* USB to RS-485 adapter */
-#define FTDI_ELV_EM1010PC_PID 0xE0EF /* Engery monitor EM 1010 PC */
-#define FTDI_PHI_FISCO_PID 0xE40B /* PHI Fisco USB to Serial cable */
-
-/*
- * Definitions for ID TECH (www.idt-net.com) devices
- */
-#define IDTECH_VID 0x0ACD /* ID TECH Vendor ID */
-#define IDTECH_IDT1221U_PID 0x0300 /* IDT1221U USB to RS-232 adapter */
-
-/*
- * Definitions for Omnidirectional Control Technology, Inc. devices
- */
-#define OCT_VID 0x0B39 /* OCT vendor ID */
-/* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */
-/* Also rebadged as Dick Smith Electronics (Aus) XH6451 */
-/* Also rebadged as SIIG Inc. model US2308 hardware version 1 */
-#define OCT_US101_PID 0x0421 /* OCT US101 USB to RS-232 */
-
-/* an infrared receiver for user access control with IR tags */
-#define FTDI_PIEGROUP_PID 0xF208 /* Product Id */
-
-/*
- * Definitions for Artemis astronomical USB based cameras
- * Check it at http://www.artemisccd.co.uk/
- */
-#define FTDI_ARTEMIS_PID 0xDF28 /* All Artemis Cameras */
-
-/*
- * Definitions for ATIK Instruments astronomical USB based cameras
- * Check it at http://www.atik-instruments.com/
- */
-#define FTDI_ATIK_ATK16_PID 0xDF30 /* ATIK ATK-16 Grayscale Camera */
-#define FTDI_ATIK_ATK16C_PID 0xDF32 /* ATIK ATK-16C Colour Camera */
-#define FTDI_ATIK_ATK16HR_PID 0xDF31 /* ATIK ATK-16HR Grayscale Camera */
-#define FTDI_ATIK_ATK16HRC_PID 0xDF33 /* ATIK ATK-16HRC Colour Camera */
-#define FTDI_ATIK_ATK16IC_PID 0xDF35 /* ATIK ATK-16IC Grayscale Camera */
-
-/*
- * Protego product ids
- */
-#define PROTEGO_SPECIAL_1 0xFC70 /* special/unknown device */
-#define PROTEGO_R2X0 0xFC71 /* R200-USB TRNG unit (R210, R220, and R230) */
-#define PROTEGO_SPECIAL_3 0xFC72 /* special/unknown device */
-#define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */
-
-/*
- * Gude Analog- und Digitalsysteme GmbH
- */
-#define FTDI_GUDEADS_E808_PID 0xE808
-#define FTDI_GUDEADS_E809_PID 0xE809
-#define FTDI_GUDEADS_E80A_PID 0xE80A
-#define FTDI_GUDEADS_E80B_PID 0xE80B
-#define FTDI_GUDEADS_E80C_PID 0xE80C
-#define FTDI_GUDEADS_E80D_PID 0xE80D
-#define FTDI_GUDEADS_E80E_PID 0xE80E
-#define FTDI_GUDEADS_E80F_PID 0xE80F
-#define FTDI_GUDEADS_E888_PID 0xE888 /* Expert ISDN Control USB */
-#define FTDI_GUDEADS_E889_PID 0xE889 /* USB RS-232 OptoBridge */
-#define FTDI_GUDEADS_E88A_PID 0xE88A
-#define FTDI_GUDEADS_E88B_PID 0xE88B
-#define FTDI_GUDEADS_E88C_PID 0xE88C
-#define FTDI_GUDEADS_E88D_PID 0xE88D
-#define FTDI_GUDEADS_E88E_PID 0xE88E
-#define FTDI_GUDEADS_E88F_PID 0xE88F
-
-/*
- * Linx Technologies product ids
- */
-#define LINX_SDMUSBQSS_PID 0xF448 /* Linx SDM-USB-QS-S */
-#define LINX_MASTERDEVEL2_PID 0xF449 /* Linx Master Development 2.0 */
-#define LINX_FUTURE_0_PID 0xF44A /* Linx future device */
-#define LINX_FUTURE_1_PID 0xF44B /* Linx future device */
-#define LINX_FUTURE_2_PID 0xF44C /* Linx future device */
-
-/* CCS Inc. ICDU/ICDU40 product ID - the FT232BM is used in an in-circuit-debugger */
-/* unit for PIC16's/PIC18's */
-#define FTDI_CCSICDU20_0_PID 0xF9D0
-#define FTDI_CCSICDU40_1_PID 0xF9D1
-#define FTDI_CCSMACHX_2_PID 0xF9D2
-#define FTDI_CCSLOAD_N_GO_3_PID 0xF9D3
-#define FTDI_CCSICDU64_4_PID 0xF9D4
-#define FTDI_CCSPRIME8_5_PID 0xF9D5
-
-/* Inside Accesso contactless reader (http://www.insidefr.com) */
-#define INSIDE_ACCESSO 0xFAD0
-
-/*
- * Intrepid Control Systems (http://www.intrepidcs.com/) ValueCAN and NeoVI
- */
-#define INTREPID_VID 0x093C
-#define INTREPID_VALUECAN_PID 0x0601
-#define INTREPID_NEOVI_PID 0x0701
-
-/*
- * Falcom Wireless Communications GmbH
- */
-#define FALCOM_VID 0x0F94 /* Vendor Id */
-#define FALCOM_TWIST_PID 0x0001 /* Falcom Twist USB GPRS modem */
-#define FALCOM_SAMBA_PID 0x0005 /* Falcom Samba USB GPRS modem */
-
-/*
- * SUUNTO product ids
- */
-#define FTDI_SUUNTO_SPORTS_PID 0xF680 /* Suunto Sports instrument */
-
-/*
- * Oceanic product ids
- */
-#define FTDI_OCEANIC_PID 0xF460 /* Oceanic dive instrument */
-
-/*
- * TTi (Thurlby Thandar Instruments)
- */
-#define TTI_VID 0x103E /* Vendor Id */
-#define TTI_QL355P_PID 0x03E8 /* TTi QL355P power supply */
-
-/*
- * Definitions for B&B Electronics products.
- */
-#define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */
-#define BANDB_USOTL4_PID 0xAC01 /* USOTL4 Isolated RS-485 Converter */
-#define BANDB_USTL4_PID 0xAC02 /* USTL4 RS-485 Converter */
-#define BANDB_USO9ML2_PID 0xAC03 /* USO9ML2 Isolated RS-232 Converter */
-#define BANDB_USOPTL4_PID 0xAC11
-#define BANDB_USPTL4_PID 0xAC12
-#define BANDB_USO9ML2DR_2_PID 0xAC16
-#define BANDB_USO9ML2DR_PID 0xAC17
-#define BANDB_USOPTL4DR2_PID 0xAC18 /* USOPTL4R-2 2-port Isolated RS-232 Converter */
-#define BANDB_USOPTL4DR_PID 0xAC19
-#define BANDB_485USB9F_2W_PID 0xAC25
-#define BANDB_485USB9F_4W_PID 0xAC26
-#define BANDB_232USB9M_PID 0xAC27
-#define BANDB_485USBTB_2W_PID 0xAC33
-#define BANDB_485USBTB_4W_PID 0xAC34
-#define BANDB_TTL5USB9M_PID 0xAC49
-#define BANDB_TTL3USB9M_PID 0xAC50
-#define BANDB_ZZ_PROG1_USB_PID 0xBA02
-
-/*
- * RM Michaelides CANview USB (http://www.rmcan.com)
- * CAN fieldbus interface adapter, added by port GmbH www.port.de)
- * Ian Abbott changed the macro names for consistency.
- */
-#define FTDI_RM_CANVIEW_PID 0xfd60 /* Product Id */
-
-/*
- * EVER Eco Pro UPS (http://www.ever.com.pl/)
- */
-
-#define EVER_ECO_PRO_CDS 0xe520 /* RS-232 converter */
-
-/*
- * 4N-GALAXY.DE PIDs for CAN-USB, USB-RS232, USB-RS422, USB-RS485,
- * USB-TTY activ, USB-TTY passiv. Some PIDs are used by several devices
- * and I'm not entirely sure which are used by which.
- */
-#define FTDI_4N_GALAXY_DE_1_PID 0xF3C0
-#define FTDI_4N_GALAXY_DE_2_PID 0xF3C1
-
-/*
- * Mobility Electronics products.
- */
-#define MOBILITY_VID 0x1342
-#define MOBILITY_USB_SERIAL_PID 0x0202 /* EasiDock USB 200 serial */
-
-/*
- * microHAM product IDs (http://www.microham.com).
- * Submitted by Justin Burket (KL1RL) <zorton@jtan.com>
- * and Mike Studer (K6EEP) <k6eep@hamsoftware.org>.
- * Ian Abbott <abbotti@mev.co.uk> added a few more from the driver INF file.
- */
-#define FTDI_MHAM_KW_PID 0xEEE8 /* USB-KW interface */
-#define FTDI_MHAM_YS_PID 0xEEE9 /* USB-YS interface */
-#define FTDI_MHAM_Y6_PID 0xEEEA /* USB-Y6 interface */
-#define FTDI_MHAM_Y8_PID 0xEEEB /* USB-Y8 interface */
-#define FTDI_MHAM_IC_PID 0xEEEC /* USB-IC interface */
-#define FTDI_MHAM_DB9_PID 0xEEED /* USB-DB9 interface */
-#define FTDI_MHAM_RS232_PID 0xEEEE /* USB-RS232 interface */
-#define FTDI_MHAM_Y9_PID 0xEEEF /* USB-Y9 interface */
-
-/*
- * Active Robots product ids.
- */
-#define FTDI_ACTIVE_ROBOTS_PID 0xE548 /* USB comms board */
-
-/*
- * Xsens Technologies BV products (http://www.xsens.com).
- */
-#define XSENS_CONVERTER_0_PID 0xD388
-#define XSENS_CONVERTER_1_PID 0xD389
-#define XSENS_CONVERTER_2_PID 0xD38A
-#define XSENS_CONVERTER_3_PID 0xD38B
-#define XSENS_CONVERTER_4_PID 0xD38C
-#define XSENS_CONVERTER_5_PID 0xD38D
-#define XSENS_CONVERTER_6_PID 0xD38E
-#define XSENS_CONVERTER_7_PID 0xD38F
-
-/*
- * Teratronik product ids.
- * Submitted by O. Wölfelschneider.
- */
-#define FTDI_TERATRONIK_VCP_PID 0xEC88 /* Teratronik device (preferring VCP driver on windows) */
-#define FTDI_TERATRONIK_D2XX_PID 0xEC89 /* Teratronik device (preferring D2XX driver on windows) */
-
-/*
- * Evolution Robotics products (http://www.evolution.com/).
- * Submitted by Shawn M. Lavelle.
- */
-#define EVOLUTION_VID 0xDEEE /* Vendor ID */
-#define EVOLUTION_ER1_PID 0x0300 /* ER1 Control Module */
-#define EVO_8U232AM_PID 0x02FF /* Evolution robotics RCM2 (FT232AM)*/
-#define EVO_HYBRID_PID 0x0302 /* Evolution robotics RCM4 PID (FT232BM)*/
-#define EVO_RCM4_PID 0x0303 /* Evolution robotics RCM4 PID */
-
-/* Pyramid Computer GmbH */
-#define FTDI_PYRAMID_PID 0xE6C8 /* Pyramid Appliance Display */
-
-/*
- * NDI (www.ndigital.com) product ids
- */
-#define FTDI_NDI_HUC_PID 0xDA70 /* NDI Host USB Converter */
-#define FTDI_NDI_SPECTRA_SCU_PID 0xDA71 /* NDI Spectra SCU */
-#define FTDI_NDI_FUTURE_2_PID 0xDA72 /* NDI future device #2 */
-#define FTDI_NDI_FUTURE_3_PID 0xDA73 /* NDI future device #3 */
-#define FTDI_NDI_AURORA_SCU_PID 0xDA74 /* NDI Aurora SCU */
-
-/*
- * Posiflex inc retail equipment (http://www.posiflex.com.tw)
- */
-#define POSIFLEX_VID 0x0d3a /* Vendor ID */
-#define POSIFLEX_PP7000_PID 0x0300 /* PP-7000II thermal printer */
-
-/*
- * Westrex International devices submitted by Cory Lee
- */
-#define FTDI_WESTREX_MODEL_777_PID 0xDC00 /* Model 777 */
-#define FTDI_WESTREX_MODEL_8900F_PID 0xDC01 /* Model 8900F */
-
-/*
- * RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com)
- */
-#define FTDI_RRCIRKITS_LOCOBUFFER_PID 0xc7d0 /* LocoBuffer USB */
-
-/*
- * Eclo (http://www.eclo.pt/) product IDs.
- * PID 0xEA90 submitted by Martin Grill.
- */
-#define FTDI_ECLO_COM_1WIRE_PID 0xEA90 /* COM to 1-Wire USB adaptor */
-
-/*
- * Papouch products (http://www.papouch.com/)
- * Submitted by Folkert van Heusden
- */
-
-#define PAPOUCH_VID 0x5050 /* Vendor ID */
-#define PAPOUCH_TMU_PID 0x0400 /* TMU USB Thermometer */
-#define PAPOUCH_QUIDO4x4_PID 0x0900 /* Quido 4/4 Module */
-
-/*
- * ACG Identification Technologies GmbH products (http://www.acg.de/).
- * Submitted by anton -at- goto10 -dot- org.
*/
-#define FTDI_ACG_HFDUAL_PID 0xDD20 /* HF Dual ISO Reader (RFID) */
-
-/*
- * Yost Engineering, Inc. products (www.yostengineering.com).
- * PID 0xE050 submitted by Aaron Prose.
- */
-#define FTDI_YEI_SERVOCENTER31_PID 0xE050 /* YEI ServoCenter3.1 USB */
-
-/*
- * ThorLabs USB motor drivers
- */
-#define FTDI_THORLABS_PID 0xfaf0 /* ThorLabs USB motor drivers */
-
-/*
- * Testo products (http://www.testo.com/)
- * Submitted by Colin Leroy
- */
-#define TESTO_VID 0x128D
-#define TESTO_USB_INTERFACE_PID 0x0001
-
-/*
- * Gamma Scout (http://gamma-scout.com/). Submitted by rsc@runtux.com.
- */
-#define FTDI_GAMMA_SCOUT_PID 0xD678 /* Gamma Scout online */
-
-/*
- * Tactrix OpenPort (ECU) devices.
- * OpenPort 1.3M submitted by Donour Sizemore.
- * OpenPort 1.3S and 1.3U submitted by Ian Abbott.
- */
-#define FTDI_TACTRIX_OPENPORT_13M_PID 0xCC48 /* OpenPort 1.3 Mitsubishi */
-#define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */
-#define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */
-
-/*
- * Telldus Technologies
- */
-#define TELLDUS_VID 0x1781 /* Vendor ID */
-#define TELLDUS_TELLSTICK_PID 0x0C30 /* RF control dongle 433 MHz using FT232RL */
-
-/*
- * IBS elektronik product ids
- * Submitted by Thomas Schleusener
- */
-#define FTDI_IBS_US485_PID 0xff38 /* IBS US485 (USB<-->RS422/485 interface) */
-#define FTDI_IBS_PICPRO_PID 0xff39 /* IBS PIC-Programmer */
-#define FTDI_IBS_PCMCIA_PID 0xff3a /* IBS Card reader for PCMCIA SRAM-cards */
-#define FTDI_IBS_PK1_PID 0xff3b /* IBS PK1 - Particel counter */
-#define FTDI_IBS_RS232MON_PID 0xff3c /* IBS RS232 - Monitor */
-#define FTDI_IBS_APP70_PID 0xff3d /* APP 70 (dust monitoring system) */
-#define FTDI_IBS_PEDO_PID 0xff3e /* IBS PEDO-Modem (RF modem 868.35 MHz) */
-#define FTDI_IBS_PROD_PID 0xff3f /* future device */
-
-/*
- * MaxStream devices www.maxstream.net
- */
-#define FTDI_MAXSTREAM_PID 0xEE18 /* Xbee PKG-U Module */
-
-/* Olimex */
-#define OLIMEX_VID 0x15BA
-#define OLIMEX_ARM_USB_OCD_PID 0x0003
-
-/* Luminary Micro Stellaris Boards, VID = FTDI_VID */
-/* FTDI 2332C Dual channel device, side A=245 FIFO (JTAG), Side B=RS232 UART */
-#define LMI_LM3S_DEVEL_BOARD_PID 0xbcd8
-#define LMI_LM3S_EVAL_BOARD_PID 0xbcd9
-
-/* www.elsterelectricity.com Elster Unicom III Optical Probe */
-#define FTDI_ELSTER_UNICOM_PID 0xE700 /* Product Id */
-
-/*
- * The Mobility Lab (TML)
- * Submitted by Pierre Castella
- */
-#define TML_VID 0x1B91 /* Vendor ID */
-#define TML_USB_SERIAL_PID 0x0064 /* USB - Serial Converter */
-
-/* Propox devices */
-#define FTDI_PROPOX_JTAGCABLEII_PID 0xD738
-
-/* Rig Expert Ukraine devices */
-#define FTDI_REU_TINY_PID 0xED22 /* RigExpert Tiny */
-
-/* Domintell products http://www.domintell.com */
-#define FTDI_DOMINTELL_DGQG_PID 0xEF50 /* Master */
-#define FTDI_DOMINTELL_DUSB_PID 0xEF51 /* DUSB01 module */
-
-/* Alti-2 products http://www.alti-2.com */
-#define ALTI2_VID 0x1BC9
-#define ALTI2_N3_PID 0x6001 /* Neptune 3 */
/* Commands */
#define FTDI_SIO_RESET 0 /* Reset the port */
@@ -910,86 +40,6 @@
#define INTERFACE_C 3
#define INTERFACE_D 4
-/*
- * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3
- * Submitted by Harald Welte <laforge@openmoko.org>
- */
-#define FIC_VID 0x1457
-#define FIC_NEO1973_DEBUG_PID 0x5118
-
-/*
- * RATOC REX-USB60F
- */
-#define RATOC_VENDOR_ID 0x0584
-#define RATOC_PRODUCT_ID_USB60F 0xb020
-
-/*
- * DIEBOLD BCS SE923
- */
-#define DIEBOLD_BCS_SE923_PID 0xfb99
-
-/*
- * Atmel STK541
- */
-#define ATMEL_VID 0x03eb /* Vendor ID */
-#define STK541_PID 0x2109 /* Zigbee Controller */
-
-/*
- * Dresden Elektronic Sensor Terminal Board
- */
-#define DE_VID 0x1cf1 /* Vendor ID */
-#define STB_PID 0x0001 /* Sensor Terminal Board */
-#define WHT_PID 0x0004 /* Wireless Handheld Terminal */
-
-/*
- * Blackfin gnICE JTAG
- * http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:gnice
- */
-#define ADI_VID 0x0456
-#define ADI_GNICE_PID 0xF000
-#define ADI_GNICEPLUS_PID 0xF001
-
-/*
- * JETI SPECTROMETER SPECBOS 1201
- * http://www.jeti.com/products/sys/scb/scb1201.php
- */
-#define JETI_VID 0x0c6c
-#define JETI_SPC1201_PID 0x04b2
-
-/*
- * Marvell SheevaPlug
- */
-#define MARVELL_VID 0x9e88
-#define MARVELL_SHEEVAPLUG_PID 0x9e8f
-
-#define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmBH */
-
-/*
- * GN Otometrics (http://www.otometrics.com)
- * Submitted by Ville Sundberg.
- */
-#define GN_OTOMETRICS_VID 0x0c33 /* Vendor ID */
-#define AURICAL_USB_PID 0x0010 /* Aurical USB Audiometer */
-
-/*
- * Bayer Ascensia Contour blood glucose meter USB-converter cable.
- * http://winglucofacts.com/cables/
- */
-#define BAYER_VID 0x1A79
-#define BAYER_CONTOUR_CABLE_PID 0x6001
-
-/*
- * Marvell OpenRD Base, Client
- * http://www.open-rd.org
- * OpenRD Base, Client use VID 0x0403
- */
-#define MARVELL_OPENRD_PID 0x9e90
-
-/*
- * Hameg HO820 and HO870 interface (using VID 0x0403)
- */
-#define HAMEG_HO820_PID 0xed74
-#define HAMEG_HO870_PID 0xed71
/*
* BmRequestType: 1100 0000b
@@ -1504,4 +554,3 @@ typedef enum {
* B2..7 Length of message - (not including Byte 0)
*
*/
-
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
new file mode 100644
index 00000000000..da92b4952ff
--- /dev/null
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -0,0 +1,986 @@
+/*
+ * vendor/product IDs (VID/PID) of devices using FTDI USB serial converters.
+ * Please keep numerically sorted within individual areas, thanks!
+ *
+ * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais
+ * from Rudolf Gugler
+ *
+ */
+
+
+/**********************************/
+/***** devices using FTDI VID *****/
+/**********************************/
+
+
+#define FTDI_VID 0x0403 /* Vendor Id */
+
+
+/*** "original" FTDI device PIDs ***/
+
+#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
+#define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */
+#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */
+#define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */
+#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */
+#define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */
+
+
+/*** third-party PIDs (using FTDI_VID) ***/
+
+/*
+ * Marvell OpenRD Base, Client
+ * http://www.open-rd.org
+ * OpenRD Base, Client use VID 0x0403
+ */
+#define MARVELL_OPENRD_PID 0x9e90
+
+/* www.candapter.com Ewert Energy Systems CANdapter device */
+#define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */
+
+/* OOCDlink by Joern Kaipf <joernk@web.de>
+ * (http://www.joernonline.de/dw/doku.php?id=start&idx=projects:oocdlink) */
+#define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */
+
+/* Luminary Micro Stellaris Boards, VID = FTDI_VID */
+/* FTDI 2332C Dual channel device, side A=245 FIFO (JTAG), Side B=RS232 UART */
+#define LMI_LM3S_DEVEL_BOARD_PID 0xbcd8
+#define LMI_LM3S_EVAL_BOARD_PID 0xbcd9
+
+#define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmBH */
+
+/* OpenDCC (www.opendcc.de) product id */
+#define FTDI_OPENDCC_PID 0xBFD8
+#define FTDI_OPENDCC_SNIFFER_PID 0xBFD9
+#define FTDI_OPENDCC_THROTTLE_PID 0xBFDA
+#define FTDI_OPENDCC_GATEWAY_PID 0xBFDB
+
+/*
+ * RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com)
+ */
+#define FTDI_RRCIRKITS_LOCOBUFFER_PID 0xc7d0 /* LocoBuffer USB */
+
+/* DMX4ALL DMX Interfaces */
+#define FTDI_DMX4ALL 0xC850
+
+/*
+ * ASK.fr devices
+ */
+#define FTDI_ASK_RDR400_PID 0xC991 /* ASK RDR 400 series card reader */
+
+/* www.starting-point-systems.com µChameleon device */
+#define FTDI_MICRO_CHAMELEON_PID 0xCAA0 /* Product Id */
+
+/*
+ * Tactrix OpenPort (ECU) devices.
+ * OpenPort 1.3M submitted by Donour Sizemore.
+ * OpenPort 1.3S and 1.3U submitted by Ian Abbott.
+ */
+#define FTDI_TACTRIX_OPENPORT_13M_PID 0xCC48 /* OpenPort 1.3 Mitsubishi */
+#define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */
+#define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */
+
+/* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */
+/* the VID is the standard ftdi vid (FTDI_VID) */
+#define FTDI_SCS_DEVICE_0_PID 0xD010 /* SCS PTC-IIusb */
+#define FTDI_SCS_DEVICE_1_PID 0xD011 /* SCS Tracker / DSP TNC */
+#define FTDI_SCS_DEVICE_2_PID 0xD012
+#define FTDI_SCS_DEVICE_3_PID 0xD013
+#define FTDI_SCS_DEVICE_4_PID 0xD014
+#define FTDI_SCS_DEVICE_5_PID 0xD015
+#define FTDI_SCS_DEVICE_6_PID 0xD016
+#define FTDI_SCS_DEVICE_7_PID 0xD017
+
+/* iPlus device */
+#define FTDI_IPLUS_PID 0xD070 /* Product Id */
+#define FTDI_IPLUS2_PID 0xD071 /* Product Id */
+
+/*
+ * Gamma Scout (http://gamma-scout.com/). Submitted by rsc@runtux.com.
+ */
+#define FTDI_GAMMA_SCOUT_PID 0xD678 /* Gamma Scout online */
+
+/* Propox devices */
+#define FTDI_PROPOX_JTAGCABLEII_PID 0xD738
+
+/*
+ * Xsens Technologies BV products (http://www.xsens.com).
+ */
+#define XSENS_CONVERTER_0_PID 0xD388
+#define XSENS_CONVERTER_1_PID 0xD389
+#define XSENS_CONVERTER_2_PID 0xD38A
+#define XSENS_CONVERTER_3_PID 0xD38B
+#define XSENS_CONVERTER_4_PID 0xD38C
+#define XSENS_CONVERTER_5_PID 0xD38D
+#define XSENS_CONVERTER_6_PID 0xD38E
+#define XSENS_CONVERTER_7_PID 0xD38F
+
+/*
+ * NDI (www.ndigital.com) product ids
+ */
+#define FTDI_NDI_HUC_PID 0xDA70 /* NDI Host USB Converter */
+#define FTDI_NDI_SPECTRA_SCU_PID 0xDA71 /* NDI Spectra SCU */
+#define FTDI_NDI_FUTURE_2_PID 0xDA72 /* NDI future device #2 */
+#define FTDI_NDI_FUTURE_3_PID 0xDA73 /* NDI future device #3 */
+#define FTDI_NDI_AURORA_SCU_PID 0xDA74 /* NDI Aurora SCU */
+
+/*
+ * Westrex International devices submitted by Cory Lee
+ */
+#define FTDI_WESTREX_MODEL_777_PID 0xDC00 /* Model 777 */
+#define FTDI_WESTREX_MODEL_8900F_PID 0xDC01 /* Model 8900F */
+
+/*
+ * ACG Identification Technologies GmbH products (http://www.acg.de/).
+ * Submitted by anton -at- goto10 -dot- org.
+ */
+#define FTDI_ACG_HFDUAL_PID 0xDD20 /* HF Dual ISO Reader (RFID) */
+
+/*
+ * Definitions for Artemis astronomical USB based cameras
+ * Check it at http://www.artemisccd.co.uk/
+ */
+#define FTDI_ARTEMIS_PID 0xDF28 /* All Artemis Cameras */
+
+/*
+ * Definitions for ATIK Instruments astronomical USB based cameras
+ * Check it at http://www.atik-instruments.com/
+ */
+#define FTDI_ATIK_ATK16_PID 0xDF30 /* ATIK ATK-16 Grayscale Camera */
+#define FTDI_ATIK_ATK16C_PID 0xDF32 /* ATIK ATK-16C Colour Camera */
+#define FTDI_ATIK_ATK16HR_PID 0xDF31 /* ATIK ATK-16HR Grayscale Camera */
+#define FTDI_ATIK_ATK16HRC_PID 0xDF33 /* ATIK ATK-16HRC Colour Camera */
+#define FTDI_ATIK_ATK16IC_PID 0xDF35 /* ATIK ATK-16IC Grayscale Camera */
+
+/*
+ * Yost Engineering, Inc. products (www.yostengineering.com).
+ * PID 0xE050 submitted by Aaron Prose.
+ */
+#define FTDI_YEI_SERVOCENTER31_PID 0xE050 /* YEI ServoCenter3.1 USB */
+
+/*
+ * ELV USB devices submitted by Christian Abt of ELV (www.elv.de).
+ * All of these devices use FTDI's vendor ID (0x0403).
+ *
+ * The previously included PID for the UO 100 module was incorrect.
+ * In fact, that PID was for ELV's UR 100 USB-RS232 converter (0xFB58).
+ *
+ * Armin Laeuger originally sent the PID for the UM 100 module.
+ */
+#define FTDI_ELV_FHZ1300PC_PID 0xE0E8 /* FHZ 1300 PC */
+#define FTDI_ELV_WS500_PID 0xE0E9 /* PC-Wetterstation (WS 500) */
+#define FTDI_ELV_HS485_PID 0xE0EA /* USB to RS-485 adapter */
+#define FTDI_ELV_EM1010PC_PID 0xE0EF /* Engery monitor EM 1010 PC */
+#define FTDI_ELV_CSI8_PID 0xE0F0 /* Computer-Schalt-Interface (CSI 8) */
+#define FTDI_ELV_EM1000DL_PID 0xE0F1 /* PC-Datenlogger fuer Energiemonitor (EM 1000 DL) */
+#define FTDI_ELV_PCK100_PID 0xE0F2 /* PC-Kabeltester (PCK 100) */
+#define FTDI_ELV_RFP500_PID 0xE0F3 /* HF-Leistungsmesser (RFP 500) */
+#define FTDI_ELV_FS20SIG_PID 0xE0F4 /* Signalgeber (FS 20 SIG) */
+#define FTDI_ELV_WS300PC_PID 0xE0F6 /* PC-Wetterstation (WS 300 PC) */
+#define FTDI_PHI_FISCO_PID 0xE40B /* PHI Fisco USB to Serial cable */
+#define FTDI_ELV_UAD8_PID 0xF068 /* USB-AD-Wandler (UAD 8) */
+#define FTDI_ELV_UDA7_PID 0xF069 /* USB-DA-Wandler (UDA 7) */
+#define FTDI_ELV_USI2_PID 0xF06A /* USB-Schrittmotoren-Interface (USI 2) */
+#define FTDI_ELV_T1100_PID 0xF06B /* Thermometer (T 1100) */
+#define FTDI_ELV_PCD200_PID 0xF06C /* PC-Datenlogger (PCD 200) */
+#define FTDI_ELV_ULA200_PID 0xF06D /* USB-LCD-Ansteuerung (ULA 200) */
+#define FTDI_ELV_ALC8500_PID 0xF06E /* ALC 8500 Expert */
+#define FTDI_ELV_FHZ1000PC_PID 0xF06F /* FHZ 1000 PC */
+#define FTDI_ELV_UR100_PID 0xFB58 /* USB-RS232-Umsetzer (UR 100) */
+#define FTDI_ELV_UM100_PID 0xFB5A /* USB-Modul UM 100 */
+#define FTDI_ELV_UO100_PID 0xFB5B /* USB-Modul UO 100 */
+/* Additional ELV PIDs that default to using the FTDI D2XX drivers on
+ * MS Windows, rather than the FTDI Virtual Com Port drivers.
+ * Maybe these will be easier to use with the libftdi/libusb user-space
+ * drivers, or possibly the Comedi drivers in some cases. */
+#define FTDI_ELV_CLI7000_PID 0xFB59 /* Computer-Light-Interface (CLI 7000) */
+#define FTDI_ELV_PPS7330_PID 0xFB5C /* Processor-Power-Supply (PPS 7330) */
+#define FTDI_ELV_TFM100_PID 0xFB5D /* Temperartur-Feuchte Messgeraet (TFM 100) */
+#define FTDI_ELV_UDF77_PID 0xFB5E /* USB DCF Funkurh (UDF 77) */
+#define FTDI_ELV_UIO88_PID 0xFB5F /* USB-I/O Interface (UIO 88) */
+
+/*
+ * EVER Eco Pro UPS (http://www.ever.com.pl/)
+ */
+
+#define EVER_ECO_PRO_CDS 0xe520 /* RS-232 converter */
+
+/*
+ * Active Robots product ids.
+ */
+#define FTDI_ACTIVE_ROBOTS_PID 0xE548 /* USB comms board */
+
+/* Pyramid Computer GmbH */
+#define FTDI_PYRAMID_PID 0xE6C8 /* Pyramid Appliance Display */
+
+/* www.elsterelectricity.com Elster Unicom III Optical Probe */
+#define FTDI_ELSTER_UNICOM_PID 0xE700 /* Product Id */
+
+/*
+ * Gude Analog- und Digitalsysteme GmbH
+ */
+#define FTDI_GUDEADS_E808_PID 0xE808
+#define FTDI_GUDEADS_E809_PID 0xE809
+#define FTDI_GUDEADS_E80A_PID 0xE80A
+#define FTDI_GUDEADS_E80B_PID 0xE80B
+#define FTDI_GUDEADS_E80C_PID 0xE80C
+#define FTDI_GUDEADS_E80D_PID 0xE80D
+#define FTDI_GUDEADS_E80E_PID 0xE80E
+#define FTDI_GUDEADS_E80F_PID 0xE80F
+#define FTDI_GUDEADS_E888_PID 0xE888 /* Expert ISDN Control USB */
+#define FTDI_GUDEADS_E889_PID 0xE889 /* USB RS-232 OptoBridge */
+#define FTDI_GUDEADS_E88A_PID 0xE88A
+#define FTDI_GUDEADS_E88B_PID 0xE88B
+#define FTDI_GUDEADS_E88C_PID 0xE88C
+#define FTDI_GUDEADS_E88D_PID 0xE88D
+#define FTDI_GUDEADS_E88E_PID 0xE88E
+#define FTDI_GUDEADS_E88F_PID 0xE88F
+
+/*
+ * Eclo (http://www.eclo.pt/) product IDs.
+ * PID 0xEA90 submitted by Martin Grill.
+ */
+#define FTDI_ECLO_COM_1WIRE_PID 0xEA90 /* COM to 1-Wire USB adaptor */
+
+/* TNC-X USB-to-packet-radio adapter, versions prior to 3.0 (DLP module) */
+#define FTDI_TNC_X_PID 0xEBE0
+
+/*
+ * Teratronik product ids.
+ * Submitted by O. Wölfelschneider.
+ */
+#define FTDI_TERATRONIK_VCP_PID 0xEC88 /* Teratronik device (preferring VCP driver on windows) */
+#define FTDI_TERATRONIK_D2XX_PID 0xEC89 /* Teratronik device (preferring D2XX driver on windows) */
+
+/* Rig Expert Ukraine devices */
+#define FTDI_REU_TINY_PID 0xED22 /* RigExpert Tiny */
+
+/*
+ * Hameg HO820 and HO870 interface (using VID 0x0403)
+ */
+#define HAMEG_HO820_PID 0xed74
+#define HAMEG_HO870_PID 0xed71
+
+/*
+ * MaxStream devices www.maxstream.net
+ */
+#define FTDI_MAXSTREAM_PID 0xEE18 /* Xbee PKG-U Module */
+
+/*
+ * microHAM product IDs (http://www.microham.com).
+ * Submitted by Justin Burket (KL1RL) <zorton@jtan.com>
+ * and Mike Studer (K6EEP) <k6eep@hamsoftware.org>.
+ * Ian Abbott <abbotti@mev.co.uk> added a few more from the driver INF file.
+ */
+#define FTDI_MHAM_KW_PID 0xEEE8 /* USB-KW interface */
+#define FTDI_MHAM_YS_PID 0xEEE9 /* USB-YS interface */
+#define FTDI_MHAM_Y6_PID 0xEEEA /* USB-Y6 interface */
+#define FTDI_MHAM_Y8_PID 0xEEEB /* USB-Y8 interface */
+#define FTDI_MHAM_IC_PID 0xEEEC /* USB-IC interface */
+#define FTDI_MHAM_DB9_PID 0xEEED /* USB-DB9 interface */
+#define FTDI_MHAM_RS232_PID 0xEEEE /* USB-RS232 interface */
+#define FTDI_MHAM_Y9_PID 0xEEEF /* USB-Y9 interface */
+
+/* Domintell products http://www.domintell.com */
+#define FTDI_DOMINTELL_DGQG_PID 0xEF50 /* Master */
+#define FTDI_DOMINTELL_DUSB_PID 0xEF51 /* DUSB01 module */
+
+/*
+ * The following are the values for the Perle Systems
+ * UltraPort USB serial converters
+ */
+#define FTDI_PERLE_ULTRAPORT_PID 0xF0C0 /* Perle UltraPort Product Id */
+
+/* Sprog II (Andrew Crosland's SprogII DCC interface) */
+#define FTDI_SPROG_II 0xF0C8
+
+/* an infrared receiver for user access control with IR tags */
+#define FTDI_PIEGROUP_PID 0xF208 /* Product Id */
+
+/* ACT Solutions HomePro ZWave interface
+ (http://www.act-solutions.com/HomePro.htm) */
+#define FTDI_ACTZWAVE_PID 0xF2D0
+
+/*
+ * 4N-GALAXY.DE PIDs for CAN-USB, USB-RS232, USB-RS422, USB-RS485,
+ * USB-TTY activ, USB-TTY passiv. Some PIDs are used by several devices
+ * and I'm not entirely sure which are used by which.
+ */
+#define FTDI_4N_GALAXY_DE_1_PID 0xF3C0
+#define FTDI_4N_GALAXY_DE_2_PID 0xF3C1
+
+/*
+ * Linx Technologies product ids
+ */
+#define LINX_SDMUSBQSS_PID 0xF448 /* Linx SDM-USB-QS-S */
+#define LINX_MASTERDEVEL2_PID 0xF449 /* Linx Master Development 2.0 */
+#define LINX_FUTURE_0_PID 0xF44A /* Linx future device */
+#define LINX_FUTURE_1_PID 0xF44B /* Linx future device */
+#define LINX_FUTURE_2_PID 0xF44C /* Linx future device */
+
+/*
+ * Oceanic product ids
+ */
+#define FTDI_OCEANIC_PID 0xF460 /* Oceanic dive instrument */
+
+/*
+ * SUUNTO product ids
+ */
+#define FTDI_SUUNTO_SPORTS_PID 0xF680 /* Suunto Sports instrument */
+
+/* USB-UIRT - An infrared receiver and transmitter using the 8U232AM chip */
+/* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */
+#define FTDI_USB_UIRT_PID 0xF850 /* Product Id */
+
+/* CCS Inc. ICDU/ICDU40 product ID -
+ * the FT232BM is used in an in-circuit-debugger unit for PIC16's/PIC18's */
+#define FTDI_CCSICDU20_0_PID 0xF9D0
+#define FTDI_CCSICDU40_1_PID 0xF9D1
+#define FTDI_CCSMACHX_2_PID 0xF9D2
+#define FTDI_CCSLOAD_N_GO_3_PID 0xF9D3
+#define FTDI_CCSICDU64_4_PID 0xF9D4
+#define FTDI_CCSPRIME8_5_PID 0xF9D5
+
+/*
+ * The following are the values for the Matrix Orbital LCD displays,
+ * which are the FT232BM ( similar to the 8U232AM )
+ */
+#define FTDI_MTXORB_0_PID 0xFA00 /* Matrix Orbital Product Id */
+#define FTDI_MTXORB_1_PID 0xFA01 /* Matrix Orbital Product Id */
+#define FTDI_MTXORB_2_PID 0xFA02 /* Matrix Orbital Product Id */
+#define FTDI_MTXORB_3_PID 0xFA03 /* Matrix Orbital Product Id */
+#define FTDI_MTXORB_4_PID 0xFA04 /* Matrix Orbital Product Id */
+#define FTDI_MTXORB_5_PID 0xFA05 /* Matrix Orbital Product Id */
+#define FTDI_MTXORB_6_PID 0xFA06 /* Matrix Orbital Product Id */
+
+/*
+ * Home Electronics (www.home-electro.com) USB gadgets
+ */
+#define FTDI_HE_TIRA1_PID 0xFA78 /* Tira-1 IR transceiver */
+
+/* Inside Accesso contactless reader (http://www.insidefr.com) */
+#define INSIDE_ACCESSO 0xFAD0
+
+/*
+ * ThorLabs USB motor drivers
+ */
+#define FTDI_THORLABS_PID 0xfaf0 /* ThorLabs USB motor drivers */
+
+/*
+ * Protego product ids
+ */
+#define PROTEGO_SPECIAL_1 0xFC70 /* special/unknown device */
+#define PROTEGO_R2X0 0xFC71 /* R200-USB TRNG unit (R210, R220, and R230) */
+#define PROTEGO_SPECIAL_3 0xFC72 /* special/unknown device */
+#define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */
+
+/*
+ * DSS-20 Sync Station for Sony Ericsson P800
+ */
+#define FTDI_DSS20_PID 0xFC82
+
+/* www.irtrans.de device */
+#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */
+
+/*
+ * RM Michaelides CANview USB (http://www.rmcan.com) (FTDI_VID)
+ * CAN fieldbus interface adapter, added by port GmbH www.port.de)
+ * Ian Abbott changed the macro names for consistency.
+ */
+#define FTDI_RM_CANVIEW_PID 0xfd60 /* Product Id */
+/* www.thoughttechnology.com/ TT-USB provide with procomp use ftdi_sio */
+#define FTDI_TTUSB_PID 0xFF20 /* Product Id */
+
+#define FTDI_USBX_707_PID 0xF857 /* ADSTech IR Blaster USBX-707 (FTDI_VID) */
+
+#define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */
+
+/*
+ * PCDJ use ftdi based dj-controllers. The following PID is
+ * for their DAC-2 device http://www.pcdjhardware.com/DAC2.asp
+ * (the VID is the standard ftdi vid (FTDI_VID), PID sent by Wouter Paesen)
+ */
+#define FTDI_PCDJ_DAC2_PID 0xFA88
+
+#define FTDI_R2000KU_TRUE_RNG 0xFB80 /* R2000KU TRUE RNG (FTDI_VID) */
+
+/*
+ * DIEBOLD BCS SE923 (FTDI_VID)
+ */
+#define DIEBOLD_BCS_SE923_PID 0xfb99
+
+/* www.crystalfontz.com devices
+ * - thanx for providing free devices for evaluation !
+ * they use the ftdi chipset for the USB interface
+ * and the vendor id is the same
+ */
+#define FTDI_XF_632_PID 0xFC08 /* 632: 16x2 Character Display */
+#define FTDI_XF_634_PID 0xFC09 /* 634: 20x4 Character Display */
+#define FTDI_XF_547_PID 0xFC0A /* 547: Two line Display */
+#define FTDI_XF_633_PID 0xFC0B /* 633: 16x2 Character Display with Keys */
+#define FTDI_XF_631_PID 0xFC0C /* 631: 20x2 Character Display */
+#define FTDI_XF_635_PID 0xFC0D /* 635: 20x4 Character Display */
+#define FTDI_XF_640_PID 0xFC0E /* 640: Two line Display */
+#define FTDI_XF_642_PID 0xFC0F /* 642: Two line Display */
+
+/*
+ * Video Networks Limited / Homechoice in the UK use an ftdi-based device
+ * for their 1Mb broadband internet service. The following PID is exhibited
+ * by the usb device supplied (the VID is the standard ftdi vid (FTDI_VID)
+ */
+#define FTDI_VNHCPCUSB_D_PID 0xfe38 /* Product Id */
+
+/* AlphaMicro Components AMC-232USB01 device (FTDI_VID) */
+#define FTDI_AMC232_PID 0xFF00 /* Product Id */
+
+/*
+ * IBS elektronik product ids (FTDI_VID)
+ * Submitted by Thomas Schleusener
+ */
+#define FTDI_IBS_US485_PID 0xff38 /* IBS US485 (USB<-->RS422/485 interface) */
+#define FTDI_IBS_PICPRO_PID 0xff39 /* IBS PIC-Programmer */
+#define FTDI_IBS_PCMCIA_PID 0xff3a /* IBS Card reader for PCMCIA SRAM-cards */
+#define FTDI_IBS_PK1_PID 0xff3b /* IBS PK1 - Particel counter */
+#define FTDI_IBS_RS232MON_PID 0xff3c /* IBS RS232 - Monitor */
+#define FTDI_IBS_APP70_PID 0xff3d /* APP 70 (dust monitoring system) */
+#define FTDI_IBS_PEDO_PID 0xff3e /* IBS PEDO-Modem (RF modem 868.35 MHz) */
+#define FTDI_IBS_PROD_PID 0xff3f /* future device */
+/* www.canusb.com Lawicel CANUSB device (FTDI_VID) */
+#define FTDI_CANUSB_PID 0xFFA8 /* Product Id */
+
+
+
+/********************************/
+/** third-party VID/PID combos **/
+/********************************/
+
+
+
+/*
+ * Atmel STK541
+ */
+#define ATMEL_VID 0x03eb /* Vendor ID */
+#define STK541_PID 0x2109 /* Zigbee Controller */
+
+/*
+ * Blackfin gnICE JTAG
+ * http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:gnice
+ */
+#define ADI_VID 0x0456
+#define ADI_GNICE_PID 0xF000
+#define ADI_GNICEPLUS_PID 0xF001
+
+/*
+ * RATOC REX-USB60F
+ */
+#define RATOC_VENDOR_ID 0x0584
+#define RATOC_PRODUCT_ID_USB60F 0xb020
+
+/*
+ * Definitions for B&B Electronics products.
+ */
+#define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */
+#define BANDB_USOTL4_PID 0xAC01 /* USOTL4 Isolated RS-485 Converter */
+#define BANDB_USTL4_PID 0xAC02 /* USTL4 RS-485 Converter */
+#define BANDB_USO9ML2_PID 0xAC03 /* USO9ML2 Isolated RS-232 Converter */
+#define BANDB_USOPTL4_PID 0xAC11
+#define BANDB_USPTL4_PID 0xAC12
+#define BANDB_USO9ML2DR_2_PID 0xAC16
+#define BANDB_USO9ML2DR_PID 0xAC17
+#define BANDB_USOPTL4DR2_PID 0xAC18 /* USOPTL4R-2 2-port Isolated RS-232 Converter */
+#define BANDB_USOPTL4DR_PID 0xAC19
+#define BANDB_485USB9F_2W_PID 0xAC25
+#define BANDB_485USB9F_4W_PID 0xAC26
+#define BANDB_232USB9M_PID 0xAC27
+#define BANDB_485USBTB_2W_PID 0xAC33
+#define BANDB_485USBTB_4W_PID 0xAC34
+#define BANDB_TTL5USB9M_PID 0xAC49
+#define BANDB_TTL3USB9M_PID 0xAC50
+#define BANDB_ZZ_PROG1_USB_PID 0xBA02
+
+/*
+ * Intrepid Control Systems (http://www.intrepidcs.com/) ValueCAN and NeoVI
+ */
+#define INTREPID_VID 0x093C
+#define INTREPID_VALUECAN_PID 0x0601
+#define INTREPID_NEOVI_PID 0x0701
+
+/*
+ * Definitions for ID TECH (www.idt-net.com) devices
+ */
+#define IDTECH_VID 0x0ACD /* ID TECH Vendor ID */
+#define IDTECH_IDT1221U_PID 0x0300 /* IDT1221U USB to RS-232 adapter */
+
+/*
+ * Definitions for Omnidirectional Control Technology, Inc. devices
+ */
+#define OCT_VID 0x0B39 /* OCT vendor ID */
+/* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */
+/* Also rebadged as Dick Smith Electronics (Aus) XH6451 */
+/* Also rebadged as SIIG Inc. model US2308 hardware version 1 */
+#define OCT_US101_PID 0x0421 /* OCT US101 USB to RS-232 */
+
+/*
+ * Icom ID-1 digital transceiver
+ */
+
+#define ICOM_ID1_VID 0x0C26
+#define ICOM_ID1_PID 0x0004
+
+/*
+ * GN Otometrics (http://www.otometrics.com)
+ * Submitted by Ville Sundberg.
+ */
+#define GN_OTOMETRICS_VID 0x0c33 /* Vendor ID */
+#define AURICAL_USB_PID 0x0010 /* Aurical USB Audiometer */
+
+/*
+ * The following are the values for the Sealevel SeaLINK+ adapters.
+ * (Original list sent by Tuan Hoang. Ian Abbott renamed the macros and
+ * removed some PIDs that don't seem to match any existing products.)
+ */
+#define SEALEVEL_VID 0x0c52 /* Sealevel Vendor ID */
+#define SEALEVEL_2101_PID 0x2101 /* SeaLINK+232 (2101/2105) */
+#define SEALEVEL_2102_PID 0x2102 /* SeaLINK+485 (2102) */
+#define SEALEVEL_2103_PID 0x2103 /* SeaLINK+232I (2103) */
+#define SEALEVEL_2104_PID 0x2104 /* SeaLINK+485I (2104) */
+#define SEALEVEL_2106_PID 0x9020 /* SeaLINK+422 (2106) */
+#define SEALEVEL_2201_1_PID 0x2211 /* SeaPORT+2/232 (2201) Port 1 */
+#define SEALEVEL_2201_2_PID 0x2221 /* SeaPORT+2/232 (2201) Port 2 */
+#define SEALEVEL_2202_1_PID 0x2212 /* SeaPORT+2/485 (2202) Port 1 */
+#define SEALEVEL_2202_2_PID 0x2222 /* SeaPORT+2/485 (2202) Port 2 */
+#define SEALEVEL_2203_1_PID 0x2213 /* SeaPORT+2 (2203) Port 1 */
+#define SEALEVEL_2203_2_PID 0x2223 /* SeaPORT+2 (2203) Port 2 */
+#define SEALEVEL_2401_1_PID 0x2411 /* SeaPORT+4/232 (2401) Port 1 */
+#define SEALEVEL_2401_2_PID 0x2421 /* SeaPORT+4/232 (2401) Port 2 */
+#define SEALEVEL_2401_3_PID 0x2431 /* SeaPORT+4/232 (2401) Port 3 */
+#define SEALEVEL_2401_4_PID 0x2441 /* SeaPORT+4/232 (2401) Port 4 */
+#define SEALEVEL_2402_1_PID 0x2412 /* SeaPORT+4/485 (2402) Port 1 */
+#define SEALEVEL_2402_2_PID 0x2422 /* SeaPORT+4/485 (2402) Port 2 */
+#define SEALEVEL_2402_3_PID 0x2432 /* SeaPORT+4/485 (2402) Port 3 */
+#define SEALEVEL_2402_4_PID 0x2442 /* SeaPORT+4/485 (2402) Port 4 */
+#define SEALEVEL_2403_1_PID 0x2413 /* SeaPORT+4 (2403) Port 1 */
+#define SEALEVEL_2403_2_PID 0x2423 /* SeaPORT+4 (2403) Port 2 */
+#define SEALEVEL_2403_3_PID 0x2433 /* SeaPORT+4 (2403) Port 3 */
+#define SEALEVEL_2403_4_PID 0x2443 /* SeaPORT+4 (2403) Port 4 */
+#define SEALEVEL_2801_1_PID 0X2811 /* SeaLINK+8/232 (2801) Port 1 */
+#define SEALEVEL_2801_2_PID 0X2821 /* SeaLINK+8/232 (2801) Port 2 */
+#define SEALEVEL_2801_3_PID 0X2831 /* SeaLINK+8/232 (2801) Port 3 */
+#define SEALEVEL_2801_4_PID 0X2841 /* SeaLINK+8/232 (2801) Port 4 */
+#define SEALEVEL_2801_5_PID 0X2851 /* SeaLINK+8/232 (2801) Port 5 */
+#define SEALEVEL_2801_6_PID 0X2861 /* SeaLINK+8/232 (2801) Port 6 */
+#define SEALEVEL_2801_7_PID 0X2871 /* SeaLINK+8/232 (2801) Port 7 */
+#define SEALEVEL_2801_8_PID 0X2881 /* SeaLINK+8/232 (2801) Port 8 */
+#define SEALEVEL_2802_1_PID 0X2812 /* SeaLINK+8/485 (2802) Port 1 */
+#define SEALEVEL_2802_2_PID 0X2822 /* SeaLINK+8/485 (2802) Port 2 */
+#define SEALEVEL_2802_3_PID 0X2832 /* SeaLINK+8/485 (2802) Port 3 */
+#define SEALEVEL_2802_4_PID 0X2842 /* SeaLINK+8/485 (2802) Port 4 */
+#define SEALEVEL_2802_5_PID 0X2852 /* SeaLINK+8/485 (2802) Port 5 */
+#define SEALEVEL_2802_6_PID 0X2862 /* SeaLINK+8/485 (2802) Port 6 */
+#define SEALEVEL_2802_7_PID 0X2872 /* SeaLINK+8/485 (2802) Port 7 */
+#define SEALEVEL_2802_8_PID 0X2882 /* SeaLINK+8/485 (2802) Port 8 */
+#define SEALEVEL_2803_1_PID 0X2813 /* SeaLINK+8 (2803) Port 1 */
+#define SEALEVEL_2803_2_PID 0X2823 /* SeaLINK+8 (2803) Port 2 */
+#define SEALEVEL_2803_3_PID 0X2833 /* SeaLINK+8 (2803) Port 3 */
+#define SEALEVEL_2803_4_PID 0X2843 /* SeaLINK+8 (2803) Port 4 */
+#define SEALEVEL_2803_5_PID 0X2853 /* SeaLINK+8 (2803) Port 5 */
+#define SEALEVEL_2803_6_PID 0X2863 /* SeaLINK+8 (2803) Port 6 */
+#define SEALEVEL_2803_7_PID 0X2873 /* SeaLINK+8 (2803) Port 7 */
+#define SEALEVEL_2803_8_PID 0X2883 /* SeaLINK+8 (2803) Port 8 */
+
+/*
+ * JETI SPECTROMETER SPECBOS 1201
+ * http://www.jeti.com/products/sys/scb/scb1201.php
+ */
+#define JETI_VID 0x0c6c
+#define JETI_SPC1201_PID 0x04b2
+
+/*
+ * FTDI USB UART chips used in construction projects from the
+ * Elektor Electronics magazine (http://elektor-electronics.co.uk)
+ */
+#define ELEKTOR_VID 0x0C7D
+#define ELEKTOR_FT323R_PID 0x0005 /* RFID-Reader, issue 09-2006 */
+
+/*
+ * Posiflex inc retail equipment (http://www.posiflex.com.tw)
+ */
+#define POSIFLEX_VID 0x0d3a /* Vendor ID */
+#define POSIFLEX_PP7000_PID 0x0300 /* PP-7000II thermal printer */
+
+/*
+ * The following are the values for two KOBIL chipcard terminals.
+ */
+#define KOBIL_VID 0x0d46 /* KOBIL Vendor ID */
+#define KOBIL_CONV_B1_PID 0x2020 /* KOBIL Konverter for B1 */
+#define KOBIL_CONV_KAAN_PID 0x2021 /* KOBIL_Konverter for KAAN */
+
+#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */
+#define FTDI_NF_RIC_PID 0x0001 /* Product Id */
+
+/*
+ * Falcom Wireless Communications GmbH
+ */
+#define FALCOM_VID 0x0F94 /* Vendor Id */
+#define FALCOM_TWIST_PID 0x0001 /* Falcom Twist USB GPRS modem */
+#define FALCOM_SAMBA_PID 0x0005 /* Falcom Samba USB GPRS modem */
+
+/* Larsen and Brusgaard AltiTrack/USBtrack */
+#define LARSENBRUSGAARD_VID 0x0FD8
+#define LB_ALTITRACK_PID 0x0001
+
+/*
+ * TTi (Thurlby Thandar Instruments)
+ */
+#define TTI_VID 0x103E /* Vendor Id */
+#define TTI_QL355P_PID 0x03E8 /* TTi QL355P power supply */
+
+/* Interbiometrics USB I/O Board */
+/* Developed for Interbiometrics by Rudolf Gugler */
+#define INTERBIOMETRICS_VID 0x1209
+#define INTERBIOMETRICS_IOBOARD_PID 0x1002
+#define INTERBIOMETRICS_MINI_IOBOARD_PID 0x1006
+
+/*
+ * Testo products (http://www.testo.com/)
+ * Submitted by Colin Leroy
+ */
+#define TESTO_VID 0x128D
+#define TESTO_USB_INTERFACE_PID 0x0001
+
+/*
+ * Mobility Electronics products.
+ */
+#define MOBILITY_VID 0x1342
+#define MOBILITY_USB_SERIAL_PID 0x0202 /* EasiDock USB 200 serial */
+
+/*
+ * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3
+ * Submitted by Harald Welte <laforge@openmoko.org>
+ */
+#define FIC_VID 0x1457
+#define FIC_NEO1973_DEBUG_PID 0x5118
+
+/* Olimex */
+#define OLIMEX_VID 0x15BA
+#define OLIMEX_ARM_USB_OCD_PID 0x0003
+
+/*
+ * Telldus Technologies
+ */
+#define TELLDUS_VID 0x1781 /* Vendor ID */
+#define TELLDUS_TELLSTICK_PID 0x0C30 /* RF control dongle 433 MHz using FT232RL */
+
+/*
+ * Bayer Ascensia Contour blood glucose meter USB-converter cable.
+ * http://winglucofacts.com/cables/
+ */
+#define BAYER_VID 0x1A79
+#define BAYER_CONTOUR_CABLE_PID 0x6001
+
+/*
+ * The following are the values for the Matrix Orbital FTDI Range
+ * Anything in this range will use an FT232RL.
+ */
+#define MTXORB_VID 0x1B3D
+#define MTXORB_FTDI_RANGE_0100_PID 0x0100
+#define MTXORB_FTDI_RANGE_0101_PID 0x0101
+#define MTXORB_FTDI_RANGE_0102_PID 0x0102
+#define MTXORB_FTDI_RANGE_0103_PID 0x0103
+#define MTXORB_FTDI_RANGE_0104_PID 0x0104
+#define MTXORB_FTDI_RANGE_0105_PID 0x0105
+#define MTXORB_FTDI_RANGE_0106_PID 0x0106
+#define MTXORB_FTDI_RANGE_0107_PID 0x0107
+#define MTXORB_FTDI_RANGE_0108_PID 0x0108
+#define MTXORB_FTDI_RANGE_0109_PID 0x0109
+#define MTXORB_FTDI_RANGE_010A_PID 0x010A
+#define MTXORB_FTDI_RANGE_010B_PID 0x010B
+#define MTXORB_FTDI_RANGE_010C_PID 0x010C
+#define MTXORB_FTDI_RANGE_010D_PID 0x010D
+#define MTXORB_FTDI_RANGE_010E_PID 0x010E
+#define MTXORB_FTDI_RANGE_010F_PID 0x010F
+#define MTXORB_FTDI_RANGE_0110_PID 0x0110
+#define MTXORB_FTDI_RANGE_0111_PID 0x0111
+#define MTXORB_FTDI_RANGE_0112_PID 0x0112
+#define MTXORB_FTDI_RANGE_0113_PID 0x0113
+#define MTXORB_FTDI_RANGE_0114_PID 0x0114
+#define MTXORB_FTDI_RANGE_0115_PID 0x0115
+#define MTXORB_FTDI_RANGE_0116_PID 0x0116
+#define MTXORB_FTDI_RANGE_0117_PID 0x0117
+#define MTXORB_FTDI_RANGE_0118_PID 0x0118
+#define MTXORB_FTDI_RANGE_0119_PID 0x0119
+#define MTXORB_FTDI_RANGE_011A_PID 0x011A
+#define MTXORB_FTDI_RANGE_011B_PID 0x011B
+#define MTXORB_FTDI_RANGE_011C_PID 0x011C
+#define MTXORB_FTDI_RANGE_011D_PID 0x011D
+#define MTXORB_FTDI_RANGE_011E_PID 0x011E
+#define MTXORB_FTDI_RANGE_011F_PID 0x011F
+#define MTXORB_FTDI_RANGE_0120_PID 0x0120
+#define MTXORB_FTDI_RANGE_0121_PID 0x0121
+#define MTXORB_FTDI_RANGE_0122_PID 0x0122
+#define MTXORB_FTDI_RANGE_0123_PID 0x0123
+#define MTXORB_FTDI_RANGE_0124_PID 0x0124
+#define MTXORB_FTDI_RANGE_0125_PID 0x0125
+#define MTXORB_FTDI_RANGE_0126_PID 0x0126
+#define MTXORB_FTDI_RANGE_0127_PID 0x0127
+#define MTXORB_FTDI_RANGE_0128_PID 0x0128
+#define MTXORB_FTDI_RANGE_0129_PID 0x0129
+#define MTXORB_FTDI_RANGE_012A_PID 0x012A
+#define MTXORB_FTDI_RANGE_012B_PID 0x012B
+#define MTXORB_FTDI_RANGE_012C_PID 0x012C
+#define MTXORB_FTDI_RANGE_012D_PID 0x012D
+#define MTXORB_FTDI_RANGE_012E_PID 0x012E
+#define MTXORB_FTDI_RANGE_012F_PID 0x012F
+#define MTXORB_FTDI_RANGE_0130_PID 0x0130
+#define MTXORB_FTDI_RANGE_0131_PID 0x0131
+#define MTXORB_FTDI_RANGE_0132_PID 0x0132
+#define MTXORB_FTDI_RANGE_0133_PID 0x0133
+#define MTXORB_FTDI_RANGE_0134_PID 0x0134
+#define MTXORB_FTDI_RANGE_0135_PID 0x0135
+#define MTXORB_FTDI_RANGE_0136_PID 0x0136
+#define MTXORB_FTDI_RANGE_0137_PID 0x0137
+#define MTXORB_FTDI_RANGE_0138_PID 0x0138
+#define MTXORB_FTDI_RANGE_0139_PID 0x0139
+#define MTXORB_FTDI_RANGE_013A_PID 0x013A
+#define MTXORB_FTDI_RANGE_013B_PID 0x013B
+#define MTXORB_FTDI_RANGE_013C_PID 0x013C
+#define MTXORB_FTDI_RANGE_013D_PID 0x013D
+#define MTXORB_FTDI_RANGE_013E_PID 0x013E
+#define MTXORB_FTDI_RANGE_013F_PID 0x013F
+#define MTXORB_FTDI_RANGE_0140_PID 0x0140
+#define MTXORB_FTDI_RANGE_0141_PID 0x0141
+#define MTXORB_FTDI_RANGE_0142_PID 0x0142
+#define MTXORB_FTDI_RANGE_0143_PID 0x0143
+#define MTXORB_FTDI_RANGE_0144_PID 0x0144
+#define MTXORB_FTDI_RANGE_0145_PID 0x0145
+#define MTXORB_FTDI_RANGE_0146_PID 0x0146
+#define MTXORB_FTDI_RANGE_0147_PID 0x0147
+#define MTXORB_FTDI_RANGE_0148_PID 0x0148
+#define MTXORB_FTDI_RANGE_0149_PID 0x0149
+#define MTXORB_FTDI_RANGE_014A_PID 0x014A
+#define MTXORB_FTDI_RANGE_014B_PID 0x014B
+#define MTXORB_FTDI_RANGE_014C_PID 0x014C
+#define MTXORB_FTDI_RANGE_014D_PID 0x014D
+#define MTXORB_FTDI_RANGE_014E_PID 0x014E
+#define MTXORB_FTDI_RANGE_014F_PID 0x014F
+#define MTXORB_FTDI_RANGE_0150_PID 0x0150
+#define MTXORB_FTDI_RANGE_0151_PID 0x0151
+#define MTXORB_FTDI_RANGE_0152_PID 0x0152
+#define MTXORB_FTDI_RANGE_0153_PID 0x0153
+#define MTXORB_FTDI_RANGE_0154_PID 0x0154
+#define MTXORB_FTDI_RANGE_0155_PID 0x0155
+#define MTXORB_FTDI_RANGE_0156_PID 0x0156
+#define MTXORB_FTDI_RANGE_0157_PID 0x0157
+#define MTXORB_FTDI_RANGE_0158_PID 0x0158
+#define MTXORB_FTDI_RANGE_0159_PID 0x0159
+#define MTXORB_FTDI_RANGE_015A_PID 0x015A
+#define MTXORB_FTDI_RANGE_015B_PID 0x015B
+#define MTXORB_FTDI_RANGE_015C_PID 0x015C
+#define MTXORB_FTDI_RANGE_015D_PID 0x015D
+#define MTXORB_FTDI_RANGE_015E_PID 0x015E
+#define MTXORB_FTDI_RANGE_015F_PID 0x015F
+#define MTXORB_FTDI_RANGE_0160_PID 0x0160
+#define MTXORB_FTDI_RANGE_0161_PID 0x0161
+#define MTXORB_FTDI_RANGE_0162_PID 0x0162
+#define MTXORB_FTDI_RANGE_0163_PID 0x0163
+#define MTXORB_FTDI_RANGE_0164_PID 0x0164
+#define MTXORB_FTDI_RANGE_0165_PID 0x0165
+#define MTXORB_FTDI_RANGE_0166_PID 0x0166
+#define MTXORB_FTDI_RANGE_0167_PID 0x0167
+#define MTXORB_FTDI_RANGE_0168_PID 0x0168
+#define MTXORB_FTDI_RANGE_0169_PID 0x0169
+#define MTXORB_FTDI_RANGE_016A_PID 0x016A
+#define MTXORB_FTDI_RANGE_016B_PID 0x016B
+#define MTXORB_FTDI_RANGE_016C_PID 0x016C
+#define MTXORB_FTDI_RANGE_016D_PID 0x016D
+#define MTXORB_FTDI_RANGE_016E_PID 0x016E
+#define MTXORB_FTDI_RANGE_016F_PID 0x016F
+#define MTXORB_FTDI_RANGE_0170_PID 0x0170
+#define MTXORB_FTDI_RANGE_0171_PID 0x0171
+#define MTXORB_FTDI_RANGE_0172_PID 0x0172
+#define MTXORB_FTDI_RANGE_0173_PID 0x0173
+#define MTXORB_FTDI_RANGE_0174_PID 0x0174
+#define MTXORB_FTDI_RANGE_0175_PID 0x0175
+#define MTXORB_FTDI_RANGE_0176_PID 0x0176
+#define MTXORB_FTDI_RANGE_0177_PID 0x0177
+#define MTXORB_FTDI_RANGE_0178_PID 0x0178
+#define MTXORB_FTDI_RANGE_0179_PID 0x0179
+#define MTXORB_FTDI_RANGE_017A_PID 0x017A
+#define MTXORB_FTDI_RANGE_017B_PID 0x017B
+#define MTXORB_FTDI_RANGE_017C_PID 0x017C
+#define MTXORB_FTDI_RANGE_017D_PID 0x017D
+#define MTXORB_FTDI_RANGE_017E_PID 0x017E
+#define MTXORB_FTDI_RANGE_017F_PID 0x017F
+#define MTXORB_FTDI_RANGE_0180_PID 0x0180
+#define MTXORB_FTDI_RANGE_0181_PID 0x0181
+#define MTXORB_FTDI_RANGE_0182_PID 0x0182
+#define MTXORB_FTDI_RANGE_0183_PID 0x0183
+#define MTXORB_FTDI_RANGE_0184_PID 0x0184
+#define MTXORB_FTDI_RANGE_0185_PID 0x0185
+#define MTXORB_FTDI_RANGE_0186_PID 0x0186
+#define MTXORB_FTDI_RANGE_0187_PID 0x0187
+#define MTXORB_FTDI_RANGE_0188_PID 0x0188
+#define MTXORB_FTDI_RANGE_0189_PID 0x0189
+#define MTXORB_FTDI_RANGE_018A_PID 0x018A
+#define MTXORB_FTDI_RANGE_018B_PID 0x018B
+#define MTXORB_FTDI_RANGE_018C_PID 0x018C
+#define MTXORB_FTDI_RANGE_018D_PID 0x018D
+#define MTXORB_FTDI_RANGE_018E_PID 0x018E
+#define MTXORB_FTDI_RANGE_018F_PID 0x018F
+#define MTXORB_FTDI_RANGE_0190_PID 0x0190
+#define MTXORB_FTDI_RANGE_0191_PID 0x0191
+#define MTXORB_FTDI_RANGE_0192_PID 0x0192
+#define MTXORB_FTDI_RANGE_0193_PID 0x0193
+#define MTXORB_FTDI_RANGE_0194_PID 0x0194
+#define MTXORB_FTDI_RANGE_0195_PID 0x0195
+#define MTXORB_FTDI_RANGE_0196_PID 0x0196
+#define MTXORB_FTDI_RANGE_0197_PID 0x0197
+#define MTXORB_FTDI_RANGE_0198_PID 0x0198
+#define MTXORB_FTDI_RANGE_0199_PID 0x0199
+#define MTXORB_FTDI_RANGE_019A_PID 0x019A
+#define MTXORB_FTDI_RANGE_019B_PID 0x019B
+#define MTXORB_FTDI_RANGE_019C_PID 0x019C
+#define MTXORB_FTDI_RANGE_019D_PID 0x019D
+#define MTXORB_FTDI_RANGE_019E_PID 0x019E
+#define MTXORB_FTDI_RANGE_019F_PID 0x019F
+#define MTXORB_FTDI_RANGE_01A0_PID 0x01A0
+#define MTXORB_FTDI_RANGE_01A1_PID 0x01A1
+#define MTXORB_FTDI_RANGE_01A2_PID 0x01A2
+#define MTXORB_FTDI_RANGE_01A3_PID 0x01A3
+#define MTXORB_FTDI_RANGE_01A4_PID 0x01A4
+#define MTXORB_FTDI_RANGE_01A5_PID 0x01A5
+#define MTXORB_FTDI_RANGE_01A6_PID 0x01A6
+#define MTXORB_FTDI_RANGE_01A7_PID 0x01A7
+#define MTXORB_FTDI_RANGE_01A8_PID 0x01A8
+#define MTXORB_FTDI_RANGE_01A9_PID 0x01A9
+#define MTXORB_FTDI_RANGE_01AA_PID 0x01AA
+#define MTXORB_FTDI_RANGE_01AB_PID 0x01AB
+#define MTXORB_FTDI_RANGE_01AC_PID 0x01AC
+#define MTXORB_FTDI_RANGE_01AD_PID 0x01AD
+#define MTXORB_FTDI_RANGE_01AE_PID 0x01AE
+#define MTXORB_FTDI_RANGE_01AF_PID 0x01AF
+#define MTXORB_FTDI_RANGE_01B0_PID 0x01B0
+#define MTXORB_FTDI_RANGE_01B1_PID 0x01B1
+#define MTXORB_FTDI_RANGE_01B2_PID 0x01B2
+#define MTXORB_FTDI_RANGE_01B3_PID 0x01B3
+#define MTXORB_FTDI_RANGE_01B4_PID 0x01B4
+#define MTXORB_FTDI_RANGE_01B5_PID 0x01B5
+#define MTXORB_FTDI_RANGE_01B6_PID 0x01B6
+#define MTXORB_FTDI_RANGE_01B7_PID 0x01B7
+#define MTXORB_FTDI_RANGE_01B8_PID 0x01B8
+#define MTXORB_FTDI_RANGE_01B9_PID 0x01B9
+#define MTXORB_FTDI_RANGE_01BA_PID 0x01BA
+#define MTXORB_FTDI_RANGE_01BB_PID 0x01BB
+#define MTXORB_FTDI_RANGE_01BC_PID 0x01BC
+#define MTXORB_FTDI_RANGE_01BD_PID 0x01BD
+#define MTXORB_FTDI_RANGE_01BE_PID 0x01BE
+#define MTXORB_FTDI_RANGE_01BF_PID 0x01BF
+#define MTXORB_FTDI_RANGE_01C0_PID 0x01C0
+#define MTXORB_FTDI_RANGE_01C1_PID 0x01C1
+#define MTXORB_FTDI_RANGE_01C2_PID 0x01C2
+#define MTXORB_FTDI_RANGE_01C3_PID 0x01C3
+#define MTXORB_FTDI_RANGE_01C4_PID 0x01C4
+#define MTXORB_FTDI_RANGE_01C5_PID 0x01C5
+#define MTXORB_FTDI_RANGE_01C6_PID 0x01C6
+#define MTXORB_FTDI_RANGE_01C7_PID 0x01C7
+#define MTXORB_FTDI_RANGE_01C8_PID 0x01C8
+#define MTXORB_FTDI_RANGE_01C9_PID 0x01C9
+#define MTXORB_FTDI_RANGE_01CA_PID 0x01CA
+#define MTXORB_FTDI_RANGE_01CB_PID 0x01CB
+#define MTXORB_FTDI_RANGE_01CC_PID 0x01CC
+#define MTXORB_FTDI_RANGE_01CD_PID 0x01CD
+#define MTXORB_FTDI_RANGE_01CE_PID 0x01CE
+#define MTXORB_FTDI_RANGE_01CF_PID 0x01CF
+#define MTXORB_FTDI_RANGE_01D0_PID 0x01D0
+#define MTXORB_FTDI_RANGE_01D1_PID 0x01D1
+#define MTXORB_FTDI_RANGE_01D2_PID 0x01D2
+#define MTXORB_FTDI_RANGE_01D3_PID 0x01D3
+#define MTXORB_FTDI_RANGE_01D4_PID 0x01D4
+#define MTXORB_FTDI_RANGE_01D5_PID 0x01D5
+#define MTXORB_FTDI_RANGE_01D6_PID 0x01D6
+#define MTXORB_FTDI_RANGE_01D7_PID 0x01D7
+#define MTXORB_FTDI_RANGE_01D8_PID 0x01D8
+#define MTXORB_FTDI_RANGE_01D9_PID 0x01D9
+#define MTXORB_FTDI_RANGE_01DA_PID 0x01DA
+#define MTXORB_FTDI_RANGE_01DB_PID 0x01DB
+#define MTXORB_FTDI_RANGE_01DC_PID 0x01DC
+#define MTXORB_FTDI_RANGE_01DD_PID 0x01DD
+#define MTXORB_FTDI_RANGE_01DE_PID 0x01DE
+#define MTXORB_FTDI_RANGE_01DF_PID 0x01DF
+#define MTXORB_FTDI_RANGE_01E0_PID 0x01E0
+#define MTXORB_FTDI_RANGE_01E1_PID 0x01E1
+#define MTXORB_FTDI_RANGE_01E2_PID 0x01E2
+#define MTXORB_FTDI_RANGE_01E3_PID 0x01E3
+#define MTXORB_FTDI_RANGE_01E4_PID 0x01E4
+#define MTXORB_FTDI_RANGE_01E5_PID 0x01E5
+#define MTXORB_FTDI_RANGE_01E6_PID 0x01E6
+#define MTXORB_FTDI_RANGE_01E7_PID 0x01E7
+#define MTXORB_FTDI_RANGE_01E8_PID 0x01E8
+#define MTXORB_FTDI_RANGE_01E9_PID 0x01E9
+#define MTXORB_FTDI_RANGE_01EA_PID 0x01EA
+#define MTXORB_FTDI_RANGE_01EB_PID 0x01EB
+#define MTXORB_FTDI_RANGE_01EC_PID 0x01EC
+#define MTXORB_FTDI_RANGE_01ED_PID 0x01ED
+#define MTXORB_FTDI_RANGE_01EE_PID 0x01EE
+#define MTXORB_FTDI_RANGE_01EF_PID 0x01EF
+#define MTXORB_FTDI_RANGE_01F0_PID 0x01F0
+#define MTXORB_FTDI_RANGE_01F1_PID 0x01F1
+#define MTXORB_FTDI_RANGE_01F2_PID 0x01F2
+#define MTXORB_FTDI_RANGE_01F3_PID 0x01F3
+#define MTXORB_FTDI_RANGE_01F4_PID 0x01F4
+#define MTXORB_FTDI_RANGE_01F5_PID 0x01F5
+#define MTXORB_FTDI_RANGE_01F6_PID 0x01F6
+#define MTXORB_FTDI_RANGE_01F7_PID 0x01F7
+#define MTXORB_FTDI_RANGE_01F8_PID 0x01F8
+#define MTXORB_FTDI_RANGE_01F9_PID 0x01F9
+#define MTXORB_FTDI_RANGE_01FA_PID 0x01FA
+#define MTXORB_FTDI_RANGE_01FB_PID 0x01FB
+#define MTXORB_FTDI_RANGE_01FC_PID 0x01FC
+#define MTXORB_FTDI_RANGE_01FD_PID 0x01FD
+#define MTXORB_FTDI_RANGE_01FE_PID 0x01FE
+#define MTXORB_FTDI_RANGE_01FF_PID 0x01FF
+
+
+
+/*
+ * The Mobility Lab (TML)
+ * Submitted by Pierre Castella
+ */
+#define TML_VID 0x1B91 /* Vendor ID */
+#define TML_USB_SERIAL_PID 0x0064 /* USB - Serial Converter */
+
+/* Alti-2 products http://www.alti-2.com */
+#define ALTI2_VID 0x1BC9
+#define ALTI2_N3_PID 0x6001 /* Neptune 3 */
+
+/*
+ * Dresden Elektronic Sensor Terminal Board
+ */
+#define DE_VID 0x1cf1 /* Vendor ID */
+#define STB_PID 0x0001 /* Sensor Terminal Board */
+#define WHT_PID 0x0004 /* Wireless Handheld Terminal */
+
+/*
+ * Papouch products (http://www.papouch.com/)
+ * Submitted by Folkert van Heusden
+ */
+
+#define PAPOUCH_VID 0x5050 /* Vendor ID */
+#define PAPOUCH_TMU_PID 0x0400 /* TMU USB Thermometer */
+#define PAPOUCH_QUIDO4x4_PID 0x0900 /* Quido 4/4 Module */
+
+/*
+ * Marvell SheevaPlug
+ */
+#define MARVELL_VID 0x9e88
+#define MARVELL_SHEEVAPLUG_PID 0x9e8f
+
+/*
+ * Evolution Robotics products (http://www.evolution.com/).
+ * Submitted by Shawn M. Lavelle.
+ */
+#define EVOLUTION_VID 0xDEEE /* Vendor ID */
+#define EVOLUTION_ER1_PID 0x0300 /* ER1 Control Module */
+#define EVO_8U232AM_PID 0x02FF /* Evolution robotics RCM2 (FT232AM)*/
+#define EVO_HYBRID_PID 0x0302 /* Evolution robotics RCM4 PID (FT232BM)*/
+#define EVO_RCM4_PID 0x0303 /* Evolution robotics RCM4 PID */
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index bbe005cefcf..f1ea3a33b6e 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -276,7 +276,7 @@ static int usb_serial_generic_write_start(struct usb_serial_port *port)
if (port->write_urb_busy)
start_io = false;
else {
- start_io = (__kfifo_len(port->write_fifo) != 0);
+ start_io = (kfifo_len(&port->write_fifo) != 0);
port->write_urb_busy = start_io;
}
spin_unlock_irqrestore(&port->lock, flags);
@@ -285,7 +285,7 @@ static int usb_serial_generic_write_start(struct usb_serial_port *port)
return 0;
data = port->write_urb->transfer_buffer;
- count = kfifo_get(port->write_fifo, data, port->bulk_out_size);
+ count = kfifo_out_locked(&port->write_fifo, data, port->bulk_out_size, &port->lock);
usb_serial_debug_data(debug, &port->dev, __func__, count, data);
/* set up our urb */
@@ -345,7 +345,7 @@ int usb_serial_generic_write(struct tty_struct *tty,
return usb_serial_multi_urb_write(tty, port,
buf, count);
- count = kfifo_put(port->write_fifo, buf, count);
+ count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock);
result = usb_serial_generic_write_start(port);
if (result >= 0)
@@ -370,7 +370,7 @@ int usb_serial_generic_write_room(struct tty_struct *tty)
(serial->type->max_in_flight_urbs -
port->urbs_in_flight);
} else if (serial->num_bulk_out)
- room = port->write_fifo->size - __kfifo_len(port->write_fifo);
+ room = kfifo_avail(&port->write_fifo);
spin_unlock_irqrestore(&port->lock, flags);
dbg("%s - returns %d", __func__, room);
@@ -391,7 +391,7 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
chars = port->tx_bytes_flight;
spin_unlock_irqrestore(&port->lock, flags);
} else if (serial->num_bulk_out)
- chars = kfifo_len(port->write_fifo);
+ chars = kfifo_len(&port->write_fifo);
dbg("%s - returns %d", __func__, chars);
return chars;
@@ -507,7 +507,7 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb)
if (status) {
dbg("%s - nonzero multi-urb write bulk status "
"received: %d", __func__, status);
- kfifo_reset(port->write_fifo);
+ kfifo_reset_out(&port->write_fifo);
} else
usb_serial_generic_write_start(port);
}
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 485fa9c5b10..2cfe2451ed9 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -127,8 +127,9 @@
#define BANDB_DEVICE_ID_US9ML2_4 0xAC30
#define BANDB_DEVICE_ID_USPTL4_2 0xAC31
#define BANDB_DEVICE_ID_USPTL4_4 0xAC32
-#define BANDB_DEVICE_ID_USOPTL4_2 0xAC42
-#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44
+#define BANDB_DEVICE_ID_USOPTL4_2 0xAC42
+#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44
+#define BANDB_DEVICE_ID_USOPTL2_4 0xAC24
/* This driver also supports
* ATEN UC2324 device using Moschip MCS7840
@@ -191,6 +192,7 @@ static struct usb_device_id moschip_port_id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)},
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)},
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)},
+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)},
{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)},
{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
{} /* terminating entry */
@@ -207,6 +209,7 @@ static __devinitdata struct usb_device_id moschip_id_table_combined[] = {
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)},
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)},
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)},
+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)},
{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)},
{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
{} /* terminating entry */
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 9a2b903492e..6e94a6711f0 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -340,6 +340,10 @@ static int option_resume(struct usb_serial *serial);
#define FOUR_G_SYSTEMS_VENDOR_ID 0x1c9e
#define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603
+/* Haier products */
+#define HAIER_VENDOR_ID 0x201e
+#define HAIER_PRODUCT_CE100 0x2009
+
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -641,6 +645,7 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
{ USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) },
{ USB_DEVICE(FOUR_G_SYSTEMS_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14) },
+ { USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 4543f359be7..33c85f7084f 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -595,8 +595,7 @@ static void port_release(struct device *dev)
usb_free_urb(port->write_urb);
usb_free_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_out_urb);
- if (!IS_ERR(port->write_fifo) && port->write_fifo)
- kfifo_free(port->write_fifo);
+ kfifo_free(&port->write_fifo);
kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer);
@@ -939,9 +938,7 @@ int usb_serial_probe(struct usb_interface *interface,
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
- port->write_fifo = kfifo_alloc(PAGE_SIZE, GFP_KERNEL,
- &port->lock);
- if (IS_ERR(port->write_fifo))
+ if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))
goto probe_error;
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
port->bulk_out_size = buffer_size;
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index 2051c9dc813..b7687c55fe1 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -2245,9 +2245,6 @@ static int ext_setcolreg(unsigned int regno, unsigned int red,
if (regno > 255)
return 1;
- if (regno > 255)
- return 1;
-
switch (external_card_type) {
case IS_VGA:
OUTB(0x3c8, regno);
diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c
index 4c10edecfb6..86d95c228ad 100644
--- a/drivers/video/backlight/adp5520_bl.c
+++ b/drivers/video/backlight/adp5520_bl.c
@@ -85,7 +85,7 @@ static int adp5520_bl_get_brightness(struct backlight_device *bl)
return error ? data->current_brightness : reg_val;
}
-static struct backlight_ops adp5520_bl_ops = {
+static const struct backlight_ops adp5520_bl_ops = {
.update_status = adp5520_bl_update_status,
.get_brightness = adp5520_bl_get_brightness,
};
diff --git a/drivers/video/backlight/adx_bl.c b/drivers/video/backlight/adx_bl.c
index 2c3bdfc620b..d769b0bab21 100644
--- a/drivers/video/backlight/adx_bl.c
+++ b/drivers/video/backlight/adx_bl.c
@@ -61,7 +61,7 @@ static int adx_backlight_check_fb(struct fb_info *fb)
return 1;
}
-static struct backlight_ops adx_backlight_ops = {
+static const struct backlight_ops adx_backlight_ops = {
.options = 0,
.update_status = adx_backlight_update_status,
.get_brightness = adx_backlight_get_brightness,
diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c
index 2cf7ba52f67..f625ffc69ad 100644
--- a/drivers/video/backlight/atmel-pwm-bl.c
+++ b/drivers/video/backlight/atmel-pwm-bl.c
@@ -113,7 +113,7 @@ static int atmel_pwm_bl_init_pwm(struct atmel_pwm_bl *pwmbl)
return pwm_channel_enable(&pwmbl->pwmc);
}
-static struct backlight_ops atmel_pwm_bl_ops = {
+static const struct backlight_ops atmel_pwm_bl_ops = {
.get_brightness = atmel_pwm_bl_get_intensity,
.update_status = atmel_pwm_bl_set_intensity,
};
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 6615ac7fa60..18829cf68b1 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -269,7 +269,7 @@ EXPORT_SYMBOL(backlight_force_update);
* ERR_PTR() or a pointer to the newly allocated device.
*/
struct backlight_device *backlight_device_register(const char *name,
- struct device *parent, void *devdata, struct backlight_ops *ops)
+ struct device *parent, void *devdata, const struct backlight_ops *ops)
{
struct backlight_device *new_bd;
int rc;
diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c
index 96774949cd3..b4bcf804379 100644
--- a/drivers/video/backlight/corgi_lcd.c
+++ b/drivers/video/backlight/corgi_lcd.c
@@ -451,7 +451,7 @@ void corgi_lcd_limit_intensity(int limit)
}
EXPORT_SYMBOL(corgi_lcd_limit_intensity);
-static struct backlight_ops corgi_bl_ops = {
+static const struct backlight_ops corgi_bl_ops = {
.get_brightness = corgi_bl_get_intensity,
.update_status = corgi_bl_update_status,
};
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c
index b9fe62b475c..da86db4374a 100644
--- a/drivers/video/backlight/cr_bllcd.c
+++ b/drivers/video/backlight/cr_bllcd.c
@@ -108,7 +108,7 @@ static int cr_backlight_get_intensity(struct backlight_device *bd)
return intensity;
}
-static struct backlight_ops cr_backlight_ops = {
+static const struct backlight_ops cr_backlight_ops = {
.get_brightness = cr_backlight_get_intensity,
.update_status = cr_backlight_set_intensity,
};
@@ -201,7 +201,7 @@ static int cr_backlight_probe(struct platform_device *pdev)
if (IS_ERR(ldp)) {
backlight_device_unregister(bdp);
pci_dev_put(lpc_dev);
- return PTR_ERR(bdp);
+ return PTR_ERR(ldp);
}
pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR,
diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c
index f2d76dae1eb..74cdc640173 100644
--- a/drivers/video/backlight/da903x_bl.c
+++ b/drivers/video/backlight/da903x_bl.c
@@ -95,7 +95,7 @@ static int da903x_backlight_get_brightness(struct backlight_device *bl)
return data->current_brightness;
}
-static struct backlight_ops da903x_backlight_ops = {
+static const struct backlight_ops da903x_backlight_ops = {
.update_status = da903x_backlight_update_status,
.get_brightness = da903x_backlight_get_brightness,
};
diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c
index 6d27f62fdcd..e6d348e6359 100644
--- a/drivers/video/backlight/generic_bl.c
+++ b/drivers/video/backlight/generic_bl.c
@@ -70,7 +70,7 @@ void corgibl_limit_intensity(int limit)
}
EXPORT_SYMBOL(corgibl_limit_intensity);
-static struct backlight_ops genericbl_ops = {
+static const struct backlight_ops genericbl_ops = {
.options = BL_CORE_SUSPENDRESUME,
.get_brightness = genericbl_get_intensity,
.update_status = genericbl_send_intensity,
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
index 7fb4eefff80..f7cc528d5be 100644
--- a/drivers/video/backlight/hp680_bl.c
+++ b/drivers/video/backlight/hp680_bl.c
@@ -98,7 +98,7 @@ static int hp680bl_get_intensity(struct backlight_device *bd)
return current_intensity;
}
-static struct backlight_ops hp680bl_ops = {
+static const struct backlight_ops hp680bl_ops = {
.get_brightness = hp680bl_get_intensity,
.update_status = hp680bl_set_intensity,
};
diff --git a/drivers/video/backlight/jornada720_bl.c b/drivers/video/backlight/jornada720_bl.c
index 7aed2565c1b..db9071fc566 100644
--- a/drivers/video/backlight/jornada720_bl.c
+++ b/drivers/video/backlight/jornada720_bl.c
@@ -93,7 +93,7 @@ out:
return ret;
}
-static struct backlight_ops jornada_bl_ops = {
+static const struct backlight_ops jornada_bl_ops = {
.get_brightness = jornada_bl_get_brightness,
.update_status = jornada_bl_update_status,
.options = BL_CORE_SUSPENDRESUME,
diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c
index a38fda1742d..939e7b830cf 100644
--- a/drivers/video/backlight/kb3886_bl.c
+++ b/drivers/video/backlight/kb3886_bl.c
@@ -134,7 +134,7 @@ static int kb3886bl_get_intensity(struct backlight_device *bd)
return kb3886bl_intensity;
}
-static struct backlight_ops kb3886bl_ops = {
+static const struct backlight_ops kb3886bl_ops = {
.get_brightness = kb3886bl_get_intensity,
.update_status = kb3886bl_send_intensity,
};
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
index 6b488b8a7ee..00a9591b000 100644
--- a/drivers/video/backlight/locomolcd.c
+++ b/drivers/video/backlight/locomolcd.c
@@ -141,7 +141,7 @@ static int locomolcd_get_intensity(struct backlight_device *bd)
return current_intensity;
}
-static struct backlight_ops locomobl_data = {
+static const struct backlight_ops locomobl_data = {
.get_brightness = locomolcd_get_intensity,
.update_status = locomolcd_set_intensity,
};
diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c
index 9edb8d7c295..2e78b0784bd 100644
--- a/drivers/video/backlight/mbp_nvidia_bl.c
+++ b/drivers/video/backlight/mbp_nvidia_bl.c
@@ -33,7 +33,7 @@ struct dmi_match_data {
unsigned long iostart;
unsigned long iolen;
/* Backlight operations structure. */
- struct backlight_ops backlight_ops;
+ const struct backlight_ops backlight_ops;
};
/* Module parameters. */
@@ -220,6 +220,24 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
},
{
.callback = mbp_dmi_match,
+ .ident = "MacBookPro 5,3",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3"),
+ },
+ .driver_data = (void *)&nvidia_chipset_data,
+ },
+ {
+ .callback = mbp_dmi_match,
+ .ident = "MacBookPro 5,4",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4"),
+ },
+ .driver_data = (void *)&nvidia_chipset_data,
+ },
+ {
+ .callback = mbp_dmi_match,
.ident = "MacBookPro 5,5",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c
index 8693e5fcd2e..409ca964352 100644
--- a/drivers/video/backlight/omap1_bl.c
+++ b/drivers/video/backlight/omap1_bl.c
@@ -125,7 +125,7 @@ static int omapbl_get_intensity(struct backlight_device *dev)
return bl->current_intensity;
}
-static struct backlight_ops omapbl_ops = {
+static const struct backlight_ops omapbl_ops = {
.get_brightness = omapbl_get_intensity,
.update_status = omapbl_update_status,
};
diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c
index 9edaf24fd82..075786e0503 100644
--- a/drivers/video/backlight/progear_bl.c
+++ b/drivers/video/backlight/progear_bl.c
@@ -54,7 +54,7 @@ static int progearbl_get_intensity(struct backlight_device *bd)
return intensity - HW_LEVEL_MIN;
}
-static struct backlight_ops progearbl_ops = {
+static const struct backlight_ops progearbl_ops = {
.get_brightness = progearbl_get_intensity,
.update_status = progearbl_set_intensity,
};
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 88716626744..9d2ec2a1cce 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -22,8 +22,10 @@
struct pwm_bl_data {
struct pwm_device *pwm;
+ struct device *dev;
unsigned int period;
- int (*notify)(int brightness);
+ int (*notify)(struct device *,
+ int brightness);
};
static int pwm_backlight_update_status(struct backlight_device *bl)
@@ -39,7 +41,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
brightness = 0;
if (pb->notify)
- brightness = pb->notify(brightness);
+ brightness = pb->notify(pb->dev, brightness);
if (brightness == 0) {
pwm_config(pb->pwm, 0, pb->period);
@@ -56,7 +58,7 @@ static int pwm_backlight_get_brightness(struct backlight_device *bl)
return bl->props.brightness;
}
-static struct backlight_ops pwm_backlight_ops = {
+static const struct backlight_ops pwm_backlight_ops = {
.update_status = pwm_backlight_update_status,
.get_brightness = pwm_backlight_get_brightness,
};
@@ -88,6 +90,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->period = data->pwm_period_ns;
pb->notify = data->notify;
+ pb->dev = &pdev->dev;
pb->pwm = pwm_request(data->pwm_id, "backlight");
if (IS_ERR(pb->pwm)) {
@@ -146,7 +149,7 @@ static int pwm_backlight_suspend(struct platform_device *pdev,
struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
if (pb->notify)
- pb->notify(0);
+ pb->notify(pb->dev, 0);
pwm_config(pb->pwm, 0, pb->period);
pwm_disable(pb->pwm);
return 0;
diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c
index 43edbada12d..e14ce4d469f 100644
--- a/drivers/video/backlight/tosa_bl.c
+++ b/drivers/video/backlight/tosa_bl.c
@@ -72,7 +72,7 @@ static int tosa_bl_get_brightness(struct backlight_device *dev)
return props->brightness;
}
-static struct backlight_ops bl_ops = {
+static const struct backlight_ops bl_ops = {
.get_brightness = tosa_bl_get_brightness,
.update_status = tosa_bl_update_status,
};
diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c
index 467bdb7efb2..e32add37a20 100644
--- a/drivers/video/backlight/wm831x_bl.c
+++ b/drivers/video/backlight/wm831x_bl.c
@@ -112,7 +112,7 @@ static int wm831x_backlight_get_brightness(struct backlight_device *bl)
return data->current_brightness;
}
-static struct backlight_ops wm831x_backlight_ops = {
+static const struct backlight_ops wm831x_backlight_ops = {
.options = BL_CORE_SUSPENDRESUME,
.update_status = wm831x_backlight_update_status,
.get_brightness = wm831x_backlight_get_brightness,
diff --git a/drivers/video/omap/lcd_ldp.c b/drivers/video/omap/lcd_ldp.c
index 5bb7f6f1460..0f5952cae85 100644
--- a/drivers/video/omap/lcd_ldp.c
+++ b/drivers/video/omap/lcd_ldp.c
@@ -24,7 +24,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
#include <mach/gpio.h>
#include <plat/mux.h>
@@ -59,7 +59,7 @@
#define TWL4030_VPLL2_DEV_GRP 0x33
#define TWL4030_VPLL2_DEDICATED 0x36
-#define t2_out(c, r, v) twl4030_i2c_write_u8(c, r, v)
+#define t2_out(c, r, v) twl_i2c_write_u8(c, r, v)
static int ldp_panel_init(struct lcd_panel *panel,
diff --git a/drivers/video/omap/lcd_omap2evm.c b/drivers/video/omap/lcd_omap2evm.c
index 006c2fe7360..7e7a65c0845 100644
--- a/drivers/video/omap/lcd_omap2evm.c
+++ b/drivers/video/omap/lcd_omap2evm.c
@@ -24,7 +24,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
#include <plat/mux.h>
#include <asm/mach-types.h>
@@ -61,9 +61,9 @@ static int omap2evm_panel_init(struct lcd_panel *panel,
gpio_direction_output(LCD_PANEL_LR, 1);
gpio_direction_output(LCD_PANEL_UD, 1);
- twl4030_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN);
- twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON);
- twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF);
+ twl_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN);
+ twl_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON);
+ twl_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF);
bklight_level = 100;
return 0;
@@ -101,7 +101,7 @@ static int omap2evm_bklight_setlevel(struct lcd_panel *panel,
u8 c;
if ((level >= 0) && (level <= 100)) {
c = (125 * (100 - level)) / 100 + 2;
- twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF);
+ twl_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF);
bklight_level = level;
}
return 0;
diff --git a/drivers/video/omap/lcd_omap3beagle.c b/drivers/video/omap/lcd_omap3beagle.c
index fc503d8f3c2..ca75cc2a87a 100644
--- a/drivers/video/omap/lcd_omap3beagle.c
+++ b/drivers/video/omap/lcd_omap3beagle.c
@@ -23,7 +23,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
#include <plat/mux.h>
#include <plat/mux.h>
diff --git a/drivers/video/omap/lcd_omap3evm.c b/drivers/video/omap/lcd_omap3evm.c
index ae2edc4081a..06840da0b09 100644
--- a/drivers/video/omap/lcd_omap3evm.c
+++ b/drivers/video/omap/lcd_omap3evm.c
@@ -23,7 +23,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
#include <plat/mux.h>
#include <asm/mach-types.h>
@@ -63,9 +63,9 @@ static int omap3evm_panel_init(struct lcd_panel *panel,
gpio_direction_output(LCD_PANEL_LR, 1);
gpio_direction_output(LCD_PANEL_UD, 1);
- twl4030_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN);
- twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON);
- twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF);
+ twl_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN);
+ twl_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON);
+ twl_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF);
bklight_level = 100;
return 0;
@@ -102,7 +102,7 @@ static int omap3evm_bklight_setlevel(struct lcd_panel *panel,
u8 c;
if ((level >= 0) && (level <= 100)) {
c = (125 * (100 - level)) / 100 + 2;
- twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF);
+ twl_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF);
bklight_level = level;
}
return 0;
diff --git a/drivers/video/omap/lcd_overo.c b/drivers/video/omap/lcd_overo.c
index 56ee192e9ee..564933ffac6 100644
--- a/drivers/video/omap/lcd_overo.c
+++ b/drivers/video/omap/lcd_overo.c
@@ -21,7 +21,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl.h>
#include <mach/gpio.h>
#include <plat/mux.h>
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index 10d8c4b4bae..d8df17a7d5f 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -680,7 +680,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
if (!viafb_gamma_table)
return -ENOMEM;
if (copy_from_user(viafb_gamma_table, argp,
- sizeof(viafb_gamma_table))) {
+ 256 * sizeof(u32))) {
kfree(viafb_gamma_table);
return -EFAULT;
}
@@ -694,7 +694,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
return -ENOMEM;
viafb_get_gamma_table(viafb_gamma_table);
if (copy_to_user(argp, viafb_gamma_table,
- sizeof(viafb_gamma_table))) {
+ 256 * sizeof(u32))) {
kfree(viafb_gamma_table);
return -EFAULT;
}
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index d958b76430a..088f32f29a6 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -368,7 +368,7 @@ config ALIM7101_WDT
config GEODE_WDT
tristate "AMD Geode CS5535/CS5536 Watchdog"
- depends on MGEODE_LX
+ depends on CS5535_MFGPT
help
This driver enables a watchdog capability built into the
CS5535/CS5536 companion chips for the AMD Geode GX and LX
@@ -815,16 +815,6 @@ config PNX833X_WDT
timer has expired and no process has written to /dev/watchdog during
that time.
-config WDT_RM9K_GPI
- tristate "RM9000/GPI hardware watchdog"
- depends on CPU_RM9000
- help
- Watchdog implementation using the GPI hardware found on
- PMC-Sierra RM9xxx CPUs.
-
- To compile this driver as a module, choose M here: the
- module will be called rm9k_wdt.
-
config SIBYTE_WDOG
tristate "Sibyte SoC hardware watchdog"
depends on CPU_SB1
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 89c045dc468..475c6110006 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -109,7 +109,6 @@ obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o
obj-$(CONFIG_INDYDOG) += indydog.o
obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
-obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
diff --git a/drivers/watchdog/geodewdt.c b/drivers/watchdog/geodewdt.c
index 9acf0015a1e..38252ff828c 100644
--- a/drivers/watchdog/geodewdt.c
+++ b/drivers/watchdog/geodewdt.c
@@ -1,6 +1,7 @@
-/* Watchdog timer for the Geode GX/LX with the CS5535/CS5536 companion chip
+/* Watchdog timer for machines with the CS5535/CS5536 companion chip
*
* Copyright (C) 2006-2007, Advanced Micro Devices, Inc.
+ * Copyright (C) 2009 Andres Salomon <dilinger@collabora.co.uk>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -19,7 +20,7 @@
#include <linux/reboot.h>
#include <linux/uaccess.h>
-#include <asm/geode.h>
+#include <linux/cs5535.h>
#define GEODEWDT_HZ 500
#define GEODEWDT_SCALE 6
@@ -46,25 +47,25 @@ MODULE_PARM_DESC(nowayout,
static struct platform_device *geodewdt_platform_device;
static unsigned long wdt_flags;
-static int wdt_timer;
+static struct cs5535_mfgpt_timer *wdt_timer;
static int safe_close;
static void geodewdt_ping(void)
{
/* Stop the counter */
- geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0);
+ cs5535_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0);
/* Reset the counter */
- geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0);
+ cs5535_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0);
/* Enable the counter */
- geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN);
+ cs5535_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN);
}
static void geodewdt_disable(void)
{
- geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0);
- geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0);
+ cs5535_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0);
+ cs5535_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0);
}
static int geodewdt_set_heartbeat(int val)
@@ -72,10 +73,10 @@ static int geodewdt_set_heartbeat(int val)
if (val < 1 || val > GEODEWDT_MAX_SECONDS)
return -EINVAL;
- geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0);
- geode_mfgpt_write(wdt_timer, MFGPT_REG_CMP2, val * GEODEWDT_HZ);
- geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0);
- geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN);
+ cs5535_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0);
+ cs5535_mfgpt_write(wdt_timer, MFGPT_REG_CMP2, val * GEODEWDT_HZ);
+ cs5535_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0);
+ cs5535_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN);
timeout = val;
return 0;
@@ -215,28 +216,25 @@ static struct miscdevice geodewdt_miscdev = {
static int __devinit geodewdt_probe(struct platform_device *dev)
{
- int ret, timer;
-
- timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING);
+ int ret;
- if (timer == -1) {
+ wdt_timer = cs5535_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING);
+ if (!wdt_timer) {
printk(KERN_ERR "geodewdt: No timers were available\n");
return -ENODEV;
}
- wdt_timer = timer;
-
/* Set up the timer */
- geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP,
+ cs5535_mfgpt_write(wdt_timer, MFGPT_REG_SETUP,
GEODEWDT_SCALE | (3 << 8));
/* Set up comparator 2 to reset when the event fires */
- geode_mfgpt_toggle_event(wdt_timer, MFGPT_CMP2, MFGPT_EVENT_RESET, 1);
+ cs5535_mfgpt_toggle_event(wdt_timer, MFGPT_CMP2, MFGPT_EVENT_RESET, 1);
/* Set up the initial timeout */
- geode_mfgpt_write(wdt_timer, MFGPT_REG_CMP2,
+ cs5535_mfgpt_write(wdt_timer, MFGPT_REG_CMP2,
timeout * GEODEWDT_HZ);
ret = misc_register(&geodewdt_miscdev);
diff --git a/drivers/watchdog/rm9k_wdt.c b/drivers/watchdog/rm9k_wdt.c
deleted file mode 100644
index bb66958b943..00000000000
--- a/drivers/watchdog/rm9k_wdt.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Watchdog implementation for GPI h/w found on PMC-Sierra RM9xxx
- * chips.
- *
- * Copyright (C) 2004 by Basler Vision Technologies AG
- * Author: Thomas Koeller <thomas.koeller@baslerweb.com>
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/reboot.h>
-#include <linux/notifier.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/io.h>
-#include <linux/uaccess.h>
-#include <asm/atomic.h>
-#include <asm/processor.h>
-#include <asm/system.h>
-#include <asm/rm9k-ocd.h>
-
-#include <rm9k_wdt.h>
-
-
-#define CLOCK 125000000
-#define MAX_TIMEOUT_SECONDS 32
-#define CPCCR 0x0080
-#define CPGIG1SR 0x0044
-#define CPGIG1ER 0x0054
-
-
-/* Function prototypes */
-static irqreturn_t wdt_gpi_irqhdl(int, void *);
-static void wdt_gpi_start(void);
-static void wdt_gpi_stop(void);
-static void wdt_gpi_set_timeout(unsigned int);
-static int wdt_gpi_open(struct inode *, struct file *);
-static int wdt_gpi_release(struct inode *, struct file *);
-static ssize_t wdt_gpi_write(struct file *, const char __user *, size_t,
- loff_t *);
-static long wdt_gpi_ioctl(struct file *, unsigned int, unsigned long);
-static int wdt_gpi_notify(struct notifier_block *, unsigned long, void *);
-static const struct resource *wdt_gpi_get_resource(struct platform_device *,
- const char *, unsigned int);
-static int __init wdt_gpi_probe(struct platform_device *);
-static int __exit wdt_gpi_remove(struct platform_device *);
-
-
-static const char wdt_gpi_name[] = "wdt_gpi";
-static atomic_t opencnt;
-static int expect_close;
-static int locked;
-
-
-/* These are set from device resources */
-static void __iomem *wd_regs;
-static unsigned int wd_irq, wd_ctr;
-
-
-/* Module arguments */
-static int timeout = MAX_TIMEOUT_SECONDS;
-module_param(timeout, int, 0444);
-MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
-
-static unsigned long resetaddr = 0xbffdc200;
-module_param(resetaddr, ulong, 0444);
-MODULE_PARM_DESC(resetaddr, "Address to write to to force a reset");
-
-static unsigned long flagaddr = 0xbffdc104;
-module_param(flagaddr, ulong, 0444);
-MODULE_PARM_DESC(flagaddr, "Address to write to boot flags to");
-
-static int powercycle;
-module_param(powercycle, bool, 0444);
-MODULE_PARM_DESC(powercycle, "Cycle power if watchdog expires");
-
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, bool, 0444);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be disabled once started");
-
-
-/* Kernel interfaces */
-static const struct file_operations fops = {
- .owner = THIS_MODULE,
- .open = wdt_gpi_open,
- .release = wdt_gpi_release,
- .write = wdt_gpi_write,
- .unlocked_ioctl = wdt_gpi_ioctl,
-};
-
-static struct miscdevice miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = wdt_gpi_name,
- .fops = &fops,
-};
-
-static struct notifier_block wdt_gpi_shutdown = {
- .notifier_call = wdt_gpi_notify,
-};
-
-
-/* Interrupt handler */
-static irqreturn_t wdt_gpi_irqhdl(int irq, void *ctxt)
-{
- if (!unlikely(__raw_readl(wd_regs + 0x0008) & 0x1))
- return IRQ_NONE;
- __raw_writel(0x1, wd_regs + 0x0008);
-
-
- printk(KERN_CRIT "%s: watchdog expired - resetting system\n",
- wdt_gpi_name);
-
- *(volatile char *) flagaddr |= 0x01;
- *(volatile char *) resetaddr = powercycle ? 0x01 : 0x2;
- iob();
- while (1)
- cpu_relax();
-}
-
-
-/* Watchdog functions */
-static void wdt_gpi_start(void)
-{
- u32 reg;
-
- lock_titan_regs();
- reg = titan_readl(CPGIG1ER);
- titan_writel(reg | (0x100 << wd_ctr), CPGIG1ER);
- iob();
- unlock_titan_regs();
-}
-
-static void wdt_gpi_stop(void)
-{
- u32 reg;
-
- lock_titan_regs();
- reg = titan_readl(CPCCR) & ~(0xf << (wd_ctr * 4));
- titan_writel(reg, CPCCR);
- reg = titan_readl(CPGIG1ER);
- titan_writel(reg & ~(0x100 << wd_ctr), CPGIG1ER);
- iob();
- unlock_titan_regs();
-}
-
-static void wdt_gpi_set_timeout(unsigned int to)
-{
- u32 reg;
- const u32 wdval = (to * CLOCK) & ~0x0000000f;
-
- lock_titan_regs();
- reg = titan_readl(CPCCR) & ~(0xf << (wd_ctr * 4));
- titan_writel(reg, CPCCR);
- wmb();
- __raw_writel(wdval, wd_regs + 0x0000);
- wmb();
- titan_writel(reg | (0x2 << (wd_ctr * 4)), CPCCR);
- wmb();
- titan_writel(reg | (0x5 << (wd_ctr * 4)), CPCCR);
- iob();
- unlock_titan_regs();
-}
-
-
-/* /dev/watchdog operations */
-static int wdt_gpi_open(struct inode *inode, struct file *file)
-{
- int res;
-
- if (unlikely(atomic_dec_if_positive(&opencnt) < 0))
- return -EBUSY;
-
- expect_close = 0;
- if (locked) {
- module_put(THIS_MODULE);
- free_irq(wd_irq, &miscdev);
- locked = 0;
- }
-
- res = request_irq(wd_irq, wdt_gpi_irqhdl, IRQF_SHARED | IRQF_DISABLED,
- wdt_gpi_name, &miscdev);
- if (unlikely(res))
- return res;
-
- wdt_gpi_set_timeout(timeout);
- wdt_gpi_start();
-
- printk(KERN_INFO "%s: watchdog started, timeout = %u seconds\n",
- wdt_gpi_name, timeout);
- return nonseekable_open(inode, file);
-}
-
-static int wdt_gpi_release(struct inode *inode, struct file *file)
-{
- if (nowayout) {
- printk(KERN_INFO "%s: no way out - watchdog left running\n",
- wdt_gpi_name);
- __module_get(THIS_MODULE);
- locked = 1;
- } else {
- if (expect_close) {
- wdt_gpi_stop();
- free_irq(wd_irq, &miscdev);
- printk(KERN_INFO "%s: watchdog stopped\n",
- wdt_gpi_name);
- } else {
- printk(KERN_CRIT "%s: unexpected close() -"
- " watchdog left running\n",
- wdt_gpi_name);
- wdt_gpi_set_timeout(timeout);
- __module_get(THIS_MODULE);
- locked = 1;
- }
- }
-
- atomic_inc(&opencnt);
- return 0;
-}
-
-static ssize_t wdt_gpi_write(struct file *f, const char __user *d, size_t s,
- loff_t *o)
-{
- char val;
-
- wdt_gpi_set_timeout(timeout);
- expect_close = (s > 0) && !get_user(val, d) && (val == 'V');
- return s ? 1 : 0;
-}
-
-static long wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
-{
- long res = -ENOTTY;
- const long size = _IOC_SIZE(cmd);
- int stat;
- void __user *argp = (void __user *)arg;
- static struct watchdog_info wdinfo = {
- .identity = "RM9xxx/GPI watchdog",
- .firmware_version = 0,
- .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING
- };
-
- if (unlikely(_IOC_TYPE(cmd) != WATCHDOG_IOCTL_BASE))
- return -ENOTTY;
-
- if ((_IOC_DIR(cmd) & _IOC_READ)
- && !access_ok(VERIFY_WRITE, arg, size))
- return -EFAULT;
-
- if ((_IOC_DIR(cmd) & _IOC_WRITE)
- && !access_ok(VERIFY_READ, arg, size))
- return -EFAULT;
-
- expect_close = 0;
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- wdinfo.options = nowayout ?
- WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING :
- WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
- WDIOF_MAGICCLOSE;
- res = __copy_to_user(argp, &wdinfo, size) ? -EFAULT : size;
- break;
-
- case WDIOC_GETSTATUS:
- break;
-
- case WDIOC_GETBOOTSTATUS:
- stat = (*(volatile char *) flagaddr & 0x01)
- ? WDIOF_CARDRESET : 0;
- res = __copy_to_user(argp, &stat, size) ?
- -EFAULT : size;
- break;
-
- case WDIOC_SETOPTIONS:
- break;
-
- case WDIOC_KEEPALIVE:
- wdt_gpi_set_timeout(timeout);
- res = size;
- break;
-
- case WDIOC_SETTIMEOUT:
- {
- int val;
- if (unlikely(__copy_from_user(&val, argp, size))) {
- res = -EFAULT;
- break;
- }
-
- if (val > MAX_TIMEOUT_SECONDS)
- val = MAX_TIMEOUT_SECONDS;
- timeout = val;
- wdt_gpi_set_timeout(val);
- res = size;
- printk(KERN_INFO "%s: timeout set to %u seconds\n",
- wdt_gpi_name, timeout);
- }
- break;
-
- case WDIOC_GETTIMEOUT:
- res = __copy_to_user(argp, &timeout, size) ?
- -EFAULT : size;
- break;
- }
-
- return res;
-}
-
-
-/* Shutdown notifier */
-static int wdt_gpi_notify(struct notifier_block *this, unsigned long code,
- void *unused)
-{
- if (code == SYS_DOWN || code == SYS_HALT)
- wdt_gpi_stop();
-
- return NOTIFY_DONE;
-}
-
-
-/* Init & exit procedures */
-static const struct resource *wdt_gpi_get_resource(struct platform_device *pdv,
- const char *name, unsigned int type)
-{
- char buf[80];
- if (snprintf(buf, sizeof(buf), "%s_0", name) >= sizeof(buf))
- return NULL;
- return platform_get_resource_byname(pdv, type, buf);
-}
-
-/* No hotplugging on the platform bus - use __devinit */
-static int __devinit wdt_gpi_probe(struct platform_device *pdv)
-{
- int res;
- const struct resource
- * const rr = wdt_gpi_get_resource(pdv, WDT_RESOURCE_REGS,
- IORESOURCE_MEM),
- * const ri = wdt_gpi_get_resource(pdv, WDT_RESOURCE_IRQ,
- IORESOURCE_IRQ),
- * const rc = wdt_gpi_get_resource(pdv, WDT_RESOURCE_COUNTER,
- 0);
-
- if (unlikely(!rr || !ri || !rc))
- return -ENXIO;
-
- wd_regs = ioremap_nocache(rr->start, rr->end + 1 - rr->start);
- if (unlikely(!wd_regs))
- return -ENOMEM;
- wd_irq = ri->start;
- wd_ctr = rc->start;
- res = misc_register(&miscdev);
- if (res)
- iounmap(wd_regs);
- else
- register_reboot_notifier(&wdt_gpi_shutdown);
- return res;
-}
-
-static int __devexit wdt_gpi_remove(struct platform_device *dev)
-{
- int res;
-
- unregister_reboot_notifier(&wdt_gpi_shutdown);
- res = misc_deregister(&miscdev);
- iounmap(wd_regs);
- wd_regs = NULL;
- return res;
-}
-
-
-/* Device driver init & exit */
-static struct platform_driver wgt_gpi_driver = {
- .driver = {
- .name = wdt_gpi_name,
- .owner = THIS_MODULE,
- },
- .probe = wdt_gpi_probe,
- .remove = __devexit_p(wdt_gpi_remove),
-};
-
-static int __init wdt_gpi_init_module(void)
-{
- atomic_set(&opencnt, 1);
- if (timeout > MAX_TIMEOUT_SECONDS)
- timeout = MAX_TIMEOUT_SECONDS;
- return platform_driver_register(&wdt_gpi_driver);
-}
-
-static void __exit wdt_gpi_cleanup_module(void)
-{
- platform_driver_unregister(&wdt_gpi_driver);
-}
-
-module_init(wdt_gpi_init_module);
-module_exit(wdt_gpi_cleanup_module);
-
-MODULE_AUTHOR("Thomas Koeller <thomas.koeller@baslerweb.com>");
-MODULE_DESCRIPTION("Basler eXcite watchdog driver for gpi devices");
-MODULE_VERSION("0.1");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
-